本节我们将编写一个遍历重定位表的示例程序,打印重定位表。
本节必须掌握的知识点:
遍历重定位表
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重定位表