导入表(IAT) word最后一个字母为D表示为2个字节,dword为2*2=4个字节

 word最后一个字母为D表示为2个字节,dword为2*2=4个字节

导入表是由一系列的IMAGE_IMPORT_DESCRIPTOR结构组成的。结构的个
数由文件引用的DLL个数决定,文件引用了多少个DLL就有多少个IMAGE_IMPORT_DESCRIPTOR
结构,最后还有一个全为零的IMAGE_IMPORT_DESCRIPTOR作为结束。(隐式加载才有输入节)     //每个IID20个字节.

输入表为若干个IID组成以及最后一个都为0的IID结构. 每个IID为20个字节

一个dll对应一个IMAGE_IMPORT_DESCRIPTOR结构。一个function对应一个IMAGE_THUNK_DATA结构。

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;
        DWORD   OriginalFirstThunk;      //指向INT

    };
    DWORD   TimeDateStamp;
    DWORD   ForwarderChain;
    DWORD   Name;                          //DLL名字 IID结构的第四个元素为DLL的名字,没有固定字节数.
    DWORD   FirstThunk;                    //指向IAT                                 
} IMAGE_IMPORT_DESCRIPTOR;

typedef struct _IMAGE_THUNK_DATA {
  union {
  PBYTE ForwarderString;
  PDWORD Function;//函数RVA地址
  DWORD Ordinal;
  PIMAGE_IMPORT_BY_NAME AddressOfData;//函数名或序号
  } ;
  } IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;                    //2个字节。一个函数的地址。   一个DLL有很多的函数。

OriginalFirstThunk和FirstThunk在一个PE没有加载到内存中的时候是一样的,都是指向一
个IMAGE_THUNK_DATA结构数组。最后以一个内容为0的结构结束其实这个结构就是一个双   //前面一个字为有内容的IMAGE_THUNK_DATE
。这个结构很有意思,因为在不同的时候这个结构代表着不同的含义。当这个双字的最高          //后面一个字为都是0的IMAGE_THUNK_DATE
位为1时,表示函数是以序号的方式导入的;当最高位为0时,表示函数是以名称方式导入的,
这是这个双字是一个RVA,指向一个IMAGE_IMPORT_BY_NAME结构,这个结构用来指定导入函数
名称。

typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;      //前面两个字节是序号,不是函数名
    BYTE    Name[1];  //字节不固定
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

Hint字段表示一个序号,不过因为是按名称导入,所以这个序号一般为零。

Name字段是函数的名称

IMAGE-IMPORT-DESCRIPTOR和IMAGE-THUNK-DATA分别对应于DLL和函数。

一个PE没有被加载到内存中的时候IMAGE_IMPORT_DESCRIPTOR中的
OriginalFirstThunk和FirstThunk是相同的,那么为什么需要占用两个字段呢?其实
是这样的,在PE文件被PE加载器加载到内存中的时候这个加载器会自动把FirstThunk的值替
换为API函数的真正入口,也就是那个前面jmp的真正地址,而OriginalFirstThunk只不过是
用来反向查找函数名而已。

具体参见: http://blog.csdn.net/enyblock/article/details/6650113

posted on 2011-12-22 21:41  wanghj_dz  阅读(379)  评论(0编辑  收藏  举报

导航