diff --git a/README.md b/README.md index 3d2f2d70..e0474ac0 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,9 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | NBT | | [`patterns/nbt.hexpat`](patterns/nbt.hexpat) | Minecraft NBT format | | NDS | `application/x-nintendo-ds-rom` | [`patterns/nds.hexpat`](patterns/nds.hexpat) | DS Cartridge Header | | NE | `application/x-ms-ne-executable` | [`patterns/ne.hexpat`](patterns/ne.hexpat) | NE header and Standard NE fields | -| nes | | [`patterns/nes.hexpat`](patterns/nes.hexpat) | .nes file format | +| nes | | [`patterns/nes.hexpat`](patterns/nes.hexpat) | Nintendo Entertainment System ROM | +| NSF | | [`patterns/nsf.hexpat`](patterns/nsf.hexpat) | NES Sound Format | +| NSFe | | [`patterns/nsfe.hexpat`](patterns/nsfe.hexpat) | NES Sound Format extended | | NotepadCache | | [`patterns/notepad-cache.hexpat`](patterns/notepad-cache.hexpat) | Windows Notepad Cache | | NotepadWindowState | | [`patterns/notepadwindowstate.hexpat`](patterns/notepadwindowstate.hexpat) | Windows 11 Notepad - Window State .bin file | | NRO | | [`patterns/nro.hexpat`](patterns/nro.hexpat) | Nintendo Switch NRO files | @@ -167,6 +169,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | SHR | | [`patterns/SHR.hexpat`](patterns/SHR.hexpat) | Apple IIgs Super Hi-Res (SHR) + PaintWorks Animation (ANI) | | shx | | [`patterns/shx.hexpat`](patterns/shx.hexpat) | ESRI index file | | smk | | [`patterns/smk.hexpat`](patterns/smk.hexpat) | Smacker video file | +| SNES | | [`patterns/snes.hexpat`](patterns/snes.hexpat) | Super Nintendo Entertainment System ROM header | | sup | | [`patterns/sup.hexpat`](patterns/sup.hexpat) | PGS Subtitle | | SPIRV | | [`patterns/spirv.hexpat`](patterns/spirv.hexpat) | SPIR-V header and instructions | | STDF | | [`patterns/stdfv4.hexpat`](patterns/stdfv4.hexpat) | Standard test data format for IC testers | diff --git a/patterns/ips.hexpat b/patterns/ips.hexpat index bccee99d..91121ae4 100644 --- a/patterns/ips.hexpat +++ b/patterns/ips.hexpat @@ -4,26 +4,25 @@ #pragma endian big -import std.mem; import std.string; struct Hunk { - u24 offset; - u16 length; - if (!length) { - u16 runCount; - u8 payload; - } - else { - u8 payload[length]; - } + u24 offset; + u16 length; + if (!length) { + u16 runCount; + u8 payload; + } + else { + u8 payload[length]; + } }; struct IPS { - char signature[5]; - Hunk hunks[while($ < std::mem::size() - (3 + 3 * (std::mem::read_string(std::mem::size()-3, 3) != "EOF")))]; - char eof[3]; - u24 truncatedSize[3+(std::mem::read_string(std::mem::size()-3, 3) != "EOF")>3]; + char signature[5]; + Hunk hunks[while($ < std::mem::size() - (3 + 3 * (std::mem::read_string(std::mem::size()-3, 3) != "EOF")))]; + char eof[3]; + u24 truncatedSize[std::mem::read_string(std::mem::size()-3, 3) != "EOF"]; }; IPS ips @ 0x00; diff --git a/patterns/nes.hexpat b/patterns/nes.hexpat index 6292ada0..797d8ec2 100644 --- a/patterns/nes.hexpat +++ b/patterns/nes.hexpat @@ -145,7 +145,7 @@ struct NES2Attributes { } MiscellaneousROMs miscellaneousROMs; DefaultExpansionDevice defaultExpansionDevice; -}; +} [[inline]]; fn renderEOF(str string) { return "\"NES\""; @@ -243,7 +243,7 @@ struct OfficialHeader { u8 complementaryChecksum [[hex::spec_name("Checksum for characterChecksum~makerID")]]; }; -u24 calculatedPRGROMSize = 16384 * ((0x0100 * $[9] & 0x0F) * ($[7] & 12 == 8) + header.prgROMSizeBy16KiBs); +u24 calculatedPRGROMSize = 16384 * ((0x0100 * ($[9] & 0x0F)) * ($[7] & 12 == 8) + header.prgROMSizeBy16KiBs); fn hasOfficialHeader() { u8 sum; @@ -263,4 +263,145 @@ struct PRGROM { }; PRGROM prgROM @ 0x10 + sizeof(trainer); -u8 chrROM[8192 * ((0x0100 * $[9] >> 4) * ($[7] & 12 == 8) + header.chrROMSizeBy8KiBs)] @ addressof(prgROM) + 16384 * header.prgROMSizeBy16KiBs; +u8 chrROM[8192 * ((0x0100 * ($[9] >> 4)) * ($[7] & 12 == 8) + header.chrROMSizeBy8KiBs)] @ addressof(prgROM) + 16384 * header.prgROMSizeBy16KiBs; + +fn identifyMapper(u16 mapperValue, u8 submapperValue) { + str mapper; + str submapper; + str designation; + match (mapperValue) { + (0): mapper = "NROM"; + (1): mapper = "MMC1B"; + (2): mapper = "UxROM"; + (3): mapper = "CNROM-32"; + (4): mapper = "MMC3"; + (5): mapper = "MMC5"; + (6): mapper = "Front Fareast Magic Card 1/2M RAM Cartridge"; + (7): mapper = "AxROM"; + (8): mapper = "Front Fareast Magic Card 1/2M RAM Cartridge (Initial latch-based banking mode 4)"; + (9): mapper = "MMC2"; + (10): mapper = "MMC4"; + (11): mapper = "Color Dreams"; + (12): mapper = "(See submapper)"; + (13): mapper = "CPROM"; + (14): mapper = "SL-1632"; + (15): mapper = "K-102xx"; + (16): mapper = "Bandai FCG boards"; + (17): mapper = "Front Fareast Super Magic Card RAM cartridge"; + (18): mapper = "SS88006 (Jaleco)"; + (19): mapper = "Namco 129/163"; + (20): mapper = "Famicom Disk System"; + (21): mapper = "VRC4a/VRC4c"; + (22): mapper = "VRC2a"; + (23): mapper = "VRC4e or VRC2b + VRC4f"; + (24): mapper = "VRC6a"; + (25): mapper = "VRC4d or VRC2c + VRC4b"; + (26): mapper = "VRC6b"; + (27): mapper = "World Hero"; + (28): mapper = "Action 53"; + (29): mapper = "RET-CUFROM"; + (30): mapper = "UNROM 512"; + (31): mapper = "NSF"; + (32): mapper = "G-101"; + (33): mapper = "TC0190"; + (34): mapper = "(See submapper)"; + (35): mapper = "J.Y. Company (8KiB WRAM)"; + (36): mapper = "01-22000-400"; + (37): mapper = "SMB+Tetris+NWC"; + (38): mapper = "Crime Busters"; + (39): mapper = "Study & Game 32-in-1"; + (40): mapper = "NTDEC 27xx"; + (41): mapper = "Caltron 6-in-1"; + (42): mapper = "FDS -> NES Hacks"; + (43): mapper = "TONY-I/YS-612"; + (44): mapper = "Super Big 7-in-1"; + (45): mapper = "GA23C"; + (46): mapper = "Rumble Station"; + (47): mapper = "Super Spike V'Ball + NWC"; + (48): mapper = "TC0690"; + (49): mapper = "Super HIK 4-in-1"; + (50): mapper = "761214"; + (51): mapper = "11-in-1 Ball Games"; + (52): mapper = "Realtec 8213"; + (53): mapper = "Supervision 16-in-1"; + (54): mapper = "Novel Diamond 9999999-in-1"; + (55): mapper = "QFJ"; + (56): mapper = "KS202"; + (57): mapper = "GK"; + (58): mapper = "WQ"; + (59): mapper = "T3H53"; + (60): mapper = "Reset-based NROM-128 4-in-1"; + (61): mapper = "(See submapper)"; + (62): mapper = "Super 700-in-1"; + (63): mapper = "(See submapper)"; + (64): mapper = "RAMBO-1"; + (65): mapper = "H3001"; + (66): mapper = "GxROM"; + (67): mapper = "Sunsoft-3"; + (68): mapper = "Sunsoft-4"; + (69): mapper = "Sunsoft FME-7/Sunsoft 5A/Sunsoft 5B"; + (70): mapper = "Family Trainer Mat"; + (71): mapper = "Camerica"; + (72): mapper = "JF-17"; + (73): mapper = "VRC3"; + (74): mapper = "860908C"; + (75): mapper = "VRC1"; + (76): mapper = "NAMCOT-3446"; + (77): mapper = "Napoleon Senki"; + (78): mapper = "74HC161/32"; + (79): mapper = "NINA-003/NINA-006"; + (80): mapper = "X1-005"; + (81): mapper = "N715021"; + (82): mapper = "X1-017"; + } + if (mapperValue == 3) { + match (submapperValue) { + (0): submapper = "Bus conflict"; + (1): submapper = "No bus conflicts"; + (2): submapper = "AND-type bus conflicts"; + } + } + else if (mapperValue == 4) designation = "TxROM"; + else if (mapperValue == 12) { + match (submapperValue) { + (0): submapper = "SL-5020B (Gouder)"; + (1): submapper = "Front Fareast Magic Card 4M RAM Cartridge"; + } + } + else if (mapperValue == 16) { + match (submapperValue) { + (0): submapper = "FCG-1/2 or LZ93D50"; + (4): submapper = "FCG-1/2"; + (5): submapper = "LZ93D50"; + } + } + else if (mapperValue == 34) { + match (submapperValue) { + (0): submapper = "NINA-001/NINA-002"; + (1): submapper = "BNROM"; + } + } + else if (mapperValue == 40) { + match (submapperValue) { + (0): submapper = "NTDEC 2722"; + (1): submapper = "NTDEC 2752"; + } + } + else if (mapperValue == 61) { + match (submapperValue) { + (0): submapper = "NTDEC 0324"; + (1): submapper = "NTDEC BS-N032"; + (_): submapper = "GS-2017"; + } + } + else if (mapperValue == 63) { + match (submapperValue) { + (0): submapper = "TH2291-3"; + (1): submapper = "82AB"; + } + } + std::print("Mapper: " + mapper + "(" + std::string::to_string(mapperValue) + ")"); + if (submapper) std::print("Submapper: " + submapper + "(" + std::string::to_string(submapperValue) + ")"); + if (designation) std::print("Designation: " + designation); +}; +identifyMapper(0x0100 * ($[8] & 0x0F) + 0x10 * ($[7] & 0x0F) + header.flags.lowerMapperNybble, $[8] >> 4); diff --git a/patterns/nsf.hexpat b/patterns/nsf.hexpat new file mode 100644 index 00000000..b80465e6 --- /dev/null +++ b/patterns/nsf.hexpat @@ -0,0 +1,109 @@ +#pragma author gmestanley +#pragma description NES Sound Format file + +import std.string; + +struct ChunkMetadata { + u32 length; + char ID[4]; +} [[inline]]; + +struct TimeChunkData { + u32 trackLengths[while($\""; +}; + +struct Header { + char signature[5] [[format("renderEOF")]]; + u8 version; + u8 songAmount; + u8 startingSong; + u16 dataLoadAddress; + u16 dataInitAddress; + u16 dataPlayAddress; + char gameName[32] [[format("formatName")]]; + char songwriting[32] [[format("formatName")]]; + char copyrightHolder[32] [[format("formatName")]]; + u16 ntscPlaySpeed; + u8 bankswitchInitValues[8]; + u16 palPlaySpeed; + Region region; + ExtraSoundChipSupport extraSoundChipSupport; + NSF2Flags nsf2flags; + u24 dataLength; +}; + +Header header @ 0x00; + +struct Chunks { + if (header.dataLength) + NSFEChunk chunks[while($ 0) { - AlignmentType enumValue = value; - return enumValue; - } - return value; + if (value) { + 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")]]; + 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) + "\""; - } - } + 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; + 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; @@ -318,886 +322,887 @@ SectionHeader sectionsTable[coffHeader.numberOfSections] @ addressof(coffHeader. u16 currentSectionIndex; fn relativeVirtualDifference() { - return sectionsTable[currentSectionIndex].rva - sectionsTable[currentSectionIndex].ptrRawData; + 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) + "\""; + return std::mem::read_unsigned(addressof(coffHeader.optionalHeader.magic), 2) / 0x41; }; // Exception Table bitfield FunctionBitfield { - prologLength : 8; - functionLength : 22; - instructions32Bit : 1; - exceptionHandler : 1; + 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; - } + 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]]; + 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")]]; + 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; - } + 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")]]; + 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(); - if (directoryTable.ordinalTableRVA > relativeVirtualDifference()) { - u16 exportOrdinalTable[directoryTable.namePointersAmount] @ directoryTable.ordinalTableRVA - relativeVirtualDifference(); - } - if (directoryTable.imageNameRVA > relativeVirtualDifference()) { - char imageName[] @ directoryTable.imageNameRVA - relativeVirtualDifference() [[format("formatNullTerminatedString")]]; - } - $ = addressof(this)+coffHeader.optionalHeader.directories[0].size; + ExportDirectoryTable directoryTable; + ExportAddress exportAddressTable[directoryTable.addressesAmount] @ directoryTable.addressTableRVA - relativeVirtualDifference(); + ExportNamePointer exportNamePointerTable[directoryTable.namePointersAmount] @ directoryTable.namePointerTableRVA - relativeVirtualDifference(); + if (directoryTable.ordinalTableRVA > relativeVirtualDifference()) { + u16 exportOrdinalTable[directoryTable.namePointersAmount] @ directoryTable.ordinalTableRVA - relativeVirtualDifference(); + } + if (directoryTable.imageNameRVA > 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")]]; + padding : 7; + flag : 1 [[name("ordinalFlag")]]; +}; + +fn formatMangledString(str string) { + return hex::dec::demangle(formatNullTerminatedString(string)); }; struct ImportsName { - u16 hint; - char name[] [[format("formatNullTerminatedString")]]; - if ($ % 2 == 1) { u8 pad; } + u16 hint; + if (std::mem::read_string($, 1) == "?") + char name[] [[format("formatMangledString")]]; + else + 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]; - } - } + 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(); - } + 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; + 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")]]; - } + 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; + 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; + 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")]]; - } + 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; + 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)) + "\""; + 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")]]; + 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")]]; + u8 blue [[color("1F77B4")]]; + u8 green [[color("2CA02C")]]; + u8 red [[color("D62728")]]; + u8 reserved [[color("828282")]]; }; u32 imageDataSize; struct Bitmap { - BitmapHeader bmh [[name("bitmapHeader")]]; + BitmapHeader bmh [[name("bitmapHeader")]]; - if ((bmh.bitCount != 24) && (bmh.bitCount != 32)) { - Colors rgbq[bmh.clrUsed*((1 << bmh.bitCount)*!bmh.clrUsed)]; - imageDataSize = imageDataSize - sizeof(rgbq); - } + 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)]; + u8 imageData[imageDataSize-sizeof(bmh)]; }; // * Cursor Resource struct Cursor { - u16 reserved; - u16 type; - if (!type) { - imageDataSize = parent.size-4; - Bitmap bitmapData [[inline]]; - } + 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 + Button = 0x80, + Edit, + Static, + ListBox, + ScrollBar, + ComboBox }; struct VLSElement { - if (std::mem::read_unsigned($, 2) == 0xFFFF) { - u16 atomDefiner; - } - else { - AtomType atom; - } + 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")]]; - } + 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; - } + 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; + 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]; - }*/ + 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]; + DialogTemplate dialogTemplate; + DialogItem items[dialogTemplate.numberOfItems]; }; // * String Resource struct StringTableResource { - std::string::SizedString16 strings[while($ < (parent.dataRVA - relativeVirtualDifference()) + parent.size)]; + std::string::SizedString16 strings[while($ < (parent.dataRVA - relativeVirtualDifference()) + parent.size)]; }; // * GroupCursor Resource struct GroupCursor { - u16 assorteddata; - u16 colors; - u16 otherassorteddata; - u16 pixels; - u16 assorteddataarray[5]; - u16 ordinalName; + u16 assorteddata; + u16 colors; + u16 otherassorteddata; + u16 pixels; + u16 assorteddataarray[5]; + u16 ordinalName; }; // * GroupIcon Resource struct GroupIconHeader { - u16 reserved; - u16 type; - u16 count; + u16 reserved; + u16 type; + u16 count; }; struct GroupIconEntry { - u8 width; - u8 height; - u8 colorCount; - u8 reserved; - u16 planes; - u16 bitCount; - u32 bytesInResource; - u16 id; + u8 width; + u8 height; + u8 colorCount; + u8 reserved; + u16 planes; + u16 bitCount; + u32 bytesInResource; + u16 id; }; struct GroupIcon { - GroupIconHeader header; - GroupIconEntry entries[header.count]; + 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)]; + u16 length; + u16 valueLength; + u16 type; + char16 key[] [[format("formatNullTerminatedString16")]]; + padding[while(!$[$] && $ < 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)]; - } + VersionEntryHeader stringInfoHeader; + if (stringInfoHeader.valueLength > 0) { + char16 string[] [[format("formatNullTerminatedString16")]]; + padding[while(!$[$])]; + } }; 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)]; - } + 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(!$[$])]; + } }; 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)]; + 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) + ")"; + char chr = char(value); + str notation = "0x"; + if (value < 0x10) notation += "0"; + if (!value) chr = "␀"; + return "'" + chr + "' (" + std::format(notation + "{:X}", value) + ")"; }; +using TrueChar = u8 [[format("displayTrueChar")]]; + // Resource Table enum ResourceID : u32 { - Cursor = 0x01, - Bitmap, - Icon, - Menu, - Dialog, - String, - Accelerator = 0x09, - StringData, - GroupCursor = 0x0C, - GroupIcon = 0x0E, - Version = 0x10, - Manifest = 0x18 + 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(); - } + 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; + 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; - } + if ($[$+3] >= 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); - } + 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; + DataField datafield; }; struct NameDirectoryEntry { - OffsetField offsetToName; - std::string::SizedString16 name @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + offsetToName.offset; + OffsetField offsetToName; + std::string::SizedString16 name @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + offsetToName.offset; - DataField datafield; + DataField datafield; }; struct ResourceDirectoryTable { - u32 characteristics; - u32 timeDateStamp; - u16 majorVersion; - u16 minorVersion; - u16 nameEntriesAmount; - u16 idEntriesAmount; + 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]; + 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; + ResourceDirectory rootDirectory; + $ = addressof(this)+coffHeader.optionalHeader.directories[2].size; }; // Base Relocations Table enum BaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - Reserved = 6, - DIR64 = 10 + Absolute, + High, + Low, + HighLow, + HighAdjacent, + Reserved = 6, + DIR64 = 10 }; enum MIPSBaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - MIPSJMPAddress, - Reserved, - MIPSJMPAddress16 = 9, - DIR64 + Absolute, + High, + Low, + HighLow, + HighAdjacent, + MIPSJMPAddress, + Reserved, + MIPSJMPAddress16 = 9, + DIR64 }; enum ARMBaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - ARMMOV32, - Reserved, - DIR64 = 10 + Absolute, + High, + Low, + HighLow, + HighAdjacent, + ARMMOV32, + Reserved, + DIR64 = 10 }; enum RISCVBaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - RISCVHigh20, - Reserved, - RISCVLow12I, - RISCVLow12S, - DIR64 = 10 + Absolute, + High, + Low, + HighLow, + HighAdjacent, + RISCVHigh20, + Reserved, + RISCVLow12I, + RISCVLow12S, + DIR64 = 10 }; enum THUMBBaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - ARMMOV32, - Reserved, - ThumbMOV32, - DIR64 = 10 + Absolute, + High, + Low, + HighLow, + HighAdjacent, + ARMMOV32, + Reserved, + ThumbMOV32, + DIR64 = 10 }; enum LoongarchBaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - Reserved = 6, - MarkLA = 8, - DIR64 = 10 + 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; - } + 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")]]; + offset : 12; + type : 4 [[format("formatBaseRelocationType")]]; }; struct BaseRelocationBlock { - u32 pageRVA; - u32 blockSize; - BaseRelocationWord word[while($ < addressof(this) + this.blockSize)] [[inline]]; + 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]]; + 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 + Unknown, + COFF, + Codeview, + FPO, + Misc, + Exception, + Fixup, + OmapToSRC, + OmapFromSRC, + Borland, + CLSID = 11, + REPRO = 16, + ExtendedDLLCharacteristics = 20 }; struct RSDS { - char signature[4]; - type::GUID guid; - u32 age; - char path[] [[format("formatNullTerminatedString")]]; + 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; + 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; + 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; + 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)]; + 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; + 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; + 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; + 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; +fn clearDirectoryChecks() { + 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 + 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(); + } + } + clearDirectoryChecks(); + + 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] @ sectionsTable[0].ptrRawData; +Section sections[coffHeader.numberOfSections] @ coffHeader.optionalHeader.sizeOfHeaders * !sectionsTable[0].sizeOfRawData + + sectionsTable[0].ptrRawData * sectionsTable[0].sizeOfRawData>0; // Symbol & String Tables enum SectionNumberType : s16 { - Undefined = 0, - Absolute = -1, - Debug = -2 + Undefined = 0, + Absolute = -1, + Debug = -2 }; enum SymbolTypeMSB : u8 { - Null = 0x00, - Pointer = 0x10, - Function = 0x20, - Array = 0x30 + 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 + 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 + 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")]]; + padding[4]; + u32 offset [[name("nameOffset")]]; } [[inline]]; struct SymbolType { - SymbolTypeMSB msb; - SymbolTypeLSB lsb; + SymbolTypeMSB msb; + SymbolTypeLSB lsb; }; fn formatSymbolType(SymbolType value) { - return "{ " + std::string::to_string(value.msb) + " | " + std::string::to_string(value.lsb) + " }"; + 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; + 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; @@ -1205,12 +1210,12 @@ bool checkForSymbols in; Symbol symbolTable[checkForSymbols * coffHeader.numberOfSymbols] @ coffHeader.pointerToSymbolTable; struct SymbolString { - char string[] [[format("formatNullTerminatedString")]]; + char string[] [[format("formatNullTerminatedString")]]; } [[inline]]; struct StringTable { - u32 size; - SymbolString strings[while($ < addressof(this) + size)]; + u32 size; + SymbolString strings[while($ < addressof(this) + size)]; } [[inline]]; StringTable stringTable[sizeof(symbolTable)>0] @ addressof(symbolTable) + sizeof(symbolTable); @@ -1220,87 +1225,87 @@ 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; - } - } - } + 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) + ")"; + 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)); + return formatHexadecimally(value ^ std::mem::read_unsigned(richHeaderEndPosition+4, 4)); }; fn unmaskBuild(u32 value) { - return formatHexadecimally(value ^ std::mem::read_unsigned(richHeaderEndPosition+4, 2)); + 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)) + ")"; + 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")]]; + u16 buildNumber [[format("unmaskBuild")]]; + u16 productID [[format("unmaskProduct")]]; + u32 objectCount [[format("unmask")]]; }; fn formatSignature(auto value) { - return "\"DanS\""; + 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; + char maskedSignature[4] [[format("formatSignature")]]; + NullPadding nullPadding[3]; + Product products[while($ < richHeaderEndPosition)]; + char signature[4]; + u32 mask; }; struct RichHeaderContainer { if (checkForRichHeader) RichHeader richHeader; }; diff --git a/patterns/snes.hexpat b/patterns/snes.hexpat new file mode 100644 index 00000000..4a6b690f --- /dev/null +++ b/patterns/snes.hexpat @@ -0,0 +1,110 @@ +#pragma author gmestanley +#pragma description Super Nintendo Entertainment System ROM header +#pragma sources snes.nesdev.org/wiki/ROM_header CPU_vectors en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map + +import std.string; + +u24 headerPosition = 0x7FC0; + +fn calculateHeaderPosition() { + if (std::mem::size() > 0x20000 && std::mem::size() < 0x600000) headerPosition += 0x8000; + else if (std::mem::size() >= 0x600000) headerPosition += 0x400000; +}; +calculateHeaderPosition(); + +enum ChipsetSubtype : u8 { + SPC7110, + ST01x, + ST018, + CX4 +}; + +struct ExpandedHeader { + char makerID[2]; + char gameID[4]; + padding[6]; + u8 expansionFlashSize [[comment("1 << N")]]; + u8 expansionRAMSize [[comment("1 << N")]]; + u8 specialVersion; + ChipsetSubtype chipsetSubtype; +}; + +struct ConditionalStruct { + if ($[headerPosition+0x1A] == 0x33) ExpandedHeader expandedHeader @ headerPosition - 0x10; + else if (!$[headerPosition+0x14]) ChipsetSubtype chipsetSubtype @ headerPosition - 1; +} [[inline]]; + +ConditionalStruct conditionalStruct @ $; + +enum MappingMode : u8 { + LoROM, + HiROM, + ExHiROM = 5 +}; + +fn formatMappingMode(u8 value) { + MappingMode enumValue = value; + return enumValue; +}; + +bitfield ROMType { + mappingMode : 4 [[format("formatMappingMode")]]; + speed : 1; + unknown : 1; +}; + +enum CoprocessorType : u8 { + DSP, + GSU, + OBC1, + SA1, + SDD1, + SRTC, + Other = 0x0E, + Custom +}; + +fn formatExtraHardwareType(u8 value) { + str valueMeaning = " (ROM"; + if (!value) valueMeaning += " only"; + else if (value) { + if (value > 3) valueMeaning += " + coprocessor"; + if (value != 3 || value != 6) valueMeaning += " + RAM"; + if (value == 2 || value > 5) valueMeaning += " + battery"; + } + return std::string::to_string(value) + valueMeaning + ")"; +}; + +fn formatCoprocessorType(u8 value) { + CoprocessorType enumValue = value; + return enumValue; +}; + +bitfield ExtraHardware { + extraHardwareType : 4 [[format("formatExtraHardwareType")]]; + coprocessorType : 4 [[format("formatCoprocessorType")]]; +}; + +enum Country : u8 { + NTSC = 1, + PAL +}; + +struct Header { + char title[21]; + ROMType romType; + ExtraHardware extraHardware; + u8 romSize [[comment("1 << N, rounded up")]]; + u8 ramSize [[comment("1 << N")]]; + Country country; + u8 developerID; + u8 romVersion; + u16 checksumComplement; + u16 checksum; + padding[4]; + u16 vectors[6]; + padding[4]; + u16 emulationModeVectors[6]; +}; + +Header header @ headerPosition;