Continue exe organization, start IIF migration

This commit is contained in:
Matt Nadareski
2021-08-27 09:42:05 -07:00
parent 4b5d0980f7
commit 2de4f3f808
33 changed files with 738 additions and 378 deletions

View File

@@ -2,7 +2,7 @@ using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
/// <summary>
/// Each entry in the export address table is a field that uses one of two formats in the following table.

View File

@@ -1,4 +1,4 @@
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
/// <summary>
/// Each entry in the export address table is a field that uses one of two formats in the following table.

View File

@@ -1,9 +1,8 @@
using System;
using System.IO;
using System.Linq;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
/// <summary>
/// Each entry in the hint/name table has the following format

View File

@@ -2,7 +2,7 @@ using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
/// <summary>
/// Each import address entry has the following format

View File

@@ -2,7 +2,7 @@ using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
/// <summary>
/// Each import directory entry has the following format

View File

@@ -0,0 +1,36 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
/// <summary>
/// The resource directory string area consists of Unicode strings, which are word-aligned.
/// These strings are stored together after the last Resource Directory entry and before the first Resource Data entry.
/// This minimizes the impact of these variable-length strings on the alignment of the fixed-size directory entries.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class ResourceDirectoryString
{
/// <summary>
/// The size of the string, not including length field itself.
/// </summary>
public ushort Length;
/// <summary>
/// The variable-length Unicode string data, word-aligned.
/// </summary>
public char[] UnicodeString;
public static ResourceDirectoryString Deserialize(Stream stream)
{
var rds = new ResourceDirectoryString();
rds.Length = stream.ReadUInt16();
rds.UnicodeString = stream.ReadChars(rds.Length, Encoding.Unicode);
return rds;
}
}
}

View File

@@ -0,0 +1,70 @@
using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
/// <summary>
/// The directory entries make up the rows of a table.
/// Each resource directory entry has the following format.
/// Whether the entry is a Name or ID entry is indicated by the
/// resource directory table, which indicates how many Name and
/// ID entries follow it (remember that all the Name entries
/// precede all the ID entries for the table). All entries for
/// the table are sorted in ascending order: the Name entries
/// by case-sensitive string and the ID entries by numeric value.
/// Offsets are relative to the address in the IMAGE_DIRECTORY_ENTRY_RESOURCE DataDirectory.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#resource-directory-entries</remarks>
internal class ResourceDirectoryTableEntry
{
#region Name Entry
/// <summary>
/// The offset of a string that gives the Type, Name, or Language ID entry, depending on level of table.
/// </summary>
public uint NameOffset;
/// <summary>
/// A 32-bit integer that identifies the Type, Name, or Language ID entry.
/// </summary>
public uint IntegerId => NameOffset;
/// <summary>
/// High bit 0. Address of a Resource Data entry (a leaf).
/// </summary>
public uint DataEntryOffset;
/// <summary>
/// High bit 1. The lower 31 bits are the address of another resource directory table (the next level down).
/// </summary>
public uint SubdirectoryOffset => DataEntryOffset;
#endregion
/// <summary>
/// Determine if an entry represents a leaf or another directory table
/// </summary>
public bool IsResourceDataEntry() => (DataEntryOffset & (1 << 31)) == 0;
public static ResourceDirectoryTableEntry Deserialize(Stream stream)
{
var idte = new ResourceDirectoryTableEntry();
idte.NameOffset = stream.ReadUInt32();
idte.DataEntryOffset = stream.ReadUInt32();
return idte;
}
public static ResourceDirectoryTableEntry Deserialize(byte[] content, int offset)
{
var idte = new ResourceDirectoryTableEntry();
idte.NameOffset = BitConverter.ToUInt32(content, offset); offset += 4;
idte.DataEntryOffset = BitConverter.ToUInt32(content, offset); offset += 4;
return idte;
}
}
}

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_FILE_HEADER
internal class CommonObjectFileFormatHeader
{
/// <summary>
/// After the MS-DOS stub, at the file offset specified at offset 0x3c, is a 4-byte signature that identifies the file as a PE format image file.
@@ -55,9 +55,9 @@ namespace BurnOutSharp.ExecutableType.Microsoft
/// </summary>
public ImageObjectCharacteristics Characteristics;
public static IMAGE_FILE_HEADER Deserialize(Stream stream)
public static CommonObjectFileFormatHeader Deserialize(Stream stream)
{
var ifh = new IMAGE_FILE_HEADER();
var ifh = new CommonObjectFileFormatHeader();
ifh.Signature = stream.ReadUInt32();
ifh.Machine = (MachineType)stream.ReadUInt16();
@@ -71,9 +71,9 @@ namespace BurnOutSharp.ExecutableType.Microsoft
return ifh;
}
public static IMAGE_FILE_HEADER Deserialize(byte[] content, int offset)
public static CommonObjectFileFormatHeader Deserialize(byte[] content, int offset)
{
var ifh = new IMAGE_FILE_HEADER();
var ifh = new CommonObjectFileFormatHeader();
ifh.Signature = BitConverter.ToUInt32(content, offset); offset += 4;
ifh.Machine = (MachineType)BitConverter.ToUInt16(content, offset); offset += 2;

View File

@@ -0,0 +1,211 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
{
/// <summary>
/// The MS-DOS EXE format, also known as MZ after its signature (the initials of Microsoft engineer Mark Zbykowski),
/// was introduced with MS-DOS 2.0 (version 1.0 only sported the simple COM format). It is designed as a relocatable
/// executable running under real mode. As such, only DOS and Windows 9x can use this format natively, but there are
/// several free DOS emulators (e.g., DOSBox) that support it and that run under various operating systems (e.g.,
/// Linux, Amiga, Windows NT, etc.). Although they can exist on their own, MZ executables are embedded in all NE, LE,
/// and PE executables, usually as stubs so that when they are ran under DOS, they display a warning.
/// </summary>
/// <remarks>https://wiki.osdev.org/MZ</remarks>
[StructLayout(LayoutKind.Sequential)]
internal class MSDOSExecutableHeader
{
#region Standard Fields
/// <summary>
/// 0x5A4D (ASCII for 'M' and 'Z') [00]
/// </summary>
public ushort Magic;
/// <summary>
/// Number of bytes in the last page. [02]
/// </summary>
public ushort LastPageBytes;
/// <summary>
/// Number of whole/partial pages. [04]
/// </summary>
public ushort Pages;
/// <summary>
/// Number of entries in the relocation table. [06]
/// </summary>
public ushort Relocations;
/// <summary>
/// The number of paragraphs taken up by the header.It can be any value, as the loader
/// just uses it to find where the actual executable data starts. It may be larger than
/// what the "standard" fields take up, and you may use it if you want to include your
/// own header metadata, or put the relocation table there, or use it for any other purpose. [08]
/// </summary>
public ushort HeaderParagraphSize;
/// <summary>
/// The number of paragraphs required by the program, excluding the PSP and program image.
/// If no free block is big enough, the loading stops. [0A]
/// </summary>
public ushort MinimumExtraParagraphs;
/// <summary>
/// The number of paragraphs requested by the program.
/// If no free block is big enough, the biggest one possible is allocated. [0C]
/// </summary>
public ushort MaximumExtraParagraphs;
/// <summary>
/// Relocatable segment address for SS. [0E]
/// </summary>
public ushort InitialSSValue;
/// <summary>
/// Initial value for SP. [10]
/// </summary>
public ushort InitialSPValue;
/// <summary>
/// When added to the sum of all other words in the file, the result should be zero. [12]
/// </summary>
public ushort Checksum;
/// <summary>
/// Initial value for IP. [14]
/// </summary>
public ushort InitialIPValue;
/// <summary>
/// Relocatable segment address for CS. [16]
/// </summary>
public ushort InitialCSValue;
/// <summary>
/// The (absolute) offset to the relocation table. [18]
/// </summary>
public ushort RelocationTableAddr;
/// <summary>
/// Value used for overlay management.
/// If zero, this is the main executable. [1A]
/// </summary>
public ushort OverlayNumber;
#endregion
#region PE Extensions
/// <summary>
/// Reserved words [1C]
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.ERES1WDS)]
public ushort[] Reserved1;
/// <summary>
/// Defined by name but no other information is given; typically zeroes [24]
/// </summary>
public ushort OEMIdentifier;
/// <summary>
/// Defined by name but no other information is given; typically zeroes [26]
/// </summary>
public ushort OEMInformation;
/// <summary>
/// Reserved words [28]
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.ERES2WDS)]
public ushort[] Reserved2;
/// <summary>
/// Starting address of the PE header [3C]
/// </summary>
public int NewExeHeaderAddr;
#endregion
public static MSDOSExecutableHeader Deserialize(Stream stream, bool asStub = true)
{
MSDOSExecutableHeader idh = new MSDOSExecutableHeader();
idh.Magic = stream.ReadUInt16();
idh.LastPageBytes = stream.ReadUInt16();
idh.Pages = stream.ReadUInt16();
idh.Relocations = stream.ReadUInt16();
idh.HeaderParagraphSize = stream.ReadUInt16();
idh.MinimumExtraParagraphs = stream.ReadUInt16();
idh.MaximumExtraParagraphs = stream.ReadUInt16();
idh.InitialSSValue = stream.ReadUInt16();
idh.InitialSPValue = stream.ReadUInt16();
idh.Checksum = stream.ReadUInt16();
idh.InitialIPValue = stream.ReadUInt16();
idh.InitialCSValue = stream.ReadUInt16();
idh.RelocationTableAddr = stream.ReadUInt16();
idh.OverlayNumber = stream.ReadUInt16();
// If we're not reading as a stub, return now
if (!asStub)
return idh;
idh.Reserved1 = new ushort[Constants.ERES1WDS];
for (int i = 0; i < Constants.ERES1WDS; i++)
{
idh.Reserved1[i] = stream.ReadUInt16();
}
idh.OEMIdentifier = stream.ReadUInt16();
idh.OEMInformation = stream.ReadUInt16();
idh.Reserved2 = new ushort[Constants.ERES2WDS];
for (int i = 0; i < Constants.ERES2WDS; i++)
{
idh.Reserved2[i] = stream.ReadUInt16();
}
idh.NewExeHeaderAddr = stream.ReadInt32();
return idh;
}
public static MSDOSExecutableHeader Deserialize(byte[] content, int offset, bool asStub = true)
{
MSDOSExecutableHeader idh = new MSDOSExecutableHeader();
idh.Magic = BitConverter.ToUInt16(content, offset); offset += 2;
idh.LastPageBytes = BitConverter.ToUInt16(content, offset); offset += 2;
idh.Pages = BitConverter.ToUInt16(content, offset); offset += 2;
idh.Relocations = BitConverter.ToUInt16(content, offset); offset += 2;
idh.HeaderParagraphSize = BitConverter.ToUInt16(content, offset); offset += 2;
idh.MinimumExtraParagraphs = BitConverter.ToUInt16(content, offset); offset += 2;
idh.MaximumExtraParagraphs = BitConverter.ToUInt16(content, offset); offset += 2;
idh.InitialSSValue = BitConverter.ToUInt16(content, offset); offset += 2;
idh.InitialSPValue = BitConverter.ToUInt16(content, offset); offset += 2;
idh.Checksum = BitConverter.ToUInt16(content, offset); offset += 2;
idh.InitialIPValue = BitConverter.ToUInt16(content, offset); offset += 2;
idh.InitialCSValue = BitConverter.ToUInt16(content, offset); offset += 2;
idh.RelocationTableAddr = BitConverter.ToUInt16(content, offset); offset += 2;
idh.OverlayNumber = BitConverter.ToUInt16(content, offset); offset += 2;
// If we're not reading as a stub, return now
if (!asStub)
return idh;
idh.Reserved1 = new ushort[Constants.ERES1WDS];
for (int i = 0; i < Constants.ERES1WDS; i++)
{
idh.Reserved1[i] = BitConverter.ToUInt16(content, offset); offset += 2;
}
idh.OEMIdentifier = BitConverter.ToUInt16(content, offset); offset += 2;
idh.OEMInformation = BitConverter.ToUInt16(content, offset); offset += 2;
idh.Reserved2 = new ushort[Constants.ERES2WDS];
for (int i = 0; i < Constants.ERES2WDS; i++)
{
idh.Reserved2[i] = BitConverter.ToUInt16(content, offset); offset += 2;
}
idh.NewExeHeaderAddr = BitConverter.ToInt32(content, offset); offset += 4;
return idh;
}
}
}

View File

@@ -3,10 +3,24 @@ using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
{
/// <summary>
/// Every image file has an optional header that provides information to the loader.
/// This header is optional in the sense that some files (specifically, object files) do not have it.
/// For image files, this header is required. An object file can have an optional header, but generally
/// this header has no function in an object file except to increase its size.
///
/// Note that the size of the optional header is not fixed.
/// The SizeOfOptionalHeader field in the COFF header must be used to validate that a probe into the file
/// for a particular data directory does not go beyond SizeOfOptionalHeader.
///
/// The NumberOfRvaAndSizes field of the optional header should also be used to ensure that no probe for
/// a particular data directory entry goes beyond the optional header.
/// In addition, it is important to validate the optional header magic number for format compatibility.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class IMAGE_OPTIONAL_HEADER
internal class OptionalHeader
{
#region Standard Fields
@@ -222,9 +236,9 @@ namespace BurnOutSharp.ExecutableType.Microsoft
#endregion
public static IMAGE_OPTIONAL_HEADER Deserialize(Stream stream)
public static OptionalHeader Deserialize(Stream stream)
{
var ioh = new IMAGE_OPTIONAL_HEADER();
var ioh = new OptionalHeader();
ioh.Magic = (OptionalHeaderType)stream.ReadUInt16();
ioh.MajorLinkerVersion = stream.ReadByteValue();
@@ -287,9 +301,9 @@ namespace BurnOutSharp.ExecutableType.Microsoft
return ioh;
}
public static IMAGE_OPTIONAL_HEADER Deserialize(byte[] content, int offset)
public static OptionalHeader Deserialize(byte[] content, int offset)
{
var ioh = new IMAGE_OPTIONAL_HEADER();
var ioh = new OptionalHeader();
ioh.Magic = (OptionalHeaderType)BitConverter.ToUInt16(content, offset); offset += 2;
ioh.MajorLinkerVersion = content[offset]; offset++;

View File

@@ -0,0 +1,132 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
{
/// <summary>
/// Each row of the section table is, in effect, a section header.
/// This table immediately follows the optional header, if any.
/// This positioning is required because the file header does not contain a direct pointer to the section table.
/// Instead, the location of the section table is determined by calculating the location of the first byte after the headers.
/// Make sure to use the size of the optional header as specified in the file header.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class SectionHeader
{
/// <summary>
/// An 8-byte, null-padded UTF-8 encoded string.
/// If the string is exactly 8 characters long, there is no terminating null.
/// For longer names, this field contains a slash (/) that is followed by an ASCII representation of a decimal number
/// that is an offset into the string table.
/// Executable images do not use a string table and do not support section names longer than 8 characters.
/// Long names in object files are truncated if they are emitted to an executable file.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.IMAGE_SIZEOF_SHORT_NAME)]
public byte[] Name;
/// <summary>
/// The total size of the section when loaded into memory.
/// If this value is greater than SizeOfRawData, the section is zero-padded.
/// This field is valid only for executable images and should be set to zero for object files.
/// </summary>
public uint VirtualSize;
/// <summary>
/// For executable images, the address of the first byte of the section relative to the image base when the section
/// is loaded into memory.
/// For object files, this field is the address of the first byte before relocation is applied; for simplicity,
/// compilers should set this to zero.
/// Otherwise, it is an arbitrary value that is subtracted from offsets during relocation.
/// </summary>
public uint VirtualAddress;
/// <summary>
/// The size of the section (for object files) or the size of the initialized data on disk (for image files).
/// For executable images, this must be a multiple of FileAlignment from the optional header.
/// If this is less than VirtualSize, the remainder of the section is zero-filled.
/// Because the SizeOfRawData field is rounded but the VirtualSize field is not, it is possible for SizeOfRawData
/// to be greater than VirtualSize as well.
/// When a section contains only uninitialized data, this field should be zero.
/// </summary>
public uint SizeOfRawData;
/// <summary>
/// The file pointer to the first page of the section within the COFF file.
/// For executable images, this must be a multiple of FileAlignment from the optional header.
/// For object files, the value should be aligned on a 4-byte boundary for best performance.
/// When a section contains only uninitialized data, this field should be zero.
/// </summary>
public uint PointerToRawData;
/// <summary>
/// The file pointer to the beginning of relocation entries for the section.
/// This is set to zero for executable images or if there are no relocations.
/// </summary>
public uint PointerToRelocations;
/// <summary>
/// The file pointer to the beginning of line-number entries for the section.
/// This is set to zero if there are no COFF line numbers.
/// This value should be zero for an image because COFF debugging information is deprecated.
/// </summary>
[Obsolete]
public uint PointerToLinenumbers;
/// <summary>
/// The number of relocation entries for the section.
/// This is set to zero for executable images.
/// </summary>
public ushort NumberOfRelocations;
/// <summary>
/// The number of line-number entries for the section.
/// This value should be zero for an image because COFF debugging information is deprecated.
/// </summary>
[Obsolete]
public ushort NumberOfLinenumbers;
/// <summary>
/// The flags that describe the characteristics of the section.
/// </summary>
public SectionCharacteristics Characteristics;
public static SectionHeader Deserialize(Stream stream)
{
var ish = new SectionHeader();
ish.Name = stream.ReadBytes(Constants.IMAGE_SIZEOF_SHORT_NAME);
ish.VirtualSize = stream.ReadUInt32();
ish.VirtualAddress = stream.ReadUInt32();
ish.SizeOfRawData = stream.ReadUInt32();
ish.PointerToRawData = stream.ReadUInt32();
ish.PointerToRelocations = stream.ReadUInt32();
ish.PointerToLinenumbers = stream.ReadUInt32();
ish.NumberOfRelocations = stream.ReadUInt16();
ish.NumberOfLinenumbers = stream.ReadUInt16();
ish.Characteristics = (SectionCharacteristics)stream.ReadUInt32();
return ish;
}
public static SectionHeader Deserialize(byte[] content, int offset)
{
var ish = new SectionHeader();
ish.Name = new byte[Constants.IMAGE_SIZEOF_SHORT_NAME];
Array.Copy(content, offset, ish.Name, 0, Constants.IMAGE_SIZEOF_SHORT_NAME); offset += Constants.IMAGE_SIZEOF_SHORT_NAME;
ish.VirtualSize = BitConverter.ToUInt32(content, offset); offset += 4;
ish.VirtualAddress = BitConverter.ToUInt32(content, offset); offset += 4;
ish.SizeOfRawData = BitConverter.ToUInt32(content, offset); offset += 4;
ish.PointerToRawData = BitConverter.ToUInt32(content, offset); offset += 4;
ish.PointerToRelocations = BitConverter.ToUInt32(content, offset); offset += 4;
ish.PointerToLinenumbers = BitConverter.ToUInt32(content, offset); offset += 4;
ish.NumberOfRelocations = BitConverter.ToUInt16(content, offset); offset += 2;
ish.NumberOfLinenumbers = BitConverter.ToUInt16(content, offset); offset += 2;
ish.Characteristics = (SectionCharacteristics)BitConverter.ToUInt32(content, offset); offset += 4;
return ish;
}
}
}

View File

@@ -1,118 +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;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// DOS 1, 2, 3 .EXE header
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class IMAGE_DOS_HEADER
{
public ushort Magic; // 00 Magic number
public ushort LastPageBytes; // 02 Bytes on last page of file
public ushort Pages; // 04 Pages in file
public ushort Relocations; // 06 Relocations
public ushort HeaderParagraphSize; // 08 Size of header in paragraphs
public ushort MinimumExtraParagraphs; // 0A Minimum extra paragraphs needed
public ushort MaximumExtraParagraphs; // 0C Maximum extra paragraphs needed
public ushort InitialSSValue; // 0E Initial (relative) SS value
public ushort InitialSPValue; // 10 Initial SP value
public ushort Checksum; // 12 Checksum
public ushort InitialIPValue; // 14 Initial IP value
public ushort InitialCSValue; // 16 Initial (relative) CS value
public ushort RelocationTableAddr; // 18 File address of relocation table
public ushort OverlayNumber; // 1A Overlay number
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.ERES1WDS)]
public ushort[] Reserved1; // 1C Reserved words
public ushort OEMIdentifier; // 24 OEM identifier (for e_oeminfo)
public ushort OEMInformation; // 26 OEM information; e_oemid specific
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.ERES2WDS)]
public ushort[] Reserved2; // 28 Reserved words
public int NewExeHeaderAddr; // 3C File address of new exe header
public static IMAGE_DOS_HEADER Deserialize(Stream stream)
{
IMAGE_DOS_HEADER idh = new IMAGE_DOS_HEADER();
idh.Magic = stream.ReadUInt16();
idh.LastPageBytes = stream.ReadUInt16();
idh.Pages = stream.ReadUInt16();
idh.Relocations = stream.ReadUInt16();
idh.HeaderParagraphSize = stream.ReadUInt16();
idh.MinimumExtraParagraphs = stream.ReadUInt16();
idh.MaximumExtraParagraphs = stream.ReadUInt16();
idh.InitialSSValue = stream.ReadUInt16();
idh.InitialSPValue = stream.ReadUInt16();
idh.Checksum = stream.ReadUInt16();
idh.InitialIPValue = stream.ReadUInt16();
idh.InitialCSValue = stream.ReadUInt16();
idh.RelocationTableAddr = stream.ReadUInt16();
idh.OverlayNumber = stream.ReadUInt16();
idh.Reserved1 = new ushort[Constants.ERES1WDS];
for (int i = 0; i < Constants.ERES1WDS; i++)
{
idh.Reserved1[i] = stream.ReadUInt16();
}
idh.OEMIdentifier = stream.ReadUInt16();
idh.OEMInformation = stream.ReadUInt16();
idh.Reserved2 = new ushort[Constants.ERES2WDS];
for (int i = 0; i < Constants.ERES2WDS; i++)
{
idh.Reserved2[i] = stream.ReadUInt16();
}
idh.NewExeHeaderAddr = stream.ReadInt32();
return idh;
}
public static IMAGE_DOS_HEADER Deserialize(byte[] content, int offset)
{
IMAGE_DOS_HEADER idh = new IMAGE_DOS_HEADER();
idh.Magic = BitConverter.ToUInt16(content, offset); offset += 2;
idh.LastPageBytes = BitConverter.ToUInt16(content, offset); offset += 2;
idh.Pages = BitConverter.ToUInt16(content, offset); offset += 2;
idh.Relocations = BitConverter.ToUInt16(content, offset); offset += 2;
idh.HeaderParagraphSize = BitConverter.ToUInt16(content, offset); offset += 2;
idh.MinimumExtraParagraphs = BitConverter.ToUInt16(content, offset); offset += 2;
idh.MaximumExtraParagraphs = BitConverter.ToUInt16(content, offset); offset += 2;
idh.InitialSSValue = BitConverter.ToUInt16(content, offset); offset += 2;
idh.InitialSPValue = BitConverter.ToUInt16(content, offset); offset += 2;
idh.Checksum = BitConverter.ToUInt16(content, offset); offset += 2;
idh.InitialIPValue = BitConverter.ToUInt16(content, offset); offset += 2;
idh.InitialCSValue = BitConverter.ToUInt16(content, offset); offset += 2;
idh.RelocationTableAddr = BitConverter.ToUInt16(content, offset); offset += 2;
idh.OverlayNumber = BitConverter.ToUInt16(content, offset); offset += 2;
idh.Reserved1 = new ushort[Constants.ERES1WDS];
for (int i = 0; i < Constants.ERES1WDS; i++)
{
idh.Reserved1[i] = BitConverter.ToUInt16(content, offset); offset += 2;
}
idh.OEMIdentifier = BitConverter.ToUInt16(content, offset); offset += 2;
idh.OEMInformation = BitConverter.ToUInt16(content, offset); offset += 2;
idh.Reserved2 = new ushort[Constants.ERES2WDS];
for (int i = 0; i < Constants.ERES2WDS; i++)
{
idh.Reserved2[i] = BitConverter.ToUInt16(content, offset); offset += 2;
}
idh.NewExeHeaderAddr = BitConverter.ToInt32(content, offset); offset += 4;
return idh;
}
}
}

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 IMAGE_RESOURCE_DIRECTORY
{
public uint Characteristics;
public uint TimeDateStamp;
public ushort MajorVersion;
public ushort MinorVersion;
public ushort NumberOfNamedEntries;
public ushort NumberOfIdEntries;
public static IMAGE_RESOURCE_DIRECTORY Deserialize(Stream stream)
{
var ird = new IMAGE_RESOURCE_DIRECTORY();
ird.Characteristics = stream.ReadUInt32();
ird.TimeDateStamp = stream.ReadUInt32();
ird.MajorVersion = stream.ReadUInt16();
ird.MinorVersion = stream.ReadUInt16();
ird.NumberOfNamedEntries = stream.ReadUInt16();
ird.NumberOfIdEntries = stream.ReadUInt16();
return ird;
}
}
}

View File

@@ -1,35 +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 IMAGE_RESOURCE_DIR_STRING_U
{
public ushort Length;
public char[] NameString;
public static IMAGE_RESOURCE_DIR_STRING_U Deserialize(Stream stream)
{
var irdsu = new IMAGE_RESOURCE_DIR_STRING_U();
irdsu.Length = stream.ReadUInt16();
irdsu.NameString = stream.ReadChars(irdsu.Length);
return irdsu;
}
}
}

View File

@@ -1,60 +0,0 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class IMAGE_SECTION_HEADER
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.IMAGE_SIZEOF_SHORT_NAME)]
public byte[] Name;
public uint VirtualSize;
public uint VirtualAddress;
public uint SizeOfRawData;
public uint PointerToRawData;
public uint PointerToRelocations;
public uint PointerToLinenumbers;
public ushort NumberOfRelocations;
public ushort NumberOfLinenumbers;
public SectionCharacteristics Characteristics;
public static IMAGE_SECTION_HEADER Deserialize(Stream stream)
{
var ish = new IMAGE_SECTION_HEADER();
ish.Name = stream.ReadBytes(Constants.IMAGE_SIZEOF_SHORT_NAME);
ish.VirtualSize = stream.ReadUInt32();
ish.VirtualAddress = stream.ReadUInt32();
ish.SizeOfRawData = stream.ReadUInt32();
ish.PointerToRawData = stream.ReadUInt32();
ish.PointerToRelocations = stream.ReadUInt32();
ish.PointerToLinenumbers = stream.ReadUInt32();
ish.NumberOfRelocations = stream.ReadUInt16();
ish.NumberOfLinenumbers = stream.ReadUInt16();
ish.Characteristics = (SectionCharacteristics)stream.ReadUInt32();
return ish;
}
public static IMAGE_SECTION_HEADER Deserialize(byte[] content, int offset)
{
var ish = new IMAGE_SECTION_HEADER();
ish.Name = new byte[Constants.IMAGE_SIZEOF_SHORT_NAME];
Array.Copy(content, offset, ish.Name, 0, Constants.IMAGE_SIZEOF_SHORT_NAME); offset += Constants.IMAGE_SIZEOF_SHORT_NAME;
ish.VirtualSize = BitConverter.ToUInt32(content, offset); offset += 4;
ish.VirtualAddress = BitConverter.ToUInt32(content, offset); offset += 4;
ish.SizeOfRawData = BitConverter.ToUInt32(content, offset); offset += 4;
ish.PointerToRawData = BitConverter.ToUInt32(content, offset); offset += 4;
ish.PointerToRelocations = BitConverter.ToUInt32(content, offset); offset += 4;
ish.PointerToLinenumbers = BitConverter.ToUInt32(content, offset); offset += 4;
ish.NumberOfRelocations = BitConverter.ToUInt16(content, offset); offset += 2;
ish.NumberOfLinenumbers = BitConverter.ToUInt16(content, offset); offset += 2;
ish.Characteristics = (SectionCharacteristics)BitConverter.ToUInt32(content, offset); offset += 4;
return ish;
}
}
}

View File

@@ -1,7 +1,7 @@
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.ExecutableType.Microsoft.Headers;
using BurnOutSharp.ExecutableType.Microsoft.Sections;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft
{
@@ -10,7 +10,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft
/// A COFF object file header consists of a COFF file header and an optional header.
/// In both cases, the file headers are followed immediately by section headers.
/// </summary>
internal class PEExecutable
internal class PortableExecutable
{
#region Headers
@@ -23,13 +23,13 @@ namespace BurnOutSharp.ExecutableType.Microsoft
/// This information enables Windows to properly execute the image file, even though it has an MS-DOS stub.
/// This file offset is placed at location 0x3c during linking.
// </summary>
public IMAGE_DOS_HEADER MSDOSStub;
public MSDOSExecutableHeader DOSStubHeader;
/// <summary>
/// At the beginning of an object file, or immediately after the signature of an image file, is a standard COFF file header in the following format.
/// Note that the Windows loader limits the number of sections to 96.
/// </summary>
public IMAGE_FILE_HEADER COFFFileHeader;
public CommonObjectFileFormatHeader ImageFileHeader;
/// <summary>
/// Every image file has an optional header that provides information to the loader.
@@ -37,7 +37,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft
/// For image files, this header is required.
/// An object file can have an optional header, but generally this header has no function in an object file except to increase its size.
/// </summary>
public IMAGE_OPTIONAL_HEADER OptionalHeader;
public OptionalHeader OptionalHeader;
/// <summary>
/// Each row of the section table is, in effect, a section header.
@@ -46,7 +46,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft
/// Instead, the location of the section table is determined by calculating the location of the first byte after the headers.
/// Make sure to use the size of the optional header as specified in the file header.
/// </summary>
public IMAGE_SECTION_HEADER[] SectionHeaders;
public SectionHeader[] SectionTable;
#endregion
@@ -63,34 +63,41 @@ namespace BurnOutSharp.ExecutableType.Microsoft
// </summary>
public ImportDataSection ImportTable;
/// <summary>
/// Resources are indexed by a multiple-level binary-sorted tree structure.
// The general design can incorporate 2**31 levels.
// By convention, however, Windows uses three levels
// </summary>
public ResourceSection ResourceSection;
#endregion
// TODO: Add more and more parts of a standard PE executable, not just the header
// TODO: Add data directory table information here instead of in IMAGE_OPTIONAL_HEADER
public static PEExecutable Deserialize(Stream stream)
public static PortableExecutable Deserialize(Stream stream)
{
PEExecutable pex = new PEExecutable();
PortableExecutable pex = new PortableExecutable();
try
{
pex.MSDOSStub = IMAGE_DOS_HEADER.Deserialize(stream); stream.Seek(pex.MSDOSStub.NewExeHeaderAddr, SeekOrigin.Begin);
pex.COFFFileHeader = IMAGE_FILE_HEADER.Deserialize(stream);
if (pex.COFFFileHeader.SizeOfOptionalHeader > 0)
pex.OptionalHeader = IMAGE_OPTIONAL_HEADER.Deserialize(stream);
pex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream); stream.Seek(pex.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
pex.ImageFileHeader = CommonObjectFileFormatHeader.Deserialize(stream);
if (pex.ImageFileHeader.SizeOfOptionalHeader > 0)
pex.OptionalHeader = OptionalHeader.Deserialize(stream);
pex.SectionHeaders = new IMAGE_SECTION_HEADER[pex.COFFFileHeader.NumberOfSections];
for (int i = 0; i < pex.COFFFileHeader.NumberOfSections; i++)
pex.SectionTable = new SectionHeader[pex.ImageFileHeader.NumberOfSections];
for (int i = 0; i < pex.ImageFileHeader.NumberOfSections; i++)
{
pex.SectionHeaders[i] = IMAGE_SECTION_HEADER.Deserialize(stream);
pex.SectionTable[i] = SectionHeader.Deserialize(stream);
}
// TODO: Uncomment these when RVA conversion works
// TODO: Uncomment these when all directories are understod and implemented
// // Export Table
// var table = pex.SectionHeaders[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_EXPORT];
// var table = pex.SectionTable[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_EXPORT];
// if (table.VirtualSize > 0)
// {
// int tableAddress = (int)EVORE.ConvertVirtualAddress(table.VirtualAddress, pex.SectionHeaders);
// int tableAddress = (int)EVORE.ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable);
// stream.Seek(tableAddress, SeekOrigin.Begin);
// pex.ExportTable = ExportDataSection.Deserialize(stream);
// }
@@ -112,33 +119,33 @@ namespace BurnOutSharp.ExecutableType.Microsoft
return pex;
}
public static PEExecutable Deserialize(byte[] content, int offset)
public static PortableExecutable Deserialize(byte[] content, int offset)
{
PEExecutable pex = new PEExecutable();
PortableExecutable pex = new PortableExecutable();
try
{
unsafe
{
pex.MSDOSStub = IMAGE_DOS_HEADER.Deserialize(content, offset); offset = pex.MSDOSStub.NewExeHeaderAddr;
pex.COFFFileHeader = IMAGE_FILE_HEADER.Deserialize(content, offset); offset += Marshal.SizeOf(pex.COFFFileHeader);
if (pex.COFFFileHeader.SizeOfOptionalHeader > 0)
pex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, offset); offset = pex.DOSStubHeader.NewExeHeaderAddr;
pex.ImageFileHeader = CommonObjectFileFormatHeader.Deserialize(content, offset); offset += Marshal.SizeOf(pex.ImageFileHeader);
if (pex.ImageFileHeader.SizeOfOptionalHeader > 0)
{
pex.OptionalHeader = IMAGE_OPTIONAL_HEADER.Deserialize(content, offset); offset += pex.COFFFileHeader.SizeOfOptionalHeader;
pex.OptionalHeader = OptionalHeader.Deserialize(content, offset); offset += pex.ImageFileHeader.SizeOfOptionalHeader;
}
pex.SectionHeaders = new IMAGE_SECTION_HEADER[pex.COFFFileHeader.NumberOfSections];
for (int i = 0; i < pex.COFFFileHeader.NumberOfSections; i++)
pex.SectionTable = new SectionHeader[pex.ImageFileHeader.NumberOfSections];
for (int i = 0; i < pex.ImageFileHeader.NumberOfSections; i++)
{
pex.SectionHeaders[i] = IMAGE_SECTION_HEADER.Deserialize(content, offset); offset += 40;
pex.SectionTable[i] = SectionHeader.Deserialize(content, offset); offset += 40;
}
// TODO: Uncomment these when RVA conversion works
// TODO: Uncomment these when all directories are understod and implemented
// // Export Table
// var table = pex.SectionHeaders[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_EXPORT];
// var table = pex.SectionTable[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_EXPORT];
// if (table.VirtualSize > 0)
// {
// int tableAddress = (int)EVORE.ConvertVirtualAddress(table.VirtualAddress, pex.SectionHeaders);
// int tableAddress = (int)EVORE.ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable);
// pex.ExportTable = ExportDataSection.Deserialize(content, tableAddress);
// }

View File

@@ -1,47 +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 or name string
/// </summary>
/// TODO: Fix this because SizeConst = 0 is not valid
[StructLayout(LayoutKind.Sequential)]
internal class RsrcString
{
/// <summary>
/// Number of bytes in string
/// </summary>
public byte Length;
/// <summary>
/// Next of string
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0)]
public char[] Text;
public static RsrcString Deserialize(Stream stream)
{
var rs = new RsrcString();
rs.Length = stream.ReadByteValue();
rs.Text = stream.ReadChars(rs.Length);
return rs;
}
}
}

View File

@@ -0,0 +1,45 @@
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.ExecutableType.Microsoft.Tables;
namespace BurnOutSharp.ExecutableType.Microsoft.Sections
{
/// <summary>
/// A series of resource directory tables relates all of the levels in the following way:
// Each directory table is followed by a series of directory entries that give the name or
// identifier (ID) for that level (Type, Name, or Language level) and an address of either
// a data description or another directory table. If the address points to a data description,
// then the data is a leaf in the tree. If the address points to another directory table,
// then that table lists directory entries at the next level down
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-rsrc-section</remarks>
internal class ResourceSection
{
/// <summary>
/// A table with just one row (unlike the debug directory).
/// This table indicates the locations and sizes of the other export tables.
/// </summary>
public ResourceDirectoryTable ResourceDirectoryTable;
public static ResourceSection Deserialize(Stream stream)
{
var rs = new ResourceSection();
rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(stream);
return rs;
}
public static ResourceSection Deserialize(byte[] content, int offset)
{
var rs = new ResourceSection();
unsafe
{
rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(content, offset); offset += Marshal.SizeOf(rs.ResourceDirectoryTable);
}
return rs;
}
}
}

View File

@@ -1,4 +1,5 @@
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.Entries;
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
{

View File

@@ -1,3 +1,5 @@
using BurnOutSharp.ExecutableType.Microsoft.Entries;
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
{
/// <summary>

View File

@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.Tools;
using BurnOutSharp.ExecutableType.Microsoft.Entries;
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
{

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.Entries;
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
{

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.Entries;
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
{

View File

@@ -0,0 +1,122 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.ExecutableType.Microsoft.Entries;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
{
/// <summary>
/// Each resource directory table has the following format.
/// This data structure should be considered the heading of a table
/// because the table actually consists of directory entries and this structure
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class ResourceDirectoryTable
{
/// <summary>
/// Resource flags.
/// This field is reserved for future use.
/// It is currently set to zero.
/// </summary>
public uint Characteristics;
/// <summary>
/// The time that the resource data was created by the resource compiler.
/// </summary>
public uint TimeDateStamp;
/// <summary>
/// The major version number, set by the user.
/// </summary>
public ushort MajorVersion;
/// <summary>
/// The minor version number, set by the user.
/// </summary>
public ushort MinorVersion;
/// <summary>
/// The number of directory entries immediately following
/// the table that use strings to identify Type, Name, or
/// Language entries (depending on the level of the table).
/// </summary>
public ushort NumberOfNamedEntries;
/// <summary>
/// The number of directory entries immediately following
/// the Name entries that use numeric IDs for Type, Name,
/// or Language entries.
/// </summary>
public ushort NumberOfIdEntries;
/// <summary>
/// The directory entries immediately following
/// the table that use strings to identify Type, Name, or
/// Language entries (depending on the level of the table).
/// </summary>
public ResourceDirectoryTableEntry[] NamedEntries;
/// <summary>
/// The directory entries immediately following
/// the Name entries that use numeric IDs for Type, Name,
/// or Language entries.
/// </summary>
public ResourceDirectoryTableEntry[] IdEntries;
// TODO: Determine how to store or reference the resource directory strings
// that immediately follow the last directory entry but before the data
public static ResourceDirectoryTable Deserialize(Stream stream)
{
var rdt = new ResourceDirectoryTable();
rdt.Characteristics = stream.ReadUInt32();
rdt.TimeDateStamp = stream.ReadUInt32();
rdt.MajorVersion = stream.ReadUInt16();
rdt.MinorVersion = stream.ReadUInt16();
rdt.NumberOfNamedEntries = stream.ReadUInt16();
rdt.NumberOfIdEntries = stream.ReadUInt16();
rdt.NamedEntries = new ResourceDirectoryTableEntry[rdt.NumberOfNamedEntries];
for (int i = 0; i < rdt.NumberOfNamedEntries; i++)
{
rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(stream);
}
rdt.IdEntries = new ResourceDirectoryTableEntry[rdt.NumberOfIdEntries];
for (int i = 0; i < rdt.NumberOfIdEntries; i++)
{
rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(stream);
}
return rdt;
}
public static ResourceDirectoryTable Deserialize(byte[] content, int offset)
{
var rdt = new ResourceDirectoryTable();
rdt.Characteristics = BitConverter.ToUInt32(content, offset); offset += 4;
rdt.TimeDateStamp = BitConverter.ToUInt32(content, offset); offset += 4;
rdt.MajorVersion = BitConverter.ToUInt16(content, offset); offset += 2;
rdt.MinorVersion = BitConverter.ToUInt16(content, offset); offset += 2;
rdt.NumberOfNamedEntries = BitConverter.ToUInt16(content, offset); offset += 2;
rdt.NumberOfIdEntries = BitConverter.ToUInt16(content, offset); offset += 2;
rdt.NamedEntries = new ResourceDirectoryTableEntry[rdt.NumberOfNamedEntries];
for (int i = 0; i < rdt.NumberOfNamedEntries; i++)
{
rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, offset); offset += 8;
}
rdt.IdEntries = new ResourceDirectoryTableEntry[rdt.NumberOfIdEntries];
for (int i = 0; i < rdt.NumberOfIdEntries; i++)
{
rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, offset); offset += 8;
}
return rdt;
}
}
}

View File

@@ -17,8 +17,8 @@ namespace BurnOutSharp.PackerType
public string CheckContents(string file, byte[] fileContent, bool includeDebug = false)
{
// Get the sections from the executable, if possible
PEExecutable pex = PEExecutable.Deserialize(fileContent, 0);
var sections = pex?.SectionHeaders;
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
var sections = pex?.SectionTable;
if (sections == null)
return null;
@@ -26,7 +26,7 @@ namespace BurnOutSharp.PackerType
var rdataSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith(".rdata"));
if (rdataSection != null)
{
int sectionAddr = (int)EVORE.ConvertVirtualAddress(rdataSection.VirtualAddress, sections);
int sectionAddr = (int)rdataSection.PointerToRawData;
int sectionEnd = sectionAddr + (int)rdataSection.VirtualSize;
var matchers = new List<ContentMatchSet>
{

View File

@@ -25,8 +25,8 @@ namespace BurnOutSharp.PackerType
public string CheckContents(string file, byte[] fileContent, bool includeDebug = false)
{
// Get the sections from the executable, if possible
PEExecutable pex = PEExecutable.Deserialize(fileContent, 0);
var sections = pex?.SectionHeaders;
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
var sections = pex?.SectionTable;
if (sections == null)
return null;
@@ -38,7 +38,7 @@ namespace BurnOutSharp.PackerType
// Loop through all "extension" sections
foreach (var section in sections.Where(s => s != null && Encoding.ASCII.GetString(s.Name).Trim('\0').EndsWith("1")))
{
int sectionAddr = (int)EVORE.ConvertVirtualAddress(section.VirtualAddress, sections);
int sectionAddr = (int)section.PointerToRawData;
int sectionEnd = sectionAddr + (int)section.VirtualSize;
var matchers = new List<ContentMatchSet>
{

View File

@@ -22,8 +22,8 @@ namespace BurnOutSharp.PackerType
public string CheckContents(string file, byte[] fileContent, bool includeDebug = false)
{
// Get the sections from the executable, if possible
PEExecutable pex = PEExecutable.Deserialize(fileContent, 0);
var sections = pex?.SectionHeaders;
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
var sections = pex?.SectionTable;
if (sections == null)
return null;
@@ -34,7 +34,7 @@ namespace BurnOutSharp.PackerType
});
if (dataSection != null)
{
int sectionAddr = (int)EVORE.ConvertVirtualAddress(dataSection.VirtualAddress, sections);
int sectionAddr = (int)dataSection.PointerToRawData;
int sectionEnd = sectionAddr + (int)dataSection.VirtualSize;
var matchers = new List<ContentMatchSet>
{
@@ -56,7 +56,7 @@ namespace BurnOutSharp.PackerType
}
// Get the DOS stub from the executable, if possible
var stub = pex?.MSDOSStub;
var stub = pex?.DOSStubHeader;
if (stub == null)
return null;

View File

@@ -22,8 +22,8 @@ namespace BurnOutSharp.PackerType
public string CheckContents(string file, byte[] fileContent, bool includeDebug = false)
{
// Get the sections from the executable, if possible
PEExecutable pex = PEExecutable.Deserialize(fileContent, 0);
var sections = pex?.SectionHeaders;
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
var sections = pex?.SectionTable;
if (sections == null)
return null;
@@ -34,7 +34,7 @@ namespace BurnOutSharp.PackerType
});
if (dataSection != null)
{
int sectionAddr = (int)EVORE.ConvertVirtualAddress(dataSection.VirtualAddress, sections);
int sectionAddr = (int)dataSection.PointerToRawData;
int sectionEnd = sectionAddr + (int)dataSection.VirtualSize;
var matchers = new List<ContentMatchSet>
{

View File

@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BurnOutSharp.ExecutableType.Microsoft;
using BurnOutSharp.Matching;
using BurnOutSharp.Tools;
@@ -43,6 +46,18 @@ namespace BurnOutSharp.PackerType
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includeDebug = false)
{
// Get the sections from the executable, if possible
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
var sections = pex?.SectionTable;
if (sections == null)
return null;
// Assembly information lives in the .rsrc section
// I need to find out how to navigate the resources in general
// as well as figure out the specific resources for both
// file info and MUI (XML) info. Once I figure this out,
// that also opens the doors to easier assembly XML checks.
var fvinfo = Utilities.GetFileVersionInfo(file);
string name = fvinfo?.FileDescription?.Trim();

View File

@@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using BurnOutSharp.ExecutableType.Microsoft;
using BurnOutSharp.ExecutableType.Microsoft.Headers;
using BurnOutSharp.Matching;
using BurnOutSharp.Tools;
@@ -16,8 +17,8 @@ namespace BurnOutSharp.PackerType
public string CheckContents(string file, byte[] fileContent, bool includeDebug = false)
{
// Get the sections from the executable, if possible
PEExecutable pex = PEExecutable.Deserialize(fileContent, 0);
var sections = pex?.SectionHeaders;
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
var sections = pex?.SectionTable;
if (sections == null)
return null;
@@ -92,7 +93,7 @@ namespace BurnOutSharp.PackerType
/// <param name="sections">Array of sections to check against</param>
/// <param name="sectionPrefix">Prefix of the sections to check for</param>
/// <returns>Real address of the section data, -1 on error</returns>
private int FindData(byte[] fileContent, IMAGE_SECTION_HEADER[] sections, string sectionPrefix)
private int FindData(byte[] fileContent, SectionHeader[] sections, string sectionPrefix)
{
// Get the two matching sections, if possible
var firstSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith($"{sectionPrefix}0"));
@@ -103,7 +104,7 @@ namespace BurnOutSharp.PackerType
return -1;
// Return the first section address
return (int)EVORE.ConvertVirtualAddress(firstSection.VirtualAddress, sections);
return (int)firstSection.PointerToRawData;
}
}
}

View File

@@ -75,6 +75,8 @@ namespace BurnOutSharp.ProtectionType
// (char)0x00 + (char)0x00 + BoG_
new ContentMatchSet(new byte?[] { 0x00, 0x00, 0x42, 0x6F, 0x47, 0x5F }, Get320to4xVersion, "SafeDisc"),
// TODO: These two following are section headers. They should be converted to section header checks instead
// stxt774
new ContentMatchSet(new byte?[] { 0x73, 0x74, 0x78, 0x74, 0x37, 0x37, 0x34 }, Get320to4xVersion, "SafeDisc"),

View File

@@ -22,6 +22,7 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using BurnOutSharp.ExecutableType.Microsoft;
using BurnOutSharp.ExecutableType.Microsoft.Headers;
using BurnOutSharp.ExecutableType.Microsoft.Sections;
using BurnOutSharp.ExecutableType.Microsoft.Tables;
@@ -35,7 +36,7 @@ namespace BurnOutSharp.Tools
/// <param name="virtualAddress">Virtual address to convert</param>
/// <param name="sections">Array of sections to check against</param>
/// <returns>Physical address, 0 on error</returns>
internal static uint ConvertVirtualAddress(uint virtualAddress, IMAGE_SECTION_HEADER[] sections)
internal static uint ConvertVirtualAddress(uint virtualAddress, SectionHeader[] sections)
{
// Loop through all of the sections
for (int i = 0; i < sections.Length; i++)
@@ -65,8 +66,8 @@ namespace BurnOutSharp.Tools
try
{
PEExecutable pex = PEExecutable.Deserialize(fileContent, 0);
return pex.COFFFileHeader.Characteristics.HasFlag(ImageObjectCharacteristics.IMAGE_FILE_DLL);
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
return pex.ImageFileHeader.Characteristics.HasFlag(ImageObjectCharacteristics.IMAGE_FILE_DLL);
}
catch
{
@@ -125,13 +126,13 @@ namespace BurnOutSharp.Tools
unsafe
{
// Read all of the executable header information
PEExecutable pex = PEExecutable.Deserialize(fileContent, 0);
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
// Find the import directory entry
IMAGE_DATA_DIRECTORY idei = pex.OptionalHeader.DataDirectories[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_IMPORT];
// Set the table index and size
int tableIndex = (int)ConvertVirtualAddress(idei.VirtualAddress, pex.SectionHeaders);
int tableIndex = (int)ConvertVirtualAddress(idei.VirtualAddress, pex.SectionTable);
int tableSize = (int)idei.Size;
if (tableIndex <= 0 || tableSize <= 0)
return null;

View File

@@ -39,11 +39,16 @@ namespace BurnOutSharp.Tools
/// <summary>
/// Read a character array from the stream
/// </summary>
public static char[] ReadChars(this Stream stream, int count)
public static char[] ReadChars(this Stream stream, int count) => stream.ReadChars(count, Encoding.Default);
/// <summary>
/// Read a character array from the stream
/// </summary>
public static char[] ReadChars(this Stream stream, int count, Encoding encoding)
{
byte[] buffer = new byte[count];
stream.Read(buffer, 0, count);
return Encoding.Default.GetString(buffer).ToCharArray();
return encoding.GetString(buffer).ToCharArray();
}
/// <summary>