PE文件信息解析(Win32, C++)

尝试解析PE文件结构, 于是编写了此PE信息助手类, 暂时完成如下信息解析

1.导出表信息(Dll模块, 函数)

789373bc69944a478ba520f165ccb4ac.png

2.导入表信息(Dll模块, 函数)

a0e1d2612d2c44c2b0c6fb3a03cdf8b8.png

3.资源表信息(字符串表, 版本信息, 清单信息)

6f9fbefa7cdd46b8994bb8a9613408ed.png

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_CURSOR
    WORD 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 和 64
    BYTE Height;				//图标的高度(以像素为单位)。 可接受的值为 16、32 和 64
    BYTE 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 成员所需的任意或零个 WORD

    struct {
        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 成员所需的任意或零个 WORD
    Var   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 成员所需的任意或零个 WORD
    WORD  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 成员所需的任意或零个 WORD
    String 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 成员所需的任意或零个 WORD
    StringTable 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 _RESOURCE_ITEM
{
    WORD ID;                    //资源ID
    WORD LangID;                //语言ID
    DWORD OffsetToData;         //数据偏移
    DWORD Size;                 //数据大小
    DWORD CodePage;             //代码页

    _RESOURCE_ITEM()
    {
        memset(this, 0, sizeof(this));
    }
}RESOURCE_ITEM;

typedef struct _STRING_TEXT
{
    _tstring StrText;           //文本内容
    WORD ID;                    //字符串ID

    _STRING_TEXT()
        :
        ID(0)
    {

    }
}STRING_TEXT;

typedef struct _RESOURCE_GROUP_INFO
{
    _tstring TypeName;                  //类型名
    WORD TypeID;                        //类型ID
    std::vector<RESOURCE_ITEM> Items;   //资源信息

    _RESOURCE_GROUP_INFO()
        :
        TypeID(0)
    {

    }
}RESOURCE_GROUP_INFO;

typedef struct _STRING_INFO
{
    _tstring Text;
    WORD  wType;

    _STRING_INFO()
        :
        wType(0)
    {

    }
}STRING_INFO;

typedef struct _STRING_FILE_ITEM
{
    _tstring Key;                   // 值名字符串
    _tstring Value;                 // 值数据字符串
    WORD wType;                     // 版本资源中的数据类型, 1: 资源包含文本数据 0: 版本资源包含二进制数据
    std::vector<uint8_t> Data;      // 二进制数据

    _STRING_FILE_ITEM()
        :
        wType(0)
    {

    }
}STRING_FILE_ITEM;

// 版本资源中的数据, 包含可为特定语言和代码页显示的版本信息
typedef struct
{
    _tstring StringCode;
    std::vector<STRING_FILE_ITEM> StringInfos;
}STRING_FILE_INFO;

typedef struct _TRANSLATION_INFO
{
    WORD LanguageID;
    WORD CodePageID;

    _TRANSLATION_INFO()
        :
        LanguageID(0),
        CodePageID(0)
    {

    }
}TRANSLATION_INFO;

// 版本信息
typedef struct
{
    VS_FIXEDFILEINFO FixedFileInfo;
    std::vector<STRING_FILE_INFO> StringFileInfo;   // 版本资源中的数据的组织
    std::vector<TRANSLATION_INFO> TranslationList;  // 应用程序或 DLL 支持的语言列表
}VERSION_INFO;

typedef struct _IMPORT_FUNCTION_INFO
{
    _tstring Name;          //函数名
    WORD Hint;              //索引, 可能为0

    _IMPORT_FUNCTION_INFO()
        :
        Hint(0)
    {

    }
}IMPORT_FUNCTION_INFO;

typedef struct _EXPORT_FUNCTION_INFO
{
    _tstring Name;          //函数名
    _tstring ForwarderName; //转发函数名
    DWORD Addr;             //函数相对偏移地址
    DWORD Ordinal;          //函数顺序

    _EXPORT_FUNCTION_INFO()
        :
        Addr(0),
        Ordinal(0)
    {

    }
}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
    // @param: fByModule        是否通过模块加载
    // @ret: bool               操作成功与否
    bool LoadFile(
        const _tstring& strPath, 
        bool fCheckSum = false, 
        bool fByModule = false
    );

    //
    // @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: void
    void PrintExportTable(bool fShowModule = true, bool fShowFunList = true);

    //
    // @brief: 打印导入表信息
    // @param: fShowModule      显示模块信息
    // @param: fShowFunList     显示函数信息
    // @ret: void
    void PrintImportTable(bool fShowModule = true, bool fShowFunList = true);

    //
    // @brief: 打印资源表信息
    // @param: fShowDetail      显示详情
    // @ret: void
    void PrintResourceTable(bool fShowDetail = true);

    //
    // @brief: 打印版本信息
    // @ret: void
    void PrintVersion();

    //
    // @brief: 打印字符串表
    // @ret: void
    void PrintStringTable();

    //
    // @brief: 打印清单信息
    // @ret: void
    void PrintManifest();

private:

    //
    // @brief: 加载PE文件信息
    // @param: strPath          文件路径
    // @param: fCheckSum        检查映像文件校验和, 校验失败此函数将直接返回false
    // @ret: bool               操作成功与否
    bool _LoadByFile(
        const _tstring& strPath,
        bool fCheckSum = false
    );

    //
    // @brief: 加载PE文件信息
    // @param: strPath          文件路径
    // @param: fCheckSum        检查映像文件校验和, 校验失败此函数将直接返回false
    // @ret: bool               操作成功与否
    bool _LoadByModule(
        const _tstring& strPath,
        bool fCheckSum = false
    );

    //
    // @brief: 清空数据
    // @ret: void
    void _Clear();

    //
    // @brief: 输出字节信息
    // @ret: void
    void _PrintfByte(LPVOID lpData, size_t size);

    //
    // @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: pSectionHeader   节信息头
    // @param: ullVirtualAddr   虚拟地址
    // @ret: LONGLONG           虚拟地址在节数据中的相对偏移
    LONGLONG _GetSectionDataOffset(
        const PIMAGE_SECTION_HEADER lpSectionHeader,
        ULONGLONG ullVirtualAddr
    );

    //
    // @brief: 获取虚拟地址在节数据内存中的位置
    // @param: lpBase           节数据内存位置
    // @param: pSectionHeader   节信息头
    // @param: ullVirtualAddr   虚拟地址
    // @ret: LONGLONG           虚拟地址在节数据内存中的位置
    LPVOID _GetSectionDataAddr(
        LPCVOID lpBase,
        const PIMAGE_SECTION_HEADER pSectionHeader,
        ULONGLONG ullVirtualAddr
    );

    //
    // @brief: 获取虚拟地址在节数据内存中的位置
    // @param: ullVirtualAddr   虚拟地址
    // @param: pSectinHeader    节信息头输出缓冲
    // @ret: bool               操作成功与否
    bool _GetSectionHeader(
        ULONGLONG ullVirtualAddr, 
        PIMAGE_SECTION_HEADER pSectinHeader
    );

    //
    // @brief: 获取地址对齐后的地址
    // @param: lpBase           起始地址
    // @param: lpAddr           地址
    // @param: dwAlign          对齐粒度
    // @ret: LPBYTE             对齐后指针
    LPBYTE _GetAlignAddr(
        LPVOID lpBase,
        LPCVOID lpAddr,
        DWORD dwAlign = sizeof(DWORD)
    );

    //
    // @brief: 加载所有信息
    // @ret: bool               操作成功与否
    bool _LoadAllInformation();

    //
    // @brief: 获取目录节数据与节标头信息
    // @param: nDirectortIndex  目录索引
    // @param: lppSection       节数据指针输出指针
    // @param: lpSectionHeader  节标头数据输出指针
    // @ret: bool               操作成功与否
    bool _GetDirectorySection(
        int nDirectortIndex, 
        LPBYTE* lppSection, 
        PIMAGE_SECTION_HEADER lpSectionHeader
    );

    //
    // @brief: 加载导出表
    // @param: lpSection        节数据
    // @param: ullVirtualAddr   目录虚拟地址
    // @param: lpSectionHeader  节标头数据输出指针
    // @ret: bool               操作成功与否
    bool _LoadExportTable(
        LPCBYTE lpSection, 
        ULONGLONG ullVirtualAddr, 
        const PIMAGE_SECTION_HEADER lpSectionHeader
    );

    //
    // @brief: 加载导入表
    // @param: lpSection        节数据
    // @param: ullVirtualAddr   目录虚拟地址
    // @param: lpSectionHeader  节标头
    // @ret: bool               操作成功与否
    bool _LoadImportTable(
        LPCBYTE lpSection, 
        ULONGLONG ullVirtualAddr, 
        const PIMAGE_SECTION_HEADER lpSectionHeader
    );

    //
    // @brief: 加载资源表
    // @param: lpSection        节数据
    // @param: ullVirtualAddr   目录虚拟地址
    // @param: lpSectionHeader  节标头
    // @ret: bool               操作成功与否
    bool _LoadResourceTable(
        LPCBYTE lpSection, 
        ULONGLONG ullVirtualAddr, 
        const PIMAGE_SECTION_HEADER lpSectionHeader
    );

    //
    // @brief: 加载资源信息
    // @param: lpSection        节数据内存指针
    // @ret: bool               操作成功与否
    bool _LoadResourceInformation(
        LPCBYTE lpSectionData, 
        const PIMAGE_SECTION_HEADER lpSectionHeader
    );

    //
    // @brief: 加载资源字符串表
    // @param: lpSection        节数据内存指针
    // @ret: info               资源组信息
    // @ret: bool               操作成功与否
    bool _LoadResourceStringTable(
        LPCBYTE lpSection,
        const PIMAGE_SECTION_HEADER lpSectionHeader,
        const RESOURCE_GROUP_INFO& info
    );

    //
    // @brief: 加载资源Manifest
    // @param: lpSection        节数据内存指针
    // @ret: info               资源组信息
    // @ret: bool               操作成功与否
    bool _LoadResourceManifest(
        LPCBYTE lpSection,
        const PIMAGE_SECTION_HEADER lpSectionHeader,
        const RESOURCE_GROUP_INFO& info
    );

    //
    // @brief: 加载资源版本信息
    // @param: lpSection        节数据内存指针
    // @ret: info               资源组信息
    // @ret: bool               操作成功与否
    bool _LoadResourceVersion(
        LPCBYTE lpSection,
        const PIMAGE_SECTION_HEADER lpSectionHeader,
        const RESOURCE_GROUP_INFO& info
    );

private:

    HANDLE m_hFile;                                                                 //PE文件句柄
    HMODULE m_hModule;                                                              //PE文件模块句柄
    LPBYTE m_pImageData;                                                            //数据地址

    //基础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>

#define LDR_IS_DATAFILE(_handle)      (((ULONG_PTR)(_handle)) & (ULONG_PTR)1)
#define LDR_IS_IMAGEMAPPING(_handle)  (((ULONG_PTR)(_handle)) & (ULONG_PTR)2)
#define LDR_IS_RESOURCE(_handle)      (LDR_IS_IMAGEMAPPING(_handle) || LDR_IS_DATAFILE(_handle))

#pragma comment(lib, "Imagehlp.lib")

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")
};

static std::string _WStrToMultiStr(UINT CodePage, const std::wstring& str)
{
    //计算缓冲区所需的字节长度
    int cbMultiByte = ::WideCharToMultiByte(CodePage, 0, str.c_str(), -1, NULL, 0, NULL, 0);
    std::string strResult(cbMultiByte, 0);

    //成功则返回写入到指示的缓冲区的字节数
    size_t nConverted = ::WideCharToMultiByte(CodePage, 0, str.c_str(), (int)str.size(), &strResult[0], (int)strResult.size(), NULL, NULL);

    //调整内容长度
    strResult.resize(nConverted);
    return strResult;
}

static std::wstring _MultiStrToWStr(UINT CodePage, const std::string& str)
{
    //计算缓冲区所需的字符长度
    int cchWideChar = ::MultiByteToWideChar(CodePage, 0, str.c_str(), -1, NULL, 0);
    std::wstring strResult(cchWideChar, 0);

    //成功则返回写入到指示的缓冲区的字符数
    size_t nConverted = ::MultiByteToWideChar(CodePage, 0, str.c_str(), (int)str.size(), &strResult[0], (int)strResult.size());

    //调整内容长度
    strResult.resize(nConverted);
    return strResult;
}

static std::string _WStrToAStr(const std::wstring& str)
{
    return _WStrToMultiStr(CP_ACP, str);
}

static std::string _WStrToU8Str(const std::wstring& str)
{
    return _WStrToMultiStr(CP_UTF8, str);
}

static _tstring _WStrToTStr(const std::wstring& str)
{
#ifdef _UNICODE
    return str;
#else
    return _WStrToMultiStr(CP_ACP, str);
#endif
}

static std::wstring _AStrToWStr(const std::string& str)
{
    return _MultiStrToWStr(CP_ACP, str);
}

static std::string _AStrToU8Str(const std::string& str)
{
    return _WStrToU8Str(_AStrToWStr(str));
}

static _tstring _AStrToTStr(const std::string& str)
{
#ifdef _UNICODE
    return _MultiStrToWStr(CP_ACP, str);
#else
    return str;
#endif
}

static std::wstring _U8StrToWStr(const std::string& str)
{
    return _MultiStrToWStr(CP_UTF8, str);
}

static std::string _U8StrToAStr(const std::string& str)
{
    return _WStrToAStr(_U8StrToWStr(str));
}

static _tstring _U8StrToTStr(const std::string& str)
{
#ifdef _UNICODE
    return _MultiStrToWStr(CP_UTF8, str);
#else
    return _WStrToAStr(_U8StrToWStr(str));
#endif
}

static std::string _TStrToAStr(const _tstring& str)
{
#ifdef _UNICODE
    return _WStrToMultiStr(CP_ACP, str);
#else
    return str;
#endif
}

static std::wstring _TStrToWStr(const _tstring& str)
{
#ifdef _UNICODE
    return str;
#else
    return _AStrToWStr(str);
#endif
}

static std::string _TStrToU8Str(const _tstring& str)
{
#ifdef _UNICODE
    return _WStrToU8Str(str);
#else
    return _WStrToU8Str(_AStrToWStr(str));
#endif
}

const int FORMAT_COUNT_MAX = (1024 * 1024 * 64);

static void ConsoleOutputA(LPCSTR pFormat, ...)
{
    size_t nCchCount = MAX_PATH;
    std::string strResult(nCchCount, 0);
    va_list args;

    va_start(args, pFormat);

    do
    {
        //格式化输出字符串
        int nSize = _vsnprintf_s(&strResult[0], nCchCount, _TRUNCATE, pFormat, args);
        if (-1 != nSize)
        {
            HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
            ::WriteConsoleA(console, strResult.c_str(), nSize, NULL, NULL);
            break;
        }

        //缓冲大小超限终止
        if (nCchCount >= FORMAT_COUNT_MAX)
        {
            break;
        }

        //重新分配缓冲
        nCchCount *= 2;
        strResult.resize(nCchCount);

    } while (true);

    va_end(args);
}

static void ConsoleOutputW(LPCWSTR pFormat, ...)
{
    size_t nCchCount = MAX_PATH;
    std::wstring strResult(nCchCount, 0);
    va_list args;

    va_start(args, pFormat);

    do
    {
        //格式化输出字符串
        int nSize = _vsnwprintf_s(&strResult[0], nCchCount, _TRUNCATE, pFormat, args);
        if (-1 != nSize)
        {
            HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
            ::WriteConsoleW(console, strResult.c_str(), nSize, NULL, NULL);
            break;
        }

        //缓冲大小超限终止
        if (nCchCount >= FORMAT_COUNT_MAX)
        {
            break;
        }

        //重新分配缓冲
        nCchCount *= 2;
        strResult.resize(nCchCount);

    } while (true);

    va_end(args);
}

static void ConsoleOutput(LPCTSTR pFormat, ...)
{
    size_t nCchCount = MAX_PATH;
    _tstring strResult(nCchCount, 0);
    va_list args;

    va_start(args, pFormat);

    do
    {
        //格式化输出字符串
        int nSize = _vsntprintf_s(&strResult[0], nCchCount, _TRUNCATE, pFormat, args);
        if (-1 != nSize)
        {
            HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
            ::WriteConsole(console, strResult.c_str(), nSize, NULL, NULL);
            break;
        }

        //缓冲大小超限终止
        if (nCchCount >= FORMAT_COUNT_MAX)
        {
            break;
        }

        //重新分配缓冲
        nCchCount *= 2;
        strResult.resize(nCchCount);

    } while (true);

    va_end(args);
}

CPEHelper::CPEHelper()
    :
    m_hFile(INVALID_HANDLE_VALUE),
    m_hModule(NULL)
{
    _Clear();
}

CPEHelper::~CPEHelper()
{
    Close();
}

bool CPEHelper::LoadFile(
    const _tstring& strPath,
    bool fCheckSum/* = false*/,
    bool fByModule/* = false*/
)
{
    bool bResult = false;
    Close();
    _Clear();

    if (fByModule)
    {
        bResult = _LoadByModule(strPath, fCheckSum);
    }
    else
    {
        bResult = _LoadByFile(strPath, fCheckSum);
    }

    if (bResult)
    {
        _LoadAllInformation();
    }
    else
    {
        Close();
    }

    return bResult;
}

bool CPEHelper::_LoadByFile(
    const _tstring& strPath,
    bool fCheckSum/* = false*/
)
{
    bool bResult = false;

    // 读取文件方式解析
    m_hFile = ::CreateFile(
        strPath.c_str(),
        GENERIC_READ,
        FILE_SHARE_READ,
        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;
        }

        // 文件头中存在校验和才进行检查
        if (0 != HeaderSum && 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)
        {
            m_OptionalHeaderMagic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
            m_NtHeader32 = ntHeader32;
            memcpy(&m_DataDirectory, &m_NtHeader32.OptionalHeader.DataDirectory, sizeof(m_DataDirectory));
        }
        // 检查 是否为 64位程序可选头
        else if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == ntHeader64.OptionalHeader.Magic)
        {
            m_OptionalHeaderMagic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
            m_NtHeader64 = 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头
        m_DosHeader = 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);

    return bResult;
}

bool CPEHelper::_LoadByModule(
    const _tstring& strPath,
    bool fCheckSum/* = false*/
)
{
    bool bResult = false;

    // 资源模块加载方式解析
    DWORD dwFlags = LOAD_LIBRARY_AS_DATAFILE;

    // 先尝试 数据文件 模式加载
    m_hModule = ::LoadLibraryEx(strPath.c_str(), 0, dwFlags);
    if (NULL == m_hModule)
    {
        // 加载失败则尝试 数据文件 + 映像资源 模式加载 
        dwFlags |= LOAD_LIBRARY_AS_IMAGE_RESOURCE;
        m_hModule = ::LoadLibraryEx(strPath.c_str(), 0, dwFlags);
    }

    if (NULL == m_hModule)
    {
        return false;
    }

    do
    {
        DWORD HeaderSum = 0;
        DWORD CheckSum = 0;

        // 计算校验和
        if (fCheckSum && (CHECKSUM_SUCCESS != ::MapFileAndCheckSum(strPath.c_str(), &HeaderSum, &CheckSum)))
        {
            break;
        }

        // 文件头中存在校验和才进行检查
        if (0 != HeaderSum && HeaderSum != CheckSum)
        {
            break;
        }

        LPBYTE pHeader = (BYTE*)m_hModule;
        m_pImageData = (BYTE*)((ULONG_PTR)pHeader & ~((ULONG_PTR)0x03));
        PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)m_pImageData;

        // 读取 DOS 头 64字节
        if (IMAGE_DOS_SIGNATURE != pDosHeader->e_magic)
        {
            break;
        }

        PIMAGE_NT_HEADERS pNtHeader = (IMAGE_NT_HEADERS*)((BYTE*)(pDosHeader)+(DWORD)(pDosHeader->e_lfanew));

        // 检查 NT头 签名
        if (IMAGE_NT_SIGNATURE != pNtHeader->Signature)
        {
            break;
        }

        // 检查 是否为 32位程序可选头
        if (IMAGE_NT_OPTIONAL_HDR32_MAGIC == pNtHeader->OptionalHeader.Magic)
        {
            m_NtHeader32 = *((PIMAGE_NT_HEADERS32)pNtHeader);
            memcpy(&m_DataDirectory, &m_NtHeader32.OptionalHeader.DataDirectory, sizeof(m_DataDirectory));
        }
        // 检查 是否为 64位程序可选头
        else if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == pNtHeader->OptionalHeader.Magic)
        {
            m_OptionalHeaderMagic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
            m_NtHeader64 = *((PIMAGE_NT_HEADERS64)pNtHeader);
            memcpy(&m_DataDirectory, &m_NtHeader64.OptionalHeader.DataDirectory, sizeof(m_DataDirectory));
        }
        // ROM可选头
        else if (IMAGE_ROM_OPTIONAL_HDR_MAGIC == pNtHeader->OptionalHeader.Magic)
        {
            m_OptionalHeaderMagic = IMAGE_ROM_OPTIONAL_HDR_MAGIC;
        }
        else
        {
            break;
        }

        m_OptionalHeaderMagic = pNtHeader->OptionalHeader.Magic;

        // 保存Dos头
        m_DosHeader = *pDosHeader;

        // 节标头偏移
        DWORD dwSectionOffset = (DWORD)(m_DosHeader.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader) + pNtHeader->FileHeader.SizeOfOptionalHeader);
        WORD wNumberOfSections = pNtHeader->FileHeader.NumberOfSections;
        PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(m_pImageData + dwSectionOffset);

        //保存标头信息
        do
        {
            for (int i = 0; i < wNumberOfSections; i++)
            {
                m_SectionHeader.push_back(pSectionHeader[i]);
            }

        } while (false);

        bResult = true;

    } while (false);

    return bResult;
}

void CPEHelper::Close()
{
    if (INVALID_HANDLE_VALUE != m_hFile)
    {
        ::CloseHandle(m_hFile);
        m_hFile = INVALID_HANDLE_VALUE;
    }

    if (NULL != m_hModule)
    {
        ::FreeLibrary(m_hModule);
        m_hModule = NULL;
    }
}

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;
    m_pImageData = NULL;
}

void CPEHelper::_PrintfByte(LPVOID lpData, size_t size)
{
    if (NULL == lpData)
    {
        return;
    }

    for (size_t i = 0; i < size; i++)
    {
        if (i != size - 1)
        {
            ConsoleOutput(_T("%02X "), ((LPBYTE)lpData)[i]);
        }
        else
        {
            ConsoleOutput(_T("%02X"), ((LPBYTE)lpData)[i]);
        }
    }
}

bool CPEHelper::_ReadFile(
    LPVOID lpBuffer,
    DWORD dwSize,
    LPDWORD lpBytesRead/* = nullptr*/,
    LONGLONG llPos/* = 0*/,
    DWORD dwFlag/* = FILE_CURRENT*/,
    bool fCheckResdSize/* = false*/
)
{
    LARGE_INTEGER  liDistanceToMove = { 0 };
    DWORD dwBytesRead = 0;
    bool bResult = FALSE;

    if (INVALID_HANDLE_VALUE == m_hFile)
    {
        return false;
    }

    liDistanceToMove.QuadPart = llPos;
    ::SetFilePointerEx(m_hFile, liDistanceToMove, NULL, dwFlag);
    bResult = ::ReadFile(m_hFile, lpBuffer, dwSize, &dwBytesRead, NULL);

    if (nullptr != lpBytesRead)
    {
        *lpBytesRead = dwBytesRead;
    }

    //设置了读取大小检查, 则当实际读取数据量与指定读取数据量相同才认为读取成功
    if (fCheckResdSize)
    {
        bResult = (dwBytesRead == dwSize);
    }

    return bResult;
}

LONGLONG CPEHelper::_GetSectionDataOffset(
    const PIMAGE_SECTION_HEADER lpSectionHeader,
    ULONGLONG ullVirtualAddr
)
{
    ULONGLONG VirtualAddrBegin = lpSectionHeader->VirtualAddress;
    ULONGLONG VirtualAddrEnd = VirtualAddrBegin + lpSectionHeader->SizeOfRawData;
    ULONGLONG ullOffset = ullVirtualAddr;
    if (ullOffset < VirtualAddrBegin || ullOffset >= VirtualAddrEnd)
    {
        return -1;
    }

    ullOffset -= VirtualAddrBegin;

    return ullOffset;
}

LPVOID CPEHelper::_GetSectionDataAddr(
    LPCVOID lpBase,
    const PIMAGE_SECTION_HEADER pSectionHeader,
    ULONGLONG ullVirtualAddr
)
{
    ULONGLONG VirtualAddrBegin = pSectionHeader->VirtualAddress;
    ULONGLONG VirtualAddrEnd = VirtualAddrBegin + pSectionHeader->SizeOfRawData;
    ULONGLONG ullOffset = VirtualAddrBegin + ullVirtualAddr - pSectionHeader->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;
}

inline LPBYTE CPEHelper::_GetAlignAddr(
    LPVOID lpBase,
    LPCVOID lpAddr,
    DWORD dwAlign
)
{
    DWORD_PTR dwOffset = 0;
    if (dwAlign)
    {
        dwOffset = (DWORD_PTR)lpBase & (dwAlign - 1);
    }

    DWORD_PTR dwPadding = ((DWORD_PTR)lpAddr - dwOffset) % dwAlign;
    return dwPadding ? (LPBYTE)lpAddr + (dwAlign - dwPadding) : (LPBYTE)lpAddr;
}

bool CPEHelper::_LoadAllInformation()
{
    // 加载导入表
    auto _FunImportTable = [this]() {
        IMAGE_SECTION_HEADER sectionHeaderImportTable = { 0 };
        LPBYTE lpSectionImportTable = NULL;

        if (_GetDirectorySection(IMAGE_DIRECTORY_ENTRY_IMPORT, &lpSectionImportTable, &sectionHeaderImportTable))
        {
            _LoadImportTable(lpSectionImportTable, m_DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, &sectionHeaderImportTable);
            if (INVALID_HANDLE_VALUE != m_hFile)
            {
                ::HeapFree(::GetProcessHeap(), 0, lpSectionImportTable);
            }
        }
        };

    // 加载导出表
    auto _FunLoadExportTable = [this]() {
        IMAGE_SECTION_HEADER sectionHeaderExportTable = { 0 };
        LPBYTE lpSectionExportTable = NULL;

        if (_GetDirectorySection(IMAGE_DIRECTORY_ENTRY_EXPORT, &lpSectionExportTable, &sectionHeaderExportTable))
        {
            _LoadExportTable(lpSectionExportTable, m_DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, &sectionHeaderExportTable);
            if (INVALID_HANDLE_VALUE != m_hFile)
            {
                ::HeapFree(::GetProcessHeap(), 0, lpSectionExportTable);
            }
        }
        };

    // 加载资源表
    auto _FunLoadResourceTable = [this]() {
        IMAGE_SECTION_HEADER sectionHeaderResourceTable = { 0 };
        LPBYTE lpSectionResourceTable = NULL;

        if (_GetDirectorySection(IMAGE_DIRECTORY_ENTRY_RESOURCE, &lpSectionResourceTable, &sectionHeaderResourceTable))
        {
            _LoadResourceTable(lpSectionResourceTable, m_DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress, &sectionHeaderResourceTable);
            if (INVALID_HANDLE_VALUE != m_hFile)
            {
                ::HeapFree(::GetProcessHeap(), 0, lpSectionResourceTable);
            }
        }
        };

    _FunImportTable();
    _FunLoadExportTable();
    _FunLoadResourceTable();
    
    return true;
}

bool CPEHelper::_GetDirectorySection(
    int nDirectortIndex,
    LPBYTE* lppSection,
    PIMAGE_SECTION_HEADER lpSectionHeader
)
{
    if (NULL == lppSection)
    {
        return false;
    }

    DWORD VirtualAddress = m_DataDirectory[nDirectortIndex].VirtualAddress;
    if (0 == VirtualAddress)
    {
        return false;
    }

    if (INVALID_HANDLE_VALUE != m_hFile)
    {
        LPBYTE lpSectionData = nullptr;
        bool fResult = false;

        do
        {
            // 获取虚拟地址所在节信息
            if (!_GetSectionHeader(VirtualAddress, lpSectionHeader))
            {
                break;
            }

            //分配节数据缓冲
            lpSectionData = (LPBYTE)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, lpSectionHeader->SizeOfRawData);
            if (NULL == lpSectionData)
            {
                break;
            }

            // 读取整个节数据
            DWORD dwReadBytes = 0;
            if (!_ReadFile(lpSectionData, lpSectionHeader->SizeOfRawData, &dwReadBytes, lpSectionHeader->PointerToRawData, FILE_BEGIN, true))
            {
                break;
            }

            fResult = true;

        } while (false);

        if (!fResult && lpSectionData)
        {
            ::HeapFree(::GetProcessHeap(), 0, lpSectionData);
        }

        if (fResult)
        {
            *lppSection = lpSectionData;
        }
    }

    if (NULL != m_hModule)
    {
        do
        {
            // 获取虚拟地址所在节信息
            if (!_GetSectionHeader(VirtualAddress, lpSectionHeader))
            {
                break;
            }

            if (LDR_IS_DATAFILE(m_hModule))
            {
                *lppSection = m_pImageData + lpSectionHeader->PointerToRawData;
            }
            else if (LDR_IS_IMAGEMAPPING(m_hModule))
            {
                *lppSection = m_pImageData + lpSectionHeader->VirtualAddress;
            }
            else
            {
                break;
            }

        } while (false);
    }

    return NULL != *lppSection;
}


bool CPEHelper::_LoadExportTable(
    LPCBYTE lpSectionData,
    ULONGLONG ullVirtualAddr,
    const PIMAGE_SECTION_HEADER lpSectionHeader
)
{
    bool fResult = false;

    if (!lpSectionData || !lpSectionHeader)
    {
        return false;
    }

    do
    {
        // 获取导出描述信息所在偏移
        ULONGLONG VirtualAddrBegin = m_DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
        ULONGLONG VirtualAddrEnd = VirtualAddrBegin + m_DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
        LONGLONG ullExportDescOffset = _GetSectionDataOffset(lpSectionHeader, ullVirtualAddr);
        if (-1 == ullExportDescOffset)
        {
            break;
        }

        // 获取导出目录信息位置
        PIMAGE_EXPORT_DIRECTORY pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)lpSectionData + ullExportDescOffset);
        LPCSTR lpDllName = (LPCSTR)_GetSectionDataAddr(lpSectionData, lpSectionHeader, pExportDirectory->Name);
        if (NULL == lpDllName)
        {
            break;
        }

        // 遍历导出表
        LPDWORD pFuncAddr = (LPDWORD)_GetSectionDataAddr(lpSectionData, lpSectionHeader, pExportDirectory->AddressOfFunctions);
        LPDWORD pNameAddr = (LPDWORD)_GetSectionDataAddr(lpSectionData, lpSectionHeader, pExportDirectory->AddressOfNames);
        LPWORD pNameOrdinalsName = (LPWORD)_GetSectionDataAddr(lpSectionData, lpSectionHeader, pExportDirectory->AddressOfNameOrdinals);
        if ((NULL == pFuncAddr) || (NULL == pNameAddr) || (NULL == pNameOrdinalsName))
        {
            break;
        }

        std::vector<EXPORT_FUNCTION_INFO> FunList;

        //预先分配空间, 速度比每次 push_back 一个信息快
        FunList.resize(pExportDirectory->NumberOfFunctions);
        for (DWORD i = 0; i < pExportDirectory->NumberOfFunctions; i++)
        {
            FunList[i].Addr = pFuncAddr[i];
            FunList[i].Ordinal = pExportDirectory->Base + i;
        }

        for (DWORD i = 0; i < pExportDirectory->NumberOfNames; i++)
        {
            LPCSTR lpFnName = (LPCSTR)_GetSectionDataAddr(lpSectionData, lpSectionHeader, 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, lpSectionHeader, FunList[dwOrdinal].Addr);
                if (NULL == lpForwarderName)
                {
                    break;
                }

                FunList[dwOrdinal].ForwarderName = _AStrToTStr(lpForwarderName);
            }
        }

        m_ExportTable.emplace(_AStrToTStr(lpDllName), FunList);

        fResult = true;

    } while (false);

    return fResult;
}

bool CPEHelper::_LoadImportTable(
    LPCBYTE lpSectionData,
    ULONGLONG ullVirtualAddr,
    const PIMAGE_SECTION_HEADER lpSectionHeader
)
{
    IMAGE_IMPORT_DESCRIPTOR emptyImportDesc = { 0 };
    bool fResult = false;

    if (!lpSectionData || !lpSectionHeader)
    {
        return false;
    }

    do
    {
        // 获取导入描述信息所在偏移
        LONGLONG ullImportDescOffset = _GetSectionDataOffset(lpSectionHeader, ullVirtualAddr);
        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)); i++)
            {
                LPCSTR lpDllName = (LPCSTR)_GetSectionDataAddr(lpSectionData, lpSectionHeader, pImportDesc[i].Name);
                if (NULL == lpDllName)
                {
                    break;
                }

                PIMAGE_THUNK_DATA32 pThunkData = (PIMAGE_THUNK_DATA32)_GetSectionDataAddr(lpSectionData, lpSectionHeader, pImportDesc[i].FirstThunk);
                if (NULL == pThunkData)
                {
                    break;
                }

                //先统计一下导入函数数量
                PIMAGE_THUNK_DATA32 pThunkDataTmp = pThunkData;
                size_t nThunkCount = 0;
                while (pThunkDataTmp->u1.AddressOfData)
                {
                    nThunkCount++;
                    pThunkDataTmp++;
                }

                std::vector<IMPORT_FUNCTION_INFO> FunList;
                //预先分配空间, 速度比每次 push_back 一个信息快
                FunList.resize(nThunkCount);

                size_t nIndex = 0;
                while (pThunkData->u1.AddressOfData)
                {
                    if (IMAGE_SNAP_BY_ORDINAL32(pThunkData->u1.AddressOfData))
                    {
                        FunList[nIndex].Hint = IMAGE_ORDINAL32(pThunkData->u1.AddressOfData);
                    }
                    else
                    {
                        PIMAGE_IMPORT_BY_NAME pImportName = (PIMAGE_IMPORT_BY_NAME)_GetSectionDataAddr(lpSectionData, lpSectionHeader, pThunkData->u1.AddressOfData);
                        if (NULL == pImportName)
                        {
                            break;
                        }

                        FunList[nIndex].Hint = pImportName->Hint;
                        FunList[nIndex].Name = _AStrToTStr((LPCSTR)&pImportName->Name);
                    }
                    nIndex++;
                    pThunkData++;
                }

                auto result = m_ImportTable.emplace(_AStrToTStr(lpDllName), FunList);
                if (!result.second)
                {
                    result.first->second.insert(result.first->second.end(), FunList.begin(), FunList.end());
                }
            }
        }

        // 64位导入表
        if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == m_OptionalHeaderMagic)
        {
            // 遍历导入表
            for (DWORD i = 0; 0 != ::memcmp(pImportDesc + i, &emptyImportDesc, sizeof(emptyImportDesc)); i++)
            {
                LPCSTR lpDllName = (LPCSTR)_GetSectionDataAddr(lpSectionData, lpSectionHeader, pImportDesc[i].Name);
                if (NULL == lpDllName)
                {
                    break;
                }

                PIMAGE_THUNK_DATA64 pThunkData = (PIMAGE_THUNK_DATA64)_GetSectionDataAddr(lpSectionData, lpSectionHeader, pImportDesc[i].FirstThunk);
                if (NULL == pThunkData)
                {
                    break;
                }

                //先统计一下导入函数数量
                PIMAGE_THUNK_DATA64 pThunkDataTmp = pThunkData;
                size_t nThunkCount = 0;
                while (pThunkDataTmp->u1.AddressOfData)
                {
                    nThunkCount++;
                    pThunkDataTmp++;
                }

                std::vector<IMPORT_FUNCTION_INFO> FunList;
                //预先分配空间, 速度比每次 push_back 一个信息快
                FunList.resize(nThunkCount);

                size_t nIndex = 0;
                while (pThunkData->u1.AddressOfData)
                {
                    if (IMAGE_SNAP_BY_ORDINAL64(pThunkData->u1.AddressOfData))
                    {
                        FunList[nIndex].Hint = IMAGE_ORDINAL64(pThunkData->u1.AddressOfData);
                    }
                    else
                    {
                        PIMAGE_IMPORT_BY_NAME pImportName = (PIMAGE_IMPORT_BY_NAME)_GetSectionDataAddr(lpSectionData, lpSectionHeader, pThunkData->u1.AddressOfData);
                        if (NULL == pImportName)
                        {
                            break;
                        }

                        FunList[nIndex].Hint = pImportName->Hint;
                        FunList[nIndex].Name = _AStrToTStr((LPCSTR)&pImportName->Name);
                    }
                    nIndex++;
                    pThunkData++;
                }

                auto result = m_ImportTable.emplace(_AStrToTStr(lpDllName), FunList);
                if (!result.second)
                {
                    result.first->second.insert(result.first->second.end(), FunList.begin(), FunList.end());
                }
            }
        }

        fResult = true;

    } while (false);

    return fResult;
}

bool CPEHelper::_LoadResourceTable(
    LPCBYTE lpSectionData,
    ULONGLONG ullVirtualAddr,
    const PIMAGE_SECTION_HEADER lpSectionHeader
)
{
    bool fResult = false;

    UNREFERENCED_PARAMETER(ullVirtualAddr);

    if (!lpSectionData || !lpSectionHeader)
    {
        return false;
    }

    do
    {
        PIMAGE_RESOURCE_DIRECTORY pDirectoryRoot = (PIMAGE_RESOURCE_DIRECTORY)lpSectionData;
        DWORD dwTpyeCount = pDirectoryRoot->NumberOfNamedEntries + pDirectoryRoot->NumberOfIdEntries;
        m_ResourceInfo.ResourceTable.resize(dwTpyeCount);
        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);
                GroupInfo.TypeName = _WStrToTStr(std::wstring(pStrName->NameString, pStrName->Length));
                GroupInfo.TypeID = 0;
            }
            else
            {
                // 预定义资源类型名字符串
                if (pEntryType->Id < _countof(g_ResourctTypeName))
                {
                    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;
                GroupInfo.Items.resize(dwLanguageCount);
                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.OffsetToData = pDataEntry->OffsetToData;
                    info.Size = pDataEntry->Size;
                    info.CodePage = pDataEntry->CodePage;

                    GroupInfo.Items[k] = info;
                }
            }

            m_ResourceInfo.ResourceTable[i] = GroupInfo;
        }

        fResult = true;

        _LoadResourceInformation(lpSectionData, lpSectionHeader);

    } while (false);

    return fResult;
}

bool CPEHelper::_LoadResourceInformation(
    LPCBYTE lpSectionData,
    const PIMAGE_SECTION_HEADER lpSectionHeader
)
{
    // 解析各种资源类型
    for (const auto& item : m_ResourceInfo.ResourceTable)
    {
        if (MAKEINTRESOURCE(item.TypeID) == RT_STRING)
        {
            // 加载 字符串表 资源
            _LoadResourceStringTable(lpSectionData, lpSectionHeader, item);
        }
        else if (MAKEINTRESOURCE(item.TypeID) == RT_MANIFEST)
        {
            // 加载 Manifest 资源
            _LoadResourceManifest(lpSectionData, lpSectionHeader, item);
        }
        else if (MAKEINTRESOURCE(item.TypeID) == RT_VERSION)
        {
            // 加载 版本 资源
            _LoadResourceVersion(lpSectionData, lpSectionHeader, item);
        }
    }

    return true;
}

bool CPEHelper::_LoadResourceStringTable(
    LPCBYTE lpSection,
    const PIMAGE_SECTION_HEADER lpSectionHeader,
    const RESOURCE_GROUP_INFO& info
)
{
    for (const auto& str : info.Items)
    {
        // 数据范围检查
        if (str.OffsetToData < lpSectionHeader->VirtualAddress ||
            str.OffsetToData >= (lpSectionHeader->VirtualAddress + lpSectionHeader->SizeOfRawData))
        {
            continue;
        }

        std::vector<STRING_TEXT> strList;

        DWORD SectionOffset = str.OffsetToData - lpSectionHeader->VirtualAddress;
        LPWORD lpLengthBegin = (LPWORD)((LPBYTE)lpSection + SectionOffset);
        LPWORD lpLengthEnd = (LPWORD)((LPBYTE)lpLengthBegin + str.Size);
        DWORD wIdBegin = (str.ID - 1) * 16;
        DWORD wIdEnd = wIdBegin + 16;
        LPWORD lpStrLength = lpLengthBegin;
        for (DWORD i = wIdBegin; i < wIdEnd; i++)
        {
            // 数据范围检查
            if (lpStrLength >= lpLengthEnd || 0 == *lpStrLength)
            {
                break;
            }

            STRING_TEXT strText;
            LPCWSTR lpStrAddr = (LPCWSTR)lpStrLength + 1;
            if ((LPBYTE)lpStrAddr < ((LPBYTE)lpLengthEnd))
            {
                strText.StrText = _WStrToTStr(std::wstring(lpStrAddr, *lpStrLength));
                strText.ID = i;
                strList.push_back(strText);
            }

            lpStrLength = (LPWORD)lpStrAddr + *lpStrLength;
        }

        auto itFind = m_ResourceInfo.StringTable.find(str.LangID);
        if (m_ResourceInfo.StringTable.end() == itFind)
        {
            m_ResourceInfo.StringTable.emplace(str.LangID, strList);
        }
        else
        {
            itFind->second.insert(itFind->second.end(), strList.begin(), strList.end());
        }
    }

    return true;
}

bool CPEHelper::_LoadResourceManifest(
    LPCBYTE lpSection,
    const PIMAGE_SECTION_HEADER lpSectionHeader,
    const RESOURCE_GROUP_INFO& info
)
{
    for (const auto& str : info.Items)
    {
        // 数据范围检查
        if (str.OffsetToData < lpSectionHeader->VirtualAddress ||
            str.OffsetToData >= (lpSectionHeader->VirtualAddress + lpSectionHeader->SizeOfRawData))
        {
            continue;
        }

        DWORD SectionOffset = str.OffsetToData - lpSectionHeader->VirtualAddress;
        LPCSTR lpStr = (LPCSTR)((LPBYTE)lpSection + SectionOffset);
        m_ResourceInfo.Manifest = _U8StrToTStr(std::string(lpStr, str.Size));
    }

    return true;
}

bool CPEHelper::_LoadResourceVersion(
    LPCBYTE lpSection,
    const PIMAGE_SECTION_HEADER lpSectionHeader,
    const RESOURCE_GROUP_INFO& info
)
{
    for (const auto& str : info.Items)
    {
        // 数据范围检查
        if (str.OffsetToData < lpSectionHeader->VirtualAddress ||
            str.OffsetToData >= (lpSectionHeader->VirtualAddress + lpSectionHeader->SizeOfRawData))
        {
            continue;
        }

        DWORD SectionOffset = str.OffsetToData - lpSectionHeader->VirtualAddress;
        PVS_VERSIONINFO lpVersion = (PVS_VERSIONINFO)((LPBYTE)lpSection + SectionOffset);

        // 存在 VS_FIXEDFILEINFO 信息
        if (0 != lpVersion->wValueLength)
        {
            VS_FIXEDFILEINFO* pFixedFileInfo = (VS_FIXEDFILEINFO*)((LPBYTE)lpVersion + sizeof(VS_VERSIONINFO));
            pFixedFileInfo = (VS_FIXEDFILEINFO*)_GetAlignAddr(lpVersion, (LPVOID)pFixedFileInfo, sizeof(DWORD));
            m_ResourceInfo.VersionInfo.FixedFileInfo = *pFixedFileInfo;
        }

        {
            VS_FIXEDFILEINFO FixedFileInfo = { 0 };
            LPBYTE lpVerBeg = (LPBYTE)lpVersion;

            // 存在 VS_FIXEDFILEINFO 信息
            if (0 != lpVersion->wValueLength)
            {
                VS_FIXEDFILEINFO* pFixedFileInfo = (VS_FIXEDFILEINFO*)((LPBYTE)lpVersion + sizeof(VS_VERSIONINFO));
                pFixedFileInfo = (VS_FIXEDFILEINFO*)_GetAlignAddr(lpVersion, pFixedFileInfo, sizeof(DWORD));
                FixedFileInfo = *pFixedFileInfo;
                lpVerBeg = (LPBYTE)lpVerBeg + sizeof(VS_VERSIONINFO) + lpVersion->wValueLength;
            }

            lpVerBeg = _GetAlignAddr(lpVersion, lpVerBeg, sizeof(DWORD));
            LPBYTE lpVerEnd = (LPBYTE)lpVersion + lpVersion->wLength;

            while (lpVerBeg < lpVerEnd)
            {
                StringFileInfo* pStringFileInfo = (StringFileInfo*)_GetAlignAddr(lpVersion, lpVerBeg, sizeof(DWORD));
                if (0 == pStringFileInfo->wLength)
                {
                    break;
                }

                // 解析 "StringFileInfo" 块
                if (0 == _wcsnicmp(L"StringFileInfo", pStringFileInfo->szKey, 14))
                {
                    LPBYTE lpStringFileInfoBeg = (LPBYTE)pStringFileInfo;
                    LPBYTE lpStringFileInfoEnd = (LPBYTE)pStringFileInfo + pStringFileInfo->wLength;
                    lpStringFileInfoBeg = (LPBYTE)(pStringFileInfo->Children);
                    while (lpStringFileInfoBeg < lpStringFileInfoEnd)
                    {
                        STRING_FILE_INFO strFileInfo;
                        StringTable* pStringTable = (StringTable*)lpStringFileInfoBeg;
                        if (0 == pStringTable->wLength)
                        {
                            break;
                        }

                        strFileInfo.StringCode = _WStrToTStr(std::wstring(pStringTable->szKey, _countof(pStringTable->szKey)));

                        LPBYTE lpStringBeg = (LPBYTE)pStringTable->Children;
                        LPBYTE lpStringEnd = (LPBYTE)pStringTable + pStringTable->wLength;
                        while (lpStringBeg < lpStringEnd)
                        {
                            const String* pString = (String*)lpStringBeg;
                            if (0 == pString->wLength)
                            {
                                break;
                            }

                            //值名
                            std::wstring strKey = pString->szKey;

                            STRING_FILE_ITEM item;

                            //值数据
                            LPCWSTR lpStrValue = pString->szKey + strKey.size() + 1;

                            //值数据位置
                            lpStrValue = (LPCWSTR)_GetAlignAddr(lpVersion, lpStrValue, sizeof(DWORD));
                            item.wType = pString->wType;

                            item.Key = _WStrToTStr(strKey);

                            //字符串类型
                            if (1 == pString->wType)
                            {
                                WORD wLength = pString->wValueLength;
                                if (wLength > 0 && L'\0' == lpStrValue[wLength - 1])
                                {
                                    wLength--;
                                }
                                std::wstring strValue = std::wstring(lpStrValue, wLength);
                                item.Value = _WStrToTStr(strValue);
                            }
                            //字节数据类型
                            else
                            {
                                DWORD dwValueSize = pString->wValueLength;
                                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);

                            lpStringBeg = _GetAlignAddr(lpVersion, lpStringBeg + pString->wLength, sizeof(DWORD));
                        }

                        m_ResourceInfo.VersionInfo.StringFileInfo.push_back(strFileInfo);
                        lpStringFileInfoBeg = _GetAlignAddr(lpVersion, (LPBYTE)pStringTable + pStringTable->wLength, sizeof(DWORD));
                    }
                }
                // 解析 "VarFileInfo" 块
                else if (0 == _wcsnicmp(L"VarFileInfo", pStringFileInfo->szKey, 11))
                {
                    VarFileInfo* pVerFileInfo = (VarFileInfo*)_GetAlignAddr(lpVersion, pStringFileInfo, sizeof(DWORD));
                    Var* pVar = (Var*)pVerFileInfo->Children;
                    if (0 == _wcsnicmp(L"Translation", pVar->szKey, 11))
                    {
                        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);
                        }
                    }
                }

                lpVerBeg = _GetAlignAddr(lpVersion, lpVerBeg + pStringFileInfo->wLength, sizeof(DWORD));
            }
        }
    }

    return true;
}

void CPEHelper::PrintResourceTable(bool fShowDetail/* = true*/)
{
    ConsoleOutput(_T("资源类型数量: %4d\n"), (int)m_ResourceInfo.ResourceTable.size());
    int i = 0;
    for (const auto& ResourceInfo : m_ResourceInfo.ResourceTable)
    {
        if (0 != ResourceInfo.TypeID)
        {
            ConsoleOutput(_T("    %4d 类型ID: %4d 类型名: %s 数量: %d\n"), i++, ResourceInfo.TypeID, ResourceInfo.TypeName.c_str(), (int)ResourceInfo.Items.size());
        }
        else
        {
            ConsoleOutput(_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)
        {
            ConsoleOutput(_T("        %4d 资源ID: %4d  节数据偏移: %08X 大小: %d 语言: %d\n"), j++, item.ID, item.OffsetToData, 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();
    }

    ConsoleOutput(_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)
        {
            ConsoleOutput(_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())
                {
                    ConsoleOutput(_T("        %4d Ordinal: %4d(%04x) Addr: %08x %s \n"), j++, fun.Ordinal, fun.Ordinal, fun.Addr, fun.Name.c_str());
                }
                else
                {
                    ConsoleOutput(_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
            {
                ConsoleOutput(_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();
    }

    ConsoleOutput(_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)
        {
            ConsoleOutput(_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())
            {
                ConsoleOutput(_T("        %4d %4d(%04x) %s\n"), j++, fun.Hint, fun.Hint, fun.Name.c_str());
            }
            else
            {
                ConsoleOutput(_T("        %4d %4d(%04x)\n"), j++, fun.Hint, fun.Hint);
            }
        }
    }
}

void CPEHelper::PrintVersion()
{
    ConsoleOutput(_T("Version:\n"));
    ConsoleOutput(_T("    StringFileInfo conut: %d\n"), (int)m_ResourceInfo.VersionInfo.StringFileInfo.size());
    for (const auto& item : m_ResourceInfo.VersionInfo.StringFileInfo)
    {
        ConsoleOutput(_T("        %s\n"), item.StringCode.c_str());

        VS_FIXEDFILEINFO& FixedFileInfo = m_ResourceInfo.VersionInfo.FixedFileInfo;
        ConsoleOutput(_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)
            {
                ConsoleOutput(_T("            %s: %s\n"), info.Key.c_str(), info.Value.c_str());
            }
            else
            {
                ConsoleOutput(_T("            %s: %s\n"), info.Key.c_str(), info.Value.c_str());
                //ConsoleOutput(_T("            %s: "), info.Key.c_str());
                //_PrintfByte((LPVOID)info.Data.data(), info.Data.size());
                //ConsoleOutput(_T("\n"));
            }
        }
    }

    ConsoleOutput(_T("    Translation conut: %d\n"), (int)m_ResourceInfo.VersionInfo.TranslationList.size());
    for (const auto& item : m_ResourceInfo.VersionInfo.TranslationList)
    {
        ConsoleOutput(_T("        0x%04X 0x%04X\n"), item.LanguageID, item.CodePageID);
    }
}

void CPEHelper::PrintStringTable()
{
    ConsoleOutput(_T("StringTable: count: %d\n"), (int)m_ResourceInfo.StringTable.size());
    for (const auto& item : m_ResourceInfo.StringTable)
    {
        ConsoleOutput(_T("    ID: %d, count: %d\n"), item.first, (int)item.second.size());

        for (const auto& info : item.second)
        {
            ConsoleOutput(_T("        %04d: %s\n"), info.ID, info.StrText.c_str());
        }
    }
}

void CPEHelper::PrintManifest()
{
    ConsoleOutput(_T("Manifest:\n"));
    ConsoleOutput(_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, "");

    int64_t timeBegin = CTimeUtils::GetCurrentTickCount();
    int64_t timeEnd = CTimeUtils::GetCurrentTickCount();
    int nRepeatCount = 1000;

    while (true)
    {
        timeBegin = CTimeUtils::GetCurrentTickCount();

        {
            CPEHelper obj;

            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)"), false);
                obj.LoadFile(_T(R"(user32.dll)"), false);
                //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 1
            obj.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"));
            obj.PrintManifest();
#else
            obj.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"));
            obj.PrintManifest();
#endif

            _tprintf(_T("Repeat count: %d Cost time: %llu ms, Speed: %0.3lf/S\n"), nRepeatCount, timeEnd - timeBegin, (double)nRepeatCount * 1000 / ((double)(timeEnd - timeBegin)));
        }

        system("pause");
    }

    return 0;
}

eeb8c6548b1b4c2fbfcea7b050324d03.png

3c723c8796eb4eca88004348232ed829.png

90f1d8ababf34877ab4bc2554f537ffd.png

d723eb8a0b374359a72d5700b836b8ec.png

ecfcede0900446deb0d0b282045527fa.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值