《Windows PE》4.1.3 IAT函数地址表

IAT(Import Address Table)表又称为函数地址表,是Windows可执行文件中的一个重要数据结构,用于存储导入函数的实际入口地址。

在可执行文件中,当一个模块需要调用另一个模块中的函数时,通常会使用导入函数的方式进行。导入函数的入口地址在程序加载时并不确定,需要在运行时进行动态链接,以获取实际的函数入口地址。IAT表就是用来存储这些实际的函数入口地址。

IAT表是一个由函数指针构成的表格,每个函数指针对应一个导入函数。在Windows可执行文件中,IAT表是一个以NULL结尾的函数指针数组,每个函数指针对应一个导入函数的实际入口地址。

IAT表通常是通过导入描述符(Import Descriptor)中的FirstThunk字段指向的地址来访问的。FirstThunk指向一个由IMAGE_THUNK_DATA结构体构成的表,每个IMAGE_THUNK_DATA结构体中的Function字段存储着导入函数的实际入口地址。

在程序加载时,操作系统会根据导入描述符中的INT表和IAT表进行动态链接,将导入函数的实际入口地址填充到IAT表中的函数指针对应的位置。这样,在程序运行时,就可以直接通过IAT表中的函数指针调用导入函数,而无需进行额外的解析和跳转。

 注意

IAT函数地址表中的函数指针是在程序加载和链接时被填充的,而导入表描述符中的IAT表中的函数指针在未绑定的状态下与INT表完全相同。如果导入表描述符的TimeDateStamp和ForwarderChain字段是一个特殊的标志值,如0xFFFFFFFF,表示导入函数已绑定,则IAT函数地址表中存储的是真实的导入函数地址。

实验二十五:如何定位IAT表?

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

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   ................

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

首先我们查找数据目录项的第12项,即IAT表项。位于00000220H地址处的RVA值为00002010H,大小为0000001CH。

此RVA地址同样位于.rdata节区。

IAT表的FOA地址=00002000H-00002000H+600H=600H。

00000600   42 21 00 00 00 00 00 00  28 21 00 00 00 00 00 00   B!......(!......

00000610   00 00 00 00 E4 68 03 66  00 00 00 00 0D 00 00 00   ....鋒.f........

00000620   B0 00 00 00 2C 20 00 00  2C 06 00 00 00 00 00 00   ?.., ..,.......

00000630   00 10 00 00 26 00 00 00  2E 74 65 78 74 00 00 00   ....&....text...

00000640   00 20 00 00 10 00 00 00  2E 69 64 61 74 61 24 35   . .......idata$5

00000650   00 00 00 00 10 20 00 00  1C 00 00 00 2E 72 64 61   ..... .......rda

00000660   74 61 00 00 2C 20 00 00  B0 00 00 00 2E 72 64 61   ta.., ..?...rda

00000670   74 61 24 7A 7A 7A 64 62  67 00 00 00 DC 20 00 00   ta$zzzdbg...?..

00000680   28 00 00 00 2E 69 64 61  74 61 24 32 00 00 00 00   (....idata$2....

00000690   04 21 00 00 14 00 00 00  2E 69 64 61 74 61 24 33   .!.......idata$3

000006A0   00 00 00 00 18 21 00 00  10 00 00 00 2E 69 64 61   .....!.......ida

000006B0   74 61 24 34 00 00 00 00  28 21 00 00 36 00 00 00   ta$4....(!..6...

000006C0   2E 69 64 61 74 61 24 36  00 00 00 00 00 30 00 00   .idata$6.....0..

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

000006E0   00 00 00 00 00 00 00 00  36 21 00 00 08 20 00 00   ........6!... ..

000006F0   18 21 00 00 00 00 00 00  00 00 00 00 50 21 00 00   .!..........P!..

00000700   00 20 00 00 00 00 00 00  00 00 00 00 00 00 00 00   . ..............

00000710   00 00 00 00 00 00 00 00  42 21 00 00 00 00 00 00   ........B!......

00000720   28 21 00 00 00 00 00 00  B1 01 4D 65 73 73 61 67   (!......?Messag

00000730   65 42 6F 78 41 00 75 73  65 72 33 32 2E 64 6C 6C   eBoxA.user32.dll

00000740   00 00 9B 00 45 78 69 74  50 72 6F 63 65 73 73 00   ..?ExitProcess.

00000750   6B 65 72 6E 65 6C 33 32  2E 64 6C 6C 00 00 00 00   kernel32.dll....

       IAT表内包含两个函数名的RVA地址:

       第一个:00002142H转为FOA地址为742H,是kernel32.dll中的ExitProcess函数。

       第二个:00002128H转为FOA地址为728H,是user32.dll中的MessagBoxA函数。

       我们再来看一下导入表描述符中的桥2(FirstThunk字段),指向IAT表。

       第一个导入表描述符FirstThunk字段的值为00002008H,转为FOA地址为608H,其RVA值为00002128H,即user32.dll中的MessagBoxA函数。

       第二个导入表描述符FirstThunk字段的值为00002000H,转为FOA地址为600H,其RVA值为00002142H,即kernel32.dll中的ExitProcess函数。

 

总结

       我们会发现,在未绑定导入函数的情况下,实验二十五中给出的IAT函数地址表中数据与INT表中的数据完全相同。如果已绑定导入函数,则IAT表直接存储真实的函数入口地址。我们将在下一节中详细讲述。

实验二十六:遍历IAT函数地址表。

我们以32位和64位记事本程序为例:

/*------------------------------------------------------------------------

 FileName:PrintImportDescriptor.c

 实验26:遍历IAT表(支持32位和64位PE)

 (c) bcdaren, 2024

-----------------------------------------------------------------------*/

#include <stdio.h>

#include <windows.h>

#define WIN64

PBYTE loadPE(LPCWSTR szFile);

VOID iat32(PBYTE lpvResult);

VOID iat64(PBYTE lpvResult);

DWORD RvaToFoa(PIMAGE_NT_HEADERS ntHeaders, DWORD rva);

int main(int argc, char* argv[])

{

    LPCWSTR szFileName = TEXT("c:\\notepad64.exe");

    //PCWSTR szFileName = TEXT("c:\\HelloWorld.exe");

    PBYTE lpAddress = NULL; //PE文件内存映射文件地址

    lpAddress = loadPE(szFileName);

    if (lpAddress)

    {

        printf("%ls\n", szFileName);

#ifdef WIN64

        iat64(lpAddress);

#else

        iat32(lpAddress);

#endif

    }

    system("pause");

    return 0;

}

//创建PE文件映射对象

PBYTE loadPE(LPCWSTR szFile)

{

    HANDLE hFile;

    LPVOID lpvResult, lpvResult2;

    char buffer[16] = { 0 };

    DWORD dwPageSize;

    DWORD dwBytesRead = 0;

    BOOL bReadFile;

    PIMAGE_DOS_HEADER psImageDOSHeader;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值