手工解析PE(重定位表)

每个DLL都有自己的imagebase,如果有多个DLL的imagebase相同,那么地址就会冲突,为了防止两个函数共用同一个地址,引入了重定位表,修改函数地址,重定位表中分为几块,每一块中又分为几项

根据PE标志找出16个数据目录中的第六个就是重定位表,根据重定位表的地址可以找到重定位表,在重定位表中继续细分,就是每一块,每一块中再细分 就是每一项,不想解释了,我都快绕晕了,反正代码就是这样 能运行 结果也没有问题,就这样吧

代码如下

<mycode.cpp>

void set_pe(char* ptr,PE* p_PE )
{
	//DOS头
	p_PE->p_e_magic=(short*)ptr;	//MZ标记 用于判断是否为可执行文件
	p_PE->p_e_cblp=(short*)ptr+1;
	p_PE->p_e_cp=(short*)ptr+2;
	p_PE->p_e_crlc=(short*)ptr+3;
	p_PE->p_e_cparhdr=(short*)ptr+4;
	p_PE->p_e_minalloc=(short*)ptr+5;
	p_PE->p_e_maxalloc=(short*)ptr+6;
	p_PE->p_e_ss=(short*)ptr+7;
	p_PE->p_e_sp=(short*)ptr+8;
	p_PE->p_e_csum=(short*)ptr+9;
	p_PE->p_e_ip=(short*)ptr+10;
	p_PE->p_e_cs=(short*)ptr+11;
	p_PE->p_e_lfarlc=(short*)ptr+12;
	p_PE->p_e_ovno=(short*)ptr+13;
	p_PE->p_e_res=(short*)ptr+17;
	p_PE->p_e_oemid=(short*)ptr+18;
	p_PE->p_e_oeminfo=(short*)ptr+19;
	p_PE->p_e_res2=(short*)ptr+20;
	p_PE->p_e_lfanew=(int*)ptr+15;  //第60个字节  一行16个字节 第四行的最后四个字节就是 e_lfanew,从文件开始偏移 *p_e_lfanew 就是PE
	//PE标记
	p_PE->p_signature = ptr+(*(p_PE->p_e_lfanew));
	//标准PE头
	p_PE->p_machine=(short*)(p_PE->p_signature+4);	//程序运行的CPU型号   0x0任何处理器 0x14C 386及后续处理器
	p_PE->p_numberofsections=(short*)(p_PE->p_signature+6);	//节的总数
	p_PE->p_timedatestamp=(int*)(p_PE->p_signature+8);
	p_PE->p_pointertosymboltable=(int*)(p_PE->p_signature+12);
	p_PE->p_numberofsymbols=(int*)(p_PE->p_signature+16);
	p_PE->p_sizeofoptionalheader=(short*)(p_PE->p_signature+20);	//可选PE头的大小  32位默认E0 64位默认F0 可以自定义
	p_PE->p_characteristics=(short*)(p_PE->p_signature+22);
	//可选PE头
	p_PE->p_magic=(short*)(p_PE->p_signature+24);	//程序运行的CPU型号   0x0任何处理器 0x14C 386及后续处理器
	p_PE->p_majorlinkerversion=(char*)(p_PE->p_signature+26);
	p_PE->p_minorlinkerversion=(char*)(p_PE->p_signature+27);
	p_PE->p_sizeofcode=(int*)(p_PE->p_signature+28); //所有代码节的和 内存对齐字节数的整数倍
	p_PE->p_sizeofinitializeddata=(int*)(p_PE->p_signature+32);	//初始化的数据大小
	p_PE->p_sizeofuninitializeddata=(int*)(p_PE->p_signature+36);	//未初始化的数据的大小
	p_PE->p_addressofentrypoint=(int*)(p_PE->p_signature+40);		//程序入口
	p_PE->p_baseofcode=(int*)(p_PE->p_signature+44);
	p_PE->p_baseofdata=(int*)(p_PE->p_signature+48);
	p_PE->p_imagebase=(int*)(p_PE->p_signature+52);				//内存镜像基址
	p_PE->p_sectionalignment=(int*)(p_PE->p_signature+56);	//内存对齐字节数
	p_PE->p_filealignment=(int*)(p_PE->p_signature+60);	//文件对齐字节数
	p_PE->p_majoroperatingsystemversion=(short*)(p_PE->p_signature+64);
	p_PE->p_minoroperatingsystemversion=(short*)(p_PE->p_signature+66);
	p_PE->p_majorimageversion=(short*)(p_PE->p_signature+68);
	p_PE->p_minorimageversion=(short*)(p_PE->p_signature+70);
	p_PE->p_majorsubsystemversion=(short*)(p_PE->p_signature+72);
	p_PE->p_minorsubsystemversion=(short*)(p_PE->p_signature+74);
	p_PE->p_win32versionvalue=(int*)(p_PE->p_signature+76);
	p_PE->p_sizeofimage=(int*)(p_PE->p_signature+80);
	p_PE->p_sizeofheaders=(int*)(p_PE->p_signature+84);
	p_PE->p_checksum=(int*)(p_PE->p_signature+88);
	p_PE->p_subsystem=(short*)(p_PE->p_signature+92);
	p_PE->p_dllcharacteristics=(short*)(p_PE->p_signature+94);
	p_PE->p_sizeofstackreserve=(int*)(p_PE->p_signature+96);
	p_PE->p_sizeofstackcommit=(int*)(p_PE->p_signature+100);
	p_PE->p_sizeofheapreserve=(int*)(p_PE->p_signature+104);
	p_PE->p_sizeofheapcommit=(int*)(p_PE->p_signature+108);
	p_PE->p_loaderflags=(int*)(p_PE->p_signature+112);
	p_PE->p_numberofrvaandsizes=(int*)(p_PE->p_signature+116);
	p_PE->p_datadirectory_base=(char*)(p_PE->p_signature+120);
	//节表
	p_PE->image_section_header_base=(p_PE->p_signature)+4+20+ *(p_PE->p_sizeofoptionalheader);
	memcpy(p_PE->name,p_PE->image_section_header_base,8);
	p_PE->name[8]='\0';
	p_PE->pmisc=(int*)(p_PE->image_section_header_base+8);
	p_PE->pvirtualaddress=(int*)(p_PE->image_section_header_base+12);
	p_PE->psizeofrawdata=(int*)(p_PE->image_section_header_base+16);
	p_PE->ppointertorawdata=(int*)(p_PE->image_section_header_base+20);
	p_PE->ppointertorelocations=(int*)(p_PE->image_section_header_base+24);
	p_PE->ppointertolinenumbers=(int*)(p_PE->image_section_header_base+28);
	p_PE->pnumberofrelocations=(short*)(p_PE->image_section_header_base+32);
	p_PE->pnumberoflinenumbers=(short*)(p_PE->image_section_header_base+34);
	p_PE->pcharacteristics=(int*)(p_PE->image_section_header_base+36);

	p_PE->DIR[0].pvirtualaddress=(int*)(p_PE->p_signature+120);		//导出表地址
	p_PE->DIR[1].pvirtualaddress=(int*)(p_PE->p_signature+128);
	p_PE->DIR[2].pvirtualaddress=(int*)(p_PE->p_signature+136);
	p_PE->DIR[3].pvirtualaddress=(int*)(p_PE->p_signature+144);
	p_PE->DIR[4].pvirtualaddress=(int*)(p_PE->p_signature+152);
	p_PE->DIR[5].pvirtualaddress=(int*)(p_PE->p_signature+160);    //重定位表地址
	p_PE->DIR[6].pvirtualaddress=(int*)(p_PE->p_signature+168);
	p_PE->DIR[7].pvirtualaddress=(int*)(p_PE->p_signature+176);
	p_PE->DIR[8].pvirtualaddress=(int*)(p_PE->p_signature+184);
	p_PE->DIR[9].pvirtualaddress=(int*)(p_PE->p_signature+192);
	p_PE->DIR[10].pvirtualaddress=(int*)(p_PE->p_signature+200);
	p_PE->DIR[11].pvirtualaddress=(int*)(p_PE->p_signature+208);
	p_PE->DIR[12].pvirtualaddress=(int*)(p_PE->p_signature+216);
	p_PE->DIR[13].pvirtualaddress=(int*)(p_PE->p_signature+224);
	p_PE->DIR[14].pvirtualaddress=(int*)(p_PE->p_signature+232);
	p_PE->DIR[15].pvirtualaddress=(int*)(p_PE->p_signature+240);

	p_PE->DIR[0].psize=(int*)(p_PE->p_signature+120+4);		//导出表地址
	p_PE->DIR[1].psize=(int*)(p_PE->p_signature+128+4);
	p_PE->DIR[2].psize=(int*)(p_PE->p_signature+136+4);
	p_PE->DIR[3].psize=(int*)(p_PE->p_signature+144+4);
	p_PE->DIR[4].psize=(int*)(p_PE->p_signature+152+4);
	p_PE->DIR[5].psize=(int*)(p_PE->p_signature+160+4);
	p_PE->DIR[6].psize=(int*)(p_PE->p_signature+168+4);
	p_PE->DIR[7].psize=(int*)(p_PE->p_signature+176+4);
	p_PE->DIR[8].psize=(int*)(p_PE->p_signature+184+4);
	p_PE->DIR[9].psize=(int*)(p_PE->p_signature+192+4);
	p_PE->DIR[10].psize=(int*)(p_PE->p_signature+200+4);
	p_PE->DIR[11].psize=(int*)(p_PE->p_signature+208+4);
	p_PE->DIR[12].psize=(int*)(p_PE->p_signature+216+4);
	p_PE->DIR[13].psize=(int*)(p_PE->p_signature+224+4);
	p_PE->DIR[14].psize=(int*)(p_PE->p_signature+232+4);
	p_PE->DIR[15].psize=(int*)(p_PE->p_signature+240+4);

	//导出表
	p_PE->p_datadirectory_base=(char*)(p_PE->p_signature+120);
	p_PE->pdirectory_entry_export_virtualaddress=(int*)(p_PE->p_signature+120);  //导出表地址 RVA内存地址
	p_PE->pdirectory_entry_export_size=(int*)(p_PE->p_signature+124);
	//重定位表
	p_PE->pdirectory_relocation_virtualaddress=(int*)(p_PE->p_signature+160);
	p_PE->sizeofblock=(int*)(p_PE->p_signature+164);

	//导出表属性
	p_PE->pexportdirectory_base= ptr + *p_PE->pdirectory_entry_export_virtualaddress;
	p_PE->characteristics=(int*)(p_PE->pexportdirectory_base);
	p_PE->timedatestamp=(int*)(p_PE->pexportdirectory_base+4);
	p_PE->majorversion=(short*)(p_PE->pexportdirectory_base+8);
	p_PE->minorversion=(short*)(p_PE->pexportdirectory_base+10);
	p_PE->exportname=(int*)(p_PE->pexportdirectory_base+12);			//导出表文件名
	p_PE->base=(int*)(p_PE->pexportdirectory_base+16);					//导出函数基址
	p_PE->numberoffunctions=(int*)(p_PE->pexportdirectory_base+20);		//导出函数个数
	p_PE->numberofnames=(int*)(p_PE->pexportdirectory_base+24);			//以函数名导出的函数个数
	p_PE->addressoffunctions=(int*)(p_PE->pexportdirectory_base+28);	//导出函数表地址
	p_PE->addressofnames=(int*)(p_PE->pexportdirectory_base+32);		//导出函数名称地址表
	p_PE->addressofnameordinals=(int*)(p_PE->pexportdirectory_base+36);	//导出函数序号地址表


}

//RVA转化为FOA
int trans_RVA_to_FOA(int pRVA,char* pfilename)
{
    //用于存放硬盘中 和 内存中的PE结构
	PE PE_file;
	PE PE_memory;
	//找出文件中的PE结构
	char* ptr=read_file_to_file_buffer(pfilename);
	set_pe(ptr,&PE_file);
	//为ImageBuffer申请空间
	char* p_imagebuffer;
	p_imagebuffer = (char*) malloc(*PE_file.p_sizeofimage);
	//找出内存中的PE结构
	if( p_imagebuffer == NULL)
	{
		printf("空间不足\n");
		return 0;
	}
	else
	{	
		memset(p_imagebuffer,0,*PE_file.p_sizeofimage);
		//这里一定要注意 p_imagebuffer里面有数据之后 才能set_pe 
		//FileBuffer内容 复制到 ImageBuffer
		trans_file_buffer_to_image_buffer(ptr,p_imagebuffer);
		set_pe(p_imagebuffer,&PE_memory);
		//printf("ImageBuffer范围:%x --> %x \n",p_imagebuffer,p_imagebuffer+(*PE_file.p_sizeofimage));
	}
	//节表大小
	int sectablesize = *PE_file.p_numberofsections*40;
	//节表结束位置
	int sectableend = (int)(PE_memory.image_section_header_base + sectablesize);
	//printf("节表范围:%x --> %x \n",PE_memory.image_section_header_base,sectableend);

	int RVA = pRVA + (int)p_imagebuffer; 
	int FOA = 0x99999999;
	int section_no;			//RVA属于第几节
	int section_offset;				//RVA节偏移
	//printf("请输入RVA值\n");
	//scanf("%p",&RVA);
	//printf("RVA = %x \n",RVA);
	
	//如果RVA在节表结束之前 那么不用转换 直接减去基址就是FOA
	if( RVA < sectableend )
	{
		FOA = RVA - (int)p_imagebuffer;
		//printf("节表之前 无需转化 FOA = %x \n",FOA);
	}
	else
	{
	//找出 RVA在内存中节数 和 节偏移量
	int rva_offset = (char*)RVA - p_imagebuffer;
	//判断是第几个节
	int i=1;
	for(i;i<=*PE_memory.p_numberofsections;i++)
	{
		// RVA的偏移量  在 两点之间 此时的节数才是我们要的
		if(     rva_offset >=    *PE_memory.pvirtualaddress 
			&&  rva_offset <   ( *PE_memory.pvirtualaddress + (*PE_memory.pmisc) ) )
		{ 
			section_no=i;
			section_offset = rva_offset - *PE_memory.pvirtualaddress ;
			//printf("RVA是第%d个节   节偏移量为%d \n",section_no,section_offset);
			break;
		}
		//image_section_header_base=image_section_header_base+40;
		//这里注意 pvirtualaddress 要往下走40个字节(一个节表的大小),
		//因为pvirtualaddress 是int 所以指针需要加10 即可 
		PE_memory.pvirtualaddress=PE_memory.pvirtualaddress+10;	
        PE_memory.pmisc=PE_memory.pmisc+10;
	}
	//根据 节数  找出文件中节的位置  第n节 需要遍历n-1次
	for(i=1;i<section_no;i++)
	{
		PE_file.ppointertorawdata=PE_file.ppointertorawdata+10;	
	}
	//加上 节偏移量 得出最终在文件中的位置
	FOA=*PE_file.ppointertorawdata+section_offset;
	//printf("FOA = %x \n",*PE_file.ppointertorawdata+section_offset);
	}
	//释放内存
	free(p_imagebuffer);
	p_imagebuffer=NULL;
	read_file_to_file_buffer_free(ptr);
	return FOA;
}


//内存地址对齐
char* trans_memory_order(char* paddr,int poffset,int block)
{
	int zhengshu=((int)(paddr+poffset))/block;
	int yushu= (int)(paddr+poffset) - zhengshu*block;
	int addsize=block-yushu;
	return (char*)(paddr + poffset + addsize);
}
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "mycode.h"

int main()
{
	char* sourcefile="D:\\CODE\\DLL\\TestDll.dll";
	char* ptr=read_file_to_file_buffer(sourcefile);
	
	PE filePE;
	set_pe(ptr,&filePE);
	//重定位表   
	int relocation_virtualaddress_foa = trans_RVA_to_FOA(*filePE.pdirectory_relocation_virtualaddress,sourcefile);
	printf("重定位表地址RVA:%x \t FOA:%x \n",*filePE.pdirectory_relocation_virtualaddress,relocation_virtualaddress_foa);
	printf("重定位表大小:%x \n",*filePE.sizeofblock);
	//重定位表的每一块
	int block_base= (int)(ptr+relocation_virtualaddress_foa);	//所有块的起始地址
	int no_block_addr = *(int*)block_base;						//第n块的起始地址
	int no_block_size = *(int*)((char*)block_base+4);			//第n块的大小
	
	int next_block_addr=0;			//下一块的地址
	int next_block_size=0x9999;		//下一块的大小
	int all_block=0;				//块数
	int all_item=0;					//每一块的项数
	int items=0;					//第几项
	int i,j;
	short block_item;				//每一项的地址
	int block_item_addr;			//地址的低12位
	int attribute;					//地址的高4位
	for( i=1; next_block_size != 0; i++ ) //下一块大小为0时 结束
	{
		items=(no_block_size-8)/2;
		printf("第%d块:RVA %x 大小%x 项数%x \n",i,no_block_addr,no_block_size,items);
		all_item=0;
		//重定位表每一块的每一项
		for(j=1;j<=items;j++)
		{
			block_item=*(short*)((char*)block_base+all_block+8+all_item*2 );
			attribute=block_item & 0xF000;				//高4位是属性
			block_item_addr=block_item & 0xFFF;			//低12位是rva地址
			printf("第%d项 RVA: %x 高4位:%x \n",j,no_block_addr+block_item_addr,attribute);
			
			all_item=all_item+1;
		}
		
		all_block=all_block+no_block_size;								//总块数增加
		next_block_addr = *(int*)((char*)block_base+all_block);			//下一块地址
		next_block_size = *(int*)((char*)block_base+all_block+4);		//下一块大小

		no_block_size=next_block_size;	//下一块改为当前块
		no_block_addr=next_block_addr;	//

	}
	return 0;
}


运行结果如下

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值