Compare commits

...

98 Commits
1.8.0 ... 2.0.0

Author SHA1 Message Date
Matt Nadareski
35acb77bf7 Bump version to 2.0.0 2022-03-27 20:43:49 -07:00
Matt Nadareski
e970a7b4d9 Clean up SafeDisc a little more 2022-03-18 21:05:09 -07:00
Matt Nadareski
f155291139 Update comments after confirmation of existence 2022-03-17 12:18:08 -07:00
Matt Nadareski
b0293419e1 Add note to Tages for future research 2022-03-17 12:16:41 -07:00
Matt Nadareski
09db225929 Simplify TAGES version checking 2022-03-17 12:13:11 -07:00
Matt Nadareski
0c52b4e236 Update to UnshieldSharp 1.6.7 2022-03-17 10:03:39 -07:00
Matt Nadareski
5dc30942ff Add missing TAGES version byte 2022-03-15 23:04:10 -07:00
Matt Nadareski
cab200e893 Add Shrinker PE detection 2022-03-15 22:44:10 -07:00
Matt Nadareski
c349f3a3c4 Add Gentee Installer detection (fixes #93) 2022-03-15 22:35:44 -07:00
Matt Nadareski
0acb29f2e9 Add Steam Client Engine check 2022-03-15 22:23:23 -07:00
Matt Nadareski
b66e01f7b4 Fix SLL comment 2022-03-15 22:11:37 -07:00
Matt Nadareski
8d6d215e57 Remove commented debug code 2022-03-15 22:10:13 -07:00
Matt Nadareski
d54a90a034 Add some missing SecuROM checks 2022-03-15 22:09:28 -07:00
Matt Nadareski
e1e7172561 Make ReadArbitraryRange safer 2022-03-15 21:30:46 -07:00
Matt Nadareski
6606b388f6 Remove duplicate comment 2022-03-15 15:48:05 -07:00
Matt Nadareski
b6c6c01358 Slightly rearrange generic content check invocation 2022-03-15 15:47:37 -07:00
Matt Nadareski
6886c5a4a2 Convert SVKP to PE content check 2022-03-15 15:39:35 -07:00
Matt Nadareski
87546a3dc8 Remove lingering unconfirmed TAGES check 2022-03-15 15:37:13 -07:00
Matt Nadareski
6e3028639a Fix one TAGES PE check 2022-03-15 15:05:08 -07:00
Matt Nadareski
386da02e27 Convert CExe to PE content check 2022-03-15 13:19:06 -07:00
Matt Nadareski
ec8c395ffa Streams 2022-03-15 12:39:22 -07:00
Matt Nadareski
9b98215fc9 Make SourceArray private in NE 2022-03-15 11:18:53 -07:00
Matt Nadareski
40e037fb2a Make SourceStream private 2022-03-15 11:11:54 -07:00
Matt Nadareski
17f8569a7e Only read resource in WinZipSFX 2022-03-15 11:11:44 -07:00
Matt Nadareski
1105f36cee Add hacky thing for Inno for now 2022-03-15 11:11:22 -07:00
Matt Nadareski
f9fcd8749b Add arbitrary reads to NE 2022-03-15 10:50:40 -07:00
Matt Nadareski
eef76d362a Fix arbitrary reads, update SecuROM check 2022-03-15 10:39:06 -07:00
Matt Nadareski
3b0e3693eb Add arbitrary range reading 2022-03-15 10:26:29 -07:00
Matt Nadareski
ba4c56997a Add Relocation section skeleton 2022-03-15 10:15:05 -07:00
Matt Nadareski
ca4d08567d Fix resetting position for DebugSection 2022-03-15 10:02:10 -07:00
Matt Nadareski
3211149996 Remove NE Inno check from PE path 2022-03-15 09:01:54 -07:00
Matt Nadareski
5a7e60cabb Use backward read for UPX 2022-03-15 00:30:33 -07:00
Matt Nadareski
46ff4b6ef9 Remove one use of SourceArray in SecuROM 2022-03-14 23:44:17 -07:00
Matt Nadareski
dc252e8d86 Add comments around remaining SourceArray usages 2022-03-14 23:32:19 -07:00
Matt Nadareski
133e29dc2e Add NameString to SectionHeader 2022-03-14 23:28:31 -07:00
Matt Nadareski
368cec4fc6 Remove more explicit content array usages 2022-03-14 23:17:45 -07:00
Matt Nadareski
65eea4301d Hide section complexity from content checks 2022-03-14 23:01:06 -07:00
Matt Nadareski
ceae505f4d Switch order of interface parameters 2022-03-14 22:51:17 -07:00
Matt Nadareski
a7e9164f4f Use SourceArray for PE checks 2022-03-14 22:49:35 -07:00
Matt Nadareski
3820546c07 Use SourceArray for NE checks 2022-03-14 22:43:26 -07:00
Matt Nadareski
0fa6673d21 Add debug section (nw) 2022-03-14 15:27:42 -07:00
Matt Nadareski
0a486c2195 Add another Uplay check, note 2022-03-14 15:08:27 -07:00
Matt Nadareski
a723fbefc3 Add some resource checks for WTM 2022-03-14 15:00:20 -07:00
Matt Nadareski
70e64e57dd Add PE content checks for Uplay 2022-03-14 14:56:41 -07:00
Matt Nadareski
edfc3c6c5d Add PE checks for Steam 2022-03-14 12:16:38 -07:00
Matt Nadareski
c4447fc505 Modernize path check for SolidShield a little 2022-03-14 12:09:03 -07:00
Matt Nadareski
a1d2292381 Add content checks for key2AudioXS 2022-03-14 12:08:35 -07:00
Matt Nadareski
033fb0c1ac Add utility checks to ImpulseReactor 2022-03-14 11:56:18 -07:00
Matt Nadareski
e80034abf1 Simplify CDS code a bit 2022-03-14 11:52:49 -07:00
Matt Nadareski
27e4a6c452 Add comment to old interface 2022-03-14 11:31:57 -07:00
Matt Nadareski
914497b76f Slightly safer checks before invoking 2022-03-14 11:26:10 -07:00
Matt Nadareski
513e799aa3 Migrate protections to new interfaces 2022-03-14 11:20:11 -07:00
Matt Nadareski
fcbf006e4e Migrate packers to new interfaces 2022-03-14 11:00:17 -07:00
Matt Nadareski
bef26e0fd7 Add more helpers for NE/PE 2022-03-14 10:49:02 -07:00
Matt Nadareski
3dde84f683 Add new helpers for NE/PE specific 2022-03-14 10:45:01 -07:00
Matt Nadareski
74c6aa06e0 Add new interfaces 2022-03-14 10:43:08 -07:00
Matt Nadareski
ffb529edb3 Granularly separate out executable types 2022-03-14 10:40:44 -07:00
Matt Nadareski
d1279a471c Add NE Resident Name table structures 2022-03-14 10:01:01 -07:00
Matt Nadareski
a7f406537e Add more SecuROM checks (fixes #70) 2022-03-14 09:03:43 -07:00
Matt Nadareski
df7d5150c1 Add yet another Steam exe (fixes #92) 2022-03-14 08:54:58 -07:00
Matt Nadareski
73e4569b3b Clean up recent TAGES change 2022-03-09 14:35:38 -08:00
SilasLaspada
30c249ce74 Massively overhaul TAGES detection (#87)
* Massively overhaul TAGES detection

* Address TAGES PR comments

* Address further PR comments
2022-03-09 14:00:33 -08:00
Matt Nadareski
ec83669d7d Create Executable constructors 2022-03-08 23:03:26 -08:00
Matt Nadareski
e765fb6c0b Simplify PSX Anti-Modchip a little 2022-03-08 22:33:39 -08:00
Matt Nadareski
76465d30ec Change fileContent to sectionContent in SmartE 2022-03-08 22:30:12 -08:00
Matt Nadareski
71d3771c1d Add "check disc" to LaserLok 2022-03-07 13:44:10 -08:00
Matt Nadareski
bfd9c12163 Update nuget packages 2022-03-07 13:39:04 -08:00
Matt Nadareski
eb57065562 Aggregate paths instead of relying on breaking 2022-03-03 16:36:32 -08:00
Matt Nadareski
3875f3b8fb Fix potential off-by-one error 2022-03-02 14:58:29 -08:00
Matt Nadareski
8c2bedd21e Add test program parameters 2022-03-02 10:17:50 -08:00
Matt Nadareski
b199a6aa54 Update README 2022-03-02 09:12:59 -08:00
Matt Nadareski
1b1f64c2de Lock unknown checks behind debug flag
This also re-enables some previously commented out checks that could not be verified.
2022-03-02 08:56:26 -08:00
Matt Nadareski
7b73cc9d9b Add alternate checks for StarForce (fixes #79) 2022-02-10 11:06:35 -08:00
Matt Nadareski
d9d84a01e5 Fix crash in SolidShield scanning (fixes #76) 2022-02-10 10:37:57 -08:00
Matt Nadareski
56f009ac56 Fail slower on resource parsing (fixes #81) 2022-02-10 10:28:59 -08:00
Matt Nadareski
96daf90ae8 Update protection notes in README 2022-02-04 15:24:41 -08:00
Matt Nadareski
b581cb3124 Disable content checks for RPT/ProRing 2022-02-04 15:24:05 -08:00
Matt Nadareski
4b0e39b950 Add Steam API DLLs to detection 2022-02-04 15:19:24 -08:00
Matt Nadareski
3a1c476edc Remove StarForce directory checks for now (fixes #77) 2022-01-30 21:07:35 -08:00
Matt Nadareski
0d62d5336c Add older Uplay installer to file list 2022-01-15 11:46:38 -08:00
Matt Nadareski
cf87279dfc Add content notes to SafeLock 2021-11-24 21:59:54 -08:00
Matt Nadareski
0006f7932a Remove overly-broad CDS checks 2021-11-22 20:30:58 -08:00
Matt Nadareski
841a39c6c7 Overhaul SafeLock checks 2021-11-21 21:18:56 -08:00
Matt Nadareski
60b12f25a6 Disable SafeLock content check for now 2021-11-21 14:04:16 -08:00
SilasLaspada
f2b96b6c50 Fix InstallAnywhere reporting (#71)
* Fix InstallAnywhere reporting

* Fix formatting

* Fix formatting again
2021-11-20 23:22:10 -08:00
Matt Nadareski
d2fad1ab29 Fix Alpha-ROM... again (fixes #69) 2021-10-29 15:19:50 -07:00
Matt Nadareski
6f6755b218 Remove over-matching TAGES check 2021-10-27 23:08:16 -07:00
SilasLaspada
9a2f2e6f17 Add initial detection for InstallAnywhere (#67) 2021-10-26 10:23:08 -07:00
Matt Nadareski
d9ca550e3b Add ProRing path checks; add note (fixes #68) 2021-10-26 10:12:21 -07:00
Matt Nadareski
ec66e87ee6 Remove one note from Alpha-ROM 2021-10-21 21:33:50 -07:00
Matt Nadareski
53ce3aee74 Refine Alpha-ROM checks; add notes 2021-10-20 21:06:43 -07:00
Matt Nadareski
1ecb06f020 Bump AppVeyor version 2021-09-24 10:44:55 -07:00
Matt Nadareski
3ce4ac785e Comment out probable NE-only check 2021-09-23 15:13:57 -07:00
Matt Nadareski
1df157434d Remove debug print 2021-09-23 15:05:46 -07:00
Matt Nadareski
594f001dda Add NE check for CD-Cops; add notes 2021-09-23 15:05:30 -07:00
Matt Nadareski
c2c6bc268e Update README 2021-09-23 13:51:28 -07:00
Matt Nadareski
7aa2207edd Add PEtite detection; add notes 2021-09-23 13:43:57 -07:00
Matt Nadareski
22aa1642a6 Partial cleanup of CD/DVD-Cops; add notes 2021-09-23 13:33:48 -07:00
114 changed files with 3009 additions and 1463 deletions

View File

@@ -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>

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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),

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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.

View 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
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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.

View File

@@ -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.

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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.

View File

@@ -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.

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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;
}
}
}

View File

@@ -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:

View File

@@ -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;
}
}
}

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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+.

View File

@@ -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.

View File

@@ -1,4 +1,3 @@
using System;
using System.IO;
using BurnOutSharp.Tools;

View File

@@ -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
}
}

View File

@@ -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");

View File

@@ -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);
}
}

View 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);
}
}

View 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);
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}
}

View 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;
}
}
}

View File

@@ -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";
}
}
}

View 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)";
}
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -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;

View 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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -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>

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;

View File

@@ -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/>

View File

@@ -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;

View File

@@ -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;

View File

@@ -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>

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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/>

View File

@@ -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;

View File

@@ -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;

View File

@@ -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"),

View File

@@ -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;

View File

@@ -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>

View File

@@ -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)
{

View File

@@ -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;
}
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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)

View File

@@ -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>

View File

@@ -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);

View File

@@ -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"
}
}

View File

@@ -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>

View File

@@ -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