分享
 
 
 

iczelion pe tut6

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Tutorial 6: Import Table

We will learn about import table in this tutorial. Let me warn you first. This tutorial is a long and difficult one for those who aren't familiar with the import table. You may need to read this tutorial several times and may even have to examine the related structures under a debugger.

Download the example.

Theory:

First of all, you should know what an import function is. An import function is a function that is not in the caller's module but is called by the module, thus the name "import". The import functions actually reside in one or more DLLs. Only the information about the functions is kept in the caller's module. That information includes the function names and the names of the DLLs in which they reside.

Now how can we find out where in the PE file the information is kept? We must turn to the data directory for the answer. I'll refresh your memory a bit. Below is the PE header:

IMAGE_NT_HEADERS STRUCT

Signature dd ?

FileHeader IMAGE_FILE_HEADER <>

OptionalHeader IMAGE_OPTIONAL_HEADER <>

IMAGE_NT_HEADERS ENDS

The last member of the optional header is the data directory:

IMAGE_OPTIONAL_HEADER32 STRUCT

....

LoaderFlags dd ?

NumberOfRvaAndSizes dd ?

DataDirectory IMAGE_DATA_DIRECTORY 16 dup(<>)

IMAGE_OPTIONAL_HEADER32 ENDS

The data directory is an array of IMAGE_DATA_DIRECTORY structure. A total of 16 members. If you remember the section table as the root directory of the sections in a PE file, you should also think of the data directory as the root directory of the logical components stored inside those sections. To be precise, the data directory contains the locations and sizes of the important data structures in the PE file. Each member contains information about an important data structure.

Member

Info inside

0

Export symbols

1

Import symbols

2

Resources

3

Exception

4

Security

5

Base relocation

6

Debug

7

Copyright string

8

Unknown

9

Thread local storage (TLS)

10

Load configuration

11

Bound Import

12

Import Address Table

13

Delay Import

14

COM descriptor

Only the members painted in gold are known to me. Now that you know what each member of the data directory contains, we can learn about the member in detail. Each member of the data directory is a structure called IMAGE_DATA_DIRECTORY which has the following definition:

IMAGE_DATA_DIRECTORY STRUCT

VirtualAddress dd ?

isize dd ?

IMAGE_DATA_DIRECTORY ENDS

VirtualAddress is actually the relative virtual address (RVA) of the data structure. For example, if this structure is for import symbols, this field contains the RVA of the IMAGE_IMPORT_DESCRIPTOR array.

isize contains the size in bytes of the data structure referred to by VirtualAddress.

Here's the general scheme on finding important data structures in a PE file:

From the DOS header, you go to the PE header

Obtain the address of the data directory in the optional header.

Multiply the size of IMAGE_DATA_DIRECTORY with the member index you want: for example if you want to know where the import symbols are, you must multiply the size of IMAGE_DATA_DIRECTORY (8 bytes) with 1.

Add the result to the address of the data directory and you have the address of the IMAGE_DATA_DIRECTORY structure that contains the info about the desired data structure.

Now we will enter into the real discussion about the import table. The address of the import table is contained in the VirtualAddress field of the second member of the data directory. The import table is actually an array of IMAGE_IMPORT_DESCRIPTOR structures. Each structure contains information about a DLL the PE file imports symbols from. For example, if the PE file imports functions from 10 different DLLs, there will be 10 members in this array. The array is terminated by the member which contain all zeroes. Now we can examine the structure in detail:

IMAGE_IMPORT_DESCRIPTOR STRUCT

union

Characteristics dd ?

OriginalFirstThunk dd ?

ends

TimeDateStamp dd ?

ForwarderChain dd ?

Name1 dd ?

FirstThunk dd ?

IMAGE_IMPORT_DESCRIPTOR ENDS

The first member of this structure is a union. Actually, the union only provides the alias for OriginalFirstThunk, so you can call it "Characteristics". This member contains the the RVA of an array of IMAGE_THUNK_DATA structures.

What is IMAGE_THUNK_DATA? It's a union of dword size. Usually, we interpret it as the pointer to an IMAGE_IMPORT_BY_NAME structure. Note that IMAGE_THUNK_DATA contains the pointer to an IMAGE_IMPORT_BY_NAME structure: not the structure itself.

Look at it this way: There are several IMAGE_IMPORT_BY_NAME structures. We collect the RVA of those structures (IMAGE_THUNK_DATAs) into an array, terminate it with 0. Then we put the RVA of the array into OriginalFirstThunk.

The IMAGE_IMPORT_BY_NAME structure contains information about an import function. Now let's see what IMAGE_IMPORT_BY_NAME structure looks like:

IMAGE_IMPORT_BY_NAME STRUCT

Hint dw ?

Name1 db ?

IMAGE_IMPORT_BY_NAME ENDS

Hint contains the index into the export table of the DLL the function resides in. This field is for use by the PE loader so it can look up the function in the DLL's export table quickly.This value is not essential and some linkers may set the value in this field to 0.

Name1 contains the name of the import function. The name is an ASCIIZ string. Note that Name1's size is defined as byte but it's really a variable-sized field. It's just that there is no way to represent a variable-sized field in a structure. The structure is provided so that you can refer to the data structure with descriptive names.

TimeDateStamp and ForwarderChain are advanced stuff: We will talk about them after you have firm grasp of the other members.

Name1 contains the RVA to the name of the DLL, in short, the pointer to the name of the DLL. The string is an ASCIIZ one.

FirstThunk is very similar to OriginalFirstThunk, ie. it contains an RVA of an array of IMAGE_THUNK_DATA structures(a different array though).

Ok, if you're still confused, look at it this way: There are several IMAGE_IMPORT_BY_NAME structures. You create two arrays, then fill them with the RVAs of those IMAGE_IMPORT_BY_NAME structures, so both arrays contain exactly the same values (i.e. exact duplicate). Now you assign the RVA of the first array to OriginalFirstThunk and the RVA of the second array to FirstThunk.

OriginalFirstThunk

IMAGE_IMPORT_BY_NAME

FirstThunk

|

|

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

...

IMAGE_THUNK_DATA

--->

--->

--->

--->

--->

--->

Function 1

Function 2

Function 3

Function 4

...

Function n

<---

<---

<---

<---

<---

<---

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

...

IMAGE_THUNK_DATA

Now you should be able to understand what I mean. Don't be confused by the name IMAGE_THUNK_DATA: it's only an RVA into IMAGE_IMPORT_BY_NAME structure. If you replace the word IMAGE_THUNK_DATA with RVA in your mind, you'll perhaps see it more clearly. The number of array elements in OriginalFirstThunk and FirstThunk array depends on the functions the PE file imports from the DLL. For example, if the PE file imports 10 functions from kernel32.dll, Name1 in the IMAGE_IMPORT_DESCRIPTOR structure will contain the RVA of the string "kernel32.dll" and there will be 10 IMAGE_THUNK_DATAs in each array.

The next question is: why do we need two arrays that are exactly the same? To answer that question, we need to know that when the PE file is loaded into memory, the PE loader will look at the IMAGE_THUNK_DATAs and IMAGE_IMPORT_BY_NAMEs and determine the addresses of the import functions. Then it replaces the IMAGE_THUNK_DATAs in the array pointed to by FirstThunk with the real addresses of the functions. Thus when the PE file is ready to run, the above picture is changed to:

OriginalFirstThunk

IMAGE_IMPORT_BY_NAME

FirstThunk

|

|

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

...

IMAGE_THUNK_DATA

--->

--->

--->

--->

--->

--->

Function 1

Function 2

Function 3

Function 4

...

Function n

Address of Function 1

Address of Function 2

Address of Function 3

Address of Function 4

...

Address of Function n

The array of RVAs pointed to by OriginalFirstThunk remains unchanged so that if the need arises to find the names of import functions, the PE loader can still find them.

There is a little twist on this *straightforward* scheme. Some functions are exported by ordinal only. It means you don't call the functions by their names: you call them by their positions. In this case, there will be no IMAGE_IMPORT_BY_NAME structure for that function in the caller's module. Instead, the IMAGE_THUNK_DATA for that function will contain the ordinal of the function in the low word and the most significant bit (MSB) of IMAGE_THUNK_DATA set to 1. For example, if a function is exported by ordinal only and its ordinal is 1234h, the IMAGE_THUNK_DATA for that function will be 80001234h. Microsoft provides a handy constant for testing the MSB of a dword, IMAGE_ORDINAL_FLAG32. It has the value of 80000000h.

Suppose that we want to list the names of ALL import functions of a PE file, we need to follow the steps below:

Verify that the file is a valid PE

From the DOS header, go to the PE header

Obtain the address of the data directory in OptionalHeader

Go to the 2nd member of the data directory. Extract the value of VirtualAddress

Use that value to go to the first IMAGE_IMPORT_DESCRIPTOR structure

Check the value of OriginalFirstThunk. If it's not zero, follow the RVA in OriginalFirstThunk to the RVA array. If OriginalFirstThunk is zero, use the value in FirstThunk instead. Some linkers generate PE files with 0 in OriginalFirstThunk. This is considered a bug. Just to be on the safe side, we check the value in OriginalFirstThunk first.

For each member in the array, we check the value of the member against IMAGE_ORDINAL_FLAG32. If the most significant bit of the member is 1, then the function is exported by ordinal and we can extract the ordinal number from the low word of the member.

If the most significant bit of the member is 0, use the value in the member as the RVA into the IMAGE_IMPORT_BY_NAME, skip Hint, and you're at the name of the function.

Skip to the next array member, and retrieve the names until the end of the array is reached (it's null -terminated). Now we are done extracting the names of the functions imported from a DLL. We go to the next DLL.

Skip to the next IMAGE_IMPORT_DESCRIPTOR and process it. Do that until the end of the array is reached (IMAGE_IMPORT_DESCRIPTOR array is terminated by a member with all zeroes in its fields).

Example:

This example opens a PE file and reads the names of all import functions of that file into an edit control. It also shows the values in the IMAGE_IMPORT_DESCRIPTOR structures.

.386

.model flat,stdcall

option casemap:none

include \masm32\include\windows.inc

include \masm32\include\kernel32.inc

include \masm32\include\comdlg32.inc

include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib

includelib \masm32\lib\kernel32.lib

includelib \masm32\lib\comdlg32.lib

IDD_MAINDLG equ 101

IDC_EDIT equ 1000

IDM_OPEN equ 40001

IDM_EXIT equ 40003

DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD

ShowImportFunctions proto :DWORD

ShowTheFunctions proto :DWORD,:DWORD

AppendText proto :DWORD,:DWORD

SEH struct

PrevLink dd ? ; the address of the previous seh structure

CurrentHandler dd ? ; the address of the new exception handler

SafeOffset dd ? ; The offset where it's safe to continue execution

PrevEsp dd ? ; the old value in esp

PrevEbp dd ? ; The old value in ebp

SEH ends

.data

AppName db "PE tutorial no.6",0

ofn OPENFILENAME <>

FilterString db "Executable Files (*.exe, *.dll)",0,"*.exe;*.dll",0

db "All Files",0,"*.*",0,0

FileOpenError db "Cannot open the file for reading",0

FileOpenMappingError db "Cannot open the file for memory mapping",0

FileMappingError db "Cannot map the file into memory",0

NotValidPE db "This file is not a valid PE",0

CRLF db 0Dh,0Ah,0

ImportDescriptor db 0Dh,0Ah,"================[ IMAGE_IMPORT_DESCRIPTOR ]=============",0

IDTemplate db "OriginalFirstThunk = %lX",0Dh,0Ah

db "TimeDateStamp = %lX",0Dh,0Ah

db "ForwarderChain = %lX",0Dh,0Ah

db "Name = %s",0Dh,0Ah

db "FirstThunk = %lX",0

NameHeader db 0Dh,0Ah,"Hint Function",0Dh,0Ah

db "-----------------------------------------",0

NameTemplate db "%u %s",0

OrdinalTemplate db "%u (ord.)",0

.data?

buffer db 512 dup(?)

hFile dd ?

hMapping dd ?

pMapping dd ?

ValidPE dd ?

.code

start:

invoke GetModuleHandle,NULL

invoke DialogBoxParam, eax, IDD_MAINDLG,NULL,addr DlgProc, 0

invoke ExitProcess, 0

DlgProc proc hDlg:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

.if uMsg==WM_INITDIALOG

invoke SendDlgItemMessage,hDlg,IDC_EDIT,EM_SETLIMITTEXT,0,0

.elseif uMsg==WM_CLOSE

invoke EndDialog,hDlg,0

.elseif uMsg==WM_COMMAND

.if lParam==0

mov eax,wParam

.if ax==IDM_OPEN

invoke ShowImportFunctions,hDlg

.else ; IDM_EXIT

invoke SendMessage,hDlg,WM_CLOSE,0,0

.endif

.endif

.else

mov eax,FALSE

ret

.endif

mov eax,TRUE

ret

DlgProc endp

SEHHandler proc uses edx pExcept:DWORD, pFrame:DWORD, pContext:DWORD, pDispatch:DWORD

mov edx,pFrame

assume edx:ptr SEH

mov eax,pContext

assume eax:ptr CONTEXT

push [edx].SafeOffset

pop [eax].regEip

push [edx].PrevEsp

pop [eax].regEsp

push [edx].PrevEbp

pop [eax].regEbp

mov ValidPE, FALSE

mov eax,ExceptionContinueExecution

ret

SEHHandler endp

ShowImportFunctions proc uses edi hDlg:DWORD

LOCAL seh:SEH

mov ofn.lStructSize,SIZEOF

ofn mov ofn.lpstrFilter, OFFSET FilterString

mov ofn.lpstrFile, OFFSET buffer

mov ofn.nMaxFile,512

mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY

invoke GetOpenFileName, ADDR ofn

.if eax==TRUE

invoke CreateFile, addr buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL

.if eax!=INVALID_HANDLE_VALUE

mov hFile, eax

invoke CreateFileMapping, hFile, NULL, PAGE_READONLY,0,0,0

.if eax!=NULL

mov hMapping, eax

invoke MapViewOfFile,hMapping,FILE_MAP_READ,0,0,0

.if eax!=NULL

mov pMapping,eax

assume fs:nothing

push fs:[0]

pop seh.PrevLink

mov seh.CurrentHandler,offset SEHHandler

mov seh.SafeOffset,offset FinalExit

lea eax,seh

mov fs:[0], eax

mov seh.PrevEsp,esp

mov seh.PrevEbp,ebp

mov edi, pMapping

assume edi:ptr IMAGE_DOS_HEADER

.if [edi].e_magic==IMAGE_DOS_SIGNATURE

add edi, [edi].e_lfanew

assume edi:ptr IMAGE_NT_HEADERS

.if [edi].Signature==IMAGE_NT_SIGNATURE

mov ValidPE, TRUE

.else

mov ValidPE, FALSE

.endif

.else

mov ValidPE,FALSE

.endif

FinalExit:

push seh.PrevLink

pop fs:[0]

.if ValidPE==TRUE

invoke ShowTheFunctions, hDlg, edi

.else

invoke MessageBox,0, addr NotValidPE, addr AppName, MB_OK+MB_ICONERROR

.endif

invoke UnmapViewOfFile, pMapping

.else

invoke MessageBox, 0, addr FileMappingError, addr AppName, MB_OK+MB_ICONERROR

.endif

invoke CloseHandle,hMapping

.else

invoke MessageBox, 0, addr FileOpenMappingError, addr AppName, MB_OK+MB_ICONERROR

.endif

invoke CloseHandle, hFile

.else

invoke MessageBox, 0, addr FileOpenError, addr AppName, MB_OK+MB_ICONERROR

.endif

.endif

ret

ShowImportFunctions endp

AppendText proc hDlg:DWORD,pText:DWORD

invoke SendDlgItemMessage,hDlg,IDC_EDIT,EM_REPLACESEL,0,pText

invoke SendDlgItemMessage,hDlg,IDC_EDIT,EM_REPLACESEL,0,addr CRLF

invoke SendDlgItemMessage,hDlg,IDC_EDIT,EM_SETSEL,-1,0

ret

AppendText endp

RVAToOffset PROC uses edi esi edx ecx pFileMap:DWORD,RVA:DWORD

mov esi,pFileMap

assume esi:ptr IMAGE_DOS_HEADER

add esi,[esi].e_lfanew

assume esi:ptr IMAGE_NT_HEADERS

mov edi,RVA ; edi == RVA

mov edx,esi

add edx,sizeof IMAGE_NT_HEADERS

mov cx,[esi].FileHeader.NumberOfSections

movzx ecx,cx

assume edx:ptr IMAGE_SECTION_HEADER

.while ecx>0 ; check all sections

.if edi>=[edx].VirtualAddress

mov eax,[edx].VirtualAddress

add eax,[edx].SizeOfRawData

.if edi<eax ; The address is in this section

mov eax,[edx].VirtualAddress

sub edi,eax

mov eax,[edx].PointerToRawData

add eax,edi ; eax == file offset

ret

.endif

.endif

add edx,sizeof IMAGE_SECTION_HEADER

dec ecx

.endw

assume edx:nothing

assume esi:nothing

mov eax,edi

ret

RVAToOffset endp

ShowTheFunctions proc uses esi ecx ebx hDlg:DWORD, pNTHdr:DWORD

LOCAL temp[512]:BYTE

invoke SetDlgItemText,hDlg,IDC_EDIT,0

invoke AppendText,hDlg,addr buffer

mov edi,pNTHdr

assume edi:ptr IMAGE_NT_HEADERS

mov edi, [edi].OptionalHeader.DataDirectory[sizeof IMAGE_DATA_DIRECTORY].VirtualAddress

invoke RVAToOffset,pMapping,edi

mov edi,eax

add edi,pMapping

assume edi:ptr IMAGE_IMPORT_DESCRIPTOR

.while !([edi].OriginalFirstThunk==0 && [edi].TimeDateStamp==0 && [edi].ForwarderChain==0 && [edi].Name1==0 && [edi].FirstThunk==0)

invoke AppendText,hDlg,addr ImportDescriptor

invoke RVAToOffset,pMapping, [edi].Name1

mov edx,eax

add edx,pMapping

invoke wsprintf, addr temp, addr IDTemplate, [edi].OriginalFirstThunk,[edi].TimeDateStamp,[edi].ForwarderChain,edx,[edi].FirstThunk invoke AppendText,hDlg,addr temp

.if [edi].OriginalFirstThunk==0

mov esi,[edi].FirstThunk

.else

mov esi,[edi].OriginalFirstThunk

.endif

invoke RVAToOffset,pMapping,esi

add eax,pMapping

mov esi,eax

invoke AppendText,hDlg,addr NameHeader

.while dword ptr [esi]!=0

test dword ptr [esi],IMAGE_ORDINAL_FLAG32

jnz ImportByOrdinal

invoke RVAToOffset,pMapping,dword ptr [esi]

mov edx,eax

add edx,pMapping

assume edx:ptr IMAGE_IMPORT_BY_NAME

mov cx, [edx].Hint

movzx ecx,cx

invoke wsprintf,addr temp,addr NameTemplate,ecx,addr [edx].Name1

jmp ShowTheText

ImportByOrdinal:

mov edx,dword ptr [esi]

and edx,0FFFFh

invoke wsprintf,addr temp,addr OrdinalTemplate,edx

ShowTheText:

invoke AppendText,hDlg,addr temp

add esi,4

.endw

add edi,sizeof IMAGE_IMPORT_DESCRIPTOR

.endw

ret

ShowTheFunctions endp

end start

Analysis:

The program shows an open file dialog box when the user clicks Open in the menu. It verifies that the file is a valid PE and then calls ShowTheFunctions.

ShowTheFunctions proc uses esi ecx ebx hDlg:DWORD, pNTHdr:DWORD

LOCAL temp[512]:BYTE

Reserve 512 bytes of stack space for string operation.

invoke SetDlgItemText,hDlg,IDC_EDIT,0

Clear the text in the edit control

invoke AppendText,hDlg,addr buffer

Insert the name of the PE file into the edit control. AppendText just sends EM_REPLACESEL messages to append the text to the edit control. Note that it sends EM_SETSEL with wParam=-1 and lParam=0 to the edit control to move the cursor to the end of the text.

mov edi,pNTHdr

assume edi:ptr IMAGE_NT_HEADERS

mov edi, [edi].OptionalHeader.DataDirectory[sizeof IMAGE_DATA_DIRECTORY].VirtualAddress

Obtain the RVA of the import symbols. edi at first points to the PE header. We use it to go to the 2nd member of the data directory array and obtain the value of VirtualAddress member.

invoke RVAToOffset,pMapping,edi

mov edi,eax

add edi,pMapping

Here comes one of the pitfalls for newcomers to PE programming. Most of the addresses in the PE file are RVAs and RVAs are meaningful only when the PE file is loaded into memory by the PE loader. In our case, we do map the file into memory but not the way the PE loader does. Thus we cannot use those RVAs directly. Somehow we have to convert those RVAs into file offsets. I write RVAToOffset function just for this purpose. I won't analyze it in detail here. Suffice to say that it checks the submitted RVA against the starting-ending RVAs of all sections in the PE file and use the value in PointerToRawData field in the IMAGE_SECTION_HEADER structure to convert the RVA to file offset.

To use this function, you pass it two parameters: the pointer to the memory mapped file and the RVA you want to convert. It returns the file offset in eax. In the above snippet, we must add the pointer to the memory mapped file to the file offset to convert it to virtual address. Seems complicated, huh? :)

assume edi:ptr IMAGE_IMPORT_DESCRIPTOR

.while !([edi].OriginalFirstThunk==0 && [edi].TimeDateStamp==0 && [edi].ForwarderChain==0 && [edi].Name1==0 && [edi].FirstThunk==0)

edi now points to the first IMAGE_IMPORT_DESCRIPTOR structure. We will walk the array until we find the structure with zeroes in all members which denotes the end of the array.

invoke AppendText,hDlg,addr ImportDescriptor

invoke RVAToOffset,pMapping, [edi].Name1

mov edx,eax

add edx,pMapping

We want to display the values of the current IMAGE_IMPORT_DESCRIPTOR structure in the edit control. Name1 is different from the other members since it contains the RVA to the name of the dll. Thus we must convert it to a virtual address first.

invoke wsprintf, addr temp, addr IDTemplate, [edi].OriginalFirstThunk,[edi].TimeDateStamp,[edi].ForwarderChain,edx,[edi].FirstThunk invoke AppendText,hDlg,addr temp

Display the values of the current IMAGE_IMPORT_DESCRIPTOR.

.if [edi].OriginalFirstThunk==0

mov esi,[edi].FirstThunk

.else

mov esi,[edi].OriginalFirstThunk

.endif

Next we prepare to walk the IMAGE_THUNK_DATA array. Normally we would choose to use the array pointed to by OriginalFirstThunk. However, some linkers errornously put 0 in OriginalFirstThunk thus we must check first if the value of OriginalFirstThunk is zero. If it is, we use the array pointed to by FirstThunk instead.

invoke RVAToOffset,pMapping,esi

add eax,pMapping

mov esi,eax

Again, the value in OriginalFirstThunk/FirstThunk is an RVA. We must convert it to virtual address.

invoke AppendText,hDlg,addr NameHeader

.while dword ptr [esi]!=0

Now we are ready to walk the array of IMAGE_THUNK_DATAs to look for the names of the functions imported from this DLL. We will walk the array until we find an entry which contains 0.

test dword ptr [esi],IMAGE_ORDINAL_FLAG32

jnz ImportByOrdinal

The first thing we do with the IMAGE_THUNK_DATA is to test it against IMAGE_ORDINAL_FLAG32. This test checks if the most significant bit of the IMAGE_THUNK_DATA is 1. If it is, the function is exported by ordinal so we have no need to process it further. We can extract its ordinal from the low word of the IMAGE_THUNK_DATA and go on with the next IMAGE_THUNK_DATA dword.

invoke RVAToOffset,pMapping,dword ptr [esi]

mov edx,eax

add edx,pMapping

assume edx:ptr IMAGE_IMPORT_BY_NAME

If the MSB of the IAMGE_THUNK_DATA is 0, it contains the RVA of IMAGE_IMPORT_BY_NAME structure. We need to convert it to virtual address first.

mov cx, [edx].Hint

movzx ecx,cx

invoke wsprintf,addr temp,addr NameTemplate,ecx,addr [edx].Name1

jmp ShowTheText

Hint is a word-sized field. We must convert it to a dword-sized value before submitting it to wsprintf. And we print both the hint and the function name in the edit control

ImportByOrdinal:

mov edx,dword ptr [esi]

and edx,0FFFFh

invoke wsprintf,addr temp,addr OrdinalTemplate,edx

In the case the function is exported by ordinal only, we zero out the high word and display the ordinal.

ShowTheText:

invoke AppendText,hDlg,addr temp

add esi,4

After inserting the function name/ordinal into the edit control, we skip to the next IMAGE_THUNK_DATA.

.endw

add edi,sizeof IMAGE_IMPORT_DESCRIPTOR

When all IMAGE_THUNK_DATA dwords in the array are processed, we skip to the next IMAGE_IMPORT_DESCRIPTOR to process the import functions from other DLLs.

Appendix:

It would be incomplete if I don't mention something about bound import. In order to explain what it is, I need to digress a bit. When the PE loader loads a PE file into memory, it examines the import table and loads the required DLLs into the process address space. Then it walks the IMAGE_THUNK_DATA array much like we did and replaces the IMAGE_THUNK_DATAs with the real addresses of the import functions. This step takes time. If somehow the programmer can predict the addresses of the functions correctly, the PE loader doesn't have to fix the IMAGE_THUNK_DATAs each time the PE file is run. Bound import is the product of that idea.

To put it in simple terms, there is a utility named bind.exe that comes with Microsoft compilers such as Visual Studio that examines the import table of a PE file and replaces the IMAGE_THUNK_DATA dwords with the addresses of the import functions.When the file is loaded, the PE loader must check if the addresses are valid. If the DLL versions do not match the ones in the PE files or if the DLLs need to be relocated, the PE loader knows that the precomputed addresses are not valid thus it must walk the array pointed to by OriginalFirstThunk to calculate the new addresses of import functions.

Bound import doesn't have much significance in our example because we use OriginalFirstThunk by default. For more information about the bound import, I recommmend LUEVELSMEYER's pe.txt.

[Iczelion's Win32 Assembly Homepage]

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有