Hook框架之Frida
Frida是一款轻量级HOOK框架,可用于多平台上,例如android、windows、ios等。
frida分为两部分,服务端运行在目标机上,通过注入进程的方式来实现劫持应用函数,另一部分运行在系统机器上。
frida上层接口支持js、python、c等。
Frida官方github地址为:frida官方github地址
安装
[电脑端]
pip install frida --upgrade # 16.3.3 pip install frida-tools --upgrade # 12.4.3
[手机端]
# 1 查看手机架构 adb shell getprop ro.product.cpu.abi # arm64-v8a # 2 下载frida-server https://github.com/frida/frida/releases # 3 根据平台下载: https://github.com/frida/frida/releases/download/16.3.3/frida-server-16.3.3-android-arm64.xz # 4 解压 # 5 推送到手机【真机】 :跟我一样的目录 adb push ./frida-server-16.3.3-android-arm64 /data/local/tmp/ # 6 给软件赋予执行权限:打开cmd adb shell # 进入到手机 su # 获取超级用户权限--》第一次--》手机上有提示:允许root权限 (需要再面具上,超级用户 > 开启Shell) cd /data/local/tmp # 进入到手机的文件夹下 ls # 没有文件,原来是空的,推动过来后,就有frida-server-16.3.3-android-arm64 ls -al # 查看文件详情,发现没有x权限 chmod +x ./frida-server-16.3.3-android-arm64 # 给它加x权限 ls -al # 查看文件详情,有x权限了,ok了 # 启动服务 ./frida-server-16.3.3-android-arm64
3) 电脑端开启端口转发(并不是必须)
# 方式一:使用命令【cmd中】 adb forward tcp:27042 tcp:27042 adb forward tcp:27043 tcp:27043 # 方式二:使用python命令【python调用系统命令--本质和上面一模一样】 import subprocess subprocess.getoutput("adb forward tcp:27042 tcp:27042") subprocess.getoutput("adb forward tcp:27043 tcp:27043")
Frida两种启动方式
# Spawn 方式适应场景:Spawn 方式是在目标应用程序启动时直接注入 Frida 的 Agent 代码 需要在应用程序启动的早期阶段进行 Hook。 需要访问和修改应用程序的内部状态,例如应用程序的全局变量、静态变量等。 需要 Hook 应用程序的初始化过程,以实现对应用程序的自定义初始化逻辑。 需要在应用程序的上下文中执行代码,并与其他模块或库进行交互。 # Attach 方式适应场景:Attach 方式是在目标应用程序已经运行的过程中动态地连接并注入 Frida 的 Agent 代码 需要对已经运行的应用程序进行 Hook,即动态地连接到正在运行的进程。 需要在应用程序运行时拦截和修改特定的方法调用。 需要实时监视和修改应用程序的行为,例如参数修改、返回值篡改等。 需要对应用程序进行调试和分析,以查找潜在的问题和漏洞。 # spawn:app不用运行,就可以,想hook,app就会执行的函数,就用这种方案 # attach:app要先运行,才可以,想hook,app启动后,点击某个按钮,才执行的,就用这种方案
使用
1.以attach的方式定位加密方法
[JS]
function login() { Java.perform(function () { // 找到包名 var SecurityUtil = Java.use("com.autohome.ahkit.utils.SecurityUtil") // 包名 . 类名 // 对方法进行重新实现 SecurityUtil.encodeMD5.implementation = function (str) { console.log('未加密之前的字符串:', str) var res = this.encodeMD5(str) // 执行原来的逻辑 console.log('加密之后的字符串:', res) return res } }) } function main() { login() } setImmediate(main())
执行命令:
frida -UF -l chezhiying_pwd_hook.js
// 参数说明:
// -U: 通过USB链接的设备
// -F: 以attach的方式注入
// -l: 加载的脚本
[Python]
基本使用:
import frida, sys jsCode = """ ...... """ process = frida.get_usb_device().attach('com.dodonew.online') // script = process.create_script(jsCode) script.load() sys.stdin.read()
// pid方式
process = frida.get_usb_device().attach(1234) # 1234 pid
示例:
import frida import sys # 获取链接设备 device = frida.get_remote_device() # sess = device.attach('车智赢+') # APP应用名称 sess = device.attach(14520) # 进程pid # 添加JS代码 src = ''' Java.perform(function(){ // 1.找到类 var util = Java.use("com.autohome.ahkit.utils.SecurityUtil"); // 2. 替换类中方法 util.encodeMD5.implementation = function(str){ console.log('传入的参数:', str); var res = this.encodeMD5(str); console.log('加密后的参数:', res); return res; }; }); ''' script = sess.create_script(src) def on_message(msg, data): print(msg, data) script.on('message', on_message) script.load() sys.stdin.read()
2.spawn方式
基本使用:
device = frida.get_usb_device() pid = device.spawn(["com.dodonew.online"]) # 以挂起方式创建进程(这里是跟attach的方式不同) process = device.attach(pid) script = process.create_script(jsCode) script.load() device.resume(pid) # 加载完脚本, 恢复进程运行 sys.stdin.read()
示例:
import frida import sys rdev = frida.get_remote_device() pid = rdev.spawn(["com.che168.autotradercloud"]) # 需要写app包名 session = rdev.attach(pid) scr = """ Java.perform(function () { var SecurityUtil = Java.use("com.autohome.ahkit.utils.SecurityUtil"); SecurityUtil.encodeMD5.implementation = function(str){ console.log("明文:",str); var res = this.encodeMD5(str); console.log("md5加密结果=",res); return res; } }); """ script = session.create_script(scr) def on_message(message, data): print(message, data) script.on("message", on_message) script.load() # 唤起应用程序 rdev.resume(pid) sys.stdin.read()
3.连接非标准端口
process = frida.get_device_manager().add_remote_device('192.168.3.68:8888').attach('com.dodonew.online')
连接多个设备:
process = frida.get_device_manager().add_remote_device('192.168.3.68:8888').attach('com.dodonew.online') script = process.create_script(jsCode) script.load() process1 = frida.get_device_manager().add_remote_device('192.168.3.69:8888').attach('com.dodonew.online') script1 = process.create_script(jsCode) script1.load() sys.stdin.read()
数据通信:
在 jscode 中可以使用send(data)
,将数据传入到 onMessage 回调函数中处理
在 js 端中可以通过 send 向 python 发送数据,而 python 要向 js 发送数据则需要使用 script.post,js 中使用 recv 来接收,演示代码如下
jsCode = """ Java.perform(function(){ var Utils = Java.use('com.dodonew.online.util.Utils'); Utils.md5.implementation = function(a){ console.log('MD5 string: ', a); var retval = this.md5(a); send(retval); recv(function(obj){ console.log(JSON.stringify(obj)); retval = obj.data; }).wait(); return retval; } }); """ def onMessage(message, data): print(message) if message["type"] == 'send': print(u"[*] {0}".format(message['payload'])) time.sleep(10) script.post({"data": "a123456"}) else: print(message)
这样就实现了, 有些运算可以在Python中实现之后,再回传回JS中继续执行后续的逻辑
辅助工具:
1.frida-gum: JS代码提示
npm install --save @types/frida-gum
常见问题:
1.frida.TransportError: timeout was reached
解决: 重启手机端的frida-server服务即可