Как посмотреть таблицу функций 64-битного модуля, когда он отображается в памяти? - PullRequest
0 голосов
/ 04 июля 2018

Моя цель - понять разматывание стека в 64-битном формате исполняемого файла PE32 + в Windows, или как следующий API может вычислять адреса пролога, тела, эпилога и т. Д. :

CONTEXT context = {0};
RtlCaptureContext(&context);

DWORD64 ImgBase = 0;
RUNTIME_FUNCTION* pRTFn = RtlLookupFunctionEntry(context.Rip, &ImgBase, NULL);
_tprintf(L"Prologue=0x%p\n", (void*)(ImgBase + pRTFn->BeginAddress));

Я знаю, что информация о смещениях всех неконечных функций, используемых компоновщиком , включена в заголовок PE32 + в каталоге исключений. Поэтому я попытался написать свою собственную функцию для ее анализа. Я попал в точку, в которой оказался в тупике:

//INFO -- must be compiled as x64 only!

void GetFunctionTable(BYTE* lpBaseAddress, size_t szImageSz)
{
    if(lpBaseAddress)
    {
        if(szImageSz > sizeof(IMAGE_DOS_HEADER))
        {
            IMAGE_DOS_HEADER* pDOSHeader = (IMAGE_DOS_HEADER*)lpBaseAddress;
            if(pDOSHeader->e_magic == IMAGE_DOS_SIGNATURE)
            {
                IMAGE_NT_HEADERS* pNtHeader = (IMAGE_NT_HEADERS*)((BYTE*)pDOSHeader + pDOSHeader->e_lfanew);

                PIMAGE_DATA_DIRECTORY pDataDirectories = NULL;
                if(pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
                {
                    //64-bit image only
                    IMAGE_NT_HEADERS64* pHdr64 = (IMAGE_NT_HEADERS64*)pNtHeader;
                    IMAGE_OPTIONAL_HEADER64* pIOH64 = &pHdr64->OptionalHeader;
                    pDataDirectories = pIOH64->DataDirectory;

                    IMAGE_DATA_DIRECTORY* pExceptDir = &pDataDirectories[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
                    if(pExceptDir->VirtualAddress &&
                        pExceptDir->Size)
                    {
                        IMAGE_RUNTIME_FUNCTION_ENTRY* pRFs = (IMAGE_RUNTIME_FUNCTION_ENTRY*)
                            GetPtrFromRVA64(pExceptDir->VirtualAddress, pNtHeader, lpBaseAddress);

                        //'pRFs' = should point to an array of RUNTIME_FUNCTION structs
                        //         but in my case it points to an empty region of memory with all zeros.
                    }
                }
            }
        }
    }
}

со следующими вспомогательными функциями:

PIMAGE_SECTION_HEADER GetEnclosingSectionHeader64(DWORD_PTR rva, PIMAGE_NT_HEADERS64 pNTHeader)
{
    PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
    unsigned int i;

    for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
    {
        if ( (rva >= section->VirtualAddress) && 
                (rva < (section->VirtualAddress + section->Misc.VirtualSize)))
            return section;
    }

    return 0;
}

LPVOID GetPtrFromRVA64(DWORD rva, const void* pNTHeader, const void* imageBase)
{
    PIMAGE_SECTION_HEADER pSectionHdr;
    INT_PTR delta;

    pSectionHdr = GetEnclosingSectionHeader64( rva, (PIMAGE_NT_HEADERS64)pNTHeader );
    if ( !pSectionHdr )
        return 0;

    delta = (INT_PTR)(pSectionHdr->VirtualAddress - pSectionHdr->PointerToRawData);
    return (PVOID) ( (BYTE*)imageBase + rva - delta );
}

Итак, я тестирую его на самоисполняемом файле:

HMODULE hMod = ::GetModuleHandle(NULL);
MODULEINFO mi = {0};
if(::GetModuleInformation(::GetCurrentProcess(), hMod, &mi, sizeof(mi)))
{
    GetFunctionTable((BYTE*)hMod, mi.SizeOfImage);
}

Но проблема в том, что внутри моего GetFunctionTable, когда я пытаюсь найти таблицу функций, отображенную в памяти в каталоге IMAGE_DIRECTORY_ENTRY_EXCEPTION, я получаю указатель (т.е. IMAGE_RUNTIME_FUNCTION_ENTRY*) на пустую область памяти , Должно быть, я неправильно переводил адрес rva.

Так что любой, кто знает, как заголовок PE32 + отображается в памяти, может показать, что я там не так делаю?

...