You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PE加载器代码无法从导出表获取正确函数RVA的问题排查

PE导出表解析RVA不符的问题排查

我在虚拟机管理程序中编写了一个极简PE加载器,目标是通过解析导出表按名称定位函数,但获取的函数RVA值和预期不符。运行环境是Linux下的QEMU虚拟化。相关代码如下:

#include <utils/stdlib.h>

__attribute__((section(".vmm")))
BYTE_PTR GetAssetFromExportedTable(BYTE_PTR physicalBaseAddress, PCHAR assetName) {
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)(physicalBaseAddress);
    if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
        logDebug("Could not find the %s address. Invalid DOS header magic!!!\n", assetName);
        return 0;
    }

    PIMAGE_NT_HEADERS64 pNtHeader = (PIMAGE_NT_HEADERS64)((BYTE_PTR)(pDosHeader) + pDosHeader->e_lfanew);
    if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
        logDebug("Could not find the %s address. Invalid NT header magic!!!\n", assetName);
        return 0;
    }
    
    PIMAGE_OPTIONAL_HEADER64 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER64)&(pNtHeader->OptionalHeader);
    if (pOptionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
        logDebug("Could not find the %s address. Invalid OPTIONAL header magic!!!\n", assetName);
        return 0;
    }

    // Retrieve Export Directory
    PIMAGE_DATA_DIRECTORY pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    if (pDataDirectory->VirtualAddress == 0) {
        return FALSE; // No export directory present
    }

    PIMAGE_EXPORT_DIRECTORY pExportedDirectory = (PIMAGE_EXPORT_DIRECTORY)((BYTE_PTR)physicalBaseAddress + pDataDirectory->VirtualAddress);
    if (pExportedDirectory == 0 || pExportedDirectory->AddressOfNames == 0) {
        logDebug("Could not find the %s address. No exported names found.\n", assetName);
        return 0;
    }

    DWORD_PTR pNames = (DWORD_PTR)((BYTE_PTR)physicalBaseAddress + pExportedDirectory->AddressOfNames);
    DWORD_PTR pFunctions = (DWORD_PTR)((BYTE_PTR)physicalBaseAddress + pExportedDirectory->AddressOfFunctions);
    WORD_PTR pOrdinals = (WORD_PTR)((BYTE_PTR)physicalBaseAddress + pExportedDirectory->AddressOfNameOrdinals);

    for (DWORD i = 0; i < pExportedDirectory->NumberOfNames; i++) {
        PCHAR pFunctionName = (PCHAR)(physicalBaseAddress + pNames[i]);
        logDebug("Name: %s, Ordinal: %x, function RVA: %x\n", pFunctionName, pOrdinals[i], pFunctions[pOrdinals[i]]);
        
        if (strcmp(pFunctionName, assetName)) {
            DWORD functionRVA = pFunctions[pOrdinals[i]];
            BYTE_PTR functionAddress = (BYTE_PTR)(physicalBaseAddress + functionRVA);
            logDebug("Found %s at address: %x\n", assetName, functionAddress);
            return functionAddress;
        }
    }
    
    logDebug("Could not find the %s address in the export table.\n", assetName);
    return 0;
}

可能导致RVA错误的潜在问题

  • 数组访问类型错误
    AddressOfNames、AddressOfFunctions是DWORD数组的RVA,AddressOfNameOrdinals是WORD数组的RVA,但你把它们转换成了DWORD_PTR/WORD_PTR后直接用数组下标访问,这相当于把指针值当成数组起始,会读取到错误的内存内容。正确的写法应该是转换成对应类型的数组指针:

    DWORD* pNames = (DWORD*)(physicalBaseAddress + pExportedDirectory->AddressOfNames);
    DWORD* pFunctions = (DWORD*)(physicalBaseAddress + pExportedDirectory->AddressOfFunctions);
    WORD* pOrdinals = (WORD*)(physicalBaseAddress + pExportedDirectory->AddressOfNameOrdinals);
    

    这是最可能导致RVA不符的核心原因。

  • 字符串比较逻辑颠倒
    strcmp返回0表示字符串相等,但你的代码中if (strcmp(pFunctionName, assetName))会在字符串不相等时进入分支,导致返回错误的函数地址,或者提前终止循环返回错误结果。正确判断应为if (strcmp(pFunctionName, assetName) == 0)。

  • 虚拟地址与物理地址转换错误
    导出表中的VirtualAddress是相对虚拟地址(RVA),如果PE文件没有加载到默认ImageBase,或者physicalBaseAddress不是加载基址对应的物理地址,直接用physicalBaseAddress + RVA计算会出错。VMM环境中需要先确认PE的实际加载基址,再将RVA转换为虚拟地址,最后通过页表映射得到物理地址。

  • 未处理转发函数
    如果导出函数是转发函数,AddressOfFunctions中的值不是真实RVA,而是指向DLLName.FunctionName格式字符串的RVA。若该值落在导出表的地址范围内(pDataDirectory->VirtualAddress <= functionRVA < pDataDirectory->VirtualAddress + pDataDirectory->Size),则需要解析转发逻辑,否则会得到错误的RVA。

  • PE对齐方式未适配
    如果读取的是磁盘上的PE文件(而非内存加载后的镜像),PE的FileAlignment和SectionAlignment不同,不能直接用RVA加文件基址访问内容。需要通过节表将RVA转换为文件偏移:文件偏移 = 节的PointerToRawData + (RVA - 节的VirtualAddress)。

内容的提问来源于stack exchange,提问作者עמית ברוניצקי

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 04:12:32