M12 · 階梯 3 · L3
逆向與動態分析工具鏈
從靜態解析(otool / nm / dyld_info / class-dump / 符號 demangle)到動態分析(lldb / dtrace / frida)的工具鏈與心智模型——靜態解你自己擁有或公開 IPSW 的映像、ObjC/Swift runtime 還原、動態分析只在自有/授權裝置上對「自己的程式」做,並認識 anti-debug 的類別與根因。不示範繞過任何保護。
逆向不是「破解」,是「把映像讀回語意」
前面 M01 教了一個映像怎麼被信任鏈驗過、M02 教了 Mach-O 的結構、M00 補了 ARM64 與 ObjC/Swift runtime 的底。這一章把這些讀回語意:給你一個 binary,你要能回答「它連了哪些 framework、匯出/匯入什麼符號、它的 ObjC class 與 method 長怎樣、它在執行期實際走哪條路」。
這是階梯 3「找攻擊面」的核心工具能力——但方向是分析,不是武器化。本章嚴守一條線:
⚠ 本章邊界(對齊 DESIGN.md §10):所有動手操作只對你自己擁有或被授權分析的程式、以及公開可下載的 Apple IPSW / kernelcache。動態分析(lldb / dtrace / frida)只在你自己的或受控授權的裝置上、對你自己的測試程式進行。本章不示範繞過任何保護機制(不繞 anti-debug、不繞簽章、不附 PoC/exploit),只教工具鏈、runtime 還原原理、以及這些技術對應的攻擊面類別、根因與偵測點。
靜態 vs 動態:兩種互補的視角
| 視角 | 看到什麼 | 看不到什麼 | 風險面 |
|---|---|---|---|
| 靜態(讀檔案,程式不執行) | 結構、符號、字串、ObjC metadata、連結關係、所有可能的程式碼路徑 | 執行期才決定的值(解密後字串、動態載入、實際走哪條分支) | 低——不執行可疑碼,🟢 |
| 動態(程式跑著時觀察) | 實際暫存器/記憶體值、實際呼叫順序、解密後狀態 | 沒被觸發的路徑、被 anti-debug 隱藏的行為 | 較高——要執行目標,需自有/授權環境,🟡 |
直覺:靜態先建地圖,動態再驗證地圖上的問號。對未知/可疑樣本,先靜態看清楚再決定要不要在隔離環境動態跑——絕不在主力機直接執行可疑碼。
挑一個你想回答的問題,看該用哪個工具(靜態看結構、動態看行為):
逆向工作台:選對工具
otool -l app · dyld_info -linked_dylibs app靜態看「結構」、動態看「行為」。要拆 Mach-O 結構本身可直接用 M02 解剖器。
只在自有/獲授權的程式上分析。`dtrace` 受 SIP 限制(需調整 csr);`lldb`/`frida` attach 受 `get-task-allow` / 簽章與系統保護約束。
🟢 靜態工具鏈:解你自己的(或公開的)映像
這些工具都只讀檔案、不執行目標,是本章的綠色主路徑。
結構與符號
otool -hv ./yourbinary # mach_header:magic / cputype / filetype / flags(接 M02)
otool -l ./yourbinary # 全部 load commands(含 LC_LOAD_DYLIB 的相依、LC_CODE_SIGNATURE)
otool -L ./yourbinary # 連結了哪些 dylib/framework(最快的「它依賴什麼」)
nm -m ./yourbinary # 符號表:哪些是 external/undefined、來自哪個 dylib
dyld_info 是現代取代「用 otool 看 bind/rebase」的工具,直接讀 chained fixups 與匯出:
dyld_info -linked_dylibs ./yourbinary # 相依 dylib 與 link 屬性(weak/reexport/upward…);要看版本用 otool -L
dyld_info -fixups ./yourbinary # dyld 會 rebase/bind 的位置(接 M02 chained fixups)
dyld_info -exports ./yourbinary # 匯出符號(trie)
⚠ errata(工具歸屬):
otool/nm/dyld_info/c++filt是 Xcode Command Line Tools 內附(透過xcrun解析路徑)。class-dump不是 macOS 內建——它是第三方開源工具,需另外安裝;近年的維護分支較能正確處理 arm64e 與 Swift 混編產物,原始版對新格式可能解析不全。別假設它在乾淨系統上存在。
ObjC / Swift runtime 還原(接 M00)
ObjC 的 class/method/protocol metadata 以結構化資料保留在 binary 的 __objc_* sections 裡,所以即使沒符號也能把介面還原出來:
dyld_info -objc ./yourObjCApp # dump ObjC metadata(classes/methods/protocols);現代、正確處理 arm64e
# chained fixups 與 relative method list(首選)
otool -oV ./yourObjCApp # 舊式 dump:x86_64/舊格式可用,但 arm64e 上 otool-classic 對 relative
# method list 解析不全(會印 'extends past end of file',是工具限制非檔案損壞)
class-dump ./yourObjCApp # (第三方)重建 @interface 標頭,看 class 與 method 簽名
Swift 與 C++ 的符號是 mangled(編碼了型別/泛型資訊),要還原成人類可讀:
nm ./yourSwiftApp | xcrun swift-demangle # Swift 符號還原(swift-demangle 在 Xcode toolchain,用 xcrun 叫)
echo '__Z3foov' | c++filt # C++ 符號還原(c++filt 為內建)
⚠ errata(呼叫方式):
swift-demangle不在/usr/bin的預設 PATH 上,它住在 Xcode toolchain 裡,正確叫法是xcrun swift-demangle(或xcrun --find swift-demangle找出完整路徑)。直接打swift-demangle在未設定的 shell 通常 command not found。
反組譯器(看控制流)
互動式反組譯(Hopper、Ghidra、IDA、radare2/rizin、Binary Ninja)把機器碼還原成組語 + 控制流圖 + 偽 C。它們同樣是靜態讀檔:載入你自己擁有或公開的 binary(或從公開 IPSW 解出的 kernelcache)來看「它怎麼分支、呼叫了什麼」。本課的 Mach-O 解剖器(M02)是它們的教學前置——先在瀏覽器裡看懂 load commands 與 section 佈局,再上真正的反組譯器就不陌生。
⚠ 從公開 IPSW 解 kernelcache、dyld shared cache 做靜態研究屬綠色合法(公開可下載、不執行);但重新散布 Apple 的二進位/還原產物可能涉及授權問題——研究自用與散布是兩回事。
🟡 動態分析:只在自有/授權裝置上,對自己的程式
動態分析要讓目標跑起來並觀察它。風險與門檻都比靜態高,因此整段標黃色,且只對你自己寫的測試程式示範。
lldb:偵錯你自己的程式
lldb 是 macOS 內建偵錯器。對你自己編譯、可被你偵錯的程式,基本流程是 launch 或 attach 後設中斷點、看暫存器/記憶體/呼叫堆疊:
clang -g -O0 -arch arm64 hello.c -o hello # 先編一個你自己的、帶符號的測試程式
lldb ./hello # 載入;(lldb) 提示下 b main / run / register read / bt
⚠ errata(能不能 attach 是有規則的,且不教繞過):
- lldb 要對一個 process 取得控制,底層需要該 process 的 task port(
task_for_pid/get-task-allow)。你自己編譯、未啟用 hardened runtime 的 debug build 預設帶get-task-allow,可被你偵錯。- Apple 平台二進位與啟用 hardened runtime / Library Validation 的程式,在一般系統上不允許被任意附加偵錯——這是 SIP / AMFI / 簽章政策的設計(接 M03/M05)。本章不示範如何取得對它們的 task port,也不示範停用這些保護。
- 偵錯他人或系統的程式需要降低系統保護(SIP/AMFI),那屬授權研究環境的操作,不在本章範圍;本章只偵錯你自己的程式。
dtrace:受 SIP 限制的全系統動態追蹤
dtrace 能在系統層級對 syscall / 函式進出 / 自訂 probe 做動態追蹤,極適合理解「程式實際呼叫了什麼」。但它受 SIP 限制:
sudo dtrace -l | head # 列出可用 probe;SIP 全開時會回 "DTrace requires additional privileges"
⚠ errata(SIP 與 dtrace,必記且不教繞過):在 SIP 完整啟用的系統上,dtrace 對系統程序的能力被刻意限制——常見徵狀就是
dtrace: failed to initialize dtrace: DTrace requires additional privileges。要在研究機放寬,需在 recoveryOS 調整 SIP(granular 的「只放開 dtrace」選項或整體csrutil disable,可用性視 macOS 版本而定,且只能在 recoveryOS 設定),這會降低該機安全(接 M05:csr bitmask 中 dtrace 相關限制位元)。本章不要求你關 SIP:dtrace 段落以對你自己的測試程式、或預錄 asciinema 回放示範即可(對齊 DESIGN.md §3.1 黃色可達性註)。判斷 SIP 一律以csrutil status為準。
frida:動態 instrumentation 框架
frida 是第三方動態插樁框架,能在執行期 hook 函式、讀寫記憶體、追 API 呼叫,常用於分析自己 app 的執行期行為。
⚠ errata(frida 的前置與邊界):frida 需另行安裝(非內建),且要對目標注入同樣需要 task port / 偵錯權限——對 hardened runtime / 平台二進位一樣受簽章與 SIP/AMFI 政策約束。本章只在自有測試程式上用 frida 觀察「自己的函式被呼叫的引數」,不示範對第三方 app 注入、繞簽章或繞 anti-debug。
anti-debug:教「類別與根因」,不教繞過
軟體(含惡意樣本)常用反偵錯手法讓動態分析變難。本章把它當成攻擊面類別與偵測點來理解,而不給任何繞過步驟:
| anti-debug 類別 | 根因(為何有效) | 偵測 / 研究對策(防禦視角) |
|---|---|---|
ptrace(PT_DENY_ATTACH) | 程序主動要求 kernel 拒絕被附加偵錯 | 靜態就能看出它呼叫了 ptrace;行為偵測可記 ES 的相關事件(接 M14) |
查 P_TRACED flag / sysctl 自檢 | 程式問 kernel「我正被偵錯嗎」 | 屬「程式自檢」類別;分析時改用靜態或非附加式觀測(如 ES NOTIFY)即可旁路其前提,不需繞它 |
| 偵測 frida/常見工具特徵 | 掃描特定 port / 字串 / 載入的庫 | 反映「工具留下指紋」這一通則;DFIR 上反過來可當該樣本在反分析的訊號 |
| 時間差檢測(timing) | 偵錯下執行變慢 | 理解其原理即可,分析改走靜態/取樣 |
⚠ errata / 防禦框架:anti-debug 的存在本身就是高價值偵測訊號——一個正常 app 通常不需要
PT_DENY_ATTACH或掃 frida。所以對 DFIR(M14)而言,「偵測到 anti-debug 行為」比「成功繞過它」更有價值。本章刻意只停在「辨識類別 + 根因 + 它在 telemetry 上長怎樣」,把「如何繞過特定保護」歸為 🔴 僅概念、不落地。
🔴 紅線:哪些東西本章只談類別、不落地
對齊 DESIGN.md §3.1 的三色分級,以下屬僅概念:
- 針對特定保護(anti-debug / 簽章 / SIP / hardened runtime)的可操作繞過步驟 → 只談「這類保護的根因與偵測」。
- 任何 offset / gadget / payload / exploit primitive 串接 → 留給 M13,且 M13 全程以抽象模型呈現(「mitigation 為何有效、攻擊者被迫轉向哪類技術」),不給可武器化細節。
- 對他人 app / 系統程序的注入、脫殼、繞驗證 → 不示範;本章的動態分析對象一律是你自己的程式。
逆向能力的正當產出是:攻擊面標註、根因歸類、為某類行為設計一條偵測規則(接 M14)。這才是階梯 3→5 要的東西。
🟢/🟡 真機操作卡(在你自己的 Mac 上,macOS 26 適用)
以下靜態段全是唯讀、對你自己擁有或公開的映像安全執行;動態段(🟡)只對你自己編的測試程式。需要 root 的標 sudo。
# ── 🟢 靜態:結構與符號(只讀檔案,不執行目標)──
otool -hv ./yourbinary # mach_header(接 M02)
otool -L ./yourbinary # 連結了哪些 dylib/framework
nm -m ./yourbinary # 符號表:external/undefined 來源
dyld_info -fixups ./yourbinary # chained fixups(dyld 會改寫的位置)
dyld_info -exports ./yourbinary # 匯出符號 trie
# ── 🟢 靜態:ObjC/Swift runtime 還原 ──
dyld_info -objc ./yourObjCApp # ObjC metadata(首選;arm64e 正確)。arm64e 上避免 otool -oV
nm ./yourSwiftApp | xcrun swift-demangle # Swift 符號還原(swift-demangle 用 xcrun 叫)
echo '__Z3foov' | c++filt # C++ 符號還原(內建)
# class-dump ./yourObjCApp # 第三方,需自行安裝後才可用
# ── 🟡 動態:只對你自己編譯、帶符號的測試程式 ──
clang -g -O0 -arch arm64 hello.c -o hello # 先做一個你能合法偵錯的目標
lldb ./hello # (lldb) b main / run / register read / bt
sudo dtrace -l | head # 列 probe;SIP 全開會 "requires additional privileges"
⚠ 危險/授權邊界(必讀):
- 靜態分析對你自己擁有或公開 IPSW 的映像是綠色合法,但重新散布 Apple 二進位/還原產物涉授權,請勿散布。
- 動態分析(lldb / dtrace / frida)只在你自有或受控授權的裝置上、對你自己的測試程式進行。對他人或系統程序的偵錯/注入需降低 SIP/AMFI,屬授權研究環境操作,不在本章範圍。
- dtrace 受 SIP 限制:放寬需在 recoveryOS 調整
csrutil(granular 的 dtrace 放行選項,或csrutil disable),會降低整機安全;本章不要求你關 SIP,可用預錄回放替代。- 本章不示範繞過任何保護機制——anti-debug / 簽章 / SIP / hardened runtime 一律只談類別、根因與偵測(DESIGN.md §10)。
下一步:M13 漏洞模型與緩解 — 把逆向看到的攻擊面收斂成「鏈的結構」,用抽象記憶體模型理解 PAC/KASLR/PPL/SPTM-TXM 等 mitigation 為何有效、攻擊者被迫轉向 data-only 的軍備競賽。全章純概念、不武器化。