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