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文件加载前

 

 
pe文件加载后
 
4)主要代码:
 

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

原文地址:https://www.cnblogs.com/guanlaiy/p/2474504.html