leanrea: 빠른 길(fast path)
이 도구들은 이미 알고 있습니다. 이 파일은 각 대상에 대한 가장 빠른 명령어와 함정만 나열합니다.
규칙
- 사본에서 작업하세요 (
cp -c는 APFS에서 즉시 복사). 각 추출 결과는$TMPDIR/re/<이름>아래에 새 디렉토리를 만들어 넣으세요. 이미 추출된 결과가 있으면 재사용하세요. - 먼저
file -b T와 매직 바이트로 유형을 판별하세요. 그 다음 가장 저렴한 인벤토리 명령을 실행하세요. 그래야만 디컴파일하거나 코드를 읽으세요. rg는 숨김 파일과 무시된 파일을 건너뜁니다. 번들러는 코드를 숨깁니다(Electron:.webpack/,.vite/). 추출된 트리는 항상rg -uu로 검색하세요.- 크거나 난독화된 파일을
cat하지 마세요. 잘라서 보세요:rg -o '.{0,200}NEEDLE.{0,200}' F | head. 역어셈블리는 한 번 파일로 덤프한 후 그 파일을 grep하세요. - 독립적인 프로브는 하나의 셸 호출로 묶어
;와echo '--- name'마커로 구분하세요(따옴표 주의: zsh는==x를 확장함). 모든 출력은head나-m으로 제한하세요. - 증거에 기반하여 답변하세요. 답변에서 각 주장을 보임(seen: 파일:오프셋 또는 심볼/문자열 인용) 또는 추론됨(inferred)으로 표시하세요. 찾지 못한 사실은 알 수 없음(unknown)이지 "없음"이 아닙니다. 정적 분석은 실행을 관찰한 것이 아닙니다.
- 도구가 없다고 막히지 마세요. 같은 행의 대체 도구를 사용하거나, 사용자가 허용하면
brew install <x>를 사용하세요. - 턴(turn)보다 바이트가 더 중요합니다. 2~4회의 도구 호출을 목표로 하세요. 한 번은 배치 리컨(recon) 호출, 그리고 한두 번의 대상 슬라이스, 마지막으로 답변입니다. 요청된 모든 항목에 대한 증거가 확보되면 중단하세요. 이미 본 것을 다시 확인하지 마세요.
첫 번째 동작: 각각 한 번 호출, 붙여넣고 실행
네이티브 (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
그런 다음 번들 전체에서 니들(needle) 슬라이스: 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의 경우 모듈 id를 grep한 후 적중 지점(hit) 근처를 슬라이스하세요. 예쁘게 출력: 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|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은 문자열 리터럴과 스텁(stub)을 인라인으로 레이블링하므로 대부분 충분합니다. 진정한 pseudocode가 필요할 때만: 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는 한 번 호출로 툴체인, 경로, 모듈, 의존성 및 빌드 플래그를 제공합니다. 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. 경로에서 크레이트: 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자리 16진수 문자는 스냅샷 해시입니다. 이를 Dart 버전에 매핑하세요. |
| WASM | wasm-objdump -x, wasm2wat, wasm-decompile (WABT). |
| SQLite | DB를 복사하고, -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 | 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 main: --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)를 먼저 diff하세요. - 재구현: 최소한의 재구현을 작성한 다음 원본과 동일한 입출력으로 테스트하세요.
설치 (요청 시에만)
brew install jadx apktool radare2 binwalk wabt wireshark ghidra · npm i -g @electron/asar · dotnet tool install -g ilspycmd · cargo install cargo-audit.