mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-09-22 14:54:56 +00:00
Combine VOB into ProtectDISC; add notes
This also means that EVORE is no longer relevant to the code and has been fully removed.
This commit is contained in:
@@ -62,7 +62,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
long lastPosition = stream.Position;
|
||||
try
|
||||
{
|
||||
int dataEntryAddress = (int)EVORE.ConvertVirtualAddress(rdte.DataEntryOffset, sections);
|
||||
int dataEntryAddress = (int)ConvertVirtualAddress(rdte.DataEntryOffset, sections);
|
||||
if (dataEntryAddress > 0)
|
||||
{
|
||||
stream.Seek(dataEntryAddress, SeekOrigin.Begin);
|
||||
@@ -93,7 +93,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
{
|
||||
try
|
||||
{
|
||||
int dataEntryAddress = (int)EVORE.ConvertVirtualAddress(rdte.DataEntryOffset, sections);
|
||||
int dataEntryAddress = (int)ConvertVirtualAddress(rdte.DataEntryOffset, sections);
|
||||
if (dataEntryAddress > 0)
|
||||
rdte.DataEntry = ResourceDataEntry.Deserialize(content, dataEntryAddress);
|
||||
}
|
||||
@@ -104,5 +104,29 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
|
||||
|
||||
return rdte;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a virtual address to a physical one
|
||||
/// </summary>
|
||||
/// <param name="virtualAddress">Virtual address to convert</param>
|
||||
/// <param name="sections">Array of sections to check against</param>
|
||||
/// <returns>Physical address, 0 on error</returns>
|
||||
private static uint ConvertVirtualAddress(uint virtualAddress, SectionHeader[] sections)
|
||||
{
|
||||
// Loop through all of the sections
|
||||
for (int i = 0; i < sections.Length; i++)
|
||||
{
|
||||
// If the section is invalid, just skip it
|
||||
if (sections[i] == null)
|
||||
continue;
|
||||
|
||||
// Attempt to derive the physical address from the current section
|
||||
var section = sections[i];
|
||||
if (virtualAddress >= section.VirtualAddress && virtualAddress <= section.VirtualAddress + section.VirtualSize)
|
||||
return section.PointerToRawData + virtualAddress - section.VirtualAddress;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
// TODO: Investigate the connection between this and VOB Protect CD/DVD
|
||||
// This protection was called VOB ProtectCD / ProtectDVD in versions prior to 6
|
||||
public class ProtectDISC : IContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
@@ -40,6 +41,48 @@ namespace BurnOutSharp.ProtectionType
|
||||
return match;
|
||||
}
|
||||
|
||||
// Get the .data section, if it exists
|
||||
var dataSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith(".data"));
|
||||
if (dataSection != null)
|
||||
{
|
||||
int sectionAddr = (int)dataSection.PointerToRawData;
|
||||
int sectionEnd = sectionAddr + (int)dataSection.VirtualSize;
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// 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"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
|
||||
// Get the second to last section
|
||||
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>
|
||||
{
|
||||
// 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"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, 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)
|
||||
@@ -52,6 +95,11 @@ namespace BurnOutSharp.ProtectionType
|
||||
new ContentMatchSet(
|
||||
new ContentMatch(new byte?[] { 0x48, 0xFA, 0x4D, 0x45, 0x54, 0x49, 0x4E, 0x46 }, start: sectionAddr, end: sectionEnd),
|
||||
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"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
|
||||
@@ -59,9 +107,39 @@ namespace BurnOutSharp.ProtectionType
|
||||
return match;
|
||||
}
|
||||
|
||||
// Get the .vob.pcd section, if it exists
|
||||
var vobpcdSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith(".vob.pcd"));
|
||||
if (vobpcdSection != null)
|
||||
return "VOB ProtectCD";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetOldVersion(string file, byte[] fileContent, List<int> positions)
|
||||
{
|
||||
int position = positions[0] + 16; // Begin reading after "VOB ProtectCD"
|
||||
char[] version = new ArraySegment<byte>(fileContent, position, 4).Select(b => (char)b).ToArray();
|
||||
if (char.IsNumber(version[0]) && char.IsNumber(version[2]) && char.IsNumber(version[3]))
|
||||
return $"{version[0]}.{version[2]}{version[3]}";
|
||||
|
||||
// Look for the legacy support version
|
||||
position = positions[0] + "VOB ProtectCD with LEGACY SYSIPHOS Support V".Length;
|
||||
version = new ArraySegment<byte>(fileContent, position, 7).Select(b => (char)b).ToArray();
|
||||
if (char.IsNumber(version[0]) && char.IsNumber(version[2]) && char.IsNumber(version[4]))
|
||||
return new string(version);
|
||||
|
||||
return "old";
|
||||
}
|
||||
|
||||
public static string GetVersion3till6(string file, byte[] fileContent, List<int> positions)
|
||||
{
|
||||
string version = GetVOBVersion(fileContent, positions[0]);
|
||||
if (version.Length > 0)
|
||||
return version;
|
||||
|
||||
return $"5.9-6.0 {GetVOBBuild(fileContent, positions[0])}";
|
||||
}
|
||||
|
||||
public static string GetVersion6till8(string file, byte[] fileContent, List<int> positions)
|
||||
{
|
||||
string version, strBuild = string.Empty;
|
||||
@@ -196,5 +274,23 @@ namespace BurnOutSharp.ProtectionType
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private static string GetVOBBuild(byte[] fileContent, int position)
|
||||
{
|
||||
if (!char.IsNumber((char)fileContent[position - 13]))
|
||||
return string.Empty; //Build info removed
|
||||
|
||||
int build = BitConverter.ToInt16(fileContent, position - 4); // Check if this is supposed to be a 4-byte read
|
||||
return $" (Build {build})";
|
||||
}
|
||||
|
||||
// TODO: Ensure that this version finding works for all known versions
|
||||
private static string GetVOBVersion(byte[] fileContent, int position)
|
||||
{
|
||||
byte version = fileContent[position - 2];
|
||||
byte subVersion = (byte)((fileContent[position - 3] & 0xF0) >> 4);
|
||||
byte subSubVersion = (byte)((fileContent[position - 4] & 0xF0) >> 4);
|
||||
return $"{version}.{subVersion}.{subSubVersion}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Tools;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
{
|
||||
public class VOBProtectCDDVD : IContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public List<ContentMatchSet> GetContentMatchSets()
|
||||
{
|
||||
return 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"),
|
||||
|
||||
// DCP-BOV + (char)0x00 + (char)0x00
|
||||
new ContentMatchSet(new byte?[] { 0x44, 0x43, 0x50, 0x2D, 0x42, 0x4F, 0x56, 0x00, 0x00 }, GetVersion, "VOB ProtectCD/DVD"),
|
||||
|
||||
// .vob.pcd
|
||||
new ContentMatchSet(new byte?[] { 0x2E, 0x76, 0x6F, 0x62, 0x2E, 0x70, 0x63, 0x64 }, "VOB ProtectCD"),
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug = false) => null;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("VOB-PCD.KEY", useEndsWith: true), "VOB ProtectCD/DVD"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string CheckFilePath(string path)
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("VOB-PCD.KEY", useEndsWith: true), "VOB ProtectCD/DVD"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(path, matchers, any: true);
|
||||
}
|
||||
|
||||
public static string GetOldVersion(string file, byte[] fileContent, List<int> positions)
|
||||
{
|
||||
int position = positions[0]--; // TODO: Verify this subtract
|
||||
char[] version = new ArraySegment<byte>(fileContent, position + 16, 4).Select(b => (char)b).ToArray(); // Begin reading after "VOB ProtectCD"
|
||||
if (char.IsNumber(version[0]) && char.IsNumber(version[2]) && char.IsNumber(version[3]))
|
||||
return $"{version[0]}.{version[2]}{version[3]}";
|
||||
|
||||
return "old";
|
||||
}
|
||||
|
||||
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
|
||||
{
|
||||
string version = GetVersion(fileContent, --positions[0]); // TODO: Verify this subtract
|
||||
if (version.Length > 0)
|
||||
return version;
|
||||
|
||||
version = SearchProtectDiscVersion(file, fileContent);
|
||||
if (version.Length > 0)
|
||||
{
|
||||
if (version.StartsWith("2"))
|
||||
version = $"6{version.Substring(1)}";
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
return $"5.9-6.0 {GetBuild(fileContent, positions[0])}";
|
||||
}
|
||||
|
||||
private static string GetBuild(byte[] fileContent, int position)
|
||||
{
|
||||
if (!char.IsNumber((char)fileContent[position - 13]))
|
||||
return string.Empty; //Build info removed
|
||||
|
||||
int build = BitConverter.ToInt16(fileContent, position - 4); // Check if this is supposed to be a 4-byte read
|
||||
return $" (Build {build})";
|
||||
}
|
||||
|
||||
private static string GetVersion(byte[] fileContent, int position)
|
||||
{
|
||||
if (fileContent[position - 2] == 5)
|
||||
{
|
||||
int index = position - 4;
|
||||
byte subsubVersion = (byte)((fileContent[index] & 0xF0) >> 4);
|
||||
index++;
|
||||
byte subVersion = (byte)((fileContent[index] & 0xF0) >> 4);
|
||||
return $"5.{subVersion}.{subsubVersion}";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// TODO: Analyze this method and figure out if this can be done without attempting execution
|
||||
private static string SearchProtectDiscVersion(string file, byte[] fileContent)
|
||||
{
|
||||
// If the file isn't executable, don't even bother
|
||||
if (!EVORE.IsPEExecutable(fileContent))
|
||||
return string.Empty;
|
||||
|
||||
// Get some of the required paths
|
||||
string tempexe = EVORE.MakeTempFile(fileContent);
|
||||
string[] dependentDlls = EVORE.CopyDependentDlls(file, fileContent);
|
||||
string pdPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ProtectDisc");
|
||||
|
||||
// Clean up any temp files before attempting to run
|
||||
Utilities.SafeTempDelete("a*.tmp");
|
||||
Utilities.SafeTempDelete("PCD*.sys");
|
||||
if (Directory.Exists(pdPath))
|
||||
Utilities.SafeDelete(Path.Combine(pdPath, "p*.dll"));
|
||||
|
||||
// Try to safely start the temp executable
|
||||
Process exe = EVORE.StartSafe(tempexe);
|
||||
if (exe == null)
|
||||
return string.Empty;
|
||||
|
||||
string version = "";
|
||||
Process[] processes = new Process[0];
|
||||
DateTime timestart = DateTime.Now;
|
||||
do
|
||||
{
|
||||
exe.Refresh();
|
||||
string[] files = null;
|
||||
|
||||
// Check for ProtectDisc 8.2-x
|
||||
if (Directory.Exists(pdPath))
|
||||
files = Directory.GetFiles(pdPath, "p*.dll");
|
||||
|
||||
if (files.Any())
|
||||
{
|
||||
string fileVersion = Utilities.GetFileVersion(files[0]);
|
||||
if (!string.IsNullOrWhiteSpace(fileVersion))
|
||||
{
|
||||
version = fileVersion;
|
||||
|
||||
// ProtectDisc 9 uses a ProtectDisc-Core dll version 8.0.x
|
||||
if (version.StartsWith("8.0"))
|
||||
version = string.Empty;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//check for ProtectDisc 7.1-8.1
|
||||
files = Directory.GetFiles(Path.GetTempPath(), "a*.tmp");
|
||||
if (files.Any())
|
||||
{
|
||||
string fileVersion = Utilities.GetFileVersion(files[0]);
|
||||
if (!string.IsNullOrWhiteSpace(fileVersion))
|
||||
{
|
||||
version = fileVersion;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (exe.HasExited)
|
||||
break;
|
||||
|
||||
processes = Process.GetProcessesByName(exe.ProcessName);
|
||||
if (processes.Length == 2)
|
||||
{
|
||||
processes[0].Refresh();
|
||||
processes[1].Refresh();
|
||||
if (processes[1].WorkingSet64 > exe.WorkingSet64)
|
||||
exe = processes[1];
|
||||
else if (processes[0].WorkingSet64 > exe.WorkingSet64) //else if (processes[0].Modules.Count > exe.Modules.Count)
|
||||
exe = processes[0];
|
||||
}
|
||||
} while (processes.Length > 0 && DateTime.Now.Subtract(timestart).TotalSeconds < 20);
|
||||
|
||||
Thread.Sleep(500);
|
||||
if (!exe.HasExited)
|
||||
{
|
||||
processes = Process.GetProcessesByName(exe.ProcessName);
|
||||
if (processes.Length == 2)
|
||||
{
|
||||
try
|
||||
{
|
||||
processes[0].Kill();
|
||||
}
|
||||
catch { }
|
||||
processes[0].Close();
|
||||
try
|
||||
{
|
||||
processes[1].Kill();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
else
|
||||
{
|
||||
exe.Refresh();
|
||||
try
|
||||
{
|
||||
exe.Kill();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
exe.Close();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Clean up any temp files after running
|
||||
Utilities.SafeDelete(tempexe);
|
||||
Utilities.SafeTempDelete("a*.tmp");
|
||||
Utilities.SafeTempDelete("PCD*.sys");
|
||||
if (Directory.Exists(pdPath))
|
||||
Utilities.SafeDelete(Path.Combine(pdPath, "p*.dll"));
|
||||
|
||||
if (dependentDlls != null)
|
||||
{
|
||||
foreach (string dll in dependentDlls)
|
||||
{
|
||||
Utilities.SafeDelete(dll);
|
||||
}
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
//this file is part of BurnOut
|
||||
//Copyright (C)2005-2010 Gernot Knippen
|
||||
//Ported code with augments Copyright (C)2018 Matt Nadareski
|
||||
//
|
||||
//This program is free software; you can redistribute it and/or
|
||||
//modify it under the terms of the GNU General Public License
|
||||
//as published by the Free Software Foundation; either
|
||||
//version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
//This program is distributed in the hope that it will be useful,
|
||||
//but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
//GNU General Public License for more details.
|
||||
//
|
||||
//You can get a copy of the GNU General Public License
|
||||
//by writing to the Free Software
|
||||
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.ExecutableType.Microsoft;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Headers;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Sections;
|
||||
using BurnOutSharp.ExecutableType.Microsoft.Tables;
|
||||
|
||||
namespace BurnOutSharp.Tools
|
||||
{
|
||||
internal static class EVORE
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert a virtual address to a physical one
|
||||
/// </summary>
|
||||
/// <param name="virtualAddress">Virtual address to convert</param>
|
||||
/// <param name="sections">Array of sections to check against</param>
|
||||
/// <returns>Physical address, 0 on error</returns>
|
||||
internal static uint ConvertVirtualAddress(uint virtualAddress, SectionHeader[] sections)
|
||||
{
|
||||
// Loop through all of the sections
|
||||
for (int i = 0; i < sections.Length; i++)
|
||||
{
|
||||
// If the section is invalid, just skip it
|
||||
if (sections[i] == null)
|
||||
continue;
|
||||
|
||||
// Attempt to derive the physical address from the current section
|
||||
var section = sections[i];
|
||||
if (virtualAddress >= section.VirtualAddress && virtualAddress <= section.VirtualAddress + section.VirtualSize)
|
||||
return section.PointerToRawData + virtualAddress - section.VirtualAddress;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the file contents represent a PE executable
|
||||
/// </summary>
|
||||
/// <param name="fileContent">File contents to check</param>
|
||||
/// <returns>True if the file is an EXE, false otherwise</returns>
|
||||
internal static bool IsPEExecutable(byte[] fileContent)
|
||||
{
|
||||
if (fileContent == null)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
|
||||
return !pex.ImageFileHeader.Characteristics.HasFlag(ImageObjectCharacteristics.IMAGE_FILE_DLL);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the file contents to a temporary file, if possible
|
||||
/// </summary>
|
||||
/// <param name="fileContent">File contents to write</param>
|
||||
/// <param name="extension">Optional extension for the temporary file, defaults to ".exe"</param>
|
||||
/// <returns>Name of the new temporary file, null on error</returns>
|
||||
internal static string MakeTempFile(byte[] fileContent, string extension = ".exe")
|
||||
{
|
||||
// Ensure the extension is set
|
||||
if (string.IsNullOrWhiteSpace(extension))
|
||||
extension = ".exe";
|
||||
else if (!extension.StartsWith("."))
|
||||
extension = $".{extension}";
|
||||
|
||||
// Get the temporary path to use
|
||||
string tempFileName = Guid.NewGuid().ToString();
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), "tmp", $"{tempFileName}{extension}");
|
||||
|
||||
// Create and fill the file, if possible
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
|
||||
using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(tempPath)))
|
||||
{
|
||||
bw.Write(fileContent);
|
||||
}
|
||||
|
||||
return Path.GetFullPath(tempPath);
|
||||
}
|
||||
catch { }
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies all required DLLs for a given executable
|
||||
/// </summary>
|
||||
/// <param name="file">Temporary file path</param>
|
||||
/// <param name="fileContent">File contents to read</param>
|
||||
/// <returns>Paths for all of the copied DLLs, null on error</returns>
|
||||
internal static string[] CopyDependentDlls(string file, byte[] fileContent)
|
||||
{
|
||||
if (fileContent == null)
|
||||
return null;
|
||||
|
||||
// Process each of the DLLs that it finds
|
||||
try
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
// Read all of the executable header information
|
||||
PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
|
||||
|
||||
// Find the import directory entry
|
||||
DataDirectoryHeader idei = pex.OptionalHeader.DataDirectories[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
|
||||
// Set the table index and size
|
||||
int tableIndex = (int)ConvertVirtualAddress(idei.VirtualAddress, pex.SectionTable);
|
||||
int tableSize = (int)idei.Size;
|
||||
if (tableIndex <= 0 || tableSize <= 0)
|
||||
return null;
|
||||
|
||||
// Load the table from index
|
||||
ImportDataSection idata = ImportDataSection.Deserialize(fileContent, tableIndex, pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0);
|
||||
ImportDirectoryTable idt = idata.ImportDirectoryTable;
|
||||
|
||||
// TODO: Use the known layout to determine the names in a more automated way instead of having to iterate
|
||||
|
||||
// Retrieve the table data
|
||||
byte[] tableData = new byte[tableSize];
|
||||
Array.Copy(fileContent, tableIndex, tableData, 0, tableSize);
|
||||
int entryCount = tableSize / 4; // Each entry is a UInt32
|
||||
|
||||
// TODO: Validate what this table actually looks like.
|
||||
// My concern about this is that it seems like each entry might be 16 bytes?
|
||||
// The original code does a += 12, reads the address, and then moves on.
|
||||
// That being said, the way that this works _does_ come up with a valid table,
|
||||
// at least something that looks like a valid table, since it shows up with
|
||||
// `ntoskrnl.exe` on the dot
|
||||
//
|
||||
// Unfortunately, for other programs, this comes up with nonsense data, so it's hard
|
||||
// to tell if the table is accurate or not.
|
||||
|
||||
// Iterate through the table and get valid DLL names
|
||||
List<string> dependentDlls = new List<string>();
|
||||
for (int i = 0; i < entryCount; i++)
|
||||
{
|
||||
// Get and validate the virtual offset
|
||||
uint entryVirtualOffset = BitConverter.ToUInt32(tableData, i * 4);
|
||||
if (entryVirtualOffset == 0)
|
||||
continue;
|
||||
|
||||
// Get the DLL name from the table and add it to the list if possible
|
||||
string entryDllName = new string(fileContent.Skip((int)entryVirtualOffset).TakeWhile(b => b > 0).Select(b => (char)b).ToArray());
|
||||
|
||||
try
|
||||
{
|
||||
if (File.Exists(Path.Combine(Path.GetDirectoryName(file), entryDllName)))
|
||||
{
|
||||
FileInfo fiDLL = new FileInfo(Path.Combine(Path.GetDirectoryName(file), entryDllName));
|
||||
dependentDlls.Add(fiDLL.CopyTo(Path.Combine(Path.GetTempPath(), entryDllName), true).FullName);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
return dependentDlls.ToArray();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to run an executable
|
||||
/// </summary>
|
||||
/// <param name="file">Executable to attempt to run</param>
|
||||
/// <returns>Process representing the running executable, null on error</returns>
|
||||
internal static Process StartSafe(string file)
|
||||
{
|
||||
if (file == null || !File.Exists(file))
|
||||
return null;
|
||||
|
||||
// Create the process to start safely
|
||||
Process safeProcess = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = file,
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
CreateNoWindow = true,
|
||||
ErrorDialog = false,
|
||||
}
|
||||
};
|
||||
|
||||
// Try to start the process, returning the handle if we can
|
||||
try
|
||||
{
|
||||
safeProcess.Start();
|
||||
return safeProcess;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -424,41 +424,5 @@ namespace BurnOutSharp.Tools
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IO Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Safely attempt to delete a path
|
||||
/// </summary>
|
||||
/// <param name="path">Path to be deleted</param>
|
||||
/// <param name="isDirectory">True to treat the path as a directory, false for a file</param>
|
||||
public static void SafeDelete(string path, bool isDirectory = false)
|
||||
{
|
||||
// No valid path means we can't delete
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return;
|
||||
|
||||
// Attempt to delete the path
|
||||
try
|
||||
{
|
||||
if (!isDirectory && File.Exists(path))
|
||||
File.Delete(path);
|
||||
else if (isDirectory && Directory.Exists(path))
|
||||
Directory.Delete(path, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Absorb any errors in deletion
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safely attempt to delete a path in the temp directory
|
||||
/// </summary>
|
||||
/// <param name="path">Path in the temp directory to be deleted</param>
|
||||
/// <param name="isDirectory">True to treat the path as a directory, false for a file</param>
|
||||
public static void SafeTempDelete(string path, bool isDirectory = false) => SafeDelete(Path.Combine(Path.GetTempPath(), path), isDirectory);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user