試與 LoadLibraryA 早期加載實(shí)戰(zhàn))
應(yīng)用安全測試漏洞掃描【免費(fèi)下載鏈接】AFLplusplusAFL is a state-of-the-art fuzzer, and #1 in benchmarks. It was originally based on AFL. Today it comes with qemu 5.1, collision-free coverage, enhanced laf-intel redqueen, AFLfast power schedules, MOpt mutators, unicorn_mode, and a lot more!項(xiàng)目地址https://gitcode.com/gh_mirrors/af/AFLplusplus點(diǎn)擊查看免費(fèi)下載本指南聚焦于 AFL QEMU 模式下 Wine 子模式-W的兩類核心問題如何通過WINEDEBUG環(huán)境變量開啟 Wine 自身的調(diào)試輸出以及如何解決 fork 后LoadLibrary動態(tài)加載失敗錯(cuò)誤碼 87的問題。讀完本文你將掌握 Wine 模式的基本運(yùn)行機(jī)制、調(diào)試通道的選擇方法以及通過修改 PE 導(dǎo)入表或鏈接.lib靜態(tài)導(dǎo)入兩種方式實(shí)現(xiàn)“早期 DLL 加載”的完整實(shí)操方案。1. 背景AFL 的 Wine 模式是什么AFL 的 QEMU 模式可以通過 Wine 運(yùn)行 Win32 PE 二進(jìn)制并進(jìn)行插樁模糊測試這一能力被稱作 Wine 模式Wine mode。在 qemu_mode/README.md 中Wine 模式被描述為“QEMU mode can use Wine to fuzz Win32 PE binaries via the-Wflag of afl-fuzz”也就是說只需在啟動afl-fuzz時(shí)附加-W選項(xiàng)即可啟用。Wine 模式在整個(gè) AFL 中屬于“binary-only 目標(biāo)模糊測試”家族的成員docs/fuzzing_binary-only_targets.md 明確指出Wine 模式用 QEMU 插樁運(yùn)行 Win32 PE 二進(jìn)制運(yùn)行前提是系統(tǒng)安裝了Wine、Python 3 以及 Python 的 pefile 包docs/features.md 亦將其列為“Win32 PE binary-only fuzzing with QEMU and Wine”特性docs/Changelog.md 記載了 Wine 模式隨 QEMU 插樁引入的歷史。需要特別說明的是Wine 模式下被模糊測試的程序仍運(yùn)行在 QEMU 用戶態(tài)模擬之中因此它天然繼承了 QEMU 模式的性能特征通常比編譯期插樁慢 25 倍參見 docs/fuzzing_binary-only_targets.md。此外部分目標(biāo)程序需要 GUI 交互這類程序必須經(jīng)過補(bǔ)丁改造才能用于無頭模糊測試。而 Wine 模式自身還有兩個(gè)特有的坑調(diào)試輸出難以閱讀、以及LoadLibrary在 fork 后加載失敗——這正是本指南要解決的內(nèi)容。2. 開啟 Wine 調(diào)試WINEDEBUG 環(huán)境變量Wine 自帶一套靈活的調(diào)試基礎(chǔ)設(shè)施。默認(rèn)情況下 Wine 的調(diào)試輸出較為沉默一旦目標(biāo)程序在 Wine 中行為異常第一件要做的事就是打開調(diào)試通道。AFL 的官方做法非常簡單設(shè)置WINEDEBUG環(huán)境變量。WINEDEBUGtimestamp,tid,loaddll ./afl-fuzz -W -i seeds -o out -- ./target.exe 示例中的timestamp、tid、loaddll分別是三個(gè) Wine 調(diào)試通道debug channel的開關(guān)timestamp為每條調(diào)試消息附加時(shí)間戳便于定位調(diào)用時(shí)序tid附加線程 ID便于區(qū)分多線程下的消息來源loaddll輸出 DLL 加載/卸載事件這是排查“庫加載失敗”類問題時(shí)的核心通道。WINEDEBUG的語法基于通道channel列表表示開啟某個(gè)通道-表示關(guān)閉以逗號分隔。需要診斷 PE 加載細(xì)節(jié)時(shí)還可疊加module、relay等通道而在調(diào)試完成后務(wù)必清空該變量或使用-all關(guān)閉全部輸出避免海量日志拖慢模糊測試循環(huán)。3. LoadLibraryA 工作區(qū)fork 后加載失敗錯(cuò)誤碼 873.1 問題現(xiàn)象Wine 模式基于 fork 服務(wù)器forkserver架構(gòu)QEMU 啟動目標(biāo)進(jìn)程后在入口點(diǎn)附近掛起并等待afl-fuzz的 fork 指令每個(gè)測試用例在 fork 出的子進(jìn)程中執(zhí)行。關(guān)鍵限制在于如果在入口點(diǎn)entry point之后、fork 發(fā)生之前程序通過LoadLibrary/LoadLibraryA動態(tài)加載了外部 DLLfork 出的子進(jìn)程將無法正確加載這些庫Windows API 會返回錯(cuò)誤碼 87。錯(cuò)誤碼 87 在 Windows 語義中對應(yīng)ERROR_INVALID_PARAMETER即“參數(shù)無效”。從 Wine 模式的實(shí)際運(yùn)行看這一錯(cuò)誤并非參數(shù)本身的問題而是 fork 語義與 Wine 內(nèi)部加載狀態(tài)之間的不一致導(dǎo)致的加載失敗。官方文檔給出的結(jié)論非常明確The forked process fails to load libraries loaded viaLoadLibraryif the load happens after the entry point (error code: 87).即凡是需要在模糊測試循環(huán)中使用的庫都必須在 fork 發(fā)生之前完成加載。3.2 解決思路既然“在入口點(diǎn)之后用LoadLibrary動態(tài)加載”不可靠那么解決方案就是把外部庫的加載時(shí)機(jī)提前到入口點(diǎn)之前讓庫隨 PE 文件本身一起在進(jìn)程早期就緒。AFL 官方文檔提供了兩種互為補(bǔ)充的手段直接修改 PE 文件的 Import Directory導(dǎo)入表讓 DLL 作為靜態(tài)導(dǎo)入在進(jìn)程啟動時(shí)被加載從 DLL 導(dǎo)出表生成.lib導(dǎo)入庫并與 harness 鏈接讓鏈接器在生成 PE 時(shí)自動寫入導(dǎo)入表?xiàng)l目。兩種手段的最終目標(biāo)一致在 PE 映像里留下導(dǎo)入記錄使系統(tǒng)在程序最早啟動階段早于我們的入口點(diǎn)與 fork完成 DLL 的映射與初始化。4. 方案一直接編輯 PE 導(dǎo)入表這是最直接的手段。任何 PE 編輯器如 CFF Explorer、LordPE 等都可以打開目標(biāo) PE 文件在Import Directory中加入目標(biāo) DLL 的名稱條目。經(jīng)過修改后PE 加載器在進(jìn)程啟動時(shí)會立刻加載該 DLL從而繞開 fork 后LoadLibrary失敗的路徑。操作要點(diǎn)在編輯前保留原始 PE 備份確認(rèn) DLL 與其依賴項(xiàng)都可被 Wine 找到可結(jié)合 2.1 節(jié)的loaddll通道驗(yàn)證加載序列修改后建議先用 Wine 單獨(dú)運(yùn)行一次確認(rèn)無導(dǎo)入表解析錯(cuò)誤常見于導(dǎo)入序號與名稱不匹配。該方案的優(yōu)勢是零編譯依賴適合對閉源、無源碼的 PE 目標(biāo)做快速修復(fù)劣勢是每次 PE 更新都需要重新打補(bǔ)丁且手工編輯導(dǎo)入表對操作者的 PE 結(jié)構(gòu)知識有一定要求。4. 方案二dumpbin lib 生成導(dǎo)入庫并鏈接如果目標(biāo)程序有對應(yīng)的 harness 源碼例如用 C 語言編寫的一個(gè)薄封裝把 PE 目標(biāo)當(dāng)作被測函數(shù)調(diào)用則可以用官方推薦的“從導(dǎo)出表生成導(dǎo)入庫”的鏈路讓鏈接器自動完成早期加載。完整步驟如下Step 1導(dǎo)出 DLL 的導(dǎo)出表dumpbin /exports filename.dlldumpbin是 MSVC 工具鏈自帶的 PE 轉(zhuǎn)儲工具。它會列出 DLL 導(dǎo)出的全部函數(shù)名及其序號。Step 2將導(dǎo)出函數(shù)名寫入.def文件將上一步輸出的導(dǎo)出函數(shù)名逐一粘貼進(jìn)一個(gè)模塊定義文件.def。典型的.def內(nèi)容形如LIBRARY filename EXPORTS FuncA FuncB FuncCStep 3用 lib 工具生成導(dǎo)入庫lib /def:deffile /OUT:libfilelib會根據(jù).def文件生成一個(gè).lib導(dǎo)入庫文件。Step 4把導(dǎo)入庫加入鏈接器選項(xiàng)將生成的.lib加入 harness 的鏈接命令行或工程配置中。Step 5在 harness 源碼中引用其導(dǎo)出符號在 harness 中對目標(biāo) DLL 的導(dǎo)出函數(shù)使用__declspec(dllimport)聲明例如__declspec(dllimport) int FuncA(void);一旦鏈接器在 harness 的目標(biāo)文件中檢測到對dllimport符號的引用它就會把對應(yīng) DLL 寫入生成 PE 的 Import Directory從而觸發(fā)早期 DLL 加載。正如文檔所強(qiáng)調(diào)的Once the usage of an export is detected (__declspec(dllimport)), the linker adds the early DLL load.相比方案一該方案由鏈接器自動維護(hù)導(dǎo)入表DLL 更新后只需重新鏈接 harness更適合有源碼、需要長期迭代的模糊測試工程。5. 源碼級佐證-W參數(shù)與 afl-wine-trace 的調(diào)用鏈理解了問題與解法后再回到源碼層面看 Wine 模式是如何串起來的這能幫你更快定位“我的環(huán)境為什么沒生效”。-W參數(shù)解析afl-fuzz在 src/afl-fuzz.c 中解析-W并置位afl-use_wine隨后在 src/afl-fuzz.c 調(diào)用get_wine_argv()重寫目標(biāo)命令行。同樣的-W邏輯也存在于 src/afl-showmap.c、src/afl-cmin.c 與 src/afl-tmin.c即覆蓋率查看、語料精簡與最小化工具也復(fù)用同一套 Wine 啟動邏輯。argv 重寫get_wine_argv()定義于 src/afl-common.c。它把目標(biāo)二進(jìn)制解析出的路徑放到new_argv[1]并把a(bǔ)rgv[0]替換為afl-wine-trace的路徑通過find_afl_binary查找從而讓真正的“執(zhí)行者”變成 Wine 模式的包裝腳本。afl-wine-trace 腳本倉庫根目錄的 afl-wine-trace 是 Wine 模式的核心包裝器它做的事與本指南的兩大主題直接相關(guān)使用pefile解析 PE 頭若未顯式設(shè)置則自動把AFL_ENTRYPOINT設(shè)為ImageBase AddressOfEntryPoint把AFL_CODE_START/AFL_CODE_END設(shè)為代碼段BaseOfCode起止——這意味著默認(rèn)插樁范圍就是目標(biāo) PE 自身的代碼段與 Wine 系統(tǒng) DLL 分離根據(jù) PE 的Machine字段AMD64/IA64 走 64 位I386 走 32 位選擇預(yù)加載qemu_mode/unsigaction/unsigaction64.so或unsigaction32.so并通過QEMU_SET_ENV一并注入WINEARCHwin64或WINEARCHwin32。unsigaction子模塊正是為 Wine 模式準(zhǔn)備的qemu_mode/unsigaction/README.md 明言它“Mainly needed by Wine mode but can be used as a separate tool”解析 QEMU 路徑優(yōu)先WINECOV_QEMU_PATH其次afl-qemu-trace最后回退到系統(tǒng)qemu-x86_64/qemu-i386與 Wine 路徑優(yōu)先AFL_WINE_PATH其次PATH中的wine、/usr/bin/wine、/usr/lib/wine/wine對參數(shù)中含.cur_input的路徑調(diào)用winepath --windows將其轉(zhuǎn)換為 Windows 風(fēng)格路徑后替換回 argv最后以os.execve(qemu, [qemu, wine] argv)啟動 QEMU→Wine→目標(biāo)程序 的完整鏈路。理解這條鏈路對排障很有幫助如果loaddll日志顯示 DLL 加載時(shí)序異??梢韵却_認(rèn)AFL_ENTRYPOINT是否被腳本正確設(shè)為 PE 入口點(diǎn)如果 Wine 環(huán)境不對則應(yīng)檢查AFL_WINE_PATH與WINEARCH的取值是否符合目標(biāo) PE 的位數(shù)。6. 排障速查從現(xiàn)象到對策現(xiàn)象排查手段對策Wine 內(nèi)部行為不透明、無法定位崩潰點(diǎn)設(shè)置WINEDEBUGtimestamp,tid,loaddll可疊加module、relay分析加載時(shí)序聚焦崩潰前的最后一條加載/調(diào)用記錄fork 子進(jìn)程調(diào)用LoadLibrary返回 87用loaddll確認(rèn)加載發(fā)生在入口點(diǎn)之后將 DLL 加入 PE Import Directory或用 dumpbin/lib 生成導(dǎo)入庫提前鏈接PE 位數(shù)與 Wine 架構(gòu)不匹配查看 afl-wine-trace 打印的 exec 命令與WINEARCH確保 32 位 PE 對應(yīng) win32、64 位 PE 對應(yīng) win64必要時(shí)用AFL_WINE_PATH指定 Wine 路徑插樁范圍異常誤插樁系統(tǒng) DLL檢查AFL_CODE_START/AFL_CODE_END取值默認(rèn)腳本已按 PE 代碼段自動設(shè)置如需插樁庫代碼再考慮AFL_INST_LIBS17. 小結(jié)AFL 的 Wine 模式讓“無源碼 Win32 PE 目標(biāo)”也能接入 QEMU 插樁模糊測試但 fork 服務(wù)器架構(gòu)與 Wine 動態(tài)加載語義之間存在天然沖突。本文梳理的WINEDEBUG調(diào)試通道與兩種“早期 DLL 加載”方案PE 導(dǎo)入表直改、.def/.lib鏈接正是解決這一沖突的標(biāo)準(zhǔn)路徑結(jié)合 afl-wine-trace 與 src/afl-common.c 的調(diào)用鏈你可以快速定位 Wine 架構(gòu)、插樁范圍與加載時(shí)序三類常見問題。相關(guān)背景與其余 QEMU 模式能力可繼續(xù)參閱 qemu_mode/README.md 與 docs/fuzzing_binary-only_targets.md。贊分享應(yīng)用安全測試漏洞掃描【免費(fèi)下載鏈接】AFLplusplusAFL is a state-of-the-art fuzzer, and #1 in benchmarks. It was originally based on AFL. Today it comes with qemu 5.1, collision-free coverage, enhanced laf-intel redqueen, AFLfast power schedules, MOpt mutators, unicorn_mode, and a lot more!項(xiàng)目地址https://gitcode.com/gh_mirrors/af/AFLplusplus點(diǎn)擊查看免費(fèi)下載相關(guān)推薦AFL FRIDA 模式故障排查與調(diào)試完全指南從環(huán)境變量診斷到 gdb 持久模式調(diào)優(yōu)AFL FRIDA 模式故障排查與調(diào)試完全指南從環(huán)境變量診斷到 gdb 持久模式調(diào)優(yōu) 導(dǎo)讀 本文以 AFL 倉庫中 frida_mode/DEBUGG應(yīng)用安全測試漏洞掃描AFL 常見問題FAQ權(quán)威指南灰盒模糊測試原理、性能調(diào)優(yōu)與故障排查實(shí)戰(zhàn)AFL 常見問題FAQ權(quán)威指南灰盒模糊測試原理、性能調(diào)優(yōu)與故障排查實(shí)戰(zhàn) 導(dǎo)讀 本文以 AFL 官方 FAQ docs/FAQ.md https應(yīng)用安全測試漏洞掃描ComfyUI-Florence2模型加載故障排查與修復(fù)指南ComfyUI Florence2模型加載故障排查與修復(fù)指南 當(dāng)你在ComfyUI中嘗試使用Florence2視覺語言模型時(shí)可能會遇到一個(gè)令人困惑的問題Fl人工智能大模型計(jì)算機(jī)視覺多模態(tài)本地部署AI 應(yīng)用上一篇GraalWasm 解釋器基準(zhǔn)套件WAT 基準(zhǔn)文件的生成、復(fù)現(xiàn)與運(yùn)行指南下一篇如何用dreamtime集成LUIS實(shí)現(xiàn)智能意圖識別完整入門教程創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考