c - 如何使用 C 转储 PE 导出函数名称?

标签 c windows winapi portable-executable

我正在尝试使用 C 解析 PE 文件。导入解析很好,但导出解析有问题。这是我为了解析导出而编写的代码:

void PrintExports(DWORD imageBase) {

// Get the export section.
PIMAGE_DOS_HEADER ptrDosHeader = (PIMAGE_DOS_HEADER)imageBase;
PIMAGE_NT_HEADERS32 ptrNtHeaders = (PIMAGE_NT_HEADERS32)(ptrDosHeader->e_lfanew + imageBase);
DWORD exportsStartRVA = ptrNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
DWORD exportsEndRVA = exportsStartRVA + ptrNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
PIMAGE_SECTION_HEADER ptrExportsHeader = GetSectionHeaderByRVA(exportsStartRVA, ptrNtHeaders);

// Check it's not null..
if (!ptrExportsHeader) 
    return;

PIMAGE_EXPORT_DIRECTORY ptrExportsDirectory = (PIMAGE_EXPORT_DIRECTORY)(imageBase + exportsStartRVA );

printf("Exports\n");
printf("    Exports.section: %s\n", ptrExportsHeader->Name);
printf("    Exports.ordinalBase: %x\n", ptrExportsDirectory->Base);
printf("    Exports.NumberOfFunctions: %x (hex)\n", ptrExportsDirectory->NumberOfFunctions);
printf("    Exports.NumberOfNames: %x (hex)\n", ptrExportsDirectory->NumberOfNames);

PDWORD ptrExportsFunctions = (PDWORD)((DWORD)ptrExportsDirectory->AddressOfFunctions + imageBase);
PDWORD ptrExportsNamesOrdinals = (PDWORD)((DWORD)ptrExportsDirectory->AddressOfNameOrdinals + imageBase);
PDWORD * ptrExportsNames = (PDWORD *)((DWORD)ptrExportsDirectory->AddressOfNames + imageBase);

printf("    Exports.functions:\n");
printf("        EntryPoint  Ordinal  Name\n");

for (int i = 0; i < ptrExportsDirectory->NumberOfFunctions; i++) {
    if (ptrExportsFunctions[i] == 0)
        continue;

    printf("        %010x  %07x", ptrExportsFunctions[i], i + ptrExportsDirectory->Base);

    if ((ptrExportsFunctions[i] >= exportsStartRVA) && (ptrExportsFunctions[i] <= exportsEndRVA))
        printf(" (forwarder -> %s)", ptrExportsFunctions[i] + imageBase);

    printf("\n");
}

return;
}

运行此代码的结果是,我获得了导出的序号和地址。当我尝试使用下面的代码获取名称时,问题就开始了(该代码应该位于“for”循环内)。发生的情况是我遇到访问冲突异常(我在本例中尝试解析的 PE 是 shell32.dll):

for (int j = 0; j < ptrExportsDirectory->NumberOfNames; j++) {
        if (ptrExportsNamesOrdinals[j] == i + ptrExportsDirectory->Base) {
            printf("  %s", ptrExportsNames[j]);
        }
    }

此外,在某些情况下(例如,如果我尝试解析的 PE 是 user32.dll),ptrExportsNamesOrdinal[j] 的值永远不可能等于 i + ptrExportsDirectory->Base。您可以看到下面的屏幕截图:

enter image description here

最佳答案

条件

(ptrExportsNamesOrdinals[j] == i + ptrExportsDirectory->Base)

用在if测试中是错误的。导出序数表实际上不包含序数,而是包含导出地址表的索引(这是 PE/COFF 规范中的错误 - 请参阅 https://stackoverflow.com/a/40001778/2646573)。

您应该使用的测试条件是

(ptrExportsNamesOrdinals[j] == i)

如示例所示:https://stackoverflow.com/a/49708023/2646573 .

关于c - 如何使用 C 转储 PE 导出函数名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57992569/

相关文章:

c - 在 C 中修剪字符串

c++ - "Catch"通过 SendMessage 方法发送的所有消息

c - 如何使用 LoadLibrary() 和 GetProcAddress() 函数将 ntdll.dll 添加到项目库中?

c - JNI 库中 OS/X 上的指针截断为 'realloc()'

无法通过 'error: missing braces around initializer'

c++ - 在 C 中使用 _EXFUN ()

c++,usleep() 已过时,Windows/MingW 的解决方法?

java - Windows 7 64位,配置2个版本的Java

c++ - 为什么这段代码被认为是可重入的?当操作系统中断线程时究竟发生了什么?

windows - 此驱动程序已被阻止加载 (Windows 2008 R2)