基址重定位表解析(x64)

admin 2024年2月23日17:19:44评论12 views字数 4284阅读14分16秒阅读模式
重定位表的结构(IMAGE_BASE_RELOCATION
typedef struct _IMAGE_BASE_RELOCATION { DWORD  VirtualAddress; // 分页基址(RVA) DWORD  SizeOfBlock; // 重定位块的大小 //WORD TypeOffset[1]; // 动态数组,每项大小为16位,前高4位是类型,后低12位是偏移} IMAGE_BASE_RELOCATION,* PIMAGE_BASE_RELOCATION;

TypeOffset 高位字节的定义:

#define IMAGE_REL_BASED_ABSOLUTE              0 // 无重定位操作,用于4字节对齐#define IMAGE_REL_BASED_HIGH                  1 // 重定位指向位置的高2个字节需要被修正#define IMAGE_REL_BASED_LOW                   2 // 重定位指向位置的低2个字节需要被修正#define IMAGE_REL_BASED_HIGHLOW               3 // 重定位指向位置的全部4个字节需要被修正#define IMAGE_REL_BASED_HIGHADJ               4#define IMAGE_REL_BASED_MACHINE_SPECIFIC_5    5#define IMAGE_REL_BASED_RESERVED              6#define IMAGE_REL_BASED_MACHINE_SPECIFIC_7    7#define IMAGE_REL_BASED_MACHINE_SPECIFIC_8    8#define IMAGE_REL_BASED_MACHINE_SPECIFIC_9    9#define IMAGE_REL_BASED_DIR64                 10 // 重定位指向位置的8个字节需要被修正
测试代码:
#include <Windows.h>#include <stdio.h>
static PCH LoadFileT(PCSTR FilePath) { // 获取文件对象 HANDLE hFile = CreateFileA(FilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwFileSize = GetFileSize(hFile, NULL); // 获取文件大小
PCH szBuffer = new CHAR[dwFileSize]; // 用于接收从文件读取的数据 memset(szBuffer, 0, dwFileSize); // 初始化内存
BOOL Result = ReadFile(hFile, szBuffer ,dwFileSize, NULL, NULL); // 读取数据
CloseHandle(hFile); // 关闭文件句柄
if (Result) { return szBuffer; } else { return NULL; }}
// RVA 转 FOAstatic DWORD RvaToFoa(DWORD dwRva, PCH szbuffer){ PIMAGE_DOS_HEADER pDos = PIMAGE_DOS_HEADER(szbuffer); // DOS Header PIMAGE_NT_HEADERS64 pNt = PIMAGE_NT_HEADERS64(szbuffer + pDos->e_lfanew); // NT Header PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt); // 节
if (dwRva < pSection->VirtualAddress)return dwRva; // 判断是否落在头部 for (size_t i = 0; i < pNt->FileHeader.NumberOfSections; i++) { // 区段的开始 = VirtualAddress // 区段的结束 = VirtualAddress + VirtualSize // 判断是否在区段 if (dwRva >= pSection[i].VirtualAddress && dwRva <= pSection[i].VirtualAddress + pSection[i].Misc.VirtualSize) { // 数据的 RVA - 区段的 RVA = 数据的 FOA - 区段的 FOA // 数据的 FOA = 数据的 RVA(传参) - 区段的 RVA + 区段的 FOA return dwRva - pSection[i].VirtualAddress + pSection[i].PointerToRawData; } }}
// 从定位表相对性的区段static PCH GetSelectName(DWORD dwRva, PCH szbuffer){ PIMAGE_DOS_HEADER pDos = PIMAGE_DOS_HEADER(szbuffer); // DOS Header PIMAGE_NT_HEADERS64 pNt = PIMAGE_NT_HEADERS64(szbuffer + pDos->e_lfanew); // NT Header PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt); // 节
if (dwRva < pSection->VirtualAddress)return NULL; for (size_t i = 0; i < pNt->FileHeader.NumberOfSections; i++) { if (dwRva >= pSection[i].VirtualAddress && dwRva <= pSection[i].VirtualAddress + pSection[i].Misc.VirtualSize) { PCH selectName = new CHAR[IMAGE_SIZEOF_SHORT_NAME+1]{0}; memcpy(selectName, pSection[i].Name, IMAGE_SIZEOF_SHORT_NAME); return selectName; } }}
// 基址重定位表static VOID BaseRelocationT(PCH szbuffer, PIMAGE_DATA_DIRECTORY pDataDirectory, PIMAGE_SECTION_HEADER pSection) { PIMAGE_DATA_DIRECTORY pBaseRelocDir = pDataDirectory + IMAGE_DIRECTORY_ENTRY_BASERELOC; // 定位到重定位表 // 使用重定位表结构体指针指向重定位表所在的内存地址 PIMAGE_BASE_RELOCATION pBaseReloc = PIMAGE_BASE_RELOCATION(RvaToFoa(pBaseRelocDir->VirtualAddress, szbuffer) + szbuffer);
PWORD pwRelocData{}; // 用于接收 TypeOffset DWORD dwItems{}; // 用于存储块个数 DWORD dwRva{}; // 用于存储TypeOffset的偏移
while (pBaseReloc->VirtualAddress && pBaseReloc->SizeOfBlock) // 判断是否存在重定位表 { dwItems =( pBaseReloc->SizeOfBlock - 8) / 2; // 个数 = (块大小 - IMAGE_BASE_RELOCATION 大小) / TypeOffset 字节数 // TypeOffset 是个数组,每个占 2 字节大小,所以除以 2 printf("Page RVA: %X, Block Size: %X, 项目数: %d, 区段: %sn", pBaseReloc->VirtualAddress, pBaseReloc->SizeOfBlock, dwItems, GetSelectName(pBaseReloc->VirtualAddress, szbuffer)); pwRelocData = PWORD((PCH)pBaseReloc + 0x8); // +8 是因为 TypeOffset 在两个 DWORD 之后 for (size_t i = 0; i < dwItems; i++) { // TypeOffset 16位, 前4位类型,后12位偏移      // 右移12位,移出去的位丢弃,空缺位用0填充,只剩下前4位 if (*(pwRelocData + i) >> 12 == IMAGE_REL_BASED_DIR64) { dwRva = *(pwRelocData + i) & 0x0FFF; // 清空前四位,只取偏移 printf("TypeOffset: %X, 类型: DIR64, Reloc RVA: %X, Reloc FOA: %Xn", *(pwRelocData + i), dwRva+ pBaseReloc->VirtualAddress, RvaToFoa(dwRva, szbuffer)); } else { printf("TypeOffset: %X, 类型: Padding(skipped)n",*(pwRelocData + i)); } } printf("n"); pBaseReloc = PIMAGE_BASE_RELOCATION(PCH(pBaseReloc) + pBaseReloc->SizeOfBlock); // 指向下一个重定位块PRIN }}
int main() { PCH buffer = LoadFileT("C:/project/PE/EXE/x64/Debug/EXE.exe");
PIMAGE_DOS_HEADER pDos = PIMAGE_DOS_HEADER(buffer); // DOS Header PIMAGE_NT_HEADERS64 pNt = PIMAGE_NT_HEADERS64(buffer + pDos->e_lfanew); // NT Header PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt); // 节 PIMAGE_OPTIONAL_HEADER64 pOptionalHeader = &pNt->OptionalHeader; // 扩展文件头 PIMAGE_DATA_DIRECTORY pDataDirectory = pOptionalHeader->DataDirectory; // 获取目录表头指针 BaseRelocationT(buffer, pDataDirectory, pSection);}

基址重定位表解析(x64)

原文始发于微信公众号(走在网安路上的哥布林):基址重定位表解析(x64)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月23日17:19:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   基址重定位表解析(x64)https://cn-sec.com/archives/2519736.html

发表评论

匿名网友 填写信息