Formalize New Executable classes; renames

This commit is contained in:
Matt Nadareski
2021-08-27 22:34:57 -07:00
parent d2606e21fe
commit e6b2be1738
5 changed files with 368 additions and 114 deletions

View File

@@ -3,10 +3,10 @@ using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
{
[StructLayout(LayoutKind.Sequential)]
internal class IMAGE_DATA_DIRECTORY
internal class DataDirectoryHeader
{
/// <summary>
/// The first field, VirtualAddress, is actually the RVA of the table.
@@ -19,24 +19,24 @@ namespace BurnOutSharp.ExecutableType.Microsoft
/// </summary>
public uint Size;
public static IMAGE_DATA_DIRECTORY Deserialize(Stream stream)
public static DataDirectoryHeader Deserialize(Stream stream)
{
var idd = new IMAGE_DATA_DIRECTORY();
var ddh = new DataDirectoryHeader();
idd.VirtualAddress = stream.ReadUInt32();
idd.Size = stream.ReadUInt32();
ddh.VirtualAddress = stream.ReadUInt32();
ddh.Size = stream.ReadUInt32();
return idd;
return ddh;
}
public static IMAGE_DATA_DIRECTORY Deserialize(byte[] content, int offset)
public static DataDirectoryHeader Deserialize(byte[] content, int offset)
{
var idd = new IMAGE_DATA_DIRECTORY();
var ddh = new DataDirectoryHeader();
idd.VirtualAddress = BitConverter.ToUInt32(content, offset); offset += 4;
idd.Size = BitConverter.ToUInt32(content, offset); offset += 4;
ddh.VirtualAddress = BitConverter.ToUInt32(content, offset); offset += 4;
ddh.Size = BitConverter.ToUInt32(content, offset); offset += 4;
return idd;
return ddh;
}
}
}

View File

@@ -0,0 +1,255 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
{
/// <summary>
/// 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>
[StructLayout(LayoutKind.Sequential)]
internal class NewExecutableHeader
{
/// <summary>
/// "NE" [00]
/// </summary>
public ushort Magic;
/// <summary>
/// The major linker version [02]
/// </summary>
public byte LinkerVersion;
/// <summary>
/// The minor linker version [03]
/// </summary>
public byte LinkerRevision;
/// <summary>
/// Offset of Entry Table [04]
/// </summary>
public ushort EntryTableOffset;
/// <summary>
/// Length of entry table in bytes [06]
/// </summary>
public ushort EntryTableSize;
/// <summary>
/// 32-bit CRC of entire contents of file [08]
/// </summary>
public uint CrcChecksum;
/// <summary>
/// Program flags, bitmapped [0C]
/// </summary>
public byte ProgramFlags;
/// <summary>
/// Application flags, bitmapped [0D]
/// </summary>
public byte ApplicationFlags;
/// <summary>
/// Automatic data segment number [0E]
/// </summary>
public ushort Autodata;
/// <summary>
/// Initial heap allocation [10]
/// </summary>
public ushort InitialHeapAlloc;
/// <summary>
/// Initial stack allocation [12]
/// </summary>
public ushort InitialStackAlloc;
/// <summary>
/// CS:IP entry point, CS is index into segment table [14]
/// </summary>
public uint InitialCSIPSetting;
/// <summary>
/// SS:SP inital stack pointer, SS is index into segment table [18]
/// </summary>
public uint InitialSSSPSetting;
/// <summary>
/// Number of segments in segment table [1C]
/// </summary>
public ushort FileSegmentCount;
/// <summary>
/// Entries in Module Reference Table [1E]
/// </summary>
public ushort ModuleReferenceTableSize;
/// <summary>
/// Size of non-resident name table [20]
/// </summary>
public ushort NonResidentNameTableSize;
/// <summary>
/// Offset of Segment Table [22]
/// </summary>
public ushort SegmentTableOffset;
/// <summary>
/// Offset of Resource Table [24]
/// </summary>
public ushort ResourceTableOffset;
/// <summary>
/// Offset of resident name table [26]
/// </summary>
public ushort ResidentNameTableOffset;
/// <summary>
/// Offset of Module Reference Table [28]
/// </summary>
public ushort ModuleReferenceTableOffset;
/// <summary>
/// Offset of Imported Names Table [2A]
/// </summary>
public ushort ImportedNamesTableOffset;
/// <summary>
/// Offset of Non-resident Names Table [2C]
/// </summary>
public uint NonResidentNamesTableOffset;
/// <summary>
/// Count of moveable entry points listed in entry table [30]
/// </summary>
public ushort MovableEntriesCount;
/// <summary>
/// File allignment size shift count (0-9 (default 512 byte pages)) [32]
/// </summary>
public ushort SegmentAlignmentShiftCount;
/// <summary>
/// Count of resource table entries [34]
/// </summary>
public ushort ResourceEntriesCount;
/// <summary>
/// Target operating system [36]
/// </summary>
public byte TargetOperatingSystem;
/// <summary>
/// Other OS/2 flags [37]
/// </summary>
public byte AdditionalFlags;
/// <summary>
/// Offset to return thunks or start of gangload area [38]
/// </summary>
public ushort ReturnThunkOffset;
/// <summary>
/// Offset to segment reference thunks or size of gangload area [3A]
/// </summary>
public ushort SegmentReferenceThunkOffset;
/// <summary>
/// Minimum code swap area size [3C]
/// </summary>
public ushort MinCodeSwapAreaSize;
/// <summary>
/// Windows SDK revison number [3E]
/// </summary>
public byte WindowsSDKRevision;
/// <summary>
/// Windows SDK version number [3F]
/// </summary>
public byte WindowsSDKVersion;
public static NewExecutableHeader Deserialize(Stream stream)
{
var neh = new NewExecutableHeader();
neh.Magic = stream.ReadUInt16();
neh.LinkerVersion = stream.ReadByteValue();
neh.LinkerRevision = stream.ReadByteValue();
neh.EntryTableOffset = stream.ReadUInt16();
neh.EntryTableSize = stream.ReadUInt16();
neh.CrcChecksum = stream.ReadUInt32();
neh.ProgramFlags = stream.ReadByteValue();
neh.ApplicationFlags = stream.ReadByteValue();
neh.Autodata = stream.ReadUInt16();
neh.InitialHeapAlloc = stream.ReadUInt16();
neh.InitialStackAlloc = stream.ReadUInt16();
neh.InitialCSIPSetting = stream.ReadUInt32();
neh.InitialSSSPSetting = stream.ReadUInt32();
neh.FileSegmentCount = stream.ReadUInt16();
neh.ModuleReferenceTableSize = stream.ReadUInt16();
neh.NonResidentNameTableSize = stream.ReadUInt16();
neh.SegmentTableOffset = stream.ReadUInt16();
neh.ResourceTableOffset = stream.ReadUInt16();
neh.ResidentNameTableOffset = stream.ReadUInt16();
neh.ModuleReferenceTableOffset = stream.ReadUInt16();
neh.ImportedNamesTableOffset = stream.ReadUInt16();
neh.NonResidentNamesTableOffset = stream.ReadUInt32();
neh.MovableEntriesCount = stream.ReadUInt16();
neh.SegmentAlignmentShiftCount = stream.ReadUInt16();
neh.ResourceEntriesCount = stream.ReadUInt16();
neh.TargetOperatingSystem = stream.ReadByteValue();
neh.AdditionalFlags = stream.ReadByteValue();
neh.ReturnThunkOffset = stream.ReadUInt16();
neh.SegmentReferenceThunkOffset = stream.ReadUInt16();
neh.MinCodeSwapAreaSize = stream.ReadUInt16();
neh.WindowsSDKRevision = stream.ReadByteValue();
neh.WindowsSDKVersion = stream.ReadByteValue();
return neh;
}
public static NewExecutableHeader Deserialize(byte[] contents, int offset)
{
var neh = new NewExecutableHeader();
neh.Magic = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.LinkerVersion = contents[offset++];
neh.LinkerRevision = contents[offset++];
neh.EntryTableOffset = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.EntryTableSize = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.CrcChecksum = BitConverter.ToUInt32(contents, offset); offset += 4;
neh.ProgramFlags = contents[offset++];
neh.ApplicationFlags = contents[offset++];
neh.Autodata = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.InitialHeapAlloc = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.InitialStackAlloc = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.InitialCSIPSetting = BitConverter.ToUInt32(contents, offset); offset += 4;
neh.InitialSSSPSetting = BitConverter.ToUInt32(contents, offset); offset += 4;
neh.FileSegmentCount = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.ModuleReferenceTableSize = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.NonResidentNameTableSize = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.SegmentTableOffset = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.ResourceTableOffset = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.ResidentNameTableOffset = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.ModuleReferenceTableOffset = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.ImportedNamesTableOffset = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.NonResidentNamesTableOffset = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.MovableEntriesCount = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.SegmentAlignmentShiftCount = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.ResourceEntriesCount = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.TargetOperatingSystem = contents[offset++];
neh.AdditionalFlags = contents[offset++];
neh.ReturnThunkOffset = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.SegmentReferenceThunkOffset = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.MinCodeSwapAreaSize = BitConverter.ToUInt16(contents, offset); offset += 2;
neh.WindowsSDKRevision = contents[offset++];
neh.WindowsSDKVersion = contents[offset++];
return neh;
}
}
}

View File

@@ -232,7 +232,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
/// Data-directory entries following the optional header
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES)]
public IMAGE_DATA_DIRECTORY[] DataDirectories;
public DataDirectoryHeader[] DataDirectories;
#endregion
@@ -292,10 +292,10 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
ioh.LoaderFlags = stream.ReadUInt32();
ioh.NumberOfRvaAndSizes = stream.ReadUInt32();
ioh.DataDirectories = new IMAGE_DATA_DIRECTORY[Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
ioh.DataDirectories = new DataDirectoryHeader[Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
for (int i = 0; i < Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
{
ioh.DataDirectories[i] = IMAGE_DATA_DIRECTORY.Deserialize(stream);
ioh.DataDirectories[i] = DataDirectoryHeader.Deserialize(stream);
}
return ioh;
@@ -361,10 +361,10 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
ioh.LoaderFlags = BitConverter.ToUInt32(content, offset); offset += 4;
ioh.NumberOfRvaAndSizes = BitConverter.ToUInt32(content, offset); offset += 4;
ioh.DataDirectories = new IMAGE_DATA_DIRECTORY[Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
ioh.DataDirectories = new DataDirectoryHeader[Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
for (int i = 0; i < Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
{
ioh.DataDirectories[i] = IMAGE_DATA_DIRECTORY.Deserialize(content, offset); offset += 8;
ioh.DataDirectories[i] = DataDirectoryHeader.Deserialize(content, offset); offset += 8;
}
return ioh;

View File

@@ -1,97 +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 header
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class IMAGE_OS2_HEADER
{
public ushort Magic; // 00 Magic number NE_MAGIC
public byte LinkerVersion; // 02 Linker Version number
public byte LinkerRevision; // 03 Linker Revision number
public ushort EntryTableOffset; // 04 Offset of Entry Table
public ushort EntryTableSize; // 06 Number of bytes in Entry Table
public uint CrcChecksum; // 08 Checksum of whole file
public ushort Flags; // 0C Flag word
public ushort Autodata; // 0E Automatic data segment number
public ushort InitialHeapAlloc; // 10 Initial heap allocation
public ushort InitialStackAlloc; // 12 Initial stack allocation
public uint InitialCSIPSetting; // 14 Initial CS:IP setting
public uint InitialSSSPSetting; // 18 Initial SS:SP setting
public ushort FileSegmentCount; // 1C Count of file segments
public ushort ModuleReferenceTableSize; // 1E Entries in Module Reference Table
public ushort NonResidentNameTableSize; // 20 Size of non-resident name table
public ushort SegmentTableOffset; // 22 Offset of Segment Table
public ushort ResourceTableOffset; // 24 Offset of Resource Table
public ushort ResidentNameTableOffset; // 26 Offset of resident name table
public ushort ModuleReferenceTableOffset; // 28 Offset of Module Reference Table
public ushort ImportedNamesTableOffset; // 2A Offset of Imported Names Table
public uint NonResidentNamesTableOffset; // 2C Offset of Non-resident Names Table
public ushort MovableEntriesCount; // 30 Count of movable entries
public ushort SegmentAlignmentShiftCount; // 32 Segment alignment shift count
public ushort ResourceEntriesCount; // 34 Count of resource entries
public byte TargetOperatingSystem; // 36 Target operating system
public byte AdditionalFlags; // 37 Additional flags
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.NERESWORDS)]
public ushort[] Reserved; // 38 3 reserved words
public byte WindowsSDKRevision; // 3E Windows SDK revison number
public byte WindowsSDKVersion; // 3F Windows SDK version number
public static IMAGE_OS2_HEADER Deserialize(Stream stream)
{
var ioh = new IMAGE_OS2_HEADER();
ioh.Magic = stream.ReadUInt16();
ioh.LinkerVersion = stream.ReadByteValue();
ioh.LinkerRevision = stream.ReadByteValue();
ioh.EntryTableOffset = stream.ReadUInt16();
ioh.EntryTableSize = stream.ReadUInt16();
ioh.CrcChecksum = stream.ReadUInt32();
ioh.Flags = stream.ReadUInt16();
ioh.Autodata = stream.ReadUInt16();
ioh.InitialHeapAlloc = stream.ReadUInt16();
ioh.InitialStackAlloc = stream.ReadUInt16();
ioh.InitialCSIPSetting = stream.ReadUInt32();
ioh.InitialSSSPSetting = stream.ReadUInt32();
ioh.FileSegmentCount = stream.ReadUInt16();
ioh.ModuleReferenceTableSize = stream.ReadUInt16();
ioh.NonResidentNameTableSize = stream.ReadUInt16();
ioh.SegmentTableOffset = stream.ReadUInt16();
ioh.ResourceTableOffset = stream.ReadUInt16();
ioh.ResidentNameTableOffset = stream.ReadUInt16();
ioh.ModuleReferenceTableOffset = stream.ReadUInt16();
ioh.ImportedNamesTableOffset = stream.ReadUInt16();
ioh.NonResidentNamesTableOffset = stream.ReadUInt32();
ioh.MovableEntriesCount = stream.ReadUInt16();
ioh.SegmentAlignmentShiftCount = stream.ReadUInt16();
ioh.ResourceEntriesCount = stream.ReadUInt16();
ioh.TargetOperatingSystem = stream.ReadByteValue();
ioh.AdditionalFlags = stream.ReadByteValue();
ioh.Reserved = new ushort[Constants.NERESWORDS];
for (int i = 0; i < Constants.NERESWORDS; i++)
{
ioh.Reserved[i] = stream.ReadUInt16();
}
ioh.WindowsSDKRevision = stream.ReadByteValue();
ioh.WindowsSDKVersion = stream.ReadByteValue();
return ioh;
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.ExecutableType.Microsoft.Headers;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// The WIN-NE executable format, designed for Windows 3.x, was the "NE", or "New Executable" format.
/// Again, a 16bit format, it alleviated the maximum size restrictions that the MZ format had.
/// </summary>
internal class NewExecutable
{
#region Headers
/// <summary>
/// he DOS stub is a valid MZ exe.
/// This enables the develper to package both an MS-DOS and Win16 version of the program,
/// but normally just prints "This Program requires Microsoft Windows".
/// The e_lfanew field (offset 0x3C) points to the NE header.
// </summary>
public MSDOSExecutableHeader DOSStubHeader;
/// <summary>
/// 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>
public NewExecutableHeader NewExecutableHeader;
#endregion
// TODO: Add more and more parts of a standard NE executable, not just the header
public static NewExecutable Deserialize(Stream stream)
{
NewExecutable nex = new NewExecutable();
try
{
// Attempt to read the DOS header first
nex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream); stream.Seek(nex.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
if (nex.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
return null;
// If the new header address is invalid for the file, it's not a NE
if (nex.DOSStubHeader.NewExeHeaderAddr >= stream.Length)
return null;
// Then attempt to read the NE header
nex.NewExecutableHeader = NewExecutableHeader.Deserialize(stream);
if (nex.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
return null;
}
catch (Exception ex)
{
//Console.WriteLine($"Errored out on a file: {ex}");
return null;
}
return nex;
}
public static NewExecutable Deserialize(byte[] content, int offset)
{
NewExecutable nex = new NewExecutable();
try
{
unsafe
{
// Attempt to read the DOS header first
nex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, offset); offset = nex.DOSStubHeader.NewExeHeaderAddr;
if (nex.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
return null;
// If the new header address is invalid for the file, it's not a PE
if (nex.DOSStubHeader.NewExeHeaderAddr >= content.Length)
return null;
// Then attempt to read the NE header
nex.NewExecutableHeader = NewExecutableHeader.Deserialize(content, offset); offset += Marshal.SizeOf(nex.NewExecutableHeader);
if (nex.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
return null;
}
}
catch (Exception ex)
{
//Console.WriteLine($"Errored out on a file: {ex}");
return null;
}
return nex;
}
}
}