深入理解PE结构中的IAT

先写一个简单的程序:

#include "stdafx.h"
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{

	MessageBox(0,0,0,0);

	ExitProcess(0);
	return 0;
}

  生成release版本的exe,然后使用od进行调试,找到调用这2个函数的地方

  调试之前,先把ALSR关闭或者生成之后使用二进制编辑器修改为00 81,防止下次加载的时候,加载地址变化

  我们在od中找到调用 MessageBox和ExitProcess的地方,发现

       call MessageBox =======> call [0x4020A8]  =====>call  760200EF

       call ExitProcess =======> call [0x402000]  =====>call    74E87A28

      OD加载exe,相当于把程序运行起来了。

         我们静态分析一下该程序中 [0x4020A8]  和 [0x402000]  这个2个地址在磁盘文件中存储的是什么值,是不是就是程序中的这2个值。

       call MessageBox =======> call [0x4020A8]  =====>call  760200EF

       call ExitProcess =======>   call [0x402000]  =====>call  74E87A28

 当前文件的ImageBase地址是0x400000,那么 0x4020A8 - 0x400000 = 0x20A8(RVA)  <====>0xEA8(FOA),0x402000 - 0x400000 = 0x2000(RVA)<====>0xE00(FOA)

 从图中可以看到      [0xEA8]--->0x00002320,                      这个值与760200EF看起来没什么关系,

                                                [0xE00]--->0x00002304,                      这个值与74E87A28看起来没什么关系

  这个时候把 0x00002320当做一个RVA,转换为FOA是0x1120,继续找[0x00001120],

                                               [0x1120]---> 0x0215

                                                                   MessageBox                 我们要调用的MessageBox函数的名称

把 0x00002304当做一个RVA,转换为FOA是0x1104,继续找[0x1104],

                                              [0x1104]---> 0x0119

                                                                   ExitProcess                       我们要调用的ExitProcess函数的名称

 现在就出现1个问题,exe运行前和运行后里面的值不一样。

程序运行的时候,和PE文件拉伸到内存中的一样的。先在4GB的虚拟内存中把exe贴进去,然后贴要用到的各个dll。

 我们在exe中引用动态链接库的时候,分为隐式链接和显示链接,隐式链接是什么时候用,什么时候把dll加载进去,同时也可以随时卸载dll。

显示链接是在程序开始的时候都把dll加载进去,程序结束,卸载dll。

如果编译、链接之后exe把用到dll里面函数的位置,都填为绝对地址,那么如果发生:1、dll更新版本了,2、dll没有占住ImageBase这个位置,加载到别的位置。

那么这个时候调用的绝对地址就会发生问题,因为dll更新版本,函数的地址就会发生变化;或者dll没有占住ImageBase这个位置,加载到别的位置,那么里面的函数地址也变了(原来是760200EF,那么现在肯定是0x85XXXXXX),如果还用原来的绝对760200EF地址,肯定会出问题。

这个时候就引入了IAT表(导入地址表),导入地址表与导入表关系密切,下一章详细分析导入地址表的结构体。

导入地址表:

          就是在程序中先存着指向要执行的函数的名称或者序号,当使用到dll中的函数的时候,使用GetProcessAddress(hInstance,函数名或者序号)找到函数的地址FunctionAddress,然后把这个FunctionAddress填到IAT表中。

           而GetProcessAddress(hInstance,函数名或者序号)查找函数地址的原理,在导出表中我们已经实现过了,hInstance是句柄,句柄是什么,句柄本质就是ImageBase。

   因为不管dll加载到什么位置,加载到ImageBase,加载不到也好,我们都可以使用句柄我们先找到要用的dll。

           函数名或者序号:在导入表中有3张表,通过这3张表找到函数名或序号找到的函数地址FunctionAddress。

           然后把找到的函数地址FunctionAddress填到IAT中,那么再调用USER32,dll中的MessageBox就不会出问题。

           IAT就是这样设计的。

加载前:    

加载后:

 查找IAT表的2种方式:

        第一种:通过导入表 (下一章详细介绍)

        第二种:数据目录项中  DataDirectory[0xC].RVA         

   0x2000 <===>0xE00(FOA)    IAT表

 这里找到第一个元素0x00002304  < ====>0x1104(FOA)

 打印IAT表的代码

void PrintfIATDirectory(void* FileBuffer)// FileBuffer为磁盘文件读到内存中的首地址
{
	unsigned int* NTOffset = (unsigned int*)((char*)FileBuffer + 0x3c);

	PE_ntHeader* lpNtHeader=(PE_ntHeader*)((unsigned char*)FileBuffer + *NTOffset);

	if(lpNtHeader->SizeofOptionalHeader == 0xF0)
	{
		//lpOptionHeade
		PE_OptionalHeader64* lpOptionHeader1= (PE_OptionalHeader64*)((char*)FileBuffer + *NTOffset + 24);
		unsigned int ImportTableOffset =  RvaToFoa(FileBuffer,lpOptionHeader1->DataDirectory[0xC].RVA);

		int IATSizeof = lpOptionHeader1->DataDirectory[0xC].SIZE;

		if(ImportTableOffset == 0)
		{
			printf("使用数据目录项查找的IAT表不存在!\n");
		}else{
			unsigned long long*  TATTable= (unsigned long long*)((unsigned char*)FileBuffer + ImportTableOffset);
			while(IATSizeof >=0)
			{
				
				printf("%016llx\n",*TATTable);
				TATTable++;
				IATSizeof = IATSizeof-8;
			}
		}

	}else if(lpNtHeader->SizeofOptionalHeader == 0xE0){

		PE_OptionalHeader32* lpOptionHeader1= (PE_OptionalHeader32*)((char*)FileBuffer + *NTOffset + 24);
	
		unsigned int ImportTableOffset =  RvaToFoa(FileBuffer,lpOptionHeader1->DataDirectory[0xC].RVA);
		
		int IATSizeof = lpOptionHeader1->DataDirectory[0xC].SIZE;

		if(ImportTableOffset == 0)
		{
			printf("使用数据目录项查找的IAT表不存在!\n");
		}else{
			unsigned int*  TATTable= (unsigned int*)((unsigned char*)FileBuffer + ImportTableOffset);
			while(IATSizeof >0)
			{
				
				printf("%08x\n",*TATTable);
				TATTable++;
				IATSizeof = IATSizeof-4;
			}
		}


	}
}

 

posted @ 2023-08-10 10:27  一日学一日功  阅读(260)  评论(0)    收藏  举报