如何在64位DLL中查找导出函数的地址?

时间:2013-12-10 22:48:56

标签: c++ windows dll 32bit-64bit reverse-engineering

我正在分析32位和64位DLL。我想找出导出函数的地址是什么。我已经处理过32位DLL,但相同的代码不适用于64位模块。

    DWORD address = (*module)->getImageBaseAddress();
    DWORD headerAddress = address + ((PIMAGE_DOS_HEADER)address)->e_lfanew;
    PIMAGE_NT_HEADERS header = (PIMAGE_NT_HEADERS)headerAddress;
    PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY)(address + header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    PVOID names = (BYTE *)address + exports->AddressOfNames;
    PVOID moduleFunctions = (BYTE *)address + exports->AddressOfFunctions;
    std::cout << "Characteristics: " << exports->Characteristics << endl;
    std::cout << "TimeDateStamp: " << exports->TimeDateStamp << endl;
    std::cout << "Major version: " << exports->MajorVersion << endl;
    std::cout << "Minor version: " << exports->MinorVersion << endl;
    std::cout << "Name: " << exports->Name << endl;
    std::cout << "Base: " << exports->Base << endl;
    std::cout << "Number of fun: " << exports->NumberOfFunctions << endl;
    std::cout << "Number of names: " << exports->NumberOfNames << endl;

    for (int i = 0; i < exports->NumberOfFunctions; i++) {
        std::cout << std::string((char*)((BYTE *)address + ((DWORD *)names)[i])) << " @ " << ((DWORD *)moduleFunctions)[i] << endl;
    }

第一个输出行看起来很好(TimeDateStamp具有正确的值,函数名称已正确解析等)。不幸的是,当我将函数的图像基础偏移与IDA在DLL文件分析后给出的偏移进行比较后,结果会有所不同。例如。对于第一个模块,我得到的偏移量等于11d0b,因为IDA没有有效的指令从这个地址开始(imageBase + 0x11d0b)。

我在64位DLL中获取函数地址的方法是否正确?为什么我会得到不同的结果?为什么32位模块的一切正常?

1 个答案:

答案 0 :(得分:5)

如果您使用64位二进制文​​件,则optional header结构的大小不同。请查看PE COFF spec以获取官方参考资料。

您需要在可选标题(第一个字段)中键入“Magic Number”,以确定要使用的结构格式。

编辑:添加显示选择正确标题格式的代码段:

char* address = (*module)->getImageBaseAddress();
char* headerAddress = address + ((PIMAGE_DOS_HEADER)address)->e_lfanew;
PIMAGE_NT_HEADERS32 header32 = (PIMAGE_NT_HEADERS32)headerAddress;
PIMAGE_NT_HEADERS64 header64 = (PIMAGE_NT_HEADERS64)headerAddress;
PIMAGE_EXPORT_DIRECTORY exports = NULL;

if (header32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) // PE32
    exports = (PIMAGE_EXPORT_DIRECTORY)(address + header32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
else if (header32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) // PE32+
    exports = (PIMAGE_EXPORT_DIRECTORY)(address + header64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
else
    return 0;

另请注意,如果您尝试从文件手动加载的图像(例如文件的原始映射)执行此操作,则需要通过查找内存中的内存地址将RVA转换为文件偏移量。部分列表以标识文件指针位置。