PE文件格式--------------导入表和IAT
pe文件导入表
1)提取导入表:在数据目录的中,索引为1的位置;
导入表起始RVA地址:IMAGE_NT_HEADER.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
导入表大小:IMAGE_NT_HEADER.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualSize
2)导入表结构:一个导入库对应下面的一个结构,pe文件引用了几个导入库文件就有几个这样的结构,最后以全0值结构结束。当pe在磁盘中时,结构中的两个域OriginalFirstThunk和FirstThunk都指向IMAGE_THUNK_DATA,当pe加载准备运行时,前者仍然指向IMAGE_THUNK_DATA,后者则有装载器修改为指向导入函数实际地址。
IMAGE_IMPORT_DESCRIPTOR struc
+00h OriginalFirstThunk: dd ;存放RVA,该RVA指向一个IMAGE_THUNK_DATA结构数组,该数组占4字节,以全0值结尾
+04h DateTimeStamp: dd
+08h ForwarderChain: dd
+0ch Name1: dd ;存放RVA,该RVA指向dll名字,该名字已0结尾
+10h FirstThunk: dd ;存放RVA,该RVA指向一个IMAGE_THUNK_DATA结构数组,该数组占4字节,以全0值结尾
IMAGE_IMPORT_DESCRIPTOR ends
IMAGE_THUNK_DATA struc
union
{
ForwarderString: dd
Function: dd
Ordinal: dd ;序号
AddressOfData: dd ;指向IMAGE_IMPORT_BY_NAME
}
IMAGE_THUNK_DATA ends
IMAGE_IMPORT_BY_NAME struc
Hint: dw ;函数序号,但有的编译器不用此域
Name1: db ;函数名称,以0结尾
IMAGE_IMPORT_BY_NAME ends
3)IAT导入地址表
pe装载后,导入表的第0项的FirstThunk指向的RVA,即为导入地址表的起始位置。
另一种更便捷的导入表提取方法是:数据目录的IMAGE_DIRECTORY_ENTRY_IAT
4)导入表图解
pe文件加载前
![](https://pic002.cnblogs.com/images/2012/402103/2012042810282037.jpg)
RvaToOffset.asm
;======================
;将RVA转化为pe文件偏移
;by 紫陌
;======================
_RvaToOffset proc _lpImageBase, _lpRva
local @offsetFile
pushad
xor eax, eax
mov @offsetFile, eax
;*******************
;判断是否为pe文件
;*******************
mov edi, _lpImageBase
assume edi:ptr IMAGE_DOS_HEADER
.if [edi].e_magic != IMAGE_DOS_SIGNATURE
xor eax, eax
jmp _overpos
.endif
add edi, [edi].e_lfanew
assume edi:ptr IMAGE_NT_HEADERS
.if [edi].Signature != IMAGE_NT_SIGNATURE
xor eax, eax
jmp _overpos
.endif
;*********************
;edi指向节表
;*********************
movzx ecx, [edi].FileHeader.NumberOfSections
movzx ebx, [edi].FileHeader.SizeOfOptionalHeader
add edi, 4
add edi, sizeof IMAGE_FILE_HEADER
add edi, ebx
assume edi:ptr IMAGE_SECTION_HEADER
mov ebx, _lpRva
.while ecx
mov edx, [edi].VirtualAddress
add edx, [edi].Misc.VirtualSize
.if ebx >= [edi].VirtualAddress && ebx <= edx
sub ebx, [edi].VirtualAddress
mov eax, [edi].PointerToRawData
add eax, ebx
mov @offsetFile, eax
jmp _overpos
.endif
add edi, sizeof IMAGE_SECTION_HEADER
dec ecx
.endw
_overpos:
assume edi:nothing
popad
mov eax, @offsetFile
ret
_RvaToOffset endp
processpefile_import.asm
;=====================
;处理pe文件导入表
;by 紫陌
;=====================
;=====================
;数据段
;=====================
.const
szTitleImportTable db 'Import Descriptor (%08X)', 0dh, 0ah, 0
szImportDescriptor db 0dh, 0ah, '*****************ImportDescriptor************************', 0dh ,0ah
db 'OriginalFirstThunk (%08X):%08X', 0dh, 0ah
db 'TimeDateStamp (%08X):%08X', 0dh, 0ah
db 'ForwarderChain (%08X):%08X', 0dh, 0ah
db 'Name1 (%08X):%08X->%s', 0dh, 0ah
db 'FirstThunk (%08X):%08X', 0dh, 0ah, 0
szTitleOrignialFirstThunk db '-----------------OriginalFirstThunk-------------------------', 0dh ,0ah, 0
szThunkData db 'Addresss or Order (%08X):%08X', 0dh, 0ah, 0
szImportByName db ' -->ImportByName (%08X):%04X %s', 0dh ,0ah, 0
szTitleFirstThunk db '-------------------FirstThunk-------------------------', 0dh ,0ah, 0
;=====================
;代码段
;=====================
.code
_ProcessPeFile_Import proc _lpImageBase
local @szBuf[512]:BYTE
local @szDllName:DWORD
local @ThunkFlag:BYTE
pushad
;**********************
;edi指向导入表
;**********************
mov edi, _lpImageBase
assume edi:ptr IMAGE_DOS_HEADER
add edi, [edi].e_lfanew
assume edi:ptr IMAGE_NT_HEADERS
mov eax, [edi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT * sizeof IMAGE_DATA_DIRECTORY].VirtualAddress
invoke _RvaToOffset, _lpImageBase, eax
mov edi, eax
add edi, _lpImageBase
assume edi:ptr IMAGE_IMPORT_DESCRIPTOR
invoke RtlZeroMemory, addr szShowMsg, sizeof szShowMsg
;***********************
;输出导入表首地址
;***********************
invoke wsprintf, addr @szBuf, addr szTitleImportTable, edi
invoke lstrcpy, addr szShowMsg, addr @szBuf
;***********************
;循环输出IMAGE_IMPORT_DESCRIPTOR
;***********************
.while !(([edi].OriginalFirstThunk == 0) && ([edi].TimeDateStamp == 0) && ([edi].ForwarderChain == 0) && ([edi].Name1 == 0) && ([edi].FirstThunk == 0))
invoke _RvaToOffset, _lpImageBase, [edi].Name1
add eax, _lpImageBase
mov @szDllName, eax
invoke wsprintf, addr @szBuf, addr szImportDescriptor, \
addr [edi].OriginalFirstThunk, [edi].OriginalFirstThunk, \
addr [edi].TimeDateStamp, [edi].TimeDateStamp, \
addr [edi].ForwarderChain, [edi].ForwarderChain, \
addr [edi].Name1, [edi].Name1, @szDllName, \
addr [edi].FirstThunk, [edi].FirstThunk
invoke lstrcat, addr szShowMsg, addr @szBuf
invoke SetWindowText, hRichEdit, addr szShowMsg
;***************************
;根据OriginalFirstThunk循环输出IMAGE_THUNK_DATA和IMAGE_IMPORT_BY_NAME
;***************************
invoke lstrcat, addr szShowMsg, addr szTitleOrignialFirstThunk
mov @ThunkFlag, 0
invoke _RvaToOffset, _lpImageBase, [edi].OriginalFirstThunk
add eax, _lpImageBase
mov esi, eax
_OriginalFirstThunk:
.while (DWORD ptr [esi]) != 0
invoke wsprintf, addr @szBuf, addr szThunkData, \
esi, \
DWORD ptr [esi]
invoke lstrcat, addr szShowMsg, addr @szBuf
mov eax, [esi]
test eax, 80000000h
jnz @F
invoke _RvaToOffset, _lpImageBase, eax
add eax, _lpImageBase
mov ebx, eax
add ebx, 2
movzx ecx, WORD ptr [eax]
invoke wsprintf, addr @szBuf, addr szImportByName, \
eax, \
ecx, \
ebx
invoke lstrcat, addr szShowMsg, addr @szBuf
@@:
add esi, 4
invoke SetWindowText, hRichEdit, addr szShowMsg
.endw
.if @ThunkFlag == 1
jmp _continuewhile
.endif
;***************************
;根据FirstThunk循环输出IMAGE_THUNK_DATA和IMAGE_IMPORT_BY_NAME
;***************************
invoke lstrcat, addr szShowMsg, addr szTitleFirstThunk
mov @ThunkFlag, 1
invoke _RvaToOffset, _lpImageBase, [edi].FirstThunk
add eax, _lpImageBase
mov esi, eax
jmp _OriginalFirstThunk
_continuewhile:
add edi, sizeof IMAGE_IMPORT_DESCRIPTOR
.endw
assume edi:nothing
popad
ret
_ProcessPeFile_Import endp
_ProcessPeFile_IAT proc _lpImageBase
local @szBuf[512]:BYTE
local @NumOfIAT
pushad
;********************
;edi指向IAT表
;********************
mov edi, _lpImageBase
assume edi:ptr IMAGE_DOS_HEADER
add edi, [edi].e_lfanew
assume edi:ptr IMAGE_NT_HEADERS
mov eax, [edi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT * sizeof IMAGE_DATA_DIRECTORY].VirtualAddress
invoke _RvaToOffset, _lpImageBase, eax
add eax, _lpImageBase
mov ecx, [edi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT * sizeof IMAGE_DATA_DIRECTORY].isize
shr ecx, 2
mov @NumOfIAT, ecx
mov edi, eax
assume edi:ptr IMAGE_THUNK_DATA
invoke lstrcat, addr szShowMsg, addr szTitleIAT
mov ecx, @NumOfIAT
.while ecx
mov @NumOfIAT, ecx
invoke wsprintf, addr @szBuf, addr szIAT, \
edi, \
[edi].u1.AddressOfData
invoke lstrcat, addr szShowMsg, addr @szBuf
mov ecx, @NumOfIAT
add edi, 4
dec ecx
.endw
invoke SetWindowText, hRichEdit, addr szShowMsg
assume edi:nothing
popad
ret
_ProcessPeFile_IAT endp