手机:小米9,已经root,android 10
电脑:win11
软件:frida-tools==12.5.1(frida==16.7.19), frida-server==16.0.10
frida是一个用于在电脑上远程注入手机apk进程进行hook调试的软件.
有电脑端frida和手机端frida-server
一,安装frida-server到手机
frida 是一款基于 Python + JavaScript 的 Hook 与调试框架,首先电脑端使用命令 pip install frida-tools
安装 frida 模块(此命令默认会安装最新版的 frida 和 frida-tools,如),
pip install frida-tools==12.5.1
frida-tools的版本不是frida版本,为什么要指定版本,因为frida-server对机器有兼容性,经过测试frida-server16.0.10,对android 7和android 10兼容性最好, frida-tools 12.5.1里面是frida16.7.19是可以正常和frida-server16.0.10通信的.
然后下载 frida-server16.0.10,下载地址:https://github.com/frida/frida/releases
frida-server 要根据你电脑端pip安装的 frida 版本,一定要用这个命令查看才准确
#查看frida版本
frida --version
如果不知道自己手机是什么平台,通过下面adb命令查看
adb shell
#查看手机平台是arm64还是x86
getprop ro.product.cpu.abi
#查看手机大量信息
getprop | grep product
经过测试17.2.17兼容性不佳,安卓7会报错,根据issure里推荐16.0.10,发现16.0.10兼容性最好,下载frida-server-16.0.10-android-arm64.xz后
解压到d盘目录,解压得到其中的文件,将其重命名为frida-server(重命名只是用于方便后续使用)
将下载好的 frida-server 使用 adb push 命令传到手机的 /data/local/tmp/ 目录下,并给予 777 读、写、执行的权限,然后直接运行 frida-server,正常不会有任何输出,当然也可以使用 & 等方式让其在后台运行。
如果默认的27042被占用,或者为了防止被识别,我们可以用-l命令修改监听端口为其他端口如27052
cmd命令如下
(如果没有安装adb ,请自行下载platform-tools,里面有adb)
复制文件到手机
d:
adb push frida-server /data/local/tmp/
启动server
adb shell
su
cd /data/local/tmp/
chmod 777 frida-server
ls -l
./frida-server
成功启动图片如下
如果出现的错误,附解决办法(全部实践解决)
错误一:
Unable to load SELinux policy from the kernel: Failed to open file ?/sys/fs/selinux/policy?: Permission denied
解决:手机需要先root,并且进adb shell 后先输入su启用超级用户root权限
错误二:
Unable to start: Error binding to address 0.0.0.0:27042: Address already in use
解决:
进adb shell,
用ps -e | grep frida-server
查看已启动的frida-server进程
kill 进程id结束
错误三:
python安装的frida版本和 手机上frida-server版本不一致也会报错:电脑上运行frida时,提示未找到frida-server
解决:用相同版本
错误四:
unable to stat file for the executable "/memfd:frida-helper-32 (deleted)": No such file or director
这个是frida-server版本和这个版本的安卓系统不兼容,我用17.2.17安装在andriod7的老手机都提示这个错误,
结局:根据issure里面找到,用16.0.10版本就行, 于是下载frida-server-16.0.10-android-arm64,果然解决了
二,电脑启动frida
设置frida端口转发监听(新开cmd窗口)
27042,27043端口用于frida-server通信的默认端口号,主要用于客户端连接服务端。
adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043
遍历手机进程,这一步就能判断是否和手机的frida server通信成功
frida-ps -U
如果提示错误
Failed to enumerate processes: unable to find process with name 'system_server'
那就是手机被root或者frida电脑版本和手机版本不对应
下面就是双端frida安装并通信成功的
记住这里的进程名,后续会用到,这里三方应用一般是中文名,系统服务是英文,是app自己设置的,不同于我们一直使用的包名。
三,逆向实践
首先把apk下载到d盘根目录,通过adb安装apk到手机,
adb install momo3.2.apk
安装后手机打开app试试会不会闪退,不会闪退才可以正常脱.
接着,查看手机安装的所有包名
adb shell pm list packages
找到一个com.maimemo.android.momo就是我们今天要实践的对象,
这次我们时间脱x60的壳,利用frida-dexdump,自动化脱壳,
正式脱壳前确保已经adb shell连上手机,并且手机已经启动frida-server监听
方法一:
我们直接用frida-dexdump来脱,新开一个cmd,安装frida-dexdump
pip install frida-dexdump
进行脱壳,-f是重新启动这个包进行注入脱壳
frida-dexdump -U -f com.maimemo.android.momo
d盘目录就出现一个包名,里面有脱好的dex文件
这些文件就可以用jadx直接打开,里面就有代码.肯定体积最大的那个就是我们要找的主文件
打开发现出错
不用着急,dex是需要修复的,接下来拿出我们的反编译神器,MT管理器,里面有个dex修复功能(需要开通会员),
去mt官网下载,https://mt2.cn/download/,然后安装到手机
adb install mt2.19.apk
把所有dex文件全部打包成dex3.2.zip,传到手机里
adb push dex3.2.zip /data/local/tmp/
手机里打开mt,进入/data/local/tmp/,解压zip,全选所有dex文件,
点dex文件,选dex修复
可能会提出有的文件修复出错,没关系,只要我们最大的dex文件修复成功就行了
修复后压缩为dex3.2ok.zip
电脑上用adb pull命令传出来,解压后,打开jadx,全部拖到jadx窗口中,这样就成功了
adb pull /data/local/tmp/dex3.2ok.zip
至此,脱壳完成,可以欣赏他的源码了
~
`
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
=================以下内容可不看我没有进行实践操作========
方法二(历史久远,自定义强,需要大神写好js):
https://github.com/GuoQiang1993/Frida-Apk-Unpack
我们把dexDump.js下到d盘根目录,
我们可以把需要执行的js写到一个js文件,然后通过frida执行
命令行执行:
frida -U -f com.maimemo.android.momo -l dexDump.js
pip install frida-dexdump
frida-dexdump -U -f com.maimemo.android.momo
扩展:frida语法学习
加载脚本有两种方式,
一种Attach模式,是直接进程存在的情况,frida注入.
这种情况使用进程名,一般是中文
frida -U -n 抖音 test.js
一种 Spawn模式,是不管进程在不在,都由frida重新启动app掌握控制权并注入。
这种情况下,需要用-f参数,并使用包名
frida -U -f com.ss.android.ugc.aweme test.js
基础使用
1、在Java环境中运行
Java.perform(function () {
}
2、Hook Class
const TargetClass = Java.use('com.example.app.MainActivity');
TargetClass.login.implementation = function (username, password) {
console.log(`用户名: ${username}, 密码: ${password}`);
return this.login(username, password); // 继续原逻辑
};
3、打印堆栈
console.log(Java.use("android.util.Log").getStackTraceString(
Java.use("java.lang.Exception").$new()
));
4、构造函数
Java.use("classname").$init(params)
5、内部类
Java.use("classname$innerclassname")
6、取变量里面的值
obj.name.value
其中name是变量名,后面需要跟一个value,才能拿到实际的值
7、枚举某个类的实例
Java.choose(className, callbacks)
例如我们想拿到Activity的实例,做一些事情,就可以用这个方式来做。