據(jù))
逆向工程開發(fā)工具【免費下載鏈接】LIEFLIEF - Library to Instrument Executable Formats (C, Python, Rust)項目地址https://gitcode.com/gh_mirrors/li/LIEF點擊查看免費下載本篇技術指南圍繞 LIEF 提供的 Ghidra 分析器Analyzer「LIEF - PE LoadConfiguration」展開講解它如何借助 LIEF 的 PE 解析能力在 Ghidra 中重建IMAGE_LOAD_CONFIG_DIRECTORY結構的完整字段布局與正確數(shù)據(jù)類型并順帶定義IMAGE_ARM64EC_METADATA、IMAGE_CHPE_METADATA_X86等用于分析 ARM64EC 混合架構二進制的新結構。讀完本文你將理解該分析器的觸發(fā)條件、生成的全部數(shù)據(jù)類型與字段語義、類型在 Ghidra 中的組織方式以及如何在 GUI 與 headless 模式下運行和驗證它。一、背景為什么 Ghidra 原生難以完整識別 Load ConfigurationPE 的加載配置Load Configuration由可選頭中的數(shù)據(jù)目錄項IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG指向其數(shù)據(jù)結構IMAGE_LOAD_CONFIG_DIRECTORY記錄了與 Windows 加載器行為相關的眾多安全與運行時元數(shù)據(jù)包括 SEH 異常處理表、Control Flow GuardCFG相關的函數(shù)表與標志位、/GS安全 Cookie、Return Flow Guard、熱補丁表、Enclave 配置指針等。該結構由微軟隨每個 Windows 版本頻繁演進新字段不斷追加舊字段在 32/64 位平臺下尺寸也不同。LIEF 在 C 頭文件 include/LIEF/PE/LoadConfigurations/LoadConfiguration.hpp 中對該結構做了完整建模其類注釋明確說明“This structure is frequently updated by Microsoft to add new metadata”。而截至當前Ghidra 內建的 PE 支持尚不能原生識別較新版本中引入的諸多屬性。LIEF 的 Ghidra 分析器正是為解決這一缺口而設計它不再讓分析師面對一堆“dq 未知語義”的裸數(shù)據(jù)而是把每個字段的名稱、類型、偏移都精確地落在 Ghidra 的數(shù)據(jù)類型系統(tǒng)與 Listing 中。其實現(xiàn)位于 plugins/ghidra/src/main/java/lief/ghidra/plugins/analyzers/pe/LoadConfigurationAnalyzer.java。此外該分析器還順帶定義了 CHPECompiled Hybrid Portable Executable即 ARM64EC元數(shù)據(jù)結構幫助逆向工程師理解 ARM64EC 混合二進制中某些函數(shù)與指針的真實用途——這一點對分析 Windows on ARM 的混合代碼尤其有價值。BinaryNinja 的 LIEF 插件也提供了同樣的能力參見 BinaryNinja 側的分析器文檔。二、分析器注冊與運行時機LoadConfigurationAnalyzer繼承自 LIEFAbstractAnalyzer在構造時完成自身注冊名稱LIEF - PE LoadConfiguration描述增強 PELoadConfiguration及其相關結構如IMAGE_ARM64EC_METADATA的類型定義類型AnalyzerType.FUNCTION_ANALYZER函數(shù)分析器在分析流程中較早參與數(shù)據(jù)布局優(yōu)先級AnalysisPriority.FORMAT_ANALYSIS.after().after()即排在格式分析階段之后默認啟用setDefaultEnablement(true)安裝插件后無需手動勾選即可生效單次分析setSupportsOneTimeAnalysis()允許對已加載程序執(zhí)行一次性補跑它的適用范圍通過canAnalyze(Program)限定只有 PE 程序復用 Ghidra 內建PEUtil.canAnalyze(program)才會觸發(fā)ELF/MachO 等格式不受影響。三、分析流程從 LIEF 解析到 Ghidra 數(shù)據(jù)落盤分析器的核心邏輯集中在added()方法整體鏈路如下加載 LIEF Binary 對象通過 Context.java 的Context.create(program, monitor, log)先由FSRL.fromProgram(program)取得當前程序的文件系統(tǒng)定位符FSRL再經(jīng)FSRLHelper.load(fsrl)經(jīng)由 JNI 橋接把同一個文件交給 LIEF 重新解析得到一個lief.pe.Binary對象。這樣分析器拿到的結構字段值全部來自 LIEF 的獨立解析而非 Ghidra 的猜測。讀取 Load Configuration調用ctx.getBin().getLoadConfiguration()返回OptionalLoadConfiguration。若該 PE 根本沒有 Load Configuration 數(shù)據(jù)目錄項則直接返回true不做任何改動。構造結構類型根據(jù)程序指針寬度決定后綴——ctx.is32bits()為32否則為64從而生成IMAGE_LOAD_CONFIG_DIRECTORY32/IMAGE_LOAD_CONFIG_DIRECTORY64結構內部名_IMAGE_LOAD_CONFIG_DIRECTORY32/64然后按 LIEF 解析出的字段存在性逐個追加成員。地址換算與落盤從Binary.getLoadConfigurationDir()取出數(shù)據(jù)目錄的 RVA經(jīng)Context.translateAddress()換算為 Ghidra 程序地址——換算規(guī)則是若目標值大于等于 LIEF 側getImageBase()則減去鏡像基址再疊加到 Ghidra 的program.getImageBase()上否則按普通偏移處理。最終ctx.defineData(address, loadConfigTy)用DataUtilities.createData在對應地址寫入該結構類型并清除沖突的默認數(shù)據(jù)。所有生成的類型都歸類在 Ghidra 的/LIEF/PE類別路徑下由 PE 版 TypeBuilder.java 的getCategoryPath()決定基類ROOT /LIEFPE 擴展PE沖突時使用DataTypeConflictHandler.REPLACE_HANDLER以 LIEF 的版本替換已有類型。四、IMAGE_LOAD_CONFIG_DIRECTORY的完整字段布局4.1 固定頭部字段分析器首先無條件添加下列固定字段名稱與類型完全對照 LoadConfigurationAnalyzer.java字段類型說明SizeU32結構自身大小也是解析器判斷結構版本的依據(jù)TimeDateStampU32時間戳MajorVersion/MinorVersionU16版本號GlobalFlagsClear/GlobalFlagsSetU32系統(tǒng)全局標志對應 Gflags.exeCriticalSectionDefaultTimeoutU32臨界區(qū)默認超時DeCommitFreeBlockThreshold/DeCommitTotalFreeThresholdUPTR堆去提交閾值指針寬度LockPrefixTableADDRx86 專有的 LOCK 前綴替換表 VAMaximumAllocationSize/VirtualMemoryThresholdUPTR最大分配/堆段閾值ProcessAffinityMaskUPTR進程關聯(lián)掩碼僅 .exeProcessHeapFlagsU32進程堆標志CSDVersionU16Service Pack 版本DependentLoadFlagsU16依賴加載標志EditListADDR系統(tǒng)保留SecurityCookieADDR/GS安全 Cookie 指針這里的基礎類型來自基類 TypeBuilder.javaU16/U32對應 Word/DWordUPTRgetUnsignedPointer()按程序指針寬度自動取 U32 或 U64ADDRgetAddrType()是寬度與指針一致的無目標類型指針RVA則使用IBO32DataTypeimage base offset32 位。4.2 按需追加的擴展字段固定頭部之后分析器針對 LIEF 能解析出的每個可選字段逐個檢測對應LoadConfiguration返回Optional的訪問器字段存在才加入結構從而保證結構尺寸與真實二進制一致。這些字段及其類型映射如下依據(jù)分析器源碼中的isPresent()分支字段類型語義SEHandlerTable指向 UPTR 的指針x86 的 SEH 處理器表SEHandlerCountUPTRSEH 表項數(shù)GuardCFCheckFunctionPointer/GuardCFDispatchFunctionPointerADDRCFG 檢查/分派函數(shù)指針GuardCFFunctionTable指向 U32 的指針CFG 合法目標表GuardCFFunctionCountUPTRCFG 目標表項數(shù)GuardFlagsIMAGE_GUARD_FLAGS枚舉CFG 相關標志見下節(jié)CodeIntegrityIMAGE_LOAD_CONFIG_CODE_INTEGRITY代碼完整性信息GuardAddressTakenIatEntryTable/GuardAddressTakenIatEntryCountADDR / UPTR取地址 IAT 表GuardLongJumpTargetTable/GuardLongJumpTargetCountADDR / UPTRlongjmp 目標表DynamicValueRelocTableADDR動態(tài)重定位表DVRTCHPEMetadataPointer指向元數(shù)據(jù)結構的指針CHPEARM64EC/x86 模擬元數(shù)據(jù)GuardRFFailureRoutine/GuardRFFailureRoutineFunctionPointerADDRReturn Flow Guard 失敗例程DynamicValueRelocTableOffsetRVA相對重定位表的偏移DynamicValueRelocTableSectionU16動態(tài)重定位表所在節(jié)索引Reserved2U16保留應為 0GuardRFVerifyStackPointerFunctionPointerADDR校驗棧指針的函數(shù)HotPatchTableOffsetRVA熱補丁表偏移Reserved3U32保留EnclaveConfigurationPointerADDREnclave 配置VolatileMetadataPointerADDR易失性元數(shù)據(jù)GuardEHContinuationTable/GuardEHContinuationCountADDR / UPTREH 延續(xù)EH Continuation表GuardXFGCheckFunctionPointer/GuardXFGDispatchFunctionPointer/GuardXFGTableDispatchFunctionPointerADDRXFG 相關指針CastGuardOsDeterminedFailureModeADDRCastGuard 失敗模式GuardMemcpyFunctionPointerADDRGuarded memcpyUmaFunctionPointersADDRUMAUnified Memory Access函數(shù)指針字段的語義說明可對照 C 側LoadConfiguration各訪問器的注釋如se_handler_table()注明“僅 x86 可用”、lock_prefix_table()注明“僅 x86”等在 include/LIEF/PE/LoadConfigurations/LoadConfiguration.hpp 中可以找到每個字段的權威解釋。正是這種“存在才加入”的策略使分析器既適配較老、較小的 Load Configuration也能完整覆蓋 Windows 11 上體積更大的新版結構。五、IMAGE_GUARD_FLAGSGuardFlags 枚舉類型GuardFlags字段沒有簡單地標注為 U32而是被注冊為一個獨立的枚舉類型IMAGE_GUARD_FLAGSPE 版TypeBuilder.getType(IMAGE_GUARD_FLAGS)首次被引用時創(chuàng)建。該枚舉在 plugins/ghidra/src/main/java/lief/ghidra/plugins/analyzers/pe/TypeBuilder.java 中定義包含以下取值枚舉成員值含義IMAGE_GUARD_CF_INSTRUMENTED0x00000100使用系統(tǒng)提供的支持執(zhí)行 CFI 檢查IMAGE_GUARD_CFW_INSTRUMENTED0x00000200執(zhí)行控制流與寫完整性檢查IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT0x00000400含合法的 CFG 目標元數(shù)據(jù)IMAGE_GUARD_SECURITY_COOKIE_UNUSED0x00000800未使用/GS安全 CookieIMAGE_GUARD_PROTECT_DELAYLOAD_IAT0x00001000支持只讀延遲加載 IATIMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION0x00002000延遲導入表位于獨立.didat節(jié)IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT0x00004000含被抑制的導出信息同時暗示存在取地址 IAT 表IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION0x00008000啟用導出抑制IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT0x00010000含 longjmp 目標信息IMAGE_GUARD_RF_INSTRUMENTED0x00020000含返回流RF插樁與元數(shù)據(jù)IMAGE_GUARD_RF_ENABLE0x00040000請求系統(tǒng)啟用返回流保護IMAGE_GUARD_RETPOLINE_PRESENT0x00100000以 retpoline 支持構建IMAGE_GUARD_EH_CONTINUATION_TABLE_PRESENT0x00400000含 EH 延續(xù)目標信息IMAGE_GUARD_XFG_ENABLED0x00800000以 XFG 構建已棄用IMAGE_GUARD_CASTGUARD_PRESENT0x01000000存在 CastGuard 插樁IMAGE_GUARD_MEMCPY_PRESENT0x02000000存在 Guarded Memcpy 插樁分析器還在此基礎上生成IMAGE_LOAD_CONFIG_CODE_INTEGRITY結構FlagsU16CI 信息是否可用、CatalogU160xFFFF 表示不可用、CatalogOffsetU320xFFFF 表示不可用、ReservedU32用于標注CodeIntegrity字段。運行后Listing 中GuardFlags字段會直接顯示為IMAGE_GUARD_CF_INSTRUMENTED這樣的具名枚舉值而非裸整數(shù)。六、ARM64EC 元數(shù)據(jù)IMAGE_ARM64EC_METADATA家族6.1 CHPEMetadataPointer 的版本化解析當 LIEF 檢測到CHPEMetadataPointer存在時分析器會進一步讀取getCHPEMetadata()。由于 CHPE 元數(shù)據(jù)存在多種變體分析器按實際類型與版本分別處理ARM64ECCHPEMetadataARM64依據(jù)getVersion()選擇類型——版本 2 使用IMAGE_ARM64EC_METADATA_V2其余使用IMAGE_ARM64EC_METADATA并把結構落盤到指針指向的地址隨后將CHPEMetadataPointer字段類型化為指向該結構的指針x86 模擬CHPEMetadataX86依據(jù)版本選擇IMAGE_CHPE_METADATA_X86、_V2或_V3無法識別退化為普通ADDR指針保證結構仍可正確定位。Java 端CHPEMetadata/CHPEMetadataARM64/CHPEMetadataX86的字段訪問器定義在 plugins/ghidra/src/main/java/lief/pe/CHPEMetadata.java 與 plugins/ghidra/src/main/java/lief/pe/CHPEMetadataARM64.java 中C 側對應模型位于 include/LIEF/PE/LoadConfigurations/CHPEMetadata.hpp、MetadataARM64.hpp 與 MetadataX86.hpp。6.2IMAGE_ARM64EC_METADATA結構定義基礎版本IMAGE_ARM64EC_METADATA在 PE 版TypeBuilder中按以下成員構建VersionULONG、CodeMapRVA、CodeMapCountULONG、CodeRangesToEntryPointsRVA、RedirectionMetadataRVA、__os_arm64x_dispatch_call_no_redirect、__os_arm64x_dispatch_ret、__os_arm64x_dispatch_call、__os_arm64x_dispatch_icall、__os_arm64x_dispatch_icall_cfg均為 RVA、AlternateEntryPoint、AuxiliaryIATRVA、CodeRangesToEntryPointsCount、RedirectionMetadataCountULONG、GetX64InformationFunctionPointer、SetX64InformationFunctionPointer、ExtraRFETableRVA、ExtraRFETableSizeULONG、__os_arm64x_dispatch_fptr、AuxiliaryIATCopyRVA。IMAGE_ARM64EC_METADATA_V2則將 V1 結構整體作為首成員V1再追加AuxDelayloadIAT、AuxDelayloadIATCopyRVA與ReservedBitFieldULONG。X86 側同理IMAGE_CHPE_METADATA_X86記錄Version與CHPECodeAddressRangeOffset/Count、各WowA64Dispatch*FunctionPointer_V2追加CompilerIATPointer_V3再追加WowA64RdtscFunctionPointer。這組結構從源碼結構上看遵循了“以版本為前綴、低版本結構嵌套進高版本”的遞增式布局便于向前兼容。6.3 對 ARM64EC 輔助數(shù)組的深度標注除了結構本身process()方法還會把 ARM64EC 元數(shù)據(jù)指向的三個關鍵數(shù)組也一并落盤見 LoadConfigurationAnalyzer.javaCodeMap按getCodeMapCount()生成IMAGE_ARM64EC_METADATA_CODE_RANGE數(shù)組。該元素是位域結構Type2 bitIMAGE_ARM64EC_METADATA_CODE_RANGE_TYPE枚舉取值ARM640、ARM64EC1、AMD642RVA30 bit構成一個 packed 的 32 位成員隨后是LengthU32CodeRangesToEntrypoints按計數(shù)生成IMAGE_ARM64EC_CODE_RANGE_ENTRY_POINT數(shù)組每項為StartRva、EndRva、EntryPoint三個 RVARedirectionMetadata生成IMAGE_ARM64EC_METADATA_REDIRECTION數(shù)組每項為From、To兩個 RVA描述 x64 調用被重定向到 ARM64EC 樁的映射。通過這些數(shù)組的定義Ghidra 能在分析 ARM64EC 二進制時自動把“代碼范圍”“入口點”“重定向”數(shù)據(jù)識別為具名結構數(shù)組而不是零散的數(shù)字。七、運行與驗證7.1 安裝前提分析器屬于 LIEF Ghidra 插件包。安裝分為兩步詳見 Ghidra 插件索引文檔將 LIEF 插件擴展包按 Ghidra 官方擴展安裝流程放入 Ghidra 的Extensions目錄將 LIEF 共享庫LIEF.dll、libLIEF.dylib或libLIEF.so放置到同一目錄例如 Linux 上為~/.config/ghidra/ghidra_版本_PUBLIC/Extensions/libLIEF.so。裝好后可在 CodeBrowser注意是 CodeBrowser 而非 Project 窗口的File Configure中看到 LIEF 配置項。若分析器未生效通常先排查共享庫是否安裝正確錯誤提示會給出期望的庫路徑少數(shù)依賴額外能力的功能還可能需要 LIEF 的 extended 版本共享庫。7.2 GUI 與 headless 兩種觸發(fā)方式GUI正常導入 PE 文件到 Ghidra 后分析器默認啟用setDefaultEnablement(true)隨自動分析運行也可在分析選項里手動觸發(fā)一次性分析。Headless倉庫提供了用于驗證分析器效果的腳本 plugins/ghidra/ghidra_scripts/RunAnalyzers.java。它以AsciiExporter導出分析前的 Listing依次調用LoadConfigurationAnalyzer、ExceptionsAnalyzer、RelocationsAnalyzer的added()再導出分析后的 Listing用于對比結構標注前后的差異。這也演示了分析器 API 的編程式調用方式構造分析器 →canAnalyze(program)判斷 →added(program, addressSet, monitor, log)執(zhí)行。7.3 效果確認運行后打開數(shù)據(jù)目錄指向的地址應能看到IMAGE_LOAD_CONFIG_DIRECTORY64或32結構整體展開字段名與官方結構一一對應、指針字段自動解析為指向真實函數(shù)/數(shù)據(jù)的引用例如GuardCFCheckFunctionPointer會顯示為PTR__guard_check_icall_...、GuardFlags以具名枚舉呈現(xiàn)。所有結構位于/LIEF/PE類型類別下可被后續(xù)分析或導出直接復用。八、原理小結一條從文件字節(jié)到 Ghidra 類型的完整鏈路從底層看該分析器打通了“文件 → LIEF 解析 → Ghidra 類型系統(tǒng)”的整條鏈路文件級LIEF 的 C 解析器按IMAGE_LOAD_CONFIG_DIRECTORY的Size字段判斷結構版本并逐一讀取字段模型見 include/LIEF/PE/LoadConfigurations/LoadConfiguration.hpp綁定層Ghidra 插件通過 JNI 將 LIEF 對象映射為lief.pe.LoadConfiguration、lief.pe.CHPEMetadata等 Java 對象訪問器與 C 模型一一對應分析器層LoadConfigurationAnalyzer按字段存在性動態(tài)拼裝StructureDataType通過TypeBuilder復用/創(chuàng)建基礎類型、枚舉與嵌套結構落盤層Context.translateAddress()完成 LIEF VA/RVA 到 Ghidra 地址的換算defineData()寫入結構沖突數(shù)據(jù)按REPLACE_HANDLER策略被替換。正是這條鏈路讓 Ghidra 中對 PE Load Configuration 的逆向從“手工對照 SDK 頭文件”升級為“結構即見即所得”同時也為后續(xù)基于 Ghidra 的自動化分析如 CFG 目標提取、ARM64EC 混合代碼梳理提供了可靠的數(shù)據(jù)基礎。使用該分析器時需要注意它依賴 LIEF 共享庫的正確安裝且分析對象必須是 Ghidra 可識別的 PE 格式生成類型固定存放于/LIEF/PE類別下如需遷移可在此處直接復制到其他類別或導出為 C 頭文件。贊分享逆向工程開發(fā)工具【免費下載鏈接】LIEFLIEF - Library to Instrument Executable Formats (C, Python, Rust)項目地址https://gitcode.com/gh_mirrors/li/LIEF點擊查看免費下載相關推薦LIEF 0.17.0 PE 模塊重大重構解析從解析器重構到 ARM64EC/ARM64X 支持LIEF 0.17.0 PE 模塊重大重構解析從解析器重構到 ARM64EC/ARM64X 支持 導讀 LIEF 0.17.0 對 PEPortable E逆向工程開發(fā)工具探索PE文件結構與逆向分析利器 - PEDA探索PE文件結構與逆向分析利器 PEDA 項目簡介 PEDAPowerful exploitation development and analysis是一網(wǎng)絡安全逆向工程創(chuàng)作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考