Java
perform()
1 | Java.perform(function(){ |
use(className)
1 | Java.perform(function(){ |
Java.choose(className, callbacks)
1 | Java.perform(function () { |
Java.enumerateLoadedClasses(callbacks)
枚举已加载的类
1 | Java.perform(function () { |
Java.enumerateLoadedClassesSync()
枚举当前 Java 虚拟机中已经加载的所有类,返回一个包含所有类名的数组。
1 | Java.perform(function () { |
Java.enumerateClassLoaders(callbacks)
枚举所有的类加载器
1 | Java.perform(function () { |
Java.enumerateClassLoadersSync()
枚举当前 Java 虚拟机中所有活跃的类加载器(ClassLoader)实例,返回一个数组。
1 | Java.perform(function () { |
Java.enumerateMethods(query)
根据 query
参数筛选符合特定名称模式的类,并返回这些类中的所有方法。
1 | Java.enumerateMethods(query) |
cast(object, targetClass)
将一个 Java 对象转换为特定的类类型。
1 | Java.perform(function () { |
classFactory
Frida 中用于操作 Java 类的一个工厂类,它提供了一系列方法来与 Java 类进行交互。默认情况下,Java.ClassFactory
使用应用程序的主类加载器,但也可以通过指定其他类加载器来创建不同的类工厂实例。
loader
当前的类加载器。Java.use()
依赖它来 Hook Java 类。
array()
用于动态创建 Java 数组对象
1 | Java.array(type, elements) |
Process
pointerSize
1 | Process.pointerSize |
以字节为单位获取指针的大小。
getCurrentThreadId()
1 | Process.getCurrentThreadId() |
获取当前线程Id。
findModuleByName(name)
根据模块名称查找并返回对应的模块对象。
如果没有找到匹配的模块,则返回一个空值(根据具体实现,可能是 null
或 undefined
)
1 | Process.findModuleByName(name) |
Module
Module属性
name
模块名
base
模块基地址
size
模块的字节大小
path
模块的路径
enumerateSymbols()
1 | var symbols = ModuleName.enumerateSymbols() |
枚举指定模块中的所以符号。
枚举的符号symbol的属性
isGlobal
type
section
name
符号的名字
address
符号的地址,指针
size
findExportByName(exportName)
1 | var addr = Module.findExportByName(moduleName|null,exportName) |
查找指定模块中导出的符号(通常是函数)的地址。
findBaseAddress(name)
1 | var addr = Module.findBaseAddress(name) |
获取指定模块的基地址。
Memory
protect(address, size, protection)
更新一块内存区域的保护属性,其中 protection
是一个字符串。
1 | Memory.protect(address,size,'rwx'); |
alloc(size)
在目标进程的内存中分配一块指定大小的内存。
1 | var ptr = Memory.alloc(size); |
allocUtf8String(str)
在目标进程的内存中分配一段 UTF-8 编码的字符串。
1 | var ptr = Memory.allocUtf8String(str); |
Native
NativePointer
new NativePointer(s)
从包含内存地址的字符串 s 创建一个新的 NativePointer 对象。
字符串可以是十进制的,也可以是以 0x 开头的十六进制表示。
ptr(s)
NativePointer 对象也可以通过ptr(s)这种简写方式进行创建。
toInt32()
将当前 NativePointer 转换为有符号的 32 位整数。
add(rhs), sub(rhs), and(rhs), or(rhs), xor(rhs)
创建一个新的 NativePointer,它是将当前的 NativePointer 与 rhs
相加、相减、按位与、按位或或按位异或后的结果,其中 rhs
可以是一个数字或另一个 NativePointer。
readCString([size = -1])
从当前内存位置读取 ASCII字符串的字节。如果知道字符串的字节数,可以提供可选的 size 参数;如果字符串以 NULL 结尾,可以省略该参数或指定为 -1。
如果地址中读取的任何 size / length 字节不可读,将抛出一个 JavaScript 异常。
NativeFunction
new NativeFunction(address, returnType, argTypes)
address
:用NativePointer
指定的函数地址。returnType
:指定返回值类型。argTypes
:一个数组,指定参数类型。
1
const FunctionName = new NativeFunction(functionAddr, "int", ["pointer", "pointer", "pointer", "pointer"]);
NativeFunction
用于调用目标进程中指定内存地址处的原生函数。
NativeCallback
new NativeCallback(func, returnType, argTypes)
func
: 创建一个新的由JavaScript function实现的NativeCallbackreturnType
: 指定返回类型。argTypes
: 数组,指定参数类型。
返回的对象是
NativeFunction
,可以传递给Interceptor.replace
。
NativeCallback
用于在目标进程中创建一个自定义的原生函数(回调函数),以便在目标进程的上下文中被调用,它的主要用途是模拟或替换目标函数的实现。
1 | Interceptor.replace(functionAddr, new NativeCallback(function () { |
Interceptor
Interceptor.attach(target, callbacks)
1 | var functionAddr = ptr(0x7777); |
注意:在32位ARM架构中,地址参数target的最低有效位必须为0(对于ARM函数)或1(对于Thumb函数)。如果通过Frida API(例如Module.getExportByName())获取地址,Frida会自动处理这个细节。
Interceptor.replace(target, replacement)
使用 replacement 替换 target 处的函数。
可以使用 NativeCallback 在 JavaScript 中实现替换。
1 | Interceptor.replace(functionAddr, new NativeCallback(function () { |
Stalker
Stalker是基于动态重新编译的代码跟踪器。 它将代码指令复制到内存中的另一个位置,在该位置对其进行调整以适应新位置并包括其他跟踪指令。 如果应用程序在原始位置检查其代码,则会发现该代码是完整无缺的,因为它是被篡改的代码的副本。
follow()
1 | Stalker.follow(threadId, options); |
Frida 对目标线程进行监控,捕获它执行过程中发生的事件(例如函数调用、返回、基本块边界等),从而进行动态分析、调试或者行为记录。
options详解
options
参数是一个对象,可以配置多种选项来控制跟踪行为。
options
参数的详细说明:
transform
自定义代码转换函数,允许对跟踪的代码进行动态修改(如插入日志、过滤指令等)。
1 | Stalker.follow(tid, { |
优化版本
1 | Stalker.follow(tid, { |
unfollow()
终止在该线程上通过 Stalker.follow()
启动的追踪操作。
flush()
刷新缓冲区。
garbageCollect()
用于垃圾回收和清理资源,释放由 Stalker 模块在追踪过程中使用的内存和系统资源。
CPU Instruction
Instruction
Instruction.parse(target)
解析内存中 target 地址处的指令,返回一个Instruction
对象。
Instruction
对象包含如下字段:
address
: 此指令的地址(EIP),类型为NativePointer
next
: 指向下一条指令的指针,您可以使用parse()
解析它size
: 此指令的大小mnemonic
: 指令助记符的字符串表示opStr
: 指令操作数的字符串表示operands
: 描述每个操作数的对象数组,每个对象至少指定类型和值,但可能还包含取决于架构的其他属性regsRead
: 此指令隐式读取的寄存器名称数组regsWritten
: 此指令隐式写入的寄存器名称数组groups
: 此指令所属的组名称数组toString()
: 转换为人类可读的字符串
Arm64Writer
new Arm64Writer(codeAddress[, { pc: ptr(‘0x1234’) }])
创建一个用于生成 ARM 机器码的代码写入器,该代码会直接写入 codeAddress
指定的内存位置,codeAddress
是一个 NativePointer
类型,第二个参数是可选的选项对象,可以通过其中的 pc
属性指定初始程序计数器(Program Counter, PC)。
返回一个ArmWriter
对象。
dispose()
释放 Arm64Writer
对象,清理内存。
flush()
用于将已生成或修改的指令刷新到内存中,以确保这些指令可以被正确执行。
putRet()
在生成的代码末尾插入一个返回指令,确保动态生成的代码块或函数能够正确返回。