一、Frida框架简介
Frida是一款基于Python + JavaScript 的hook框架,本质是一种动态插桩技术。可以用于Android、Windows、iOS等各大平台,其执行脚本基于Python或者Node.js写成,而注入代码用JavaScript写成,所以有必要了解一些这些语言的语法。本文主要讲述了Android上Frida框架的使用。
二、Android Frida环境搭建
使用Frida需要Python 3环境,在Windows上目前预编译的版本需要Python3.7,暂时不支持Python 3.8。关于Python的安装这里就不再赘述。同时你还需要安装好pip。然后就可以安装frida了,使用如下的命令:
pip3 install frida frida-tools
除此之外,我们还需要下载Frida的Server端,可以从Github上下载:https://github.com/frida/frida/releases。这里我们选择Android的版本,arm是32位而arm64是64位,还有x86和x86_64版本提供,根据自己手机的类型下载。
下载解压之后要将Server端推送到手机上,和IDA的Debug Server类似,我们将其推送至/data/local/tmp/目录:
adb push frida-server-12.8.11-android-arm64 /data/local/tmp/
类似地,为其赋予执行权限,并使用root身份启动它。
cd /data/local/tmp/ su chmod +x frida-server-12.8.11-android-arm64 ./frida-server-12.8.11-android-arm64
如果不想使用命令行工具,也可以尝试一下我自己封装的FridaHooker,它提供了一种利用图形化界面管理frida的方法,会为你自动识别手机的类型并为你安装和启动frida,地址为:https://github.com/wrlu/FridaHooker。
启动后,在电脑上执行命令,以连接到USB上的frida server:
frida-ps -Ua
如果能成功显示出进程列表,那么就证明启动成功。如果显示不出,说明是Server端没有启动,如果只能显示出两三个进程,说明没有以root身份启动Server端。不过有时候会显示出Windows的进程列表,这种情况最好使用下面的Python绑定方法使用frida。
- 同时这里还支持连接远程frida server,可以使用如下命令:
frida-ps -H
三、Frida Hook Android Java代码
Frida注入控制程序使用Python写成,可以使用任何你喜欢的IDE,这里不再叙述。示例代码如下:
import sys import frida js_file_name = 'Hook.js' process_name = 'com.xxx.xxx' # 自定义回调函数 def on_message(message, data): if message['type'] == 'send': print("[*] {0}".format(message['payload'])) else: print(message) def get_js_code(): js_file = open(js_file_name, 'r') return js_file.read() if __name__ == '__main__': # 附加到进程并得到进程对象 process = frida.get_usb_device().attach(process_name) # 指定JavaScript脚本 script = process.create_script(get_js_code()) # 加载JavaScript脚本 script.on('message', on_message) script.load() # 读取返回输入 sys.stdin.read()
该脚本首先获取了USB设备,也就是我们连接的手机。然后附加到了我们指定的进程上,这里是
com.xxx.xxx
,所以在执行脚本之前要先在手机上启动好欲hook的目标程序。然后加载了JavaScript脚本并获取了其返回的内容。JavaScript脚本中将实现具体的Hook功能,内容如下:Java.perform(function () { var LogUtil = Java.use('com.xxx.xxx.xxx.LogUtil'); LogUtil.isDebug.implementation = function () { send('Hooking isDebug method'); return true; } });
这里是要Hook一个Java方法,首先使用Java.use
找到Java的类,然后调用方法的implementation
来实现Hook,提供一个回调函数,这个函数将覆盖原有的函数。本例中是将该方法的返回值强制修改为true
,这样就完成了Hook。
有时候Hook会超时,所以可以把上述代码放在以下的代码块里,但是不是必须的:
setImmediate(function() { ... });
frida允许你一次性Hook多个进程,也可以一次性注入多个脚本,所以假如有m个进程,n个脚本,每次就可以执行m * n个注入任务。但是要注意的是如果注入的进程或脚本过多,可能会导致手机崩溃。这里有我的一个示例代码,提供了较为完善的脚本加载和注入功能,源代码详见:https://github.com/wrlu/Frida-Hook-Android。
四、Frida Hook Android Native方法
到以上内容显示出Frida的优势只是不需要重启手机,比较方便。但是Frida还可以完成Xposed不能完成的任务,那就是来Hook Native方法,也就是so动态库中的C/C++方法。示例代码如下:
Interceptor.attach(Module.findExportByName("libc.so" , "open"), { onEnter: function(args) { log("open() called!") }, onLeave:function(retval){ } });
这里面和Java层Hook有些类似,使用Interceptor.attach来附加到动态库,使用Module.findExportByName来找到要Hook的函数,第一个参数是模块名称,第二个参数就是函数名。里面的代码和Java层Hook比较相似。
五、Frida CLI
就像Scapy这样的框架一样,Frida也是可以通过CLI访问的,要完成上面Python脚本的内容,可以用以下的命令代替:
frida -U -l [JavaScript脚本] [进程名] frida -H [主机名:端口] -l [JavaScript脚本] # e.g. frida -U -l ./hook.js com.huawei.xxx frida -H 192.168.3.2:27042 -l ./hook.js com.huawei.xxx
六、使用Python连接远程frida server
frida使用的是TCP协议进行连接,也支持连接远程的frida server,在Python中有一个
get_remote_device()
方法,后来发现这个函数默认连接的是127.0.0.1:27042,而且不能更改。后来才发现应该用如下的方法:host = '192.168.3.2:27042' manager = frida.get_device_manager() remote_device = manager.add_remote_device(host) remote_device.get_process(process_name) remote_process = remote_device.attach(process_name)
在我编写的SecMobile的项目中,使用了这种方法,配合frp代理工具实现了集成管理frida受控端的功能。但是感觉可能没啥卵用,只有集成化测试的时候有用,自己用意义不大。
七、常见错误
- NotSupportedError错误:remote_write PTRACE_POKEDATA head failed: 5
- 华为的设备需要重新编译内核,开启CONFIG_HUAWEI_PTRACE_POKE_ON编译选项,才可以正常使用frida,详情:https://github.com/frida/frida/issues/910
- NotSupportedError错误:MagiskHide相关
- 在Magisk Manager中禁用MagiskHide即可
InvalidArgumentError错误:设备未连接
- 使用形如device = manager.get_device(‘909KPWQ2080977’, 1)的写法,详情:https://github.com/frida/frida/issues/1111
八、后续
- 使用形如device = manager.get_device(‘909KPWQ2080977’, 1)的写法,详情:https://github.com/frida/frida/issues/1111
本文介绍了Frida在Android Hook上的应用,实际上Frida还可以Hook其他系统的代码,有时间会再撰写文章进行讲解。