墨锋
Published on 2025-03-31 / 3 Visits
0
0

[翻译]FRIDA官方文档-示例-JavaScript

JavaScript

连接 Node.js 进程的 V8 虚拟机注入任意 JS 代码

 // 获取 libuv 函数指针
 const uv_default_loop = new NativeFunction(Module.getExportByName(null, 'uv_default_loop'), 'pointer', []);
 const uv_async_init = new NativeFunction(Module.getExportByName(null, 'uv_async_init'), 'int', ['pointer', 'pointer', 'pointer']);
 const uv_async_send = new NativeFunction(Module.getExportByName(null, 'uv_async_send'), 'int', ['pointer']);
 const uv_close = new NativeFunction(Module.getExportByName(null, 'uv_close'), 'void', ['pointer', 'pointer']);
 const uv_unref = new NativeFunction(Module.getExportByName(null, 'uv_unref'), 'void', ['pointer']);
 ​
 // 获取 V8 引擎函数指针
 const v8_Isolate_GetCurrent = new NativeFunction(Module.getExportByName(null, '_ZN2v87Isolate10GetCurrentEv'), 'pointer', []);
 const v8_Isolate_GetCurrentContext = new NativeFunction(Module.getExportByName(null, '_ZN2v87Isolate17GetCurrentContextEv'), 'pointer', ['pointer']);
 ​
 // 获取 V8 句柄作用域函数
 const v8_HandleScope_init = new NativeFunction(Module.getExportByName(null, '_ZN2v811HandleScopeC1EPNS_7IsolateE'), 'void', ['pointer', 'pointer']);
 const v8_HandleScope_finalize = new NativeFunction(Module.getExportByName(null, '_ZN2v811HandleScopeD1Ev'), 'void', ['pointer']);
 ​
 // 获取 V8 字符串处理函数
 const v8_String_NewFromUtf8 = new NativeFunction(Module.getExportByName(null, '_ZN2v86String11NewFromUtf8EPNS_7IsolateEPKcNS_13NewStringTypeEi'), 'pointer', ['pointer', 'pointer', 'int', 'int']);
 ​
 // 获取 V8 脚本编译执行函数
 const v8_Script_Compile = new NativeFunction(Module.getExportByName(null, '_ZN2v86Script7CompileENS_5LocalINS_7ContextEEENS1_INS_6StringEEEPNS_12ScriptOriginE'), 'pointer', ['pointer', 'pointer', 'pointer']);
 const v8_Script_Run = new NativeFunction(Module.getExportByName(null, '_ZN2v86Script3RunENS_5LocalINS_7ContextEEE'), 'pointer', ['pointer', 'pointer']);
 ​
 // 字符串类型枚举
 const NewStringType = {
   kNormal: 0,      // 普通字符串
   kInternalized: 1 // 内部化字符串
 };
 ​
 const pending = []; // 待执行脚本队列
 ​
 // 异步回调处理函数
 const processPending = new NativeCallback(function () {
   const isolate = v8_Isolate_GetCurrent(); // 获取当前 V8 隔离实例
 ​
   const scope = Memory.alloc(24); // 分配句柄作用域内存
   v8_HandleScope_init(scope, isolate); // 初始化句柄作用域
 ​
   const context = v8_Isolate_GetCurrentContext(isolate); // 获取当前上下文
 ​
   // 执行队列中的所有脚本
   while (pending.length > 0) {
     const item = pending.shift();
     const source = v8_String_NewFromUtf8(isolate, Memory.allocUtf8String(item), NewStringType.kNormal, -1);
     const script = v8_Script_Compile(context, source, NULL);
     const result = v8_Script_Run(script, context);
   }
 ​
   v8_HandleScope_finalize(scope); // 释放句柄作用域
 }, 'void', ['pointer']);
 ​
 // 关闭回调函数
 const onClose = new NativeCallback(function () {
   Script.unpin(); // 解除内存固定
 }, 'void', ['pointer']);
 ​
 // 初始化异步句柄
 const handle = Memory.alloc(128);
 uv_async_init(uv_default_loop(), handle, processPending);
 uv_unref(handle);
 ​
 // 设置弱引用回调
 Script.bindWeak(handle, () => {
   Script.pin(); // 固定内存防止GC
   uv_close(handle, onClose); // 关闭句柄
 });
 ​
 // 脚本执行函数
 function run(source) {
   pending.push(source); // 加入执行队列
   uv_async_send(handle); // 触发异步执行
 }
 ​
 // 示例:注入并执行代码
 run('console.log("通过Frida注入执行");');

追踪 Perl 5 进程中的函数调用

 const pointerSize = Process.pointerSize; // 获取指针大小
 const SV_OFFSET_FLAGS = pointerSize + 4; // SV 结构体 flags 偏移量
 const PVGV_OFFSET_NAMEHEK = 4 * pointerSize; // PVGV 结构体名称偏移量
 ​
 const SVt_PVGV = 9; // 类型标识:GV (Glob Value)
 ​
 // 挂钩 Perl 的函数入口点
 Interceptor.attach(Module.getExportByName(null, 'Perl_pp_entersub'), {
   onEnter(args) {
     const interpreter = args[0]; // Perl 解释器指针
     const stack = interpreter.readPointer(); // 读取调用栈
 ​
     const sub = stack.readPointer(); // 获取被调函数
 ​
     const flags = sub.add(SV_OFFSET_FLAGS).readU32(); // 读取类型标志
     const type = flags & 0xff; // 提取类型标识
     if (type === SVt_PVGV) {
       /* 
        * 注意:此处 console.log() 会影响性能,
        * 实际应用中应使用 send() 批量发送事件
        */
       console.log(GvNAME(sub) + '()'); // 输出函数名
     } else {
       // 其他类型暂不处理
     }
   }
 });
 ​
 // 获取 GV 名称
 function GvNAME(sv) {
   const body = sv.readPointer(); // 读取 GV 主体
   const nameHek = body.add(PVGV_OFFSET_NAMEHEK).readPointer(); // 获取名称指针
   return nameHek.add(8).readUtf8String(); // 读取 UTF-8 字符串
 }

欢迎点击上方"改进此页面"提交更多示例代码!

关键术语说明:

  1. libuv - Node.js 使用的跨平台异步 I/O 库

  2. V8 Isolate - V8 引擎的独立实例环境

  3. HandleScope - V8 的句柄作用域管理

  4. PVGV - Perl 的全局变量值结构

  5. 弱引用(Weak Reference) - 不影响垃圾回收的对象引用


原文链接:JavaScript | Frida • A world-class dynamic instrumentation toolkit

翻译来源:DeepSeek


Comment