《Windows PE》4.1导入表

导入表顾名思义,就是记录外部导入函数信息的表。这些信息包括外部导入函数的序号、名称、地址和所属的DLL动态链接库的名称。Windows程序中使用的所有API接口函数都是从系统DLL中调用的。当然也可能是自定义的DLL动态链接库。对于调用方,我们称之为导入函数,而对于DLL动态链接库而言,则称之为导出函数。我们将在下一章中再详细讲述导出表。

本节必须掌握的知识点:

        导入表数据结构

        PE中的导入表

        IAT函数地址表

        手工重构导入表

4.1.1 导入表数据结构

导入表(Import Table)是PE(可执行文件、动态链接库等)文件中的一个数据结构,用于记录该模块所依赖的外部函数和库。在运行时,操作系统根据导入表中的信息来解析和加载这些外部函数和库。导入表数据是一组导入表描述符结构。每组为20个字节。导入表的位置和大小信息保存在数据目录项的第1项(从第0项开始)。

导入表包含以下重要的信息

●导入描述符表(Import Descriptor Table):记录每个被导入的模块的信息,如模块名称、导入地址表的位置等。

●导入地址表(Import Address Table):记录外部函数的地址,在加载时会被填充为实际函数的地址。

●导入名称表(Import Name Table):记录外部函数的名称。

导入表描述符的结构如下

typedef struct _IMAGE_IMPORT_DESCRIPTOR {

    union {

        DWORD Characteristics; //特征值,对于终止的空导入描述符为0

        DWORD OriginalFirstThunk; //指向原始未绑定的导入地址表的RVA

//(PIMAGE_THUNK_DATA)

    } DUMMYUNIONNAME;

DWORD TimeDateStamp; //时间戳,如果未绑定则为0。

//绑定时为-1,并在IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT中记录实际日期\时间戳(新的BIND中),否则为绑定到的DLL的日期/时间戳(旧的BIND中)

    DWORD ForwarderChain; //正向链表索引,如果没有正向链表则为-1

    DWORD Name;         //DLL模块名称的RVA

    DWORD FirstThunk; //导入地址表(IAT)的RVA,如果已绑定,则IAT包含实际地址

} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;

●OriginalFirstThunk字段的作用是记录导入函数的信息。对于每个导入模块,OriginalFirstThunk字段是一个指针,指向一个由IMAGE_THUNK_DATA类型的结构体构成的表。每个IMAGE_THUNK_DATA结构体存储着导入函数的信息,包括函数名称或序号。

OriginalFirstThunk指向的表中的每个IMAGE_THUNK_DATA结构体有两种可能的形式:

  1. 如果导入函数是通过名称进行导入,IMAGE_THUNK_DATA结构体中的值是一个指向函数名称的指针。
  2. 如果导入函数是通过序号进行导入,IMAGE_THUNK_DATA结构体中的值是函数的序号。

通过解析OriginalFirstThunk指向的表,可以获取导入模块中所有导入函数的名称或序号。这些信息后续可以用于将导入的函数地址与对应的函数名称或序号进行关联。

 注意

1.OriginalFirstThunk字段在已绑定的PE文件中可能会被覆盖,此时可以通过FirstThunk字段来获取已绑定的导入地址表。

2.ForwarderChain用于指示导入函数的转发链(Forwarder Chain)。

在PE文件中,导入表描述符用于描述导入函数的相关信息,包括导入模块的名称、导入地址表的位置等。而转发链是指导入函数在一个模块中被转发到另一个模块的一种机制。

转发链的作用是将一个导入函数的调用转发到另一个模块中的函数。当一个导入函数被调用时,如果它在当前模块中没有找到,就会根据转发链找到另一个模块,并在那个模块中寻找匹配的函数来处理该调用。

ForwarderChain字段在导入表描述符中记录了转发链的信息,它的值表示下一个导入函数描述符在导入表中的索引。如果ForwarderChain字段的值为-1,表示没有转发链,即没有导入函数被转发到其他模块。

需要注意的是,转发链是可选的,不是所有的导入函数都会使用转发链。只有在某些特定的情况下,如跨模块调用或模块间的函数重定向时,才会使用转发链来实现导入函数的转发。

●下面是winnt.h头文件中IMAGE_THUNK_DATA结构体的定义:

#include "pshpack8.h"                // Use align 8 for the 64-bit IAT.

typedef struct _IMAGE_THUNK_DATA64 {

    union {

        ULONGLONG ForwarderString// PBYTE

        ULONGLONG Function;         // PDWORD

        ULONGLONG Ordinal;

        ULONGLONG AddressOfData;    // PIMAGE_IMPORT_BY_NAME

    } u1;

} IMAGE_THUNK_DATA64;

typedef IMAGE_THUNK_DATA64 * PIMAGE_THUNK_DATA64;

#include "poppack.h"               // Back to 4 byte packing

typedef struct _IMAGE_THUNK_DATA32 {

    union {

        DWORD ForwarderString;      // PBYTE

        DWORD Function;             // PDWORD

        DWORD Ordinal;

        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME

    } u1;

} IMAGE_THUNK_DATA32;

typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;

IMAGE_THUNK_DATA结构体的字段含义如下:

1.ForwarderString:如果存在转发导入(forwarding import),则该字段保存转发字符串的指针;否则,该字段为0。

2.Function:导入函数的地址。如果导入函数是通过名称进行导入,则该字段保存函数的地址;如果导入函数是通过序号进行导入,则该字段保存函数的序号。

3.Ordinal:如果导入函数是通过序号进行导入,则该字段保存函数的序号;否则,该字段为0。

4.AddressOfData:如果导入函数是通过名称进行导入,则该字段保存一个指向IMAGE_IMPORT_BY_NAME结构体的指针,该结构体包含函数的名称;否则,该字段保存一个指向函数的地址的指针。

IMAGE_THUNK_DATA结构体用于描述PE文件中的导入地址表(Import Address Table,IAT)或原始未绑定导入地址表(Original Unbound Import Address Table)中的每个导入函数的信息。

通过解析IMAGE_THUNK_DATA结构体的字段,可以获取导入函数的地址或序号,以及函数的名称(如果是通过名称进行导入)。

 注意

1.MAGE_THUNK_DATA结构体在64位的PE文件中使用_IMAGE_THUNK_DATA64。

2.对于32位的PE文件,相应的结构体是_IMAGE_THUNK_DATA32。它们之间的区别在于64位PE文件使用ULONGLONG表示64位指针类型,而32位PE文件使用DWORD表示32位指针类型。

       ●IMAGE_IMPORT_BY_NAME结构体:                        

IMAGE_IMPORT_BY_NAME是Windows可执行文件(PE文件)中的一个结构体,用于描述通过名称导入函数的信息。

以下是IMAGE_IMPORT_BY_NAME结构体的定义:

typedef struct _IMAGE_IMPORT_BY_NAME {

    WORD    Hint;

    BYTE    Name[1];

} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

IMAGE_IMPORT_BY_NAME结构体的字段含义如下:

1.Hint:导入函数的提示值(Hint),是一个16位的无符号整数。它提供了关于导入函数的一些附加信息,例如函数的重载情况等。在导入描述符中,通过OriginalFirstThunk指向的表中的IMAGE_THUNK_DATA结构体的Ordinal字段存储了函数的序号,而Hint字段则提供了与该序号对应的提示值。

2.Name:导入函数的名称,是一个以NULL结尾的字符串。

IMAGE_IMPORT_BY_NAME结构体用于描述PE文件中的导入地址表(Import Address Table,IAT)或原始未绑定导入地址表(Original Unbound Import Address Table)中,通过名称进行导入的函数的信息。

通过解析IMAGE_IMPORT_BY_NAME结构体的字段,可以获取导入函数的名称以及与之对应的提示值(如果有的话)。

4.1.2 PE中的导入表

       接下来我们通过具体实例分析PE中的导入表。

实验二十三:如何定位导入表?

●我们以32位汇编版HelloWorld.exe为例,将其拖入WinHex,如下所示:

00000000   4D 5A 90 00 03 00 00 00  04 00 00 00 FF FF 00 00   MZ............

00000010   B8 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00   ?......@.......

00000020   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................

00000030   00 00 00 00 00 00 00 00  00 00 00 00 C8 00 00 00   ............?..

000000C0   00 00 00 00 00 00 00 00  50 45 00 00 4C 01 04 00   ........PE..L...

000000D0   E4 68 03 66 00 00 00 00  00 00 00 00 E0 00 02 01   鋒.f........?..

000000E0   0B 01 0E 10 00 02 00 00  00 06 00 00 00 00 00 00   ................

000000F0   00 10 00 00 00 10 00 00  00 20 00 00 00 00 40 00   ......... ....@.

00000100   00 10 00 00 00 02 00 00  06 00 00 00 00 00 00 00   ................

00000110   06 00 00 00 00 00 00 00  00 50 00 00 00 04 00 00   .........P......

00000120   00 00 00 00 02 00 40 81  00 00 10 00 00 10 00 00   ......@.........

00000130   00 00 10 00 00 10 00 00  00 00 00 00 10 00 00 00   ................

00000140   00 00 00 00 00 00 00 00  DC 20 00 00 3C 00 00 00   ........?..<...

00000150   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................

00000160   00 00 00 00 00 00 00 00  00 40 00 00 10 00 00 00   .........@......

00000170   10 20 00 00 1C 00 00 00  00 00 00 00 00 00 00 00   . ..............

00000180   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................

00000190   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................

000001A0   00 20 00 00 10 00 00 00  00 00 00 00 00 00 00 00   . ..............

000001B0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................

       ●导入表数据目录项

DOS头的IMAGE_DOS_HEADER. e_lfanew字段000000C8H指向IMAGE_NT_HEADERS32。

IMAGE_NT_HEADERS32.OptionalHeader.DataDirectory[1*8]指向导入表数据目录项00000148H地址处。

导入表的RVA地址为000020DCH,大小为0000003C。

       ●定位导入表

000001C0   2E 74 65 78 74 00 00 00  26 00 00 00 00 10 00 00   .text...&.......

000001D0   00 02 00 00 00 04 00 00  00 00 00 00 00 00 00 00   ................

000001E0   00 00 00 00 20 00 00 60  2E 72 64 61 74 61 00 00   .... ..`.rdata..

000001F0   5E 01 00 00 00 20 00 00  00 02 00 00 00 06 00 00   ^.... ..........

00000200   00 00 00 00 00 00 00 00  00 00 00 00 40 00 00 40   ............@..@

00000210   2E 64 61 74 61 00 00 00  1B 00 00 00 00 30 00 00   .data........0..

00000220   00 02 00 00 00 08 00 00  00 00 00 00 00 00 00 00   ................

00000230   00 00 00 00 40 00 00 C0  2E 72 65 6C 6F 63 00 00   ....@..?reloc..

00000240   10 00 00 00 00 40 00 00  00 02 00 00 00 0A 00 00   .....@..........

00000250   00 00 00 00 00 00 00 00  00 00 00 00 40 00 00 42   ............@..B

       将导入表数据目录项的RVA地址转换为FOA文件偏移地址。

       RVA地址000020DCH位于.rdata节区00002000H~0000215EH区间。

       FOA地址=000020DCH-00002000H+00000600H=000006DCH。

目录项目的第1个结构就是导入表                                             

                                                

typedef struct _IMAGE_DATA_DIRECTORY {                                              

    DWORD   VirtualAddress;                                    //RVA 指向导入表结构             

    DWORD   Size;                                             

} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;                                             

                                                

      将RVA转换成FOA                                        

                                                

typedef struct _IMAGE_IMPORT_DESCRIPTOR {                                                

    union {                                             

        DWORD   Characteristics;                                                        

        DWORD   OriginalFirstThunk;                                                   

    };                                              

    DWORD   TimeDateStamp;                                                         

    DWORD   ForwarderChain;                                                          

    DWORD   Name;                                         

    DWORD   FirstThunk;                                                                

} IMAGE_IMPORT_DESCRIPTOR;                                          

typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED

*PIMAGE_IMPORT_DESCRIPTOR;                                               

000006D0  1B 00 00 00 2E 64 61 74  61 00 00 00 20 21 00 00   .....data... !..

000006E0  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值