Communitygithub.com

aicodeking/leanrea

使用純本機 CLI 工具逆向工程已發布的軟體,無需 MCP。涵蓋 Electron/JS 捆綁包、原生 Mach-O/ELF/PE、Go/Rust/.NET/Flutter/WASM 二進位檔案、APK、SQLite、pcap、韌體和網站。可用於解釋功能運作方式、提取版本/依賴項、比較版本或重建功能。

leanrea 是什麼?

leanrea 是一項 AI 助手技能,旨在快速且系統性地對已發布的軟體進行逆向工程,完全依賴本機 CLI 工具,無需 MCP 協定。它支援多種目標類型,包括 Electron 應用程式、JS 捆綁包、原生 Mach-O/ELF/PE 二進位檔案、Go、Rust、.NET、Flutter、WASM、Android APK、SQLite 資料庫、pcap 網路封包、韌體和網站。該技能提供針對每個目標類型最快診斷命令的明確「路由器」,並強調批次偵測調用、智能切片(使用 `rg` 和標題)以及低成本盤點(如字串和匯入)以將工具調用次數限制在 2-4 次。它還包含嚴格的規則,例如使用副本、從對 `file` 的呼叫開始,以及引用所見證據來標記答案中的主張。支援的平台包括 macOS(使用 `otool`、`lipo`、`lldb`、`nm`)和 Linux(使用 `readelf`、`objdump`),並安裝了補充工具(如 `jadx`、`apktool`、`radare2`、`ilspycmd`、`cargo-audit`),在典型軟體工程工作流程中為 Claude Code、Codex 和 Cursor 等助手提供了強大的逆向工程能力。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/aicodeking/leanrea/tree/HEAD/leanrea

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

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' 標記(需要引號:zsh 會展開裸的 ==x)將獨立的探查批次處理為一個 shell 調用。每個輸出都用 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。表面:`rg -n -o '.{0,120}(ipcMain.(handle
網路捆綁包 / 最小化 JS找到 sourceMappingURL。如果映射包含 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(先 thin: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
原生程式碼邏輯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 / PEreadelf -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 | rg -m1 -A200 'Go buildinf'。符號在剝離後仍然存在:go tool nm T | rg main\.。
Rust依賴項(cargo-auditable):cargo audit bin T,或提取 .dep-v0 / __DATA,.dep-v0 並進行 zlib-inflate。編譯器: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 APKjadx -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 版本。
WASMwasm-objdump -x、wasm2wat、wasm-decompile(WABT)。
SQLite複製資料庫,以及 -wal 檔案(如果存在)。sqlite3 'file:C?mode=ro' '.schema',然後 SELECT * FROM t LIMIT 20。
plist / nib / carplutil -p F。Info.plist 包含套件 ID、URL 方案和隱私權字串。資產目錄:assetutil --info Assets.car。
pcap / HARtshark -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 fuses 允許時)。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。
  • 比較版本:在比較任何程式碼之前,先 diff 盤點清單(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。

相關技能