diff --git a/Assets/Dumper/DUMPDATA/botReqData.json b/Assets/Dumper/DUMPDATA/botReqData.json new file mode 100644 index 0000000..2c8cffb --- /dev/null +++ b/Assets/Dumper/DUMPDATA/botReqData.json @@ -0,0 +1,39 @@ + +[ + {"Role":"assault","Limit":2,"Difficulty":"easy"}, + {"Role":"assault","Limit":2,"Difficulty":"normal"}, + {"Role":"assault","Limit":2,"Difficulty":"hard"}, + {"Role":"marksman","Limit":2,"Difficulty":"normal"}, + {"Role":"marksman","Limit":2,"Difficulty":"hard"}, + {"Role":"pmcBot","Limit":2,"Difficulty":"normal"}, + {"Role":"bossGluhar","Limit":2,"Difficulty":"normal"}, + {"Role":"followerGluharAssault","Limit":2,"Difficulty":"normal"}, + {"Role":"followerGluharSecurity","Limit":2,"Difficulty":"normal"}, + {"Role":"followerGluharScout","Limit":2,"Difficulty":"normal"}, + {"Role":"bossKolontay","Limit":2,"Difficulty":"normal"}, + {"Role":"followerKolontayAssault","Limit":2,"Difficulty":"normal"}, + {"Role":"followerKolontaySecurity","Limit":2,"Difficulty":"normal"}, + {"Role":"bossBoar","Limit":2,"Difficulty":"normal"}, + {"Role":"followerBoar","Limit":2,"Difficulty":"normal"}, + {"Role":"followerBoarClose1","Limit":2,"Difficulty":"normal"}, + {"Role":"followerBoarClose2","Limit":2,"Difficulty":"normal"}, + {"Role":"bossBoarSniper","Limit":2,"Difficulty":"normal"}, + {"Role":"exUsec","Limit":2,"Difficulty":"normal"}, + {"Role":"bossZryachiy","Limit":2,"Difficulty":"normal"}, + {"Role":"followerZryachiy","Limit":2,"Difficulty":"normal"}, + {"Role":"bossKnight","Limit":2,"Difficulty":"normal"}, + {"Role":"followerBigPipe","Limit":2,"Difficulty":"normal"}, + {"Role":"followerBirdEye","Limit":2,"Difficulty":"normal"}, + {"Role":"bossBully","Limit":2,"Difficulty":"normal"}, + {"Role":"followerBully","Limit":2,"Difficulty":"normal"}, + {"Role":"sectantPriest","Limit":2,"Difficulty":"normal"}, + {"Role":"sectantWarrior","Limit":2,"Difficulty":"normal"}, + {"Role":"bossTagilla","Limit":2,"Difficulty":"normal"}, + {"Role":"gifter","Limit":2,"Difficulty":"normal"}, + {"Role":"bossSanitar","Limit":2,"Difficulty":"normal"}, + {"Role":"bossKilla","Limit":2,"Difficulty":"normal"}, + {"Role":"bossKojaniy","Limit":2,"Difficulty":"normal"}, + {"Role":"followerKojaniy","Limit":2,"Difficulty":"normal"}, + {"Role":"skier","Limit":2,"Difficulty":"normal"}, + {"Role":"peacemaker","Limit":2,"Difficulty":"normal"} +] diff --git a/Assets/Dumper/DUMPDATA/config.json b/Assets/Dumper/DUMPDATA/config.json new file mode 100644 index 0000000..4598933 --- /dev/null +++ b/Assets/Dumper/DUMPDATA/config.json @@ -0,0 +1,15 @@ +{ + "Name": "Dumper", + "MapNames": [ "Interchange", "factory4_day", "laboratory", "bigmap", "Lighthouse", "RezervBase", "Sandbox", "Sandbox_high", "Shoreline", "TarkovStreets", "Woods" ], + "DateTimeFormat": "yyyy-MM-dd_HH-mm-ss", + "QuickDumpEnabled": true, + "SptTimings": { + "SingleIterationDelayMs": 10000, + "AllIterationDelayMs": 300000 + }, + "SptReflections": { + "MainUrlPropName": "get_MainURLFull", + "ParamFieldName": "Params", + "RequestFieldName": "responseText" + } +} \ No newline at end of file diff --git a/Assets/Dumper/DUMPDATA/raidSettings.json b/Assets/Dumper/DUMPDATA/raidSettings.json new file mode 100644 index 0000000..f48c7eb --- /dev/null +++ b/Assets/Dumper/DUMPDATA/raidSettings.json @@ -0,0 +1,7 @@ +{ + "serverId": null, + "location": "Lighthouse", + "timeVariant": "CURR", + "mode": "PVE_OFFLINE", + "playerSide": "Pmc" +} \ No newline at end of file diff --git a/Assets/Dumper/DumpLib.dll b/Assets/Dumper/DumpLib.dll new file mode 100644 index 0000000..bd93e8d Binary files /dev/null and b/Assets/Dumper/DumpLib.dll differ diff --git a/Templates/MappingTemplate.jsonc b/Assets/Templates/MappingTemplate.jsonc similarity index 100% rename from Templates/MappingTemplate.jsonc rename to Assets/Templates/MappingTemplate.jsonc diff --git a/Templates/Settings.jsonc b/Assets/Templates/Settings.jsonc similarity index 100% rename from Templates/Settings.jsonc rename to Assets/Templates/Settings.jsonc diff --git a/de4dot/AssemblyData.dll b/Assets/de4dot/AssemblyData.dll similarity index 100% rename from de4dot/AssemblyData.dll rename to Assets/de4dot/AssemblyData.dll diff --git a/de4dot/de4dot.blocks.dll b/Assets/de4dot/de4dot.blocks.dll similarity index 100% rename from de4dot/de4dot.blocks.dll rename to Assets/de4dot/de4dot.blocks.dll diff --git a/de4dot/de4dot.code.dll b/Assets/de4dot/de4dot.code.dll similarity index 100% rename from de4dot/de4dot.code.dll rename to Assets/de4dot/de4dot.code.dll diff --git a/de4dot/de4dot.cui.dll b/Assets/de4dot/de4dot.cui.dll similarity index 100% rename from de4dot/de4dot.cui.dll rename to Assets/de4dot/de4dot.cui.dll diff --git a/de4dot/de4dot.exe b/Assets/de4dot/de4dot.exe similarity index 100% rename from de4dot/de4dot.exe rename to Assets/de4dot/de4dot.exe diff --git a/de4dot/de4dot.mdecrypt.dll b/Assets/de4dot/de4dot.mdecrypt.dll similarity index 100% rename from de4dot/de4dot.mdecrypt.dll rename to Assets/de4dot/de4dot.mdecrypt.dll diff --git a/de4dot/dnlib.dll b/Assets/de4dot/dnlib.dll similarity index 100% rename from de4dot/dnlib.dll rename to Assets/de4dot/dnlib.dll diff --git a/DumpLib/DumpLib.csproj b/DumpLib/DumpLib.csproj new file mode 100644 index 0000000..5370cef --- /dev/null +++ b/DumpLib/DumpLib.csproj @@ -0,0 +1,20 @@ + + + + net471 + DumpLib + 1.0.0 + latestmajor + enable + enable + ..\Assets\Dumper + + + + + + + + + + diff --git a/DumpLib/DumpyTool.cs b/DumpLib/DumpyTool.cs new file mode 100644 index 0000000..8f5ed20 --- /dev/null +++ b/DumpLib/DumpyTool.cs @@ -0,0 +1,338 @@ +using System; +using System.IO; +using System.Reflection; +using System.Threading.Tasks; +using Newtonsoft.Json; +using DumpLib.Helpers; +using DumpLib.Models; + +namespace DumpLib +{ + public static class DumpyTool + { + /// + /// + /// + public static string DumpDataPath = (Directory.GetCurrentDirectory() + "\\DUMPDATA\\").Replace("\\\\", "\\"); + + public static SptConfigClass ConfigSettings = (SptConfigClass)GetSptConfig(); + + /// + /// always start from 1 as their iterations are 1 to 6 + /// + public static int Iteration = 1; + + /// + /// Method to create a "combined" Type that takes a GenericType + /// Example: ClientApplication + GInterface145 = ClientApplication(GInterface145) + /// + /// Object (Type) + /// Object (Type) + /// Type + public static Type CreateGenericType(object firstType, object secondType) + { + try + { + return (firstType as Type).MakeGenericType(new Type[] { secondType as Type }); + } + catch (Exception e) + { + UtilsHelper.LogError("CreateCombinedType"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// + /// + /// + /// + public static MethodInfo CreateDeserializerMethod(object type) + { + try + { + return ReflectionHelper.GetDeserializerMethodInfo().MakeGenericMethod(new Type[] { type as Type }); + } + catch (Exception e) + { + UtilsHelper.LogError("CreateCombinedMethod"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// + /// + /// + public static object CreateBackendSessionAndTarkovApp(out object tarkovApp) + { + try + { + // To get to this point and keeping this generic + // Get types required + var singletonType = ReflectionHelper.GetSingletonType(); + var clientApplicationType = ReflectionHelper.GetClientApplicationType(); + var interfaceType = ReflectionHelper.GetInterfaceType(); + + // Create singleton + var clientApplicationInterfaceType = CreateGenericType(clientApplicationType, interfaceType); + var singletonClientApplicationInterfaceType = CreateGenericType(singletonType, clientApplicationInterfaceType); + + // Get singleton instance + var singletonClientApplicationInterfaceInstance = ReflectionHelper.GetSingletonInstance(singletonClientApplicationInterfaceType); + + tarkovApp = singletonClientApplicationInterfaceInstance; + return ReflectionHelper.GetBackendSession(singletonClientApplicationInterfaceInstance); + } + catch (Exception e) + { + UtilsHelper.LogError("CreateBackendSession"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// + /// + /// + public static object GetWaveSettings() + { + try + { + // combine List<> and WaveSettingsType + var listWaveType = CreateGenericType(ReflectionHelper.GetListType(), ReflectionHelper.GetWaveSettingsType()); + + // combine with JsonConvert.DeserializeObject<>() and invoke with getCurrentDir + "\\DUMPDATA\\.replace("\\\\","\\") + "botReqData.json"; + return CreateDeserializerMethod(listWaveType).Invoke(null, new[] { File.ReadAllText(Path.Combine(DumpDataPath, "botReqData.json")) }); + } + catch (Exception e) + { + UtilsHelper.LogError("GetWaveSettings"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// + /// + /// + public static object GetSptConfig() + { + try + { + return CreateDeserializerMethod(typeof(SptConfigClass)).Invoke(null, + new[] { File.ReadAllText(Path.Combine(DumpDataPath, "config.json")) }); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + public static object GetRaidSettings() + { + try + { + return CreateDeserializerMethod(ReflectionHelper.GetLocalRaidSettingsType()).Invoke(null, + new[] { File.ReadAllText(Path.Combine(DumpDataPath, "raidSettings.json")) }); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + public static bool GotBackend = false; + public static object WaveSettings = null; + public static object RaidSettings = null; + public static object AppRaidSettings = null; + public static FieldInfo MainMenuController = null; + public static object Session = null; + public static object TarkovApp = null; + public static int ErrorCounter = 0; + + /// + /// Method to run main menu Task, this will request data from BSG, map loot and bot data + /// + public static async Task StartDumpyTask() + { + if (!ConfigSettings.QuickDumpEnabled) + { + return; + } + + await Task.Factory.StartNew(async delegate + { + UtilsHelper.LogInfo("[Dumpy] Starting Dumpy Loop"); + while (true) + { + try + { + if (!GotBackend) + { + // get client backend session + Session = CreateBackendSessionAndTarkovApp(out TarkovApp); + // get field for MainMenuController + MainMenuController = ReflectionHelper.GetMainMenuControllerField(); + // get wave information from json + WaveSettings = GetWaveSettings(); + // get Raid Settings from json + RaidSettings = GetRaidSettings(); + // get Raid settings from tarkovApp + AppRaidSettings = ReflectionHelper.GetRaidSettingsFromApp(TarkovApp); + + CheckVariableConditions(); + GotBackend = true; + } + } + catch (Exception e) + { + UtilsHelper.LogError("[Dumpy] Exception occured in StartDumpyTask::GotBackend"); + UtilsHelper.LogError(e); + + if (ErrorCounter > 3) + { + UtilsHelper.LogError("[Dumpy] ErrorsCounter was above 3, exiting app!"); + // use EFT method to close app + ReflectionHelper.GetApplicationQuitMethod().Invoke(null, null); + } + + ErrorCounter += 1; + + UtilsHelper.LogError("[Dumpy] Resetting backend and trying again"); + ClearVariables(); + } + + try + { + if (Iteration > 6) + { + // reset to 1 + Iteration = 1; + + UtilsHelper.LogInfo($"[Dumpy] Restarting Loop in {ConfigSettings.SptTimings.AllIterationDelayMs}ms"); + var controller = MainMenuController.GetValue(TarkovApp); + + if (controller != null) + { + controller.GetType().GetMethod("StopAfkMonitor").Invoke(controller, null); + } + + await Task.Delay(ConfigSettings.SptTimings.AllIterationDelayMs); + } + else + { + UtilsHelper.LogInfo($"Map iteration number: {Iteration}"); + foreach (var map in ConfigSettings.MapNames) + { + // theory is send a request SendRaidSettings before starting + + // Set location in the RaidSettings object + UtilsHelper.LogInfo($"[Dumpy] Setting RaidSettings location to: {map}"); + RaidSettings.GetType().GetField("location").SetValue(RaidSettings, map); + + // Call server with new map name + UtilsHelper.LogInfo($"[Dumpy] Getting loot for {map}"); + await (Task)Session.GetType().GetMethod("LocalRaidStarted") + .Invoke(Session, new[] { RaidSettings }); + + // Call server with bot wave data + UtilsHelper.LogInfo($"[Dumpy] Getting Bot Data"); + await (Task)Session.GetType().GetMethod("LoadBots") + .Invoke(Session, new[] { WaveSettings }); + + await Task.Delay(ConfigSettings.SptTimings.SingleIterationDelayMs); + } + + Iteration++; + } + } + catch (Exception e) + { + UtilsHelper.LogError("[Dumpy] Exception occured in StartDumpyTask::Iteration"); + UtilsHelper.LogError(e); + + if (ErrorCounter > 3) + { + UtilsHelper.LogError("[Dumpy] ErrorsCounter was above 3, exiting app"); + // use EFT method to close app + ReflectionHelper.GetApplicationQuitMethod().Invoke(null, null); + } + + ErrorCounter += 1; + + UtilsHelper.LogError("[Dumpy] Resetting backend and trying again"); + ClearVariables(); + } + } + }, TaskCreationOptions.LongRunning); + } + + private static void CheckVariableConditions() + { + UtilsHelper.LogInfo($"[Dumpy] CheckVariableConditions"); + UtilsHelper.LogInfo($"[Dumpy] GotBackend- type: {GotBackend.GetType()} null?: {GotBackend == null}"); + UtilsHelper.LogInfo($"[Dumpy] WaveSettings- type: {WaveSettings.GetType()} null?: {WaveSettings == null}"); + UtilsHelper.LogInfo($"[Dumpy] MainMenuController- type: {MainMenuController.GetType()} null?: {MainMenuController == null}"); + UtilsHelper.LogInfo($"[Dumpy] Session- type: {Session.GetType()} null?: {Session == null}"); + UtilsHelper.LogInfo($"[Dumpy] TarkovApp- type: {TarkovApp.GetType()} null?: {TarkovApp == null}"); + UtilsHelper.LogInfo($"[Dumpy] RaidSettings- type: {RaidSettings.GetType()} null?: {RaidSettings == null}"); + UtilsHelper.LogInfo($"[Dumpy] CheckVariableConditions"); + UtilsHelper.LogInfo($"[Dumpy] AppRaidSettings- type: {AppRaidSettings.GetType()} null?: {AppRaidSettings == null}"); + UtilsHelper.LogInfo($"[Dumpy] CheckVariableConditions"); + UtilsHelper.LogInfo($"[Dumpy] -----------------------------------------------------------------------------"); + } + + private static void ClearVariables() + { + GotBackend = false; + WaveSettings = null; + MainMenuController = null; + Session = null; + TarkovApp = null; + RaidSettings = null; + AppRaidSettings = null; + } + + /// + /// Method to log Requests and Responses + /// + /// object (Type) + /// object (Type) + public static void LogRequestResponse(object requestType, object responseText) + { + try + { + var uri = new Uri((string)requestType.GetType().GetMethod(ConfigSettings.SptReflections.MainUrlPropName).Invoke(requestType, null)); + var path = (Directory.GetCurrentDirectory() + "\\HTTP_DATA\\").Replace("\\\\", "\\"); + var file = uri.LocalPath.Replace("/", ".").Remove(0, 1); + var time = DateTime.Now.ToString(ConfigSettings.DateTimeFormat); + + if (Directory.CreateDirectory(path).Exists) + { + var reqParams = requestType.GetType().GetField(ConfigSettings.SptReflections.ParamFieldName).GetValue(requestType); + if (Directory.CreateDirectory($@"{path}req.{file}").Exists) + { + if (reqParams != null) + File.WriteAllText($@"{path}req.{file}\\req.{file}_{time}_{ConfigSettings.Name}.json", JsonConvert.SerializeObject(reqParams)); + } + + if (Directory.CreateDirectory($@"{path}resp.{file}").Exists) + File.WriteAllText($@"{path}resp.{file}\\resp.{file}_{time}_{ConfigSettings.Name}.json", (string)responseText); + } + } + catch (Exception e) + { + UtilsHelper.LogError("[Dumpy] Exception occured at LogRequestResponse"); + UtilsHelper.LogError(e); + throw; + } + } + } +} \ No newline at end of file diff --git a/DumpLib/Helpers/ReflectionHelper.cs b/DumpLib/Helpers/ReflectionHelper.cs new file mode 100644 index 0000000..1e80ee1 --- /dev/null +++ b/DumpLib/Helpers/ReflectionHelper.cs @@ -0,0 +1,260 @@ +using System; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace DumpLib.Helpers +{ + public static class ReflectionHelper + { + private static Assembly _newtonAssembly = Assembly.LoadFrom((Directory.GetCurrentDirectory() + "\\EscapeFromTarkov_Data\\Managed\\Newtonsoft.Json.dll").Replace("\\\\", "\\")); + + private static Assembly _msAssembly = Assembly.LoadFrom((Directory.GetCurrentDirectory() + "\\EscapeFromTarkov_Data\\Managed\\mscorlib.dll").Replace("\\\\", "\\")); + + private static Assembly _eftAssembly = Assembly.LoadFrom((Directory.GetCurrentDirectory() + "\\EscapeFromTarkov_Data\\Managed\\Assembly-CSharp.dll").Replace("\\\\", "\\")); + + private static Assembly _comfortAssembly = Assembly.LoadFrom((Directory.GetCurrentDirectory() + "\\EscapeFromTarkov_Data\\Managed\\Comfort.dll").Replace("\\\\", "\\")); + + /// + /// Method to get Singleton<> type from Comfort.dll + /// + /// Type + public static Type GetSingletonType() + { + try + { + return _comfortAssembly.GetTypes().First(x => x.Name.StartsWith("Singleton")); + } + catch (Exception e) + { + UtilsHelper.LogError("GetSingletonType"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// Method to get ClientApplication<> type from EFT's assembly + /// + /// Type + public static Type GetClientApplicationType() + { + try + { + return _eftAssembly.GetTypes().First(x => x.Name.StartsWith("ClientApplication")); + } + catch (Exception e) + { + UtilsHelper.LogError("GetClientApplicationType"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// Method to get (as of 25/01/2024 - GInterface145) type from EFT's assembly + /// + /// Type + public static Type GetInterfaceType() + { + try + { + return _eftAssembly.GetTypes() + .First(x => x.IsInterface && x.GetMethods().Any(m => m.Name == "GetPhpSessionId")); + } + catch (Exception e) + { + UtilsHelper.LogError("GetInterfaceType"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// Method to get TarkovApplication type from EFT's assembly + /// + /// Type + public static Type GetTarkovApplicationType() + { + try + { + return _eftAssembly.GetTypes().First(x => x.Name == "TarkovApplication"); + } + catch (Exception e) + { + UtilsHelper.LogError("GetTarkovApplicationType"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// Method to get (as of 25/01/2024 - GClass1464) type from EFT's assembly + /// + /// + public static object GetWaveSettingsType() + { + try + { + return _eftAssembly.GetTypes().First(x => + { + // if type contains Role, Limit and Difficulty, return true + var fields = x.GetFields(); + if (fields.Any(f => f.Name == "Role") && fields.Any(f => f.Name == "Limit") && fields.Any(f => f.Name == "Difficulty") && fields.Length == 3) + return true; + + return false; + }); + } + catch (Exception e) + { + UtilsHelper.LogError("GetWaveSettingsType"); + UtilsHelper.LogError(e); + throw; + } + } + + public static Type GetListType() + { + try + { + return _msAssembly.GetTypes().First(x => x.Name.StartsWith("List") && x.Namespace == "System.Collections.Generic"); + } + catch (Exception e) + { + UtilsHelper.LogError("GetListType"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// Method to get FieldInfo of a field on the TarkovApplication Type for later use + /// + /// FieldInfo + public static FieldInfo GetMainMenuControllerField() + { + try + { + return GetTarkovApplicationType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic) + .First(x => x.FieldType.GetMethods().Any(m => m.Name == "StopAfkMonitor")); + } + catch (Exception e) + { + UtilsHelper.LogError("GetMainMenuControllerField"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// Method to get the Instance of a Singleton(Type) passed in + /// + /// object (Type) + /// object (Type) + /// object + public static object GetSingletonInstance(object singletonType) + { + try + { + return (singletonType as Type).GetProperty("Instance", BindingFlags.Public | BindingFlags.Static) + .GetGetMethod().Invoke(singletonType, null); + } + catch (Exception e) + { + UtilsHelper.LogError("GetSingletonInstance"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// Method to get BackendSession object from the instance passed in + /// + /// object (Type) + /// object + public static object GetBackendSession(object instance) + { + try + { + return GetTarkovApplicationType().GetMethod("GetClientBackEndSession").Invoke(instance, null); + } + catch (Exception e) + { + UtilsHelper.LogError("GetBackendSession"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// Method to get DeserializeObject from Newtonsoft assembly + /// + /// MethodInfo + public static MethodInfo GetDeserializerMethodInfo() + { + try + { + return _newtonAssembly.GetTypes().First(x => x.Name == "JsonConvert").GetMethods().First(m => + m.Name == "DeserializeObject" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && + m.GetParameters().Any(p => p.ParameterType == typeof(string))); + } + catch (Exception e) + { + UtilsHelper.LogError("GetDeserializerMethodInfo"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// Method to get Quit method from EFT (as of 20/05/2024 - GClass1955) + /// + /// MethodInfo + public static MethodInfo GetApplicationQuitMethod() + { + try + { + return _eftAssembly.GetTypes().First(x => x.GetMethods().Any(y => y.Name == "Quit")).GetMethod("Quit"); + } + catch (Exception e) + { + UtilsHelper.LogError("GetApplicationQuitMethod"); + UtilsHelper.LogError(e); + throw; + } + } + + /// + /// Method to get LocalRaidSettings Type from EFT + /// + /// object + public static object GetLocalRaidSettingsType() + { + try + { + return _eftAssembly.GetTypes().First(x => x.Name == "LocalRaidSettings"); + } + catch (Exception e) + { + UtilsHelper.LogError("GetLocalRaidSettingsType"); + UtilsHelper.LogError(e); + throw; + } + } + + public static object GetRaidSettingsFromApp(object tarkovApp) + { + try + { + return tarkovApp.GetType().GetField("_raidSettings").GetValue(tarkovApp); + } + catch (Exception e) + { + UtilsHelper.LogError("GetRaidSettingsFromApp"); + UtilsHelper.LogError(e); + throw; + } + } + } +} \ No newline at end of file diff --git a/DumpLib/Helpers/UtilsHelper.cs b/DumpLib/Helpers/UtilsHelper.cs new file mode 100644 index 0000000..b89d25f --- /dev/null +++ b/DumpLib/Helpers/UtilsHelper.cs @@ -0,0 +1,64 @@ +using System; +using System.IO; + +namespace DumpLib.Helpers +{ + public static class UtilsHelper + { + private static string _loggerPath = (Directory.GetCurrentDirectory() + "\\DUMPDATA\\Log.txt").Replace("\\\\", "\\"); + + /// + /// Log message to something + /// + /// object + private static void LogMessage(object message, string messageType) + { + StreamWriter writer = null; + try + { + writer = new StreamWriter(_loggerPath, true); + writer.WriteLine($"[{messageType}] - {DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}"); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + finally + { + if (writer != null) + { + writer.Close(); + writer.Dispose(); + } + } + } + + /// + /// Log message to something + /// + /// object + public static void LogError(object message) + { + LogMessage(message, "Error"); + } + + /// + /// Log message to something + /// + /// object + public static void LogInfo(object message) + { + LogMessage(message, "Info"); + } + + /// + /// Log message to something + /// + /// object + public static void LogDebug(object message) + { + LogMessage(message, "Debug"); + } + } +} \ No newline at end of file diff --git a/DumpLib/Models/SptConfigClass.cs b/DumpLib/Models/SptConfigClass.cs new file mode 100644 index 0000000..26f5c23 --- /dev/null +++ b/DumpLib/Models/SptConfigClass.cs @@ -0,0 +1,57 @@ +namespace DumpLib.Models +{ + public class SptConfigClass + { + /// + /// Default: Test + /// + public string Name { get; set; } + + /// + /// Default: [ "Interchange", "factory4_day", "laboratory", "bigmap", "Lighthouse", "RezervBase", "Sandbox", "Shoreline", "TarkovStreets", "Woods" ] + /// + public string[] MapNames { get; set; } + + /// + /// Default: "yyyy-MM-dd_HH-mm-ss" + /// + public string DateTimeFormat { get; set; } + + public bool QuickDumpEnabled { get; set; } + + public SptReflections SptReflections { get; set; } + + public SptTimings SptTimings { get; set; } + } + + public class SptTimings + { + /// + /// Default: 10s * 1000ms = 10000ms + /// + public int SingleIterationDelayMs { get; set; } + + /// + /// Default: 5m * 60s * 1000ms = 300000ms + /// + public int AllIterationDelayMs { get; set; } + } + + public class SptReflections + { + /// + /// Default: "get_MainURLFull" as of 128476 client + /// + public string MainUrlPropName { get; set; } + + /// + /// Default: "Params" as of 128476 client + /// + public string ParamFieldName { get; set; } + + /// + /// Default: "responseText" as of 128476 client + /// + public string RequestFieldName { get; set; } + } +} \ No newline at end of file diff --git a/ReCodeItCLI/Commands/Dumper.cs b/ReCodeItCLI/Commands/Dumper.cs new file mode 100644 index 0000000..43c79c5 --- /dev/null +++ b/ReCodeItCLI/Commands/Dumper.cs @@ -0,0 +1,39 @@ +using CliFx; +using CliFx.Attributes; +using CliFx.Infrastructure; +using ReCodeIt.Utils; +using ReCodeItLib.Dumper; + +namespace ReCodeIt.Commands; + +[Command("Dumper", Description = "Generates a dumper zip")] +public class Dumper : ICommand +{ + [CommandParameter(0, IsRequired = true, Description = "The absolute path to your DeObfuscated assembly file, folder must contain all references to be resolved.")] + public string GameAssemblyPath { get; init; } + + [CommandParameter(1, IsRequired = true, Description = "The absolute path to your FileChecker.dll file, folder must contain all refgerences to be resolved.")] + public string CheckerAssemblyPath { get; init; } + + private Dumpy _dumpy { get; set; } + + public ValueTask ExecuteAsync(IConsole console) + { + DataProvider.IsCli = true; + DataProvider.LoadAppSettings(); + + Logger.Log("Creating Dumper..."); + + _dumpy = new Dumpy(GameAssemblyPath, CheckerAssemblyPath, Path.GetDirectoryName(GameAssemblyPath)); + _dumpy.CreateDumpFolders(); + _dumpy.CreateDumper(); + + Logger.Log("Complete", ConsoleColor.Green); + + // Wait for log termination + Logger.Terminate(); + while (Logger.IsRunning()) { } + + return default; + } +} \ No newline at end of file diff --git a/ReCodeItCLI/ReCodeIt.csproj b/ReCodeItCLI/ReCodeIt.csproj index 24eb2c2..ae4ce9c 100644 --- a/ReCodeItCLI/ReCodeIt.csproj +++ b/ReCodeItCLI/ReCodeIt.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/RecodeIt.sln b/RecodeIt.sln index e6edcaf..1f0f886 100644 --- a/RecodeIt.sln +++ b/RecodeIt.sln @@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReCodeItLib", "RecodeItLib\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReCodeIt", "ReCodeItCLI\ReCodeIt.csproj", "{E404EC0B-06D2-4964-8ABA-A634F259655C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DumpLib", "DumpLib\DumpLib.csproj", "{D0837899-F129-46DB-8BDB-7C9AFB72BD30}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -83,6 +85,26 @@ Global {E404EC0B-06D2-4964-8ABA-A634F259655C}.Release|x64.Build.0 = Release|Any CPU {E404EC0B-06D2-4964-8ABA-A634F259655C}.Release|x86.ActiveCfg = Release|Any CPU {E404EC0B-06D2-4964-8ABA-A634F259655C}.Release|x86.Build.0 = Release|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Debug|ARM.ActiveCfg = Debug|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Debug|ARM.Build.0 = Debug|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Debug|ARM64.Build.0 = Debug|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Debug|x64.ActiveCfg = Debug|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Debug|x64.Build.0 = Debug|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Debug|x86.ActiveCfg = Debug|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Debug|x86.Build.0 = Debug|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Release|Any CPU.Build.0 = Release|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Release|ARM.ActiveCfg = Release|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Release|ARM.Build.0 = Release|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Release|ARM64.ActiveCfg = Release|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Release|ARM64.Build.0 = Release|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Release|x64.ActiveCfg = Release|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Release|x64.Build.0 = Release|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Release|x86.ActiveCfg = Release|Any CPU + {D0837899-F129-46DB-8BDB-7C9AFB72BD30}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/RecodeItLib/Dumper/Dumpy.cs b/RecodeItLib/Dumper/Dumpy.cs new file mode 100644 index 0000000..b3b1b2a --- /dev/null +++ b/RecodeItLib/Dumper/Dumpy.cs @@ -0,0 +1,331 @@ +using System.Collections; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using ReCodeIt.Utils; + +namespace ReCodeItLib.Dumper; + +public class Dumpy +{ + private ModuleDefMD? _gameModule { get; set; } + private ModuleDefMD? _checkerModule { get; set; } + private string _assemblyPath { get; set; } + private string _fileCheckerPath { get; set; } + private string _path { get; set; } + private List? _gameTypes { get; set; } + private List? _checkerTypes { get; set; } + + public Dumpy(string assemblyPath, string fileCheckerPath, string path) + { + _assemblyPath = assemblyPath; + _fileCheckerPath = fileCheckerPath; + _path = path; + + if (!File.Exists(_assemblyPath)) + { + Logger.Log($"File does not exist at: {_assemblyPath}", ConsoleColor.Red); + return; + } + + if (!File.Exists(_fileCheckerPath)) + { + Logger.Log($"File does not exist at: {_fileCheckerPath}", ConsoleColor.Red); + return; + } + + _gameModule = DataProvider.LoadModule(_assemblyPath); + _checkerModule = DataProvider.LoadModule(_fileCheckerPath); + _gameTypes = _gameModule.GetTypes().ToList(); + _checkerTypes = _checkerModule.GetTypes().ToList(); + } + + public void CreateDumper() + { + if (_gameModule == null || _gameTypes == null) + { + Logger.Log($"_gameModule or _gameTypes in Dumpy was null", ConsoleColor.Red); + return; + } + + if (_checkerModule == null || _checkerTypes == null) + { + Logger.Log($"_checkerModule or _checkerTypes in Dumpy was null", ConsoleColor.Red); + return; + } + + // make changes to assembly + + // get required types + // var backRequestType = _gameTypes.Where(DumpyTypeHelper.GetBackRequestType).ToList(); + // var validateCertType = _gameTypes.Where(DumpyTypeHelper.GetValidateCertType).ToList(); + // var runValidationType = _gameTypes.Where(DumpyTypeHelper.GetRunValidationType).ToList(); + // var dumpyTaskType = _gameTypes.Where(DumpyTypeHelper.GetMenuscreenType).ToList(); + + // check types + // CheckNullOrMulti(backRequestType, "BackRequest"); + // CheckNullOrMulti(validateCertType, "ValidateCertificate"); + // CheckNullOrMulti(runValidationType, "RunValidation"); + // CheckNullOrMulti(dumpyTaskType, "DumpyTask"); + + // apply code changes + // SetBackRequestCode(backRequestType[0]); + // SetValidateCertCode(validateCertificateType[0]); + // SetRunValidationCode(runValidationType[0]); + // SetDumpyTaskCode(dumpyTaskType[0]); + + // TODO: Write game assembly to file + + // get types + // var ensureConsistencyTypes = _checkerTypes.Where(DumpyTypeHelper.GetEnsureConsistencyType).ToList(); + // check types + // CheckNullOrMulti(ensureConsistencyTypes, "EnsureConsistency"); + + // apply code changes + // SetEnsureConsistencyCode(ensureConsistencyType[0]); + // SetEnsureConsistencySingleCode(ensureConsistencyType[0]); + + // TODO: Write fileChecker assembly to file + } + + public void CreateDumpFolders() + { + // create dumper folders + } + + /// + /// Checks for null or multiple types + /// + /// ICollection + /// string + private void CheckNullOrMulti(ICollection types, string name = "") + { + if (types == null) + { + Logger.Log($"{name} was null"); + } + + if (types.Count > 1) + { + Logger.Log($"{name} count was more than 1"); + } + } + + /// + /// Finds the method with backRequest and bResponse as params. + /// Checks the method instructions before modification has a count of 269, + /// if this is not the case, this needs to be checked. + /// This type passed in is the only type with this method. + /// + /// + /// + private void SetBackRequestCode(TypeDef type) + { + // find method + var method = type.Methods.First(x => x.Parameters.Any(p => p.Name is "backRequest" && x.Parameters.Any(p => p.Name == "bResponse"))); + + if (method == null || method.Body.Instructions.Count != 269) + { + Logger.Log($"BackRequest Instructions count has changed from 269 to {method.Body.Instructions.Count}", ConsoleColor.Red); + } + + var startOfInstructions = 252; + // var liList = DumpyInstructionsHelper.GetBackRequestInstructions(); + var index = method.Body.Instructions[startOfInstructions]; + + // foreach (var li in liList) + // { + // // something along these lines, this needs to be tested + // method.Body.Instructions.InsertBefore(index, li); + // } + + // create instruction + var ins = Instruction.Create(OpCodes.Brfalse_S, method.Body.Instructions[startOfInstructions]); + + // replace instruction at 220 with this + method.Body.Instructions[220] = ins; + } + + /// + /// Finds the method called ValidateCertificate. + /// Checks that we found two of these methods, + /// if this is not the case, this needs to be checked. + /// This type passed in is the only type with this method. + /// + /// + /// + private void SetValidateCertCode(TypeDef type) + { + var methods = type.Methods.Where(x => + x.Name == "ValidateCertificate"); // should be 2 + + // check make sure nothing has changed + var firstMethod = methods.FirstOrDefault(m => m.Parameters.Any(p => p.Name == "certificate")); + var secondMethod = methods.FirstOrDefault(m => m.Parameters.Any(p => p.Name == "certificateData")); + + if (firstMethod?.Body.Instructions.Count != 55 || secondMethod?.Body.Instructions.Count != 14) + { + Logger.Log($"Instruction count has changed, method with 'certificate' as a param - before: 51, now: {firstMethod.Body.Instructions.Count}, " + + $"method with 'certificateData' as a param - before: 14, now: {secondMethod.Body.Instructions.Count}", ConsoleColor.Red); + } + + if (methods.Count() != 2) + { + Logger.Log($"ValidateCertificate should be found twice, count was: {methods.Count()}", ConsoleColor.Red); + } + + foreach (var method in methods) + { + // clear these from the body. + method.Body.Instructions.Clear(); + method.Body.Variables.Clear(); + method.Body.ExceptionHandlers.Clear(); + + // return true; + var ins = Instruction.Create(OpCodes.Ldc_I4_1); + var ins1 = Instruction.Create(OpCodes.Ret); + + // add instructions + method.Body.Instructions.Add(ins); + method.Body.Instructions.Add(ins1); + } + } + + /// + /// Finds the method called RunValidation and MoveNext. + /// Checks that we found two of these methods, + /// if this is not the case, this needs to be checked. + /// This type passed in is the only type with this method. + /// + /// + /// + private void SetRunValidationCode(TypeDef type) + { + var method = type.Methods.First(x => x.Name == "RunValidation"); + var method2 = type.NestedTypes[0].Methods.First(x => x.Name == "MoveNext"); + + if (method == null || method.Body.Instructions.Count != 25) + { + Logger.Log($"RunValidation Instructions count has changed from 25 to {method.Body.Instructions.Count}"); + } + + if (method2 == null || method2.Body.Instructions.Count != 171) + { + Logger.Log($"RunValidation's MoveNext Instructions count has changed from 171 to {method2.Body.Instructions.Count}"); + } + + // Clear these from the body of each method respectively + method.Body.Instructions.Clear(); + method2.Body.Instructions.Clear(); + method2.Body.Variables.Clear(); + method2.Body.ExceptionHandlers.Clear(); + + // var liList = DumpyInstructionsHelper.GetRunValidationInstructions(oldAssembly, method); + // var liList2 = DumpyInstructionsHelper.GetRunValidationInstructionsMoveNext(oldAssembly, method2); + + // foreach (var instruction in liList) + // { + // method.Body.Instructions.Append(instruction); + // } + // + // foreach (var instruction in liList2) + // { + // method2.Body.Instructions.Append(instruction); + // } + + var ins = Instruction.Create(OpCodes.Leave_S, method2.Body.Instructions[14]); // Create instruction to jump to index 14 + var ins1 = Instruction.Create(OpCodes.Leave_S, method2.Body.Instructions[method2.Body.Instructions.IndexOf(method2.Body.Instructions.Last())]); // Create instruction to jump to last index + + method2.Body.Instructions.InsertAfter(method2.Body.Instructions[5], ins); // Instruction to jump from 5 to 14 + method2.Body.Instructions.InsertAfter(method2.Body.Instructions[14], ins1); // Instruction to jump from 14 to last index + + // Create exception handler with defined indexes + var handler = new ExceptionHandler(ExceptionHandlerType.Catch) + { + TryStart = method2.Body.Instructions[3], + TryEnd = method2.Body.Instructions[7], + HandlerStart = method2.Body.Instructions[7], + HandlerEnd = method2.Body.Instructions[16], + // CatchType = method2.Module.ImportReference(typeof(Exception)), // needs fixing + }; + + // Add exception handler to method body + method2.Body.ExceptionHandlers.Add(handler); + } + + private void SetDumpyTaskCode(TypeDef type) + { + var method = type.Methods.First(x => x.Name == "Awake"); + + if (method == null || method.Body.Instructions.Count != 62) + { + Logger.Log($"MainMenu is null or isnt 62 instructions, SOMETHING HAD CHANGED!", ConsoleColor.Red); + } + + // var liList = DumpyInstructionsHelper.GetDumpyTaskInstructions(oldAssembly, method); + + var index = method.Body.Instructions.First(x => x.OpCode == OpCodes.Ret); + + // foreach (var item in liList) + // { + // method.Body.Instructions.InsertBefore(index, item); + // } + } + + /// + /// Finds the method called EnsureConsistency. + /// if this is not the case, this needs to be checked. + /// This type passed in is the only type with this method. + /// + /// + /// + private static void SetEnsureConsistencyCode(TypeDef type) + { + var method = type.Methods.First(x => x.Name == "EnsureConsistency"); + + if (method == null || method.Body.Instructions.Count != 152) + { + Logger.Log($"EnsureConsistency Instructions count has changed from 152 to {method.Body.Instructions.Count}", ConsoleColor.Red); + } + + // clear these from the method body + method.Body.Instructions.Clear(); + method.Body.Variables.Clear(); + method.Body.ExceptionHandlers.Clear(); + + // var liList = DumpyInstructionsHelper.GetEnsureConsistencyInstructions(oldFileChecker, method); + // + // foreach (var li in liList) + // { + // method.Body.Instructions.Append(li); + // } + } + + /// + /// Finds the method called EnsureConsistencySingle. + /// if this is not the case, this needs to be checked. + /// This type passed in is the only type with this method. + /// + /// + /// + private static void SetEnsureConsistencySingleCode(TypeDef type) + { + var method = type.Methods.First(x => x.Name == "EnsureConsistencySingle"); + + if (method == null || method.Body.Instructions.Count != 101) + { + Logger.Log($"EnsureConsistencySingle Instructions count has changed from 101 to {method.Body.Instructions.Count}", ConsoleColor.Red); + } + + // clear these from the method body + method.Body.Instructions.Clear(); + method.Body.Variables.Clear(); + method.Body.ExceptionHandlers.Clear(); + + // var liList = DumpyInstructionsHelper.GetEnsureConsistencyInstructions(oldFileChecker, method); + // + // foreach (var li in liList) + // { + // method.Body.Instructions.Append(li); + // } + } +} \ No newline at end of file diff --git a/RecodeItLib/Dumper/DumpyInstructionsHelper.cs b/RecodeItLib/Dumper/DumpyInstructionsHelper.cs new file mode 100644 index 0000000..dcf252f --- /dev/null +++ b/RecodeItLib/Dumper/DumpyInstructionsHelper.cs @@ -0,0 +1,170 @@ +// using System; +// using System.Collections.Generic; +// using System.Linq; +// using System.Threading.Tasks; +// using DumpLib; +// +// namespace ReCodeItLib.Dumper; +// +// public static class DumpyInstructionsHelper +// { +// /// +// /// Sets up local variables and returns a List of instructions to add. +// /// +// /// AssemblyDefinition +// /// MethodDefinition +// /// List +// public static List GetBackRequestInstructions(AssemblyDefinition assembly, MethodDefinition method) +// { +// return new List +// { +// Instruction.Create(OpCodes.Ldarg_1), +// Instruction.Create(OpCodes.Ldloc_S, method.Body.Variables[6]), +// Instruction.Create(OpCodes.Call, assembly.MainModule.ImportReference(typeof(DumpLib.DumpyTool).GetMethod("LogRequestResponse", new[] { typeof(object), typeof(object) }))) +// }; +// } +// +// /// +// /// Returns a List of instructions to be added to the method. +// /// This is an Async method so there is two parts, this part and a RunValidation method. +// /// +// /// AssemblyDefinition +// /// MethodDefinition +// /// List +// public static List GetRunValidationInstructionsMoveNext(AssemblyDefinition assembly, MethodDefinition method) +// { +// // Add our own local variables +// +// // var1 index0 class1159Type +// var sptClassType = assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType); +// var sptClass = new VariableDefinition(sptClassType); +// method.Body.Variables.Add(sptClass); +// +// // var2 index1 ExceptionType +// var sptExceptionType = method.Module.ImportReference(typeof(Exception)); +// var sptException = new VariableDefinition(sptExceptionType); +// method.Body.Variables.Add(sptException); +// +// return new List +// { +// // most of this is to keep the Async happy +// +// Instruction.Create(OpCodes.Ldarg_0), +// Instruction.Create(OpCodes.Ldfld, assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[2]), +// Instruction.Create(OpCodes.Stloc_0), +// +// // this.Succeed = true; +// Instruction.Create(OpCodes.Ldloc_0), +// Instruction.Create(OpCodes.Ldc_I4_1), +// Instruction.Create(OpCodes.Call, assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).Methods.First(x => x.Name == "set_Succeed")), +// +// Instruction.Create(OpCodes.Stloc_1), +// Instruction.Create(OpCodes.Ldarg_0), +// Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)-2), +// Instruction.Create(OpCodes.Stfld, assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[0]), +// Instruction.Create(OpCodes.Ldarg_0), +// Instruction.Create(OpCodes.Ldflda, assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[1]), +// Instruction.Create(OpCodes.Ldloc_1), +// Instruction.Create(OpCodes.Call, +// method.Module.ImportReference(assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[1].FieldType.Resolve().Methods.First(x => x.Name == "SetException"))), +// +// Instruction.Create(OpCodes.Ldarg_0), +// Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)-2), +// Instruction.Create(OpCodes.Stfld, assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[0]), +// +// Instruction.Create(OpCodes.Ldarg_0), +// Instruction.Create(OpCodes.Ldflda, assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[1]), +// Instruction.Create(OpCodes.Call, method.Module.ImportReference(assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[1].FieldType.Resolve().Methods.First(x => x.Name == "SetResult"))), +// +// Instruction.Create(OpCodes.Ret), +// }; +// } +// +// /// +// /// Returns a List of instructions to be added to the method. +// /// This is an Async method so there is two parts, this part and a RunValidation method. +// /// +// /// AssemblyDefinition +// /// MethodDefinition +// /// List +// public static List GetEnsureConsistencyInstructions(AssemblyDefinition oldFileChecker, MethodDefinition method) +// { +// // init local vars +// // var1 index0 TimeSpan type +// var sptTimeSpanType = method.Module.ImportReference(typeof(TimeSpan)); +// var sptClass = new VariableDefinition(sptTimeSpanType); +// method.Body.Variables.Add(sptClass); +// +// // Create genericInstance of a method +// var type = oldFileChecker.MainModule.GetTypes().First(DumpyTypeHelper.GetEnsureConsistencyType).NestedTypes[0].Interfaces[0].InterfaceType; +// var typeMethod = method.Module.ImportReference(typeof(Task).GetMethod("FromResult")); +// var instanceType = new GenericInstanceMethod(typeMethod); +// instanceType.GenericArguments.Add(type); +// +// return new List +// { +// // return Task.FromResult(ConsistencyController.CheckResult.Succeed(default(TimeSpan))); +// Instruction.Create(OpCodes.Ldloca_S, method.Body.Variables[0]), +// Instruction.Create(OpCodes.Initobj, method.Module.ImportReference(typeof(TimeSpan))), +// Instruction.Create(OpCodes.Ldloc_0), +// Instruction.Create(OpCodes.Call, oldFileChecker.MainModule.GetTypes().First(DumpyTypeHelper.GetEnsureConsistencyType).NestedTypes[0].Methods.First(x => x.Name == "Succeed")), +// Instruction.Create(OpCodes.Call, instanceType), +// Instruction.Create(OpCodes.Ret) +// }; +// } +// +// /// +// /// Returns a List of instructions to be added to the method. +// /// This is an Async method so there is two parts, this part and a MoveNext method. +// /// +// /// AssemblyDefinition +// /// MethodDefinition +// /// List +// public static List GetRunValidationInstructions(AssemblyDefinition assembly, MethodDefinition method) +// { +// // Create genericInstance of a method +// var type = assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0]; +// var typeMethod = method.Module.ImportReference(assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[1].FieldType.Resolve().Methods.First(x => x.Name == "Start")); +// var instanceMethod = new GenericInstanceMethod(typeMethod); +// instanceMethod.GenericArguments.Add(type); +// +// return new List +// { +// // d__.<>t__builder = AsyncTaskMethodBuilder.Create(); +// Instruction.Create(OpCodes.Ldloca_S, method.Body.Variables[0]), +// Instruction.Create(OpCodes.Call, method.Module.ImportReference(assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[1].FieldType.Resolve().Methods.First(x => x.Name == "Create"))), +// Instruction.Create(OpCodes.Stfld, assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[1]), +// +// // d__.<>4__this = this; +// Instruction.Create(OpCodes.Ldloca_S, method.Body.Variables[0]), +// Instruction.Create(OpCodes.Ldarg_0), +// Instruction.Create(OpCodes.Stfld, assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[2]), +// +// // d__.<>1__state = -1; +// Instruction.Create(OpCodes.Ldloca_S, method.Body.Variables[0]), +// Instruction.Create(OpCodes.Ldc_I4_M1), +// Instruction.Create(OpCodes.Stfld, assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[0]), +// +// // d__.<>t__builder.Startd__0>(ref d__); +// Instruction.Create(OpCodes.Ldloca_S, method.Body.Variables[0]), +// Instruction.Create(OpCodes.Ldflda, assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[1]), +// Instruction.Create(OpCodes.Ldloca_S, method.Body.Variables[0]), +// Instruction.Create(OpCodes.Call, instanceMethod), +// +// // return d__.<>t__builder.Task; +// Instruction.Create(OpCodes.Ldloca_S, method.Body.Variables[0]), +// Instruction.Create(OpCodes.Ldflda, assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[1]), +// Instruction.Create(OpCodes.Call, method.Module.ImportReference(assembly.MainModule.GetTypes().First(DumpyTypeHelper.GetRunValidationType).NestedTypes[0].Fields[1].FieldType.Resolve().Methods.First(x => x.Name == "get_Task"))), +// Instruction.Create(OpCodes.Ret), +// }; +// } +// +// public static List GetDumpyTaskInstructions(AssemblyDefinition oldAssembly, MethodDefinition method) +// { +// return new List +// { +// Instruction.Create(OpCodes.Call, oldAssembly.MainModule.ImportReference(typeof(DumpyTool).GetMethod("StartDumpyTask"))), +// Instruction.Create(OpCodes.Pop) +// }; +// } +// } \ No newline at end of file diff --git a/RecodeItLib/Dumper/DumpyTypeHelper.cs b/RecodeItLib/Dumper/DumpyTypeHelper.cs new file mode 100644 index 0000000..92fdb6f --- /dev/null +++ b/RecodeItLib/Dumper/DumpyTypeHelper.cs @@ -0,0 +1,54 @@ +// using System.Linq; +// using Mono.Cecil; +// +// namespace ReCodeItLib.Dumper; +// +// public static class DumpyTypeHelper +// { +// /// +// /// Gets the type that has a method called SendAndHandleRetries. +// /// This type is the only one with method. +// /// +// /// TypeDefinition +// /// boolean +// public static bool GetBackRequestType(TypeDefinition type) +// { +// return type.Methods.Any(m => m.Name == "SendAndHandleRetries"); +// } +// +// /// +// /// Gets the type that has a method called ValidateCertificate as the name. +// /// +// /// TypeDefinition +// /// boolean +// public static bool GetValidateCertificateType(TypeDefinition type) +// { +// return type.Methods.Any(m => m.Name == "ValidateCertificate"); +// } +// +// /// +// /// Gets the type that has a method called RunValidation as the name. +// /// +// /// TypeDefinition +// /// boolean +// public static bool GetRunValidationType(TypeDefinition type) +// { +// return type.Methods.Any(m => m.Name == "RunValidation"); +// } +// +// /// +// /// Gets the type that has ConsistencyController as the name. +// /// FilesChecker.dll is not obfuscated. +// /// +// /// TypeDefinition +// /// boolean +// public static bool GetEnsureConsistencyType(TypeDefinition type) +// { +// return type.Name == "ConsistencyController"; +// } +// +// public static bool GetMenuScreenType(TypeDefinition type) +// { +// return type.Name == "MenuScreen"; +// } +// } \ No newline at end of file diff --git a/RecodeItLib/Dumper/InstructionsExtensions.cs b/RecodeItLib/Dumper/InstructionsExtensions.cs new file mode 100644 index 0000000..0c47b58 --- /dev/null +++ b/RecodeItLib/Dumper/InstructionsExtensions.cs @@ -0,0 +1,49 @@ +using dnlib.DotNet.Emit; + +namespace ReCodeItLib.Dumper; + +public static class InstructionsExtensions +{ + public static void InsertBefore(this IList instructions, Instruction target, Instruction instruction) + { + if (target == null) + { + throw new ArgumentNullException(nameof (target)); + } + + if (instruction == null) + { + throw new ArgumentNullException(nameof (instruction)); + } + + int index = instructions.IndexOf(target); + if (index == -1) + { + throw new ArgumentOutOfRangeException(nameof (target)); + } + + instructions.Insert(index, instruction); + } + + public static void InsertAfter(this IList instructions, Instruction target, Instruction instruction) + { + if (target == null) + { + throw new ArgumentNullException(nameof (target)); + } + + if (instruction == null) + { + throw new ArgumentNullException(nameof (instruction)); + } + + int index = instructions.IndexOf(target); + + if (index == -1) + { + throw new ArgumentOutOfRangeException(nameof (target)); + } + + instructions.Insert(index + 1, instruction); + } +} \ No newline at end of file diff --git a/RecodeItLib/ReCodeItLib.csproj b/RecodeItLib/ReCodeItLib.csproj index 420ec58..2472aa9 100644 --- a/RecodeItLib/ReCodeItLib.csproj +++ b/RecodeItLib/ReCodeItLib.csproj @@ -18,4 +18,14 @@ + + + + + + + + Assets\DumpLib.dll + + diff --git a/RecodeItLib/Remapper/DeObfuscator.cs b/RecodeItLib/Remapper/DeObfuscator.cs index 3aebe88..0b5cee6 100644 --- a/RecodeItLib/Remapper/DeObfuscator.cs +++ b/RecodeItLib/Remapper/DeObfuscator.cs @@ -9,7 +9,7 @@ public static class Deobfuscator { public static void Deobfuscate(string assemblyPath) { - var executablePath = Path.Combine(DataProvider.DataPath, "De4dot", "de4dot.exe"); + var executablePath = Path.Combine(DataProvider.DataPath, "Assets", "De4dot", "de4dot.exe"); string token;