mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-02-04 05:35:49 +00:00
Compare commits
98 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35acb77bf7 | ||
|
|
e970a7b4d9 | ||
|
|
f155291139 | ||
|
|
b0293419e1 | ||
|
|
09db225929 | ||
|
|
0c52b4e236 | ||
|
|
5dc30942ff | ||
|
|
cab200e893 | ||
|
|
c349f3a3c4 | ||
|
|
0acb29f2e9 | ||
|
|
b66e01f7b4 | ||
|
|
8d6d215e57 | ||
|
|
d54a90a034 | ||
|
|
e1e7172561 | ||
|
|
6606b388f6 | ||
|
|
b6c6c01358 | ||
|
|
6886c5a4a2 | ||
|
|
87546a3dc8 | ||
|
|
6e3028639a | ||
|
|
386da02e27 | ||
|
|
ec8c395ffa | ||
|
|
9b98215fc9 | ||
|
|
40e037fb2a | ||
|
|
17f8569a7e | ||
|
|
1105f36cee | ||
|
|
f9fcd8749b | ||
|
|
eef76d362a | ||
|
|
3b0e3693eb | ||
|
|
ba4c56997a | ||
|
|
ca4d08567d | ||
|
|
3211149996 | ||
|
|
5a7e60cabb | ||
|
|
46ff4b6ef9 | ||
|
|
dc252e8d86 | ||
|
|
133e29dc2e | ||
|
|
368cec4fc6 | ||
|
|
65eea4301d | ||
|
|
ceae505f4d | ||
|
|
a7e9164f4f | ||
|
|
3820546c07 | ||
|
|
0fa6673d21 | ||
|
|
0a486c2195 | ||
|
|
a723fbefc3 | ||
|
|
70e64e57dd | ||
|
|
edfc3c6c5d | ||
|
|
c4447fc505 | ||
|
|
a1d2292381 | ||
|
|
033fb0c1ac | ||
|
|
e80034abf1 | ||
|
|
27e4a6c452 | ||
|
|
914497b76f | ||
|
|
513e799aa3 | ||
|
|
fcbf006e4e | ||
|
|
bef26e0fd7 | ||
|
|
3dde84f683 | ||
|
|
74c6aa06e0 | ||
|
|
ffb529edb3 | ||
|
|
d1279a471c | ||
|
|
a7f406537e | ||
|
|
df7d5150c1 | ||
|
|
73e4569b3b | ||
|
|
30c249ce74 | ||
|
|
ec83669d7d | ||
|
|
e765fb6c0b | ||
|
|
76465d30ec | ||
|
|
71d3771c1d | ||
|
|
bfd9c12163 | ||
|
|
eb57065562 | ||
|
|
3875f3b8fb | ||
|
|
8c2bedd21e | ||
|
|
b199a6aa54 | ||
|
|
1b1f64c2de | ||
|
|
7b73cc9d9b | ||
|
|
d9d84a01e5 | ||
|
|
56f009ac56 | ||
|
|
96daf90ae8 | ||
|
|
b581cb3124 | ||
|
|
4b0e39b950 | ||
|
|
3a1c476edc | ||
|
|
0d62d5336c | ||
|
|
cf87279dfc | ||
|
|
0006f7932a | ||
|
|
841a39c6c7 | ||
|
|
60b12f25a6 | ||
|
|
f2b96b6c50 | ||
|
|
d2fad1ab29 | ||
|
|
6f6755b218 | ||
|
|
9a2f2e6f17 | ||
|
|
d9ca550e3b | ||
|
|
ec66e87ee6 | ||
|
|
53ce3aee74 | ||
|
|
1ecb06f020 | ||
|
|
3ce4ac785e | ||
|
|
1df157434d | ||
|
|
594f001dda | ||
|
|
c2c6bc268e | ||
|
|
7aa2207edd | ||
|
|
22aa1642a6 |
@@ -8,12 +8,12 @@
|
||||
<Description>Port of BurnOut to C#, with additions</Description>
|
||||
<Authors>Matt Nadareski;Gernot Knippen</Authors>
|
||||
<Product>BurnOutSharp</Product>
|
||||
<Copyright>Copyright (c)2005-2010 Gernot Knippen, Copyright (c)2018-2021 Matt Nadareski</Copyright>
|
||||
<Copyright>Copyright (c)2005-2010 Gernot Knippen, Copyright (c)2018-2022 Matt Nadareski</Copyright>
|
||||
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
|
||||
<RepositoryUrl>https://github.com/mnadareski/BurnOutSharp</RepositoryUrl>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
<Version>2.0.0</Version>
|
||||
<AssemblyVersion>2.0.0</AssemblyVersion>
|
||||
<FileVersion>2.0.0</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
</PropertyGroup>
|
||||
@@ -23,13 +23,13 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SharpCompress" Version="0.29.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||
<PackageReference Include="Teronis.MSBuild.Packaging.ProjectBuildInPackage" Version="0.1.7">
|
||||
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
|
||||
<PackageReference Include="Teronis.MSBuild.Packaging.ProjectBuildInPackage" Version="1.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="UnshieldSharp" Version="1.6.6" />
|
||||
<PackageReference Include="UnshieldSharp" Version="1.6.7" />
|
||||
<PackageReference Include="WiseUnpacker" Version="1.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// Resource type and name strings
|
||||
/// </summary>
|
||||
public class NEResourceNameString
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of the type or name string that follows. A zero value
|
||||
/// indicates the end of the resource type and name string, also
|
||||
/// the end of the resource table.
|
||||
/// </summary>
|
||||
public byte Length;
|
||||
|
||||
/// <summary>
|
||||
/// ASCII text of the type or name string.
|
||||
/// </summary>
|
||||
public char[] Value;
|
||||
|
||||
public static NEResourceNameString Deserialize(Stream stream)
|
||||
{
|
||||
var rds = new NEResourceNameString();
|
||||
|
||||
rds.Length = stream.ReadByteValue();
|
||||
rds.Value = stream.ReadChars(rds.Length, Encoding.ASCII);
|
||||
|
||||
return rds;
|
||||
}
|
||||
|
||||
public static NEResourceNameString Deserialize(byte[] content, ref int offset)
|
||||
{
|
||||
var rds = new NEResourceNameString();
|
||||
|
||||
rds.Length = content.ReadByte(ref offset);
|
||||
rds.Value = Encoding.ASCII.GetChars(content, offset, rds.Length); offset += rds.Length;
|
||||
|
||||
return rds;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,83 @@ using System;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
{
|
||||
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#debug-type
|
||||
public enum DebugType : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// An unknown value that is ignored by all tools.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_UNKNOWN = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The COFF debug information (line numbers, symbol table, and string table).
|
||||
/// This type of debug information is also pointed to by fields in the file headers.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_COFF = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The Visual C++ debug information.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_CODEVIEW = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The frame pointer omission (FPO) information.
|
||||
/// This information tells the debugger how to interpret nonstandard stack frames,
|
||||
/// which use the EBP register for a purpose other than as a frame pointer.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_FPO = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The location of DBG file.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_MISC = 4,
|
||||
|
||||
/// <summary>
|
||||
/// A copy of .pdata section.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_EXCEPTION = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_FIXUP = 6,
|
||||
|
||||
/// <summary>
|
||||
/// The mapping from an RVA in image to an RVA in source image.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_OMAP_TO_SRC = 7,
|
||||
|
||||
/// <summary>
|
||||
/// The mapping from an RVA in source image to an RVA in image.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_OMAP_FROM_SRC = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for Borland.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_BORLAND = 9,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_RESERVED10 = 10,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_CLSID = 11,
|
||||
|
||||
/// <summary>
|
||||
/// PE determinism or reproducibility.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_REPRO = 16,
|
||||
|
||||
/// <summary>
|
||||
/// Extended DLL characteristics bits.
|
||||
/// </summary>
|
||||
IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS = 20,
|
||||
}
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#dll-characteristics
|
||||
[Flags]
|
||||
public enum DllCharacteristics : ushort
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.MZ.Headers
|
||||
{
|
||||
/// <summary>
|
||||
/// The MS-DOS EXE format, also known as MZ after its signature (the initials of Microsoft engineer Mark Zbykowski),
|
||||
@@ -0,0 +1,79 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// These name strings are case-sensitive and are not null-terminated
|
||||
/// </summary>
|
||||
public class ResidentNameTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of the name string that follows.
|
||||
/// A zero value indicates the end of the name table.
|
||||
/// </summary>
|
||||
public byte Length;
|
||||
|
||||
/// <summary>
|
||||
/// ASCII text of the name string.
|
||||
/// </summary>
|
||||
public byte[] Data;
|
||||
|
||||
/// <summary>
|
||||
/// Ordinal number (index into entry table).
|
||||
/// This value is ignored for the module name.
|
||||
/// </summary>
|
||||
public ushort OrdinalNumber;
|
||||
|
||||
/// <summary>
|
||||
/// ASCII text of the name string
|
||||
/// </summary>
|
||||
public string DataAsString
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Data == null)
|
||||
return string.Empty;
|
||||
|
||||
// Try to read direct as ASCII
|
||||
try
|
||||
{
|
||||
return Encoding.ASCII.GetString(Data);
|
||||
}
|
||||
catch { }
|
||||
|
||||
// If ASCII encoding fails, then just return an empty string
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public static ResidentNameTableEntry Deserialize(Stream stream)
|
||||
{
|
||||
var rnte = new ResidentNameTableEntry();
|
||||
|
||||
rnte.Length = stream.ReadByteValue();
|
||||
if (rnte.Length == 0)
|
||||
return rnte;
|
||||
|
||||
rnte.Data = stream.ReadBytes(rnte.Length);
|
||||
rnte.OrdinalNumber = stream.ReadUInt16();
|
||||
|
||||
return rnte;
|
||||
}
|
||||
|
||||
public static ResidentNameTableEntry Deserialize(byte[] content, ref int offset)
|
||||
{
|
||||
var rnte = new ResidentNameTableEntry();
|
||||
|
||||
rnte.Length = content.ReadByte(ref offset);
|
||||
if (rnte.Length == 0)
|
||||
return rnte;
|
||||
|
||||
rnte.Data = content.ReadBytes(ref offset, rnte.Length);
|
||||
rnte.OrdinalNumber = content.ReadUInt16(ref offset);
|
||||
|
||||
return rnte;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// Resource type and name strings
|
||||
/// </summary>
|
||||
public class ResourceNameString
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of the type or name string that follows. A zero value
|
||||
/// indicates the end of the resource type and name string, also
|
||||
/// the end of the resource table.
|
||||
/// </summary>
|
||||
public byte Length;
|
||||
|
||||
/// <summary>
|
||||
/// ASCII text of the type or name string.
|
||||
/// </summary>
|
||||
public char[] Value;
|
||||
|
||||
public static ResourceNameString Deserialize(Stream stream)
|
||||
{
|
||||
var rns = new ResourceNameString();
|
||||
|
||||
rns.Length = stream.ReadByteValue();
|
||||
rns.Value = stream.ReadChars(rns.Length, Encoding.ASCII);
|
||||
|
||||
return rns;
|
||||
}
|
||||
|
||||
public static ResourceNameString Deserialize(byte[] content, ref int offset)
|
||||
{
|
||||
var rns = new ResourceNameString();
|
||||
|
||||
rns.Length = content.ReadByte(ref offset);
|
||||
rns.Value = Encoding.ASCII.GetChars(content, offset, rns.Length); offset += rns.Length;
|
||||
|
||||
return rns;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// A table of resources for this type
|
||||
/// </summary>
|
||||
public class NEResourceTableEntry
|
||||
public class ResourceTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// File offset to the contents of the resource data,
|
||||
@@ -45,9 +44,9 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
/// </summary>
|
||||
public ushort Usage;
|
||||
|
||||
public static NEResourceTableEntry Deserialize(Stream stream)
|
||||
public static ResourceTableEntry Deserialize(Stream stream)
|
||||
{
|
||||
var ni = new NEResourceTableEntry();
|
||||
var ni = new ResourceTableEntry();
|
||||
|
||||
ni.Offset = stream.ReadUInt16();
|
||||
ni.Length = stream.ReadUInt16();
|
||||
@@ -59,9 +58,9 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
return ni;
|
||||
}
|
||||
|
||||
public static NEResourceTableEntry Deserialize(byte[] content, ref int offset)
|
||||
public static ResourceTableEntry Deserialize(byte[] content, ref int offset)
|
||||
{
|
||||
var ni = new NEResourceTableEntry();
|
||||
var ni = new ResourceTableEntry();
|
||||
|
||||
ni.Offset = content.ReadUInt16(ref offset);
|
||||
ni.Length = content.ReadUInt16(ref offset);
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// Resource type information block
|
||||
@@ -31,7 +30,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
/// <summary>
|
||||
/// Reserved.
|
||||
/// </summary>
|
||||
public NEResourceTableEntry[] ResourceTable;
|
||||
public ResourceTableEntry[] ResourceTable;
|
||||
|
||||
public static ResourceTypeInformationBlock Deserialize(Stream stream)
|
||||
{
|
||||
@@ -41,10 +40,10 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
rtib.ResourceCount = stream.ReadUInt16();
|
||||
rtib.Reserved = stream.ReadUInt32();
|
||||
|
||||
rtib.ResourceTable = new NEResourceTableEntry[rtib.ResourceCount];
|
||||
rtib.ResourceTable = new ResourceTableEntry[rtib.ResourceCount];
|
||||
for (int i = 0; i < rtib.ResourceCount; i++)
|
||||
{
|
||||
rtib.ResourceTable[i] = NEResourceTableEntry.Deserialize(stream);
|
||||
rtib.ResourceTable[i] = ResourceTableEntry.Deserialize(stream);
|
||||
}
|
||||
|
||||
return rtib;
|
||||
@@ -58,10 +57,10 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
rtib.ResourceCount = content.ReadUInt16(ref offset);
|
||||
rtib.Reserved = content.ReadUInt32(ref offset);
|
||||
|
||||
rtib.ResourceTable = new NEResourceTableEntry[rtib.ResourceCount];
|
||||
rtib.ResourceTable = new ResourceTableEntry[rtib.ResourceCount];
|
||||
for (int i = 0; i < rtib.ResourceCount; i++)
|
||||
{
|
||||
rtib.ResourceTable[i] = NEResourceTableEntry.Deserialize(content, ref offset);
|
||||
rtib.ResourceTable[i] = ResourceTableEntry.Deserialize(content, ref offset);
|
||||
}
|
||||
|
||||
return rtib;
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// The segment table contains an entry for each segment in the executable
|
||||
@@ -10,7 +9,7 @@ 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>
|
||||
public class NESegmentTableEntry
|
||||
public class SegmentTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Logical-sector offset (n byte) to the contents of the segment
|
||||
@@ -35,9 +34,9 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
/// </summary>
|
||||
public ushort MinimumAllocation;
|
||||
|
||||
public static NESegmentTableEntry Deserialize(Stream stream)
|
||||
public static SegmentTableEntry Deserialize(Stream stream)
|
||||
{
|
||||
var nste = new NESegmentTableEntry();
|
||||
var nste = new SegmentTableEntry();
|
||||
|
||||
nste.StartFileSector = stream.ReadUInt16();
|
||||
nste.BytesInFile = stream.ReadUInt16();
|
||||
@@ -47,9 +46,9 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
return nste;
|
||||
}
|
||||
|
||||
public static NESegmentTableEntry Deserialize(byte[] content, ref int offset)
|
||||
public static SegmentTableEntry Deserialize(byte[] content, ref int offset)
|
||||
{
|
||||
var nste = new NESegmentTableEntry();
|
||||
var nste = new SegmentTableEntry();
|
||||
|
||||
nste.StartFileSector = content.ReadUInt16(ref offset);
|
||||
nste.BytesInFile = content.ReadUInt16(ref offset);
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Headers
|
||||
{
|
||||
/// <summary>
|
||||
/// The NE header is a relatively large structure with multiple characteristics.
|
||||
233
BurnOutSharp/ExecutableType/Microsoft/NE/NewExecutable.cs
Normal file
233
BurnOutSharp/ExecutableType/Microsoft/NE/NewExecutable.cs
Normal file
@@ -0,0 +1,233 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.MZ.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE.Headers;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.NE
|
||||
{
|
||||
/// <summary>
|
||||
/// The WIN-NE executable format, designed for Windows 3.x, was the "NE", or "New Executable" format.
|
||||
/// Again, a 16bit format, it alleviated the maximum size restrictions that the MZ format had.
|
||||
/// </summary>
|
||||
public class NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// Value determining if the executable is initialized or not
|
||||
/// </summary>
|
||||
public bool Initialized { get; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Source array that the executable was parsed from
|
||||
/// </summary>
|
||||
private readonly byte[] _sourceArray = null;
|
||||
|
||||
/// <summary>
|
||||
/// Source stream that the executable was parsed from
|
||||
/// </summary>
|
||||
private readonly Stream _sourceStream = null;
|
||||
|
||||
#region Headers
|
||||
|
||||
/// <summary>
|
||||
/// he DOS stub is a valid MZ exe.
|
||||
/// This enables the develper to package both an MS-DOS and Win16 version of the program,
|
||||
/// but normally just prints "This Program requires Microsoft Windows".
|
||||
/// The e_lfanew field (offset 0x3C) points to the NE header.
|
||||
// </summary>
|
||||
public MSDOSExecutableHeader DOSStubHeader;
|
||||
|
||||
/// <summary>
|
||||
/// The NE header is a relatively large structure with multiple characteristics.
|
||||
/// Because of the age of the format some items are unclear in meaning.
|
||||
/// </summary>
|
||||
public NewExecutableHeader NewExecutableHeader;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tables
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
// TODO: Add more and more parts of a standard NE executable, not just the header
|
||||
// TODO: Tables? What about the tables?
|
||||
// TODO: Implement the rest of the structures found at http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm
|
||||
// (Left off at RESIDENT-NAME TABLE)
|
||||
|
||||
/// <summary>
|
||||
/// Create a NewExecutable object from a stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream representing a file</param>
|
||||
/// <remarks>
|
||||
/// This constructor assumes that the stream is already in the correct position to start parsing
|
||||
/// </remarks>
|
||||
public NewExecutable(Stream stream)
|
||||
{
|
||||
if (stream == null || !stream.CanRead || !stream.CanSeek)
|
||||
return;
|
||||
|
||||
this.Initialized = Deserialize(stream);
|
||||
this._sourceStream = stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a NewExecutable object from a byte array
|
||||
/// </summary>
|
||||
/// <param name="fileContent">Byte array representing a file</param>
|
||||
/// <param name="offset">Positive offset representing the current position in the array</param>
|
||||
public NewExecutable(byte[] fileContent, int offset)
|
||||
{
|
||||
if (fileContent == null || fileContent.Length == 0 || offset < 0)
|
||||
return;
|
||||
|
||||
this.Initialized = Deserialize(fileContent, offset);
|
||||
this._sourceArray = fileContent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize a NewExecutable object from a stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream representing a file</param>
|
||||
private bool Deserialize(Stream stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Attempt to read the DOS header first
|
||||
this.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream);
|
||||
stream.Seek(this.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
|
||||
if (this.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
|
||||
return false;
|
||||
|
||||
// If the new header address is invalid for the file, it's not a NE
|
||||
if (this.DOSStubHeader.NewExeHeaderAddr >= stream.Length)
|
||||
return false;
|
||||
|
||||
// Then attempt to read the NE header
|
||||
this.NewExecutableHeader = NewExecutableHeader.Deserialize(stream);
|
||||
if (this.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
|
||||
return false;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Console.WriteLine($"Errored out on a file: {ex}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize a NewExecutable object from a byte array
|
||||
/// </summary>
|
||||
/// <param name="fileContent">Byte array representing a file</param>
|
||||
/// <param name="offset">Positive offset representing the current position in the array</param>
|
||||
private bool Deserialize(byte[] content, int offset)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Attempt to read the DOS header first
|
||||
this.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, ref offset);
|
||||
offset = this.DOSStubHeader.NewExeHeaderAddr;
|
||||
if (this.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
|
||||
return false;
|
||||
|
||||
// If the new header address is invalid for the file, it's not a PE
|
||||
if (this.DOSStubHeader.NewExeHeaderAddr >= content.Length)
|
||||
return false;
|
||||
|
||||
// Then attempt to read the NE header
|
||||
this.NewExecutableHeader = NewExecutableHeader.Deserialize(content, ref offset);
|
||||
if (this.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Console.WriteLine($"Errored out on a file: {ex}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Read an arbitrary range from the source
|
||||
/// </summary>
|
||||
/// <param name="rangeStart">The start of where to read data from, -1 means start of source</param>
|
||||
/// <param name="length">How many bytes to read, -1 means read until end</param>
|
||||
/// <returns></returns>
|
||||
public byte[] ReadArbitraryRange(int rangeStart = -1, int length = -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
// If we have a source stream, use that
|
||||
if (this._sourceStream != null)
|
||||
return ReadArbitraryRangeFromSourceStream(rangeStart, length);
|
||||
|
||||
// If we have a source array, use that
|
||||
if (this._sourceArray != null)
|
||||
return ReadArbitraryRangeFromSourceArray(rangeStart, length);
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// TODO: How to handle this differently?
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an arbitrary range from the stream source, if possible
|
||||
/// </summary>
|
||||
/// <param name="rangeStart">The start of where to read data from, -1 means start of source</param>
|
||||
/// <param name="length">How many bytes to read, -1 means read until end</param>
|
||||
/// <returns></returns>
|
||||
private byte[] ReadArbitraryRangeFromSourceStream(int rangeStart, int length)
|
||||
{
|
||||
lock (this._sourceStream)
|
||||
{
|
||||
int startingIndex = (int)Math.Max(rangeStart, 0);
|
||||
int readLength = (int)Math.Min(length == -1 ? length = Int32.MaxValue : length, this._sourceStream.Length);
|
||||
|
||||
long originalPosition = this._sourceStream.Position;
|
||||
this._sourceStream.Seek(startingIndex, SeekOrigin.Begin);
|
||||
byte[] sectionData = this._sourceStream.ReadBytes(readLength);
|
||||
this._sourceStream.Seek(originalPosition, SeekOrigin.Begin);
|
||||
return sectionData;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an arbitrary range from the array source, if possible
|
||||
/// </summary>
|
||||
/// <param name="rangeStart">The start of where to read data from, -1 means start of source</param>
|
||||
/// <param name="length">How many bytes to read, -1 means read until end</param>
|
||||
/// <returns></returns>
|
||||
private byte[] ReadArbitraryRangeFromSourceArray(int rangeStart, int length)
|
||||
{
|
||||
int startingIndex = (int)Math.Max(rangeStart, 0);
|
||||
int readLength = (int)Math.Min(length == -1 ? length = Int32.MaxValue : length, this._sourceArray.Length);
|
||||
|
||||
try
|
||||
{
|
||||
return this._sourceArray.ReadBytes(ref startingIndex, readLength);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Just absorb errors for now
|
||||
// TODO: Investigate why and when this would be hit
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE.Entries;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// The resident-name table follows the resource table, and contains this
|
||||
/// module's name string and resident exported procedure name strings. The
|
||||
/// first string in this table is this module's name. These name strings
|
||||
/// are case-sensitive and are not null-terminated.
|
||||
/// </summary>
|
||||
public class ResidentNameTable
|
||||
{
|
||||
/// <summary>
|
||||
/// The first string in this table is this module's name.
|
||||
/// These name strings are case-sensitive and are not null-terminated.
|
||||
/// </summary>
|
||||
public ResidentNameTableEntry[] NameTableEntries;
|
||||
|
||||
public static ResidentNameTable Deserialize(Stream stream)
|
||||
{
|
||||
var rnt = new ResidentNameTable();
|
||||
|
||||
var nameTableEntries = new List<ResidentNameTableEntry>();
|
||||
while (true)
|
||||
{
|
||||
var rnte = ResidentNameTableEntry.Deserialize(stream);
|
||||
if (rnte == null || rnte.Length == 0)
|
||||
break;
|
||||
|
||||
nameTableEntries.Add(rnte);
|
||||
}
|
||||
|
||||
rnt.NameTableEntries = nameTableEntries.ToArray();
|
||||
|
||||
return rnt;
|
||||
}
|
||||
|
||||
public static ResidentNameTable Deserialize(byte[] content, ref int offset)
|
||||
{
|
||||
var rnt = new ResidentNameTable();
|
||||
|
||||
var nameTableEntries = new List<ResidentNameTableEntry>();
|
||||
while (true)
|
||||
{
|
||||
var rnte = ResidentNameTableEntry.Deserialize(content, ref offset);
|
||||
if (rnte == null || rnte.Length == 0)
|
||||
break;
|
||||
|
||||
nameTableEntries.Add(rnte);
|
||||
}
|
||||
|
||||
rnt.NameTableEntries = nameTableEntries.ToArray();
|
||||
|
||||
return rnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Entries;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE.Entries;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// The resource table follows the segment table and contains entries for
|
||||
@@ -16,7 +15,7 @@ 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>
|
||||
public class NEResourceTable
|
||||
public class ResourceTable
|
||||
{
|
||||
/// <summary>
|
||||
/// Alignment shift count for resource data.
|
||||
@@ -33,13 +32,13 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
/// resource table. Note that these strings are NOT null terminated and
|
||||
/// are case sensitive.
|
||||
/// </summary>
|
||||
public NEResourceNameString[] TypeAndNameStrings;
|
||||
public ResourceNameString[] TypeAndNameStrings;
|
||||
|
||||
public static NEResourceTable Deserialize(Stream stream)
|
||||
public static ResourceTable Deserialize(Stream stream)
|
||||
{
|
||||
var nrt = new NEResourceTable();
|
||||
var rt = new ResourceTable();
|
||||
|
||||
nrt.AlignmentShiftCount = stream.ReadUInt16();
|
||||
rt.AlignmentShiftCount = stream.ReadUInt16();
|
||||
var typeInformationBlocks = new List<ResourceTypeInformationBlock>();
|
||||
while (true)
|
||||
{
|
||||
@@ -50,28 +49,28 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
typeInformationBlocks.Add(block);
|
||||
}
|
||||
|
||||
nrt.TypeInformationBlocks = typeInformationBlocks.ToArray();
|
||||
rt.TypeInformationBlocks = typeInformationBlocks.ToArray();
|
||||
|
||||
var typeAndNameStrings = new List<NEResourceNameString>();
|
||||
var typeAndNameStrings = new List<ResourceNameString>();
|
||||
while (true)
|
||||
{
|
||||
var str = NEResourceNameString.Deserialize(stream);
|
||||
var str = ResourceNameString.Deserialize(stream);
|
||||
if (str.Length == 0)
|
||||
break;
|
||||
|
||||
typeAndNameStrings.Add(str);
|
||||
}
|
||||
|
||||
nrt.TypeAndNameStrings = typeAndNameStrings.ToArray();
|
||||
rt.TypeAndNameStrings = typeAndNameStrings.ToArray();
|
||||
|
||||
return nrt;
|
||||
return rt;
|
||||
}
|
||||
|
||||
public static NEResourceTable Deserialize(byte[] content, ref int offset)
|
||||
public static ResourceTable Deserialize(byte[] content, ref int offset)
|
||||
{
|
||||
var nrt = new NEResourceTable();
|
||||
var rt = new ResourceTable();
|
||||
|
||||
nrt.AlignmentShiftCount = content.ReadUInt16(ref offset);
|
||||
rt.AlignmentShiftCount = content.ReadUInt16(ref offset);
|
||||
var typeInformationBlocks = new List<ResourceTypeInformationBlock>();
|
||||
while (true)
|
||||
{
|
||||
@@ -82,21 +81,21 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
typeInformationBlocks.Add(block);
|
||||
}
|
||||
|
||||
nrt.TypeInformationBlocks = typeInformationBlocks.ToArray();
|
||||
rt.TypeInformationBlocks = typeInformationBlocks.ToArray();
|
||||
|
||||
var typeAndNameStrings = new List<NEResourceNameString>();
|
||||
var typeAndNameStrings = new List<ResourceNameString>();
|
||||
while (true)
|
||||
{
|
||||
var str = NEResourceNameString.Deserialize(content, ref offset);
|
||||
var str = ResourceNameString.Deserialize(content, ref offset);
|
||||
if (str.Length == 0)
|
||||
break;
|
||||
|
||||
typeAndNameStrings.Add(str);
|
||||
}
|
||||
|
||||
nrt.TypeAndNameStrings = typeAndNameStrings.ToArray();
|
||||
rt.TypeAndNameStrings = typeAndNameStrings.ToArray();
|
||||
|
||||
return nrt;
|
||||
return rt;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Headers;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
{
|
||||
/// <summary>
|
||||
/// The WIN-NE executable format, designed for Windows 3.x, was the "NE", or "New Executable" format.
|
||||
/// Again, a 16bit format, it alleviated the maximum size restrictions that the MZ format had.
|
||||
/// </summary>
|
||||
public class NewExecutable
|
||||
{
|
||||
#region Headers
|
||||
|
||||
/// <summary>
|
||||
/// he DOS stub is a valid MZ exe.
|
||||
/// This enables the develper to package both an MS-DOS and Win16 version of the program,
|
||||
/// but normally just prints "This Program requires Microsoft Windows".
|
||||
/// The e_lfanew field (offset 0x3C) points to the NE header.
|
||||
// </summary>
|
||||
public MSDOSExecutableHeader DOSStubHeader;
|
||||
|
||||
/// <summary>
|
||||
/// The NE header is a relatively large structure with multiple characteristics.
|
||||
/// Because of the age of the format some items are unclear in meaning.
|
||||
/// </summary>
|
||||
public NewExecutableHeader NewExecutableHeader;
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Add more and more parts of a standard NE executable, not just the header
|
||||
// TODO: Tables? What about the tables?
|
||||
// TODO: Implement the rest of the structures found at http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm
|
||||
// (Left off at RESIDENT-NAME TABLE)
|
||||
|
||||
public static NewExecutable Deserialize(Stream stream)
|
||||
{
|
||||
NewExecutable nex = new NewExecutable();
|
||||
|
||||
try
|
||||
{
|
||||
// Attempt to read the DOS header first
|
||||
nex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream);
|
||||
stream.Seek(nex.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
|
||||
if (nex.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
|
||||
return null;
|
||||
|
||||
// If the new header address is invalid for the file, it's not a NE
|
||||
if (nex.DOSStubHeader.NewExeHeaderAddr >= stream.Length)
|
||||
return null;
|
||||
|
||||
// Then attempt to read the NE header
|
||||
nex.NewExecutableHeader = NewExecutableHeader.Deserialize(stream);
|
||||
if (nex.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
|
||||
return null;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Console.WriteLine($"Errored out on a file: {ex}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return nex;
|
||||
}
|
||||
|
||||
public static NewExecutable Deserialize(byte[] content, int offset)
|
||||
{
|
||||
NewExecutable nex = new NewExecutable();
|
||||
|
||||
try
|
||||
{
|
||||
// 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;
|
||||
|
||||
// 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)
|
||||
{
|
||||
//Console.WriteLine($"Errored out on a file: {ex}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return nex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// The base relocation table is divided into blocks.
|
||||
/// Each block represents the base relocations for a 4K page.
|
||||
/// Each block must start on a 32-bit boundary.
|
||||
/// </summary>
|
||||
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#base-relocation-block</remarks>
|
||||
public class BaseRelocationBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// The image base plus the page RVA is added to each offset to create the VA where the base relocation must be applied.
|
||||
/// </summary>
|
||||
public uint PageRVA;
|
||||
|
||||
/// <summary>
|
||||
/// The total number of bytes in the base relocation block, including the Page RVA and Block Size fields and the Type/Offset fields that follow.
|
||||
/// </summary>
|
||||
public uint BlockSize;
|
||||
|
||||
public static BaseRelocationBlock Deserialize(Stream stream)
|
||||
{
|
||||
var brb = new BaseRelocationBlock();
|
||||
|
||||
brb.PageRVA = stream.ReadUInt32();
|
||||
brb.BlockSize = stream.ReadUInt32();
|
||||
|
||||
// TODO: Read in the type/offset field entries
|
||||
|
||||
return brb;
|
||||
}
|
||||
|
||||
public static BaseRelocationBlock Deserialize(byte[] content, ref int offset)
|
||||
{
|
||||
var brb = new BaseRelocationBlock();
|
||||
|
||||
brb.PageRVA = content.ReadUInt32(ref offset);
|
||||
brb.BlockSize = content.ReadUInt32(ref offset);
|
||||
|
||||
// TODO: Read in the type/offset field entries
|
||||
|
||||
return brb;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Tools;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// Each entry in the export address table is a field that uses one of two formats in the following table.
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// Each entry in the export address table is a field that uses one of two formats in the following table.
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// Each entry in the hint/name table has the following format
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// Each import address entry has the following format
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// Each import directory entry has the following format
|
||||
@@ -2,10 +2,10 @@ using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// Each Resource Data entry describes an actual unit of raw data in the Resource Data area.
|
||||
@@ -33,6 +33,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
if (Data == null || codePage < 0)
|
||||
return string.Empty;
|
||||
|
||||
// Try to convert to UTF-8 first
|
||||
try
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
@@ -40,11 +41,17 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
byte[] convertedData = Encoding.Convert(originalEncoding, Encoding.UTF8, Data);
|
||||
return Encoding.UTF8.GetString(convertedData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch { }
|
||||
|
||||
// Then try to read direct as ASCII
|
||||
try
|
||||
{
|
||||
return Encoding.ASCII.GetString(Data);
|
||||
}
|
||||
|
||||
catch { }
|
||||
|
||||
// If both encodings fail, then just return an empty string
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// The resource directory string area consists of Unicode strings, which are word-aligned.
|
||||
@@ -1,10 +1,9 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Tables;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
|
||||
{
|
||||
/// <summary>
|
||||
/// The directory entries make up the rows of a table.
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Headers
|
||||
{
|
||||
public class CommonObjectFileFormatHeader
|
||||
{
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Headers
|
||||
{
|
||||
public class DataDirectoryHeader
|
||||
{
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Headers
|
||||
{
|
||||
/// <summary>
|
||||
/// Every image file has an optional header that provides information to the loader.
|
||||
@@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Headers
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Headers
|
||||
{
|
||||
/// <summary>
|
||||
/// Each row of the section table is, in effect, a section header.
|
||||
@@ -22,6 +23,35 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Headers
|
||||
/// Long names in object files are truncated if they are emitted to an executable file.
|
||||
/// </summary>
|
||||
public byte[] Name;
|
||||
|
||||
/// <summary>
|
||||
/// Section name as a string, trimming any trailing null bytes
|
||||
/// </summary>
|
||||
public string NameString
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Name == null || this.Name.Length == 0)
|
||||
return null;
|
||||
|
||||
// First try decoding as UTF-8
|
||||
try
|
||||
{
|
||||
return Encoding.UTF8.GetString(this.Name).TrimEnd('\0');
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Then try decoding as ASCII
|
||||
try
|
||||
{
|
||||
return Encoding.ASCII.GetString(this.Name).TrimEnd('\0');
|
||||
}
|
||||
catch { }
|
||||
|
||||
// If it fails, return null
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The total size of the section when loaded into memory.
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Sections;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.MZ.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Sections;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE
|
||||
{
|
||||
/// <summary>
|
||||
/// The PE file header consists of a Microsoft MS-DOS stub, the PE signature, the COFF file header, and an optional header.
|
||||
@@ -15,6 +15,21 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
/// </summary>
|
||||
public class PortableExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// Value determining if the executable is initialized or not
|
||||
/// </summary>
|
||||
public bool Initialized { get; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Source array that the executable was parsed from
|
||||
/// </summary>
|
||||
private readonly byte[] _sourceArray = null;
|
||||
|
||||
/// <summary>
|
||||
/// Source stream that the executable was parsed from
|
||||
/// </summary>
|
||||
private readonly Stream _sourceStream = null;
|
||||
|
||||
#region Headers
|
||||
|
||||
/// <summary>
|
||||
@@ -25,7 +40,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
/// At location 0x3c, the stub has the file offset to the PE signature.
|
||||
/// 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>
|
||||
/// </summary>
|
||||
public MSDOSExecutableHeader DOSStubHeader;
|
||||
|
||||
/// <summary>
|
||||
@@ -55,6 +70,13 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
|
||||
#region Tables
|
||||
|
||||
/// <summary>
|
||||
/// The .debug section is used in object files to contain compiler-generated debug information and in image files to contain
|
||||
/// all of the debug information that is generated.
|
||||
/// This section describes the packaging of debug information in object and image files.
|
||||
/// </summary>
|
||||
public DebugSection DebugDirectory;
|
||||
|
||||
/// <summary>
|
||||
/// The export data section, named .edata, contains information about symbols that other images can access through dynamic linking.
|
||||
/// Exported symbols are generally found in DLLs, but DLLs can also import symbols.
|
||||
@@ -66,6 +88,12 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
/// </summary>
|
||||
public ImportDataSection ImportTable;
|
||||
|
||||
/// <summary>
|
||||
/// The base relocation table contains entries for all base relocations in the image.
|
||||
/// The Base Relocation Table field in the optional header data directories gives the number of bytes in the base relocation table.
|
||||
/// </summary>
|
||||
public RelocationSection RelocationTable;
|
||||
|
||||
/// <summary>
|
||||
/// Resources are indexed by a multiple-level binary-sorted tree structure.
|
||||
/// The general design can incorporate 2**31 levels.
|
||||
@@ -87,7 +115,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
// X - .edata *1 protection Export tables
|
||||
// X - .idata *1 protection Import tables
|
||||
// X - .rdata 11 protections Read-only initialized data
|
||||
// - .rsrc *1 protection Resource directory [Mostly taken care of, last protection needs research]
|
||||
// - .rsrc *1 protection Resource directory [TODO: Mostly taken care of, last protection needs research]
|
||||
// X - .text 6 protections Executable code (free format)
|
||||
// Y - .tls *1 protection Thread-local storage (object only)
|
||||
//
|
||||
@@ -97,7 +125,11 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
// X - .grand *1 protection CD-Cops / DVD-Cops
|
||||
// X - .init *1 protection SolidShield
|
||||
// - .pec2 *1 protection PE Compact [Unconfirmed]
|
||||
// - .NOS0 *1 protection UPX (NOS Variant)
|
||||
// - .NOS1 *1 protection UPX (NOS Variant)
|
||||
// X - .txt2 *1 protection SafeDisc
|
||||
// - .UPX0 *1 protection UPX
|
||||
// - .UPX1 *1 protection UPX
|
||||
//
|
||||
// Here is a list of non-standard sections whose data is not read by various protections:
|
||||
// - .brick 1 protection StarForce
|
||||
@@ -108,15 +140,11 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
// - .ldr 1 protection 3PLock
|
||||
// - .ldt 1 protection 3PLock
|
||||
// - .nicode 1 protection Armadillo
|
||||
// - .NOS0 1 protection UPX (NOS Variant) [Used as endpoint]
|
||||
// - .NOS1 1 protection UPX (NOS Variant) [Used as endpoint]
|
||||
// - .pec1 1 protection PE Compact
|
||||
// - .securom 1 protection SecuROM
|
||||
// - .sforce 1 protection StarForce
|
||||
// - stxt371 1 protection SafeDisc
|
||||
// - stxt774 1 protection SafeDisc
|
||||
// - .UPX0 1 protection UPX [Used as endpoint]
|
||||
// - .UPX1 1 protection UPX [Used as endpoint]
|
||||
// - .vob.pcd 1 protection VOB ProtectCD
|
||||
// - _winzip_ 1 protection WinZip SFX
|
||||
// - XPROT 1 protection JoWood
|
||||
@@ -152,6 +180,252 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Create a PortableExecutable object from a stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream representing a file</param>
|
||||
/// <remarks>
|
||||
/// This constructor assumes that the stream is already in the correct position to start parsing
|
||||
/// </remarks>
|
||||
public PortableExecutable(Stream stream)
|
||||
{
|
||||
if (stream == null || !stream.CanRead || !stream.CanSeek)
|
||||
return;
|
||||
|
||||
this._sourceStream = stream;
|
||||
this.Initialized = Deserialize(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a PortableExecutable object from a byte array
|
||||
/// </summary>
|
||||
/// <param name="fileContent">Byte array representing a file</param>
|
||||
/// <param name="offset">Positive offset representing the current position in the array</param>
|
||||
public PortableExecutable(byte[] fileContent, int offset)
|
||||
{
|
||||
if (fileContent == null || fileContent.Length == 0 || offset < 0)
|
||||
return;
|
||||
|
||||
this._sourceArray = fileContent;
|
||||
this.Initialized = Deserialize(fileContent, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize a PortableExecutable object from a stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream representing a file</param>
|
||||
private bool Deserialize(Stream stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Attempt to read the DOS header first
|
||||
this.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream); stream.Seek(this.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
|
||||
if (this.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
|
||||
return false;
|
||||
|
||||
// If the new header address is invalid for the file, it's not a PE
|
||||
if (this.DOSStubHeader.NewExeHeaderAddr >= stream.Length)
|
||||
return false;
|
||||
|
||||
// Then attempt to read the PE header
|
||||
this.ImageFileHeader = CommonObjectFileFormatHeader.Deserialize(stream);
|
||||
if (this.ImageFileHeader.Signature != Constants.IMAGE_NT_SIGNATURE)
|
||||
return false;
|
||||
|
||||
// If the optional header is supposed to exist, read that as well
|
||||
if (this.ImageFileHeader.SizeOfOptionalHeader > 0)
|
||||
this.OptionalHeader = OptionalHeader.Deserialize(stream);
|
||||
|
||||
// Then read in the section table
|
||||
this.SectionTable = new SectionHeader[this.ImageFileHeader.NumberOfSections];
|
||||
for (int i = 0; i < this.ImageFileHeader.NumberOfSections; i++)
|
||||
{
|
||||
this.SectionTable[i] = SectionHeader.Deserialize(stream);
|
||||
}
|
||||
|
||||
#region Structured Tables
|
||||
|
||||
// // Debug Section
|
||||
// var table = this.GetLastSection(".debug", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
|
||||
// this.DebugSection = DebugSection.Deserialize(stream, this.SectionTable);
|
||||
// }
|
||||
|
||||
// // Export Table
|
||||
// var table = this.GetLastSection(".edata", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
|
||||
// this.ExportTable = ExportDataSection.Deserialize(stream, this.SectionTable);
|
||||
// }
|
||||
|
||||
// // Import Table
|
||||
// table = this.GetSection(".idata", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
|
||||
// this.ImportTable = ImportDataSection.Deserialize(stream, this.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0);
|
||||
// }
|
||||
|
||||
// // Relocation Section
|
||||
// var table = this.GetLastSection(".reloc", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
|
||||
// this.RelocationTable = RelocationSection.Deserialize(stream);
|
||||
// }
|
||||
|
||||
// Resource Table
|
||||
var table = this.GetLastSection(".rsrc", true);
|
||||
if (table != null && table.VirtualSize > 0)
|
||||
{
|
||||
stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
|
||||
this.ResourceSection = ResourceSection.Deserialize(stream, this.SectionTable);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Freeform Sections
|
||||
|
||||
// Data Section
|
||||
this.DataSectionRaw = this.ReadRawSection(".data", force: true, first: false) ?? this.ReadRawSection("DATA", force: true, first: false);
|
||||
|
||||
// Export Table
|
||||
this.ExportDataSectionRaw = this.ReadRawSection(".edata", force: true, first: false);
|
||||
|
||||
// Import Table
|
||||
this.ImportDataSectionRaw = this.ReadRawSection(".idata", force: true, first: false);
|
||||
|
||||
// Resource Data Section
|
||||
this.ResourceDataSectionRaw = this.ReadRawSection(".rdata", force: true, first: false);
|
||||
|
||||
// Text Section
|
||||
this.TextSectionRaw = this.ReadRawSection(".text", force: true, first: false);
|
||||
|
||||
#endregion
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Console.WriteLine($"Errored out on a file: {ex}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize a PortableExecutable object from a byte array
|
||||
/// </summary>
|
||||
/// <param name="fileContent">Byte array representing a file</param>
|
||||
/// <param name="offset">Positive offset representing the current position in the array</param>
|
||||
private bool Deserialize(byte[] content, int offset)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Attempt to read the DOS header first
|
||||
this.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, ref offset);
|
||||
offset = this.DOSStubHeader.NewExeHeaderAddr;
|
||||
if (this.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
|
||||
return false;
|
||||
|
||||
// If the new header address is invalid for the file, it's not a PE
|
||||
if (this.DOSStubHeader.NewExeHeaderAddr >= content.Length)
|
||||
return false;
|
||||
|
||||
// Then attempt to read the PE header
|
||||
this.ImageFileHeader = CommonObjectFileFormatHeader.Deserialize(content, ref offset);
|
||||
if (this.ImageFileHeader.Signature != Constants.IMAGE_NT_SIGNATURE)
|
||||
return false;
|
||||
|
||||
// If the optional header is supposed to exist, read that as well
|
||||
if (this.ImageFileHeader.SizeOfOptionalHeader > 0)
|
||||
this.OptionalHeader = OptionalHeader.Deserialize(content, ref offset);
|
||||
|
||||
// Then read in the section table
|
||||
this.SectionTable = new SectionHeader[this.ImageFileHeader.NumberOfSections];
|
||||
for (int i = 0; i < this.ImageFileHeader.NumberOfSections; i++)
|
||||
{
|
||||
this.SectionTable[i] = SectionHeader.Deserialize(content, ref offset);
|
||||
}
|
||||
|
||||
#region Structured Tables
|
||||
|
||||
// // Debug Section
|
||||
// var table = this.GetLastSection(".debug", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// int tableAddress = (int)table.PointerToRawData;
|
||||
// this.DebugSection = DebugSection.Deserialize(content, ref tableAddress, this.SectionTable);
|
||||
// }
|
||||
|
||||
// // Export Table
|
||||
// var table = this.GetLastSection(".edata", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// int tableAddress = (int)table.PointerToRawData;
|
||||
// this.ExportTable = ExportDataSection.Deserialize(content, ref tableAddress, this.SectionTable);
|
||||
// }
|
||||
|
||||
// // Import Table
|
||||
// table = this.GetSection(".idata", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// int tableAddress = (int)table.PointerToRawData;
|
||||
// this.ImportTable = ImportDataSection.Deserialize(content, ref tableAddress, this.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0);
|
||||
// }
|
||||
|
||||
// // Relocation Section
|
||||
// var table = this.GetLastSection(".reloc", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// int tableAddress = (int)table.PointerToRawData;
|
||||
// this.RelocationTable = RelocationSection.Deserialize(content, ref tableAddress);
|
||||
// }
|
||||
|
||||
// Resource Table
|
||||
var table = this.GetLastSection(".rsrc", true);
|
||||
if (table != null && table.VirtualSize > 0)
|
||||
{
|
||||
int tableAddress = (int)table.PointerToRawData;
|
||||
this.ResourceSection = ResourceSection.Deserialize(content, ref tableAddress, this.SectionTable);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Freeform Sections
|
||||
|
||||
// Data Section
|
||||
this.DataSectionRaw = this.ReadRawSection(".data", force: true, first: false) ?? this.ReadRawSection("DATA", force: true, first: false);
|
||||
|
||||
// Export Table
|
||||
this.ExportDataSectionRaw = this.ReadRawSection(".edata", force: true, first: false);
|
||||
|
||||
// Import Table
|
||||
this.ImportDataSectionRaw = this.ReadRawSection(".idata", force: true, first: false);
|
||||
|
||||
// Resource Data Section
|
||||
this.ResourceDataSectionRaw = this.ReadRawSection(".rdata", force: true, first: false);
|
||||
|
||||
// Text Section
|
||||
this.TextSectionRaw = this.ReadRawSection(".text", force: true, first: false);
|
||||
|
||||
#endregion
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Console.WriteLine($"Errored out on a file: {ex}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
@@ -167,13 +441,13 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
if (sectionNames == null)
|
||||
return false;
|
||||
|
||||
// If we're checking exactly, return only exact matches (with nulls trimmed)
|
||||
// If we're checking exactly, return only exact matches
|
||||
if (exact)
|
||||
return sectionNames.Any(n => n.Trim('\0').Equals(sectionName));
|
||||
return sectionNames.Any(n => n.Equals(sectionName));
|
||||
|
||||
// Otherwise, check if section name starts with the value
|
||||
else
|
||||
return sectionNames.Any(n => n.Trim('\0').StartsWith(sectionName));
|
||||
return sectionNames.Any(n => n.StartsWith(sectionName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -216,13 +490,13 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
if (SectionTable == null || !SectionTable.Any())
|
||||
return null;
|
||||
|
||||
// If we're checking exactly, return only exact matches (with nulls trimmed)
|
||||
// If we're checking exactly, return only exact matches
|
||||
if (exact)
|
||||
return SectionTable.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).Trim('\0').Equals(sectionName));
|
||||
return SectionTable.FirstOrDefault(s => s.NameString.Equals(sectionName));
|
||||
|
||||
// Otherwise, check if section name starts with the value
|
||||
else
|
||||
return SectionTable.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).Trim('\0').StartsWith(sectionName));
|
||||
return SectionTable.FirstOrDefault(s => s.NameString.StartsWith(sectionName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -239,11 +513,11 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
|
||||
// If we're checking exactly, return only exact matches (with nulls trimmed)
|
||||
if (exact)
|
||||
return SectionTable.LastOrDefault(s => Encoding.ASCII.GetString(s.Name).Trim('\0').Equals(sectionName));
|
||||
return SectionTable.LastOrDefault(s => s.NameString.Equals(sectionName));
|
||||
|
||||
// Otherwise, check if section name starts with the value
|
||||
else
|
||||
return SectionTable.LastOrDefault(s => Encoding.ASCII.GetString(s.Name).Trim('\0').StartsWith(sectionName));
|
||||
return SectionTable.LastOrDefault(s => s.NameString.StartsWith(sectionName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -255,7 +529,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
if (SectionTable == null || SectionTable.Length == 0)
|
||||
return null;
|
||||
|
||||
return SectionTable.Select(s => Encoding.ASCII.GetString(s.Name)).ToArray();
|
||||
return SectionTable.Select(s => s.NameString).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -265,7 +539,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
{
|
||||
foreach (var section in SectionTable)
|
||||
{
|
||||
string sectionName = Encoding.ASCII.GetString(section.Name).Trim('\0');
|
||||
string sectionName = section.NameString;
|
||||
int sectionAddr = (int)section.PointerToRawData;
|
||||
int sectionEnd = sectionAddr + (int)section.VirtualSize;
|
||||
Console.WriteLine($"{sectionName}: {sectionAddr} -> {sectionEnd}");
|
||||
@@ -273,50 +547,85 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the raw bytes from a section, if possible
|
||||
/// Read an arbitrary range from the source
|
||||
/// </summary>
|
||||
public byte[] ReadRawSection(Stream stream, string sectionName, bool force = false, bool first = true, int offset = 0)
|
||||
/// <param name="rangeStart">The start of where to read data from, -1 means start of source</param>
|
||||
/// <param name="length">How many bytes to read, -1 means read until end</param>
|
||||
/// <returns></returns>
|
||||
public byte[] ReadArbitraryRange(int rangeStart = -1, int length = -1)
|
||||
{
|
||||
// Special cases for non-forced, non-offset data
|
||||
if (!force && offset == 0)
|
||||
try
|
||||
{
|
||||
switch (sectionName)
|
||||
{
|
||||
case ".data":
|
||||
return DataSectionRaw;
|
||||
case ".edata":
|
||||
return ExportDataSectionRaw;
|
||||
case ".idata":
|
||||
return ImportDataSectionRaw;
|
||||
case ".rdata":
|
||||
return ResourceDataSectionRaw;
|
||||
case ".text":
|
||||
return TextSectionRaw;
|
||||
}
|
||||
}
|
||||
// If we have a source stream, use that
|
||||
if (this._sourceStream != null)
|
||||
return ReadArbitraryRangeFromSourceStream(rangeStart, length);
|
||||
|
||||
var section = first ? GetFirstSection(sectionName, true) : GetLastSection(sectionName, true);
|
||||
if (section == null)
|
||||
// If we have a source array, use that
|
||||
if (this._sourceArray != null)
|
||||
return ReadArbitraryRangeFromSourceArray(rangeStart, length);
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
|
||||
lock (stream)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
int startingIndex = (int)Math.Max(section.PointerToRawData + offset, 0);
|
||||
int readLength = (int)Math.Min(section.VirtualSize - offset, stream.Length);
|
||||
// TODO: How to handle this differently?
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
long originalPosition = stream.Position;
|
||||
stream.Seek(startingIndex, SeekOrigin.Begin);
|
||||
byte[] sectionData = stream.ReadBytes(readLength);
|
||||
stream.Seek(originalPosition, SeekOrigin.Begin);
|
||||
/// <summary>
|
||||
/// Read an arbitrary range from the stream source, if possible
|
||||
/// </summary>
|
||||
/// <param name="rangeStart">The start of where to read data from, -1 means start of source</param>
|
||||
/// <param name="length">How many bytes to read, -1 means read until end</param>
|
||||
/// <returns></returns>
|
||||
private byte[] ReadArbitraryRangeFromSourceStream(int rangeStart, int length)
|
||||
{
|
||||
lock (this._sourceStream)
|
||||
{
|
||||
int startingIndex = (int)Math.Max(rangeStart, 0);
|
||||
int readLength = (int)Math.Min(length == -1 ? length = Int32.MaxValue : length, this._sourceStream.Length);
|
||||
|
||||
long originalPosition = this._sourceStream.Position;
|
||||
this._sourceStream.Seek(startingIndex, SeekOrigin.Begin);
|
||||
byte[] sectionData = this._sourceStream.ReadBytes(readLength);
|
||||
this._sourceStream.Seek(originalPosition, SeekOrigin.Begin);
|
||||
return sectionData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an arbitrary range from the array source, if possible
|
||||
/// </summary>
|
||||
/// <param name="rangeStart">The start of where to read data from, -1 means start of source</param>
|
||||
/// <param name="length">How many bytes to read, -1 means read until end</param>
|
||||
/// <returns></returns>
|
||||
private byte[] ReadArbitraryRangeFromSourceArray(int rangeStart, int length)
|
||||
{
|
||||
int startingIndex = (int)Math.Max(rangeStart, 0);
|
||||
int readLength = (int)Math.Min(length == -1 ? length = Int32.MaxValue : length, this._sourceArray.Length);
|
||||
|
||||
try
|
||||
{
|
||||
return this._sourceArray.ReadBytes(ref startingIndex, readLength);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Just absorb errors for now
|
||||
// TODO: Investigate why and when this would be hit
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the raw bytes from a section, if possible
|
||||
/// </summary>
|
||||
public byte[] ReadRawSection(byte[] content, string sectionName, bool force = false, bool first = true, int offset = 0)
|
||||
/// <param name="sectionName">The name of the section to attempt to read</param>
|
||||
/// <param name="force">True to force reading the section from the underlying source, false to use cached values, if possible</param>
|
||||
/// <param name="first">True to use the first section with a matching name, false to use the last section</param>
|
||||
/// <param name="offset">Offset to start reading at, default is 0</param>
|
||||
public byte[] ReadRawSection(string sectionName, bool force = false, bool first = true, int offset = 0)
|
||||
{
|
||||
// Special cases for non-forced, non-offset data
|
||||
if (!force && offset == 0)
|
||||
@@ -336,191 +645,17 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
}
|
||||
}
|
||||
|
||||
// Get the section, if possible
|
||||
var section = first ? GetFirstSection(sectionName, true) : GetLastSection(sectionName, true);
|
||||
if (section == null)
|
||||
return null;
|
||||
|
||||
int startingIndex = (int)Math.Max(section.PointerToRawData + offset, 0);
|
||||
int readLength = (int)Math.Min(section.VirtualSize - offset, content.Length);
|
||||
|
||||
return content.ReadBytes(ref startingIndex, readLength);
|
||||
// Return the raw data from that section
|
||||
int rangeStart = (int)(section.PointerToRawData + offset);
|
||||
int rangeEnd = (int)(section.VirtualSize - offset);
|
||||
return ReadArbitraryRange(rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static PortableExecutable Deserialize(Stream stream)
|
||||
{
|
||||
PortableExecutable pex = new PortableExecutable();
|
||||
|
||||
try
|
||||
{
|
||||
// Attempt to read the DOS header first
|
||||
pex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream); stream.Seek(pex.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
|
||||
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 >= stream.Length)
|
||||
return null;
|
||||
|
||||
// Then attempt to read the PE header
|
||||
pex.ImageFileHeader = CommonObjectFileFormatHeader.Deserialize(stream);
|
||||
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(stream);
|
||||
|
||||
// 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(stream);
|
||||
}
|
||||
|
||||
#region Structured Tables
|
||||
|
||||
// // Export Table
|
||||
// var table = pex.GetLastSection(".edata", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
|
||||
// pex.ExportTable = ExportDataSection.Deserialize(stream, pex.SectionTable);
|
||||
// }
|
||||
|
||||
// // Import Table
|
||||
// table = pex.GetSection(".idata", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
|
||||
// pex.ImportTable = ImportDataSection.Deserialize(stream, pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0);
|
||||
// }
|
||||
|
||||
// Resource Table
|
||||
var table = pex.GetLastSection(".rsrc", true);
|
||||
if (table != null && table.VirtualSize > 0)
|
||||
{
|
||||
stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
|
||||
pex.ResourceSection = ResourceSection.Deserialize(stream, pex.SectionTable);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Freeform Sections
|
||||
|
||||
// Data Section
|
||||
pex.DataSectionRaw = pex.ReadRawSection(stream, ".data", force: true, first: false) ?? pex.ReadRawSection(stream, "DATA", force: true, first: false);
|
||||
|
||||
// Export Table
|
||||
pex.ExportDataSectionRaw = pex.ReadRawSection(stream, ".edata", force: true, first: false);
|
||||
|
||||
// Import Table
|
||||
pex.ImportDataSectionRaw = pex.ReadRawSection(stream, ".idata", force: true, first: false);
|
||||
|
||||
// Resource Data Section
|
||||
pex.ResourceDataSectionRaw = pex.ReadRawSection(stream, ".rdata", force: true, first: false);
|
||||
|
||||
// Text Section
|
||||
pex.TextSectionRaw = pex.ReadRawSection(stream, ".text", force: true, first: false);
|
||||
|
||||
#endregion
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Console.WriteLine($"Errored out on a file: {ex}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return pex;
|
||||
}
|
||||
|
||||
public static PortableExecutable Deserialize(byte[] content, int offset)
|
||||
{
|
||||
PortableExecutable pex = new PortableExecutable();
|
||||
|
||||
try
|
||||
{
|
||||
// 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++)
|
||||
{
|
||||
pex.SectionTable[i] = SectionHeader.Deserialize(content, ref offset);
|
||||
}
|
||||
|
||||
#region Structured Tables
|
||||
|
||||
// // Export Table
|
||||
// var table = pex.GetLastSection(".edata", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// int tableAddress = (int)table.PointerToRawData;
|
||||
// pex.ExportTable = ExportDataSection.Deserialize(content, ref tableAddress, pex.SectionTable);
|
||||
// }
|
||||
|
||||
// // Import Table
|
||||
// table = pex.GetSection(".idata", true);
|
||||
// if (table != null && table.VirtualSize > 0)
|
||||
// {
|
||||
// int tableAddress = (int)table.PointerToRawData;
|
||||
// pex.ImportTable = ImportDataSection.Deserialize(content, tableAddress, pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0);
|
||||
// }
|
||||
|
||||
// Resource Table
|
||||
var table = pex.GetLastSection(".rsrc", true);
|
||||
if (table != null && table.VirtualSize > 0)
|
||||
{
|
||||
int tableAddress = (int)table.PointerToRawData;
|
||||
pex.ResourceSection = ResourceSection.Deserialize(content, ref tableAddress, pex.SectionTable);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Freeform Sections
|
||||
|
||||
// Data Section
|
||||
pex.DataSectionRaw = pex.ReadRawSection(content, ".data", force: true, first: false) ?? pex.ReadRawSection(content, "DATA", force: true, first: false);
|
||||
|
||||
// Export Table
|
||||
pex.ExportDataSectionRaw = pex.ReadRawSection(content, ".edata", force: true, first: false);
|
||||
|
||||
// Import Table
|
||||
pex.ImportDataSectionRaw = pex.ReadRawSection(content, ".idata", force: true, first: false);
|
||||
|
||||
// Resource Data Section
|
||||
pex.ResourceDataSectionRaw = pex.ReadRawSection(content, ".rdata", force: true, first: false);
|
||||
|
||||
// Text Section
|
||||
pex.TextSectionRaw = pex.ReadRawSection(content, ".text", force: true, first: false);
|
||||
|
||||
#endregion
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Console.WriteLine($"Errored out on a file: {ex}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return pex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
|
||||
{
|
||||
/// <summary>
|
||||
/// The .debug section is used in object files to contain compiler-generated debug information and in image files to contain
|
||||
/// all of the debug information that is generated.
|
||||
/// This section describes the packaging of debug information in object and image files.
|
||||
/// </summary>
|
||||
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-debug-section</remarks>
|
||||
public class DebugSection
|
||||
{
|
||||
/// <summary>
|
||||
/// Image files contain an optional debug directory that indicates what form of debug information is present and where it is.
|
||||
/// This directory consists of an array of debug directory entries whose location and size are indicated in the image optional header.
|
||||
/// </summary>
|
||||
public DebugDirectory DebugDirectory;
|
||||
|
||||
public static DebugSection Deserialize(Stream stream)
|
||||
{
|
||||
long originalPosition = stream.Position;
|
||||
var ds = new DebugSection();
|
||||
|
||||
ds.DebugDirectory = DebugDirectory.Deserialize(stream);
|
||||
|
||||
// TODO: Read in raw debug data
|
||||
|
||||
stream.Seek(originalPosition, SeekOrigin.Begin);
|
||||
return ds;
|
||||
}
|
||||
|
||||
public static DebugSection Deserialize(byte[] content, ref int offset)
|
||||
{
|
||||
int originalPosition = offset;
|
||||
var ds = new DebugSection();
|
||||
|
||||
ds.DebugDirectory = DebugDirectory.Deserialize(content, ref offset);
|
||||
|
||||
// TODO: Read in raw debug data
|
||||
|
||||
offset = originalPosition;
|
||||
return ds;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Tables;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Sections
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
|
||||
{
|
||||
/// <summary>
|
||||
/// The .pdata section contains an array of function table entries that are used for exception handling.
|
||||
@@ -1,10 +1,10 @@
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Entries;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Tables;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Sections
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
|
||||
{
|
||||
/// <summary>
|
||||
/// The export data section, named .edata, contains information about symbols that other images can access through dynamic linking.
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Tables;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Sections
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
|
||||
{
|
||||
/// <summary>
|
||||
/// All image files that import symbols, including virtually all executable (EXE) files, have an .idata section.
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
|
||||
{
|
||||
/// <summary>
|
||||
/// The base relocation table contains entries for all base relocations in the image.
|
||||
/// The Base Relocation Table field in the optional header data directories gives the number of bytes in the base relocation table.
|
||||
/// The base relocation table is divided into blocks.
|
||||
/// Each block represents the base relocations for a 4K page.
|
||||
/// Each block must start on a 32-bit boundary.
|
||||
/// </summary>
|
||||
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-reloc-section-image-only</remarks>
|
||||
public class RelocationSection
|
||||
{
|
||||
/// <summary>
|
||||
/// The base relocation table is divided into blocks.
|
||||
/// </summary>
|
||||
public BaseRelocationBlock[] BaseRelocationTable;
|
||||
|
||||
public static RelocationSection Deserialize(Stream stream, int blockCount)
|
||||
{
|
||||
long originalPosition = stream.Position;
|
||||
|
||||
var rs = new RelocationSection();
|
||||
rs.BaseRelocationTable = new BaseRelocationBlock[blockCount];
|
||||
for (int i = 0; i < blockCount; i++)
|
||||
{
|
||||
rs.BaseRelocationTable[i] = BaseRelocationBlock.Deserialize(stream);
|
||||
}
|
||||
|
||||
stream.Seek(originalPosition, SeekOrigin.Begin);
|
||||
return rs;
|
||||
}
|
||||
|
||||
public static RelocationSection Deserialize(byte[] content, ref int offset, int blockCount)
|
||||
{
|
||||
int originalPosition = offset;
|
||||
|
||||
var rs = new RelocationSection();
|
||||
rs.BaseRelocationTable = new BaseRelocationBlock[blockCount];
|
||||
for (int i = 0; i < blockCount; i++)
|
||||
{
|
||||
rs.BaseRelocationTable[i] = BaseRelocationBlock.Deserialize(content, ref offset);
|
||||
}
|
||||
|
||||
offset = originalPosition;
|
||||
return rs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Tables;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Sections
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
|
||||
{
|
||||
/// <summary>
|
||||
/// A series of resource directory tables relates all of the levels in the following way:
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// Image files contain an optional debug directory that indicates what form of debug information is present and where it is.
|
||||
/// This directory consists of an array of debug directory entries whose location and size are indicated in the image optional header.
|
||||
/// </summary>
|
||||
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#debug-directory-image-only</remarks>
|
||||
public class DebugDirectory
|
||||
{
|
||||
/// <summary>
|
||||
/// Reserved, must be 0.
|
||||
/// </summary>
|
||||
public uint Characteristics;
|
||||
|
||||
/// <summary>
|
||||
/// The time and date that the debug data was created.
|
||||
/// </summary>
|
||||
public uint TimeDateStamp;
|
||||
|
||||
/// <summary>
|
||||
/// The major version number of the debug data format.
|
||||
/// </summary>
|
||||
public ushort MajorVersion;
|
||||
|
||||
/// <summary>
|
||||
/// The minor version number of the debug data format.
|
||||
/// </summary>
|
||||
public ushort MinorVersion;
|
||||
|
||||
/// <summary>
|
||||
/// The format of debugging information. This field enables support of multiple debuggers.
|
||||
/// </summary>
|
||||
public DebugType DebugType;
|
||||
|
||||
/// <summary>
|
||||
/// The size of the debug data (not including the debug directory itself).
|
||||
/// </summary>
|
||||
public uint SizeOfData;
|
||||
|
||||
/// <summary>
|
||||
/// The address of the debug data when loaded, relative to the image base.
|
||||
/// </summary>
|
||||
public uint AddressOfRawData;
|
||||
|
||||
/// <summary>
|
||||
/// The file pointer to the debug data.
|
||||
/// </summary>
|
||||
public uint PointerToRawData;
|
||||
|
||||
public static DebugDirectory Deserialize(Stream stream)
|
||||
{
|
||||
var dd = new DebugDirectory();
|
||||
|
||||
dd.Characteristics = stream.ReadUInt32();
|
||||
dd.TimeDateStamp = stream.ReadUInt32();
|
||||
dd.MajorVersion = stream.ReadUInt16();
|
||||
dd.MinorVersion = stream.ReadUInt16();
|
||||
dd.DebugType = (DebugType)stream.ReadUInt32();
|
||||
dd.SizeOfData = stream.ReadUInt32();
|
||||
dd.AddressOfRawData = stream.ReadUInt32();
|
||||
dd.PointerToRawData = stream.ReadUInt32();
|
||||
|
||||
return dd;
|
||||
}
|
||||
|
||||
public static DebugDirectory Deserialize(byte[] content, ref int offset)
|
||||
{
|
||||
var dd = new DebugDirectory();
|
||||
|
||||
dd.Characteristics = content.ReadUInt32(ref offset);
|
||||
dd.TimeDateStamp = content.ReadUInt32(ref offset);
|
||||
dd.MajorVersion = content.ReadUInt16(ref offset);
|
||||
dd.MinorVersion = content.ReadUInt16(ref offset);
|
||||
dd.DebugType = (DebugType)content.ReadUInt32(ref offset);
|
||||
dd.SizeOfData = content.ReadUInt32(ref offset);
|
||||
dd.AddressOfRawData = content.ReadUInt32(ref offset);
|
||||
dd.PointerToRawData = content.ReadUInt32(ref offset);
|
||||
|
||||
return dd;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// The export symbol information begins with the export directory table, which describes the remainder of the export symbol information.
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// The export ordinal table is an array of 16-bit unbiased indexes into the export address table.
|
||||
@@ -1,6 +1,6 @@
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Entries;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// The .pdata section contains an array of function table entries that are used for exception handling.
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Entries;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// One hint/name table suffices for the entire import section.
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Entries;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// The structure and content of the import address table are identical to those of the import lookup table, until the file is bound.
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Entries;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// The import information begins with the import directory table, which describes the remainder of the import information.
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// An import lookup table is an array of 32-bit numbers for PE32 or an array of 64-bit numbers for PE32+.
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Entries;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.Tables
|
||||
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// Each resource directory table has the following format.
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
@@ -18,6 +19,16 @@ namespace BurnOutSharp.FileType
|
||||
/// </summary>
|
||||
private static readonly IEnumerable<IContentCheck> contentCheckClasses = InitContentCheckClasses();
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all INEContentCheck types
|
||||
/// </summary>
|
||||
private static readonly IEnumerable<INEContentCheck> neContentCheckClasses = InitNEContentCheckClasses();
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPEContentCheck types
|
||||
/// </summary>
|
||||
private static readonly IEnumerable<IPEContentCheck> peContentCheckClasses = InitPEContentCheckClasses();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool ShouldScan(byte[] magic)
|
||||
{
|
||||
@@ -70,65 +81,104 @@ namespace BurnOutSharp.FileType
|
||||
// Files can be protected in multiple ways
|
||||
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
|
||||
|
||||
// Load the current file content
|
||||
// Load the current file content for debug only
|
||||
byte[] fileContent = null;
|
||||
try
|
||||
if (scanner.IncludeDebug)
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
try
|
||||
{
|
||||
fileContent = br.ReadBytes((int)stream.Length);
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
{
|
||||
fileContent = br.ReadBytes((int)stream.Length);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Utilities.AppendToDictionary(protections, file, "[Out of memory attempting to open]");
|
||||
return protections;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Utilities.AppendToDictionary(protections, file, "[Out of memory attempting to open]");
|
||||
return protections;
|
||||
}
|
||||
|
||||
// TODO: Start moving toward reading from the stream directly. In theory,
|
||||
// deserialization can be done at this point, and if all of the sections are populated
|
||||
// properly, nearly all of the content checks can be dealt with without having
|
||||
// to take up as much memory as it does right now reading into the fileContent
|
||||
// byte array
|
||||
|
||||
// Create PortableExecutable and NewExecutable objects for use in the checks
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
|
||||
NewExecutable nex = NewExecutable.Deserialize(fileContent, 0);
|
||||
PortableExecutable pex = new PortableExecutable(stream);
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
NewExecutable nex = new NewExecutable(stream);
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// Create PortableExecutable and NewExecutable objects for use in the checks
|
||||
// PortableExecutable pex = PortableExecutable.Deserialize(stream);
|
||||
// stream.Seek(0, SeekOrigin.Begin);
|
||||
// NewExecutable nex = NewExecutable.Deserialize(stream);
|
||||
// stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// Iterate through all content checks
|
||||
Parallel.ForEach(contentCheckClasses, contentCheckClass =>
|
||||
// Iterate through all generic content checks
|
||||
if (fileContent != null)
|
||||
{
|
||||
// Track if any protection is found
|
||||
bool foundProtection = false;
|
||||
|
||||
// Check using custom content checks first
|
||||
string protection = contentCheckClass.CheckContents(file, fileContent, scanner.IncludeDebug, pex, nex);
|
||||
foundProtection |= !string.IsNullOrWhiteSpace(protection);
|
||||
if (ShouldAddProtection(contentCheckClass, scanner, protection))
|
||||
Utilities.AppendToDictionary(protections, file, protection);
|
||||
|
||||
// If we have an IScannable implementation
|
||||
if (contentCheckClass is IScannable scannable)
|
||||
Parallel.ForEach(contentCheckClasses, contentCheckClass =>
|
||||
{
|
||||
if (file != null && !string.IsNullOrEmpty(protection))
|
||||
string protection = contentCheckClass.CheckContents(file, fileContent, scanner.IncludeDebug, pex, nex);
|
||||
if (ShouldAddProtection(contentCheckClass, scanner, protection))
|
||||
Utilities.AppendToDictionary(protections, file, protection);
|
||||
|
||||
// If we have an IScannable implementation
|
||||
if (contentCheckClass is IScannable scannable)
|
||||
{
|
||||
var subProtections = scannable.Scan(scanner, null, file);
|
||||
Utilities.PrependToKeys(subProtections, file);
|
||||
Utilities.AppendToDictionary(protections, subProtections);
|
||||
if (file != null && !string.IsNullOrEmpty(protection))
|
||||
{
|
||||
var subProtections = scannable.Scan(scanner, null, file);
|
||||
Utilities.PrependToKeys(subProtections, file);
|
||||
Utilities.AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// If we have a NE executable, iterate through all NE content checks
|
||||
if (nex?.Initialized == true)
|
||||
{
|
||||
Parallel.ForEach(neContentCheckClasses, contentCheckClass =>
|
||||
{
|
||||
// Check using custom content checks first
|
||||
string protection = contentCheckClass.CheckNEContents(file, nex, scanner.IncludeDebug);
|
||||
if (ShouldAddProtection(contentCheckClass, scanner, protection))
|
||||
Utilities.AppendToDictionary(protections, file, protection);
|
||||
|
||||
// If we have an IScannable implementation
|
||||
if (contentCheckClass is IScannable scannable)
|
||||
{
|
||||
if (file != null && !string.IsNullOrEmpty(protection))
|
||||
{
|
||||
var subProtections = scannable.Scan(scanner, null, file);
|
||||
Utilities.PrependToKeys(subProtections, file);
|
||||
Utilities.AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// If we have a PE executable, iterate through all PE content checks
|
||||
if (pex?.Initialized == true)
|
||||
{
|
||||
Parallel.ForEach(peContentCheckClasses, contentCheckClass =>
|
||||
{
|
||||
// Check using custom content checks first
|
||||
string protection = contentCheckClass.CheckPEContents(file, pex, scanner.IncludeDebug);
|
||||
if (ShouldAddProtection(contentCheckClass, scanner, protection))
|
||||
Utilities.AppendToDictionary(protections, file, protection);
|
||||
|
||||
// If we have an IScannable implementation
|
||||
if (contentCheckClass is IScannable scannable)
|
||||
{
|
||||
if (file != null && !string.IsNullOrEmpty(protection))
|
||||
{
|
||||
var subProtections = scannable.Scan(scanner, null, file);
|
||||
Utilities.PrependToKeys(subProtections, file);
|
||||
Utilities.AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all IContentCheck implementations
|
||||
/// </summary>
|
||||
@@ -138,6 +188,26 @@ namespace BurnOutSharp.FileType
|
||||
.Where(t => t.IsClass && t.GetInterface(nameof(IContentCheck)) != null)
|
||||
.Select(t => Activator.CreateInstance(t) as IContentCheck);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all INEContentCheck implementations
|
||||
/// </summary>
|
||||
private static IEnumerable<INEContentCheck> InitNEContentCheckClasses()
|
||||
{
|
||||
return Assembly.GetExecutingAssembly().GetTypes()
|
||||
.Where(t => t.IsClass && t.GetInterface(nameof(INEContentCheck)) != null)
|
||||
.Select(t => Activator.CreateInstance(t) as INEContentCheck);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all IPEContentCheck implementations
|
||||
/// </summary>
|
||||
private static IEnumerable<IPEContentCheck> InitPEContentCheckClasses()
|
||||
{
|
||||
return Assembly.GetExecutingAssembly().GetTypes()
|
||||
.Where(t => t.IsClass && t.GetInterface(nameof(IPEContentCheck)) != null)
|
||||
.Select(t => Activator.CreateInstance(t) as IPEContentCheck);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check to see if a protection should be added or not
|
||||
@@ -156,5 +226,43 @@ namespace BurnOutSharp.FileType
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check to see if a protection should be added or not
|
||||
/// </summary>
|
||||
/// <param name="neContentCheckClass">Class that was last used to check</param>
|
||||
/// <param name="scanner">Scanner object for state tracking</param>
|
||||
/// <param name="protection">The protection result to be checked</param>
|
||||
private bool ShouldAddProtection(INEContentCheck neContentCheckClass, Scanner scanner, string protection)
|
||||
{
|
||||
// If we have a valid content check based on settings
|
||||
if (!neContentCheckClass.GetType().Namespace.ToLowerInvariant().Contains("packertype") || scanner.ScanPackers)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(protection))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check to see if a protection should be added or not
|
||||
/// </summary>
|
||||
/// <param name="peContentCheckClass">Class that was last used to check</param>
|
||||
/// <param name="scanner">Scanner object for state tracking</param>
|
||||
/// <param name="protection">The protection result to be checked</param>
|
||||
private bool ShouldAddProtection(IPEContentCheck peContentCheckClass, Scanner scanner, string protection)
|
||||
{
|
||||
// If we have a valid content check based on settings
|
||||
if (!peContentCheckClass.GetType().Namespace.ToLowerInvariant().Contains("packertype") || scanner.ScanPackers)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(protection))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,16 @@ namespace BurnOutSharp.FileType
|
||||
if (fileContent.Contains("MediaMax technology"))
|
||||
Utilities.AppendToDictionary(protections, file, "MediaMax CD-3");
|
||||
|
||||
// The full line from a sample is as follows:
|
||||
//
|
||||
// The files securom_v7_01.dat and securom_v7_01.bak have been created during the installation of a SecuROM protected application.
|
||||
//
|
||||
// TODO: Use the filenames in this line to get the version out of it
|
||||
|
||||
// SecuROM
|
||||
if (fileContent.Contains("SecuROM protected application"))
|
||||
Utilities.AppendToDictionary(protections, file, "SecuROM");
|
||||
|
||||
// XCP
|
||||
if (fileContent.Contains("http://cp.sonybmg.com/xcp/"))
|
||||
Utilities.AppendToDictionary(protections, file, "XCP");
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
|
||||
namespace BurnOutSharp
|
||||
{
|
||||
// TODO: This should either include an override that takes a Stream instead of the byte[]
|
||||
// OR have a completely separate check for when it's an executable specifically
|
||||
// TODO: This should be retired in lieu of the I*ContentCheck interfaces
|
||||
internal interface IContentCheck
|
||||
{
|
||||
/// <summary>
|
||||
@@ -14,6 +15,7 @@ namespace BurnOutSharp
|
||||
/// <param name="fileContent">Byte array representing the file contents</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>String containing any protections found in the file</returns>
|
||||
/// <remarks>This still includes PE and NE because this is primarily used for debug testing</remarks>
|
||||
string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex);
|
||||
}
|
||||
}
|
||||
|
||||
17
BurnOutSharp/INEContentCheck.cs
Normal file
17
BurnOutSharp/INEContentCheck.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
|
||||
namespace BurnOutSharp
|
||||
{
|
||||
// TODO: This should either include an override that takes a Stream instead of the byte[]
|
||||
internal interface INEContentCheck
|
||||
{
|
||||
/// <summary>
|
||||
/// Check a path for protections based on file contents
|
||||
/// </summary>
|
||||
/// <param name="file">File to check for protection indicators</param>
|
||||
/// <param name="nex">NewExecutable representing the read-in file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>String containing any protections found in the file</returns>
|
||||
string CheckNEContents(string file, NewExecutable nex, bool includeDebug);
|
||||
}
|
||||
}
|
||||
17
BurnOutSharp/IPEContentCheck.cs
Normal file
17
BurnOutSharp/IPEContentCheck.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
|
||||
namespace BurnOutSharp
|
||||
{
|
||||
// TODO: This should either include an override that takes a Stream instead of the byte[]
|
||||
internal interface IPEContentCheck
|
||||
{
|
||||
/// <summary>
|
||||
/// Check a path for protections based on file contents
|
||||
/// </summary>
|
||||
/// <param name="file">File to check for protection indicators</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <param name="pex">PortableExecutable representing the read-in file</param>
|
||||
/// <returns>String containing any protections found in the file</returns>
|
||||
string CheckPEContents(string file, PortableExecutable pex, bool includeDebug);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
// TODO: Add extraction and verify that all versions are detected
|
||||
public class AdvancedInstaller : IContentCheck
|
||||
public class AdvancedInstaller : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
// TODO: Add version checking, if possible
|
||||
public class Armadillo : IContentCheck
|
||||
public class Armadillo : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -23,19 +23,21 @@ namespace BurnOutSharp.PackerType
|
||||
return "Armadillo";
|
||||
|
||||
// Loop through all "extension" sections -- usually .data1 or .text1
|
||||
foreach (var section in sections.Where(s => s != null && Encoding.ASCII.GetString(s.Name).Trim('\0').EndsWith("1")))
|
||||
foreach (var section in sections.Where(s => s != null && s.NameString.EndsWith("1")))
|
||||
{
|
||||
string sectionName = Encoding.ASCII.GetString(section.Name).Trim('\0');
|
||||
var sectionRaw = pex.ReadRawSection(fileContent, sectionName);
|
||||
var matchers = new List<ContentMatchSet>
|
||||
var sectionRaw = pex.ReadRawSection(section.NameString);
|
||||
if (sectionRaw != null)
|
||||
{
|
||||
// ARMDEBUG
|
||||
new ContentMatchSet(new byte?[] { 0x41, 0x52, 0x4D, 0x44, 0x45, 0x42, 0x55, 0x47 }, $"Armadillo"),
|
||||
};
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// ARMDEBUG
|
||||
new ContentMatchSet(new byte?[] { 0x41, 0x52, 0x4D, 0x44, 0x45, 0x42, 0x55, 0x47 }, $"Armadillo"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, sectionRaw, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
string match = MatchUtil.GetFirstMatch(file, sectionRaw, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
// The official website for CExe also includes the source code (which does have to be retrieved by the Wayback Machine)
|
||||
// http://www.scottlu.com/Content/CExe.html
|
||||
public class CExe : IContentCheck, IScannable
|
||||
public class CExe : IPEContentCheck, IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool ShouldScan(byte[] magic) => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var stub = pex?.DOSStubHeader;
|
||||
|
||||
@@ -1,14 +1,42 @@
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
// TODO: Figure out how to more granularly determine versions like PiD,
|
||||
// at least for the 2.41 -> 2.75 range
|
||||
// TODO: Detect 3.15 and up (maybe looking for `Metamorphism`)
|
||||
public class EXEStealth : IContentCheck
|
||||
public class EXEStealth : IContentCheck, IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
if (includeDebug)
|
||||
{
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// ??[[__[[_ + (char)0x00 + {{ + (char)0x0 + (char)0x00 + {{ + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x0 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + ?;??;??
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x3F, 0x3F, 0x5B, 0x5B, 0x5F, 0x5F, 0x5B, 0x5B,
|
||||
0x5F, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x7B, 0x7B,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x3F, 0x3B, 0x3F, 0x3F, 0x3B, 0x3F,
|
||||
0x3F
|
||||
}, "EXE Stealth"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -31,22 +59,6 @@ namespace BurnOutSharp.PackerType
|
||||
return "EXE Stealth 2.76";
|
||||
|
||||
return null;
|
||||
|
||||
// TODO: Could not be confirmed with any sample, so disabling for now
|
||||
// var contentMatchSets = new List<ContentMatchSet>
|
||||
// {
|
||||
// // ??[[__[[_ + (char)0x00 + {{ + (char)0x0 + (char)0x00 + {{ + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x0 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + ?;??;??
|
||||
// new ContentMatchSet(new byte?[]
|
||||
// {
|
||||
// 0x3F, 0x3F, 0x5B, 0x5B, 0x5F, 0x5F, 0x5B, 0x5B,
|
||||
// 0x5F, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x7B, 0x7B,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x20, 0x3F, 0x3B, 0x3F, 0x3F, 0x3B, 0x3F,
|
||||
// 0x3F
|
||||
// }, "EXE Stealth"),
|
||||
// };
|
||||
|
||||
// return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
44
BurnOutSharp/PackerType/GenteeInstaller.cs
Normal file
44
BurnOutSharp/PackerType/GenteeInstaller.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
// TODO: Add extraction
|
||||
public class GenteeInstaller : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .data section, if it exists
|
||||
if (pex.DataSectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// Gentee installer
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x47, 0x65, 0x6E, 0x74, 0x65, 0x65, 0x20, 0x69,
|
||||
0x6E, 0x73, 0x74, 0x61, 0x6C, 0x6C, 0x65, 0x72,
|
||||
}, "Gentee Installer"),
|
||||
|
||||
// ginstall.dll
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x67, 0x69, 0x6E, 0x73, 0x74, 0x61, 0x6C, 0x6C,
|
||||
0x2E, 0x64, 0x6C, 0x6C,
|
||||
}, "Gentee Installer"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, pex.DataSectionRaw, matchers, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,78 +4,63 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
public class InnoSetup : IContentCheck, IScannable
|
||||
public class InnoSetup : INEContentCheck, IPEContentCheck, IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool ShouldScan(byte[] magic) => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckNEContents(string file, NewExecutable nex, bool includeDebug)
|
||||
{
|
||||
// Try to read the contents as a PE executable
|
||||
if (pex != null)
|
||||
// Get the DOS stub from the executable, if possible
|
||||
var stub = nex?.DOSStubHeader;
|
||||
if (stub == null)
|
||||
return null;
|
||||
|
||||
// Check for "Inno" in the reserved words
|
||||
if (stub.Reserved2[4] == 0x6E49 && stub.Reserved2[5] == 0x6F6E)
|
||||
{
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
string version = GetOldVersion(file, nex);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"Inno Setup {version}";
|
||||
|
||||
// Get the DATA/.data section, if it exists
|
||||
if (pex.DataSectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// Inno Setup Setup Data (
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x49, 0x6E, 0x6E, 0x6F, 0x20, 0x53, 0x65, 0x74,
|
||||
0x75, 0x70, 0x20, 0x53, 0x65, 0x74, 0x75, 0x70,
|
||||
0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x28
|
||||
}, GetVersion, "Inno Setup"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, pex.DataSectionRaw, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
|
||||
// Get the DOS stub from the executable, if possible
|
||||
var stub = pex?.DOSStubHeader;
|
||||
if (stub == null)
|
||||
return null;
|
||||
|
||||
// Check for "Inno" in the reserved words
|
||||
if (stub.Reserved2[4] == 0x6E49 && stub.Reserved2[5] == 0x6F6E)
|
||||
{
|
||||
string version = GetOldVersion(file, fileContent);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"Inno Setup {version}";
|
||||
|
||||
return "Inno Setup (Unknown Version)";
|
||||
}
|
||||
return "Inno Setup (Unknown Version)";
|
||||
}
|
||||
|
||||
// Try to read the contents as an NE executable
|
||||
if (nex != null)
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the DATA/.data section, if it exists
|
||||
if (pex.DataSectionRaw != null)
|
||||
{
|
||||
// Get the DOS stub from the executable, if possible
|
||||
var stub = nex?.DOSStubHeader;
|
||||
if (stub == null)
|
||||
return null;
|
||||
|
||||
// Check for "Inno" in the reserved words
|
||||
if (stub.Reserved2[4] == 0x6E49 && stub.Reserved2[5] == 0x6F6E)
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
string version = GetOldVersion(file, fileContent);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"Inno Setup {version}";
|
||||
|
||||
return "Inno Setup (Unknown Version)";
|
||||
}
|
||||
// Inno Setup Setup Data (
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x49, 0x6E, 0x6E, 0x6F, 0x20, 0x53, 0x65, 0x74,
|
||||
0x75, 0x70, 0x20, 0x53, 0x65, 0x74, 0x75, 0x70,
|
||||
0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x28
|
||||
}, GetVersion, "Inno Setup"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, pex.DataSectionRaw, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -126,17 +111,23 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetOldVersion(string file, byte[] fileContent)
|
||||
private static string GetOldVersion(string file, NewExecutable nex)
|
||||
{
|
||||
// TODO: Only sample is an NE executable - verify if this is in PE as well or where in the NE this lives
|
||||
var matchers = new List<ContentMatchSet>
|
||||
// TODO: Don't read entire file
|
||||
// TODO: Only 64 bytes at the end of the file is needed
|
||||
var data = nex.ReadArbitraryRange();
|
||||
if (data != null)
|
||||
{
|
||||
// "rDlPtS02" + (char)0x87 + "eVx"
|
||||
new ContentMatchSet(new byte?[] { 0x72, 0x44, 0x6C, 0x50, 0x74, 0x53, 0x30, 0x32, 0x87, 0x65, 0x56, 0x78 }, "1.2.16 or earlier"),
|
||||
};
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// "rDlPtS02" + (char)0x87 + "eVx"
|
||||
new ContentMatchSet(new byte?[] { 0x72, 0x44, 0x6C, 0x50, 0x74, 0x53, 0x30, 0x32, 0x87, 0x65, 0x56, 0x78 }, "1.2.16 or earlier"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, false);
|
||||
return match ?? "Unknown 1.X";
|
||||
return MatchUtil.GetFirstMatch(file, data, matchers, false) ?? "Unknown 1.X";
|
||||
}
|
||||
|
||||
return "Unknown 1.X";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
67
BurnOutSharp/PackerType/InstallAnywhere.cs
Normal file
67
BurnOutSharp/PackerType/InstallAnywhere.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
public class InstallAnywhere : IPEContentCheck, IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool ShouldScan(byte[] magic) => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
string name = Utilities.GetFileDescription(pex);
|
||||
if (!string.IsNullOrWhiteSpace(name) && name.StartsWith("InstallAnywhere Self Extractor", StringComparison.OrdinalIgnoreCase))
|
||||
return $"InstallAnywhere {GetVersion(pex)}";
|
||||
|
||||
name = Utilities.GetProductName(pex);
|
||||
if (!string.IsNullOrWhiteSpace(name) && name.StartsWith("InstallAnywhere", StringComparison.OrdinalIgnoreCase))
|
||||
return $"InstallAnywhere {GetVersion(pex)}";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.OpenRead(file))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
// TODO: Add extraction, which may be possible with the current libraries but needs to be investigated further.
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetVersion(PortableExecutable pex)
|
||||
{
|
||||
// Check the file version first
|
||||
string version = Utilities.GetFileVersion(pex);
|
||||
if (!string.IsNullOrEmpty(version))
|
||||
return version;
|
||||
|
||||
// Then check the manifest version
|
||||
version = Utilities.GetManifestVersion(pex);
|
||||
if (!string.IsNullOrEmpty(version))
|
||||
return version;
|
||||
|
||||
return "(Unknown Version)";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
public class InstallerVISE : IContentCheck, IScannable
|
||||
public class InstallerVISE : IPEContentCheck, IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool ShouldScan(byte[] magic) => true;
|
||||
|
||||
//TODO: Add exact version detection for Windows builds, make sure versions before 3.X are detected as well, and detect the Mac builds.
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
// TODO: Add extraction, seems to primarily use MSZip compression.
|
||||
public class IntelInstallationFramework : IContentCheck
|
||||
public class IntelInstallationFramework : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -2,20 +2,20 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
// TODO: Add extraction, which should be possible with LibMSPackN, but it refuses to extract due to SFX files lacking the typical CAB identifiers.
|
||||
public class MicrosoftCABSFX : IContentCheck, IScannable
|
||||
public class MicrosoftCABSFX : IPEContentCheck, IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool ShouldScan(byte[] magic) => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
public class NSIS : IContentCheck
|
||||
public class NSIS : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
// TODO: Add extraction and better version detection
|
||||
public class PECompact : IContentCheck
|
||||
public class PECompact : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
namespace BurnOutSharp.PackerType
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
public class Petite
|
||||
public class PEtite : IPEContentCheck
|
||||
{
|
||||
/*
|
||||
* Possible strings for PEtite Win32 Executable Compressor (Unknown how to get version)
|
||||
* - petite - 40 70 65 74 69 74 65 (Made with Version 2.4, Compression Level 1-9)
|
||||
*/
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .petite section, if it exists -- TODO: Is there a version number that can be found?
|
||||
bool nicodeSection = pex.ContainsSection(".petite", exact: true);
|
||||
if (nicodeSection)
|
||||
return "PEtite";
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
public class SetupFactory : IContentCheck, IScannable
|
||||
public class SetupFactory : IPEContentCheck, IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool ShouldScan(byte[] magic) => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
27
BurnOutSharp/PackerType/Shrinker.cs
Normal file
27
BurnOutSharp/PackerType/Shrinker.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
// TODO: Add extraction
|
||||
public class Shrinker : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .shrink0 and .shrink2 sections, if they exist -- TODO: Confirm if both are needed or either/or is fine
|
||||
bool shrink0Section = pex.ContainsSection(".shrink0", true);
|
||||
bool shrink2Section = pex.ContainsSection(".shrink2", true);
|
||||
if (shrink0Section || shrink2Section)
|
||||
return "Shrinker";
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
public class UPX : IContentCheck
|
||||
public class UPX : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -16,35 +16,29 @@ namespace BurnOutSharp.PackerType
|
||||
return null;
|
||||
|
||||
// Standard UPX
|
||||
int foundPosition = FindData(pex, "UPX");
|
||||
if (foundPosition > -1)
|
||||
var sectionData = FindData(pex, "UPX");
|
||||
if (sectionData != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// UPX!
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[] { 0x55, 0x50, 0x58, 0x21 }, end: foundPosition),
|
||||
GetVersion,
|
||||
"UPX"),
|
||||
new ContentMatchSet(new byte?[] { 0x55, 0x50, 0x58, 0x21 }, GetVersion, "UPX"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
return MatchUtil.GetFirstMatch(file, sectionData, matchers, includeDebug);
|
||||
}
|
||||
|
||||
// NOS Variant
|
||||
foundPosition = FindData(pex, "NOS");
|
||||
if (foundPosition > -1)
|
||||
sectionData = FindData(pex, "NOS");
|
||||
if (sectionData != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// NOS
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[] { 0x4E, 0x4F, 0x53, 0x20 }, end: foundPosition),
|
||||
GetVersion,
|
||||
"UPX (NOS Variant)"),
|
||||
new ContentMatchSet(new byte?[] { 0x4E, 0x4F, 0x53, 0x20 }, GetVersion, "UPX (NOS Variant)"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
return MatchUtil.GetFirstMatch(file, sectionData, matchers, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -84,8 +78,8 @@ namespace BurnOutSharp.PackerType
|
||||
/// </summary>
|
||||
/// <param name="pex">PortableExecutable representing the read-in file</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(PortableExecutable pex, string sectionPrefix)
|
||||
/// <returns>Section data, null on error</returns>
|
||||
private byte[] FindData(PortableExecutable pex, string sectionPrefix)
|
||||
{
|
||||
// Get the two matching sections, if possible
|
||||
var firstSection = pex.GetFirstSection($"{sectionPrefix}0", exact: true);
|
||||
@@ -93,10 +87,10 @@ namespace BurnOutSharp.PackerType
|
||||
|
||||
// If either section is null, we can't do anything
|
||||
if (firstSection == null || secondSection == null)
|
||||
return -1;
|
||||
return null;
|
||||
|
||||
// Return the first section address
|
||||
return (int)firstSection.PointerToRawData;
|
||||
// This subtract is needed because the version is before the section
|
||||
return pex.ReadRawSection($"{sectionPrefix}0", first: true, offset: -128);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
using SharpCompress.Archives;
|
||||
@@ -10,13 +10,13 @@ using SharpCompress.Archives.Rar;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
public class WinRARSFX : IContentCheck, IScannable
|
||||
public class WinRARSFX : IPEContentCheck, IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool ShouldScan(byte[] magic) => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -3,6 +3,8 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
using SharpCompress.Archives;
|
||||
@@ -10,106 +12,110 @@ using SharpCompress.Archives.Zip;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
public class WinZipSFX : IContentCheck, IScannable
|
||||
public class WinZipSFX : INEContentCheck, IPEContentCheck, IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool ShouldScan(byte[] magic) => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckNEContents(string file, NewExecutable nex, bool includeDebug)
|
||||
{
|
||||
// Try to read the contents as a PE executable
|
||||
if (pex != null)
|
||||
// Get the DOS stub from the executable, if possible
|
||||
var stub = nex?.DOSStubHeader;
|
||||
if (stub == null)
|
||||
return null;
|
||||
|
||||
string version = GetNEHeaderVersion(nex);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
|
||||
version = GetNEUnknownHeaderVersion(nex, file, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .rdata section, if it exists
|
||||
if (pex.ResourceDataSectionRaw != null)
|
||||
{
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .rdata section, if it exists
|
||||
if (pex.ResourceDataSectionRaw != null)
|
||||
{
|
||||
string version = GetSFXSectionDataVersion(file, pex.ResourceDataSectionRaw, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
}
|
||||
|
||||
// Get the _winzip_ section, if it exists
|
||||
bool winzipSection = pex.ContainsSection("_winzip_", exact: true);
|
||||
if (winzipSection)
|
||||
{
|
||||
string version = GetPEHeaderVersion(pex);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
|
||||
version = GetAdjustedManifestVersion(pex);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
|
||||
return "WinZip SFX Unknown Version (32-bit)";
|
||||
}
|
||||
|
||||
#region Unknown Version checks
|
||||
|
||||
// Get the .rdata section, if it exists
|
||||
if (pex.ResourceDataSectionRaw != null)
|
||||
{
|
||||
string version = GetSFXSectionDataUnknownVersion(file, pex.ResourceDataSectionRaw, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
}
|
||||
|
||||
// Get the .data section, if it exists
|
||||
if (pex.DataSectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// WinZip Self-Extractor header corrupt.
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70, 0x20, 0x53,
|
||||
0x65, 0x6C, 0x66, 0x2D, 0x45, 0x78, 0x74, 0x72,
|
||||
0x61, 0x63, 0x74, 0x6F, 0x72, 0x20, 0x68, 0x65,
|
||||
0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6F, 0x72,
|
||||
0x72, 0x75, 0x70, 0x74, 0x2E,
|
||||
}, "Unknown Version (32-bit)"),
|
||||
|
||||
// winzip\shell\open\command
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x77, 0x69, 0x6E, 0x7A, 0x69, 0x70, 0x5C, 0x73,
|
||||
0x68, 0x65, 0x6C, 0x6C, 0x5C, 0x6F, 0x70, 0x65,
|
||||
0x6E, 0x5C, 0x63, 0x6F, 0x6D, 0x6D, 0x61, 0x6E,
|
||||
0x64,
|
||||
}, "Unknown Version (32-bit)"),
|
||||
};
|
||||
|
||||
string version = MatchUtil.GetFirstMatch(file, pex.DataSectionRaw, matchers, false);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
{
|
||||
// Try to grab the value from the manifest, if possible
|
||||
string manifestVersion = GetAdjustedManifestVersion(pex);
|
||||
if (!string.IsNullOrWhiteSpace(manifestVersion))
|
||||
return $"WinZip SFX {manifestVersion}";
|
||||
|
||||
return $"WinZip SFX {version}";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
// Try to read the contents as an NE executable
|
||||
if (nex != null)
|
||||
{
|
||||
string version = GetNEHeaderVersion(nex);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
|
||||
version = GetNEUnknownHeaderVersion(nex, file, fileContent, includeDebug);
|
||||
string version = GetSFXSectionDataVersion(file, pex.ResourceDataSectionRaw, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
}
|
||||
|
||||
// Get the _winzip_ section, if it exists
|
||||
bool winzipSection = pex.ContainsSection("_winzip_", exact: true);
|
||||
if (winzipSection)
|
||||
{
|
||||
string version = GetPEHeaderVersion(pex);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
|
||||
version = GetAdjustedManifestVersion(pex);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
|
||||
return "WinZip SFX Unknown Version (32-bit)";
|
||||
}
|
||||
|
||||
#region Unknown Version checks
|
||||
|
||||
// Get the .rdata section, if it exists
|
||||
if (pex.ResourceDataSectionRaw != null)
|
||||
{
|
||||
string version = GetSFXSectionDataUnknownVersion(file, pex.ResourceDataSectionRaw, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
}
|
||||
|
||||
// Get the .data section, if it exists
|
||||
if (pex.DataSectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// WinZip Self-Extractor header corrupt.
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70, 0x20, 0x53,
|
||||
0x65, 0x6C, 0x66, 0x2D, 0x45, 0x78, 0x74, 0x72,
|
||||
0x61, 0x63, 0x74, 0x6F, 0x72, 0x20, 0x68, 0x65,
|
||||
0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6F, 0x72,
|
||||
0x72, 0x75, 0x70, 0x74, 0x2E,
|
||||
}, "Unknown Version (32-bit)"),
|
||||
|
||||
// winzip\shell\open\command
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x77, 0x69, 0x6E, 0x7A, 0x69, 0x70, 0x5C, 0x73,
|
||||
0x68, 0x65, 0x6C, 0x6C, 0x5C, 0x6F, 0x70, 0x65,
|
||||
0x6E, 0x5C, 0x63, 0x6F, 0x6D, 0x6D, 0x61, 0x6E,
|
||||
0x64,
|
||||
}, "Unknown Version (32-bit)"),
|
||||
};
|
||||
|
||||
string version = MatchUtil.GetFirstMatch(file, pex.DataSectionRaw, matchers, false);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
{
|
||||
// Try to grab the value from the manifest, if possible
|
||||
string manifestVersion = GetAdjustedManifestVersion(pex);
|
||||
if (!string.IsNullOrWhiteSpace(manifestVersion))
|
||||
return $"WinZip SFX {manifestVersion}";
|
||||
|
||||
return $"WinZip SFX {version}";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -763,23 +769,31 @@ namespace BurnOutSharp.PackerType
|
||||
/// <summary>
|
||||
/// Get the unknown version from the NE header value combinations
|
||||
/// </summary>
|
||||
private string GetNEUnknownHeaderVersion(NewExecutable nex, string file, byte[] fileContent, bool includeDebug)
|
||||
private string GetNEUnknownHeaderVersion(NewExecutable nex, string file, bool includeDebug)
|
||||
{
|
||||
// TODO: Like with PE, convert this into a preread in the header code
|
||||
int resourceStart = nex.DOSStubHeader.NewExeHeaderAddr + nex.NewExecutableHeader.ResourceTableOffset;
|
||||
int resourceEnd = nex.DOSStubHeader.NewExeHeaderAddr + nex.NewExecutableHeader.ModuleReferenceTableOffset;
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// WZ-SE-01
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[]
|
||||
{
|
||||
0x57, 0x5A, 0x2D, 0x53, 0x45, 0x2D, 0x30, 0x31
|
||||
}, start: resourceStart, end: resourceEnd),
|
||||
"Unknown Version (16-bit)"),
|
||||
};
|
||||
int resourceLength = resourceEnd - resourceStart;
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
var resourceData = nex.ReadArbitraryRange(resourceStart, resourceLength);
|
||||
if (resourceData != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// WZ-SE-01
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[]
|
||||
{
|
||||
0x57, 0x5A, 0x2D, 0x53, 0x45, 0x2D, 0x30, 0x31
|
||||
}, start: resourceStart, end: resourceEnd),
|
||||
"Unknown Version (16-bit)"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, resourceData, matchers, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2,40 +2,50 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
using Wise = WiseUnpacker.WiseUnpacker;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
public class WiseInstaller : IContentCheck, IScannable
|
||||
public class WiseInstaller : INEContentCheck, IPEContentCheck, IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool ShouldScan(byte[] magic) => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckNEContents(string file, NewExecutable nex, bool includeDebug)
|
||||
{
|
||||
// Get the DOS stub from the executable, if possible
|
||||
var stub = nex?.DOSStubHeader;
|
||||
if (stub == null)
|
||||
return null;
|
||||
|
||||
// TODO: Don't read entire file
|
||||
var data = nex.ReadArbitraryRange();
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
// TODO: Keep this around until it can be confirmed with NE checks as well
|
||||
// TODO: This _may_ actually over-match. See msvbvm50.exe for an example
|
||||
var neMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// WiseMain
|
||||
new ContentMatchSet(new byte?[] { 0x57, 0x69, 0x73, 0x65, 0x4D, 0x61, 0x69, 0x6E }, "Wise Installation Wizard Module"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, data, neMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
{
|
||||
if (nex != null)
|
||||
{
|
||||
// TODO: Keep this around until it can be confirmed with NE checks as well
|
||||
// TODO: This _may_ actually over-match. See msvbvm50.exe for an example
|
||||
var neMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// WiseMain
|
||||
new ContentMatchSet(new byte?[] { 0x57, 0x69, 0x73, 0x65, 0x4D, 0x61, 0x69, 0x6E }, "Wise Installation Wizard Module"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, neMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the .data section, if it exists
|
||||
if (pex.DataSectionRaw != null)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
{
|
||||
public class dotFuscator : IContentCheck
|
||||
public class dotFuscator : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,14 +1,38 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
// TODO: Figure out how to get version numbers
|
||||
public class ActiveMARK : IContentCheck
|
||||
public class ActiveMARK : IContentCheck, IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
if (includeDebug)
|
||||
{
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// " " + (char)0xC2 + (char)0x16 + (char)0x00 + (char)0xA8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0xB8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x86 + (char)0xC8 + (char)0x16 + (char)0x00 + (char)0x9A + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x10 + (char)0xC2 + (char)0x16 + (char)0x00
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x20, 0xC2, 0x16, 0x00, 0xA8, 0xC1, 0x16, 0x00,
|
||||
0xB8, 0xC1, 0x16, 0x00, 0x86, 0xC8, 0x16, 0x00,
|
||||
0x9A, 0xC1, 0x16, 0x00, 0x10, 0xC2, 0x16, 0x00
|
||||
}, "ActiveMARK 5"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -16,7 +40,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
return null;
|
||||
|
||||
// Get the last .bss section, if it exists
|
||||
var bssSectionRaw = pex.ReadRawSection(fileContent, ".bss", first: false);
|
||||
var bssSectionRaw = pex.ReadRawSection(".bss", first: false);
|
||||
if (bssSectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
@@ -30,19 +54,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
return match;
|
||||
}
|
||||
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// " " + (char)0xC2 + (char)0x16 + (char)0x00 + (char)0xA8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0xB8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x86 + (char)0xC8 + (char)0x16 + (char)0x00 + (char)0x9A + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x10 + (char)0xC2 + (char)0x16 + (char)0x00
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x20, 0xC2, 0x16, 0x00, 0xA8, 0xC1, 0x16, 0x00,
|
||||
0xB8, 0xC1, 0x16, 0x00, 0x86, 0xC8, 0x16, 0x00,
|
||||
0x9A, 0xC1, 0x16, 0x00, 0x10, 0xC2, 0x16, 0x00
|
||||
}, "ActiveMARK 5"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,44 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class AlphaROM : IContentCheck
|
||||
// TODO: Alternative string possibilities:
|
||||
// - \AlphaDiscLog.txt
|
||||
// - \SETTEC
|
||||
// - AlphaROM
|
||||
// - SETTEC0000SETTEC1111
|
||||
// - SOFTWARE\SETTEC
|
||||
// TODO: Are there version numbers?
|
||||
public class AlphaROM : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .data section, if it exists
|
||||
if (pex.DataSectionRaw != null)
|
||||
{
|
||||
// SETTEC
|
||||
new ContentMatchSet(new byte?[] { 0x53, 0x45, 0x54, 0x54, 0x45, 0x43 }, "Alpha-ROM"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// \SETTEC
|
||||
new ContentMatchSet(new byte?[] { 0x5C, 0x53, 0x45, 0x54, 0x54, 0x45, 0x43 }, "Alpha-ROM"),
|
||||
|
||||
// SETTEC0000
|
||||
new ContentMatchSet(new byte?[] { 0x53, 0x45, 0x54, 0x54, 0x45, 0x43, 0x30, 0x30, 0x30, 0x30 }, "Alpha-ROM"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, pex.DataSectionRaw, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class CDCheck : IContentCheck
|
||||
public class CDCheck : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -2,27 +2,23 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class CDDVDCops : IContentCheck, IPathCheck
|
||||
public class CDDVDCops : IContentCheck, INEContentCheck, IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .grand section, if it exists
|
||||
var grandSectionRaw = pex.ReadRawSection(fileContent, ".grand", first: true);
|
||||
if (grandSectionRaw != null)
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
if (includeDebug)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// TODO: Remove from here once it's confirmed that no PE executables contain this string
|
||||
// CD-Cops, ver.
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
@@ -30,7 +26,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
|
||||
}, GetVersion, "CD-Cops"),
|
||||
|
||||
// DVD-Cops, ver.
|
||||
// // DVD-Cops, ver.
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x44, 0x56, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73,
|
||||
@@ -38,15 +34,31 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, GetVersion, "DVD-Cops"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, grandSectionRaw, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
|
||||
// return "CD-Cops (Unknown Version)";
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckNEContents(string file, NewExecutable nex, bool includeDebug)
|
||||
{
|
||||
// Get the DOS stub from the executable, if possible
|
||||
var stub = nex?.DOSStubHeader;
|
||||
if (stub == null)
|
||||
return null;
|
||||
|
||||
// TODO: Don't read entire file
|
||||
var data = nex.ReadArbitraryRange();
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
// TODO: Do something with these strings in the NE header(?)
|
||||
// - CDCOPS
|
||||
// - CDcops assembly-language DLL
|
||||
|
||||
// TODO: Figure out what NE section this lives in
|
||||
var neMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// CD-Cops, ver.
|
||||
new ContentMatchSet(new byte?[]
|
||||
@@ -54,16 +66,25 @@ namespace BurnOutSharp.ProtectionType
|
||||
0x43, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73, 0x2C,
|
||||
0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
|
||||
}, GetVersion, "CD-Cops"),
|
||||
|
||||
// DVD-Cops, ver.
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x44, 0x56, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73,
|
||||
0x2C, 0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
|
||||
}, GetVersion, "DVD-Cops"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
return MatchUtil.GetFirstMatch(file, data, neMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .grand section, if it exists -- TODO: Confirm is this is in DVD-Cops as well
|
||||
bool grandSection = pex.ContainsSection(".grand", exact: true);
|
||||
if (grandSection)
|
||||
return "CD-Cops";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class CDKey : IContentCheck
|
||||
public class CDKey : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class CDLock : IContentCheck, IPathCheck
|
||||
public class CDLock : IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class CDSHiELDSE : IContentCheck
|
||||
public class CDSHiELDSE : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -15,7 +15,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
return null;
|
||||
|
||||
// Get the code/CODE section, if it exists
|
||||
var codeSectionRaw = pex.ReadRawSection(fileContent, "code", first: true) ?? pex.ReadRawSection(fileContent, "CODE", first: true);
|
||||
var codeSectionRaw = pex.ReadRawSection("code", first: true) ?? pex.ReadRawSection("CODE", first: true);
|
||||
if (codeSectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
|
||||
@@ -4,29 +4,39 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class CactusDataShield : IContentCheck, IPathCheck
|
||||
public class CactusDataShield : IContentCheck, IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
private List<ContentMatchSet> GetContentMatchSets()
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
{
|
||||
// TODO: Both of these are found in Mac binaries
|
||||
return new List<ContentMatchSet>
|
||||
// TODO: Limit these checks to Mac binaries
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
if (includeDebug)
|
||||
{
|
||||
// CDSPlayer
|
||||
new ContentMatchSet(new byte?[] { 0x43, 0x44, 0x53, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72 }, "Cactus Data Shield 200"),
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// CDSPlayer
|
||||
new ContentMatchSet(new byte?[] { 0x43, 0x44, 0x53, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72 }, "Cactus Data Shield 200"),
|
||||
|
||||
// yucca.cds
|
||||
new ContentMatchSet(new byte?[] { 0x79, 0x75, 0x63, 0x63, 0x61, 0x2E, 0x63, 0x64, 0x73 }, "Cactus Data Shield 200"),
|
||||
};
|
||||
// yucca.cds
|
||||
new ContentMatchSet(new byte?[] { 0x79, 0x75, 0x63, 0x63, 0x61, 0x2E, 0x63, 0x64, 0x73 }, "Cactus Data Shield 200"),
|
||||
};
|
||||
|
||||
if (contentMatchSets != null && contentMatchSets.Any())
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -50,10 +60,6 @@ namespace BurnOutSharp.ProtectionType
|
||||
return match;
|
||||
}
|
||||
|
||||
var contentMatchSets = GetContentMatchSets();
|
||||
if (contentMatchSets != null && contentMatchSets.Any())
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -67,7 +73,6 @@ namespace BurnOutSharp.ProtectionType
|
||||
new PathMatchSet(new PathMatch("CDSPlayer.app", useEndsWith: true), GetVersion, "Cactus Data Shield"),
|
||||
new PathMatchSet(new PathMatch("PJSTREAM.DLL", useEndsWith: true), GetVersion, "Cactus Data Shield"),
|
||||
new PathMatchSet(new PathMatch("wmmp.exe", useEndsWith: true), GetVersion, "Cactus Data Shield"),
|
||||
new PathMatchSet(new PathMatch(".cds", useEndsWith: true), GetVersion, "Cactus Data Shield"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
@@ -82,7 +87,6 @@ namespace BurnOutSharp.ProtectionType
|
||||
new PathMatchSet(new PathMatch("CDSPlayer.app", useEndsWith: true), "Cactus Data Shield 200"),
|
||||
new PathMatchSet(new PathMatch("PJSTREAM.DLL", useEndsWith: true), "Cactus Data Shield 200"),
|
||||
new PathMatchSet(new PathMatch("wmmp.exe", useEndsWith: true), "Cactus Data Shield 200"),
|
||||
new PathMatchSet(new PathMatch(".cds", useEndsWith: true), "Cactus Data Shield 200"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(path, matchers, any: true);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class CengaProtectDVD : IContentCheck
|
||||
public class CengaProtectDVD : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,13 +1,38 @@
|
||||
using System.Linq;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
// CodeLock / CodeLok / CopyLok
|
||||
public class CodeLock : IContentCheck
|
||||
public class CodeLock : IContentCheck, IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
if (includeDebug)
|
||||
{
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// CODE-LOCK.OCX
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x43, 0x4F, 0x44, 0x45, 0x2D, 0x4C, 0x4F, 0x43,
|
||||
0x4B, 0x2E, 0x4F, 0x43, 0x58
|
||||
}, "CodeLock / CodeLok / CopyLok"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -20,19 +45,6 @@ namespace BurnOutSharp.ProtectionType
|
||||
return "CodeLock / CodeLok / CopyLok";
|
||||
|
||||
return null;
|
||||
|
||||
// TODO: Could not be confirmed with any sample, so disabling for now
|
||||
// var contentMatchSets = new List<ContentMatchSet>
|
||||
// {
|
||||
// // CODE-LOCK.OCX
|
||||
// new ContentMatchSet(new byte?[]
|
||||
// {
|
||||
// 0x43, 0x4F, 0x44, 0x45, 0x2D, 0x4C, 0x4F, 0x43,
|
||||
// 0x4B, 0x2E, 0x4F, 0x43, 0x58
|
||||
// }, "CodeLock / CodeLok / CopyLok"),
|
||||
// };
|
||||
|
||||
// return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
@@ -11,17 +12,22 @@ namespace BurnOutSharp.ProtectionType
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
if (includeDebug)
|
||||
{
|
||||
// Tom Commander
|
||||
new ContentMatchSet(new byte?[]
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
0x54, 0x6F, 0x6D, 0x20, 0x43, 0x6F, 0x6D, 0x6D,
|
||||
0x61, 0x6E, 0x64, 0x65, 0x72
|
||||
}, "CopyKiller"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
// Tom Commander
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x54, 0x6F, 0x6D, 0x20, 0x43, 0x6F, 0x6D, 0x6D,
|
||||
0x61, 0x6E, 0x64, 0x65, 0x72
|
||||
}, "CopyKiller"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
@@ -12,10 +12,10 @@ namespace BurnOutSharp.ProtectionType
|
||||
// - Look into `ccinstall`, `Services/EACOM`, `TSLHost`, `SIGS/UploadThread/exchangeAuthToken`,
|
||||
// `blazeURL`, `psapi.dll`, `DasmX86Dll.dll`, `NVCPL.dll`, `iphlpapi.dll`, `dbghelp.dll`,
|
||||
// `WS2_32.dll`,
|
||||
public class ElectronicArts : IContentCheck
|
||||
public class ElectronicArts : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class GFWL : IContentCheck, IPathCheck
|
||||
public class GFWL : IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
@@ -8,16 +8,28 @@ namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
// Note that this set of checks also contains "Stardock Product Activation"
|
||||
// This is intentional, as that protection is highly related to Impulse Reactor
|
||||
public class ImpulseReactor : IContentCheck, IPathCheck
|
||||
public class ImpulseReactor : IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
string name = Utilities.GetFileDescription(pex);
|
||||
if (!string.IsNullOrWhiteSpace(name) && name.Contains("ImpulseReactor Dynamic Link Library"))
|
||||
return $"Impulse Reactor Core Module {Utilities.GetFileVersion(pex)}";
|
||||
|
||||
name = Utilities.GetProductName(pex);
|
||||
if (!string.IsNullOrWhiteSpace(name) && name.Contains("ImpulseReactor Dynamic Link Library"))
|
||||
return $"Impulse Reactor Core Module {Utilities.GetFileVersion(pex)}";
|
||||
|
||||
name = Utilities.GetOriginalFileName(pex);
|
||||
if (!string.IsNullOrWhiteSpace(name) && name.Contains("ReactorActivate.exe"))
|
||||
return $"Stardock Product Activation {Utilities.GetFileVersion(pex)}";
|
||||
|
||||
// Get the .rdata section, if it exists
|
||||
if (pex.ResourceDataSectionRaw != null)
|
||||
{
|
||||
@@ -30,6 +42,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
};
|
||||
bool containsCheck = pex.ResourceDataSectionRaw.FirstPosition(check, out int position);
|
||||
|
||||
// TODO: Find what resource this is in
|
||||
// A + (char)0x00 + T + (char)0x00 + T + (char)0x00 + L + (char)0x00 + I + (char)0x00 + S + (char)0x00 + T + (char)0x00 + (char)0x00 + (char)0x00 + E + (char)0x00 + L + (char)0x00 + E + (char)0x00 + M + (char)0x00 + E + (char)0x00 + N + (char)0x00 + T + (char)0x00 + (char)0x00 + (char)0x00 + N + (char)0x00 + O + (char)0x00 + T + (char)0x00 + A + (char)0x00 + T + (char)0x00 + I + (char)0x00 + O + (char)0x00 + N + (char)0x00
|
||||
byte?[] check2 = new byte?[]
|
||||
{
|
||||
@@ -54,7 +67,6 @@ namespace BurnOutSharp.ProtectionType
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
{
|
||||
// TODO: Verify if these are AND or OR
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("ImpulseReactor.dll", useEndsWith: true), Utilities.GetFileVersion, "Impulse Reactor Core Module"),
|
||||
@@ -67,7 +79,6 @@ namespace BurnOutSharp.ProtectionType
|
||||
/// <inheritdoc/>
|
||||
public string CheckFilePath(string path)
|
||||
{
|
||||
// TODO: Verify if these are AND or OR
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("ImpulseReactor.dll", useEndsWith: true), Utilities.GetFileVersion, "Impulse Reactor Core Module"),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class Intenium : IContentCheck
|
||||
public class Intenium : IPEContentCheck
|
||||
{
|
||||
/*
|
||||
* Possible strings for finding INTENIUM Trial & Buy Protection
|
||||
@@ -22,7 +22,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
*/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
@@ -9,10 +9,10 @@ namespace BurnOutSharp.ProtectionType
|
||||
// Interesting note: the former protection "Xtreme-Protector" was found to be a
|
||||
// subset of the JoWood X-Prot checks, more specifically the XPROT section check
|
||||
// that now outputs a version of v1.4+.
|
||||
public class JoWood : IContentCheck
|
||||
public class JoWood : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -24,7 +24,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
if (extSection)
|
||||
{
|
||||
// Get the .dcrtext section, if it exists
|
||||
var dcrtextSectionRaw = pex.ReadRawSection(fileContent, ".dcrtext");
|
||||
var dcrtextSectionRaw = pex.ReadRawSection(".dcrtext");
|
||||
if (dcrtextSectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
|
||||
@@ -1,11 +1,30 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class Key2AudioXS : IPathCheck
|
||||
public class Key2AudioXS : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
string name = Utilities.GetFileDescription(pex);
|
||||
if (!string.IsNullOrWhiteSpace(name) && name.Contains("SDKHM (KEEP)"))
|
||||
return "key2AudioXS";
|
||||
else if (!string.IsNullOrWhiteSpace(name) && name.Contains("SDKHM (KEPT)"))
|
||||
return "key2AudioXS";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
@@ -10,17 +11,22 @@ namespace BurnOutSharp.ProtectionType
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
if (includeDebug)
|
||||
{
|
||||
// KEY-LOCK COMMAND
|
||||
new ContentMatchSet(new byte?[]
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
0x4B, 0x45, 0x59, 0x2D, 0x4C, 0x4F, 0x43, 0x4B,
|
||||
0x20, 0x43, 0x4F, 0x4D, 0x4D, 0x41, 0x4E, 0x44
|
||||
}, "Key-Lock (Dongle)"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
// KEY-LOCK COMMAND
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x4B, 0x45, 0x59, 0x2D, 0x4C, 0x4F, 0x43, 0x4B,
|
||||
0x20, 0x43, 0x4F, 0x4D, 0x4D, 0x41, 0x4E, 0x44
|
||||
}, "Key-Lock (Dongle)"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class LaserLok : IContentCheck, IPathCheck
|
||||
public class LaserLok : IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// TODO: Additional checks that may or may not be useful with the below
|
||||
//
|
||||
@@ -87,11 +87,11 @@ namespace BurnOutSharp.ProtectionType
|
||||
}
|
||||
|
||||
if (containsCheck && containsCheck2)
|
||||
return $"LaserLok {GetVersion(pex.TextSectionRaw, position2)} {GetBuild(pex.TextSectionRaw, true)}" + (includeDebug ? $" (Index {position}, {position2})" : string.Empty);
|
||||
return $"LaserLok {GetVersion(pex.TextSectionRaw, position2)} {GetBuild(pex.TextSectionRaw, true)} [Check disc for physical ring]" + (includeDebug ? $" (Index {position}, {position2})" : string.Empty);
|
||||
else if (containsCheck && !containsCheck2)
|
||||
return $"LaserLok Marathon {GetBuild(pex.TextSectionRaw, false)}" + (includeDebug ? $" (Index {position})" : string.Empty);
|
||||
return $"LaserLok Marathon {GetBuild(pex.TextSectionRaw, false)} [Check disc for physical ring]" + (includeDebug ? $" (Index {position})" : string.Empty);
|
||||
else if (!containsCheck && containsCheck2)
|
||||
return $"LaserLok {GetVersion(pex.TextSectionRaw, --position2)} {GetBuild(pex.TextSectionRaw, false)}" + (includeDebug ? $" (Index {position2})" : string.Empty);
|
||||
return $"LaserLok {GetVersion(pex.TextSectionRaw, --position2)} {GetBuild(pex.TextSectionRaw, false)} [Check disc for physical ring]" + (includeDebug ? $" (Index {position2})" : string.Empty);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -101,17 +101,17 @@ namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet($"LASERLOK{Path.DirectorySeparatorChar}", "LaserLok"),
|
||||
new PathMatchSet($"LASERLOK{Path.DirectorySeparatorChar}", "LaserLok [Check disc for physical ring]"),
|
||||
|
||||
// TODO: Verify if these are OR or AND
|
||||
new PathMatchSet(new PathMatch("NOMOUSE.SP", useEndsWith: true), GetVersion16Bit, "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("NOMOUSE.COM", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("l16dll.dll", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("laserlok.in", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o10", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o11", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o12", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("laserlok.out", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("NOMOUSE.SP", useEndsWith: true), GetVersion16Bit, "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("NOMOUSE.COM", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("l16dll.dll", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("laserlok.in", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o10", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o11", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o12", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("laserlok.out", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
@@ -122,16 +122,16 @@ namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("NOMOUSE.SP", useEndsWith: true), GetVersion16Bit, "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("NOMOUSE.SP", useEndsWith: true), GetVersion16Bit, "LaserLok [Check disc for physical ring]"),
|
||||
|
||||
// TODO: Verify if these are OR or AND
|
||||
new PathMatchSet(new PathMatch("NOMOUSE.COM", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("l16dll.dll", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("laserlok.in", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o10", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o11", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o12", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("laserlok.out", useEndsWith: true), "LaserLok"),
|
||||
new PathMatchSet(new PathMatch("NOMOUSE.COM", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("l16dll.dll", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("laserlok.in", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o10", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o11", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("laserlok.o12", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
new PathMatchSet(new PathMatch("laserlok.out", useEndsWith: true), "LaserLok [Check disc for physical ring]"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(path, matchers, any: true);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class MediaMaxCD3 : IContentCheck, IPathCheck
|
||||
public class MediaMaxCD3 : IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class OnlineRegistration : IContentCheck
|
||||
public class OnlineRegistration : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class Origin : IContentCheck, IPathCheck
|
||||
public class Origin : IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent,bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class PSXAntiModchip : IContentCheck
|
||||
{
|
||||
// TODO: Figure out PSX binary header so this can be checked explicitly.
|
||||
// For now, this means that the CheckContents check is redundant for external
|
||||
// use through other programs
|
||||
/// <inheritdoc/>
|
||||
private List<ContentMatchSet> GetContentMatchSets()
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
{
|
||||
// TODO: Detect Red Hand protection
|
||||
return new List<ContentMatchSet>
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// SOFTWARE TERMINATED\nCONSOLE MAY HAVE BEEN MODIFIED\n CALL 1-888-780-7690
|
||||
new ContentMatchSet(new byte?[]
|
||||
@@ -41,15 +45,8 @@ namespace BurnOutSharp.ProtectionType
|
||||
0x30, 0x59, 0x30, 0x02
|
||||
}, "PlayStation Anti-modchip (Japanese)"),
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Figure out PSX binary header so this can be checked explicitly.
|
||||
// For now, this means that the CheckContents check is redundant for external
|
||||
// use through other programs
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
{
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, GetContentMatchSets(), includeDebug);
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using System.Text;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
// This protection was called VOB ProtectCD / ProtectDVD in versions prior to 6
|
||||
public class ProtectDISC : IContentCheck
|
||||
public class ProtectDISC : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -21,19 +22,19 @@ namespace BurnOutSharp.ProtectionType
|
||||
var fourthSection = sections.Length < 4 ? null : sections[3];
|
||||
if (fourthSection != null)
|
||||
{
|
||||
int sectionAddr = (int)fourthSection.PointerToRawData;
|
||||
int sectionEnd = sectionAddr + (int)fourthSection.VirtualSize;
|
||||
var matchers = new List<ContentMatchSet>
|
||||
var fourthSectionData = pex.ReadRawSection(fourthSection.NameString, first: true);
|
||||
if (fourthSectionData != null)
|
||||
{
|
||||
// ACE-PCD
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[] { 0x41, 0x43, 0x45, 0x2D, 0x50, 0x43, 0x44 }, start: sectionAddr, end: sectionEnd),
|
||||
GetVersion6till8, "ProtectDISC"),
|
||||
};
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// ACE-PCD
|
||||
new ContentMatchSet(new byte?[] { 0x41, 0x43, 0x45, 0x2D, 0x50, 0x43, 0x44 }, GetVersion6till8, "ProtectDISC"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
string match = MatchUtil.GetFirstMatch(file, fourthSectionData, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the .data section, if it exists
|
||||
@@ -54,47 +55,48 @@ namespace BurnOutSharp.ProtectionType
|
||||
var secondToLastSection = sections.Length > 1 ? sections[sections.Length - 2] : null;
|
||||
if (secondToLastSection != null)
|
||||
{
|
||||
int sectionAddr = (int)secondToLastSection.PointerToRawData;
|
||||
int sectionEnd = sectionAddr + (int)secondToLastSection.VirtualSize;
|
||||
var matchers = new List<ContentMatchSet>
|
||||
var secondToLastSectionData = pex.ReadRawSection(secondToLastSection.NameString, first: true);
|
||||
if (secondToLastSectionData != null)
|
||||
{
|
||||
// VOB ProtectCD
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[]
|
||||
{
|
||||
0x56, 0x4F, 0x42, 0x20, 0x50, 0x72, 0x6F, 0x74,
|
||||
0x65, 0x63, 0x74, 0x43, 0x44
|
||||
}, start: sectionAddr, end: sectionEnd),
|
||||
GetOldVersion, "VOB ProtectCD/DVD"),
|
||||
};
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// VOB ProtectCD
|
||||
new ContentMatchSet(
|
||||
new byte?[]
|
||||
{
|
||||
0x56, 0x4F, 0x42, 0x20, 0x50, 0x72, 0x6F, 0x74,
|
||||
0x65, 0x63, 0x74, 0x43, 0x44
|
||||
},
|
||||
GetOldVersion,
|
||||
"VOB ProtectCD/DVD"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
string match = MatchUtil.GetFirstMatch(file, secondToLastSectionData, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the last section (example names: ACE5, akxpxgcv, and piofinqb)
|
||||
var lastSection = sections.LastOrDefault();
|
||||
if (lastSection != null)
|
||||
{
|
||||
int sectionAddr = (int)lastSection.PointerToRawData;
|
||||
int sectionEnd = sectionAddr + (int)lastSection.VirtualSize;
|
||||
var matchers = new List<ContentMatchSet>
|
||||
var lastSectionData = pex.ReadRawSection(lastSection.NameString, first: true);
|
||||
if (lastSectionData != null)
|
||||
{
|
||||
// HúMETINF
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[] { 0x48, 0xFA, 0x4D, 0x45, 0x54, 0x49, 0x4E, 0x46 }, start: sectionAddr, end: sectionEnd),
|
||||
GetVersion76till10, "ProtectDISC"),
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// HúMETINF
|
||||
new ContentMatchSet(new byte?[] { 0x48, 0xFA, 0x4D, 0x45, 0x54, 0x49, 0x4E, 0x46 }, GetVersion76till10, "ProtectDISC"),
|
||||
|
||||
// DCP-BOV + (char)0x00 + (char)0x00
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[] { 0x44, 0x43, 0x50, 0x2D, 0x42, 0x4F, 0x56, 0x00, 0x00 }, start: sectionAddr, end: sectionEnd),
|
||||
GetVersion3till6, "VOB ProtectCD/DVD"),
|
||||
};
|
||||
// DCP-BOV + (char)0x00 + (char)0x00
|
||||
new ContentMatchSet(new byte?[] { 0x44, 0x43, 0x50, 0x2D, 0x42, 0x4F, 0x56, 0x00, 0x00 }, GetVersion3till6, "VOB ProtectCD/DVD"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
string match = MatchUtil.GetFirstMatch(file, lastSectionData, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the .vob.pcd section, if it exists
|
||||
|
||||
@@ -1,27 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.NE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
// Renamed to ProRing at some point
|
||||
public class RingPROTECH : IContentCheck
|
||||
public class RingPROTECH : IContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
if (includeDebug)
|
||||
{
|
||||
// (char)0x00 + Allocator + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00
|
||||
new ContentMatchSet(new byte?[]
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
0x00, 0x41, 0x6C, 0x6C, 0x6F, 0x63, 0x61, 0x74,
|
||||
0x6F, 0x72, 0x00, 0x00, 0x00, 0x00
|
||||
}, "Ring PROTECH / ProRing [Check disc for physical ring]"),
|
||||
// (char)0x00 + Allocator + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x00, 0x41, 0x6C, 0x6C, 0x6F, 0x63, 0x61, 0x74,
|
||||
0x6F, 0x72, 0x00, 0x00, 0x00, 0x00
|
||||
}, "Ring PROTECH / ProRing [Check disc for physical ring]"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Confirm if these checks are only for ProRing or if they are also for older Ring PROTECH
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("protect.pro", useEndsWith: true), "Ring PROTECH / ProRing [Check disc for physical ring]"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckFilePath(string path)
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("protect.pro", useEndsWith: true), "Ring PROTECH / ProRing [Check disc for physical ring]"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(path, matchers, any: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
// TODO: Figure out how versions/version ranges work for this protection
|
||||
public class SVKProtector : IContentCheck
|
||||
public class SVKProtector : IPEContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the image file header from the executable, if possible
|
||||
if (pex?.ImageFileHeader == null)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
// TODO: Figure out how to properly distinguish SafeDisc and SafeCast since both use
|
||||
// the same generic BoG_ string. The current combination check doesn't seem consistent
|
||||
public class SafeDisc : IContentCheck, IPathCheck
|
||||
public class SafeDisc : IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <summary>
|
||||
/// Set of all PathMatchSets for this protection
|
||||
@@ -47,7 +47,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
};
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -59,22 +59,22 @@ namespace BurnOutSharp.ProtectionType
|
||||
return $"SafeCast";
|
||||
|
||||
// Get the .text section, if it exists
|
||||
string match = CheckSectionForProtection(file, fileContent, includeDebug, pex, ".text");
|
||||
string match = CheckSectionForProtection(file, includeDebug, pex, ".text");
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
|
||||
// Get the .txt2 section, if it exists
|
||||
match = CheckSectionForProtection(file, fileContent, includeDebug, pex, ".txt2");
|
||||
match = CheckSectionForProtection(file, includeDebug, pex, ".txt2");
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
|
||||
// Get the CODE section, if it exists
|
||||
match = CheckSectionForProtection(file, fileContent, includeDebug, pex, "CODE");
|
||||
match = CheckSectionForProtection(file, includeDebug, pex, "CODE");
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
|
||||
// Get the .data section, if it exists
|
||||
match = CheckSectionForProtection(file, fileContent, includeDebug, pex, ".data");
|
||||
match = CheckSectionForProtection(file, includeDebug, pex, ".data");
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
bool stxt371Section = pex.ContainsSection("stxt371", exact: true);
|
||||
bool stxt774Section = pex.ContainsSection("stxt774", exact: true);
|
||||
if (stxt371Section || stxt774Section)
|
||||
return $"SafeDisc {Get320to4xVersion(file, fileContent, null)}";
|
||||
return $"SafeDisc {Get320to4xVersion(null, null, null)}";
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -122,157 +122,190 @@ namespace BurnOutSharp.ProtectionType
|
||||
return $"{version}.{subVersion:00}.{subsubVersion:000}";
|
||||
}
|
||||
|
||||
// TODO: Continue collecting SHA-1 hashes instead of sizes
|
||||
public static string GetDPlayerXVersion(string firstMatchedString, IEnumerable<string> files)
|
||||
{
|
||||
if (firstMatchedString == null || !File.Exists(firstMatchedString))
|
||||
return string.Empty;
|
||||
|
||||
FileInfo fi = new FileInfo(firstMatchedString);
|
||||
if (fi.Length == 81408)
|
||||
return "1.0x";
|
||||
else if (fi.Length == 155648)
|
||||
return "1.1x";
|
||||
|
||||
// a8ed1613d47d1b5064300ff070484528ebb20a3b - Bundled with 1.11.000
|
||||
else if (fi.Length == 156160)
|
||||
return "1.1x-1.2x";
|
||||
|
||||
// ed680e9a13f593e7a80a69ee1035d956ab62212b
|
||||
// 66d8589343e00fa3e11bbf462e38c6f502515bea - Bundled with 1.30.010
|
||||
else if (fi.Length == 163328)
|
||||
return "1.3x";
|
||||
else if (fi.Length == 165888)
|
||||
return "1.35";
|
||||
|
||||
// 5751ae2ee805d31227cfe7680f3c8be4ab8945a3
|
||||
else if (fi.Length == 172544)
|
||||
return "1.40";
|
||||
else if (fi.Length == 173568)
|
||||
return "1.4x";
|
||||
else if (fi.Length == 136704)
|
||||
return "1.4x";
|
||||
else if (fi.Length == 138752)
|
||||
return "1.5x";
|
||||
|
||||
// f7a57f83bdc29040e20fd37cd0c6d7e6b2984180 - 78848 - Bundled with 1.00.030
|
||||
else
|
||||
return "1";
|
||||
switch (fi.Length)
|
||||
{
|
||||
case 81_408:
|
||||
return "1.0x";
|
||||
case 155_648:
|
||||
return "1.1x";
|
||||
case 156_160:
|
||||
return "1.1x-1.2x";
|
||||
case 163_328:
|
||||
return "1.3x";
|
||||
case 165_888:
|
||||
return "1.35";
|
||||
case 172_544:
|
||||
return "1.40";
|
||||
case 173_568:
|
||||
return "1.4x";
|
||||
case 136_704:
|
||||
return "1.4x";
|
||||
case 138_752:
|
||||
return "1.5x";
|
||||
default:
|
||||
return "1";
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Continue collecting SHA-1 hashes instead of sizes
|
||||
public static string GetDrvmgtVersion(string firstMatchedString, IEnumerable<string> files)
|
||||
{
|
||||
if (firstMatchedString == null || !File.Exists(firstMatchedString))
|
||||
return string.Empty;
|
||||
|
||||
FileInfo fi = new FileInfo(firstMatchedString);
|
||||
if (fi.Length == 34816)
|
||||
return "1.0x";
|
||||
|
||||
// d31725ff99be44bc1bfff171f4c4705f786b8e91
|
||||
// 87c0da1b52681fa8052a915e85699738993bea72 - Bundled with 1.11.000
|
||||
else if (fi.Length == 32256)
|
||||
return "1.1x-1.3x";
|
||||
|
||||
// 8e41db1c60bbac631b06ad4f94adb4214a0e65dc
|
||||
else if (fi.Length == 31744)
|
||||
return "1.4x";
|
||||
|
||||
// 04ed7ac39fe7a6fab497a498cbcff7da19bf0556
|
||||
// 5198da51184ca9f3a8096c6136f645b454a85f6c - Bundled with 2.30.030
|
||||
// 1437c8c149917c76f741c6dbee6b6b0cc0664f13 - Bundled with 2.40.010, 4.60.000
|
||||
else if (fi.Length == 34304)
|
||||
return "1.5x-2.40";
|
||||
|
||||
// 27d5e7f7eee1f22ebdaa903a9e58a7fdb50ef82c
|
||||
else if (fi.Length == 35840)
|
||||
return "2.51-2.60";
|
||||
|
||||
// 88c7aa6e91c9ba5f2023318048e3c3571088776f
|
||||
else if (fi.Length == 40960)
|
||||
return "2.70";
|
||||
|
||||
// ea6e24b1f306391cd78a1e7c2f2c0c31828ef004
|
||||
else if (fi.Length == 23552)
|
||||
return "2.80";
|
||||
|
||||
// e21ff43c2e663264d6cb11fbbc31eb1dcee42b1a
|
||||
// b824ed257946eee93f438b25c855e9dde7a3671a
|
||||
// 7c5ab9bdf965b70e60b99086519327168f43f362 - Bundled with 4.00.002
|
||||
else if (fi.Length == 41472)
|
||||
return "2.90-3.10";
|
||||
|
||||
// ecb341ab36c5b3b912f568d347368a6a2def8d5f
|
||||
else if (fi.Length == 24064)
|
||||
return "3.15-3.20";
|
||||
|
||||
// a5247ec0ec50b8f470c93bf23e3f2514c402d5ad - 46592 - Bundled with 4.60.000 (2x)
|
||||
else
|
||||
return "1-4";
|
||||
switch (fi.Length)
|
||||
{
|
||||
case 34_816:
|
||||
return "1.0x";
|
||||
case 32_256:
|
||||
return "1.1x-1.3x";
|
||||
case 31_744:
|
||||
return "1.4x";
|
||||
case 34_304:
|
||||
return "1.5x-2.40";
|
||||
case 35_840:
|
||||
return "2.51-2.60";
|
||||
case 40_960:
|
||||
return "2.70";
|
||||
case 23_552:
|
||||
return "2.80";
|
||||
case 41_472:
|
||||
return "2.90-3.10";
|
||||
case 24_064:
|
||||
return "3.15-3.20";
|
||||
default:
|
||||
return "1-4";
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Continue collecting SHA-1 hashes instead of sizes
|
||||
public static string GetSecdrvVersion(string firstMatchedString, IEnumerable<string> files)
|
||||
{
|
||||
if (firstMatchedString == null || !File.Exists(firstMatchedString))
|
||||
return string.Empty;
|
||||
|
||||
FileInfo fi = new FileInfo(firstMatchedString);
|
||||
if (fi.Length == 20128)
|
||||
return "2.10";
|
||||
switch (fi.Length)
|
||||
{
|
||||
case 20_128:
|
||||
return "2.10";
|
||||
case 27_440:
|
||||
return "2.30";
|
||||
case 28_624:
|
||||
return "2.40";
|
||||
case 18_768:
|
||||
return "2.50";
|
||||
case 28_400:
|
||||
return "2.51";
|
||||
case 29_392:
|
||||
return "2.60";
|
||||
case 11_376:
|
||||
return "2.70";
|
||||
case 12_464:
|
||||
return "2.80";
|
||||
case 12_400:
|
||||
return "2.90";
|
||||
case 12_528:
|
||||
return "3.10-3.15";
|
||||
case 11_973:
|
||||
return "3.20";
|
||||
|
||||
// f68a1370660f8b94f896bbba8dc6e47644d19092
|
||||
else if (fi.Length == 27440)
|
||||
return "2.30";
|
||||
// 14_304 - Bundled wtih 1.11.000
|
||||
// 10_848 - Bundled with 1.40.004
|
||||
// 143_68 - UNKNOWN
|
||||
// 163_644 - Bundled with 4.00.002, 4.60.000
|
||||
default:
|
||||
return "1-4";
|
||||
}
|
||||
}
|
||||
|
||||
// 60bc8c3222081bf76466c521474d63714afd43cd
|
||||
else if (fi.Length == 28624)
|
||||
return "2.40";
|
||||
// TODO: Continue collecting SHA-1 hashes instead of sizes
|
||||
private string GetVersionFromSHA1Hash(string sha1Hash)
|
||||
{
|
||||
switch (sha1Hash.ToLowerInvariant())
|
||||
{
|
||||
// dplayerx.dll
|
||||
case "f7a57f83bdc29040e20fd37cd0c6d7e6b2984180":
|
||||
return "1.00.030";
|
||||
case "a8ed1613d47d1b5064300ff070484528ebb20a3b":
|
||||
return "1.11.000";
|
||||
case "ed680e9a13f593e7a80a69ee1035d956ab62212b":
|
||||
return "1.3x";
|
||||
case "66d8589343e00fa3e11bbf462e38c6f502515bea":
|
||||
return "1.30.010";
|
||||
case "5751ae2ee805d31227cfe7680f3c8be4ab8945a3":
|
||||
return "1.40";
|
||||
|
||||
// 08ceca66432278d8c4e0f448436b77583c3c61c8
|
||||
else if (fi.Length == 18768)
|
||||
return "2.50";
|
||||
// drvmgt.dll
|
||||
case "d31725ff99be44bc1bfff171f4c4705f786b8e91":
|
||||
return "1.1x-1.3x";
|
||||
case "87c0da1b52681fa8052a915e85699738993bea72":
|
||||
return "1.11.000";
|
||||
case "8e41db1c60bbac631b06ad4f94adb4214a0e65dc":
|
||||
return "1.4x";
|
||||
case "04ed7ac39fe7a6fab497a498cbcff7da19bf0556":
|
||||
return "1.5x-2.40";
|
||||
case "5198da51184ca9f3a8096c6136f645b454a85f6c":
|
||||
return "2.30.030";
|
||||
case "1437c8c149917c76f741c6dbee6b6b0cc0664f13":
|
||||
return "2.40.010"; // Also 4.60.000, might be a fluke
|
||||
case "27d5e7f7eee1f22ebdaa903a9e58a7fdb50ef82c":
|
||||
return "2.51-2.60";
|
||||
case "88c7aa6e91c9ba5f2023318048e3c3571088776f":
|
||||
return "2.70";
|
||||
case "ea6e24b1f306391cd78a1e7c2f2c0c31828ef004":
|
||||
return "2.80";
|
||||
case "e21ff43c2e663264d6cb11fbbc31eb1dcee42b1a":
|
||||
case "b824ed257946eee93f438b25c855e9dde7a3671a":
|
||||
return "2.90-3.10";
|
||||
case "ecb341ab36c5b3b912f568d347368a6a2def8d5f":
|
||||
return "3.15-3.20";
|
||||
case "7c5ab9bdf965b70e60b99086519327168f43f362":
|
||||
return "4.00.002";
|
||||
case "a5247ec0ec50b8f470c93bf23e3f2514c402d5ad":
|
||||
return "4.60.000";
|
||||
|
||||
// 10080eb46bf76ac9cf9ea74372cfa4313727f0ca
|
||||
else if (fi.Length == 28400)
|
||||
return "2.51";
|
||||
else if (fi.Length == 29392)
|
||||
return "2.60";
|
||||
// secdrv.sys
|
||||
case "b64ad3ec82f2eb9fb854512cb59c25a771322181":
|
||||
return "1.11.000";
|
||||
case "ebf69b0a96adfc903b7e486708474dc864cc0c7c":
|
||||
return "1.40.004";
|
||||
case "f68a1370660f8b94f896bbba8dc6e47644d19092":
|
||||
return "2.30";
|
||||
case "60bc8c3222081bf76466c521474d63714afd43cd":
|
||||
return "2.40";
|
||||
case "08ceca66432278d8c4e0f448436b77583c3c61c8":
|
||||
return "2.50";
|
||||
case "10080eb46bf76ac9cf9ea74372cfa4313727f0ca":
|
||||
return "2.51";
|
||||
case "832d359a6de191c788b0e61e33f3d01f8d793d3c":
|
||||
return "2.70";
|
||||
case "afcfaac945a5b47712719a5e6a7eb69e36a5a6e0":
|
||||
case "cb24fbe8aa23a49e95f3c83fb15123ffb01f43f4":
|
||||
return "2.80";
|
||||
case "0383b69f98d0a9c0383c8130d52d6b431c79ac48":
|
||||
return "2.90";
|
||||
case "d7c9213cc78ff57f2f655b050c4d5ac065661aa9":
|
||||
return "3.20";
|
||||
case "fc6fedacc21a7244975b8f410ff8673285374cc2":
|
||||
return "4.00.002"; // Also 4.60.000, might be a fluke
|
||||
case "2d9f54f35f5bacb8959ef3affdc3e4209a4629cb":
|
||||
return "1-4";
|
||||
|
||||
// 832d359a6de191c788b0e61e33f3d01f8d793d3c
|
||||
else if (fi.Length == 11376)
|
||||
return "2.70";
|
||||
|
||||
// afcfaac945a5b47712719a5e6a7eb69e36a5a6e0
|
||||
// cb24fbe8aa23a49e95f3c83fb15123ffb01f43f4
|
||||
else if (fi.Length == 12464)
|
||||
return "2.80";
|
||||
|
||||
// 0383b69f98d0a9c0383c8130d52d6b431c79ac48
|
||||
else if (fi.Length == 12400)
|
||||
return "2.90";
|
||||
else if (fi.Length == 12528)
|
||||
return "3.10";
|
||||
else if (fi.Length == 12528)
|
||||
return "3.15";
|
||||
|
||||
// d7c9213cc78ff57f2f655b050c4d5ac065661aa9
|
||||
else if (fi.Length == 11973)
|
||||
return "3.20";
|
||||
|
||||
// b64ad3ec82f2eb9fb854512cb59c25a771322181 - 14304 - Bundled wtih 1.11.000
|
||||
// ebf69b0a96adfc903b7e486708474dc864cc0c7c - 10848 - Bundled with 1.40.004
|
||||
// 2d9f54f35f5bacb8959ef3affdc3e4209a4629cb - 14368 - UNKNOWN
|
||||
// fc6fedacc21a7244975b8f410ff8673285374cc2 - 163644 - Bundled with 4.00.002, 4.60.000
|
||||
else
|
||||
return "1-4";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private string CheckSectionForProtection(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, string sectionName)
|
||||
private string CheckSectionForProtection(string file, bool includeDebug, PortableExecutable pex, string sectionName)
|
||||
{
|
||||
// This subtract is needed because BoG_ starts before the section
|
||||
var sectionRaw = pex.ReadRawSection(fileContent, sectionName, first: true, offset: -64);
|
||||
var sectionRaw = pex.ReadRawSection(sectionName, first: true, offset: -64);
|
||||
if (sectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class SafeLock : IContentCheck, IPathCheck
|
||||
// https://www.cdrinfo.pl/cdr/porady/safelock/safelock.php3
|
||||
// Notes for possible future content checks:
|
||||
// - Protected files (that haven't been renamed) will contain a couple of strings at the end:
|
||||
// + SafeLock.dat
|
||||
// + Proszê w³o¿yæ p³ytê CD do CDROM-u
|
||||
// + Proszê w³o¿yæ oryginaln¹ p³ytê CD do CDROM-u
|
||||
// - Also at the end is an ASCII number possibly indicating version:
|
||||
// + 0.99.15 uses "3144288522"
|
||||
// + 0.99.22 uses "1614884465"
|
||||
// + 1.0.4 uses "3574069264"
|
||||
// - All of the above is at the very end of the file
|
||||
// - All auxiliary files (like .001, .128, and .dat) seem to be encrypted or padding data
|
||||
public class SafeLock : IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// SafeLock
|
||||
new ContentMatchSet(new byte?[] { 0x53, 0x61, 0x66, 0x65, 0x4C, 0x6F, 0x63, 0x6B }, "SafeLock"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
{
|
||||
// TODO: Verify if these are OR or AND
|
||||
// Technically all need to exist but some might be renamed
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("SafeLock.dat", useEndsWith: true), "SafeLock"),
|
||||
new PathMatchSet(new PathMatch("SafeLock.DAT", useEndsWith: true), "SafeLock"),
|
||||
new PathMatchSet(new PathMatch("SafeLock.001", useEndsWith: true), "SafeLock"),
|
||||
new PathMatchSet(new PathMatch("SafeLock.002", useEndsWith: true), "SafeLock"),
|
||||
new PathMatchSet(new PathMatch("SafeLock.128", useEndsWith: true), "SafeLock"),
|
||||
new PathMatchSet(new PathMatch("SafeLock.256", useEndsWith: true), "SafeLock"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
@@ -39,9 +39,11 @@ namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("SafeLock.dat", useEndsWith: true), "SafeLock"),
|
||||
new PathMatchSet(new PathMatch("SafeLock.DAT", useEndsWith: true), "SafeLock"),
|
||||
new PathMatchSet(new PathMatch("SafeLock.001", useEndsWith: true), "SafeLock"),
|
||||
new PathMatchSet(new PathMatch("SafeLock.002", useEndsWith: true), "SafeLock"),
|
||||
new PathMatchSet(new PathMatch("SafeLock.128", useEndsWith: true), "SafeLock"),
|
||||
new PathMatchSet(new PathMatch("SafeLock.256", useEndsWith: true), "SafeLock"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(path, matchers, any: true);
|
||||
|
||||
@@ -3,69 +3,91 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
// TODO: Investigate why White Label v8 doesn't get detected - http://redump.org/disc/48997/
|
||||
// TODO: Does the ".shr" section in the code have anything to do with this?
|
||||
// TODO: Investigate SecuROM for Macintosh
|
||||
public class SecuROM : IContentCheck, IPathCheck
|
||||
public class SecuROM : IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
string name = Utilities.GetFileDescription(pex);
|
||||
if (!string.IsNullOrWhiteSpace(name) && name.Contains("SecuROM PA"))
|
||||
return $"SecuROM PA v{Utilities.GetFileVersion(pex)}";
|
||||
|
||||
// Get the matrosch section, if it exists
|
||||
bool matroschSection = pex.ContainsSection("matrosch", exact: true);
|
||||
if (matroschSection)
|
||||
return $"SecuROM Matroschka Package";
|
||||
|
||||
// Get the .securom section, if it exists
|
||||
bool securomSection = pex.ContainsSection(".securom", exact: true);
|
||||
if (securomSection)
|
||||
return $"SecuROM {GetV7Version(fileContent)}";
|
||||
return $"SecuROM {GetV7Version(pex)}";
|
||||
|
||||
// TODO: This needs a lot of verification, including version
|
||||
// Get the .shr section, if it exists
|
||||
bool shrSection = pex.ContainsSection(".shr", exact: true);
|
||||
if (shrSection)
|
||||
return $"SecuROM 8 (White Label)";
|
||||
|
||||
// Get the .sll section, if it exists
|
||||
bool sllSection = pex.ContainsSection(".sll", exact: true);
|
||||
if (sllSection)
|
||||
return $"SecuROM SLL Protected (for SecuROM v8.x)";
|
||||
|
||||
// Search after the last section
|
||||
// TODO: Figure out how to do this in a more reasonable way
|
||||
var lastSection = sections.LastOrDefault();
|
||||
if (lastSection != null)
|
||||
{
|
||||
int sectionAddr = (int)lastSection.PointerToRawData;
|
||||
int sectionEnd = sectionAddr + (int)lastSection.VirtualSize;
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// AddD + (char)0x03 + (char)0x00 + (char)0x00 + (char)0x00)
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[] { 0x41, 0x64, 0x64, 0x44, 0x03, 0x00, 0x00, 0x00 }, start: sectionEnd),
|
||||
GetV4Version, "SecuROM"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
var postLastSectionData = pex.ReadArbitraryRange(rangeStart: sectionEnd);
|
||||
if (postLastSectionData != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// AddD + (char)0x03 + (char)0x00 + (char)0x00 + (char)0x00)
|
||||
new ContentMatchSet(new byte?[] { 0x41, 0x64, 0x64, 0x44, 0x03, 0x00, 0x00, 0x00 }, GetV4Version, "SecuROM"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, postLastSectionData, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the sections 5+, if they exist (example names: .fmqyrx, .vcltz, .iywiak)
|
||||
for (int i = 4; i < sections.Length; i++)
|
||||
{
|
||||
var nthSection = sections[i];
|
||||
string nthSectionName = Encoding.ASCII.GetString(nthSection.Name).Trim('\0');
|
||||
string nthSectionName = nthSection.NameString;
|
||||
if (nthSection != null && nthSectionName != ".idata" && nthSectionName != ".rsrc")
|
||||
{
|
||||
int sectionAddr = (int)nthSection.PointerToRawData;
|
||||
int sectionEnd = sectionAddr + (int)nthSection.VirtualSize;
|
||||
var matchers = new List<ContentMatchSet>
|
||||
var nthSectionData = pex.ReadRawSection(nthSectionName, first: true);
|
||||
if (nthSectionData != null)
|
||||
{
|
||||
// (char)0xCA + (char)0xDD + (char)0xDD + (char)0xAC + (char)0x03
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[] { 0xCA, 0xDD, 0xDD, 0xAC, 0x03 }, start: sectionAddr, end: sectionEnd),
|
||||
GetV5Version, "SecuROM"),
|
||||
};
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// (char)0xCA + (char)0xDD + (char)0xDD + (char)0xAC + (char)0x03
|
||||
new ContentMatchSet(new byte?[] { 0xCA, 0xDD, 0xDD, 0xAC, 0x03 }, GetV5Version, "SecuROM"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
string match = MatchUtil.GetFirstMatch(file, nthSectionData, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +143,14 @@ namespace BurnOutSharp.ProtectionType
|
||||
new PathMatchSet(new PathMatch("SINTF32.DLL", useEndsWith: true), "SecuROM New"),
|
||||
new PathMatchSet(new PathMatch("SINTF16.DLL", useEndsWith: true), "SecuROM New"),
|
||||
new PathMatchSet(new PathMatch("SINTFNT.DLL", useEndsWith: true), "SecuROM New"),
|
||||
|
||||
// TODO: Find more samples of this for different versions
|
||||
new PathMatchSet(new List<PathMatch>
|
||||
{
|
||||
new PathMatch("securom_v7_01.bak", useEndsWith: true),
|
||||
new PathMatch("securom_v7_01.dat", useEndsWith: true),
|
||||
new PathMatch("securom_v7_01.tmp", useEndsWith: true),
|
||||
}, "SecuROM 7.01"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
@@ -140,6 +170,10 @@ namespace BurnOutSharp.ProtectionType
|
||||
new PathMatchSet(new PathMatch("SINTF32.DLL", useEndsWith: true), "SecuROM New"),
|
||||
new PathMatchSet(new PathMatch("SINTF16.DLL", useEndsWith: true), "SecuROM New"),
|
||||
new PathMatchSet(new PathMatch("SINTFNT.DLL", useEndsWith: true), "SecuROM New"),
|
||||
|
||||
new PathMatchSet(new PathMatch("securom_v7_01.bak", useEndsWith: true), "SecuROM 7.01"),
|
||||
new PathMatchSet(new PathMatch("securom_v7_01.dat", useEndsWith: true), "SecuROM 7.01"),
|
||||
new PathMatchSet(new PathMatch("securom_v7_01.tmp", useEndsWith: true), "SecuROM 7.01"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(path, matchers, any: true);
|
||||
@@ -198,10 +232,11 @@ namespace BurnOutSharp.ProtectionType
|
||||
return $"{version}.{subVersion[0]}{subVersion[1]}.{subSubVersion[0]}{subSubVersion[1]}.{subSubSubVersion[0]}{subSubSubVersion[1]}{subSubSubVersion[2]}{subSubSubVersion[3]}";
|
||||
}
|
||||
|
||||
private static string GetV7Version(byte[] fileContent)
|
||||
// These live in the MS-DOS stub, for some reason
|
||||
private static string GetV7Version(PortableExecutable pex)
|
||||
{
|
||||
int index = 236;
|
||||
byte[] bytes = new ReadOnlySpan<byte>(fileContent, index, 4).ToArray();
|
||||
int index = 172; // 64 bytes for DOS stub, 236 bytes in total
|
||||
byte[] bytes = new ReadOnlySpan<byte>(pex.DOSStubHeader.ExecutableData, index, 4).ToArray();
|
||||
|
||||
//SecuROM 7 new and 8
|
||||
if (bytes[3] == 0x5C) // if (bytes[0] == 0xED && bytes[3] == 0x5C {
|
||||
@@ -212,8 +247,8 @@ namespace BurnOutSharp.ProtectionType
|
||||
// SecuROM 7 old
|
||||
else
|
||||
{
|
||||
index = 122;
|
||||
bytes = new ReadOnlySpan<byte>(fileContent, index, 2).ToArray();
|
||||
index = 58; // 64 bytes for DOS stub, 122 bytes in total
|
||||
bytes = new ReadOnlySpan<byte>(pex.DOSStubHeader.ExecutableData, index, 2).ToArray();
|
||||
return $"7.{bytes[0] ^ 0x10:00}.{bytes[1] ^ 0x10:0000}"; //return "7.01-7.10"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class SmartE : IContentCheck, IPathCheck
|
||||
public class SmartE : IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -33,7 +33,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
return match;
|
||||
|
||||
// Get the .tls section, if it exists
|
||||
var tlsSectionRaw = pex.ReadRawSection(fileContent, ".tls", first: false);
|
||||
var tlsSectionRaw = pex.ReadRawSection(".tls", first: false);
|
||||
match = GetMatchForSection(file, tlsSectionRaw, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
@@ -71,7 +71,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
/// <summary>
|
||||
/// Check a section for the SmartE string(s)
|
||||
/// </summary>
|
||||
private string GetMatchForSection(SectionHeader section, string file, byte[] fileContent, bool includeDebug)
|
||||
private string GetMatchForSection(SectionHeader section, string file, byte[] sectionContent, bool includeDebug)
|
||||
{
|
||||
if (section == null)
|
||||
return null;
|
||||
@@ -86,7 +86,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
"SmartE"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
return MatchUtil.GetFirstMatch(file, sectionContent, matchers, includeDebug);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
@@ -10,21 +10,10 @@ namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
// TODO: Not matching all SolidShield Wrapper v1 (See JackKeane)
|
||||
// TODO: Not matching all SolidShield Wrapper v1 (See NFS11)
|
||||
public class SolidShield : IContentCheck, IPathCheck
|
||||
public class SolidShield : IPEContentCheck, IPathCheck
|
||||
{
|
||||
/// <summary>
|
||||
/// Set of all PathMatchSets for this protection
|
||||
/// </summary>
|
||||
private static readonly List<PathMatchSet> pathMatchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("dvm.dll", useEndsWith: true), "SolidShield"),
|
||||
new PathMatchSet(new PathMatch("hc.dll", useEndsWith: true), "SolidShield"),
|
||||
new PathMatchSet(new PathMatch("solidshield-cd.dll", useEndsWith: true), "SolidShield"),
|
||||
new PathMatchSet(new PathMatch("c11prot.dll", useEndsWith: true), "SolidShield"),
|
||||
};
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug, PortableExecutable pex, NewExecutable nex)
|
||||
public string CheckPEContents(string file, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
@@ -48,7 +37,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
return $"SolidShield Activation Manager Module {GetFileVersion(pex)}";
|
||||
|
||||
// Get the .init section, if it exists
|
||||
var initSectionRaw = pex.ReadRawSection(fileContent, ".init", first: true);
|
||||
var initSectionRaw = pex.ReadRawSection(".init", first: true);
|
||||
if (initSectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
@@ -75,9 +64,9 @@ namespace BurnOutSharp.ProtectionType
|
||||
|
||||
// Search the last two available sections
|
||||
var sectionNames = pex.GetSectionNames();
|
||||
for (int i = sectionNames.Length - 2; i < sectionNames.Length; i++)
|
||||
for (int i = (sectionNames.Length >= 2 ? sectionNames.Length - 2 : 0); i < sectionNames.Length; i++)
|
||||
{
|
||||
var nthSectionRaw = pex.ReadRawSection(fileContent, sectionNames[i], first: false);
|
||||
var nthSectionRaw = pex.ReadRawSection(sectionNames[i], first: false);
|
||||
if (nthSectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
@@ -102,14 +91,30 @@ namespace BurnOutSharp.ProtectionType
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("dvm.dll", useEndsWith: true), "SolidShield"),
|
||||
new PathMatchSet(new PathMatch("hc.dll", useEndsWith: true), "SolidShield"),
|
||||
new PathMatchSet(new PathMatch("solidshield-cd.dll", useEndsWith: true), "SolidShield"),
|
||||
new PathMatchSet(new PathMatch("c11prot.dll", useEndsWith: true), "SolidShield"),
|
||||
};
|
||||
|
||||
// TODO: Verify if these are OR or AND
|
||||
return MatchUtil.GetAllMatches(files, pathMatchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckFilePath(string path)
|
||||
{
|
||||
return MatchUtil.GetFirstMatch(path, pathMatchers, any: true);
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("dvm.dll", useEndsWith: true), "SolidShield"),
|
||||
new PathMatchSet(new PathMatch("hc.dll", useEndsWith: true), "SolidShield"),
|
||||
new PathMatchSet(new PathMatch("solidshield-cd.dll", useEndsWith: true), "SolidShield"),
|
||||
new PathMatchSet(new PathMatch("c11prot.dll", useEndsWith: true), "SolidShield"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(path, matchers, any: true);
|
||||
}
|
||||
|
||||
public static string GetExeWrapperVersion(string file, byte[] fileContent, List<int> positions)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user