关于 leanrea
leanrea 是面向分析人员的逆向工程技能,用于检查二进制文件、应用包和数据文件。它侧重快速收集证据、定向检查代码,并清晰标注结论依据。
主要功能
- 01按文件类型和魔数选择流程
- 02提供快速检查命令
- 03搜索隐藏文件和打包代码
- 04区分已观察、推断和未知信息
适用场景
- 01初步分析陌生可执行文件
- 02检查 Electron 应用包
- 03在提取文件中定位代码或字符串
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ aicodeking/ leanrea --skill leanrea安装后在 Claude Code 中输入/leanrea确认已加载。
详细介绍
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。 - 将互相独立的探查合并到一次 shell 调用中,用
;分隔,并用echo '--- name'标记(需加引号:zsh 会展开不带引号的==x)。每项输出都用head或-m限制长度。 - 根据证据作答。在回答中,将每项断言标记为 已见(引用 file:offset,或符号/字符串)或 推断。未找到的事实属于未知,而非“缺失”。静态读取不等于观察到实际执行。
- 缺少某个工具并非阻碍。使用同一行中的备用方案;如果用户允许,也可以使用
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。接口:`rg -n -o '.{0,120}(ipcMain.(handle |
| Web 包 / 压缩后的 JS | 查找 sourceMappingURL。如果映射文件包含 sourcesContent,则导出源代码:jq -r '.sources[]'。对于 webpack,搜索模块 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)无法反编译:使用 strings 和运行时钩子。 |
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 | rg -A3 'LC_(RPATH|BUILD_VERSION)';codesign -d --entitlements :- T;otool -ov(ObjC 类/方法);xcrun swift-demangle --compact。 |
| 原生代码逻辑 | 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 | rg 'bl|call|literal|cmp'。otool 会在内联位置标记字符串字面量和存根,通常这些信息就足够了。仅在需要真正的伪代码时使用:Ghidra analyzeHeadless $D p -import T -postScript DecompileAll.java -deleteProject 或 r2 -qc 'aaa; pdc @ sym.X' T。 |
| 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 一次即可显示工具链、路径、mod、依赖项和构建标志。没有 Go 时:strings -a T | rg -m1 -A200 'Go buildinf' 。即使经过剥离,符号仍会保留:go tool nm T | rg main\.。 |
| Rust | 依赖项(cargo-auditable):cargo audit bin T,或提取 .dep-v0 / __DATA,.dep-v0 并进行 zlib 解压。编译器:strings -a T | rg -o '/rustc/[0-9a-f]{40}' | sort -u。根据路径查找 crate:strings -a T | rg -o '[a-z0-9_-]+-[0-9]+\.[0-9]+\.[0-9]+/src' | sort -u。 |
.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 包含 bundle 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 | sort -u。HAR:jq -r '.log.entries[].request | .method+" "+.url'。 |
| 固件 | 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 主进程:--inspect(仅当 RunAsNode/inspect 熔断开关允许时)。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 注册,最后检查渲染器/预加载脚本。
- 比较版本时:先对比清单(
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。
评论
支持 Markdown