运行环境
● Python – latest 3.x is highly recommended
● Windows, macOS, or Linux
安装方法
使用命令 sudo pip install frida
或从https://build.frida.re/frida/下载
以cat命令为例,检查frida是否正确安装:
$ cp /bin/cat /tmp/cat $ /tmp/cat
打开一个新的终端,创建example.py ,写入如下代码:
import frida session = frida.attach("cat") print([x.name for x in session.enumerate_modules()])
在linux系统下,还需执行如下命令确保开启调试非子进程:
$ sudo sysctl kernel.yama.ptrace_scope=0
然后运行examp.py,应该得到类似如下结果:
基本使用方法
源码:frida/core.py 和frida/tracer.py
1.枚举模块
如果我们执行print(session.enumerate_modules())
就会得到类似如下的结果:
[Module(name="cat", base_address=0x400000, size=20480, path="/bin/cat"), ...]
其中base_address是模块的基地址
2.枚举内存范围
枚举当前目标进程映射的所有内存范围:enumerate_ranges(mask)
执行print s.enumerate_ranges('rw-'),会得到类似如下的结果:
[Range(base_address=0x2d4160a06000, size=1019904, protection='rwx'), ...]
base_address是这个范围的基址。
3.读写内存
read_bytes(address, n):从目标进程地址address中读取n字节数据。
write_bytes(address, data):将data以字节形式写入到address中。
操作模式
(1)注入模式
主要在root或者越狱的手机上使用
(2)嵌入模式
非root非越狱机上使用。通过嵌入一个叫frida-gadget的共享库到目标app中
(3)预加载模式
不涉及到任何TCP或者对外的通信,同意需要用到共享库frida-gadget。需要设置环境变量FRIDA_GADGET_SCRIPT用于指向一个js文件。
如linux环境下,可以创建一个包含以下内容的hook.js文件:
'use strict'; rpc.exports = { init: function () { Interceptor.attach(Module.findExportByName(null, 'open'), { onEnter: function (args) { var path = Memory.readUtf8String(args[0]); console.log('open("' + path + '")'); } }); } };
最新的frida-gadget地址:https://github.com/frida/frida/releases/tag/10.2.1
然后设置两个环境变量
LD_PRELOAD=/path/to/frida-gadget.so FRIDA_GADGET_SCRIPT=/path/to/hook.js
然后启动目标进程。
同样可以使用FRIDA_GADGET_ENV=development来开发自己的逻辑,以便于frida-gadget 监控文件更改,一旦发现文件更改后自动重新加载。
函数操作
首先我们来创建一个实验代码hello.c
#include#include void f (int n) { printf ("Number: %d\n", n); } int main (int argc, char * argv[]) { int i = 0; printf ("f() is at %p\n", f); while (1) { f (i++); sleep (1); } }
执行命令gcc -Wall hello.c -o hello进行编译,然后运行,记录f()函数的地址0x40057d
(1)hook函数
编写hook代码hook.py用于hook函数调用,返回函数参数,具体代码如下:
from __future__ import print_function import frida import sys session = frida.attach("hello") script = session.create_script(""" Interceptor.attach(ptr("%s"), { onEnter: function(args) { send(args[0].toInt32()); } }); """ % int(sys.argv[1], 16)) def on_message(message, data): print(message) script.on('message', on_message) script.load() sys.stdin.read()
执行 python hook.py 0x40057d
得到如下结果:
(2)修改函数参数
创建modify.py,代码如下:
import frida import sys session = frida.attach("hello") script = session.create_script(""" Interceptor.attach(ptr("%s"), { onEnter: function(args) { args[0] = ptr("1337"); } }); """ % int(sys.argv[1], 16)) script.load() sys.stdin.read()
执行python modify.py 0x400544后会发现输出的值变了
(3)函数调用
创建call.py
import frida import sys session = frida.attach("hello") script = session.create_script(""" var f = new NativeFunction(ptr("%s"), 'void', ['int']); f(1911); f(1911); f(1911); """ % int(sys.argv[1], 16)) script.load()
运行得到如下结果:
(4)注入字符串并调用函数
创建hello.c
#include#include int f (const char * s) { printf ("String: %s\n", s); return 0; } int main (int argc, char * argv[]) { const char * s = "Testing!"; printf ("f() is at %p\n", f); printf ("s is at %p\n", s); while (1) { f (s); sleep (1); } }
创建脚本stringhook.py,使用frida注入一段字符串到内存中,然后调用f()函数:
from __future__ import print_function import frida import sys session = frida.attach("hi") script = session.create_script(""" var st = Memory.allocUtf8String(" I love you!"); var f = new NativeFunction(ptr("%s"), 'int', ['pointer']); // In NativeFunction param 2 is the return value type, // and param 3 is an array of input types f(st); """ % int(sys.argv[1], 16)) def on_message(message, data): print(message) script.on('message', on_message) script.load()
运行python stringhook.py 0x40057d,得到如下结果: