零、基本使用
frida -U -l hello_world.js com.android.settings 挂载脚本
./fs1287amd64 -l 0.0.0.0:6666 自定义端口
脚本智能补全
1
2
3
4git clone <https://github.com/oleavr/frida-agent-example.git>
cd frida-agent-example/
npm install
## 使用vscode打开此工程,在agent文件夹下编写ts,会有智能提示。
一、输出
1. console
1.1console之log
在官方API有两种打印的方式,分别是console、send。
1 | function printf() { |
1.2console之hexdump
打印内存中的地址,target参数可以是ArrayBuffer或者NativePointer,而options参数则是自定义输出格式可以填这几个参数offset、length、header、ansi。
1 | var libc =Module.findBaseAddress('libqservice.so'); |
2. send
send是在python层定义的on_message回调函数,jscode内所有的信息都被监控script.on('message', on_message)
,当输出信息的时候on_message函数会拿到其数据再通过format转换。
核心作用:的是能够直接将数据以json格式输出,(数据是二进制的时候)也可以使用send。
注:使用send的时候会自动将对象转json格式输出
1 | Java.perform(function () |
console直接输出了[object Object],无法输出其正常的内容,因为jni_env实际上是一个对象,但是使用send的时候会自动将对象转json格式输出。
3 变量类型
索引 | API | 含义 |
---|---|---|
new Int64(v) | 定义一个有符号Int64类型的变量值为v,参数v可以是字符串或者以0x开头的的十六进制值 | |
2 | new UInt64(v) | 定义一个无符号Int64类型的变量值为v,参数v可以是字符串或者以0x开头的的十六进制值 |
3 | new NativePointer(s) | 定义一个指针,指针地址为s;可简写为ptr(s) |
ptr(“0”) | 同上;NULL的简写 |
二、Process常用api
1.Process.id
1 | Process.id:返回附加目标进程的PID |
2 Process.isDebuggerAttached()
Process.isDebuggerAttached()
:检测当前是否对目标程序已经附加
3 Process.enumerateModules()
枚举当前加载的模块,返回模块对象的数组。Process.enumerateModules()
会枚举当前所有已加载的so
模块,并且返回了数组Module
对象。
4 Process.getCurrentThreadId()
Process.getCurrentThreadId()
:获取此线程的操作系统特定 ID
作为值。
1 | function frida_Process() { |
5 Process.enumerateThreads()
Process.enumerateThreads()
:枚举当前所有的线程,
1 | function frida_Process() { |
三、Module常用api
1 Module对象的属性
name
:规范模块名称作为字符串base
:基地址为NativePointer
size
:字节大小path
:完整的文件系统路径作为字符串
1 | function frida_Modle(){ |
执行结果:
1 | 模块的名字--->SettingsGoogle.odex |
2 常见Module对象的API
2.1 Module.load(path)
加载指定so文件,返回一个Module对象。如果无法加载指定的模块,则会引发异常。
1 | function frida_Module(){ |
2.2 Process.enumerateModules()
枚举所有的加载的模块,并返加Module数组对象
2.3 enumerateExports()
枚举模块中所有Import库函数,返回Module数组对象
type
:函数类型name
:函数名称address
:函数地址
1 | function frida_Module(){ |
执行结果如下:
1 | name--->_ZN6xposed39XposedBridge_invokeOriginalMethodNativeEP7_JNIEnvP7_jclassP8_jobjectiP13_jobjectArrayS3_S5_S7_ |
2.4 enumerateImports()
枚举模块中所有Export库函数,返回Module数组对象
type
:函数类型name
:函数名称module
:模块名称作为字符串address
:函数地址
具体用法同2.3
2.5 enumerateSymbols()
枚举模块中所有Symbol库函数,返回Module数组对象
isGloba
:布尔值,指定符号是否全局可见type
:函数类型name
:符号名称作为字符串address
:绝对地址size
:如果存在,则一个数字,以字节为单位指定符号的大小
具体用法同2.3
2.6 Module.ensureInitialized(name):
确保已运行指定模块的初始化程序。这对于早期检测非常重要,例如,代码在流程生命周期的早期运行,以便能够与API安全交互。
2.7 Module.findExportByName(exportName), Module.getExportByName(exportName)
1 | 用法:findExportByName(moduleName,exportName) |
返回so文件中Export函数库中函数名称为exportName函数的绝对地址。如果不知道该模块,则可以通过它null代替其名称,但这可能是一项代价高昂的搜索,应避免使用。如果找不到这样的模块或导出,则findExportByName函数将返回null,而getExportByName函数将引发异常。
1 | function frida_Module(){ |
执行结果:
1 | getExportByName----->0x70faf42028 |
2.8 Module.findBaseAddress(name)、Module.getBaseAddress(name)
返回name 模块的基地址。如果找不到此类模块,则findBaseAddress函数将返回null,而getBaseAddress函数将引发异常。
1 | function frida_Module(){ |
执行结果
1 | findBaseAddress----->0x70faf36000 |
四、Memory常用api
1 搜索数据
1.1 Memory.scan
Memory.scan(address, size, pattern, callbacks):
扫描内存以查找pattern在address和给定的内存范围内的情况size。此函数相当于搜索内存的功能。
1.2 Memory.scanSync
返回多个匹配到条件的数据
注:pattern参数必须是双字符的格式,如‘1f 2d ?f’,不能是‘1f 2d ?’
1 | function frida_Memory() { |
执行结果如下:
1 | 进程的名字是--->app_process64_xposed |
2 内存分配Memory.alloc
在目标进程中的堆上申请size大小的内存,并且会按照Process.pageSize对齐,返回一个NativePointer,并且申请的内存如果在JavaScript里面没有对这个内存的使用的时候会自动释放的。也就是说,如果不想要这个内存被释放,需要自己保存一份对这个内存块的引用。
3 内存复制Memory.copy
Memory.copy(dst, src, n)
,不返回任何内容。
1 | function frida_Memory() { |
4 写入数据Memory.writeByteArray
将字节数组写入一个指定内存。
5 读取数据Memory.readByteArray
注:读取内存数据时,只能用hexdump读取16进制数据
写入数据与读取数据示例:
1 | function frida_Memory() { |
显示结果如下:
1 | 4.写入数据----->0x799f3a1cf0 |