PE导出表

导出表位于数据目录表的第一个位置
导出表结构

typedef struct _IMAGE_EXPORT_DIRECTORY {
  +0x0   DWORD   Characteristics;   
  +0x4   DWORD   TimeDateStamp;  
  +0x8   WORD    MajorVersion;
  +0xa   WORD    MinorVersion;
  +0xc   DWORD   Name; //指向该导出表文件名	(RVA)
  +0x10  DWORD   Base;//导出表的起始序号 (序号表的最小序号)
  +0x14  DWORD   NumberOfFunctions;      // 所有导出函数的个数(序号的最大减去最小+1)
  +0x18  DWORD   NumberOfNames;          //以函数名导出的函数的个数  序号表的个数
  +0x1c  DWORD   AddressOfFunctions;     //导出函数的地址表偏移(RVA)
  +0x20  DWORD   AddressOfNames;         //函数名称表偏移(RVA)
  +0x24  DWORD   AddressOfNameOrdinals;  //函数序号表偏移(RVA)
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

在这里插入图片描述

测试DLL导出函数序号和名字

LIBRARY test
EXPORTS

add @15  
sub @11
mul @31
div1 @17
VOID PrintExportTable(PVOID pImageBuffer)
{
	DWORD dwAddressOfExportTable = 0;
	DWORD dwSizeOfExportTable = 0;
	//获取image_export_table 结构的数据

	PIMAGE_NT_HEADERS NtHeaders = (PIMAGE_NT_HEADERS)(((PIMAGE_DOS_HEADER)pImageBuffer)->e_lfanew + (ULONG_PTR)pImageBuffer);
	if (NtHeaders->OptionalHeader.Magic == 0x10b)
	{
		dwAddressOfExportTable = ((PIMAGE_OPTIONAL_HEADER32)(&NtHeaders->OptionalHeader))->DataDirectory[0].VirtualAddress;
		dwSizeOfExportTable = ((PIMAGE_OPTIONAL_HEADER32)(&NtHeaders->OptionalHeader))->DataDirectory[0].Size;
	}
	else
	{
		dwAddressOfExportTable = ((PIMAGE_OPTIONAL_HEADER64)(&NtHeaders->OptionalHeader))->DataDirectory[0].VirtualAddress;
		dwSizeOfExportTable = ((PIMAGE_OPTIONAL_HEADER64)(&NtHeaders->OptionalHeader))->DataDirectory[0].Size;
	}

	if (0 == dwAddressOfExportTable)
	{
		return;
	}

	PIMAGE_EXPORT_DIRECTORY pied = (PIMAGE_EXPORT_DIRECTORY)((char*)pImageBuffer + dwAddressOfExportTable);
	PULONG   AddressOfFunctions = (PULONG)((char*)pImageBuffer + pied->AddressOfFunctions);
	PULONG   AddressOfNames = (PULONG)((char*)pImageBuffer + pied->AddressOfNames);
	PUSHORT   AddressOfNameOrdinals = (PUSHORT)((char*)pImageBuffer + pied->AddressOfNameOrdinals);

	printf("DLL名字%s  导出Base:%d\n", (char*)(pied->Name +(ULONG64)pImageBuffer), pied->Base);
	
	/*
	在内存中的排列
		导出地址表 
		导出名字表
		导出序号表
		这三个表紧挨着  因此 遍历导出地址表可以AddressOfFunctions < AddressOfNames来判断边界
	*/
	//导出地址表
	int iIndex = 0;
	while (AddressOfFunctions < AddressOfNames)
	{
		if (*AddressOfFunctions)
		{
			printf("索引:%d  函数地址:0x%x\n", iIndex, *AddressOfFunctions);
		}
		AddressOfFunctions++;
		iIndex++;
	}
	printf("\n\n");
	//导出名字表  函数名字表是按照字母顺序排列的(可以二分法查找)
	for (size_t i = 0; i < pied->NumberOfNames; i++)
	{
		printf("导出函数名:%s\n", (char*)pImageBuffer + AddressOfNames[i]);
	}
	printf("\n\n");
	//导出序号表紧挨着的是 pied->Name  然后是函数名
	while (AddressOfNameOrdinals < pied->Name + (ULONG64)pImageBuffer)
	{
		//实际的序号值是减去了Base
		printf("序号表中序号:%d  真正的导出序号:%d\n", *AddressOfNameOrdinals ,*AddressOfNameOrdinals + pied->Base);
		AddressOfNameOrdinals++;
	}
}

打印的3张表如下
在这里插入图片描述

在这里插入图片描述

根据名字查找函数地址:

例如查找mul函数:
1:在名字表中对比,mul函数在名字表中的索引是2 (从0开始)
2:在序号表索引2找出函数索引,在这里是20
3:在地址表索引20的位置得到函数地址0xc7a0

根据序号找函数地址

例如查找序号15
1.序号减去base 得到4
2.对比序号表,第0项就是序号4
3.函数名就是名字表第0项 add
4.在地址表索引4找到函数地址0xc7c0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值