IAT结构分析

IAT结构分析

IAT介绍

解决兼容问题(不同机器的dll版本不同,地址自然不同),操作系统就必须提供一些措施来确保可以在其他版本的Windows操作系统,以及DLL版本下也能正常运行。

这时IAT(Import Address Table:输入函数地址表)就应运而生了。

IAT定位

手工寻找

  • 利用PEview找到程序的NT头的可选头内有个import table此处记录了其RVA。
  • 根据结构体 IMAGE_IMPORT_DESCRIPTOR即导入表结构确定dll名称和IAT表的
typedef struct _IMAGE_IMPORT_DESCRIPTOR {

     union {

          DWORD Characteristics;         

          DWORD OriginalFirstThunk;//该字段指向导入名称表(INT),该RVA是一个IMAGE_THUNK_DATA结构体0x01b218

     };

      DWORD TimeDateStamp;//可以忽略,一般为0      

      DWORD ForwarderChain;//一般为0      

      DWORD Name;//指向DLL的名称的RVA地址            

      DWORD FirstThunk;//该字段包含导入地址表(IAT)的RVA,IAT是一个IMAGE_THUNK_DATA结构体数组 0x01b000  0x01b3e0

} IMAGE_IMPORT_DESCRIPTOR;
  • 根据IAT表的指针 找到导入函数的序数和该函数的名字
typedef struct _IMAGE_IMPORT_BY_NAME {

     WORD Hint;         //该函数的导出序数

     BYTE Name[1];      // 该函数的名字

} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

程序实现

#include<windows.h>
#include<stdio.h>
BOOL ImportAddressTablefind(IN HMODULE hModule)
{
	IMAGE_DOS_HEADER* pImageDosHearder = (IMAGE_DOS_HEADER*)hModule;
	IMAGE_OPTIONAL_HEADER* pImageOptionalHeader = (IMAGE_OPTIONAL_HEADER*)((DWORD)hModule + pImageDosHearder->e_lfanew + 24);//获取可选头的地址
	IMAGE_IMPORT_DESCRIPTOR* pImageImportDescriptor = (IMAGE_IMPORT_DESCRIPTOR*)
		((DWORD)hModule + pImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);//导入表地址

	while (pImageImportDescriptor != 0)
	{
		LPCSTR base = (PSTR)(PBYTE)GetModuleHandle(NULL);
		LPCSTR pszModName = (PSTR)(base + pImageImportDescriptor->Name);//导入表动态链接库名称
		IMAGE_THUNK_DATA* pImageThunkData = (IMAGE_THUNK_DATA*)((DWORD)hModule + pImageImportDescriptor->FirstThunk);//获取动态链接库中的IAT函数地址0x1b000
		IMAGE_IMPORT_BY_NAME ** Original =(IMAGE_IMPORT_BY_NAME **) ((DWORD)hModule + pImageImportDescriptor->OriginalFirstThunk);//获取0x1b214//0x
		while (pImageThunkData->u1.Function)
		{
			
			unsigned int fun = (unsigned int)(PBYTE)(*Original)->Name;
			LPCSTR funcname =base+ fun;
			LPDWORD lpFunctionAddress = (LPDWORD)&(pImageThunkData->u1.Function);
			__try
			{
				printf("dllname:%s funcname:%s addr:%x\n", pszModName, funcname, *lpFunctionAddress);
			}
			__except (1)
			{
				system("pause");
			}
			pImageThunkData++;
			*Original++;
		}

		
		pImageImportDescriptor++;
	}
	return true;
}
int main()
{
	ImportAddressTablefind(::GetModuleHandle(NULL));
	system("pause");
}

IAT脱壳修复

原因

我们运行程序,利用OD将其直接dump,此时我们发现,依据导入表找到IAT指针,发现指针为0。但是脱壳结束时IAT地址已经被写好。如果我们直接dump所运行程序,因为INT指针缺失,程序肯定运行不了。

修复

起初利用工具ImpREC自动查找IAT,查找的IAT有点错误,我们根据OD来看找到正确IAT表的RVA和size最后还有OEP,但是多出两个无效指针,看了一下不是动态链接库函数地址,将其删除即可。

修复后的PE结构

程序新建了一个区段,程序的导入表并且与导入表相关都在在这个区段,并且INT不在为0,为结构体 _IMAGE_IMPORT_BY_NAME 的双重指针。这样就能重新给IAT赋值。

PE重定位

由于部分程序开启了ASLR,利用IAT时的地址也会随着加载基址变化而变化,导致硬编码在程序中的内存地址随当前加载地址变化而改变的处理就是重定位。

重定位表一般位于可选头的BASE RELOCATION TABLE,这是一个记录硬编码地址偏移的列表。其中表中前两个为基准地址和大小后面为typeoffset。

type为4位,offset为12为,offset+基准地址+程序基址=程序该改变硬编码的VA

参考链接
https://www.xuepojie.com/thread-5155-1-1.html
https://www.xuepojie.com/forum.php?mod=viewthread&tid=5156&highlight=%B5%DA%C8%FD%CA%AE%CB%C4%D5%C2-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值