Dan*_*Dan 5 c format portable-executable
我正在尝试为Windows编写一个exe包装器.到目前为止,我已经掌握了一些基础知识.我要做的部分是阅读"BOUND IMPORT目录表"(或.idata部分?),基本上是PE文件的一部分,其中包含加载程序需要导入的DLL列表.
我想知道最好的方法是:
[A]找出IAT的位置(因为运行PEView对几个不同的.exe似乎表明这个列表可以包含在多个不同的地方)然后读取列表
要么
[B]找到一种直接读取exe需要导入的DLL列表的方法.
有办法做到这一点吗?有没有进一步阅读的人可以推荐IAT应该在哪里以及如何阅读它?
另外,这是一个pdf,可以帮助您了解结构的命名和组织方式.一些有用的程序:CFF Explorer和一个好的十六进制编辑器.
我的回答与上述不同之处在于它描述了一种在磁盘上仍然可执行的内容中手动执行上述操作的方法.
要获取IAT的相对虚拟地址(运行时的地址,即RVA):
IMAGE_DOS_HEADER结构.e_lfanew字段进入IMAGE_NT_HEADERS结构.
从偏移0开始,向下跳转0x3c并取消引用以获得IMAGE_NT_HEADERS的开始. OptionalHeader(由IMAGE_NT_HEADERS包含,因此连续).要获得IMAGE_OPTIONAL_HEADER结构(尽管它的名称,它不再是可选的),知道它是IMAGE_NT_HEADER中的第三个结构.
要访问OptionalHeader,请将0x18添加到之前取消引用的值如果要遍历DLL的列表及其功能地址,有一些背景知识:
磁盘上指定的RVA不允许您遍历文件,因为RVA表示二进制文件加载到内存时的地址; 要遍历磁盘上的二进制文件,您需要将RVA值转换为正确的形式.公式很简单; HMODULE + RVA = PE元素的线性地址.HMODULE也称为基地址.但是获取基地址实际上需要一个有点冗长的算法,并且取决于您所讨论的RVA的值实际上是什么.要获取给定RVA的基址的值,以便计算磁盘上PE元素的线性地址:
获取sectionHeader; 为此,请浏览部分列表(例如.data,.text,ect),直到找到问题的RVA在currentSection.VirtualAddress和currentSection.VirtualAddress + currentSection.size中的部分.
1.1)首先,在NT_HEADERS结构中找到FileHeader中的节数.它是FileHeader中2字节Machine number之后的2个字节.*要手动执行此操作:将0x6添加到e_lfanew取消引用的值; 所以从0的偏移量跳转0x3c,取消引用该值,然后将0x6取消引用.然后读取两个字节并解释为整数.
1.2)找到第一部分的位置; 它与OptionalHeader相邻.请记住,OptionalHeader中的DataDirectories数组.OptionalHeader长216个字节,加上结尾的2个字表示它的结束; 所以取十六进制的224(0xe0)并将其添加到从开始的0x3c处取消引用的值以获得第一个部分位置.
1.3)要查找RVA所在的部分标题,请继续针对您当前的部分执行此测试.如果测试失败,请转到下一部分.如果您遍历所有部分并发现您到达结束的NULL字,那么该文件应该已损坏或您犯了错误.测试如下:将要转换的RVA与指向该部分虚拟地址的可用指针进行比较; RVA应该> =到该部分的虚拟地址,并且<该部分的虚拟地址和虚拟大小的总和.通过将12添加到该部分的地址,可以找到该部分的虚拟地址.该部分的虚拟大小可以通过8到该部分的地址找到.总结一下:传递if - (section.virtualAddress + section.virtualSize)> RVA> = section.其VirtualAddress.*要迭代到下一节,节描述的长度为0x28; 您只需将0x28添加到当前节指针即可转到下一个指针.最后一节是一个空字节来表示结束.
从获得的节头中,执行以下操作:(baseAddress + RVA) - (sectionHeader.virtualAddress - sectionhHeader.PointerToRawData).*如上所述,sectionHeader的virtualAddress与sectionHeader本身相距12个字节.PointerToRawData距离节标题20.
那是满口的.如果你想回顾一下,你应该阅读Rootkit Arsenal中第5章(挂钩呼叫表)的第257-60页,但是为了更容易理解的图形,请查看我在顶部附近给出的openrce.org pdf链接.
要做到这一点,然而从......开始:
使用上述算法,将导入目录的RVA转换为可用指针,并使用以下算法迭代导入目录数组.
4.1)对于importDescriptor,将名称字段RVA转换为指针以获取名称.它可能是null
4.2)要获取导入的每个例程的名称和地址,请获取导入描述符的OriginalFirstThunk和FirstThunk RVA条目.每个OFT和FT都可以为null,这表示它是空的,所以检查一下.
4.3)将OFT RVA转换为指针; OFT对应于ILT,FT对应于IAT.ILT和IAT可以为空,表示它们是空的.
4.4)获取从ILT指针导入的函数的名称,以及IAT指针中函数的地址.要移动到下一个导入的函数,请记住ILT和IAT是数组; 下一个元素是一个恒定的距离.
4.5)检查获得的新ILT和IAT指针值是否为零; 如果它们不为零,重复一遍.如果其中任何一个为零,则您已经点击为该dll导入的函数列表的末尾; 导入描述符也是一个重复数组,因此导入的下一个dll的偏移量是常量.基本上,您正在迭代dll,并且对于每个dll,您正在迭代以这种方式导入的函数.19
是的,您可以通过浏览可执行文件的标头来找到 IAT。在看winnt.h标题声明。
有关如何找到头信息的绝佳击穿,见马特·皮特里克的串联MSDN杂志“在深入查找到的Win32可移植可执行文件格式”,零件我和II。
您还可以从此处获取实际的 Microsoft PE 规范。
TL;DR:基本上查找的顺序如下:
IMAGE_DOS_HEADER结构。e_lfanew字段到达IMAGE_NT_HEADERS结构。OptionalHeader到达IMAGE_OPTIONAL_HEADER结构(尽管它的名字,它不再是可选)。DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]数组IMAGE_IMPORT_DESCRIPTOR。每个导入的 DLL 有一个条目。此数组中的最后一个条目将被清零。Name每个条目中的字段是一个指向 DLL 名称的 RVA。该FirstThunk字段是一个指向该 DLL 的 IAT 的 RVA,它是一个IMAGE_THUNK_DATA结构数组。| 归档时间: |
|
| 查看次数: |
2879 次 |
| 最近记录: |