首页 > PE文件格式 > PE文件格式解析(三)——导入表的解析

PE文件格式解析(三)——导入表的解析

在解析导入表之前,要先得到PE文件的数据目录表,数据目录表存在于可选头之中,以一个数组的形式存在,第二个元素指出导入表的一些信息。具体请参考《PE文件之IMAGE_OPTIONAL_HEADER》一文。

通过IMAGE_DATA_DIRECTORY的第二个VirtualAddress可以得到导入表的RVA(到处都是RVA,所以弄懂RVA的概念以及熟悉RVA与Offset的转换是十分重要的,具体请参考《PE文件格式解析(二)》一文)。将RVA转为Offset之后,就可以读取IMAGE_IMPORT_DESCRIPTOR结构了,每一个DLL都由IMAGE_IMPORT_DESCRIPTOR指明,最后一个IMAGE_IMPORT_DESCRIPTOR为空。IMAGE_IMPORT_DESCRIPTOR的name域指出了DLL名字所在的RVA地址,需要将其转换为Offset才可以读取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;

IMAGE_IMPORT_DESCRIPTOR的OriginalFirstThunk指明了一个个IMAGE_THUNK_DATA结构的元素,最后一个IMAGE_THUNK_DATA的元素为空。IMAGE_THUNK_DATA元素,IMAGE_THUNK_DATA定义如下:

1
2
3
4
5
6
7
8
typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA32;

对于IMAGE_THUNK_DATA,如果最高位为1,则表示函数以序号的方式从DLL中导出引用,低31位表示序号;如果最高位为0,则表示名字导出,此时32位表示一个RVA,这个RVA指向一个结构为IMAGE_IMPORT_BY_NAME的元素。其定义如下:

1
2
3
4
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    BYTE    Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

Hint表示函数驻留在DLL中的序号,不是必须的。
Name指向一个函数的ASCII字符串名字,以0结束。注意这里由于内存对齐的原因,导致IMAGE_IMPORT_BY_NAME的大小为4,所以如果是读文件,那么会读入4个字节,而Hint占2个字节,所以剩余的两个字节为函数名称的前两个字节,千万别忘了。否则你会看到得到的函数名称前面少了两个字符。

大概就是这个样子。感觉整个最关键的地方还是RVA的理解和转换。还是来一张《加密与解密第三版》的一张截图。

导入表结构解析

另外附一张我写的程序截图:

导入表解析效果截图

关于PE文件格式,网上有很多资料,建议去看雪论坛找,很全很详细,包括微软官方文档翻译版。如果喜欢看书的话可以看《加密与解密》第三版或者罗云彬的《Windows环境下32位汇编语言程序设计》,觉得罗云彬的书讲得很好。

下一个任务:简单任务管理器的编写。


觉得文章还不错?点击此处对作者进行打赏!


本文地址: 程序人生 >> PE文件格式解析(三)——导入表的解析
作者:代码疯子(Wins0n) 本站内容如无声明均属原创,转载请保留作者信息与原文链接,谢谢!


更多



分类: PE文件格式 标签: , ,
  1. 本文目前尚无任何评论.