libpe Библиотека разбора бинарных файлов PE32/PE32+
Библиотека для анализа внутренних структур PE32/PE32+ бинарных файлов
Введение
libpe – это легкая и очень быстрая библиотека для разбора бинарных файлов PE32 (x86) и PE32+ (x64), реализованная в виде модуля C++20.
Содержание
- Особенности
- Использование
- Методы классаExpand
- Вспомогательные методыExpand
- КартыExpand
- Лицензия
Особенности
- Работает с бинарными файлами PE32 (x86) и PE32+ (x64)
- Получает все структуры данных PE32 / PE32+:
- Заголовок MSDOS
- «Rich» заголовок
- NT / Файл / Опциональные заголовки
- Таблицы данных
- Разделы
- Таблица экспорта
- Таблица импорта
- Таблица ресурсов
- Таблица исключений
- Таблица безопасности
- Таблица перемещений
- Таблица отладки
- Таблица TLS
- Каталог конфигурации загрузки
- Таблица связанного импорта
- Таблица отложенного импорта
- Таблица COM
Pepper – одно из приложений, которое построено на основе libpe
.
Использование
import libpe; int main() { libpe::Clibpe pe(L"C:\\myFile.exe"); //или pe.OpenFile(L"C:\\myFile.exe"); const auto peImp = pe.GetImport(); if(peImp) { ... } ... }
Методы
OpenFile
auto OpenFile(const wchar_t* pwszFile)->int;
Открывает файл для дальнейшей обработки, пока не будет вызвано CloseFile
или объект Clibpe
выйдет из области видимости и файл будет закрыт автоматически в деструкторе.
libpe::Clibpe pe; if(pe.OpenFile(L"C:\\MyFile.exe") == PEOK) { ... }
CloseFile();
void CloseFile();
Явно закрывает ранее открытый файл с помощью OpenFile(const wchar_t*)
. Этот метод вызывается автоматически в деструкторе Clibpe
.
GetDOSHeader
[[nodiscard]] auto GetDOSHeader()const->std::optional<IMAGE_DOS_HEADER>;
Возвращает стандартный заголовок MS-DOS файла.
GetRichHeader
[[nodiscard]] auto GetRichHeader()const->std::optional<PERICHHDR_VEC>;
Возвращает массив так называемых неподтвержденных и неофициальных «Rich» структур.
struct PERICHHDR { DWORD dwOffset; //Смещение записи файла. WORD wId; //Идентификатор записи. WORD wVersion; //Версия записи. DWORD dwCount; //Количество вхождений. }; using PERICHHDR_VEC = std::vector<PERICHHDR>;
GetNTHeader
[[nodiscard]] auto GetNTHeader()const->std::optional<PENTHDR>;
Возвращает заголовок NT файла.
struct PENTHDR { DWORD dwOffset; //Смещение заголовка файла. union UNPENTHDR { //Объединение x86 или x64 NT заголовка. IMAGE_NT_HEADERS32 stNTHdr32; //Заголовок x86. IMAGE_NT_HEADERS64 stNTHdr64; //Заголовок x64. } unHdr; };
GetDataDirs
[[nodiscard]] auto GetDataDirs()const->std::optional<PEDATADIR_VEC>;
Возвращает массив структур каталогов данных файла.
struct PEDATADIR { IMAGE_DATA_DIRECTORY stDataDir; //Стандартный заголовок. std::string strSection; //Имя секции, в которой находится этот каталог (указывает на нее). }; using PEDATADIR_VEC = std::vector<PEDATADIR>;
GetSecHeaders
[[nodiscard]] auto GetSecHeaders()const->std::optional<PESECHDR_VEC>;
Возвращает массив структур заголовков секций файла.
struct PESECHDR { DWORD dwOffset; //Смещение дескриптора заголовков секций файла. IMAGE_SECTION_HEADER stSecHdr; //Стандартный заголовок секции. std::string strSecName; //Полное имя секции. }; using PESECHDR_VEC = std::vector<PESECHDR>;
GetExport
[[nodiscard]] auto GetExport()const->std::optional<PEEXPORT>;
Возвращает информацию о экспорте файла.
struct PEEXPORTFUNC { DWORD dwFuncRVA; // RVA функции. DWORD dwOrdinal; // Ординал функции. DWORD dwNameRVA; // RVA имени функции. std::string strFuncName; // Имя функции. std::string strForwarderName; // Имя переадресованной функции. }; struct PEEXPORT { DWORD dwOffset; // Смещение в файле для дескриптора заголовка экспорта. IMAGE_EXPORT_DIRECTORY stExportDesc; // Стандартный дескриптор заголовка экспорта. std::string strModuleName; // Фактическое имя модуля. std::vector<PEEXPORTFUNC> vecFuncs; // Массив структур экспортированных функций. };
Пример:
libpe::Clibpe pe(L"ПУТЬ_К_ФАЙЛУ_PE"); const auto peExport = pe.GetExport(); if (!peExport) { return; } peExport->stExportDesc; // Структура IMAGE_EXPORT_DIRECTORY. peExport->strModuleName; // Имя экспортируемого модуля. peExport->vecFuncs; // Вектор экспортируемых функций. for (const auto& itFuncs : peExport->vecFuncs) { itFuncs.strFuncName; // Имя функции. itFuncs.dwOrdinal; // Ординал. itFuncs.dwFuncRVA; // RVA функции. itFuncs.strForwarderName; // Имя переадресованной функции. }
GetImport
[[nodiscard]] auto GetImport()const->std::optional<PEIMPORT_VEC>;
Возвращает массив записей таблицы импорта файла.
struct PEIMPORTFUNC { union UNPEIMPORTTHUNK { IMAGE_THUNK_DATA32 stThunk32; // Стандартная заглушка x86. IMAGE_THUNK_DATA64 stThunk64; // Стандартная заглушка x64. } unThunk; IMAGE_IMPORT_BY_NAME stImpByName; // Структура стандартного IMAGE_IMPORT_BY_NAME. std::string strFuncName; // Имя функции. }; struct PEIMPORT { DWORD dwOffset; // Смещение в файле для дескриптора импорта. IMAGE_IMPORT_DESCRIPTOR stImportDesc; // Стандартный дескриптор импорта. std::string strModuleName; // Импортируемое имя модуля. std::vector<PEIMPORTFUNC> vecImportFunc; // Массив импортируемых функций. }; using PEIMPORT_VEC = std::vector<PEIMPORT>;
Пример:
libpe::Clibpe pe(L"C:\\Windows\\notepad.exe"); const auto peImp = pe.GetImport(); if (!peImp) { return -1; } for (const auto& itModule : *peImp) { // Цикл по всем импортам, которые // содержит данный PE-файл. std::cout << std::format("{}, Imported funcs: {}\r\n", itModule.strModuleName, itModule.vecImportFunc.size()); for (const auto& itFuncs : itModule.vecImportFunc) { // Цикл по всем функциям, импортированным из модуля itModule. itFuncs.strFuncName; // Имя импортированной функции. itFuncs.stImpByName; // Структура IMAGE_IMPORT_BY_NAME для этой функции. itFuncs.unThunk.stThunk32; // Объединение IMAGE_THUNK_DATA32 или // IMAGE_THUNK_DATA64 (в зависимости от типа PE). } }
GetResources
[[nodiscard]] auto GetResources()const->std::optional<PERESROOT>;
Возвращает все ресурсы файла.
Пример:
Следующий фрагмент кода заполняет std::wstring
типами и именами всех ресурсов, которыми обладает файл PE, и выводит его в стандартный std::wcout
.
#include <format> #include <iostream> #include <string> import libpe; using namespace libpe; int main() { libpe::Clibpe pe; if (pe.OpenFile(L"C:\\Windows\\notepad.exe") != PEOK) { return -1; } const auto peResRoot = pe.GetResources(); if (!peResRoot) { return -1; } std::wstring wstrResData; // Этот wstring будет содержать все ресурсы по имени. for (const auto& iterRoot : peResRoot->vecResData) { // Основной цикл извлечения ресурсов. auto ilvlRoot = 0; auto pResDirEntry = &iterRoot.stResDirEntry; // КОРНЕВОЙ IMAGE_RESOURCE_DIRECTORY_ENTRY if (pResDirEntry->NameIsString) { wstrResData += std::format(L"Entry: {} [Name: {}]\r\n", ilvlRoot, iterRoot.wstrResName); } else { if (const auto iter = MapResID.find(pResDirEntry->Id); iter != MapResID.end()) { wstrResData += std::format(L"Entry: {} [Id: {}, {}]\r\n", ilvlRoot, pResDirEntry->Id, iter->second); } else { wstrResData += std::format(L"Entry: {} [Id: {}]\r\n", ilvlRoot, pResDirEntry->Id); } } if (pResDirEntry->DataIsDirectory) { auto ilvl2 = 0; auto pstResLvL2 = &iterRoot.stResLvL2; for (const auto& iterLvL2 : pstResLvL2->vecResData) { pResDirEntry = &iterLvL2.stResDirEntry; // Уровень 2 // IMAGE_RESOURCE_DIRECTORY_ENTRY if (pResDirEntry->NameIsString) { wstrResData += std::format (L" Entry: {}, Name: {}\r\n", ilvl2, iterLvL2.wstrResName); } else { wstrResData += std::format (L" Entry: {}, Id: {}\r\n", ilvl2, pResDirEntry->Id); } if (pResDirEntry->DataIsDirectory) { auto ilvl3 = 0; auto pstResLvL3 = &iterLvL2.stResLvL3; for (const auto& iterLvL3 : pstResLvL3->vecResData) { pResDirEntry = &iterLvL3.stResDirEntry; // Уровень 3 // IMAGE_RESOURCE_DIRECTORY_ENTRY if (pResDirEntry->NameIsString) { wstrResData += std::format (L" Entry: {}, Name: {}\r\n", ilvl3, iterLvL3.wstrResName); } else { wstrResData += std::format (L" Entry: {}, lang: {}\r\n", ilvl3, pResDirEntry->Id); } ++ilvl3; } } ++ilvl2; } } ++ilvlRoot; } std::wcout << wstrResData;
GetExceptions
[[nodiscard]] auto GetExceptions()const->std::optional<PEEXCEPTION_VEC>;
Возвращает массив записей Исключений файла.
struct PEEXCEPTION { DWORD dwOffset; //Смещение относительно начала //файла для дескриптора исключений. _IMAGE_RUNTIME_FUNCTION_ENTRY stRuntimeFuncEntry; //Стандартный //заголовок _IMAGE_RUNTIME_FUNCTION_ENTRY. }; using PEEXCEPTION_VEC = std::vector<PEEXCEPTION>;
GetSecurity
[[nodiscard]] auto GetSecurity()const->std::optional<PESECURITY_VEC>;
Возвращает массив записей Безопасности файла.
struct PEWIN_CERTIFICATE { //Полная копия структуры WIN_CERTIFICATE //из <WinTrust.h>. DWORD dwLength; WORD wRevision; WORD wCertificateType; BYTE bCertificate[1]; }; struct PESECURITY { DWORD dwOffset; //Смещение относительно начала файла для данного дескриптора безопасности. PEWIN_CERTIFICATE stWinSert; //Структура WIN_CERTIFICATE. }; using PESECURITY_VEC = std::vector<PESECURITY>;
GetRelocations
[[nodiscard]] auto GetRelocations()const->std::optional<PERELOC_VEC>;
Возвращает массив информации о перемещениях файла.
struct PERELOCDATA { DWORD dwOffset; //Смещение относительно начала файла для дескриптора данных о перемещении. WORD wRelocType; //Тип перемещения. WORD wRelocOffset; //Смещение перемещения (смещение, к которому необходимо применить перемещение). }; struct PERELOC { DWORD dwOffset; //Смещение относительно начала файла для //дескриптора перемещения. IMAGE_BASE_RELOCATION stBaseReloc; //Стандартный заголовок IMAGE_BASE_RELOCATION. std::vector<PERELOCDATA> vecRelocData; //Массив структур данных о перемещении. }; using PERELOC_VEC = std::vector<PERELOC>;
GetDebug
[[nodiscard]] auto GetDebug()const->std::optional<PEDEBUG_VEC>;
Возвращает массив записей Отладки файла.
struct PEDEBUGDBGHDR { //dwHdr[6] - массив из первых шести DWORD //данных IMAGE_DEBUG_DIRECTORY::PointerToRawData (заголовок отладочной информации). //Их значение зависит от значения dwHdr[0] (сигнатуры). //Если dwHdr[0] == 0x53445352 (Ascii "RSDS"), то это файл PDB 7.0: // Затем dwHdr[1]-dwHdr[4] - это GUID (*((GUID*)&dwHdr[1])). dwHdr[5] - счетчик/возраст. //Если dwHdr[0] == 0x3031424E (Ascii "NB10"), то это файл PDB 2.0: // Тогда dwHdr[1] - это смещение. dwHdr[2] - это время/сигнатура. dwHdr[3] - счетчик/возраст. DWORD dwHdr[6]; std::string strPDBName; //Имя/путь к файлу PDB. }; struct PEDEBUG { DWORD dwOffset; //Смещение относительно начала файла для дескриптора отладки. IMAGE_DEBUG_DIRECTORY stDebugDir; //Стандартный заголовок IMAGE_DEBUG_DIRECTORY. PEDEBUGDBGHDR stDebugHdrInfo; //Заголовок отладочной информации. }; using PEDEBUG_VEC = std::vector<PEDEBUG>;
GetTLS
[[nodiscard]] auto GetTLS()const->std::optional<PETLS>;
Возвращает информацию о Местном хранилище потоков файла.
struct PETLS { DWORD dwOffset; //Смещение относительно начала файла для //заголовка местного хранилища потоков. union UNPETLS { IMAGE_TLS_DIRECTORY32 stTLSDir32; //Стандартный заголовок x86 для местного хранилища потоков. IMAGE_TLS_DIRECTORY64 stTLSDir64; //Заголовок местного хранилища потоков x64. } unTLS; std::vector<DWORD> vecTLSCallbacks; //Массив обратных вызовов местного хранилища потоков. };
GetLoadConfig
[[nodiscard]] auto GetLoadConfig()const->std::optional;;
Возвращает информацию о каталоге Load Config файла.
struct PELOADCONFIG { DWORD dwOffset; // Файловый смещение описателя LCD. union UNPELOADCONFIG { IMAGE_LOAD_CONFIG_DIRECTORY32 stLCD32; // Описатель LCD x86. IMAGE_LOAD_CONFIG_DIRECTORY64 stLCD64; // Описатель LCD x64. } unLCD; };
GetBoundImport
[[nodiscard]] auto GetBoundImport()const->std::optional;;
Возвращает массив записей Bound Import файла.
struct PEBOUNDFORWARDER { DWORD dwOffset; // Файловое смещение описателя Bound Forwarder. IMAGE_BOUND_FORWARDER_REF stBoundForwarder; // Стандартная структура IMAGE_BOUND_FORWARDER_REF. std::string strBoundForwarderName; // Имя привязанного экспорта. }; struct PEBOUNDIMPORT { DWORD dwOffset; // Файловое смещение описателя Bound Import. IMAGE_BOUND_IMPORT_DESCRIPTOR stBoundImpDesc; // Стандартная структура IMAGE_BOUND_IMPORT_DESCRIPTOR. std::string strBoundName; // Имя Bound Import. std::vector vecBoundForwarder; // Массив структур Bound Forwarder. }; using PEBOUNDIMPORT_VEC = std::vector;;
GetDelayImport
[[nodiscard]] auto GetDelayImport()const->std::optional;;
Возвращает массив записей Delay Import файла.
struct PEDELAYIMPORTFUNC { union UNPEDELAYIMPORTTHUNK { struct x32 { IMAGE_THUNK_DATA32 stImportAddressTable; // x86 структура Import Address Table. IMAGE_THUNK_DATA32 stImportNameTable; // x86 структура Import Name Table. IMAGE_THUNK_DATA32 stBoundImportAddressTable; // x86 структура Bound Import Address Table. IMAGE_THUNK_DATA32 stUnloadInformationTable; // x86 структура Unload Information Table. } st32; struct x64 { IMAGE_THUNK_DATA64 stImportAddressTable; // x64 структура Import Address Table. IMAGE_THUNK_DATA64 stImportNameTable; // x64 структура Import Name Table. IMAGE_THUNK_DATA64 stBoundImportAddressTable; // x64 структура Bound Import Address Table. IMAGE_THUNK_DATA64 stUnloadInformationTable; // x64 структура Unload Information Table. } st64; } unThunk; IMAGE_IMPORT_BY_NAME stImpByName; // Стандартная структура IMAGE_IMPORT_BY_NAME. std::string strFuncName; // Имя функции. }; struct PEDELAYIMPORT { DWORD dwOffset; // Файловое смещение этого записи Delay Import. IMAGE_DELAYLOAD_DESCRIPTOR stDelayImpDesc; // Стандартная структура IMAGE_DELAYLOAD_DESCRIPTOR. std::string strModuleName; // Имя импортируемого модуля. std::vector vecDelayImpFunc; // Массив функций модуля Delay Import. }; using PEDELAYIMPORT_VEC = std::vector;;
GetCOMDescriptor
[[nodiscard]] auto GetCOMDescriptor()const->std::optional;;
Возвращает информацию о файле .NET.
struct PECOMDESCRIPTOR { DWORD dwOffset; // Файловое смещение описателя IMAGE_COR20_HEADER. IMAGE_COR20_HEADER stCorHdr; // Стандартная структура IMAGE_COR20_HEADER. };
Вспомогательные методы
Эти автономные методы не требуют активного объекта Clibpe
с открытым файлом. Вместо этого они принимают ссылки на ранее полученные структуры.
GetFileType
[[nodiscard]] inline constexpr auto GetFileType(const PENTHDR& stNTHdr)->EFileType
Возвращает тип файла PE в виде перечисления EFileType
.
enum class EFileType : std::uint8_t { UNKNOWN = 0, PE32, PE64, PEROM };
GetImageBase
[[nodiscard]] inline constexpr auto GetImageBase(const PENTHDR& stNTHdr)->ULONGLONG
Возвращает базовый адрес файла.
GetOffsetFromRVA
[[nodiscard]] inline constexpr auto GetOffsetFromRVA (ULONGLONG ullRVA, const PESECHDR_VEC& vecSecHdr)->DWORD
Преобразует RVA файла в физическое смещение файла на диске.
FlatResources
[[nodiscard]] inline constexpr auto FlatResources(const PERESROOT& stResRoot)
Эта функция является своего рода упрощенной версией метода GetResources
. Она принимает структуру PERESROOT
, возвращаемую методом GetResources
, и возвращает std::vector
структур PERESFLAT
. PERESFLAT
– это легкая структура, которая содержит только указатели на фактические данные ресурсов, в отличие от тяжелой структуры PERESROOT
. Функция FlatResources
сглаживает все ресурсы, делая доступ к ним более удобным.
struct PERESFLAT { std::span<const std::byte> spnData { }; // Данные ресурса. std::wstring_view wsvTypeStr { }; // Название типа ресурса. std::wstring_view wsvNameStr { }; // Название ресурса (собственное имя ресурса). std::wstring_view wsvLangStr { }; // Название языка ресурса. WORD wTypeID { }; // Идентификатор типа ресурса //(RT_CURSOR, RT_BITMAP и т.д.). WORD wNameID { }; // Идентификатор имени ресурса (собственный идентификатор ресурса). WORD wLangID { }; // Идентификатор языка ресурса. }; using PERESFLAT_VEC = std::vector<PERESFLAT>;
Maps
Файл PE состоит из множества структур, которые в свою очередь содержат множество полей, некоторые из которых имеют предопределенные значения. Эти карты предназначены для упрощения преобразования таких полей в формат, понятный человеку. Они представляют собой простые карты std::unordered_map<DWORD, std::wstring_view>
.
Обратите внимание, что некоторые поля могут иметь только одно значение, в то время как другие могут объединять множество значений с помощью побитовой операции или |
.
MapFileHdrMachine
Эта карта формирует одно из значений поля IMAGE_NT_HEADERS::IMAGE_FILE_HEADER::Machine
.
MapFileHdrCharact
Эта карта формирует одно или несколько значений из поля IMAGE_NT_HEADERS::IMAGE_FILE_HEADER::Characteristics
.
const auto pNTHdr = m_pLibpe->GetNTHeader(); const auto pDescr = &pNTHdr->unHdr.stNTHdr32.FileHeader; //Одинаково для x86/x64. std::wstring wstrCharact; for (const auto& flags : MapFileHdrCharact) { if (flags.first & pDescr->Characteristics) { wstrCharact += flags.second; wstrCharact += L"\n"; } }
MapOptHdrMagic
Эта карта формирует одно из значений поля IMAGE_NT_HEADERS::IMAGE_OPTIONAL_HEADER::Magic
.
MapOptHdrSubsystem
Эта карта формирует одно из значений поля IMAGE_NT_HEADERS::IMAGE_OPTIONAL_HEADER::Subsystem
.
MapOptHdrDllCharact
Эта карта формирует одно или несколько значений из поля IMAGE_NT_HEADERS::IMAGE_OPTIONAL_HEADER::DllCharacteristics
.
const auto pNTHdr = m_pLibpe->GetNTHeader(); const auto pOptHdr = &pNTHdr->unHdr.stNTHdr32.OptionalHeader //For x64: //pNTHdr->unHdr.stNTHdr64.OptionalHeader std::wstring wstrCharact; for (const auto& flags : MapOptHdrDllCharact) { if (flags.first & pOptHdr->DllCharacteristics) { wstrCharact += flags.second; wstrCharact += L"\n"; } }
MapSecHdrCharact
Этот map формирует одно или несколько значений из поля IMAGE_SECTION_HEADER::Characteristics
.
const auto pSecHeaders = m_pLibpe->GetSecHeaders(); std::wstring wstrCharact; auto IdOfSection = 0; //ID нужной секции. for (const auto& flags : MapSecHdrCharact) { if (flags.first & pSecHeaders->at(IdOfSection).stSecHdr.Characteristics) { wstrCharact += flags.second; wstrCharact += L"\n"; } }
MapResID
Этот map формирует одно из значений из поля IMAGE_RESOURCE_DIRECTORY_ENTRY::Id
.
MapWinCertRevision
Этот map формирует одно из значений из поля WIN_CERTIFICATE::wRevision
.
MapWinCertType
Этот map формирует одно из значений из поля WIN_CERTIFICATE::wCertificateType
.
MapRelocType
Этот map формирует одно из значений из поля PERELOCDATA::wRelocType
.
MapDbgType
Этот map формирует одно из значений из поля IMAGE_DEBUG_DIRECTORY::Type
.
MapTLSCharact
Этот map формирует одно из значений из поля IMAGE_TLS_DIRECTORY::Characteristics
.
MapLCDGuardFlags
Этот map формирует одно или несколько значений из поля IMAGE_LOAD_CONFIG_DIRECTORY::GuardFlags
.
const auto pLCD = m_pLibpe->GetLoadConfig(); const auto pPELCD = &pLCD->unLCD.stLCD32; //For x64: pLCD->unLCD.stLCD64 std::wstring wstrGFlags; for (const auto& flags : MapLCDGuardFlags) { if (flags.first & pPELCD->GuardFlags) { wstrGFlags += flags.second; wstrGFlags += L"\n"; } }
MapCOR20Flags
Этот map формирует одно или несколько значений из поля IMAGE_COR20_HEADER::Flags
.
const auto pCOMDesc = m_pLibpe->GetCOMDescriptor(); std::wstring wstrFlags; for (const auto& flags : MapCOR20Flags) { if (flags.first & pCOMDesc->stCorHdr.Flags) { wstrFlags += flags.second; wstrFlags += L"\n"; } }
Leave a Reply