一、为什么要移动重定位表
数据目录中的表是分散在各个节里的,如果对节进行加密,操作系统找不到表,就无法加载程序。因此加密前要先把表移动到新的节里。
二、怎么移动
计算重定位表的大小,首先要遍历重定位表,累加 SizeOfBlock,然后新增一个节,大小是表的大小文件对齐。最后把表复制到新增节的开头,然后更新数据目录的VirtualAddress指向新的重定位表。
三、代码
// 移动重定位表到新增节,返回新缓冲区的大小
DWORD MoveRelocationTableToNewSection(LPVOID pFileBuffer, LPVOID *pNewFileBuffer, DWORD dwFileBufferSize)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
PIMAGE_SECTION_HEADER pSectionHeader = \
(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
PIMAGE_BASE_RELOCATION pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + \
RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[5].VirtualAddress));
size_t i = 0;
DWORD dwRelocationTableSize = 0;
while (pRelocationTable->VirtualAddress || pRelocationTable->SizeOfBlock)
{
dwRelocationTableSize += pRelocationTable->SizeOfBlock;
//printf("%x\n", (pRelocationTable->SizeOfBlock - 8) / 2 );
pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationTable + pRelocationTable->SizeOfBlock);
}
DWORD dwNewBufferSize = AddSection(pFileBuffer, pNewFileBuffer, dwFileBufferSize, \
Align(dwRelocationTableSize, pOptionHeader->FileAlignment));
pDosHeader = (PIMAGE_DOS_HEADER)*pNewFileBuffer;
pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
// 修改新增节属性为可读、含已初始化数据
pSectionHeader[pPEHeader->NumberOfSections - 1].Characteristics = 0x40000040;
// 指针指向重定位表
pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)*pNewFileBuffer + \
RvaToFoa(*pNewFileBuffer, pOptionHeader->DataDirectory[5].VirtualAddress));
// 定义插入点为新增节的起始地址
LPVOID pInsert = (LPVOID)((DWORD)*pNewFileBuffer + pSectionHeader[pPEHeader->NumberOfSections - 1].PointerToRawData);
// 拷贝重定位表
memcpy(pInsert, (LPVOID)pRelocationTable, dwRelocationTableSize);
// 更新目录项,指向新的重定位表
pOptionHeader->DataDirectory[5].VirtualAddress = FoaToRva(*pNewFileBuffer, \
(DWORD)pInsert - (DWORD)*pNewFileBuffer);
return dwNewBufferSize;
}
四、运行结果
修改前和修改后对比