Skip to content

Instantly share code, notes, and snippets.

@rikkimax
Created March 25, 2017 11:28
Show Gist options
  • Select an option

  • Save rikkimax/314e3bce3f42b5a61ede60693454e43c to your computer and use it in GitHub Desktop.

Select an option

Save rikkimax/314e3bce3f42b5a61ede60693454e43c to your computer and use it in GitHub Desktop.
/// From http://www.delorie.com/djgpp/doc/exe/ and winnt.h
module definitions.msdos;
import std.experimental.allocator : IAllocator, make, makeArray, dispose;
///
final class MSDOS_Header {
private {
IAllocator allocator;
}
~this() {
allocator.dispose(relocs);
allocator.dispose(overlay_data);
}
///
ushort bytes_in_last_block;
///
ushort blocks_in_file;
///
MZReloc[] relocs;
///
ushort header_paragraphs;
///
ushort min_extra_paragraphs;
///
ushort max_extra_paragraphs;
///
ushort ss;
///
ushort sp;
///
ushort checksum;
///
ushort ip;
///
ushort cs;
/// Must be >= 0x40
ushort reloc_table_offset = 0x40;
///
ushort overlay_number;
//ushort[4] reserved1;
///
ushort oem_identifier;
///
ushort oem_information;
//ushort[10] reserved2;
///
uint extended_header_offset;
/// overload data
ubyte[] overlay_data;
///
ubyte[] toBytes(IAllocator allocator) {
import std.bitmanip : nativeToLittleEndian;
// validation of relocation table offset
if (reloc_table_offset < 0x40)
return null;
ubyte[] ret = allocator.makeArray!ubyte(fullFileSize);
ret[0 .. 2] = cast(ubyte[2])"MZ";
ret[2 .. 4] = nativeToLittleEndian!ushort(bytes_in_last_block);
ret[4 .. 6] = nativeToLittleEndian!ushort(blocks_in_file);
ret[6 .. 8] = nativeToLittleEndian!ushort(cast(ushort)relocs.length);
ret[8 .. 10] = nativeToLittleEndian!ushort(header_paragraphs);
ret[10 .. 12] = nativeToLittleEndian!ushort(min_extra_paragraphs);
ret[12 .. 14] = nativeToLittleEndian!ushort(max_extra_paragraphs);
ret[14 .. 16] = nativeToLittleEndian!ushort(ss);
ret[16 .. 18] = nativeToLittleEndian!ushort(sp);
ret[18 .. 20] = nativeToLittleEndian!ushort(checksum);
ret[20 .. 22] = nativeToLittleEndian!ushort(ip);
ret[22 .. 24] = nativeToLittleEndian!ushort(cs);
ret[24 .. 26] = nativeToLittleEndian!ushort(reloc_table_offset);
ret[26 .. 28] = nativeToLittleEndian!ushort(overlay_number);
ret[28 .. 36] = 0;
ret[36 .. 38] = nativeToLittleEndian!ushort(oem_identifier);
ret[38 .. 40] = nativeToLittleEndian!ushort(oem_information);
ret[40 .. 60] = 0;
ret[60 .. 64] = nativeToLittleEndian!uint(extended_header_offset);
ret[64 .. 64 + overlay_data.length] = overlay_data;
size_t offset = reloc_table_offset;
foreach(reloc; relocs) {
ret[offset .. offset + 2] = nativeToLittleEndian!ushort(reloc.offset);
ret[offset + 2 .. offset + 4] = nativeToLittleEndian!ushort(reloc.segment);
offset += 4;
}
return ret;
}
///
static bool from(ubyte[] data, IAllocator allocator, out MSDOS_Header ret) {
import std.bitmanip : littleEndianToNative;
if (data.length < 0x40)
return false;
if (data[0 .. 2] != "MZ")
return false;
ret = allocator.make!MSDOS_Header;
ret.allocator = allocator;
ret.bytes_in_last_block = littleEndianToNative!ushort(data[2 .. 4]);
ret.blocks_in_file = littleEndianToNative!ushort(data[4 .. 6]);
ret.relocs = allocator.makeArray!MZReloc(data[6 .. 8]);
ret.header_paragraphs = littleEndianToNative!ushort(data[8 .. 10]);
ret.min_extra_paragraphs = littleEndianToNative!ushort(data[10 .. 12]);
ret.max_extra_paragraphs = littleEndianToNative!ushort(data[12 .. 14]);
ret.ss = littleEndianToNative!ushort(data[14 .. 16]);
ret.sp = littleEndianToNative!ushort(data[16 .. 18]);
ret.checksum = littleEndianToNative!ushort(data[18 .. 20]);
ret.ip = littleEndianToNative!ushort(data[20 .. 22]);
ret.cs = littleEndianToNative!ushort(data[22 .. 24]);
ret.reloc_table_offset = littleEndianToNative!ushort(data[24 .. 26]);
ret.overlay_number = littleEndianToNative!ushort(data[26 .. 28]);
ret.oem_identifier = littleEndianToNative!ushort(data[36 .. 38]);
ret.oem_information = littleEndianToNative!ushort(data[38 .. 40]);
ret.extended_header_offset = littleEndianToNative!uint(data[60 .. 64]);
if (data.length < 64 + ret.reloc_table_offset) {
allocator.dispose(ret.relocs);
return false;
}
ret.overlay_data = allocator.makeArray!ubyte(ret.reloc_table_offset - 64);
ret.overlay_data = data[64 .. 64 + ret.reloc_table_offset];
if (data.length < 64 + ret.reloc_table_offset + (4 * ret.relocs.length)) {
allocator.dispose(ret.relocs);
allocator.dispose(ret.overlay_data);
return false;
}
size_t offset = ret.reloc_table_offset;
foreach(ref reloc; ret.relocs) {
reloc.offset = littleEndianToNative!ushort(*cast(ubyte[2]*)data[offset .. offset + 2].ptr);
reloc.segment = littleEndianToNative!ushort(*cast(ubyte[2]*)data[offset + 2 .. offset + 4].ptr);
offset += 4;
}
return true;
}
///
size_t fullFileSize() {
assert(reloc_table_offset >= 0x40, "Invalid location of relocation table");
return reloc_table_offset + (4 * relocs.length) + overlay_data.length;
}
}
///
struct MZReloc {
///
ushort offset;
///
ushort segment;
}
/// A common MS-DOS header that is ready for use by e.g. PE-COFF or OMF
/// that probably won't be executable within DOS
static const(ubyte)[] Empty_MSDOS_Header = cast(const(ubyte)[])x"
4d 5a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00
";
/// An untested MS-DOS stub that should force the program to quit
static const(ubyte)[] Empty_MSDOS_Stub = cast(const(ubyte)[])x"
B8 4C 00 CD 21
";
/// A common MS-DOS header
/// that should be executable within DOS
static const(ubyte)[] Common_MSDOS_Header = cast(const(ubyte)[])x"
4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00
B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
";
/// A common MS-DOS stub that is used with PE-COFF executables
/// that should be executable within DOS
static const(ubyte)[] Common_MSDOS_Stub = cast(const(ubyte)[])x"
0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68
69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F
74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20
6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00
83 C2 32 29 C7 A3 5C 7A C7 A3 5C 7A C7 A3 5C 7A
CE DB D8 7A C6 A3 5C 7A CE DB C9 7A C5 A3 5C 7A
CE DB CF 7A DA A3 5C 7A C7 A3 5D 7A 33 A3 5C 7A
CE DB DF 7A D3 A3 5C 7A CE DB D5 7A CC A3 5C 7A
CE DB C8 7A C6 A3 5C 7A CE DB CD 7A C6 A3 5C 7A
52 69 63 68 C7 A3 5C 7A 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
";
/// http://pierrelib.pagesperso-orange.fr/exec_formats/OMF_v1.1.pdf
/// TODO: representations of each record type
module definitions.omf;
import std.experimental.allocator : IAllocator, make, makeArray, dispose;
///
final class OMF_Records {
///
OMF_Record[] records;
private {
IAllocator allocator;
}
~this() {
foreach(record; records) {
allocator.dispose(record.data);
}
allocator.dispose(records);
}
///
ubyte[] toBytes(IAllocator allocator) {
import std.bitmanip : nativeToLittleEndian;
ubyte[] ret = allocator.makeArray!ubyte(fullFileSize);
size_t offset;
foreach(record; records) {
ret[offset] = cast(ubyte)record.type;
ret[offset + 1 .. offset + 3] = nativeToLittleEndian!ushort(cast(ushort)record.data.length);
ret[offset + 3] = record.checksum;
offset += 4;
ret[offset .. offset + record.data.length] = record.data[];
offset += record.data.length;
}
return ret;
}
///
static OMF_Records from(ubyte[] data, IAllocator allocator) {
import std.bitmanip : littleEndianToNative;
size_t i, countRecords;
while(i + 4 <= data.length) {
i += littleEndianToNative!ushort(*cast(ubyte[2]*)data[i + 1 .. i + 3].ptr) + 4;
countRecords++;
}
OMF_Records ret = allocator.make!OMF_Records;
ret.allocator = allocator;
ret.records = allocator.makeArray!OMF_Record(countRecords);
i = 0;
countRecords = 0;
while (i + 4 < data.length) {
size_t dataLength = littleEndianToNative!ushort(*cast(ubyte[2]*)data[i + 1 .. i + 3].ptr);
ubyte[] recdata = data[i + 3 .. i + 3 + dataLength];
ret.records[i].type = cast(OMF_Record_Type)data[i];
ret.records[i].checksum = data[i + 3 + dataLength];
ret.records[i].data = allocator.makeArray!ubyte(recdata.length);
ret.records[i].data = recdata[];
i += dataLength + 4;
countRecords++;
}
return ret;
}
///
size_t fullFileSize() {
size_t ret;
foreach(ref record; records)
ret += 4 + record.data.length;
return ret;
}
}
///
enum OMF_Record_Type {
///
THEADR = 0x80,
///
LHEADR = 0x82,
///
COMENT = 0x88,
///
IMPDEF = COMENT,
///
EXPDEF = COMENT,
///
INCDEF = COMENT,
///
LNKDEF = COMENT,
///
LIBMOD = COMENT,
///
EXESTR = COMENT,
///
INCERR = COMENT,
///
NOPAD = COMENT,
///
WKEXT = COMENT,
///
LZEXT = COMENT,
///
MODEND_16 = 0x8A,
///
MODEND_32 = 0x8B,
///
EXTDEF = 0x8C,
///
PUBDEF_16 = 0x90,
///
PUBDEF_32 = 0x91,
///
LINNUM_16 = 0x94,
///
LINNUM_32 = 0x95,
///
LNAMES = 0x96,
///
SEGDEF_16 = 0x98,
///
SEGDEF_32 = 0x99,
///
GRPDEF = 0x9A,
///
FIXUPP_16 = 0x9C,
///
FIXUPP_32 = 0x9D,
///
LEDATA_16 = 0xA0,
///
LEDATA_32 = 0xA1,
///
LIDATA_16 = 0xA2,
///
LIDATA_32 = 0xA3,
///
COMDEF = 0xB0,
///
BAKPAT_16 = 0xB2,
///
BAKPAT_32 = 0xB3,
/// LEXTDEF_a == LEXTDEF_b
LEXTDEF_a = 0xB4,
/// LEXTDEF_a == LEXTDEF_b
LEXTDEF_b = 0xB5,
///
LPUBDEF_16 = 0xB6,
///
LPUBDEF_32 = 0xB7,
///
LCOMDEF = 0xB8,
///
CEXTDEF = 0xBC,
///
COMDAT_16 = 0xC2,
///
COMDAT_32 = 0xC3,
///
LINSYM_16 = 0xC4,
///
LINSYM_32 = 0xC5,
///
ALIAS = 0xC6,
///
NBKPAT_16 = 0xC8,
///
NBKPAT_32 = 0xC9,
///
LLNAMES = 0xCA,
///
VERNUM = 0xCC,
///
VENDEXT = 0xCE
}
///
struct OMF_Record {
///
OMF_Record_Type type;
///
ubyte[] data;
///
ubyte checksum;
///
string getCountCharString(size_t offset) {
if (data.length > offset) {
size_t offset_e, length;
if (data[offset] & 0x80) {
if (data.length > offset + 1) {
length = (data[offset] & 0x7F) * 0x100 + data[offset + 1];
offset_e = 1;
} else
return null;
} else
length = data[offset];
if (data.length >= offset + offset_e + 1 + length) {
offset += 1 + offset_e;
return cast(string)data[offset .. offset + length];
} else
return null;
} else
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment