0 adb常见命令
一般模拟器(非真机模拟器)的安装目录下会有一个adb.exe。如果安装了Android Studio的话也会附带一个adb。如果两种情况都没有则需要去自己下载一个。调试远端的设备(本机上的模拟器一般不用,如雷电模拟器)需要先使用adb connect进行连接再shell。
先启动手机上的lamda。使用lamda是为了挂代{过}{滤}理+安装证书。
mitmproxy使用pip命令即可安装(它是一个python module):
pip install mitmproxy
安装mitmproxy的证书(运行mitmdump挂起服务器,浏览器走mitm的代{过}{滤}理访问mitm.it即可安装证书)并挂上mitmproxy的代{过}{滤}理如下:
from lamda.client import *
d=Device("192.168.3.31")
profile = GproxyProfile()
profile.type = GproxyType.HTTP_CONNECT
profile.drop_udp = True
profile.host = "192.168.3.82"
profile.port = 8899
d.start_gproxy(profile)
d.beep()
这个脚本在手机端lamda启动后运行一次,听到beep声表示运行成功。
install_ca_certificate就是安装证书的命令,只需要运行一次。
手机端的配置结束,接下来pip安装mitmproxy,使用upstram模式转发流量到上流代{过}{滤}理服务器(即BP)即可。
命令为:
mitmdump --mode upstream:127.0.0.1:8080 --listen-port 8899 --ssl-insecure
上面的mitmweb也可以改成mitmproxy 或mitmdump 主要是中间流量的表现形式不同。
1.2 虚拟机、手机逃避代{过}{滤}理检测
有时候直接使用系统的代{过}{滤}理会被APK检测到。有些APK的包使用了参数NO_PROXY,会绕过系统代{过}{滤}理发送,有些则会在检测到代{过}{滤}理的时候停止发包。
目前知道的能够绕过代{过}{滤}理的工具有两个,HTTPDroid和lamda。lamda挂代{过}{滤}理参考上面的脚本,这个我测试过是可以绕过代{过}{滤}理检测的。HTTPDroid及其他基于iptables的工具据称在原理上是可以绕过的。
但是HTTPDroid不能在夜神模拟器上安装。我的建议是普通模拟器上使用lamda,真机模拟器上使用HTTPDroid(因为lamda不能在真机模拟器上使用)或者真机宿主机安装小黄鸟(HTTPCanary)。
1.3 真机虚拟机逃避代{过}{滤}理检测(真机虚拟机)
有时候APK会校验用户所处的环境是否是真机,这个时候建议直接使用真机或在真机上安装虚拟机。这个原理跟反反爬虫是一样的:再多的掩饰都是虚的,程序员总能从你想不到的角度进行检测,所以最好直接在真机里做操作。比如安装真机虚拟机如VMOS。
但是真机虚拟机是无法使用lamda的(实际的真机可以),用VMOS抓包的一个方式是代{过}{滤}理到宿主机的小黄鸟(HTTPCanary),导出.0证书,小黄鸟设置目标应用,虚拟机安装证书。
也可以通过转换过的.0证书+模拟器挂代{过}{滤}理代{过}{滤}理到mitmproxy然后中转到burpsuite。一样的。
3 证书与双向认证
3.1 安装证书的小TIPS
由于虚拟机可能不能直接装证书,即使有ROOT(具体为什么我不知道),只能将证书导出为.0格式然后复制到/system/etc/security/cacerts/下。
cer、pem等格式的证书可以通过openssl转换为.0格式之后手动安装。
命令为(pem与cer都是这个):
openssl x509 -inform PEM -subject_hash_old -in mitmproxy-ca-cert.pem -out out.0
3.2 证书校验绕过
有时候,APK会这样:

校验通信中证书的签发HOST。这种情况需要用户反编译找到hostname然后自行制作一个此hostname的证书。证书可以通过openssl生成。
3.3 双向认证(双签)绕过
双向认证,指的是APK与服务器各自有一个私钥,每次通信时,通信包会经过两次加密。或者换句话说,就是APK发送到服务器的包要被客户端证书签名,服务器发送到APK的包要被服务器证书签名(如果APK本身还设置了)。这就导致BP等使用的自签名证书不会被服务器端接受。
SSL双向认证体系中,客户端与服务端各拥有一对证书和密钥,在通信过程中:
(1)客户端建立通信,发送SSL版本等信息给服务端
(2)服务端发送服务端证书给客户端,客户端会校验服务端的证书是否在许可范围内
(3)客户端校验通过后,发送客户端证书给服务端,服务端也会校验客户端证书是否在许可范围内
综上所述,要成功抓到经过双向签名的包,需要同时绕过客户端和服务端双端的认证。客户端的认证可以通过Xposed模块SSLUnpinning或者JustTrustMe绕过,而服务端认证则需要获得APK文件中的证书。
反编译APK,找到APK中保存的客户端证书,还有它的密码。公私钥一般作为单独文件存储(也有APK直接写死在代码里,不过证书是有过期时间的,所以应该没什么APK会这么做),密钥则会写在代码里,需要反编译查找。

如果代码未经混淆,直接搜索ClientKeyStore.load即可找到打开bks证书的语句,第二个参数即为密码,第一个参数为证书文件名。
由于Android证书端的证书格式为bks,而BP需要的证书格式为p12,所以我们还需要转换证书的格式。下载portecle后转换证书的格式,然后在BP中导入即可抓到包:

4 使用Drozer扫描Android本地漏洞
drozer主要 用来查找androidAPK本身的漏洞,而非对应后端的漏洞。
4.1 安装与启动
下载地址:
https://github.com/WithSecureLabs/drozer/releases
需要先额外安装一个python2.7,再运行安装程序。如果环境中已经有其他版本的python了,请先看下节。
在运行drozer.bat文件无报错后,我们开始配置手机端的agent和依赖。搜索python2文件夹下的apk文件,找到standard-agent.apk,将其装在手机上,然后打开APK,点击右下角的开启打开agent。adb方面转发端口,使用命令:
.\adb.exe forward tcp:31415 tcp:31415
然后电脑处使用命令:
.\drozer.bat console connect
运行成功应该如下:

4.2 额外安装py2下的各种问题
现在基本没人会使用py2编程了,所以很多人会先装py3。
在4.1安装python2时,如果想将py2不冲突的放进环境变量里,可以将py2文件夹里的python.exe更名为python2.exe然后将路径放在PATH下(不像放在PATH也可以,后面的python2替换为绝对路径)。
点击安装,选择之前安装的python2文件夹,进入\Scripts文件夹下,将drozer.bat文件中的python替换为python2再运行即可启动dozer。
然后我们开始配置依赖。移动到pip2.exe所在的文件夹使用与平时使用pip相同的命令安装service_identity、twisted、pyopenssl、pyyaml、protobuf即可。
有时候下载的py2里没有pip文件,需要在这里获取get-pip.py:
https://bootstrap.pypa.io/pip/2.7/get-pip.py
全文复制后保存为python文件,然后使用py2运行就行了。但是这样获取的pip有个问题就是没有能访问的镜像源,所以每次安装时带上选项,使用国内的镜像源即可:
-i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
4.3 常见命令(dz控制台下)
查看APK列表:
run app.package.list
-f 选项可以按照关键词查找APK。
查看APK暴露的activity列表:
run app.activity.info -a 包名
拉起Activity:
run app.activity.start --component 包名 活动名(activity)
枚举Provider:
run app.provider.info -a 包名
SQL注入扫描:
run scanner.provider.injection -a 包名
5 插件框架
这两个框架的模块安装方式都是一样的:模块本身就是一个APK,直接安装APK即会被识别。
5.1 安装使用Magisk
电脑端模拟器安装Magisk可以参照此文章:https://www.52pojie.cn/thread-1583586-1-1.html
使用Magisk而不使用XPOSED的原因是Magisk对文件系统的破坏性小,且不需要事先ROOT,适用范围广一些。并且Magisk上可以集成Xposed。
对于真机模拟器而言,已知光速模拟器可以安装Magisk,但是一般情况下需要付费VIP。VMOS据说安装之后并不好用,可能还是要用其自带的XPOSED。
可以使用Magisk Manager 安装Magisk。安装后,如果Manager提示更新但一直下载失败,请打开设置换源为https://qianyegroup.gitee.io/magiskbuilds/updates/custom_md2.json。
5.2 安装使用Xposed
这是真机模拟器的不得已之选。使用VMOS PRO的虚拟机会自带一个XPOSED。
6 使用Frida
由于lamda中自带了frida,本节分为使用lamda与不使用lamda两种方式讲解(可惜不能兼容真机模拟器,不然是想默认使用lamda讲解的)
6.1 安装
Frida与Drozer一样,也是基于python的分布式框架。分为服务端与客户端两个。客户端(本机)使用pip安装:
pip install frida
pip install frida-tools
pip install objection
服务端(安装过lamda的手机不需要安装,也就是可以跳过下面的内容直接到使用部分)访问github页面选择下载:https://github.com/frida/frida/
服务端和客户端的版本要一致,由于pip安装时会自动选择版本,我们这里以客户端版本为准。
使用
pip list | findstr frida
查看frida的版本,adb命令行中使用
getprop ro.product.cpu.abi
获取架构,然后选择对应的frida-server,如:



解压文件,adb push到/data/local/tmp,对frida-server-xxx文件chmod 777然后执行即可。
6.1.1 lamda使用frida的适配
以当前最新的lamda版本(3.150)为例。首先,需要运行命令:
pip3 install -U --force-reinstall lamda[full]
然后,确定frida版本为15.X,frida-tools为12.1.X。
否则将会出现frida命令执行反复横跳,一会成功一会提示版本不匹配的问题。
6.2 基础使用
使用lamda中的frida与普通情况相似,但是需要在每一条frida命令下添加参数:-H 192.168.0.2:65000(ip请改成手机ip),而原生frida需要让adb转发frida端口出来:
adb forward tcp:27043 tcp:27043
adb forward tcp:27042 tcp:27042
在已经连接adb的情况下,cmd使用:
frida-ps -U
来进行一个热身。这个命令显示的是手机进程列表。

使用命令(如果程序太多,考虑使用frida-ps -Ua,它只会显示运行中APK)
frida-ps -Uai
获取当前运行所有APK的包名:

进入frida-shell:
frida -H 192.168.3.61:65000 -f com.busuu.android.enc

6.2.1 lamda中frida的另一种使用方式
即在python脚本中进行。我给一个示例代码:
import lamda
from lamda.client import *
device=Device("192.168.3.61")
fridar=device.frida
fridar.enumerate_processes()
如果追求动态使用的话,可以在python自己的shell中运行这些代码。
7 使用Jadx进行反编译
这个东西很容易安装,就不讲了。
安装后直接将要反编译的apk文件拖进程序即可:

对于APK中的dex文件,有些能反编译出来,有些不能。
不过根据使用经验,还有一些额外的设置推荐赠送:
- 首选项里打开反混淆,方便追踪方法
- 如果要搜索被混淆过的、被编码的,反正很长的文件,最好复制出来在第三方编辑器中查找,不然很容易卡死
7.1 先谈谈APK本身
安卓应用说来说去其实就是基于google android框架下的一类代码打包成的可运行包。与web应用不同,这些包一般都经过了编译才能在目标平台运行(想象一下jar包,里面的代码就是从.java文件编译成了.class字节码,APK可以看做大号带资源的jar包),我们是没办法直接看到源代码的。
用解压缩文件打开一个apk包可以看到其结构如下:

如果读者做过android开发,可以发现apk的结构和它作为源代码的结构基本类似,只是明文代码变成了编译后的文件。
我拿一个android工程的目录做例子,进行对比:

assets文件、res文件、AndroidManifest.xml保持不变,java文件夹中的源代码包被放在主目录,META-INF文件夹为签名。多出来的文件为.dex文件与.arsc文件(如果此APK使用NPK开发,也就是调用了CPP代码,还会出现lib文件夹,下面放的是CPP的二进制文件.so)。前者为Android原生的可执行文件(当作安卓上的exe),后者为资源映射文件。
7.2. Jadx+Frida 进行Hook
最新版本中,可以右键选择函数,然后复制为frida片段(在反混淆开启时此选项生成的代码是错误的):

不过我更推荐自己写。
我们以函数getLevels为例(获取用户等级):

先找到其类名和函数名。然后对照原函数写原始Hook(熟悉前端Hook的人不会陌生,因为原始Hook代码为JS):
Java.perform(function(){
var Course=Java.use('com.busuu.android.api.course.model.ApiCourse');
Course.getLevels.implementation=function(){
console.log("Hook start");
var level=this.getLevels();
console.log(level.toString());
return level;
}
})
然后我们再写一个python脚本,使frida挂上Hook:
import frida,sys
appPacknName = "com.busuu.android.enc" #请填写对应要调试APK的包名
scriptFile = "1.js" #JS文件名
HOST="192.168.3.61:65000" #frida 位置
输出日志的回调方法
def on_message(message, data):
if message['type'] == 'send':
print(" {0}".format(message['payload']))
else:
print(message)
manager = frida.get_device_manager()
device = manager.add_remote_device(HOST)
spawn模式,找到目标包名并重启,在启动前注入脚本
pid = device.spawn([appPacknName])
session = device.attach(pid)
device.resume(pid) #以上两行的顺序不能错
with open(scriptFile, encoding='UTF-8') as f :
script = session.create_script(f.read())
script.on("message", on_message)
script.load() #把js代码注入到目标应用中
设置一直监听
sys.stdin.read()
运行此脚本,frida会自动重启APK并挂上Hook。执行效果如下:
加上android:debuggable=“true”,然后保存:
。
如果附加进程后一直卡在链接窗口,关闭USB调试试试。
将待调试的Smali语句Ctrl+B打上断点,然后按右上角小BUG打开调试窗口,手机打开目标APK,JEB选择设备和进程,点击附加开始动态调试。

APK壳的原理其实不难理解,我们可以理解为另一种对源代码的混淆和加密。
具体的来说,就是通过替换APK运行过程中的dex文件加载器为自定义的加载器以读取dex文件,这样做开发者就可以额外对dex文件进行加密。目前APK加壳技术有dex整体加密、函数抽取、VMP加壳等类型。有些壳每次都会读取整个dex文件,这种比较容易脱壳;有些壳是分段读取的,或者使用了更复杂的技术,就需要进一步的调试。
有些壳可以直接通过工具识别出来,有些自定义壳需要自己看代码识别。
使用APK Messenger或者在线平台摸瓜、南明离火,手机端的MT管理器可以识别出一些壳来。直接用工具打开即可。
不是JAVA函数而是Native函数,这个APK可能使用了VMP/Dex2C加壳
- 如果dex文件并不完整,关键类和函数的代码是空的(函数return null,查看smali代码一片nop),这个APK可能使用了函数抽取加壳
- 可以查看资源文件->lib中的so文件文件名是否是已知的加壳读取器文件名
- 如果APK看上去不像需要使用NPK技术(调用CPP,大多数情况下是调用底层方法),却带有.so文件,大概率使用了壳
以下文章里有八中常见壳的脱修教程,本节的乐固脱壳步骤参考的就是此文:[https://www.52pojie.cn/thread-1453091-1-1.html](https://www.52pojie.cn/thread-1453091-1-1.html)
Dex整体加固脱壳修复打包示范,以安全家3.8.9为例,使用GDA检测可以看到为乐固:
反编译dex文件**(指的是原dex文件,不是脱下来的)**,然后查找真实appname。
这里使用backsmali,命令为 java -jar .\baksmali-2.5.2.jar d .\cookie_3561024.dex。
全局搜索.field static className:Ljava/lang/String;找到对应的字段(这个需要搜索的字段每个加固是不一样的,毕竟加固相当于自定义读取器,每个厂家代码不同):
,得到smali源码文件夹。
在文件夹中找到AndroidManifest.xml文件,找到application元素的android:name字段,替换为刚才找到的值:

然后,删除根目录下的classes{n}.dex文件,放入第一步中修复好的dex文件并将它们重命名为classes{n}.dex。
跟第八节中的步骤一样。打开NP管理器,选择APK文件,可以看到加固已经没有了,但是显示校验不通过。
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681441579974-921b0fd3-6f1f-4c94-a7e3-bd72ad2b34ef.png
点击功能,选择签名然后安装签名后的APK即可:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681440439215-021f7549-0f70-479e-a83a-1d783bc4eecb.png