|
@@ -0,0 +1,149 @@
|
|
|
+using System;
|
|
|
+using System.IO;
|
|
|
+using System.Security.Cryptography;
|
|
|
+using AssemblyUnhollower;
|
|
|
+using BepInEx.Logging;
|
|
|
+using Il2CppDumper;
|
|
|
+
|
|
|
+namespace BepInEx.IL2CPP
|
|
|
+{
|
|
|
+ internal static class ProxyAssemblyGenerator
|
|
|
+ {
|
|
|
+ public static string GameAssemblyPath => Path.Combine(Paths.GameRootPath, "GameAssembly.dll");
|
|
|
+
|
|
|
+ private static string HashPath => Path.Combine(Preloader.IL2CPPUnhollowedPath, "assembly-hash.txt");
|
|
|
+
|
|
|
+ private static string tempDumperDirectory => Path.Combine(Preloader.IL2CPPUnhollowedPath, "temp");
|
|
|
+
|
|
|
+ private static ManualLogSource Il2cppDumperLogger = Logger.CreateLogSource("Il2CppDumper");
|
|
|
+
|
|
|
+
|
|
|
+ private static string ComputeGameAssemblyHash()
|
|
|
+ {
|
|
|
+ using var md5 = MD5.Create();
|
|
|
+ using var assemblyStream = File.OpenRead(GameAssemblyPath);
|
|
|
+
|
|
|
+ var hash = md5.ComputeHash(assemblyStream);
|
|
|
+
|
|
|
+ return Utility.ByteArrayToString(hash);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static bool CheckIfGenerationRequired()
|
|
|
+ {
|
|
|
+ if (!Directory.Exists(Preloader.IL2CPPUnhollowedPath))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ if (!File.Exists(HashPath))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ if (ComputeGameAssemblyHash() != File.ReadAllText(HashPath))
|
|
|
+ {
|
|
|
+ Preloader.Log.LogInfo("Detected a game update, will regenerate proxy assemblies");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void GenerateAssemblies()
|
|
|
+ {
|
|
|
+ var domain = AppDomain.CreateDomain("GeneratorDomain", null, new AppDomainSetup
|
|
|
+ {
|
|
|
+ ApplicationBase = Paths.BepInExAssemblyDirectory
|
|
|
+ });
|
|
|
+
|
|
|
+ var runner = (AppDomainRunner)domain.CreateInstanceAndUnwrap(typeof(AppDomainRunner).Assembly.FullName, typeof(AppDomainRunner).FullName);
|
|
|
+
|
|
|
+ runner.Setup(Paths.ExecutablePath, Preloader.IL2CPPUnhollowedPath);
|
|
|
+ runner.GenerateAssembliesInternal(new AppDomainListener());
|
|
|
+
|
|
|
+ AppDomain.Unload(domain);
|
|
|
+
|
|
|
+ Directory.Delete(tempDumperDirectory, true);
|
|
|
+
|
|
|
+ File.WriteAllText(HashPath, ComputeGameAssemblyHash());
|
|
|
+ }
|
|
|
+
|
|
|
+ [Serializable]
|
|
|
+ private class AppDomainListener : MarshalByRefObject
|
|
|
+ {
|
|
|
+ public void DoPreloaderLog(object data, LogLevel level)
|
|
|
+ {
|
|
|
+ Preloader.Log.Log(level, data);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void DoDumperLog(object data, LogLevel level)
|
|
|
+ {
|
|
|
+ Il2cppDumperLogger.Log(level, data);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void DoUnhollowerLog(object data, LogLevel level)
|
|
|
+ {
|
|
|
+ Preloader.UnhollowerLog.Log(level, data);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [Serializable]
|
|
|
+ private class AppDomainRunner : MarshalByRefObject
|
|
|
+ {
|
|
|
+ public void Setup(string executablePath, string unhollowedPath)
|
|
|
+ {
|
|
|
+ Paths.SetExecutablePath(executablePath);
|
|
|
+ Preloader.IL2CPPUnhollowedPath = unhollowedPath;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void GenerateAssembliesInternal(AppDomainListener listener)
|
|
|
+ {
|
|
|
+ listener.DoPreloaderLog("Generating Il2CppUnhollower assemblies", LogLevel.Message);
|
|
|
+
|
|
|
+ System.Threading.Thread.Sleep(5000);
|
|
|
+
|
|
|
+ if (Directory.Exists(Preloader.IL2CPPUnhollowedPath))
|
|
|
+ Directory.Delete(Preloader.IL2CPPUnhollowedPath, true);
|
|
|
+
|
|
|
+ Directory.CreateDirectory(Preloader.IL2CPPUnhollowedPath);
|
|
|
+
|
|
|
+ string tempDumperDirectory = Path.Combine(Preloader.IL2CPPUnhollowedPath, "temp");
|
|
|
+ Directory.CreateDirectory(tempDumperDirectory);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ var dumperConfig = new Config
|
|
|
+ {
|
|
|
+ GenerateScript = false,
|
|
|
+ GenerateDummyDll = true
|
|
|
+ };
|
|
|
+
|
|
|
+ listener.DoPreloaderLog("Generating Il2CppDumper intermediate assemblies", LogLevel.Info);
|
|
|
+
|
|
|
+ Il2CppDumper.Il2CppDumper.PerformDump(GameAssemblyPath,
|
|
|
+ Path.Combine(Paths.GameRootPath, $"{Paths.ProcessName}_Data", "il2cpp_data", "Metadata", "global-metadata.dat"),
|
|
|
+ tempDumperDirectory,
|
|
|
+ dumperConfig,
|
|
|
+ s => listener.DoDumperLog(s, LogLevel.Debug));
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ listener.DoPreloaderLog("Executing Il2CppUnhollower generator", LogLevel.Info);
|
|
|
+
|
|
|
+ System.Threading.Thread.Sleep(5000);
|
|
|
+
|
|
|
+ UnhollowerBaseLib.LogSupport.InfoHandler += s => listener.DoUnhollowerLog(s, LogLevel.Info);
|
|
|
+ UnhollowerBaseLib.LogSupport.WarningHandler += s => listener.DoUnhollowerLog(s, LogLevel.Warning);
|
|
|
+ UnhollowerBaseLib.LogSupport.TraceHandler += s => listener.DoUnhollowerLog(s, LogLevel.Debug);
|
|
|
+ UnhollowerBaseLib.LogSupport.ErrorHandler += s => listener.DoUnhollowerLog(s, LogLevel.Error);
|
|
|
+
|
|
|
+ var unhollowerOptions = new UnhollowerOptions
|
|
|
+ {
|
|
|
+ GameAssemblyPath = GameAssemblyPath,
|
|
|
+ MscorlibPath = Path.Combine(Paths.GameRootPath, "mono", "Managed", "mscorlib.dll"),
|
|
|
+ SourceDir = Path.Combine(tempDumperDirectory, "DummyDll"),
|
|
|
+ OutputDir = Preloader.IL2CPPUnhollowedPath
|
|
|
+ };
|
|
|
+
|
|
|
+ AssemblyUnhollower.Program.Main(unhollowerOptions);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|