PE文件解析(4):导入表的解析

导入表

什么是导入表?
导入表记录了一个exe或者一个dll所用到的其他模块导出的函数。
在这里插入图片描述
数据目录表的第二个元素记录着导入包的位置,导出表我们上节课已经解析过 了,今天我们来解析导入表。

导入表结构体解析

在这里插入图片描述

导入名称表: INT
导入地址表:IAT

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;// 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;// RVA 指向(IMAGE_THUNK_DATA)结构体数组 INT
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;     // 时间戳 0 if not bound                              
    DWORD   ForwarderChain;    // -1 if no forwarders
    DWORD   Name;//RVA dll文件名称
	DWORD   FirstThunk;  //  RVA to IAT 导入地址表 IMAGE_THUNK_DATA数组
} IMAGE_IMPORT_DESCRIPTOR;

重要字段:

  • OriginalFirstThunk:是导入表的导入名称表(INT)的RVA。
  • Name:作为导入的DLL文件的名称,RVA。
  • FirstThunk:是导入表的导入地址表(IAT)的RVA。
  • OriginalFirstThunk-->IMAGE_THUNK_DATA 如果IMAGE_THUNK_DATA 最高位为1 则是按序号导入,否则就是按名称导入的。

根据OriginalFirstThunk或者FirstThunk可以得到导入名称表INT和IAT,表示INT和IAT的结构体如下:

typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA32;
  • Ordinal:用来标记此函数是按序号导入还是按照名称导入

INT或者IAT的 AddressOfData字段:是一个RVA,通过它可以得到按名称导入的表 PIMAGE_IMPORT_BY_NAME

typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;//导入函数索引(根据编译器的不同这个地方放的东西不一样)
    CHAR   Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
  • Name:每一个函数的名称

寻找导入表的位置

我们使用010editor工具来寻找导入表的位置:

  1. 首先找到数据目录表的第二个元素,它所存储的偏移及大小表示的是导入表的偏移和大小: 1B17Ch 和80大小。
    在这里插入图片描述

  2. 然后在区段中寻找合适位置:可以看到,第五个区段的RVA是1B000h,在内存中的大小是2339d ,导入表的RVA正好位于此字段内,因此使用公式:导入表的FOA=导入表的RVA - 区段的RVA +区段的FOA,得到了导入表的在文件中的偏移地址: 1b17c - 1b000 + 8000 = 817C
    在这里插入图片描述

  3. 得到的 817C就是我们在文件中的偏移地址,搜索可得:这就是导入表的位置(注意:817C 加上文件基址才是真正的位置,010editor工具可以省略基址直接由偏移得到,但是在代码解析或则其他工具中,我们必须加上文件基址)。
    在这里插入图片描述


代码解析导入表


void cPE::GetImportTable()
{
	//获取导入表的地址
	IMAGE_DATA_DIRECTORY ImPortAddr = pOptionHeader->DataDirectory[1];
	//得到导入表
	PIMAGE_IMPORT_DESCRIPTOR ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)(RvaToFoa(ImPortAddr.VirtualAddress) + FileBuff);
	if (ImportTable == NULL)
	{
		printf("导入表为空!\n");
		return;
	}
	//导入表会有多个,导入表只要不为空,则它的字段也一定不为空,如果它的字段为空,则此导入表遍历到了最后
	while (ImportTable->OriginalFirstThunk)
	{
		printf("TimeDataStamp=%d\n", ImportTable->TimeDateStamp);
		//RVA Name
		char* dllName=RvaToFoa(ImportTable->Name) + FileBuff;
		printf("Dll文件名称: %s\n", dllName);
		//得到导入名称表 INT
		PIMAGE_THUNK_DATA pThunkData = (PIMAGE_THUNK_DATA)(RvaToFoa(ImportTable->OriginalFirstThunk) + FileBuff);

		while (pThunkData->u1.Function)
		{
			//判断是否按序号导入
			if (pThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG32)	//0x80000000
			{
				printf("按序号导入: %d\n", IMAGE_ORDINAL32(pThunkData->u1.Ordinal));
			}
			else
			{
				//否则就是按名称导入
				PIMAGE_IMPORT_BY_NAME importName = (PIMAGE_IMPORT_BY_NAME)(RvaToFoa(pThunkData->u1.AddressOfData) + FileBuff);
				printf("按名称导入: %s\n", importName->Name);
			}
			pThunkData++;
		}
		ImportTable++;
	}
}

运行如下:打印出调用此程序的导入的所有的dll文件所加载的函数,按名称或者序号导入。
在这里插入图片描述

可以看到:导入表的位置和我们在010editor中解析的导入表的位置一致
在这里插入图片描述
在这里插入图片描述

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuleo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值