Github: 6d9K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6D9K9h3c8G2L8X3N6&6L8$3!0G2i4K6u0r3c8%4g2E0g2s2u0S2j5$3f1`.
基于 Frida Gum (Stalker) 引擎的 ARM64 真机动态指令追踪工具,支持 Android 和 iOS 平台。
GumTrace 以共享库的形式注入目标进程,对指定模块进行指令级别的动态追踪,并将完整的执行轨迹写入日志文件。
项目附带一个独立的离线污点分析工具(src/taint/),可对 GumTrace 生成的日志进行正向/反向数据流追踪:
每行指令记录的格式如下:
示例:
GumTrace 编译为共享库,导出以下 C 接口:
初始化追踪器。
启动追踪。会创建一个后台线程定期刷写日志文件。
停止追踪,刷写并关闭日志文件。
通过 Frida 脚本加载 GumTrace 共享库并调用其导出接口,即可对目标进程进行指令追踪。完整示例见 example.js。
注意: 如果 SO 加载失败(dlopen 返回 NULL),通常是 SELinux 阻止了从 /data/local/tmp/ 加载共享库。需要先关闭 SELinux:
项目提供了 010 Editor 脚本 TaintTracker.1sc,可以在 010 Editor 中直接对 trace 日志进行交互式污点分析。
安装:
使用:
GumTrace 内置了对常见库函数参数的自动解析:
| 参数 |
类型 |
说明 |
module_names |
const char* |
要追踪的模块名,多个用逗号分隔(如 "libtarget.so,libutils.so") |
trace_file_path |
char* |
日志输出文件路径 |
thread_id |
int |
要追踪的线程 ID(0 表示追踪当前线程) |
options |
GUM_OPTIONS |
选项位掩码,1 启用 DEBUG 模式(高频刷写日志) |
| 类别 |
函数 |
| 字符串操作 |
strlen, strcmp, strncmp, strcpy, strcat, strstr, strdup 等 |
| 内存操作 |
memcpy, memmove, memset, memcmp, memmem 等 |
| 文件操作 |
open, openat, read, write, fopen, close 等 |
| 内存分配 |
malloc, calloc, realloc, free |
| 内存映射 |
mmap, mprotect |
| 动态链接 |
dlopen, dlsym, dlclose |
| 格式化 |
sprintf, snprintf, sscanf |
| 系统 |
syscall, __system_property_get, sysconf |
| JNI (Android) |
FindClass, GetMethodID, CallObjectMethod, GetStringUTFChars 等全部 JNI 函数 |
| ObjC (iOS) |
objc_msgSend, objc_retain, objc_release, NSClassFromString 等 |
[模块名] 0x绝对地址!0x相对偏移 助记符 操作数; 寄存器名=值 mem_r=地址 mem_w=地址
[libtarget.so] 0x7a3c001890!0x1890 ldr x0, [x1,
-> x0=0x12345678
call func: strcmp(0x7a3c050010, 0x7a3c060000)
args0: hello
args1: world
ret: 0xffffffffffffffff
./build_android.sh
./build_ios.sh
cd src/taint
mkdir -p build && cd build
cmake ..
cmake --build .
adb push build_android/libGumTrace.so /data/local/tmp/
adb shell setenforce 0
let traceSoName = 'libGumTrace.so'
let targetSo = 'libtarget.so'
let gumtrace_init = null
let gumtrace_run = null
let gumtrace_unrun = null
function loadGumTrace() {
let dlopen = new NativeFunction(Module.findGlobalExportByName('dlopen'), 'pointer', ['pointer', 'int'])
let dlsym = new NativeFunction(Module.findGlobalExportByName('dlsym'), 'pointer', ['pointer', 'pointer'])
let soHandle = dlopen(Memory.allocUtf8String('/data/local/tmp/' + traceSoName), 2)
gumtrace_init = new NativeFunction(
dlsym(soHandle, Memory.allocUtf8String('init')),
'void', ['pointer', 'pointer', 'int', 'int'])
gumtrace_run = new NativeFunction(
dlsym(soHandle, Memory.allocUtf8String('run')),
'void', [])
gumtrace_unrun = new NativeFunction(
dlsym(soHandle, Memory.allocUtf8String('unrun')),
'void', [])
}
function startTrace() {
loadGumTrace()
let moduleNames = Memory.allocUtf8String(targetSo)
let outputPath = Memory.allocUtf8String('/data/data/com.example.app/trace.log')
let threadId = 0
let options = 0
gumtrace_init(moduleNames, outputPath, threadId, options)
gumtrace_run()
}
function stopTrace() {
gumtrace_unrun()
}
let targetModule = Process.findModuleByName(targetSo)
Interceptor.attach(targetModule.base.add(0x1234), {
onEnter() {
startTrace()
this.tracing = true
},
onLeave() {
if (this.tracing) stopTrace()
}
})
frida -U -f com.example.app -l hook.js
adb pull /data/data/com.example.app/trace.log .
./taint_tracker -i trace.log -o result.log -f x0 -l 100
./taint_tracker -i trace.log -o result.log -b x0 -l 500
./taint_tracker -i trace.log -o result.log -f mem:0x1000 -l 100
./taint_tracker -i trace.log -o result.log -f x0 -a 0x1890
./taint_tracker -i trace.log -o result.log -b x0 -p 1048576
GumTrace/
├── CMakeLists.txt
├── build_android.sh
├── build_ios.sh
├── example.js
├── libs/
│ ├── FridaGum-Android-17.6.2.h
│ └── FridaGum-IOS-17.6.2.h
└── src/
├── main.cpp
├── GumTrace.h/cpp
├── CallbackContext.h/cpp
├── FuncPrinter.h/cpp
├── Utils.h/cpp
├── platform.h
└── taint/
├── CMakeLists.txt
├── main.cpp
├── TraceParser.h/cpp
├── TaintEngine.h/cpp
└── TaintTracker.1sc
注意: 如果 SO 加载失败(dlopen 返回 NULL),通常是 SELinux 阻止了从 /data/local/tmp/ 加载共享库。需要先关闭 SELinux:
adb shell setenforce 0
| 参数 |
类型 |
说明 |
module_names |
const char* |
要追踪的模块名,多个用逗号分隔(如 "libtarget.so,libutils.so") |
trace_file_path |
char* |
日志输出文件路径 |
thread_id |
int |
要追踪的线程 ID(0 表示追踪当前线程) |
options |
GUM_OPTIONS |
选项位掩码,1 启用 DEBUG 模式(高频刷写日志) |
| 类别 |
函数 |
| 字符串操作 |
strlen, strcmp, strncmp, strcpy, strcat, strstr, strdup 等 |
| 内存操作 |
memcpy, memmove, memset, memcmp, memmem 等 |
| 文件操作 |
open, openat, read, write, fopen, close 等 |
| 内存分配 |
malloc, calloc, realloc, free |
| 内存映射 |
mmap, mprotect |
| 动态链接 |
dlopen, dlsym, dlclose |
| 格式化 |
sprintf, snprintf, sscanf |
| 系统 |
syscall, __system_property_get, sysconf |
| JNI (Android) |
FindClass, GetMethodID, CallObjectMethod, GetStringUTFChars 等全部 JNI 函数 |
| ObjC (iOS) |
objc_msgSend, objc_retain, objc_release, NSClassFromString 等 |
- Trace UI - 本项目官方指定的 trace 分析工具。高性能 ARM64 执行 trace 可视化分析工具。基于 Tauri 2 + React 构建的桌面应用,专为安全研究员设计,支持千万行或亿行级大规模 trace 的流畅浏览、函数调用树折叠、反向污点追踪、内存/寄存器实时查看等功能。Trace Ul 与 GumTrace 深度适配,是在分析 trace 日志时的得力助手。感谢 @imj01y 的开源贡献!
- 指令级追踪 — 逐条记录 ARM64 指令的执行,包括模块名、绝对地址、相对偏移、助记符和操作数
- 寄存器快照 — 记录每条指令执行时的寄存器读写值(通用寄存器 x0-x28、SIMD 寄存器 q/d/s/h/b、SP、FP、LR、NZCV)
- 内存访问追踪 — 记录内存读写的目标地址(mem_r / mem_w),支持基址 + 索引 + 偏移的复合寻址计算
- 函数调用拦截 — 自动识别 BL/BLR/BR/B 指令的跳转目标,匹配已知符号后打印函数参数和返回值
- 系统调用追踪 — 拦截 SVC 指令,根据系统调用号解析函数名(覆盖 Linux aarch64 全部系统调用)
- Android JNI 追踪 — 自动识别 JNI 函数调用,解析 jclass、jmethodID、jstring 等 JNI 对象
- iOS ObjC 追踪 — 拦截 objc_msgSend,解析类名、selector,打印 NSDictionary/NSArray/NSString/NSData/NSNumber 等 ObjC 对象
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 1天前
被lidongyooo编辑
,原因: