图太多了,一个一个重传应该不行,先传md过来看看会不会被夹图
0 adb常见命令
一般模拟器(非真机模拟器)的安装目录下会有一个adb.exe。如果安装了Android Studio的话也会附带一个adb。如果两种情况都没有则需要去自己下载一个。调试远端的设备(本机上的模拟器一般不用,如雷电模拟器)需要先使用adb connect进行连接再shell。
1 代{过}{滤}理
1.1 挂代{过}{滤}理步骤
(这个方法真机模拟器无法使用,真机挂代{过}{滤}理方式请看下文第二节)
使用burpsuite、mitmproxy、lamda。
lamda github页面:https://github.com/rev1si0n/lamda/
首先需要准备一个root权限的手机。下载lamda的安装脚本adb中使用sh运行安装(详细步骤请自行查看lamda的ReadMe)。主机中使用pip安装lamda的客户端。
手机如果是模拟器,配置到与主机同一个网段则需要使用桥接模式。使用桥接模式后互相能ping通就可以了。
启动lamda的命令:
sh /data/local/tmp/x86/bin/launch.sh
先启动手机上的lamda。使用lamda是为了挂代{过}{滤}理+安装证书。
mitmproxy使用pip命令即可安装(它是一个python module):
pip install mitmproxy
安装mitmproxy的证书(运行mitmdump挂起服务器,浏览器走mitm的代{过}{滤}理访问mitm.it即可安装证书)并挂上mitmproxy的代{过}{滤}理如下:
#启动代{过}{滤}理
# sh /data/local/tmp/x86/bin/launch.sh
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.install_ca_certificate("mitmproxy-ca-cert.cer")
d.start_gproxy(profile)
#d.stop_gproxy()
#d.uninstall_ca_certificate("cacert.der")
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
#以下使用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(){ //这里开始是Hook函数,前面的getLevels为要Hook的函数名
console.log("Hook start");
var level=this.getLevels(); //获取下返回值
console.log(level.toString());
return level; //返回函数执行结果,否则这就不是一个纯正的Hook了
}
})
然后我们再写一个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。执行效果如下:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681206175077-fd94df56-8b0e-4b30-b0c4-382f35650258.png#averageHue=%23010101&clientId=u1f85cc59-315a-4&from=paste&height=99&id=u7017dc6e&originHeight=99&originWidth=485&originalType=binary&ratio=1&rotation=0&showTitle=false&size=2399&status=done&style=none&taskId=ua0237936-ac94-400e-9344-61741f73f12&title=&width=485)
## 7.3 Jadx远程调试
由于我这里用的夜神模拟器有个一直占用端口的adb,Jadx基于adb的远程动态调试暂时不可用。
# 8 使用apktool解包、修改、重新打包、签名APK
在进行动态调试之前,我们要先判断APK是否允许调试。如果APK不允许调试,我们就需要反编译解包APK,修改其中的AndroidManifest.xml文件并重新打包签名。
另外一些情况中,我们也需要通过修改APK的代码达到绕过校验等目的。
我们以第一种情况为例,下载apktool,这是Android官方的工具,下载方式应该很简单。
## 8.1 解包修改文件并重新打包
使用命令
> java -jar .\apktool_2.7.0.jar d -f C:\Users\HONOR\Desktop\bosuu2501.apk
对APK进行反编译:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681284423897-8ec91aa7-cdee-4c20-af6c-60cb8ce6f0c3.png#averageHue=%23010101&clientId=u1f85cc59-315a-4&from=paste&height=302&id=ub999c1d9&originHeight=302&originWidth=983&originalType=binary&ratio=1&rotation=0&showTitle=false&size=14337&status=done&style=none&taskId=u90b4768c-2a91-42c5-9e8d-75eacac73de&title=&width=983)
编译完成后,切入文件夹,找到AndroidManifest.xml,修改:
在application标签里(理论上只会有一个这种标签)加上android:debuggable=“true”,然后保存:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681284821824-ebcab80f-36eb-42e3-88b3-1b8c1b481203.png#averageHue=%238c684a&clientId=u1f85cc59-315a-4&from=paste&height=1048&id=u768c7553&originHeight=1048&originWidth=1920&originalType=binary&ratio=1&rotation=0&showTitle=false&size=415710&status=done&style=none&taskId=u3d458213-fde2-419a-9e99-74fa22b63dd&title=&width=1920)
然后继续使用apktool
> java -jar .\apktool_2.7.0.jar b .\bosuu2501\
将APK文件夹进行打包:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681285181692-75766e4b-0f81-4d1b-a7d8-5f3b46a600f3.png#averageHue=%23000000&clientId=u1f85cc59-315a-4&from=paste&height=340&id=ua0f30776&originHeight=340&originWidth=749&originalType=binary&ratio=1&rotation=0&showTitle=false&size=13795&status=done&style=none&taskId=uf088aba8-e0de-4656-bc95-ab8f492f40e&title=&width=749)
## 8.2 签名
之前我们说过,APK包里会有一个META-INF文件夹用于签名。APK在运行时,安卓会先对APK的签名进行校验,所以我们需要将修改过的APK重新签名使其通过校验。
签名的话,方式有很多种,可以使用Android官方的工具jarsigner,也可以使用MT管理器等APK。
考虑到使用jarsigner的传统艺能是打一大段命令行,这里就直接使用MT管理器进行签名。adb push打包后的apk文件到手机中,打开MT管理器,切到目录下,长按文件,选择签名即可:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681286438244-9b0afdc3-b343-48d7-8c7f-e2ba80dfc329.png#averageHue=%23d9d8d8&clientId=u1f85cc59-315a-4&from=paste&height=1020&id=u134152ae&originHeight=1020&originWidth=596&originalType=binary&ratio=1&rotation=0&showTitle=false&size=146594&status=done&style=none&taskId=u0c730ba6-6bbe-4d59-9b3d-b060cc7fe16&title=&width=596)
签名后,会出现一个相同名字后缀为_sign的apk文件,直接安装此文件,成功。
# 9 使用JEB进行反编译与远程调试
不推荐单独使用JEB进行反编译,因为它初始给出的代码为Smali。
同时,JEB也挺容易卡的,可以在它的根目录下创建jvmopt.txt文件并输入参数-Xmx8G以提高其运行内存。
## 9.1 使用JEB对照查看Java代码与Smali代码
直接使用JEB打开APK文件,在文件树中选择要查看的JAVA类,右键选择解析:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681268832407-3b0458a0-3c61-4922-a22f-45b746e537f4.png#averageHue=%23f0eeed&clientId=u1f85cc59-315a-4&from=paste&height=752&id=ud15f2f4a&originHeight=752&originWidth=600&originalType=binary&ratio=1&rotation=0&showTitle=false&size=82400&status=done&style=none&taskId=u11fd2233-6109-4886-81a6-768453f98d8&title=&width=600)
以打开Java代码。然后在选中行中右键再次点击解析,会定位到其Smali代码:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681268943333-72f7bede-4474-479a-a8f5-d59d56ea319c.png#averageHue=%23f4f2f1&clientId=u1f85cc59-315a-4&from=paste&height=1048&id=ua69c570d&originHeight=1048&originWidth=1920&originalType=binary&ratio=1&rotation=0&showTitle=false&size=233720&status=done&style=none&taskId=uff097eed-229a-4622-b387-e9db62d8c4b&title=&width=1920)
## 9.2 使用JEB对APK进行动态调试
使用动态调试之前,需要确保以下几点:
- adb已经连接上手机
- 手机打开了USB调试
- 手机的USB调试中指定调试APK为目标,并打开“等待调试程序”
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681287071550-7a3db90e-75ff-4c6e-926a-eff7f4a837be.png#averageHue=%23f3efef&clientId=u1f85cc59-315a-4&from=paste&height=662&id=u70383d24&originHeight=662&originWidth=575&originalType=binary&ratio=1&rotation=0&showTitle=false&size=84114&status=done&style=none&taskId=uaf13d323-4269-4eeb-8a7a-162bca33ab5&title=&width=575)
如果在选择调试应用中没有调试目标,需要考虑APK没有打开允许调试的选项。
如果APK附加进程后直接闪退,请使用最后修改打包签名后的APK进行反编译(也就是说,最后你在手机上运行的是什么APK就要用什么APK进行反编译)。
如果附加进程后一直卡在链接窗口,关闭USB调试试试。
将待调试的Smali语句Ctrl+B打上断点,然后按右上角小BUG打开调试窗口,手机打开目标APK,JEB选择设备和进程,点击附加开始动态调试。
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681291155791-9cf89076-6e46-42a4-ba48-cd9bfa85e209.png#averageHue=%23f3efee&clientId=u1f85cc59-315a-4&from=paste&height=935&id=u8c0edf15&originHeight=935&originWidth=1186&originalType=binary&ratio=1&rotation=0&showTitle=false&size=135915&status=done&style=none&taskId=uc3a34e08-6730-4f2a-8445-4ce4037c438&title=&width=1186)
调试成功,可以看到已经在断点处停下:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681350194091-bbb42951-3624-4690-a998-8eea84a07da0.png#averageHue=%23b1b685&clientId=ua02b84a8-af5e-4&from=paste&height=1048&id=u3f9f55d8&originHeight=1048&originWidth=1920&originalType=binary&ratio=1&rotation=0&showTitle=false&size=221179&status=done&style=none&taskId=ue3d00c9a-9a16-4fd3-8f16-4f907a64972&title=&width=1920)
# 10 脱壳
本章节涉及具体技术原理请参考:
- [https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458457914&idx=1&sn=1d505597b47089cbd8bdc1e6e0a2b068&chksm=b18e27b086f9aea63d4404f118b0dc4c0b87c5986f20e556a5a85c967834df0d7f3e8e6d98d6&scene=27](https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458457914&idx=1&sn=1d505597b47089cbd8bdc1e6e0a2b068&chksm=b18e27b086f9aea63d4404f118b0dc4c0b87c5986f20e556a5a85c967834df0d7f3e8e6d98d6&scene=27)
APK壳的原理其实不难理解,我们可以理解为另一种对源代码的混淆和加密。
具体的来说,就是通过替换APK运行过程中的dex文件加载器为自定义的加载器以读取dex文件,这样做开发者就可以额外对dex文件进行加密。目前APK加壳技术有dex整体加密、函数抽取、VMP加壳等类型。有些壳每次都会读取整个dex文件,这种比较容易脱壳;有些壳是分段读取的,或者使用了更复杂的技术,就需要进一步的调试。
## 10.1 识别APK是否加壳
有些壳可以直接通过工具识别出来,有些自定义壳需要自己看代码识别。
### 10.1.1 工具识别APK是否加壳
使用APK Messenger或者在线平台摸瓜、南明离火,手机端的MT管理器可以识别出一些壳来。直接用工具打开即可。
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681353691653-e4f8276f-bf7e-4ee2-9bc4-eee27c0e0b97.png#averageHue=%23cfcfcf&clientId=ua02b84a8-af5e-4&from=paste&height=228&id=u92140c1a&originHeight=228&originWidth=503&originalType=binary&ratio=1&rotation=0&showTitle=false&size=12313&status=done&style=none&taskId=ud0c111df-d64c-45ba-83a2-ccd878d4080&title=&width=503)
### 10.1.2 查看反编译代码判断APK是否加壳
下面给出一些可以用来识别APK是否加壳的TIPS,不一定准确。
- 如果dex文件中的自定义函数(非ANDROID自带)不是JAVA函数而是Native函数,这个APK可能使用了VMP/Dex2C加壳
- 如果dex文件并不完整,关键类和函数的代码是空的(函数return null,查看smali代码一片nop),这个APK可能使用了函数抽取加壳
- 可以查看资源文件->lib中的so文件文件名是否是已知的加壳读取器文件名
- 如果APK看上去不像需要使用NPK技术(调用CPP,大多数情况下是调用底层方法),却带有.so文件,大概率使用了壳
## 10.2 ⭐腾讯乐固(御安全)简单脱壳修复并重新打包
以下文章里有八中常见壳的脱修教程,本节的乐固脱壳步骤参考的就是此文:[https://www.52pojie.cn/thread-1453091-1-1.html](https://www.52pojie.cn/thread-1453091-1-1.html)
Dex整体加固脱壳修复打包示范,以安全家3.8.9为例,使用GDA检测可以看到为乐固:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681440642402-6b182abd-683a-4532-aa1f-6f379b683cb9.png#averageHue=%23f5fafd&clientId=u59f98cda-4554-4&from=paste&height=474&id=ud284369a&originHeight=474&originWidth=671&originalType=binary&ratio=1&rotation=0&showTitle=false&size=49104&status=done&style=none&taskId=ue764104d-e879-4546-909f-f889bc73d12&title=&width=671)
已知壳如果能脱下来,那么详细的脱壳步骤就是**使用工具脱壳->替换、删除dex文件->用脱下来dex文件的入口修改AndroidManifest.xml文件->修复dex->重新打包->签名**。
### 10.2.1 脱出dex文件并删改、修复
使用工具为BlackDex,请注意此APK分位数版本,需要按照手机位数下载32位或64位。
打开工具,直接选择APK自动脱壳:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681375222324-a54570aa-3831-46ab-a1db-29f46ece905a.png#averageHue=%237c7c7c&clientId=ua02b84a8-af5e-4&from=paste&height=1020&id=u5976c8dd&originHeight=1020&originWidth=596&originalType=binary&ratio=1&rotation=0&showTitle=false&size=85250&status=done&style=none&taskId=ufaf14536-b848-4307-a3f6-f9e0b0741ad&title=&width=596)
脱出来了四个dex文件:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681440838646-36b6810a-7c52-4210-a5dc-b4d0ce7e3225.png#averageHue=%232a2928&clientId=u59f98cda-4554-4&from=paste&height=167&id=u1675aafe&originHeight=167&originWidth=697&originalType=binary&ratio=1&rotation=0&showTitle=false&size=20264&status=done&style=none&taskId=ub1e22faa-4f55-4408-b8c6-9c46898f3af&title=&width=697)
将APK用解压缩软件打开,对比两边的dex文件大小:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681440880345-2e465cdc-3a8c-42b0-9294-679175164517.png#averageHue=%23787776&clientId=u59f98cda-4554-4&from=paste&height=668&id=ud4f293e3&originHeight=668&originWidth=1904&originalType=binary&ratio=1&rotation=0&showTitle=false&size=171942&status=done&style=none&taskId=uea423b9a-3ad3-4955-ad8c-4c7817149a3&title=&width=1904)
可以看到有两个dex文件与原始dex大小相同,删去这两个dex。
剩下的dex留个备份,然后用NP管理器打开进行dex文件修复,选择全部修复:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681436996892-68726ccb-39f8-4749-8fca-7c512932429a.png#averageHue=%23888888&clientId=u59f98cda-4554-4&from=paste&height=1020&id=EIS5C&originHeight=1020&originWidth=596&originalType=binary&ratio=1&rotation=0&showTitle=false&size=112433&status=done&style=none&taskId=u414e1f4b-513f-4456-8722-2bdd2ca9326&title=&width=596)
### 10.2.2 查找真实入口并进行替换
gda打开或使用baksmali(前者是国人写的软件,后者貌似是什么官方工具,都很容易下载)反编译dex文件**(指的是原dex文件,不是脱下来的)**,然后查找真实appname。
这里使用backsmali,命令为 java -jar .\baksmali-2.5.2.jar d .\cookie_3561024.dex。
全局搜索.field static className:Ljava/lang/String;找到对应的字段(这个需要搜索的字段每个加固是不一样的,毕竟加固相当于自定义读取器,每个厂家代码不同):
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681435267476-129e267b-37df-4246-8a6e-ef0d58112d5e.png#averageHue=%2395724c&clientId=u59f98cda-4554-4&from=paste&height=398&id=acitn&originHeight=398&originWidth=1907&originalType=binary&ratio=1&rotation=0&showTitle=false&size=91926&status=done&style=none&taskId=u405beb53-e611-420d-8563-929191aa3f8&title=&width=1907)
向下看,找到赋值部分:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681439911517-dd6eb7a0-4f9b-414b-aec0-8bdabc538b52.png#averageHue=%23201e1e&clientId=u59f98cda-4554-4&from=paste&height=635&id=ZYVrO&originHeight=635&originWidth=1252&originalType=binary&ratio=1&rotation=0&showTitle=false&size=60980&status=done&style=none&taskId=u4f3b3bf5-614f-40ec-a5b9-c2b7ee86ef8&title=&width=1252)
可以看到值为com.nursinghome.monitor.base.MyApp,这就是APK的真实入口名。
电脑端使用apktool对apk进行反编译(命令参考上面章节),得到smali源码文件夹。
在文件夹中找到AndroidManifest.xml文件,找到application元素的android:name字段,替换为刚才找到的值:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681437934210-6b751fc6-0bbd-4c61-a712-ecdea17224db.png#averageHue=%23262221&clientId=u59f98cda-4554-4&from=paste&height=144&id=u9c9d7a0a&originHeight=144&originWidth=1431&originalType=binary&ratio=1&rotation=0&showTitle=false&size=42918&status=done&style=none&taskId=ub36f71a4-19af-4be4-819c-afed9893a19&title=&width=1431)
### 10.2.3 重新编译APK并删除加固文件、替换dex
替换完成后,保存文件,使用apktool重新编译:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681441280037-63b8469a-cfeb-4b0e-bc93-a8b871d2ed7e.png#averageHue=%23000000&clientId=u59f98cda-4554-4&from=paste&height=149&id=ub25a9b34&originHeight=149&originWidth=618&originalType=binary&ratio=1&rotation=0&showTitle=false&size=5712&status=done&style=none&taskId=uc1a07510-088a-4ad8-beb9-5ebaf4859e4&title=&width=618)
然后用解压缩软件打开编译后的APK文件,查找并删除以下文件:
- 0O等类似开头长得很混乱的文件,如0OO00l111l1l
- tencent_stub
- tosversion
- 其他名字中带有shell的文件(主要是so文件)
然后,删除根目录下的classes{n}.dex文件,放入第一步中修复好的dex文件并将它们重命名为classes{n}.dex。
### 10.2.4 重新签名,安装
跟第八节中的步骤一样。打开NP管理器,选择APK文件,可以看到加固已经没有了,但是显示校验不通过。
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681441579974-921b0fd3-6f1f-4c94-a7e3-bd72ad2b34ef.png#averageHue=%23d5d4d3&clientId=u59f98cda-4554-4&from=paste&height=422&id=u4e691af3&originHeight=422&originWidth=545&originalType=binary&ratio=1&rotation=0&showTitle=false&size=49320&status=done&style=none&taskId=uc906d2f5-f6f3-4567-85cb-8abc3d9b86a&title=&width=545)
点击功能,选择签名然后安装签名后的APK即可:
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32358243/1681440439215-021f7549-0f70-479e-a83a-1d783bc4eecb.png#averageHue=%237b7876&clientId=u59f98cda-4554-4&from=paste&height=1020&id=ub3124c75&originHeight=1020&originWidth=596&originalType=binary&ratio=1&rotation=0&showTitle=false&size=129866&status=done&style=none&taskId=ue4fbcae5-7b2d-4e23-9e08-b321950d9b0&title=&width=596)