#pragma once #include "../../main.h" #include "../../runtime/panic_assert.h" #include #ifdef __cplusplus extern "C" { #endif // PE Header Magic, comes after the MS-DOS stub and right before PE Header #define EXECFORMAT_PE_HEADER_MAGIC "PE\0" // comes with a \0 itself // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format typedef struct { uint16_t machineType; uint16_t numSections; uint32_t unixTimestamp; uint32_t offsetSymbolTable; uint32_t numSymbols; uint16_t sizeofOptionalHeader; uint16_t flags; // "Characteristics" } PACKED execformat_pe_Header; // Machine types #define EXECFORMAT_PE_MACHINE_UNKNOWN 0x0u // The content of this field is assumed to be applicable to any machine type #define EXECFORMAT_PE_MACHINE_AMD64 0x8664u // x64 #define EXECFORMAT_PE_MACHINE_I386 0x14cu // Intel 386 or later processors and compatible processors #define EXECFORMAT_PE_MACHINE_EBC 0xebcu // EFI byte code // Characteristics #define EXECFORMAT_PE_FLAG_RELOCS_STRIPPED 0x0001u // base relocs removed and must be loaded at its preferred base address. #define EXECFORMAT_PE_FLAG_EXECUTABLE_IMAGE 0x0002u // the image file is valid and can be run. #define EXECFORMAT_PE_FLAG_LINE_NUMS_STRIPPED 0x0004u // COFF line numbers removed. deprecated and should be zero. #define EXECFORMAT_PE_FLAG_LOCAL_SYMS_STRIPPED 0x0008u // COFF symbol table entries for local symbols removed. deprecated and should be zero. #define EXECFORMAT_PE_FLAG_AGGRESSIVE_WS_TRIM 0x0010u // Aggressively trim working set. deprecated and later and must be zero. #define EXECFORMAT_PE_FLAG_LARGE_ADDRESS_AWARE 0x0020u // Application can handle >2GB addresses. #define EXECFORMAT_PE_FLAG_RESERVED_0x0040 0x0040u #define EXECFORMAT_PE_FLAG_BYTES_REVERSED_LO 0x0080u // Little endian. This flag is deprecated and should be zero. #define EXECFORMAT_PE_FLAG_32BIT_MACHINE 0x0100u // Machine is based on a 32-bit-word architecture. #define EXECFORMAT_PE_FLAG_DEBUG_STRIPPED 0x0200u // Debugging information is removed from the image file. #define EXECFORMAT_PE_FLAG_REMOVABLE_RUN_FROM_SWAP 0x0400u // If the image is on removable media, fully load it and copy it to the swap file. #define EXECFORMAT_PE_FLAG_NET_RUN_FROM_SWAP 0x0800u // If the image is on network media, fully load it and copy it to the swap file. #define EXECFORMAT_PE_FLAG_SYSTEM 0x1000u // The image file is a system file, not a user program. #define EXECFORMAT_PE_FLAG_DLL 0x2000u // The image file is a dynamic-link library (DLL). #define EXECFORMAT_PE_FLAG_UP_SYSTEM_ONLY 0x4000u // The file should be run only on a uniprocessor machine. #define EXECFORMAT_PE_FLAG_BYTES_REVERSED_HI 0x8000u // Big endian. This flag is deprecated and should be zero. // Optional Header Magic #define EXECFORMAT_PE_OPTIONAL_HEADER_MAGIC_PE32 0x10bu // 2-byte magic for PE32 Optional Header, right following the PE Header. #define EXECFORMAT_PE_OPTIONAL_HEADER_MAGIC_PE32P 0x20bu // 2-byte magic for PE32+ Optional Header, right following the PE Header. typedef struct { uint16_t magic; // either 0x10b for PE32, or 0x20b for PE32+ uint8_t majorLinkerVersion, minorLinkerVersion; uint32_t sizeofText; // size of the .text section, or the sum of all text sections uint32_t sizeofData; // size of initialized data sections uint32_t sizeofBss; // size of uninitialized data uint32_t offsetofEntryPoint; // offset of the entry point (starting address) relative to the image base uint32_t offsetofText; // offset of the start of .text section relative to the image base } PACKED execformat_pe_OptionalHeader_StandardFields_PE32P; typedef struct { uint16_t magic; // either 0x10b for PE32, or 0x20b for PE32+ uint8_t majorLinkerVersion, minorLinkerVersion; uint32_t sizeofText; // size of the .text section, or the sum of all text sections uint32_t sizeofData; // size of initialized data sections uint32_t sizeofBss; // size of uninitialized data uint32_t offsetofEntryPoint; // offset of the entry point (starting address) relative to the image base uint32_t offsetofText; // offset of the start of .text section relative to the image base uint32_t offsetofData; // only present in PE32 images } PACKED execformat_pe_OptionalHeader_StandardFields_PE32; // PE32+ struct with a 64-bit ImageBase typedef struct { uint64_t imageBase; // The preferred address of the first byte of image when loaded into memory; must be aligned to 64K. uint32_t sectionAlignment; // The alignment (in bytes) of sections when they are loaded into memory. uint32_t fileAlignment; // The alignment factor (in bytes) that is used to align the raw data of sections in the image file. uint16_t majorOSVersion, minorOSVersion; // The version number of the required operating system. uint16_t majorImageVersion, minorImageVersion; uint16_t majorSubsystemVersion, minorSubsystemVersion; uint32_t win32VersionValue; // Reserved, must be 0 uint32_t sizeofImage; // Size in bytes of the image, including all headers as the image is loaded into memory. uint32_t sizeofHeaders; // Combined size of the MS-DOS stub, PE header, and section headers rounded up to FileAlignment. uint32_t checksum; // Checksum of an unknown(???) algorithm uint16_t subsystem; // Subsystem uint16_t dllFlags; // DLL Characteristics uint64_t sizeofStackReserve, sizeofStackCommit; uint64_t sizeofHeapReserve, sizeofHeapCommit; uint32_t loaderFlags; // Reserved, must be 0 uint32_t numRVAandSizes; // The number of data-directory entries in the remainder of the optional header. Each describes a location and size. } PACKED execformat_pe_OptionalHeader_WindowsFields_PE32P; // PE32 struct with a 32-bit ImageBase typedef struct { uint32_t imageBase; // The preferred address of the first byte of image when loaded into memory; must be aligned to 64K. uint32_t sectionAlignment; // The alignment (in bytes) of sections when they are loaded into memory. uint32_t fileAlignment; // The alignment factor (in bytes) that is used to align the raw data of sections in the image file. uint16_t majorOSVersion, minorOSVersion; // The version number of the required operating system. uint16_t majorImageVersion, minorImageVersion; uint16_t majorSubsystemVersion, minorSubsystemVersion; uint32_t win32VersionValue; // Reserved, must be 0 uint32_t sizeofImage; // Size in bytes of the image, including all headers as the image is loaded into memory. uint32_t sizeofHeaders; // Combined size of the MS-DOS stub, PE header, and section headers rounded up to FileAlignment. uint32_t checksum; // Checksum of an unknown(???) algorithm uint16_t subsystem; // Subsystem uint16_t dllFlags; // DLL Characteristics uint32_t sizeofStackReserve, sizeofStackCommit; uint32_t sizeofHeapReserve, sizeofHeapCommit; uint32_t loaderFlags; // Reserved, must be 0 uint32_t numRVAandSizes; // The number of data-directory entries in the remainder of the optional header. Each describes a location and size. } PACKED execformat_pe_OptionalHeader_WindowsFields_PE32; // Subsystems #define EXECFORMAT_PE_SUBSYSTEM_UNKNOWN 0 #define EXECFORMAT_PE_SUBSYSTEM_NATIVE 1 // Device drivers and native Windows processes #define EXECFORMAT_PE_SUBSYSTEM_WINDOWS_GUI 2 // Windows graphical user interface (GUI) subsystem #define EXECFORMAT_PE_SUBSYSTEM_WINDOWS_CUI 3 // Windows character subsystem #define EXECFORMAT_PE_SUBSYSTEM_OS2_CUI 5 // OS/2 character subsystem #define EXECFORMAT_PE_SUBSYSTEM_POSIX_CUI 7 // POSIX character subsystem #define EXECFORMAT_PE_SUBSYSTEM_NATIVE_WINDOWS 8 // Native Win9x driver #define EXECFORMAT_PE_SUBSYSTEM_WINDOWS_CE_GUI 9 // Windows CE #define EXECFORMAT_PE_SUBSYSTEM_EFI_APPLICATION 10 // Extensible Firmware Interface (EFI) application #define EXECFORMAT_PE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 // EFI Boot Services driver #define EXECFORMAT_PE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 // EFI Runtime driver #define EXECFORMAT_PE_SUBSYSTEM_EFI_ROM 13 // EFI ROM image #define EXECFORMAT_PE_SUBSYSTEM_XBOX 14 // XBOX #define EXECFORMAT_PE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16 // Windows boot application // DLL Characteristics #define EXECFORMAT_PE_DLLFLAG_RESERVED_0x0001 0x0001u // Reserved, must be 0 #define EXECFORMAT_PE_DLLFLAG_RESERVED_0x0002 0x0002u // Reserved, must be 0 #define EXECFORMAT_PE_DLLFLAG_RESERVED_0x0004 0x0004u // Reserved, must be 0 #define EXECFORMAT_PE_DLLFLAG_RESERVED_0x0008 0x0008u // Reserved, must be 0 #define EXECFORMAT_PE_DLLFLAG_HIGH_ENTROPY_VA 0x0020u // Image can handle a high entropy 64-bit virtual address space. #define EXECFORMAT_PE_DLLFLAG_DYNAMIC_BASE 0x0040u // DLL can be relocated at load time. #define EXECFORMAT_PE_DLLFLAG_FORCE_INTEGRITY 0x0080u // Code Integrity checks are enforced. #define EXECFORMAT_PE_DLLFLAG_NX_COMPAT 0x0100u // Image is NX compatible. #define EXECFORMAT_PE_DLLFLAG_NO_ISOLATION 0x0200u // Isolation aware, but do not isolate the image. #define EXECFORMAT_PE_DLLFLAG_NO_SEH 0x0400u // Does not use structured exception (SE) handling. #define EXECFORMAT_PE_DLLFLAG_NO_BIND 0x0800u // Do not bind the image. #define EXECFORMAT_PE_DLLFLAG_APPCONTAINER 0x1000u // Image must execute in an AppContainer. #define EXECFORMAT_PE_DLLFLAG_WDM_DRIVER 0x2000u // A WDM driver. #define EXECFORMAT_PE_DLLFLAG_GUARD_CF 0x4000u // Image supports Control Flow Guard. #define EXECFORMAT_PE_DLLFLAG_TERMINAL_SERVER_AWARE 0x8000u // Terminal Server aware. typedef struct { uint32_t Offset; uint32_t Size; } PACKED execformat_pe_OptionalHeader_DataDirectory; // Data Directory entry indexes #define EXECFORMAT_PE_DATADIR_INDEX_EXPORT 0 // .edata #define EXECFORMAT_PE_DATADIR_INDEX_IMPORT 1 // .idata #define EXECFORMAT_PE_DATADIR_INDEX_RESOURCE 2 // .rsrc #define EXECFORMAT_PE_DATADIR_INDEX_EXCEPTION 3 // .pdata #define EXECFORMAT_PE_DATADIR_INDEX_CERTIFICATE 4 #define EXECFORMAT_PE_DATADIR_INDEX_BASE_RELOCATION 5 // .reloc #define EXECFORMAT_PE_DATADIR_INDEX_DEBUG 6 // .debug #define EXECFORMAT_PE_DATADIR_INDEX_ARCHITECTURE 7 // Reserved, must be 0 #define EXECFORMAT_PE_DATADIR_INDEX_GLOBAL_PTR 8 // The RVA of the value to be stored in the global pointer register. The size must be 0. #define EXECFORMAT_PE_DATADIR_INDEX_TLS 9 // .tls #define EXECFORMAT_PE_DATADIR_INDEX_LOAD_CONFIG 10 #define EXECFORMAT_PE_DATADIR_INDEX_BOUND_IMPORT 11 #define EXECFORMAT_PE_DATADIR_INDEX_IAT 12 // Import Address Table #define EXECFORMAT_PE_DATADIR_INDEX_DELAY_IMPORT_DESC 13 // Delay Import Descriptor #define EXECFORMAT_PE_DATADIR_INDEX_CLR_RUNTIME_HEADER 14 // Common Language Runtime header #define EXECFORMAT_PE_DATADIR_INDEX_RESERVED_15 15 // Reserved, must be 0 typedef struct { execformat_pe_OptionalHeader_StandardFields_PE32P std; execformat_pe_OptionalHeader_WindowsFields_PE32P win; execformat_pe_OptionalHeader_DataDirectory data[1]; } PACKED execformat_pe_OptionalHeader_PE32P; typedef struct { execformat_pe_OptionalHeader_StandardFields_PE32 std; execformat_pe_OptionalHeader_WindowsFields_PE32 win; execformat_pe_OptionalHeader_DataDirectory data[1]; } PACKED execformat_pe_OptionalHeader_PE32; static inline void execformat_pe_OptionalHeader_CheckPacking() { assert(sizeof(execformat_pe_OptionalHeader_StandardFields_PE32) == 28); assert(sizeof(execformat_pe_OptionalHeader_StandardFields_PE32P) == 24); assert(sizeof(execformat_pe_OptionalHeader_WindowsFields_PE32) == 68); assert(sizeof(execformat_pe_OptionalHeader_WindowsFields_PE32P) == 88); assert(offsetof(execformat_pe_OptionalHeader_PE32, std) == 0); assert(offsetof(execformat_pe_OptionalHeader_PE32, win) == 28); assert(offsetof(execformat_pe_OptionalHeader_PE32, data[0]) == 96); assert(offsetof(execformat_pe_OptionalHeader_PE32P, std) == 0); assert(offsetof(execformat_pe_OptionalHeader_PE32P, win) == 24); assert(offsetof(execformat_pe_OptionalHeader_PE32P, data[0]) == 112); } typedef struct { char name[8]; uint32_t virtualSize; uint32_t virtualAddr; // Offset(RVA) instead of a real Virtual Address uint32_t sizeofRawData; uint32_t pointerToRawData; // The file pointer to the first page of the section within the file. uint32_t pointerToRelocations; uint32_t pointerToLineNumbers; uint16_t numRelocations; uint16_t numLineNumbers; // deprecated, should be 0 uint32_t flags; // The flags that describe the characteristics of the section. } PACKED execformat_pe_SectionHeader; // Section Characteristics #define EXECFORMAT_PE_SECTIONFLAG_NO_PAD 0x00000008u // section should not be padded to the next boundary, obsolete. #define EXECFORMAT_PE_SECTIONFLAG_CNT_CODE 0x00000020u // section contains executable code. #define EXECFORMAT_PE_SECTIONFLAG_CNT_INITIALIZED_DATA 0x00000040u // section contains initialized data. #define EXECFORMAT_PE_SECTIONFLAG_CNT_UNINITIALIZED_DATA 0x00000080u // section contains uninitialized data. #define EXECFORMAT_PE_SECTIONFLAG_LNK_OTHER 0x00000100u // Reserved. #define EXECFORMAT_PE_SECTIONFLAG_LNK_INFO 0x00000200u // section contains comments or other info. .drectve section has this type. #define EXECFORMAT_PE_SECTIONFLAG_LNK_REMOVE 0x00000800u // section will not become part of the image. valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_LNK_COMDAT 0x00001000u // The section contains COMDAT data. valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_GPREL 0x00008000u // section contains data referenced through the global pointer (GP). #define EXECFORMAT_PE_SECTIONFLAG_MEM_PURGEABLE 0x00020000u // Reserved. #define EXECFORMAT_PE_SECTIONFLAG_MEM_16BIT 0x00020000u // Reserved. #define EXECFORMAT_PE_SECTIONFLAG_MEM_LOCKED 0x00040000u // Reserved. #define EXECFORMAT_PE_SECTIONFLAG_MEM_PRELOAD 0x00080000u // Reserved. // Section Characteristics - Alignment (only for object files) #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_1BYTES 0x00100000u // Align data on a 1-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_2BYTES 0x00200000u // Align data on a 2-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_4BYTES 0x00300000u // Align data on a 4-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_8BYTES 0x00400000u // Align data on a 8-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_16BYTES 0x00500000u // Align data on a 16-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_32BYTES 0x00600000u // Align data on a 32-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_64BYTES 0x00700000u // Align data on a 64-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_128BYTES 0x00800000u // Align data on a 128-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_256BYTES 0x00900000u // Align data on a 256-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_512BYTES 0x00a00000u // Align data on a 512-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_1024BYTES 0x00b00000u // Align data on a 1024-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_2048BYTES 0x00c00000u // Align data on a 2048-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_4096BYTES 0x00d00000u // Align data on a 4096-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_8192BYTES 0x00e00000u // Align data on a 8192-byte boundary. Valid only for object files. #define EXECFORMAT_PE_SECTIONFLAG_ALIGN_MASK 0x00f00000u // Mask for section data alignment type. // Section Characteristics - Memory #define EXECFORMAT_PE_SECTIONFLAG_LNK_NRELOC_OVFL 0x01000000u // section contains extended relocations. #define EXECFORMAT_PE_SECTIONFLAG_MEM_DISCARDABLE 0x02000000u // section can be discarded as needed. #define EXECFORMAT_PE_SECTIONFLAG_MEM_NOT_CACHED 0x04000000u // section cannot be cached. #define EXECFORMAT_PE_SECTIONFLAG_MEM_NOT_PAGED 0x08000000u // section cannot be paged out. #define EXECFORMAT_PE_SECTIONFLAG_MEM_SHARED 0x10000000u // section can be shared in memory. #define EXECFORMAT_PE_SECTIONFLAG_MEM_EXECUTE 0x20000000u // section can be executed as code. #define EXECFORMAT_PE_SECTIONFLAG_MEM_READ 0x40000000u // section can be read. #define EXECFORMAT_PE_SECTIONFLAG_MEM_WRITE 0x80000000u // section can be written to. #ifdef __cplusplus } // extern "C" #endif