Files
ImHex-Patterns/patterns/pe.hexpat
paxcut 6697fc23a4 themes: Updated the custom themes to the new text editor color palettes (#255)
* Updated the custom themes to the new text editor color palettes designed for full syntax highlighting, but the existing themes should look just like they did before.

* impr: renamed pattern-placed-variable to calculated-pointer and added view
fix: pe pattern could read past the end of file if symbol search option was turned on and input file had no symbols. In that case a StringTable array that has 1 element would be created and place at offset 0 where the size variable was set to a large number creating the error. The fix is to set the size of the array using numberOfSymbols>0

* Fix: that was a bad choice for the size of the stringTable array because  even if findSymbols is not on the file can contain symbols. This was causing the pe unit test to fail. To get the right array size use sizeof(symbolTable)>0 which will be 1 only if findSymbols is true and the file actually contains symbols
2024-11-17 13:52:30 +01:00

1304 lines
37 KiB
Rust

#pragma author WerWolv
#pragma description Microsoft PE Portable Executable (exe/dll)
#pragma MIME application/x-dosexec
#pragma MIME application/x-msdownload
#pragma MIME application/vnd.microsoft.portable-executable
import std.core;
import std.string;
import type.guid;
import type.time;
struct DOSHeader {
char signature[2] [[hex::spec_name("e_magic")]];
u16 extraPageSize [[hex::spec_name("e_cblp")]];
u16 numberOfPages [[hex::spec_name("e_cp")]];
u16 relocations [[name("stubRelocations"), hex::spec_name("e_crlc")]];
u16 headerSizeInParagraphs [[hex::spec_name("e_cparhdr")]];
u16 minimumAllocatedParagraphs [[hex::spec_name("e_minalloc")]];
u16 maximumAllocatedParagraphs [[hex::spec_name("e_maxalloc")]];
u16 initialSSValue [[hex::spec_name("e_ss")]];
u16 initialRelativeSPValue [[hex::spec_name("e_sp")]];
u16 checksum [[name("stubChecksum"), hex::spec_name("e_csum")]];
u16 initialRelativeIPValue [[hex::spec_name("e_ip")]];
u16 initialCSValue [[hex::spec_name("e_cs")]];
u16 relocationsTablePointer [[hex::spec_name("e_lfarlc")]];
u16 overlayNumber [[hex::spec_name("e_ovno")]];
u16 reservedWords[4] [[hex::spec_name("e_res")]];
u16 oemIdentifier [[hex::spec_name("e_oemid")]];
u16 oemInformation [[hex::spec_name("e_oeminfo")]];
u16 otherReservedWords[10] [[hex::spec_name("e_res2")]];
u32 coffHeaderPointer [[hex::spec_name("e_lfanew")]];
};
u16 dosMessageOffset;
fn isstubdata(char c) {
return c == 0x0D || c == 0x0A || c == '$';
};
struct DOSStub {
u8 code[while($ < addressof(this) + dosMessageOffset)];
char message[while(!isstubdata(std::mem::read_unsigned($, 1)))];
char data[while(std::mem::read_string($-1, 1) != "$")];
} [[hex::spec_name("e_program")]];
fn finddosmessage() {
for (u8 i = $, i < $+16, i += 1) {
if (std::mem::read_unsigned(i, 1) == 0xBA) { // Message offset instruction
dosMessageOffset = std::mem::read_unsigned(i+1, 2);
break;
}
}
};
struct PEHeader {
DOSHeader dosHeader;
finddosmessage();
if (!dosMessageOffset)
u8 dosStub[while(std::mem::read_unsigned($, 4))] [[hex::spec_name("e_program")]];
else DOSStub dosStub;
};
PEHeader peHeader @ 0x00;
enum ArchitectureType : u16 {
Unknown = 0x00,
ALPHAAXPOld = 0x183,
ALPHAAXP = 0x184,
ALPHAAXP64Bit = 0x284,
AM33 = 0x1D3,
AMD64 = 0x8664,
ARM = 0x1C0,
ARM64 = 0xAA64,
ARMNT = 0x1C4,
CLRPureMSIL = 0xC0EE,
EBC = 0xEBC,
I386 = 0x14C,
I860 = 0x14D,
IA64 = 0x200,
LOONGARCH32 = 0x6232,
LOONGARCH64 = 0x6264,
M32R = 0x9041,
MIPS16 = 0x266,
MIPSFPU = 0x366,
MIPSFPU16 = 0x466,
MOTOROLA68000 = 0x268,
POWERPC = 0x1F0,
POWERPCFP = 0x1F1,
POWERPC64 = 0x1F2,
R3000 = 0x162,
R4000 = 0x166,
R10000 = 0x168,
RISCV32 = 0x5032,
RISCV64 = 0x5064,
RISCV128 = 0x5128,
SH3 = 0x1A2,
SH3DSP = 0x1A3,
SH4 = 0x1A6,
SH5 = 0x1A8,
THUMB = 0x1C2,
WCEMIPSV2 = 0x169
} [[hex::spec_name("MachineType")]];
enum PEFormat : u16 {
ROM = 0x107,
PE32 = 0x10B,
PE32Plus = 0x20B
};
enum SubsystemType : u16 {
Unknown = 0x00,
Native = 0x01,
WindowsGUI = 0x02,
WindowsCUI = 0x03,
OS2CUI = 0x05,
POSIXCUI = 0x07,
Windows9xNative = 0x08,
WindowsCEGUI = 0x09,
EFIApplication = 0x0A,
EFIBootServiceDriver = 0x0B,
EFIRuntimeDriver = 0x0C,
EFIROM = 0x0D,
Xbox = 0x0E,
WindowsBootApplication = 0x10
};
bitfield Characteristics {
baseRelocationsStripped : 1 [[hex::spec_name("IMAGE_FILE_RELOCS_STRIPPED")]];
executableImage : 1 [[hex::spec_name("IMAGE_FILE_EXECUTABLE_IMAGE")]];
lineNumbersStripped : 1 [[hex::spec_name("IMAGE_FILE_LINE_NUMS_STRIPPED")]];
symbolsStripped : 1 [[hex::spec_name("IMAGE_FILE_LOCAL_SYMS_STRIPPED")]];
aggressivelyTrimWorkingSet : 1 [[hex::spec_name("IMAGE_FILE_AGGRESSIVE_WS_TRIM")]];
largeAddressAware : 1 [[hex::spec_name("IMAGE_FILE_LARGE_ADDRESS_AWARE")]];
padding : 1;
bytesReversedLo : 1 [[hex::spec_name("IMAGE_FILE_BYTES_REVERSED_LO")]];
machine32Bit : 1 [[hex::spec_name("IMAGE_FILE_32BIT_MACHINE")]];
debugInfoStripped : 1 [[hex::spec_name("IMAGE_FILE_DEBUG_STRIPPED")]];
removableRunFromSwap : 1 [[hex::spec_name("IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP")]];
netRunFromSwap : 1 [[hex::spec_name("IMAGE_FILE_NET_RUN_FROM_SWAP")]];
systemFile : 1 [[hex::spec_name("IMAGE_FILE_SYSTEM")]];
dll : 1 [[hex::spec_name("IMAGE_FILE_DLL")]];
uniprocessorMachineOnly : 1 [[hex::spec_name("IMAGE_FILE_UP_SYSTEM_ONLY")]];
bytesReversedHi : 1 [[hex::spec_name("IMAGE_FILE_BYTES_REVERSED_HI")]];
};
bitfield DLLCharacteristics {
callWhenLoaded : 1;
callWhenThreadTerminates : 1;
callWhenThreadStarts : 1;
callWhenExiting : 1;
padding : 1;
highEntropyVA : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA")]];
dynamicBase : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE")]];
forceIntegrity : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY")]];
nxCompatible : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NX_COMPAT")]];
noIsolation : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NO_ISOLATION")]];
noSEH : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NO_SEH")]];
doNotBind : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NO_BIND")]];
appContainer : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_APPCONTAINER")]];
isWDMDriver : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_WDM_DRIVER")]];
supportsControlFlowGuard : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_GUARD_CF")]];
terminalServerAware : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE ")]];
};
bitfield LoaderFlags {
prestartBreakpoint : 1 [[comment("Invoke a breakpoint instruction before starting the process")]];
postloadingDebugger : 1 [[comment("Invoke a debugger on the process after it's been loaded")]];
padding : 30;
} [[comment("(Officially declared reserved by Microsoft)")]];
struct DataDirectory {
u32 rva;
u32 size;
};
struct OptionalHeader {
PEFormat magic;
u8 majorLinkerVersion;
u8 minorLinkerVersion;
u32 sizeOfCode;
u32 sizeOfInitializedData;
u32 sizeOfUninitializedData;
u32 addressOfEntryPoint;
u32 baseOfCode;
if (magic == PEFormat::PE32Plus) {
u64 imageBase;
}
else {
u32 baseOfData;
u32 imageBase;
}
u32 virtualSectionAlignment [[hex::spec_name("sectionAlignment")]];
u32 rawSectionAlignment [[hex::spec_name("fileAlignment")]];
u16 majorOperatingSystemVersion;
u16 minorOperatingSystemVersion;
u16 majorImageVersion;
u16 minorImageVersion;
u16 majorSubsystemVersion;
u16 minorSubsystemVersion;
u32 win32VersionValue;
u32 sizeOfImage;
u32 sizeOfHeaders;
u32 checksum;
SubsystemType subsystem;
DLLCharacteristics dllCharacteristics;
if (magic == PEFormat::PE32Plus) {
u64 sizeOfStackReserve;
u64 sizeOfStackCommit;
u64 sizeOfHeapReserve;
u64 sizeOfHeapCommit;
}
else {
u32 sizeOfStackReserve;
u32 sizeOfStackCommit;
u32 sizeOfHeapReserve;
u32 sizeOfHeapCommit;
}
LoaderFlags loaderFlags;
u32 numberOfRVAsAndSizes [[hex::spec_name("numberOfRvaAndSizes")]];
DataDirectory directories[numberOfRVAsAndSizes];
};
struct COFFHeader {
char signature[4];
ArchitectureType architecture [[hex::spec_name("machine")]];
u16 numberOfSections;
type::time32_t timeDateStamp;
u32 pointerToSymbolTable;
u32 numberOfSymbols;
u16 sizeOfOptionalHeader;
Characteristics characteristics;
OptionalHeader optionalHeader;
};
COFFHeader coffHeader @ peHeader.dosHeader.coffHeaderPointer;
enum AlignmentType : u8 {
BoundaryOf1Byte = 1,
BoundaryOf2Bytes,
BoundaryOf4Bytes,
BoundaryOf8Bytes,
BoundaryOf16Bytes,
BoundaryOf32Bytes,
BoundaryOf64Bytes,
BoundaryOf128Bytes,
BoundaryOf256Bytes,
BoundaryOf512Bytes,
BoundaryOf1024Bytes,
BoundaryOf2048Bytes,
BoundaryOf4096Bytes,
BoundaryOf8192Bytes,
};
fn formatAlignmentBits(u8 value) {
if (value > 0) {
AlignmentType enumValue = value;
return enumValue;
}
return value;
};
bitfield SectionFlags {
padding : 3;
doNotPad : 1 [[hex::spec_name("IMAGE_SCN_TYPE_NO_PAD")]];
padding : 1;
containsCode : 1 [[hex::spec_name("IMAGE_SCN_CNT_CODE")]];
containsInitializedData : 1 [[hex::spec_name("IMAGE_SCN_CNT_INITIALIZED_DATA")]];
containsUninitializedData : 1 [[hex::spec_name("IMAGE_SCN_CNT_UNINITIALIZED_DATA")]];
linkOther : 1 [[hex::spec_name("IMAGE_SCN_LNK_OTHER")]];
linkHasInformation : 1 [[hex::spec_name("IMAGE_SCN_LNK_INFO")]];
padding : 1;
linkRemove : 1 [[hex::spec_name("IMAGE_SCN_LNK_REMOVE")]];
linkHasCOMDAT : 1 [[hex::spec_name("IMAGE_SCN_LNK_COMDAT")]];
padding : 1;
resetSpeculativeExceptions : 1 [[hex::spec_name("")]];
globalPointerRelocations : 1 [[hex::spec_name("IMAGE_SCN_GPREL")]];
purgeable : 1 [[hex::spec_name("IMAGE_SCN_MEM_PURGEABLE")]];
is16Bit : 1 [[hex::spec_name("IMAGE_SCN_MEM_16BIT")]];
locked : 1 [[hex::spec_name("IMAGE_SCN_MEM_LOCKED")]];
preloaded : 1 [[hex::spec_name("IMAGE_SCN_MEM_PRELOAD")]];
dataAlignment : 4 [[format("formatAlignmentBits")]];
linkExtendedRelocations : 1 [[hex::spec_name("IMAGE_SCN_LNK_NRELOC_OVFL")]];
discardable : 1 [[hex::spec_name("IMAGE_SCN_MEM_DISCARDABLE")]];
notCached : 1 [[hex::spec_name("IMAGE_SCN_MEM_NOT_CACHED")]];
notPageable : 1 [[hex::spec_name("IMAGE_SCN_MEM_NOT_PAGED")]];
shared : 1 [[hex::spec_name("IMAGE_SCN_MEM_SHARED")]];
executed : 1 [[hex::spec_name("IMAGE_SCN_MEM_EXECUTE")]];
read : 1 [[hex::spec_name("IMAGE_SCN_MEM_READ")]];
writtenOn : 1 [[hex::spec_name("IMAGE_SCN_MEM_WRITE")]];
};
fn formatSectionName(str string) {
for (u8 i = 0, i < 8, i += 1) {
if (std::mem::read_unsigned($+i, 1) == 0) {
return "\"" + std::string::substr(string, 0, i) + "\"";
}
}
};
struct SectionHeader {
char name[8] [[name("sectionName"), hex::spec_name("name"), format("formatSectionName")]];
u32 virtualSize;
u32 rva [[hex::spec_name("virtualAddress")]];
u32 sizeOfRawData;
u32 ptrRawData;
u32 ptrRelocations;
u32 ptrLineNumbers;
u16 numberOfRelocations;
u16 numberOfLineNumbers;
SectionFlags characteristics;
};
SectionHeader sectionsTable[coffHeader.numberOfSections] @ addressof(coffHeader.optionalHeader) + coffHeader.sizeOfOptionalHeader;
// General Section things
u16 currentSectionIndex;
fn relativeVirtualDifference() {
return sectionsTable[currentSectionIndex].rva - sectionsTable[currentSectionIndex].ptrRawData;
};
fn wordsize() {
return std::mem::read_unsigned(addressof(coffHeader.optionalHeader.magic), 2) / 0x41;
};
fn formatNullTerminatedString(str string) {
return "\"" + std::string::substr(string, 0, std::string::length(string)-1) + "\"";
};
// Exception Table
bitfield FunctionBitfield {
prologLength : 8;
functionLength : 22;
instructions32Bit : 1;
exceptionHandler : 1;
};
struct FunctionTableEntry {
if (coffHeader.architecture == ArchitectureType::MIPSFPU || coffHeader.architecture == ArchitectureType::R3000) {
u32 beginVA;
u32 endVA;
u32 exceptionHandlerPointer;
u32 handlerDataPointer;
u32 prologEndVA;
} else if (coffHeader.architecture == ArchitectureType::ARM || coffHeader.architecture == ArchitectureType::ARM64 || coffHeader.architecture == ArchitectureType::ARMNT ||
coffHeader.architecture == ArchitectureType::POWERPC || coffHeader.architecture == ArchitectureType::POWERPCFP ||
coffHeader.architecture == ArchitectureType::SH3 || coffHeader.architecture == ArchitectureType::SH3DSP || coffHeader.architecture == ArchitectureType::SH4) {
u32 beginVA;
FunctionBitfield miscellaneousBits;
} else if (coffHeader.architecture == ArchitectureType::AMD64 || coffHeader.architecture == ArchitectureType::IA64) {
u32 beginRVA;
u32 endRVA;
u32 unwindInformationRVA;
}
};
struct ExceptionTable {
FunctionTableEntry functionTableEntries[while($ < (coffHeader.optionalHeader.directories[3].rva - relativeVirtualDifference()) + coffHeader.optionalHeader.directories[3].size)] [[inline]];
};
// Exports Table
struct ExportDirectoryTable {
u32 flags [[name("exportFlags")]];
type::time32_t timeDateStamp [[name("exportTimeDateStamp")]];
u16 majorVersion;
u16 minorVersion;
u32 imageNameRVA;
u32 ordinalBase [[name("exportOrdinalBase")]];
u32 addressesAmount [[name("exportAddressesAmount")]];
u32 namePointersAmount [[name("exportNamePointersAmount")]];
u32 addressTableRVA [[name("exportAddressTableRVA")]];
u32 namePointerTableRVA [[name("exportNamePointerTableRVA")]];
u32 ordinalTableRVA [[name("exportOrdinalTableRVA")]];
};
struct ExportAddress {
if (sectionsTable[currentSectionIndex].ptrRawData > std::mem::read_unsigned($, 4) > sectionsTable[currentSectionIndex].sizeOfRawData) {
u32 exportRVA;
}
else {
u32 forwarderRVA;
}
};
struct ExportNamePointer {
u32 exportNameRVA;
char exportName[] @ exportNameRVA - relativeVirtualDifference() [[format("formatNullTerminatedString")]];
};
struct ExportsTable {
ExportDirectoryTable directoryTable;
ExportAddress exportAddressTable[directoryTable.addressesAmount] @ directoryTable.addressTableRVA - relativeVirtualDifference();
ExportNamePointer exportNamePointerTable[directoryTable.namePointersAmount] @ directoryTable.namePointerTableRVA - relativeVirtualDifference();
u16 exportOrdinalTable[directoryTable.namePointersAmount] @ directoryTable.ordinalTableRVA - relativeVirtualDifference();
char imageName[] @ directoryTable.imageNameRVA - relativeVirtualDifference() [[format("formatNullTerminatedString")]];
$ = addressof(this)+coffHeader.optionalHeader.directories[0].size;
};
// Imports Table
bitfield OrdinalFlagByte {
padding : 7;
flag : 1 [[name("ordinalFlag")]];
};
struct ImportsName {
u16 hint;
char name[] [[format("formatNullTerminatedString")]];
if ($ % 2 == 1) { u8 pad; }
};
struct ImportsAddress {
OrdinalFlagByte ordinalFlagByte @ $+(wordsize()-1);
if (ordinalFlagByte.flag) {
u16 ordinalNumber;
padding[wordsize()-2];
} else {
u32 nameTableRVA;
if (coffHeader.optionalHeader.magic == PEFormat::PE32Plus) {
padding[4];
}
}
};
struct ImportsLookup : ImportsAddress {
if (!ordinalFlagByte.flag && std::mem::read_unsigned($-wordsize(), wordsize()) > 0) {
ImportsName name @ nameTableRVA - relativeVirtualDifference();
}
};
struct ImportsDirectory {
u32 lookupTableRVA;
u32 timeDateStamp;
u32 forwarderChain;
u32 dllNameRVA;
u32 addressTableRVA;
};
struct ImportsStructure {
if (parent.importsDirectoryTable[std::core::array_index()].lookupTableRVA > 0) {
ImportsLookup lookupTable[while(std::mem::read_unsigned($, wordsize()) != 0)] @ parent.importsDirectoryTable[std::core::array_index()].lookupTableRVA - relativeVirtualDifference();
}
if (parent.importsDirectoryTable[std::core::array_index()].addressTableRVA > 0) {
ImportsAddress addressTable[while(std::mem::read_unsigned($, wordsize()) != 0)] @ parent.importsDirectoryTable[std::core::array_index()].addressTableRVA - relativeVirtualDifference();
}
if (parent.importsDirectoryTable[std::core::array_index()].dllNameRVA > 0) {
char dllName[] @ parent.importsDirectoryTable[std::core::array_index()].dllNameRVA - relativeVirtualDifference() [[format("formatNullTerminatedString")]];
}
} [[inline]];
struct ImportsTable {
ImportsDirectory importsDirectoryTable[while(std::mem::read_unsigned($, 16) != 0)];
ImportsStructure importsStructures[sizeof(importsDirectoryTable)/sizeof(importsDirectoryTable[0])] [[inline]];
$ = addressof(this)+coffHeader.optionalHeader.directories[1].size;
};
struct DelayedImportsDirectory {
u32 attributes;
u32 name;
u32 moduleHandle;
u32 delayImportAddressTable;
u32 delayImportNameTable;
u32 boundDelayImportTable;
u32 unloadDelayImportTable;
u32 timeStamp;
};
struct DelayImportsStructure {
if (parent.delayImportsDirectoryTable[std::core::array_index()].delayImportNameTable > 0) {
ImportsLookup delayedLookupTable[while(std::mem::read_unsigned($, wordsize()) != 0)] @ parent.delayImportsDirectoryTable[std::core::array_index()].delayImportNameTable - relativeVirtualDifference();
}
if (parent.delayImportsDirectoryTable[std::core::array_index()].name > 0) {
char dllName[] @ parent.delayImportsDirectoryTable[std::core::array_index()].name - relativeVirtualDifference() [[format("formatNullTerminatedString")]];
}
} [[inline]];
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#delay-load-import-tables-image-only
struct DelayedImportsTable {
DelayedImportsDirectory delayImportsDirectoryTable[while(std::mem::read_unsigned($, 16) != 0)];
DelayImportsStructure delayImportsStructures[sizeof(delayImportsDirectoryTable)/sizeof(delayImportsDirectoryTable[0])] [[inline]];
$ = addressof(this)+coffHeader.optionalHeader.directories[1].size;
};
// General Resource Table things
fn formatNullTerminatedString16(str string) {
return "\"" + std::string::substr(string, 0, std::string::length(string)) + "\"";
};
// * Bitmap Resource
struct BitmapHeader {
u32 size [[name("bitmapSize")]];
u32 width [[name("bitmapWidth")]];
u32 height [[name("bitmapHeight")]];
u16 planes [[name("bitmapPlanes")]];
u16 bitCount [[name("bitmapBitCount")]];
u32 compression [[name("bitmapCompression")]];
u32 imageSize [[name("bitmapImageSize")]];
u32 xPelsPerMeter [[name("bitmapXPelsPerMeter")]];
u32 yPelsPerMeter [[name("bitmapYPelsPerMeter")]];
u32 clrUsed [[name("bitmapClrUsed")]];
u32 clrImportant [[name("bitmapClrImportant")]];
};
struct Colors {
u8 blue [[color("1F77B4")]];
u8 green [[color("2CA02C")]];
u8 red [[color("D62728")]];
u8 reserved [[color("828282")]];
};
u32 imageDataSize;
struct Bitmap {
BitmapHeader bmh [[name("bitmapHeader")]];
if ((bmh.bitCount != 24) && (bmh.bitCount != 32)) {
Colors rgbq[bmh.clrUsed*((1 << bmh.bitCount)*!bmh.clrUsed)];
imageDataSize = imageDataSize - sizeof(rgbq);
}
u8 imageData[imageDataSize-sizeof(bmh)];
};
// * Cursor Resource
struct Cursor {
u16 reserved;
u16 type;
if (!type) {
imageDataSize = parent.size-4;
Bitmap bitmapData [[inline]];
}
};
// * Dialog Resource
enum AtomType : u16 {
Button = 0x80,
Edit,
Static,
ListBox,
ScrollBar,
ComboBox
};
struct VLSElement {
if (std::mem::read_unsigned($, 2) == 0xFFFF) {
u16 atomDefiner;
}
else {
AtomType atom;
}
};
struct VariableLengthStructure {
if (std::mem::read_unsigned($, 2) == 0xFFFF) {
VLSElement vlsElement[2];
}
else {
char16 string[] [[format("formatNullTerminatedString16")]];
}
};
struct DialogTemplate {
if (parent.parent.parent.parent.id == 0x411) {
u16 version;
u16 signature;
u32 helpContextIdentifier;
u32 extendedStyles;
u32 style;
}
else {
u32 style;
u32 extendedStyles;
}
u16 numberOfItems;
u16 x;
u16 y;
u16 width;
u16 height;
if (parent.parent.parent.parent.id == 0x409 || parent.parent.parent.parent.id == 0x411) {
VariableLengthStructure dialogMenu;
VariableLengthStructure dialogClass;
char16 dialogTitle[] [[format("formatNullTerminatedString16")]];
u16 dialogFontSize;
if (parent.parent.parent.parent.id == 0x411) {
u16 weight;
bool italic;
u8 charset;
}
char16 dialogFontTypeface[] [[format("formatNullTerminatedString16")]];
if (($+2)%16 == 0 || 4 || 8 || 12)
u16 alignment;
}
};
struct DialogItemTemplate {
if (parent.parent.parent.parent.parent.id == 0x411) {
u32 helpContextIdentifier;
u32 extendedStyles [[name("itemExtendedStyles")]];
u32 style [[name("itemStyle")]];
}
else {
u32 style [[name("itemStyle")]];
u32 extendedStyles [[name("itemExtendedStyles")]];
}
u16 x;
u16 y;
u16 width;
u16 height;
if (parent.parent.parent.parent.parent.id == 0x409 || parent.parent.parent.parent.parent.id == 0x411) {
u32 controlID;
VariableLengthStructure windowClass;
VariableLengthStructure dialogItemTitle;
u16 extraCount;
} else {
u16 controlID;
}
if (($+2)%16 == 0 || 4 || 8)
u16 alignment;
};
struct DialogItem {
DialogItemTemplate template [[inline]];
/*if (parent.parent.parent.parent.id == 0x409 || parent.parent.parent.parent.id == 0x411) {
u8 itemCreationData[template.extraCount];
}*/
};
struct Dialog {
DialogTemplate dialogTemplate;
DialogItem items[dialogTemplate.numberOfItems];
};
// * String Resource
struct StringTableResource {
std::string::SizedString16<u16> strings[while($ < (parent.dataRVA - relativeVirtualDifference()) + parent.size)];
};
// * GroupCursor Resource
struct GroupCursor {
u16 assorteddata;
u16 colors;
u16 otherassorteddata;
u16 pixels;
u16 assorteddataarray[5];
u16 ordinalName;
};
// * GroupIcon Resource
struct GroupIconHeader {
u16 reserved;
u16 type;
u16 count;
};
struct GroupIconEntry {
u8 width;
u8 height;
u8 colorCount;
u8 reserved;
u16 planes;
u16 bitCount;
u32 bytesInResource;
u16 id;
};
struct GroupIcon {
GroupIconHeader header;
GroupIconEntry entries[header.count];
};
// * Version Resource
struct VersionEntryHeader {
u16 length;
u16 valueLength;
u16 type;
char16 key[] [[format("formatNullTerminatedString16")]];
padding[while(std::mem::read_unsigned($, 1) == 0 && $ < addressof(key)+sizeof(key)+5)];
};
struct StringInfo {
VersionEntryHeader stringInfoHeader;
if (stringInfoHeader.valueLength > 0) {
char16 string[] [[format("formatNullTerminatedString16")]];
padding[while(std::mem::read_unsigned($, 1) == 0)];
}
};
struct VersionEntry {
VersionEntryHeader header [[inline]];
if (header.key == "StringFileInfo") {
VersionEntryHeader stringTableHeader;
StringInfo strings[while($ < addressof(stringTableHeader) + stringTableHeader.length)];
}
else if (header.key == "VarFileInfo") {
VersionEntryHeader varHeader;
u16 translation[varHeader.valueLength / 2];
}
else {
u8 value[header.valueLength];
padding[while(std::mem::read_unsigned($, 1) == 0)];
}
};
struct Version {
VersionEntryHeader header [[inline]];
u32 signature;
u16 structVersion[2];
u16 fileVersion[4];
u16 productVersion[4];
u32 fileFlagsMask[2];
u32 fileFlags;
u32 fileOS;
u32 fileType;
u32 fileSubType;
u32 fileTimestamp;
VersionEntry children[while($ < (parent.dataRVA - relativeVirtualDifference()) + parent.size)];
};
// * Resources Using TrueChar
fn displayTrueChar(u8 value) {
str notation = "0x";
if (value < 0x10)
notation += "0";
if (value == 0)
return "'␀' (" + std::format(notation + "{:X}", value) + ")";
else
return "'" + char(value) + "' (" + std::format(notation + "{:X}", value) + ")";
};
// Resource Table
enum ResourceID : u32 {
Cursor = 0x01,
Bitmap,
Icon,
Menu,
Dialog,
String,
Accelerator = 0x09,
StringData,
GroupCursor = 0x0C,
GroupIcon = 0x0E,
Version = 0x10,
Manifest = 0x18
};
ResourceID resourceIDType;
using TrueChar = u8 [[format("displayTrueChar")]];
struct DataEntry {
u32 dataRVA;
u32 size;
u32 codepage;
u32 reserved;
if (resourceIDType == ResourceID::Cursor) {
Cursor cursor @ dataRVA - relativeVirtualDifference();
}
else if (resourceIDType == ResourceID::Bitmap || (resourceIDType == ResourceID::Icon && std::mem::read_string((dataRVA - relativeVirtualDifference())+1, 3) != "PNG")) {
imageDataSize = size;
Bitmap bitmap @ dataRVA - relativeVirtualDifference();
}
else if (resourceIDType == ResourceID::Dialog) {
Dialog dialog @ dataRVA - relativeVirtualDifference();
}
else if (resourceIDType == ResourceID::String) {
StringTableResource stringTableResource @ dataRVA - relativeVirtualDifference();
}
else if (resourceIDType == ResourceID::StringData) {
TrueChar stringData[size] @ dataRVA - relativeVirtualDifference();
}
else if (resourceIDType == ResourceID::GroupCursor) {
GroupCursor groupCursor @ dataRVA - relativeVirtualDifference();
}
else if (resourceIDType == ResourceID::GroupIcon) {
GroupIcon groupIcon @ dataRVA - relativeVirtualDifference();
}
else if (resourceIDType == ResourceID::Version) {
Version version @ dataRVA - relativeVirtualDifference();
}
else if (resourceIDType == ResourceID::Manifest) {
TrueChar manifest[size] @ dataRVA - relativeVirtualDifference();
}
else {
u8 resource[size] @ dataRVA - relativeVirtualDifference();
}
};
using ResourceDirectory;
bitfield OffsetField {
offset : 31;
pointingToDirectory : 1;
};
struct DataField {
if (std::mem::read_unsigned($+3, 1) >= 0x80) {
OffsetField offsetToData;
ResourceDirectory directory @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + offsetToData.offset;
}
else {
u32 offsetToData;
DataEntry dataEntry @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + offsetToData;
}
} [[inline]];
struct IdDirectoryEntry {
if ($ > coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + 0x10 + 8*(parent.directoryTable.nameEntriesAmount + parent.directoryTable.idEntriesAmount)) {
u32 id;
}
else {
ResourceID id;
resourceIDType = std::mem::read_unsigned(addressof(id), 4);
}
DataField datafield;
};
struct NameDirectoryEntry {
OffsetField offsetToName;
std::string::SizedString16<u16> name @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + offsetToName.offset;
DataField datafield;
};
struct ResourceDirectoryTable {
u32 characteristics;
u32 timeDateStamp;
u16 majorVersion;
u16 minorVersion;
u16 nameEntriesAmount;
u16 idEntriesAmount;
};
struct ResourceDirectory {
ResourceDirectoryTable directoryTable [[hex::spec_name("resourceDirectoryTable")]];
NameDirectoryEntry nameEntries[directoryTable.nameEntriesAmount];
IdDirectoryEntry idEntries[directoryTable.idEntriesAmount];
};
struct ResourceTable {
ResourceDirectory rootDirectory;
$ = addressof(this)+coffHeader.optionalHeader.directories[2].size;
};
// Base Relocations Table
enum BaseRelocationType : u8 {
Absolute,
High,
Low,
HighLow,
HighAdjacent,
Reserved = 6,
DIR64 = 10
};
enum MIPSBaseRelocationType : u8 {
Absolute,
High,
Low,
HighLow,
HighAdjacent,
MIPSJMPAddress,
Reserved,
MIPSJMPAddress16 = 9,
DIR64
};
enum ARMBaseRelocationType : u8 {
Absolute,
High,
Low,
HighLow,
HighAdjacent,
ARMMOV32,
Reserved,
DIR64 = 10
};
enum RISCVBaseRelocationType : u8 {
Absolute,
High,
Low,
HighLow,
HighAdjacent,
RISCVHigh20,
Reserved,
RISCVLow12I,
RISCVLow12S,
DIR64 = 10
};
enum THUMBBaseRelocationType : u8 {
Absolute,
High,
Low,
HighLow,
HighAdjacent,
ARMMOV32,
Reserved,
ThumbMOV32,
DIR64 = 10
};
enum LoongarchBaseRelocationType : u8 {
Absolute,
High,
Low,
HighLow,
HighAdjacent,
Reserved = 6,
MarkLA = 8,
DIR64 = 10
};
fn formatBaseRelocationType(u8 value) {
if (coffHeader.architecture == ArchitectureType::MIPS16 || coffHeader.architecture == ArchitectureType::MIPSFPU || coffHeader.architecture == ArchitectureType::MIPSFPU16 ||
coffHeader.architecture == ArchitectureType::R3000 || coffHeader.architecture == ArchitectureType::R4000 || coffHeader.architecture == ArchitectureType::R10000) {
MIPSBaseRelocationType mipsTypeBits = value;
return mipsTypeBits;
}
else if (coffHeader.architecture == ArchitectureType::ARM || coffHeader.architecture == ArchitectureType::ARM64 || coffHeader.architecture == ArchitectureType::ARMNT) {
ARMBaseRelocationType armTypeBits = value;
return armTypeBits;
}
else if (coffHeader.architecture == ArchitectureType::RISCV32 || coffHeader.architecture == ArchitectureType::RISCV64 || coffHeader.architecture == ArchitectureType::RISCV128) {
RISCVBaseRelocationType riscvTypeBits = value;
return riscvTypeBits;
}
else if (coffHeader.architecture == ArchitectureType::THUMB) {
THUMBBaseRelocationType thumbTypeBits = value;
return thumbTypeBits;
}
else if (coffHeader.architecture == ArchitectureType::LOONGARCH32 || coffHeader.architecture == ArchitectureType::LOONGARCH64) {
LoongarchBaseRelocationType loongarchTypeBits = value;
return loongarchTypeBits;
}
else {
BaseRelocationType genericTypeBits = value;
return genericTypeBits;
}
};
bitfield BaseRelocationWord {
offset : 12;
type : 4 [[format("formatBaseRelocationType")]];
};
struct BaseRelocationBlock {
u32 pageRVA;
u32 blockSize;
BaseRelocationWord word[while($ < addressof(this) + this.blockSize)] [[inline]];
};
struct BaseRelocationTable {
BaseRelocationBlock baseRelocationBlocks[while($ < addressof(this) + coffHeader.optionalHeader.directories[5].size)] [[inline]];
};
// Debug Table
enum DebugType : u32 {
Unknown,
COFF,
Codeview,
FPO,
Misc,
Exception,
Fixup,
OmapToSRC,
OmapFromSRC,
Borland,
Reserved10,
CLSID,
REPRO = 16,
ExtendedDLLCharacteristics = 20
};
struct RSDS {
char signature[4];
type::GUID guid;
u32 age;
char path[] [[format("formatNullTerminatedString")]];
};
struct DebugDirectory {
u32 characteristics;
type::time32_t timeDateStamp;
u16 majorVersion;
u16 minorVersion;
DebugType type;
u32 sizeOfData;
u32 virtualAddressOfRawData;
u32 pointerOfRawData;
};
struct DebugData {
DebugDirectory directory;
if (std::mem::read_string(directory.pointerOfRawData, 4) == "RSDS") {
RSDS rsds @ directory.pointerOfRawData;
}
else {
u8 data[directory.sizeOfData] @ directory.pointerOfRawData;
}
$ = addressof(this)+coffHeader.optionalHeader.directories[6].size;
};
// TLS Table
struct TLSTable {
if (coffHeader.optionalHeader.magic == PEFormat::PE32Plus) {
u64 rawDataStartVA;
u64 rawDataEndVA;
u64 indexAddress;
u64 callbacksAddress;
}
else {
u32 rawDataStartVA;
u32 rawDataEndVA;
u32 indexAddress;
u32 callbacksAddress;
}
u32 zeroFillSize;
u32 characteristics;
$ = addressof(this)+coffHeader.optionalHeader.directories[9].size;
};
// CRT Section
struct CRTSection {
u64 virtualAddresses[while($ < sectionsTable[currentSectionIndex].ptrRawData + sectionsTable[currentSectionIndex].sizeOfRawData)];
};
// Sections
struct LineNumber {
if (std::mem::read_unsigned($+4) > 0) {
u32 virtualAddress;
} else {
u32 symbolTableIndex;
}
u32 lineNumber;
};
bool dataDirectoryInSection[coffHeader.optionalHeader.numberOfRVAsAndSizes];
fn checkForDataDirectory() {
for (u32 i = 0, i < coffHeader.optionalHeader.numberOfRVAsAndSizes, i += 1)
if (coffHeader.optionalHeader.directories[i].rva - relativeVirtualDifference() < sectionsTable[currentSectionIndex].ptrRawData+sectionsTable[currentSectionIndex].sizeOfRawData
&& coffHeader.optionalHeader.directories[i].rva - relativeVirtualDifference() >= $)
dataDirectoryInSection[i] = true;
};
fn noDataDirectories() {
for (u32 i = 0, i < coffHeader.optionalHeader.numberOfRVAsAndSizes, i += 1)
if (dataDirectoryInSection[i]) return false;
return true;
};
fn clearBoolArray() {
for (u32 i = 0, i < coffHeader.optionalHeader.numberOfRVAsAndSizes, i += 1)
dataDirectoryInSection[i] = false;
};
struct Section {
checkForDataDirectory();
if (noDataDirectories()) {
if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".CRT")) // CRT section
CRTSection crtSection;
else
u8 freeformSection[sectionsTable[currentSectionIndex].sizeOfRawData]; // Freeform data section
}
else {
if (dataDirectoryInSection[0]) {
ExportsTable exportTable @ coffHeader.optionalHeader.directories[0].rva - relativeVirtualDifference();
}
if (dataDirectoryInSection[1]) {
ImportsTable importTable @ coffHeader.optionalHeader.directories[1].rva - relativeVirtualDifference();
}
if (dataDirectoryInSection[2]) {
ResourceTable resourceTable @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference();
}
if (dataDirectoryInSection[3]) {
ExceptionTable exceptionTable @ coffHeader.optionalHeader.directories[3].rva - relativeVirtualDifference();
}
if (dataDirectoryInSection[5]) {
BaseRelocationTable baseRelocationTable @ coffHeader.optionalHeader.directories[5].rva - relativeVirtualDifference();
}
if (dataDirectoryInSection[6]) {
DebugData debugData @ coffHeader.optionalHeader.directories[6].rva - relativeVirtualDifference();
}
if (dataDirectoryInSection[7]) {
char copyright[] @ coffHeader.optionalHeader.directories[7].rva - relativeVirtualDifference() [[format("formatNullTerminatedString")]];
}
if (dataDirectoryInSection[9]) {
TLSTable tlsTable @ coffHeader.optionalHeader.directories[9].rva - relativeVirtualDifference();
}
if (dataDirectoryInSection[13]) {
DelayedImportsTable delayedImportTable @ coffHeader.optionalHeader.directories[13].rva - relativeVirtualDifference();
}
}
clearBoolArray();
LineNumber lineNumbers[sectionsTable[currentSectionIndex].numberOfLineNumbers] @ sectionsTable[currentSectionIndex].ptrLineNumbers;
// Next section
if (sectionsTable[currentSectionIndex].sizeOfRawData > 0) // If the size of the next section is bigger than 0
$ = addressof(this) + sectionsTable[currentSectionIndex].sizeOfRawData; // Put the current offset at the start of it to account for any bytes left
if (currentSectionIndex < coffHeader.numberOfSections-1) // If it's not the last section (to not make $ the address of an inexistent section)
$ = sectionsTable[currentSectionIndex+1].ptrRawData; // Put the current offset at the next section's address
currentSectionIndex += 1; // Make the current section index the next section's index
} [[name(sectionsTable[currentSectionIndex-1].name)]];
Section sections[coffHeader.numberOfSections] @ coffHeader.optionalHeader.sizeOfHeaders;
// Symbol & String Tables
enum SectionNumberType : s16 {
Undefined = 0,
Absolute = -1,
Debug = -2
};
enum SymbolTypeMSB : u8 {
Null = 0x00,
Pointer = 0x10,
Function = 0x20,
Array = 0x30
};
enum SymbolTypeLSB : u8 {
Null = 0x00,
Void = 0x01,
Char = 0x02,
Short = 0x03,
Integer = 0x04,
Long = 0x05,
Float = 0x06,
Double = 0x07,
Struct = 0x08,
Union = 0x09,
Enum = 0x0A,
MemberOfEnum = 0x0B,
Byte = 0x0C,
Word = 0x0D,
UInt = 0x0E,
DWord = 0x0F
};
enum StorageClassType : s8 {
EndOfFunction = -1,
Null = 0,
Automatic = 1,
External = 2,
Static = 3,
Register = 4,
DefinedExternally = 5,
Label = 6,
UndefinedLabel = 7,
MemberOfStruct = 8,
Argument = 9,
StructTag = 10,
MemberOfUnion = 11,
UnionTag = 12,
TypeDefinition = 13,
UndefinedStatic = 14,
EnumTag = 15,
MemberOfEnum = 16,
RegisterParameter = 17,
Bitfield = 18,
Block = 100,
BlockFunction = 101,
EndOfStruct = 102,
File = 103,
Section = 104,
WeakExternal = 105,
CLRToken = 107
};
struct SymbolNameOffset {
padding[4];
u32 offset [[name("nameOffset")]];
} [[inline]];
struct SymbolType {
SymbolTypeMSB msb;
SymbolTypeLSB lsb;
};
fn formatSymbolType(SymbolType value) {
return "{ " + std::string::to_string(value.msb) + " | " + std::string::to_string(value.lsb) + " }";
};
struct Symbol {
if (std::mem::read_unsigned($, 4) == 0)
SymbolNameOffset nameOffset;
else char shortName[8];
u32 value;
SectionNumberType sectionNumber;
SymbolType type [[format("formatSymbolType")]];
StorageClassType storageClass;
u8 numberOfAuxSymbols;
};
bool checkForSymbols in;
Symbol symbolTable[checkForSymbols * coffHeader.numberOfSymbols] @ coffHeader.pointerToSymbolTable;
struct SymbolString {
char string[] [[format("formatNullTerminatedString")]];
} [[inline]];
struct StringTable {
u32 size;
SymbolString strings[while($ < addressof(this) + size)];
} [[inline]];
StringTable stringTable[sizeof(symbolTable)>0] @ addressof(symbolTable) + sizeof(symbolTable);
// Rich Header
bool checkForRichHeader in;
u16 richHeaderEndPosition;
u32 richHeaderPosition;
fn findRichHeader() {
if (checkForRichHeader) {
for (u16 richEndCursor = peHeader.dosHeader.coffHeaderPointer, richEndCursor > peHeader.dosHeader.headerSizeInParagraphs*16, richEndCursor -= 1) {
if (std::mem::read_string(richEndCursor, 4) == "Rich") {
richHeaderEndPosition = richEndCursor;
//0x18 is the size of a Rich Header body with one product
for (u16 richCursor = richHeaderEndPosition - 0x18, richCursor > peHeader.dosHeader.headerSizeInParagraphs*16, richCursor -= 1) {
if (str(std::mem::read_unsigned(richCursor, 4) ^ std::mem::read_unsigned(richHeaderEndPosition+4, 4)) == "DanS") {
richHeaderPosition = richCursor;
break;
}
}
break;
}
}
}
};
findRichHeader();
fn formatHexadecimally(auto value) {
return std::string::to_string(value) + " (" + std::format("0x{:X}", value) + ")";
};
fn unmask(u32 value) {
return formatHexadecimally(value ^ std::mem::read_unsigned(richHeaderEndPosition+4, 4));
};
fn unmaskBuild(u32 value) {
return formatHexadecimally(value ^ std::mem::read_unsigned(richHeaderEndPosition+4, 2));
};
fn unmaskProduct(u16 type) {
str value = "Unknown";
str notation = "0x";
if (type ^ std::mem::read_unsigned(richHeaderEndPosition+6, 2) < 0x10) { notation += "0"; }
match(type ^ std::mem::read_unsigned(richHeaderEndPosition+6, 2)) {
(0x00): value = "Unmarked";
(0x01): value = "Imports";
(0x04): value = "STDLIBDLL";
(0x06): value = "VS97CVTRes";
(0x0A): value = "VS98CCompiler";
(0x0B): value = "VS98CPPCompiler";
(0x0C): value = "OldNames";
(0x0E): value = "MASM613";
(0x0F): value = "VS2003Assembler";
(0x16): value = "VC6SP5";
(0x19): value = "VS2002Linker";
(0x1C): value = "VS2002CCompiler";
(0x1D): value = "VS2002CPPCompiler";
(0x5D): value = "VS2003SDKIMP";
(0x60): value = "VS2003CPPCompiler";
(0x6D): value = "VS2005CCompiler";
(0x6E): value = "VS2005CPPCompiler";
(0x7B): value = "VS2005Linker";
(0x93): value = "VS2008Linker";
(0x9D): value = "Linker12";
(0x9E): value = "MASM10";
(0xAA): value = "VS2010CCompiler";
(0xAB): value = "VS2010CPPCompiler";
(0xFF): value = "VS2015CVTRes";
(0x101 | 0x102): value = "VS2015Linker";
(0x103): value = "VS2015Assembler";
(0x104): value = "VS2015CCompiler";
(0x105): value = "VS2015CPPCompiler";
}
return value + " (" + std::format(notation + "{:X}", type ^ std::mem::read_unsigned(richHeaderEndPosition+6, 2)) + ")";
};
struct Product {
u16 buildNumber [[format("unmaskBuild")]];
u16 productID [[format("unmaskProduct")]];
u32 objectCount [[format("unmask")]];
};
fn formatSignature(auto value) {
return "\"DanS\"";
};
using NullPadding = u32 [[format("unmask")]];
struct RichHeader {
char maskedSignature[4] [[format("formatSignature")]];
NullPadding nullPadding[3];
Product products[while($ < richHeaderEndPosition)];
char signature[4];
u32 mask;
};
struct RichHeaderContainer { if (checkForRichHeader) RichHeader richHeader; };
RichHeaderContainer richHeaderContainer @ richHeaderPosition [[inline]];