【问题标题】:PIMAGE_EXPORT_DIRECTORY - Memory Access ErrorPIMAGE_EXPORT_DIRECTORY - 内存访问错误
【发布时间】:2014-10-28 18:58:11
【问题描述】:

我正在尝试在 kernel32.dll 中找到 loadlibrary 的 RVA。我已经阅读了一些关于解析 PE 标头的文档,但我似乎无法找出为什么我指向导出目录的指针似乎无效。

hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        err = GetLastError();
        return err;
    }

    hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if (hFileMapping == 0)
    {
        err = GetLastError();
        CloseHandle(fileName);
        return err;
    }

    lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
    if (lpFileBase == 0)
    {
        err = GetLastError();
        CloseHandle(fileName);
        CloseHandle(hFileMapping);
        return err;
    }

    dosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
    pNTHeader = (PIMAGE_NT_HEADERS)((BYTE*)dosHeader + dosHeader->e_lfanew);
    base = (DWORD64)dosHeader;

我在这里打开文件,一切似乎都很好,当我用调试器运行这里时。

    exportsStartRVA = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    exportsEndRVA = exportsStartRVA + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;

这里我成功访问了DataDirectory,得到了Export Directory的VirtualAddress和Size。

PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned i;
for (i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++)
{
    // Is the RVA within this section?
    if ((exportsStartRVA >= section->VirtualAddress) &&
        (exportsStartRVA < (section->VirtualAddress + section->Misc.VirtualSize)))
        break;
}

我遍历所有部分,直到获得包含 exportStartRVA 的部分标题。现在“section”指针指向导出目录的Section Header。

exportDir = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)base + exportsStartRVA + section->PointerToRawData - section->VirtualAddress);

这里我得到一个指向导出目录的指针。

PDWORD pfunctions = (PDWORD)((PBYTE)base + (DWORD64)exportDir->AddressOfFunctions + header->PointerToRawData - header->VirtualAddress);
PDWORD ordinals = (PDWORD)((PBYTE)base + (DWORD64)exportDir->AddressOfNameOrdinals + header->PointerToRawData - header->VirtualAddress);
PSTR* name = (PSTR*)((PBYTE)base + (DWORD64)exportDir->AddressOfNames + header->PointerToRawData - header->VirtualAddress);
PSTR funcName;

for (unsigned i = 0; i < (DWORD64)exportDir->NumberOfNames; i++)
{
    funcName = name[i];
}

编辑:我认为问题在于我的取消引用,funcName 实际上除了内存访问错误之外没有给我任何东西。

【问题讨论】:

  • 不管怎样,乍一看,你的逻辑对我来说还不错。您是否尝试过取消引用导出目录中的任何指针以查看是否可以将您带到看起来有效的任何地方?
  • 我在上面添加了一段代码。 funcName 始终是“地址处的内存读取错误”。我想我的取消引用可能有问题。我只是假设 exportDir 是错误的,因为 WinDBG 给了我“内存访问错误”
  • 是的,指向 ExportDir 的指针有效,它只是不会从内存访问错误更新,直到我真正从中读取我的错误。所以问题在于我的取消引用。我会更新这个。

标签: c++ windows portable-executable


【解决方案1】:

AddressOfNames 是 RVA 到字符串名称列表的 RVA,而不是字符串列表的 RVA。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-30
    • 2016-02-26
    相关资源
    最近更新 更多