数据目录中的表是分散在各个节里的,如果对节进行加密,操作系统找不到表,就无法加载程序。因此加密前要先把表移动到新的节里。计算重定位表的大小,首先要遍历重定位表,累加SizeOfBlock
然后新增一个节,大小是表的大小文件对齐。最后把表复制到新增节的开头,然后更新数据目录的VirtualAddress
指向新的重定位表
总体来说本文要比上一篇移动导出表简单一些
新增节的函数已经在上一篇博客中提到
解析DOS头,PE头,节表,数据目录的第六个是重定位表,将RVA
转FOA
得到文件偏移和重定位表
xxxxxxxxxx
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 +
RvaToFileOffset(pFileBuffer, pOptionHeader->DataDirectory[5].VirtualAddress));
计算所有重定位表块的大小,以新增对应大小的节
当VA
和SizeOfBlock
非零时遍历,每次增加SizeOfBlock
大小
xxxxxxxxxx
DWORD dwRelocationTableSize = 0;
while (pRelocationTable->VirtualAddress || pRelocationTable->SizeOfBlock)
{
dwRelocationTableSize += pRelocationTable->SizeOfBlock;
pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationTable + pRelocationTable->SizeOfBlock);
}
按照文件对齐进行对齐后作为新增节的大小进行新增操作(代码在前文)
xxxxxxxxxx
DWORD dwNewBufferSize = AddSection(pFileBuffer, pNewFileBuffer, dwFileBufferSize,
AlignLength(dwRelocationTableSize, pOptionHeader->FileAlignment));
修改新增节属性为可读、含已初始化数据
xxxxxxxxxx
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;
拿到重定位表的指针和新增节后的最后一节(新节)的起始地址(PointerToRawData
)
目标是将重定位表全部复制到这里
xxxxxxxxxx
pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)*pNewFileBuffer +
RvaToFileOffset(*pNewFileBuffer, pOptionHeader->DataDirectory[5].VirtualAddress));
LPVOID pInsert = (LPVOID)((DWORD)*pNewFileBuffer + pSectionHeader[pPEHeader->NumberOfSections - 1].PointerToRawData);
从新增节首地址开始复制重定位表的全部内容,大小为之前计算的各个块总大小
xxxxxxxxxx
memcpy(pInsert, (LPVOID)pRelocationTable, dwRelocationTableSize);
修改数据目录中重定位表的VA
值为新节的起始地址
xxxxxxxxxx
pOptionHeader->DataDirectory[5].VirtualAddress = FoaToImageOffset(*pNewFileBuffer,
(DWORD)pInsert - (DWORD)*pNewFileBuffer);
完整代码
xxxxxxxxxx
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 +
RvaToFileOffset(pFileBuffer, pOptionHeader->DataDirectory[5].VirtualAddress));
DWORD dwRelocationTableSize = 0;
while (pRelocationTable->VirtualAddress || pRelocationTable->SizeOfBlock)
{
dwRelocationTableSize += pRelocationTable->SizeOfBlock;
pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationTable + pRelocationTable->SizeOfBlock);
}
DWORD dwNewBufferSize = AddSection(pFileBuffer, pNewFileBuffer, dwFileBufferSize,
AlignLength(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 + \
RvaToFileOffset(*pNewFileBuffer, pOptionHeader->DataDirectory[5].VirtualAddress));
LPVOID pInsert = (LPVOID)((DWORD)*pNewFileBuffer + pSectionHeader[pPEHeader->NumberOfSections - 1].PointerToRawData);
memcpy(pInsert, (LPVOID)pRelocationTable, dwRelocationTableSize);
pOptionHeader->DataDirectory[5].VirtualAddress = FoaToImageOffset(*pNewFileBuffer,
pSectionHeader[pPEHeader->NumberOfSections - 1].PointerToRawData);
return dwNewBufferSize;
}
运行结果