seo公司网站,临沂哪里有做网站,论坛式网站建设,网页设计作品特色及亮点Relocation#xff08;重定位#xff09;是一种将程序中的一些地址修正为运行时可用的实际地址的机制。在程序编译过程中#xff0c;由于程序中使用了各种全局变量和函数#xff0c;这些变量和函数的地址还没有确定#xff0c;因此它们的地址只能暂时使用一个相对地址。当…Relocation重定位是一种将程序中的一些地址修正为运行时可用的实际地址的机制。在程序编译过程中由于程序中使用了各种全局变量和函数这些变量和函数的地址还没有确定因此它们的地址只能暂时使用一个相对地址。当程序被加载到内存中运行时这些相对地址需要被修正为实际的绝对地址这个过程就是重定位。
在Windows操作系统中程序被加载到内存中运行时需要将程序中的各种内存地址进行重定位以使程序能够正确地运行。Windows系统使用PEPortable Executable文件格式来存储可执行程序其中包括重定位信息。当程序被加载到内存中时系统会解析这些重定位信息并将程序中的各种内存地址进行重定位。
重定位表一般出现在DLL中因为DLL都是动态加载所以地址不固定DLL的入口点在整个执行过程中至少要执行2次一次是在开始时执行初始化工作一次则是在结束时做最后的收尾工作重定位表则是解决DLL的地址问题为了能找到重定位表首先我们需要使用PeView工具查询DataDirectory数据目录表在其中找到Base relocation字段里面的0x00001800则是重定位表基地址 我们通过使用WinHex工具定位到0x00001800即可看到重定位表信息如下图中的1000代表的是重定位RVA地址绿色的0104代表的则是重定位块的长度后面则是每两个字节代表一个重定位块0A是重定位地址30则是重定位的类型以此顺序向下排列。 重定位表也是分页排列的每一页大小都是1000字节通过使用FixRelocPage命令即可查询到当前程序中的重定位块信息并以第一个为例查询一下起始地址RVA为1000的页上有哪些重定位结构如下图所示 其中的重定位RVA地址0000100A是用标黄色的1000加上标蓝色的0xA得到的。而修正RVA地址00003000加上模块基地址63FF00003000得到的则是第一个被修正的内存地址读者可使用x64dbg跳转到该程序内自行确认。
重定位表的修复原理与IAT修复完全一致我们需要分别读入脱壳前与脱壳后的两个程序接着通过循环正确的重定位表信息并依次覆盖到脱壳后的程序内以此实现对重定位表的修复功能实现代码如下所示
#include windows.h
#include stdio.hstruct TypeOffset
{WORD Offset : 12; // 低12位代表重定位地址WORD Type : 4; // 高4位代表重定位类型
};DWORD FileSize 0; // 定义文件大小
DWORD FileBase 0; // 保存文件的基地址// 定义全局变量,来存储DOS,NT,Section头
PIMAGE_DOS_HEADER DosHeader nullptr;
PIMAGE_NT_HEADERS NtHeader nullptr;
PIMAGE_FILE_HEADER FileHead nullptr;// 将RVA转换为FOA的函数
DWORD RVAtoFOA(DWORD rva)
{auto SectionTables IMAGE_FIRST_SECTION(NtHeader); // 获取区段表WORD Count NtHeader-FileHeader.NumberOfSections; // 获取区段数量for (int i 0; i Count; i){// 判断是否存在于区段中DWORD Section_Start SectionTables[i].VirtualAddress;DWORD Section_Ends SectionTables[i].VirtualAddress SectionTables[i].SizeOfRawData;if (rva Section_Start rva Section_Ends){// 找到之后计算位置并返回值return rva - SectionTables[i].VirtualAddress SectionTables[i].PointerToRawData;}}return -1;
}// 打开PE文件
bool OpenPeFile(LPCSTR FileName)
{// 打开文件HANDLE Handle CreateFileA(FileName, GENERIC_READ, NULL,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (Handle INVALID_HANDLE_VALUE)return false;// 获取文件大小FileSize GetFileSize(Handle, NULL);// 读取文件数据DWORD OperSize 0;FileBase (DWORD)new BYTE[FileSize];ReadFile(Handle, (LPVOID)FileBase, FileSize, OperSize, NULL);// 获取DOS头并判断是不是一个有效的DOS文件DosHeader (PIMAGE_DOS_HEADER)FileBase;if (DosHeader-e_magic ! IMAGE_DOS_SIGNATURE)return false;// 获取 NT 头并判断是不是一个有效的PE文件NtHeader (PIMAGE_NT_HEADERS)(FileBase DosHeader-e_lfanew);if (NtHeader-Signature ! IMAGE_NT_SIGNATURE)return false;// 判断是不是一个32位文件if (NtHeader-OptionalHeader.Magic ! 0x010B)return false;CloseHandle(Handle);return true;
}// 修复重定位表
void RepairFixReloc(char new_file[])
{DWORD base NtHeader-OptionalHeader.ImageBase;// 1. 获取重定位表的 rvaDWORD RelocRVA NtHeader-OptionalHeader.DataDirectory[5].VirtualAddress;// 2. 获取重定位表auto Reloc (PIMAGE_BASE_RELOCATION)(FileBase RVAtoFOA(RelocRVA));// 3. 遍历重定位表中的重定位块以0结尾while (Reloc-SizeOfBlock ! 0){// 3.1 输出分页基址printf([↓] 分页基址: 0x%08X \n\n, Reloc-VirtualAddress);// 3.2 找到重定位项auto Offset (TypeOffset*)(Reloc 1);// 3.3 计算重定位项的个数// Reloc-SizeOfBlock 保存的是整个重定位块的大小 结构体 重定位项数组// Reloc-SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) 得到单个数组大小// 上面的结果 \ 2 重定位项的个数原因是重定位项的大小为两个字节DWORD Size (Reloc-SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2;// 3.4 遍历所有的重定位项for (DWORD i 0; i Size; i){DWORD Type Offset[i].Type; // 获取重定位类型只关心为3的类型DWORD pianyi Offset[i].Offset; // 获取重定位的偏移值DWORD rva pianyi Reloc-VirtualAddress; // 获取要重定位的地址所在的RVADWORD foa RVAtoFOA(rva); // 获取要重定位的地址所在的FOADWORD fa foa FileBase; // 获取要重定位的地址所在的faDWORD addr *(DWORD*)fa; // 获取要重定位的地址DWORD new_addr addr - base 0x1500000; // 计算重定位后的数据: addr - oldbase newbase// 将重定位后的数据写回缓冲区(文件)if (Offset[i].Type 3)*(DWORD*)fa new_addr;printf(\t [-] 重定位RVA: 0x%08X | 重定位FOA: 0x%08X | 重定位地址: 0x%08X | 修正地址: 0x%08X \n, rva, foa, addr, new_addr);}// 找到下一个重定位块Reloc (PIMAGE_BASE_RELOCATION)((DWORD)Reloc Reloc-SizeOfBlock);}// 保存修正后的文件NtHeader-OptionalHeader.ImageBase 0x1500000;// 打开一个新文件HANDLE new_handle CreateFileA(new_file, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if (new_handle INVALID_HANDLE_VALUE)return;DWORD OperSize 0;// 保存修正好的程序BOOL ret WriteFile(new_handle, (LPVOID)FileBase, FileSize, OperSize, NULL);if (ret TRUE){printf(\n\n);CloseHandle(new_handle);printf([*] 修复 %s 文件 \t 写入基址: %08X \t 总长度: %d \t 写入长度: %d \n, new_file, FileBase, FileSize, OperSize);}
}void Banner()
{printf( ____ _ _ _ ____ _ \n);printf(| __ ) _ _(_) | __| | | _ \\ ___| | ___ ___ \n);printf(| _ \\| | | | | |/ _ | | |_) / _ \\ |/ _ \\ / __|\n);printf(| |_) | |_| | | | (_| | | _ __/ | (_) | (__ \n);printf(|____/ \\__,_|_|_|\\__,_| |_| \\_\\___|_|\\___/ \\___|\n);printf( \n);printf(Reloc 重定位表快速修复工具 \t By: LyShark \n);printf(Usage: BuildFix [原文件位置] [修复后文件位置] \n\n\n);
}int main(int argc, char* argv[])
{Banner();if (argc 3){bool flag OpenPeFile(argv[1]);if (true flag){RepairFixReloc(argv[2]);}}return 0;
}运行上述程序读者可自行传入脱壳前的程序与脱壳后的程序此时则会实现自动替换如下图所示 本文作者 王瑞 本文链接 https://www.lyshark.com/post/3c1b31b5.html 版权声明 本博客所有文章除特别声明外均采用 BY-NC-SA 许可协议。转载请注明出处