Process file info resources; cleanup; refactors

This commit is contained in:
Matt Nadareski
2021-09-10 02:58:59 -07:00
parent 5628cf8d73
commit 905d440367
50 changed files with 1067 additions and 327 deletions

View File

@@ -35,7 +35,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
return eate;
}
public static ExportAddressTableEntry Deserialize(byte[] content, int offset)
public static ExportAddressTableEntry Deserialize(byte[] content, ref int offset)
{
var eate = new ExportAddressTableEntry();

View File

@@ -58,7 +58,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
return hnte;
}
public static HintNameTableEntry Deserialize(byte[] content, int offset)
public static HintNameTableEntry Deserialize(byte[] content, ref int offset)
{
var hnte = new HintNameTableEntry();

View File

@@ -66,7 +66,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
return iate;
}
public static ImportAddressTableEntry Deserialize(byte[] content, int offset)
public static ImportAddressTableEntry Deserialize(byte[] content, ref int offset)
{
var iate = new ImportAddressTableEntry();

View File

@@ -66,7 +66,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
return idte;
}
public static ImportDirectoryTableEntry Deserialize(byte[] content, int offset)
public static ImportDirectoryTableEntry Deserialize(byte[] content, ref int offset)
{
var idte = new ImportDirectoryTableEntry();

View File

@@ -1,5 +1,4 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using BurnOutSharp.Tools;
@@ -8,7 +7,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
/// <summary>
/// Resource type and name strings
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class NEResourceNameString
{
/// <summary>
@@ -33,12 +31,12 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
return rds;
}
public static NEResourceNameString Deserialize(byte[] contents, int offset)
public static NEResourceNameString Deserialize(byte[] content, ref int offset)
{
var rds = new NEResourceNameString();
rds.Length = contents[offset++];
rds.Value = Encoding.ASCII.GetChars(contents, offset, rds.Length);
rds.Length = content[offset++];
rds.Value = Encoding.ASCII.GetChars(content, offset, rds.Length); offset += rds.Length;
return rds;
}

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
@@ -8,7 +7,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
/// <summary>
/// A table of resources for this type
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class NEResourceTableEntry
{
/// <summary>
@@ -61,16 +59,16 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
return ni;
}
public static NEResourceTableEntry Deserialize(byte[] contents, int offset)
public static NEResourceTableEntry Deserialize(byte[] content, ref 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;
ni.Offset = BitConverter.ToUInt16(content, offset); offset += 2;
ni.Length = BitConverter.ToUInt16(content, offset); offset += 2;
ni.Flags = (ResourceTableEntryFlags)BitConverter.ToUInt16(content, offset); offset += 2;
ni.ResourceID = BitConverter.ToUInt16(content, offset); offset += 2;
ni.Handle = BitConverter.ToUInt16(content, offset); offset += 2;
ni.Usage = BitConverter.ToUInt16(content, offset); offset += 2;
return ni;
}

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
@@ -11,7 +10,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
/// 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>
@@ -49,7 +47,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
return nste;
}
public static NESegmentTableEntry Deserialize(byte[] content, int offset)
public static NESegmentTableEntry Deserialize(byte[] content, ref int offset)
{
var nste = new NESegmentTableEntry();

View File

@@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using BurnOutSharp.ExecutableType.Microsoft.Headers;
using BurnOutSharp.Tools;
@@ -11,7 +10,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
/// <summary>
/// Each Resource Data entry describes an actual unit of raw data in the Resource Data area.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class ResourceDataEntry
{
/// <summary>
@@ -27,7 +25,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
/// <summary>
/// A unit of resource data in the Resource Data area.
/// </summary>
public string EncodedData
public string DataAsUTF8String
{
get
{
@@ -38,7 +36,9 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
try
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
return Encoding.GetEncoding(codePage).GetString(Data);
var originalEncoding = Encoding.GetEncoding(codePage);
byte[] convertedData = Encoding.Convert(originalEncoding, Encoding.UTF8, Data);
return Encoding.UTF8.GetString(convertedData);
}
catch (Exception ex)
{
@@ -85,7 +85,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
return rde;
}
public static ResourceDataEntry Deserialize(byte[] content, int offset, SectionHeader[] sections)
public static ResourceDataEntry Deserialize(byte[] content, ref int offset, SectionHeader[] sections)
{
var rde = new ResourceDataEntry();

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using BurnOutSharp.Tools;
@@ -11,7 +10,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
/// 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>
@@ -34,12 +32,12 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
return rds;
}
public static ResourceDirectoryString Deserialize(byte[] content, int offset)
public static ResourceDirectoryString Deserialize(byte[] content, ref int offset)
{
var rds = new ResourceDirectoryString();
rds.Length = BitConverter.ToUInt16(content, offset); offset += 2;
rds.UnicodeString = Encoding.Unicode.GetString(content, offset, rds.Length);
rds.UnicodeString = Encoding.Unicode.GetString(content, offset, rds.Length); offset += rds.Length;
return rds;
}

View File

@@ -111,7 +111,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
return rdte;
}
public static ResourceDirectoryTableEntry Deserialize(byte[] content, int offset, long sectionStart, SectionHeader[] sections)
public static ResourceDirectoryTableEntry Deserialize(byte[] content, ref int offset, long sectionStart, SectionHeader[] sections)
{
var rdte = new ResourceDirectoryTableEntry();
@@ -120,7 +120,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
int nameAddress = (int)(rdte.NameOffset + sectionStart);
if (nameAddress >= 0 && nameAddress < content.Length)
rdte.Name = ResourceDirectoryString.Deserialize(content, nameAddress);
rdte.Name = ResourceDirectoryString.Deserialize(content, ref nameAddress);
}
rdte.DataEntryOffset = BitConverter.ToUInt32(content, offset); offset += 4;
@@ -128,13 +128,13 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
{
int dataEntryAddress = (int)(rdte.DataEntryOffset + sectionStart);
if (dataEntryAddress > 0 && dataEntryAddress < content.Length)
rdte.DataEntry = ResourceDataEntry.Deserialize(content, dataEntryAddress, sections);
rdte.DataEntry = ResourceDataEntry.Deserialize(content, ref dataEntryAddress, sections);
}
else
{
int subdirectoryAddress = (int)(rdte.SubdirectoryOffset + sectionStart);
if (subdirectoryAddress > 0 && subdirectoryAddress < content.Length)
rdte.Subdirectory = ResourceDirectoryTable.Deserialize(content, subdirectoryAddress, sectionStart, sections);
rdte.Subdirectory = ResourceDirectoryTable.Deserialize(content, ref subdirectoryAddress, sectionStart, sections);
}
// TODO: Add parsing for further directory table entries in the tree

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
@@ -8,7 +7,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
/// <summary>
/// Resource type information block
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class ResourceTypeInformationBlock
{
/// <summary>
@@ -52,18 +50,18 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
return rtib;
}
public static ResourceTypeInformationBlock Deserialize(byte[] contents, int offset)
public static ResourceTypeInformationBlock Deserialize(byte[] content, ref 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.TypeID = BitConverter.ToUInt16(content, offset); offset += 2;
rtib.ResourceCount = BitConverter.ToUInt16(content, offset); offset += 2;
rtib.Reserved = BitConverter.ToUInt32(content, 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;
rtib.ResourceTable[i] = NEResourceTableEntry.Deserialize(content, ref offset);
}
return rtib;

View File

@@ -1,11 +1,9 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
{
[StructLayout(LayoutKind.Sequential)]
internal class CommonObjectFileFormatHeader
{
/// <summary>
@@ -71,7 +69,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
return ifh;
}
public static CommonObjectFileFormatHeader Deserialize(byte[] content, int offset)
public static CommonObjectFileFormatHeader Deserialize(byte[] content, ref int offset)
{
var ifh = new CommonObjectFileFormatHeader();

View File

@@ -1,11 +1,9 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
{
[StructLayout(LayoutKind.Sequential)]
internal class DataDirectoryHeader
{
/// <summary>
@@ -29,7 +27,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
return ddh;
}
public static DataDirectoryHeader Deserialize(byte[] content, int offset)
public static DataDirectoryHeader Deserialize(byte[] content, ref int offset)
{
var ddh = new DataDirectoryHeader();

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
@@ -14,7 +13,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
/// 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
@@ -102,7 +100,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
/// <summary>
/// Reserved words [1C]
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.ERES1WDS)]
public ushort[] Reserved1;
/// <summary>
@@ -118,7 +115,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
/// <summary>
/// Reserved words [28]
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.ERES2WDS)]
public ushort[] Reserved2;
/// <summary>
@@ -168,7 +164,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
return idh;
}
public static MSDOSExecutableHeader Deserialize(byte[] content, int offset, bool asStub = true)
public static MSDOSExecutableHeader Deserialize(byte[] content, ref int offset, bool asStub = true)
{
MSDOSExecutableHeader idh = new MSDOSExecutableHeader();

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
@@ -10,7 +9,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
/// 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>
@@ -216,42 +214,42 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
return neh;
}
public static NewExecutableHeader Deserialize(byte[] contents, int offset)
public static NewExecutableHeader Deserialize(byte[] content, ref 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.ToUInt32(contents, offset); offset += 4;
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++];
neh.Magic = BitConverter.ToUInt16(content, offset); offset += 2;
neh.LinkerVersion = content[offset++];
neh.LinkerRevision = content[offset++];
neh.EntryTableOffset = BitConverter.ToUInt16(content, offset); offset += 2;
neh.EntryTableSize = BitConverter.ToUInt16(content, offset); offset += 2;
neh.CrcChecksum = BitConverter.ToUInt32(content, offset); offset += 4;
neh.ProgramFlags = content[offset++];
neh.ApplicationFlags = content[offset++];
neh.Autodata = BitConverter.ToUInt16(content, offset); offset += 2;
neh.InitialHeapAlloc = BitConverter.ToUInt16(content, offset); offset += 2;
neh.InitialStackAlloc = BitConverter.ToUInt16(content, offset); offset += 2;
neh.InitialCSIPSetting = BitConverter.ToUInt32(content, offset); offset += 4;
neh.InitialSSSPSetting = BitConverter.ToUInt32(content, offset); offset += 4;
neh.FileSegmentCount = BitConverter.ToUInt16(content, offset); offset += 2;
neh.ModuleReferenceTableSize = BitConverter.ToUInt16(content, offset); offset += 2;
neh.NonResidentNameTableSize = BitConverter.ToUInt16(content, offset); offset += 2;
neh.SegmentTableOffset = BitConverter.ToUInt16(content, offset); offset += 2;
neh.ResourceTableOffset = BitConverter.ToUInt16(content, offset); offset += 2;
neh.ResidentNameTableOffset = BitConverter.ToUInt16(content, offset); offset += 2;
neh.ModuleReferenceTableOffset = BitConverter.ToUInt16(content, offset); offset += 2;
neh.ImportedNamesTableOffset = BitConverter.ToUInt16(content, offset); offset += 2;
neh.NonResidentNamesTableOffset = BitConverter.ToUInt32(content, offset); offset += 4;
neh.MovableEntriesCount = BitConverter.ToUInt16(content, offset); offset += 2;
neh.SegmentAlignmentShiftCount = BitConverter.ToUInt16(content, offset); offset += 2;
neh.ResourceEntriesCount = BitConverter.ToUInt16(content, offset); offset += 2;
neh.TargetOperatingSystem = content[offset++];
neh.AdditionalFlags = content[offset++];
neh.ReturnThunkOffset = BitConverter.ToUInt16(content, offset); offset += 2;
neh.SegmentReferenceThunkOffset = BitConverter.ToUInt16(content, offset); offset += 2;
neh.MinCodeSwapAreaSize = BitConverter.ToUInt16(content, offset); offset += 2;
neh.WindowsSDKRevision = content[offset++];
neh.WindowsSDKVersion = content[offset++];
return neh;
}

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
@@ -19,7 +18,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
/// 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 OptionalHeader
{
#region Standard Fields
@@ -231,7 +229,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
/// <summary>
/// Data-directory entries following the optional header
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES)]
public DataDirectoryHeader[] DataDirectories;
#endregion
@@ -301,7 +298,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
return ioh;
}
public static OptionalHeader Deserialize(byte[] content, int offset)
public static OptionalHeader Deserialize(byte[] content, ref int offset)
{
var ioh = new OptionalHeader();
@@ -364,7 +361,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
ioh.DataDirectories = new DataDirectoryHeader[Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
for (int i = 0; i < Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
{
ioh.DataDirectories[i] = DataDirectoryHeader.Deserialize(content, offset); offset += 8;
ioh.DataDirectories[i] = DataDirectoryHeader.Deserialize(content, ref offset);
}
return ioh;

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
@@ -12,7 +11,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
/// 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>
@@ -23,7 +21,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
/// 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>
@@ -110,7 +107,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
return ish;
}
public static SectionHeader Deserialize(byte[] content, int offset)
public static SectionHeader Deserialize(byte[] content, ref int offset)
{
var ish = new SectionHeader();

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.ExecutableType.Microsoft.Headers;
namespace BurnOutSharp.ExecutableType.Microsoft
@@ -41,7 +40,8 @@ namespace BurnOutSharp.ExecutableType.Microsoft
try
{
// Attempt to read the DOS header first
nex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream); stream.Seek(nex.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
nex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream);
stream.Seek(nex.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
if (nex.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
return null;
@@ -70,22 +70,20 @@ namespace BurnOutSharp.ExecutableType.Microsoft
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;
// Attempt to read the DOS header first
nex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, ref 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;
// 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;
}
// Then attempt to read the NE header
nex.NewExecutableHeader = NewExecutableHeader.Deserialize(content, ref offset);
if (nex.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
return null;
}
catch (Exception ex)
{

View File

@@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using BurnOutSharp.ExecutableType.Microsoft.Headers;
using BurnOutSharp.ExecutableType.Microsoft.Sections;
@@ -234,59 +233,54 @@ namespace BurnOutSharp.ExecutableType.Microsoft
try
{
unsafe
// Attempt to read the DOS header first
pex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, ref offset);
offset = pex.DOSStubHeader.NewExeHeaderAddr;
if (pex.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
return null;
// If the new header address is invalid for the file, it's not a PE
if (pex.DOSStubHeader.NewExeHeaderAddr >= content.Length)
return null;
// Then attempt to read the PE header
pex.ImageFileHeader = CommonObjectFileFormatHeader.Deserialize(content, ref offset);
if (pex.ImageFileHeader.Signature != Constants.IMAGE_NT_SIGNATURE)
return null;
// If the optional header is supposed to exist, read that as well
if (pex.ImageFileHeader.SizeOfOptionalHeader > 0)
pex.OptionalHeader = OptionalHeader.Deserialize(content, ref offset);
// Then read in the section table
pex.SectionTable = new SectionHeader[pex.ImageFileHeader.NumberOfSections];
for (int i = 0; i < pex.ImageFileHeader.NumberOfSections; i++)
{
// Attempt to read the DOS header first
pex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, offset); offset = pex.DOSStubHeader.NewExeHeaderAddr;
if (pex.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
return null;
pex.SectionTable[i] = SectionHeader.Deserialize(content, ref offset);
}
// If the new header address is invalid for the file, it's not a PE
if (pex.DOSStubHeader.NewExeHeaderAddr >= content.Length)
return null;
// // Export Table
// var table = pex.GetSection(".edata", true);
// if (table != null && table.VirtualSize > 0)
// {
// int tableAddress = (int)ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable);
// pex.ExportTable = ExportDataSection.Deserialize(content, tableAddress);
// }
// Then attempt to read the PE header
pex.ImageFileHeader = CommonObjectFileFormatHeader.Deserialize(content, offset); offset += Marshal.SizeOf(pex.ImageFileHeader);
if (pex.ImageFileHeader.Signature != Constants.IMAGE_NT_SIGNATURE)
return null;
// // Import Table
// table = pex.GetSection(".idata", true);
// if (table != null && table.VirtualSize > 0)
// {
// int tableAddress = (int)ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable);
// pex.ImportTable = ImportDataSection.Deserialize(content, tableAddress, pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0);
// }
// If the optional header is supposed to exist, read that as well
if (pex.ImageFileHeader.SizeOfOptionalHeader > 0)
{
pex.OptionalHeader = OptionalHeader.Deserialize(content, offset);
offset += pex.ImageFileHeader.SizeOfOptionalHeader;
}
// Then read in the section table
pex.SectionTable = new SectionHeader[pex.ImageFileHeader.NumberOfSections];
for (int i = 0; i < pex.ImageFileHeader.NumberOfSections; i++)
{
pex.SectionTable[i] = SectionHeader.Deserialize(content, offset); offset += 40;
}
// // Export Table
// var table = pex.GetSection(".edata", true);
// if (table != null && table.VirtualSize > 0)
// {
// int tableAddress = (int)ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable);
// pex.ExportTable = ExportDataSection.Deserialize(content, tableAddress);
// }
// // Import Table
// table = pex.GetSection(".idata", true);
// if (table != null && table.VirtualSize > 0)
// {
// int tableAddress = (int)ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable);
// pex.ImportTable = ImportDataSection.Deserialize(content, tableAddress, pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0);
// }
// Resource Table
var table = pex.GetSection(".rsrc", true);
if (table != null && table.VirtualSize > 0)
{
int tableAddress = (int)ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable);
pex.ResourceSection = ResourceSection.Deserialize(content, tableAddress, pex.SectionTable);
}
// Resource Table
var table = pex.GetSection(".rsrc", true);
if (table != null && table.VirtualSize > 0)
{
int tableAddress = (int)ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable);
pex.ResourceSection = ResourceSection.Deserialize(content, ref tableAddress, pex.SectionTable);
}
}
catch (Exception ex)

View File

@@ -0,0 +1,202 @@
using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
internal class FixedFileInfo
{
/// <summary>
/// Contains the value 0xFEEF04BD.
/// This is used with the szKey member of the VS_VERSIONINFO structure when searching a file for the VS_FIXEDFILEINFO structure.
/// </summary>
public uint Signature;
/// <summary>
/// The binary version number of this structure.
/// The high-order word of this member contains the major version number, and the low-order word contains the minor version number.
/// </summary>
public uint StrucVersion;
/// <summary>
/// The most significant 32 bits of the file's binary version number.
/// This member is used with dwFileVersionLS to form a 64-bit value used for numeric comparisons.
/// </summary>
public uint FileVersionMS;
/// <summary>
/// The least significant 32 bits of the file's binary version number.
/// This member is used with dwFileVersionMS to form a 64-bit value used for numeric comparisons.
/// </summary>
public uint FileVersionLS;
/// <summary>
/// The most significant 32 bits of the binary version number of the product with which this file was distributed.
/// This member is used with dwProductVersionLS to form a 64-bit value used for numeric comparisons.
/// </summary>
public uint ProductVersionMS;
/// <summary>
/// The least significant 32 bits of the binary version number of the product with which this file was distributed.
/// This member is used with dwProductVersionMS to form a 64-bit value used for numeric comparisons.
/// </summary>
public uint ProductVersionLS;
/// <summary>
/// Contains a bitmask that specifies the valid bits in dwFileFlags.
/// A bit is valid only if it was defined when the file was created.
/// </summary>
public uint FileFlagsMask;
/// <summary>
/// Contains a bitmask that specifies the Boolean attributes of the file. This member can include one or more of the following values.
///
/// VS_FF_DEBUG (0x00000001L) The file contains debugging information or is compiled with debugging features enabled.
/// VS_FF_INFOINFERRED (0x00000010L) The file's version structure was created dynamically; therefore, some of the members in this structure may be empty or incorrect. This flag should never be set in a file's VS_VERSIONINFO data.
/// VS_FF_PATCHED (0x00000004L) The file has been modified and is not identical to the original shipping file of the same version number.
/// VS_FF_PRERELEASE (0x00000002L) The file is a development version, not a commercially released product.
/// VS_FF_PRIVATEBUILD (0x00000008L) The file was not built using standard release procedures. If this flag is set, the StringFileInfo structure should contain a PrivateBuild entry.
/// VS_FF_SPECIALBUILD (0x00000020L) The file was built by the original company using standard release procedures but is a variation of the normal file of the same version number. If this flag is set, the StringFileInfo structure should contain a SpecialBuild entry.
/// </summary>
/// <remarks>TODO: Make an enum out of this</remarks>
public uint FileFlags;
/// <summary>
/// The operating system for which this file was designed. This member can be one of the following values.
///
/// VOS_DOS (0x00010000L) The file was designed for MS-DOS.
/// VOS_NT (0x00040000L) The file was designed for Windows NT.
/// VOS__WINDOWS16 (0x00000001L) The file was designed for 16-bit Windows.
/// VOS__WINDOWS32 (0x00000004L) The file was designed for 32-bit Windows.
/// VOS_OS216 (0x00020000L) The file was designed for 16-bit OS/2.
/// VOS_OS232 (0x00030000L) The file was designed for 32-bit OS/2.
/// VOS__PM16 (0x00000002L) The file was designed for 16-bit Presentation Manager.
/// VOS__PM32 (0x00000003L) The file was designed for 32-bit Presentation Manager.
/// VOS_UNKNOWN (0x00000000L) The operating system for which the file was designed is unknown to the system.
///
/// An application can combine these values to indicate that the file was designed for one operating system running on another.
/// The following dwFileOS values are examples of this, but are not a complete list.
///
/// VOS_DOS_WINDOWS16 (0x00010001L) The file was designed for 16-bit Windows running on MS-DOS.
/// VOS_DOS_WINDOWS32 (0x00010004L) The file was designed for 32-bit Windows running on MS-DOS.
/// VOS_NT_WINDOWS32 (0x00040004L) The file was designed for Windows NT.
/// VOS_OS216_PM16 (0x00020002L) The file was designed for 16-bit Presentation Manager running on 16-bit OS/2.
/// VOS_OS232_PM32 (0x00030003L) The file was designed for 32-bit Presentation Manager running on 32-bit OS/2.
/// </summary>
/// <remarks>TODO: Make an enum out of this</remarks>
public uint FileOS;
/// <summary>
/// The general type of file. This member can be one of the following values. All other values are reserved.
///
/// VFT_APP (0x00000001L) The file contains an application.
/// VFT_DLL (0x00000002L) The file contains a DLL.
/// VFT_DRV (0x00000003L) The file contains a device driver. If dwFileType is VFT_DRV, dwFileSubtype contains a more specific description of the driver.
/// VFT_FONT (0x00000004L) The file contains a font. If dwFileType is VFT_FONT, dwFileSubtype contains a more specific description of the font file.
/// VFT_STATIC_LIB (0x00000007L) The file contains a static-link library.
/// VFT_UNKNOWN (0x00000000L) The file type is unknown to the system.
/// VFT_VXD (0x00000005L) The file contains a virtual device.
/// </summary>
/// <remarks>TODO: Make an enum out of this</remarks>
public uint FileType;
/// <summary>
/// The function of the file. The possible values depend on the value of dwFileType.
/// For all values of dwFileType not described in the following list, dwFileSubtype is zero.
///
/// If dwFileType is VFT_DRV, dwFileSubtype can be one of the following values.
///
/// VFT2_DRV_COMM (0x0000000AL) The file contains a communications driver.
/// VFT2_DRV_DISPLAY (0x00000004L) The file contains a display driver.
/// VFT2_DRV_INSTALLABLE (0x00000008L) The file contains an installable driver.
/// VFT2_DRV_KEYBOARD (0x00000002L) The file contains a keyboard driver.
/// VFT2_DRV_LANGUAGE (0x00000003L) The file contains a language driver.
/// VFT2_DRV_MOUSE (0x00000005L) The file contains a mouse driver.
/// VFT2_DRV_NETWORK (0x00000006L) The file contains a network driver.
/// VFT2_DRV_PRINTER (0x00000001L) The file contains a printer driver.
/// VFT2_DRV_SOUND (0x00000009L) The file contains a sound driver.
/// VFT2_DRV_SYSTEM (0x00000007L) The file contains a system driver.
/// VFT2_DRV_VERSIONED_PRINTER (0x0000000CL) The file contains a versioned printer driver.
/// VFT2_UNKNOWN (0x00000000L) The driver type is unknown by the system.
///
/// If dwFileType is VFT_FONT, dwFileSubtype can be one of the following values.
///
/// VFT2_FONT_RASTER (0x00000001L) The file contains a raster font.
/// VFT2_FONT_TRUETYPE (0x00000003L) The file contains a TrueType font.
/// VFT2_FONT_VECTOR (0x00000002L) The file contains a vector font.
/// VFT2_UNKNOWN (0x00000000L) The font type is unknown by the system.
///
/// If dwFileType is VFT_VXD, dwFileSubtype contains the virtual device identifier included in the virtual device control block.
/// All dwFileSubtype values not listed here are reserved.
/// </summary>
/// <remarks>TODO: Make an enum out of this</remarks>
public uint FileSubtype;
/// <summary>
/// The most significant 32 bits of the file's 64-bit binary creation date and time stamp.
/// </summary>
public uint FileDateMS;
/// <summary>
/// The least significant 32 bits of the file's 64-bit binary creation date and time stamp.
/// </summary>
public uint FileDateLS;
public static FixedFileInfo Deserialize(Stream stream)
{
FixedFileInfo ffi = new FixedFileInfo();
ushort temp;
while ((temp = stream.ReadUInt16()) == 0x0000);
stream.Seek(-2, SeekOrigin.Current);
ffi.Signature = stream.ReadUInt32();
ffi.StrucVersion = stream.ReadUInt32();
ffi.FileVersionMS = stream.ReadUInt32();
ffi.FileVersionLS = stream.ReadUInt32();
ffi.ProductVersionMS = stream.ReadUInt32();
ffi.ProductVersionLS = stream.ReadUInt32();
ffi.FileFlagsMask = stream.ReadUInt32();
ffi.FileFlags = stream.ReadUInt32();
ffi.FileOS = stream.ReadUInt32();
ffi.FileType = stream.ReadUInt32();
ffi.FileSubtype = stream.ReadUInt32();
ffi.FileDateMS = stream.ReadUInt32();
ffi.FileDateLS = stream.ReadUInt32();
return ffi;
}
public static FixedFileInfo Deserialize(byte[] content, ref int offset)
{
FixedFileInfo ffi = new FixedFileInfo();
ushort temp;
bool padded = false;
while ((temp = BitConverter.ToUInt16(content, offset)) == 0x0000)
{
offset += 2;
padded = true;
}
if (padded)
offset -= 2;
ffi.Signature = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.StrucVersion = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.FileVersionMS = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.FileVersionLS = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.ProductVersionMS = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.ProductVersionLS = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.FileFlagsMask = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.FileFlags = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.FileOS = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.FileType = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.FileSubtype = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.FileDateMS = BitConverter.ToUInt32(content, offset); offset += 4;
ffi.FileDateLS = BitConverter.ToUInt32(content, offset); offset += 4;
return ffi;
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
/// <summary>
/// If you use the Var structure to list the languages your application or DLL supports instead of using multiple version resources,
/// use the Value member to contain an array of DWORD values indicating the language and code page combinations supported by this file.
/// The low-order word of each DWORD must contain a Microsoft language identifier, and the high-order word must contain the IBM code page number.
/// Either high-order or low-order word can be zero, indicating that the file is language or code page independent.
/// If the Var structure is omitted, the file will be interpreted as both language and code page independent.
/// </summary>
internal class LanguageCodePage
{
/// <summary>
/// The low-order word of each DWORD must contain a Microsoft language identifier
/// </summary>
public ushort MicrosoftLanguageIdentifier;
/// <summary>
/// The high-order word must contain the IBM code page number
/// </summary>
public ushort IBMCodePageNumber;
public static LanguageCodePage Deserialize(Stream stream)
{
LanguageCodePage lcp = new LanguageCodePage();
lcp.MicrosoftLanguageIdentifier = stream.ReadUInt16();
lcp.IBMCodePageNumber = stream.ReadUInt16();
return lcp;
}
public static LanguageCodePage Deserialize(byte[] content, ref int offset)
{
LanguageCodePage lcp = new LanguageCodePage();
lcp.MicrosoftLanguageIdentifier = BitConverter.ToUInt16(content, offset); offset += 2;
lcp.IBMCodePageNumber = BitConverter.ToUInt16(content, offset); offset += 2;
return lcp;
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
internal class Resource
{
/// <summary>
/// The length, in bytes, of the resource structure.
/// This length does not include any padding that aligns any subsequent version resource data on a 32-bit boundary.
/// </summary>
public ushort Length;
/// <summary>
/// The length, in bytes, of the Value member.
/// This value is zero if there is no Value member associated with the current version structure.
/// </summary>
public ushort ValueLength;
/// <summary>
/// The type of data in the version resource.
/// This member is 1 if the version resource contains text data and 0 if the version resource contains binary data.
/// </summary>
public ushort Type;
/// <summary>
/// A Unicode string representing the key
/// </summary>
public string Key;
public static Resource Deserialize(Stream stream)
{
Resource r = new Resource();
while ((r.Length = stream.ReadUInt16()) == 0x0000);
r.Length = stream.ReadUInt16();
r.ValueLength = stream.ReadUInt16();
r.Type = stream.ReadUInt16();
r.Key = stream.ReadString(Encoding.Unicode);
return r;
}
public static Resource Deserialize(byte[] content, ref int offset)
{
Resource r = new Resource();
while ((r.Length = BitConverter.ToUInt16(content, offset)) == 0x0000)
{
offset += 2;
}
offset += 2;
r.ValueLength = BitConverter.ToUInt16(content, offset); offset += 2;
r.Type = BitConverter.ToUInt16(content, offset); offset += 2;
List<char> keyChars = new List<char>();
while (BitConverter.ToUInt16(content, offset) != 0x0000)
{
keyChars.Add(Encoding.Unicode.GetChars(content, offset, 2)[0]); offset += 2;
}
offset += 2;
r.Key = new string(keyChars.ToArray());
return r;
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
internal class StringFileInfo : Resource
{
/// <summary>
/// An array of one or more StringTable structures.
/// Each StringTable structure's szKey member indicates the appropriate language and code page for displaying the text in that StringTable structure.
/// </summary>
public StringTable Children;
public static new StringFileInfo Deserialize(Stream stream)
{
StringFileInfo sfi = new StringFileInfo();
Resource resource = Resource.Deserialize(stream);
if (resource.Key != "StringFileInfo")
return null;
sfi.Length = resource.Length;
sfi.ValueLength = resource.ValueLength;
sfi.Type = resource.Type;
sfi.Key = resource.Key;
sfi.Children = StringTable.Deserialize(stream);
return sfi;
}
public static new StringFileInfo Deserialize(byte[] content, ref int offset)
{
StringFileInfo sfi = new StringFileInfo();
Resource resource = Resource.Deserialize(content, ref offset);
if (resource.Key != "StringFileInfo")
return null;
sfi.Length = resource.Length;
sfi.ValueLength = resource.ValueLength;
sfi.Type = resource.Type;
sfi.Key = resource.Key;
sfi.Children = StringTable.Deserialize(content, ref offset);
return sfi;
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.IO;
using System.Text;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
internal class StringStruct : Resource
{
/// <summary>
/// Typically contains a list of languages that the application or DLL supports.
/// </summary>
public string Value;
public static new StringStruct Deserialize(Stream stream)
{
StringStruct s = new StringStruct();
Resource resource = Resource.Deserialize(stream);
s.Length = resource.Length;
s.ValueLength = resource.ValueLength;
s.Type = resource.Type;
s.Key = resource.Key;
stream.Seek(stream.Position % 4 == 0 ? 0 : 4 - (stream.Position % 4), SeekOrigin.Current);
s.Value = new string(stream.ReadChars(s.ValueLength));
return s;
}
public static new StringStruct Deserialize(byte[] content, ref int offset)
{
StringStruct s = new StringStruct();
Resource resource = Resource.Deserialize(content, ref offset);
s.Length = resource.Length;
s.ValueLength = resource.ValueLength;
s.Type = resource.Type;
s.Key = resource.Key;
offset += offset % 4 == 0 ? 0 : 4 - (offset % 4);
s.Value = Encoding.Unicode.GetString(content, offset, s.ValueLength * 2); offset += s.ValueLength * 2;
return s;
}
}
}

View File

@@ -0,0 +1,57 @@
using System.Collections.Generic;
using System.IO;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
internal class StringTable : Resource
{
/// <summary>
/// An array of one or more String structures.
/// </summary>
public StringStruct[] Children;
public static new StringTable Deserialize(Stream stream)
{
StringTable st = new StringTable();
Resource resource = Resource.Deserialize(stream);
if (resource.Key.Length != 8)
return null;
st.Length = resource.Length;
st.ValueLength = resource.ValueLength;
st.Type = resource.Type;
st.Key = resource.Key;
// TODO: Deserialize the Value array
stream.Seek(st.Length - 6 - (st.Key.Length * 2), SeekOrigin.Begin);
return st;
}
public static new StringTable Deserialize(byte[] content, ref int offset)
{
int originalPosition = offset;
StringTable st = new StringTable();
Resource resource = Resource.Deserialize(content, ref offset);
if (resource.Key.Length != 8)
return null;
st.Length = resource.Length;
st.ValueLength = resource.ValueLength;
st.Type = resource.Type;
st.Key = resource.Key;
var tempValue = new List<StringStruct>();
while (offset - originalPosition < st.Length)
{
tempValue.Add(StringStruct.Deserialize(content, ref offset));
}
st.Children = tempValue.ToArray();
return st;
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
internal class Var : Resource
{
/// <summary>
/// An array of one or more values that are language and code page identifier pairs.
///
/// If you use the Var structure to list the languages your application or DLL supports instead of using multiple version resources,
/// use the Value member to contain an array of DWORD values indicating the language and code page combinations supported by this file.
/// The low-order word of each DWORD must contain a Microsoft language identifier, and the high-order word must contain the IBM code page number.
/// Either high-order or low-order word can be zero, indicating that the file is language or code page independent.
/// If the Var structure is omitted, the file will be interpreted as both language and code page independent.
/// </summary>
public LanguageCodePage[] Value;
public static new Var Deserialize(Stream stream)
{
Var v = new Var();
Resource resource = Resource.Deserialize(stream);
if (resource.Key != "Translation")
return null;
v.Length = resource.Length;
v.ValueLength = resource.ValueLength;
v.Type = resource.Type;
v.Key = resource.Key;
// TODO: Deserialize the Value array
return v;
}
public static new Var Deserialize(byte[] content, ref int offset)
{
Var v = new Var();
Resource resource = Resource.Deserialize(content, ref offset);
if (resource.Key != "Translation")
return null;
v.Length = resource.Length;
v.ValueLength = resource.ValueLength;
v.Type = resource.Type;
v.Key = resource.Key;
// TODO: Deserialize the Value array
return v;
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
internal class VarFileInfo : Resource
{
/// <summary>
/// Typically contains a list of languages that the application or DLL supports.
/// </summary>
public Var Children;
public static new VarFileInfo Deserialize(Stream stream)
{
VarFileInfo vfi = new VarFileInfo();
Resource resource = Resource.Deserialize(stream);
if (resource.Key != "VarFileInfo")
return null;
vfi.Length = resource.Length;
vfi.ValueLength = resource.ValueLength;
vfi.Type = resource.Type;
vfi.Key = resource.Key;
vfi.Children = Var.Deserialize(stream);
return vfi;
}
public static new VarFileInfo Deserialize(byte[] content, ref int offset)
{
VarFileInfo vfi = new VarFileInfo();
Resource resource = Resource.Deserialize(content, ref offset);
if (resource.Key != "VarFileInfo")
return null;
vfi.Length = resource.Length;
vfi.ValueLength = resource.ValueLength;
vfi.Type = resource.Type;
vfi.Key = resource.Key;
vfi.Children = Var.Deserialize(content, ref offset);
return vfi;
}
}
}

View File

@@ -0,0 +1,131 @@
using System.IO;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
internal class VersionInfo : Resource
{
/// <summary>
/// Arbitrary data associated with this VS_VERSIONINFO structure.
/// The wValueLength member specifies the length of this member;
/// if wValueLength is zero, this member does not exist.
/// </summary>
public FixedFileInfo Value;
/// <summary>
/// An array of zero or one StringFileInfo structures, and zero or one VarFileInfo structures
/// that are children of the current VS_VERSIONINFO structure.
/// </summary>
public StringFileInfo ChildrenStringFileInfo;
/// <summary>
/// An array of zero or one StringFileInfo structures, and zero or one VarFileInfo structures
/// that are children of the current VS_VERSIONINFO structure.
/// </summary>
public VarFileInfo ChildrenVarFileInfo;
public static new VersionInfo Deserialize(Stream stream)
{
long originalPosition = stream.Position;
VersionInfo vi = new VersionInfo();
Resource resource = Resource.Deserialize(stream);
if (resource.Key != "VS_VERSION_INFO")
return null;
vi.Length = resource.Length;
vi.ValueLength = resource.ValueLength;
vi.Type = resource.Type;
vi.Key = resource.Key;
if (vi.ValueLength > 0)
vi.Value = FixedFileInfo.Deserialize(stream);
if (stream.Position - originalPosition > vi.Length)
return vi;
long preChildOffset = stream.Position;
Resource firstChild = Resource.Deserialize(stream);
if (firstChild.Key == "StringFileInfo")
{
stream.Seek(preChildOffset, SeekOrigin.Begin);
vi.ChildrenStringFileInfo = StringFileInfo.Deserialize(stream);
}
else if (firstChild.Key == "VarFileInfo")
{
stream.Seek(preChildOffset, SeekOrigin.Begin);
vi.ChildrenVarFileInfo = VarFileInfo.Deserialize(stream);
}
if (stream.Position - originalPosition > vi.Length)
return vi;
preChildOffset = stream.Position;
Resource secondChild = Resource.Deserialize(stream);
if (secondChild.Key == "StringFileInfo")
{
stream.Seek(preChildOffset, SeekOrigin.Begin);
vi.ChildrenStringFileInfo = StringFileInfo.Deserialize(stream);
}
else if (secondChild.Key == "VarFileInfo")
{
stream.Seek(preChildOffset, SeekOrigin.Begin);
vi.ChildrenVarFileInfo = VarFileInfo.Deserialize(stream);
}
return vi;
}
public static new VersionInfo Deserialize(byte[] content, ref int offset)
{
int originalOffset = offset;
VersionInfo vi = new VersionInfo();
Resource resource = Resource.Deserialize(content, ref offset);
if (resource.Key != "VS_VERSION_INFO")
return null;
vi.Length = resource.Length;
vi.ValueLength = resource.ValueLength;
vi.Type = resource.Type;
vi.Key = resource.Key;
if (vi.ValueLength > 0)
vi.Value = FixedFileInfo.Deserialize(content, ref offset);
if (offset - originalOffset > vi.Length)
return vi;
int preChildOffset = offset;
Resource firstChild = Resource.Deserialize(content, ref offset);
if (firstChild.Key == "StringFileInfo")
{
offset = preChildOffset;
vi.ChildrenStringFileInfo = StringFileInfo.Deserialize(content, ref offset);
}
else if (firstChild.Key == "VarFileInfo")
{
offset = preChildOffset;
vi.ChildrenVarFileInfo = VarFileInfo.Deserialize(content, ref offset);
}
if (offset - originalOffset > vi.Length)
return vi;
preChildOffset = offset;
Resource secondChild = Resource.Deserialize(content, ref offset);
if (secondChild.Key == "StringFileInfo")
{
offset = preChildOffset;
vi.ChildrenStringFileInfo = StringFileInfo.Deserialize(content, ref offset);
}
else if (secondChild.Key == "VarFileInfo")
{
offset = preChildOffset;
vi.ChildrenVarFileInfo = VarFileInfo.Deserialize(content, ref offset);
}
return vi;
}
}
}

View File

@@ -1,5 +1,4 @@
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.ExecutableType.Microsoft.Tables;
namespace BurnOutSharp.ExecutableType.Microsoft.Sections
@@ -56,18 +55,15 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Sections
return eds;
}
public static ExportDataSection Deserialize(byte[] content, int offset)
public static ExportDataSection Deserialize(byte[] content, ref int offset)
{
var eds = new ExportDataSection();
unsafe
{
eds.ExportDirectoryTable = ExportDirectoryTable.Deserialize(content, offset); offset += Marshal.SizeOf(eds.ExportDirectoryTable);
// eds.ExportAddressTable = ExportAddressTable.Deserialize(content, offset, count: 0); offset += Marshal.SizeOf(eds.ExportAddressTable); // TODO: Figure out where this count comes from
// eds.NamePointerTable = ExportNamePointerTable.Deserialize(content, offset, count: 0); offset += Marshal.SizeOf(eds.NamePointerTable); // TODO: Figure out where this count comes from
// eds.OrdinalTable = ExportOrdinalTable.Deserialize(content, offset, count: 0); offset += Marshal.SizeOf(eds.OrdinalTable); // TODO: Figure out where this count comes from
// eds.ExportNameTable = ExportNameTable.Deserialize(stream); offset += Marshal.SizeOf(eds.ExportAddressTable); // TODO: set this table based on the NamePointerTable value
}
eds.ExportDirectoryTable = ExportDirectoryTable.Deserialize(content, ref offset);
// eds.ExportAddressTable = ExportAddressTable.Deserialize(content, ref offset, count: 0); // TODO: Figure out where this count comes from
// eds.NamePointerTable = ExportNamePointerTable.Deserialize(content, ref offset, count: 0); // TODO: Figure out where this count comes from
// eds.OrdinalTable = ExportOrdinalTable.Deserialize(content, ref offset, count: 0); // TODO: Figure out where this count comes from
// eds.ExportNameTable = ExportNameTable.Deserialize(content, ref offset); // TODO: set this table based on the NamePointerTable value
return eds;
}

View File

@@ -57,28 +57,24 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Sections
return ids;
}
public static ImportDataSection Deserialize(byte[] content, int offset, bool pe32plus, int hintCount)
public static ImportDataSection Deserialize(byte[] content, ref int offset, bool pe32plus, int hintCount)
{
var ids = new ImportDataSection();
ids.ImportDirectoryTable = ImportDirectoryTable.Deserialize(content, offset); offset += 20 * ids.ImportDirectoryTable.Entries.Length;
ids.ImportDirectoryTable = ImportDirectoryTable.Deserialize(content, ref offset);
List<ImportLookupTable> tempLookupTables = new List<ImportLookupTable>();
while (true)
{
var tempLookupTable = ImportLookupTable.Deserialize(content, offset, pe32plus);
if (tempLookupTable.EntriesPE32 != null)
offset += 4 * tempLookupTable.EntriesPE32.Length;
else if (tempLookupTable.EntriesPE32Plus != null)
offset += 8 * tempLookupTable.EntriesPE32Plus.Length;
else
var tempLookupTable = ImportLookupTable.Deserialize(content, ref offset, pe32plus);
if (tempLookupTable.EntriesPE32 == null && tempLookupTable.EntriesPE32Plus == null)
break;
tempLookupTables.Add(tempLookupTable);
}
// TODO: Update the offset, if possible
ids.HintNameTable = HintNameTable.Deserialize(content, offset, hintCount);
ids.HintNameTable = HintNameTable.Deserialize(content, ref offset, hintCount);
return ids;
}

View File

@@ -1,5 +1,4 @@
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.ExecutableType.Microsoft.Headers;
using BurnOutSharp.ExecutableType.Microsoft.Tables;
@@ -32,15 +31,12 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Sections
return rs;
}
public static ResourceSection Deserialize(byte[] content, int offset, SectionHeader[] sections)
public static ResourceSection Deserialize(byte[] content, ref int offset, SectionHeader[] sections)
{
var rs = new ResourceSection();
unsafe
{
long sectionStart = offset;
rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(content, offset, sectionStart, sections); offset += Marshal.SizeOf(rs.ResourceDirectoryTable);
}
long sectionStart = offset;
rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(content, ref offset, sectionStart, sections);
return rs;
}

View File

@@ -26,14 +26,14 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
return eat;
}
public static ExportAddressTable Deserialize(byte[] content, int offset, int count)
public static ExportAddressTable Deserialize(byte[] content, ref int offset, int count)
{
var eat = new ExportAddressTable();
eat.Entries = new ExportAddressTableEntry[count];
for (int i = 0; i < count; i++)
{
eat.Entries[i] = ExportAddressTableEntry.Deserialize(content, offset); offset += 4;
eat.Entries[i] = ExportAddressTableEntry.Deserialize(content, ref offset);
}
return eat;

View File

@@ -90,7 +90,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
return edt;
}
public static ExportDirectoryTable Deserialize(byte[] content, int offset)
public static ExportDirectoryTable Deserialize(byte[] content, ref int offset)
{
var edt = new ExportDirectoryTable();

View File

@@ -28,7 +28,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
return enpt;
}
public static ExportNamePointerTable Deserialize(byte[] content, int offset, int count)
public static ExportNamePointerTable Deserialize(byte[] content, ref int offset, int count)
{
var enpt = new ExportNamePointerTable();

View File

@@ -28,7 +28,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
return edt;
}
public static ExportOrdinalTable Deserialize(byte[] content, int offset, int count)
public static ExportOrdinalTable Deserialize(byte[] content, ref int offset, int count)
{
var edt = new ExportOrdinalTable();

View File

@@ -25,14 +25,14 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
return hnt;
}
public static HintNameTable Deserialize(byte[] content, int offset, int count)
public static HintNameTable Deserialize(byte[] content, ref int offset, int count)
{
var hnt = new HintNameTable();
hnt.Entries = new HintNameTableEntry[count];
for (int i = 0; i < count; i++)
{
hnt.Entries[i] = HintNameTableEntry.Deserialize(content, offset);
hnt.Entries[i] = HintNameTableEntry.Deserialize(content, ref offset);
offset += 2 + hnt.Entries[i].Name.Length + hnt.Entries[i].Pad;
}

View File

@@ -33,14 +33,14 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
return iat;
}
public static ImportAddressTable Deserialize(byte[] content, int offset)
public static ImportAddressTable Deserialize(byte[] content, ref int offset)
{
var iat = new ImportAddressTable();
List<ImportAddressTableEntry> tempEntries = new List<ImportAddressTableEntry>();
while (true)
{
var entry = ImportAddressTableEntry.Deserialize(content, offset); offset += 20;
var entry = ImportAddressTableEntry.Deserialize(content, ref offset);
tempEntries.Add(entry);
if (entry.IsNull())
break;

View File

@@ -33,14 +33,14 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
return idt;
}
public static ImportDirectoryTable Deserialize(byte[] content, int offset)
public static ImportDirectoryTable Deserialize(byte[] content, ref int offset)
{
var idt = new ImportDirectoryTable();
List<ImportDirectoryTableEntry> tempEntries = new List<ImportDirectoryTableEntry>();
while (true)
{
var entry = ImportDirectoryTableEntry.Deserialize(content, offset); offset += 20;
var entry = ImportDirectoryTableEntry.Deserialize(content, ref offset);
tempEntries.Add(entry);
if (entry.IsNull())
break;

View File

@@ -58,7 +58,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
return ilt;
}
public static ImportLookupTable Deserialize(byte[] content, int offset, bool pe32plus)
public static ImportLookupTable Deserialize(byte[] content, ref int offset, bool pe32plus)
{
var ilt = new ImportLookupTable();

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.ExecutableType.Microsoft.Entries;
using BurnOutSharp.Tools;
@@ -17,7 +16,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
/// 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>
@@ -69,22 +67,19 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
return nrt;
}
public static NEResourceTable Deserialize(byte[] contents, int offset)
public static NEResourceTable Deserialize(byte[] content, ref int offset)
{
var nrt = new NEResourceTable();
nrt.AlignmentShiftCount = BitConverter.ToUInt16(contents, offset); offset += 2;
nrt.AlignmentShiftCount = BitConverter.ToUInt16(content, 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);
}
var block = ResourceTypeInformationBlock.Deserialize(content, ref offset);
if (block.TypeID == 0)
break;
typeInformationBlocks.Add(block);
}
nrt.TypeInformationBlocks = typeInformationBlocks.ToArray();
@@ -92,14 +87,11 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
var typeAndNameStrings = new List<NEResourceNameString>();
while (true)
{
unsafe
{
var str = NEResourceNameString.Deserialize(contents, offset); offset += Marshal.SizeOf(str);
if (str.Length == 0)
break;
var str = NEResourceNameString.Deserialize(content, ref offset);
if (str.Length == 0)
break;
typeAndNameStrings.Add(str);
}
typeAndNameStrings.Add(str);
}
nrt.TypeAndNameStrings = typeAndNameStrings.ToArray();

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using BurnOutSharp.ExecutableType.Microsoft.Entries;
using BurnOutSharp.ExecutableType.Microsoft.Headers;
using BurnOutSharp.Tools;
@@ -12,7 +11,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
/// 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>
@@ -94,7 +92,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
return rdt;
}
public static ResourceDirectoryTable Deserialize(byte[] content, int offset, long sectionStart, SectionHeader[] sections)
public static ResourceDirectoryTable Deserialize(byte[] content, ref int offset, long sectionStart, SectionHeader[] sections)
{
var rdt = new ResourceDirectoryTable();
@@ -108,13 +106,13 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
rdt.NamedEntries = new ResourceDirectoryTableEntry[rdt.NumberOfNamedEntries];
for (int i = 0; i < rdt.NumberOfNamedEntries; i++)
{
rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, offset, sectionStart, sections); offset += 8;
rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, ref offset, sectionStart, sections);
}
rdt.IdEntries = new ResourceDirectoryTableEntry[rdt.NumberOfIdEntries];
for (int i = 0; i < rdt.NumberOfIdEntries; i++)
{
rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, offset, sectionStart, sections); offset += 8;
rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, ref offset, sectionStart, sections);
}
return rdt;

View File

@@ -31,7 +31,7 @@ namespace BurnOutSharp.PackerType
&& (name.Equals("Intel(R) Installation Framework", StringComparison.OrdinalIgnoreCase)
|| name.Equals("Intel Installation Framework", StringComparison.OrdinalIgnoreCase)))
{
return $"Intel Installation Framework {Utilities.GetFileVersion(file)}";
return $"Intel Installation Framework {Utilities.GetFileVersion(fileContent)}";
}
name = fvinfo?.ProductName?.Trim();
@@ -39,7 +39,7 @@ namespace BurnOutSharp.PackerType
&& (name.Equals("Intel(R) Installation Framework", StringComparison.OrdinalIgnoreCase)
|| name.Equals("Intel Installation Framework", StringComparison.OrdinalIgnoreCase)))
{
return $"Intel Installation Framework {Utilities.GetFileVersion(file)}";
return $"Intel Installation Framework {Utilities.GetFileVersion(fileContent)}";
}
// Get the sections from the executable, if possible

View File

@@ -36,7 +36,7 @@ namespace BurnOutSharp.PackerType
{
string version = GetVersion(file, fileContent, null);
if (!string.IsNullOrWhiteSpace(version))
return $"Microsoft CAB SFX v{Utilities.GetFileVersion(file)}";
return $"Microsoft CAB SFX v{Utilities.GetFileVersion(fileContent)}";
return "Microsoft CAB SFX";
}
@@ -46,7 +46,7 @@ namespace BurnOutSharp.PackerType
{
string version = GetVersion(file, fileContent, null);
if (!string.IsNullOrWhiteSpace(version))
return $"Microsoft CAB SFX v{Utilities.GetFileVersion(file)}";
return $"Microsoft CAB SFX v{Utilities.GetFileVersion(fileContent)}";
return "Microsoft CAB SFX";
}
@@ -158,7 +158,7 @@ namespace BurnOutSharp.PackerType
// This method of version detection is suboptimal because the version is sometimes the version of the included software, not the SFX itself.
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
{
string version = Utilities.GetFileVersion(file);
string version = Utilities.GetFileVersion(fileContent);
if (!string.IsNullOrWhiteSpace(version))
return $"v{version}";

View File

@@ -122,7 +122,7 @@ namespace BurnOutSharp.PackerType
return version;
// Then check the file version
version = Utilities.GetFileVersion(file);
version = Utilities.GetFileVersion(fileContent);
if (!string.IsNullOrEmpty(version))
return version;

View File

@@ -47,13 +47,13 @@ namespace BurnOutSharp.ProtectionType
string name = fvinfo?.FileDescription?.Trim();
if (!string.IsNullOrWhiteSpace(name) && name.Contains("Registration code installer program"))
return $"EA CdKey Registration Module {Utilities.GetFileVersion(file)}";
return $"EA CdKey Registration Module {Utilities.GetFileVersion(fileContent)}";
else if (!string.IsNullOrWhiteSpace(name) && name.Equals("EA DRM Helper", StringComparison.OrdinalIgnoreCase))
return $"EA DRM Protection {Utilities.GetFileVersion(file)}";
return $"EA DRM Protection {Utilities.GetFileVersion(fileContent)}";
name = fvinfo?.InternalName?.Trim();
if (!string.IsNullOrWhiteSpace(name) && name.Equals("CDCode", StringComparison.Ordinal))
return $"EA CdKey Registration Module {Utilities.GetFileVersion(file)}";
return $"EA CdKey Registration Module {Utilities.GetFileVersion(fileContent)}";
// Get the sections from the executable, if possible
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);

View File

@@ -28,9 +28,9 @@ namespace BurnOutSharp.ProtectionType
string name = fvinfo?.FileDescription?.Trim();
if (!string.IsNullOrWhiteSpace(name) && name.StartsWith("Games for Windows - LIVE Zero Day Piracy Protection", StringComparison.OrdinalIgnoreCase))
return $"Games for Windows LIVE - Zero Day Piracy Protection Module {Utilities.GetFileVersion(file)}";
return $"Games for Windows LIVE - Zero Day Piracy Protection Module {Utilities.GetFileVersion(fileContent)}";
else if (!string.IsNullOrWhiteSpace(name) && name.StartsWith("Games for Windows", StringComparison.OrdinalIgnoreCase))
return $"Games for Windows LIVE {Utilities.GetFileVersion(file)}";
return $"Games for Windows LIVE {Utilities.GetFileVersion(fileContent)}";
// Get the sections from the executable, if possible
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);

View File

@@ -57,17 +57,17 @@ namespace BurnOutSharp.ProtectionType
string name = fvinfo?.FileDescription?.Trim();
if (!string.IsNullOrWhiteSpace(name) && name.StartsWith("DVM Library", StringComparison.OrdinalIgnoreCase))
return $"SolidShield {Utilities.GetFileVersion(file)}";
return $"SolidShield {Utilities.GetFileVersion(fileContent)}";
else if (!string.IsNullOrWhiteSpace(name) && name.StartsWith("Solidshield Activation Library", StringComparison.OrdinalIgnoreCase))
return $"SolidShield Core.dll {Utilities.GetFileVersion(file)}";
return $"SolidShield Core.dll {Utilities.GetFileVersion(fileContent)}";
else if (!string.IsNullOrWhiteSpace(name) && name.StartsWith("Activation Manager", StringComparison.OrdinalIgnoreCase))
return $"SolidShield Activation Manager Module {GetFileVersion(file, fileContent, null)}";
name = fvinfo?.ProductName?.Trim();
if (!string.IsNullOrWhiteSpace(name) && name.StartsWith("Solidshield Activation Library", StringComparison.OrdinalIgnoreCase))
return $"SolidShield Core.dll {Utilities.GetFileVersion(file)}";
return $"SolidShield Core.dll {Utilities.GetFileVersion(fileContent)}";
else if (!string.IsNullOrWhiteSpace(name) && name.StartsWith("Solidshield Library", StringComparison.OrdinalIgnoreCase))
return $"SolidShield Core.dll {Utilities.GetFileVersion(file)}";
return $"SolidShield Core.dll {Utilities.GetFileVersion(fileContent)}";
else if (!string.IsNullOrWhiteSpace(name) && name.StartsWith("Activation Manager", StringComparison.OrdinalIgnoreCase))
return $"SolidShield Activation Manager Module {GetFileVersion(file, fileContent, null)}";
@@ -224,7 +224,7 @@ namespace BurnOutSharp.ProtectionType
{
string companyName = Utilities.GetFileVersionInfo(file)?.CompanyName.ToLowerInvariant();
if (!string.IsNullOrWhiteSpace(companyName) && (companyName.Contains("solidshield") || companyName.Contains("tages")))
return Utilities.GetFileVersion(file);
return Utilities.GetFileVersion(fileContent);
return null;
}

View File

@@ -28,7 +28,7 @@ namespace BurnOutSharp.ProtectionType
string name = fvinfo?.LegalCopyright?.Trim();
if (!string.IsNullOrWhiteSpace(name) && name.Contains("Protection Technology"))
return $"StarForce {Utilities.GetFileVersion(file)}";
return $"StarForce {Utilities.GetFileVersion(fileContent)}";
// TODO: Find what fvinfo field actually maps to this
name = fvinfo?.FileDescription?.Trim();
@@ -155,7 +155,7 @@ namespace BurnOutSharp.ProtectionType
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
{
return $"{Utilities.GetFileVersion(file)} ({fileContent.Skip(positions[1] + 22).TakeWhile(c => c != 0x00)})";
return $"{Utilities.GetFileVersion(fileContent)} ({fileContent.Skip(positions[1] + 22).TakeWhile(c => c != 0x00)})";
}
}
}

View File

@@ -1,11 +1,84 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using BurnOutSharp.Matching;
namespace BurnOutSharp.Tools
{
internal static class BufferExtensions
internal static class Extensions
{
// TODO: Add extensions for BitConverter.ToX(); offset += x;
#region Byte Arrays
/// <summary>
/// Find all positions of one array in another, if possible, if possible
/// </summary>
public static List<int> FindAllPositions(this byte[] stack, byte?[] needle, int start = 0, int end = -1)
{
// Get the outgoing list
List<int> positions = new List<int>();
// Initialize the loop variables
bool found = true;
int lastPosition = start;
var matcher = new ContentMatch(needle, end: end);
// Loop over and get all positions
while (found)
{
matcher.Start = lastPosition;
(found, lastPosition) = matcher.Match(stack, false);
if (found)
positions.Add(lastPosition);
}
return positions;
}
/// <summary>
/// Find the first position of one array in another, if possible
/// </summary>
public static bool FirstPosition(this byte[] stack, byte?[] needle, out int position, int start = 0, int end = -1)
{
var matcher = new ContentMatch(needle, start, end);
(bool found, int foundPosition) = matcher.Match(stack, false);
position = foundPosition;
return found;
}
/// <summary>
/// Find the last position of one array in another, if possible
/// </summary>
public static bool LastPosition(this byte[] stack, byte?[] needle, out int position, int start = 0, int end = -1)
{
var matcher = new ContentMatch(needle, start, end);
(bool found, int foundPosition) = matcher.Match(stack, true);
position = foundPosition;
return found;
}
/// <summary>
/// See if a byte array starts with another
/// </summary>
public static bool StartsWith(this byte[] stack, byte?[] needle)
{
return stack.FirstPosition(needle, out int _, start: 0, end: 1);
}
/// <summary>
/// See if a byte array ends with another
/// </summary>
public static bool EndsWith(this byte[] stack, byte?[] needle)
{
return stack.FirstPosition(needle, out int _, start: stack.Length - needle.Length);
}
#endregion
#region Streams
/// <summary>
/// Read a byte from the stream
/// </summary>
@@ -109,6 +182,32 @@ namespace BurnOutSharp.Tools
byte[] buffer = new byte[8];
stream.Read(buffer, 0, 8);
return BitConverter.ToUInt64(buffer, 0);
}
}
/// <summary>
/// Read a null-terminated string from the stream
/// </summary>
public static string ReadString(this Stream stream) => stream.ReadString(Encoding.Default);
/// <summary>
/// Read a null-terminated string from the stream
/// </summary>
public static string ReadString(this Stream stream, Encoding encoding)
{
byte[] nullTerminator = encoding.GetBytes(new char[] { '\0' });
int charWidth = nullTerminator.Length;
List<byte> tempBuffer = new List<byte>();
byte[] buffer = new byte[charWidth];
while (stream.Read(buffer, 0, charWidth) != 0 && buffer.SequenceEqual(nullTerminator))
{
tempBuffer.AddRange(buffer);
}
return encoding.GetString(tempBuffer.ToArray());
}
#endregion
}
}

View File

@@ -6,6 +6,8 @@ using System.IO;
using System.Linq;
using System.Xml;
using BurnOutSharp.ExecutableType.Microsoft;
using BurnOutSharp.ExecutableType.Microsoft.Entries;
using BurnOutSharp.ExecutableType.Microsoft.Resources;
using BurnOutSharp.ExecutableType.Microsoft.Sections;
using BurnOutSharp.ExecutableType.Microsoft.Tables;
using BurnOutSharp.Matching;
@@ -180,73 +182,6 @@ namespace BurnOutSharp.Tools
#endregion
#region Byte Arrays
/// <summary>
/// Find all positions of one array in another, if possible, if possible
/// </summary>
public static List<int> FindAllPositions(this byte[] stack, byte?[] needle, int start = 0, int end = -1)
{
// Get the outgoing list
List<int> positions = new List<int>();
// Initialize the loop variables
bool found = true;
int lastPosition = start;
var matcher = new ContentMatch(needle, end: end);
// Loop over and get all positions
while (found)
{
matcher.Start = lastPosition;
(found, lastPosition) = matcher.Match(stack, false);
if (found)
positions.Add(lastPosition);
}
return positions;
}
/// <summary>
/// Find the first position of one array in another, if possible
/// </summary>
public static bool FirstPosition(this byte[] stack, byte?[] needle, out int position, int start = 0, int end = -1)
{
var matcher = new ContentMatch(needle, start, end);
(bool found, int foundPosition) = matcher.Match(stack, false);
position = foundPosition;
return found;
}
/// <summary>
/// Find the last position of one array in another, if possible
/// </summary>
public static bool LastPosition(this byte[] stack, byte?[] needle, out int position, int start = 0, int end = -1)
{
var matcher = new ContentMatch(needle, start, end);
(bool found, int foundPosition) = matcher.Match(stack, true);
position = foundPosition;
return found;
}
/// <summary>
/// See if a byte array starts with another
/// </summary>
public static bool StartsWith(this byte[] stack, byte?[] needle)
{
return stack.FirstPosition(needle, out int _, start: 0, end: 1);
}
/// <summary>
/// See if a byte array ends with another
/// </summary>
public static bool EndsWith(this byte[] stack, byte?[] needle)
{
return stack.FirstPosition(needle, out int _, start: stack.Length - needle.Length);
}
#endregion
#region Protection
/// <summary>
@@ -269,6 +204,36 @@ namespace BurnOutSharp.Tools
}
}
/// <summary>
/// Get the file version info object related to file contents, if possible
/// </summary>
/// <param name="fileContent">Byte array representing the file contents</param>
/// <returns>FileVersionInfo object on success, null on error</returns>
public static VersionInfo GetVersionInfo(byte[] fileContent)
{
if (fileContent == null || !fileContent.Any())
return null;
// If we don't have a PE executable, just return null
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
var resourceSection = pex?.ResourceSection;
if (resourceSection == null)
return null;
var resource = FindResourceInSection(resourceSection, dataContains: "V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0");
try
{
int index = 0;
return VersionInfo.Deserialize(resource.Data, ref index);
}
catch (Exception ex)
{
// Console.WriteLine(ex);
return null;
}
}
/// <summary>
/// Get the file version as reported by the filesystem
/// </summary>
@@ -284,6 +249,29 @@ namespace BurnOutSharp.Tools
else
return fvinfo.ProductVersion.Replace(", ", ".");
}
/// <summary>
/// Get the file version as reported by the filesystem
/// </summary>
/// <param name="fileContent">Byte array representing the file contents</param>
/// <returns>Version string, null on error</returns>
/// TODO: Add override that takes an existing PE
public static string GetFileVersion(byte[] fileContent)
{
var resourceStrings = GetVersionInfo(fileContent)?.ChildrenStringFileInfo?.Children?.Children;
if (resourceStrings == null)
return null;
var fileVersion = resourceStrings.FirstOrDefault(s => s.Key == "FileVersion");
if (!string.IsNullOrWhiteSpace(fileVersion?.Value))
return fileVersion.Value.Replace(", ", ".");
var productVersion = resourceStrings.FirstOrDefault(s => s.Key == "ProductVersion");
if (!string.IsNullOrWhiteSpace(productVersion?.Value))
return productVersion.Value.Replace(", ", ".");
return null;
}
/// <summary>
/// Wrapper for GetFileVersion for use in content matching
@@ -292,7 +280,7 @@ namespace BurnOutSharp.Tools
/// <param name="fileContent">Byte array representing the file contents</param>
/// <param name="positions">Last matched positions in the contents</param>
/// <returns>Version string, null on error</returns>
public static string GetFileVersion(string file, byte[] fileContent, List<int> positions) => GetFileVersion(file);
public static string GetFileVersion(string file, byte[] fileContent, List<int> positions) => GetFileVersion(fileContent);
/// <summary>
/// Wrapper for GetFileVersion for use in path matching
@@ -388,7 +376,7 @@ namespace BurnOutSharp.Tools
/// <param name="dataStart">String to use if checking for data starting with a string</param>
/// <param name="dataContains">String to use if checking for data contains a string</param>
/// <returns>Full encoded resource data, null on error</returns>
private static string FindResourceInSection(ResourceSection rs, string dataStart = null, string dataContains = null)
private static ResourceDataEntry FindResourceInSection(ResourceSection rs, string dataStart = null, string dataContains = null)
{
if (rs == null)
return null;
@@ -403,7 +391,7 @@ namespace BurnOutSharp.Tools
/// <param name="dataStart">String to use if checking for data starting with a string</param>
/// <param name="dataContains">String to use if checking for data contains a string</param>
/// <returns>Full encoded resource data, null on error</returns>
private static string FindResourceInTable(ResourceDirectoryTable rdt, string dataStart, string dataContains)
private static ResourceDataEntry FindResourceInTable(ResourceDirectoryTable rdt, string dataStart, string dataContains)
{
if (rdt == null)
return null;
@@ -412,15 +400,15 @@ namespace BurnOutSharp.Tools
{
if (rdte.IsResourceDataEntry() && rdte.DataEntry != null)
{
if (dataStart != null && rdte.DataEntry.EncodedData.StartsWith(dataStart))
return rdte.DataEntry.EncodedData;
else if (dataContains != null && rdte.DataEntry.EncodedData.Contains(dataContains))
return rdte.DataEntry.EncodedData;
if (dataStart != null && rdte.DataEntry.DataAsUTF8String.StartsWith(dataStart))
return rdte.DataEntry;
else if (dataContains != null && rdte.DataEntry.DataAsUTF8String.Contains(dataContains))
return rdte.DataEntry;
}
else
{
string manifest = FindResourceInTable(rdte.Subdirectory, dataStart, dataContains);
if (!string.IsNullOrWhiteSpace(manifest))
var manifest = FindResourceInTable(rdte.Subdirectory, dataStart, dataContains);
if (manifest != null)
return manifest;
}
}
@@ -429,15 +417,15 @@ namespace BurnOutSharp.Tools
{
if (rdte.IsResourceDataEntry() && rdte.DataEntry != null)
{
if (dataStart != null && rdte.DataEntry.EncodedData.StartsWith(dataStart))
return rdte.DataEntry.EncodedData;
else if (dataContains != null && rdte.DataEntry.EncodedData.Contains(dataContains))
return rdte.DataEntry.EncodedData;
if (dataStart != null && rdte.DataEntry.DataAsUTF8String.StartsWith(dataStart))
return rdte.DataEntry;
else if (dataContains != null && rdte.DataEntry.DataAsUTF8String.Contains(dataContains))
return rdte.DataEntry;
}
else
{
string manifest = FindResourceInTable(rdte.Subdirectory, dataStart, dataContains);
if (!string.IsNullOrWhiteSpace(manifest))
var manifest = FindResourceInTable(rdte.Subdirectory, dataStart, dataContains);
if (manifest != null)
return manifest;
}
}
@@ -450,7 +438,7 @@ namespace BurnOutSharp.Tools
/// </summary>
/// <param name="rs">ResourceSection from the executable</param>
/// <returns>Full assembly manifest, null on error</returns>
private static string FindAssemblyManifest(ResourceSection rs) => FindResourceInSection(rs, dataStart: "<assembly");
private static string FindAssemblyManifest(ResourceSection rs) => FindResourceInSection(rs, dataStart: "<assembly").DataAsUTF8String;
/// <summary>
/// Get the assembly identity node from an embedded manifest