quickjs-hook JS API
本文档描述的是当前 quickjs-hook runtime 里可直接使用的 JS API。文档只写当前分支已经实现的能力,不把原始 Frida 的完整 index.d.ts 直接当成事实。
1. 全局对象
当前脚本默认可见:
consoleptr()hexdump()MemoryModuleProcessThreadhook()/unhook()InterceptorcallNative()JavaJnisend()/recv()qbdi
- 仅在启用
qbdifeature 时存在
2. AddressLike
很多地址参数都接受 AddressLike:
NativePointernumberbigint- 十六进制字符串,如
0x7f12345678
2.1 hexdump()
支持 Frida 风格的全局 hexdump(target, options?)。
target 当前支持:
NativePointerArrayBuffer
options 当前支持:
address- 自定义显示地址,支持
NativePointer/number/bigint
- 自定义显示地址,支持
offsetlengthheaderansi
默认行为:
- 指针目标未传
length时,默认 dump256字节 header默认trueansi默认false
1 | |
3. NativePointer
3.1 创建
1 | |
3.2 指针运算
支持:
add(offset)sub(offset)isNull()equals(other)compare(other)and(mask)or(mask)xor(mask)not()shl(bits)shr(bits)
1 | |
3.3 读写实例方法
支持:
readU8()readU16()readU32()readU64()readPointer()readCString(maxLen?)readUtf8String(maxLen?)readByteArray(length)writeU8(value)writeU16(value)writeU32(value)writeU64(value)writePointer(value)writeUtf8String(value)
1 | |
3.4 转换
支持:
toString()toJSON()toNumber()toInt()
toNumber() / toInt() 当前返回 BigInt,用于保留 64 位地址精度。
4. Memory
4.1 读取
支持:
Memory.readU8(addr)Memory.readU16(addr)Memory.readU32(addr)Memory.readU64(addr)Memory.readPointer(addr)Memory.readCString(addr, maxLen?)Memory.readUtf8String(addr, maxLen?)Memory.readByteArray(addr, length)
4.2 写入
支持:
Memory.writeU8(addr, value)Memory.writeU16(addr, value)Memory.writeU32(addr, value)Memory.writeU64(addr, value)Memory.writePointer(addr, value)Memory.writeUtf8String(addr, value)
4.3 分配与复制
支持:
Memory.alloc(size, options?)Memory.allocUtf8String(value)Memory.copy(dst, src, size)Memory.dup(addr, size)Memory.protect(addr, size, protection)
1 | |
说明:
alloc()/allocUtf8String()返回的都是NativePointer。- 当前实现支持基础所有权释放;不要依赖超复杂的生命周期语义。
protect()目前只提供底层mprotect()风格能力。- 当前没有实现
Memory.scan()、Memory.patchCode()。
5. Module
支持:
Module.findExportByName(moduleName, symbolName)Module.getExportByName(moduleName, symbolName)Module.findGlobalExportByName(symbolName)Module.findBaseAddress(moduleName)Module.findByAddress(addr)Module.enumerateModules()
1 | |
返回的模块对象结构:
1 | |
6. Process
当前实现的是 Frida 高频只读子集。
属性:
Process.idProcess.archProcess.platformProcess.pointerSizeProcess.pageSize
方法:
Process.findModuleByName(name)Process.getModuleByName(name)Process.findModuleByAddress(addr)Process.getModuleByAddress(addr)Process.enumerateModules()Process.myPid()- 兼容别名,等价于
Process.id
- 兼容别名,等价于
1 | |
6.1 Thread
当前只实现了最小可用子集:
Thread.sleep(delay)
说明:
delay单位是秒,和 Frida 一致。- 支持小数,例如
Thread.sleep(0.05)表示睡眠 50 ms。 - 当前实现是阻塞当前线程,不包含
Thread.backtrace()。
1 | |
7. Native Hook
当前有两套语义,必须区分:
hook()/unhook()- replace 模式
Interceptor.attach()/listener.detach()/Interceptor.detachAll()- attach 模式
7.1 hook()
1 | |
说明:
hook()会接管目标函数的执行流。- 是否调用原函数由
ctx.orig()决定。 unhook()只对应hook()安装的 replace hook。
7.2 Interceptor.attach()
1 | |
说明:
- 当前 callback 继续沿用本项目的
ctx形状。 - 本轮没有实现
Interceptor.replace()/revert()/flush()。
7.3 callNative()
1 | |
callNative() 适合简单整数参数/返回值的场景,不等价于 Frida 的 NativeFunction。
8. Java
8.1 Java.perform()
Java.perform(fn) 是当前推荐主路径。现在已经对齐到 Frida 风格的 pending-loader 语义:
- ClassLoader 已就绪时立即执行
- 未就绪时排队,并通过
ActivityThread.currentApplication()、handleBindApplication()、getPackageInfo()、LoadedApk.makeApplication()等路径尽早拿到 app loader
1 | |
8.2 Java.ready()
Java.ready(fn) 仍然保留,行为与 Java.perform(fn) 一致。为了 Frida 脚本迁移,推荐新脚本优先写 Java.perform(fn)。
8.3 Java.performNow()
Java.performNow(fn) 已可用。它会立即附着到 VM 并执行回调,同时尽力探测当前 app loader,但不保证 app loader 一定已经 ready。
1 | |
8.4 其他 Frida 风格 Java helper
当前还支持这些主路径 helper:
Java.classFactory.loaderJava.cast(obj, Klass)Java.retain(obj)Java.array(type, elements)Java.isMainThread()
8.5 Java.use()
支持:
Java.use(className)Class.$new(...)Class.method.overload(...)Class.method.overloadsClass.method.implementation = fnClass.method.impl = fn- 兼容旧写法
1 | |
指定 overload:
1 | |
遍历 overload:
1 | |
.impl 路径下的 Java hook ctx 常见字段:
thisObjargsenvorig(...)
说明:
.implementation = function(arg0, arg1...) {}走 Frida 主路径,回调参数就是 Java 实参,this.method(...)会调用当前 hook 对应的原方法。.impl = function(ctx) {}保留旧语义,ctx.orig(newArgs...)仍支持带新参数调用原方法。- Java hook 直接
return即作为 Java 返回值。 - 当前已实现
Java.cast、Java.retain、Java.performNow、Java.array、Java.classFactory.loader、Java.isMainThread()。 - 当前仍然没有实现
Java.choose、Java.scheduleOnMainThread()、Java.openClassFile()、Java.registerClass()。
9. Jni
Jni 仍然分两层:
- 底层 Rust 注册的
_xxx jni_boot.js补上的高层包装
业务脚本优先使用:
Jni.addr(...)Jni.find(...)Jni.entries(...)Jni.tableJni.helper
1 | |
10. send / recv
当前实现支持基本 GumJS 风格消息接口:
send(message, data?)recv(callback)recv(type, callback)recv(...).wait()recv(...).cancel()
1 | |
说明:
send/recv依赖宿主的消息转发。- 当前没有实现 Frida 风格定时器,因此不要假设
setTimeout()/setInterval()可用。
11. qbdi
仅在构建时启用 qbdi feature 才可用。常见接口仍包括:
newVM()destroyVM(vm)addInstrumentedRange(vm, start, end)addInstrumentedModule(vm, name)addInstrumentedModuleFromAddr(vm, addr)run(vm, start, stop)call(vm, target, ...args)getGPR(vm, reg)setGPR(vm, reg, value)lastError()shutdown()
12. 迁移建议
- Frida 里的
Interceptor.attach()优先直接迁移到当前的Interceptor.attach()。 - Frida 里的
Java.perform()直接迁移到当前的Java.perform()。 - Frida 里的
.implementation可以直接用;旧文档里的.impl继续兼容。 NativeFunction/NativeCallback当前还没有,不要硬套。setTimeout()/setInterval()当前还没有,不要把 GumJS 定时逻辑直接搬过来。