输入表在PE中的结构及加载过程

来源:互联网 发布:unity3d webplayer 编辑:程序博客网 时间:2024/05/29 02:22

http://hi.baidu.com/mymillet/blog/item/0c09123debead3c19f3d6249.html

输入表结构我们知道,程序调用外部的dll函数通常都是下面这种形式:
    call my_label
    ...
my_label: jmp dword ptr [xxxxxxxx]
    对一个dll中的函数的调用总是通过一个地址间接的调用的.这些地址就放在输入表里(所以如果你改动了输入表, 可能也需要改my_label: jmp dword ptr [xxxxxxxx]).
    
    输入表(Import Table),简而言之,就是描述该pe文件从哪几个动态连接库导入了什么函数的一组结构数组.在这里我希望能用最简洁的语言让你明白什么是输入表.输入表的组成并不复杂,只用到三个结构.它们是:IMAGE_IMPORT_DESCRIPTOR,IMAGE_THUNK_DATA,IMAGE_IMPORT_BY_NAME.
    我们先看一下框图.

                           IMAGE_IMPORT_DESCRIPTOR
                          |---------------------------|
|---------------------| OriginalFirstThunk  |
|                         |---------------------------|
|                         | TimeDateStamp      |
|                         |---------------------------|
|                         | ForwarderChain     |
|                         |---------------------------|
|                         |       Name                |----> "USER32.DLL"
|                         |---------------------------|
|                         |     FirstThunk          |---------------------------------------------------------------------|
|                         |---------------------------|(装入内存后FirstThunk指向的结构数组会被修改)      |
|                                                                                                                                                |
|     Hint-name table                  IMAGE_IMPORT_BY_NAME   import address table(IAT)      |
|     |--------------------------------|     |--------------------------------|     |--------------------------------|      |
|-> | IMAGE_THUNK_DATA |-->| 44 | "GetMessage"        |<--| IMAGE_THUNK_DATA|<---|
      |--------------------------------|     |-----|--------------------------|     |--------------------------------|
      | IMAGE_THUNK_DATA |-->| 72 | "LoadIcon"             |<--| IMAGE_THUNK_DATA |
      |--------------------------------|     |-----|--------------------------|     |--------------------------------|
      |     ......                           |-->| ..    |    ......                     |<--|     ......                            |
      |--------------------------------|    |------|--------------------------|    |---------------------------------|
      |       NULL                      |     |       NULL                       |
      |--------------------------------|    |----------------------------------|

    当然,这是描述从一个dll中引入函数的情形.从几个dll中引入函数,那么就有几个这样的结构.同时,这也是磁盘文件上的结构.装入内存后FirstThunk指向的结构数组会被修改.可以看下面的图.
    我们先来熟悉一下这三个结构的定义:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
         DWORD Characteristics;       // 0 for terminating null import descriptor
         DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    };
    DWORD TimeDateStamp;          // 0 if not bound,
                                                        // -1 if bound, and real date\time stamp
                                                        //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                                        // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD ForwarderChain;          // -1 if no forwarders
    DWORD Name;
    DWORD FirstThunk;                  // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;

typedef struct _IMAGE_THUNK_DATA32 {
    union {
         PBYTE   ForwarderString;
         PDWORD Function;
         DWORD Ordinal;
         PIMAGE_IMPORT_BY_NAME   AddressOfData;
    } u1;
} IMAGE_THUNK_DATA32;

 

typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;                 //指出函数在所在的dll的输出表中的序号
    BYTE    Name[1];            //指出要输入的函数的函数名
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

 

IMAGE_IMPORT_DESCRIPTOR结构的各个域的含义:
1)union {
         DWORD Characteristics;
         DWORD OriginalFirstThunk;
   };
    这个联合指向一个 IMAGE_THUNK_DATA 类型的结构数组.这个联合不是很重要,可以为0.
 
2)TimeDateStamp
    该dll的时间日期戳,一般为0.
 
3)ForwarderChain
    正向连接索引.一般为0.
 
4)Name
    dll名字的RVA.
 
5)FirstThunk
    这个域也是一个RVA,指向一个DWORD数组,数组以NULL结束.数组中的每个DWORD实际上是一个IMAGE_THUNK_DATA结构的联合体。IMAGE_THUNK_DATA联合体通常被解释为一个指向IMAGE_IMPORT_BY_NAME结构的RVA.

    从上图我们可以看出有两个并行的指针数组都指向IMAGE_IMPORT_BY_NAME结构.事实上,OriginalFirstThunk指向的IMAGE_THUNK_DATA结构数组从来不被修改,该数组有时也叫提示名表(Hint-name table),提示名表总是指向IMAGE_IMPORT_BY_NAME结构数组.而FirstThunk指向的IMAGE_THUNK_DATA结构数组在该pe文件被加载时,加载程序会修改该数组的内容.加载程序迭代搜索数组的每一个指针,找到每一个IMAGE_IMPORT_BY_NAME结构所对应的输入函数的地址,然后加载程序用找到的地址修改相应的IMAGE_THUNK_DATA结构.(这是理解加载过程的关键).
    如前面提到的
          call my_label
          ...
my_label: jmp dword ptr [xxxxxxxx]
    其中的xxxxxxxx就是FirstThunk指向的IMAGE_THUNK_DATA数组中的一个的值.因为FirstThunk所指向的数组在加载后是所有输入函数的地址,因此它被称为输入地址表(Import Address Table,IAT).
    pe文件加载后输入表的情形如下:
                           IMAGE_IMPORT_DESCRIPTOR
                           |--------------------------|
|---------------------| OriginalFirstThunk |
|                         |---------------------------|
|                         | TimeDateStamp     |
|                         |---------------------------|
|                         | ForwarderChain     |
|                         |---------------------------|
|                         |       Name                |----> "USER32.DLL"
|                         |---------------------------|
|                         |     FirstThunk          |-----------------------------------------------------------|
|                         |---------------------------|                                                                       |
|                                                                                                                                   |
|     Hint-name table           IMAGE_IMPORT_BY_NAME  import address table(IAT)  |
|    |--------------------------------|     |-----------------------------| |------------------------------|      |
|->| IMAGE_THUNK_DATA |-->| 44 | "GetMessage"    | |ptr of GetMessage      |<----|
    |---------------------------------|     |----|------------------------| |------------------------------|
    | IMAGE_THUNK_DATA |--> | 72 | "LoadIcon"          | | ptr of LoadIcon           |
    |---------------------------------|     |----|------------------------| |------------------------------|
    |     ......                             |-->| .. |    ......                    | |     ......                         |
    |---------------------------------|     |----|------------------------| |------------------------------|
    |       NULL                       |   
 
 

 

原创粉丝点击