diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 0000000..ec94239 --- /dev/null +++ b/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 067341936b8cb2242be3bdc83f3ca3cd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ObfuscateUtil.cs b/Editor/ObfuscateUtil.cs new file mode 100644 index 0000000..a7815e2 --- /dev/null +++ b/Editor/ObfuscateUtil.cs @@ -0,0 +1,79 @@ +using HybridCLR.Editor; +using Obfuz.Settings; +using Obfuz; +using System; +using System.Collections.Generic; +using UnityEditor; +using System.IO; +using UnityEngine; +using Obfuz.Unity; + +namespace Obfuz4HybridCLR +{ + public static class ObfuscateUtil + { + public static bool AreSameDirectory(string path1, string path2) + { + try + { + var dir1 = new DirectoryInfo(path1); + var dir2 = new DirectoryInfo(path2); + + return dir1.FullName.TrimEnd('\\') == dir2.FullName.TrimEnd('\\'); + } + catch + { + return false; + } + } + + public static void ObfuscateHotUpdateAssemblies(BuildTarget target, string outputDir) + { + string hotUpdateDllPath = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target); + + AssemblySettings assemblySettings = ObfuzSettings.Instance.assemblySettings; + ObfuscationProcess.ValidateReferences(hotUpdateDllPath, new HashSet(assemblySettings.GetAssembliesToObfuscate()), new HashSet(assemblySettings.GetObfuscationRelativeAssemblyNames())); + var assemblySearchPaths = new List + { + hotUpdateDllPath, + }; + if (AreSameDirectory(hotUpdateDllPath, outputDir)) + { + throw new Exception($"hotUpdateDllPath:{hotUpdateDllPath} can't be same to outputDir:{outputDir}"); + } + Obfuscate(target, assemblySearchPaths, outputDir); + foreach (string hotUpdateAssemblyName in SettingsUtil.HotUpdateAssemblyNamesExcludePreserved) + { + string srcFile = $"{hotUpdateDllPath}/{hotUpdateAssemblyName}.dll"; + string dstFile = $"{outputDir}/{hotUpdateAssemblyName}.dll"; + // only copy non obfuscated assemblies + if (File.Exists(srcFile) && !File.Exists(dstFile)) + { + File.Copy(srcFile, dstFile, true); + Debug.Log($"[CompileAndObfuscateDll] Copy nonObfuscated assembly {srcFile} to {dstFile}"); + } + } + } + + public static void Obfuscate(BuildTarget target, List assemblySearchPaths, string obfuscatedAssemblyOutputPath) + { + var obfuzSettings = ObfuzSettings.Instance; + + var assemblySearchDirs = assemblySearchPaths; + ObfuscatorBuilder builder = ObfuscatorBuilder.FromObfuzSettings(obfuzSettings, target, true); + builder.InsertTopPriorityAssemblySearchPaths(assemblySearchDirs); + builder.CoreSettingsFacade.obfuscatedAssemblyOutputPath = obfuscatedAssemblyOutputPath; + + foreach (var assemblySearchDir in builder.CoreSettingsFacade.assemblySearchPaths) + { + if (AreSameDirectory(assemblySearchDir, obfuscatedAssemblyOutputPath)) + { + throw new Exception($"assemblySearchDir:{assemblySearchDir} can't be same to ObfuscatedAssemblyOutputPath:{obfuscatedAssemblyOutputPath}"); + } + } + + Obfuscator obfuz = builder.Build(); + obfuz.Run(); + } + } +} diff --git a/Editor/ObfuscateUtil.cs.meta b/Editor/ObfuscateUtil.cs.meta new file mode 100644 index 0000000..3702fdd --- /dev/null +++ b/Editor/ObfuscateUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7f5fe18513bcdd4c8960d908e88402e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Obfuz4HybridCLR.asmdef b/Editor/Obfuz4HybridCLR.asmdef new file mode 100644 index 0000000..2af5cd5 --- /dev/null +++ b/Editor/Obfuz4HybridCLR.asmdef @@ -0,0 +1,19 @@ +{ + "name": "Obfuz4HybridCLR.Editor", + "rootNamespace": "", + "references": [ + "GUID:2373f786d14518f44b0f475db77ba4de", + "GUID:66e09fc524ec6594b8d6ca1d91aa1a41" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Editor/Obfuz4HybridCLR.asmdef.meta b/Editor/Obfuz4HybridCLR.asmdef.meta new file mode 100644 index 0000000..cc375a6 --- /dev/null +++ b/Editor/Obfuz4HybridCLR.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3743e71edcd5bd8499007797ef02cbfb +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PrebuildCommandExt.cs b/Editor/PrebuildCommandExt.cs new file mode 100644 index 0000000..f5c161e --- /dev/null +++ b/Editor/PrebuildCommandExt.cs @@ -0,0 +1,124 @@ +using HybridCLR.Editor.Commands; +using HybridCLR.Editor; +using Obfuz.Settings; +using Obfuz; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using System.Reflection; +using System; +using System.IO; +using HybridCLR.Editor.Link; +using HybridCLR.Editor.Meta; +using UnityEditor.Build; +using HybridCLR.Editor.Installer; +using HybridCLR.Editor.MethodBridge; +using System.Linq; +using Analyzer = HybridCLR.Editor.MethodBridge.Analyzer; +using HybridCLR.Editor.Settings; +using Obfuz.Utils; +using FileUtil = Obfuz.Utils.FileUtil; +using IAssemblyResolver = HybridCLR.Editor.Meta.IAssemblyResolver; +using CombinedAssemblyResolver = HybridCLR.Editor.Meta.CombinedAssemblyResolver; +using MetaUtil = HybridCLR.Editor.Meta.MetaUtil; +using AssemblyCache = HybridCLR.Editor.Meta.AssemblyCache; + +namespace Obfuz4HybridCLR +{ + public static class PrebuildCommandExt + { + public static string GetObfuscatedHotUpdateAssemblyOutputPath(BuildTarget target) + { + return $"{ObfuzSettings.Instance.ObfuzRootDir}/{target}/ObfuscatedHotUpdateAssemblies"; + } + + + [MenuItem("HybridCLR/ObfuzExtension/GenerateAll")] + public static void GenerateAll() + { + var installer = new InstallerController(); + if (!installer.HasInstalledHybridCLR()) + { + throw new BuildFailedException($"You have not initialized HybridCLR, please install it via menu 'HybridCLR/Installer'"); + } + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + CompileDllCommand.CompileDll(target); + Il2CppDefGeneratorCommand.GenerateIl2CppDef(); + LinkGeneratorCommand.GenerateLinkXml(target); + StripAOTDllCommand.GenerateStripedAOTDlls(target); + AOTReferenceGeneratorCommand.GenerateAOTGenericReference(target); + + string obfuscatedHotUpdateDllPath = GetObfuscatedHotUpdateAssemblyOutputPath(target); + ObfuscateUtil.ObfuscateHotUpdateAssemblies(target, obfuscatedHotUpdateDllPath); + GenerateMethodBridgeAndReversePInvokeWrapper(target, obfuscatedHotUpdateDllPath); + } + + [MenuItem("HybridCLR/ObfuzExtension/CompileAndObfuscateDll")] + public static void CompileAndObfuscateDll() + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + CompileDllCommand.CompileDll(target); + + string obfuscatedHotUpdateDllPath = GetObfuscatedHotUpdateAssemblyOutputPath(target); + ObfuscateUtil.ObfuscateHotUpdateAssemblies(target, obfuscatedHotUpdateDllPath); + } + + public static IAssemblyResolver CreateObfuscatedHotUpdateAssemblyResolver(BuildTarget target, List obfuscatedHotUpdateAssemblies, string obfuscatedHotUpdateDllPath) + { + return new FixedSetAssemblyResolver(obfuscatedHotUpdateDllPath, obfuscatedHotUpdateAssemblies); + } + + public static IAssemblyResolver CreateObfuscatedHotUpdateAndAOTAssemblyResolver(BuildTarget target, List hotUpdateAssemblies, List assembliesToObfuscate, string obfuscatedHotUpdateDllPath) + { + return new CombinedAssemblyResolver( + CreateObfuscatedHotUpdateAssemblyResolver(target, hotUpdateAssemblies.Intersect(assembliesToObfuscate).ToList(), obfuscatedHotUpdateDllPath), + MetaUtil.CreateHotUpdateAssemblyResolver(target, hotUpdateAssemblies.Except(assembliesToObfuscate).ToList()), + MetaUtil.CreateAOTAssemblyResolver(target) + ); + } + + public static void GenerateMethodBridgeAndReversePInvokeWrapper(BuildTarget target, string obfuscatedHotUpdateDllPath) + { + string aotDllDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target); + List aotAssemblyNames = Directory.Exists(aotDllDir) ? + Directory.GetFiles(aotDllDir, "*.dll", SearchOption.TopDirectoryOnly).Select(Path.GetFileNameWithoutExtension).ToList() + : new List(); + if (aotAssemblyNames.Count == 0) + { + throw new Exception($"no aot assembly found. please run `HybridCLR/Generate/All` or `HybridCLR/Generate/AotDlls` to generate aot dlls before runing `HybridCLR/Generate/MethodBridge`"); + } + AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateAOTAssemblyResolver(target), aotAssemblyNames); + + var methodBridgeAnalyzer = new Analyzer(new Analyzer.Options + { + MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration), + Collector = collector, + }); + + methodBridgeAnalyzer.Run(); + + List hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; + var cache = new AssemblyCache(CreateObfuscatedHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls, ObfuzSettings.Instance.assemblySettings.GetAssembliesToObfuscate(), obfuscatedHotUpdateDllPath)); + + var reversePInvokeAnalyzer = new MonoPInvokeCallbackAnalyzer(cache, hotUpdateDlls); + reversePInvokeAnalyzer.Run(); + + var calliAnalyzer = new CalliAnalyzer(cache, hotUpdateDlls); + calliAnalyzer.Run(); + var pinvokeAnalyzer = new PInvokeAnalyzer(cache, hotUpdateDlls); + pinvokeAnalyzer.Run(); + var callPInvokeMethodSignatures = pinvokeAnalyzer.PInvokeMethodSignatures; + + string templateFile = $"{SettingsUtil.TemplatePathInPackage}/MethodBridge.cpp.tpl"; + string outputFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp"; + + var callNativeMethodSignatures = calliAnalyzer.CalliMethodSignatures.Concat(pinvokeAnalyzer.PInvokeMethodSignatures).ToList(); + + var generateMethodBridgeMethod = typeof(MethodBridgeGeneratorCommand).GetMethod("GenerateMethodBridgeCppFile", BindingFlags.NonPublic | BindingFlags.Static); + generateMethodBridgeMethod.Invoke(null, new object[] { methodBridgeAnalyzer.GenericMethods, reversePInvokeAnalyzer.ReversePInvokeMethods, callNativeMethodSignatures, templateFile, outputFile }); + + MethodBridgeGeneratorCommand.CleanIl2CppBuildCache(); + } + } +} diff --git a/Editor/PrebuildCommandExt.cs.meta b/Editor/PrebuildCommandExt.cs.meta new file mode 100644 index 0000000..2bcd1c7 --- /dev/null +++ b/Editor/PrebuildCommandExt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: afc965e1afdfc8e47b8a70be7a93cf25 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/LICENSE.meta b/LICENSE.meta new file mode 100644 index 0000000..dd09461 --- /dev/null +++ b/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3036602f815e31341b4445f0e331b58e +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json new file mode 100644 index 0000000..15dc618 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "com.code-philosophy.obfuz4hybridclr", + "version": "1.0.0", + "displayName": "Obfuz4HybridCLR", + "description": "Obfuz4HybridCLR is a obfuz extension for HybridCLR", + "category": "Scripting", + "documentationUrl": "https://www.obfuz.com", + "changelogUrl": "https://github.com/focus-creative-games/obfuz/commits/main/", + "licensesUrl": "https://github.com/focus-creative-games/obfuz/blob/main/com.code-philosophy.obfuz4hybridclr/LICENSE", + "keywords": [ + "obfuz", + "obfuscation", + "obfuscator", + "confuser", + "code-philosophy" + ], + "author": { + "name": "Code Philosophy", + "email": "obfuz@code-philosophy.com", + "url": "https://code-philosophy.com" + } +} \ No newline at end of file diff --git a/package.json.meta b/package.json.meta new file mode 100644 index 0000000..5577b3b --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9ac66e213a764b840b2533ee30123717 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: