尝试解析PE文件结构, 于是编写了此PE信息助手类, 暂时完成如下信息解析
1.导入表信息
2.导入表信息
3.资源表信息
CPEHelper.h
#pragma once
//
// @brief: PE文件解析助手类
// @copyright: Copyright 2024 FlameCyclone
// @license:
// @birth: Created by Visual Studio 2022 on 2024-02-04
// @version: V1.0.0
// @revision: last revised by FlameCyclone on 2024-02-04
//
#include
#include
#include
#include
#include
#include
CPEHelper.cpp
#include "CPEHelper.h"
#include
#include
#pragma comment(lib, "Imagehlp.lib")
// Directory Entries
/*
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
*/
static LPCTSTR g_ResourctTypeName[] = {
_T("RT_NONE"),
_T("Cursor"),
_T("Bitmap"),
_T("Icon"),
_T("Menu"),
_T("Dialog"),
_T("String Table"),
_T("Font dir"),
_T("Font"),
_T("Accelerator"),
_T("Application-defined resource (raw data"),
_T("Message-table entry"),
_T("Cursor Group"),
_T("RT_NONE"),
_T("Icon Group"),
_T("RT_NONE"),
_T("Version Info"),
_T("RT_DLGINCLUDE"),
_T("RT_NONE"),
_T("Plug and Play resource"),
_T("VXD"),
_T("Animated cursor"),
_T("Animated icon"),
_T("Html"),
_T("Manifest")
};
std::string CPEHelper::_WStrToMultiStr(UINT CodePage, const std::wstring& str)
{
std::string strResult;
LPSTR lpMultiByteStr = NULL;
do
{
//计算缓冲区所需的字节大小
int nConverted = 0;
nConverted = ::WideCharToMultiByte(CodePage, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
if (0 == nConverted)
{
break;
}
//分配内存
lpMultiByteStr = (LPSTR)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, nConverted);
if (NULL == lpMultiByteStr)
{
break;
}
//转换
nConverted = ::WideCharToMultiByte(CodePage, 0, str.c_str(), -1, lpMultiByteStr, nConverted, NULL, NULL);
if (0 == nConverted)
{
break;
}
strResult = lpMultiByteStr;
} while (false);
//释放字符串缓冲
if (NULL != lpMultiByteStr)
{
::HeapFree(::GetProcessHeap(), 0, lpMultiByteStr);
lpMultiByteStr = NULL;
}
return strResult;
}
std::wstring CPEHelper::_MultiStrToWStr(UINT CodePage, const std::string& str)
{
std::wstring strResult;
LPWSTR lpWideStr = NULL;
do
{
//计算缓冲区所需的字节大小
int nConverted = 0;
nConverted = ::MultiByteToWideChar(CodePage, 0, str.c_str(), -1, NULL, 0);
if (0 == nConverted)
{
break;
}
//分配缓冲内存
lpWideStr = (LPWSTR)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, nConverted * sizeof(WCHAR));
if (NULL == lpWideStr)
{
break;
}
//转换字符串
nConverted = ::MultiByteToWideChar(CodePage, 0, str.c_str(), -1, lpWideStr, nConverted);
if (0 == nConverted)
{
break;
}
strResult = lpWideStr;
} while (false);
//释放字符串缓冲
if (NULL != lpWideStr)
{
::HeapFree(::GetProcessHeap(), 0, lpWideStr);
lpWideStr = NULL;
}
return strResult;
}
std::string CPEHelper::_WStrToAStr(const std::wstring& str)
{
return _WStrToMultiStr(CP_ACP, str);
}
std::string CPEHelper::_WStrToU8Str(const std::wstring& str)
{
return _WStrToMultiStr(CP_UTF8, str);
}
_tstring CPEHelper::_WStrToTStr(const std::wstring& str)
{
#ifdef _UNICODE
return str;
#else
return _WStrToMultiStr(CP_ACP, str);
#endif
}
std::wstring CPEHelper::_AStrToWStr(const std::string& str)
{
return _MultiStrToWStr(CP_ACP, str);
}
std::string CPEHelper::_AStrToU8Str(const std::string& str)
{
return _WStrToU8Str(_AStrToWStr(str));
}
_tstring CPEHelper::_AStrToTStr(const std::string& str)
{
#ifdef _UNICODE
return _MultiStrToWStr(CP_ACP, str);
#else
return str;
#endif
}
std::wstring CPEHelper::_U8StrToWStr(const std::string& str)
{
return _MultiStrToWStr(CP_UTF8, str);
}
std::string CPEHelper::_U8StrToAStr(const std::string& str)
{
return _WStrToAStr(_U8StrToWStr(str));
}
_tstring CPEHelper::_U8StrToTStr(const std::string& str)
{
#ifdef _UNICODE
return _MultiStrToWStr(CP_UTF8, str);
#else
return _WStrToAStr(_U8StrToWStr(str));
#endif
}
std::string CPEHelper::_TStrToAStr(const _tstring& str)
{
#ifdef _UNICODE
return _WStrToMultiStr(CP_ACP, str);
#else
return str;
#endif
}
std::wstring CPEHelper::_TStrToWStr(const _tstring& str)
{
#ifdef _UNICODE
return str;
#else
return _AStrToWStr(str);
#endif
}
std::string CPEHelper::_TStrToU8Str(const _tstring& str)
{
#ifdef _UNICODE
return _WStrToU8Str(str);
#else
return _WStrToU8Str(_AStrToWStr(str));
#endif
}
CPEHelper::CPEHelper()
:
m_hFile(INVALID_HANDLE_VALUE)
{
_Clear();
}
CPEHelper::~CPEHelper()
{
Close();
}
bool CPEHelper::LoadFile(const _tstring& strPath, bool fCheckSum/* = true*/)
{
bool bResult = false;
Close();
_Clear();
m_hFile = ::CreateFile(
strPath.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (INVALID_HANDLE_VALUE == m_hFile)
{
return false;
}
do
{
DWORD HeaderSum = 0;
DWORD CheckSum = 0;
// 计算校验和
if (fCheckSum && (CHECKSUM_SUCCESS != ::MapFileAndCheckSum(strPath.c_str(), &HeaderSum, &CheckSum)))
{
break;
}
// 读取 DOS 头 64字节
IMAGE_DOS_HEADER dosHeader = { 0 };
DWORD dwBytesRead = 0;
if (!_ReadFile(&dosHeader, sizeof(dosHeader), &dwBytesRead, 0, FILE_BEGIN, true) || IMAGE_DOS_SIGNATURE != dosHeader.e_magic)
{
break;
}
// 读取 NT头(32位版本) 248字节
IMAGE_NT_HEADERS32 ntHeader32 = { 0 };
if (!_ReadFile(&ntHeader32, sizeof(ntHeader32), &dwBytesRead, dosHeader.e_lfanew, FILE_BEGIN, true))
{
break;
}
// 读取 NT头(64位版本) 264字节
IMAGE_NT_HEADERS64 ntHeader64 = { 0 };
if (!_ReadFile(&ntHeader64, sizeof(ntHeader64), &dwBytesRead, dosHeader.e_lfanew, FILE_BEGIN, true))
{
break;
}
// 检查 NT头 签名
if (IMAGE_NT_SIGNATURE != ntHeader32.Signature)
{
break;
}
// 检查 是否为 32位程序可选头
if (IMAGE_NT_OPTIONAL_HDR32_MAGIC == ntHeader32.OptionalHeader.Magic)
{
if (fCheckSum && (CheckSum != ntHeader32.OptionalHeader.CheckSum))
{
break;
}
m_OptionalHeaderMagic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
memcpy_s(&m_NtHeader32, sizeof(m_NtHeader32), &ntHeader32, sizeof(ntHeader32));
memcpy(&m_DataDirectory, &m_NtHeader32.OptionalHeader.DataDirectory, sizeof(m_DataDirectory));
}
// 检查 是否为 64位程序可选头
else if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == ntHeader64.OptionalHeader.Magic)
{
if (fCheckSum && (CheckSum != ntHeader64.OptionalHeader.CheckSum))
{
break;
}
m_OptionalHeaderMagic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
memcpy_s(&m_NtHeader64, sizeof(m_NtHeader64), &ntHeader64, sizeof(ntHeader64));
memcpy(&m_DataDirectory, &m_NtHeader64.OptionalHeader.DataDirectory, sizeof(m_DataDirectory));
}
// ROM可选头
else if (IMAGE_ROM_OPTIONAL_HDR_MAGIC == ntHeader32.OptionalHeader.Magic)
{
m_OptionalHeaderMagic = IMAGE_ROM_OPTIONAL_HDR_MAGIC;
}
else
{
break;
}
// 保存Dos头
memcpy(&m_DosHeader, &dosHeader, sizeof(m_DosHeader));
// 节标头偏移
DWORD dwSectionOffset = (DWORD)(dosHeader.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader) + ntHeader32.FileHeader.SizeOfOptionalHeader);
WORD wNumberOfSections = ntHeader32.FileHeader.NumberOfSections;
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMAGE_SECTION_HEADER) * wNumberOfSections);
if (nullptr == pSectionHeader)
{
break;
}
//保存标头信息
do
{
if (!_ReadFile(pSectionHeader, sizeof(IMAGE_SECTION_HEADER) * wNumberOfSections, &dwBytesRead, dwSectionOffset, FILE_BEGIN, true))
{
break;
}
for (int i = 0; i < wNumberOfSections; i++)
{
m_SectionHeader.push_back(pSectionHeader[i]);
}
} while (false);
// 释放节标头缓冲
if (pSectionHeader)
{
::HeapFree(::GetProcessHeap(), 0, pSectionHeader);
}
bResult = true;
} while (false);
if (bResult)
{
_LoadAllInformation();
}
else
{
Close();
}
return bResult;
}
void CPEHelper::Close()
{
if (INVALID_HANDLE_VALUE != m_hFile)
{
::CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
}
}
const std::map<_tstring, std::vector>& CPEHelper::GetImportTable() const
{
return m_ImportTable;
}
const std::map<_tstring, std::vector>& CPEHelper::GetExportTable() const
{
return m_ExportTable;
}
const RESOURCE_INFO& CPEHelper::GetResourceInfo() const
{
return m_ResourceInfo;
}
void CPEHelper::_Clear()
{
memset(&m_DosHeader, 0, sizeof(m_DosHeader));
memset(&m_NtHeader32, 0, sizeof(m_NtHeader32));
memset(&m_NtHeader64, 0, sizeof(m_NtHeader64));
memset(&m_DataDirectory, 0, sizeof(m_DataDirectory));
m_ResourceDirectoryEntrys.clear();
m_SectionHeader.clear();
m_ImportTable.clear();
m_ExportTable.clear();
m_ResourceInfo.clear();
m_OptionalHeaderMagic = 0;
}
void CPEHelper::_PrintfByte(LPVOID lpData, size_t size)
{
if (NULL == lpData)
{
return;
}
for (int i = 0; i < size; i++)
{
if (i != size - 1)
{
_tprintf(_T("%02X "), ((LPBYTE)lpData)[i]);
}
else
{
_tprintf(_T("%02X"), ((LPBYTE)lpData)[i]);
}
}
}
bool CPEHelper::_GetFileSize(unsigned long long& ullSize) const
{
if (INVALID_HANDLE_VALUE == m_hFile)
{
return false;
}
LARGE_INTEGER ullFileSize = { 0 };
if (!::GetFileSizeEx(m_hFile, &ullFileSize))
{
return false;
}
ullSize = ullFileSize.QuadPart;
return true;
}
bool CPEHelper::_ReadFile(
LPVOID lpBuffer,
DWORD dwSize,
LPDWORD lpBytesRead/* = nullptr*/,
LONGLONG llPos/* = 0*/,
DWORD dwFlag/* = FILE_CURRENT*/,
bool fCheckResdSize/* = false*/
)
{
if (INVALID_HANDLE_VALUE == m_hFile)
{
return false;
}
LARGE_INTEGER liDistanceToMove = { 0 };
BOOL bResult = FALSE;
liDistanceToMove.QuadPart = llPos;
::SetFilePointerEx(m_hFile, liDistanceToMove, NULL, dwFlag);
DWORD dwBytesRead = 0;
bResult = ::ReadFile(m_hFile, lpBuffer, dwSize, &dwBytesRead, NULL);
if (!bResult)
{
return bResult;
}
if (nullptr != lpBytesRead)
{
*lpBytesRead = dwBytesRead;
}
//设置了大区大小检查, 则当实际读取数据量与指定读取数据量相同才认为读取成功
if (fCheckResdSize)
{
bResult = (dwBytesRead == dwSize);
}
return bResult;
}
LONGLONG CPEHelper::_GetSectionDataOffset(
const IMAGE_SECTION_HEADER& sectionHeader,
ULONGLONG ullVirtualAddr
)
{
ULONGLONG VirtualAddrBegin = sectionHeader.VirtualAddress;
ULONGLONG VirtualAddrEnd = VirtualAddrBegin + sectionHeader.SizeOfRawData;
ULONGLONG ullOffset = ullVirtualAddr;
if (ullOffset < VirtualAddrBegin || ullOffset >= VirtualAddrEnd)
{
return -1;
}
ullOffset -= VirtualAddrBegin;
return ullOffset;
}
LPVOID CPEHelper::_GetSectionDataAddr(
LPVOID lpBase,
const IMAGE_SECTION_HEADER& sectionHeader,
ULONGLONG ullVirtualAddr
)
{
ULONGLONG VirtualAddrBegin = sectionHeader.VirtualAddress;
ULONGLONG VirtualAddrEnd = VirtualAddrBegin + sectionHeader.SizeOfRawData;
ULONGLONG ullOffset = VirtualAddrBegin + ullVirtualAddr - sectionHeader.VirtualAddress;
if (ullOffset < VirtualAddrBegin || ullOffset >= VirtualAddrEnd)
{
return NULL;
}
ullOffset -= VirtualAddrBegin;
return (LPBYTE)lpBase + ullOffset;
}
bool CPEHelper::_GetSectionHeader(
ULONGLONG ullVirtualAddr,
PIMAGE_SECTION_HEADER pSectinHeader
)
{
for (const auto& item : m_SectionHeader)
{
ULONGLONG VirtualAddrBegin = item.VirtualAddress;
ULONGLONG VirtualAddrEnd = item.VirtualAddress + item.SizeOfRawData;
if ((ullVirtualAddr >= VirtualAddrBegin) && (ullVirtualAddr < VirtualAddrEnd))
{
if (pSectinHeader)
{
*pSectinHeader = item;
}
return true;
}
}
return false;
}
LPVOID CPEHelper::_GetAlignAddr(
const LPVOID lpAddr,
DWORD dwAlign
)
{
DWORD_PTR dwPadding = ((DWORD_PTR)lpAddr % dwAlign);
if (0 == dwPadding)
{
return lpAddr;
}
return (LPBYTE)lpAddr + (dwAlign - dwPadding);
}
bool CPEHelper::_LoadAllInformation()
{
// 加载资源表
_LoadResourceTable();
// 加载导出表
_LoadExportTable();
// 加载导入表
_LoadImportTable();
return true;
}
bool CPEHelper::_LoadExportTable()
{
bool fResult = false;
DWORD VirtualAddress = m_DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (0 == VirtualAddress)
{
return false;
}
LPBYTE lpSectionData = nullptr;
do
{
// 获取虚拟地址所在节信息
IMAGE_SECTION_HEADER sectionHeader = { 0 };
if (!_GetSectionHeader(VirtualAddress, §ionHeader))
{
break;
}
//分配节数据缓冲
lpSectionData = (LPBYTE)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sectionHeader.SizeOfRawData);
if (NULL == lpSectionData)
{
break;
}
// 读取整个节数据
DWORD dwReadBytes = 0;
if (!_ReadFile(lpSectionData, sectionHeader.SizeOfRawData, &dwReadBytes, sectionHeader.PointerToRawData, FILE_BEGIN, true))
{
break;
}
// 获取导出描述信息所在偏移
ULONGLONG VirtualAddrBegin = m_DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
ULONGLONG VirtualAddrEnd = VirtualAddrBegin + m_DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
LONGLONG ullExportDescOffset = _GetSectionDataOffset(sectionHeader, VirtualAddress);
if (-1 == ullExportDescOffset)
{
break;
}
// 获取导出目录信息位置
PIMAGE_EXPORT_DIRECTORY pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)lpSectionData + ullExportDescOffset);
LPCSTR lpDllName = (LPCSTR)_GetSectionDataAddr(lpSectionData, sectionHeader, pExportDirectory->Name);
if (NULL == lpDllName)
{
break;
}
// 遍历导出表
LPDWORD pFuncAddr = (LPDWORD)_GetSectionDataAddr(lpSectionData, sectionHeader, pExportDirectory->AddressOfFunctions);
LPDWORD pNameAddr = (LPDWORD)_GetSectionDataAddr(lpSectionData, sectionHeader, pExportDirectory->AddressOfNames);
LPWORD pNameOrdinalsName = (LPWORD)_GetSectionDataAddr(lpSectionData, sectionHeader, pExportDirectory->AddressOfNameOrdinals);
if ((NULL == pFuncAddr) || (NULL == pNameAddr) || (NULL == pNameOrdinalsName))
{
break;
}
std::vector FunList;
for (DWORD i = 0; i < pExportDirectory->NumberOfFunctions; i++)
{
EXPORT_FUNCTION_INFO info;
info.Addr = pFuncAddr[i];
info.Ordinal = pExportDirectory->Base + i;
FunList.push_back(info);
}
for (DWORD i = 0; i < pExportDirectory->NumberOfNames; i++)
{
LPCSTR lpFnName = (LPCSTR)_GetSectionDataAddr(lpSectionData, sectionHeader, pNameAddr[i]);
if (NULL == lpFnName)
{
break;
}
DWORD dwOrdinal = pNameOrdinalsName[i];
FunList[dwOrdinal].Name = _AStrToTStr(lpFnName);
//转发函数
if ((FunList[dwOrdinal].Addr >= VirtualAddrBegin && FunList[dwOrdinal].Addr < VirtualAddrEnd))
{
LPCSTR lpForwarderName = (LPCSTR)_GetSectionDataAddr(lpSectionData, sectionHeader, FunList[dwOrdinal].Addr);
if (NULL == lpForwarderName)
{
break;
}
FunList[dwOrdinal].ForwarderName = _AStrToTStr(lpForwarderName);
}
}
m_ExportTable.insert(std::make_pair(_AStrToTStr(lpDllName), FunList));
fResult = true;
} while (false);
// 释放节数据缓冲
if (lpSectionData)
{
::HeapFree(::GetProcessHeap(), 0, lpSectionData);
}
return fResult;
}
bool CPEHelper::_LoadImportTable()
{
IMAGE_IMPORT_DESCRIPTOR emptyImportDesc = { 0 };
bool fResult = false;
DWORD VirtualAddress = m_DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if (0 == VirtualAddress)
{
return false;
}
LPBYTE lpSectionData = nullptr;
do
{
// 获取虚拟地址所在节信息
IMAGE_SECTION_HEADER sectionHeader = { 0 };
if (!_GetSectionHeader(VirtualAddress, §ionHeader))
{
break;
}
//分配节数据缓冲
lpSectionData = (LPBYTE)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sectionHeader.SizeOfRawData);
if (NULL == lpSectionData)
{
break;
}
// 读取整个节数据
DWORD dwReadBytes = 0;
if (!_ReadFile(lpSectionData, sectionHeader.SizeOfRawData, &dwReadBytes, sectionHeader.PointerToRawData, FILE_BEGIN, true))
{
break;
}
// 获取导入描述信息所在偏移
LONGLONG ullImportDescOffset = _GetSectionDataOffset(sectionHeader, VirtualAddress);
if (-1 == ullImportDescOffset)
{
break;
}
// 导入描述
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(LPBYTE)(lpSectionData + ullImportDescOffset);
// 32位导入表
if (IMAGE_NT_OPTIONAL_HDR32_MAGIC == m_OptionalHeaderMagic)
{
// 遍历导入表
for (DWORD i = 0; 0 != ::memcmp(pImportDesc + i, &emptyImportDesc, sizeof(emptyImportDesc)) != 0; i++)
{
LPCSTR DllName = (LPCSTR)_GetSectionDataAddr(lpSectionData, sectionHeader, pImportDesc[i].Name);
if (NULL == DllName)
{
break;
}
PIMAGE_THUNK_DATA32 pThunkData = (PIMAGE_THUNK_DATA32)_GetSectionDataAddr(lpSectionData, sectionHeader, pImportDesc[i].FirstThunk);
if (NULL == pThunkData)
{
break;
}
std::vector FunList;
while (pThunkData->u1.AddressOfData)
{
if (IMAGE_SNAP_BY_ORDINAL32(pThunkData->u1.AddressOfData))
{
IMPORT_FUNCTION_INFO info;
info.Hint = IMAGE_ORDINAL32(pThunkData->u1.AddressOfData);
FunList.push_back(info);
}
else
{
PIMAGE_IMPORT_BY_NAME pImportName = (PIMAGE_IMPORT_BY_NAME)_GetSectionDataAddr(lpSectionData, sectionHeader, pThunkData->u1.AddressOfData);
if (NULL == pImportName)
{
break;
}
IMPORT_FUNCTION_INFO info;
info.Hint = pImportName->Hint;
info.Name = _AStrToTStr((LPCSTR)&pImportName->Name);
FunList.push_back(info);
}
pThunkData++;
}
m_ImportTable.insert(std::make_pair(_AStrToTStr(DllName), FunList));
}
}
// 64位导入表
if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == m_OptionalHeaderMagic)
{
// 遍历导入表
for (DWORD i = 0; 0 != ::memcmp(pImportDesc + i, &emptyImportDesc, sizeof(emptyImportDesc)) != 0; i++)
{
LPCSTR DllName = (LPCSTR)_GetSectionDataAddr(lpSectionData, sectionHeader, pImportDesc[i].Name);
if (NULL == DllName)
{
break;
}
PIMAGE_THUNK_DATA64 pThunkData = (PIMAGE_THUNK_DATA64)_GetSectionDataAddr(lpSectionData, sectionHeader, pImportDesc[i].FirstThunk);
if (NULL == pThunkData)
{
break;
}
std::vector FunList;
while (pThunkData->u1.AddressOfData)
{
if (IMAGE_SNAP_BY_ORDINAL64(pThunkData->u1.AddressOfData))
{
IMPORT_FUNCTION_INFO info;
info.Hint = IMAGE_ORDINAL64(pThunkData->u1.AddressOfData);
FunList.push_back(info);
}
else
{
PIMAGE_IMPORT_BY_NAME pImportName = (PIMAGE_IMPORT_BY_NAME)_GetSectionDataAddr(lpSectionData, sectionHeader, pThunkData->u1.AddressOfData);
if (NULL == pImportName)
{
break;
}
IMPORT_FUNCTION_INFO info;
info.Hint = pImportName->Hint;
info.Name = _AStrToTStr((LPCSTR)&pImportName->Name);
FunList.push_back(info);
}
pThunkData++;
}
m_ImportTable.insert(std::make_pair(_AStrToTStr(DllName), FunList));
}
}
fResult = true;
} while (false);
// 释放节数据缓冲
if (lpSectionData)
{
::HeapFree(::GetProcessHeap(), 0, lpSectionData);
}
return fResult;
}
bool CPEHelper::_LoadResourceTable()
{
bool fResult = false;
DWORD VirtualAddress = m_DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
if (0 == VirtualAddress)
{
return false;
}
LPBYTE lpSectionData = nullptr;
do
{
// 获取虚拟地址所在节信息
IMAGE_SECTION_HEADER sectionHeader = { 0 };
if (!_GetSectionHeader(VirtualAddress, §ionHeader))
{
break;
}
//分配节数据缓冲
lpSectionData = (LPBYTE)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sectionHeader.SizeOfRawData);
if (NULL == lpSectionData)
{
break;
}
// 读取整个节数据
DWORD dwReadBytes = 0;
if (!_ReadFile(lpSectionData, sectionHeader.SizeOfRawData, &dwReadBytes, sectionHeader.PointerToRawData, FILE_BEGIN, true))
{
break;
}
PIMAGE_RESOURCE_DIRECTORY pDirectoryRoot = (PIMAGE_RESOURCE_DIRECTORY)lpSectionData;
DWORD dwTpyeCount = pDirectoryRoot->NumberOfNamedEntries + pDirectoryRoot->NumberOfIdEntries;
for (DWORD i = 0; i < dwTpyeCount; i++)
{
//资源类型目录子项
PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntryType = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pDirectoryRoot + 1) + i;
m_ResourceDirectoryEntrys.push_back(*pEntryType);
RESOURCE_GROUP_INFO GroupInfo;
// 资源类型ID
if (pEntryType->NameIsString)
{
PIMAGE_RESOURCE_DIR_STRING_U pStrName = (PIMAGE_RESOURCE_DIR_STRING_U)((LPBYTE)pDirectoryRoot + pEntryType->NameOffset);
WCHAR szName[MAX_PATH] = { 0 };
memcpy_s(szName, sizeof(szName), pStrName->NameString, pStrName->Length * sizeof(WCHAR));
GroupInfo.TypeName = _WStrToTStr(szName);
GroupInfo.TypeID = 0;
}
else
{
GroupInfo.TypeName = g_ResourctTypeName[pEntryType->Id];
GroupInfo.TypeID = pEntryType->Id;
}
// 资源类型ID子项
PIMAGE_RESOURCE_DIRECTORY pDirectoryDataID = (PIMAGE_RESOURCE_DIRECTORY)((LPBYTE)pDirectoryRoot + pEntryType->OffsetToDirectory);
DWORD dwCount = pDirectoryDataID->NumberOfNamedEntries + pDirectoryDataID->NumberOfIdEntries;
for (DWORD j = 0; j < dwCount; j++)
{
RESOURCE_ITEM info;
// 资源类型ID子项
PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntryDataID = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pDirectoryDataID + 1) + j;
info.ID = pEntryDataID->Id;
//各种语言版本的资源数据
PIMAGE_RESOURCE_DIRECTORY pDirectoryLanguage = (PIMAGE_RESOURCE_DIRECTORY)((LPBYTE)pDirectoryRoot + pEntryDataID->OffsetToDirectory);
DWORD dwLanguageCount = pDirectoryLanguage->NumberOfNamedEntries + pDirectoryLanguage->NumberOfIdEntries;
for (DWORD k = 0; k < dwLanguageCount; k++)
{
//资源ID与数据偏移, 数据大小
PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntryLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pDirectoryLanguage + 1) + k;
PIMAGE_RESOURCE_DATA_ENTRY pDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((LPBYTE)pDirectoryRoot + pEntryLanguage->OffsetToDirectory);
info.LangID = pEntryLanguage->Id;
info.SectionOffset = pDataEntry->OffsetToData - sectionHeader.VirtualAddress;
info.Size = pDataEntry->Size;
GroupInfo.Items.push_back(info);
}
}
m_ResourceInfo.ResourceTable.push_back(GroupInfo);
}
fResult = true;
_LoadResourceInformation(lpSectionData);
} while (false);
// 释放节数据缓冲
if (lpSectionData)
{
::HeapFree(::GetProcessHeap(), 0, lpSectionData);
}
return fResult;
}
bool CPEHelper::_LoadResourceInformation(const LPBYTE lpSectionData)
{
// 解析各种资源类型
for (const auto& item : m_ResourceInfo.ResourceTable)
{
if (MAKEINTRESOURCE(item.TypeID) == RT_STRING)
{
// 加载 字符串表 资源
_LoadResourceStringTable(lpSectionData, item);
}
else if (MAKEINTRESOURCE(item.TypeID) == RT_MANIFEST)
{
// 加载 Manifest 资源
_LoadResourceManifest(lpSectionData, item);
}
else if (MAKEINTRESOURCE(item.TypeID) == RT_VERSION)
{
// 加载 版本 资源
_LoadResourceVersion(lpSectionData, item);
}
}
return true;
}
bool CPEHelper::_LoadResourceStringTable(
const LPBYTE lpSection,
const RESOURCE_GROUP_INFO& info
)
{
LPWSTR lpStrBuf = nullptr;
DWORD dwStringBufSize = UINT16_MAX;
lpStrBuf = (LPWSTR)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dwStringBufSize);
if (NULL == lpStrBuf)
{
return false;
}
for (const auto& str : info.Items)
{
std::vector strList;
WORD wIdBegin = (str.ID - 1) * 16;
LPWORD lpLength = (LPWORD)((LPBYTE)lpSection + str.SectionOffset);
for (WORD i = wIdBegin; i < wIdBegin + 16; i++)
{
if (0 != *lpLength)
{
memcpy_s(lpStrBuf, dwStringBufSize, lpLength + 1, *lpLength * sizeof(WCHAR));
lpStrBuf[*lpLength] = L'\0';
STRING_TEXT strText;
strText.StrText = _WStrToTStr(lpStrBuf);
strText.ID = i;
strList.push_back(strText);
lpLength += *lpLength;
}
lpLength++;
}
auto itFind = m_ResourceInfo.StringTable.find(str.LangID);
if (m_ResourceInfo.StringTable.end() == itFind)
{
m_ResourceInfo.StringTable.insert(std::make_pair(str.LangID, strList));
}
else
{
itFind->second.insert(itFind->second.end(), strList.begin(), strList.end());
}
}
if (NULL != lpStrBuf)
{
::HeapFree(::GetProcessHeap(), 0, lpStrBuf);
}
return true;
}
bool CPEHelper::_LoadResourceManifest(
const LPBYTE lpSection,
const RESOURCE_GROUP_INFO& info
)
{
for (const auto& str : info.Items)
{
LPCSTR lpStr = (LPCSTR)((LPBYTE)lpSection + str.SectionOffset);
m_ResourceInfo.Manifest = _U8StrToTStr(lpStr);
}
return true;
}
bool CPEHelper::_LoadResourceVersion(
const LPBYTE lpSection,
const RESOURCE_GROUP_INFO& info
)
{
for (const auto& str : info.Items)
{
PVS_VERSIONINFO lpVersion = (PVS_VERSIONINFO)((LPBYTE)lpSection + str.SectionOffset);
// 存在 VS_FIXEDFILEINFO 信息
if (0 != lpVersion->wValueLength)
{
VS_FIXEDFILEINFO* pFixedFileInfo = (VS_FIXEDFILEINFO*)((LPBYTE)lpVersion + sizeof(VS_VERSIONINFO));
pFixedFileInfo = (VS_FIXEDFILEINFO*)_GetAlignAddr(pFixedFileInfo, sizeof(DWORD));
m_ResourceInfo.VersionInfo.FixedFileInfo = *pFixedFileInfo;
}
// 解析 StringFileInfo
StringFileInfo* pStringFileInfo = (StringFileInfo*)((LPBYTE)lpVersion + sizeof(VS_VERSIONINFO) + lpVersion->wValueLength);
pStringFileInfo = (StringFileInfo*)_GetAlignAddr(pStringFileInfo, sizeof(DWORD));
{
StringTable* pStringTable = (StringTable*)(pStringFileInfo->Children);
STRING_FILE_INFO strFileInfo;
WCHAR szCodeBuf[MAX_PATH] = { 0 };
memcpy_s(szCodeBuf, sizeof(szCodeBuf), pStringTable->szKey, sizeof(pStringTable->szKey));
strFileInfo.StringCode = _WStrToTStr(szCodeBuf);
LPBYTE lpBegin = (LPBYTE)pStringTable->Children;
LPBYTE lpEnd = lpBegin + pStringTable->wLength - sizeof(STRING_FILE_INFO);
while (lpBegin < lpEnd)
{
String* pString = (String*)lpBegin;
WCHAR szBufKey[MAX_PATH] = { 0 };
WCHAR szBufValue[MAX_PATH] = { 0 };
DWORD dwValueSize = pString->wValueLength;
STRING_FILE_ITEM item;
//字符串类型
if (1 == pString->wType)
{
dwValueSize *= sizeof(WORD);
}
//值名
LPCWSTR lpKey = pString->szKey;
for (DWORD i = 0; 0 != *lpKey; i++, lpKey++)
{
szBufKey[i] = *lpKey;
}
lpKey++;
item.Key = _WStrToTStr(szBufKey);
//值数据位置
lpKey = (LPCWSTR)_GetAlignAddr((LPVOID)lpKey, sizeof(DWORD));
item.wType = pString->wType;
//字符串类型
if (1 == pString->wType)
{
memcpy_s(szBufValue, sizeof(szBufValue), lpKey, dwValueSize);
item.Value = _WStrToTStr(szBufValue);
}
//字节数据类型
else
{
memcpy_s(szBufValue, sizeof(szBufValue), lpKey, dwValueSize);
item.Value = _WStrToTStr(szBufValue);
item.Data.resize(dwValueSize);
LPBYTE lpData = (LPBYTE)lpKey;
for (DWORD i = 0; i < dwValueSize; i++)
{
item.Data[i] = lpData[i];
}
}
strFileInfo.StringInfos.push_back(item);
lpBegin += pString->wLength;
lpBegin = (LPBYTE)_GetAlignAddr(lpBegin, sizeof(DWORD));
}
m_ResourceInfo.VersionInfo.StringFileInfo.push_back(strFileInfo);
}
// 解析 VarFileInfo
VarFileInfo* pVerFileInfo = (VarFileInfo*)((LPBYTE)pStringFileInfo + pStringFileInfo->wLength);
pVerFileInfo = (VarFileInfo*)_GetAlignAddr(pVerFileInfo, sizeof(DWORD));
if ((LPBYTE)pVerFileInfo < ((LPBYTE)lpVersion + lpVersion->wLength))
{
Var* pVar = pVerFileInfo->Children;
for (DWORD i = 0; i < pVar->wValueLength / sizeof(DWORD); i++)
{
TRANSLATION_INFO transInfo;
transInfo.CodePageID = pVar->Value[i].CodePageID;
transInfo.LanguageID = pVar->Value[i].LanguageID;
m_ResourceInfo.VersionInfo.TranslationList.push_back(transInfo);
}
}
}
return true;
}
void CPEHelper::PrintResourceTable(bool fShowDetail/* = true*/)
{
_tprintf(_T("资源类型数量: %4d\n"), (int)m_ResourceInfo.ResourceTable.size());
int i = 0;
for (const auto& ResourceInfo : m_ResourceInfo.ResourceTable)
{
if (0 != ResourceInfo.TypeID)
{
_tprintf(_T(" %4d 类型ID: %4d 类型名: %s 数量: %d\n"), i++, ResourceInfo.TypeID, ResourceInfo.TypeName.c_str(), (int)ResourceInfo.Items.size());
}
else
{
_tprintf(_T(" %4d 类型ID: \"%s\" 数量: %d\n"), i++, ResourceInfo.TypeName.c_str(), (int)ResourceInfo.Items.size());
}
if (!fShowDetail)
{
continue;
}
int j = 0;
for (const auto& item : ResourceInfo.Items)
{
_tprintf(_T(" %4d 资源ID: %4d 节数据偏移: %08X 大小: %d 语言: %d\n"), j++, item.ID, item.SectionOffset, item.Size, item.LangID);
}
}
}
void CPEHelper::PrintExportTable(bool fShowModule/* = true*/, bool fShowFunList/* = true*/)
{
int nFunctionCount = 0;
for (const auto& item : m_ExportTable)
{
nFunctionCount += (int)item.second.size();
}
_tprintf(_T("Export module count: %d function count: %d\n"), (int)m_ExportTable.size(), nFunctionCount);
int i = 0;
for (const auto& item : m_ExportTable)
{
if (fShowModule)
{
_tprintf(_T(" %4d %s function count: %4d\n"), i++, item.first.c_str(), (int)item.second.size());
}
if (!fShowFunList)
{
continue;
}
int j = 0;
for (const auto& fun : item.second)
{
if (!fun.Name.empty())
{
if (fun.ForwarderName.empty())
{
_tprintf(_T(" %4d Ordinal: %4d(%04x) Addr: %08x %s \n"), j++, fun.Ordinal, fun.Ordinal, fun.Addr, fun.Name.c_str());
}
else
{
_tprintf(_T(" %4d Ordinal: %4d(%04x) Addr: %08x %s -> %s \n"), j++, fun.Ordinal, fun.Ordinal, fun.Addr, fun.Name.c_str(), fun.ForwarderName.c_str());
}
}
else
{
_tprintf(_T(" %4d Ordinal: %4d(%04x) Addr: %08x \n"), j++, fun.Ordinal, fun.Ordinal, fun.Addr);
}
}
}
}
void CPEHelper::PrintImportTable(bool fShowModule/* = true*/, bool fShowFunList/* = true*/)
{
int nFunctionCount = 0;
for (const auto& item : m_ImportTable)
{
nFunctionCount += (int)item.second.size();
}
_tprintf(_T("Import module count: %d function count: %d\n"), (int)m_ImportTable.size(), nFunctionCount);
int i = 0;
for (const auto& item : m_ImportTable)
{
if (fShowModule)
{
_tprintf(_T(" %d %s count: %d\n"), i++, item.first.c_str(), (int)item.second.size());
}
if (!fShowFunList)
{
continue;
}
int j = 0;
for (const auto& fun : item.second)
{
if (!fun.Name.empty())
{
_tprintf(_T(" %4d %4d(%04x) %s\n"), j++, fun.Hint, fun.Hint, fun.Name.c_str());
}
else
{
_tprintf(_T(" %4d %4d(%04x)\n"), j++, fun.Hint, fun.Hint);
}
}
}
}
void CPEHelper::PrintVersion()
{
_tprintf(_T("Version:\n"));
_tprintf(_T(" StringFileInfo conut: %d\n"), (int)m_ResourceInfo.VersionInfo.StringFileInfo.size());
for (const auto& item : m_ResourceInfo.VersionInfo.StringFileInfo)
{
_tprintf(_T(" %s\n"), item.StringCode.c_str());
for (const auto& info : item.StringInfos)
{
if (info.wType)
{
_tprintf(_T(" %s: %s\n"), info.Key.c_str(), info.Value.c_str());
}
else
{
_tprintf(_T(" %s: "), info.Key.c_str());
_PrintfByte((LPVOID)info.Data.data(), info.Data.size());
_tprintf(_T("\n"));
}
}
}
_tprintf(_T(" Translation conut: %d\n"), (int)m_ResourceInfo.VersionInfo.TranslationList.size());
for (const auto& item : m_ResourceInfo.VersionInfo.TranslationList)
{
_tprintf(_T(" 0x%04X 0x%04X\n"), item.LanguageID, item.CodePageID);
}
}
void CPEHelper::PrintManifest()
{
_tprintf(_T("Manifest:\n"));
_tprintf(_T("%s\n"), m_ResourceInfo.Manifest.c_str());
}
测试
main.c
#include
#include
#include
#include "CPEHelper.h"
#include "CTimeUtils.h"
int main()
{
setlocale(LC_ALL, "");
CPEHelper obj;
//obj.LoadFile(_T(R"(qt-opensource-windows-x86-5.14.2.exe)"));
//obj.LoadFile(_T(R"(gfx_win_101.3790_101.2114.exe)"));
int64_t timeBegin = CTimeUtils::GetCurrentTickCount();
int64_t timeEnd = CTimeUtils::GetCurrentTickCount();
int nRepeatCount = 100;
while (true)
{
timeBegin = CTimeUtils::GetCurrentTickCount();
for (int i = 0; i < nRepeatCount; i++)
{
//obj.LoadFile(_T(R"(qt-opensource-windows-x86-5.14.2.exe)"), true);
//obj.LoadFile(_T(R"(shell32.dll)"));
obj.LoadFile(_T(R"(user32.dll)"), true);
//obj.LoadFile(_T(R"(CPEUtils.exe)"));
//obj.LoadFile(_T(R"(shell32.dll)"));
//obj.LoadFile(_T(R"(KernelBase.dll)"));
//obj.LoadFile(_T(R"(ntdll.dll)"));
}
RESOURCE_INFO info = obj.GetResourceInfo();
timeEnd = CTimeUtils::GetCurrentTickCount();
#if 1
obj.PrintExportTable(false, false);
_tprintf(_T("\n"));
obj.PrintImportTable(false, false);
_tprintf(_T("\n"));
obj.PrintResourceTable(false);
_tprintf(_T("\n"));
obj.PrintVersion();
_tprintf(_T("\n"));
#else
obj.PrintExportTable(true, true);
_tprintf(_T("\n"));
obj.PrintImportTable(true, true);
_tprintf(_T("\n"));
obj.PrintResourceTable(false);
_tprintf(_T("\n"));
obj.PrintVersion();
_tprintf(_T("\n"));
#endif
//obj.PrintManifest();
_tprintf(_T("repeat count: %d cost time: %llu ms\n"), nRepeatCount, timeEnd - timeBegin);
system("pause");
}
return 0;
}