PE目录项之重定位表(解析、移动、模拟运作)
文章目录
0.说明
观看滴水逆向视频总结(部分截图来自于滴水课件)
编译器:vc++6.0
编写语言:c
观看滴水逆向视频总结(部分截图来自于滴水课件)
欢迎大家留言交流😃^ __ ^
可以加我qq一起学习:1245885144😄🤣
这篇文章写得好!滴水逆向三期 PE基础 移动重定位表与修改IMAGEBASE
1.解析重定位表
(1)作用
背景
- 程序在加载的过程中,是将自己的pe文件按照SectionAlignment对齐+ImageBase拉伸后,贴到内存中,就会存在,多个dll无法站住自己的ImageBase,被迫修改ImageBase
- 每个文件的内存数据中,一部分的汇编语句的寻址,后面接的是一个固定的地址(硬编码),这个地址是在自己原有的ImageBase之上的。
如果一个PE结构修改ImageBase,那么文件内部的固定地址就会失效,且pe程序内的固定地址很多。
此时就需要一张表来记录 存储这些固定地址 的地址(RVA),当ImageBase修改时,系统随即根据这张表里记录的RVA,修正这个RVA所指向的固定地址。这张表就是重定位表。
真正的重定位表还会有细分之处
(2)详解
由于pe程序内存在很多要修改的固定地址,系统为了方便存储和查找,就将存储在pe内存中各个区段的固定地址,按RVA大小分成多个区段。(比如:1000~2000, 2000~3000 ,3000~4000……),且每个区段只需要记录一个区段头地址,下面的表就记录这个区段的RVA的尾部,这个尾部与区段头相或(或者相加),即得到真正的RVA。
所以,
重定位表记录的要修改的固定地址所在内存位置的RVA:每个RVA区段(块)的VirtualAddress+(下面的2字节数据 & 0xfff),(取2进制数低12位)。
一般默认每个块的地址个数为:(SizeOfBlock - 8)/2
如何确定重定位表结束:因为每个RVA区段(块)是连在一起的,我们秩序按照SizeOfBlock,挨个遍历,如果VirtualAddress和SizeOfBlock同时为0,代表结束。
2.移动重定位表到新建节区
3.模拟重定位表工作
(1)重定位表的工作
如果PE程序运行时,在内存中站住了自己ImageBase的内存位置,此时重定位表就没有用。
如果PE程序运行时,在内存中没有站住自己ImageBase的内存位置,就需要修正重定位表的固定地址。
比如,原本dll程序自身的ImageBase为10000000,但是发现内存中这个位置已有一个dll,而内存中12000000的位置是空的,那自己只能修改ImageBase为12000000,贴到这里来,两个位置差值为2000000,所以重定位表中的RVA所指向的每一个固定地址,都要自增2000000,这样就完成了重定位表的工作。
(2)模拟它工作
- 第一步:将PE文件读取到内存中。
- 第二步:修改ImageBase,记录ImageBase前后差值
- 第三部:遍历重定位表中的RVA所指向的固定地址,将其加上ImageBase的前后差值。
- 第四部:将PE文件存盘
不吹不黑,这篇文章写得好😃!滴水逆向三期 PE基础 移动重定位表与修改IMAGEBASE
4.C源代码
代码省略了新增节区和RVA与FOA的转换。
(1)解析重定位表
//功能:解析、打印重定位表
//参数:指向该程序被读取到内存的指针
//返回值:无
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)模拟重定位表工作
//功能:修正重定位表(先修改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😄🤣