frida各模块js与cpp函数分析对照(八)

admin 2026-04-07 01:07:53 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文档系统分析Frida框架中Tools模块(Console、Hexdump、Worker、Cloak、Profiler)的JavaScriptAPI与底层C/C++实现之间的五层架构映射关系,详细列出各模块函数对应表、内存布局及执行流程,并提供安全编程实践与实战案例(如内存扫描、性能监控),为安全研究人员深入理解Frida工具链实现原理和二次开发提供技术参考。 综合评分: 85 文章分类: 安全工具,二进制安全,逆向分析,安全开发,WEB安全


cover_image

frida各模块js与cpp函数分析对照(八)

原创

haidragon haidragon

安全狗的自我修养

2026年4月5日 11:40 湖南

  • 官网:http://securitytech.cc

    Tools模块 JavaScript与底层C++函数映射关系分析

    文档概述

    本文档详细分析Frida中Console、Hexdump、Worker、Cloak、Profiler等工具模块的JavaScript API与其底层C/C++实现之间的映射关系,涵盖完整的五层架构模型分析。

    五层架构模型分析

    1. 接口定义层 (JavaScript API Layer)

    Console模块主要接口:

    Hexdump模块主要接口:

    Worker模块主要接口:

    Cloak模块主要接口:

    Profiler模块主要接口:

    其他工具接口:

    2. 基础结构层 (GumJS Binding Layer)

    在 subprojects/frida-gum/bindings/gumjs目录中,Tools模块的绑定实现在相关文件中。

    关键数据结构


### 3. 具体实现层 (Platform-specific Implementation)

#### Console实现 ( gumjs-console.c)

关键函数:

#### Hexdump实现 ( gumhexdump.c)

关键函数:

#### Worker实现 ( gumjs-worker.c)

关键函数:

#### Cloak实现 ( gumcloak.c)

关键函数:

#### Profiler实现 ( gumprofiler.c)

关键函数:

### 4. 工厂模式层 (Backend Factory)

#### 采样器工厂


#### 工作线程工厂


#### 控制台工厂


### 5. 应用集成层 (Integration with Frida Core)

Tools模块通过frida-core与上层应用集成,提供统一的API接口,并与事件系统、消息通道和线程管理深度集成。

## 详细函数映射关系表

### Console映射表

| JavaScript Function | C Function | File Location | Description | | — | — | — | — | | console.log() | gumjs_console_log() | gumjs-console.c | 发送日志消息 | | console.warn() | gumjs_console_warn() | gumjs-console.c | 发送警告消息 | | console.error() | gumjs_console_error() | gumjs-console.c | 发送错误消息 |

### Hexdump映射表

| JavaScript Function | C Function | File Location | Description | | — | — | — | — | | hexdump() | gum_hexdump_with_options() | gumhexdump.c | 生成内存十六进制转储 |

### Worker映射表

| JavaScript Constructor/Method | C Function | File Location | Description | | — | — | — | — | | newWorker() | gum_worker_new() | gumjs-worker.c | 创建工作线程 | | worker.postMessage() | gum_worker_post_message() | gumjs-worker.c | 发送消息到工作线程 | | worker.terminate() | gum_worker_terminate() | gumjs-worker.c | 终止工作线程 |

### Cloak映射表

| JavaScript Function | C Function | File Location | Description | | — | — | — | — | | Cloak.add() | gum_cloak_add() | gumcloak.c | 添加反调试隐藏规则 | | Cloak.remove() | gum_cloak_remove() | gumcloak.c | 移除反调试隐藏规则 | | Cloak.isApplied() | gum_cloak_is_applied() | gumcloak.c | 检查隐藏是否已应用 |

### Profiler映射表

| JavaScript Function | C Function | File Location | Description | | — | — | — | — | | Profiler.start() | gum_profiler_start() | gumprofiler.c | 开始性能剖析 | | Profiler.stop() | gum_profiler_stop() | gumprofiler.c | 停止性能剖析 | | Profiler.depth | gum_profiler_get_depth() | gumprofiler.c | 获取当前调用深度 |

## 内存布局与数据结构可视化

### GumConsole结构体内存布局


### GumWorker结构体内存布局


### GumHexdumpOptions结构体内存布局


### GumSampler结构体内存布局


## 系统调用级执行流程追踪

### console.log()执行流程

### hexdump()执行流程

### Worker.postMessage()执行流程

### Cloak.add()执行流程

### Profiler.start()执行流程

## 跨平台差异与抽象机制

### 平台特定实现

### 抽象层设计


## 调试命令与安全实践

### GDB调试示例


### 性能优化建议

### 安全考虑

## 错误处理与边界情况

### 常见错误场景

### 最佳实践

“javascript // 安全的控制台日志 function safeLog(…args) { try { // 过滤敏感信息 const safeArgs = args.map(arg => { if (typeof arg === ‘string’ && arg.includes(‘password’)) { return arg.replace(/password.?”/g, ‘password”:”**”‘); } return arg; });


} catch (e) { // 忽略日志错误,不影响主逻辑 } }

// 安全的内存转储 function safeHexdump(address, length = 256) { try { if (!address || address.isNull()) { throw new Error(‘Invalid address’); }


} catch (e) { console.error(‘Hexdump failed:’, e); return null; } }

// 安全的工作线程使用 function createSafeWorker(script) { try { const worker = new Worker(script);


} catch (e) { console.error(‘Failed to create worker:’, e); return null; } }

// 安全的性能剖析 function safeProfile(samplerType, durationMs = 1000) { try { let SamplerClass; switch (samplerType) { case ‘cycle’: SamplerClass = CycleSampler; break; case ‘wallclock’: SamplerClass = WallClockSampler; break; case ‘callcount’: SamplerClass = CallCountSampler; break; default: throw new Error(‘Unsupported sampler type’); }


} catch (e) { console.error(‘Profiling failed:’, e); } }


### 自定义内存分析工具

“javascript // 内存模式扫描工具 class MemoryScanner { constructor(baseAddress, size) { this.base = baseAddress; this.size = size; }

findPattern(pattern) { const matches = []; const scanResults = Memory.scanSync(this.base, this.size, pattern);


}

getContextAround(address, bytes = 16) { const start = address.sub(bytes / 2); const end = address.add(bytes / 2);


}

dumpRegion(name, address, length = 64) { console.log( ===${name}===); console.log(hexdump(address, { length: length, header: true })); console.log(‘==================’); } }

// 使用示例 const scanner = new MemoryScanner(Process.findModuleByName(‘libtarget.so’).base, 0x100000); const matches = scanner.findPattern(’48 89 ?? ?? ?? 48 8b’); matches.forEach(match => { console.log(‘Found pattern at:’, match.address); console.log(‘Context:’, match.context); });


### 底层扩展点

## 版本兼容性与演进

### API变更历史

### 向后兼容性保证

## 实战案例分析

### 案例1: 高级调试日志

“javascript // 实现带有调用栈的日志系统 function createStackLogger() { const originalLog = console.log;

console.log = function(…args) { try { // 获取调用栈 const stack = Thread.backtrace(Thread.backtrace(null, Backtracer.ACCURATE)) .map(DebugSymbol.fromAddress) .slice(1, 6) // 限制栈深度 .join(‘\n ‘);


}; }

// 启用栈日志 createStackLogger(); console.log(‘This message includes call stack!’);


### 案例3: 后台内存扫描

`javascript // 使用Worker进行后台内存扫描 function backgroundMemoryScan(pattern, callback) { const workerScript =const pattern = ‘${pattern}’; const base = ${Process.findModuleByName(‘libtarget.so’).base}; const size = ${0x100000};


`;

const worker = new Worker(workerScript);

worker.on(‘message’, (message) => { try { const results = JSON.parse(message); callback(null, results); } catch (e) { callback(e, null); } worker.terminate(); });

worker.on(‘error’, (error) => { callback(error, null); worker.terminate(); });

return worker; }

// 使用示例 backgroundMemoryScan(’48 89 ?? ?? ?? 48 8b’, (error, results) => { if (error) { console.error(‘Scan failed:’, error); } else { console.log(‘Found’, results.length, ‘matches’); results.forEach(addr => console.log(‘Match at:’, addr)); } });


### 案例5: 实时性能监控

“javascript // 实时性能监控面板 function createPerformanceDashboard() { const dashboard = { cpu: new CycleSampler(), memory: new MallocCountSampler(), calls: new CallCountSampler() };

// 开始监控 Object.values(dashboard).forEach(sampler => Profiler.start(sampler));

// 定期更新仪表板 const interval = setInterval(() => { console.clear(); console.log(‘=== Performance Dashboard ===’); console.log( CPUCycles:${dashboard.cpu.value}); console.log( MemoryAllocations:${dashboard.memory.value}); console.log( FunctionCalls:${dashboard.calls.value}); console.log(‘=============================’); }, 1000);

// 返回控制函数 return { stop: () => { clearInterval(interval); Object.values(dashboard).forEach(sampler => Profiler.stop()); console.log(‘Performance dashboard stopped’); }, getMetrics: () => ({ cpu: dashboard.cpu.value, memory: dashboard.memory.value, calls: dashboard.calls.value }) }; }

// 使用示例 const dashboard = createPerformanceDashboard();

// 5秒后停止 setTimeout(() => { dashboard.stop(); }, 5000);


c GUMJSDECLAREFUNCTION (gumjssend) GUMJSDECLAREFUNCTION (gumjssetincomingmessage_callback)


c struct _GumQuickMessageSink { JSValue callback; GumQuickCore * core; };


## 扩展功能:垃圾回收与内存管理

### Garbage Collection

Frida提供了手动触发垃圾回收的接口,用于在内存密集型操作后释放内存。

#### 接口定义层

#### 基础结构层

在 gumquickcore.c中声明:


#### 具体实现层

#### 使用场景

“javascript // 内存密集型操作后 for (let i = 0; i < 10000; i++) { // 创建大量临时对象 const data = Memory.alloc(1024); // … 处理数据 }

// 手动触发垃圾回收 gc();

console.log(‘Memory cleaned up’);


c GUMJSDECLAREFUNCTION (gumjssettimeout) GUMJSDECLAREFUNCTION (gumjssetinterval) GUMJSDECLAREFUNCTION (gumjscleartimer)


c struct _GumQuickScheduledCallback { gint id; gboolean repeat; JSValue func; GSource * source; GumQuickCore * core; };


// 调试通信问题 try { send({type: ‘debug’, message: ‘test’}); } catch (e) { console.error(‘Send failed:’, e.message); }

// 设置超时的接收 let received = false; recv((message) => { received = true; console.log(‘Received:’, message); }).wait(); // 阻塞等待

if (!received) { console.warn(‘No message received within timeout’); }


// 大量定时器的正确管理 const timers = [];

// 创建定时器时保存引用 const timer1 = setTimeout(() => { // 处理逻辑 }, 1000); timers.push(timer1);

const timer2 = setInterval(() => { // 处理逻辑 }, 5000); timers.push(timer2);

// 清理时取消所有定时器 function cleanup() { timers.forEach(timer => { clearTimeout(timer); clearInterval(timer); }); timers.length = 0;


}


// 监控通信性能 const startTime = Date.now(); send({type: ‘large_data’, data: largeArrayBuffer}); const sendTime = Date.now() – startTime;

console.log( Sendtook ${sendTime}ms);

// 监控GC影响 const heapBefore = Frida.heapSize; gc(); const heapAfter = Frida.heapSize; console.log( GC freed ${heapBefore-heapAfter}bytes); “`

  • QuickJS实现: 调用 JS_RunGC()触发垃圾回收

  • V8实现: 调用V8的垃圾回收API

  • gc() – 立即触发JavaScript引擎的垃圾回收

  • 核心API保持稳定

  • 新功能通过扩展方式添加

  • 废弃的API会标记并提供迁移路径

  • Frida早期版本: 基本的Console和setTimeout支持

  • Frida 6.x: 添加Worker和Hexdump支持

  • Frida 8.x: 添加Cloak和Profiler支持

  • Frida 10.x: 完善跨平台支持和性能优化

  • Frida 12.x: 优化内存使用和错误处理

  • Frida 14.x: 改进Worker线程稳定性和Profiler准确性

  • 可以通过修改 gumjs-console.c添加新的日志级别或格式

  • 通过修改 gumhexdump.c添加新的内存转储格式

  • 扩展Worker模块支持更多的消息类型和序列化格式

  • 添加新的采样器类型支持更多的性能指标

  • Console错误:

  • 消息通道断开:日志消息丢失

  • 内存不足:无法分配消息缓冲区

  • 格式化错误:复杂对象序列化失败

  • Hexdump错误:

  • 无效地址:无法读取内存

  • 权限不足:无法访问受保护内存

  • 内存不足:无法分配输出缓冲区

  • Worker错误:

  • 脚本语法错误:工作线程启动失败

  • 消息序列化失败:无法发送复杂对象

  • 线程创建失败:系统资源不足

  • Cloak错误:

  • 规则冲突:多个隐藏规则相互干扰

  • 系统调用拦截失败:无法完全隐藏

  • 性能影响:隐藏机制导致性能下降

  • Console安全: 避免泄露敏感信息到日志

  • Worker安全: 注意工作线程的权限和隔离

  • Cloak安全: 理解反调试技术的局限性

  • Profiler安全: 注意性能剖析对目标应用的影响

  • Console优化:

  • 避免频繁的日志输出影响性能

  • 使用条件日志减少不必要的输出

  • 批量处理日志消息

  • Worker优化:

  • 重用工作线程避免频繁创建/销毁

  • 使用适当的消息大小避免内存浪费

  • 及时终止不再需要的工作线程

  • Profiler优化:

  • 选择合适的采样器类型

  • 控制采样频率避免过度开销

  • 及时停止剖析避免内存泄漏

  • Console消息通道:

  • 所有平台: 通过frida-core的统一消息通道

  • 传输协议: 基于JSON的消息格式

  • 异步处理: 非阻塞的消息发送

  • Hexdump内存访问:

  • Darwin: 使用Mach VM API进行安全内存读取

  • Linux: 使用信号处理捕获访问违规

  • Windows: 使用结构化异常处理(SEH)

  • Worker线程管理:

  • POSIX系统: 使用pthread API

  • Windows: 使用Windows线程API

  • 统一抽象: 通过GLib的GThread封装

  • Cloak反调试技术:

  • Darwin: 隐藏dyld信息、修改进程信息

  • Linux: 隐藏/proc信息、修改ptrace检测

  • Android: 隐藏Java层信息、修改系统属性

  • 拦截相关系统调用

  • 修改内存保护属性

  • 隐藏进程/线程信息

  • 添加地址偏移

  • 生成十六进制字节

  • 生成ASCII字符表示

  • 应用ANSI颜色(如果启用)

  • gum_profiler_start()

  • gum_profiler_stop()

  • gum_profiler_get_depth()

  • 采样器框架: 统一的采样器接口

  • 性能计数: 各种性能指标的收集

  • 调用栈跟踪: 函数调用深度和路径跟踪

  • gum_cloak_add()

  • gum_cloak_remove()

  • gum_cloak_is_applied()

  • 反调试隐藏: 隐藏Frida的存在痕迹

  • 系统调用拦截: 拦截可能暴露Frida的系统调用

  • 内存隐藏: 隐藏Frida相关的内存区域

  • gum_worker_new()

  • gum_worker_post_message()

  • gum_worker_terminate()

  • 线程管理: 创建和管理独立的工作线程

  • 消息队列: 线程间消息传递机制

  • 脚本执行: 在工作线程中执行JavaScript代码

  • gum_hexdump()

  • gum_hexdump_with_options()

  • 内存读取: 安全的内存读取和错误处理

  • 格式化输出: 支持多种输出格式(ANSI颜色、头部信息等)

  • 缓冲区管理: 动态分配输出缓冲区

  • gumjs_console_log()

  • gumjs_console_warn()

  • gumjs_console_error()

  • 消息通道: 通过frida-core的消息通道发送日志消息

  • 格式化处理: 支持多种数据类型的格式化输出

  • 异步发送: 非阻塞的消息发送机制

  • setTimeout(callback,delay)

  • clearTimeout(timerId)

  • setImmediate(callback)

  • clearImmediate(immediateId)

  • Profiler.start()

  • Profiler.stop()

  • Profiler.depth

  • Sampler相关接口:

  • CycleSampler

  • BusyCycleSampler

  • WallClockSampler

  • UserTimeSampler

  • MallocCountSampler

  • CallCountSampler

  • Cloak.add(predicate)

  • Cloak.remove(predicate)

  • Cloak.isApplied()

  • newWorker(script)

  • worker.postMessage(message)

  • worker.on('message',callback)

  • worker.on('error',callback)

  • worker.terminate()

  • hexdump(target,options)

  • options.offset

  • options.length

  • options.header

  • options.ansi

  • console.log(message)

  • console.warn(message)

  • console.error(message)

  • console.info(message)

  • console.debug(message)

  1. ### 性能监控

  2. // 触发垃圾回收

  3. gc();

  4. ### 内存泄漏预防

  5. #### 具体实现层

  6. -**GSource集成**:使用GLib的GSource机制实现跨平台定时器

  7. -**事件循环**:定时器回调在JavaScript事件循环中执行

  8. -**资源管理**:自动清理已取消或已完成的定时器

  9. #### 详细函数映射表

  10. |JavaScriptFunction|&nbsp;C&nbsp;Function|FileLocation|Description|

  11. |-------------------|------------|---------------|-------------|

  12. |setTimeout()|gumjssettimeout()|gumquickcore.c|设置一次性定时器|

  13. |setInterval()|gumjssetinterval()|gumquickcore.c|设置重复定时器|

  14. |clearTimeout()/clearInterval()|gumjscleartimer()|gumquickcore.c|清除定时器|

  15. ## 扩展功能:简写API (Shorthand)

  16. ### Shorthand APIs

  17. Frida提供了一些简写的全局函数,简化常见操作:

  18. #### 内存读写简写

  19. 虽然主要的内存操作通过MemoryNativePointer进行,但Frida也提供了一些便捷的全局函数:

  20. -**ptr(address)**-快速创建NativePointer

  21. -**NULL**-空指针常量

  22. -**TRUE/FALSE**-布尔常量

  23. #### 模块查找简写

  24. -**Module.findExportByName(moduleName, symbolName)**-查找导出符号

  25. -**Module.getBaseAddress(moduleName)**-获取模块基地址

  26. 这些简写API实际上是对相应模块方法的全局包装,提高了代码的可读性和编写效率。

  27. ## 跨平台差异与兼容性

  28. ### 通信机制差异

  29. -**所有平台**:send()/recv()行为一致

  30. -**性能差异**:不同平台的消息序列化性能可能略有差异

  31. ### 定时器精度

  32. -**Unix/Linux/macOS**:基于GLibGSource,精度较高

  33. -**Windows**:基于Windows定时器,精度受系统影响

  34. -**Android**:受Linux内核定时器影响

  35. ### 垃圾回收行为

  36. -**QuickJS**:增量标记清除GC,暂停时间短

  37. -**V8**:分代GC,大内存应用性能更好

  38. ## 调试命令与安全实践

  39. ### 通信调试

  40. 关键数据结构:

  41. ## 扩展功能:定时事件系统

  42. ### Timing Events

  43. Frida提供了标准的Web&nbsp;API定时器接口,用于异步任务调度。

  44. #### 接口定义层

  45. -**setTimeout(callback, delay, …args)**-延迟执行一次

  46. -**setInterval(callback, delay, …args)**-重复执行

  47. -**clearTimeout(timerId)**-取消setTimeout

  48. -**clearInterval(timerId)**-取消setInterval

  49. #### 基础结构层

  50. gumquickcore.c中实现:

  51. GUMJS_DECLARE_FUNCTION&nbsp;(gumjs_gc)

  52. #### 具体实现层

  53. -**send实现**:将JavaScript对象序列化为JSON,通过frida-core的消息通道发送到主机

  54. -**recv实现**:注册消息回调,在接收到主机消息时反序列化并调用JavaScript回调

  55. #### 详细函数映射表

  56. |JavaScriptFunction|&nbsp;C&nbsp;Function|FileLocation|Description|

  57. |-------------------|------------|---------------|-------------|

  58. |send()|gumjs_send()|gumquickcore.c|发送消息到主机|

  59. |recv()|gumjssetincomingmessagecallback()|gumquickcore.c|设置接收消息的回调|

  60. #### 实战案例:加密数据提取

  61. ``javascript

  62. // 注入脚本中

  63. Interceptor.attach(targetFunction,{

  64. onLeave:function(retval){

  65. var&nbsp;decrypted&nbsp;=&nbsp;retval.readUtf8String();

  66. // 发送解密数据到主机

  67. send({

  68. type:'decrypted_data',

  69. timestamp:Date.now(),

  70. data:&nbsp;decrypted

  71. });

  72. }

  73. });

  74. // 主机端 (Python)

  75. def&nbsp;on_message(message,&nbsp;data):

  76. if&nbsp;message['type']=='decrypted_data':

  77. print(f"Decrypted: {message['data']}")

  78. # 保存到文件或进一步处理

  79. script.on('message',&nbsp;on消息)

  80. 关键数据结构:

  81. ## 总结与最佳实践

  82. Tools模块为Frida提供了丰富的实用工具,从基础的日志输出到高级的性能剖析和反调试功能。理解其JS与C++的映射关系有助于:

  83. 1.**高效调试**:利用Console和Hexdump进行高效的调试和分析

  84. 2.**性能优化**:使用Profiler和Sampler进行精确的性能监控

  85. 3.**安全增强**:通过Cloak模块增强反调试能力

  86. 4.**异步处理**:利用Worker模块进行后台任务处理

  87. 通过本文档的五层架构分析,开发者可以全面掌握Tools模块的工作原理和使用技巧,为各种动态分析任务提供强大的工具支持。

  88. ## 扩展功能:主机与注入进程通信机制

  89. ### Communication between Host and Injected Process

  90. Frida提供了强大的双向通信机制,允许注入的JavaScript代码与主机(Python/Node.js等)进行数据交换。

  91. #### 接口定义层 (JavaScript API Layer)

  92. -**send(message, data)**-向主机发送消息

  93. -message:可序列化的JavaScript对象(通常是包含type字段的对象)

  94. -data:可选的二进制数据(ArrayBuffer或NativePointer)

  95. -**recv(callback)**-接收来自主机的消息

  96. -callback:处理接收到消息的回调函数

  97. #### 基础结构层 (GumJS Binding Layer)

  98. gumquickcore.c中实现:

  99. ### 案例4: 反调试增强

  100. ``javascript

  101. // 使用Cloak模块增强反调试能力

  102. function&nbsp;enhanceAntiDebug(){

  103. if(!Cloak.isApplied()){

  104. // 添加自定义隐藏规则

  105. const&nbsp;hideFridaPredicate&nbsp;=Module.findExportByName(null,'some_function');

  106. if(hideFridaPredicate){

  107. Cloak.add(hideFridaPredicate);

  108. console.log('Custom anti-debug rule added');

  109. }

  110. // 隐藏常见的Frida特征

  111. const&nbsp;fridaFeatures&nbsp;=[

  112. 'frida-agent',

  113. 'frida-server',

  114. 'gum-js-loop',

  115. 'gmain'

  116. ];

  117. fridaFeatures.forEach(feature&nbsp;=>{

  118. try{

  119. const&nbsp;featureAddr&nbsp;=Module.findExportByName(null,&nbsp;feature);

  120. if(featureAddr){

  121. Cloak.add(featureAddr);

  122. }

  123. }catch(e){

  124. // 忽略未找到的特征

  125. }

  126. });

  127. console.log('Anti-debug enhancement completed');

  128. }else{

  129. console.log('Cloak already applied');

  130. }

  131. }

  132. enhanceAntiDebug();

  133. const&nbsp;results&nbsp;=[];

  134. Memory.scanSync(base,&nbsp;size,&nbsp;pattern).forEach(match&nbsp;=>{

  135. results.push(match.address.toString());

  136. });

  137. postMessage(JSON.stringify(results));

  138. ### 案例2: 内存泄漏检测

  139. ``javascript

  140. // 使用MallocCountSampler检测内存泄漏

  141. function&nbsp;detectMemoryLeaks(durationMs&nbsp;=10000){

  142. const&nbsp;sampler&nbsp;=newMallocCountSampler();

  143. const&nbsp;initialCount&nbsp;=0;

  144. Profiler.start(sampler);

  145. setTimeout(()=>{

  146. const&nbsp;finalCount&nbsp;=&nbsp;sampler.value;

  147. Profiler.stop();

  148. console.log(Memory allocations during ${durationMs}ms: ${finalCount – initialCount});

  149. if(finalCount&nbsp;-&nbsp;initialCount&nbsp;>1000){

  150. console.warn('Potential memory leak detected!');

  151. // 进一步分析

  152. const&nbsp;callCountSampler&nbsp;=newCallCountSampler();

  153. Profiler.start(callCountSampler);

  154. setTimeout(()=>{

  155. Profiler.stop();

  156. console.log('Function calls during analysis:',&nbsp;callCountSampler.value);

  157. },1000);

  158. }

  159. },&nbsp;durationMs);

  160. }

  161. detectMemoryLeaks();

  162. // 输出带栈的日志

  163. originalLog.call(console,...args,'\n &nbsp;Stack:',&nbsp;stack);

  164. }catch(e){

  165. // 回退到普通日志

  166. originalLog.call(console,...args);

  167. }

  168. ### 自定义性能监控

  169. ``javascript

  170. // 高级性能监控器

  171. classPerformanceMonitor{

  172. constructor(){

  173. this.samplers&nbsp;=newMap();

  174. this.metrics&nbsp;=newMap();

  175. }

  176. startMonitoring(metrics&nbsp;=['cpu','memory','calls']){

  177. metrics.forEach(metric&nbsp;=>{

  178. let&nbsp;sampler;

  179. switch(metric){

  180. case'cpu':

  181. sampler&nbsp;=newCycleSampler();

  182. break;

  183. case'memory':

  184. sampler&nbsp;=newMallocCountSampler();

  185. break;

  186. case'calls':

  187. sampler&nbsp;=newCallCountSampler();

  188. break;

  189. default:

  190. console.warn(Unknown metric: ${metric});

  191. return;

  192. }

  193. this.samplers.set(metric,&nbsp;sampler);

  194. Profiler.start(sampler);

  195. });

  196. console.log('Performance monitoring started for:',Array.from(this.samplers.keys()));

  197. }

  198. stopMonitoring(){

  199. this.samplers.forEach((sampler,&nbsp;metric)=>{

  200. Profiler.stop();

  201. this.metrics.set(metric,&nbsp;sampler.value);

  202. });

  203. this.samplers.clear();

  204. console.log('Performance monitoring stopped');

  205. }

  206. getMetrics(){

  207. const&nbsp;currentMetrics&nbsp;={};

  208. // 获取当前采样器值

  209. this.samplers.forEach((sampler,&nbsp;metric)=>{

  210. currentMetrics[metric]=&nbsp;sampler.value;

  211. });

  212. // 合并历史指标

  213. this.metrics.forEach((value,&nbsp;metric)=>{

  214. if(!currentMetrics.hasOwnProperty(metric)){

  215. currentMetrics[metric]=&nbsp;value;

  216. }

  217. });

  218. return&nbsp;currentMetrics;

  219. }

  220. report(){

  221. const&nbsp;metrics&nbsp;=this.getMetrics();

  222. console.log('Performance Report:');

  223. Object.entries(metrics).forEach(([metric,&nbsp;value])=>{

  224. console.log(  ${metric}: ${value});

  225. });

  226. }

  227. }

  228. // 使用示例

  229. const&nbsp;monitor&nbsp;=newPerformanceMonitor();

  230. monitor.startMonitoring(['cpu','calls']);

  231. // 执行一些操作

  232. setTimeout(()=>{

  233. monitor.report();

  234. monitor.stopMonitoring();

  235. },5000);

  236. try{

  237. return&nbsp;hexdump(start,{

  238. offset:0,

  239. length:&nbsp;bytes,

  240. header:false,

  241. ansi:false

  242. });

  243. }catch(e){

  244. return'Unable to read memory context';

  245. }

  246. scanResults.forEach(match&nbsp;=>{

  247. const&nbsp;context&nbsp;=this.getContextAround(match.address,32);

  248. matches.push({

  249. address:&nbsp;match.address,

  250. context:&nbsp;context,

  251. hex:&nbsp;hexdump(match.address,{&nbsp;length:16,&nbsp;ansi:false})

  252. });

  253. });

  254. return&nbsp;matches;

  255. ## 攻击检测场景映射

  256. ### 可用于检测的场景

  257. -**反调试检测**:使用Cloak模块隐藏Frida存在

  258. -**性能监控**:使用Profiler模块监控应用性能

  259. -**内存分析**:使用Hexdump模块分析内存内容

  260. -**异步处理**:使用Worker模块进行后台分析

  261. ### 防御绕过技术

  262. -**日志过滤**:过滤可能暴露Frida的日志消息

  263. -**内存加密**:加密敏感数据避免Hexdump泄露

  264. -**多线程检测**:检测和规避Worker线程

  265. -**性能混淆**:干扰Profiler的采样结果

  266. ## 性能分析与优化

  267. ### 时间复杂度分析

  268. -**Console操作**:&nbsp;O(1),但涉及消息序列化和传输

  269. -**Hexdump操作**:&nbsp;O(n),n为转储的字节数

  270. -**Worker操作**:&nbsp;O(m),m为消息处理复杂度

  271. -**Profiler操作**:&nbsp;O(1)&nbsp;per sample,采样频率影响总体开销

  272. ### 内存使用分析

  273. -**Console**:每条消息需要分配临时缓冲区

  274. -**Hexdump**:需要分配输出字符串缓冲区(约4x输入大小)

  275. -**Worker**:每个工作线程需要独立的JS引擎实例

  276. -**Profiler**:采样器需要存储历史数据和统计信息

  277. ### 优化建议

  278. -**Console**:批量发送日志消息,减少消息数量

  279. -**Hexdump**:限制转储长度,避免大内存分配

  280. -**Worker**:重用工作线程,避免频繁创建

  281. -**Profiler**:选择低开销的采样器,控制采样频率

  282. ## 扩展功能与自定义实现

  283. ### 自定义日志系统

  284. ``javascript

  285. // 增强的日志系统

  286. classEnhancedLogger{

  287. constructor(prefix&nbsp;=''){

  288. this.prefix&nbsp;=&nbsp;prefix;

  289. this.level&nbsp;='info';

  290. this.levels&nbsp;={

  291. debug:0,

  292. info:1,

  293. warn:2,

  294. error:3

  295. };

  296. }

  297. setLevel(level){

  298. this.level&nbsp;=&nbsp;level;

  299. }

  300. log(level,...args){

  301. if(this.levels[level]>=this.levels[this.level]){

  302. const&nbsp;timestamp&nbsp;=newDate().toISOString();

  303. const&nbsp;message&nbsp;=[${timestamp}] [${level.toUpperCase()}] ${this.prefix ? this.prefix + ‘: ‘ : ”}${args.join(‘ ‘)};

  304. console.log(message);

  305. }

  306. }

  307. debug(...args){this.log('debug',...args);}

  308. info(...args){this.log('info',...args);}

  309. warn(...args){this.log('warn',...args);}

  310. error(...args){this.log('error',...args);}

  311. }

  312. // 使用示例

  313. const&nbsp;logger&nbsp;=newEnhancedLogger('MyModule');

  314. logger.setLevel('debug');

  315. logger.info('Application started');

  316. logger.debug('Debug information');

  317. const&nbsp;sampler&nbsp;=newSamplerClass();

  318. Profiler.start(sampler);

  319. setTimeout(()=>{

  320. Profiler.stop();

  321. console.log(Profiling results for ${samplerType}:,&nbsp;sampler.value);

  322. },&nbsp;durationMs);

  323. worker.on('error',(error)=>{

  324. console.error('Worker error:',&nbsp;error);

  325. });

  326. worker.on('message',(message)=>{

  327. try{

  328. // 处理工作线程消息

  329. handleMessage(message);

  330. }catch(e){

  331. console.error('Message handling error:',&nbsp;e);

  332. }

  333. });

  334. return&nbsp;worker;

  335. return&nbsp;hexdump(address,{

  336. offset:0,

  337. length:&nbsp;length,

  338. header:true,

  339. ansi:false

  340. });

  341. console.log(...safeArgs);

  342. # 在控制台消息发送处设置断点

  343. (gdb)break&nbsp;gumjs_console_log

  344. # 查看消息内容

  345. (gdb)&nbsp;info args

  346. (gdb)&nbsp;x/s $rdi &nbsp;# 查看消息字符串

  347. # 在十六进制转储处设置断点

  348. (gdb)break&nbsp;gum_hexdump_with_options

  349. (gdb)&nbsp;info registers

  350. (gdb)&nbsp;x/32bx&nbsp;$rdi &nbsp;# 查看目标内存内容

  351. // 采样器抽象接口

  352. struct_GumSampler

  353. {

  354. GObject&nbsp;parent;

  355. GumSamplerType&nbsp;type;

  356. guint64 start_time;

  357. guint64 sample_count;

  358. void(*&nbsp;start)(GumSampler*&nbsp;self);

  359. void(*&nbsp;stop)(GumSampler*&nbsp;self);

  360. guint64&nbsp;(*&nbsp;get_current_value)(GumSampler*&nbsp;self);

  361. void(*&nbsp;reset)(GumSampler*&nbsp;self);

  362. };

  363. // 工作线程抽象接口

  364. struct_GumWorker

  365. {

  366. GObject&nbsp;parent;

  367. GThread*&nbsp;thread;

  368. GumWorkerMessageQueue*&nbsp;message_queue;

  369. gchar&nbsp;*&nbsp;script;

  370. gboolean is_terminated;

  371. gboolean&nbsp;(*&nbsp;post_message)(GumWorker*&nbsp;self,const&nbsp;gchar&nbsp;*&nbsp;message);

  372. void(*&nbsp;terminate)(GumWorker*&nbsp;self);

  373. gboolean&nbsp;(*&nbsp;is_alive)(GumWorker*&nbsp;self);

  374. };

  375. JavaScript调用 Profiler.start(sampler) → GumJS绑定层

  376. 调用 gum_profiler_start(sampler)

  377. 初始化采样器状态

  378. 记录开始时间戳

  379. 设置采样间隔(如果适用)

  380. 开始收集性能数据

  381. 返回控制权给JavaScript

  382. 返回操作结果

  383. JavaScript调用 Cloak.add(predicate) → GumJS绑定层

  384. 调用 gum_cloak_add(predicate)

  385. 验证predicate函数的有效性

  386. 将predicate添加到隐藏规则列表

  387. 如果隐藏尚未应用,应用所有规则:

  388. JavaScript调用 worker.postMessage(message) → GumJS绑定层

  389. 调用 gum_worker_post_message(worker,message)

  390. 序列化消息内容为字符串

  391. 将消息添加到工作线程的消息队列

  392. 如果工作线程正在等待消息,唤醒它

  393. 返回控制权给JavaScript(异步操作)

  394. 返回格式化的字符串

  395. JavaScript调用 hexdump(target,options) → GumJS绑定层

  396. 调用 gum_hexdump_with_options(target,options)

  397. 验证目标地址和长度的有效性

  398. 安全读取内存内容(处理访问违规)

  399. 根据选项格式化输出:

  400. JavaScript调用 console.log(message) → GumJS绑定层

  401. 调用 gumjs_console_log(message)

  402. 格式化消息内容(处理多个参数和不同数据类型)

  403. 通过frida-core的消息通道发送消息

  404. 主机端接收消息并输出到控制台

  405. 返回控制权给JavaScript

  406. +------------------+

  407. |&nbsp;type&nbsp;(GumSamplerType)|->采样器类型

  408. +------------------+

  409. |&nbsp;start_time&nbsp;(guint64)|->开始时间戳

  410. +------------------+

  411. |&nbsp;sample_count&nbsp;(guint64)|->采样次数

  412. +------------------+

  413. |&nbsp;current_value&nbsp;(guint64)|->当前采样值

  414. +------------------+

  415. +------------------+

  416. |&nbsp;offset&nbsp;(gssize)|->起始偏移量

  417. +------------------+

  418. |&nbsp;length&nbsp;(gsize)|->转储长度

  419. +------------------+

  420. |&nbsp;header&nbsp;(gboolean)|->是否显示头部

  421. +------------------+

  422. |&nbsp;ansi&nbsp;(gboolean)|->是否使用ANSI颜色

  423. +------------------+

  424. +------------------+

  425. |&nbsp;thread&nbsp;(GThread*)|->工作线程句柄

  426. +------------------+

  427. |&nbsp;message_queue&nbsp;(GumWorkerMessageQueue*)|->消息队列

  428. +------------------+

  429. |&nbsp;script&nbsp;(char*)|->工作线程脚本内容

  430. +------------------+

  431. |&nbsp;is_terminated&nbsp;(gboolean)|->是否已终止

  432. +------------------+

  433. |&nbsp;mutex&nbsp;(GMutex)|->线程同步互斥锁

  434. +------------------+

  435. +------------------+

  436. |&nbsp;script&nbsp;(GumScript*)|->脚本上下文引用

  437. +------------------+

  438. |&nbsp;message_handler&nbsp;(GumScriptMessageHandler)|->消息处理器回调

  439. +------------------+

  440. |&nbsp;message_data&nbsp;(gpointer)|->消息处理器用户数据

  441. +------------------+

  442. // GumConsole工厂

  443. GumConsole*

  444. gum_console_new&nbsp;(GumScript*&nbsp;script);

  445. void

  446. gum_console_set_message_handler&nbsp;(GumConsole*&nbsp;console,GumScriptMessageHandler&nbsp;handler,&nbsp;gpointer data);

  447. // GumWorker工厂

  448. GumWorker*

  449. gum_worker_new&nbsp;(const&nbsp;gchar&nbsp;*&nbsp;script);

  450. GumWorkerMessageQueue*

  451. gum_worker_message_queue_new&nbsp;(void);

  452. // GumSampler工厂

  453. GumSampler*

  454. gum_cycle_sampler_new&nbsp;(void);

  455. GumSampler*

  456. gum_busy_cycle_sampler_new&nbsp;(void);

  457. GumSampler*

  458. gum_wall_clock_sampler_new&nbsp;(void);

  459. GumSampler*

  460. gum_user_time_sampler_new&nbsp;(void);

  461. GumSampler*

  462. gum_malloc_count_sampler_new&nbsp;(void);

  463. GumSampler*

  464. gum_call_count_sampler_new&nbsp;(void);

  465. // Console相关的结构

  466. typedefstruct_GumConsoleApi{

  467. void(*&nbsp;log)(const&nbsp;gchar&nbsp;*&nbsp;message);

  468. void(*&nbsp;warn)(const&nbsp;gchar&nbsp;*&nbsp;message);

  469. void(*&nbsp;error)(const&nbsp;gchar&nbsp;*&nbsp;message);

  470. void(*&nbsp;info)(const&nbsp;gchar&nbsp;*&nbsp;message);

  471. void(*&nbsp;debug)(const&nbsp;gchar&nbsp;*&nbsp;message);

  472. }GumConsoleApi;

  473. // Hexdump相关的结构

  474. typedefstruct_GumHexdumpApi{

  475. gchar&nbsp;*(*&nbsp;hexdump)(gconstpointer target,GumHexdumpOptions*&nbsp;options);

  476. }GumHexdumpApi;

  477. // Worker相关的结构

  478. typedefstruct_GumWorkerApi{

  479. GumWorker*(*&nbsp;new_worker)(const&nbsp;gchar&nbsp;*&nbsp;script);

  480. void(*&nbsp;post_message)(GumWorker*&nbsp;worker,const&nbsp;gchar&nbsp;*&nbsp;message);

  481. void(*&nbsp;terminate)(GumWorker*&nbsp;worker);

  482. }GumWorkerApi;

  483. // Cloak相关的结构

  484. typedefstruct_GumCloakApi{

  485. gboolean&nbsp;(*&nbsp;add)(GumAddress&nbsp;predicate);

  486. gboolean&nbsp;(*&nbsp;remove)(GumAddress&nbsp;predicate);

  487. gboolean&nbsp;(*&nbsp;is_applied)(void);

  488. }GumCloakApi;

  489. // Profiler相关的结构

  490. typedefstruct_GumProfilerApi{

  491. void(*&nbsp;start)(GumSampler*&nbsp;sampler);

  492. void(*&nbsp;stop)(void);

  493. gint&nbsp;(*&nbsp;get_depth)(void);

  494. }GumProfilerApi;

  • 公众号:安全狗的自我修养
  • vx:2207344074
  • http://gitee.com/haidragon
  • http://github.com/haidragon
  • bilibili:haidragonx

#

#


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:安全狗的自我修养 haidragon haidragon《frida各模块js与cpp函数分析对照(八)》

评论:0   参与:  0