手工解析PE(导出表的使用)

手工解析PE(导出表)_GNAIXGNAHZ的博客-CSDN博客上一节讲了如何解析导出表的结构,最终结果就是要解析出导出表的三个地址:名称表地址、序号表地址、函数表地址,有了这三张表 我们才可以进一步使用导出表,找到我们想要的函数地址

名称表中存放的是名称的地址,所以我们找到名称表时,不能直接用里面的值,需要解引用得到的才是函数名称

序号表中存放的是导出函数的序号,但是并不是真正的序号,表值+base 才是真正导出序号,所以我们在使用时,找到序号表的值后还需要加base才可以

函数表中存放的是导出函数的地址,这个地址是内存中的地址,只要我们清楚函数表中第几个是我们要的函数,就可以取到对应的地址

名称表、序号表、函数表 都可以通过解析导出表结构得到:

步骤

有了这三张表,我们

首先要遍历名称表,找到我们需要的函数和其所在名称表的名称下标,

然后根据名称下标 = 序号表的下标 找到序号表下标所对应的序号

最后根据序号表中的序号 = 函数表下标 找到函数表中的函数地址

注意以上提到的地址全是内存地址,在使用时转化为文件地址更方便我们操作

代码如下

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "mycode.h"

int main()
{
	char* sourcefile="D:\\CODE\\DLL\\TestDll.dll";
	//char* sourcefile="D:\\CODE\\DEMO\\004\\Debug\\004.dll";
	char* ptr=read_file_to_file_buffer(sourcefile);
	
	PE filePE;
	set_pe(ptr,&filePE);
	printf("导出表地址:%x \n",*filePE.pdirectory_entry_export_virtualaddress);
	int FOA=0x99999999;
	int i=0;
	for( i;i<16;i++ )
	{
		FOA=trans_RVA_to_FOA(*filePE.DIR[i].pvirtualaddress,sourcefile);
		printf("第%d个表:\n",i+1);
		printf("RVA地址:%x\t\t",*filePE.DIR[i].pvirtualaddress);
		printf("FOA地址:%x\t\t",FOA);
		printf("大小:%x\n",*filePE.DIR[i].psize);
	
	}
	//地址表 地址
	char* addressoffunctions = ptr + *filePE.addressoffunctions;	//每次移动4字节
	char* addressofordianls = ptr + *filePE.addressofnameordinals;	//每次移动2字节
	char* addressofnames = ptr + *filePE.addressofnames;			//每次移动4字节

	//[地址][名称数组下标][名称地址]
	int funs_index;			//[函数数组下标]
	int ordi_index;			//[序号数组下标]
	int name_index;			//[名称数组下标]

	int funs_value_rva;		//[函数地址]
	int ordi_value_rva;		//[序号值]
	int name_value_rva;		//[名称地址]

	int funs_value_foa;		//rva对应的foa
	int ordi_value_foa;		//rva对应的foa
	int name_value_foa;		//rva对应的foa

	//遍历名称地址表
	//遍历序号地址表
	//遍历函数地址表


	//遍历名称地址表
	printf("\n名称列表:\n");
	int name_length=0;
	for( name_index=0;name_index < *filePE.numberofnames;name_index++)
	{
		name_value_rva = *((int*)addressofnames+name_index);				//名称表里 存的是名字的地址 想得到名字 需要加*	 [地址][名称数组下标][名称地址]
		name_value_foa = trans_RVA_to_FOA(name_value_rva,sourcefile);
		printf("\n 名称地址name_value_rva : %p\t 名称地址name_value_foa : %p\  ",name_value_rva,name_value_foa ); 
		//计算名称长度  直到0x00结尾 名称结束
		name_length=0;
		for(i=0;*(ptr + name_value_foa + i +1) != 0x00;i++)
		{
			name_length++;
		}
		//打印名称
		printf("函数名称:[%d]",name_index); 
		for(i=0;i<=name_length+1;i++)
		{
			printf("%c",*(ptr + name_value_foa + i -1)); 
		}
	}

	//遍历序号地址表
	printf("\n\n序号列表:\n\n");
	for( ordi_index=0;ordi_index < *filePE.numberofnames;ordi_index++)
	{
		ordi_value_rva = *((short*)addressofordianls + ordi_index);
		printf("[%d]:%d \n",ordi_index,ordi_value_rva);
	}

	//遍历函数地址表
	printf("\n函数列表:\n");
	for( funs_index=0;funs_index < *filePE.numberoffunctions;funs_index++)
	{
		funs_value_rva = *((int*)addressoffunctions + funs_index);
		funs_value_foa =  trans_RVA_to_FOA(funs_value_rva,sourcefile);
		printf("\n [%d] 函数地址funs_value_rva : %p\t 函数地址funs_value_foa : %p  ",funs_index,funs_value_rva,funs_value_foa );  
	}

	//根据名称查找函数地址
	char* findname="Mul";
	//根据序号查找函数地址
	int findno=1;

	//printf("\n\n当前查找函数: %s  长度  %d \n",findname,strlen(findname));
	//strcmp(char *a, char *b);

	//1.根据名称 在名称表 找到序号表的下标
	int findnameresultno=0;
	for( name_index=0;name_index < *filePE.numberofnames;name_index++)
	{
		name_value_rva = *((int*)addressofnames+name_index);				//名称表里 存的是名字的地址 想得到名字 需要加*	 [地址][名称数组下标][名称地址]
		name_value_foa = trans_RVA_to_FOA(name_value_rva,sourcefile);
		printf("\n 名称地址name_value_rva : %p\t 名称地址name_value_foa : %p\  ",name_value_rva,name_value_foa ); 
		//计算名称长度  直到0x00结尾 名称结束
		name_length=0;
		for(i=0;*(ptr + name_value_foa + i +1) != 0x00;i++)
		{
			name_length++;
		}
		//打印名称
		printf("函数名称:[%d]",name_index); 
		for(i=0;i<=name_length+1;i++)
		{
			printf("%c",*(ptr + name_value_foa + i -1)); 
		}
		//判断是否相对
		
		if( memcmp(findname,ptr + name_value_foa,name_length + 2) == 0  ) //加2 是为了到达 0x00的长度
		{
			findnameresultno=name_index;
			//printf("\n\t find result oridinal下标: %d \n",findnameresultno);
		}
	}

	//2.根据序号表的下标 在序号表 找到函数表的下标
	int findordiresultno;
	for( ordi_index=0;ordi_index < *filePE.numberofnames;ordi_index++)
	{
		if( ordi_index == findnameresultno)
		{
			ordi_value_rva = *((short*)addressofordianls + ordi_index);
			findordiresultno=ordi_value_rva;
			//printf("\t \nfind result 序号: %d \n",findordiresultno + *filePE.base); //序号 = base + 表值
			//printf("\t \nfind result 函数下标: %d \n",findordiresultno);
		}
	}

	//3.根据函数表的下标 在函数表 找到函数的地址
	int findfunresultaddr;
	for( funs_index=0;funs_index < *filePE.numberoffunctions;funs_index++)
	{
		if( funs_index == findordiresultno )
		{
			funs_value_rva = *((int*)addressoffunctions + funs_index);
			funs_value_foa =  trans_RVA_to_FOA(funs_value_rva,sourcefile);
			findfunresultaddr = funs_value_foa;
			//printf("\t find result 函数地址RVA: %x \n",funs_value_rva);
			//printf("\t find result 函数地址FOA: %x \n",funs_value_foa);
		}
	}

	printf("\n\n当前查找函数: %s  长度  %d \n",findname,strlen(findname));
	printf("\t find result oridinal下标: %d \n",findnameresultno);
	printf("\t find result 序号: %d \n",findordiresultno + *filePE.base); //序号 = base + 表值
	printf("\t find result 函数下标: %d \n",findordiresultno);
	printf("\t find result 函数地址RVA: %x \n",funs_value_rva);
	printf("\t find result 函数地址FOA: %x \n",funs_value_foa);

	return 0;
}



运行结果如下,可以把三张表的内容全都遍历出来,最终结果与PE工具对比一致

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值