Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patcher #23

Draft
wants to merge 3 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions Scope.Installer/Installer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace Scope.Installer
/// </summary>
public class Installer
{
// TODO
/// <summary>
/// The URL to download the Scope files from.
/// </summary>
Expand Down Expand Up @@ -53,9 +54,7 @@ public static async Task Main(string[] args)
string gameFolder = await GetSLFolder();
if (!Directory.Exists(gameFolder) || Directory.GetFiles(gameFolder).Contains("SCPSL.exe"))
{
Console.WriteLine("Could not find the game folder, aborting.");
Console.Read();
Environment.Exit(0);
Error("Could not find the game folder, aborting.");
}

try
Expand All @@ -68,18 +67,14 @@ public static async Task Main(string[] args)

if (hash != ZipHash)
{
Console.WriteLine("The archive hash does not match!");
Console.Read();
Environment.Exit(0);
Error("The archive hash does not match!");
}

Console.WriteLine("Extracting files...");
var archive = new ZipArchive(download);
if (archive.Entries.All(x => !x.FullName.StartsWith("ScopeStuff")))
{
Console.WriteLine("Unable to find archive contents, is the installer outdated?");
Console.Read();
Environment.Exit(0);
Error("Unable to find archive contents, is the installer outdated?");
}

Console.WriteLine("Moving files...");
Expand Down Expand Up @@ -137,9 +132,7 @@ public static async Task Main(string[] args)
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.Read();
Environment.Exit(0);
Error(ex.ToString());
}
}

Expand Down Expand Up @@ -170,9 +163,7 @@ private static async Task<Stream> Download(string url)
throw;
}

Console.WriteLine("Check your internet connection and Scope server status and try again");
Console.Read();
Environment.Exit(0);
Error("Check your internet connection and Scope server status and try again");
}

return stream;
Expand Down Expand Up @@ -274,5 +265,14 @@ private static async Task<string> GetSLFolder()

return SLPath;
}

public static void Error(string message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
Console.ResetColor();
Console.Read();
Environment.Exit(0);
}
}
}
4 changes: 4 additions & 0 deletions Scope.Installer/Scope.Installer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
</PackageReference>
</ItemGroup>

<ItemGroup>
<Compile Include="Installer.cs" />
</ItemGroup>

<PropertyGroup>
<DocumentationFile>bin\Debug\Scope.Installer.xml</DocumentationFile>
<NoWarn>$(NoWarn),1573,1591,1712</NoWarn>
Expand Down
66 changes: 66 additions & 0 deletions Scope.Patcher/Deserializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
namespace Scope.Patcher
{
using System.Collections.Generic;
using System.IO;
using Models;

public static class Deserializer
{
public static PatchCollection Read(string patchFile)
{
if (!File.Exists(patchFile))
{
throw new FileNotFoundException(nameof(patchFile));
}

var patches = Deserialize1337(File.ReadAllLines(patchFile), out var name);
return new PatchCollection(name, patches);
}

private static IEnumerable<Patch> Deserialize1337(string[] lines, out string assemblyname)
{
string file = null;
List<Patch> result = new List<Patch>();

foreach (var line in lines)
{
if (string.IsNullOrWhiteSpace(line))
{
continue;
}

if (line.StartsWith(">"))
{
if (file is null)
{
file = line.Substring(1);
continue;
}
else
{
break;
}
}

if (file is null)
{
throw new InvalidDataException("Patch file is not valid!");
}

var splitData = line.Replace("->", ":").Split(':');
if (splitData.Length != 3)
{
throw new InvalidDataException("Unable to read patch data!");
}

result.Add(new Patch(
uint.Parse(splitData[0], System.Globalization.NumberStyles.HexNumber),
byte.Parse(splitData[1], System.Globalization.NumberStyles.HexNumber),
byte.Parse(splitData[1], System.Globalization.NumberStyles.HexNumber)));
}

assemblyname = file;
return result;
}
}
}
16 changes: 16 additions & 0 deletions Scope.Patcher/Models/Patch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Scope.Patcher.Models
{
public struct Patch
{
public uint Address { get; private set; }
public byte OldValue { get; private set; }
public byte NewValue { get; private set; }

public Patch(uint address, byte oldValue, byte newValue)
{
Address = address;
OldValue = oldValue;
NewValue = newValue;
}
}
}
28 changes: 28 additions & 0 deletions Scope.Patcher/Models/PatchCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace Scope.Patcher.Models
{
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;

public class PatchCollection : List<Patch>
{
public string AssemblyName { get; internal set; }
public bool CanPatch => this.AssemblyName is not null && this.Count > 0;

public PatchCollection()
{
}

public PatchCollection(string assemblyName, IEnumerable<Patch> patches)
{
if (patches == null)
{
throw new ArgumentNullException(nameof(patches));
}

this.AddRange(patches);
this.AssemblyName = assemblyName;
}
}
}
60 changes: 60 additions & 0 deletions Scope.Patcher/Patcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
namespace Scope.Patcher
{
using System;
using System.IO;
using Models;

public static class Patcher
{
public static void Patch(this PatchCollection patches, string path, out bool expected, bool checkOld = false, bool backup = false)
{
if (!File.Exists(path))
{
throw new FileNotFoundException(nameof(path));
}

if (patches.Count < 1)
{
throw new IndexOutOfRangeException(nameof(patches));
}

expected = true;
var data = File.ReadAllBytes(path);
foreach (var patch in patches)
{
if(patch.Address > data.Length)
{
continue;
}

if(data[patch.Address] != patch.OldValue)
{
if (checkOld)
{
throw new Exception(
$"Data does not match (expected: {patch.OldValue}, actual: {data[patch.Address]})");
}
else
{
expected = false;
}
}

data[patch.Address] = patch.NewValue;
}

if(backup)
{
Console.WriteLine("Backup already exists, continue? (y/n)");
var input = Console.ReadLine()?.ToLower();
if(input != "y")
{
return;
}
File.Copy(path, $"{path}.old", true);
}

File.WriteAllBytes(path, data);
}
}
}
109 changes: 109 additions & 0 deletions Scope.Patcher/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
namespace Scope.Patcher
{
using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Models;
using Newtonsoft.Json;

internal class Program
{
public static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: Scope.Patcher.exe <path to x64dbg exported patches>");
Console.WriteLine("Usage: Scope.Patcher.exe <path to generated patches> <path to assembly>");
}

if (args.Length == 1)
{
if (!File.Exists(args.ElementAt(0)))
{
Error("Unable to find file: " + args.ElementAt(0));
}

try
{
var collection = Deserializer.Read(args.ElementAt(0));
if (!collection.CanPatch)
{
Error("The file is incomplete!, aborting...");
}
var json = JsonSerializer.Create();
using (TextWriter tw = new StreamWriter("patches.json"))
{
using var jw = new JsonTextWriter(tw);
jw.WriteComment(collection.AssemblyName);
json.Serialize(jw, collection);
}
}
catch (InvalidDataException e)
{
Error("The patch file is invalid: " + e.Message);
}
catch (Exception e)
{
Error("An error occurred while reading the patch file: " + e.Message);
}
}

if (args.Length == 2)
{
if (!File.Exists(args.ElementAt(0)) || !File.Exists(args.ElementAt(1)))
{
Error("Unable to find files!");
}

PatchCollection collection;
string lines;
using (TextReader tr = new StreamReader(args.ElementAt(0)))
{
lines = tr.ReadToEnd();
collection = JsonConvert.DeserializeObject<PatchCollection>(lines);
}

if (collection is null)
{
Error("Unable to read the file!");
}

if (Regex.Match(lines, @"\/\*[^\\]+\*\/", RegexOptions.Multiline | RegexOptions.IgnoreCase).Success)
{
collection!.AssemblyName = lines.Substring(lines.IndexOf(@"/*"));
}

if (!collection!.CanPatch)
{
Error("The patch file is incomplete!, aborting...");
}

collection.Patch(args.ElementAt(1), out var expected);
if (!expected)
{
Warn("Old values didnt match!");
}
}
}

internal static void Error(string message, bool exit = false)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
Console.ResetColor();
if (exit)
{
Console.Read();
Environment.Exit(0);
}
}

internal static void Warn(string message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(message);
Console.ResetColor();
}
}
}
Loading