#pragma description NE header and Standard NE fields #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; u8 overlayInformation[0x20]; u32 neHeaderPointer; }; u16 dosMessageOffset; u16 pointedCodeOffset; fn finddosmessage() { for (u8 i = 0, $+i < std::mem::read_unsigned(0x3C, 4), i = i + 1) { if (std::mem::read_unsigned($+i, 1) == 0xBA) { // MOV instruction dosMessageOffset = std::mem::read_unsigned($+i+1, 2); break; } } }; fn findpointingcode() { for (u8 i = 0, $+i < std::mem::read_unsigned(0x3C, 4), i = i + 1) { if (std::mem::read_unsigned($+i, 1) == 0xE8) { // CALL instruction pointedCodeOffset = std::mem::read_unsigned($+i+1, 2); return true; } } return false; }; fn isdosdata(char c) { return c == 0x0D || c == '$'; }; struct DOSStub { if (findpointingcode()) { u8 pointingCode[3]; u8 code[while(std::mem::read_unsigned($, 1) != 0x00)] @ addressof(this) + pointedCodeOffset + 3; char message[while(!isdosdata(std::mem::read_unsigned($, 1)))]; char data[while(std::mem::read_string($-1, 1) != "$")]; } else { finddosmessage(); if (dosMessageOffset > 0) { u8 code[while($ != addressof(this) + dosMessageOffset)]; char message[while(!isdosdata(std::mem::read_unsigned($, 1)))]; char data[while(std::mem::read_string($-1, 1) != "$")]; } else { char code[while(std::mem::read_unsigned($, 1) != 0x00)]; } } }; struct FileHeader { DOSHeader dosHeader; DOSStub dosStub @ dosHeader.headerSizeInParagraphs * 16; }; FileHeader fileHeader @ 0x00; enum DGroupType : u8 { NoAutoData, SingleData, MultipleData, Null }; fn formatDGroupType(u8 value) { DGroupType dgroup = value; return dgroup; }; enum AppType : u8 { None, Fullscreen, WinPMCompatible, UsesWinPM }; fn formatAppType(u8 value) { AppType app = value; return app; }; bitfield ProgramFlags { dGroupType : 2 [[format("formatDGroupType")]]; globalInitialization : 1; protectedModeOnly : 1; instructions86 : 1; instructions286 : 1; instructions386 : 1; instructionsX87 : 1; }; bitfield ApplicationFlags { applicationType : 2 [[format("formatAppType")]]; padding : 1; os2Application : 1; reserved : 1; imageError : 1; nonConforming : 1; dll : 1; }; enum OSType : u8 { Unknown = 0x00, OS2 = 0x01, Win16 = 0x02, DOS4 = 0x03, Win32 = 0x04, BorlandOSServices = 0x05, PharlapDOSExtenderOS2 = 0x81, PharlapDOSExtenderWindows = 0x82 }; bitfield OS2EXEFlags { longFilename : 1; protectedMode : 1; proportionalFonts : 1; gangloadArea : 1; }; struct NEHeader { char signature[2]; u8 majorLinkerVersion; u8 minorLinkerVersion; u16 entryTableOffset; u16 entryTableLength; u32 fileCRC; ProgramFlags programFlags; ApplicationFlags appFlags; u16 autoDataSegmentIndex; u16 initHeapSize; u16 initStackSize; u32 entryPoint; u32 initialStackPointer; u16 segmentCount; u16 moduleReferenceCount; u16 nonResidentNamesTableSize; u16 segmentTableOffset; u16 resourceTableOffset; u16 residentNamesTableOffset; u16 moduleReferenceTableOffset; u16 importedNamesTableOffset; u8 *nonResidentNamesTablePointer[nonResidentNamesTableSize] : u32; u16 moveableEntryCount; u16 fileAlignmentSizeShiftCount; u16 resourceCount; OSType targetOS; OS2EXEFlags os2ExeFlags; u16 thunksReturnOffset; u16 segmentReferenceThunksOffset; u16 minimumCodeSwapAreaSize; u8 expectedMinorWindowsVersion; u8 expectedMajorWindowsVersion; }; NEHeader neHeader @ fileHeader.dosHeader.neHeaderPointer; bitfield SegmentTableFlags { dataSegment : 1; typeMask : 2; padding : 1; moveable : 1; padding : 1; preloaded : 1; padding : 1; containsRelocationInfo : 1; padding : 1; discardPriority : 4; }; struct SegmentTable { u16 segmentDataPointer; u16 segmentLength; SegmentTableFlags segmentTableFlags; u16 minimumAllocationSize; }; SegmentTable segmentTable[neHeader.segmentCount] @ addressof(neHeader) + neHeader.segmentTableOffset; bitfield BlockFlags { padding : 4; moveable : 1; shared : 1; preload : 1; padding : 9; }; struct ResourceTypeInformationBlock { u8 *resourcePointer : u16; u16 resourceLength; BlockFlags flags; u16 resourceID; u32 reserved; }; struct ResourceRecord { u16 typeID; u16 numberOfResources; u32 reserved; ResourceTypeInformationBlock blocks[numberOfResources]; }; struct ResourceTable { u16 alignmentShiftCount; ResourceRecord records[neHeader.resourceTableEntryCount]; u8 stringLength; char string[stringLength]; }; ResourceTable resourceTable[neHeader.resourceCount] @ addressof(neHeader) + neHeader.resourceTableOffset; struct ResidentName { u8 stringLength; char string[stringLength]; u16 ordinalNumber; }; ResidentName residentNameTable[while($+1 < addressof(neHeader) + neHeader.moduleReferenceTableOffset)] @ addressof(neHeader) + neHeader.residentNamesTableOffset; struct ModuleReference { u16 moduleNameOffset; }; ModuleReference moduleReferenceTable[neHeader.moduleReferenceCount] @ addressof(neHeader) + neHeader.moduleReferenceTableOffset; struct ImportedNameTable { u8 stringLength; char string[stringLength]; }; ImportedNameTable importedNameTable[while($ < addressof(neHeader) + neHeader.entryTableOffset)] @ addressof(neHeader) + neHeader.importedNamesTableOffset; enum EntryDataType : u8 { Unused, Fixed = 0x01 ... 0xFE, Moveable }; struct EntryTable { u8 entryCount; EntryDataType segmentIndicator; }; EntryTable entryTable[neHeader.entryTableLength/2] @ addressof(neHeader) + neHeader.entryTableOffset;