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

    技术2023-10-08  113

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

    文章目录

    PE目录项之重定位表(解析、移动、模拟运作)0.说明1.解析重定位表(1)作用(2)详解 2.移动重定位表到新建节区3.模拟重定位表工作(1)重定位表的工作(2)模拟它工作 4.C源代码(1)解析重定位表(2)移动重定位表(3)模拟重定位表工作

    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😄🤣

    Processed: 0.012, SQL: 9