2017-05-31 66 views
1

您好我正在尝试在python脚本中创建一个导入表格构建器,就像MacT的Import Reconstructor一样。如何解决来自PE上IAT的转发API?

但是我很难找到从转发的API获取原始API信息的方法。例如,我从IAT得到了一个“ntdll!RtlDecodePointer”,但它是从“kernel32!DecodePointer”转发的,我没有任何想法可以找到它。

我是否需要搜索导入目录中的每个加载模块的ForwarderChain?

回答

0

不,ForwarderChain in Import directory与此无关。

当装载机决心kernel32.DecodePointer一些PE进口 - 它认为,这点有些地址IMAGE_EXPORT_DIRECTORYKERNEL32.DLL的 - 这就是所谓的转出口。装载机在这种情况下明白kernel32.DecodePointer点不是代码,而是在格式字符串somedll.somefunction或形式somedll.#someordinal作为结果装载机是尽量负载somedll并通过名称或搜索somefunctionsomeordinal按顺序。这个搜索如何查看can(以及在向前输出的情况下)递归。它停了,当我们终于得到函数地址不在里面IMAGE_EXPORT_DIRECTORY - 这个地址,将存储在IAT或进程失败 - 我们没有找到dll /或在此dll导出。

注意,这里deliminator(DLL功能名之间 - 不!.)有趣的问题 - 什么是如果包含.在自己的名字somedll - 说my.x64.dll。老版本的窗口不正确的进程名是这样的(my.x64.dll.somefunc),因为它在搜索字符串第一.通过strchr - 因此将搜索x64.dll.somefuncmy DLL和失败。但现在这是固定的 - 装载机使用strrchr - 他搜索字符串中的最后.

为每年因此我们不能扩展指定全DLL名称 -

#pragma comment(linker, "/export:fn=kernel32.dll.DecodePointer"); 
GetProcAddress((HMODULE)&__ImageBase, "fn"); 

不能说在XP。但现在 - 确切地说win10,可能是win8.1(需要检查),这是正确的,将是工作 - xp将搜索dll.DecodePointerkernel32而win10搜索DecodePointerkernel32.dll。也从这里指出,如果没有.dll扩展名,现在我们不能将输出转发到模块,现在 - 没有这种限制。(加载默认追加.DLL后缀对加载库名,如果不包含.它 - 所以,当呼叫LoadLibrary("my") - 实际上将被打开并装载"my.DLL",但"my.""my.x64"后缀.DLL将不追加(在名称.字符))

所以如果回到你的具体例子 - kernel32.DecodePointer指向IMAGE_EXPORT_DIRECTORYkernel32.dll。装载机阅读通过这个地址 - NTDLL.RtlDecodePointer - 调用strrchr(或strchr旧版本)在这个字符串找到.最后加载NTDLL - >NTDLL.DLL(后缀添加,因为在名称中没有.)并搜索RtlDecodePointer - 地址找到它不在IMAGE_EXPORT_DIRECTORYntdll.dll - 所以这是代码地址。这里过程已停止,地址RtlDecodePointer保存在初始PEIAT

你从自己身边需要重复装载程序步骤。但在现代操作系统中存在一个问题 - 许多字符串以API-MS-* dll名称开头。这不是真正的DLL,但The API Set Schema - 无文件和可变的方式,如何加载程序解析此名称

+0

谢谢你的解释。我想我需要学习更多关于操作原理......:' – Vanz

0

听起来像你想要区分Fowarder字符串和常规函数地址,同时解析模块的导出表的能力。

我不建议在你知道它的Forwarder字符串之前解析这个Forwarder字符串,因为有一个更简单的方法。诀窍是检查导出的函数的地址是否在导出段内存范围内。这是PE/COFF规范的“导出地址表”部分所述的官方方法。

对不起,我下面的示例代码是在C中,而不是Python,但仍应该给你这个想法。另请注意,下面的检查适用于PE32和PE64图像。

当您解析导出表时,您将已经有一个指向IMAGE_DATA_DIRECTORY导出部分的指针。从那里你可以获得一个指向IMAGE_EXPORT_DIRECTORY的指针。例如。

IMAGE_DATA_DIRECTORY* pExportEntry = pOptHeader->DataDirectory->arDataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT; 
... 
//code to convert pExportEntry->VirtualAddress into file offset and store in dwExportTableFileOffset 
... 
IMAGE_EXPORT_DIRECTORY* pExportTable = (IMAGE_EXPORT_DIRECTORY*)(ImageFileBase + dwExportTableFileOffset); 

假设你已经从pExportTable-> AddressOfFunctions检索功能的数组指针,下面的检查工作之下,无论该功能是否通过名称或oridinal出口。如果函数#i的函数地址(如下面的arFuncs [i]所示)位于导出段(您已经解析)内,则该地址指向格式为<MODULE>的Forwarder字符串。 <ExportName>,否则它是一个常规函数。

if (arFuncs[i] >= pExportEntry->VirtualAddress && arFuncs[i] < pExportEntry->VirtualAddress+pExportEntry->Size) 
{ 
    //function address is RVA to Forwarder String; e.g. NTDLL.RtlDecodePointer 
} 
else 
{ 
    //function address is RVA to actual code within current module 
} 
+0

非常感谢。你的例子对我很有帮助! – Vanz