PE 移动/修复重定位表
下面的代码实现:
1、先移动了重定位表
2、然后修改重定位表结构指向移动后的重定位的地址
3、接着手动Imagebase自增1000
4、最后修复重定位表
重定位表的作用就是:当实际加载到内存中的Imagebase与本该加载时候的Imagebase地址不同的时候 就需要进行修复重定位表
其实重定位表中存的是需要修改的函数的地址偏移!
void MoveRelocationTable(PVOID pFileBuffer, PDWORD OldBufferSize,PVOID* pNewBuffer){ PIMAGE_DOS_HEADER pImageDosHeader = NULL; PIMAGE_FILE_HEADER pImageFileHeader = NULL; PIMAGE_OPTIONAL_HEADER32 pImageOptionalHeader = NULL; PIMAGE_SECTION_HEADER pImageSectionHeaderGroup = NULL; PIMAGE_SECTION_HEADER NewSec = NULL; PIMAGE_BASE_RELOCATION pRelocationDirectory = NULL; DWORD isOk; DWORD NewLength=0; PVOID LastSection = NULL; PVOID CodeSection = NULL; PVOID AddressOfSectionTable = NULL; PVOID pTemp; DWORD AllSizeOfBlock = 0; DWORD RVA = 0; DWORD FOA = 0; int NumberOfRelocation=0; PWORD Location = NULL; int i = 0; DWORD RVA_Data; WORD reloData; pImageDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pImageFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageDosHeader + pImageDosHeader->e_lfanew + 4); pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pImageFileHeader + sizeof(IMAGE_FILE_HEADER)); pImageSectionHeaderGroup = (PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader + pImageFileHeader->SizeOfOptionalHeader); //判断是否可以容纳相应的节表 isOk = (DWORD)pImageOptionalHeader->SizeOfHeaders - ((DWORD)pImageDosHeader->e_lfanew + IMAGE_SIZEOF_FILE_HEADER + pImageFileHeader->SizeOfOptionalHeader + 40*pImageFileHeader->NumberOfSections); if(isOk < 80){ printf("空间太小 无法进行添加!"); return; } //生成对应的内存大小的空间 NewLength += *OldBufferSize + 0x1000; *pNewBuffer = (PVOID)malloc(NewLength); ZeroMemory(*pNewBuffer,NewLength); //拷贝之前内存空间 到 当前新生成的内存空间 memcpy(*pNewBuffer,pFileBuffer,*OldBufferSize); //获取新的结构体 pImageDosHeader = (PIMAGE_DOS_HEADER)(*pNewBuffer); pImageFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageDosHeader + pImageDosHeader->e_lfanew + 4); pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pImageFileHeader + sizeof(IMAGE_FILE_HEADER)); pImageSectionHeaderGroup = (PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader + pImageFileHeader->SizeOfOptionalHeader); // pImageFileHeader->NumberOfSections修改 pImageFileHeader->NumberOfSections = pImageFileHeader->NumberOfSections + 1; // pImageOptionalHeader->SizeOfImage修改 pImageOptionalHeader->SizeOfImage = (DWORD)pImageOptionalHeader->SizeOfImage + 0x1000; // 复制代码段的节数据到 当前最后一个节数据后面 CodeSection = (PVOID)(&pImageSectionHeaderGroup[0]); LastSection = (PVOID)(DWORD)(&pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-1]); memcpy(LastSection,CodeSection,40); //修正相关属性 NewSec = (PIMAGE_SECTION_HEADER)LastSection; strcpy(NewSec,".NewSec"); NewSec->Misc.VirtualSize = 0x1000; NewSec->SizeOfRawData = 0x1000; NewSec->VirtualAddress = pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].VirtualAddress + pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].SizeOfRawData; NewSec->PointerToRawData = pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].PointerToRawData + pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].SizeOfRawData; *OldBufferSize = NewLength; //到这里新增节已经完成了 AddressOfSectionTable = (PVOID)((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData); //printf("%x",AddressOfSectionTable); //重定位表的FOA RVA_TO_FOA(*pNewBuffer,pImageOptionalHeader->DataDirectory[5].VirtualAddress,&FOA); //获取结构 pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)*pNewBuffer + FOA); pTemp = pRelocationDirectory; //printf("%x",pRelocationDirectory->VirtualAddress); //获取重定位表大小 while(pRelocationDirectory->SizeOfBlock && pRelocationDirectory->VirtualAddress){ AllSizeOfBlock = pRelocationDirectory->SizeOfBlock; pRelocationDirectory = ((DWORD)pRelocationDirectory + (DWORD)pRelocationDirectory->SizeOfBlock); } //复制重定位表到新增的节数据中 memcpy(AddressOfSectionTable,pTemp,AllSizeOfBlock); //将PE可选头中的重定位的地址指向新增节数据的起始地址 pImageOptionalHeader->DataDirectory[5].VirtualAddress = (DWORD)AddressOfSectionTable; //修改DLL的ImageBase //pImageOptionalHeader->ImageBase += 1000; //============================================================= //============================================================= //============================================================= //============================================================= printf("pRelocationDirectory_RVA:%x\n",pImageOptionalHeader->DataDirectory[5].VirtualAddress); RVA_TO_FOA(pFileBuffer,pImageOptionalHeader->DataDirectory[5].VirtualAddress,&FOA); printf("pRelocationDirectory_FOA:%x\n", FOA); pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer+(DWORD)FOA); //定位第一张重定位表 文件中的地址 while(pRelocationDirectory->SizeOfBlock && pRelocationDirectory->VirtualAddress){ printf("VirtualAddress :%08X\n", pRelocationDirectory->VirtualAddress); printf("SizeOfBlock :%08X\n", pRelocationDirectory->SizeOfBlock); printf("================= BlockData Start ======================\n"); NumberOfRelocation = (pRelocationDirectory->SizeOfBlock - 8)/2;// 每个重定位块中的数据项的数量 Location = (PWORD)((DWORD)pRelocationDirectory + 8); // 加上8个字节 for(i=0;i<NumberOfRelocation;i++){ if(Location[i] >> 12 != 0){ //判断是否是垃圾数据 // WORD类型的变量进行接收 reloData = (Location[i] & 0xFFF); //这里进行与操作 只取4字节 二进制的后12位 RVA_Data = pRelocationDirectory->VirtualAddress + reloData; //这个是RVA的地址 RVA_TO_FOA(pFileBuffer,RVA_Data,&FOA); printf("第[%04X]项 数据项的数据为:[%04X] 数据属性为:[%X] RVA的地址为:[%08X] 重定位的数据:[%08X]\n" ,i+1 ,reloData ,(Location[i] >> 12) ,RVA_Data ,*(PDWORD)((DWORD)pFileBuffer+(DWORD)FOA)); //这里是自增的 进行修复重定位,上面的imagebase我们自增了1000,那么要修复的地址都需要自增1000 *(PDWORD)((DWORD)pFileBuffer+(DWORD)FOA) = *(PDWORD)((DWORD)pFileBuffer+(DWORD)FOA) + 1000; } } pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationDirectory + (DWORD)pRelocationDirectory->SizeOfBlock); //上面的for循环完成之后,跳转到下个重定位块 继续如上的操作 } //============================================================= //============================================================= //============================================================= //============================================================= //保存文件 MyWriteFile(*pNewBuffer,NewLength); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY