本节我们将编写一个遍历重定位表的示例程序,打印重定位表。
本节必须掌握的知识点:
遍历重定位表
6.2.1 遍历重定位表
实验四十三:遍历重定位表

以下代码实现打印"c:\\notepad64.exe"进程重定位表的所有信息。
/*------------------------------------------------------------------------
 FileName:PrintImportDescriptor.c
 实验43:遍历重定位表(支持32位和64位PE)
 (c) bcdaren, 2024
-----------------------------------------------------------------------*/
#include <stdio.h>
#include <windows.h>
#include <winnt.h>
#define WIN64
PBYTE creatfilemap(LPCWSTR szFile);
VOID printReloc(PBYTE lpvResult);
DWORD RvaToFoa(PIMAGE_NT_HEADERS ntHeaders, DWORD rva);
int main(int argc, char* argv[])
{
    //LPCWSTR szFileName = TEXT("c:\\winResult.dll");
    LPCWSTR szFileName = TEXT("c:\\notepad64.exe");
    PBYTE lpAddress = NULL; //PE文件内存映射文件地址
    lpAddress = creatfilemap(szFileName);
    if (lpAddress)
    {
        printf("%ls\n", szFileName);
        printReloc(lpAddress);
    }
    system("pause");
    return 0;
}
//创建PE文件映射对象
PBYTE creatfilemap(LPCWSTR szFile)
{
    HANDLE hFile;
    HANDLE hMapFile = NULL;
    PBYTE lpMemory = NULL;  //PE文件内存映射文件地址
    char buffer[16] = { 0 };
    DWORD dwFileSize;
    DWORD dwBytesRead = 0;
    PIMAGE_DOS_HEADER lpstDOS = NULL;
    PIMAGE_NT_HEADERS lpstNT = NULL;
    hFile = CreateFile(szFile,
        GENERIC_READ,          // 只读打开
        FILE_SHARE_READ,       // 允许其他进程以读取方式打开文件
        NULL,                  // 默认安全属性
        OPEN_EXISTING,         // 打开已存在的文件
        FILE_ATTRIBUTE_NORMAL, // 普通文件
        NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        printf("打开文件失败!\n");
    else
    {
        dwFileSize = GetFileSize(hFile, 0);//获得文件大小可通过结构体获取
        //创建内存映射文件
        if (dwFileSize)
        {
            if (hMapFile = CreateFileMapping(hFile, NULL,
PAGE_READONLY, 0, 0, NULL))
            {
                //获得文件在内存的映象起始位置
                lpMemory = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
                if (!lpMemory)
                    printf("获取映像起始地址失败!\n");
                //检查PE文件是否有效
                lpstDOS = (PIMAGE_DOS_HEADER)lpMemory;
                if (lpstDOS->e_magic != IMAGE_DOS_SIGNATURE)
                    printf("非PE格式文件!\n");
                lpstNT = (PIMAGE_NT_HEADERS)(lpMemory + lpstDOS->e_lfanew);
                if (lpstNT->Signature != IMAGE_NT_SIGNATURE)
                    printf("非PE格式文件!\n");
            }
        }
    }
    return lpMemory;
}
//32位PE文件
VOID printReloc(PBYTE lpvResult)
{
    PIMAGE_DOS_HEADER pImageDOSHeader = (PIMAGE_DOS_HEADER)lpvResult;
#ifdef WIN64
    PIMAGE_NT_HEADERS64 psImageNTHeader = (PIMAGE_NT_HEADERS64)(lpvResult + pImageDOSHeader->e_lfanew);
#else
    PIMAGE_NT_HEADERS32 psImageNTHeader = (PIMAGE_NT_HEADERS32)(lpvResult + pImageDOSHeader->e_lfanew);
#endif
    //重定位表RVA
    DWORD RelocRVA = psImageNTHeader->OptionalHeader.DataDirectory[5].VirtualAddress;
    DWORD dwTemp = 0;
    //获取重定位表FOA地址
    PIMAGE_BASE_RELOCATION pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)RvaToFoa((PIMAGE_NT_HEADERS)psImageNTHeader, RelocRVA);
    dwTemp = (DWORD)pImageDOSHeader + (DWORD)pImageBaseRelocation;
    for(DWORD i = 0; (DWORD*)(((PIMAGE_BASE_RELOCATION)dwTemp)->VirtualAddress ) != 0; i++)
    {
        printf("virtual address : 0x%08x\n", ((PIMAGE_BASE_RELOCATION)dwTemp)->VirtualAddress);
        printf("size of block   : 0x%08x\n", ((PIMAGE_BASE_RELOCATION)dwTemp)->SizeOfBlock);
        for (DWORD j = 0; j < ((PIMAGE_BASE_RELOCATION)dwTemp)->SizeOfBlock - 8; j += 2)
        {
            printf("%4x\t", *(WORD*)(dwTemp + 8 + j));
        }
        dwTemp += ((PIMAGE_BASE_RELOCATION)dwTemp)->SizeOfBlock;
        printf("\n");
    }
}
//RVA转FOA
DWORD RvaToFoa(PIMAGE_NT_HEADERS ntHeaders, DWORD rva) {
    //ntHeaders+4+sizeof(IMAGE_FILE_HEADER)+FileHeader.SizeOfOptionalHeader(32或64位PE)
    PIMAGE_SECTION_HEADER sectionHeader = IMAGE_FIRST_SECTION(ntHeaders);
    WORD numberOfSections = ntHeaders->FileHeader.NumberOfSections;
    for (WORD i = 0; i < numberOfSections; i++) {
        DWORD sectionStartRva = sectionHeader->VirtualAddress;
        DWORD sectionEndRva = sectionStartRva + sectionHeader->SizeOfRawData;
        if (rva >= sectionStartRva && rva < sectionEndRva) {
            DWORD foa = sectionHeader->PointerToRawData + (rva –
sectionStartRva);
            return foa;
        }
        sectionHeader++;
    }
    return 0;  // RVA not found
}
图6-3 打印notepad64.exe重定位表


















