PE目录项之重定位表(解析、移动、模拟运作)

PE目录项之重定位表(解析、移动、模拟运作)

0.说明

观看滴水逆向视频总结(部分截图来自于滴水课件)

编译器:vc++6.0

编写语言:c

观看滴水逆向视频总结(部分截图来自于滴水课件)

欢迎大家留言交流😃^ __ ^

可以加我qq一起学习:1245885144😄🤣

这篇文章写得好!滴水逆向三期 PE基础 移动重定位表与修改IMAGEBASE

1.解析重定位表

(1)作用

背景

  1. 程序在加载的过程中,是将自己的pe文件按照SectionAlignment对齐+ImageBase拉伸后,贴到内存中,就会存在,多个dll无法站住自己的ImageBase,被迫修改ImageBase
  2. 每个文件的内存数据中,一部分的汇编语句的寻址,后面接的是一个固定的地址(硬编码),这个地址是在自己原有的ImageBase之上的。

如果一个PE结构修改ImageBase,那么文件内部的固定地址就会失效,且pe程序内的固定地址很多。

此时就需要一张表来记录 存储这些固定地址 的地址(RVA),当ImageBase修改时,系统随即根据这张表里记录的RVA,修正这个RVA所指向的固定地址。这张表就是重定位表。

image-20200703144516790

真正的重定位表还会有细分之处

(2)详解

image-20200703145746715

由于pe程序内存在很多要修改的固定地址,系统为了方便存储和查找,就将存储在pe内存中各个区段的固定地址,按RVA大小分成多个区段。(比如:1000~2000, 2000~3000 ,3000~4000……),且每个区段只需要记录一个区段头地址,下面的表就记录这个区段的RVA的尾部,这个尾部与区段头相或(或者相加),即得到真正的RVA。

image-20200703151418414

所以,

重定位表记录的要修改的固定地址所在内存位置的RVA:每个RVA区段(块)的VirtualAddress+(下面的2字节数据 & 0xfff),(取2进制数低12位)。

一般默认每个块的地址个数为:(SizeOfBlock - 8)/2

如何确定重定位表结束:因为每个RVA区段(块)是连在一起的,我们秩序按照SizeOfBlock,挨个遍历,如果VirtualAddress和SizeOfBlock同时为0,代表结束。

2.移动重定位表到新建节区

image-20200703154031902

3.模拟重定位表工作

(1)重定位表的工作

如果PE程序运行时,在内存中站住了自己ImageBase的内存位置,此时重定位表就没有用。

如果PE程序运行时,在内存中没有站住自己ImageBase的内存位置,就需要修正重定位表的固定地址。

比如,原本dll程序自身的ImageBase为10000000,但是发现内存中这个位置已有一个dll,而内存中12000000的位置是空的,那自己只能修改ImageBase为12000000,贴到这里来,两个位置差值为2000000,所以重定位表中的RVA所指向的每一个固定地址,都要自增2000000,这样就完成了重定位表的工作。

(2)模拟它工作

  1. 第一步:将PE文件读取到内存中。
  2. 第二步:修改ImageBase,记录ImageBase前后差值
  3. 第三部:遍历重定位表中的RVA所指向的固定地址,将其加上ImageBase的前后差值。
  4. 第四部:将PE文件存盘

不吹不黑,这篇文章写得好😃!滴水逆向三期 PE基础 移动重定位表与修改IMAGEBASE

4.C源代码

代码省略了新增节区和RVA与FOA的转换。

(1)解析重定位表

image-20200703155552292

image-20200703155607955

//功能:解析、打印重定位表
//参数:指向该程序被读取到内存的指针
//返回值:无
void ReadPE( LPVOID pFileBuffer )
{
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS32 pNtHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;

	PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;

	PIMAGE_BASE_RELOCATION pBaseRelocation = NULL;
 
DWORD Size = 0;
	DWORD i = 0;
	DWORD FOA=0;
	DWORD RVA=0;
	DWORD NumberOfRelocationAddress = 0;

	//注意是两字节型的指针
	PWORD pRelocation = NULL;//指向 重定位表中需要重定位的地址 的指针

	
	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer ;
	pNtHeader = (PIMAGE_NT_HEADERS32)( (DWORD)pDosHeader + pDosHeader->e_lfanew );
	pFileHeader = (PIMAGE_FILE_HEADER)( (DWORD)pNtHeader + 4);

	pOptionHeader = (PIMAGE_OPTIONAL_HEADER)( (DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER );
	
//	pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pDataDirectory[5];
//	pBaseRelocation = (PIMAGE_BASE_RELOCATION)( (DWORD)pDosHeader + ConvertRvaToFoa(pDataDirectory->VirtualAddress , pFileBuffer));
	
	pDataDirectory = (PIMAGE_DATA_DIRECTORY)pOptionHeader->DataDirectory ;
	pBaseRelocation	= (PIMAGE_BASE_RELOCATION)( (DWORD)pDosHeader + ConvertRvaToFoa( (&pDataDirectory[5])->VirtualAddress , pFileBuffer ) );//第6个目录表(重定位表的目录)的地址,
	
	while(pBaseRelocation->SizeOfBlock && pBaseRelocation->VirtualAddress )
	{
		pRelocation = (PWORD)( (DWORD)pBaseRelocation + IMAGE_SIZEOF_BASE_RELOCATION );//指向重定位表中的地址表
	
		printf("***************************************************************************************\n");
		printf("VirtualAddress :%-10x",pBaseRelocation->VirtualAddress );
		printf("SizeOfBlock :%-10X",pBaseRelocation->SizeOfBlock );
		
		NumberOfRelocationAddress = (pBaseRelocation->SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION)/2 ;
		
		printf("NumberOfRelocationAddress :%-10X\n", NumberOfRelocationAddress );

		printf("*********************************************\n");
		printf(" RVA(0x)             Type                FOA                 TrueRelocationAddress\n");

		for(i = NumberOfRelocationAddress ; i>0 ; pRelocation++ ,i-- )//pRelocation++遍历重定位表中的地址表
		{
			RVA = (*pRelocation&0xfff)|pBaseRelocation->VirtualAddress;
			printf(" %-20X", RVA);
			
			printf("%-20X", (*pRelocation&0xf000)>>12 );
			
			FOA = ConvertRvaToFoa(RVA , pFileBuffer);
			printf("%-20X", FOA);

			printf("%-20X\n",*(PDWORD)( (DWORD)pDosHeader + FOA));
		}
		Size +=pBaseRelocation->SizeOfBlock;
		
		pBaseRelocation = (PIMAGE_BASE_RELOCATION)( (DWORD)pBaseRelocation + pBaseRelocation->SizeOfBlock );//遍历重定位表
		printf("\n");

	}

	printf("%x\n",Size);
	printf("%X\n",(&pDataDirectory[5])->Size );

	free(pFileBuffer);
}

(2)移动重定位表

//功能:移动重定位表到新增节
//参数:指向文件内存的指针
//返回值:无
void MoveRelocationTableToNewSection( LPVOID pFileBuffer )
{	
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS32 pNtHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;
	
	PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
	
	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer ;
	pNtHeader = (PIMAGE_NT_HEADERS32)( (DWORD)pDosHeader + pDosHeader->e_lfanew );
	pFileHeader = (PIMAGE_FILE_HEADER)( (DWORD)pNtHeader + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER)( (DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
	
	pDataDirectory = (PIMAGE_DATA_DIRECTORY)pOptionHeader->DataDirectory;

	//复制重定位表
	memcpy( (PDWORD)( (DWORD)pDosHeader+FileSize) , (PDWORD)( (DWORD)pDosHeader+ ConvertRvaToFoa( (&pDataDirectory[5])->VirtualAddress , pFileBuffer) ) ,(&pDataDirectory[5])->Size );

	//修改指向重定位表的指针
	(&pDataDirectory[5])->VirtualAddress = ConvertFoaToRva( FileSize , pFileBuffer  );

}	

(3)模拟重定位表工作

image-20200703160402851

//功能:修正重定位表(先修改ImageBase,再修正重定位表)
//参数:指向该程序被读取到内存的指针
//返回值:无
void AmendRelocationTable( LPVOID pFileBuffer )
{
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS32 pNtHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;

	PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
	PIMAGE_BASE_RELOCATION pBaseRelocation = NULL;
	
	DWORD i =0;
	DWORD ImageBaseOffset = 0;//ImageBase的偏移
	PWORD pRelocation = NULL;

	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer ;
	pNtHeader = (PIMAGE_NT_HEADERS32)( (DWORD)pDosHeader + pDosHeader->e_lfanew );
	pFileHeader = (PIMAGE_FILE_HEADER)( (DWORD)pNtHeader + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER)( (DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
	
	pDataDirectory = (PIMAGE_DATA_DIRECTORY)pOptionHeader->DataDirectory ;
	
	pBaseRelocation = (PIMAGE_BASE_RELOCATION)( (DWORD)pDosHeader + ConvertRvaToFoa( (&pDataDirectory[5])->VirtualAddress , pFileBuffer)  );
	
	//ImageBase的偏移
	ImageBaseOffset = 0x200000;
	
	//修改ImageBase
	printf("ImageBase :%X\n",pOptionHeader->ImageBase );
	pOptionHeader->ImageBase += ImageBaseOffset;
	printf("Amended,ImageBase :%X\n",pOptionHeader->ImageBase );

	
	while(  pBaseRelocation->VirtualAddress && pBaseRelocation->SizeOfBlock  )
	{
		pRelocation = (PWORD)( (DWORD)pBaseRelocation + IMAGE_SIZEOF_BASE_RELOCATION);
		
		for(i = (pBaseRelocation->SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION)/2 ; i>0 ; pRelocation++ ,i--)//遍历重定位表中的地址
			if( (*pRelocation) >>12 )
				*(PDWORD)( (DWORD)pDosHeader + ConvertRvaToFoa( (*pRelocation&0xfff)|pBaseRelocation->VirtualAddress  , pFileBuffer) ) += ImageBaseOffset;

		pBaseRelocation = (PIMAGE_BASE_RELOCATION)( (DWORD)pBaseRelocation + pBaseRelocation->SizeOfBlock );//遍历重定位表
	}
}

可以加我qq一起学习:1245885144😄🤣

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值