首页
社区
课程
招聘
[原创] Blutter 工具 SIGSEGV 崩溃问题分析与修复 (附代码补丁)
发表于: 4天前 619

[原创] Blutter 工具 SIGSEGV 崩溃问题分析与修复 (附代码补丁)

4天前
619

一、问题描述

在使用 Blutter(一款 Flutter 应用逆向工程工具)分析 Android Flutter 应用时,程序在执行过程中发生 SIGSEGV (段错误) 崩溃。

环境信息

  • 工具: Blutter (最新版本)
  • 目标应用: Flutter 3.11.4 编译的 Android ARM64 应用
  • 操作系统: Kali Linux (x86_64)
  • 执行命令:
python3 blutter.py ~/xxx/xxx/lib/arm64-v8a ~/xxx/blutter_out_put

错误信息

Dumping Object Pool
Traceback (most recent call last):
  File "blutter.py", line 248, in <module>
    main(args.indir, args.outdir, args.rebuild, args.vs_sln, args.no_analysis)
  File "blutter.py", line 230, in main
    main2(libapp_file, libflutter_file, outdir, rebuild_blutter, create_vs_sln, no_analysis)
  File "blutter.py", line 221, in main2
    build_and_run(input)
  File "blutter.py", line 210, in build_and_run
    subprocess.run([input.blutter_file, '-i', input.libapp_path, '-o', input.outdir], check=True)
subprocess.CallProcessError: Command '[...]' died with <Signals.SIGSEGV: 11>.

二、分析过程

1. 初步分析

首先检查了输入文件和 blutter 可执行文件的架构:

# 检查 libapp.so 架构
file libapp.so
# ELF 64-bit LSB shared object, ARM aarch64

# 检查 blutter 可执行文件架构
file blutter_dartvm3.11.4_android_arm64
# ELF 64-bit LSB pie executable, x86-64

初步怀疑是架构不匹配问题,但经过分析发现 blutter 的设计是正确的:

  • Blutter 可执行文件运行在 x86-64 主机上
  • Dart VM 库编译为 x86-64,但配置为解析 ARM64 快照数据

2. 使用 GDB 定位崩溃点

gdb -batch -ex "run ..." -ex "bt" --args blutter_dartvm3.11.4_android_arm64 ...

第一次崩溃回溯:

#0  0x00005555555c25c7 in DartDumper::getPoolObjectDescription[abi:cxx11](long, bool)
#1  0x00005555555c2aae in DartDumper::DumpObjectPool(char const*)
#2  0x00005555555827b2 in main

寄存器状态:

rax            0x0                 0    ← NULL 指针!
rbx            0x7fffffffc9d0      140737488341456
rcx            0x408ec0000be00000  4651866571552063488
rdx            0x6d7138            7172408

关键发现:rax = 0x0,说明函数返回了 空指针,但代码直接解引用导致了崩溃。

3. 定位源代码问题

通过分析汇编代码和源码,发现问题出在 blutter/src/DartDumper.cppgetPoolObjectDescription 函数:

// 第 803-806 行
const auto imm = pool.RawValueAt(idx + 1);
auto dartFn = app.GetFunction(imm - app.base());  // 可能返回 nullptr!
return std::format("[pp+{:#x}] UnlinkedCall: {:#x} - {}",
                   offset, dartFn->Address(), dartFn->FullName().c_str());  // 空指针解引用!

检查 GetFunction 函数实现:

// blutter/src/DartApp.cpp
DartFnBase* DartApp::GetFunction(uint64_t addr)
{
    auto fn = functions.find(addr);
    if (fn != functions.end()) {
        return fn->second;
    }
    auto stub = stubs.find(addr);
    if (stub != stubs.end()) {
        return stub->second;
    }
    // ... 其他逻辑 ...
    return nullptr;  // 找不到时返回 nullptr!
}

4. 发现多处相同问题

通过代码搜索,发现共有 3 处存在相同的空指针解引用问题:

位置 函数 行号
1 getPoolObjectDescription ~806
2 DumpStructHeaderFile ~194
3 ObjectToString (kFunctionCid case) ~493

三、根本原因

Blutter 在处理某些 Flutter 应用时,DartApp::GetFunction() 可能返回 nullptr,但调用方没有检查返回值就直接解引用,导致段错误。

这种情况可能发生在:

  1. 应用使用了混淆技术
  2. 某些函数未在标准位置注册
  3. UnlinkedCall 引用的函数地址无法解析

四、修复方案

修复代码

文件: blutter/src/DartDumper.cpp

修复 1: getPoolObjectDescription 函数

// 第 803-809 行
auto unlinkTargetType = pool.TypeAt(idx + 1);
if (unlinkTargetType == dart::ObjectPool::EntryType::kImmediate) {
    const auto imm = pool.RawValueAt(idx + 1);
    auto dartFn = app.GetFunction(imm - app.base());
+   if (dartFn == nullptr) {
+       return std::format("[pp+{:#x}] UnlinkedCall: {:#x} - [unknown function]", offset, imm);
+   }
    return std::format("[pp+{:#x}] UnlinkedCall: {:#x} - {}",
                       offset, dartFn->Address(), dartFn->FullName().c_str());
}

修复 2: DumpStructHeaderFile 函数

// 第 192-196 行
if (unlinkTargetType == dart::ObjectPool::EntryType::kImmediate) {
    const auto imm = pool.RawValueAt(i + 1);
    auto dartFn = app.GetFunction(imm - app.base());
+   if (dartFn == nullptr) {
+       name = std::format("UnlinkedCall_{:#x}_unknown_{:#x}", offset, imm);
+   } else {
        name = std::format("UnlinkedCall_{:#x}_{:#x}", offset, dartFn->Address(), offset);
+   }
}

修复 3: ObjectToString 函数 (kFunctionCid case)

// 第 491-496 行
case dart::kFunctionCid: {
    // stub never be in Object Pool
-   auto dartFn = app.GetFunction(dart::Function::Cast(obj).entry_point() - app.base())->AsFunction();
+   auto dartFnBase = app.GetFunction(dart::Function::Cast(obj).entry_point() - app.base());
+   if (dartFnBase == nullptr) {
+       return std::format("Function: [unknown] ({:#x})", dart::Function::Cast(obj).entry_point() - app.base());
+   }
+   auto dartFn = dartFnBase->AsFunction();
    if (dartFn->IsClosure()) {

重新编译

cd /root/apps/blutter
python3 blutter.py ~/xxx/xxx/lib/arm64-v8a ~/xxx/blutter_out_put --rebuild

五、修复验证

执行结果

libapp is loaded at 0x7effda200000
Dart heap at 0x7efe00000000
Analyzing the application
Dumping Object Pool
Generating application assemblies
Generating Frida script

输出文件

blutter_out_put/
├── asm/                  # 反汇编的 Dart 代码
├── blutter_frida.js      # Frida 动态分析脚本
├── ida_script/           # IDA Pro 辅助脚本
├── objs.txt              # 对象完整转储
└── pp.txt                # 对象池转储

输出样例

pp.txt (对象池转储):

pool heap offset: 0x580080
[pp+0x10] Stub: Subtype7TestCache (0x1f248c)
[pp+0x18] Stub: Subtype6TestCache (0x1f2768)
[pp+0x40] List(5) [0x1, 0x2, 0x2, 0x2, Null]
[pp+0x50] String: "file:///Users/flora/Work/Flutter/xxx/.dart_tool/flutter_build/dart_plugin_registrant.dart"
[pp+0x168] Obj!MethodChannel@40b431 : {
  off_8: "plugins.flutter.io/path_provider",
  off_c_Obj!tqa@40b811
}

asm/ABi.dart (反汇编代码):

// class id: 2108, size: 0x30, field offset: 0x8
class SM extends Object {

  [closure] Future<void> <anonymous closure>(dynamic, tNa) async {
    // ** addr: 0x6fdd80, size: 0x18c
    // 0x6fdd80: EnterFrame
    //     0x6fdd80: stp             fp, lr, [SP, #-0x10]!
    //     0x6fdd84: mov             fp, SP
    // ...
  }
}

六、总结

问题本质

这是一个典型的 空指针解引用 漏洞,由以下因素导致:

  1. GetFunction() 函数设计上可能返回 nullptr
  2. 调用方未进行防御性检查
  3. 只在特定应用场景下触发(函数无法解析时)

修复效果

  • ✅ 程序不再崩溃
  • ✅ 成功生成所有逆向分析文件
  • ✅ 对于无法解析的函数,输出 [unknown function] 标记

建议

  1. 代码审查建议: Blutter 项目应检查所有 GetFunction() 调用点,确保都有空指针检查
  2. 用户体验: 对于无法解析的函数,可以考虑增加日志输出,便于调试
  3. 防御性编程: 建议在 GetFunction() 内部处理边界情况,或返回一个默认的空函数对象

七、相关资源

  • Blutter 项目: ee8K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6%4L8%4u0S2N6$3W2@1i4K6u0r3j5X3I4#2N6s2c8W2M7R3`.`.
  • Flutter 反向工程: Blutter 通过编译 Dart AOT Runtime 来实现 Flutter 应用的逆向分析
  • 问题修复: 3 处空指针检查,共 13 行代码修改

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 4天前 被幻鳕编辑 ,原因: 敏感信息脱敏
收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回