解析PE资源表与重定位表
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解析PE资源表与重定位表相关的知识,希望对你有一定的参考价值。
#include<Windows.h>
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<commdlg.h>
using namespace std;
DWORD dwFileSize;
BYTE* g_pFileImageBase = 0;
PIMAGE_NT_HEADERS g_pNt = 0;
DWORD RVAtoFOA(DWORD dwRVA);
//显示pe头
//参数为内存映射首地址
void myPE() {
OPENFILENAME stOF;
HANDLE hFile, hMapFile;
DWORD totalSize; //文件大小
LPVOID lpMemory; //内存映像文件在内存的起始位置
char szFileName[MAX_PATH] = { 0 }; //要打开的文件路径及名称名
char bufTemp1[10]; //每个字符的十六进制字节码
char bufTemp2[20]; //第一列
char lpServicesBuffer[100]; //一行的所有内容
char bufDisplay[50]; //第三列ASCII码字符
DWORD dwCount; //计数,逢16则重新计
DWORD dwCount1; //地址顺号
DWORD dwBlanks; //最后一行空格数
char szExtPe[] = TEXT("PE Files\0*.exe;*.dll;*.scr;*.fon;*.drv\0All Files(*.*)\0*.*\0\0");
RtlZeroMemory(&stOF, sizeof(stOF));
stOF.lStructSize = sizeof(stOF);
//stOF.hwndOwner = (HWND)GetModuleHandle(NULL);
stOF.lpstrFilter = szExtPe;
stOF.lpstrFile = szFileName;
stOF.nMaxFile = MAX_PATH;
stOF.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&stOF)) //让用户选择打开的文件
{
hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
//如果是无效的句柄
if (hFile == INVALID_HANDLE_VALUE) {
printf("文件打开失败\n");
return;
}
//获取文件大小
dwFileSize = GetFileSize(hFile, NULL);
g_pFileImageBase = new BYTE[dwFileSize]{};
DWORD dwRead;
//将文件读取到内存中
bool bRet =ReadFile(hFile, g_pFileImageBase, dwFileSize, &dwRead, NULL);
//如果读取失败就返回
if (!bRet)
{
delete[] g_pFileImageBase;
}
//关闭句柄
CloseHandle(hFile);
/////////////////////////////////dos头///////////////////////////////////////////////
//typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
// WORD e_magic; // Magic number
// WORD e_cblp; // Bytes on last page of file
// WORD e_cp; // Pages in file
// WORD e_crlc; // Relocations
// WORD e_cparhdr; // Size of header in paragraphs
// WORD e_minalloc; // Minimum extra paragraphs needed
// WORD e_maxalloc; // Maximum extra paragraphs needed
// WORD e_ss; // Initial (relative) SS value
// WORD e_sp; // Initial SP value
// WORD e_csum; // Checksum
// WORD e_ip; // Initial IP value
// WORD e_cs; // Initial (relative) CS value
// WORD e_lfarlc; // File address of relocation table
// WORD e_ovno; // Overlay number
// WORD e_res[4]; // Reserved words
// WORD e_oemid; // OEM identifier (for e_oeminfo)
// WORD e_oeminfo; // OEM information; e_oemid specific
// WORD e_res2[10]; // Reserved words
// LONG e_lfanew; // File address of new exe header
//} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
/////////////////////////////////dos头///////////////////////////////////////////////
//使用PIMAGE_DOS_HEADER(占64字节)解释前64个字节
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)g_pFileImageBase;
//判断PE文件的标识是否正确,有一个不对,那么它就不是PE文件
if (pDos->e_magic != IMAGE_DOS_SIGNATURE)//0x5A4D(‘MZ‘)
{
return ;
}
cout << "---------------------------DOS头(_IMAGE_DOS_HEADER)------------------------------- "<< endl;
cout << hex << "WORD e_magic: " << pDos->e_magic << endl;
cout << hex << "WORD e_cblp: " << pDos->e_cblp << endl;
cout << hex << "WORD e_cp: " << pDos->e_cp << endl;
cout << hex << "WORD e_cblp: " << pDos->e_cblp << endl;
cout << hex << "WORD e_cparhdr: " << pDos->e_cparhdr << endl;
cout << hex << "WORD e_minalloc: " << pDos->e_minalloc << endl;
cout << hex << "WORD e_ss: " << pDos->e_ss << endl;
cout << hex << "WORD e_sp: " << pDos->e_sp << endl;
cout << hex << "WORD e_csum: " << pDos->e_csum << endl;
cout << hex << "WORD e_ip: " << pDos->e_ip << endl;
cout << hex << "WORD e_cs: " << pDos->e_cs << endl;
cout << hex << "WORD e_lfarlc: " << pDos->e_lfarlc << endl;
cout << hex << "WORD e_ovno: " << pDos->e_ovno << endl;
cout << hex << "WORD e_res[4]: " << *(pDos->e_res) << endl;
cout << hex << "WORD e_oemid: " << pDos->e_oemid << endl;
cout << hex << "WORD e_oeminfo: " << pDos->e_oeminfo << endl;
cout << hex << "WORD e_res2[10]: " << *(pDos->e_res2) << endl;
cout << hex << "WORD e_lfanew: " << pDos->e_lfanew << endl;
/////////////////////////////////NT头///////////////////////////////////////////////
/*typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;*/
g_pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + g_pFileImageBase);
if (g_pNt->Signature != IMAGE_NT_SIGNATURE)//0x00004550(‘PE‘)
{
return ;
}
cout << "---------------------------NT头(PIMAGE_NT_HEADERS)------------------------------- " << endl;
cout << hex << "DWORD Signature; " << g_pNt->Signature << endl;
cout << hex << "IMAGE_FILE_HEADER FileHeader; " << &g_pNt->OptionalHeader << endl;
cout << hex << "IMAGE_OPTIONAL_HEADER32 OptionalHeader; " << &g_pNt->OptionalHeader << endl;
/////////////////////////////////FILE头///////////////////////////////////////////////
/*typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;*/
PIMAGE_FILE_HEADER mytmf = &(g_pNt->FileHeader);
cout << "---------------------------FILE头(IMAGE_FILE_HEADER )----------------------------- " << endl;
cout << hex << "WORD Machine; " << mytmf->Machine << endl;
cout << hex << "WORD NumberOfSections; " << mytmf->NumberOfSections << endl;
cout << hex << "DWORD TimeDateStamp; " << mytmf->TimeDateStamp << endl;
cout << hex << "DWORD PointerToSymbolTable; " << mytmf->PointerToSymbolTable << endl;
cout << hex << "DWORD NumberOfSymbols; " << mytmf->NumberOfSymbols << endl;
cout << hex << "WORD SizeOfOptionalHeader; " << mytmf->SizeOfOptionalHeader << endl;
cout << hex << "WORD Characteristics; " << mytmf->Characteristics << endl;
/////////////////////////////////Optional头///////////////////////////////////////////////
//
// Optional header format.
//
//typedef struct _IMAGE_OPTIONAL_HEADER {
// //
// // Standard fields.
// //
// WORD Magic;
// BYTE MajorLinkerVersion;
// BYTE MinorLinkerVersion;
// DWORD SizeOfCode;
// DWORD SizeOfInitializedData;
// DWORD SizeOfUninitializedData;
// DWORD AddressOfEntryPoint;
// DWORD BaseOfCode;
// DWORD BaseOfData;
// //
// // NT additional fields.
// //
// DWORD ImageBase;
// DWORD SectionAlignment;
// DWORD FileAlignment;
// WORD MajorOperatingSystemVersion;
// WORD MinorOperatingSystemVersion;
// WORD MajorImageVersion;
// WORD MinorImageVersion;
// WORD MajorSubsystemVersion;
// WORD MinorSubsystemVersion;
// DWORD Win32VersionValue;
// DWORD SizeOfImage;
// DWORD SizeOfHeaders;
// DWORD CheckSum;
// WORD Subsystem;
// WORD DllCharacteristics;
// DWORD SizeOfStackReserve;
// DWORD SizeOfStackCommit;
// DWORD SizeOfHeapReserve;
// DWORD SizeOfHeapCommit;
// DWORD LoaderFlags;
// DWORD NumberOfRvaAndSizes;
// IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
//} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
PIMAGE_OPTIONAL_HEADER32 myoption = &(g_pNt->OptionalHeader);
cout << "---------------------------OPTIONAL头(PIMAGE_OPTIONAL_HEADER32 )-------------------------------------------------- " << endl;
cout << "---------------------------------------Standard fields.------------------------------------------------------------- " << endl;
cout << hex << "WORD Magic; " << myoption->Magic << endl;
cout << hex << "BYTE MajorLinkerVersion; " << myoption->MajorLinkerVersion << endl;
cout << hex << "BYTE MinorLinkerVersion; " << myoption->MinorLinkerVersion << endl;
cout << hex << "DWORD SizeOfCode; " << myoption->SizeOfCode << endl;
cout << hex << "DWORD SizeOfInitializedData; " << myoption->SizeOfInitializedData << endl;
cout << hex << "DWORD SizeOfUninitializedData; " << myoption->SizeOfUninitializedData << endl;
cout << hex << "DWORD AddressOfEntryPoint; " << myoption->AddressOfEntryPoint << endl;
cout << hex << "DWORD BaseOfCode; " << myoption->BaseOfCode << endl;
cout << hex << "DWORD BaseOfData; " << myoption->BaseOfData << endl;
cout << "----------------------------------------- NT additional fields.----------------------------------------------------- " << endl;
cout << hex << "DWORD ImageBase; " << myoption->ImageBase << endl;
cout << hex << "DWORD SectionAlignment; " << myoption->SectionAlignment << endl;
cout << hex << "DWORD FileAlignment; " << myoption->FileAlignment << endl;
cout << hex << "WORD MajorOperatingSystemVersion; " << myoption->MajorOperatingSystemVersion << endl;
cout << hex << "WORD MinorOperatingSystemVersion; " << myoption->MinorOperatingSystemVersion << endl;
cout << hex << "WORD MajorImageVersion; " << myoption->MajorImageVersion << endl;
cout << hex << "DWORD SectionAlignment; " << myoption->SectionAlignment << endl;
cout << hex << "WORD MinorImageVersion; " << myoption->MinorImageVersion << endl;
cout << hex << "WORD MajorSubsystemVersion; " << myoption->MajorSubsystemVersion << endl;
cout << hex << "WORD MinorSubsystemVersion; " << myoption->MinorSubsystemVersion << endl;
cout << hex << "DWORD Win32VersionValue; " << myoption->Win32VersionValue << endl;
cout << hex << "DWORD SizeOfImage; " << myoption->SizeOfImage << endl;
cout << hex << "DWORD SizeOfHeaders; " << myoption->SizeOfHeaders << endl;
cout << hex << "DWORD CheckSum; " << myoption->CheckSum << endl;
cout << hex << "WORD Subsystem; " << myoption->Subsystem << endl;
cout << hex << "WORD DllCharacteristics; " << myoption->DllCharacteristics << endl;
cout << hex << "DWORD SizeOfStackReserve; " << myoption->SizeOfStackReserve << endl;
cout << hex << "DWORD SizeOfStackCommit; " << myoption->SizeOfStackCommit << endl;
cout << hex << "DWORD SizeOfHeapReserve; " << myoption->SizeOfHeapReserve << endl;
cout << hex << "DWORD SizeOfHeapCommit; " << myoption->SizeOfHeapCommit << endl;
cout << hex << "DWORD LoaderFlags; " << myoption->LoaderFlags << endl;
cout << hex << "DWORD NumberOfRvaAndSizes; " << myoption->NumberOfRvaAndSizes << endl;
cout << hex << "IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];" << &(myoption->DataDirectory) << endl;
/////////////////////////////////////////////所有区段表头////////////////////////////////////////////////////
/*typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;*/
//所有区表头都在一起
//大文件头中找区段数
int nCountOfSection = g_pNt->FileHeader.NumberOfSections;
//取第一个区表头
PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(g_pNt);
//循环
for (int i = 0; i < nCountOfSection; i++)
{
cout << "----------------------第"<<i<<"个-----PIMAGE_SECTION_HEADER头(PIMAGE_OPTIONAL_HEADER32 )----------------------------- " << endl;
cout << "BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; " << pSec->Name << endl;
cout << hex << "DWORD PhysicalAddress; " << pSec->Misc.PhysicalAddress << endl;
cout << hex << "DWORD VirtualSize; " << pSec->Misc.VirtualSize << endl;
cout << hex << "DWORD VirtualAddress; " << pSec->VirtualAddress << endl;
cout << hex << "DWORD SizeOfRawData; " << pSec->SizeOfRawData << endl;
cout << hex << "DWORD PointerToRawData; " << pSec->PointerToRawData << endl;
cout << hex << "DWORD PointerToRelocations; " << pSec->PointerToRelocations << endl;
cout << hex << "WORD PointerToLinenumbers; " << pSec->PointerToLinenumbers << endl;
cout << hex << "WORD NumberOfRelocations; " << pSec->NumberOfRelocations << endl;
cout << hex << "DWORD NumberOfLinenumbers; " << pSec->NumberOfLinenumbers << endl;
cout << hex << "DWORD Characteristics; " << pSec->Characteristics << endl;
cout << hex << "在文件中相对文件偏移; " << RVAtoFOA(pSec->VirtualAddress) << endl;
//下一个区表头首地址
++pSec;
}
/////////////////////////////////////////////导出表///////////////////////////////////////////////////////////
//typedef struct _IMAGE_EXPORT_DIRECTORY {
// DWORD Characteristics;
// DWORD TimeDateStamp;
// WORD MajorVersion;
// WORD MinorVersion;
// DWORD Name;
// DWORD Base;
// DWORD NumberOfFunctions;
// DWORD NumberOfNames;
// DWORD AddressOfFunctions; // RVA from base of image
// DWORD AddressOfNames; // RVA from base of image
// DWORD AddressOfNameOrdinals; // RVA from base of image
//} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
//找到导出表 也就是第一个表下标为0
DWORD dwExportRVA =g_pNt->OptionalHeader.DataDirectory[0].VirtualAddress;
//获取在文件中的位置
PIMAGE_EXPORT_DIRECTORY pExport =(PIMAGE_EXPORT_DIRECTORY)(RVAtoFOA(dwExportRVA) + g_pFileImageBase);
//模块名字
char* pName = (char*)(RVAtoFOA(pExport->Name) + g_pFileImageBase);
printf("%s\n", pName);
//地址表中的个数
DWORD dwCountOfFuntions = pExport->NumberOfFunctions;
//名称表中的个数
DWORD dwCountOfNames = pExport->NumberOfNames;
//地址表地址
PDWORD pAddrOfFuntion = (PDWORD)(RVAtoFOA(pExport->AddressOfFunctions) + g_pFileImageBase);
//名称表地址
PDWORD pAddrOfName = (PDWORD)(RVAtoFOA(pExport->AddressOfNames) + g_pFileImageBase);
//序号表地址
PWORD pAddrOfOrdial = (PWORD)(RVAtoFOA(pExport->AddressOfNameOrdinals) + g_pFileImageBase);
//base值
DWORD dwBase = pExport->Base;
//遍历地址表中的元素
cout << "-----------------------------------------导出表中的导出函数与导出序号-------------------------------------------------- " << endl;
if (dwExportRVA == 0) {
printf("没有导出表\n");
//return;
}
else {
for (int i = 0; i < dwCountOfFuntions;i++)
{
//地址表中可能存在无用的值(就是为0的值)
if (pAddrOfFuntion[i] == 0)
{
continue;
}
//根据序号表中是否有值(地址表的下标值),
//来判断是否是名称导出
bool bRet = false;
for (int j = 0; j < dwCountOfNames;j++)
{
//i为地址表下标j为序号表的下标(值为地址表下标)
//判断是否在序号表中
if (i == pAddrOfOrdial[j])
{
//因为序号表与名称表的位置一一对应
//取出名称表中的名称地址RVA
DWORD dwNameRVA = pAddrOfName[j];
char* pFunName = (char*)(RVAtoFOA(dwNameRVA) + g_pFileImageBase);
printf("%04d %s 0x%08x\n", i + dwBase, pFunName, pAddrOfFuntion[i]);
bRet = true;
break;
}
}
if (!bRet)
{
//序号表中没有,说明是以序号导出的
printf("%04d %08X\n", i + dwBase, pAddrOfFuntion[i]);
}
}
}
/////////////////////////////////////////////导出表///////////////////////////////////////////////////////////
//typedef struct _IMAGE_IMPORT_DESCRIPTOR {
// union {
// DWORD Characteristics; // 0 for terminating null import descriptor
// DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
// } DUMMYUNIONNAME;
// DWORD TimeDateStamp; // 0 if not bound,
// // -1 if bound, and real date\time stamp
// // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
// // O.W. date/time stamp of DLL bound to (Old BIND)
// DWORD ForwarderChain; // -1 if no forwarders
// DWORD Name;
// DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
//} IMAGE_IMPORT_DESCRIPTOR;
//typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
cout << "-----------------------------------------导入表中的导入函数与导入模块-------------------------------------------------- " << endl;
//找到导入表 也就是第二个下标为1
DWORD dwImpotRVA = g_pNt->OptionalHeader.DataDirectory[1].VirtualAddress;
//在文件中的位置
DWORD dwImportInFile = (DWORD)(RVAtoFOA(dwImpotRVA) + g_pFileImageBase);
PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)dwImportInFile;
//遍历每一个导入表 通过最后一个为0作为判断条件
if (dwImpotRVA == 0) {
printf("没有导入表\n");
return;
}
else {
while (pImport->Name)
{
//函数名称地址
PIMAGE_THUNK_DATA pFirsThunk =
(PIMAGE_THUNK_DATA)(RVAtoFOA(pImport->FirstThunk) + g_pFileImageBase);
//模块名
char* pName = (char*)(RVAtoFOA(pImport->Name) + g_pFileImageBase);
printf("导入模块名字%s\n", pName);
//也是通过最后一个为0作为判断条件
while (pFirsThunk->u1.AddressOfData)
{
//判断导入方式
if (IMAGE_SNAP_BY_ORDINAL32(pFirsThunk->u1.AddressOfData))
{
//说明是序号导入(低16位是其序号)
printf("\t\t%04X \n", pFirsThunk->u1.Ordinal & 0xFFFF);
}
else
{
//名称导入
PIMAGE_IMPORT_BY_NAME pImportName =
(PIMAGE_IMPORT_BY_NAME)(RVAtoFOA(pFirsThunk->u1.AddressOfData) + g_pFileImageBase);
printf("\t\t%04X %s \n", pImportName->Hint, pImportName->Name);
}
//
pFirsThunk++;
}
pImport++;
}
}
cout << "--------------------------------------------------资源表--------------------------------------------------------------- " << endl;
//注意的是NameOffset偏移 OffsetToDirectory偏移 OffsetToData偏移都是资源表最开始的偏移
//找到资源表
DWORD dwResRVA =
g_pNt->OptionalHeader.DataDirectory[2].VirtualAddress;
DWORD dwResFOA = (DWORD)(RVAtoFOA(dwResRVA) + g_pFileImageBase);
PIMAGE_RESOURCE_DIRECTORY pRes = (PIMAGE_RESOURCE_DIRECTORY)dwResFOA;
//资源有三层 每一层都以一个PIMAGE_RESOURCE_DIRECTORY开头,之后跟数个
//PIMAGE_RESOURCE_DIRECTORY_ENTRY结构,可以说第一层由一个PIMAGE_RESOURCE_DIRECTORY
//与一个PIMAGE_RESOURCE_DIRECTORY_ENTRY结构体组成
//第一层(种类)
//种类个数
DWORD dwCountOfResType =
pRes->NumberOfIdEntries + pRes->NumberOfNamedEntries;
for (int i = 0; i < dwCountOfResType;i++)
{ //pRes代表PIMAGE_RESOURCE_DIRECTORY的首地址+1之后就是后面的PIMAGE_RESOURCE_DIRECTORY_ENTRY首地址
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResEntry =
(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes + 1);
//typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
//这个联合体说明资源叫什么 如果这种资源是已知的也就是微软定义的那么
//联合体最高位为0也就是NameIsString成员为0这个时候整个四字节(union)代表着已知资源的类型,也就是ID起
//作用 如果这种资源是未知是那么NameIsString的最高位为1 低31位指向一个name的结构体(PIMAGE_RESOURCE_DIR_STRING_U)偏移,也就是DWORD Name;起作用
// union {
// struct {
// DWORD NameOffset : 31;
// DWORD NameIsString : 1;
// } DUMMYSTRUCTNAME;
// DWORD Name;
// WORD Id;
// } DUMMYUNIONNAME;
//这个联合体说明资源在哪里
//当DataIsDirectory字段为1时(也就是这个四字节最高位为1)说明这个联合体表示的地方是一个目录,OffsetToDirectory(低31位)表示具体有
//多少个地方,这个些地方就是第二层
// union {
// DWORD OffsetToData;
// struct {
// DWORD OffsetToDirectory : 31;
// DWORD DataIsDirectory : 1;
// } DUMMYSTRUCTNAME2;
// } DUMMYUNIONNAME2;
//} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
//判断这种资源是字符串还是ID
if (pResEntry->NameIsString)
{
//如果是字符串,NameOffset保存的就是这个字符串的RVA
//得到名字字符串的FOA
DWORD dwNameFOA = (DWORD)(RVAtoFOA(pResEntry->NameOffset) + g_pFileImageBase);
//NameOffset所指向的结构体是IMAGE_RESOURCE_DIR_STRING_U类型
//这里保存了字符串的长度和起始位置
PIMAGE_RESOURCE_DIR_STRING_U pName = (PIMAGE_RESOURCE_DIR_STRING_U)dwNameFOA;
//这里的字符串不是以0结尾的,所以需要拷贝出来加上‘\0’结尾后再打印
WCHAR *pResName = new WCHAR[pName->Length + 1]{};
memcpy(pResName, pName, (pName->Length) * sizeof(WCHAR));
//因为是WCHAR,所以用wprintf
wprintf(L"%s\n", pResName);
//释放内存
delete[] pResName;
}
else //id
{
char* arryResType[] = { "", "鼠标指针(Cursor)", "位图(Bitmap)", "图标(Icon)", "菜单(Menu)"
, "对话框(Dialog)", "字符串列表(String Table)", "字体目录(Font Directory)", "字体(Font)", "快捷键(Accelerators)"
, "非格式化资源(Unformatted)", "消息列表(Message Table)", "鼠标指针组(Croup Cursor)", "", "图标组(Group Icon)", ""
, "版本信息(Version Information)" };
if (pResEntry->Id < 17)
{
printf("arryResType[pResEntry->Id] %s\n", arryResType[pResEntry->Id]);
}
else
{
printf("pResEntry->Id %04X\n", pResEntry->Id);
}
//判断是否有下一层(0个表示没有下一层)
if (pResEntry->DataIsDirectory)
{ //到了第二层相对结构体同样和上一层一样但是OffsetToDirectory就指向对三层了
DWORD dwResSecond = (DWORD)pRes + pResEntry->OffsetToDirectory;
PIMAGE_RESOURCE_DIRECTORY pResSecond = (PIMAGE_RESOURCE_DIRECTORY)dwResSecond;
//第二层个数
DWORD dwCountOfSecond =
pResSecond->NumberOfIdEntries + pResSecond->NumberOfNamedEntries;
//遍历每一个资源
for (int iSecond = 0; iSecond < dwCountOfSecond;iSecond++)
{
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResSecondEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResSecond + 1);
//判断这种资源是字符串还是ID
if (pResEntry->NameIsString)
{
//如果是字符串,NameOffset保存的就是这个字符串的RVA
//得到名字字符串的FOA
DWORD dwNameFOA = (DWORD)(RVAtoFOA(pResEntry->NameOffset) + g_pFileImageBase);
//NameOffset所指向的结构体是IMAGE_RESOURCE_DIR_STRING_U类型
//这里保存了字符串的长度和起始位置
PIMAGE_RESOURCE_DIR_STRING_U pName = (PIMAGE_RESOURCE_DIR_STRING_U)dwNameFOA;
//这里的字符串不是以0结尾的,所以需要拷贝出来加上‘\0’结尾后再打印
WCHAR *pResName = new WCHAR[pName->Length + 1]{};
memcpy(pResName, pName, (pName->Length) * sizeof(WCHAR));
wprintf(L"pResName %s\n", pResName);
delete[] pResName;
}
else //id
{
printf("pResEntry->Id %04X\n", pResEntry->Id);
}
//判断有没有下一层
//第三层 同样套路从第一个结构体开始找 到了OffsetToDirectory就是第三层了
//这里要注意的是到了第三层这个IMAGE_RESOURCE_DIRECTORY_ENTRY结构体的第一个联合体就没用了
//同时第二个联合体的DataIsDirectory为0没有下一层了
//通过OffsetToData字段找到资源结构体的偏移(指向_IMAGE_RESOURCE_DATA_ENTRY结构体)
if (pResSecondEntry->DataIsDirectory)
{
//第三层的起始位置
DWORD dwResThrid =
(DWORD)pRes + pResSecondEntry->OffsetToDirectory;
PIMAGE_RESOURCE_DIRECTORY pResThrid = (PIMAGE_RESOURCE_DIRECTORY)dwResThrid;
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResThridEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResThrid + 1);
//第三层,已经是最后一层,使用PIMAGE_RESOURCE_DIRECTORY_ENTRY中的
//OffsetToData成员,得到PIMAGE_RESOURCE_DATA_ENTRY结构的位置
/*typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
DWORD OffsetToData; //资源偏移
DWORD Size;
DWORD CodePage;
DWORD Reserved;
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
*/
PIMAGE_RESOURCE_DATA_ENTRY pResData =
(PIMAGE_RESOURCE_DATA_ENTRY)(pResThridEntry->OffsetToData + (DWORD)pRes);
//资源的RVA和Size
DWORD dwResDataRVA = pResData->OffsetToData;
DWORD dwResDataSize = pResData->Size;
//PIMAGE_RESOURCE_DATA_ENTRY中的OffsetToData是个RVA
DWORD dwResDataFOA = (DWORD)(RVAtoFOA(dwResDataRVA) + g_pFileImageBase);
//资源的二进制数据
//遍历打印资源的二进制数据 这里就只能是二进制了
PBYTE pData = (PBYTE)dwResDataFOA;
for (int iData = 0; iData < dwResDataSize; iData++)
{
if (iData % 16 == 0 && iData != 0)
{
printf("\n");
}
printf("%02X ", pData[iData]);
}
printf("\n");
}
//下一个资源
pResSecondEntry++;
}
}
}
//下一种资源
pResEntry++;
}
cout << "----------------------------------------------------重定位表------------------------------------------------------------ " << endl;
//因为代码用的是绝对地址因此要有定位表
//当重定位发生时,只需要现在pe文件的加载基址,用现在的加载基址减去默认加载基址得到一个数,再用这个数加上需要重定位的数据即可,所以重定位
//表中保存的只是需要重定位信息
typedef struct _OFFSET_TYPE
{
WORD offset : 12; //本页的偏移量
WORD type : 4; //重定位类型(3)
}OFFSET_TYPE, *POFFSET_TYPE;
//重定位表RVA
DWORD dwRelocRVA = g_pNt->OptionalHeader.DataDirectory[5].VirtualAddress;
//是否为空
if (!dwRelocRVA)
{
printf("没有重定位表\n");
return;
}
//重定位表在文件中的地址
PIMAGE_BASE_RELOCATION pReloc = (PIMAGE_BASE_RELOCATION)(RVAtoFOA(dwRelocRVA) + g_pFileImageBase);
//循环重定位表
//如果SizeOfBlock为0,说明没有需要重定位的数据了
while (pReloc->SizeOfBlock)
{
//当前重定位页RVA
printf("%08X\n\n", pReloc->VirtualAddress);
//这一页一共有多少个重定位块(即多少个需要重定位的数据)
DWORD dwCount = (pReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
//指向重定位块地址
POFFSET_TYPE pOffset = (POFFSET_TYPE)(pReloc + 1);
//遍历每一个重定位块
for (int i = 0; i < dwCount;i++)
{
//在这一页中的位置地址RVA
DWORD dwRelocDataRVA = pReloc->VirtualAddress + pOffset->offset;
//转成FOA
DWORD dwRelocDataFOA = (DWORD)(RVAtoFOA(dwRelocDataRVA) + g_pFileImageBase);
//实际需要重定位的数据地址是个VA
DWORD dwRealDataVA = *(DWORD*)dwRelocDataFOA;
//转成RVA(这就是内存中的转换完成的相对地址了)
DWORD dwRealDataRVA = dwRealDataVA - g_pNt->OptionalHeader.ImageBase;
//再转FOA(RVA在文件中的地址)
DWORD dwRealDataFOA = (DWORD)(RVAtoFOA(dwRealDataRVA) + g_pFileImageBase);
//需要重定位的具体数据(字节数不确定)
DWORD dwData = *(DWORD*)dwRealDataFOA;
printf("需要重定位的第%d个数据 RVA:%08X VA:%08X DATA:%08X\n",
i + 1, dwRelocDataRVA, dwRealDataVA, dwData);
//下一个重定位数据位置
pOffset++;
}
//下一页
pReloc =
(PIMAGE_BASE_RELOCATION)(pReloc->SizeOfBlock + (DWORD)pReloc);
}
return ;
}
}
//void _openFile();
DWORD RVAtoFOA(DWORD dwRVA)
{
//此RVA落在哪个区段中
//找到所在区段后,
//减去所在区段的起始位置,加上在文件中的起始位置
//大文件头中找区段数
int nCountOfSection = g_pNt->FileHeader.NumberOfSections;
//区段表头
PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(g_pNt);
//在扩展头中找到块对齐数
DWORD dwSecAligment = g_pNt->OptionalHeader.SectionAlignment;
//循环
for (int i = 0; i < nCountOfSection; i++)
{
//求在内存中的真实大小
//Misc.VirtualSize % dwSecAligment如果是0代表刚好对齐否则就先对齐(非0就是真)
//Misc.VirtualSize / dwSecAligment * dwSecAligment + dwSecAligment //最后加上余数的对齐
DWORD dwRealVirSize = pSec->Misc.VirtualSize % dwSecAligment ?
pSec->Misc.VirtualSize / dwSecAligment * dwSecAligment + dwSecAligment
: pSec->Misc.VirtualSize;
//区段中的相对虚拟地址转文件偏移 思路是 用要转换的地址与各个区
//段起始地址做比较如果落在一个区段中(大于起始地址小于起始地址加区段最大偏移和),
//就用要转换的相对虚拟地址减去区段的起始地址的相对虚拟地址,
//得到了这个地址相对这个区段偏移,再用得到的这个偏移加上区段在文件中的偏移的起始位置
//(pointerToRawData字段)就是他在文件中的文件偏移
if (dwRVA >= pSec->VirtualAddress &&
dwRVA < pSec->VirtualAddress + dwRealVirSize)
{
//FOA = RVA - 内存中区段的起始位置 + 在文件中区段的起始位置
return dwRVA - pSec->VirtualAddress + pSec->PointerToRawData;
}
//下一个区段地址
pSec++;
}
}
int main() {
myPE();
cin.get();
}
以上是关于解析PE资源表与重定位表的主要内容,如果未能解决你的问题,请参考以下文章