mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-07-09 02:16:46 +00:00
Combine SafeCast into SafeDisc; improvements
This commit is contained in:
@@ -233,17 +233,38 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
/// <summary>
|
||||
/// Get the raw bytes from a section, if possible
|
||||
/// </summary>
|
||||
public byte[] ReadRawSection(Stream stream, string sectionName, bool first = true)
|
||||
public byte[] ReadRawSection(Stream stream, string sectionName, bool first = true, int offset = 0)
|
||||
{
|
||||
// Special cases for non-offset data
|
||||
if (offset == 0)
|
||||
{
|
||||
switch (sectionName)
|
||||
{
|
||||
case ".data":
|
||||
return DataSectionRaw;
|
||||
case ".edata":
|
||||
return ExportDataSectionRaw;
|
||||
case ".idata":
|
||||
return ImportDataSectionRaw;
|
||||
case ".rdata":
|
||||
return ResourceDataSectionRaw;
|
||||
case ".text":
|
||||
return TextSectionRaw;
|
||||
}
|
||||
}
|
||||
|
||||
var section = first ? GetFirstSection(sectionName, true) : GetLastSection(sectionName, true);
|
||||
if (section == null)
|
||||
return null;
|
||||
|
||||
lock (stream)
|
||||
{
|
||||
int startingIndex = (int)Math.Max(section.PointerToRawData + offset, 0);
|
||||
int readLength = (int)Math.Min(section.VirtualSize - offset, stream.Length);
|
||||
|
||||
long originalPosition = stream.Position;
|
||||
stream.Seek((int)section.PointerToRawData, SeekOrigin.Begin);
|
||||
byte[] sectionData = stream.ReadBytes((int)section.VirtualSize);
|
||||
stream.Seek(startingIndex, SeekOrigin.Begin);
|
||||
byte[] sectionData = stream.ReadBytes(readLength);
|
||||
stream.Seek(originalPosition, SeekOrigin.Begin);
|
||||
return sectionData;
|
||||
}
|
||||
@@ -253,14 +274,34 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
/// <summary>
|
||||
/// Get the raw bytes from a section, if possible
|
||||
/// </summary>
|
||||
public byte[] ReadRawSection(byte[] content, string sectionName, bool first = true)
|
||||
public byte[] ReadRawSection(byte[] content, string sectionName, bool first = true, int offset = 0)
|
||||
{
|
||||
// Special cases for non-offset data
|
||||
if (offset == 0)
|
||||
{
|
||||
switch (sectionName)
|
||||
{
|
||||
case ".data":
|
||||
return DataSectionRaw;
|
||||
case ".edata":
|
||||
return ExportDataSectionRaw;
|
||||
case ".idata":
|
||||
return ImportDataSectionRaw;
|
||||
case ".rdata":
|
||||
return ResourceDataSectionRaw;
|
||||
case ".text":
|
||||
return TextSectionRaw;
|
||||
}
|
||||
}
|
||||
|
||||
var section = first ? GetFirstSection(sectionName, true) : GetLastSection(sectionName, true);
|
||||
if (section == null)
|
||||
return null;
|
||||
|
||||
int offset = (int)section.PointerToRawData;
|
||||
return content.ReadBytes(ref offset, (int)section.VirtualSize);
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -358,7 +399,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
pex.DataSectionRaw = pex.ReadRawSection(stream, ".data", false) ?? pex.ReadRawSection(stream, "DATA", false);
|
||||
|
||||
// Export Table
|
||||
pex.ImportDataSectionRaw = pex.ReadRawSection(stream, ".edata", false);
|
||||
pex.ExportDataSectionRaw = pex.ReadRawSection(stream, ".edata", false);
|
||||
|
||||
// Import Table
|
||||
pex.ImportDataSectionRaw = pex.ReadRawSection(stream, ".idata", false);
|
||||
@@ -446,7 +487,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft
|
||||
pex.DataSectionRaw = pex.ReadRawSection(content, ".data", false) ?? pex.ReadRawSection(content, "DATA", false);
|
||||
|
||||
// Export Table
|
||||
pex.ImportDataSectionRaw = pex.ReadRawSection(content, ".edata", false);
|
||||
pex.ExportDataSectionRaw = pex.ReadRawSection(content, ".edata", false);
|
||||
|
||||
// Import Table
|
||||
pex.ImportDataSectionRaw = pex.ReadRawSection(content, ".idata", false);
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
// TODO: Add the content checks from SafeDisc here
|
||||
// TODO: Investigate if this entire file should be wrapped into SafeDisc
|
||||
public class SafeCast : 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>
|
||||
{
|
||||
new ContentMatchSet(new List<byte?[]>
|
||||
{
|
||||
// BoG_ *90.0&!! Yy>
|
||||
new byte?[]
|
||||
{
|
||||
0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30,
|
||||
0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59,
|
||||
0x79, 0x3E
|
||||
},
|
||||
|
||||
// product activation library
|
||||
new byte?[]
|
||||
{
|
||||
0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x20,
|
||||
0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69,
|
||||
0x6F, 0x6E, 0x20, 0x6C, 0x69, 0x62, 0x72, 0x61,
|
||||
0x72, 0x79
|
||||
},
|
||||
}, GetVersion, "SafeCast"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("cdac11ba.exe", useEndsWith: true), "SafeCast"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckFilePath(string path)
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("cdac11ba.exe", useEndsWith: true), "SafeCast"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(path, matchers, any: true);
|
||||
}
|
||||
|
||||
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
|
||||
{
|
||||
int index = positions[0] + 20; // Begin reading after "BoG_ *90.0&!! Yy>" for old SafeDisc
|
||||
int version = fileContent.ReadInt32(ref index);
|
||||
int subVersion = fileContent.ReadInt32(ref index);
|
||||
int subsubVersion = fileContent.ReadInt32(ref index);
|
||||
|
||||
if (version != 0)
|
||||
return $"{version}.{subVersion:00}.{subsubVersion:000}";
|
||||
|
||||
index = positions[0] + 18 + 14; // Begin reading after "BoG_ *90.0&!! Yy>" for newer SafeDisc
|
||||
version = fileContent.ReadInt32(ref index);
|
||||
subVersion = fileContent.ReadInt32(ref index);
|
||||
subsubVersion = fileContent.ReadInt32(ref index);
|
||||
|
||||
if (version == 0)
|
||||
return string.Empty;
|
||||
|
||||
return $"{version}.{subVersion:00}.{subsubVersion:000}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
@@ -7,6 +8,8 @@ using BurnOutSharp.Tools;
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
@@ -38,6 +41,9 @@ namespace BurnOutSharp.ProtectionType
|
||||
new PathMatchSet(new PathMatch("00000001.LT1", useEndsWith: true), "SafeDisc Lite"),
|
||||
|
||||
new PathMatchSet(".SafeDiscDVD.bundle", "SafeDisc for Macintosh"),
|
||||
|
||||
new PathMatchSet(new PathMatch("cdac11ba.exe", useEndsWith: true), "SafeCast"),
|
||||
new PathMatchSet(new PathMatch("cdac14ba.dll", useEndsWith: true), "SafeCast"),
|
||||
};
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -48,117 +54,29 @@ namespace BurnOutSharp.ProtectionType
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .text section, if it exists -- TODO: Figure out how to capture this automatically
|
||||
var textSection = pex.GetFirstSection(".text", exact: true);
|
||||
if (textSection != null)
|
||||
{
|
||||
// This subtract is needed because BoG_ starts before the .text section
|
||||
int sectionAddr = (int)textSection.PointerToRawData - 64;
|
||||
int sectionEnd = sectionAddr + (int)textSection.VirtualSize;
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// BoG_ *90.0&!! Yy>
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[]
|
||||
{
|
||||
0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30,
|
||||
0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59,
|
||||
0x79, 0x3E
|
||||
}, start: sectionAddr, end: sectionEnd),
|
||||
GetVersion, "SafeDisc"),
|
||||
string name = Utilities.GetFileDescription(pex);
|
||||
if (!string.IsNullOrWhiteSpace(name) && name.Equals("SafeCast2", StringComparison.OrdinalIgnoreCase))
|
||||
return $"SafeCast";
|
||||
|
||||
// (char)0x00 + (char)0x00 + BoG_
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[] { 0x00, 0x00, 0x42, 0x6F, 0x47, 0x5F }, start: sectionAddr, end: sectionEnd),
|
||||
Get320to4xVersion, "SafeDisc"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
// Get the .text section, if it exists
|
||||
string match = CheckSectionForProtection(file, fileContent, includeDebug, pex, ".text");
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
|
||||
// Get the .txt2 section, if it exists
|
||||
var txt2Section = pex.GetFirstSection(".txt2", exact: true);
|
||||
if (txt2Section != null)
|
||||
{
|
||||
// This subtract is needed because BoG_ starts before the .txt2 section
|
||||
int sectionAddr = (int)txt2Section.PointerToRawData - 64;
|
||||
int sectionEnd = sectionAddr + (int)txt2Section.VirtualSize;
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// BoG_ *90.0&!! Yy>
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[]
|
||||
{
|
||||
0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30,
|
||||
0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59,
|
||||
0x79, 0x3E
|
||||
}, start: sectionAddr, end: sectionEnd),
|
||||
GetVersion, "SafeDisc"),
|
||||
|
||||
// (char)0x00 + (char)0x00 + BoG_
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[] { 0x00, 0x00, 0x42, 0x6F, 0x47, 0x5F }, start: sectionAddr, end: sectionEnd),
|
||||
Get320to4xVersion, "SafeDisc"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
match = CheckSectionForProtection(file, fileContent, includeDebug, pex, ".txt2");
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
|
||||
// Get the CODE section, if it exists
|
||||
var codeSection = pex.GetFirstSection("CODE", exact: true);
|
||||
if (codeSection != null)
|
||||
{
|
||||
// This subtract is needed because BoG_ starts before the CODE section
|
||||
int sectionAddr = (int)codeSection.PointerToRawData - 64;
|
||||
int sectionEnd = sectionAddr + (int)codeSection.VirtualSize;
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// BoG_ *90.0&!! Yy>
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[]
|
||||
{
|
||||
0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30,
|
||||
0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59,
|
||||
0x79, 0x3E
|
||||
}, start: sectionAddr, end: sectionEnd),
|
||||
GetVersion, "SafeDisc"),
|
||||
|
||||
// (char)0x00 + (char)0x00 + BoG_
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[] { 0x00, 0x00, 0x42, 0x6F, 0x47, 0x5F }, start: sectionAddr, end: sectionEnd),
|
||||
Get320to4xVersion, "SafeDisc"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
match = CheckSectionForProtection(file, fileContent, includeDebug, pex, "CODE");
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
|
||||
// Get the .data section, if it exists
|
||||
if (pex.DataSectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// BoG_ *90.0&!! Yy>
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30,
|
||||
0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59,
|
||||
0x79, 0x3E
|
||||
}, GetVersion, "SafeDisc"),
|
||||
|
||||
// (char)0x00 + (char)0x00 + BoG_
|
||||
new ContentMatchSet(new byte?[] { 0x00, 0x00, 0x42, 0x6F, 0x47, 0x5F }, Get320to4xVersion, "SafeDisc"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, pex.DataSectionRaw, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
match = CheckSectionForProtection(file, fileContent, includeDebug, pex, ".data");
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
|
||||
// Get the stxt371 and stxt774 sections, if they exist -- TODO: Confirm if both are needed or either/or is fine
|
||||
bool stxt371Section = pex.ContainsSection("stxt371", exact: true);
|
||||
@@ -350,5 +268,51 @@ namespace BurnOutSharp.ProtectionType
|
||||
else
|
||||
return "1-4";
|
||||
}
|
||||
|
||||
private string CheckSectionForProtection(string file, byte[] fileContent, 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);
|
||||
if (sectionRaw != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
new ContentMatchSet(new List<byte?[]>
|
||||
{
|
||||
// BoG_ *90.0&!! Yy>
|
||||
new byte?[]
|
||||
{
|
||||
0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30,
|
||||
0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59,
|
||||
0x79, 0x3E
|
||||
},
|
||||
|
||||
// product activation library
|
||||
new byte?[]
|
||||
{
|
||||
0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x20,
|
||||
0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69,
|
||||
0x6F, 0x6E, 0x20, 0x6C, 0x69, 0x62, 0x72, 0x61,
|
||||
0x72, 0x79
|
||||
},
|
||||
}, GetVersion, "SafeCast"),
|
||||
|
||||
// BoG_ *90.0&!! Yy>
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30,
|
||||
0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59,
|
||||
0x79, 0x3E
|
||||
}, GetVersion, "SafeDisc"),
|
||||
|
||||
// (char)0x00 + (char)0x00 + BoG_
|
||||
new ContentMatchSet(new byte?[] { 0x00, 0x00, 0x42, 0x6F, 0x47, 0x5F }, Get320to4xVersion, "SafeDisc"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, sectionRaw, matchers, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user