#pragma MIME application/x-dosexec #pragma MIME application/x-msdownload #pragma bitfield_order right_to_left #pragma pattern_limit 0x400000 #include #include struct DOSHeader { char signature[2]; u16 lastPageSize; u16 numberOfPages; u16 relocations; u16 headerSizeInParagraphs; u16 minimumAllocatedParagraphs; u16 maximumAllocatedParagraphs; u16 initialSSValue; u16 initialRelativeSPValue; u16 checksum; u16 initialRelativeIPValue; u16 initialCSValue; u16 relocationsTablePointer; u16 overlayNumber; u16 reservedWords[4]; u16 oemIdentifier; u16 oemInformation; u16 otherReservedWords[10]; u32 coffHeaderPointer; }; u16 dosMessageOffset; fn isntdosmessage(char c) { return c == 0x0D || c == '$'; }; fn finddosmessage() { for (u8 i = 0, $+i < std::mem::read_unsigned(0x3C, 4), i = i + 1) { if (std::mem::read_unsigned($+i, 1) == 0xBA) { dosMessageOffset = std::mem::read_unsigned($+i+1, 2); break; } } }; struct DOSStub { finddosmessage(); if (dosMessageOffset > 0) { u8 code[while($ != addressof(this) + dosMessageOffset)]; char message[while(!isntdosmessage(std::mem::read_unsigned($, 1)))]; char data[while(std::mem::read_string($-1, 1) != "$")]; } else { u8 code[while(std::mem::read_unsigned($, 6) != 0x00)] @ dosHeader.headerSizeInParagraphs * 16; } }; struct PEHeader { DOSHeader dosHeader; DOSStub dosStub @ dosHeader.headerSizeInParagraphs * 16; }; PEHeader peHeader @ 0x00; enum MachineType : u16 { Unknown = 0x00, AM33 = 0x1D3, AMD64 = 0x8664, ARM = 0x1C0, ARM64 = 0xAA64, ARMNT = 0x1C4, DECAlphaAXP = 0x183, EBC = 0xEBC, I386 = 0x14C, I860 = 0x14D, IA64 = 0x200, LOONGARCH32 = 0x6232, LOONGARCH64 = 0x6264, M32R = 0x9041, MIPS16 = 0x266, MIPSFPU = 0x366, MIPSFPU16 = 0x466, POWERPC = 0x1F0, POWERPCFP = 0x1F1, R4000 = 0x166, RISCV32 = 0x5032, RISCV64 = 0x5064, RISCV128 = 0x5128, SH3 = 0x1A2, SH3DSP = 0x1A3, SH4 = 0x1A6, SH5 = 0x1A8, THUMB = 0x1C2, WCEMIPSV2 = 0x169 }; 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 { relocationsStripped : 1; executableImage : 1; lineNumbersStripped : 1; localSymbolsStripped : 1; aggressivelyTrimWorkingSet : 1; largeAddressAware : 1; padding : 1; bytesReversedLo : 1; is32BitMachine : 1; debugInfoStripped : 1; removableRunFromSwap : 1; netRunFromSwap : 1; system : 1; dll : 1; uniprocessorMachineOnly : 1; bytesReversedHi : 1; }; bitfield DLLCharacteristics { padding : 5; highEntropyVA : 1; dynamicBase : 1; forceIntegrity : 1; nxCompatible : 1; noIsolation : 1; noSEH : 1; doNotBind : 1; appContainer : 1; wdmDriver : 1; cfGuard : 1; terminalServerAware : 1; }; struct DataDirectory { u32 virtualAddress; u32 size; }; struct OptionalHeader { PEFormat magic; u8 majorLinkerVersion; u8 minorLinkerVersion; u32 sizeOfCode; u32 sizeOfInitializedData; u32 sizeOfUninitializedData; u32 addressOfEntryPoint; u32 baseOfCode; if (magic == PEFormat::PE32) { u32 baseOfData; u32 imageBase; } else if (magic == PEFormat::PE32Plus) { u64 imageBase; } u32 sectionAlignment; u32 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::PE32) { u32 sizeOfStackReserve; u32 sizeOfStackCommit; u32 sizeOfHeapReserve; u32 sizeOfHeapCommit; } else if (magic == PEFormat::PE32Plus) { u64 sizeOfStackReserve; u64 sizeOfStackCommit; u64 sizeOfHeapReserve; u64 sizeOfHeapCommit; } u32 loaderFlags; u32 numberOfRVAsAndSizes; DataDirectory directories[numberOfRVAsAndSizes]; }; struct COFFHeader { char signature[4]; MachineType machine; u16 numberOfSections; u32 timeDateStamp; u32 pointerToSymbolTable; u32 numberOfSymbols; u16 sizeOfOptionalHeader; Characteristics characteristics; if (sizeOfOptionalHeader > 0x00) { OptionalHeader optionalHeader; } }; COFFHeader coffHeader @ peHeader.dosHeader.coffHeaderPointer; enum AlignmentType : u8 { None, BoundaryOf1Byte, BoundaryOf2Bytes, BoundaryOf4Bytes, BoundaryOf8Bytes, BoundaryOf16Bytes, BoundaryOf32Bytes, BoundaryOf64Bytes, BoundaryOf128Bytes, BoundaryOf256Bytes, BoundaryOf512Bytes, BoundaryOf1024Bytes, BoundaryOf2048Bytes, BoundaryOf4096Bytes, BoundaryOf8192Bytes, }; fn formatAlignmentBits(u8 value) { AlignmentType enumValue = value; return enumValue; }; bitfield SectionFlags { padding : 3; doNotPad : 1; padding : 1; containsCode : 1; containsInitializedData : 1; containsUninitializedData : 1; linkOther : 1; containsComments : 1; padding : 1; remove : 1; containsCOMDATData : 1; padding : 2; globalPointerRelocation : 1; purgeable : 1; is16Bit : 1; locked : 1; preloaded : 1; dataAlignment : 4 [[format("formatAlignmentBits")]]; extendedRelocations : 1; discardable : 1; notCacheable : 1; notPageable : 1; shared : 1; executed : 1; read : 1; writtenTo : 1; }; struct SectionHeader { char name[8]; if (coffHeader.characteristics.executableImage) { u32 virtualSize; } else { u32 physicalAddress; } u32 virtualAddress; u32 sizeOfRawData; u32 ptrRawData; u32 ptrRelocations; u32 ptrLineNumbers; u16 numberOfRelocations; u16 numberOfLineNumbers; SectionFlags characteristics; }; SectionHeader sectionsTable[coffHeader.numberOfSections] @ addressof(coffHeader.characteristics)+2 + coffHeader.sizeOfOptionalHeader; // Declarations of sections and units used by them u16 currentSectionIndex; fn updateSectionIndex() { currentSectionIndex = currentSectionIndex + 1; }; fn virtualDataDifference() { return sectionsTable[currentSectionIndex].virtualAddress - sectionsTable[currentSectionIndex].ptrRawData; }; fn formatNullTerminatedString(str string) { return "\"" + std::string::substr(string, 0, std::string::length(string)-4) + "\""; }; // Exception Section bitfield ExceptionSectionBits { functionLength : 22; instructions32Bit : 1; exceptionHandler : 1; }; struct FunctionTableEntry { if (coffHeader.machine == MachineType::MIPSFPU) { u32 beginVA; u32 endVA; u32 exceptionHandlerPointer; u32 handlerDataPointer; u32 prologEndVA; } else if (coffHeader.machine == MachineType::ARM || coffHeader.machine == MachineType::ARM64 || coffHeader.machine == MachineType::ARMNT || coffHeader.machine == MachineType::POWERPC || coffHeader.machine == MachineType::POWERPCFP || coffHeader.machine == MachineType::SH3 || coffHeader.machine == MachineType::SH4) { u32 beginVA; u8 prologLength; ExceptionSectionBits miscellaneousBits; } else if (coffHeader.machine == MachineType::AMD64 || coffHeader.machine == MachineType::IA64) { u32 beginRVA; u32 endRVA; u32 unwindInformationRVA; } }; // Exports Section struct ExportDirectoryTable { u32 exportFlags; u32 timeDateStamp; u16 majorVersion; u16 minorVersion; u32 nameRVA; u32 ordinalBase; u32 addressTableEntries; u32 numberOfNamePointers; u32 exportAddressTableRVA; u32 namePointerRVA; u32 ordinalTableRVA; }; struct ExportName { char name[] [[format("formatNullTerminatedString")]]; }; struct ExportAddress { if (std::mem::read_unsigned($, 4) > sectionsTable[currentSectionIndex].sizeOfRawData && std::mem::read_unsigned($, 4) < sectionsTable[currentSectionIndex].ptrRawData) { u32 exportRVA; } else { u32 forwarderRVA; } }; struct ExportNamePointer { u32 exportNameRVA; ExportName exportName @ exportNameRVA - virtualDataDifference(); }; struct ExportsSection { ExportDirectoryTable exportDirectoryTable; ExportAddress exportAddressTable[exportDirectoryTable.addressTableEntries] @ exportDirectoryTable.exportAddressTableRVA - virtualDataDifference(); ExportNamePointer exportNamePointerTable[exportDirectoryTable.numberOfNamePointers] @ exportDirectoryTable.namePointerRVA - virtualDataDifference(); u16 exportOrdinalTable[exportDirectoryTable.numberOfNamePointers] @ exportDirectoryTable.ordinalTableRVA - virtualDataDifference(); char dllName[] @ exportDirectoryTable.nameRVA - virtualDataDifference() [[format("formatNullTerminatedString")]]; }; // Imports + Readonly Data Section fn architecture() { return std::mem::read_unsigned(addressof(coffHeader.optionalHeader.magic), 2) / 0x41; }; bitfield OrdinalFlagByte { flag : 1; padding : 7; } [[left_to_right]]; struct NameTableEntry { u16 hint; char name[] [[format("formatNullTerminatedString")]]; if ($ % 2 == 1) { u8 pad; } }; struct AddressTableEntry { OrdinalFlagByte ordinalFlagByte @ $+(architecture()-1); if (ordinalFlagByte.flag) { u16 ordinalNumber; u8 nullPadding[architecture()-2]; } else { u32 nameTableRVA; if (coffHeader.optionalHeader.magic == PEFormat::PE32Plus) { u8 nullPadding[4]; } } }; struct LookupTableEntry : AddressTableEntry { if (!ordinalFlagByte.flag && std::mem::read_unsigned($, architecture()) > 0) { NameTableEntry name @ nameTableRVA - virtualDataDifference(); } }; struct DirectoryTable { u32 lookupTableRVA; u32 timeDateStamp; u32 forwarderChain; u32 dllNameRVA; u32 addressTableRVA; } [[static]]; u16 importsIndex; struct ImportsStructure { LookupTableEntry lookupTable[while(std::mem::read_unsigned($, architecture()) != 0)] @ parent.directoryTables[importsIndex].lookupTableRVA - virtualDataDifference(); AddressTableEntry addressTable[while(std::mem::read_unsigned($, architecture()) != 0)] @ parent.directoryTables[importsIndex].addressTableRVA - virtualDataDifference(); char dllName[] @ parent.directoryTables[importsIndex].dllNameRVA - virtualDataDifference() [[format("formatNullTerminatedString")]]; importsIndex = importsIndex + 1; } [[inline]]; struct ImportsSection { DirectoryTable directoryTables[while(std::mem::read_unsigned($, 16) != 0x00)]; DirectoryTable nullDirectoryTable; ImportsStructure importsStructures[sizeof(directoryTables) / sizeof(directoryTables[0])]; }; struct ReadonlyDataSection { if (coffHeader.optionalHeader.numberOfRVAsAndSizes >= 0xC) { $ += coffHeader.optionalHeader.directories[0xC].size; } u8 readonlyDataStart[while($ < coffHeader.optionalHeader.directories[1].virtualAddress - virtualDataDifference())]; ImportsSection importsSection; }; // Resource Section using ResourceDirectory; struct ResourceString { u16 length; char16 string[length]; }; struct NameDirectoryEntry { if (std::mem::read_unsigned($+3, 1) == 0x80) { u32 relativeOffsetToName; ResourceString name @ sectionsTable[currentSectionIndex].ptrRawData + (relativeOffsetToName - 0x80000000); } else { char name[4]; } u32 relativeOffsetToData; ResourceDirectory directory @ sectionsTable[currentSectionIndex].ptrRawData + (relativeOffsetToData - 0x80000000); }; // * Bitmap Resource struct BitmapHeader { u32 bitmapSize; u32 bitmapWidth; u32 bitmapHeight; u16 bitmapPlanes; u16 bitmapBitCount; u32 bitmapCompression; u32 bitmapImageSize; u32 bitmapXPelsPerMeter; u32 bitmapYPelsPerMeter; u32 bitmapClrUsed; u32 bitmapClrImportant; }; struct Colors { u8 blue [[color("1F77B4")]]; u8 green [[color("2CA02C")]]; u8 red [[color("D62728")]]; u8 reserved [[color("828282")]]; }; struct Bitmap { BitmapHeader bmh; if ((bmh.bitmapBitCount != 24) && (bmh.bitmapBitCount != 32)) { if (bmh.bitmapClrUsed > 0) { Colors rgbq[bmh.bitmapClrUsed]; } else { Colors rgbq[1 << bmh.bitmapBitCount]; } } }; // * Dialog Resource struct DialogTemplate { u32 style; u32 extendedStyles; u16 numberOfItems; u16 x; u16 y; u16 width; u16 height; }; struct DialogItemTemplate { u32 style; u32 extendedStyles; u16 x; u16 y; u16 width; u16 height; u16 id; }; struct NullTerminatedString16 { char16 string[while(std::mem::read_unsigned($, 2) != 0)]; char16 terminatingNull; } [[inline]]; 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 { NullTerminatedString16 string; } }; struct DialogItem { u16 alignment; DialogItemTemplate template; VariableLengthStructure itemClass; VariableLengthStructure itemTitle; u16 itemCreationData; if (itemCreationData > 0) { u8 itemData[itemCreationData]; } }; struct Dialog { DialogTemplate dialogTemplate; u16 dialogMenu; VariableLengthStructure dialogClass; VariableLengthStructure dialogTitle; u16 dialogFontSize; char16 dialogFontTypeface[while(std::mem::read_unsigned($, 2) != 0)]; u16 terminatingNull; DialogItem items[while($ < (parent.dataRVA - virtualDataDifference()) + parent.size)]; }; // * String Resource struct StringTableResource { ResourceString strings[while(std::mem::read_unsigned($, 2) != 0x00)]; u16 nullPadding[while($ < (parent.dataRVA - virtualDataDifference()) + 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[while(std::mem::read_unsigned($, 2) != 0)]; u16 terminatingNull; u8 nullPadding[while(std::mem::read_unsigned($, 1) == 0 && $ < addressof(terminatingNull)+5)]; } [[inline]]; struct StringInfo { VersionEntryHeader stringInfoHeader; if (stringInfoHeader.valueLength > 0) { NullTerminatedString16 string; u8 nullPadding[while(std::mem::read_unsigned($, 1) == 0)]; } }; struct VersionEntry { VersionEntryHeader header; if (std::string::starts_with(std::string::to_string(header.key), "VS_VERSION_INFO")) { u32 signature; u16 structVersion[2]; u16 fileVersion[4]; u16 productVersion[4]; u32 fileFlagsMask[2]; u32 fileFlags; u32 fileOS; u32 fileType; u32 fileSubType; u32 fileTimestamp; } else if (std::string::starts_with(std::string::to_string(header.key), "StringFileInfo")) { VersionEntryHeader stringTable; StringInfo strings[while($ < addressof(stringTable) + stringTable.length)]; } else if (std::string::starts_with(std::string::to_string(header.key), "VarFileInfo")) { VersionEntryHeader var; u16 translation[var.valueLength / 2]; } else { u8 value[header.valueLength*2]; u8 nullPadding[while(std::mem::read_unsigned($, 1) == 0)]; } }; // * Resources Using TrueChar fn displayTrueChar(u8 value) { if (value < 0x10) { if (value == 0x00) { return "'␀' (" + std::format("0x0{:X}", value) + ")"; } else { return "'" + char(value) + "' (" + std::format("0x0{:X}", value) + ")"; } } else { return "'" + char(value) + "' (" + std::format("0x{:X}", value) + ")"; } }; using TrueChar = u8 [[format("displayTrueChar")]]; struct XML { u8 bom[while(std::mem::read_unsigned($, 1) != '<')]; TrueChar contents[parent.size - sizeof(bom)] [[inline]]; }; // * The rest of the section enum ResourceID : u32 { Cursor = 0x01, Bitmap, Icon, Menu, Dialog, String, StringData = 0x0A, GroupCursor = 0x0C, GroupIcon = 0x0E, Version = 0x10, Manifest = 0x18 }; ResourceID resourceIDType; struct DataEntry { u32 dataRVA; u32 size; u32 codepage; u32 reserved; if (resourceIDType == ResourceID::Bitmap || (resourceIDType == ResourceID::Icon && std::mem::read_string((dataRVA-virtualDataDifference())+1, 3) != "PNG")) { Bitmap bitmap @ dataRVA - virtualDataDifference(); } else if (resourceIDType == ResourceID::Dialog) { Dialog dialog @ dataRVA - virtualDataDifference(); } else if (resourceIDType == ResourceID::String) { StringTableResource stringTableResource @ dataRVA - virtualDataDifference(); } else if (resourceIDType == ResourceID::StringData) { TrueChar stringData[size] @ dataRVA - virtualDataDifference(); } else if (resourceIDType == ResourceID::GroupCursor) { GroupCursor groupCursor @ dataRVA - virtualDataDifference(); } else if (resourceIDType == ResourceID::GroupIcon) { GroupIcon groupIcon @ dataRVA - virtualDataDifference(); } else if (resourceIDType == ResourceID::Version) { VersionEntry version[while($ < (dataRVA - virtualDataDifference()) + size)] @ dataRVA - virtualDataDifference(); } else if (resourceIDType == ResourceID::Manifest) { XML manifest @ dataRVA - virtualDataDifference(); } else { u8 resource[size] @ dataRVA - virtualDataDifference(); } }; struct IdDirectoryEntry { if ($ > (coffHeader.optionalHeader.directories[2].virtualAddress - virtualDataDifference()) + 0x10 + 8*(std::mem::read_unsigned(coffHeader.optionalHeader.directories[2].virtualAddress - virtualDataDifference() + 12, 2) + std::mem::read_unsigned(coffHeader.optionalHeader.directories[2].virtualAddress - virtualDataDifference() + 14, 2))) { u32 id; } else { ResourceID id; resourceIDType = id; } u32 offsetToData; if (offsetToData >= 0x80000000) { ResourceDirectory directory @ (coffHeader.optionalHeader.directories[2].virtualAddress - virtualDataDifference()) + (offsetToData - 0x80000000); } else { DataEntry dataEntry @ (coffHeader.optionalHeader.directories[2].virtualAddress - virtualDataDifference()) + offsetToData; } }; struct ResourceDirectoryTable { u32 characteristics; u32 timeDateStamp; u16 majorVersion; u16 minorVersion; u16 nameEntriesAmount; u16 idEntriesAmount; }; struct ResourceDirectory { ResourceDirectoryTable resourceDirectoryTable; NameDirectoryEntry nameEntries[resourceDirectoryTable.nameEntriesAmount]; IdDirectoryEntry idEntries[resourceDirectoryTable.idEntriesAmount]; }; struct ResourceSection { ResourceDirectory rootDirectory; }; // Relocations Section 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 formatMIPSType(u8 value) { MIPSBaseRelocationType mipsTypeBits = value; return mipsTypeBits; }; fn formatARMType(u8 value) { ARMBaseRelocationType armTypeBits = value; return armTypeBits; }; fn formatRISCVType(u8 value) { RISCVBaseRelocationType riscvTypeBits = value; return riscvTypeBits; }; fn formatTHUMBType(u8 value) { THUMBBaseRelocationType thumbTypeBits = value; return thumbTypeBits; }; fn formatLoongarchType(u8 value) { LoongarchBaseRelocationType loongarchTypeBits = value; return loongarchTypeBits; }; fn formatGenericType(u8 value) { BaseRelocationType genericTypeBits = value; return genericTypeBits; }; bitfield MIPSBaseRelocationWord { type : 4 [[format("formatMIPSType")]]; offset : 12; }; bitfield ARMBaseRelocationWord { type : 4 [[format("formatARMType")]]; offset : 12; }; bitfield RISCVBaseRelocationWord { type : 4 [[format("formatRISCVType")]]; offset : 12; }; bitfield THUMBBaseRelocationWord { type : 4 [[format("formatTHUMBType")]]; offset : 12; }; bitfield LoongarchBaseRelocationWord { type : 4 [[format("formatLoongarchType")]]; offset : 12; }; bitfield GenericBaseRelocationWord { type : 4 [[format("formatGenericType")]]; offset : 12; }; struct BaseRelocationBlock { u32 pageRVA; u32 blockSize; if (coffHeader.machine == MachineType::MIPS16 || coffHeader.machine == MachineType::MIPSFPU || coffHeader.machine == MachineType::MIPSFPU16) { MIPSBaseRelocationWord word; } else if (coffHeader.machine == MachineType::ARM || coffHeader.machine == MachineType::ARM64 || coffHeader.machine == MachineType::ARMNT) { ARMBaseRelocationWord word; } else if (coffHeader.machine == MachineType::RISCV32 || coffHeader.machine == MachineType::RISCV64 || coffHeader.machine == MachineType::RISCV128) { RISCVBaseRelocationWord word; } else if (coffHeader.machine == MachineType::THUMB) { THUMBBaseRelocationWord word; } else if (coffHeader.machine == MachineType::LOONGARCH32 || coffHeader.machine == MachineType::LOONGARCH64) { LoongarchBaseRelocationWord word; } else { GenericBaseRelocationWord word; } }; struct BaseRelocationTable { BaseRelocationBlock baseRelocationBlocks[while($ < (coffHeader.optionalHeader.directories[5].virtualAddress - virtualDataDifference()) + coffHeader.optionalHeader.directories[5].size)]; }; // Debug Section enum DebugType : u32 { Unknown, COFF, Codeview, FPO, Misc, Exception, Fixup, OmapToSRC, OmapFromSRC, Borland, Reserved10, CLSID, REPRO = 16, ExtendedDLLCharacteristics = 20 }; struct DebugDirectory { u32 characteristics; u32 timeDateStamp; u32 majorVersion; u32 minorVersion; DebugType type; u32 sizeOfData; u32 virtualAddressOfRawData; u32 pointerOfRawData; }; struct DebugSection { DebugDirectory directory; }; // TLS Section struct TLSSection { if (coffHeader.optionalHeader.magic == PEFormat::PE32) { u32 rawDataStartVA; u32 rawDataEndVA; u32 indexAddress; u32 callbacksAddress; } else if (coffHeader.optionalHeader.magic == PEFormat::PE32Plus) { u64 rawDataStartVA; u64 rawDataEndVA; u64 indexAddress; u64 callbacksAddress; } u32 zeroFillSize; u32 characteristics; }; // CRT Section struct CRTSection { u64 addresses[while($ < sectionsTable[currentSectionIndex].ptrRawData + sectionsTable[currentSectionIndex].sizeOfRawData)]; }; // General Section things struct LineNumber { u32 lineNumber @ $ + 4; if (lineNumber > 0x00) { u32 virtualAddress; } else { u32 symbolTableIndex; } $ += 4; }; fn importsPrint(str value) { std::print("Check for .idata section " + value); }; fn separateImportsSection() { bool returnedValue; if (coffHeader.optionalHeader.directories[1].size > 0) { for (u16 i = 0, i < coffHeader.numberOfSections, i = i + 1) { if (std::string::starts_with(sectionsTable[i].name, ".idata")) { importsPrint("successful. It is section " + std::string::to_string(i) + ", so the read-only data section won't have an imports section in it"); returnedValue = true; break; } } } if (!returnedValue) { importsPrint("failed! This means there is no separate imports section"); } return returnedValue; }; struct Section { if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".pdata")) { // Exception section FunctionTableEntry functionTableEntries[while($ < (coffHeader.optionalHeader.directories[3].virtualAddress - virtualDataDifference()) + coffHeader.optionalHeader.directories[3].size)] [[name("exceptionSection")]]; } else if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".edata")) { // Exports section ExportsSection exportsSection; } else if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".idata")) { // Imports section ImportsSection importsSection; } else if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".rdata")) { // Read-only data section if (separateImportsSection()) { u8 readonlyDataSection[sectionsTable[currentSectionIndex].sizeOfRawData]; } else { ReadonlyDataSection readOnlyDataSection; } } else if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".rsrc")) { // Resource section ResourceSection resourceSection; } else if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".reloc")) { // Base relocations section BaseRelocationTable relocationsSection; } else if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".debug") || std::string::starts_with(sectionsTable[currentSectionIndex].name, ".build")) { // Debug section DebugSection debugSection; } else if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".tls")) { // Thread-local storage section TLSSection tlsSection; } else if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".CRT")) { // CRT section CRTSection crtSection; } else { u8 freeformSection[sectionsTable[currentSectionIndex].sizeOfRawData]; // Freeform data section } // Other things LineNumber lineNumbers[sectionsTable[currentSectionIndex].numberOfLineNumbers] @ sectionsTable[currentSectionIndex].ptrLineNumbers; // Next section if (currentSectionIndex < coffHeader.numberOfSections-1) { // If it's not the last section (to avoid problems this code would have with it) updateSectionIndex(); // Make the current section index the next section's index if (sectionsTable[currentSectionIndex].sizeOfRawData > 0) { // If the next section isn't empty $ = sectionsTable[currentSectionIndex].ptrRawData; // Put the current offset at the start of it to account for any bytes left } } } [[inline]]; fn btoi(bool value) { if (value) { return 1; } else { return 0; } }; bool nonemptySections; u16 firstNonemptySection; fn findFirstNonemptySection() { for (u16 i = 0, i < coffHeader.numberOfSections, i = i + 1) { if (sectionsTable[i].sizeOfRawData > 0) { nonemptySections = true; firstNonemptySection = i; break; } } }; findFirstNonemptySection(); Section sections[btoi(nonemptySections) * coffHeader.numberOfSections] @ sectionsTable[firstNonemptySection].ptrRawData; // Rich Header enum ProductType : u16 { Unmarked = 0x00 ^ richHeaderEnd[0].mask.maskArray[1], Imports = 0x01 ^ richHeaderEnd[0].mask.maskArray[1], STDLIBDLL = 0x04 ^ richHeaderEnd[0].mask.maskArray[1], VC6CVTRes = 0x06 ^ richHeaderEnd[0].mask.maskArray[1], VC6CCompiler = 0x0A ^ richHeaderEnd[0].mask.maskArray[1], VC6CPPCompiler = 0x0B ^ richHeaderEnd[0].mask.maskArray[1], OldNames = 0x0C ^ richHeaderEnd[0].mask.maskArray[1], MASM613 = 0x0E ^ richHeaderEnd[0].mask.maskArray[1], VC2003Assembler = 0x0F ^ richHeaderEnd[0].mask.maskArray[1], VC6SP5 = 0x16 ^ richHeaderEnd[0].mask.maskArray[1], VC2002Linker = 0x19 ^ richHeaderEnd[0].mask.maskArray[1], VC2002CCompiler = 0x1C ^ richHeaderEnd[0].mask.maskArray[1], VC2002CPPCompiler = 0x1D ^ richHeaderEnd[0].mask.maskArray[1], VC2003SDKIMP = 0x5D ^ richHeaderEnd[0].mask.maskArray[1], VC2003CPPCompiler = 0x60 ^ richHeaderEnd[0].mask.maskArray[1], VC2008SDKIMP = 0x93 ^ richHeaderEnd[0].mask.maskArray[1], Linker12 = 0x9D ^ richHeaderEnd[0].mask.maskArray[1], MASM10 = 0x9E ^ richHeaderEnd[0].mask.maskArray[1], VC2010CCompiler = 0xAA ^ richHeaderEnd[0].mask.maskArray[1], VC2010CPPCompiler = 0xAB ^ richHeaderEnd[0].mask.maskArray[1], VC2015CVTRES = 0xFF ^ richHeaderEnd[0].mask.maskArray[1], VC2015Linker = 0x101 ... 0x102 ^ richHeaderEnd[0].mask.maskArray[1], VC2015Assembler = 0x103 ^ richHeaderEnd[0].mask.maskArray[1], VC2015CCompiler = 0x104 ^ richHeaderEnd[0].mask.maskArray[1], VC2015CPPCompiler = 0x105 ^ richHeaderEnd[0].mask.maskArray[1] }; union RichHeaderMask { u32 maskVariable; u16 maskArray[2]; }; struct RichHeaderEnd { char signature[4]; RichHeaderMask mask; } [[inline]]; bool checkForRichHeader in; u16 richHeaderEndPosition; fn initializeRichHeader() { if (checkForRichHeader) { for (u16 richEndCursor = sizeof(peHeader), richEndCursor < addressof(coffHeader), richEndCursor = richEndCursor + 1) { if (std::mem::read_string(richEndCursor, 4) == "Rich") { richHeaderEndPosition = richEndCursor; break; } } } }; initializeRichHeader(); RichHeaderEnd richHeaderEnd[checkForRichHeader] @ richHeaderEndPosition; fn formatSignature(auto value) { return "\"DanS\" "; }; fn formatHexadecimally(auto value) { return std::string::to_string(value) + " (" + std::format("0x{:X}", value) + ")"; }; fn unmaskBuild(u16 value) { return formatHexadecimally(value ^ richHeaderEnd[0].mask.maskArray[0]); }; fn unmask(u32 value) { return formatHexadecimally(value ^ richHeaderEnd[0].mask.maskVariable); }; using NullPadding = u32 [[format("unmask")]]; struct Product { u16 buildNumber [[format("unmaskBuild")]]; ProductType productID; u32 objectCount [[format("unmask")]]; }; struct RichHeaderCorpus { char maskedSignature[4] [[format("formatSignature")]]; NullPadding nullPadding[3]; Product products[while($ < richHeaderEndPosition)]; } [[inline]]; u8 richHeaderCorpusPosition; fn setupRichHeader() { if (checkForRichHeader) { //0x20 is the size of a Rich Header with one product for (u16 richCorpusCursor = richHeaderEndPosition - 0x20, richCorpusCursor > sizeof(peHeader), richCorpusCursor = richCorpusCursor - 0x01) { if (str(std::mem::read_unsigned(richCorpusCursor, 4) ^ richHeaderEnd[0].mask.maskVariable) == "DanS") { richHeaderCorpusPosition = richCorpusCursor; break; } } } }; setupRichHeader(); RichHeaderCorpus richHeaderCorpus[checkForRichHeader] @ richHeaderCorpusPosition; // 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 SymbolNameAddress { u32 zeroes; u32 offset; }; struct SymbolType { SymbolTypeMSB msb; SymbolTypeLSB lsb; }; struct Symbol { if (std::mem::read_unsigned($, 4) == 0) { SymbolNameAddress nameAddress; } else { char shortName[8]; } u32 value; SectionNumberType sectionNumber; SymbolType type; StorageClassType storageClass; u8 numberOfAuxSymbols; }; bool checkForDebugInformation in; Symbol symbolTable[btoi(checkForDebugInformation) * coffHeader.numberOfSymbols] @ coffHeader.pointerToSymbolTable; struct StringTableString { char string[] [[format("formatNullTerminatedString")]]; } [[inline]]; struct StringTable { u32 size; StringTableString strings[while($ < addressof(this) + size)]; } [[inline]]; StringTable stringTable[checkForDebugInformation] @ addressof(symbolTable) + sizeof(symbolTable);