pDOSHeader = ctypes.cast(hModule, ctypes.POINTER(IMAGE_DOS_HEADER)).contents
e_lfanew_offset = pDOSHeader.e_lfanew
offset_to_NTHeaders = e_lfanew_offset + hModule
pNTHeaders = ctypes.cast(offset_to_NTHeaders,ctypes.POINTER(IMAGE_NT_HEADERS)).contents
pImage_NT_Headers = pNTHeaders.OptionalHeader
pDataDirectory = pImage_NT_Headers.DataDirectory
pDataDirectory_IAT = pDataDirectory[13]
#1 楼
不要依靠PE数据目录中的IAT条目来准确。找到IAT的唯一真正准确的方法是找到从反汇编代码到静态导入的API函数的实际调用。以IDA中的以下代码为例:
FF 15 44 60 03 01 call ds:GetVersion
FF 15 44 60 03 01
的实际拆卸是call dword ptr ds:[1036044h]
,但是IDA知道这指向GetVersion()
,因此它显示的是“漂亮”的拆卸。在此示例中,地址1036044h
实际上是kernel32.dll的IAT中GetVersion()
条目的虚拟地址。这样,您现在可以在虚拟地址1036044h
附近的内存中查找“向上”和“向下”,以查找kernel32.dll的IAT的开始和结束。99%的时间中,所有IAT将在内存中背对背,因此您应该能够只知道一个IAT条目地址就能找到所有IAT。因为如果反汇编的代码已经打包,则依赖于PE导入表将失败,而上述方法将适用于打包和非打包的样本。
#2 楼
注意:仅当从磁盘读取PE时适用。如果使用pefile
而不是Python ctypes
,则可以简化代码。这是获取某些API名称的十六进制地址的快速脚本。 import pefile
try:
pe = pefile.PE(f)
except:
print 'could not load file...exiting'
return
ep = pe.OPTIONAL_HEADER.AddressOfEntryPoint
ep_ava = ep+pe.OPTIONAL_HEADER.ImageBase
API_addr = None
for entry in pe.DIRECTORY_ENTRY_IMPORT:
for imp in entry.imports:
if 'SOME_API' in imp.name:
API_addr = hex(imp.address).lower()
如果对
pefile
有疑问,请查看用法示例。
评论
如果反汇编的代码已经打包,则将失败。查找由代码本身生成的IAT引用更加可靠。
–詹森·格夫纳(Jason Geffner)
13 Sep 26 '21:54
@JasonGeffner你是对的,我没有意识到他指的是内存句柄。也许下次用户在此处提出问题时,他将添加更多详细信息,例如其他问题...stackoverflow.com/questions/19018906/…
– alexanderh
2013年9月26日23:00