PE装载机的搬迁

时间:2017-08-07 15:50:41

标签: c windows portable-executable

我正在尝试让PE加载器更多地了解Portable Executables。我坚持的是IAT的处理。我无法理解这段代码的作用。

PIMAGE_THUNK_DATA nameRef = (PIMAGE_THUNK_DATA)((DWORD_PTR)dwMapBase + pImportDesc->Characteristics);
    PIMAGE_THUNK_DATA symbolRef = (PIMAGE_THUNK_DATA)((DWORD_PTR)dwMapBase + pImportDesc->FirstThunk);
    for (; nameRef->u1.AddressOfData; nameRef++, symbolRef++)
    {
        if (nameRef->u1.AddressOfData & 0x80000000)
        {
            symbolRef->u1.AddressOfData = (DWORD)GetProcAddress(hMod, MAKEINTRESOURCE(nameRef->u1.AddressOfData));
        }
        else
        {
            pImportName = (PIMAGE_IMPORT_BY_NAME)(dwMapBase + nameRef->u1.AddressOfData);
            symbolRef->u1.Function = (DWORD)GetProcAddress(hMod, (LPCSTR)pImportName->Name);
        }
    }

我知道虽然Characteristics我们确定了授予页面READ, WRITEEXECUTE权限的部分,但这里没有发生任何类似的事情。通过使用一些已经存在的代码,我编写了一个PE加载器,但没有错误,可执行文件没有加载。只是向正确的方向暗示就足够了。感谢。

可在此处找到PS代码https://pastebin.com/0ZEn0i8k

2 个答案:

答案 0 :(得分:2)

您放置的那段代码恰好只有一个目标:解析导入表,因此每次调用外部函数都可以使用该导入函数的实际地址。您可以查看此页面以获取更多技术信息:https://msdn.microsoft.com/en-us/library/ms809762.aspx

  

DWORD特征

     

有一次,这可能是一组标志。但是,微软改变了它的含义,从不打扰更新WINNT.H。该字段实际上是指针数组的偏移量(RVA)。这些指针中的每一个都指向IMAGE_IMPORT_BY_NAME结构。

因此,您的代码段会将一个指向导入记录数组的指针作为 nameRef 变量。然后,每个导入可以是一种可能的模式:

  1. 按功能序号导入:这是“if”发生的地方。由于用户代码从未映射到如此高的区域,因此,常数总是与0x8000000组合。所以,那个“八大”只是说“这不是一个地址!”。
  2. 按功能名称导入:这是“其他”分支。 “big 8”下面的任何非零 AddressOfData 都指向ASCII-Z字符串。
  3. 零 - 这是导入结束表,虚拟记录。
  4. 在两个非零情况下,GetProcAddress都应解析导入(按序号或按名称)到内存中的实际地址。

答案 1 :(得分:-1)

如果您查找IMAGE_IMPORT_DESCRIPTOR定义,则可以查看CharacteristicsOriginalFirstThunk共享联盟。所以真正的代码可以写成

PIMAGE_THUNK_DATA nameRef = (PIMAGE_THUNK_DATA)
((DWORD_PTR)dwMapBase + pImportDesc->OriginalFirstThunk);
这将是同样的效果。不过这个

(DWORD)GetProcAddress 不会引起任何问题吗?