[
  {
    "path": ".clang-tidy",
    "content": "Checks: '*,\r\n-cppcoreguidelines-*,-google-*,-fuchsia-*,-hicpp-*,-cert-*,-clang-*,-llvmlibc-*,-altera-*,-boost-*,-abseil-*,\r\n-bugprone-easily-swappable-parameters,\r\n-bugprone-implicit-widening-of-multiplication-result,\r\n-bugprone-narrowing-conversions,\r\n-bugprone-use-after-move,\r\n-llvm-header-guard,\r\n-llvm-include-order,\r\n-llvm-namespace-comment,\r\n-llvm-qualified-auto,\r\n-misc-include-cleaner,\r\n-misc-non-private-member-variables-in-classes,\r\n-misc-no-recursion,\r\n-misc-use-after-move,\r\n-misc-use-internal-linkage,\r\n-modernize-use-trailing-return-type,\r\n-modernize-avoid-c-arrays,\r\n-modernize-use-nodiscard,\r\n-modernize-use-ranges,\r\n-performance-no-int-to-ptr,\r\n-portability-simd-intrinsics,\r\n-readability-avoid-nested-conditional-operator,\r\n-readability-braces-around-statements,\r\n-readability-implicit-bool-conversion,\r\n-readability-magic-numbers,\r\n-readability-redundant-access-specifiers,\r\n-readability-isolate-declaration,\r\n-readability-qualified-auto,\r\n-readability-convert-member-functions-to-static,\r\n-readability-misleading-indentation,\r\n-readability-function-cognitive-complexity,\r\n-readability-identifier-length,\r\n-readability-named-parameter,\r\ngoogle-readability-casting'\r\n\r\nHeaderFilterRegex: ''"
  },
  {
    "path": ".editorconfig",
    "content": "root = true\r\n\r\n[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]\r\ncpp_generate_documentation_comments = xml\r\ncpp_indent_braces = false\r\ncpp_indent_multi_line_relative_to = innermost_parenthesis\r\ncpp_indent_within_parentheses = indent\r\ncpp_indent_preserve_within_parentheses = true\r\ncpp_indent_case_contents = true\r\ncpp_indent_case_labels = false\r\ncpp_indent_case_contents_when_block = false\r\ncpp_indent_lambda_braces_when_parameter = true\r\ncpp_indent_goto_labels = one_left\r\ncpp_indent_preprocessor = one_left\r\ncpp_indent_access_specifiers = false\r\ncpp_indent_namespace_contents = true\r\ncpp_indent_preserve_comments = true\r\ncpp_new_line_before_open_brace_namespace = same_line\r\ncpp_new_line_before_open_brace_type = same_line\r\ncpp_new_line_before_open_brace_function = ignore\r\ncpp_new_line_before_open_brace_block = same_line\r\ncpp_new_line_before_open_brace_lambda = same_line\r\ncpp_new_line_scope_braces_on_separate_lines = false\r\ncpp_new_line_close_brace_same_line_empty_type = false\r\ncpp_new_line_close_brace_same_line_empty_function = false\r\ncpp_new_line_before_catch = true\r\ncpp_new_line_before_else = true\r\ncpp_new_line_before_while_in_do_while = false\r\ncpp_space_before_function_open_parenthesis = remove\r\ncpp_space_within_parameter_list_parentheses = false\r\ncpp_space_between_empty_parameter_list_parentheses = false\r\ncpp_space_after_keywords_in_control_flow_statements = true\r\ncpp_space_within_control_flow_statement_parentheses = false\r\ncpp_space_before_lambda_open_parenthesis = false\r\ncpp_space_within_cast_parentheses = false\r\ncpp_space_after_cast_close_parenthesis = false\r\ncpp_space_within_expression_parentheses = false\r\ncpp_space_before_block_open_brace = true\r\ncpp_space_between_empty_braces = true\r\ncpp_space_before_initializer_list_open_brace = true\r\ncpp_space_within_initializer_list_braces = true\r\ncpp_space_preserve_in_initializer_list = false\r\ncpp_space_before_open_square_bracket = false\r\ncpp_space_within_square_brackets = false\r\ncpp_space_before_empty_square_brackets = false\r\ncpp_space_between_empty_square_brackets = false\r\ncpp_space_group_square_brackets = true\r\ncpp_space_within_lambda_brackets = false\r\ncpp_space_between_empty_lambda_brackets = false\r\ncpp_space_before_comma = false\r\ncpp_space_after_comma = true\r\ncpp_space_remove_around_member_operators = true\r\ncpp_space_before_inheritance_colon = true\r\ncpp_space_before_constructor_colon = true\r\ncpp_space_remove_before_semicolon = true\r\ncpp_space_after_semicolon = true\r\ncpp_space_remove_around_unary_operator = true\r\ncpp_space_around_binary_operator = insert\r\ncpp_space_around_assignment_operator = insert\r\ncpp_space_pointer_reference_alignment = ignore\r\ncpp_space_around_ternary_operator = insert\r\ncpp_wrap_preserve_blocks = one_liners\r\n"
  },
  {
    "path": ".gitignore",
    "content": "#################\r\n## Eclipse\r\n#################\r\n\r\n*stacktrace.*\r\n*.zip\r\n*.rar\r\n*.exe\r\n*.pydevproject\r\n.project\r\n.metadata\r\nbin/\r\ntmp/\r\n*.tmp\r\n*.bak\r\n*.swp\r\n*~.nib\r\nlocal.properties\r\n.classpath\r\n.settings/\r\n.loadpath\r\n\r\n# External tool builders\r\n.externalToolBuilders/\r\n\r\n# Locally stored \"Eclipse launch configurations\"\r\n*.launch\r\n\r\n# CDT-specific\r\n.cproject\r\n\r\n# PDT-specific\r\n.buildpath\r\n\r\n\r\n#################\r\n## Visual Studio\r\n#################\r\n\r\n## Ignore Visual Studio temporary files, build results, and\r\n## files generated by popular Visual Studio add-ons.\r\n\r\n.vs/\r\n\r\n# User-specific files\r\n*.suppress\r\n*.suo\r\n*.user\r\n*.sln.docstates\r\n*.opendb\r\n*solution_suppressions.cfg\r\n\r\n# Build results\r\n\r\n[Dd]ebug*/\r\n[Rr]elease*/\r\nx64/\r\nbuild/\r\n[Bb]in/\r\n[Oo]bj/\r\n\r\n# MSTest test Results\r\n[Tt]est[Rr]esult*/\r\n[Bb]uild[Ll]og.*\r\n\r\n*_i.c\r\n*_p.c\r\n*.ilk\r\n*.meta\r\n*.obj\r\n*.pch\r\n*.pdb\r\n*.pgc\r\n*.pgd\r\n*.rsp\r\n*.sbr\r\n*.tlb\r\n*.tli\r\n*.tlh\r\n*.tmp\r\n*.tmp_proj\r\n*.log\r\n*.vspscc\r\n*.vssscc\r\n.builds\r\n*.pidb\r\n*.log\r\n*.scc\r\n\r\n# Visual C++ cache files\r\nipch/\r\n*.aps\r\n*.ncb\r\n*.opensdf\r\n*.sdf\r\n*.cachefile\r\n*.cd\r\n*.i-*\r\n\r\n# Visual Studio profiler\r\n*.psess\r\n*.vsp\r\n*.vspx\r\n\r\n# Guidance Automation Toolkit\r\n*.gpState\r\n\r\n# ReSharper is a .NET coding add-in\r\n_ReSharper*/\r\n*.[Rr]e[Ss]harper\r\n\r\n# TeamCity is a build add-in\r\n_TeamCity*\r\n\r\n# DotCover is a Code Coverage Tool\r\n*.dotCover\r\n\r\n# NCrunch\r\n*.ncrunch*\r\n.*crunch*.local.xml\r\n\r\n# Installshield output folder\r\n[Ee]xpress/\r\n\r\n# DocProject is a documentation generator add-in\r\nDocProject/buildhelp/\r\nDocProject/Help/*.HxT\r\nDocProject/Help/*.HxC\r\nDocProject/Help/*.hhc\r\nDocProject/Help/*.hhk\r\nDocProject/Help/*.hhp\r\nDocProject/Help/Html2\r\nDocProject/Help/html\r\n\r\n# Click-Once directory\r\npublish/\r\n\r\n# Publish Web Output\r\n*.Publish.xml\r\n*.pubxml\r\n*.publishproj\r\n\r\n# NuGet Packages Directory\r\n## TODO: If you have NuGet Package Restore enabled, uncomment the next line\r\n#packages/\r\n\r\n# Windows Azure Build Output\r\ncsx\r\n*.build.csdef\r\n\r\n# Windows Store app package directory\r\nAppPackages/\r\n\r\n# Others\r\nsql/\r\n*.Cache\r\nClientBin/\r\n[Ss]tyle[Cc]op.*\r\n~$*\r\n*~\r\n*.dbmdl\r\n*.[Pp]ublish.xml\r\n*.pfx\r\n*.publishsettings\r\n\r\n# RIA/Silverlight projects\r\nGenerated_Code/\r\n\r\n# Backup & report files from converting an old project file to a newer\r\n# Visual Studio version. Backup files are not needed, because we have git ;-)\r\n_UpgradeReport_Files/\r\nBackup*/\r\nUpgradeLog*.XML\r\nUpgradeLog*.htm\r\n\r\n# SQL Server files\r\nApp_Data/*.mdf\r\nApp_Data/*.ldf\r\n\r\n#############\r\n## Windows detritus\r\n#############\r\n\r\n# Windows image file caches\r\nThumbs.db\r\nehthumbs.db\r\n\r\n# Folder config file\r\nDesktop.ini\r\n\r\n# Recycle Bin used on file shares\r\n$RECYCLE.BIN/\r\n\r\n# Mac crap\r\n.DS_Store\r\n\r\n\r\n#############\r\n## Python\r\n#############\r\n\r\n*.py[cod]\r\n\r\n# Packages\r\n*.egg\r\n*.egg-info\r\ndist/\r\nbuild/\r\neggs/\r\nparts/\r\nvar/\r\nsdist/\r\ndevelop-eggs/\r\n.installed.cfg\r\n\r\n# Installer logs\r\npip-log.txt\r\n\r\n# Unit test / coverage reports\r\n.coverage\r\n.tox\r\n\r\n#Translations\r\n*.mo\r\n\r\n#Mr Developer\r\n.mr.developer.cfg\r\n*.db\r\n*.db"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018-2022 Jovibor, https://github.com/jovibor\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "## Introduction\r\n**libpe** is a lightweight and very fast library for parsing **PE32(x86)** and **PE32+(x64)** binaries, implemented as a C++20 module.\r\n\r\n## Table of Contents\r\n* [Features](#features)\r\n* [Usage](#usage)\r\n* [Class Methods](#class-methods) <details><summary>_Expand_</summary>\r\n  * [OpenFile](#openfile)\r\n  * [CloseFile](#closefile)\r\n  * [GetDOSHeader](#getdosheader)\r\n  * [GetRichHeader](#getrichheader)\r\n  * [GetNTHeader](#getntheader)\r\n  * [GetDataDirs](#getdatadirs)\r\n  * [GetSecHeaders](#getsecheaders)\r\n  * [GetExport](#getexport)\r\n  * [GetImport](#getimport)\r\n  * [GetResources](#getresources)\r\n  * [GetExceptions](#getexceptions)\r\n  * [GetSecurity](#getsecurity)\r\n  * [GetRelocations](#getrelocations)\r\n  * [GetDebug](#getdebug)\r\n  * [GetTLS](#gettls)\r\n  * [GetLoadConfig](#getloadconfig)\r\n  * [GetBoundImport](#getboundimport)\r\n  * [GetDelayImport](#getdelayimport)\r\n  * [GetCOMDescriptor](#getcomdescriptor)\r\n  </details>\r\n* [Helper Methods](#helper-methods) <details><summary>_Expand_</summary>\r\n  * [GetFileType](#getfiletype)\r\n  * [GetImageBase](#getimagebase)\r\n  * [GetOffsetFromRVA](#getoffsetfromrva)\r\n  * [FlatResources](#flatresources)\r\n  </details>\r\n* [Maps](#maps) <details><summary>_Expand_</summary>\r\n  * [MapFileHdrMachine](#mapfilehdrmachine)\r\n  * [MapFileHdrCharact](#mapfilehdrcharact)\r\n  * [MapOptHdrMagic](#mapopthdrmagic)\r\n  * [MapOptHdrSubsystem](#mapopthdrsubsystem)\r\n  * [MapOptHdrDllCharact](#mapophdrdllcharact)\r\n  * [MapSecHdrCharact](#mapsechdrcharact)\r\n  * [MapResID](#mapresid)\r\n  * [MapWinCertRevision](#mapwincertrevision)\r\n  * [MapWinCertType](#mapwincerttype)\r\n  * [MapRelocType](#mapreloctype)\r\n  * [MapDbgType](#mapdbgtype)\r\n  * [MapTLSCharact](#maptlscharact)\r\n  * [MapLCDGuardFlags](#maplcdguardflags)\r\n  * [MapCOR20Flags](#mapcor20flags)\r\n  </details>\r\n* [License](#license)\r\n\r\n## [](#)Features\r\n* Works with both **PE32(x86)** and **PE32+(x64)** binaries\r\n* Obtains all **PE32/PE32+** data structures:\r\n    * MSDOS Header\r\n    * «Rich» Header\r\n    * NT/File/Optional Headers\r\n    * Data Directories\r\n    * Sections\r\n    * Export Table\r\n    * Import Table\r\n    * Resource Table\r\n    * Exceptions Table\r\n    * Security Table\r\n    * Relocations Table\r\n    * Debug Table\r\n    * TLS Table\r\n    * Load Config Directory\r\n    * Bound Import Table\r\n    * Delay Import Table\r\n    * COM Table\r\n\r\n[Pepper](https://github.com/jovibor/Pepper) is one of the apps that is built on top of the **libpe**.\r\n\r\n## [](#)Usage\r\n```cpp\r\nimport libpe;\r\n\r\nint main() {\r\n    libpe::Clibpe pe(L\"C:\\\\myFile.exe\"); //or pe.OpenFile(L\"C:\\\\myFile.exe\");\r\n    const auto peImp = pe.GetImport();\r\n    if(peImp) {\r\n    ...\r\n    }\r\n    ...\r\n}\r\n```\r\n\r\n## [](#)Methods\r\n### OpenFile\r\n```cpp\r\nauto OpenFile(const wchar_t* pwszFile)->int;\r\n```\r\nOpens a file for further processing, until [`CloseFile`](#closefile) is called or `Clibpe` object goes out of scope and file closes automatically in destructor.\r\n```cpp\r\nlibpe::Clibpe pe;\r\nif(pe.OpenFile(L\"C:\\\\MyFile.exe\") == PEOK) {\r\n    ...\r\n}\r\n```\r\n\r\n### [](#)CloseFile();\r\n```cpp\r\nvoid CloseFile();\r\n```\r\nExplicitly closes file that was previously opened with the [`OpenFile(const wchar_t*)`](#openfile). This method is invoked automatically in `Clibpe` destructor.\r\n\r\n### [](#)GetDOSHeader\r\n```cpp\r\n[[nodiscard]] auto GetDOSHeader()const->std::optional<IMAGE_DOS_HEADER>;\r\n```\r\nReturns a file's standard **MSDOS** header.\r\n\r\n### [](#)GetRichHeader\r\n```cpp\r\n[[nodiscard]] auto GetRichHeader()const->std::optional<PERICHHDR_VEC>;\r\n```\r\nReturns an array of the unofficial and undocumented so called **«Rich»** structures.\r\n```cpp\r\nstruct PERICHHDR {\r\n    DWORD dwOffset; //File's raw offset of the entry.\r\n    WORD  wId;      //Entry Id.\r\n    WORD  wVersion; //Entry version.\r\n    DWORD dwCount;  //Amount of occurrences.\r\n};\r\nusing PERICHHDR_VEC = std::vector<PERICHHDR>;\r\n```\r\n\r\n### [](#)GetNTHeader\r\n```cpp\r\n[[nodiscard]] auto GetNTHeader()const->std::optional<PENTHDR>;\r\n```\r\nReturns a file's **NT** header.\r\n```cpp\r\nstruct PENTHDR {\r\n    DWORD dwOffset;   //File's raw offset of the header.\r\n    union UNPENTHDR { //Union of either x86 or x64 NT header.\r\n        IMAGE_NT_HEADERS32 stNTHdr32; //x86 Header.\r\n        IMAGE_NT_HEADERS64 stNTHdr64; //x64 Header.\r\n    } unHdr;\r\n};\r\n```\r\n\r\n### [](#)GetDataDirs\r\n```cpp\r\n[[nodiscard]] auto GetDataDirs()const->std::optional<PEDATADIR_VEC>;\r\n```\r\nReturns an array of file's **Data directories** structs.\r\n```cpp\r\nstruct PEDATADIR {\r\n    IMAGE_DATA_DIRECTORY stDataDir;  //Standard header.\r\n    std::string          strSection; //Name of the section this directory resides in (points to).\r\n};\r\nusing PEDATADIR_VEC = std::vector<PEDATADIR>;\r\n```\r\n\r\n### [](#)GetSecHeaders\r\n```cpp\r\n[[nodiscard]] auto GetSecHeaders()const->std::optional<PESECHDR_VEC>;\r\n```\r\nReturns an array of file's **Sections headers** structs.\r\n```cpp\r\nstruct PESECHDR {\r\n    DWORD                dwOffset;   //File's raw offset of this section header descriptor.\r\n    IMAGE_SECTION_HEADER stSecHdr;   //Standard section header.\r\n    std::string          strSecName; //Section full name.\r\n};\r\nusing PESECHDR_VEC = std::vector<PESECHDR>;\r\n```\r\n\r\n### [](#)GetExport\r\n```cpp\r\n[[nodiscard]] auto GetExport()const->std::optional<PEEXPORT>;\r\n```\r\nReturns a file's **Export** information.\r\n```cpp\r\nstruct PEEXPORTFUNC {\r\n    DWORD       dwFuncRVA;        //Function RVA.\r\n    DWORD       dwOrdinal;        //Function ordinal.\r\n    DWORD       dwNameRVA;        //Name RVA.\r\n    std::string strFuncName;      //Function name.\r\n    std::string strForwarderName; //Function forwarder name.\r\n};\r\nstruct PEEXPORT {\r\n    DWORD                     dwOffset;      //File's raw offset of the Export header descriptor.\r\n    IMAGE_EXPORT_DIRECTORY    stExportDesc;  //Standard export header descriptor.\r\n    std::string               strModuleName; //Actual module name.\r\n    std::vector<PEEXPORTFUNC> vecFuncs;      //Array of the exported functions struct.\t\r\n};\r\n```\r\n**Example:**\r\n```cpp\r\nlibpe::Clibpe pe(L\"PATH_TO_PE_FILE\");\r\nconst auto peExport = pe.GetExport();\r\nif (!peExport) {\r\n    return;\r\n}\r\n\r\npeExport->stExportDesc;  //IMAGE_EXPORT_DIRECTORY struct.\r\npeExport->strModuleName; //Export module name.\r\npeExport->vecFuncs;      //Vector of exported functions.\r\n\r\nfor (const auto& itFuncs : peExport->vecFuncs) {\r\n    itFuncs.strFuncName;      //Function name.\r\n    itFuncs.dwOrdinal;        //Ordinal.\r\n    itFuncs.dwFuncRVA;        //Function RVA.\r\n    itFuncs.strForwarderName; //Forwarder name.\r\n}\r\n```\r\n\r\n### [](#)GetImport\r\n```cpp\r\n[[nodiscard]] auto GetImport()const->std::optional<PEIMPORT_VEC>;\r\n```\r\nReturns an array of file's **Import table** entries.\r\n```cpp\r\nstruct PEIMPORTFUNC {\r\n    union UNPEIMPORTTHUNK {\r\n    \tIMAGE_THUNK_DATA32 stThunk32; //x86 standard thunk.\r\n\t    IMAGE_THUNK_DATA64 stThunk64; //x64 standard thunk.\r\n\t} unThunk;\r\n    IMAGE_IMPORT_BY_NAME stImpByName; //Standard IMAGE_IMPORT_BY_NAME struct\r\n    std::string          strFuncName; //Function name.\r\n};\r\nstruct PEIMPORT {\r\n    DWORD                     dwOffset;      //File's raw offset of the Import descriptor.\r\n    IMAGE_IMPORT_DESCRIPTOR   stImportDesc;  //Standard Import descriptor.\r\n    std::string               strModuleName; //Imported module name.\r\n    std::vector<PEIMPORTFUNC> vecImportFunc; //Array of imported functions.\r\n};\r\nusing PEIMPORT_VEC = std::vector<PEIMPORT>;\r\n```\r\n\r\n**Example**\r\n```cpp\r\nlibpe::Clibpe pe(L\"C:\\\\Windows\\\\notepad.exe\");\r\nconst auto peImp = pe.GetImport();\r\nif (!peImp) {\r\n    return -1;\r\n}\r\n\r\nfor (const auto& itModule : *peImp) { //Cycle through all imports that this PE file contains.\r\n    std::cout << std::format(\"{}, Imported funcs: {}\\r\\n\", itModule.strModuleName, itModule.vecImportFunc.size());\r\n    for (const auto& itFuncs : itModule.vecImportFunc) { //Cycle through all the functions imported from itModule module.\r\n        itFuncs.strFuncName;       //Imported function name.\r\n        itFuncs.stImpByName;       //IMAGE_IMPORT_BY_NAME struct for this function.\r\n        itFuncs.unThunk.stThunk32; //Union of IMAGE_THUNK_DATA32 or IMAGE_THUNK_DATA64 (depending on the PE type).\r\n    }\r\n}\r\n```\r\n\r\n### [](#)GetResources\r\n```cpp\r\n[[nodiscard]] auto GetResources()const->std::optional<PERESROOT>;\r\n```\r\nReturns all file's resources.\r\n\r\n##### Example:\r\nThe next code snippet populates `std::wstring` with all resources' types and names that PE binary possesses, and prints it to the standard `std::wcout`.\r\n```cpp\r\n#include <format>\r\n#include <iostream>\r\n#include <string>\r\n\r\nimport libpe;\r\nusing namespace libpe;\r\n\r\nint main()\r\n{\r\n    libpe::Clibpe pe;\r\n    if (pe.OpenFile(L\"C:\\\\Windows\\\\notepad.exe\") != PEOK) {\r\n        return -1;\r\n    }\r\n\r\n    const auto peResRoot = pe.GetResources();\r\n    if (!peResRoot) {\r\n        return -1;\r\n    }\r\n\r\n    std::wstring wstrResData; //This wstring will contain all resources by name.\r\n    for (const auto& iterRoot : peResRoot->vecResData) { //Main loop to extract Resources.\r\n        auto ilvlRoot = 0;\r\n        auto pResDirEntry = &iterRoot.stResDirEntry; //ROOT IMAGE_RESOURCE_DIRECTORY_ENTRY\r\n        if (pResDirEntry->NameIsString) {\r\n            wstrResData += std::format(L\"Entry: {} [Name: {}]\\r\\n\", ilvlRoot, iterRoot.wstrResName);\r\n        }\r\n        else {\r\n            if (const auto iter = MapResID.find(pResDirEntry->Id); iter != MapResID.end()) {\r\n                wstrResData += std::format(L\"Entry: {} [Id: {}, {}]\\r\\n\", ilvlRoot, pResDirEntry->Id, iter->second);\r\n            }\r\n            else {\r\n                wstrResData += std::format(L\"Entry: {} [Id: {}]\\r\\n\", ilvlRoot, pResDirEntry->Id);\r\n            }\r\n        }\r\n\r\n        if (pResDirEntry->DataIsDirectory) {\r\n            auto ilvl2 = 0;\r\n            auto pstResLvL2 = &iterRoot.stResLvL2;\r\n            for (const auto& iterLvL2 : pstResLvL2->vecResData) {\r\n                pResDirEntry = &iterLvL2.stResDirEntry; //Level 2 IMAGE_RESOURCE_DIRECTORY_ENTRY\r\n                if (pResDirEntry->NameIsString) {\r\n                    wstrResData += std::format(L\"    Entry: {}, Name: {}\\r\\n\", ilvl2, iterLvL2.wstrResName);\r\n                }\r\n                else {\r\n                    wstrResData += std::format(L\"    Entry: {}, Id: {}\\r\\n\", ilvl2, pResDirEntry->Id);\r\n                }\r\n\r\n                if (pResDirEntry->DataIsDirectory) {\r\n                    auto ilvl3 = 0;\r\n                    auto pstResLvL3 = &iterLvL2.stResLvL3;\r\n                    for (const auto& iterLvL3 : pstResLvL3->vecResData) {\r\n                        pResDirEntry = &iterLvL3.stResDirEntry; //Level 3 IMAGE_RESOURCE_DIRECTORY_ENTRY\r\n                        if (pResDirEntry->NameIsString) {\r\n                            wstrResData += std::format(L\"        Entry: {}, Name: {}\\r\\n\", ilvl3, iterLvL3.wstrResName);\r\n                        }\r\n                        else {\r\n                            wstrResData += std::format(L\"        Entry: {}, lang: {}\\r\\n\", ilvl3, pResDirEntry->Id);\r\n                        }\r\n                        ++ilvl3;\r\n                    }\r\n                }\r\n                ++ilvl2;\r\n            }\r\n        }\r\n        ++ilvlRoot;\r\n    }\r\n    std::wcout << wstrResData;\r\n```\r\n\r\n### [](#)GetExceptions\r\n```cpp\r\n[[nodiscard]] auto GetExceptions()const->std::optional<PEEXCEPTION_VEC>;\r\n```\r\nReturns an array of file's **Exception** entries.\r\n```cpp\r\nstruct PEEXCEPTION {\r\n    DWORD                         dwOffset;           //File's raw offset of the exceptions descriptor.\r\n    _IMAGE_RUNTIME_FUNCTION_ENTRY stRuntimeFuncEntry; //Standard _IMAGE_RUNTIME_FUNCTION_ENTRY header.\r\n};\r\nusing PEEXCEPTION_VEC = std::vector<PEEXCEPTION>;\r\n```\r\n\r\n### [](#)GetSecurity\r\n```cpp\r\n[[nodiscard]] auto GetSecurity()const->std::optional<PESECURITY_VEC>;\r\n```\r\nReturns an array of file's **Security** entries.\r\n```cpp\r\nstruct PEWIN_CERTIFICATE { //Full replica of the WIN_CERTIFICATE struct from the <WinTrust.h>.\r\n    DWORD dwLength;\r\n    WORD  wRevision;\r\n    WORD  wCertificateType;\r\n    BYTE  bCertificate[1];\r\n};\r\nstruct PESECURITY {\r\n    DWORD             dwOffset;  //File's raw offset of this security descriptor.\r\n    PEWIN_CERTIFICATE stWinSert; //Standard WIN_CERTIFICATE struct.\r\n};\r\nusing PESECURITY_VEC = std::vector<PESECURITY>;\r\n```\r\n\r\n### [](#)GetRelocations\r\n```cpp\r\n[[nodiscard]] auto GetRelocations()const->std::optional<PERELOC_VEC>;\r\n```\r\nReturns an array of file's relocation information.\r\n```cpp\r\nstruct PERELOCDATA {\r\n    DWORD dwOffset;     //File's raw offset of the Relocation data descriptor.\r\n    WORD  wRelocType;   //Relocation type.\r\n    WORD  wRelocOffset; //Relocation offset (Offset the relocation must be applied to.)\r\n};\r\nstruct PERELOC {\r\n    DWORD                    dwOffset;     //File's raw offset of the Relocation descriptor.\r\n    IMAGE_BASE_RELOCATION    stBaseReloc;  //Standard IMAGE_BASE_RELOCATION header.\r\n    std::vector<PERELOCDATA> vecRelocData; //Array of the Relocation data struct.\r\n};\r\nusing PERELOC_VEC = std::vector<PERELOC>;\r\n```\r\n\r\n### [](#)GetDebug\r\n```cpp\r\n[[nodiscard]] auto GetDebug()const->std::optional<PEDEBUG_VEC>;\r\n```\r\nReturns an array of file's **Debug** entries.\r\n```cpp\r\nstruct PEDEBUGDBGHDR {\r\n    //dwHdr[6] is an array of the first six DWORDs of IMAGE_DEBUG_DIRECTORY::PointerToRawData data (Debug info header).\r\n    //Their meaning varies depending on dwHdr[0] (Signature) value.\r\n    //If dwHdr[0] == 0x53445352 (Ascii \"RSDS\") it's PDB 7.0 file:\r\n    // Then dwHdr[1]-dwHdr[4] is GUID (*((GUID*)&dwHdr[1])). dwHdr[5] is Counter/Age.\r\n    //If dwHdr[0] == 0x3031424E (Ascii \"NB10\") it's PDB 2.0 file:\r\n    // Then dwHdr[1] is Offset. dwHdr[2] is Time/Signature. dwHdr[3] is Counter/Age.\r\n    DWORD       dwHdr[6];\r\n    std::string strPDBName; //PDB file name/path.\r\n};\r\nstruct PEDEBUG {\r\n    DWORD                 dwOffset;       //File's raw offset of the Debug descriptor.\r\n    IMAGE_DEBUG_DIRECTORY stDebugDir;     //Standard IMAGE_DEBUG_DIRECTORY header.\r\n    PEDEBUGDBGHDR         stDebugHdrInfo; //Debug info header.\r\n};\r\nusing PEDEBUG_VEC = std::vector<PEDEBUG>;\r\n```\r\n\r\n### [](#)GetTLS\r\n```cpp\r\n[[nodiscard]] auto GetTLS()const->std::optional<PETLS>;\r\n```\r\nReturns file's **Thread Local Storage** information.\r\n```cpp\r\nstruct PETLS {\r\n    DWORD              dwOffset;          //File's raw offset of the TLS header descriptor.\r\n    union UNPETLS {\r\n    \tIMAGE_TLS_DIRECTORY32 stTLSDir32; //x86 standard TLS header.\r\n    \tIMAGE_TLS_DIRECTORY64 stTLSDir64; //x64 TLS header.\r\n    } unTLS;\r\n    std::vector<DWORD> vecTLSCallbacks;   //Array of the TLS callbacks.\r\n};\r\n```\r\n\r\n### [](#)GetLoadConfig\r\n```cpp\r\n[[nodiscard]] auto GetLoadConfig()const->std::optional<PELOADCONFIG>;\r\n```\r\nReturns file's **Load Config Directory** info.\r\n```cpp\r\nstruct PELOADCONFIG {\r\n    DWORD dwOffset;                            //File's raw offset of the LCD descriptor.\r\n    union UNPELOADCONFIG {\r\n    \tIMAGE_LOAD_CONFIG_DIRECTORY32 stLCD32; //x86 LCD descriptor.\r\n    \tIMAGE_LOAD_CONFIG_DIRECTORY64 stLCD64; //x64 LCD descriptor.\r\n    } unLCD;\r\n};\r\n```\r\n\r\n### [](#)GetBoundImport\r\n```cpp\r\n[[nodiscard]] auto GetBoundImport()const->std::optional<PEBOUNDIMPORT_VEC>;\r\n```\r\nReturns an array of file's **Bound Import** entries.\r\n```cpp\r\nstruct PEBOUNDFORWARDER {\r\n    DWORD                     dwOffset;              //File's raw offset of the Bound Forwarder descriptor.\r\n    IMAGE_BOUND_FORWARDER_REF stBoundForwarder;      //Standard IMAGE_BOUND_FORWARDER_REF struct.\r\n    std::string               strBoundForwarderName; //Bound forwarder name.\r\n};\r\nstruct PEBOUNDIMPORT {\r\n    DWORD                         dwOffset;          //File's raw offset of the Bound Import descriptor.\r\n    IMAGE_BOUND_IMPORT_DESCRIPTOR stBoundImpDesc;    //Standard IMAGE_BOUND_IMPORT_DESCRIPTOR struct.\r\n    std::string                   strBoundName;      //Bound Import name.\r\n    std::vector<PEBOUNDFORWARDER> vecBoundForwarder; //Array of the Bound Forwarder structs.\r\n};\r\nusing PEBOUNDIMPORT_VEC = std::vector<PEBOUNDIMPORT>;\r\n```\r\n\r\n### [](#)GetDelayImport\r\n```cpp\r\n[[nodiscard]] auto GetDelayImport()const->std::optional<PEDELAYIMPORT_VEC>;\r\n```\r\nReturns an array of file's **Delay Import** entries.\r\n```cpp\r\nstruct PEDELAYIMPORTFUNC {\r\n    union UNPEDELAYIMPORTTHUNK {\r\n        struct x32 {\r\n            IMAGE_THUNK_DATA32 stImportAddressTable;      //x86 Import Address Table struct.\r\n            IMAGE_THUNK_DATA32 stImportNameTable;         //x86 Import Name Table struct.\r\n            IMAGE_THUNK_DATA32 stBoundImportAddressTable; //x86 Bound Import Address Table struct.\r\n            IMAGE_THUNK_DATA32 stUnloadInformationTable;  //x86 Unload Information Table struct.\r\n        } st32;\r\n        struct x64 {\r\n            IMAGE_THUNK_DATA64 stImportAddressTable;      //x64 Import Address Table struct.\r\n            IMAGE_THUNK_DATA64 stImportNameTable;         //x64 Import Name Table struct.\r\n            IMAGE_THUNK_DATA64 stBoundImportAddressTable; //x64 Bound Import Address Table struct\r\n            IMAGE_THUNK_DATA64 stUnloadInformationTable;  //x64 Unload Information Table struct.\r\n        } st64;\r\n    } unThunk;\r\n    IMAGE_IMPORT_BY_NAME stImpByName; //Standard IMAGE_IMPORT_BY_NAME struct.\r\n    std::string          strFuncName; //Function name.\r\n};\r\nstruct PEDELAYIMPORT {\r\n    DWORD                          dwOffset;        //File's raw offset of this Delay Import descriptor.\r\n    IMAGE_DELAYLOAD_DESCRIPTOR     stDelayImpDesc;  //Standard IMAGE_DELAYLOAD_DESCRIPTOR struct.\r\n    std::string                    strModuleName;   //Import module name.\r\n    std::vector<PEDELAYIMPORTFUNC> vecDelayImpFunc; //Array of the Delay Import module functions.\r\n};\r\nusing PEDELAYIMPORT_VEC = std::vector<PEDELAYIMPORT>;\r\n```\r\n\r\n### [](#)GetCOMDescriptor\r\n```cpp\r\n[[nodiscard]] auto GetCOMDescriptor()const->std::optional<PECOMDESCRIPTOR>;\r\n```\r\nGets file's **.NET** info.\r\n```cpp\r\nstruct PECOMDESCRIPTOR {\r\n    DWORD              dwOffset; //File's raw offset of the IMAGE_COR20_HEADER descriptor.\r\n    IMAGE_COR20_HEADER stCorHdr; //Standard IMAGE_COR20_HEADER struct.\r\n};\r\n```\r\n\r\n## [](#)Helper Methods\r\nThese freestanding methods do not need an active `Clibpe` object with an opened file. They instead take references to the previously obtained structures.\r\n\r\n### [](#)GetFileType\r\n```cpp\r\n[[nodiscard]] inline constexpr auto GetFileType(const PENTHDR& stNTHdr)->EFileType\r\n```\r\nReturns **PE** file type in form of the `EFileType` enum.\r\n```cpp\r\nenum class EFileType : std::uint8_t {\r\n    UNKNOWN = 0, PE32, PE64, PEROM\r\n};\r\n```\r\n\r\n### [](#)GetImageBase\r\n```cpp\r\n[[nodiscard]] inline constexpr auto GetImageBase(const PENTHDR& stNTHdr)->ULONGLONG\r\n```\r\nReturns file's **Image Base**.\r\n\r\n### [](#)GetOffsetFromRVA\r\n```cpp\r\n[[nodiscard]] inline constexpr auto GetOffsetFromRVA(ULONGLONG ullRVA, const PESECHDR_VEC& vecSecHdr)->DWORD\r\n```\r\nConverts file's RVA to the file's physical raw offset on disk.\r\n\r\n### [](#)FlatResources\r\n```cpp\r\n[[nodiscard]] inline constexpr auto FlatResources(const PERESROOT& stResRoot)\r\n```\r\nThis function is kind of a light version of the `GetResources` method. It takes `PERESROOT` struct returned by the `GetResources`, and returns `std::vector` of `PERESFLAT` structures.  \r\n`PERESFLAT` is a light struct that only possesses pointers to an actual resources data, unlike heavy `PERESROOT`. `FlatResources` flattens all resources, making accessing them more convenient.\r\n```cpp\r\nstruct PERESFLAT {\r\n    std::span<const std::byte> spnData { };    //Resource data.\r\n    std::wstring_view          wsvTypeStr { }; //Resource Type name.\r\n    std::wstring_view          wsvNameStr { }; //Resource Name name (resource itself name).\r\n    std::wstring_view          wsvLangStr { }; //Resource Lang name.\r\n    WORD                       wTypeID { };    //Resource Type ID (RT_CURSOR, RT_BITMAP, etc...).\r\n    WORD                       wNameID { };    //Resource Name ID (resource itself ID).\r\n    WORD                       wLangID { };    //Resource Lang ID.\r\n};\r\nusing PERESFLAT_VEC = std::vector<PERESFLAT>;\r\n```\r\n\r\n## [](#)Maps\r\nA **PE** file consists of many structures, they in turn possess many fields some of which have predefined values.  \r\nThese maps are meant to alleviate such fields' conversion to a human-reading format. They are simple `std::unordered_map<DWORD, std::wstring_view>` maps.\r\n\r\nNote that some fields can only have one value, while the others can combine many values with a bitwise `or |` operation.\r\n\r\n### [](#)MapFileHdrMachine\r\nThis map forms one of the values from `IMAGE_NT_HEADERS::IMAGE_FILE_HEADER::Machine` field.\r\n\r\n### [](#)MapFileHdrCharact\r\nThis map forms one or more values from `IMAGE_NT_HEADERS::IMAGE_FILE_HEADER::Characteristics` field.\r\n```cpp\r\nconst auto pNTHdr = m_pLibpe->GetNTHeader();\r\nconst auto pDescr = &pNTHdr->unHdr.stNTHdr32.FileHeader; //Same for both x86/x64.\r\nstd::wstring  wstrCharact;\r\nfor (const auto& flags : MapFileHdrCharact) {\r\n    if (flags.first & pDescr->Characteristics) {\r\n        wstrCharact += flags.second;\r\n        wstrCharact += L\"\\n\";\r\n    }\r\n}\r\n```\r\n\r\n### [](#)MapOptHdrMagic\r\nThis map forms one of the values from `IMAGE_NT_HEADERS::IMAGE_OPTIONAL_HEADER::Magic` field.\r\n\r\n### [](#)MapOptHdrSubsystem\r\nThis map forms one of the values from `IMAGE_NT_HEADERS::IMAGE_OPTIONAL_HEADER::Subsystem` field.\r\n\r\n### [](#)MapOptHdrDllCharact\r\nThis map forms one or more values from `IMAGE_NT_HEADERS::IMAGE_OPTIONAL_HEADER::DllCharacteristics` field.\r\n```cpp\r\nconst auto pNTHdr = m_pLibpe->GetNTHeader();\r\nconst auto pOptHdr = &pNTHdr->unHdr.stNTHdr32.OptionalHeader //For x64: pNTHdr->unHdr.stNTHdr64.OptionalHeader\r\nstd::wstring wstrCharact;\r\nfor (const auto& flags : MapOptHdrDllCharact) {\r\n    if (flags.first & pOptHdr->DllCharacteristics) {\r\n        wstrCharact += flags.second;\r\n        wstrCharact += L\"\\n\";\r\n    }\r\n}\r\n```\r\n\r\n### [](#)MapSecHdrCharact\r\nThis map forms one or more values from `IMAGE_SECTION_HEADER::Characteristics` field.\r\n```cpp\r\nconst auto pSecHeaders = m_pLibpe->GetSecHeaders();\r\nstd::wstring wstrCharact;\r\nauto IdOfSection = 0; //ID of desired section.\r\nfor (const auto& flags : MapSecHdrCharact) {\r\n    if (flags.first & pSecHeaders->at(IdOfSection).stSecHdr.Characteristics) {\r\n        wstrCharact += flags.second;\r\n        wstrCharact += L\"\\n\";\r\n    }\r\n}\r\n```\r\n\r\n### [](#)MapResID\r\nThis map forms one of the values from `IMAGE_RESOURCE_DIRECTORY_ENTRY::Id` field.\r\n\r\n### [](#)MapWinCertRevision\r\nThis map forms one of the values from  `WIN_CERTIFICATE::wRevision` field.\r\n\r\n### [](#)MapWinCertType\r\nThis map forms one of the values from `WIN_CERTIFICATE::wCertificateType` field.\r\n\r\n### [](#)MapRelocType\r\nThis map forms one of the values from `PERELOCDATA::wRelocType` field.\r\n\r\n### [](#)MapDbgType\r\nThis map forms one of the values from `IMAGE_DEBUG_DIRECTORY::Type` field.\r\n\r\n### [](#)MapTLSCharact\r\nThis map forms one of the values from `IMAGE_TLS_DIRECTORY::Characteristics` field.\r\n\r\n### [](#)MapLCDGuardFlags\r\nThis map forms one or more values from `IMAGE_LOAD_CONFIG_DIRECTORY::GuardFlags` field.\r\n```cpp\r\nconst auto pLCD = m_pLibpe->GetLoadConfig();\r\nconst auto pPELCD = &pLCD->unLCD.stLCD32; //For x64: pLCD->unLCD.stLCD64\r\nstd::wstring wstrGFlags;\r\nfor (const auto& flags : MapLCDGuardFlags) {\r\n    if (flags.first & pPELCD->GuardFlags) {\r\n        wstrGFlags += flags.second;\r\n        wstrGFlags += L\"\\n\";\r\n    }\r\n}\r\n```\r\n\r\n### [](#)MapCOR20Flags\r\nThis map forms one or more values from `IMAGE_COR20_HEADER::Flags` field.\r\n```cpp\r\nconst auto pCOMDesc = m_pLibpe->GetCOMDescriptor();\r\nstd::wstring wstrFlags;\r\nfor (const auto& flags : MapCOR20Flags) {\r\n    if (flags.first & pCOMDesc->stCorHdr.Flags) {\r\n        wstrFlags += flags.second;\r\n        wstrFlags += L\"\\n\";\r\n    }\r\n}\r\n```\r\n\r\n## [](#)**License**\r\nThis software is available under the **MIT License**."
  },
  {
    "path": "libpe/libpe.ixx",
    "content": "/*****************************************************************\r\n* Copyright © 2018-present Jovibor https://github.com/jovibor/   *\r\n* Library for parsing PE32 (x86) and PE32+ (x64) binaries.       *\r\n* Official git repository: https://github.com/jovibor/libpe      *\r\n* This software is available under the \"MIT License\".            *\r\n*****************************************************************/\r\nmodule;\r\n#include <Windows.h>\r\n#include <cassert>\r\n#include <iostream>\r\n#include <optional>\r\n#include <span>\r\n#include <string>\r\n#include <strsafe.h>\r\n#include <unordered_map>\r\n#include <vector>\r\nexport module libpe;\r\n\r\nnamespace libpe::ut { //Utility.\r\n\t//Check overflow of addition.\r\n\t[[nodiscard]] constexpr bool IsSumOverflow(DWORD_PTR dwFirst, DWORD_PTR dwSecond) {\r\n\t\treturn (dwFirst + dwSecond) < dwFirst;\r\n\t}\r\n}\r\n\r\nexport namespace libpe {\r\n\tconstexpr auto LIBPE_VERSION_MAJOR = 2;\r\n\tconstexpr auto LIBPE_VERSION_MINOR = 0;\r\n\tconstexpr auto LIBPE_VERSION_PATCH = 0;\r\n\r\n\t//Rich.\r\n\tstruct PERICHHDR {\r\n\t\tDWORD dwOffset { }; //File's raw offset of this entry.\r\n\t\tWORD  wId { };      //Entry Id.\r\n\t\tWORD  wVersion { }; //Entry version.\r\n\t\tDWORD dwCount { };  //Amount of occurrences.\r\n\t};\r\n\tusing PERICHHDR_VEC = std::vector<PERICHHDR>;\r\n\r\n\t//NT header.\r\n\tstruct PENTHDR {\r\n\t\tDWORD dwOffset { }; //File's raw offset of this header.\r\n\t\tunion UNPENTHDR {   //Union of either x86 or x64 NT header.\r\n\t\t\tIMAGE_NT_HEADERS32 stNTHdr32; //x86 Header.\r\n\t\t\tIMAGE_NT_HEADERS64 stNTHdr64; //x64 Header.\r\n\t\t} unHdr { };\r\n\t};\r\n\tconst std::unordered_map<WORD, std::wstring_view> MapFileHdrMachine { //IMAGE_FILE_HEADER::Machine.\r\n\t\t{ static_cast<WORD>(0), L\"IMAGE_FILE_MACHINE_UNKNOWN\" },\r\n\t\t{ static_cast<WORD>(0x0001), L\"IMAGE_FILE_MACHINE_TARGET_HOST\" },\r\n\t\t{ static_cast<WORD>(0x014c), L\"IMAGE_FILE_MACHINE_I386\" },\r\n\t\t{ static_cast<WORD>(0x0162), L\"IMAGE_FILE_MACHINE_R3000\" },\r\n\t\t{ static_cast<WORD>(0x0166), L\"IMAGE_FILE_MACHINE_R4000\" },\r\n\t\t{ static_cast<WORD>(0x0168), L\"IMAGE_FILE_MACHINE_R10000\" },\r\n\t\t{ static_cast<WORD>(0x0169), L\"IMAGE_FILE_MACHINE_WCEMIPSV2\" },\r\n\t\t{ static_cast<WORD>(0x0184), L\"IMAGE_FILE_MACHINE_ALPHA\" },\r\n\t\t{ static_cast<WORD>(0x01a2), L\"IMAGE_FILE_MACHINE_SH3\" },\r\n\t\t{ static_cast<WORD>(0x01a3), L\"IMAGE_FILE_MACHINE_SH3DSP\" },\r\n\t\t{ static_cast<WORD>(0x01a4), L\"IMAGE_FILE_MACHINE_SH3E\" },\r\n\t\t{ static_cast<WORD>(0x01a6), L\"IMAGE_FILE_MACHINE_SH4\" },\r\n\t\t{ static_cast<WORD>(0x01a8), L\"IMAGE_FILE_MACHINE_SH5\" },\r\n\t\t{ static_cast<WORD>(0x01c0), L\"IMAGE_FILE_MACHINE_ARM\" },\r\n\t\t{ static_cast<WORD>(0x01c2), L\"IMAGE_FILE_MACHINE_THUMB\" },\r\n\t\t{ static_cast<WORD>(0x01c4), L\"IMAGE_FILE_MACHINE_ARMNT\" },\r\n\t\t{ static_cast<WORD>(0x01d3), L\"IMAGE_FILE_MACHINE_AM33\" },\r\n\t\t{ static_cast<WORD>(0x01F0), L\"IMAGE_FILE_MACHINE_POWERPC\" },\r\n\t\t{ static_cast<WORD>(0x01f1), L\"IMAGE_FILE_MACHINE_POWERPCFP\" },\r\n\t\t{ static_cast<WORD>(0x0200), L\"IMAGE_FILE_MACHINE_IA64\" },\r\n\t\t{ static_cast<WORD>(0x0266), L\"IMAGE_FILE_MACHINE_MIPS16\" },\r\n\t\t{ static_cast<WORD>(0x0284), L\"IMAGE_FILE_MACHINE_ALPHA64\" },\r\n\t\t{ static_cast<WORD>(0x0366), L\"IMAGE_FILE_MACHINE_MIPSFPU\" },\r\n\t\t{ static_cast<WORD>(0x0466), L\"IMAGE_FILE_MACHINE_MIPSFPU16\" },\r\n\t\t{ static_cast<WORD>(0x0520), L\"IMAGE_FILE_MACHINE_TRICORE\" },\r\n\t\t{ static_cast<WORD>(0x0CEF), L\"IMAGE_FILE_MACHINE_CEF\" },\r\n\t\t{ static_cast<WORD>(0x0EBC), L\"IMAGE_FILE_MACHINE_EBC\" },\r\n\t\t{ static_cast<WORD>(0x8664), L\"IMAGE_FILE_MACHINE_AMD64\" },\r\n\t\t{ static_cast<WORD>(0x9041), L\"IMAGE_FILE_MACHINE_M32R\" },\r\n\t\t{ static_cast<WORD>(0xAA64), L\"IMAGE_FILE_MACHINE_ARM64\" },\r\n\t\t{ static_cast<WORD>(0xC0EE), L\"IMAGE_FILE_MACHINE_CEE\" }\r\n\t};\r\n\tconst std::unordered_map<WORD, std::wstring_view> MapFileHdrCharact { //IMAGE_FILE_HEADER::Characteristics.\r\n\t\t{ static_cast<WORD>(0x0001), L\"IMAGE_FILE_RELOCS_STRIPPED\" },\r\n\t\t{ static_cast<WORD>(0x0002), L\"IMAGE_FILE_EXECUTABLE_IMAGE\" },\r\n\t\t{ static_cast<WORD>(0x0004), L\"IMAGE_FILE_LINE_NUMS_STRIPPED\" },\r\n\t\t{ static_cast<WORD>(0x0008), L\"IMAGE_FILE_LOCAL_SYMS_STRIPPED\" },\r\n\t\t{ static_cast<WORD>(0x0010), L\"IMAGE_FILE_AGGRESIVE_WS_TRIM\" },\r\n\t\t{ static_cast<WORD>(0x0020), L\"IMAGE_FILE_LARGE_ADDRESS_AWARE\" },\r\n\t\t{ static_cast<WORD>(0x0080), L\"IMAGE_FILE_BYTES_REVERSED_LO\" },\r\n\t\t{ static_cast<WORD>(0x0100), L\"IMAGE_FILE_32BIT_MACHINE\" },\r\n\t\t{ static_cast<WORD>(0x0200), L\"IMAGE_FILE_DEBUG_STRIPPED\" },\r\n\t\t{ static_cast<WORD>(0x0400), L\"IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP\" },\r\n\t\t{ static_cast<WORD>(0x0800), L\"IMAGE_FILE_NET_RUN_FROM_SWAP\" },\r\n\t\t{ static_cast<WORD>(0x1000), L\"IMAGE_FILE_SYSTEM\" },\r\n\t\t{ static_cast<WORD>(0x2000), L\"IMAGE_FILE_DLL\" },\r\n\t\t{ static_cast<WORD>(0x4000), L\"IMAGE_FILE_UP_SYSTEM_ONLY\" },\r\n\t\t{ static_cast<WORD>(0x8000), L\"IMAGE_FILE_BYTES_REVERSED_HI\" }\r\n\t};\r\n\tconst std::unordered_map<WORD, std::wstring_view> MapOptHdrMagic { //IMAGE_OPTIONAL_HEADER::Magic.\r\n\t\t{ static_cast<WORD>(0x10b), L\"IMAGE_NT_OPTIONAL_HDR32_MAGIC\" },\r\n\t\t{ static_cast<WORD>(0x20b), L\"IMAGE_NT_OPTIONAL_HDR64_MAGIC\" },\r\n\t\t{ static_cast<WORD>(0x107), L\"IMAGE_ROM_OPTIONAL_HDR_MAGIC\" }\r\n\t};\r\n\tconst std::unordered_map<WORD, std::wstring_view> MapOptHdrSubsystem { //IMAGE_OPTIONAL_HEADER::Subsystem.\r\n\t\t{ static_cast<WORD>(0), L\"IMAGE_SUBSYSTEM_UNKNOWN\" },\r\n\t\t{ static_cast<WORD>(1), L\"IMAGE_SUBSYSTEM_NATIVE\" },\r\n\t\t{ static_cast<WORD>(2), L\"IMAGE_SUBSYSTEM_WINDOWS_GUI\" },\r\n\t\t{ static_cast<WORD>(3), L\"IMAGE_SUBSYSTEM_WINDOWS_CUI\" },\r\n\t\t{ static_cast<WORD>(5), L\"IMAGE_SUBSYSTEM_OS2_CUI\" },\r\n\t\t{ static_cast<WORD>(7), L\"IMAGE_SUBSYSTEM_POSIX_CUI\" },\r\n\t\t{ static_cast<WORD>(8), L\"IMAGE_SUBSYSTEM_NATIVE_WINDOWS\" },\r\n\t\t{ static_cast<WORD>(9), L\"IMAGE_SUBSYSTEM_WINDOWS_CE_GUI\" },\r\n\t\t{ static_cast<WORD>(10), L\"IMAGE_SUBSYSTEM_EFI_APPLICATION\" },\r\n\t\t{ static_cast<WORD>(11), L\"IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER\" },\r\n\t\t{ static_cast<WORD>(12), L\"IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER\" },\r\n\t\t{ static_cast<WORD>(13), L\"IMAGE_SUBSYSTEM_EFI_ROM\" },\r\n\t\t{ static_cast<WORD>(14), L\"IMAGE_SUBSYSTEM_XBOX\" },\r\n\t\t{ static_cast<WORD>(16), L\"IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION\" },\r\n\t\t{ static_cast<WORD>(17), L\"IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG\" }\r\n\t};\r\n\tconst std::unordered_map<WORD, std::wstring_view> MapOptHdrDllCharact { //IMAGE_OPTIONAL_HEADER::DllCharacteristics.\r\n\t\t{ static_cast<WORD>(0x0001), L\"IMAGE_LIBRARY_PROCESS_INIT\" },\r\n\t\t{ static_cast<WORD>(0x0002), L\"IMAGE_LIBRARY_PROCESS_TERM\" },\r\n\t\t{ static_cast<WORD>(0x0004), L\"IMAGE_LIBRARY_THREAD_INIT\" },\r\n\t\t{ static_cast<WORD>(0x0008), L\"IMAGE_LIBRARY_THREAD_TERM\" },\r\n\t\t{ static_cast<WORD>(0x0020), L\"IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA\" },\r\n\t\t{ static_cast<WORD>(0x0040), L\"IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE\" },\r\n\t\t{ static_cast<WORD>(0x0080), L\"IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY\" },\r\n\t\t{ static_cast<WORD>(0x0100), L\"IMAGE_DLLCHARACTERISTICS_NX_COMPAT\" },\r\n\t\t{ static_cast<WORD>(0x0200), L\"IMAGE_DLLCHARACTERISTICS_NO_ISOLATION\" },\r\n\t\t{ static_cast<WORD>(0x0400), L\"IMAGE_DLLCHARACTERISTICS_NO_SEH\" },\r\n\t\t{ static_cast<WORD>(0x0800), L\"IMAGE_DLLCHARACTERISTICS_NO_BIND\" },\r\n\t\t{ static_cast<WORD>(0x1000), L\"IMAGE_DLLCHARACTERISTICS_APPCONTAINER\" },\r\n\t\t{ static_cast<WORD>(0x2000), L\"IMAGE_DLLCHARACTERISTICS_WDM_DRIVER\" },\r\n\t\t{ static_cast<WORD>(0x4000), L\"IMAGE_DLLCHARACTERISTICS_GUARD_CF\" },\r\n\t\t{ static_cast<WORD>(0x8000), L\"IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE\" }\r\n\t};\r\n\r\n\t//Data directories.\r\n\tstruct PEDATADIR {\r\n\t\tIMAGE_DATA_DIRECTORY stDataDir { }; //Standard header.\r\n\r\n\t\t//Section index number, in which this directory resides.\r\n\t\t//This index is also the actual index into the PESECHDR_VEC vector (from GetSecHeaders()).\r\n\t\t//If the IMAGE_DATA_DIRECTORY::VirtualAddress is > 0 and this index equals 0xFFFFFFFF (DWORD max),\r\n\t\t//it means that directory's VirtualAddress points to an invalid/nonexistent section,\r\n\t\t//and the PE file is most likely corrupted.\r\n\t\tDWORD                dwSecIdx { };\r\n\t};\r\n\tusing PEDATADIR_VEC = std::vector<PEDATADIR>;\r\n\r\n\t//Sections headers.\r\n\t//For more info check:\r\n\t//docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_image_section_header#members\r\n\t//«An 8-byte, null-padded UTF-8 string. For longer names, this member contains a forward slash (/) \r\n\t//followed by an ASCII representation of a decimal number that is an offset into the string table.»\r\n\tstruct PESECHDR {\r\n\t\tDWORD                dwOffset { }; //File's raw offset of this section header descriptor.\r\n\t\tIMAGE_SECTION_HEADER stSecHdr { }; //Standard section header.\r\n\t\tstd::string          strSecName;   //Section full name.\r\n\t};\r\n\tusing PESECHDR_VEC = std::vector<PESECHDR>;\r\n\r\n\tconst std::unordered_map<DWORD, std::wstring_view> MapSecHdrCharact { //IMAGE_SECTION_HEADER::Characteristics.\r\n\t\t{ 0x00000000, L\"IMAGE_SCN_TYPE_REG (Reserved)\" },\r\n\t\t{ 0x00000001, L\"IMAGE_SCN_TYPE_DSECT (Reserved)\" },\r\n\t\t{ 0x00000002, L\"IMAGE_SCN_TYPE_NOLOAD (Reserved)\" },\r\n\t\t{ 0x00000004, L\"IMAGE_SCN_TYPE_GROUP (Reserved)\" },\r\n\t\t{ 0x00000008, L\"IMAGE_SCN_TYPE_NO_PAD (Reserved)\" },\r\n\t\t{ 0x00000010, L\"IMAGE_SCN_TYPE_COPY (Reserved)\" },\r\n\t\t{ 0x00000020, L\"IMAGE_SCN_CNT_CODE (Section contains code)\" },\r\n\t\t{ 0x00000040, L\"IMAGE_SCN_CNT_INITIALIZED_DATA (Section contains initialized data)\" },\r\n\t\t{ 0x00000080, L\"IMAGE_SCN_CNT_UNINITIALIZED_DATA (Section contains uninitialized data)\" },\r\n\t\t{ 0x00000100, L\"IMAGE_SCN_LNK_OTHER (Reserved)\" },\r\n\t\t{ 0x00000200, L\"IMAGE_SCN_LNK_INFO (Section contains comments or some other type of information)\" },\r\n\t\t{ 0x00000400, L\"IMAGE_SCN_TYPE_OVER (Reserved)\" },\r\n\t\t{ 0x00000800, L\"IMAGE_SCN_LNK_REMOVE (Section contents will not become part of image)\" },\r\n\t\t{ 0x00001000, L\"IMAGE_SCN_LNK_COMDAT (Section contents comdat)\" },\r\n\t\t{ 0x00004000, L\"IMAGE_SCN_NO_DEFER_SPEC_EXC (Reset speculative exceptions handling bits in the TLB entries for this section)\" },\r\n\t\t{ 0x00008000, L\"IMAGE_SCN_GPREL (Section content can be accessed relative to GP)\" },\r\n\t\t{ 0x00010000, L\"IMAGE_SCN_MEM_SYSHEAP (Obsolete)\" },\r\n\t\t{ 0x00020000, L\"IMAGE_SCN_MEM_PURGEABLE\" },\r\n\t\t{ 0x00040000, L\"IMAGE_SCN_MEM_LOCKED\" },\r\n\t\t{ 0x00080000, L\"IMAGE_SCN_MEM_PRELOAD\" },\r\n\t\t{ 0x00100000, L\"IMAGE_SCN_ALIGN_1BYTES\" },\r\n\t\t{ 0x00200000, L\"IMAGE_SCN_ALIGN_2BYTES\" },\r\n\t\t{ 0x00300000, L\"IMAGE_SCN_ALIGN_4BYTES\" },\r\n\t\t{ 0x00400000, L\"IMAGE_SCN_ALIGN_8BYTES\" },\r\n\t\t{ 0x00500000, L\"IMAGE_SCN_ALIGN_16BYTES (Default alignment if no others are specified)\" },\r\n\t\t{ 0x00600000, L\"IMAGE_SCN_ALIGN_32BYTES\" },\r\n\t\t{ 0x00700000, L\"IMAGE_SCN_ALIGN_64BYTES\" },\r\n\t\t{ 0x00800000, L\"IMAGE_SCN_ALIGN_128BYTES\" },\r\n\t\t{ 0x00900000, L\"IMAGE_SCN_ALIGN_256BYTES\" },\r\n\t\t{ 0x00A00000, L\"IMAGE_SCN_ALIGN_512BYTES\" },\r\n\t\t{ 0x00B00000, L\"IMAGE_SCN_ALIGN_1024BYTES\" },\r\n\t\t{ 0x00C00000, L\"IMAGE_SCN_ALIGN_2048BYTES\" },\r\n\t\t{ 0x00D00000, L\"IMAGE_SCN_ALIGN_4096BYTES\" },\r\n\t\t{ 0x00E00000, L\"IMAGE_SCN_ALIGN_8192BYTES\" },\r\n\t\t{ 0x00F00000, L\"IMAGE_SCN_ALIGN_MASK\" },\r\n\t\t{ 0x01000000, L\"IMAGE_SCN_LNK_NRELOC_OVFL (Section contains extended relocations)\" },\r\n\t\t{ 0x02000000, L\"IMAGE_SCN_MEM_DISCARDABLE (Section can be discarded)\" },\r\n\t\t{ 0x04000000, L\"IMAGE_SCN_MEM_NOT_CACHED (Section is not cachable)\" },\r\n\t\t{ 0x08000000, L\"IMAGE_SCN_MEM_NOT_PAGED (Section is not pageable)\" },\r\n\t\t{ 0x10000000, L\"IMAGE_SCN_MEM_SHARED (Section is shareable)\" },\r\n\t\t{ 0x20000000, L\"IMAGE_SCN_MEM_EXECUTE (Section is executable)\" },\r\n\t\t{ 0x40000000, L\"IMAGE_SCN_MEM_READ (Section is readable)\" },\r\n\t\t{ 0x80000000, L\"IMAGE_SCN_MEM_WRITE (Section is writeable)\" }\r\n\t};\r\n\r\n\t//Export table.\r\n\tstruct PEEXPORTFUNC {\r\n\t\tDWORD       dwFuncRVA { };    //Function RVA.\r\n\t\tDWORD       dwOrdinal { };    //Function ordinal.\r\n\t\tDWORD       dwNameRVA { };    //Name RVA.\r\n\t\tstd::string strFuncName;      //Function name.\r\n\t\tstd::string strForwarderName; //Function forwarder name.\r\n\t};\r\n\tstruct PEEXPORT {\r\n\t\tDWORD                     dwOffset { };     //File's raw offset of the Export header descriptor.\r\n\t\tIMAGE_EXPORT_DIRECTORY    stExportDesc { }; //Standard export header descriptor.\r\n\t\tstd::string               strModuleName;    //Actual module name.\r\n\t\tstd::vector<PEEXPORTFUNC> vecFuncs;         //Array of the exported functions struct.\t\r\n\t};\r\n\r\n\t//Import table:\r\n\tstruct PEIMPORTFUNC {\r\n\t\tunion UNPEIMPORTTHUNK {\r\n\t\t\tIMAGE_THUNK_DATA32 stThunk32;     //x86 standard thunk.\r\n\t\t\tIMAGE_THUNK_DATA64 stThunk64;     //x64 standard thunk.\r\n\t\t} unThunk { };\r\n\t\tIMAGE_IMPORT_BY_NAME stImpByName { }; //Standard IMAGE_IMPORT_BY_NAME struct\r\n\t\tstd::string          strFuncName;     //Function name.\r\n\t};\r\n\tstruct PEIMPORT {\r\n\t\tDWORD                     dwOffset { };     //File's raw offset of this Import descriptor.\r\n\t\tIMAGE_IMPORT_DESCRIPTOR   stImportDesc { }; //Standard Import descriptor.\r\n\t\tstd::string               strModuleName;    //Imported module name.\r\n\t\tstd::vector<PEIMPORTFUNC> vecImportFunc;    //Array of imported functions.\r\n\t};\r\n\tusing PEIMPORT_VEC = std::vector<PEIMPORT>;\r\n\r\n\t/**************************************Resources by Levels*******************************************\r\n\t* There are 3 levels of resources: 1. Type 2. Name 3. Language.\t\t\t\t\t\t\t\t\t\t*\r\n\t* https://docs.microsoft.com/en-us/windows/desktop/Debug/pe-format#the-rsrc-section\t\t\t\t\t*\r\n\t* Highest (root) resource structure is PERESROOT. It's a struct\tthat includes:                      *\r\n\t* an IMAGE_RESOURCE_DIRECTORY of root resource directory itself and vector<PERESROOTDATA>,          *\r\n\t* that contains structs of all IMAGE_RESOURCE_DIRECTORY_ENTRY structures of the root resource       *\r\n\t* directory. It also includes: wstring(Resource name), IMAGE_RESOURCE_DATA_ENTRY,                   *\r\n\t* vector<byte> (RAW resource data), and PERESLVL2 that is a struct of the next, second, resource    *\r\n\t* level, that replicates struct of root resource level.\tPERESLVL2 includes IMAGE_RESOURCE_DIRECTORY *\r\n\t* of the second resource level, and vector<PERESLVL2DATA> that includes PERESLVL3 that is a struct  *\r\n\t* of the last, third, level of resources. Like previous two, this last level's struct consist of    *\r\n\t* IMAGE_RESOURCE_DIRECTORY and vector<PERESLVL3DATA>, that is again a vector of structs of all      *\r\n\t* IMAGE_RESOURCE_DIRECTORY_ENTRY of the last, third, level of resources.                            *\r\n\t****************************************************************************************************/\r\n\r\n\t//Level 3/Lang (the lowest) resources.\r\n\tstruct PERESLVL3DATA {\r\n\t\tIMAGE_RESOURCE_DIRECTORY_ENTRY stResDirEntry { };  //Level 3 (Lang) standard IMAGE_RESOURCE_DIRECTORY_ENTRY struct.\r\n\t\tstd::wstring                   wstrResName;        //Level 3 (Lang) resource name.\r\n\t\tIMAGE_RESOURCE_DATA_ENTRY      stResDataEntry { }; //Level 3 (Lang) standard IMAGE_RESOURCE_DATA_ENTRY struct.\r\n\t\tstd::vector<std::byte>         vecRawResData;      //Level 3 (Lang) resource raw data.\r\n\t};\r\n\tusing PERESLANGDATA = PERESLVL3DATA;\r\n\r\n\tstruct PERESLVL3 {\r\n\t\tDWORD                      dwOffset { };   //File's raw offset of this level 3 IMAGE_RESOURCE_DIRECTORY descriptor.\r\n\t\tIMAGE_RESOURCE_DIRECTORY   stResDir { };   //Level 3 standard IMAGE_RESOURCE_DIRECTORY header.\r\n\t\tstd::vector<PERESLVL3DATA> vecResData;     //Array of level 3 resource entries.\r\n\t};\r\n\tusing PERESLANG = PERESLVL3;\r\n\r\n\t//Level 2/Name resources — Includes Lang resourses.\r\n\tstruct PERESLVL2DATA {\r\n\t\tIMAGE_RESOURCE_DIRECTORY_ENTRY stResDirEntry { };  //Level 2 (Name) standard IMAGE_RESOURCE_DIRECTORY_ENTRY struct.\r\n\t\tstd::wstring                   wstrResName;        //Level 2 (Name) resource name.\r\n\t\tIMAGE_RESOURCE_DATA_ENTRY      stResDataEntry { }; //Level 2 (Name) standard IMAGE_RESOURCE_DATA_ENTRY struct.\r\n\t\tstd::vector<std::byte>         vecRawResData;      //Level 2 (Name) resource raw data.\r\n\t\tPERESLVL3                      stResLvL3;          //Level 3 (Lang) resource struct.\r\n\t};\r\n\tusing PERESNAMEDATA = PERESLVL2DATA;\r\n\r\n\tstruct PERESLVL2 {\r\n\t\tDWORD                      dwOffset { };   //File's raw offset of this level 2 IMAGE_RESOURCE_DIRECTORY descriptor.\r\n\t\tIMAGE_RESOURCE_DIRECTORY   stResDir { };   //Level 2 standard IMAGE_RESOURCE_DIRECTORY header.\r\n\t\tstd::vector<PERESLVL2DATA> vecResData;     //Array of level 2 resource entries.\r\n\t};\r\n\tusing PERESNAME = PERESLVL2;\r\n\r\n\t//Level 1/Type resources — Includes Name Resources.\r\n\tstruct PERESROOTDATA {\r\n\t\tIMAGE_RESOURCE_DIRECTORY_ENTRY stResDirEntry { };  //Level root (Type) standard IMAGE_RESOURCE_DIRECTORY_ENTRY struct.\r\n\t\tstd::wstring                   wstrResName;\t       //Level root (Type) resource name.\r\n\t\tIMAGE_RESOURCE_DATA_ENTRY      stResDataEntry { }; //Level root (Type) standard IMAGE_RESOURCE_DATA_ENTRY struct.\r\n\t\tstd::vector<std::byte>         vecRawResData;      //Level root (Type) resource raw data.\r\n\t\tPERESLVL2                      stResLvL2;          //Level 2 (Name) resource struct.\r\n\t};\r\n\tusing PERESTYPEDATA = PERESROOTDATA;\r\n\r\n\tstruct PERESROOT {\r\n\t\tDWORD                      dwOffset { }; //File's raw offset of this level root IMAGE_RESOURCE_DIRECTORY descriptor.\r\n\t\tIMAGE_RESOURCE_DIRECTORY   stResDir { }; //Level root standard IMAGE_RESOURCE_DIRECTORY header.\r\n\t\tstd::vector<PERESROOTDATA> vecResData;   //Array of level root resource entries.\r\n\t};\r\n\tusing PERESTYPE = PERESROOT;\r\n\r\n\t//Flattened resources.\r\n\tstruct PERESFLAT {\r\n\t\tstd::span<const std::byte> spnData;     //Resource data.\r\n\t\tstd::wstring_view          wsvTypeStr;  //Resource Type name.\r\n\t\tstd::wstring_view          wsvNameStr;  //Resource Name name (resource itself name).\r\n\t\tstd::wstring_view          wsvLangStr;  //Resource Lang name.\r\n\t\tWORD                       wTypeID { }; //Resource Type ID (RT_CURSOR, RT_BITMAP, etc...).\r\n\t\tWORD                       wNameID { }; //Resource Name ID (resource itself ID).\r\n\t\tWORD                       wLangID { }; //Resource Lang ID.\r\n\t};\r\n\tusing PERESFLAT_VEC = std::vector<PERESFLAT>;\r\n\tconst std::unordered_map<WORD, std::wstring_view> MapResID {\r\n\t\t{ static_cast<WORD>(1), L\"RT_CURSOR\" },\r\n\t\t{ static_cast<WORD>(2), L\"RT_BITMAP\" },\r\n\t\t{ static_cast<WORD>(3), L\"RT_ICON\" },\r\n\t\t{ static_cast<WORD>(4), L\"RT_MENU\" },\r\n\t\t{ static_cast<WORD>(5), L\"RT_DIALOG\" },\r\n\t\t{ static_cast<WORD>(6), L\"RT_STRING\" },\r\n\t\t{ static_cast<WORD>(7), L\"RT_FONTDIR\" },\r\n\t\t{ static_cast<WORD>(8), L\"RT_FONT\" },\r\n\t\t{ static_cast<WORD>(9), L\"RT_ACCELERATOR\" },\r\n\t\t{ static_cast<WORD>(10), L\"RT_RCDATA\" },\r\n\t\t{ static_cast<WORD>(11), L\"RT_MESSAGETABLE\" },\r\n\t\t{ static_cast<WORD>(12), L\"RT_GROUP_CURSOR\" },\r\n\t\t{ static_cast<WORD>(14), L\"RT_GROUP_ICON\" },\r\n\t\t{ static_cast<WORD>(16), L\"RT_VERSION\" },\r\n\t\t{ static_cast<WORD>(17), L\"RT_DLGINCLUDE\" },\r\n\t\t{ static_cast<WORD>(19), L\"RT_PLUGPLAY\" },\r\n\t\t{ static_cast<WORD>(20), L\"RT_VXD\" },\r\n\t\t{ static_cast<WORD>(21), L\"RT_ANICURSOR\" },\r\n\t\t{ static_cast<WORD>(22), L\"RT_ANIICON\" },\r\n\t\t{ static_cast<WORD>(23), L\"RT_HTML\" },\r\n\t\t{ static_cast<WORD>(24), L\"RT_MANIFEST\" },\r\n\t\t{ static_cast<WORD>(28), L\"RT_RIBBON_XML\" },\r\n\t\t{ static_cast<WORD>(240), L\"RT_DLGINIT\" },\r\n\t\t{ static_cast<WORD>(241), L\"RT_TOOLBAR\" }\r\n\t};\r\n\t/*********************************Resources End*****************************************/\r\n\r\n\t//Exception table.\r\n\tstruct PEEXCEPTION {\r\n\t\tDWORD                         dwOffset { };           //File's raw offset of this exception's descriptor.\r\n\t\t_IMAGE_RUNTIME_FUNCTION_ENTRY stRuntimeFuncEntry { }; //Standard _IMAGE_RUNTIME_FUNCTION_ENTRY header.\r\n\t};\r\n\tusing PEEXCEPTION_VEC = std::vector<PEEXCEPTION>;\r\n\r\n\t//Security table.\r\n\tstruct PEWIN_CERTIFICATE { //Full replica of the WIN_CERTIFICATE struct from the <WinTrust.h>.\r\n\t\tDWORD dwLength { };\r\n\t\tWORD  wRevision { };\r\n\t\tWORD  wCertificateType { };\r\n\t\tBYTE  bCertificate[1] { };\r\n\t};\r\n\tstruct PESECURITY {\r\n\t\tDWORD             dwOffset { }; //File's raw offset of this security descriptor.\r\n\t\tPEWIN_CERTIFICATE stWinSert;    //Standard WIN_CERTIFICATE struct.\r\n\t};\r\n\tusing PESECURITY_VEC = std::vector<PESECURITY>;\r\n\tconst std::unordered_map<WORD, std::wstring_view> MapWinCertRevision { //WIN_CERTIFICATE::wRevision.\r\n\t\t{ static_cast<WORD>(0x0100), L\"WIN_CERT_REVISION_1_0\" },\r\n\t\t{ static_cast<WORD>(0x0200), L\"WIN_CERT_REVISION_2_0\" }\r\n\t};\r\n\tconst std::unordered_map<WORD, std::wstring_view> MapWinCertType { //WIN_CERTIFICATE::wCertificateType.\r\n\t\t{ static_cast<WORD>(0x0001), L\"WIN_CERT_TYPE_X509\" },\r\n\t\t{ static_cast<WORD>(0x0002), L\"WIN_CERT_TYPE_PKCS_SIGNED_DATA\" },\r\n\t\t{ static_cast<WORD>(0x0003), L\"WIN_CERT_TYPE_RESERVED_1\" },\r\n\t\t{ static_cast<WORD>(0x0004), L\"WIN_CERT_TYPE_TS_STACK_SIGNED\" }\r\n\t};\r\n\r\n\t//Relocation table.\r\n\tstruct PERELOCDATA {\r\n\t\tDWORD dwOffset { };     //File's raw offset of this Relocation data descriptor.\r\n\t\tWORD  wRelocType { };   //Relocation type.\r\n\t\tWORD  wRelocOffset { }; //Relocation offset (Offset the relocation must be applied to.)\r\n\t};\r\n\tconst std::unordered_map<WORD, std::wstring_view> MapRelocType { //PERELOCDATA::wRelocType.\r\n\t\t{ static_cast<WORD>(0), L\"IMAGE_REL_BASED_ABSOLUTE\" },\r\n\t\t{ static_cast<WORD>(1), L\"IMAGE_REL_BASED_HIGH\" },\r\n\t\t{ static_cast<WORD>(2), L\"IMAGE_REL_BASED_LOW\" },\r\n\t\t{ static_cast<WORD>(3), L\"IMAGE_REL_BASED_HIGHLOW\" },\r\n\t\t{ static_cast<WORD>(4), L\"IMAGE_REL_BASED_HIGHADJ\" },\r\n\t\t{ static_cast<WORD>(5), L\"IMAGE_REL_BASED_MACHINE_SPECIFIC_5\" },\r\n\t\t{ static_cast<WORD>(6), L\"IMAGE_REL_BASED_RESERVED\" },\r\n\t\t{ static_cast<WORD>(7), L\"IMAGE_REL_BASED_MACHINE_SPECIFIC_7\" },\r\n\t\t{ static_cast<WORD>(8), L\"IMAGE_REL_BASED_MACHINE_SPECIFIC_8\" },\r\n\t\t{ static_cast<WORD>(9), L\"IMAGE_REL_BASED_MACHINE_SPECIFIC_9\" },\r\n\t\t{ static_cast<WORD>(10), L\"IMAGE_REL_BASED_DIR64\" }\r\n\t};\r\n\tstruct PERELOC {\r\n\t\tDWORD                    dwOffset { };    //File's raw offset of this Relocation descriptor.\r\n\t\tIMAGE_BASE_RELOCATION    stBaseReloc { }; //Standard IMAGE_BASE_RELOCATION header.\r\n\t\tstd::vector<PERELOCDATA> vecRelocData;    //Array of the Relocation data struct.\r\n\t};\r\n\tusing PERELOC_VEC = std::vector<PERELOC>;\r\n\r\n\r\n\t//Debug table.\r\n\tstruct PEDEBUGDBGHDR {\r\n\t\t//dwHdr[6] is an array of the first six DWORDs of IMAGE_DEBUG_DIRECTORY::PointerToRawData data (Debug info header).\r\n\t\t//Their meaning varies depending on dwHdr[0] (Signature) value.\r\n\t\t//If dwHdr[0] == 0x53445352 (Ascii \"RSDS\") it's PDB 7.0 file:\r\n\t\t// Then dwHdr[1]-dwHdr[4] is GUID (*((GUID*)&dwHdr[1])). dwHdr[5] is Counter/Age.\r\n\t\t//If dwHdr[0] == 0x3031424E (Ascii \"NB10\") it's PDB 2.0 file:\r\n\t\t// Then dwHdr[1] is Offset. dwHdr[2] is Time/Signature. dwHdr[3] is Counter/Age.\r\n\t\tDWORD       dwHdr[6] { };\r\n\t\tstd::string strPDBName;   //PDB file name/path.\r\n\t};\r\n\tstruct PEDEBUG {\r\n\t\tDWORD                 dwOffset { };   //File's raw offset of this Debug descriptor.\r\n\t\tIMAGE_DEBUG_DIRECTORY stDebugDir { }; //Standard IMAGE_DEBUG_DIRECTORY header.\r\n\t\tPEDEBUGDBGHDR         stDebugHdrInfo; //Debug info header.\r\n\t};\r\n\tusing PEDEBUG_VEC = std::vector<PEDEBUG>;\r\n\tconst std::unordered_map<DWORD, std::wstring_view> MapDbgType { //IMAGE_DEBUG_DIRECTORY::Type.\r\n\t\t{ 0UL, L\"IMAGE_DEBUG_TYPE_UNKNOWN\" },\r\n\t\t{ 1UL, L\"IMAGE_DEBUG_TYPE_COFF\" },\r\n\t\t{ 2UL, L\"IMAGE_DEBUG_TYPE_CODEVIEW\" },\r\n\t\t{ 3UL, L\"IMAGE_DEBUG_TYPE_FPO\" },\r\n\t\t{ 4UL, L\"IMAGE_DEBUG_TYPE_MISC\" },\r\n\t\t{ 5UL, L\"IMAGE_DEBUG_TYPE_EXCEPTION\" },\r\n\t\t{ 6UL, L\"IMAGE_DEBUG_TYPE_FIXUP\" },\r\n\t\t{ 7UL, L\"IMAGE_DEBUG_TYPE_OMAP_TO_SRC\" },\r\n\t\t{ 8UL, L\"IMAGE_DEBUG_TYPE_OMAP_FROM_SRC\" },\r\n\t\t{ 9UL, L\"IMAGE_DEBUG_TYPE_BORLAND\" },\r\n\t\t{ 10UL, L\"IMAGE_DEBUG_TYPE_RESERVED10\" },\r\n\t\t{ 11UL, L\"IMAGE_DEBUG_TYPE_CLSID\" },\r\n\t\t{ 12UL, L\"IMAGE_DEBUG_TYPE_VC_FEATURE\" },\r\n\t\t{ 13UL, L\"IMAGE_DEBUG_TYPE_POGO\" },\r\n\t\t{ 14UL, L\"IMAGE_DEBUG_TYPE_ILTCG\" },\r\n\t\t{ 15UL, L\"IMAGE_DEBUG_TYPE_MPX\" },\r\n\t\t{ 16UL, L\"IMAGE_DEBUG_TYPE_REPRO\" }\r\n\t};\r\n\r\n\t//TLS table.\r\n\tstruct PETLS {\r\n\t\tDWORD              dwOffset { };      //File's raw offset of the TLS header descriptor.\r\n\t\tunion UNPETLS {\r\n\t\t\tIMAGE_TLS_DIRECTORY32 stTLSDir32; //x86 standard TLS header.\r\n\t\t\tIMAGE_TLS_DIRECTORY64 stTLSDir64; //x64 TLS header.\r\n\t\t} unTLS { };\r\n\t\tstd::vector<DWORD> vecTLSCallbacks;   //Array of the TLS callbacks.\r\n\t};\r\n\tconst std::unordered_map<DWORD, std::wstring_view> MapTLSCharact { //IMAGE_TLS_DIRECTORY::Characteristics.\r\n\t\t{ 0x00100000UL, L\"IMAGE_SCN_ALIGN_1BYTES\" },\r\n\t\t{ 0x00200000UL, L\"IMAGE_SCN_ALIGN_2BYTES\" },\r\n\t\t{ 0x00300000UL, L\"IMAGE_SCN_ALIGN_4BYTES\" },\r\n\t\t{ 0x00400000UL, L\"IMAGE_SCN_ALIGN_8BYTES\" },\r\n\t\t{ 0x00500000UL, L\"IMAGE_SCN_ALIGN_16BYTES\" },\r\n\t\t{ 0x00600000UL, L\"IMAGE_SCN_ALIGN_32BYTES\" },\r\n\t\t{ 0x00700000UL, L\"IMAGE_SCN_ALIGN_64BYTES\" },\r\n\t\t{ 0x00800000UL, L\"IMAGE_SCN_ALIGN_128BYTES\" },\r\n\t\t{ 0x00900000UL, L\"IMAGE_SCN_ALIGN_256BYTES\" },\r\n\t\t{ 0x00A00000UL, L\"IMAGE_SCN_ALIGN_512BYTES\" },\r\n\t\t{ 0x00B00000UL, L\"IMAGE_SCN_ALIGN_1024BYTES\" },\r\n\t\t{ 0x00C00000UL, L\"IMAGE_SCN_ALIGN_2048BYTES\" },\r\n\t\t{ 0x00D00000UL, L\"IMAGE_SCN_ALIGN_4096BYTES\" },\r\n\t\t{ 0x00E00000UL, L\"IMAGE_SCN_ALIGN_8192BYTES\" },\r\n\t\t{ 0x00F00000UL, L\"IMAGE_SCN_ALIGN_MASK\" }\r\n\t};\r\n\r\n\t//LoadConfigDirectory.\r\n\tstruct PELOADCONFIG {\r\n\t\tDWORD dwOffset { };                        //File's raw offset of the LCD descriptor.\r\n\t\tunion UNPELOADCONFIG {\r\n\t\t\tIMAGE_LOAD_CONFIG_DIRECTORY32 stLCD32; //x86 LCD descriptor.\r\n\t\t\tIMAGE_LOAD_CONFIG_DIRECTORY64 stLCD64; //x64 LCD descriptor.\r\n\t\t} unLCD { };\r\n\t};\r\n\tconst std::unordered_map<DWORD, std::wstring_view> MapLCDGuardFlags { //IMAGE_LOAD_CONFIG_DIRECTORY::GuardFlags.\r\n\t\t{ 0x00000100UL, L\"IMAGE_GUARD_CF_INSTRUMENTED (Module performs control flow integrity checks using system-supplied support)\" },\r\n\t\t{ 0x00000200UL, L\"IMAGE_GUARD_CFW_INSTRUMENTED (Module performs control flow and write integrity checks)\" },\r\n\t\t{ 0x00000400UL, L\"IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT (Module contains valid control flow target metadata)\" },\r\n\t\t{ 0x00000800UL, L\"IMAGE_GUARD_SECURITY_COOKIE_UNUSED (Module does not make use of the /GS security cookie)\" },\r\n\t\t{ 0x00001000UL, L\"IMAGE_GUARD_PROTECT_DELAYLOAD_IAT (Module supports read only delay load IAT)\" },\r\n\t\t{ 0x00002000UL, L\"IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION (Delayload import table in its own .didat section (with nothing else in it) that can be freely reprotected)\" },\r\n\t\t{ 0x00004000UL, L\"IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT (Module contains suppressed export information. This also infers that the address taken IAT table is also present in the load config.)\" },\r\n\t\t{ 0x00008000UL, L\"IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION (Module enables suppression of exports)\" },\r\n\t\t{ 0x00010000UL, L\"IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT (Module contains longjmp target information)\" },\r\n\t\t{ 0x00020000UL, L\"IMAGE_GUARD_RF_INSTRUMENTED (Module contains return flow instrumentation and metadata)\" },\r\n\t\t{ 0x00040000UL, L\"IMAGE_GUARD_RF_ENABLE (Module requests that the OS enable return flow protection)\" },\r\n\t\t{ 0x00080000UL, L\"IMAGE_GUARD_RF_STRICT (Module requests that the OS enable return flow protection in strict mode)\" },\r\n\t\t{ 0xF0000000UL, L\"IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK (Stride of Guard CF function table encoded in these bits (additional count of bytes per element))\" },\r\n\t\t{ 28UL, L\"IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT (Shift to right-justify Guard CF function table stride)\" }\r\n\t};\r\n\r\n\t//Bound import table.\r\n\tstruct PEBOUNDFORWARDER {\r\n\t\tDWORD                     dwOffset { };          //File's raw offset of this Bound Forwarder descriptor.\r\n\t\tIMAGE_BOUND_FORWARDER_REF stBoundForwarder { };  //Standard IMAGE_BOUND_FORWARDER_REF struct.\r\n\t\tstd::string               strBoundForwarderName; //Bound forwarder name.\r\n\t};\r\n\tstruct PEBOUNDIMPORT {\r\n\t\tDWORD                         dwOffset { };       //File's raw offset of this Bound Import descriptor.\r\n\t\tIMAGE_BOUND_IMPORT_DESCRIPTOR stBoundImpDesc { }; //Standard IMAGE_BOUND_IMPORT_DESCRIPTOR struct.\r\n\t\tstd::string                   strBoundName;       //Bound Import name.\r\n\t\tstd::vector<PEBOUNDFORWARDER> vecBoundForwarder;  //Array of the Bound Forwarder structs.\r\n\t};\r\n\tusing PEBOUNDIMPORT_VEC = std::vector<PEBOUNDIMPORT>;\r\n\r\n\t//Delay import table.\r\n\tstruct PEDELAYIMPORTFUNC {\r\n\t\tunion UNPEDELAYIMPORTTHUNK {\r\n\t\t\tstruct x32 {\r\n\t\t\t\tIMAGE_THUNK_DATA32 stImportAddressTable;      //x86 Import Address Table struct.\r\n\t\t\t\tIMAGE_THUNK_DATA32 stImportNameTable;         //x86 Import Name Table struct.\r\n\t\t\t\tIMAGE_THUNK_DATA32 stBoundImportAddressTable; //x86 Bound Import Address Table struct.\r\n\t\t\t\tIMAGE_THUNK_DATA32 stUnloadInformationTable;  //x86 Unload Information Table struct.\r\n\t\t\t} st32;\r\n\t\t\tstruct x64 {\r\n\t\t\t\tIMAGE_THUNK_DATA64 stImportAddressTable;      //x64 Import Address Table struct.\r\n\t\t\t\tIMAGE_THUNK_DATA64 stImportNameTable;         //x64 Import Name Table struct.\r\n\t\t\t\tIMAGE_THUNK_DATA64 stBoundImportAddressTable; //x64 Bound Import Address Table struct\r\n\t\t\t\tIMAGE_THUNK_DATA64 stUnloadInformationTable;  //x64 Unload Information Table struct.\r\n\t\t\t} st64;\r\n\t\t} unThunk;\r\n\t\tIMAGE_IMPORT_BY_NAME stImpByName { }; //Standard IMAGE_IMPORT_BY_NAME struct.\r\n\t\tstd::string          strFuncName;     //Function name.\r\n\t};\r\n\tstruct PEDELAYIMPORT {\r\n\t\tDWORD                          dwOffset { };       //File's raw offset of this Delay Import descriptor.\r\n\t\tIMAGE_DELAYLOAD_DESCRIPTOR     stDelayImpDesc { }; //Standard IMAGE_DELAYLOAD_DESCRIPTOR struct.\r\n\t\tstd::string                    strModuleName;      //Import module name.\r\n\t\tstd::vector<PEDELAYIMPORTFUNC> vecDelayImpFunc;    //Array of the Delay Import module functions.\r\n\t};\r\n\tusing PEDELAYIMPORT_VEC = std::vector<PEDELAYIMPORT>;\r\n\r\n\t//COM descriptor table.\r\n\tstruct PECOMDESCRIPTOR {\r\n\t\tDWORD              dwOffset { }; //File's raw offset of the IMAGE_COR20_HEADER descriptor.\r\n\t\tIMAGE_COR20_HEADER stCorHdr { }; //Standard IMAGE_COR20_HEADER struct.\r\n\t};\r\n\tconst std::unordered_map<DWORD, std::wstring_view> MapCOR20Flags { //IMAGE_COR20_HEADER::Flags.\r\n\t\t{ 1UL, L\"COMIMAGE_FLAGS_ILONLY\" },\r\n\t\t{ 2UL, L\"COMIMAGE_FLAGS_32BITREQUIRED\" },\r\n\t\t{ 4UL, L\"COMIMAGE_FLAGS_IL_LIBRARY\" },\r\n\t\t{ 8UL, L\"COMIMAGE_FLAGS_STRONGNAMESIGNED\" },\r\n\t\t{ 16UL, L\"COMIMAGE_FLAGS_NATIVE_ENTRYPOINT\" },\r\n\t\t{ 65536UL, L\"COMIMAGE_FLAGS_TRACKDEBUGDATA\" },\r\n\t\t{ 131072UL, L\"COMIMAGE_FLAGS_32BITPREFERRED\" }\r\n\t};\r\n\r\n\tenum class EFileType : std::uint8_t {\r\n\t\tUNKNOWN = 0, PE32, PE64, PEROM\r\n\t};\r\n\r\n\t//Return codes.\r\n\tconstexpr auto PEOK = 0x0;\r\n\tconstexpr auto ERR_FILE_OPEN = 0x01;\r\n\tconstexpr auto ERR_FILE_SIZESMALL = 0x02;\r\n\tconstexpr auto ERR_FILE_MAPPING = 0x03;\r\n\tconstexpr auto ERR_FILE_NODOSHDR = 0x04;\r\n\r\n\t//Helper methods.\r\n\r\n\t[[nodiscard]] constexpr auto GetFileType(const PENTHDR& stNTHdr) -> EFileType\r\n\t{\r\n\t\tconst auto& refNTHdr = stNTHdr.unHdr.stNTHdr32;\r\n\t\tif (refNTHdr.Signature != IMAGE_NT_SIGNATURE)\r\n\t\t\treturn EFileType::UNKNOWN;\r\n\r\n\t\tconst auto& refOptHdr = refNTHdr.OptionalHeader;\r\n\t\tswitch (refOptHdr.Magic) {\r\n\t\tcase IMAGE_NT_OPTIONAL_HDR32_MAGIC:\r\n\t\t\treturn EFileType::PE32;\r\n\t\tcase IMAGE_NT_OPTIONAL_HDR64_MAGIC:\r\n\t\t\treturn EFileType::PE64;\r\n\t\tcase IMAGE_ROM_OPTIONAL_HDR_MAGIC:\r\n\t\t\treturn EFileType::PEROM;\r\n\t\tdefault:\r\n\t\t\treturn EFileType::UNKNOWN;\r\n\t\t}\r\n\t}\r\n\r\n\t[[nodiscard]] constexpr auto GetImageBase(const PENTHDR& stNTHdr) -> ULONGLONG\r\n\t{\r\n\t\tswitch (GetFileType(stNTHdr)) {\r\n\t\tcase EFileType::PE32:\r\n\t\t\treturn stNTHdr.unHdr.stNTHdr32.OptionalHeader.ImageBase;\r\n\t\tcase EFileType::PE64:\r\n\t\t\treturn stNTHdr.unHdr.stNTHdr64.OptionalHeader.ImageBase;\r\n\t\tdefault:\r\n\t\t\treturn { };\r\n\t\t}\r\n\t}\r\n\r\n\t[[nodiscard]] constexpr auto GetOffsetFromRVA(ULONGLONG ullRVA, const PESECHDR_VEC& vecSecHdr) -> DWORD\r\n\t{\r\n\t\tfor (const auto& stSec : vecSecHdr) {\r\n\t\t\tif (const auto pSecHdr = &stSec.stSecHdr; (ullRVA >= pSecHdr->VirtualAddress) //Is RVA within this section?\r\n\t\t\t\t&& (ullRVA < (pSecHdr->VirtualAddress + pSecHdr->Misc.VirtualSize))) {\r\n\t\t\t\treturn static_cast<DWORD>(ullRVA) - pSecHdr->VirtualAddress + pSecHdr->PointerToRawData;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn { };\r\n\t}\r\n\r\n\t[[nodiscard]] constexpr auto FlatResources(const PERESROOT& stResRoot) -> PERESFLAT_VEC\r\n\t{\r\n\t\tstd::size_t sTotalRes { 0 }; //How many resources total?\r\n\t\tfor (const auto& iterRoot : stResRoot.vecResData) { //To reserve space in vector, count total amount of resources.\r\n\t\t\tif (iterRoot.stResDirEntry.DataIsDirectory) { //Level Root.\r\n\t\t\t\tfor (const auto& iterLvL2 : iterRoot.stResLvL2.vecResData) {\r\n\t\t\t\t\tif (iterLvL2.stResDirEntry.DataIsDirectory) { //Level 2 IMAGE_RESOURCE_DIRECTORY_ENTRY.\r\n\t\t\t\t\t\tsTotalRes += iterLvL2.stResLvL3.vecResData.size(); //Level 3.\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\t++sTotalRes;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\t++sTotalRes;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tstd::vector<PERESFLAT> vecData;\r\n\t\tvecData.reserve(sTotalRes);\r\n\t\tfor (const auto& iterRoot : stResRoot.vecResData) {\r\n\t\t\tPERESFLAT stRes { };\r\n\t\t\tconst auto pResDirEntryRoot = &iterRoot.stResDirEntry; //Level Root IMAGE_RESOURCE_DIRECTORY_ENTRY.\r\n\t\t\tif (pResDirEntryRoot->NameIsString) {\r\n\t\t\t\tstRes.wsvTypeStr = iterRoot.wstrResName;\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tstRes.wTypeID = pResDirEntryRoot->Id;\r\n\t\t\t}\r\n\r\n\t\t\tif (pResDirEntryRoot->DataIsDirectory) {\r\n\t\t\t\tfor (const auto& iterLvL2 : iterRoot.stResLvL2.vecResData) {\r\n\t\t\t\t\tconst auto pResDirEntry2 = &iterLvL2.stResDirEntry; //Level 2 IMAGE_RESOURCE_DIRECTORY_ENTRY.\r\n\t\t\t\t\tif (pResDirEntry2->NameIsString) {\r\n\t\t\t\t\t\tstRes.wsvNameStr = iterLvL2.wstrResName;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tstRes.wNameID = pResDirEntry2->Id;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (pResDirEntry2->DataIsDirectory) {\r\n\t\t\t\t\t\tfor (const auto& iterLvL3 : iterLvL2.stResLvL3.vecResData) {\r\n\t\t\t\t\t\t\tconst auto pResDirEntry3 = &iterLvL3.stResDirEntry; //Level 3 IMAGE_RESOURCE_DIRECTORY_ENTRY.\r\n\t\t\t\t\t\t\tif (pResDirEntry3->NameIsString) {\r\n\t\t\t\t\t\t\t\tstRes.wsvLangStr = iterLvL3.wstrResName;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\t\tstRes.wLangID = pResDirEntry3->Id;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tstRes.spnData = iterLvL3.vecRawResData;\r\n\t\t\t\t\t\t\tvecData.emplace_back(stRes);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tstRes.spnData = iterLvL2.vecRawResData;\r\n\t\t\t\t\t\tvecData.emplace_back(stRes);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tstRes.spnData = iterRoot.vecRawResData;\r\n\t\t\t\tvecData.emplace_back(stRes);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn vecData;\r\n\t}\r\n\r\n\tclass Clibpe final {\r\n\tpublic:\r\n\t\tClibpe() = default;\r\n\t\tClibpe(const wchar_t* pwszFile);\r\n\t\tClibpe(const Clibpe&) = delete;\r\n\t\tClibpe(Clibpe&&) = delete;\r\n\t\t~Clibpe();\r\n\t\tauto OpenFile(const wchar_t* pwszFile) -> int;\r\n\t\tauto OpenFile(std::span<const std::byte> spnData) -> int;\r\n\t\tvoid CloseFile();\r\n\t\t[[nodiscard]] auto GetDOSHeader()const -> std::optional<IMAGE_DOS_HEADER>;\r\n\t\t[[nodiscard]] auto GetRichHeader()const -> std::optional<PERICHHDR_VEC>;\r\n\t\t[[nodiscard]] auto GetNTHeader()const -> std::optional<PENTHDR>;\r\n\t\t[[nodiscard]] auto GetDataDirs()const -> std::optional<PEDATADIR_VEC>;\r\n\t\t[[nodiscard]] auto GetSecHeaders()const -> std::optional<PESECHDR_VEC>;\r\n\t\t[[nodiscard]] auto GetExport()const -> std::optional<PEEXPORT>;\r\n\t\t[[nodiscard]] auto GetImport()const -> std::optional<PEIMPORT_VEC>;\r\n\t\t[[nodiscard]] auto GetResources()const -> std::optional<PERESROOT>;\r\n\t\t[[nodiscard]] auto GetExceptions()const -> std::optional<PEEXCEPTION_VEC>;\r\n\t\t[[nodiscard]] auto GetSecurity()const -> std::optional<PESECURITY_VEC>;\r\n\t\t[[nodiscard]] auto GetRelocations()const -> std::optional<PERELOC_VEC>;\r\n\t\t[[nodiscard]] auto GetDebug()const -> std::optional<PEDEBUG_VEC>;\r\n\t\t[[nodiscard]] auto GetTLS()const -> std::optional<PETLS>;\r\n\t\t[[nodiscard]] auto GetLoadConfig()const -> std::optional<PELOADCONFIG>;\r\n\t\t[[nodiscard]] auto GetBoundImport()const -> std::optional<PEBOUNDIMPORT_VEC>;\r\n\t\t[[nodiscard]] auto GetDelayImport()const -> std::optional<PEDELAYIMPORT_VEC>;\r\n\t\t[[nodiscard]] auto GetCOMDescriptor()const -> std::optional<PECOMDESCRIPTOR>;\r\n\tprivate:\r\n\t\t[[nodiscard]] auto GetFileSize()const -> ULONGLONG;\r\n\t\t[[nodiscard]] auto GetBaseAddr()const -> DWORD_PTR;\r\n\t\t[[nodiscard]] auto GetDosPtr()const -> const IMAGE_DOS_HEADER*;\r\n\t\t[[nodiscard]] auto GetDirEntryRVA(DWORD dwEntry)const -> DWORD;\r\n\t\t[[nodiscard]] auto GetDirEntrySize(DWORD dwEntry)const -> DWORD;\r\n\t\t[[nodiscard]] auto GetImageBase()const -> ULONGLONG;\r\n\t\t[[nodiscard]] auto GetSecHdrFromShortName(LPCSTR lpszName)const -> PIMAGE_SECTION_HEADER;\r\n\t\t[[nodiscard]] auto GetSecHdrFromRVA(ULONGLONG ullRVA)const -> PIMAGE_SECTION_HEADER;\r\n\t\t[[nodiscard]] auto GetSecIdxFromRVA(ULONGLONG ullRVA)const -> std::optional<DWORD>;\r\n\t\ttemplate<typename T>\r\n\t\t[[nodiscard]] auto GetTData(ULONGLONG ullOffset)const -> T;\r\n\t\ttemplate<typename T>\r\n\t\t[[nodiscard]] auto IsPtrSafe(T tAddr, bool fCanReferenceBoundary = false)const -> bool;\r\n\t\t[[nodiscard]] auto PtrToOffset(LPCVOID lp)const -> DWORD;\r\n\t\t[[nodiscard]] auto RVAToPtr(ULONGLONG ullRVA)const -> LPVOID;\r\n\t\tbool ParseDOSHeader();\r\n\t\tbool ParseNTFileOptHeader();\r\n\tprivate:\r\n\t\tstd::span<const std::byte> m_spnData;  //File data.\r\n\t\tPIMAGE_NT_HEADERS32 m_pNTHeader32 { }; //NT header for x86.\r\n\t\tPIMAGE_NT_HEADERS64 m_pNTHeader64 { }; //NT header for x64.\r\n\t\tEFileType m_ePEType { }; //PE type: x64 or x86.\r\n\t\tHANDLE m_hFile { };      //Opened file handle.\r\n\t\tHANDLE m_hFileMap { };   //File-mapping handle.\r\n\t\tLPVOID m_pFileView { };  //File mapping-view handle.\r\n\t\tbool m_fOpened { };      //Is file successfully opened (by any OpenFile method)?\r\n\t\tbool m_fFileHandle { };  //Was file handle opened (by OpenFile(const wchar_t* pwszFile))?\r\n\t\tbool m_fHasNTHdr { };    //Does file have at least NT header.\r\n\t};\r\n\r\n\tClibpe::Clibpe(const wchar_t* pwszFile)\r\n\t{\r\n\t\tOpenFile(pwszFile);\r\n\t}\r\n\r\n\tClibpe::~Clibpe()\r\n\t{\r\n\t\tCloseFile();\r\n\t}\r\n\r\n\tauto Clibpe::OpenFile(const wchar_t* pwszFile)->int\r\n\t{\r\n\t\tassert(pwszFile != nullptr);\r\n\t\tif (m_fFileHandle) {\r\n\t\t\tCloseFile();\r\n\t\t}\r\n\r\n\t\tm_hFile = ::CreateFileW(pwszFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);\r\n\t\tassert(m_hFile != INVALID_HANDLE_VALUE);\r\n\t\tif (m_hFile == INVALID_HANDLE_VALUE)\r\n\t\t\treturn ERR_FILE_OPEN;\r\n\r\n\t\tLARGE_INTEGER stLI { };\r\n\t\tif (::GetFileSizeEx(m_hFile, &stLI) == FALSE || stLI.QuadPart < sizeof(IMAGE_DOS_HEADER)) {\r\n\t\t\t::CloseHandle(m_hFile);\r\n\t\t\treturn ERR_FILE_SIZESMALL;\r\n\t\t}\r\n\r\n\t\tm_hFileMap = ::CreateFileMappingW(m_hFile, nullptr, PAGE_READONLY, 0, 0, nullptr);\r\n\t\tassert(m_hFileMap != nullptr);\r\n\t\tif (m_hFileMap == nullptr) {\r\n\t\t\t::CloseHandle(m_hFile);\r\n\t\t\treturn ERR_FILE_MAPPING;\r\n\t\t}\r\n\r\n\t\tm_pFileView = ::MapViewOfFile(m_hFileMap, FILE_MAP_READ, 0, 0, 0);\r\n\t\tassert(m_pFileView != nullptr); //Not enough memory? File is too big?\r\n\t\tif (m_pFileView == nullptr) {\r\n\t\t\t::CloseHandle(m_hFileMap);\r\n\t\t\t::CloseHandle(m_hFile);\r\n\t\t\treturn ERR_FILE_MAPPING;\r\n\t\t}\r\n\r\n\t\tm_fFileHandle = true;\r\n\r\n\t\treturn OpenFile({ static_cast<std::byte*>(m_pFileView), static_cast<std::size_t>(stLI.QuadPart) });\r\n\t}\r\n\r\n\tauto Clibpe::OpenFile(std::span<const std::byte> spnData)->int\r\n\t{\r\n\t\tassert(!spnData.empty());\r\n\t\tif (m_fOpened) {\r\n\t\t\tCloseFile();\r\n\t\t}\r\n\r\n\t\tif (spnData.size() < sizeof(IMAGE_DOS_HEADER))\r\n\t\t\treturn ERR_FILE_SIZESMALL;\r\n\r\n\t\tm_spnData = spnData;\r\n\r\n\t\tif (!ParseDOSHeader()) {\r\n\t\t\tCloseFile();\r\n\t\t\treturn ERR_FILE_NODOSHDR;\r\n\t\t}\r\n\r\n\t\tm_fOpened = true;\r\n\t\tParseNTFileOptHeader();\r\n\r\n\t\treturn PEOK;\r\n\t}\r\n\r\n\tvoid Clibpe::CloseFile()\r\n\t{\r\n\t\tif (m_fFileHandle) {\r\n\t\t\t::UnmapViewOfFile(m_pFileView);\r\n\t\t\t::CloseHandle(m_hFileMap);\r\n\t\t\t::CloseHandle(m_hFile);\r\n\t\t}\r\n\t\tm_hFile = nullptr;\r\n\t\tm_hFileMap = nullptr;\r\n\t\tm_pFileView = nullptr;\r\n\t\tm_pNTHeader32 = nullptr;\r\n\t\tm_pNTHeader64 = nullptr;\r\n\t\tm_ePEType = { };\r\n\t\tm_spnData = { };\r\n\t\tm_fHasNTHdr = false;\r\n\t\tm_fFileHandle = false;\r\n\t\tm_fOpened = false;\r\n\t}\r\n\r\n\tauto Clibpe::GetDOSHeader()const->std::optional<IMAGE_DOS_HEADER>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\treturn *GetDosPtr();\r\n\t}\r\n\r\n\tauto Clibpe::GetRichHeader()const->std::optional<PERICHHDR_VEC>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\t//Undocumented, so called «Rich» header, dwells not in all PE files.\r\n\t\t//«Rich» stub starts at 0x80 offset, before pDosHdr->e_lfanew (PE header offset start).\r\n\t\t//If e_lfanew <= 0x80 — there is no «Rich» header.\r\n\r\n\t\tconst auto ullBaseAddr = GetBaseAddr();\r\n\t\tconst auto e_lfanew = GetDosPtr()->e_lfanew;\r\n\t\tif (e_lfanew <= 0x80 || !IsPtrSafe(ullBaseAddr + static_cast<DWORD_PTR>(e_lfanew)))\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tconst auto pRichStartVA = reinterpret_cast<PDWORD>(ullBaseAddr + 0x80);\r\n\t\tauto pRichIter = pRichStartVA;\r\n\t\tconst auto ulDWORDs = (e_lfanew - 0x80) / sizeof(DWORD); //Maximum amount of DWORDs to check.\r\n\r\n\t\tfor (auto i = 0UL; i < ulDWORDs; ++i, ++pRichIter) {\r\n\t\t\t//Check for the \"Rich\" (ASCII) sign, it's always at the end of the «Rich» header.\r\n\t\t\t//Then take a DWORD right after the \"Rich\" sign, it's a XOR mask.\r\n\t\t\t//Apply this mask to the first DWORD of the «Rich» header, it must be a \"DanS\" (ASCII) after XORing.\r\n\t\t\tif ((*pRichIter == 0x68636952/*\"Rich\"*/) && ((*pRichStartVA ^ *(pRichIter + 1)) == 0x536E6144/*\"DanS\"*/)\r\n\t\t\t\t&& (reinterpret_cast<DWORD_PTR>(pRichIter) >= ullBaseAddr + 0x90)) { //To avoid too small (bogus) «Rich» header.\r\n\t\t\t\t//An amount of all «Rich» DOUBLE_DWORD structs.\r\n\t\t\t\t//First 16 bytes in the «Rich» header are irrelevant, it's \"DanS\" itself and 12 zeroed bytes.\r\n\t\t\t\t//That's why we subtracting 0x90, to find out the amount of all «Rich» structures:\r\n\t\t\t\t//0x80 («Rich» start) + 16 (0xF) = 0x90.\r\n\r\n\t\t\t\tconst auto dwRichQWORDs = static_cast<DWORD>((reinterpret_cast<DWORD_PTR>(pRichIter) - ullBaseAddr) - 0x90) / 8;\r\n\t\t\t\tconst auto dwRichXORMask = *(pRichIter + 1); //XOR mask of «Rich» header.\r\n\t\t\t\tauto pRichData = reinterpret_cast<PDWORD>(ullBaseAddr + 0x90); //Beginning of the «Rich» DOUBLE_DWORD structs.\r\n\t\t\t\tPERICHHDR_VEC vecRichHdr;\r\n\t\t\t\tfor (auto j = 0UL; j < dwRichQWORDs; ++j) {\r\n\t\t\t\t\t//Pushing double DWORD of «Rich» structure, disassembling first DWORD by two WORDs.\r\n\t\t\t\t\tvecRichHdr.emplace_back(static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(pRichData) - ullBaseAddr),\r\n\t\t\t\t\t\tHIWORD(dwRichXORMask ^ *pRichData), LOWORD(dwRichXORMask ^ *pRichData), dwRichXORMask ^ *(pRichData + 1));\r\n\t\t\t\t\tpRichData += 2; //Jump to the next DOUBLE_DWORD.\r\n\t\t\t\t}\r\n\t\t\t\treturn vecRichHdr;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn std::nullopt;\r\n\t}\r\n\r\n\tauto Clibpe::GetNTHeader()const->std::optional<PENTHDR>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened || !m_fHasNTHdr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPENTHDR stNTHdr;\r\n\t\tswitch (m_ePEType) {\r\n\t\tcase EFileType::PE32:\r\n\t\t\tstNTHdr.unHdr.stNTHdr32 = *m_pNTHeader32;\r\n\t\t\tstNTHdr.dwOffset = PtrToOffset(m_pNTHeader32);\r\n\t\t\tbreak;\r\n\t\tcase EFileType::PE64:\r\n\t\t\tstNTHdr.unHdr.stNTHdr64 = *m_pNTHeader64;\r\n\t\t\tstNTHdr.dwOffset = PtrToOffset(m_pNTHeader64);\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\treturn std::nullopt;\r\n\t\t}\r\n\r\n\t\treturn stNTHdr;\r\n\t}\r\n\r\n\tauto Clibpe::GetDataDirs()const->std::optional<PEDATADIR_VEC>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened || !m_fHasNTHdr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPIMAGE_DATA_DIRECTORY pDataDir;\r\n\t\tDWORD dwRVAAndSizes;\r\n\r\n\t\tswitch (m_ePEType) {\r\n\t\tcase EFileType::PE32:\r\n\t\t\tpDataDir = reinterpret_cast<PIMAGE_DATA_DIRECTORY>(m_pNTHeader32->OptionalHeader.DataDirectory);\r\n\t\t\tdwRVAAndSizes = m_pNTHeader32->OptionalHeader.NumberOfRvaAndSizes;\r\n\t\t\tbreak;\r\n\t\tcase EFileType::PE64:\r\n\t\t\tpDataDir = reinterpret_cast<PIMAGE_DATA_DIRECTORY>(m_pNTHeader64->OptionalHeader.DataDirectory);\r\n\t\t\tdwRVAAndSizes = m_pNTHeader64->OptionalHeader.NumberOfRvaAndSizes;\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\treturn std::nullopt;\r\n\t\t}\r\n\r\n\t\tPEDATADIR_VEC vecDataDirs;\r\n\t\tfor (DWORD itDir = IMAGE_DIRECTORY_ENTRY_EXPORT; itDir < (dwRVAAndSizes > 15 ? 15 : dwRVAAndSizes); ++itDir, ++pDataDir) {\r\n\t\t\tDWORD dwSecIndex { };\r\n\t\t\tif (itDir != IMAGE_DIRECTORY_ENTRY_SECURITY) { //RVA of the IMAGE_DIRECTORY_ENTRY_SECURITY is a file RAW offset.\r\n\t\t\t\tdwSecIndex = GetSecIdxFromRVA(pDataDir->VirtualAddress).value_or(0xFFFFFFFFUL);\r\n\t\t\t}\r\n\r\n\t\t\tvecDataDirs.emplace_back(*pDataDir, dwSecIndex);\r\n\t\t}\r\n\r\n\t\treturn vecDataDirs.empty() ? std::nullopt : std::optional<PEDATADIR_VEC>(std::move(vecDataDirs));\r\n\t}\r\n\r\n\tauto Clibpe::GetSecHeaders()const->std::optional<PESECHDR_VEC>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened || !m_fHasNTHdr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPIMAGE_SECTION_HEADER pSecHdr;\r\n\t\tWORD wNumSections;\r\n\t\tDWORD dwSymbolTable;\r\n\t\tDWORD dwNumberOfSymbols;\r\n\r\n\t\tswitch (m_ePEType) {\r\n\t\tcase EFileType::PE32:\r\n\t\t\tpSecHdr = IMAGE_FIRST_SECTION(m_pNTHeader32);\r\n\t\t\twNumSections = m_pNTHeader32->FileHeader.NumberOfSections;\r\n\t\t\tdwSymbolTable = m_pNTHeader32->FileHeader.PointerToSymbolTable;\r\n\t\t\tdwNumberOfSymbols = m_pNTHeader32->FileHeader.NumberOfSymbols;\r\n\t\t\tbreak;\r\n\t\tcase EFileType::PE64:\r\n\t\t\tpSecHdr = IMAGE_FIRST_SECTION(m_pNTHeader64);\r\n\t\t\twNumSections = m_pNTHeader64->FileHeader.NumberOfSections;\r\n\t\t\tdwSymbolTable = m_pNTHeader64->FileHeader.PointerToSymbolTable;\r\n\t\t\tdwNumberOfSymbols = m_pNTHeader64->FileHeader.NumberOfSymbols;\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\treturn std::nullopt;\r\n\t\t}\r\n\r\n\t\tPESECHDR_VEC vecSecHeaders;\r\n\t\tvecSecHeaders.reserve(wNumSections);\r\n\r\n\t\tfor (auto itSec = 0UL; itSec < wNumSections; ++itSec, ++pSecHdr) {\r\n\t\t\tif (!IsPtrSafe(reinterpret_cast<DWORD_PTR>(pSecHdr) + sizeof(IMAGE_SECTION_HEADER)))\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tstd::string strSecRealName;\r\n\t\t\tif (pSecHdr->Name[0] == '/') {\r\n\t\t\t\t//Deprecated, but still used \"feature\" of a section name.\r\n\t\t\t\t//«An 8-byte, null-padded UTF-8 string. There is no terminating null character \r\n\t\t\t\t//if the string is exactly eight characters long.\r\n\t\t\t\t//For longer names, this member contains a forward slash (/) followed by an ASCII \r\n\t\t\t\t//representation of a decimal number that is an offset into the string table.»\r\n\t\t\t\t//https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_section_header\r\n\t\t\t\t//The String Table dwells right after the end of a Symbol Table.\r\n\t\t\t\t//Each symbol in the Symbol Table occupies exactly 18 bytes.\r\n\t\t\t\t//So the String Table's beginning can be calculated as:\r\n\t\t\t\t//FileHeader.PointerToSymbolTable + FileHeader.NumberOfSymbols * 18;\r\n\r\n\t\t\t\tconst auto pStart = reinterpret_cast<const char*>(&pSecHdr->Name[1]);\r\n\t\t\t\tchar* pEnd { };\r\n\t\t\t\terrno = 0;\r\n\t\t\t\tconst auto lOffset = ::strtol(pStart, &pEnd, 10);\r\n\t\t\t\tif (pEnd == pStart || errno == ERANGE) {\r\n\t\t\t\t\tcontinue; //Going next section entry.\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst auto lpszSecRealName = reinterpret_cast<const char*>(GetBaseAddr()\r\n\t\t\t\t\t+ static_cast<DWORD_PTR>(dwSymbolTable) + (static_cast<DWORD_PTR>(dwNumberOfSymbols) * 18)\r\n\t\t\t\t\t+ static_cast<DWORD_PTR>(lOffset));\r\n\t\t\t\tif (IsPtrSafe(lpszSecRealName)) {\r\n\t\t\t\t\tstrSecRealName = lpszSecRealName;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvecSecHeaders.emplace_back(PtrToOffset(pSecHdr), *pSecHdr, std::move(strSecRealName));\r\n\t\t}\r\n\r\n\t\treturn vecSecHeaders.empty() ? std::nullopt : std::optional<PESECHDR_VEC>(std::move(vecSecHeaders));\r\n\t}\r\n\r\n\tauto Clibpe::GetExport()const->std::optional<PEEXPORT>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tconst auto dwExportStartRVA = GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_EXPORT);\r\n\t\tconst auto dwExportEndRVA = dwExportStartRVA + GetDirEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);\r\n\t\tconst auto pExportDir = static_cast<PIMAGE_EXPORT_DIRECTORY>(RVAToPtr(dwExportStartRVA));\r\n\t\tif (pExportDir == nullptr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tconst auto pdwFuncRVA = static_cast<PDWORD>(RVAToPtr(pExportDir->AddressOfFunctions));\r\n\t\tif (pdwFuncRVA == nullptr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tconst auto pwFuncOrdinals = static_cast<PWORD>(RVAToPtr(pExportDir->AddressOfNameOrdinals));\r\n\t\tconst auto pdwFuncNames = static_cast<PDWORD>(RVAToPtr(pExportDir->AddressOfNames));\r\n\t\tstd::vector<PEEXPORTFUNC> vecFuncs;\r\n\r\n\t\ttry {\r\n\t\t\tfor (auto iterFuncRVA = 0UL; iterFuncRVA < pExportDir->NumberOfFunctions; ++iterFuncRVA) {\r\n\t\t\t\tif (!IsPtrSafe(pdwFuncRVA + iterFuncRVA)) //Checking pdwFuncRVA array.\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tconst auto dwFuncRVA = pdwFuncRVA[iterFuncRVA]; //Function RVA;\r\n\t\t\t\tif (dwFuncRVA == 0) //if RVA==0 —> going next entry.\r\n\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\tstd::string strFuncName;\r\n\t\t\t\tDWORD dwFuncNameRVA { };\r\n\t\t\t\tif (pdwFuncNames != nullptr && pwFuncOrdinals != nullptr) {\r\n\t\t\t\t\tfor (auto iterFuncNames = 0UL; iterFuncNames < pExportDir->NumberOfNames; ++iterFuncNames) {\r\n\t\t\t\t\t\tif (!IsPtrSafe(pwFuncOrdinals + iterFuncNames)) //Checking pwFuncOrdinals array.\r\n\t\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\t\t//Correspondence between ordinal-name-RVA:\r\n\t\t\t\t\t\t//ordinal = Biased_Ordinal - OrdinalBase;\r\n\t\t\t\t\t\t//FuncRVA = AddressOfFunctions[ordinal];\r\n\t\t\t\t\t\t//index = Search_In_AddressOfNameOrdinals(ordinal);\r\n\t\t\t\t\t\t//FuncNameRVA = AddressOfNames[index];\r\n\r\n\t\t\t\t\t\t//Comparing data in ordinals array (unbiased ordinals) with the index in the array of func RVA.\r\n\t\t\t\t\t\t//This index is in fact a true unbiased ordinal of exported function.\r\n\t\t\t\t\t\t//If found then iterFuncNames is an index in the array of func names.\r\n\t\t\t\t\t\tif (pwFuncOrdinals[iterFuncNames] == iterFuncRVA) {\r\n\t\t\t\t\t\t\tdwFuncNameRVA = pdwFuncNames[iterFuncNames]; //Export func name RVA.\r\n\t\t\t\t\t\t\tif (const auto pszFuncName = static_cast<LPCSTR>(RVAToPtr(dwFuncNameRVA)); //Checking func name for length correctness.\r\n\t\t\t\t\t\t\t\tpszFuncName != nullptr && (::StringCchLengthA(pszFuncName, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\t\t\t\t\tstrFuncName = pszFuncName;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tstd::string strForwarderName;\r\n\t\t\t\tif ((dwFuncRVA >= dwExportStartRVA) && (dwFuncRVA <= dwExportEndRVA)) {\r\n\t\t\t\t\tif (const auto pszForwarderName = static_cast<LPCSTR>(RVAToPtr(dwFuncRVA)); //Checking forwarder name for length correctness.\r\n\t\t\t\t\t\tpszForwarderName && (::StringCchLengthA(pszForwarderName, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\t\t\tstrForwarderName = pszForwarderName;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvecFuncs.emplace_back(dwFuncRVA, iterFuncRVA + pExportDir->Base /*Biased ordinal*/, dwFuncNameRVA,\r\n\t\t\t\t\tstd::move(strFuncName), std::move(strForwarderName));\r\n\t\t\t}\r\n\r\n\t\t\tstd::string strModuleName; //Actual IMG name.\r\n\t\t\tif (const auto szExportName = static_cast<LPCSTR>(RVAToPtr(pExportDir->Name)); //Checking Export name for length correctness.\r\n\t\t\t\tszExportName && (::StringCchLengthA(szExportName, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\tstrModuleName = szExportName;\r\n\t\t\t}\r\n\r\n\t\t\treturn std::make_optional<PEEXPORT>(PtrToOffset(pExportDir), *pExportDir, std::move(strModuleName), std::move(vecFuncs));\r\n\t\t}\r\n\t\tcatch (const std::exception& e) {\r\n\t\t\tvecFuncs.clear();\r\n\t\t\tstd::cerr << \"Exception in GetExport(): \" << e.what();\r\n\t\t}\r\n\r\n\t\treturn std::nullopt;\r\n\t}\r\n\r\n\tauto Clibpe::GetImport()const->std::optional<PEIMPORT_VEC>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tauto pImpDesc = static_cast<PIMAGE_IMPORT_DESCRIPTOR>(RVAToPtr(GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_IMPORT)));\r\n\t\tif (pImpDesc == nullptr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPEIMPORT_VEC vecImport;\r\n\t\ttry {\r\n\t\t\t//Counter for import modules. If it exceeds iMaxModules we stop parsing file, it's definitely bogus.\r\n\t\t\t//Very unlikely PE file has more than 1000 import modules.\r\n\t\t\tconstexpr auto iMaxModules = 1000;\r\n\t\t\tconstexpr auto iMaxFuncs = 5000;\r\n\t\t\tint iModulesCount = 0;\r\n\r\n\t\t\tif (m_ePEType == EFileType::PE32) {\r\n\t\t\t\twhile (pImpDesc->Name != 0) {\r\n\t\t\t\t\tauto pThunk32 = reinterpret_cast<PIMAGE_THUNK_DATA32>(static_cast<DWORD_PTR>(pImpDesc->OriginalFirstThunk));\r\n\t\t\t\t\tif (pThunk32 == nullptr) {\r\n\t\t\t\t\t\tpThunk32 = reinterpret_cast<PIMAGE_THUNK_DATA32>(static_cast<DWORD_PTR>(pImpDesc->FirstThunk));\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (pThunk32 != nullptr) {\r\n\t\t\t\t\t\tpThunk32 = static_cast<PIMAGE_THUNK_DATA32>(RVAToPtr(reinterpret_cast<DWORD_PTR>(pThunk32)));\r\n\t\t\t\t\t\tif (pThunk32 == nullptr)\r\n\t\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\t\tstd::vector<PEIMPORTFUNC> vecFunc;\r\n\t\t\t\t\t\t//Counter for import module funcs, if it exceeds iMaxFuncs we stop parsing import descr, it's definitely bogus.\r\n\t\t\t\t\t\tint iFuncsCount = 0;\r\n\r\n\t\t\t\t\t\twhile (pThunk32->u1.AddressOfData != 0) {\r\n\t\t\t\t\t\t\tPEIMPORTFUNC::UNPEIMPORTTHUNK unImpThunk32;\r\n\t\t\t\t\t\t\tunImpThunk32.stThunk32 = *pThunk32;\r\n\t\t\t\t\t\t\tIMAGE_IMPORT_BY_NAME stImpByName { };\r\n\t\t\t\t\t\t\tstd::string strFuncName;\r\n\t\t\t\t\t\t\tif (!(pThunk32->u1.Ordinal & IMAGE_ORDINAL_FLAG32)) {\r\n\t\t\t\t\t\t\t\tif (const auto pName = static_cast<PIMAGE_IMPORT_BY_NAME>(RVAToPtr(pThunk32->u1.AddressOfData));\r\n\t\t\t\t\t\t\t\t\tpName && (::StringCchLengthA(pName->Name, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\t\t\t\t\t\tstImpByName = *pName;\r\n\t\t\t\t\t\t\t\t\tstrFuncName = pName->Name;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tvecFunc.emplace_back(unImpThunk32, stImpByName, std::move(strFuncName));\r\n\r\n\t\t\t\t\t\t\tif (!IsPtrSafe(++pThunk32))\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\tif (++iFuncsCount == iMaxFuncs)\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tstd::string strDllName;\r\n\t\t\t\t\t\tif (const auto szName = static_cast<LPCSTR>(RVAToPtr(pImpDesc->Name));\r\n\t\t\t\t\t\t\tszName && (::StringCchLengthA(szName, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\t\t\t\tstrDllName = szName;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tvecImport.emplace_back(PtrToOffset(pImpDesc), *pImpDesc, std::move(strDllName), std::move(vecFunc));\r\n\r\n\t\t\t\t\t\tif (!IsPtrSafe(++pImpDesc))\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse { //No IMPORT pointers for that DLL?...\r\n\t\t\t\t\t\tif (!IsPtrSafe(++pImpDesc))  //Going next dll.\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (++iModulesCount == iMaxModules)\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse if (m_ePEType == EFileType::PE64) {\r\n\t\t\t\twhile (pImpDesc->Name != 0) {\r\n\t\t\t\t\tauto pThunk64 = reinterpret_cast<PIMAGE_THUNK_DATA64>(static_cast<DWORD_PTR>(pImpDesc->OriginalFirstThunk));\r\n\t\t\t\t\tif (pThunk64 == nullptr) {\r\n\t\t\t\t\t\tpThunk64 = reinterpret_cast<PIMAGE_THUNK_DATA64>(static_cast<DWORD_PTR>(pImpDesc->FirstThunk));\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (pThunk64 != nullptr) {\r\n\t\t\t\t\t\tpThunk64 = static_cast<PIMAGE_THUNK_DATA64>(RVAToPtr(reinterpret_cast<DWORD_PTR>(pThunk64)));\r\n\t\t\t\t\t\tif (pThunk64 == nullptr)\r\n\t\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\t\tstd::vector<PEIMPORTFUNC> vecFunc;\r\n\t\t\t\t\t\tint iFuncsCount = 0;\r\n\r\n\t\t\t\t\t\twhile (pThunk64->u1.AddressOfData != 0) {\r\n\t\t\t\t\t\t\tPEIMPORTFUNC::UNPEIMPORTTHUNK unImpThunk64;\r\n\t\t\t\t\t\t\tunImpThunk64.stThunk64 = *pThunk64;\r\n\t\t\t\t\t\t\tIMAGE_IMPORT_BY_NAME stImpByName { };\r\n\t\t\t\t\t\t\tstd::string strFuncName;\r\n\t\t\t\t\t\t\tif (!(pThunk64->u1.Ordinal & IMAGE_ORDINAL_FLAG64)) {\r\n\t\t\t\t\t\t\t\tif (const auto pName = static_cast<PIMAGE_IMPORT_BY_NAME>(RVAToPtr(pThunk64->u1.AddressOfData));\r\n\t\t\t\t\t\t\t\t\tpName && (::StringCchLengthA(pName->Name, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\t\t\t\t\t\tstImpByName = *pName;\r\n\t\t\t\t\t\t\t\t\tstrFuncName = pName->Name;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tvecFunc.emplace_back(unImpThunk64, stImpByName, std::move(strFuncName));\r\n\r\n\t\t\t\t\t\t\tif (!IsPtrSafe(++pThunk64))\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\tif (++iFuncsCount == iMaxFuncs)\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tstd::string strDllName;\r\n\t\t\t\t\t\tif (const auto szName = static_cast<LPCSTR>(RVAToPtr(pImpDesc->Name));\r\n\t\t\t\t\t\t\tszName && (::StringCchLengthA(szName, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\t\t\t\tstrDllName = szName;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tvecImport.emplace_back(PtrToOffset(pImpDesc), *pImpDesc, std::move(strDllName), std::move(vecFunc));\r\n\r\n\t\t\t\t\t\tif (!IsPtrSafe(++pImpDesc))\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tif (!IsPtrSafe(++pImpDesc))\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (++iModulesCount == iMaxModules)\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn vecImport.empty() ? std::nullopt : std::optional<PEIMPORT_VEC>(std::move(vecImport));\r\n\t\t}\r\n\t\tcatch (const std::exception& e) {\r\n\t\t\tvecImport.clear();\r\n\t\t\tstd::cerr << \"Exception in GetImport(): \" << e.what();\r\n\t\t}\r\n\r\n\t\treturn std::nullopt;\r\n\t}\r\n\r\n\tauto Clibpe::GetResources()const->std::optional<PERESROOT>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tconst auto pResDirRoot = static_cast<PIMAGE_RESOURCE_DIRECTORY>(RVAToPtr(GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_RESOURCE)));\r\n\t\tif (pResDirRoot == nullptr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tauto pResDirEntryRoot = reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(pResDirRoot + 1);\r\n\t\tif (!IsPtrSafe(pResDirEntryRoot))\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tstd::vector<PERESROOTDATA> vecResDataRoot;\r\n\t\ttry {\r\n\t\t\tconst DWORD dwNumOfEntriesRoot = pResDirRoot->NumberOfNamedEntries + pResDirRoot->NumberOfIdEntries;\r\n\t\t\tif (!IsPtrSafe(pResDirEntryRoot + dwNumOfEntriesRoot))\r\n\t\t\t\treturn std::nullopt;\r\n\r\n\t\t\tvecResDataRoot.reserve(dwNumOfEntriesRoot);\r\n\t\t\tfor (auto iLvLRoot = 0UL; iLvLRoot < dwNumOfEntriesRoot; ++iLvLRoot) {\r\n\t\t\t\tPIMAGE_RESOURCE_DATA_ENTRY pResDataEntryRoot { };\r\n\t\t\t\tstd::wstring wstrResNameRoot;\r\n\t\t\t\tstd::vector<std::byte> vecRawResDataRoot;\r\n\t\t\t\tPERESLVL2 stResLvL2 { };\r\n\r\n\t\t\t\tif (pResDirEntryRoot->NameIsString) { //Name of Resource Type (ICON, BITMAP, MENU, etc...).\r\n\t\t\t\t\tif (ut::IsSumOverflow(reinterpret_cast<DWORD_PTR>(pResDirRoot), static_cast<DWORD_PTR>(pResDirEntryRoot->NameOffset)))\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tif (const auto pResDirStr = reinterpret_cast<PIMAGE_RESOURCE_DIR_STRING_U>(reinterpret_cast<DWORD_PTR>(pResDirRoot)\r\n\t\t\t\t\t\t+ static_cast<DWORD_PTR>(pResDirEntryRoot->NameOffset)); IsPtrSafe(pResDirStr)) {\r\n\t\t\t\t\t\t//Copy not more then MAX_PATH chars into wstrResNameRoot, avoiding overflow.\r\n\t\t\t\t\t\twstrResNameRoot.assign(pResDirStr->NameString, pResDirStr->Length < MAX_PATH ? pResDirStr->Length : MAX_PATH);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (pResDirEntryRoot->DataIsDirectory) {\r\n\t\t\t\t\tconst auto pResDirLvL2 = reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY>(reinterpret_cast<DWORD_PTR>(pResDirRoot)\r\n\t\t\t\t\t\t+ static_cast<DWORD_PTR>(pResDirEntryRoot->OffsetToDirectory));\r\n\t\t\t\t\tif (!IsPtrSafe(pResDirLvL2))\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tif (pResDirLvL2 == pResDirRoot) { //Resource loop hack.\r\n\t\t\t\t\t\tstResLvL2 = { .dwOffset { PtrToOffset(pResDirLvL2) }, .stResDir { *pResDirLvL2 } };\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tauto pResDirEntryLvL2 = reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(pResDirLvL2 + 1);\r\n\t\t\t\t\t\tconst DWORD dwNumOfEntriesLvL2 = pResDirLvL2->NumberOfNamedEntries + pResDirLvL2->NumberOfIdEntries;\r\n\t\t\t\t\t\tif (!IsPtrSafe(pResDirEntryLvL2 + dwNumOfEntriesLvL2))\r\n\t\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\t\tstd::vector<PERESLVL2DATA> vecResDataLvL2;\r\n\t\t\t\t\t\tvecResDataLvL2.reserve(dwNumOfEntriesLvL2);\r\n\t\t\t\t\t\tfor (auto iLvL2 = 0UL; iLvL2 < dwNumOfEntriesLvL2; ++iLvL2) {\r\n\t\t\t\t\t\t\tPIMAGE_RESOURCE_DATA_ENTRY pResDataEntryLvL2 { };\r\n\t\t\t\t\t\t\tstd::wstring wstrResNameLvL2;\r\n\t\t\t\t\t\t\tstd::vector<std::byte> vecRawResDataLvL2;\r\n\t\t\t\t\t\t\tPERESLVL3 stResLvL3 { };\r\n\r\n\t\t\t\t\t\t\tif (pResDirEntryLvL2->NameIsString) { //Name of resource itself if not presented by ID (\"AFX_MY_SUPER_DIALOG\"...).\r\n\t\t\t\t\t\t\t\tif (ut::IsSumOverflow(reinterpret_cast<DWORD_PTR>(pResDirRoot), static_cast<DWORD_PTR>(pResDirEntryLvL2->NameOffset)))\r\n\t\t\t\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\t\t\t\tif (const auto pResDirStr2 = reinterpret_cast<PIMAGE_RESOURCE_DIR_STRING_U>(reinterpret_cast<DWORD_PTR>(pResDirRoot)\r\n\t\t\t\t\t\t\t\t\t+ static_cast<DWORD_PTR>(pResDirEntryLvL2->NameOffset)); IsPtrSafe(pResDirStr2)) {\r\n\t\t\t\t\t\t\t\t\t//Copy not more then MAX_PATH chars into wstrResNameLvL2, avoiding overflow.\r\n\t\t\t\t\t\t\t\t\twstrResNameLvL2.assign(pResDirStr2->NameString, pResDirStr2->Length < MAX_PATH ? pResDirStr2->Length : MAX_PATH);\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (pResDirEntryLvL2->DataIsDirectory) {\r\n\t\t\t\t\t\t\t\tconst auto pResDirLvL3 = reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY>(reinterpret_cast<DWORD_PTR>(pResDirRoot)\r\n\t\t\t\t\t\t\t\t\t+ static_cast<DWORD_PTR>(pResDirEntryLvL2->OffsetToDirectory));\r\n\t\t\t\t\t\t\t\tif (!IsPtrSafe(pResDirLvL3))\r\n\t\t\t\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\t\t\t\tif (pResDirLvL3 == pResDirLvL2 || pResDirLvL3 == pResDirRoot) {\r\n\t\t\t\t\t\t\t\t\tstResLvL3 = { .dwOffset { PtrToOffset(pResDirLvL3) }, .stResDir { *pResDirLvL3 } };\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\t\t\tauto pResDirEntryLvL3 = reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(pResDirLvL3 + 1);\r\n\t\t\t\t\t\t\t\t\tconst DWORD dwNumOfEntriesLvL3 = pResDirLvL3->NumberOfNamedEntries + pResDirLvL3->NumberOfIdEntries;\r\n\t\t\t\t\t\t\t\t\tif (!IsPtrSafe(pResDirEntryLvL3 + dwNumOfEntriesLvL3))\r\n\t\t\t\t\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\t\t\t\t\tstd::vector<PERESLVL3DATA> vecResDataLvL3;\r\n\t\t\t\t\t\t\t\t\tvecResDataLvL3.reserve(dwNumOfEntriesLvL3);\r\n\t\t\t\t\t\t\t\t\tfor (auto iLvL3 = 0UL; iLvL3 < dwNumOfEntriesLvL3; ++iLvL3) {\r\n\t\t\t\t\t\t\t\t\t\tstd::wstring wstrResNameLvL3;\r\n\t\t\t\t\t\t\t\t\t\tstd::vector<std::byte> vecRawResDataLvL3;\r\n\r\n\t\t\t\t\t\t\t\t\t\tif (pResDirEntryLvL3->NameIsString) {\r\n\t\t\t\t\t\t\t\t\t\t\tif (ut::IsSumOverflow(reinterpret_cast<DWORD_PTR>(pResDirRoot), static_cast<DWORD_PTR>(pResDirEntryLvL3->NameOffset)))\r\n\t\t\t\t\t\t\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\t\t\t\t\t\t\tif (const auto pResDirStr3 = reinterpret_cast<PIMAGE_RESOURCE_DIR_STRING_U>(reinterpret_cast<DWORD_PTR>(pResDirRoot)\r\n\t\t\t\t\t\t\t\t\t\t\t\t+ static_cast<DWORD_PTR>(pResDirEntryLvL3->NameOffset)); IsPtrSafe(pResDirStr3)) {\r\n\t\t\t\t\t\t\t\t\t\t\t\t//Copy not more then MAX_PATH chars into wstrResNameLvL3, avoiding overflow.\r\n\t\t\t\t\t\t\t\t\t\t\t\twstrResNameLvL3.assign(pResDirStr3->NameString, pResDirStr3->Length < MAX_PATH ? pResDirStr3->Length : MAX_PATH);\r\n\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t\t\tconst auto pResDataEntryLvL3 = reinterpret_cast<PIMAGE_RESOURCE_DATA_ENTRY>(reinterpret_cast<DWORD_PTR>(pResDirRoot)\r\n\t\t\t\t\t\t\t\t\t\t\t+ static_cast<DWORD_PTR>(pResDirEntryLvL3->OffsetToData));\r\n\t\t\t\t\t\t\t\t\t\tif (IsPtrSafe(pResDataEntryLvL3)) {\t//Resource LvL 3 RAW Data.\r\n\t\t\t\t\t\t\t\t\t\t\t//IMAGE_RESOURCE_DATA_ENTRY::OffsetToData is actually a general RVA,\r\n\t\t\t\t\t\t\t\t\t\t\t//not an offset from root IMAGE_RESOURCE_DIRECTORY, like IMAGE_RESOURCE_DIRECTORY_ENTRY::OffsetToData.\r\n\r\n\t\t\t\t\t\t\t\t\t\t\t//Checking RAW Resource data pointer out of bounds.\r\n\t\t\t\t\t\t\t\t\t\t\tif (const auto pThirdResRawDataBegin = static_cast<std::byte*>(RVAToPtr(pResDataEntryLvL3->OffsetToData));\r\n\t\t\t\t\t\t\t\t\t\t\t\tpThirdResRawDataBegin && IsPtrSafe(reinterpret_cast<DWORD_PTR>(pThirdResRawDataBegin)\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t+ static_cast<DWORD_PTR>(pResDataEntryLvL3->Size), true)) {\r\n\t\t\t\t\t\t\t\t\t\t\t\tvecRawResDataLvL3.assign(pThirdResRawDataBegin, pThirdResRawDataBegin + pResDataEntryLvL3->Size);\r\n\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t\t\tvecResDataLvL3.emplace_back(*pResDirEntryLvL3, std::move(wstrResNameLvL3),\r\n\t\t\t\t\t\t\t\t\t\t\tIsPtrSafe(pResDataEntryLvL3) ? *pResDataEntryLvL3 : IMAGE_RESOURCE_DATA_ENTRY { }, std::move(vecRawResDataLvL3));\r\n\r\n\t\t\t\t\t\t\t\t\t\tif (!IsPtrSafe(++pResDirEntryLvL3))\r\n\t\t\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\tstResLvL3 = { .dwOffset { PtrToOffset(pResDirLvL3) }, .stResDir { *pResDirLvL3 },\r\n\t\t\t\t\t\t\t\t\t\t.vecResData { std::move(vecResDataLvL3) } };\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse { //Resource LvL2 RAW Data.\r\n\t\t\t\t\t\t\t\tpResDataEntryLvL2 = reinterpret_cast<PIMAGE_RESOURCE_DATA_ENTRY>(reinterpret_cast<DWORD_PTR>(pResDirRoot)\r\n\t\t\t\t\t\t\t\t\t+ static_cast<DWORD_PTR>(pResDirEntryLvL2->OffsetToData));\r\n\t\t\t\t\t\t\t\tif (IsPtrSafe(pResDataEntryLvL2)) {\r\n\t\t\t\t\t\t\t\t\t//Checking RAW Resource data pointer out of bounds.\r\n\t\t\t\t\t\t\t\t\tif (const auto pSecondResRawDataBegin = static_cast<std::byte*>(RVAToPtr(pResDataEntryLvL2->OffsetToData));\r\n\t\t\t\t\t\t\t\t\t\tpSecondResRawDataBegin && IsPtrSafe(reinterpret_cast<DWORD_PTR>(pSecondResRawDataBegin)\r\n\t\t\t\t\t\t\t\t\t\t\t+ static_cast<DWORD_PTR>(pResDataEntryLvL2->Size), true)) {\r\n\t\t\t\t\t\t\t\t\t\tvecRawResDataLvL2.assign(pSecondResRawDataBegin, pSecondResRawDataBegin + pResDataEntryLvL2->Size);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tvecResDataLvL2.emplace_back(*pResDirEntryLvL2, std::move(wstrResNameLvL2),\r\n\t\t\t\t\t\t\t\tIsPtrSafe(pResDataEntryLvL2) ? *pResDataEntryLvL2 : IMAGE_RESOURCE_DATA_ENTRY { }, std::move(vecRawResDataLvL2), stResLvL3);\r\n\r\n\t\t\t\t\t\t\tif (!IsPtrSafe(++pResDirEntryLvL2))\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tstResLvL2 = { .dwOffset { PtrToOffset(pResDirLvL2) }, .stResDir { *pResDirLvL2 },\r\n\t\t\t\t\t\t\t.vecResData { std::move(vecResDataLvL2) } };\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse { //Resource LvL Root RAW Data.\r\n\t\t\t\t\tpResDataEntryRoot = reinterpret_cast<PIMAGE_RESOURCE_DATA_ENTRY>(reinterpret_cast<DWORD_PTR>(pResDirRoot)\r\n\t\t\t\t\t\t+ static_cast<DWORD_PTR>(pResDirEntryRoot->OffsetToData));\r\n\t\t\t\t\tif (IsPtrSafe(pResDataEntryRoot)) {\r\n\t\t\t\t\t\t//Checking RAW Resource data pointer out of bounds.\r\n\t\t\t\t\t\tif (const auto pRootResRawDataBegin = static_cast<std::byte*>(RVAToPtr(pResDataEntryRoot->OffsetToData));\r\n\t\t\t\t\t\t\tpRootResRawDataBegin && IsPtrSafe(reinterpret_cast<DWORD_PTR>(pRootResRawDataBegin)\r\n\t\t\t\t\t\t\t\t+ static_cast<DWORD_PTR>(pResDataEntryRoot->Size), true)) {\r\n\t\t\t\t\t\t\tvecRawResDataRoot.assign(pRootResRawDataBegin, pRootResRawDataBegin + pResDataEntryRoot->Size);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tvecResDataRoot.emplace_back(*pResDirEntryRoot, std::move(wstrResNameRoot),\r\n\t\t\t\t\tIsPtrSafe(pResDataEntryRoot) ? *pResDataEntryRoot : IMAGE_RESOURCE_DATA_ENTRY { },\r\n\t\t\t\t\tstd::move(vecRawResDataRoot), stResLvL2);\r\n\r\n\t\t\t\tif (!IsPtrSafe(++pResDirEntryRoot))\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\treturn std::make_optional<PERESROOT>(PtrToOffset(pResDirRoot), *pResDirRoot, std::move(vecResDataRoot));\r\n\t\t}\r\n\t\tcatch (const std::exception& e) {\r\n\t\t\tvecResDataRoot.clear();\r\n\t\t\tstd::cerr << \"Exception in GetResources(): \" << e.what();\r\n\t\t}\r\n\r\n\t\treturn std::nullopt;\r\n\t}\r\n\r\n\tauto Clibpe::GetExceptions()const->std::optional<PEEXCEPTION_VEC>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\t//IMAGE_RUNTIME_FUNCTION_ENTRY (without leading underscore) might have different typedef,\r\n\t\t//depending on defined platform, see winnt.h\r\n\t\tauto pRuntimeFuncsEntry = static_cast<_PIMAGE_RUNTIME_FUNCTION_ENTRY>(RVAToPtr(GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_EXCEPTION)));\r\n\t\tif (pRuntimeFuncsEntry == nullptr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tconst auto dwEntries = GetDirEntrySize(IMAGE_DIRECTORY_ENTRY_EXCEPTION) / static_cast<DWORD>(sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY));\r\n\t\tif (!dwEntries || !IsPtrSafe(reinterpret_cast<DWORD_PTR>(pRuntimeFuncsEntry) + static_cast<DWORD_PTR>(dwEntries)))\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPEEXCEPTION_VEC vecException;\r\n\t\tfor (auto i = 0UL; i < dwEntries; ++i, ++pRuntimeFuncsEntry) {\r\n\t\t\tif (!IsPtrSafe(pRuntimeFuncsEntry))\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tvecException.emplace_back(PtrToOffset(pRuntimeFuncsEntry), *pRuntimeFuncsEntry);\r\n\t\t}\r\n\r\n\t\treturn vecException.empty() ? std::nullopt : std::optional<PEEXCEPTION_VEC>(std::move(vecException));\r\n\t}\r\n\r\n\tauto Clibpe::GetSecurity()const->std::optional<PESECURITY_VEC>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tconst auto dwSecurityDirOffset = GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_SECURITY);\r\n\t\tconst auto dwSecurityDirSize = GetDirEntrySize(IMAGE_DIRECTORY_ENTRY_SECURITY);\r\n\t\tif (dwSecurityDirOffset == 0 || dwSecurityDirSize == 0)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\t//Checks for bogus file offsets that can cause DWORD_PTR overflow.\r\n\t\tif (ut::IsSumOverflow(static_cast<DWORD_PTR>(dwSecurityDirOffset), GetBaseAddr()))\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tauto dwSecurityDirStartVA = GetBaseAddr() + static_cast<DWORD_PTR>(dwSecurityDirOffset);\r\n\t\tif (ut::IsSumOverflow(dwSecurityDirStartVA, static_cast<DWORD_PTR>(dwSecurityDirSize)))\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tconst auto dwSecurityDirEndVA = dwSecurityDirStartVA + static_cast<DWORD_PTR>(dwSecurityDirSize);\r\n\r\n\t\tif (!IsPtrSafe(dwSecurityDirStartVA) || !IsPtrSafe(dwSecurityDirEndVA, true))\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPESECURITY_VEC vecSecurity;\r\n\t\twhile (dwSecurityDirStartVA < dwSecurityDirEndVA) {\r\n\t\t\tconst auto pCertificate = reinterpret_cast<PEWIN_CERTIFICATE*>(dwSecurityDirStartVA);\r\n\t\t\tconst auto dwCertSize = pCertificate->dwLength - static_cast<DWORD>(offsetof(PEWIN_CERTIFICATE, bCertificate));\r\n\t\t\tif (!IsPtrSafe(dwSecurityDirStartVA + static_cast<DWORD_PTR>(dwCertSize)))\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tvecSecurity.emplace_back(PtrToOffset(pCertificate), *pCertificate);\r\n\r\n\t\t\t//Get next certificate entry, all entries start at 0x8 aligned address.\r\n\t\t\tconst auto dwRemainder = (8 - (pCertificate->dwLength & 7)) & 7;\r\n\t\t\tconst auto dwLength = pCertificate->dwLength + dwRemainder;\r\n\t\t\tdwSecurityDirStartVA += static_cast<DWORD_PTR>(dwLength);\r\n\t\t\tif (!IsPtrSafe(dwSecurityDirStartVA))\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\treturn vecSecurity.empty() ? std::nullopt : std::optional<PESECURITY_VEC>(std::move(vecSecurity));\r\n\t}\r\n\r\n\tauto Clibpe::GetRelocations()const->std::optional<PERELOC_VEC>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tauto pBaseRelocDesc = static_cast<PIMAGE_BASE_RELOCATION>(RVAToPtr(GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_BASERELOC)));\r\n\t\tif (pBaseRelocDesc == nullptr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPERELOC_VEC vecRelocs;\r\n\t\ttry {\r\n\t\t\tif (!pBaseRelocDesc->SizeOfBlock || !pBaseRelocDesc->VirtualAddress) {\r\n\t\t\t\tvecRelocs.emplace_back(PtrToOffset(pBaseRelocDesc), *pBaseRelocDesc, std::vector<PERELOCDATA> { });\r\n\t\t\t}\r\n\r\n\t\t\twhile ((pBaseRelocDesc->SizeOfBlock) && (pBaseRelocDesc->VirtualAddress)) {\r\n\t\t\t\tif (pBaseRelocDesc->SizeOfBlock < sizeof(IMAGE_BASE_RELOCATION)) {\r\n\t\t\t\t\tvecRelocs.emplace_back(PtrToOffset(pBaseRelocDesc), *pBaseRelocDesc, std::vector<PERELOCDATA>{ });\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t//Amount of Reloc entries.\r\n\t\t\t\tDWORD dwNumRelocEntries = (pBaseRelocDesc->SizeOfBlock - static_cast<DWORD>(sizeof(IMAGE_BASE_RELOCATION))) / static_cast<DWORD>(sizeof(WORD));\r\n\t\t\t\tauto pwRelocEntry = reinterpret_cast<PWORD>(reinterpret_cast<DWORD_PTR>(pBaseRelocDesc) + sizeof(IMAGE_BASE_RELOCATION));\r\n\t\t\t\tstd::vector<PERELOCDATA> vecRelocData;\r\n\t\t\t\tfor (auto i = 0UL; i < dwNumRelocEntries; ++i, ++pwRelocEntry) {\r\n\t\t\t\t\tif (!IsPtrSafe(pwRelocEntry))\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tconst WORD wRelocType = (*pwRelocEntry & 0xF000) >> 12; //Getting HIGH 4 bits of reloc's entry WORD —> reloc type.\r\n\t\t\t\t\tvecRelocData.emplace_back(PtrToOffset(pwRelocEntry), wRelocType, static_cast<WORD>((*pwRelocEntry) & 0x0fff)/*Low 12 bits —> Offset*/);\r\n\t\t\t\t\tif (wRelocType == IMAGE_REL_BASED_HIGHADJ) {\t//The base relocation adds the high 16 bits of the difference to the 16-bit field at offset.\r\n\t\t\t\t\t\t//The 16-bit field represents the high value of a 32-bit word. \r\n\t\t\t\t\t\t//The low 16 bits of the 32-bit value are stored in the 16-bit word that follows this base relocation.\r\n\t\t\t\t\t\t//This means that this base relocation occupies two slots. (MSDN)\r\n\t\t\t\t\t\tif (!IsPtrSafe(++pwRelocEntry)) {\r\n\t\t\t\t\t\t\tvecRelocData.clear();\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tvecRelocData.emplace_back(PtrToOffset(pwRelocEntry), wRelocType, *pwRelocEntry /*The low 16-bit field.*/);\r\n\t\t\t\t\t\t--dwNumRelocEntries; //to compensate ++pwRelocEntry.\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvecRelocs.emplace_back(PtrToOffset(pBaseRelocDesc), *pBaseRelocDesc, std::move(vecRelocData));\r\n\r\n\t\t\t\t//Too big (bogus) SizeOfBlock may cause DWORD_PTR overflow. Checking to prevent.\r\n\t\t\t\tif (ut::IsSumOverflow(reinterpret_cast<DWORD_PTR>(pBaseRelocDesc), static_cast<DWORD_PTR>(pBaseRelocDesc->SizeOfBlock)))\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tpBaseRelocDesc = reinterpret_cast<PIMAGE_BASE_RELOCATION>(reinterpret_cast<DWORD_PTR>(pBaseRelocDesc)\r\n\t\t\t\t\t+ static_cast<DWORD_PTR>(pBaseRelocDesc->SizeOfBlock));\r\n\t\t\t\tif (!IsPtrSafe(pBaseRelocDesc))\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\treturn vecRelocs.empty() ? std::nullopt : std::optional<PERELOC_VEC>(std::move(vecRelocs));\r\n\t\t}\r\n\t\tcatch (const std::exception& e) {\r\n\t\t\tvecRelocs.clear();\r\n\t\t\tstd::cerr << \"Exception in GetRelocations(): \" << e.what();\r\n\t\t}\r\n\r\n\t\treturn std::nullopt;\r\n\t}\r\n\r\n\tauto Clibpe::GetDebug()const->std::optional<PEDEBUG_VEC>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tconst auto dwDebugDirRVA = GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_DEBUG);\r\n\t\tif (!dwDebugDirRVA)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPIMAGE_DEBUG_DIRECTORY pDebugDir;\r\n\t\tDWORD dwDebugDirSize;\r\n\t\tauto pDebugSecHdr = GetSecHdrFromShortName(\".debug\");\r\n\t\tif (pDebugSecHdr && (pDebugSecHdr->VirtualAddress == dwDebugDirRVA)) {\r\n\t\t\tpDebugDir = reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>(GetBaseAddr() + static_cast<DWORD_PTR>(pDebugSecHdr->PointerToRawData));\r\n\t\t\tdwDebugDirSize = GetDirEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG) * static_cast<DWORD>(sizeof(IMAGE_DEBUG_DIRECTORY));\r\n\t\t}\r\n\t\telse { //Looking for the debug directory.\r\n\t\t\tif (pDebugSecHdr = GetSecHdrFromRVA(dwDebugDirRVA); pDebugSecHdr == nullptr)\r\n\t\t\t\treturn std::nullopt;\r\n\r\n\t\t\tif (pDebugDir = static_cast<PIMAGE_DEBUG_DIRECTORY>(RVAToPtr(dwDebugDirRVA)); pDebugDir == nullptr)\r\n\t\t\t\treturn std::nullopt;\r\n\r\n\t\t\tdwDebugDirSize = GetDirEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG);\r\n\t\t}\r\n\r\n\t\tconst auto dwDebugEntries = dwDebugDirSize / static_cast<DWORD>(sizeof(IMAGE_DEBUG_DIRECTORY));\r\n\r\n\t\tif (!dwDebugEntries || ut::IsSumOverflow(reinterpret_cast<DWORD_PTR>(pDebugDir), static_cast<DWORD_PTR>(dwDebugDirSize)) ||\r\n\t\t\t!IsPtrSafe(reinterpret_cast<DWORD_PTR>(pDebugDir) + static_cast<DWORD_PTR>(dwDebugDirSize)))\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPEDEBUG_VEC vecDebug;\r\n\t\ttry {\r\n\t\t\tfor (auto i = 0UL; i < dwDebugEntries; ++i) {\r\n\t\t\t\tPEDEBUGDBGHDR stDbgHdr;\r\n\t\t\t\tfor (auto iterDbgHdr = 0UL; iterDbgHdr < (sizeof(PEDEBUGDBGHDR::dwHdr) / sizeof(DWORD)); ++iterDbgHdr) {\r\n\t\t\t\t\tstDbgHdr.dwHdr[iterDbgHdr] = GetTData<DWORD>(static_cast<size_t>(pDebugDir->PointerToRawData) + (sizeof(DWORD) * iterDbgHdr));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (pDebugDir->Type == IMAGE_DEBUG_TYPE_CODEVIEW) {\r\n\t\t\t\t\tDWORD dwOffset = 0;\r\n\t\t\t\t\tif (stDbgHdr.dwHdr[0] == 0x53445352) { //\"RSDS\"\r\n\t\t\t\t\t\tdwOffset = sizeof(DWORD) * 6;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (stDbgHdr.dwHdr[0] == 0x3031424E) { //\"NB10\"\r\n\t\t\t\t\t\tdwOffset = sizeof(DWORD) * 4;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tstd::string strPDBName;\r\n\t\t\t\t\tif (dwOffset > 0) {\r\n\t\t\t\t\t\tfor (auto iterStr = 0UL; iterStr < MAX_PATH; ++iterStr) {\r\n\t\t\t\t\t\t\tconst auto byte = GetTData<BYTE>(pDebugDir->PointerToRawData + dwOffset + iterStr);\r\n\t\t\t\t\t\t\tif (byte == 0) //End of string.\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\tstrPDBName += byte;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tstDbgHdr.strPDBName = std::move(strPDBName);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvecDebug.emplace_back(PtrToOffset(pDebugDir), *pDebugDir, stDbgHdr);\r\n\t\t\t\tif (!IsPtrSafe(++pDebugDir))\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\treturn vecDebug.empty() ? std::nullopt : std::optional<PEDEBUG_VEC>(std::move(vecDebug));\r\n\t\t}\r\n\t\tcatch (const std::exception& e) {\r\n\t\t\tvecDebug.clear();\r\n\t\t\tstd::cerr << \"Exception in GetDebug(): \" << e.what();\r\n\t\t}\r\n\r\n\t\treturn std::nullopt;\r\n\t}\r\n\r\n\tauto Clibpe::GetTLS()const->std::optional<PETLS>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tconst auto dwTLSDirRVA = GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_TLS);\r\n\t\tif (!dwTLSDirRVA)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tstd::vector<DWORD> vecTLSCallbacks;\r\n\t\ttry {\r\n\t\t\tULONGLONG ullAddressOfCallBacks;\r\n\t\t\tPETLS::UNPETLS varTLSDir;\r\n\t\t\tPDWORD pdwTLSPtr;\r\n\r\n\t\t\tif (m_ePEType == EFileType::PE32) {\r\n\t\t\t\tconst auto pTLSDir32 = static_cast<PIMAGE_TLS_DIRECTORY32>(RVAToPtr(dwTLSDirRVA));\r\n\t\t\t\tif (pTLSDir32 == nullptr)\r\n\t\t\t\t\treturn std::nullopt;\r\n\r\n\t\t\t\tvarTLSDir.stTLSDir32 = *pTLSDir32;\r\n\t\t\t\tpdwTLSPtr = reinterpret_cast<PDWORD>(pTLSDir32);\r\n\t\t\t\tullAddressOfCallBacks = pTLSDir32->AddressOfCallBacks;\r\n\t\t\t}\r\n\t\t\telse if (m_ePEType == EFileType::PE64) {\r\n\t\t\t\tconst auto pTLSDir64 = static_cast<PIMAGE_TLS_DIRECTORY64>(RVAToPtr(dwTLSDirRVA));\r\n\t\t\t\tif (pTLSDir64 == nullptr)\r\n\t\t\t\t\treturn std::nullopt;\r\n\r\n\t\t\t\tvarTLSDir.stTLSDir64 = *pTLSDir64;\r\n\t\t\t\tpdwTLSPtr = reinterpret_cast<PDWORD>(pTLSDir64);\r\n\t\t\t\tullAddressOfCallBacks = pTLSDir64->AddressOfCallBacks;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t\treturn std::nullopt;\r\n\r\n\t\t\tif (auto pTLSCallbacks = static_cast<PDWORD>(RVAToPtr(ullAddressOfCallBacks - GetImageBase())); pTLSCallbacks != nullptr) {\r\n\t\t\t\twhile (*pTLSCallbacks) {\r\n\t\t\t\t\tvecTLSCallbacks.push_back(*pTLSCallbacks);\r\n\t\t\t\t\tif (!IsPtrSafe(++pTLSCallbacks)) {\r\n\t\t\t\t\t\tvecTLSCallbacks.clear();\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn std::make_optional<PETLS>(PtrToOffset(pdwTLSPtr), varTLSDir, std::move(vecTLSCallbacks));\r\n\t\t}\r\n\t\tcatch (const std::exception& e) {\r\n\t\t\tvecTLSCallbacks.clear();\r\n\t\t\tstd::cerr << \"Exception in GetTLS(): \" << e.what();\r\n\t\t}\r\n\r\n\t\treturn std::nullopt;\r\n\t}\r\n\r\n\tauto Clibpe::GetLoadConfig()const->std::optional<PELOADCONFIG>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tswitch (m_ePEType) {\r\n\t\tcase EFileType::PE32:\r\n\t\t{\r\n\t\t\tconst auto pLCD32 = static_cast<PIMAGE_LOAD_CONFIG_DIRECTORY32>(RVAToPtr(GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG)));\r\n\t\t\tif (!pLCD32 || !IsPtrSafe(reinterpret_cast<DWORD_PTR>(pLCD32) + sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)))\r\n\t\t\t\treturn std::nullopt;\r\n\r\n\t\t\treturn { PELOADCONFIG { .dwOffset { PtrToOffset(pLCD32) }, .unLCD { .stLCD32 { *pLCD32 } } } };\r\n\t\t}\r\n\t\tcase EFileType::PE64:\r\n\t\t{\r\n\t\t\tconst auto pLCD64 = static_cast<PIMAGE_LOAD_CONFIG_DIRECTORY64>(RVAToPtr(GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG)));\r\n\t\t\tif (!pLCD64 || !IsPtrSafe(reinterpret_cast<DWORD_PTR>(pLCD64) + sizeof(PIMAGE_LOAD_CONFIG_DIRECTORY64)))\r\n\t\t\t\treturn std::nullopt;\r\n\r\n\t\t\treturn { PELOADCONFIG { .dwOffset { PtrToOffset(pLCD64) }, .unLCD { .stLCD64 { *pLCD64 } } } };\r\n\t\t}\r\n\t\tdefault:\r\n\t\t\treturn std::nullopt;\r\n\t\t}\r\n\t}\r\n\r\n\tauto Clibpe::GetBoundImport()const->std::optional<PEBOUNDIMPORT_VEC>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tauto pBoundImpDesc = static_cast<PIMAGE_BOUND_IMPORT_DESCRIPTOR>(RVAToPtr(GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT)));\r\n\t\tif (pBoundImpDesc == nullptr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPEBOUNDIMPORT_VEC vecBoundImp;\r\n\t\twhile (pBoundImpDesc->TimeDateStamp != 0) {\r\n\t\t\tstd::vector<PEBOUNDFORWARDER> vecBoundForwarders;\r\n\t\t\tauto pBoundImpForwarder = reinterpret_cast<PIMAGE_BOUND_FORWARDER_REF>(pBoundImpDesc + 1);\r\n\t\t\tif (!IsPtrSafe(pBoundImpForwarder))\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tfor (auto i = 0UL; i < pBoundImpDesc->NumberOfModuleForwarderRefs; ++i) {\r\n\t\t\t\tstd::string strForwarderModuleName { };\r\n\r\n\t\t\t\tif (const auto szName = reinterpret_cast<LPCSTR>(reinterpret_cast<DWORD_PTR>(pBoundImpDesc) + pBoundImpForwarder->OffsetModuleName);\r\n\t\t\t\t\tIsPtrSafe(szName)) {\r\n\t\t\t\t\tif (szName && (::StringCchLengthA(szName, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\t\t\tstrForwarderModuleName = szName;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvecBoundForwarders.emplace_back(PtrToOffset(pBoundImpForwarder), *pBoundImpForwarder, std::move(strForwarderModuleName));\r\n\r\n\t\t\t\tif (!IsPtrSafe(++pBoundImpForwarder))\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tpBoundImpDesc = reinterpret_cast<PIMAGE_BOUND_IMPORT_DESCRIPTOR>(reinterpret_cast<DWORD_PTR>(pBoundImpDesc) + sizeof(IMAGE_BOUND_FORWARDER_REF));\r\n\t\t\t\tif (!IsPtrSafe(pBoundImpDesc))\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tstd::string strModuleName;\r\n\t\t\tif (const auto szName = reinterpret_cast<LPCSTR>(reinterpret_cast<DWORD_PTR>(pBoundImpDesc) + pBoundImpDesc->OffsetModuleName);\r\n\t\t\t\tIsPtrSafe(szName)) {\r\n\t\t\t\tif (::StringCchLengthA(szName, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER) {\r\n\t\t\t\t\tstrModuleName = szName;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvecBoundImp.emplace_back(PtrToOffset(pBoundImpDesc), *pBoundImpDesc, std::move(strModuleName), std::move(vecBoundForwarders));\r\n\r\n\t\t\tif (!IsPtrSafe(++pBoundImpDesc))\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\treturn vecBoundImp.empty() ? std::nullopt : std::optional<PEBOUNDIMPORT_VEC>(std::move(vecBoundImp));\r\n\t}\r\n\r\n\tauto Clibpe::GetDelayImport()const->std::optional<PEDELAYIMPORT_VEC>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tauto pDelayImpDescr = static_cast<PIMAGE_DELAYLOAD_DESCRIPTOR>(RVAToPtr(GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)));\r\n\t\tif (pDelayImpDescr == nullptr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPEDELAYIMPORT_VEC vecDelayImp;\r\n\r\n\t\tif (m_ePEType == EFileType::PE32) {\r\n\t\t\twhile (pDelayImpDescr->DllNameRVA != 0) {\r\n\t\t\t\tauto pThunk32Name = reinterpret_cast<PIMAGE_THUNK_DATA32>(static_cast<DWORD_PTR>(pDelayImpDescr->ImportNameTableRVA));\r\n\t\t\t\tif (pThunk32Name == nullptr) {\r\n\t\t\t\t\tif (!IsPtrSafe(++pDelayImpDescr))\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tstd::vector<PEDELAYIMPORTFUNC> vecFunc;\r\n\t\t\t\t\tpThunk32Name = static_cast<PIMAGE_THUNK_DATA32>(RVAToPtr(reinterpret_cast<DWORD_PTR>(pThunk32Name)));\r\n\t\t\t\t\tauto pThunk32IAT = static_cast<PIMAGE_THUNK_DATA32>(RVAToPtr(pDelayImpDescr->ImportAddressTableRVA));\r\n\t\t\t\t\tauto pThunk32BoundIAT = static_cast<PIMAGE_THUNK_DATA32>(RVAToPtr(pDelayImpDescr->BoundImportAddressTableRVA));\r\n\t\t\t\t\tauto pThunk32UnloadInfoTable = static_cast<PIMAGE_THUNK_DATA32>(RVAToPtr(pDelayImpDescr->UnloadInformationTableRVA));\r\n\r\n\t\t\t\t\tif (pThunk32Name == nullptr)\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\twhile (pThunk32Name->u1.AddressOfData) {\r\n\t\t\t\t\t\tPEDELAYIMPORTFUNC::UNPEDELAYIMPORTTHUNK unDelayImpThunk32 { };\r\n\t\t\t\t\t\tunDelayImpThunk32.st32.stImportAddressTable = *pThunk32Name;\r\n\t\t\t\t\t\tunDelayImpThunk32.st32.stImportNameTable = pThunk32IAT ? *pThunk32IAT : IMAGE_THUNK_DATA32 { };\r\n\t\t\t\t\t\tunDelayImpThunk32.st32.stBoundImportAddressTable = pThunk32BoundIAT ? *pThunk32BoundIAT : IMAGE_THUNK_DATA32 { };\r\n\t\t\t\t\t\tunDelayImpThunk32.st32.stUnloadInformationTable = pThunk32UnloadInfoTable ? *pThunk32UnloadInfoTable : IMAGE_THUNK_DATA32 { };\r\n\r\n\t\t\t\t\t\tstd::string strFuncName;\r\n\t\t\t\t\t\tIMAGE_IMPORT_BY_NAME stImpByName { };\r\n\t\t\t\t\t\tif (!(pThunk32Name->u1.Ordinal & IMAGE_ORDINAL_FLAG32)) {\r\n\t\t\t\t\t\t\tif (const auto pName = static_cast<PIMAGE_IMPORT_BY_NAME>(RVAToPtr(pThunk32Name->u1.AddressOfData));\r\n\t\t\t\t\t\t\t\tpName && (::StringCchLengthA(pName->Name, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\t\t\t\t\tstImpByName = *pName;\r\n\t\t\t\t\t\t\t\tstrFuncName = pName->Name;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tvecFunc.emplace_back(unDelayImpThunk32, stImpByName, std::move(strFuncName));\r\n\r\n\t\t\t\t\t\tif (!IsPtrSafe(++pThunk32Name))\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tif (pThunk32IAT) {\r\n\t\t\t\t\t\t\tif (!IsPtrSafe(++pThunk32IAT))\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (pThunk32BoundIAT) {\r\n\t\t\t\t\t\t\tif (!IsPtrSafe(++pThunk32BoundIAT))\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (pThunk32UnloadInfoTable) {\r\n\t\t\t\t\t\t\tif (!IsPtrSafe(++pThunk32UnloadInfoTable))\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tstd::string strDllName;\r\n\t\t\t\t\tif (const auto szName = static_cast<LPCSTR>(RVAToPtr(pDelayImpDescr->DllNameRVA));\r\n\t\t\t\t\t\tszName != nullptr && (::StringCchLengthA(szName, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\t\t\tstrDllName = szName;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tvecDelayImp.emplace_back(PtrToOffset(pDelayImpDescr), *pDelayImpDescr, std::move(strDllName), std::move(vecFunc));\r\n\r\n\t\t\t\t\tif (!IsPtrSafe(++pDelayImpDescr))\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\telse if (m_ePEType == EFileType::PE64) {\r\n\t\t\twhile (pDelayImpDescr->DllNameRVA != 0) {\r\n\t\t\t\tauto pThunk64Name = reinterpret_cast<PIMAGE_THUNK_DATA64>(static_cast<DWORD_PTR>(pDelayImpDescr->ImportNameTableRVA));\r\n\r\n\t\t\t\tif (pThunk64Name == nullptr) {\r\n\t\t\t\t\tif (!IsPtrSafe(++pDelayImpDescr))\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tstd::vector<PEDELAYIMPORTFUNC> vecFunc;\r\n\t\t\t\t\tpThunk64Name = static_cast<PIMAGE_THUNK_DATA64>(RVAToPtr(reinterpret_cast<DWORD_PTR>(pThunk64Name)));\r\n\t\t\t\t\tauto pThunk64IAT = static_cast<PIMAGE_THUNK_DATA64>(RVAToPtr(pDelayImpDescr->ImportAddressTableRVA));\r\n\t\t\t\t\tauto pThunk64BoundIAT = static_cast<PIMAGE_THUNK_DATA64>(RVAToPtr(pDelayImpDescr->BoundImportAddressTableRVA));\r\n\t\t\t\t\tauto pThunk64UnloadInfoTable = static_cast<PIMAGE_THUNK_DATA64>(RVAToPtr(pDelayImpDescr->UnloadInformationTableRVA));\r\n\r\n\t\t\t\t\tif (pThunk64Name == nullptr)\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\twhile (pThunk64Name->u1.AddressOfData) {\r\n\t\t\t\t\t\tPEDELAYIMPORTFUNC::UNPEDELAYIMPORTTHUNK unDelayImpThunk64 { };\r\n\t\t\t\t\t\tunDelayImpThunk64.st64.stImportAddressTable = *pThunk64Name;\r\n\t\t\t\t\t\tunDelayImpThunk64.st64.stImportNameTable = pThunk64IAT ? *pThunk64IAT : IMAGE_THUNK_DATA64 { };\r\n\t\t\t\t\t\tunDelayImpThunk64.st64.stBoundImportAddressTable = pThunk64BoundIAT ? *pThunk64BoundIAT : IMAGE_THUNK_DATA64 { };\r\n\t\t\t\t\t\tunDelayImpThunk64.st64.stUnloadInformationTable = pThunk64UnloadInfoTable ? *pThunk64UnloadInfoTable : IMAGE_THUNK_DATA64 { };\r\n\r\n\t\t\t\t\t\tstd::string strFuncName;\r\n\t\t\t\t\t\tIMAGE_IMPORT_BY_NAME stImpByName { };\r\n\t\t\t\t\t\tif (!(pThunk64Name->u1.Ordinal & IMAGE_ORDINAL_FLAG64)) {\r\n\t\t\t\t\t\t\tif (const auto pName = static_cast<PIMAGE_IMPORT_BY_NAME>(RVAToPtr(pThunk64Name->u1.AddressOfData));\r\n\t\t\t\t\t\t\t\tpName && (::StringCchLengthA(pName->Name, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\t\t\t\t\tstImpByName = *pName;\r\n\t\t\t\t\t\t\t\tstrFuncName = pName->Name;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tvecFunc.emplace_back(unDelayImpThunk64, stImpByName, std::move(strFuncName));\r\n\r\n\t\t\t\t\t\tif (!IsPtrSafe(++pThunk64Name))\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tif (pThunk64IAT) {\r\n\t\t\t\t\t\t\tif (!IsPtrSafe(++pThunk64IAT))\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (pThunk64BoundIAT) {\r\n\t\t\t\t\t\t\tif (!IsPtrSafe(++pThunk64BoundIAT))\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (pThunk64UnloadInfoTable) {\r\n\t\t\t\t\t\t\tif (!IsPtrSafe(++pThunk64UnloadInfoTable))\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tstd::string strDllName;\r\n\t\t\t\t\tif (const auto szName = static_cast<LPCSTR>(RVAToPtr(pDelayImpDescr->DllNameRVA));\r\n\t\t\t\t\t\tszName != nullptr && (::StringCchLengthA(szName, MAX_PATH, nullptr) != STRSAFE_E_INVALID_PARAMETER)) {\r\n\t\t\t\t\t\tstrDllName = szName;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tvecDelayImp.emplace_back(PtrToOffset(pDelayImpDescr), *pDelayImpDescr, std::move(strDllName), std::move(vecFunc));\r\n\r\n\t\t\t\t\tif (!IsPtrSafe(++pDelayImpDescr))\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn vecDelayImp.empty() ? std::nullopt : std::optional<PEDELAYIMPORT_VEC>(std::move(vecDelayImp));\r\n\t}\r\n\r\n\tauto Clibpe::GetCOMDescriptor()const->std::optional<PECOMDESCRIPTOR>\r\n\t{\r\n\t\tassert(m_fOpened);\r\n\t\tif (!m_fOpened)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tconst auto pCOR20Hdr = static_cast<PIMAGE_COR20_HEADER>(RVAToPtr(GetDirEntryRVA(IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)));\r\n\t\tif (pCOR20Hdr == nullptr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\treturn std::make_optional<PECOMDESCRIPTOR>(PtrToOffset(pCOR20Hdr), *pCOR20Hdr);\r\n\t}\r\n\r\n\r\n\t//Private methods.\r\n\r\n\tauto Clibpe::GetFileSize()const->ULONGLONG\r\n\t{\r\n\t\treturn m_spnData.size();\r\n\t}\r\n\r\n\tauto Clibpe::GetBaseAddr()const->DWORD_PTR\r\n\t{\r\n\t\treturn reinterpret_cast<DWORD_PTR>(m_spnData.data());\r\n\t}\r\n\r\n\tauto Clibpe::GetDosPtr()const->const IMAGE_DOS_HEADER*\r\n\t{\r\n\t\treturn reinterpret_cast<const IMAGE_DOS_HEADER*>(m_spnData.data());\r\n\t}\r\n\r\n\tauto Clibpe::GetDirEntryRVA(DWORD dwEntry)const->DWORD\r\n\t{\r\n\t\tif (!m_fHasNTHdr)\r\n\t\t\treturn { };\r\n\r\n\t\tswitch (m_ePEType) {\r\n\t\tcase EFileType::PE32:\r\n\t\t\treturn m_pNTHeader32->OptionalHeader.DataDirectory[dwEntry].VirtualAddress;\r\n\t\tcase EFileType::PE64:\r\n\t\t\treturn m_pNTHeader64->OptionalHeader.DataDirectory[dwEntry].VirtualAddress;\r\n\t\tdefault:\r\n\t\t\treturn { };\r\n\t\t}\r\n\t}\r\n\r\n\tauto Clibpe::GetDirEntrySize(DWORD dwEntry)const->DWORD\r\n\t{\r\n\t\tif (!m_fHasNTHdr)\r\n\t\t\treturn { };\r\n\r\n\t\tswitch (m_ePEType) {\r\n\t\tcase EFileType::PE32:\r\n\t\t\treturn m_pNTHeader32->OptionalHeader.DataDirectory[dwEntry].Size;\r\n\t\tcase EFileType::PE64:\r\n\t\t\treturn m_pNTHeader64->OptionalHeader.DataDirectory[dwEntry].Size;\r\n\t\tdefault:\r\n\t\t\treturn { };\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tauto Clibpe::GetImageBase()const->ULONGLONG\r\n\t{\r\n\t\tswitch (m_ePEType) {\r\n\t\tcase EFileType::PE32:\r\n\t\t\treturn m_pNTHeader32->OptionalHeader.ImageBase;\r\n\t\tcase EFileType::PE64:\r\n\t\t\treturn m_pNTHeader64->OptionalHeader.ImageBase;\r\n\t\tdefault:\r\n\t\t\treturn { };\r\n\t\t}\r\n\t}\r\n\r\n\tauto Clibpe::GetSecHdrFromShortName(LPCSTR lpszName)const->PIMAGE_SECTION_HEADER\r\n\t{\r\n\t\tif (!m_fHasNTHdr)\r\n\t\t\treturn nullptr;\r\n\r\n\t\tPIMAGE_SECTION_HEADER pSecHdr;\r\n\t\tWORD wNumberOfSections;\r\n\r\n\t\tswitch (m_ePEType) {\r\n\t\tcase EFileType::PE32:\r\n\t\t\tpSecHdr = IMAGE_FIRST_SECTION(m_pNTHeader32);\r\n\t\t\twNumberOfSections = m_pNTHeader32->FileHeader.NumberOfSections;\r\n\t\t\tbreak;\r\n\t\tcase EFileType::PE64:\r\n\t\t\tpSecHdr = IMAGE_FIRST_SECTION(m_pNTHeader64);\r\n\t\t\twNumberOfSections = m_pNTHeader64->FileHeader.NumberOfSections;\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\treturn nullptr;\r\n\t\t}\r\n\r\n\t\tfor (auto itSec = 0UL; itSec < wNumberOfSections; ++itSec, ++pSecHdr) {\r\n\t\t\tif (!IsPtrSafe(reinterpret_cast<DWORD_PTR>(pSecHdr) + sizeof(IMAGE_SECTION_HEADER)))\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tif (::strncmp(reinterpret_cast<const char*>(pSecHdr->Name), lpszName, IMAGE_SIZEOF_SHORT_NAME) == 0)\r\n\t\t\t\treturn pSecHdr;\r\n\t\t}\r\n\r\n\t\treturn nullptr;\r\n\t}\r\n\r\n\tauto Clibpe::GetSecHdrFromRVA(ULONGLONG ullRVA)const->PIMAGE_SECTION_HEADER\r\n\t{\r\n\t\tif (!m_fHasNTHdr)\r\n\t\t\treturn nullptr;\r\n\r\n\t\tPIMAGE_SECTION_HEADER pSecHdr;\r\n\t\tWORD wNumberOfSections;\r\n\r\n\t\tswitch (m_ePEType) {\r\n\t\tcase EFileType::PE32:\r\n\t\t\tpSecHdr = IMAGE_FIRST_SECTION(m_pNTHeader32);\r\n\t\t\twNumberOfSections = m_pNTHeader32->FileHeader.NumberOfSections;\r\n\t\t\tbreak;\r\n\t\tcase EFileType::PE64:\r\n\t\t\tpSecHdr = IMAGE_FIRST_SECTION(m_pNTHeader64);\r\n\t\t\twNumberOfSections = m_pNTHeader64->FileHeader.NumberOfSections;\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\treturn nullptr;\r\n\t\t}\r\n\r\n\t\tfor (auto itSec = 0UL; itSec < wNumberOfSections; ++itSec, ++pSecHdr) {\r\n\t\t\tif (!IsPtrSafe(reinterpret_cast<DWORD_PTR>(pSecHdr) + sizeof(IMAGE_SECTION_HEADER)))\r\n\t\t\t\treturn nullptr;\r\n\r\n\t\t\t//Is RVA within this section?\r\n\t\t\tif ((ullRVA >= pSecHdr->VirtualAddress) && (ullRVA < (pSecHdr->VirtualAddress + pSecHdr->Misc.VirtualSize))) {\r\n\t\t\t\treturn pSecHdr;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn nullptr;\r\n\t}\r\n\r\n\tauto Clibpe::GetSecIdxFromRVA(ULONGLONG ullRVA)const->std::optional<DWORD>\r\n\t{\r\n\t\tif (!m_fHasNTHdr)\r\n\t\t\treturn std::nullopt;\r\n\r\n\t\tPIMAGE_SECTION_HEADER pSecHdr;\r\n\t\tWORD wNumberOfSections;\r\n\r\n\t\tswitch (m_ePEType) {\r\n\t\tcase EFileType::PE32:\r\n\t\t\tpSecHdr = IMAGE_FIRST_SECTION(m_pNTHeader32);\r\n\t\t\twNumberOfSections = m_pNTHeader32->FileHeader.NumberOfSections;\r\n\t\t\tbreak;\r\n\t\tcase EFileType::PE64:\r\n\t\t\tpSecHdr = IMAGE_FIRST_SECTION(m_pNTHeader64);\r\n\t\t\twNumberOfSections = m_pNTHeader64->FileHeader.NumberOfSections;\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\treturn std::nullopt;\r\n\t\t}\r\n\r\n\t\tfor (auto itSec = 0UL; itSec < wNumberOfSections; ++itSec, ++pSecHdr) {\r\n\t\t\tif (!IsPtrSafe(reinterpret_cast<DWORD_PTR>(pSecHdr) + sizeof(IMAGE_SECTION_HEADER))) {\r\n\t\t\t\treturn std::nullopt;\r\n\t\t\t}\r\n\r\n\t\t\t//Is RVA within this section?\r\n\t\t\tif ((ullRVA >= pSecHdr->VirtualAddress) && (ullRVA < (pSecHdr->VirtualAddress + pSecHdr->Misc.VirtualSize))) {\r\n\t\t\t\treturn itSec; //Section sequential index in a PE file.\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn std::nullopt;\r\n\t}\r\n\r\n\ttemplate<typename T>\r\n\tauto Clibpe::GetTData(ULONGLONG ullOffset)const->T\r\n\t{\r\n\t\tif (ullOffset > (GetFileSize() - sizeof(T))) //Check for file size exceeding.\r\n\t\t\treturn { };\r\n\r\n\t\treturn *reinterpret_cast<T*>(GetBaseAddr() + ullOffset);\r\n\t}\r\n\r\n\ttemplate<typename T>\r\n\tauto Clibpe::IsPtrSafe(const T tAddr, bool fCanReferenceBoundary)const->bool\r\n\t{\r\n\t\t/**************************************************************************************************\r\n\t\t* This func checks given pointer for nullptr and, more important, whether it fits allowed bounds. *\r\n\t\t* In PE headers there are plenty of places where wrong (bogus) values for pointers might reside,  *\r\n\t\t* causing many runtime «fun» if trying to dereference them.                                       *\r\n\t\t* Second arg (fCanReferenceBoundary) shows if pointer can point to the very end of a file, it's   *\r\n\t\t* valid for some PE structures. Template is used just for convenience, sometimes there is a need  *\r\n\t\t* to check pure address DWORD_PTR instead of a pointer.                                           *\r\n\t\t**************************************************************************************************/\r\n\t\tDWORD_PTR dwAddr;\r\n\t\tif constexpr (!std::is_same_v<T, DWORD_PTR>) {\r\n\t\t\tdwAddr = reinterpret_cast<DWORD_PTR>(tAddr);\r\n\t\t}\r\n\t\telse {\r\n\t\t\tdwAddr = tAddr;\r\n\t\t}\r\n\r\n\t\tconst auto ullBase = GetBaseAddr();\r\n\t\tconst auto ullMaxAddr = ullBase + GetFileSize();\r\n\r\n\t\treturn ((dwAddr == 0) || (dwAddr < ullBase)) ? false :\r\n\t\t\t(fCanReferenceBoundary ? dwAddr <= ullMaxAddr : dwAddr < ullMaxAddr);\r\n\t}\r\n\r\n\tauto Clibpe::PtrToOffset(LPCVOID lp)const->DWORD\r\n\t{\r\n\t\tif (lp == nullptr)\r\n\t\t\treturn 0;\r\n\r\n\t\treturn static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(lp) - GetBaseAddr());\r\n\t}\r\n\r\n\tauto Clibpe::RVAToPtr(ULONGLONG ullRVA)const->LPVOID\r\n\t{\r\n\t\tconst auto pSecHdr = GetSecHdrFromRVA(ullRVA);\r\n\t\tif (pSecHdr == nullptr)\r\n\t\t\treturn nullptr;\r\n\r\n\t\tconst auto ptr = reinterpret_cast<LPVOID>(GetBaseAddr() + ullRVA\r\n\t\t\t- static_cast<DWORD_PTR>(pSecHdr->VirtualAddress) + static_cast<DWORD_PTR>(pSecHdr->PointerToRawData));\r\n\r\n\t\treturn IsPtrSafe(ptr, true) ? ptr : nullptr;\r\n\t}\r\n\r\n\tbool Clibpe::ParseDOSHeader()\r\n\t{\r\n\t\t//If a file has at least MSDOS header signature then we can assume\r\n\t\t//that this is a minimally correct PE file, and process further.\r\n\t\treturn GetDosPtr()->e_magic == IMAGE_DOS_SIGNATURE;\r\n\t}\r\n\r\n\tbool Clibpe::ParseNTFileOptHeader()\r\n\t{\r\n\t\tconst auto pNTHeader = reinterpret_cast<PIMAGE_NT_HEADERS32>(GetBaseAddr()\r\n\t\t\t+ static_cast<DWORD_PTR>(GetDosPtr()->e_lfanew));\r\n\t\tif (!IsPtrSafe(reinterpret_cast<DWORD_PTR>(pNTHeader) + sizeof(IMAGE_NT_HEADERS32)))\r\n\t\t\treturn false;\r\n\r\n\t\tif (pNTHeader->Signature != IMAGE_NT_SIGNATURE)\r\n\t\t\treturn false;\r\n\r\n\t\tswitch (pNTHeader->OptionalHeader.Magic) {\r\n\t\tcase IMAGE_NT_OPTIONAL_HDR32_MAGIC:\r\n\t\t\tm_ePEType = EFileType::PE32;\r\n\t\t\tm_pNTHeader32 = pNTHeader;\r\n\t\t\tbreak;\r\n\t\tcase IMAGE_NT_OPTIONAL_HDR64_MAGIC:\r\n\t\t\tm_ePEType = EFileType::PE64;\r\n\t\t\tm_pNTHeader64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(pNTHeader);\r\n\t\t\tbreak;\r\n\t\t//case IMAGE_ROM_OPTIONAL_HDR_MAGIC: //Not implemented.\r\n\t\tdefault:\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tm_fHasNTHdr = true;\r\n\r\n\t\treturn true;\r\n\t}\r\n}"
  },
  {
    "path": "test/libpe.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.27428.1\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"libpe\", \"libpe.vcxproj\", \"{3C2559D5-7A9A-4E39-A2C5-C4D4806376EA}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{3C2559D5-7A9A-4E39-A2C5-C4D4806376EA}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{3C2559D5-7A9A-4E39-A2C5-C4D4806376EA}.Debug|x64.Build.0 = Debug|x64\n\t\t{3C2559D5-7A9A-4E39-A2C5-C4D4806376EA}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{3C2559D5-7A9A-4E39-A2C5-C4D4806376EA}.Debug|x86.Build.0 = Debug|Win32\n\t\t{3C2559D5-7A9A-4E39-A2C5-C4D4806376EA}.Release|x64.ActiveCfg = Release|x64\n\t\t{3C2559D5-7A9A-4E39-A2C5-C4D4806376EA}.Release|x64.Build.0 = Release|x64\n\t\t{3C2559D5-7A9A-4E39-A2C5-C4D4806376EA}.Release|x86.ActiveCfg = Release|Win32\n\t\t{3C2559D5-7A9A-4E39-A2C5-C4D4806376EA}.Release|x86.Build.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {875A30FD-5011-4251-862B-A11EE1A8B119}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "test/libpe.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"..\\libpe\\libpe.ixx\" />\r\n    <ClCompile Include=\"test.cpp\" />\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <VCProjectVersion>15.0</VCProjectVersion>\r\n    <ProjectGuid>{3C2559D5-7A9A-4E39-A2C5-C4D4806376EA}</ProjectGuid>\r\n    <Keyword>Win32Proj</Keyword>\r\n    <RootNamespace>libpe</RootNamespace>\r\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <IntDir>$(SolutionDir)bin\\obj\\$(Configuration)\\$(Platform)\\</IntDir>\r\n    <TargetName>$(ProjectName)d</TargetName>\r\n    <OutDir>$(SolutionDir)bin\\</OutDir>\r\n    <GenerateManifest>false</GenerateManifest>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <OutDir>$(SolutionDir)bin\\</OutDir>\r\n    <IntDir>$(SolutionDir)bin\\obj\\$(Configuration)\\$(Platform)\\</IntDir>\r\n    <TargetName>$(ProjectName)64d</TargetName>\r\n    <GenerateManifest>false</GenerateManifest>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <EmbedManifest>false</EmbedManifest>\r\n    <IntDir>$(SolutionDir)bin\\obj\\$(Configuration)\\$(Platform)\\</IntDir>\r\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\r\n    <OutDir>$(SolutionDir)bin\\</OutDir>\r\n    <GenerateManifest>false</GenerateManifest>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <EmbedManifest>false</EmbedManifest>\r\n    <OutDir>$(SolutionDir)bin\\</OutDir>\r\n    <IntDir>$(SolutionDir)bin\\obj\\$(Configuration)\\$(Platform)\\</IntDir>\r\n    <TargetName>$(ProjectName)64</TargetName>\r\n    <GenerateManifest>false</GenerateManifest>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <ConformanceMode>true</ConformanceMode>\r\n      <LanguageStandard>stdcpp20</LanguageStandard>\r\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <AdditionalOptions>/NOCOFFGRPINFO /pdbaltpath:%_PDB% %(AdditionalOptions)</AdditionalOptions>\r\n      <ManifestFile />\r\n    </Link>\r\n    <PostBuildEvent>\r\n      <Command>\r\n      </Command>\r\n    </PostBuildEvent>\r\n    <BuildLog />\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <ConformanceMode>true</ConformanceMode>\r\n      <LanguageStandard>stdcpp20</LanguageStandard>\r\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <AdditionalOptions>/NOCOFFGRPINFO /pdbaltpath:%_PDB% %(AdditionalOptions)</AdditionalOptions>\r\n      <ManifestFile />\r\n    </Link>\r\n    <PostBuildEvent>\r\n      <Command>\r\n      </Command>\r\n    </PostBuildEvent>\r\n    <BuildLog />\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <AdditionalIncludeDirectories>\r\n      </AdditionalIncludeDirectories>\r\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\r\n      <ProgramDataBaseFileName />\r\n      <XMLDocumentationFileName />\r\n      <AdditionalOptions>%(AdditionalOptions)</AdditionalOptions>\r\n      <LanguageStandard>stdcpp20</LanguageStandard>\r\n      <OmitFramePointers>true</OmitFramePointers>\r\n      <ConformanceMode>true</ConformanceMode>\r\n      <ForcedIncludeFiles>\r\n      </ForcedIncludeFiles>\r\n      <ShowIncludes />\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>false</GenerateDebugInformation>\r\n      <ProgramDatabaseFile />\r\n      <ManifestFile />\r\n      <ProfileGuidedDatabase />\r\n      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\r\n      <ImportLibrary>\r\n      </ImportLibrary>\r\n      <AdditionalOptions>/NOCOFFGRPINFO /pdbaltpath:%_PDB% %(AdditionalOptions)</AdditionalOptions>\r\n    </Link>\r\n    <BuildLog />\r\n    <PostBuildEvent>\r\n      <Command>\r\n      </Command>\r\n    </PostBuildEvent>\r\n    <Manifest>\r\n      <OutputManifestFile />\r\n    </Manifest>\r\n    <Xdcmake>\r\n      <OutputFile />\r\n    </Xdcmake>\r\n    <ResourceCompile>\r\n      <AdditionalIncludeDirectories>include</AdditionalIncludeDirectories>\r\n    </ResourceCompile>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <SDLCheck>false</SDLCheck>\r\n      <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <ConformanceMode>true</ConformanceMode>\r\n      <AdditionalIncludeDirectories>\r\n      </AdditionalIncludeDirectories>\r\n      <LanguageStandard>stdcpp20</LanguageStandard>\r\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\r\n      <OmitFramePointers>true</OmitFramePointers>\r\n      <AdditionalOptions>%(AdditionalOptions)</AdditionalOptions>\r\n      <XMLDocumentationFileName />\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>false</GenerateDebugInformation>\r\n      <AdditionalOptions>/NOCOFFGRPINFO /pdbaltpath:%_PDB% %(AdditionalOptions)</AdditionalOptions>\r\n      <ManifestFile />\r\n      <ProgramDatabaseFile />\r\n      <ProfileGuidedDatabase />\r\n      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\r\n    </Link>\r\n    <Manifest>\r\n      <OutputManifestFile />\r\n    </Manifest>\r\n    <BuildLog />\r\n    <PostBuildEvent>\r\n      <Command>\r\n      </Command>\r\n    </PostBuildEvent>\r\n    <BuildLog />\r\n  </ItemDefinitionGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "test/test.cpp",
    "content": "#include <format>\r\n#include <iostream>\r\n#include <string>\r\n\r\nimport libpe;\r\nusing namespace libpe;\r\n\r\nint wmain(int argc, wchar_t* argv[])\r\n{\r\n\tstd::wstring_view wsvFile { L\"C:\\\\Windows\\\\notepad.exe\" }; //Default file.\r\n\tif (argc > 1) {\r\n\t\twsvFile = argv[1];\r\n\t}\r\n\r\n\tlibpe::Clibpe pe;\r\n\tif (pe.OpenFile(wsvFile.data()) != PEOK) {\r\n\t\tstd::cout << \"Open file failed.\";\r\n\t\treturn -1;\r\n\t}\r\n\r\n\tconstexpr auto svFormat = \"{:*^{}}\\r\\n\";\r\n\tconstexpr auto wsvFormat = L\"{:*^{}}\\r\\n\";\r\n\tconstexpr auto uiWidth = 100UL;\r\n\r\n\tstd::string strRich = std::format(svFormat, \"Rich\", uiWidth);\r\n\tif (const auto peRich = pe.GetRichHeader(); peRich) {\r\n\t\tfor (const auto& ref : *peRich) {\r\n\t\t\tstrRich += std::format(\"ID: {:04X}, Ver: {:05}, Count: {}\\r\\n\", ref.wId, ref.wVersion, ref.dwCount);\r\n\t\t}\r\n\t}\r\n\telse {\r\n\t\tstrRich += \"No Rich header.\\r\\n\";\r\n\t}\r\n\tstd::cout << strRich << \"\\r\\n\";\r\n\r\n\tstd::wstring wstrResources = std::format(wsvFormat, L\"Resources\", uiWidth);\r\n\tif (const auto peResRoot = pe.GetResources(); peResRoot) {\r\n\t\tfor (const auto& iterRoot : peResRoot->vecResData) { //Main loop to extract Resources.\r\n\t\t\tauto ilvlRoot = 0;\r\n\t\t\tauto pResDirEntry = &iterRoot.stResDirEntry; //ROOT IMAGE_RESOURCE_DIRECTORY_ENTRY\r\n\t\t\tif (pResDirEntry->NameIsString) {\r\n\t\t\t\twstrResources += std::format(L\"Entry: {} [Name: {}]\\r\\n\", ilvlRoot, iterRoot.wstrResName);\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tif (const auto iter = MapResID.find(pResDirEntry->Id); iter != MapResID.end()) {\r\n\t\t\t\t\twstrResources += std::format(L\"Entry: {} [Id: {}, {}]\\r\\n\", ilvlRoot, pResDirEntry->Id, iter->second);\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\twstrResources += std::format(L\"Entry: {} [Id: {}]\\r\\n\", ilvlRoot, pResDirEntry->Id);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (pResDirEntry->DataIsDirectory) {\r\n\t\t\t\tauto ilvl2 = 0;\r\n\t\t\t\tauto pstResLvL2 = &iterRoot.stResLvL2;\r\n\t\t\t\tfor (const auto& iterLvL2 : pstResLvL2->vecResData) {\r\n\t\t\t\t\tpResDirEntry = &iterLvL2.stResDirEntry; //Level 2 IMAGE_RESOURCE_DIRECTORY_ENTRY\r\n\t\t\t\t\tif (pResDirEntry->NameIsString) {\r\n\t\t\t\t\t\twstrResources += std::format(L\"    Entry: {}, Name: {}\\r\\n\", ilvl2, iterLvL2.wstrResName);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\twstrResources += std::format(L\"    Entry: {}, Id: {}\\r\\n\", ilvl2, pResDirEntry->Id);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (pResDirEntry->DataIsDirectory) {\r\n\t\t\t\t\t\tauto ilvl3 = 0;\r\n\t\t\t\t\t\tauto pstResLvL3 = &iterLvL2.stResLvL3;\r\n\t\t\t\t\t\tfor (const auto& iterLvL3 : pstResLvL3->vecResData) {\r\n\t\t\t\t\t\t\tpResDirEntry = &iterLvL3.stResDirEntry; //Level 3 IMAGE_RESOURCE_DIRECTORY_ENTRY\r\n\t\t\t\t\t\t\tif (pResDirEntry->NameIsString) {\r\n\t\t\t\t\t\t\t\twstrResources += std::format(L\"        Entry: {}, Name: {}\\r\\n\", ilvl3, iterLvL3.wstrResName);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\t\twstrResources += std::format(L\"        Entry: {}, lang: {}\\r\\n\", ilvl3, pResDirEntry->Id);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t++ilvl3;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t++ilvl2;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t++ilvlRoot;\r\n\t\t}\r\n\t}\r\n\telse {\r\n\t\twstrResources += L\"No Resources found.\\r\\n\";\r\n\t}\r\n\tstd::wcout << wstrResources << L\"\\r\\n\";\r\n\r\n\tstd::string strImports = std::format(svFormat, \"Imports\", uiWidth);\r\n\tif (const auto peImp = pe.GetImport(); peImp) {\r\n\t\tfor (const auto& itModule : *peImp) { //Cycle through all imports.\r\n\t\t\tstrImports += std::format(\"{}, Funcs: {}\\r\\n\", itModule.strModuleName, itModule.vecImportFunc.size());\r\n\t\t}\r\n\t}\r\n\telse {\r\n\t\tstrImports += \"No Imports found.\\r\\n\";\r\n\t}\r\n\tstd::cout << strImports << \"\\r\\n\";\r\n\r\n\tstd::string strSecurity = std::format(svFormat, \"Security Directory\", uiWidth);\r\n\tif (const auto peSecur = pe.GetSecurity(); peSecur) {\r\n\t\tfor (const auto& itSecur : *peSecur) {\r\n\t\t\tconst auto& refWinSert = itSecur.stWinSert;\r\n\t\t\tstrSecurity += std::format(\"Offset: {}, Length: {}, Revision: {}, Cert Type: {}\\r\\n\",\r\n\t\t\t\titSecur.dwOffset, refWinSert.dwLength, refWinSert.wRevision, refWinSert.wCertificateType);\r\n\t\t}\r\n\t}\r\n\telse {\r\n\t\tstrSecurity += \"No Security directory found.\\r\\n\";\r\n\t}\r\n\tstd::cout << strSecurity << \"\\r\\n\";\r\n\r\n\treturn 0;\r\n}"
  }
]