滴水逆向三期 PE基础 导入表解析

假的分析

源码
在学习这节的时候第一遍并没有弄懂到底怎么回事, 等遍历完了再回头去看才懂, 推荐可以先把表打印出来再体会表结构.

真的分析

软件依然是某云音乐的主程序.
在这里插入图片描述
在这里插入图片描述
按照顺序依次为
1 遍历 _IMAGE_IMPORT_DESCRIPTOR
2 遍历OriginalFirstThunk中的ThunkValue偏移
3 遍历打印ThunkValue(本身还是偏移)
4 遍历IMAGE_THUNK_DATA32(ThunkValue所指向的值)

1 打印重要基础数据
while (pImportDescriptor->OriginalFirstThunk)
{
	DWORD rvaFirstThunk = pImportDescriptor->FirstThunk;
	DWORD rvaOriginalFirstThunk = pImportDescriptor->OriginalFirstThunk;
	printf("RVA_OriginalFirstTunk: %2x    RVA_Name: %2x    RVA_FirstThunk: %2x\n", pImportDescriptor->OriginalFirstThunk, pImportDescriptor->Name, pImportDescriptor->FirstThunk);
	DWORD foaName = RvaDataToFoaData(pFileBuffer, pImportDescriptor->Name, FALSE);
	printf("DLL's name: %s\n", (char *)((DWORD)pFileBuffer + foaName));
	printf("-------------------------------------------------------------------------\n");
	pImportDescriptor++;
	printf("-------------------------------------------------------------------------\n");
}

在这里插入图片描述

2 3打印OriginalFirstThunk中的ThunkValue偏移及其本身(ThunkValue还是个偏移)
DWORD foaOriginalFirstThunk = RvaDataToFoaData(pFileBuffer, rvaOriginalFirstThunk, FALSE);
DWORD OriginalThunkValue = *(DWORD *)((DWORD)pFileBuffer + foaOriginalFirstThunk);
printf("Show the OriginalFirstThunk:\n");
while (OriginalThunkValue)
{
	printf("RVA_OriginalFirstThunk: %2x    FOA_OriginalFirstThunk: %2x", pImportDescriptor->OriginalFirstThunk, foaOriginalFirstThunk);
	printf("    OriginalThunkValue: %2x\n", OriginalThunkValue);
}
puts("");

在这里插入图片描述

4 打印IMAGE_THUNK_DATA32(ThunkValue所指向的值)

如果最高位为1 那么去掉1之后的就是函数序号
否则该值指向_IMAGE_IMPORT_BY_NAME

struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;                 
    BYTE    Name[1];            
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

结构: 双字节的Hint 以及name的起始地址

if ((OriginalThunkValue & 0x80000000) == 0x1)
{
	DWORD ordinalOfFunction = (OriginalThunkValue & 0x7FFFFFFF);
	TODO;
}
else
{
	DWORD RVA_OFT_HintAndNameOfFunction = OriginalThunkValue;
	DWORD FOA_OFT_HintAndNameOfFunction = RvaDataToFoaData(pFileBuffer, RVA_OFT_HintAndNameOfFunction, FALSE);
	WORD hint = *(WORD *)((DWORD)pFileBuffer + FOA_OFT_HintAndNameOfFunction);
	char * NameOfFunction = (char *)((DWORD)pFileBuffer + FOA_OFT_HintAndNameOfFunction + 2);
	printf("RVA_OriginalThunkNameOfFunction: %2x    FOA_NameOfFunction: %2x\n", RVA_OFT_HintAndNameOfFunction, FOA_OFT_HintAndNameOfFunction);
	printf("OriginalThunkHint: %2x\nNameOfFunction: %2s\n\n", hint, NameOfFunction);
}

在这里插入图片描述

5 重复2 3 4打印FirstThunk相关
整体代码
while (pImportDescriptor->OriginalFirstThunk)
{
	DWORD rvaFirstThunk= pImportDescriptor->FirstThunk;
	DWORD rvaOriginalFirstThunk = pImportDescriptor->OriginalFirstThunk;
	printf("RVA_OriginalFirstTunk: %2x    RVA_Name: %2x    RVA_FirstThunk: %2x\n", pImportDescriptor->OriginalFirstThunk, pImportDescriptor->Name, pImportDescriptor->FirstThunk);
	DWORD foaName = RvaDataToFoaData(pFileBuffer, pImportDescriptor->Name, FALSE);
	printf("DLL's name: %s\n", (char *)((DWORD)pFileBuffer + foaName));
	printf("-------------------------------------------------------------------------\n");

	DWORD foaOriginalFirstThunk = RvaDataToFoaData(pFileBuffer, rvaOriginalFirstThunk, FALSE);
	DWORD OriginalThunkValue = *(DWORD *)((DWORD)pFileBuffer + foaOriginalFirstThunk);
	printf("Show the OriginalFirstThunk:\n");
	while (OriginalThunkValue)
	{
		printf("RVA_OriginalFirstThunk: %2x    FOA_OriginalFirstThunk: %2x", pImportDescriptor->OriginalFirstThunk, foaOriginalFirstThunk);
		printf("    OriginalThunkValue: %2x\n", OriginalThunkValue);
		if ((OriginalThunkValue & 0x80000000) == 0x1)
		{
			DWORD ordinalOfFunction = (OriginalThunkValue & 0x7FFFFFFF);
			TODO;
		}
		else
		{
			DWORD RVA_OFT_HintAndNameOfFunction = OriginalThunkValue;
			DWORD FOA_OFT_HintAndNameOfFunction = RvaDataToFoaData(pFileBuffer, RVA_OFT_HintAndNameOfFunction, FALSE);
			WORD hint = *(WORD *)((DWORD)pFileBuffer + FOA_OFT_HintAndNameOfFunction);
			char * NameOfFunction = (char *)((DWORD)pFileBuffer + FOA_OFT_HintAndNameOfFunction + 2);
			printf("RVA_OriginalThunkNameOfFunction: %2x    FOA_NameOfFunction: %2x\n", RVA_OFT_HintAndNameOfFunction, FOA_OFT_HintAndNameOfFunction);
			printf("OriginalThunkHint: %2x\nNameOfFunction: %2s\n\n", hint, NameOfFunction);
		}
		pImportDescriptor->OriginalFirstThunk += 4;
		foaOriginalFirstThunk = RvaDataToFoaData(pFileBuffer, pImportDescriptor->OriginalFirstThunk, FALSE);
		OriginalThunkValue = *(DWORD *)((DWORD)pFileBuffer + foaOriginalFirstThunk);
	}
	puts("");

	DWORD foaFirstThunk = RvaDataToFoaData(pFileBuffer, rvaFirstThunk, FALSE);
	DWORD FirstThunkValue = *(DWORD *)((DWORD)pFileBuffer + foaFirstThunk);
	printf("Show the FirstThunk: \n");
	while (FirstThunkValue)
	{
		printf("RVA_FirstThunk: %2x            FOA_FirstThunk: %2x", rvaFirstThunk, foaFirstThunk);
		
		printf("            FirstThunkValue: %2x\n", FirstThunkValue);
		if ((FirstThunkValue & 0x80000000) == 0x1)
		{
			DWORD ordinalOfFunction = (FirstThunkValue & 0x7FFFFFFF);
			TODO;
		}
		else
		{
			DWORD RVA_FT_HintAndNameOfFunction = FirstThunkValue;
			DWORD FOA_FT_HintAndNameOfFunction = RvaDataToFoaData(pFileBuffer, RVA_FT_HintAndNameOfFunction, FALSE);
			WORD hint = *(WORD *)((DWORD)pFileBuffer + FOA_FT_HintAndNameOfFunction);
			char * NameOfFunction = (char *)((DWORD)pFileBuffer + FOA_FT_HintAndNameOfFunction + 2);
			printf("RVA_FirstThunkNameOfFunction: %2x    FOA_FirstThunkNameOfFunction: %2x\n", RVA_FT_HintAndNameOfFunction, FOA_FT_HintAndNameOfFunction);
			printf("FirstThunkHint: %2x\nFirstThunkNameOfFunction: %2s\n\n", hint, NameOfFunction);
		}
		pImportDescriptor->FirstThunk += 4;
		foaFirstThunk = RvaDataToFoaData(pFileBuffer, pImportDescriptor->FirstThunk, FALSE);
		FirstThunkValue = *(DWORD *)((DWORD)pFileBuffer + foaFirstThunk);
	}
	puts("");

	pImportDescriptor++;
	printf("-------------------------------------------------------------------------\n");
}
最终结果

在这里插入图片描述

真的分析

ps: 为了方便分析程序用的视频同款Messagebox函数…
在这里插入图片描述

导入表中最重要的三个数据OriginalFirstThunk Name FirstThunk, 名字没什么好说的.

OFT FT 分为PE加载前和加载后, 分别存放Immpor Name Table与 Import Address Table
但是里面在PE加载前即二进制文件是一模一样的 真正产生区别的在于PE加载后.
在这里插入图片描述
在这里插入图片描述
OD中看到 [40203C]直接指向了函数地址

这里发生改变的原因是加载PE文件后系统会遍历INT并调用GetProcAddress得到函数地址复制到IAT中.

一些问题

为什么要有两个表?
第一个原因是如果直接在IAT中写入地址没有INT那么想要获取函数名字就有困难, 相当于给api备份.
我自己想的是每个电脑的地址不一样 每次动态加载需要依靠函数名字来获取. 保证在不同的机器上运行
老师讲学了下个表才能讲第二个原因, 学完回来更新.

学完本节, 最大的感悟就是预习, OFT和FP困扰我挺久, 其实先把表遍历出来的就是在预习, 当自己能先把表遍历完, 再去理解内容就变得很清晰.

在这里插入图片描述
ps: 建了个学习讨论群, 欢迎新朋友加入:1094301686

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

四位

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

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

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

打赏作者

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

抵扣说明:

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

余额充值