Add more NE structures

This commit is contained in:
Matt Nadareski
2021-08-27 23:29:34 -07:00
parent e6b2be1738
commit e652e43cba
14 changed files with 488 additions and 369 deletions

View File

@@ -0,0 +1,46 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
/// <summary>
/// Resource type and name strings
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class NEResourceNameString
{
/// <summary>
/// Length of the type or name string that follows. A zero value
/// indicates the end of the resource type and name string, also
/// the end of the resource table.
/// </summary>
public byte Length;
/// <summary>
/// ASCII text of the type or name string.
/// </summary>
public char[] Value;
public static NEResourceNameString Deserialize(Stream stream)
{
var rds = new NEResourceNameString();
rds.Length = stream.ReadByteValue();
rds.Value = stream.ReadChars(rds.Length, Encoding.ASCII);
return rds;
}
public static NEResourceNameString Deserialize(byte[] contents, int offset)
{
var rds = new NEResourceNameString();
rds.Length = contents[offset++];
rds.Value = Encoding.ASCII.GetChars(contents, offset, rds.Length);
return rds;
}
}
}

View File

@@ -0,0 +1,78 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
/// <summary>
/// A table of resources for this type
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class NEResourceTableEntry
{
/// <summary>
/// File offset to the contents of the resource data,
/// relative to beginning of file. The offset is in terms
/// of the alignment shift count value specified at
/// beginning of the resource table.
/// </summary>
public ushort Offset;
/// <summary>
/// Length of the resource in the file (in bytes).
/// </summary>
public ushort Length;
/// <summary>
/// Resource flags
/// </summary>
public ResourceTableEntryFlags Flags;
/// <summary>
/// This is an integer type if the high-order
/// bit is set (8000h), otherwise it is the offset to the
/// resource string, the offset is relative to the
/// beginning of the resource table.
/// </summary>
public ushort ResourceID;
/// <summary>
/// Reserved.
/// </summary>
public ushort Handle;
/// <summary>
/// Reserved.
/// </summary>
public ushort Usage;
public static NEResourceTableEntry Deserialize(Stream stream)
{
var ni = new NEResourceTableEntry();
ni.Offset = stream.ReadUInt16();
ni.Length = stream.ReadUInt16();
ni.Flags = (ResourceTableEntryFlags)stream.ReadUInt16();
ni.ResourceID = stream.ReadUInt16();
ni.Handle = stream.ReadUInt16();
ni.Usage = stream.ReadUInt16();
return ni;
}
public static NEResourceTableEntry Deserialize(byte[] contents, int offset)
{
var ni = new NEResourceTableEntry();
ni.Offset = BitConverter.ToUInt16(contents, offset); offset += 2;
ni.Length = BitConverter.ToUInt16(contents, offset); offset += 2;
ni.Flags = (ResourceTableEntryFlags)BitConverter.ToUInt16(contents, offset); offset += 2;
ni.ResourceID = BitConverter.ToUInt16(contents, offset); offset += 2;
ni.Handle = BitConverter.ToUInt16(contents, offset); offset += 2;
ni.Usage = BitConverter.ToUInt16(contents, offset); offset += 2;
return ni;
}
}
}

View File

@@ -0,0 +1,64 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
/// <summary>
/// The segment table contains an entry for each segment in the executable
/// file. The number of segment table entries are defined in the segmented
/// EXE header. The first entry in the segment table is segment number 1.
/// The following is the structure of a segment table entry.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class NESegmentTableEntry
{
/// <summary>
/// Logical-sector offset (n byte) to the contents of the segment
/// data, relative to the beginning of the file. Zero means no
/// file data.
/// </summary>
public ushort StartFileSector;
/// <summary>
/// Length of the segment in the file, in bytes. Zero means 64K.
/// </summary>
public ushort BytesInFile;
/// <summary>
/// Attribute flags
/// </summary>
public SegmentTableEntryFlags Flags;
/// <summary>
/// Minimum allocation size of the segment, in bytes.
/// Total size of the segment. Zero means 64K
/// </summary>
public ushort MinimumAllocation;
public static NESegmentTableEntry Deserialize(Stream stream)
{
var nste = new NESegmentTableEntry();
nste.StartFileSector = stream.ReadUInt16();
nste.BytesInFile = stream.ReadUInt16();
nste.Flags = (SegmentTableEntryFlags)stream.ReadUInt16();
nste.MinimumAllocation = stream.ReadUInt16();
return nste;
}
public static NESegmentTableEntry Deserialize(byte[] content, int offset)
{
var nste = new NESegmentTableEntry();
nste.StartFileSector = BitConverter.ToUInt16(content, offset); offset += 2;
nste.BytesInFile = BitConverter.ToUInt16(content, offset); offset += 2;
nste.Flags = (SegmentTableEntryFlags)BitConverter.ToUInt16(content, offset); offset += 2;
nste.MinimumAllocation = BitConverter.ToUInt16(content, offset); offset += 2;
return nste;
}
}
}

View File

@@ -0,0 +1,72 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
/// <summary>
/// Resource type information block
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class ResourceTypeInformationBlock
{
/// <summary>
/// Type ID. This is an integer type if the high-order bit is
/// set (8000h); otherwise, it is an offset to the type string,
/// the offset is relative to the beginning of the resource
/// table. A zero type ID marks the end of the resource type
/// information blocks.
/// </summary>
public ushort TypeID;
/// <summary>
/// Number of resources for this type.
/// </summary>
public ushort ResourceCount;
/// <summary>
/// Reserved.
/// </summary>
public uint Reserved;
/// <summary>
/// Reserved.
/// </summary>
public NEResourceTableEntry[] ResourceTable;
public static ResourceTypeInformationBlock Deserialize(Stream stream)
{
var rtib = new ResourceTypeInformationBlock();
rtib.TypeID = stream.ReadUInt16();
rtib.ResourceCount = stream.ReadUInt16();
rtib.Reserved = stream.ReadUInt32();
rtib.ResourceTable = new NEResourceTableEntry[rtib.ResourceCount];
for (int i = 0; i < rtib.ResourceCount; i++)
{
rtib.ResourceTable[i] = NEResourceTableEntry.Deserialize(stream);
}
return rtib;
}
public static ResourceTypeInformationBlock Deserialize(byte[] contents, int offset)
{
var rtib = new ResourceTypeInformationBlock();
rtib.TypeID = BitConverter.ToUInt16(contents, offset); offset += 2;
rtib.ResourceCount = BitConverter.ToUInt16(contents, offset); offset += 2;
rtib.Reserved = BitConverter.ToUInt32(contents, offset); offset += 4;
rtib.ResourceTable = new NEResourceTableEntry[rtib.ResourceCount];
for (int i = 0; i < rtib.ResourceCount; i++)
{
rtib.ResourceTable[i] = NEResourceTableEntry.Deserialize(contents, offset); offset += 12;
}
return rtib;
}
}
}

View File

@@ -588,107 +588,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft
NRSOFF32 = 0x0D,
}
/// <summary>
/// Format of NS_FLAGS(x)
///
/// x Unused
/// h Huge segment
/// c 32-bit code segment
/// d Discardable segment
/// DD I/O privilege level (286 DPL bits)
/// c Conforming segment
/// r Segment has relocations
/// e Execute/read only
/// p Preload segment
/// P Pure segment
/// m Movable segment
/// i Iterated segment
/// ttt Segment type
/// </summary>
[Flags]
internal enum NsFlags : ushort
{
/// <summary>
/// Segment type mask
/// </summary>
NSTYPE = 0x0007,
/// <summary>
/// Code segment
/// </summary>
NSCODE = 0x0000,
/// <summary>
/// Data segment
/// </summary>
NSDATA = 0x0001,
/// <summary>
/// Iterated segment flag
/// </summary>
NSITER = 0x0008,
/// <summary>
/// Movable segment flag
/// </summary>
NSMOVE = 0x0010,
/// <summary>
/// Shared segment flag
/// </summary>
NSSHARED = 0x0020,
/// <summary>
/// For compatibility
/// </summary>
NSPURE = 0x0020,
/// <summary>
/// Preload segment flag
/// </summary>
NSPRELOAD = 0x0040,
/// <summary>
/// Execute-only (code segment), or read-only (data segment)
/// </summary>
NSEXRD = 0x0080,
/// <summary>
/// Segment has relocations
/// </summary>
NSRELOC = 0x0100,
/// <summary>
/// Conforming segment
/// </summary>
NSCONFORM = 0x0200,
/// <summary>
/// I/O privilege level (286 DPL bits)
/// </summary>
NSDPL = 0x0C00,
/// <summary>
/// Left shift count for SEGDPL field
/// </summary>
SHIFTDPL = 10,
/// <summary>
/// Segment is discardable
/// </summary>
NSDISCARD = 0x1000,
/// <summary>
/// 32-bit code segment
/// </summary>
NS32BIT = 0x2000,
/// <summary>
/// Huge memory segment, length of segment and minimum allocation size are in segment sector units
/// </summary>
NSHUGE = 0x4000,
}
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-image-only
internal enum OptionalHeaderType : ushort
{
@@ -708,6 +607,26 @@ namespace BurnOutSharp.ExecutableType.Microsoft
PE32Plus = 0x20b,
}
/// http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm
[Flags]
internal enum ResourceTableEntryFlags : ushort
{
/// <summary>
/// Resource is not fixed.
/// </summary>
MOVEABLE = 0x0010,
/// <summary>
/// Resource can be shared.
/// </summary>
PURE = 0x0020,
/// <summary>
/// Resource is preloaded.
/// </summary>
PRELOAD = 0x0040,
}
/// <summary>
/// Predefined Resource Types
/// </summary>
@@ -956,6 +875,91 @@ namespace BurnOutSharp.ExecutableType.Microsoft
/// </summary>
IMAGE_SCN_MEM_WRITE = 0x80000000,
}
/// http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm
[Flags]
internal enum SegmentTableEntryFlags : ushort
{
/// <summary>
/// Segment-type field.
/// </summary>
TYPE = 0x0007,
/// <summary>
/// Code-segment type.
/// </summary>
CODE = 0x0000,
/// <summary>
/// Data-segment type.
/// </summary>
DATA = 0x0001,
/// <summary>
/// Iterated segment flag
/// </summary>
ITER = 0x0008,
/// <summary>
/// Segment is not fixed.
/// </summary>
MOVEABLE = 0x0010,
/// <summary>
/// Shared segment flag
/// </summary>
SHARED = 0x0020,
/// <summary>
/// For compatibility
/// </summary>
PURE = 0x0020,
/// <summary>
/// Segment will be preloaded; read-only if this is a data segment.
/// </summary>
PRELOAD = 0x0040,
/// <summary>
/// Execute-only (code segment), or read-only (data segment)
/// </summary>
EXRD = 0x0080,
/// <summary>
/// Set if segment has relocation records.
/// </summary>
RELOCINFO = 0x0100,
/// <summary>
/// Conforming segment
/// </summary>
CONFORM = 0x0200,
/// <summary>
/// I/O privilege level (286 DPL bits)
/// </summary>
DPL = 0x0C00,
/// <summary>
/// Left shift count for SEGDPL field
/// </summary>
SHIFTDPL = 10,
/// <summary>
/// Discard priority.
/// </summary>
DISCARD = 0x1000,
/// <summary>
/// 32-bit code segment
/// </summary>
NS32BIT = 0x2000,
/// <summary>
/// Huge memory segment, length of segment and minimum allocation size are in segment sector units
/// </summary>
HUGE = 0x4000,
}
[Flags]
internal enum TargetOperatingSystems : byte

View File

@@ -9,36 +9,40 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
/// The NE header is a relatively large structure with multiple characteristics.
/// Because of the age of the format some items are unclear in meaning.
/// </summary>
/// <remarks>http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm</remarks>
[StructLayout(LayoutKind.Sequential)]
internal class NewExecutableHeader
{
/// <summary>
/// "NE" [00]
/// Signature word. [00]
/// "N" is low-order byte.
/// "E" is high-order byte.
/// </summary>
public ushort Magic;
/// <summary>
/// The major linker version [02]
/// Version number of the linker. [02]
/// </summary>
public byte LinkerVersion;
/// <summary>
/// The minor linker version [03]
/// Revision number of the linker. [03]
/// </summary>
public byte LinkerRevision;
/// <summary>
/// Offset of Entry Table [04]
/// Entry Table file offset, relative to the beginning of the segmented EXE header. [04]
/// </summary>
public ushort EntryTableOffset;
/// <summary>
/// Length of entry table in bytes [06]
/// Number of bytes in the entry table. [06]
/// </summary>
public ushort EntryTableSize;
/// <summary>
/// 32-bit CRC of entire contents of file [08]
/// 32-bit CRC of entire contents of file. [08]
/// These words are taken as 00 during the calculation.
/// </summary>
public uint CrcChecksum;

View File

@@ -1,43 +0,0 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class NAMEINFO
{
public ushort Offset;
public ushort Length;
public ushort Flags;
public ushort ID;
public ushort Handle;
public ushort Usage;
public static NAMEINFO Deserialize(Stream stream)
{
var ni = new NAMEINFO();
ni.Offset = stream.ReadUInt16();
ni.Length = stream.ReadUInt16();
ni.Flags = stream.ReadUInt16();
ni.ID = stream.ReadUInt16();
ni.Handle = stream.ReadUInt16();
ni.Usage = stream.ReadUInt16();
return ni;
}
}
}

View File

@@ -30,6 +30,9 @@ namespace BurnOutSharp.ExecutableType.Microsoft
#endregion
// TODO: Add more and more parts of a standard NE executable, not just the header
// TODO: Tables? What about the tables?
// TODO: Implement the rest of the structures found at http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm
// (Left off at RESIDENT-NAME TABLE)
public static NewExecutable Deserialize(Stream stream)
{

View File

@@ -1,41 +0,0 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// Resource table
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class NewRsrc
{
/// <summary>
/// Alignment shift count for resources
/// </summary>
public ushort AlignmentShiftCount;
public RsrcTypeInfo TypeInfo;
public static NewRsrc Deserialize(Stream stream)
{
var nr = new NewRsrc();
nr.AlignmentShiftCount = stream.ReadUInt16();
nr.TypeInfo = RsrcTypeInfo.Deserialize(stream);
return nr;
}
}
}

View File

@@ -1,57 +0,0 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// New .EXE segment table entry
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class NewSeg
{
/// <summary>
/// File sector of start of segment
/// </summary>
public ushort StartFileSector;
/// <summary>
/// Number of bytes in file
/// </summary>
public ushort BytesInFile;
/// <summary>
/// Attribute flags
/// </summary>
public ushort Flags;
/// <summary>
/// Minimum allocation in bytes
/// </summary>
public ushort MinimumAllocation;
public static NewSeg Deserialize(Stream stream)
{
var ns = new NewSeg();
ns.StartFileSector = stream.ReadUInt16();
ns.BytesInFile = stream.ReadUInt16();
ns.Flags = stream.ReadUInt16();
ns.MinimumAllocation = stream.ReadUInt16();
return ns;
}
}
}

View File

@@ -1,42 +0,0 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class ResourceTable
{
public ushort rscAlignShift;
public TYPEINFO TypeInfo;
public ushort rscEndTypes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0)]
public sbyte[][] rscResourceNames;
public byte rscEndNames;
public static ResourceTable Deserialize(Stream stream)
{
var rt = new ResourceTable();
rt.rscAlignShift = stream.ReadUInt16();
rt.TypeInfo = TYPEINFO.Deserialize(stream);
rt.rscEndTypes = stream.ReadUInt16();
rt.rscResourceNames = null; // TODO: Figure out size
rt.rscEndNames = stream.ReadByteValue();
return rt;
}
}
}

View File

@@ -1,40 +0,0 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// Resource type information block
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class RsrcTypeInfo
{
public ushort ID;
public ushort rt_nres;
public uint rt_proc;
public static RsrcTypeInfo Deserialize(Stream stream)
{
var rti = new RsrcTypeInfo();
rti.ID = stream.ReadUInt16();
rti.rt_nres = stream.ReadUInt16();
rti.rt_proc = stream.ReadUInt32();
return rti;
}
}
}

View File

@@ -1,39 +0,0 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class TYPEINFO
{
public ushort TypeID;
public ushort ResourceCount;
public uint Reserved;
public NAMEINFO NameInfo;
public static TYPEINFO Deserialize(Stream stream)
{
var ti = new TYPEINFO();
ti.TypeID = stream.ReadUInt16();
ti.ResourceCount = stream.ReadUInt16();
ti.Reserved = stream.ReadUInt32();
ti.NameInfo = NAMEINFO.Deserialize(stream);
return ti;
}
}
}

View File

@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.ExecutableType.Microsoft.Entries;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
{
/// <summary>
/// The resource table follows the segment table and contains entries for
/// each resource in the executable file. The resource table consists of
/// an alignment shift count, followed by a table of resource records. The
/// resource records define the type ID for a set of resources. Each
/// resource record contains a table of resource entries of the defined
/// type. The resource entry defines the resource ID or name ID for the
/// resource. It also defines the location and size of the resource.
/// </summary>
/// <remarks>http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm</remarks>
[StructLayout(LayoutKind.Sequential)]
internal class NEResourceTable
{
/// <summary>
/// Alignment shift count for resource data.
/// </summary>
public ushort AlignmentShiftCount;
/// <summary>
/// A table of resource type information blocks.
/// </summary>
public ResourceTypeInformationBlock[] TypeInformationBlocks;
/// <summary>
/// Resource type and name strings are stored at the end of the
/// resource table. Note that these strings are NOT null terminated and
/// are case sensitive.
/// </summary>
public NEResourceNameString[] TypeAndNameStrings;
public static NEResourceTable Deserialize(Stream stream)
{
var nrt = new NEResourceTable();
nrt.AlignmentShiftCount = stream.ReadUInt16();
var typeInformationBlocks = new List<ResourceTypeInformationBlock>();
while (true)
{
var block = ResourceTypeInformationBlock.Deserialize(stream);
if (block.TypeID == 0)
break;
typeInformationBlocks.Add(block);
}
nrt.TypeInformationBlocks = typeInformationBlocks.ToArray();
var typeAndNameStrings = new List<NEResourceNameString>();
while (true)
{
var str = NEResourceNameString.Deserialize(stream);
if (str.Length == 0)
break;
typeAndNameStrings.Add(str);
}
nrt.TypeAndNameStrings = typeAndNameStrings.ToArray();
return nrt;
}
public static NEResourceTable Deserialize(byte[] contents, int offset)
{
var nrt = new NEResourceTable();
nrt.AlignmentShiftCount = BitConverter.ToUInt16(contents, offset); offset += 2;
var typeInformationBlocks = new List<ResourceTypeInformationBlock>();
while (true)
{
unsafe
{
var block = ResourceTypeInformationBlock.Deserialize(contents, offset); offset += Marshal.SizeOf(block);
if (block.TypeID == 0)
break;
typeInformationBlocks.Add(block);
}
}
nrt.TypeInformationBlocks = typeInformationBlocks.ToArray();
var typeAndNameStrings = new List<NEResourceNameString>();
while (true)
{
unsafe
{
var str = NEResourceNameString.Deserialize(contents, offset); offset += Marshal.SizeOf(str);
if (str.Length == 0)
break;
typeAndNameStrings.Add(str);
}
}
nrt.TypeAndNameStrings = typeAndNameStrings.ToArray();
return nrt;
}
}
}