当前位置: 首页 > news >正文

逆向分析新思路:当Flutter遇上Frida,如何Hook加密函数并自吐算法参数?

Flutter逆向工程进阶:Frida在Dart层的加密算法追踪实战

当移动应用开发进入Flutter时代,逆向工程师们发现传统的Hook技术突然变得力不从心。那些在Java层游刃有余的Frida脚本,面对Flutter编译后的Dart二进制文件时常常束手无策。本文将带你突破这一技术瓶颈,探索Flutter应用逆向分析的全新方法论。

1. Flutter逆向的特殊挑战与突破点

Flutter应用的独特架构给逆向工程带来了三重障碍:首先,业务逻辑被编译为机器码而非Dalvik字节码;其次,Dart语言的运行时环境与Android原生截然不同;最后,跨平台特性使得关键代码可能隐藏在引擎层而非应用层。

关键差异对比表:

特性Android原生应用Flutter应用
代码形式Dalvik字节码/SmaliARM/x86机器码
加密函数位置Java/Kotlin层Dart编译后的so/C++引擎层
通信机制JNI调用Platform Channel/Dart VM
符号信息保留方法签名可能被Strip

实践中我们发现三个主要突破口:

  • libflutter.so中的Dart VM相关函数
  • 通过Hook Skia图形调用逆向UI逻辑
  • 拦截Platform Channel的跨语言通信

提示:Flutter 3.0+版本开始默认启用Dart Obfuscation,需要准备对应的符号表文件

2. 构建Flutter逆向分析环境

工欲善其事,必先利其器。针对Flutter逆向的特殊需求,我们需要增强标准工具链:

# 基础工具 pip3 install frida frida-tools --upgrade # Flutter专用扩展 git clone https://github.com/rscloura/Doldrums.git cd Doldrums && make

环境配置清单:

  • Frida 16.1.3+ (支持最新ARMv8指令集)
  • IDA Pro 7.7+ (配备Dart分析插件)
  • Dart SDK (用于解析snapshot文件)
  • jadx-gui (分析Platform Channel的Java端)

在真机调试时,需要特别注意Flutter引擎的版本匹配:

// 检测Flutter引擎版本 Interceptor.attach(Module.findExportByName("libflutter.so", "_ZN3dart3bin19GetDartVmSnapshotDataEPKc"), { onEnter: function(args) { console.log("[+] Flutter Engine Detected: " + Memory.readUtf8String(args[0])); } });

3. Dart层加密函数的定位策略

与传统Android逆向不同,Flutter应用的加密逻辑通常通过以下三种形式实现:

  1. Dart FFI调用原生库:通过dart:ffi直接调用C/C++加密库
  2. Platform Channel桥接:在Java/Kotlin层实现加密后回调
  3. 纯Dart实现:使用Dart的crypto包或自定义算法

实战案例:定位AES加密函数

// 方法1:扫描内存特征 const aesPattern = '61 65 73 28 00'; // 'aes('的16进制 Memory.scan(Module.findBaseAddress('libapp.so'), Module.findBaseAddress('libapp.so').size, aesPattern, { onMatch: function(address, size){ console.log('[+] Potential AES function at:' + address); } }); // 方法2:Hook Dart_Invoke const dartInvoke = Module.findExportByName("libflutter.so", "_ZN3dart6Mirror11InvokeClassENS_6ThreadEPNS_6ObjectERKNS_6ArrayEb"); Interceptor.attach(dartInvoke, { onEnter: function(args) { const funcName = Memory.readUtf8String(args[2]); if(funcName.includes('encrypt')) { console.log(`[+] Dart加密调用: ${funcName}`); this.params = args[3]; } }, onLeave: function(retval) { if(this.params) { console.log(hexdump(this.params)); } } });

4. 高级Hook技巧:Dart对象解析

Dart VM的对象模型与JVM差异显著,需要特殊处理才能正确解析参数和返回值。以下是一个完整的Dart String对象提取方案:

function readDartString(address) { const isCompressed = (Memory.readU8(address.add(0x0b)) & 0x01) === 0; const length = Memory.readU32(address.add(0x04)); let result = ''; if(isCompressed) { const chars = Memory.readByteArray(address.add(0x0c), length); result = String.fromCharCode.apply(null, new Uint8Array(chars)); } else { for(let i=0; i<length; i++) { const char = Memory.readU16(address.add(0x0c + i*2)); result += String.fromCharCode(char); } } return result; } // 使用示例 const dartStringPtr = ptr(0x7abc1234); console.log(readDartString(dartStringPtr));

对于更复杂的Dart对象,可以借助Doldrums工具库提供的封装:

const DartObject = require('doldrums').DartObject; // 解析Dart Map对象 const mapPtr = ptr(0x7faa5678); const dartMap = new DartObject(mapPtr); dartMap.entries.forEach(([key, value]) => { console.log(`${key.toString()} => ${value.toString()}`); });

5. 完整实战:自吐加密参数系统

结合上述技术,我们可以构建一个完整的Flutter加密参数监控系统:

// 监控Dart层的加密调用 const cryptoMethods = ['encrypt', 'decrypt', 'sign', 'verify']; cryptoMethods.forEach(method => { const symbol = DebugSymbol.fromName(`_Dart_${method}`); if(symbol) { Interceptor.attach(symbol.address, { onEnter: function(args) { console.log(`\n[+] ${method} called`); for(let i=0; i<3; i++) { // 前三个参数 try { const obj = new DartObject(args[i]); console.log(`arg${i}: ${obj.toString()}`); } catch(e) {} } }, onLeave: function(retval) { try { const obj = new DartObject(retval); console.log(`retval: ${obj.toString()}`); } catch(e) {} } }); } }); // 监控C层的加密调用 const nativeCrypto = [ 'EVP_EncryptInit', 'EVP_DecryptInit', 'AES_encrypt', 'AES_decrypt' ]; nativeCrypto.forEach(func => { const addr = Module.findExportByName(null, func); if(addr) { Interceptor.attach(addr, { onEnter: function(args) { console.log(`\n[+] Native ${func} called`); console.log(hexdump(args[1], { length: 32 })); } }); } });

性能优化技巧:

  • 使用Stalker过滤非关键线程
  • 对高频调用设置条件断点
  • 缓存已解析的Dart类结构

6. 对抗Flutter逆向防护措施

随着Flutter应用安全意识的提升,越来越多的防护手段被采用:

常见防护方案破解方法:

  1. 符号表混淆

    • 使用Doldrums的符号恢复功能
    • 基于调用关系重建符号
  2. JIT陷阱

    // 检测并绕过JIT陷阱 const dartCode = Memory.alloc(0x1000); Interceptor.attach(Module.findExportByName("libflutter.so", "_ZN3dart6kernel14CodeGenerator7VisitCEv"), { onLeave: function(retval) { if(this.context.x1 > 0x10000000) { // 可疑内存区域 Memory.protect(this.context.x1, 0x1000, 'rwx'); } } });
  3. 反调试措施

    • 修改/proc/self/status的TracerPid字段
    • Hooksyscall监控ptrace调用

7. 自动化分析框架搭建

为提高分析效率,可以构建自动化分析流水线:

# flutter_analyzer.py import frida from dart_parser import DartParser class FlutterAnalyzer: def __init__(self, package_name): self.session = frida.get_usb_device().attach(package_name) self.dart_parser = DartParser() def hook_crypto(self): script = self.session.create_script(""" // Frida脚本内容 """) script.on('message', self.on_message) script.load() def on_message(self, message, data): if message['type'] == 'send': payload = message['payload'] if payload.get('type') == 'dart_object': parsed = self.dart_parser.parse(payload['data']) print(f"[DART] {parsed}") # 其他消息处理...

框架组件:

  • Dart对象解析器
  • 调用关系图谱构建器
  • 加密模式识别模块
  • 自动化报告生成器

在逆向Flutter应用的过程中,最令我惊讶的是Dart VM的高效性反而成为了逆向分析的突破口——通过内存模式识别,我们往往可以快速定位关键函数。记得在一次商业App的分析中,正是通过监控Dart_Invoke的调用频率,意外发现了一个隐藏很深的加密通信模块。

http://www.cnnetsun.cn/news/2486631.html

相关文章:

  • Linux网络编程实战:从Socket基础到高并发服务器设计
  • 从‘黑窗口’到彩色世界:用GLUT快速实现你的第一个OpenGL图形程序(含完整代码解析)
  • UnityPackage Extractor终极指南:快速免费提取Unity资源包
  • ADS1110与51单片机I2C通信详解:手把手教你驱动并读取三路电压(附常见问题排查)
  • 用Python串口控制机械臂:从RS232协议解析到完整指令序列编程实战
  • 从一次安全扫描告警说起:聊聊SSH Banner那点事与自定义的‘安全艺术’
  • 华科计组实验通关秘籍:用Logisim搞定数据表示九大关卡(附避坑指南与源码)
  • 告别C盘爆满!保姆级教程:在D盘用Qt在线安装器搞定6.2.4开发环境(附组件选择避坑指南)
  • OmniSharp-vim与fzf、vim-clap深度集成:提升C开发效率的7个关键点
  • 拆解ESP32-C3最小系统:除了MCU,你的开发板还需要哪些外围电路?(附BOM清单)
  • 如何快速掌握Rufus:从USB格式化到启动盘制作的终极指南
  • 用GEE和Landsat 8数据,5步搞定城市生态健康“体检报告”(附完整代码)
  • CANN/cann-recipes-train:一站式平台快速启动RL训练示例
  • 终极指南:如何在OneNote 2016中实现专业级代码高亮
  • 轻量级人脸检测方案:解决移动端AI视觉部署的核心痛点
  • LDDC歌词工具:5分钟掌握专业级歌词下载与格式转换完整指南
  • Windows字体自定义终极指南:用No!! MeiryoUI打造你的专属界面
  • 如何在Linux系统上快速部署Tsukimi:打造你的个人媒体中心
  • django-tenants测试策略:单元测试、集成测试与持续集成
  • 避开勒让德函数那些坑:GRACE数据处理中MATLAB高效计算与调试技巧
  • TikTok-Live-Connector实战项目:构建自动化聊天机器人系统的完整指南
  • 如何快速集成Android-shapeLoadingView:5分钟实现酷炫加载效果
  • 终极Android安全研究路线图:从零基础到专家的完整学习路径规划 [特殊字符]
  • Medieval Fantasy City Generator 实战:集成到游戏引擎的完整方案
  • 为什么选择Omnizart?5大核心优势解析音乐转录革命
  • CausalImpact最佳实践:避免因果推断中的7个常见陷阱
  • 深入解析PyTorch-FCN架构:FCN32s、FCN16s、FCN8s模型对比分析
  • 《Windows Sysinternals实战指南》PsTools 学习笔记(7.5):PsExec 的备用凭据与安全基线
  • torchtitan-npu:在昇腾集群上训练大模型
  • linux PATH介绍