Click here to Skip to main content
14,388,136 members

libpe

Rate this:
5.00 (10 votes)
Please Sign up or sign in to vote.
5.00 (10 votes)
30 Oct 2019MIT
Windows library for working with PE/PE+ binaries' inner information

PE32/PE32+ binaries viewer library.

Official github repository: https://github.com/jovibor/libpe

Table of Contents

Introduction

libpe is a Windows library for obtaining inner information from the Portable Executable Format binaries. The library is implemented as a pure abstract virtual interface with a decent number of methods.

  • Works with PE32(x86) and PE32+(x64) binaries
  • Supports PE/PE+ binaries of any size (although PE format is restricted to 4GB)
  • All inner PE/PE+ data structures, headers and layouts
    • MSDOS Header
    • «Rich» Header
    • NT/File/Optional Headers
    • Data Directories
    • Sections
    • Export Table
    • Import Table
    • Resource Table
    • Exceptions Table
    • Security Table
    • Relocations Table
    • Debug Table
    • TLS Table
    • Load Config Directory
    • Bound Import Table
    • Delay Import Table
    • COM Table
  • Built with /std:c++17 standard conformance

Pepper is one of the gui apps that is built on top of the libpe, and using it extensively.

Usage

The usage of the library is quite simple:

  1. Add libpe.h header file into your project.
  2. Add #include "libpe.h" where you suppose to use it.
  3. Declare libpe_ptr variable: libpe_ptr pLibpe { Createlibpe() };
  4. Put libpe.lib into your project's folder, so that linker can see it.
  5. Put libpe.dll next to your executable.

Factory function Createlibpe returns IlibpeUnPtr - unique_ptr with custom deleter.
In the client code, you should use libpe_ptr type which is an alias to either IlibpeUnPtr - a unique_ptr, or IlibpeShPtr - a shared_ptr.

//using libpe_ptr = IlibpeUnPtr;
using libpe_ptr = IlibpeShPtr;

Uncomment what serves best for you, and comment out the other.

If you, for some reason, need a raw interface pointer, you can directly call CreateRawlibpe function, which returns Ilibpe interface pointer, but in this case, you will need to call Destroy method manually afterwards, to destroy Ilibpe object.

The libpe uses its own namespace, so you either add the:

using namespace libpe;

or use namespace prefix libpe::

Methods

All libpe methods return HRESULT.
When method executes successfully, it returns S_OK, otherwise error code is returned.

LoadPe

HRESULT LoadPe(LPCWSTR);

This is the first method you call to proceed with a PE file.

libpe_ptr pLibpe { Createlibpe() };
if(pLibpe->LoadPe(L"C:\\MyFile.exe") == S_OK)
{
    ...
}

After this method succeeds, you can then call all the other methods to retrieve needed information. The PE file itself doesn't stay in memory any longer, so you don't have to explicitly unload it.

GetImageInfo

HRESULT GetImageInfo(DWORD&);

This method returns DWORD variable with the currently loaded file's flags.
These flags are listed below:

Flag Value Meaning
IMAGE_FLAG_PE32 0x00000001 Image is x32 file.
IMAGE_FLAG_PE64 0x00000002 Image is x64 file.
IMAGE_FLAG_DOSHEADER 0x00000004 Image has DOS header.
IMAGE_FLAG_RICHHEADER 0x00000008 Image has "Rich" header.
IMAGE_FLAG_NTHEADER 0x00000010 Image has NT header.
IMAGE_FLAG_FILEHEADER 0x00000020 Image has File header.
IMAGE_FLAG_OPTHEADER 0x00000040 Image has Optional header.
IMAGE_FLAG_DATADIRECTORIES 0x00000080 Image has Data directories.
IMAGE_FLAG_SECTIONS 0x00000100 Image has one or more Sections.
IMAGE_FLAG_EXPORT 0x00000200 Image has Export table.
IMAGE_FLAG_IMPORT 0x00000400 Image has Import table.
IMAGE_FLAG_RESOURCE 0x00000800 Image has Resource table.
IMAGE_FLAG_EXCEPTION 0x00001000 Image has Exception table.
IMAGE_FLAG_SECURITY 0x00002000 Image has Security table.
IMAGE_FLAG_BASERELOC 0x00004000 Image has Relocations.
IMAGE_FLAG_DEBUG 0x00008000 Image has Debug directory.
IMAGE_FLAG_ARCHITECTURE 0x00010000 Image has Architecture table.
IMAGE_FLAG_GLOBALPTR 0x00020000 Image has GlobalPtr table.
IMAGE_FLAG_TLS 0x00040000 Image has TLS directory.
IMAGE_FLAG_LOADCONFIG 0x00080000 Image has Load config directory.
IMAGE_FLAG_BOUNDIMPORT 0x00100000 Image has Bound import table.
IMAGE_FLAG_IAT 0x00200000 Image has IAT table.
IMAGE_FLAG_DELAYIMPORT 0x00400000 Image has Delay import table.
IMAGE_FLAG_COMDESCRIPTOR 0x00800000 Image has .NET related stuff.

There can be any combination of these flags, they all can be OR'ed.
You can also use a standalone tiny helper function ImageHasFlag to find out if the given flag is set in a variable.

libpe_ptr pLibpe { Createlibpe() };
if(pLibpe->LoadPe(L"C:\\MyFile.exe") == S_OK)
{
    DWORD dwFlags;
    pLibpe->GetImageInfo(dwFlags);
    bool fIs32 = ImageHasFlag(dwFlags, IMAGE_FLAG_PE32);         //Now we know if the binary 
                                                                 //is x32 or not.
    bool fIsDebugData = ImageHasFlag(dwFlags, IMAGE_FLAG_DEBUG); //Now we know if binary 
                                                                 //has embedded Debug info.
}

GetImageFlag

HRESULT GetImageFlag(DWORD dwFlag, bool& f);

This helper function is very similar to the GetImageInfo, but, in contrast, it receives information about just one given flar at a time.

libpe_ptr pLibpe { Createlibpe() };
if(pLibpe->LoadPe(L"C:\\MyFile.exe") == S_OK)
{
    bool fIsDebugData;
    pLibpe->GetImageFlag(IMAGE_FLAG_DEBUG, fIsDebugData);
}

GetOffsetFromRVA

HRESULT GetOffsetFromRVA(ULONGLONG ullRVA, DWORD& dwOffset);

Converts file's RVA (Relative Virtual Address) to the raw file offset.

GetOffsetFromVA

HRESULT GetOffsetFromVA(ULONGLONG ullVA, DWORD& dwOffset);

Converts file's VA (Virtual Address) to the raw file offset.

GetMSDOSHeader

HRESULT GetMSDOSHeader(PCLIBPE_DOSHEADER&);

Gets file's standard MSDOS header, in form of PCLIBPE_DOSHEADER.

using PCLIBPE_DOSHEADER = const IMAGE_DOS_HEADER*;

GetRichHeader

HRESULT GetRichHeader(PCLIBPE_RICHHEADER_VEC&);

Gets array of the unofficial and undocumented so called «Rich» header structures.

struct LIBPE_RICH {
    DWORD dwOffsetRich; //File's raw offset of the entry.
    WORD  wId;          //Entry Id.
    WORD  wVersion;     //Entry version.
    DWORD dwCount;      //Amount of occurrences.
};
using LIBPE_RICHHEADER_VEC = std::vector<LIBPE_RICH>;
using PCLIBPE_RICHHEADER_VEC = const LIBPE_RICHHEADER_VEC*;

GetNTHeader

HRESULT GetNTHeader(PCLIBPE_NTHEADER_VAR&);

Gets file's NT header.

struct LIBPE_NTHEADER {
    DWORD dwOffsetNTHdrDesc; //File's raw offset of the header.
    union LIBPE_NTHEADER_VAR {
    	IMAGE_NT_HEADERS32 stNTHdr32; //x86 Header.
    	IMAGE_NT_HEADERS64 stNTHdr64; //x64 Header.
    }varHdr;
};
using PCLIBPE_NTHEADER = const LIBPE_NTHEADER*;

GetFileHeader

HRESULT GetFileHeader(PCLIBPE_FILEHEADER&);

Gets file's File header.

using PCLIBPE_FILEHEADER = const IMAGE_FILE_HEADER*;

GetOptionalHeader

HRESULT GetOptionalHeader(PCLIBPE_OPTHEADER_VAR&);

Gets file's Optional header.

union LIBPE_OPTHEADER_VAR {
    IMAGE_OPTIONAL_HEADER32 stOptHdr32; //x86 header.
    IMAGE_OPTIONAL_HEADER64 stOptHdr64; //x64 header.
};
using PCLIBPE_OPTHEADER_VAR = const LIBPE_OPTHEADER_VAR*;

GetDataDirectories

HRESULT GetDataDirectories(PCLIBPE_DATADIRS_VEC&);

Gets array of the file's Data directories structs.

struct LIBPE_DATADIR {
    IMAGE_DATA_DIRECTORY stDataDir;       //Standard header.
    std::string          strSecResidesIn; //Name of the section 
                                          //this directory resides in (points to).
};
using LIBPE_DATADIRS_VEC = std::vector<LIBPE_DATADIR>;
using PCLIBPE_DATADIRS_VEC = const LIBPE_DATADIRS_VEC*;

GetSectionsHeaders

HRESULT GetSectionsHeaders(PCLIBPE_SECHEADERS_VEC&);

Gets array of the file's Sections headers structs.

struct LIBPE_SECHEADERS {
    DWORD                 dwOffsetSecHdrDesc; //File's raw offset of the 
                                              //section header descriptor.
    IMAGE_SECTION_HEADER  stSecHdr;           //Standard section header.
    std::string           strSecName;         //Section full name.
};
using LIBPE_SECHEADERS_VEC = std::vector<LIBPE_SECHEADERS>;
using PCLIBPE_SECHEADERS_VEC = const LIBPE_SECHEADERS_VEC*;

GetExport

HRESULT GetExport(PCLIBPE_EXPORT&);

Gets file's Export information.

struct LIBPE_EXPORT_FUNC {
    DWORD       dwRVA;            //Function RVA.
    DWORD       dwOrdinal;        //Function ordinal.
    std::string strFuncName;      //Function name.
    std::string strForwarderName; //Function forwarder name.
};
struct LIBPE_EXPORT {
    DWORD				dwOffsetExportDesc; //File's raw offset of the Export header descriptor.
    IMAGE_EXPORT_DIRECTORY		stExportDesc;	//Standard export header descriptor.
    std::string			strModuleName;	        //Actual module name.
    std::vector<LIBPE_EXPORT_FUNC>	vecFuncs;   //Array of the exported functions struct.
};
using PCLIBPE_EXPORT = const LIBPE_EXPORT*;

Example
Getting Export information is very simple:

libpe_ptr pLibpe { Createlibpe() };
pLibpe->LoadPe(L"PATH_TO_PE_FILE")

PCLIBPE_EXPORT pExport;
pLibpe->GetExport(pExport)

pExport->stExportDesc;  //IMAGE_EXPORT_DIRECTORY struct.
pExport->strModuleName; //Export module name.
pExport->vecFuncs;      //Vector of exported functions.

for (auto& itFuncs : pExport->vecFuncs)
{
    itFuncs.strFuncName;      //Function name.
    itFuncs.dwOrdinal;        //Ordinal.
    itFuncs.dwRVA;            //Function RVA.
    itFuncs.strForwarderName; //Forwarder name.
}

GetImport

HRESULT GetImport(PCLIBPE_IMPORT_VEC&);

Gets array of the file's Import table entries.

struct LIBPE_IMPORT_FUNC {
    union LIBPE_IMPORT_THUNK_VAR {
    	IMAGE_THUNK_DATA32 stThunk32; //x86 standard thunk.
    	IMAGE_THUNK_DATA64 stThunk64; //x64 standard thunk.
    }varThunk;
    IMAGE_IMPORT_BY_NAME stImpByName; //Standard IMAGE_IMPORT_BY_NAME struct
    std::string          strFuncName; //Function name.
};
struct LIBPE_IMPORT_MODULE {
    DWORD                          dwOffsetImpDesc; //File's raw offset of the 
                                                    //Import descriptor.
    IMAGE_IMPORT_DESCRIPTOR        stImportDesc;    //Standard Import descriptor.
    std::string                    strModuleName;   //Imported module name.
    std::vector<LIBPE_IMPORT_FUNC> vecImportFunc;   //Array of imported functions.
};
using LIBPE_IMPORT_VEC = std::vector<LIBPE_IMPORT_MODULE>;
using PCLIBPE_IMPORT_VEC = const LIBPE_IMPORT_VEC*;

Example
To obtain Import table information from the file, see the following code:

libpe_ptr pLibpe { Createlibpe() };
pLibpe->LoadPe(L"PATH_TO_PE_FILE")

PCLIBPE_IMPORT_VEC pImport;
if(pLibpe->GetImport(pImport) != S_OK)
    return;

bool fx32;
pLibpe->GetImageFlag(IMAGE_FLAG_PE32, fx32);

for (auto& itModule : *pImport) //Cycle through all imports that this PE file contains.
{
    auto pImpDesc = &itModule.stImportDesc; //IMAGE_IMPORT_DESCRIPTOR struct.
    auto& str = itModule.strModuleName;     //Name of the import module.
	
    for (auto& itFuncs : itModule.vecImportFunc) //Cycle through all the 
                                                 //functions imported from itModule module.
    {
    	itFuncs.strFuncName;        //Imported function name (std::string).
        itFuncs.stImpByName;        //IMAGE_IMPORT_BY_NAME struct for this function.
       
        itFuncs.varThunk.stThunk32; //Union of IMAGE_THUNK_DATA32 or 
                                    //IMAGE_THUNK_DATA64 (depending on the binary type).
        if(fx32)
            itFuncs.varThunk.stThunk32 //We process stThunk32 data
        else
            itFuncs.varThunk.stThunk64 //We process stThunk64 data
    }
}

GetResources

HRESULT GetResources(PCLIBPE_RESOURCE_ROOT&);

Retrieves all the binary's resources.

//Level 3 (the lowest) Resources.
struct LIBPE_RESOURCE_LVL3_DATA {
    IMAGE_RESOURCE_DIRECTORY_ENTRY stResDirEntryLvL3;   //Level 3 standard 
                                                        //IMAGE_RESOURCE_DIRECTORY_ENTRY struct.
    std::wstring                   wstrResNameLvL3;     //Level 3 resource name.
    IMAGE_RESOURCE_DATA_ENTRY      stResDataEntryLvL3;  //Level 3 standard 
                                                        //IMAGE_RESOURCE_DATA_ENTRY struct.
    std::vector<std::byte>         vecResRawDataLvL3;   //Level 3 resource raw data.
};
struct LIBPE_RESOURCE_LVL3 {
    DWORD                                 dwOffsetResLvL3; //File's raw offset of the 
                                                           //level 3 IMAGE_RESOURCE_DIRECTORY 
                                                           //descriptor.
    IMAGE_RESOURCE_DIRECTORY              stResDirLvL3;    //Level 3 standard 
                                                           //IMAGE_RESOURCE_DIRECTORY header.
    std::vector<LIBPE_RESOURCE_LVL3_DATA> vecResLvL3;      //Array of level 3 resource entries.
};
using PCLIBPE_RESOURCE_LVL3 = const LIBPE_RESOURCE_LVL3*;

//Level 2 Resources — Includes LVL3 Resources.
struct LIBPE_RESOURCE_LVL2_DATA {
    IMAGE_RESOURCE_DIRECTORY_ENTRY stResDirEntryLvL2;  //Level 2 standard 
                                                       //IMAGE_RESOURCE_DIRECTORY_ENTRY struct.
    std::wstring                   wstrResNameLvL2;    //Level 2 resource name.
    IMAGE_RESOURCE_DATA_ENTRY      stResDataEntryLvL2; //Level 2 standard 
                                                       //IMAGE_RESOURCE_DATA_ENTRY struct.
    std::vector<std::byte>         vecResRawDataLvL2;  //Level 2 resource raw data.
    LIBPE_RESOURCE_LVL3            stResLvL3;          //Level 3 resource struct.
};
struct LIBPE_RESOURCE_LVL2 {
    DWORD                                 dwOffsetResLvL2; //File's raw offset of the 
                                                           //level 2 IMAGE_RESOURCE_DIRECTORY 
                                                           //descriptor.
    IMAGE_RESOURCE_DIRECTORY              stResDirLvL2;    //Level 2 standard 
                                                           //IMAGE_RESOURCE_DIRECTORY header.
    std::vector<LIBPE_RESOURCE_LVL2_DATA> vecResLvL2;      //Array of level 2 resource entries.
};
using PCLIBPE_RESOURCE_LVL2 = const LIBPE_RESOURCE_LVL2*;

//Level 1 (Root) Resources — Includes LVL2 Resources.
struct LIBPE_RESOURCE_ROOT_DATA {
    IMAGE_RESOURCE_DIRECTORY_ENTRY stResDirEntryRoot;  //Level 1 standard 
                                                       //IMAGE_RESOURCE_DIRECTORY_ENTRY struct.
    std::wstring                   wstrResNameRoot;    //Level 1 resource name.
    IMAGE_RESOURCE_DATA_ENTRY      stResDataEntryRoot; //Level 1 standard 
                                                       //IMAGE_RESOURCE_DATA_ENTRY struct.
    std::vector<std::byte>         vecResRawDataRoot;  //Level 1 resource raw data.
    LIBPE_RESOURCE_LVL2            stResLvL2;          //Level 2 resource struct.
};
struct LIBPE_RESOURCE_ROOT {
	DWORD                                 dwOffsetResRoot; //File's raw offset of the 
                                                           //level 1 IMAGE_RESOURCE_DIRECTORY 
                                                           //descriptor.
	IMAGE_RESOURCE_DIRECTORY              stResDirRoot;    //Level 1 standard 
                                                           //IMAGE_RESOURCE_DIRECTORY header.
	std::vector<LIBPE_RESOURCE_ROOT_DATA> vecResRoot;      //Array of level 1 resource entries.
};
using PCLIBPE_RESOURCE_ROOT = const LIBPE_RESOURCE_ROOT*;
Example

The next code excerpt populates std::wstring with all resources' types and names, that PE binary possesses, and prints it to the standard std::wcout.

#include <iostream>
#include <map>
#include "libpe.h"

using namespace libpe;

//Helper map
const std::map<WORD, std::wstring> g_mapResType {
{ 1, L"RT_CURSOR" },
{ 2, L"RT_BITMAP" },
{ 3, L"RT_ICON" },
{ 4, L"RT_MENU" },
{ 5, L"RT_DIALOG" },
{ 6, L"RT_STRING" },
{ 7, L"RT_FONTDIR" },
{ 8, L"RT_FONT" },
{ 9, L"RT_ACCELERATOR" },
{ 10, L"RT_RCDATA" },
{ 11, L"RT_MESSAGETABLE" },
{ 12, L"RT_GROUP_CURSOR" },
{ 14, L"RT_GROUP_ICON" },
{ 16, L"RT_VERSION" },
{ 17, L"RT_DLGINCLUDE" },
{ 19, L"RT_PLUGPLAY" },
{ 20, L"RT_VXD" },
{ 21, L"RT_ANICURSOR" },
{ 22, L"RT_ANIICON" },
{ 23, L"RT_HTML" },
{ 24, L"RT_MANIFEST" },
{ 28, L"RT_RIBBON_XML" },
{ 240, L"RT_DLGINIT" },
{ 241, L"RT_TOOLBAR" }
};

libpe_ptr pLibpe { Createlibpe() };
if (pLibpe->LoadPe(L"C:\\PATH_TO_PE_FILE") != S_OK)
    return;

PCLIBPE_RESOURCE_ROOT pResRoot;
if (pLibpe->GetResources(pResRoot) != S_OK)
    return;

WCHAR wstr[MAX_PATH];
long ilvlRoot = 0, ilvl2 = 0, ilvl3 = 0;
std::wstring wstring; // This wstring will contain all resources by name.

//Main loop to extract Resources.
for (auto& iterRoot : pResRoot->vecResRoot)
{
    auto pResDirEntry = &iterRoot.stResDirEntryRoot; //ROOT IMAGE_RESOURCE_DIRECTORY_ENTRY
    if (pResDirEntry->DataIsDirectory)
    {
    	if (pResDirEntry->NameIsString)
            swprintf(wstr, MAX_PATH, L"Entry: %li [Name: %s]", 
                     ilvlRoot, iterRoot.wstrResNameRoot.data());
    	else
    	{
            auto iter = g_mapResType.find(pResDirEntry->Id);
            if (iter != g_mapResType.end())
                swprintf(wstr, MAX_PATH, L"Entry: %li [Id: %u, %s]", 
                         ilvlRoot, pResDirEntry->Id, iter->second.data());
            else
                swprintf(wstr, MAX_PATH, L"Entry: %li [Id: %u]", ilvlRoot, pResDirEntry->Id);
        }

        wstring += wstr;
        wstring += L"\r\n";
        ilvl2 = 0;

        auto pstResLvL2 = &iterRoot.stResLvL2;
        for (auto& iterLvL2 : pstResLvL2->vecResLvL2)
        {
            pResDirEntry = &iterLvL2.stResDirEntryLvL2; //Level 2 IMAGE_RESOURCE_DIRECTORY_ENTRY
            if (pResDirEntry->DataIsDirectory)
            {
                if (pResDirEntry->NameIsString)
                    swprintf(wstr, MAX_PATH, L"Entry: %li, Name: %s", 
                             ilvl2, iterLvL2.wstrResNameLvL2.data());
                else
                    swprintf(wstr, MAX_PATH, L"Entry: %li, Id: %u", ilvl2, pResDirEntry->Id);

                wstring += L"    ";
                wstring += wstr;
                wstring += L"\r\n";
                ilvl3 = 0;

                auto pstResLvL3 = &iterLvL2.stResLvL3;
                for (auto& iterLvL3 : pstResLvL3->vecResLvL3)
                {
                    pResDirEntry = &iterLvL3.stResDirEntryLvL3; //Level 3 
                                                                //IMAGE_RESOURCE_DIRECTORY_ENTRY
                    if (pResDirEntry->NameIsString)
                        swprintf(wstr, MAX_PATH, L"Entry: %li, Name: %s", 
                                 ilvl3, iterLvL3.wstrResNameLvL3.data());
                    else
                        swprintf(wstr, MAX_PATH, L"Entry: %li, lang: %u", 
                                 ilvl3, pResDirEntry->Id);

                    wstring += L"        ";
                    wstring += wstr;
                    wstring += L"\r\n";
                    ilvl3++;
                }
            }
            else
            {	//DATA Level 2, if any.
                pResDirEntry = &iterLvL2.stResDirEntryLvL2;

                if (pResDirEntry->NameIsString)
                    swprintf(wstr, MAX_PATH, L"Entry: %li, Name: %s", 
                             ilvl2, iterLvL2.wstrResNameLvL2.data());
                else
                    swprintf(wstr, MAX_PATH, L"Entry: %li, lang: %u", ilvl2, pResDirEntry->Id);
            }
            ilvl2++;
        }
    }
    else
    {	//DATA Level Root, if any.
        pResDirEntry = &iterRoot.stResDirEntryRoot;

        if (pResDirEntry->NameIsString)
            swprintf(wstr, MAX_PATH, L"Entry: %li, Name: %s", 
                     ilvlRoot, iterRoot.wstrResNameRoot.data());
        else
            swprintf(wstr, MAX_PATH, L"Entry: %li, lang: %u", ilvlRoot, pResDirEntry->Id);
    }
    ilvlRoot++;
}
std::wcout << wstring; //Print to wcout;

GetExceptions

HRESULT GetExceptions(PCLIBPE_EXCEPTION_VEC&);

Gets array of the file's Exception entries.

struct LIBPE_EXCEPTION {
    DWORD                         dwOffsetRuntimeFuncDesc; //File's raw offset of the 
                                                           //exceptions descriptor.
    _IMAGE_RUNTIME_FUNCTION_ENTRY stRuntimeFuncEntry;      //Standard 
                                                           //_IMAGE_RUNTIME_FUNCTION_ENTRY 
                                                           //header.
};
using LIBPE_EXCEPTION_VEC = std::vector<LIBPE_EXCEPTION>;
using PCLIBPE_EXCEPTION_VEC = const LIBPE_EXCEPTION_VEC*;

GetSecurity

HRESULT GetSecurity(PCLIBPE_SECURITY_VEC&);

Gets array of the file's Security entries.

struct LIBPE_SECURITY {
    DWORD           dwOffsetWinCertDesc; //File's raw offset of the security descriptor.
    WIN_CERTIFICATE stWinSert;           //Standard WIN_CERTIFICATE header.
};
using LIBPE_SECURITY_VEC = std::vector<LIBPE_SECURITY>;
using PCLIBPE_SECURITY_VEC = const LIBPE_SECURITY_VEC*;

GetRelocations

HRESULT GetRelocations(PCLIBPE_RELOCATION_VEC&);

Gets array of the file's relocation information.

struct LIBPE_RELOC_DATA {
    DWORD dwOffsetRelocData; //File's raw offset of the Relocation data descriptor.
    WORD  wRelocType;        //Relocation type.
    WORD  wRelocOffset;      //Relocation offset (Offset the relocation must be applied to.)
};
struct LIBPE_RELOCATION {
    DWORD                         dwOffsetReloc; //File's raw offset of the 
                                                 //Relocation descriptor.
    IMAGE_BASE_RELOCATION         stBaseReloc;   //Standard IMAGE_BASE_RELOCATION header.
    std::vector<LIBPE_RELOC_DATA> vecRelocData;  //Array of the Relocation data struct.
};
using LIBPE_RELOCATION_VEC = std::vector<LIBPE_RELOCATION>;
using PCLIBPE_RELOCATION_VEC = const LIBPE_RELOCATION_VEC*;

GetDebug

HRESULT GetDebug(PCLIBPE_DEBUG_VEC&);

Gets array of the file's Debug entries.

struct LIBPE_DEBUG_DBGHDR
{
    //dwHdr[6] is an array of the first six DWORDs of 
    //IMAGE_DEBUG_DIRECTORY::PointerToRawData data (Debug info header).
    //Their meaning varies depending on dwHdr[0] (Signature) value.
    //If dwHdr[0] == 0x53445352 (Ascii "RSDS") it's PDB 7.0 file:
    // Then dwHdr[1]-dwHdr[4] is GUID (*((GUID*)&dwHdr[1])). dwHdr[5] is Counter/Age.
    //If dwHdr[0] == 0x3031424E (Ascii "NB10") it's PDB 2.0 file:
    // Then dwHdr[1] is Offset. dwHdr[2] is Time/Signature. dwHdr[3] is Counter/Age.
    DWORD       dwHdr[6];
    std::string strPDBName; //PDB file name/path.
}; 
struct LIBPE_DEBUG {
    DWORD                 dwOffsetDebug;  //File's raw offset of the Debug descriptor.
    IMAGE_DEBUG_DIRECTORY stDebugDir;     //Standard IMAGE_DEBUG_DIRECTORY header.
    LIBPE_DEBUG_DBGHDR    stDebugHdrInfo; //Debug info header.
};
using LIBPE_DEBUG_VEC = std::vector<LIBPE_DEBUG>;
using PCLIBPE_DEBUG_VEC = const LIBPE_DEBUG_VEC*;

GetTLS

HRESULT GetTLS(PCLIBPE_TLS&);

Gets file's Thread Local Storage information.

struct LIBPE_TLS {
    DWORD              dwOffsetTLS;       //File's raw offset of the TLS header descriptor.
    union LIBPE_TLS_VAR {
    	IMAGE_TLS_DIRECTORY32 stTLSDir32; //x86 standard TLS header.
    	IMAGE_TLS_DIRECTORY64 stTLSDir64; //x64 TLS header.
    }varTLS;
    std::vector<DWORD> vecTLSCallbacks;   //Array of the TLS callbacks.
};
using PCLIBPE_TLS = const LIBPE_TLS*;

GetLoadConfig

HRESULT GetLoadConfig(PCLIBPE_LOADCONFIG&);

Gets files's LCD info.

struct LIBPE_LOADCONFIG {
    DWORD dwOffsetLCD; //File's raw offset of the LCD descriptor.
    union LIBPE_LOADCONFIG_VAR {
    	IMAGE_LOAD_CONFIG_DIRECTORY32 stLCD32; //x86 LCD descriptor.
    	IMAGE_LOAD_CONFIG_DIRECTORY64 stLCD64; //x64 LCD descriptor.
    }varLCD;
};
using PCLIBPE_LOADCONFIG = const LIBPE_LOADCONFIG*;

GetBoundImport

HRESULT GetBoundImport(PCLIBPE_BOUNDIMPORT_VEC&);

Gets array of the file's Bound Import entries.

struct LIBPE_BOUNDFORWARDER {
    DWORD                     dwOffsetBoundForwDesc; //File's raw offset of the 
                                                     //Bound Forwarder descriptor.
    IMAGE_BOUND_FORWARDER_REF stBoundForwarder;      //Standard IMAGE_BOUND_FORWARDER_REF 
                                                     //struct.
    std::string               strBoundForwarderName; //Bound forwarder name.
};
struct LIBPE_BOUNDIMPORT {
    DWORD                             dwOffsetBoundImpDesc; //File's raw offset of the 
                                                            //Bound Import descriptor.
    IMAGE_BOUND_IMPORT_DESCRIPTOR     stBoundImpDesc;       //Standard 
                                                            //IMAGE_BOUND_IMPORT_DESCRIPTOR 
                                                            //struct.
    std::string                       strBoundName;         //Bound Import name.
    std::vector<LIBPE_BOUNDFORWARDER> vecBoundForwarder;    //Array of the Bound Forwarder 
                                                            //structs.
};
using LIBPE_BOUNDIMPORT_VEC = std::vector<LIBPE_BOUNDIMPORT>;
using PCLIBPE_BOUNDIMPORT_VEC = const LIBPE_BOUNDIMPORT_VEC*;

GetDelayImport

HRESULT GetDelayImport(PCLIBPE_DELAYIMPORT_VEC&);

Gets array of the file's Delay Import entries.

struct LIBPE_DELAYIMPORT_FUNC {
    union LIBPE_DELAYIMPORT_THUNK_VAR
    {
    	struct x32 {
    	    IMAGE_THUNK_DATA32 stImportAddressTable;      //x86 Import Address Table struct.
    	    IMAGE_THUNK_DATA32 stImportNameTable;         //x86 Import Name Table struct.
    	    IMAGE_THUNK_DATA32 stBoundImportAddressTable; //x86 Bound Import Address 
                                                          //Table struct.
    	    IMAGE_THUNK_DATA32 stUnloadInformationTable;  //x86 Unload Information Table struct.
    	}st32;
    	struct x64 {
    	    IMAGE_THUNK_DATA64 stImportAddressTable;      //x64 Import Address Table struct.
    	    IMAGE_THUNK_DATA64 stImportNameTable;         //x64 Import Name Table struct.
            IMAGE_THUNK_DATA64 stBoundImportAddressTable; //x64 Bound Import Address 
                                                          //Table struct
            IMAGE_THUNK_DATA64 stUnloadInformationTable;  //x64 Unload Information Table struct.
    	}st64;
    }varThunk;
    IMAGE_IMPORT_BY_NAME stImpByName; //Standard IMAGE_IMPORT_BY_NAME struct.
    std::string          strFuncName; //Function name.
};
struct LIBPE_DELAYIMPORT {
    DWORD                               dwOffsetDelayImpDesc; //File's raw offset of the 
                                                              //Delay Import descriptor.
    IMAGE_DELAYLOAD_DESCRIPTOR          stDelayImpDesc;       //Standard 
                                                              //IMAGE_DELAYLOAD_DESCRIPTOR 
                                                              //struct.
    std::string                         strModuleName;        //Import module name.
    std::vector<LIBPE_DELAYIMPORT_FUNC> vecDelayImpFunc;      //Array of the Delay Import 
                                                              //module functions.
};
using LIBPE_DELAYIMPORT_VEC = std::vector<LIBPE_DELAYIMPORT>;
using PCLIBPE_DELAYIMPORT_VEC = const LIBPE_DELAYIMPORT_VEC*;

GetCOMDescriptor

HRESULT GetCOMDescriptor(PCLIBPE_COMDESCRIPTOR&);

Gets file's .NET info.

struct LIBPE_COMDESCRIPTOR {
    DWORD              dwOffsetComDesc; //File's raw offset of the 
                                        //IMAGE_COR20_HEADER descriptor.
    IMAGE_COR20_HEADER stCorHdr;        //Standard IMAGE_COR20_HEADER struct.
};
using PCLIBPE_COMDESCRIPTOR = const LIBPE_COMDESCRIPTOR*;

Destroy

HRESULT Destroy();

Destroys the libpe object.
You don't usually call this method, it will be called automatically during object destruction.

Exported Functions

libpe has few "C" interface functions which it exports.

CreateRawlibpe

extern "C" ILIBPEAPI HRESULT __cdecl CreateRawlibpe(Ilibpe*&);

It's the main function that creates raw Ilibpe interface pointer, but you barely need to use it in your code.
See the Usage section for more information.

libpeInfo

extern "C" ILIBPEAPI PCLIBPE_INFO __cdecl libpeInfo();

Returns pointer to LIBPE_INFO, which is libpe service information structure.

struct LIBPE_INFO
{
    const wchar_t* pwszVersion { };        //WCHAR version string.
    union {
        unsigned long long ullVersion { }; //ULONGLONG version number.
        struct {
            short wMajor;
            short wMinor;
            short wMaintenance;
            short wRevision;
        }stVersion;
    };
};
using PCLIBPE_INFO = const LIBPE_INFO*;

Error Codes

All libpe methods return S_OK code when they executed successfully.
Although, if something goes wrong, the error codes come onto the scene.

Error code Value
E_CALL_LOADPE_FIRST 0xFFFF
E_FILE_CREATEFILE_FAILED 0x0010
E_FILE_SIZE_TOO_SMALL 0x0011
E_FILE_CREATEFILEMAPPING_FAILED 0x0012
E_FILE_MAPVIEWOFFILE_FAILED 0x0013
E_FILE_MAPVIEWOFFILE_SECTION_FAILED 0x0014
E_FILE_SECTION_DATA_CORRUPTED 0x0015
E_IMAGE_TYPE_UNSUPPORTED 0x0016
E_IMAGE_HAS_NO_DOSHEADER 0x0017
E_IMAGE_HAS_NO_RICHHEADER 0x0018
E_IMAGE_HAS_NO_NTHEADER 0x0019
E_IMAGE_HAS_NO_FILEHEADER 0x001A
E_IMAGE_HAS_NO_OPTHEADER 0x001B
E_IMAGE_HAS_NO_DATADIRECTORIES 0x001C
E_IMAGE_HAS_NO_SECTIONS 0x001D
E_IMAGE_HAS_NO_EXPORT 0x001E
E_IMAGE_HAS_NO_IMPORT 0x001F
E_IMAGE_HAS_NO_RESOURCE 0x0020
E_IMAGE_HAS_NO_EXCEPTION 0x0021
E_IMAGE_HAS_NO_SECURITY 0x0022
E_IMAGE_HAS_NO_BASERELOC 0x0023
E_IMAGE_HAS_NO_DEBUG 0x0024
E_IMAGE_HAS_NO_ARCHITECTURE 0x0025
E_IMAGE_HAS_NO_GLOBALPTR 0x0026
E_IMAGE_HAS_NO_TLS 0x0027
E_IMAGE_HAS_NO_LOADCONFIG 0x0028
E_IMAGE_HAS_NO_BOUNDIMPORT 0x0029
E_IMAGE_HAS_NO_IAT 0x002A
E_IMAGE_HAS_NO_DELAYIMPORT 0x002B
E_IMAGE_HAS_NO_COMDESCRIPTOR 0x002C

If you want to get these error codes in readable format, here is the helper std::map.

#define TO_WSTR_MAP(x) {x, L## #x}
inline const std::map<DWORD, std::wstring> g_mapLibpeErrors {
    TO_WSTR_MAP(E_CALL_LOADPE_FIRST),
    TO_WSTR_MAP(E_FILE_CREATEFILE_FAILED),
    TO_WSTR_MAP(E_FILE_SIZE_TOO_SMALL),
    TO_WSTR_MAP(E_FILE_CREATEFILEMAPPING_FAILED),
    TO_WSTR_MAP(E_FILE_MAPVIEWOFFILE_FAILED),
    TO_WSTR_MAP(E_FILE_MAPVIEWOFFILE_SECTION_FAILED),
    TO_WSTR_MAP(E_FILE_SECTION_DATA_CORRUPTED),
    TO_WSTR_MAP(E_IMAGE_TYPE_UNSUPPORTED),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_DOSHEADER),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_RICHHEADER),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_NTHEADER),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_FILEHEADER),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_OPTHEADER),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_DATADIRECTORIES),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_SECTIONS),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_EXPORT),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_IMPORT),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_RESOURCE),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_EXCEPTION),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_SECURITY),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_BASERELOC),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_DEBUG),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_ARCHITECTURE),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_GLOBALPTR),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_TLS),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_LOADCONFIG),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_BOUNDIMPORT),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_IAT),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_DELAYIMPORT),
    TO_WSTR_MAP(E_IMAGE_HAS_NO_COMDESCRIPTOR)
};

You can use it as follows:

libpe_ptr pLibpe { Createlibpe() };

HRESULT hr = pLibpe->LoadPe(L"C:\\MyFile.exe");
if (hr != S_OK)
{
    WCHAR wstr[MAX_PATH];
    const auto it = g_mapLibpeErrors.find(hr);
    if (it != g_mapLibpeErrors.end())
    	swprintf_s(wstr, L"File load failed with libpe error code: 
                   0x0%X\n%s", hr, it->second.data());
    else
    	swprintf_s(wstr, L"File load failed with libpe error code: 0x0%X", hr);

    MessageBoxW(nullptr, wstr, L"File load failed.", MB_ICONERROR);
}

License

This software is available under the MIT License.

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Jovibor
Russian Federation Russian Federation
No Biography provided

Comments and Discussions

 
QuestionHow list the exports function of a dll Pin
Apprieu (Apprieu)7-Dec-19 2:58
MemberApprieu (Apprieu)7-Dec-19 2:58 
AnswerRe: How list the exports function of a dll Pin
Jovibor8-Dec-19 13:43
MemberJovibor8-Dec-19 13:43 
QuestionHow list List Library ? Pin
Apprieu (Apprieu)16-Nov-19 7:28
MemberApprieu (Apprieu)16-Nov-19 7:28 
AnswerRe: How list List Library ? Pin
Jovibor16-Nov-19 13:06
MemberJovibor16-Nov-19 13:06 
PraiseMy vote of 5 Pin
Michael Haephrati6-Nov-19 12:21
professionalMichael Haephrati6-Nov-19 12:21 
SuggestionComment/Uncomment Pin
soho31-Oct-19 3:12
Membersoho31-Oct-19 3:12 
GeneralRe: Comment/Uncomment Pin
Jovibor31-Oct-19 7:30
MemberJovibor31-Oct-19 7:30 
BugWrong github URL Pin
Alexandre Bencz12-Sep-19 15:20
MemberAlexandre Bencz12-Sep-19 15:20 
GeneralRe: Wrong github URL Pin
Jovibor12-Sep-19 15:57
MemberJovibor12-Sep-19 15:57 
GeneralRe: Wrong github URL Pin
Red1_KM22-Sep-19 9:28
professionalRed1_KM22-Sep-19 9:28 
QuestionHox Add MFC control like Dlg About Pin
Apprieu (Apprieu)9-Sep-19 6:20
MemberApprieu (Apprieu)9-Sep-19 6:20 
AnswerRe: Hox Add MFC control like Dlg About Pin
Jovibor9-Sep-19 7:22
MemberJovibor9-Sep-19 7:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Stats

12.3K views
69 downloads
19 bookmarked