Skip to content

Commit

Permalink
patterns/ne: Adding pattern file for NE executables (WerWolv#58)
Browse files Browse the repository at this point in the history
* Update pe.hexpat

Implementing a number of things and fixing others

* Update pe.hexpat

Adding the readonlyData pattern

* Update pe.hexpat

Testing putting the number of tabs on Github to 4 instead of 8 (so that comments on the code for the Sections don't break)

* Update pe.hexpat

Reverting change that turned out to be needless

* Update pe.hexpat

Actually sending the `products[while($ != richHeaderEndPosition)]` to `products[while($ < richHeaderEndPosition)]` change

* Add files via upload

Adding NE test file

* Add files via upload

Adding NE pattern file

* Update ne.hexpat

Fixing the error with the entry table assignment

* Update README.md

Added the NE pattern file to the list of patterns
  • Loading branch information
gmestanley authored Nov 19, 2022
1 parent 01a1bd0 commit 9887da7
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Hex patterns, include patterns and magic files for the use with the ImHex Hex Ed
| BMP | `image/bmp` | [`patterns/bmp.hexpat`](patterns/bmp.hexpat) | OS2/Windows Bitmap files |
| ELF | `application/x-executable` | [`patterns/elf.hexpat`](patterns/elf.hexpat) | ELF header in elf binaries |
| PE | `application/x-dosexec` | [`patterns/pe.hexpat`](patterns/pe.hexpat) | PE header, COFF header, Standard COFF fields and Windows Specific fields |
| NE | | [`patterns/ne.hexpat`](patterns/ne.hexpat) | NE header and Standard NE fields |
| Intel HEX | | [`patterns/intel_hex.hexpat`](patterns/intel_hex.hexpat) | [Intel hexadecimal object file format definition]("https://en.wikipedia.org/wiki/Intel_HEX") |
| MIDI | `audio/midi` | [`patterns/midi.hexpat`](patterns/midi.hexpat) | MIDI header, event fields provided |
| WAV | `audio/wav` | [`patterns/wav.hexpat`](patterns/wav.hexpat) | RIFF header, WAVE header, PCM header |
Expand Down
264 changes: 264 additions & 0 deletions patterns/ne.hexpat
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
#include <std/mem.pat>

#pragma bitfield_order right_to_left

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;
} [[right_to_left]];

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;
Binary file added tests/patterns/test_data/ne.hexpat.exe
Binary file not shown.

0 comments on commit 9887da7

Please sign in to comment.