C++ PE文件信息解析

尝试解析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 <stdint.h>
#include <wtypesbase.h>
#include <windows.h>
#include <string>
#include <vector>
#include <map>#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif#pragma pack(push)
#pragma pack(1)// https://learn.microsoft.com/zh-cn/windows/win32/menurc/newheader
typedef struct {WORD Reserved;				//保留;必须为零WORD ResType;				//资源类型 1: RES_ICON	2: RES_CURSORWORD ResCount;				//资源组中的图标或游标组件数
} ICON_GROUP_HEADER, * LPICON_GROUP_HEADER;// https://learn.microsoft.com/zh-cn/windows/win32/menurc/resdir
// https://learn.microsoft.com/zh-cn/windows/win32/menurc/iconresdir
typedef struct {BYTE Width;					//图标的宽度(以像素为单位)。 可接受的值为 16、32 和 64BYTE Height;				//图标的高度(以像素为单位)。 可接受的值为 16、32 和 64BYTE ColorCount;			//图标中的颜色数。 可接受的值为 2、8 和 16。BYTE reserved;				//保留;必须设置为与图标文件标头中保留字段的值相同的值WORD Planes;				//图标或光标位图中的颜色平面数WORD BitCount;				//图标或光标位图中每像素的位数DWORD BytesInRes;			//资源的大小(以字节为单位)WORD IconId;				//具有唯一序号标识符的图标或光标
} ICON_ENTRY, * LPICON_ENTRY;typedef struct {ICON_GROUP_HEADER Header;	//图标组头部ICON_ENTRY	IconEntry[1];	//单个图标信息
}ICON_GROUP_DIR, * LPICON_GROUP_DIR;// https://learn.microsoft.com/zh-cn/windows/win32/menurc/var-str
typedef struct {WORD  wLength;                  // Var 结构的长度(以字节为单位)WORD  wValueLength;             // Value 成员的长度(以字节为单位)WORD  wType;                    // 版本资源中的数据类型, 1: 资源包含文本数据 0: 版本资源包含二进制数据WCHAR szKey[12];                // Unicode 字符串 L“Translation”WORD  Padding;                  // 在 32 位边界上对齐 Value 成员所需的任意或零个 WORDstruct {WORD LanguageID;            //低序字: Microsoft 语言标识符WORD CodePageID;            //高序字: IBM 代码页码}Value[1];
} Var;// https://learn.microsoft.com/zh-cn/windows/win32/menurc/varfileinfo
typedef struct {WORD  wLength;                  // 整个 VarFileInfo 块(包括 Children 成员指示的所有结构)的长度(以字节为单位)WORD  wValueLength;             // 此成员始终等于零WORD  wType;                    // 版本资源中的数据类型, 1: 资源包含文本数据 0: 版本资源包含二进制数据WCHAR szKey[12];                // Unicode 字符串 L“VarFileInfo”WORD  Padding;                  // 在 32 位边界上对齐 Children 成员所需的任意或零个 WORDVar   Children[1];              // 通常包含应用程序或 DLL 支持的语言列表
} VarFileInfo;// https://learn.microsoft.com/zh-cn/windows/win32/menurc/string-str
typedef struct {WORD  wLength;                  // 此 字符串 结构的长度(以字节为单位)WORD  wValueLength;             // Value 成员的大小(以字为单位)WORD  wType;                    // 版本资源中的数据类型, 1: 资源包含文本数据 0: 版本资源包含二进制数据WCHAR szKey[1];                 // 任意长度的 Unicode 字符串WORD  Padding;                  // 在 32 位边界上对齐 Value 成员所需的任意或零个 WORDWORD  Value[1];                 // 以零结尾的字符串
} String;// https://learn.microsoft.com/zh-cn/windows/win32/menurc/stringtable
typedef struct {WORD   wLength;                 // 此 StringTable 结构的长度(以字节为单位),包括 Children 成员指示的所有结构WORD   wValueLength;            // 此成员始终等于零WORD   wType;                   // 版本资源中的数据类型, 1: 资源包含文本数据 0: 版本资源包含二进制数据WCHAR  szKey[8];                // 存储为 Unicode 字符串的 8 位十六进制数WORD   Padding;                 // 在 32 位边界上对齐 Children 成员所需的任意或零个 WORDString Children[1];             // 一个或多个 String 结构的数组
} StringTable;// https://learn.microsoft.com/zh-cn/windows/win32/menurc/stringfileinfo
typedef struct {WORD        wLength;            // 整个 StringFileInfo 块的长度(以字节为单位)WORD        wValueLength;       // 此成员始终等于零WORD        wType;              // 版本资源中的数据类型, 1: 资源包含文本数据 0: 版本资源包含二进制数据WCHAR       szKey[14];          // Unicode 字符串 L“StringFileInfo”WORD        Padding;            // 在 32 位边界上对齐 Children 成员所需的任意或零个 WORDStringTable Children[1];        // 一个或多个 StringTable 结构的数组
} StringFileInfo;// VS 文件版本信息
// https://learn.microsoft.com/zh-cn/windows/win32/menurc/vs-versioninfo
typedef struct {WORD             wLength;       // VS_VERSIONINFO 结构的长度(以字节为单位),此长度不包括在 32 位边界上对齐任何后续版本资源数据的填充WORD             wValueLength;  // Value 成员的长度(以字节为单位)WORD             wType;         // 版本资源中的数据类型, 1: 资源包含文本数据 0: 版本资源包含二进制数据WCHAR            szKey[15];     // Unicode 字符串 L“VS_VERSION_INFO”WORD             Padding1;      // 在 32 位边界上对齐 Children 成员所需的任意或零个 WORD//VS_FIXEDFILEINFO Value//WORD             Padding2//WORD             Children
} VS_VERSIONINFO, *PVS_VERSIONINFO;
#pragma pack(pop)typedef struct {WORD ID;                    //资源IDWORD LangID;                //语言IDDWORD SectionOffset;        //数据偏移(在节数据中的偏移位置)DWORD Size;                 //数据大小
}RESOURCE_ITEM;typedef struct {_tstring StrText;           //文本内容WORD ID;                    //字符串ID
}STRING_TEXT;typedef struct {_tstring TypeName;                  //类型名WORD TypeID;                        //类型IDstd::vector<RESOURCE_ITEM> Items;   //资源信息
}RESOURCE_GROUP_INFO;typedef struct
{_tstring Text;WORD  wType;
}STRING_INFO;typedef struct
{_tstring Key;                   // 值名字符串_tstring Value;                 // 值数据字符串WORD wType;                     // 版本资源中的数据类型, 1: 资源包含文本数据 0: 版本资源包含二进制数据std::vector<uint8_t> Data;      // 二进制数据
}STRING_FILE_ITEM;// 版本资源中的数据, 包含可为特定语言和代码页显示的版本信息
typedef struct
{_tstring StringCode;std::vector<STRING_FILE_ITEM> StringInfos;
}STRING_FILE_INFO;typedef struct
{WORD LanguageID;WORD CodePageID;
}TRANSLATION_INFO;// 版本信息
typedef struct
{VS_FIXEDFILEINFO FixedFileInfo;std::vector<STRING_FILE_INFO> StringFileInfo;   // 版本资源中的数据的组织std::vector<TRANSLATION_INFO> TranslationList;  // 应用程序或 DLL 支持的语言列表
}VERSION_INFO;typedef struct
{_tstring Name;          //函数名WORD Hint;              //索引, 可能为0
}IMPORT_FUNCTION_INFO;typedef struct
{_tstring Name;          //函数名_tstring ForwarderName; //转发函数名DWORD Addr;             //函数相对偏移地址DWORD Ordinal;          //函数顺序
}EXPORT_FUNCTION_INFO;typedef struct _RESOURCE_INFO
{std::vector<RESOURCE_GROUP_INFO> ResourceTable;             //资源表信息std::map<WORD, std::vector<STRING_TEXT>> StringTable;       //资源字符串表VERSION_INFO VersionInfo;                                   //资源版本信息_tstring Manifest;                                          //资源清单void clear(){ResourceTable.clear();StringTable.clear();VersionInfo.StringFileInfo.clear();VersionInfo.TranslationList.clear();memset(&VersionInfo.FixedFileInfo, 0, sizeof(VersionInfo.FixedFileInfo));}}RESOURCE_INFO;class CPEHelper
{
public:CPEHelper();~CPEHelper();//// @brief: 加载PE文件信息// @param: strPath          文件路径// @param: fCheckSum        检查映像文件校验和, 校验失败此函数将直接返回false// @ret: bool               操作成功与否bool LoadFile(const _tstring& strPath, bool fCheckSum = true);//// @brief: 关闭文件占用// @ret: bool               操作成功与否void Close();//// @brief: 获取导入表信息// @ret: std::map<_tstring, std::vector<IMPORT_FUNCTION_INFO>>  导入表信息const std::map<_tstring, std::vector<IMPORT_FUNCTION_INFO>>& GetImportTable() const;//// @brief: 获取导出表信息// @ret: std::map<_tstring, std::vector<IMPORT_FUNCTION_INFO>>  导出表信息const std::map<_tstring, std::vector<EXPORT_FUNCTION_INFO>>& GetExportTable() const;//// @brief: 获取资源表信息// @ret: RESOURCE_INFO                                          资源信息const RESOURCE_INFO& GetResourceInfo() const;//// @brief: 打印导出表信息// @param: fShowModule      显示模块信息// @param: fShowFunList     显示函数信息// @ret: voidvoid PrintExportTable(bool fShowModule = true, bool fShowFunList = true);//// @brief: 打印导入表信息// @param: fShowModule      显示模块信息// @param: fShowFunList     显示函数信息// @ret: voidvoid PrintImportTable(bool fShowModule = true, bool fShowFunList = true);//// @brief: 打印资源表信息// @param: fShowDetail      显示详情// @ret: voidvoid PrintResourceTable(bool fShowDetail = true);//// @brief: 打印版本信息// @ret: voidvoid PrintVersion();//// @brief: 打印字符串表// @ret: voidvoid PrintStringTable();//// @brief: 打印清单信息// @ret: voidvoid PrintManifest();private://// @brief: 清空数据// @ret: voidvoid _Clear();//// @brief: 输出字节信息// @ret: voidvoid _PrintfByte(LPVOID lpData, size_t size);//// @brief: 获取文件大小// @param: ullSize          文件大小// @ret: bool               操作成功与否bool _GetFileSize(unsigned long long& ullSize) const;//// @brief: 读取文件// @param: lpBuffer         读取数据存放缓冲// @param: dwSize           缓冲大小(字节)// @param: lpBytesRead      实际读取大小(字节)// @param: llPos            读取文件数据位置// @param: dwFlag           设置位置标志 FILE_BEGIN: 文件开头 FILE_CURRENT: 当前文件指针 FILE_END: 文件结束位置// @param: fCheckResdSize   是否检查读取长度// @ret: bool               操作成功与否bool _ReadFile(LPVOID lpBuffer, DWORD dwSize, LPDWORD lpBytesRead = nullptr,LONGLONG llPos = 0,DWORD dwFlag = FILE_CURRENT, bool fCheckResdSize = false);//// @brief: 获取虚拟地址在节数据中的相对偏移// @param: sectionHeader    节信息头// @param: ullVirtualAddr   虚拟地址// @ret: LONGLONG           虚拟地址在节数据中的相对偏移LONGLONG _GetSectionDataOffset(const IMAGE_SECTION_HEADER& sectionHeader, ULONGLONG ullVirtualAddr);//// @brief: 获取虚拟地址在节数据内存中的位置// @param: lpBase           节数据内存位置// @param: sectionHeader    节信息头// @param: ullVirtualAddr   虚拟地址// @ret: LONGLONG           虚拟地址在节数据内存中的位置LPVOID _GetSectionDataAddr(LPVOID lpBase, const IMAGE_SECTION_HEADER& sectionHeader, ULONGLONG ullVirtualAddr);//// @brief: 获取虚拟地址在节数据内存中的位置// @param: ullVirtualAddr   虚拟地址// @param: pSectinHeader    节信息头输出缓冲// @ret: bool               操作成功与否bool _GetSectionHeader(ULONGLONG ullVirtualAddr, PIMAGE_SECTION_HEADER pSectinHeader);//// @brief: 获取地址对齐后的地址// @param: lpAddr           地址// @param: dwAlign          对齐粒度// @ret: LPVOID             对齐后指针LPCVOID _GetAlignAddr(LPCVOID lpAddr, DWORD dwAlign = sizeof(DWORD));//// @brief: 加载所有信息// @ret: bool               操作成功与否bool _LoadAllInformation();//// @brief: 加载导出表// @ret: bool               操作成功与否bool _LoadExportTable();//// @brief: 加载导入表// @ret: bool               操作成功与否bool _LoadImportTable();//// @brief: 加载资源表// @ret: bool               操作成功与否bool _LoadResourceTable();//// @brief: 加载资源信息// @param: lpSection        节数据内存指针// @ret: bool               操作成功与否bool _LoadResourceInformation(const LPBYTE lpSectionData);//// @brief: 加载资源字符串表// @param: lpSection        节数据内存指针// @ret: info               资源组信息// @ret: bool               操作成功与否bool _LoadResourceStringTable(const LPBYTE lpSection,const RESOURCE_GROUP_INFO& info);//// @brief: 加载资源Manifest// @param: lpSection        节数据内存指针// @ret: info               资源组信息// @ret: bool               操作成功与否bool _LoadResourceManifest(const LPBYTE lpSection,const RESOURCE_GROUP_INFO& info);//// @brief: 加载资源版本信息// @param: lpSection        节数据内存指针// @ret: info               资源组信息// @ret: bool               操作成功与否bool _LoadResourceVersion(const LPBYTE lpSection,const RESOURCE_GROUP_INFO& info);// 宽字符转多字节字符static std::string _WStrToMultiStr(UINT CodePage, const std::wstring& str);// 多字节字符转宽字符static std::wstring _MultiStrToWStr(UINT CodePage, const std::string& str);// 宽字符串转换static std::string _WStrToU8Str(const std::wstring& str);static std::string _WStrToAStr(const std::wstring& str);static _tstring _WStrToTStr(const std::wstring& str);// ANSI字符转换static std::wstring _AStrToWStr(const std::string& str);static std::string _AStrToU8Str(const std::string& str);static _tstring _AStrToTStr(const std::string& str);// UTF-8字符串转换static std::wstring _U8StrToWStr(const std::string& str);static std::string _U8StrToAStr(const std::string& str);static _tstring _U8StrToTStr(const std::string& str);// 中立字符串转换static std::string _TStrToAStr(const _tstring& str);static std::wstring _TStrToWStr(const _tstring& str);static std::string _TStrToU8Str(const _tstring& str);private:HANDLE m_hFile;                                                                 //PE文件句柄//基础PE信息IMAGE_DOS_HEADER m_DosHeader;                                                   //Dos头IMAGE_NT_HEADERS32 m_NtHeader32;                                                //NT头(32位)IMAGE_NT_HEADERS64 m_NtHeader64;                                                //NT头(64位)IMAGE_DATA_DIRECTORY m_DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];         //数据目录std::vector<IMAGE_SECTION_HEADER> m_SectionHeader;                              //节头信息std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY> m_ResourceDirectoryEntrys;          //资源目录信息//数据目录解析相关成员std::map<_tstring, std::vector<IMPORT_FUNCTION_INFO>> m_ImportTable;            //导入表信息std::map<_tstring, std::vector<EXPORT_FUNCTION_INFO>> m_ExportTable;            //导出表信息RESOURCE_INFO m_ResourceInfo;                                                   //资源信息WORD m_OptionalHeaderMagic;                                                     //可选头魔数
};

CPEHelper.cpp

#include "CPEHelper.h"
#include <tchar.h>
#include <imagehlp.h>#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 _UNICODEreturn str;
#elsereturn _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 _UNICODEreturn _MultiStrToWStr(CP_ACP, str);
#elsereturn 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 _UNICODEreturn _MultiStrToWStr(CP_UTF8, str);
#elsereturn _WStrToAStr(_U8StrToWStr(str));
#endif
}std::string CPEHelper::_TStrToAStr(const _tstring& str)
{
#ifdef _UNICODEreturn _WStrToMultiStr(CP_ACP, str);
#elsereturn str;
#endif
}std::wstring CPEHelper::_TStrToWStr(const _tstring& str)
{
#ifdef _UNICODEreturn str;
#elsereturn _AStrToWStr(str);
#endif
}std::string CPEHelper::_TStrToU8Str(const _tstring& str)
{
#ifdef _UNICODEreturn _WStrToU8Str(str);
#elsereturn _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<IMPORT_FUNCTION_INFO>>& CPEHelper::GetImportTable() const
{return m_ImportTable;
}const std::map<_tstring, std::vector<EXPORT_FUNCTION_INFO>>& 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;
}LPCVOID CPEHelper::_GetAlignAddr(LPCVOID 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, &sectionHeader)){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<EXPORT_FUNCTION_INFO> 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, &sectionHeader)){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<IMPORT_FUNCTION_INFO> 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<IMPORT_FUNCTION_INFO> 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, &sectionHeader)){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;// 资源类型IDif (pEntryType->NameIsString){PIMAGE_RESOURCE_DIR_STRING_U pStrName = (PIMAGE_RESOURCE_DIR_STRING_U)((LPBYTE)pDirectoryRoot + pEntryType->NameOffset);GroupInfo.TypeName = _WStrToTStr(std::wstring(pStrName->NameString, pStrName->Length));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
)
{for (const auto& str : info.Items){std::vector<STRING_TEXT> 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){STRING_TEXT strText;strText.StrText = _WStrToTStr(std::wstring((LPCTSTR)lpLength + 1, *lpLength));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());}}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;}// 解析 StringFileInfoStringFileInfo* pStringFileInfo = (StringFileInfo*)((LPBYTE)lpVersion + sizeof(VS_VERSIONINFO) + lpVersion->wValueLength);pStringFileInfo = (StringFileInfo*)_GetAlignAddr(pStringFileInfo, sizeof(DWORD));{STRING_FILE_INFO strFileInfo;StringTable* pStringTable = (StringTable*)(pStringFileInfo->Children);strFileInfo.StringCode = _WStrToTStr(std::wstring(pStringTable->szKey, _countof(pStringTable->szKey)));LPBYTE lpBegin = (LPBYTE)pStringTable->Children;LPBYTE lpEnd = lpBegin + pStringTable->wLength - sizeof(STRING_FILE_INFO);while (lpBegin < lpEnd){String* pString = (String*)lpBegin;DWORD dwValueSize = pString->wValueLength;STRING_FILE_ITEM item;std::wstring strKey = pString->szKey;item.Key = _WStrToTStr(strKey);//值名LPCWSTR lpStrValue = pString->szKey;lpStrValue += strKey.size() + 1;//值数据位置lpStrValue = (LPCWSTR)_GetAlignAddr(lpStrValue, sizeof(DWORD));item.wType = pString->wType;//字符串类型if (1 == pString->wType){item.Value = _WStrToTStr(std::wstring(lpStrValue, dwValueSize));}//字节数据类型else{item.Value = _WStrToTStr(std::wstring(lpStrValue, dwValueSize));item.Data.resize(dwValueSize);for (DWORD i = 0; i < dwValueSize; i++){item.Data[i] = ((LPBYTE)lpStrValue)[i];}}strFileInfo.StringInfos.push_back(item);lpBegin += pString->wLength;lpBegin = (LPBYTE)_GetAlignAddr(lpBegin, sizeof(DWORD));}m_ResourceInfo.VersionInfo.StringFileInfo.push_back(strFileInfo);}// 解析 VarFileInfoVarFileInfo* 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());VS_FIXEDFILEINFO& FixedFileInfo = m_ResourceInfo.VersionInfo.FixedFileInfo;_tprintf(_T("            FileVersion: %d.%d.%d.%d\n"),HIWORD(FixedFileInfo.dwFileVersionMS),LOWORD(FixedFileInfo.dwFileVersionMS),HIWORD(FixedFileInfo.dwFileVersionLS),LOWORD(FixedFileInfo.dwFileVersionLS));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: %s\n"), info.Key.c_str(), info.Value.c_str());//_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::PrintStringTable()
{_tprintf(_T("StringTable: count: %d\n"), (int)m_ResourceInfo.StringTable.size());for (const auto& item : m_ResourceInfo.StringTable){_tprintf(_T("    ID: %d, count: %d\n"), item.first, (int)item.second.size());for (const auto& info : item.second){_tprintf(_T("        %04d: %s\n"), info.ID, info.StrText.c_str());}}
}void CPEHelper::PrintManifest()
{_tprintf(_T("Manifest:\n"));_tprintf(_T("%s\n"), m_ResourceInfo.Manifest.c_str());
}

测试

main.c

#include <iostream>
#include <windows.h>
#include <tchar.h>
#include "CPEHelper.h"
#include "CTimeUtils.h"int main()
{setlocale(LC_ALL, "");CPEHelper obj;int64_t timeBegin = CTimeUtils::GetCurrentTickCount();int64_t timeEnd = CTimeUtils::GetCurrentTickCount();int nRepeatCount = 1;while (true){timeBegin = CTimeUtils::GetCurrentTickCount();for (int i = 0; i < nRepeatCount; i++){//obj.LoadFile(_T(R"(gfx_win_101.3790_101.2114.exe)"), false);//obj.LoadFile(_T(R"(CPEUtils.exe)"), false);//obj.LoadFile(_T(R"(qt-opensource-windows-x86-5.14.2.exe)"), true);obj.LoadFile(_T(R"(user32.dll)"), true);//obj.LoadFile(_T(R"(ndis.sys)"), true);//obj.LoadFile(_T(R"(shell32.dll)"), true);//obj.LoadFile(_T(R"(KernelBase.dll)"), true);//obj.LoadFile(_T(R"(ntdll.dll)"), true);}RESOURCE_INFO info = obj.GetResourceInfo();timeEnd = CTimeUtils::GetCurrentTickCount();#if 0obj.PrintExportTable(false, false);_tprintf(_T("\n"));obj.PrintImportTable(false, false);_tprintf(_T("\n"));obj.PrintResourceTable(false);_tprintf(_T("\n"));obj.PrintStringTable();_tprintf(_T("\n"));obj.PrintVersion();_tprintf(_T("\n"));
#elseobj.PrintExportTable(true, true);_tprintf(_T("\n"));obj.PrintImportTable(true, true);_tprintf(_T("\n"));obj.PrintResourceTable(true);_tprintf(_T("\n"));obj.PrintStringTable();_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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/669873.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件价值8-站点连通性检查

站点连通性检查&#xff0c;即看网站是否能访问得通&#xff0c;实用价值不大&#xff0c;不过用来作软件应用入门还不错。 代码&#xff1a; import urllib.request import tkinter as tkdef test_connectivity():window tk.Tk()window.geometry(600x400)window.resizable(F…

输出超级玛丽2_题解

【题解提供者】吴立强 解法 思路 本题代码非常简单&#xff0c;直接一行一行对齐后输出即可&#xff0c;只是比较麻烦。 代码展示 #include <iostream> using namespace std;int main() {printf(" ********\n");printf(" …

普通编程,机器学习与深度学习

普通编程&#xff1a;基于人手动设置规则&#xff0c;由输入产生输出经典机器学习&#xff1a;人手工指定需要的特征&#xff0c;通过一些数学原理对特征与输出的匹配模式进行学习&#xff0c;也就是更新相应的参数&#xff0c;从而使数学表达式能够更好的根据给定的特征得到准…

Java 学习和实践笔记(1)

2024年&#xff0c;决定好好学习计算机语言Java. B站上选了这个课程&#xff1a;【整整300集】浙大大佬160小时讲完的Java教程&#xff08;学习路线Java笔记&#xff09;零基础&#xff0c;就从今天开始学吧。 在这些语言中&#xff0c;C语言是最基础的语言&#xff0c;绝大多…

Blender_pmx导出fbx

Blender_pmx导出fbx 学无止境&#xff1f; 相关链接&#xff1a; Blender教程&#xff1a; Blender中文手册介绍 — Blender Manualhttps://docs.blender.org/manual/zh-hans/2.79/about/introduction.htmlhttps://www.blendercn.org/https://www.blendercn.org/Blender下载…

1978-2023年全国整体GDP平减指数计算模板(含计算公式代码+计算结果且可任意调整基期)

1978-2023年全国整体GDP平减指数、实际GDP数据&#xff08;可任意调整基期&#xff09; 1、时间&#xff1a;1978-2023年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;名义GDP、实际GDP、国内生产总值指数、GDP平减指数 4、数据内含原始数据计算公式代码&…

JVM 性能调优 - JVM 参数基础(2)

查看 JDK 版本 $ java -version java version "1.8.0_151" Java(TM) SE Runtime Environment (build 1.8.0_151-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode) 查看 Java 帮助文档 $ java -help 用法: java [-options] class [args...] …

牛客“迎新春,过大年”多校程序设计竞赛A题

题目描述&#xff1a; 这里有个小trick 当时也看到数据范围的问题了 n 是 1 e 6 ∑ i 1 n a [ i ] < 5 e 7 n是1e6 \quad \sum_{i1}^na[i]<5e7 n是1e6∑i1n​a[i]<5e7 我们考虑不同的数 1 2 . . . k − 1 k 1 \quad 2 \quad ... k-1 \quad k 12...k−1k s u m …

【UE 材质】扇形材质

目录 效果 步骤 &#xff08;1&#xff09;控制扇形的弧宽度 &#xff08;2&#xff09;控制扇形的角度 &#xff08;3&#xff09;完整节点 效果 步骤 &#xff08;1&#xff09;控制扇形的弧宽度 创建一个材质&#xff0c;混合模式设置为“Additive”&#xff0c;着色…

论文阅读——MP-Former

MP-Former: Mask-Piloted Transformer for Image Segmentation https://arxiv.org/abs/2303.07336 mask2former问题是&#xff1a;相邻层得到的掩码不连续&#xff0c;差别很大 denoising training非常有效地稳定训练时期之间的二分匹配。去噪训练的关键思想是将带噪声的GT坐标…

第2节、让电机转起来【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍用简单的方式&#xff0c;让步进电机转起来。其目的之一是对电机转动有直观的感受&#xff0c;二是熟悉整个开发流程。本系列教程必要的51单片机基础包括IO口操作、中断、定时器三个部分&#…

紫光展锐M6780丨用MEMC捕捉每帧精彩

在之前的系列专栏里&#xff0c;我们揭秘了紫光展锐首颗AI8K超高清智能显示芯片平台M6780的AI-PQ、AI-SR以及Local Dimming技术。今天&#xff0c;揭秘M6780让急速动态画面清晰无拖影的绝招——MEMC&#xff08;运动估计与运动补偿技术&#xff09;。 刷新率是电视画质评估维度…

【算法】枚举——蓝桥杯、日期统计、特殊日期(位数之和)、2023、特殊日期(倍数)、跑步锻炼

文章目录 蓝桥杯日期统计特殊日期&#xff08;位数之和&#xff09;2023特殊日期&#xff08;倍数&#xff09;跑步锻炼 蓝桥杯 日期统计 日期统计 如果暴力枚举100个数的八次循环那就是1016次运算&#xff0c;时间复杂度太高了&#xff0c;好在前四次的2023是确定的&#xf…

Android用setRectToRect实现Bitmap基于Matrix矩阵scale缩放RectF动画,Kotlin(一)

Android用setRectToRect实现Bitmap基于Matrix矩阵scale缩放RectF动画&#xff0c;Kotlin&#xff08;一&#xff09; 基于Matrix&#xff0c;控制Bitmap的setRectToRect的目标RectF的宽高。从很小的宽高开始&#xff0c;不断迭代增加setRectToRect的目标RectF的宽高&#xff0c…

ideaIU-2023.2.1安装教程

ideaIU-2023.2.1安装教程 一、ideaIU-2023.2.1安装1.1 下载IdeaIU-2023.2.1安装包1.2 安装ideaIU-2023.2.1 二、ideaIU-2023.2.1激活 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 一、ideaIU-2023.2.1安装 1.1 下载IdeaIU-2023.2.1安装包…

Linux - ps 命令详解

Linux 为我们提供了一个名为 ps 的实用程序&#xff0c;用于查看与系统上的进程相关的信息&#xff0c;它是 Process Status 的缩写 这份 ps 命令备忘清单的快速参考列表&#xff0c;包含常用选项和示例。 语法 $ ps [options]命令运行示例&#xff0c;列出当前 shell 中的所有…

canvas缩放坐标系(scale)

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

紫光展锐M6780丨一语即达,“声”临其境

在前面四期&#xff0c;紫光展锐针对M6780的显示技术进行了系列揭秘。虽名为“智能显示芯片”&#xff0c;但M6780的魅力远不止于超高清智能显示&#xff0c;更有智能语音交互功能&#xff0c;助力打造数字世界的交互新体验。 智能语音技术是一种基于人工智能和语音识别技术的创…

踩坑了,MySQL数据库生成大量奇怪的大文件

作者&#xff1a;田逸&#xff08;formyz&#xff09; 一大早就收到某个数据库服务器磁盘满的报警信息&#xff0c;其中数据盘使用率超过90%&#xff0c;如下图所示。 这是一台刚上线不久的MySQL从库服务器&#xff0c;数据盘的总容量是300G。先登录系统&#xff0c;查看主从同…

【VUE】UniAPP之uview组件库,自定义tag封装,支持添加u-icon图标

组件代码 <template><view class"tag" :class"[props.mode, props.shape]"><slot name"left"><!-- icon图标 没有传入图标时不显示 --><u-icon v-if"props.icon ! " :name"props.icon" :color&…