leanrea: 快速路径
你已经了解这些工具。本文件仅列出每个目标的最快命令以及常见陷阱。
规则
- 对副本进行操作(APFS 上
cp -c是瞬间的)。将每次解压放入$TMPDIR/re/<name>下的新目录中。如果已有解压结果,则复用。 - 首先通过
file -b T和魔数字节进行路由。接下来运行最廉价的清单检查。之后再反编译或阅读代码。 rg会跳过隐藏和忽略的文件,而打包工具会隐藏代码(Electron:.webpack/、.vite/)。始终使用rg -uu搜索解压后的目录树。- 切勿
cat一个大文件或已压缩的文件。使用切片:rg -o '.{0,200}NEEDLE.{0,200}' F | head。将反汇编结果保存到一个文件中,然后 grep 该文件。 - 使用
;和echo '--- name'标记将独立的探测任务批处理到一次 SHELL 调用中(注意引用:zsh 会展开裸的==x)。每个输出限制为head或-m。 - 基于证据作答。在回答中,将每个声明标记为 已看到(引用文件:偏移量、符号或字符串)或 推断。未找到的事实应标记为 未知,而不是“不存在”。静态阅读并非实际执行观察。
- 缺少工具不是障碍。使用同一行的备选方案,或者在用户允许的情况下使用
brew install <x>。 - 轮次比字节更昂贵。目标是 2–4 次工具调用:一次批量侦察调用,一两次针对性切片,然后回答。当询问的每个项目都有了证据时停止。不要重新验证你已经看到的内容。
第一步:每个目标一个调用,粘贴后运行
原生 (Mach-O):
T=./bin; D=$TMPDIR/re/$(basename $T); mkdir -p $D; file $T; lipo -info $T; otool -L $T; echo '--- EXPORTS'; nm -gU $T | head -150; echo '--- IMPORTS'; nm -u $T | rg -v '^__Z|napi_' | tr '\n' ' '; echo; echo '--- STRINGS'; strings -a -n 6 $T | rg -v '^[_$.]' | head -400; otool -tV $T > $D/dis.txt; echo '--- FUNCS'; rg '^[_a-zA-Z].*:$' $D/dis.txt | rg -v '^_?_?Z?N?St3' | head -150
然后阅读一个函数:awk '/^FUNC_LABEL:$/{p=1;next} p&&/^[_a-zA-Z].*:$/{exit} p' $D/dis.txt | rg 'bl|b\.|cmp|literal|mov\s+w2'。
Electron:
A=./app.asar; X=$TMPDIR/re/asar; rm -rf $X; npx -y @electron/asar extract $A $X && jq '{name,version,main}' $X/package.json; find $X -path '*/node_modules' -prune -o -type f \( -name '*.js' -o -name '*.node' \) -print | head -60; ls ${A}.unpacked/node_modules 2>/dev/null; rg -uu -l --glob '!node_modules' 'exposeInMainWorld' $X
然后在捆绑包中切片搜索目标字符串:rg -uu -o --glob '!node_modules' '.{0,250}NEEDLE.{0,250}' $X | head -20。
Go:通常仅 go version -m T 就能回答问题。
路由表
| 目标(检测方式) | 最快路径 |
|---|---|
Electron 应用 (*.app/Contents/Resources/app.asar) | npx -y @electron/asar extract app.asar X(另见 app.asar.unpacked/ 中的 .node 插件)。入口点:jq .main X/package.json。表面API:`rg -n -o '.{0,120}(ipcMain.(handle |
| Web 捆绑包 / 压缩的 JS | 查找 sourceMappingURL。如果 source map 有 sourcesContent,则提取源代码:jq -r '.sources[]'。对于 webpack,grep 模块 ID,然后在命中位置周围切片。对于美化打印:npx -y prettier --parser babel F > F.pretty.js,然后按行范围读取。 |
| Hermes / bytenode / V8 快照 | Hermes 魔数为 c6 1f bc 03(index.android.bundle):使用 hermes-dec / hbc-decompiler。.jsc(bytenode)无法反编译:使用字符串和运行时钩子。 |
Mach-O(file:Mach-O) | lipo -info(先瘦身:lipo -thin arm64 -o T1 T)。然后:otool -L(库);xcrun dyld_info -exports -imports;nm -gU(导出)/ nm -u(导入 = 能力映射);strings -a -n 6;`otool -l |
| 原生代码逻辑 | otool -tV T > $D/dis.txt(或 llvm-objdump -d --no-show-raw-insn -C)。找到函数:rg -n '^_?.*Name.*:$'。读取调用/字符串线索:`awk '/^FUNC:/{p=1} p&&/^[_a-zA-Z].*:$/&&!/FUNC/{exit} p' dis.txt |
| ELF / PE | readelf -hlSW、readelf -dW(NEEDED)、nm -D --defined-only、objdump -d -M intel。PE:objdump -x、pefile/wrestool(用于资源)。checksec:pwn checksec。 |
Go(__go_buildinfo、.go.buildinfo) | go version -m T 在一次调用中提供工具链、路径、模块、依赖项和构建标志。如果没有 Go:`strings -a T |
| Rust | 依赖项(cargo-auditable):cargo audit bin T,或提取 .dep-v0 / __DATA,.dep-v0 并执行 zlib-inflate。编译器:`strings -a T |
.NET(file:Mono/.Net) | ilspycmd -p -o X T.dll(安装:dotnet tool install -g ilspycmd),然后 rg。P/Invoke:rg DllImport X。NativeAOT/IL2CPP 是原生代码:使用原生代码的行。 |
| Android APK | jadx -d X --show-bad-code a.apk 然后 rg。仅需资源/清单:apktool d --no-src -o X a.apk。快速查看:unzip -l a.apk。lib/*/libflutter.so 表示 Flutter(Dart AOT:blutter);libhermes.so 表示 React Native(见 Hermes 行)。 |
| Flutter 快照哈希 | 在 libapp.so 中,找到魔数 f5 f5 dc dc;+20 偏移处的 32 个十六进制字符是快照哈希。将其映射到 Dart 版本。 |
| WASM | wasm-objdump -x、wasm2wat、wasm-decompile(WABT)。 |
| SQLite | 复制数据库,如果存在 -wal 文件也一并复制。sqlite3 'file:C?mode=ro' '.schema',然后 SELECT * FROM t LIMIT 20。 |
| plist / nib / car | plutil -p F。Info.plist 保存捆绑包 ID、URL 方案和隐私字符串。资源目录:assetutil --info Assets.car。 |
| pcap / HAR | tshark -r C -q -z conv,tcp;`tshark -r C -T fields -e dns.qry.name -e tls.handshake.extensions_server_name -e http.request.full_uri |
| 固件 | binwalk -e F 或 unblob -e X F。然后通过此表路由每个提取的二进制文件。 |
| 网站 | curl -sL URL 获取 HTML 和脚本 src,然后获取 JS 并进行切片。对于运行时行为,使用带有网络日志的无头浏览器(Playwright page.on('request'))或 Chrome --remote-debugging-port。 |
| 运行中的应用 / 运行时 | macOS:lldb -p PID、dtrace/fs_usage/log stream --predicate 'process=="X"'。Electron main:--inspect(仅在 RunAsNode/inspect fuse 允许的情况下)。Android:adb logcat、frida -U -f pkg -l hook.js。 |
速度模式
- 优先检查字符串和导入。对于小型二进制文件,
nm -u+strings+ 导出列表通常无需反汇编即可回答“它做了什么”。 - 要查找谁使用了某个字符串:从
otool -tV的“literal pool for”注释中获取其地址,或使用rg -n 'literal pool for: "X'。然后在该行上方找到包围函数标签。 bl目标中的 C++ 名称已经告诉你协议(例如getpeereid、write、std::hash)。读取调用序列,而不是每条指令。- 对于 JS,从原生/JS 边界向内进行:找到原生调用,然后找到其调用者类,接着找到 IPC 注册,最后找到渲染器/preload。
- 版本比较:在比较任何代码之前,先比较清单(
nm、模块列表、go version -m)。 - 功能重建:编写最小的重新实现,然后针对原始版本进行测试(相同的输入,相同的输出)。
安装(仅按需)
brew install jadx apktool radare2 binwalk wabt wireshark ghidra · npm i -g @electron/asar · dotnet tool install -g ilspycmd · cargo install cargo-audit。