From c8482799c53c08023d86104614ae9897e4c0510e Mon Sep 17 00:00:00 2001 From: Alex-Rachel <574809918@qq.com> Date: Sat, 26 Jul 2025 18:16:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A5obfuz->3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameScripts/HotFix/GameLogic/GameApp.cs | 9 +- .../HotFix/GameLogic/GameLogic.asmdef | 3 +- .../GameLogic/UI/BattleMainUI/BattleMainUI.cs | 3 +- .../Obfuz/SymbolObfus/symbol-mapping.xml | 596 +++++++++-- .../Data~/hybridclr_version.json | 14 +- .../Editor/Commands/StripAOTDllCommand.cs | 4 +- .../RELEASELOG.md | 15 + .../Runtime/LoadImageErrorCode.cs | 3 + .../package.json | 2 +- .../com.code-philosophy.obfuz/Editor.meta | 8 - .../Editor/Conf.meta | 8 - .../Conf/XmlAssemblyTypeMethodRuleParser.cs | 263 ----- .../XmlAssemblyTypeMethodRuleParser.cs.meta | 11 - .../Editor/Conf/XmlFieldRuleParser.cs | 203 ---- .../Editor/Conf/XmlFieldRuleParser.cs.meta | 11 - .../Editor/ConfigurablePassPolicy.cs | 544 ---------- .../Editor/ConfigurablePassPolicy.cs.meta | 11 - .../Editor/ConstValues.cs | 34 - .../Editor/ConstValues.cs.meta | 11 - .../Editor/Data.meta | 8 - .../Editor/Data/ConstFieldAllocator.cs | 269 ----- .../Editor/Data/ConstFieldAllocator.cs.meta | 11 - .../Editor/Data/RvaDataAllocator.cs | 324 ------ .../Editor/Data/RvaDataAllocator.cs.meta | 11 - .../Editor/Emit.meta | 8 - .../Editor/Emit/BasicBlockCollection.cs | 310 ------ .../Editor/Emit/BasicBlockCollection.cs.meta | 11 - .../Editor/Emit/DefaultMetadataImporter.cs | 423 -------- .../Emit/DefaultMetadataImporter.cs.meta | 11 - .../Editor/Emit/EntityExtensions.cs | 15 - .../Editor/Emit/EntityExtensions.cs.meta | 11 - .../Editor/Emit/EvalStackCalculator.cs | 967 ------------------ .../Editor/Emit/EvalStackCalculator.cs.meta | 11 - .../Editor/Emit/GroupByModuleEntityManager.cs | 89 -- .../Emit/GroupByModuleEntityManager.cs.meta | 11 - .../Editor/Emit/LocalVariableAllocator.cs | 74 -- .../Emit/LocalVariableAllocator.cs.meta | 11 - .../Editor/EncryptionVM.meta | 8 - .../EncryptionInstructionWithOpCode.cs | 25 - .../EncryptionInstructionWithOpCode.cs.meta | 11 - .../EncryptionVM/IEncryptionInstruction.cs | 24 - .../IEncryptionInstruction.cs.meta | 11 - .../Editor/EncryptionVM/Instructions.meta | 8 - .../Instructions/AddInstruction.cs | 35 - .../Instructions/AddInstruction.cs.meta | 11 - .../Instructions/AddRotateXorInstruction.cs | 62 -- .../AddRotateXorInstruction.cs.meta | 11 - .../Instructions/AddXorRotateInstruction.cs | 62 -- .../AddXorRotateInstruction.cs.meta | 11 - .../Instructions/BitRotateInstruction.cs | 46 - .../Instructions/BitRotateInstruction.cs.meta | 11 - .../Instructions/EncryptFunction.cs | 44 - .../Instructions/EncryptFunction.cs.meta | 11 - .../Instructions/MultipleInstruction.cs | 46 - .../Instructions/MultipleInstruction.cs.meta | 11 - .../MultipleRotateXorInstruction.cs | 65 -- .../MultipleRotateXorInstruction.cs.meta | 11 - .../MultipleXorRotateInstruction.cs | 65 -- .../MultipleXorRotateInstruction.cs.meta | 11 - .../Instructions/XorAddRotateInstruction.cs | 62 -- .../XorAddRotateInstruction.cs.meta | 11 - .../Instructions/XorInstruction.cs | 36 - .../Instructions/XorInstruction.cs.meta | 11 - .../XorMultipleRotateInstruction.cs | 65 -- .../XorMultipleRotateInstruction.cs.meta | 11 - .../Editor/EncryptionVM/VirtualMachine.cs | 17 - .../EncryptionVM/VirtualMachine.cs.meta | 11 - .../VirtualMachineCodeGenerator.cs | 203 ---- .../VirtualMachineCodeGenerator.cs.meta | 11 - .../EncryptionVM/VirtualMachineCreator.cs | 68 -- .../VirtualMachineCreator.cs.meta | 11 - .../EncryptionVM/VirtualMachineSimulator.cs | 90 -- .../VirtualMachineSimulator.cs.meta | 11 - .../Editor/GarbageCodeGeneration.meta | 8 - .../ConfigGarbageCodeGenerator.cs | 117 --- .../ConfigGarbageCodeGenerator.cs.meta | 11 - .../GarbageCodeGenerator.cs | 92 -- .../GarbageCodeGenerator.cs.meta | 11 - .../ISpecificGarbageCodeGenerator.cs | 22 - .../ISpecificGarbageCodeGenerator.cs.meta | 11 - .../SpecificGarbageCodeGeneratorBase.cs | 106 -- .../SpecificGarbageCodeGeneratorBase.cs.meta | 11 - .../UIGarbageCodeGenerator.cs | 157 --- .../UIGarbageCodeGenerator.cs.meta | 11 - .../Editor/IObfuscationPass.cs | 15 - .../Editor/IObfuscationPass.cs.meta | 11 - .../Editor/ObfusPasses.meta | 8 - .../BasicBlockObfuscationPassBase.cs | 53 - .../BasicBlockObfuscationPassBase.cs.meta | 11 - .../Editor/ObfusPasses/CallObfus.meta | 8 - .../ObfusPasses/CallObfus/CallObfusPass.cs | 166 --- .../CallObfus/CallObfusPass.cs.meta | 11 - .../ConfigurableObfuscationPolicy.cs | 300 ------ .../ConfigurableObfuscationPolicy.cs.meta | 11 - .../CallObfus/DelegateProxyAllocator.cs | 263 ----- .../CallObfus/DelegateProxyAllocator.cs.meta | 11 - .../CallObfus/DelegateProxyObfuscator.cs | 83 -- .../CallObfus/DelegateProxyObfuscator.cs.meta | 11 - .../CallObfus/DispatchProxyAllocator.cs | 273 ----- .../CallObfus/DispatchProxyAllocator.cs.meta | 11 - .../CallObfus/DispatchProxyObfuscator.cs | 53 - .../CallObfus/DispatchProxyObfuscator.cs.meta | 11 - .../CallObfus/IObfuscationPolicy.cs | 19 - .../CallObfus/IObfuscationPolicy.cs.meta | 11 - .../ObfusPasses/CallObfus/IObfuscator.cs | 20 - .../ObfusPasses/CallObfus/IObfuscator.cs.meta | 11 - .../Editor/ObfusPasses/CallObfus/MethodKey.cs | 30 - .../ObfusPasses/CallObfus/MethodKey.cs.meta | 11 - .../SpecialWhiteListMethodCalculator.cs | 122 --- .../SpecialWhiteListMethodCalculator.cs.meta | 11 - .../Editor/ObfusPasses/CleanUp.meta | 8 - .../CleanUp/CleanUpInstructionPass.cs | 41 - .../CleanUp/CleanUpInstructionPass.cs.meta | 11 - .../CleanUp/RemoveObfuzAttributesPass.cs | 67 -- .../CleanUp/RemoveObfuzAttributesPass.cs.meta | 11 - .../Editor/ObfusPasses/ConstEncrypt.meta | 8 - .../ConstEncrypt/ConfigurableEncryptPolicy.cs | 490 --------- .../ConfigurableEncryptPolicy.cs.meta | 11 - .../ConstEncrypt/ConstEncryptPass.cs | 137 --- .../ConstEncrypt/ConstEncryptPass.cs.meta | 11 - .../ConstEncrypt/DefaultConstEncryptor.cs | 337 ------ .../DefaultConstEncryptor.cs.meta | 11 - .../ConstEncrypt/IConstEncryptor.cs | 32 - .../ConstEncrypt/IConstEncryptor.cs.meta | 11 - .../ConstEncrypt/IEncryptPolicy.cs | 43 - .../ConstEncrypt/IEncryptPolicy.cs.meta | 11 - .../Editor/ObfusPasses/ControlFlowObfus.meta | 8 - .../ConfigurableObfuscationPolicy.cs | 133 --- .../ConfigurableObfuscationPolicy.cs.meta | 11 - .../ControlFlowObfus/ControlFlowObfusPass.cs | 80 -- .../ControlFlowObfusPass.cs.meta | 11 - .../ControlFlowObfus/DefaultObfuscator.cs | 20 - .../DefaultObfuscator.cs.meta | 11 - .../ControlFlowObfus/IObfuscator.cs | 15 - .../ControlFlowObfus/IObfuscator.cs.meta | 11 - .../MethodControlFlowCalculator.cs | 894 ---------------- .../MethodControlFlowCalculator.cs.meta | 11 - .../Editor/ObfusPasses/EvalStackObfus.meta | 8 - .../ConfigurableObfuscationPolicy.cs | 147 --- .../ConfigurableObfuscationPolicy.cs.meta | 11 - .../EvalStackObfus/DefaultObfuscator.cs | 225 ---- .../EvalStackObfus/DefaultObfuscator.cs.meta | 11 - .../EvalStackObfus/EvalStackObfusPass.cs | 114 --- .../EvalStackObfus/EvalStackObfusPass.cs.meta | 11 - .../ObfusPasses/EvalStackObfus/IObfuscator.cs | 24 - .../EvalStackObfus/IObfuscator.cs.meta | 11 - .../Editor/ObfusPasses/ExprObfus.meta | 8 - .../ConfigurableObfuscationPolicy.cs | 143 --- .../ConfigurableObfuscationPolicy.cs.meta | 11 - .../ObfusPasses/ExprObfus/ExprObfusPass.cs | 173 ---- .../ExprObfus/ExprObfusPass.cs.meta | 11 - .../ObfusPasses/ExprObfus/IObfuscator.cs | 28 - .../ObfusPasses/ExprObfus/IObfuscator.cs.meta | 11 - .../ObfusPasses/ExprObfus/Obfuscators.meta | 8 - .../Obfuscators/AdvancedObfuscator.cs | 110 -- .../Obfuscators/AdvancedObfuscator.cs.meta | 11 - .../ExprObfus/Obfuscators/BasicObfuscator.cs | 282 ----- .../Obfuscators/BasicObfuscator.cs.meta | 11 - .../Obfuscators/MostAdvancedObfuscator.cs | 83 -- .../MostAdvancedObfuscator.cs.meta | 11 - .../Editor/ObfusPasses/FieldEncrypt.meta | 8 - .../FieldEncrypt/ConfigurableEncryptPolicy.cs | 45 - .../ConfigurableEncryptPolicy.cs.meta | 11 - .../FieldEncrypt/DefaultFieldEncryptor.cs | 201 ---- .../DefaultFieldEncryptor.cs.meta | 11 - .../FieldEncrypt/FieldEncryptPass.cs | 102 -- .../FieldEncrypt/FieldEncryptPass.cs.meta | 11 - .../FieldEncrypt/IEncryptPolicy.cs | 14 - .../FieldEncrypt/IEncryptPolicy.cs.meta | 11 - .../FieldEncrypt/IFieldEncryptor.cs | 26 - .../FieldEncrypt/IFieldEncryptor.cs.meta | 11 - .../Editor/ObfusPasses/Instinct.meta | 8 - .../ObfusPasses/Instinct/InstinctPass.cs | 138 --- .../ObfusPasses/Instinct/InstinctPass.cs.meta | 11 - .../InstructionObfuscationPassBase.cs | 46 - .../InstructionObfuscationPassBase.cs.meta | 11 - .../ObfusPasses/ObfuscationMethodPassBase.cs | 47 - .../ObfuscationMethodPassBase.cs.meta | 11 - .../Editor/ObfusPasses/ObfuscationPassBase.cs | 18 - .../ObfusPasses/ObfuscationPassBase.cs.meta | 11 - .../Editor/ObfusPasses/ObfuscationPassType.cs | 26 - .../ObfusPasses/ObfuscationPassType.cs.meta | 11 - .../Editor/ObfusPasses/SymbolObfus.meta | 8 - .../ObfusPasses/SymbolObfus/INameMaker.cs | 37 - .../SymbolObfus/INameMaker.cs.meta | 11 - .../SymbolObfus/IObfuscationPolicy.cs | 17 - .../SymbolObfus/IObfuscationPolicy.cs.meta | 11 - .../ObfusPasses/SymbolObfus/NameMakers.meta | 8 - .../SymbolObfus/NameMakers/DebugNameMaker.cs | 31 - .../NameMakers/DebugNameMaker.cs.meta | 11 - .../SymbolObfus/NameMakers/INameScope.cs | 11 - .../SymbolObfus/NameMakers/INameScope.cs.meta | 11 - .../SymbolObfus/NameMakers/NameMakerBase.cs | 116 --- .../NameMakers/NameMakerBase.cs.meta | 11 - .../NameMakers/NameMakerFactory.cs | 23 - .../NameMakers/NameMakerFactory.cs.meta | 11 - .../SymbolObfus/NameMakers/NameScope.cs | 41 - .../SymbolObfus/NameMakers/NameScope.cs.meta | 11 - .../SymbolObfus/NameMakers/NameScopeBase.cs | 63 -- .../NameMakers/NameScopeBase.cs.meta | 11 - .../NameMakers/WordSetNameMaker.cs | 22 - .../NameMakers/WordSetNameMaker.cs.meta | 11 - .../ObfusPasses/SymbolObfus/Policies.meta | 8 - .../SymbolObfus/Policies/CacheRenamePolicy.cs | 67 -- .../Policies/CacheRenamePolicy.cs.meta | 11 - .../Policies/CombineRenamePolicy.cs | 40 - .../Policies/CombineRenamePolicy.cs.meta | 11 - .../Policies/ConfigurableRenamePolicy.cs | 792 -------------- .../Policies/ConfigurableRenamePolicy.cs.meta | 11 - .../Policies/ObfuscationPolicyBase.cs | 33 - .../Policies/ObfuscationPolicyBase.cs.meta | 11 - .../SymbolObfus/Policies/SupportPassPolicy.cs | 45 - .../Policies/SupportPassPolicy.cs.meta | 11 - .../Policies/SystemRenamePolicy.cs | 120 --- .../Policies/SystemRenamePolicy.cs.meta | 11 - .../SymbolObfus/Policies/UnityRenamePolicy.cs | 264 ----- .../Policies/UnityRenamePolicy.cs.meta | 11 - .../ReflectionCompatibilityDetector.cs | 306 ------ .../ReflectionCompatibilityDetector.cs.meta | 11 - .../SymbolObfus/RenameRecordMap.cs | 742 -------------- .../SymbolObfus/RenameRecordMap.cs.meta | 11 - .../SymbolObfus/SymbolObfusPass.cs | 31 - .../SymbolObfus/SymbolObfusPass.cs.meta | 11 - .../ObfusPasses/SymbolObfus/SymbolRename.cs | 864 ---------------- .../SymbolObfus/SymbolRename.cs.meta | 11 - .../VirtualMethodGroupCalculator.cs | 299 ------ .../VirtualMethodGroupCalculator.cs.meta | 11 - .../Editor/ObfuscationMethodWhitelist.cs | 110 -- .../Editor/ObfuscationMethodWhitelist.cs.meta | 11 - .../Editor/ObfuscationPassContext.cs | 70 -- .../Editor/ObfuscationPassContext.cs.meta | 11 - .../Editor/Obfuscator.cs | 352 ------- .../Editor/Obfuscator.cs.meta | 11 - .../Editor/ObfuscatorBuilder.cs | 207 ---- .../Editor/ObfuscatorBuilder.cs.meta | 11 - .../Editor/Obfuz.Editor.asmdef | 18 - .../Editor/Obfuz.Editor.asmdef.meta | 7 - .../Editor/Pipeline.cs | 47 - .../Editor/Pipeline.cs.meta | 11 - .../Editor/Settings.meta | 8 - .../Editor/Settings/AssemblySettings.cs | 41 - .../Editor/Settings/AssemblySettings.cs.meta | 11 - .../Editor/Settings/BuildPipelineSettings.cs | 18 - .../Settings/BuildPipelineSettings.cs.meta | 11 - .../Settings/CallObfuscationSettings.cs | 53 - .../Settings/CallObfuscationSettings.cs.meta | 11 - .../Settings/ConstEncryptionSettings.cs | 33 - .../Settings/ConstEncryptionSettings.cs.meta | 11 - .../ControlFlowObfuscationSettings.cs | 31 - .../ControlFlowObfuscationSettings.cs.meta | 11 - .../Editor/Settings/EncryptionVMSettings.cs | 18 - .../Settings/EncryptionVMSettings.cs.meta | 11 - .../Settings/EvalStackObfuscationSettings.cs | 27 - .../EvalStackObfuscationSettings.cs.meta | 11 - .../Settings/ExprObfuscationSettings.cs | 27 - .../Settings/ExprObfuscationSettings.cs.meta | 11 - .../Settings/FieldEncryptionSettings.cs | 33 - .../Settings/FieldEncryptionSettings.cs.meta | 11 - .../Settings/GarbageCodeGenerationSettings.cs | 41 - .../GarbageCodeGenerationSettings.cs.meta | 11 - .../Editor/Settings/ObfuscationLevel.cs | 10 - .../Editor/Settings/ObfuscationLevel.cs.meta | 11 - .../Settings/ObfuscationPassSettings.cs | 16 - .../Settings/ObfuscationPassSettings.cs.meta | 11 - .../Editor/Settings/ObfuzSettings.cs | 122 --- .../Editor/Settings/ObfuzSettings.cs.meta | 11 - .../Editor/Settings/ObfuzSettingsProvider.cs | 123 --- .../Settings/ObfuzSettingsProvider.cs.meta | 11 - .../Editor/Settings/PolymorphicDllSettings.cs | 18 - .../Settings/PolymorphicDllSettings.cs.meta | 11 - .../Editor/Settings/SecretSettings.cs | 28 - .../Editor/Settings/SecretSettings.cs.meta | 11 - .../Settings/SymbolObfuscationSettings.cs | 70 -- .../SymbolObfuscationSettings.cs.meta | 11 - .../Editor/Unity.meta | 8 - .../Editor/Unity/LinkXmlProcess.cs | 149 --- .../Editor/Unity/LinkXmlProcess.cs.meta | 11 - .../Editor/Unity/LiteSymbolMappingReader.cs | 116 --- .../Unity/LiteSymbolMappingReader.cs.meta | 11 - .../Editor/Unity/ObfuscationBeginEventArgs.cs | 8 - .../Unity/ObfuscationBeginEventArgs.cs.meta | 11 - .../Editor/Unity/ObfuscationEndEventArgs.cs | 9 - .../Unity/ObfuscationEndEventArgs.cs.meta | 11 - .../Editor/Unity/ObfuscationProcess.cs | 144 --- .../Editor/Unity/ObfuscationProcess.cs.meta | 11 - .../Editor/Unity/ObfuzMenu.cs | 88 -- .../Editor/Unity/ObfuzMenu.cs.meta | 11 - .../UnityProjectManagedAssemblyResolver.cs | 57 -- ...nityProjectManagedAssemblyResolver.cs.meta | 11 - .../Editor/Utils.meta | 8 - .../Editor/Utils/AssemblyCache.cs | 88 -- .../Editor/Utils/AssemblyCache.cs.meta | 11 - .../Editor/Utils/AssemblyResolverBase.cs | 7 - .../Editor/Utils/AssemblyResolverBase.cs.meta | 11 - .../Editor/Utils/AssertUtil.cs | 28 - .../Editor/Utils/AssertUtil.cs.meta | 11 - .../Editor/Utils/BurstCompileComputeCache.cs | 90 -- .../Utils/BurstCompileComputeCache.cs.meta | 11 - .../Editor/Utils/CachedDictionary.cs | 33 - .../Editor/Utils/CachedDictionary.cs.meta | 11 - .../Editor/Utils/CollectionExtensions.cs | 20 - .../Editor/Utils/CollectionExtensions.cs.meta | 11 - .../Editor/Utils/CombinedAssemblyResolver.cs | 33 - .../Utils/CombinedAssemblyResolver.cs.meta | 11 - .../Editor/Utils/ConfigUtil.cs | 78 -- .../Editor/Utils/ConfigUtil.cs.meta | 11 - .../Editor/Utils/ConstObfusUtil.cs | 177 ---- .../Editor/Utils/ConstObfusUtil.cs.meta | 11 - .../Utils/DisableTypeDefFindCacheScope.cs | 21 - .../DisableTypeDefFindCacheScope.cs.meta | 11 - .../Editor/Utils/EncryptionUtil.cs | 45 - .../Editor/Utils/EncryptionUtil.cs.meta | 11 - .../Editor/Utils/FileUtil.cs | 96 -- .../Editor/Utils/FileUtil.cs.meta | 11 - .../Editor/Utils/GenericArgumentContext.cs | 111 -- .../Utils/GenericArgumentContext.cs.meta | 11 - .../Editor/Utils/HashUtil.cs | 67 -- .../Editor/Utils/HashUtil.cs.meta | 11 - .../Editor/Utils/IAssemblyResolver.cs | 7 - .../Editor/Utils/IAssemblyResolver.cs.meta | 11 - .../Editor/Utils/IRandom.cs | 17 - .../Editor/Utils/IRandom.cs.meta | 11 - .../Editor/Utils/KeyGenerator.cs | 37 - .../Editor/Utils/KeyGenerator.cs.meta | 11 - .../Editor/Utils/MathUtil.cs | 58 -- .../Editor/Utils/MathUtil.cs.meta | 11 - .../Editor/Utils/MetaUtil.cs | 922 ----------------- .../Editor/Utils/MetaUtil.cs.meta | 11 - .../Editor/Utils/NameMatcher.cs | 43 - .../Editor/Utils/NameMatcher.cs.meta | 11 - .../Editor/Utils/NumberRange.cs | 14 - .../Editor/Utils/NumberRange.cs.meta | 11 - .../Utils/ObfuzIgnoreScopeComputeCache.cs | 243 ----- .../ObfuzIgnoreScopeComputeCache.cs.meta | 11 - .../Editor/Utils/PathAssemblyResolver.cs | 28 - .../Editor/Utils/PathAssemblyResolver.cs.meta | 11 - .../Editor/Utils/PlatformUtil.cs | 13 - .../Editor/Utils/PlatformUtil.cs.meta | 11 - .../Editor/Utils/RandomUtil.cs | 19 - .../Editor/Utils/RandomUtil.cs.meta | 11 - .../Editor/Utils/RandomWithKey.cs | 63 -- .../Editor/Utils/RandomWithKey.cs.meta | 11 - .../Editor/Utils/ReflectionUtil.cs | 31 - .../Editor/Utils/ReflectionUtil.cs.meta | 11 - .../Editor/Utils/ThisArgType.cs | 9 - .../Editor/Utils/ThisArgType.cs.meta | 11 - .../Editor/Utils/TypeSigUtil.cs | 219 ---- .../Editor/Utils/TypeSigUtil.cs.meta | 11 - .../com.code-philosophy.obfuz/LICENSE | 21 - .../com.code-philosophy.obfuz/LICENSE.meta | 7 - .../com.code-philosophy.obfuz/Plugins.meta | 8 - .../Plugins/dnlib.dll | Bin 1263616 -> 0 bytes .../Plugins/dnlib.dll.meta | 69 -- .../com.code-philosophy.obfuz/README.md | 73 -- .../com.code-philosophy.obfuz/README.md.meta | 7 - .../com.code-philosophy.obfuz/REAME-EN.md | 73 -- .../REAME-EN.md.meta | 7 - .../com.code-philosophy.obfuz/Runtime.meta | 8 - .../Runtime/AssetUtility.cs | 15 - .../Runtime/AssetUtility.cs.meta | 11 - .../Runtime/ConstUtility.cs | 78 -- .../Runtime/ConstUtility.cs.meta | 11 - .../Runtime/EncryptFieldAttribute.cs | 9 - .../Runtime/EncryptFieldAttribute.cs.meta | 11 - .../Runtime/EncryptionScope.cs | 31 - .../Runtime/EncryptionScope.cs.meta | 11 - .../Runtime/EncryptionService.cs | 127 --- .../Runtime/EncryptionService.cs.meta | 11 - .../Runtime/EncryptorBase.cs | 362 ------- .../Runtime/EncryptorBase.cs.meta | 11 - .../Runtime/ExprUtility.cs | 247 ----- .../Runtime/ExprUtility.cs.meta | 11 - .../Runtime/IEncryptor.cs | 30 - .../Runtime/IEncryptor.cs.meta | 11 - .../Runtime/NullEncryptor.cs | 89 -- .../Runtime/NullEncryptor.cs.meta | 11 - .../Runtime/ObfuscationInstincts.cs | 34 - .../Runtime/ObfuscationInstincts.cs.meta | 11 - .../Runtime/ObfuscationTypeMapper.cs | 72 -- .../Runtime/ObfuscationTypeMapper.cs.meta | 11 - .../Runtime/Obfuz.Runtime.asmdef | 14 - .../Runtime/Obfuz.Runtime.asmdef.meta | 7 - .../Runtime/ObfuzIgnoreAttribute.cs | 20 - .../Runtime/ObfuzIgnoreAttribute.cs.meta | 11 - .../Runtime/ObfuzScope.cs | 24 - .../Runtime/ObfuzScope.cs.meta | 11 - .../com.code-philosophy.obfuz/package.json | 22 - .../package.json.meta | 7 - .../Editor.meta | 8 - .../Editor/ObfuscateUtil.cs | 118 --- .../Editor/ObfuscateUtil.cs.meta | 11 - .../Editor/Obfuz4HybridCLR.asmdef | 19 - .../Editor/Obfuz4HybridCLR.asmdef.meta | 7 - .../Editor/Polymorphic.meta | 8 - .../Polymorphic/PolymorphicCodeGenerator.cs | 224 ---- .../PolymorphicCodeGenerator.cs.meta | 11 - .../Editor/Polymorphic/TableMetaInfos.cs | 300 ------ .../Editor/Polymorphic/TableMetaInfos.cs.meta | 11 - .../Editor/PrebuildCommandExt.cs | 164 --- .../Editor/PrebuildCommandExt.cs.meta | 11 - .../LICENSE | 21 - .../LICENSE.meta | 7 - .../README.md | 2 - .../README.md.meta | 7 - .../Templates~/MetadataReader.h.tpl | 96 -- .../Templates~/PolymorphicDatas.h.tpl | 88 -- .../Templates~/PolymorphicDefs.h.tpl | 28 - .../Templates~/PolymorphicRawImage.cpp.tpl | 897 ---------------- .../Templates~/PolymorphicRawImage.h.tpl | 58 -- .../package.json | 22 - .../package.json.meta | 7 - UnityProject/Packages/manifest.json | 2 + UnityProject/Packages/packages-lock.json | 14 +- UnityProject/ProjectSettings/Obfuz.asset | 6 +- 414 files changed, 572 insertions(+), 25113 deletions(-) delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlFieldRuleParser.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlFieldRuleParser.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConfigurablePassPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConfigurablePassPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConstValues.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConstValues.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/ConstFieldAllocator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/ConstFieldAllocator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/RvaDataAllocator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/RvaDataAllocator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/BasicBlockCollection.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/BasicBlockCollection.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/DefaultMetadataImporter.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/DefaultMetadataImporter.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EntityExtensions.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EntityExtensions.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EvalStackCalculator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EvalStackCalculator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/GroupByModuleEntityManager.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/GroupByModuleEntityManager.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/LocalVariableAllocator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/LocalVariableAllocator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/EncryptionInstructionWithOpCode.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/EncryptionInstructionWithOpCode.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/IEncryptionInstruction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/IEncryptionInstruction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddInstruction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddInstruction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddRotateXorInstruction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddRotateXorInstruction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddXorRotateInstruction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddXorRotateInstruction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/BitRotateInstruction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/BitRotateInstruction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/EncryptFunction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/EncryptFunction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleInstruction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleInstruction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleRotateXorInstruction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleRotateXorInstruction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleXorRotateInstruction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleXorRotateInstruction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorAddRotateInstruction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorAddRotateInstruction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorInstruction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorInstruction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorMultipleRotateInstruction.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorMultipleRotateInstruction.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachine.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachine.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCodeGenerator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCodeGenerator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCreator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCreator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineSimulator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineSimulator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ConfigGarbageCodeGenerator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ConfigGarbageCodeGenerator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/GarbageCodeGenerator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/GarbageCodeGenerator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ISpecificGarbageCodeGenerator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ISpecificGarbageCodeGenerator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/SpecificGarbageCodeGeneratorBase.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/SpecificGarbageCodeGeneratorBase.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/UIGarbageCodeGenerator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/UIGarbageCodeGenerator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/IObfuscationPass.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/IObfuscationPass.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/BasicBlockObfuscationPassBase.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/BasicBlockObfuscationPassBase.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/CallObfusPass.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/CallObfusPass.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/MethodKey.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/MethodKey.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/SpecialWhiteListMethodCalculator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/SpecialWhiteListMethodCalculator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/CleanUpInstructionPass.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/CleanUpInstructionPass.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/RemoveObfuzAttributesPass.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/RemoveObfuzAttributesPass.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConfigurableEncryptPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConfigurableEncryptPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IConstEncryptor.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IConstEncryptor.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IEncryptPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IEncryptPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ControlFlowObfusPass.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ControlFlowObfusPass.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/DefaultObfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/DefaultObfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/IObfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/IObfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/MethodControlFlowCalculator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/MethodControlFlowCalculator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/DefaultObfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/DefaultObfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/EvalStackObfusPass.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/EvalStackObfusPass.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/IObfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/IObfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ExprObfusPass.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ExprObfusPass.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/IObfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/IObfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/AdvancedObfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/AdvancedObfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/BasicObfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/BasicObfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/MostAdvancedObfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/MostAdvancedObfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/ConfigurableEncryptPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/ConfigurableEncryptPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/DefaultFieldEncryptor.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/DefaultFieldEncryptor.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/FieldEncryptPass.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/FieldEncryptPass.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IEncryptPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IEncryptPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IFieldEncryptor.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IFieldEncryptor.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct/InstinctPass.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct/InstinctPass.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/InstructionObfuscationPassBase.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/InstructionObfuscationPassBase.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationMethodPassBase.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationMethodPassBase.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassBase.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassBase.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassType.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassType.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/INameMaker.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/INameMaker.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/IObfuscationPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/IObfuscationPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/DebugNameMaker.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/DebugNameMaker.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/INameScope.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/INameScope.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerBase.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerBase.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerFactory.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerFactory.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScope.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScope.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScopeBase.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScopeBase.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/WordSetNameMaker.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/WordSetNameMaker.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CacheRenamePolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CacheRenamePolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CombineRenamePolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CombineRenamePolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ConfigurableRenamePolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ConfigurableRenamePolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ObfuscationPolicyBase.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ObfuscationPolicyBase.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SupportPassPolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SupportPassPolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SystemRenamePolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SystemRenamePolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/UnityRenamePolicy.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/UnityRenamePolicy.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/ReflectionCompatibilityDetector.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/ReflectionCompatibilityDetector.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/RenameRecordMap.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/RenameRecordMap.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolObfusPass.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolObfusPass.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolRename.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolRename.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/VirtualMethodGroupCalculator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/VirtualMethodGroupCalculator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationMethodWhitelist.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationMethodWhitelist.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationPassContext.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationPassContext.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuscator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuscator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscatorBuilder.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscatorBuilder.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuz.Editor.asmdef delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuz.Editor.asmdef.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Pipeline.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Pipeline.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/AssemblySettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/AssemblySettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/BuildPipelineSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/BuildPipelineSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/CallObfuscationSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/CallObfuscationSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ConstEncryptionSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ConstEncryptionSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ControlFlowObfuscationSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ControlFlowObfuscationSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EncryptionVMSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EncryptionVMSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EvalStackObfuscationSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EvalStackObfuscationSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ExprObfuscationSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ExprObfuscationSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/FieldEncryptionSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/FieldEncryptionSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/GarbageCodeGenerationSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/GarbageCodeGenerationSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationLevel.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationLevel.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationPassSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationPassSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettingsProvider.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettingsProvider.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/PolymorphicDllSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/PolymorphicDllSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SecretSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SecretSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SymbolObfuscationSettings.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SymbolObfuscationSettings.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationBeginEventArgs.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationBeginEventArgs.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationEndEventArgs.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationEndEventArgs.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationProcess.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationProcess.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuzMenu.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuzMenu.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/UnityProjectManagedAssemblyResolver.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/UnityProjectManagedAssemblyResolver.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyCache.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyCache.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyResolverBase.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyResolverBase.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssertUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssertUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/BurstCompileComputeCache.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/BurstCompileComputeCache.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CachedDictionary.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CachedDictionary.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CollectionExtensions.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CollectionExtensions.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CombinedAssemblyResolver.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CombinedAssemblyResolver.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConfigUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConfigUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConstObfusUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConstObfusUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/DisableTypeDefFindCacheScope.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/DisableTypeDefFindCacheScope.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/EncryptionUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/EncryptionUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/FileUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/FileUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/GenericArgumentContext.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/GenericArgumentContext.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/HashUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/HashUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IAssemblyResolver.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IAssemblyResolver.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IRandom.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IRandom.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/KeyGenerator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/KeyGenerator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MathUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MathUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MetaUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MetaUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NameMatcher.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NameMatcher.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NumberRange.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NumberRange.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ObfuzIgnoreScopeComputeCache.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ObfuzIgnoreScopeComputeCache.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PathAssemblyResolver.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PathAssemblyResolver.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PlatformUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PlatformUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomWithKey.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomWithKey.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ReflectionUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ReflectionUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ThisArgType.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ThisArgType.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/TypeSigUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/TypeSigUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/LICENSE delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/LICENSE.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Plugins.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Plugins/dnlib.dll delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Plugins/dnlib.dll.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/README.md delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/README.md.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/REAME-EN.md delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/REAME-EN.md.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/AssetUtility.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/AssetUtility.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ConstUtility.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ConstUtility.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptFieldAttribute.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptFieldAttribute.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionScope.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionScope.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionService.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionService.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptorBase.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptorBase.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ExprUtility.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ExprUtility.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/IEncryptor.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/IEncryptor.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/NullEncryptor.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/NullEncryptor.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationInstincts.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationInstincts.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationTypeMapper.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationTypeMapper.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/Obfuz.Runtime.asmdef delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/Obfuz.Runtime.asmdef.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzIgnoreAttribute.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzIgnoreAttribute.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzScope.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzScope.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/package.json delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz/package.json.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/ObfuscateUtil.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/ObfuscateUtil.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Obfuz4HybridCLR.asmdef delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Obfuz4HybridCLR.asmdef.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/PolymorphicCodeGenerator.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/PolymorphicCodeGenerator.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/TableMetaInfos.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/TableMetaInfos.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/PrebuildCommandExt.cs delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/PrebuildCommandExt.cs.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/LICENSE delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/LICENSE.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/README.md delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/README.md.meta delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/MetadataReader.h.tpl delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicDatas.h.tpl delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicDefs.h.tpl delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicRawImage.cpp.tpl delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicRawImage.h.tpl delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/package.json delete mode 100644 UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/package.json.meta diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp.cs index f6877d2f..df4954be 100644 --- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp.cs +++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp.cs @@ -1,6 +1,9 @@ using System.Collections.Generic; using System.Reflection; using GameLogic; +#if ENABLE_OBFUZ +using Obfuz; +#endif using TEngine; #pragma warning disable CS0436 @@ -8,6 +11,9 @@ using TEngine; /// /// 游戏App。 /// +#if ENABLE_OBFUZ +[ObfuzIgnore] +#endif public partial class GameApp { private static List _hotfixAssembly; @@ -23,12 +29,13 @@ public partial class GameApp Log.Warning("======= 看到此条日志代表你成功运行了热更新代码 ======="); Log.Warning("======= Entrance GameApp ======="); Utility.Unity.AddDestroyListener(Release); + Log.Warning("======= StartGameLogic ======="); StartGameLogic(); } private static void StartGameLogic() { - GameEvent.Get().ShowLoginUI(); + // GameEvent.Get().ShowLoginUI(); GameModule.UI.ShowUIAsync(); } diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameLogic.asmdef b/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameLogic.asmdef index 675be791..adc437b8 100644 --- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameLogic.asmdef +++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameLogic.asmdef @@ -10,7 +10,8 @@ "GUID:47f9fc774596be54ebfed7739cd70c86", "GUID:1aa3e8589868c80499255710874679c0", "GUID:d8b63aba1907145bea998dd612889d6b", - "GUID:756335c0388f7114790e504ed368ae1d" + "GUID:756335c0388f7114790e504ed368ae1d", + "GUID:4140bd2e2764f1f47ab93125ecb61942" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/UI/BattleMainUI/BattleMainUI.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/UI/BattleMainUI/BattleMainUI.cs index 12557c87..7c19fd7d 100644 --- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/UI/BattleMainUI/BattleMainUI.cs +++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/UI/BattleMainUI/BattleMainUI.cs @@ -1,9 +1,8 @@ using UnityEngine; -using UnityEngine.UI; -using TEngine; namespace GameLogic { + [Obfuz.ObfuzIgnore(Obfuz.ObfuzScope.TypeName)] [Window(UILayer.UI)] class BattleMainUI : UIWindow { diff --git a/UnityProject/Assets/Obfuz/SymbolObfus/symbol-mapping.xml b/UnityProject/Assets/Obfuz/SymbolObfus/symbol-mapping.xml index 510f5e90..7525a61b 100644 --- a/UnityProject/Assets/Obfuz/SymbolObfus/symbol-mapping.xml +++ b/UnityProject/Assets/Obfuz/SymbolObfus/symbol-mapping.xml @@ -7,21 +7,21 @@ - + - - + + - - + + - + @@ -34,7 +34,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -140,26 +140,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -176,7 +156,6 @@ - @@ -186,7 +165,6 @@ - @@ -194,11 +172,8 @@ - - - @@ -213,19 +188,15 @@ - - - - @@ -237,28 +208,8 @@ - - - - - - - - - - - - - - - - - - - - @@ -349,6 +300,7 @@ + @@ -373,6 +325,7 @@ + @@ -409,6 +362,7 @@ + @@ -487,6 +441,7 @@ + @@ -516,6 +471,7 @@ + @@ -533,6 +489,7 @@ + @@ -666,9 +623,6 @@ - - - @@ -683,7 +637,6 @@ - @@ -753,7 +706,6 @@ - @@ -773,19 +725,13 @@ - - - - - - - - - - - - - + + + + + + + @@ -835,7 +781,7 @@ - + @@ -928,7 +874,7 @@ - + @@ -1284,6 +1230,466 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5470,6 +5876,7 @@ + @@ -7120,6 +7527,7 @@ + @@ -7177,6 +7585,7 @@ + @@ -7480,6 +7889,7 @@ + @@ -7489,6 +7899,7 @@ + @@ -7496,6 +7907,7 @@ + @@ -7522,6 +7934,7 @@ + @@ -7529,6 +7942,7 @@ + @@ -8065,6 +8479,7 @@ + @@ -8116,6 +8531,7 @@ + @@ -8123,6 +8539,7 @@ + @@ -8134,6 +8551,7 @@ + @@ -8144,6 +8562,7 @@ + @@ -8163,6 +8582,7 @@ + @@ -8313,6 +8733,7 @@ + @@ -8322,6 +8743,7 @@ + @@ -8333,6 +8755,7 @@ + @@ -8347,6 +8770,7 @@ + @@ -8363,6 +8787,7 @@ + @@ -8378,6 +8803,7 @@ + @@ -8393,6 +8819,7 @@ + @@ -8401,6 +8828,7 @@ + @@ -8546,6 +8974,7 @@ + @@ -8560,6 +8989,7 @@ + @@ -8570,6 +9000,7 @@ + @@ -8708,6 +9139,7 @@ + @@ -8715,6 +9147,7 @@ + @@ -8722,6 +9155,7 @@ + @@ -8912,6 +9346,7 @@ + @@ -9006,6 +9441,7 @@ + @@ -9015,6 +9451,7 @@ + @@ -9024,6 +9461,7 @@ + @@ -9031,6 +9469,7 @@ + @@ -9372,18 +9811,21 @@ + + + \ No newline at end of file diff --git a/UnityProject/Packages/com.code-philosophy.hybridclr/Data~/hybridclr_version.json b/UnityProject/Packages/com.code-philosophy.hybridclr/Data~/hybridclr_version.json index afda70ec..93672f79 100644 --- a/UnityProject/Packages/com.code-philosophy.hybridclr/Data~/hybridclr_version.json +++ b/UnityProject/Packages/com.code-philosophy.hybridclr/Data~/hybridclr_version.json @@ -2,37 +2,37 @@ "versions": [ { "unity_version":"2019", - "hybridclr" : { "branch":"v8.3.0"}, + "hybridclr" : { "branch":"v8.4.0"}, "il2cpp_plus": { "branch":"v2019-8.1.0"} }, { "unity_version":"2020", - "hybridclr" : { "branch":"v8.3.0"}, + "hybridclr" : { "branch":"v8.4.0"}, "il2cpp_plus": { "branch":"v2020-8.1.0"} }, { "unity_version":"2021", - "hybridclr" : { "branch":"v8.3.0"}, + "hybridclr" : { "branch":"v8.4.0"}, "il2cpp_plus": { "branch":"v2021-8.1.0"} }, { "unity_version":"2022", - "hybridclr" : { "branch":"v8.3.0"}, + "hybridclr" : { "branch":"v8.4.0"}, "il2cpp_plus": { "branch":"v2022-8.2.0"} }, { "unity_version":"2022-tuanjie", - "hybridclr" : { "branch":"v8.3.0"}, + "hybridclr" : { "branch":"v8.4.0"}, "il2cpp_plus": { "branch":"v2022-tuanjie-8.3.0"} }, { "unity_version":"2023", - "hybridclr" : { "branch":"v8.3.0"}, + "hybridclr" : { "branch":"v8.4.0"}, "il2cpp_plus": { "branch":"v2023-8.1.0"} }, { "unity_version":"6000", - "hybridclr" : { "branch":"v8.3.0"}, + "hybridclr" : { "branch":"v8.4.0"}, "il2cpp_plus": { "branch":"v6000-8.1.0"} } ] diff --git a/UnityProject/Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs b/UnityProject/Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs index 8e6560a9..09a6f73a 100644 --- a/UnityProject/Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs +++ b/UnityProject/Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs @@ -136,8 +136,8 @@ namespace HybridCLR.Editor.Commands options = buildOptions, target = target, targetGroup = BuildPipeline.GetBuildTargetGroup(target), -#if UNITY_2021_1_OR_NEWER - subtarget = (int)EditorUserBuildSettings.standaloneBuildSubtarget, +#if UNITY_SERVER + subtarget = (int)StandaloneBuildSubtarget.Server, #endif }; diff --git a/UnityProject/Packages/com.code-philosophy.hybridclr/RELEASELOG.md b/UnityProject/Packages/com.code-philosophy.hybridclr/RELEASELOG.md index 372cb43f..8cf8136f 100644 --- a/UnityProject/Packages/com.code-philosophy.hybridclr/RELEASELOG.md +++ b/UnityProject/Packages/com.code-philosophy.hybridclr/RELEASELOG.md @@ -1,5 +1,20 @@ # ReleaseLog +## 8.4.0 + +Release Date: 2025-07-26. + +### Runtime + +- **[new] IMPORTANT! support custom image format** +- [change] the type of field `offset` of ldsfld, stfld, ldthreadlocalfld、stthreadlocalfld changed from uint16_t to uint32_t so that supports class with huge static fields. +- [opt] optimize to use NewValueTypeVar_Ctor_0 for new zero-argument value type and System.Activator.CreateInstance<T>() +- [opt] optimize new ValueType with zero arguments. + +### Editor + +- [fix] fix the issue that `Texture Compression` option in Build Settings was changed after running `HybridCLR/Generate/All` on Android platform + ## 8.3.0 Release Date: 2025-07-04. diff --git a/UnityProject/Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs b/UnityProject/Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs index 93d4b386..d3278101 100644 --- a/UnityProject/Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs +++ b/UnityProject/Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs @@ -11,6 +11,9 @@ namespace HybridCLR HOMOLOGOUS_ASSEMBLY_HAS_LOADED, // can not load supplementary metadata assembly for the same assembly INVALID_HOMOLOGOUS_MODE, // invalid homologous image mode PDB_BAD_FILE, // invalid pdb file + UNKNOWN_IMAGE_FORMAT, + UNSUPPORT_FORMAT_VERSION, + UNMATCH_FORMAT_VARIANT, }; } diff --git a/UnityProject/Packages/com.code-philosophy.hybridclr/package.json b/UnityProject/Packages/com.code-philosophy.hybridclr/package.json index 47508adf..196808c7 100644 --- a/UnityProject/Packages/com.code-philosophy.hybridclr/package.json +++ b/UnityProject/Packages/com.code-philosophy.hybridclr/package.json @@ -1,6 +1,6 @@ { "name": "com.code-philosophy.hybridclr", - "version": "8.3.0", + "version": "8.4.0", "displayName": "HybridCLR", "description": "HybridCLR is a fully featured, zero-cost, high-performance, low-memory solution for Unity's all-platform native c# hotupdate.", "category": "Scripting", diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor.meta deleted file mode 100644 index e4fe3a4d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 2326b426d539e084dbddf7f7c23ed1bd -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf.meta deleted file mode 100644 index d42ac4f6..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 241df8eaf3a34dc47a0873c37ddb2695 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs deleted file mode 100644 index 8b349974..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs +++ /dev/null @@ -1,263 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Xml; -using UnityEngine; - -namespace Obfuz.Conf -{ - public interface IRule - { - void InheritParent(T parentRule); - } - - - public interface IMethodRule where R : IRule - { - string Name { get; set; } - NameMatcher NameMatcher { get; set; } - - R Rule { get; set; } - } - - public abstract class MethodRuleBase : IMethodRule where R : IRule - { - public string Name { get; set; } - public NameMatcher NameMatcher { get; set; } - - public R Rule { get; set; } - } - - public interface ITypeRule where T : IMethodRule where R : IRule - { - string Name { get; set; } - - NameMatcher NameMatcher { get; set; } - - R Rule { get; set; } - - List Methods { get; set; } - } - - public abstract class TypeRuleBase : ITypeRule where T : IMethodRule where R : IRule - { - public string Name { get; set; } - - public NameMatcher NameMatcher { get; set; } - - public R Rule { get; set; } - - public List Methods { get; set; } - } - - public interface IAssemblyRule where TType : ITypeRule where TMethod : IMethodRule where TRule : IRule - { - string Name { get; set; } - - TRule Rule { get; set; } - - List Types { get; set; } - } - public abstract class AssemblyRuleBase : IAssemblyRule where TType : ITypeRule where TMethod : IMethodRule where TRule : IRule - { - public string Name { get; set; } - - public TRule Rule { get; set; } - - public List Types { get; set; } - } - - public class XmlAssemblyTypeMethodRuleParser - where TMethod : IMethodRule, new() - where TType : ITypeRule, new() - where TAssembly : IAssemblyRule, new() - where TRule : IRule, new() - { - private readonly HashSet _toObfuscatedAssemblyNames; - private readonly Func _ruleParser; - private readonly Action _unknownNodeTypeHandler; - private readonly Dictionary _assemblySpecs = new Dictionary(); - - public XmlAssemblyTypeMethodRuleParser(IEnumerable toObfuscatedAssemblyNames, Func ruleParser, Action unknownNodeTypeHandler) - { - _toObfuscatedAssemblyNames = new HashSet(toObfuscatedAssemblyNames); - _ruleParser = ruleParser; - _unknownNodeTypeHandler = unknownNodeTypeHandler; - } - - public Dictionary AssemblySpecs => _assemblySpecs; - - public void LoadConfigs(IEnumerable configFiles) - { - foreach (var configFile in configFiles) - { - LoadConfig(configFile); - } - } - - public void LoadConfig(string configFile) - { - if (string.IsNullOrEmpty(configFile)) - { - throw new Exception($"Invalid xml file {configFile}, file name is empty"); - } - Debug.Log($"ConfigurableObfuscationPolicy::LoadConfig {configFile}"); - var doc = new XmlDocument(); - doc.Load(configFile); - var root = doc.DocumentElement; - if (root.Name != "obfuz") - { - throw new Exception($"Invalid xml file {configFile}, root name should be 'obfuz'"); - } - foreach (XmlNode node in root.ChildNodes) - { - if (!(node is XmlElement ele)) - { - continue; - } - switch (ele.Name) - { - case "assembly": - { - TAssembly assSpec = ParseAssembly(configFile, ele); - _assemblySpecs.Add(assSpec.Name, assSpec); - break; - } - default: - { - if (_unknownNodeTypeHandler == null) - { - throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}"); - } - _unknownNodeTypeHandler(configFile, ele); - break; - } - } - } - } - - private TAssembly ParseAssembly(string configFile, XmlElement ele) - { - var assemblySpec = new TAssembly(); - string name = ele.GetAttribute("name"); - if (!_toObfuscatedAssemblyNames.Contains(name)) - { - throw new Exception($"Invalid xml file {configFile}, assembly name {name} isn't in toObfuscatedAssemblyNames"); - } - if (_assemblySpecs.ContainsKey(name)) - { - throw new Exception($"Invalid xml file {configFile}, assembly name {name} is duplicated"); - } - assemblySpec.Name = name; - assemblySpec.Rule = _ruleParser(configFile, ele); - - var types = new List(); - assemblySpec.Types = types; - foreach (XmlNode node in ele.ChildNodes) - { - if (!(node is XmlElement childEle)) - { - continue; - } - switch (childEle.Name) - { - case "type": - { - types.Add(ParseType(configFile, childEle)); - break; - } - default: - { - throw new Exception($"Invalid xml file, unknown node {childEle.Name}"); - } - } - } - return assemblySpec; - } - - private TType ParseType(string configFile, XmlElement element) - { - var typeSpec = new TType(); - - string name = element.GetAttribute("name"); - typeSpec.Name = name; - typeSpec.NameMatcher = new NameMatcher(name); - typeSpec.Rule = _ruleParser(configFile, element); - - var methods = new List(); - typeSpec.Methods = methods; - foreach (XmlNode node in element.ChildNodes) - { - if (!(node is XmlElement ele)) - { - continue; - } - switch (ele.Name) - { - case "method": - { - methods.Add(ParseMethod(configFile, ele)); - break; - } - default: - { - throw new Exception($"Invalid xml file, unknown node {ele.Name}"); - } - } - } - return typeSpec; - } - - private TMethod ParseMethod(string configFile, XmlElement element) - { - var methodSpec = new TMethod(); - string name = element.GetAttribute("name"); - methodSpec.Name = name; - methodSpec.NameMatcher = new NameMatcher(name); - methodSpec.Rule = _ruleParser(configFile, element); - return methodSpec; - } - - public TRule GetMethodRule(MethodDef method, TRule defaultRule) - { - var assemblyName = method.DeclaringType.Module.Assembly.Name; - if (!_assemblySpecs.TryGetValue(assemblyName, out var assSpec)) - { - return defaultRule; - } - string declaringTypeName = method.DeclaringType.FullName; - foreach (var typeSpec in assSpec.Types) - { - if (typeSpec.NameMatcher.IsMatch(declaringTypeName)) - { - foreach (var methodSpec in typeSpec.Methods) - { - if (methodSpec.NameMatcher.IsMatch(method.Name)) - { - return methodSpec.Rule; - } - } - return typeSpec.Rule; - } - } - return assSpec.Rule; - } - - public void InheritParentRules(TRule defaultRule) - { - foreach (TAssembly assSpec in _assemblySpecs.Values) - { - assSpec.Rule.InheritParent(defaultRule); - foreach (TType typeSpec in assSpec.Types) - { - typeSpec.Rule.InheritParent(assSpec.Rule); - foreach (TMethod methodSpec in typeSpec.Methods) - { - methodSpec.Rule.InheritParent(typeSpec.Rule); - } - } - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs.meta deleted file mode 100644 index 84f5aa9b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 36a3e142db81f6d4bb54938525e31973 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlFieldRuleParser.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlFieldRuleParser.cs deleted file mode 100644 index 5cef8c98..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlFieldRuleParser.cs +++ /dev/null @@ -1,203 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Xml; - -namespace Obfuz.Conf -{ - - - - public class XmlFieldRuleParser where R : class, new() - { - private readonly HashSet _toObfuscatedAssemblyNames; - private readonly Func _ruleParser; - private readonly Action _unknownNodeTypeHandler; - private readonly Dictionary _assemblySpecs = new Dictionary(); - - - private class FieldSpec - { - public string Name { get; set; } - public NameMatcher NameMatcher { get; set; } - - public R Rule { get; set; } - } - - private class TypeSpec - { - public string Name { get; set; } - - public NameMatcher NameMatcher { get; set; } - - public List Fields { get; set; } - } - - private class AssemblySpec - { - public string Name { get; set; } - - public List Types { get; set; } - } - - public XmlFieldRuleParser(IEnumerable toObfuscatedAssemblyNames, Func ruleParser, Action unknownNodeTypeHandler) - { - _toObfuscatedAssemblyNames = new HashSet(toObfuscatedAssemblyNames); - _ruleParser = ruleParser; - _unknownNodeTypeHandler = unknownNodeTypeHandler; - } - - public void LoadConfigs(IEnumerable configFiles) - { - foreach (var configFile in configFiles) - { - LoadConfig(configFile); - } - } - - public void LoadConfig(string configFile) - { - if (string.IsNullOrEmpty(configFile)) - { - throw new Exception($"Invalid xml file {configFile}, file name is empty"); - } - var doc = new XmlDocument(); - doc.Load(configFile); - var root = doc.DocumentElement; - if (root.Name != "obfuz") - { - throw new Exception($"Invalid xml file {configFile}, root name should be 'obfuz'"); - } - foreach (XmlNode node in root.ChildNodes) - { - if (!(node is XmlElement ele)) - { - continue; - } - switch (ele.Name) - { - case "assembly": - { - AssemblySpec assSpec = ParseAssembly(configFile, ele); - _assemblySpecs.Add(assSpec.Name, assSpec); - break; - } - default: - { - if (_unknownNodeTypeHandler == null) - { - throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}"); - } - _unknownNodeTypeHandler(configFile, ele); - break; - } - } - } - } - - private AssemblySpec ParseAssembly(string configFile, XmlElement ele) - { - var assemblySpec = new AssemblySpec(); - string name = ele.GetAttribute("name"); - if (!_toObfuscatedAssemblyNames.Contains(name)) - { - throw new Exception($"Invalid xml file {configFile}, assembly name {name} isn't in toObfuscatedAssemblyNames"); - } - if (_assemblySpecs.ContainsKey(name)) - { - throw new Exception($"Invalid xml file {configFile}, assembly name {name} is duplicated"); - } - assemblySpec.Name = name; - - var types = new List(); - assemblySpec.Types = types; - foreach (XmlNode node in ele.ChildNodes) - { - if (!(node is XmlElement childEle)) - { - continue; - } - switch (childEle.Name) - { - case "type": - { - types.Add(ParseType(configFile, childEle)); - break; - } - default: - { - throw new Exception($"Invalid xml file, unknown node {childEle.Name}"); - } - } - } - return assemblySpec; - } - - private TypeSpec ParseType(string configFile, XmlElement element) - { - var typeSpec = new TypeSpec(); - - string name = element.GetAttribute("name"); - typeSpec.Name = name; - typeSpec.NameMatcher = new NameMatcher(name); - - var fields = new List(); - typeSpec.Fields = fields; - foreach (XmlNode node in element.ChildNodes) - { - if (!(node is XmlElement ele)) - { - continue; - } - switch (ele.Name) - { - case "field": - { - fields.Add(ParseField(configFile, ele)); - break; - } - default: - { - throw new Exception($"Invalid xml file, unknown node {ele.Name}"); - } - } - } - return typeSpec; - } - - private FieldSpec ParseField(string configFile, XmlElement element) - { - var fieldSpec = new FieldSpec(); - string name = element.GetAttribute("name"); - fieldSpec.Name = name; - fieldSpec.NameMatcher = new NameMatcher(name); - fieldSpec.Rule = _ruleParser(configFile, element); - return fieldSpec; - } - - public R GetFieldRule(FieldDef field) - { - var assemblyName = field.DeclaringType.Module.Assembly.Name; - if (!_assemblySpecs.TryGetValue(assemblyName, out var assSpec)) - { - return null; - } - string declaringTypeName = field.DeclaringType.FullName; - foreach (var typeSpec in assSpec.Types) - { - if (typeSpec.NameMatcher.IsMatch(declaringTypeName)) - { - foreach (var fieldSpec in typeSpec.Fields) - { - if (fieldSpec.NameMatcher.IsMatch(field.Name)) - { - return fieldSpec.Rule; - } - } - } - } - return null; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlFieldRuleParser.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlFieldRuleParser.cs.meta deleted file mode 100644 index d8995b9e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Conf/XmlFieldRuleParser.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1578270b9b81e1e4dba84d562c91090f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConfigurablePassPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConfigurablePassPolicy.cs deleted file mode 100644 index 3a94a919..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConfigurablePassPolicy.cs +++ /dev/null @@ -1,544 +0,0 @@ -using dnlib.DotNet; -using Obfuz.ObfusPasses; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Xml; -using UnityEngine; - -namespace Obfuz -{ - public class ConfigurablePassPolicy - { - class PassRule - { - public ObfuscationPassType? enablePasses; - public ObfuscationPassType? disablePasses; - public ObfuscationPassType? addPasses; - public ObfuscationPassType? removePasses; - public ObfuscationPassType finalPasses; - - public void InheritParent(PassRule parentRule, ObfuscationPassType globalEnabledPasses) - { - finalPasses = parentRule.finalPasses; - if (enablePasses != null) - { - finalPasses = enablePasses.Value; - } - if (disablePasses != null) - { - finalPasses = ~disablePasses.Value; - } - if (addPasses != null) - { - finalPasses |= addPasses.Value; - } - if (removePasses != null) - { - finalPasses &= ~removePasses.Value; - } - finalPasses &= globalEnabledPasses; - } - } - - class SpecBase - { - public string name; - public NameMatcher nameMatcher; - public PassRule rule; - } - - class MethodSpec : SpecBase - { - } - - class FieldSpec : SpecBase - { - } - - class PropertySpec : SpecBase - { - } - - class EventSpec : SpecBase - { - } - - class TypeSpec : SpecBase - { - public List fields = new List(); - public List methods = new List(); - public List properties = new List(); - public List events = new List(); - } - - class AssemblySpec - { - public string name; - public NameMatcher nameMatcher; - public PassRule rule; - public List types = new List(); - } - - private readonly ObfuscationPassType _enabledPasses; - private readonly HashSet _toObfuscatedAssemblyNames; - private readonly List _assemblySpecs = new List(); - private readonly PassRule _defaultPassRule; - - private string _curLoadingConfig; - - public ConfigurablePassPolicy(IEnumerable toObfuscatedAssemblyNames, ObfuscationPassType enabledPasses, List configFiles) - { - _toObfuscatedAssemblyNames = new HashSet(toObfuscatedAssemblyNames); - _enabledPasses = enabledPasses; - _defaultPassRule = new PassRule { finalPasses = enabledPasses }; - LoadConfigs(configFiles); - InheritParentRules(enabledPasses); - } - - private void LoadConfigs(IEnumerable configFiles) - { - foreach (var configFile in configFiles) - { - LoadConfig(configFile); - } - } - - private void InheritParentRules(ObfuscationPassType enablePasses) - { - var defaultRule = new PassRule - { - enablePasses = enablePasses, - finalPasses = enablePasses, - }; - foreach (AssemblySpec assSpec in _assemblySpecs) - { - assSpec.rule.InheritParent(defaultRule, enablePasses); - foreach (TypeSpec typeSpec in assSpec.types) - { - typeSpec.rule.InheritParent(assSpec.rule, enablePasses); - foreach (FieldSpec fieldSpec in typeSpec.fields) - { - fieldSpec.rule.InheritParent(typeSpec.rule, enablePasses); - } - foreach (MethodSpec methodSpec in typeSpec.methods) - { - methodSpec.rule.InheritParent(typeSpec.rule, enablePasses); - } - foreach (PropertySpec propertySpec in typeSpec.properties) - { - propertySpec.rule.InheritParent(typeSpec.rule, enablePasses); - } - foreach (EventSpec eventSpec in typeSpec.events) - { - eventSpec.rule.InheritParent(typeSpec.rule, enablePasses); - } - } - } - } - - public void LoadConfig(string configFile) - { - if (string.IsNullOrEmpty(configFile)) - { - throw new Exception($"Invalid xml file {configFile}, file name is empty"); - } - _curLoadingConfig = configFile; - - Debug.Log($"ConfigurablePassPolicy::LoadConfig {configFile}"); - var doc = new XmlDocument(); - doc.Load(configFile); - var root = doc.DocumentElement; - if (root.Name != "obfuz") - { - throw new Exception($"Invalid xml file {configFile}, root name should be 'obfuz'"); - } - foreach (XmlNode node in root.ChildNodes) - { - if (!(node is XmlElement ele)) - { - continue; - } - switch (ele.Name) - { - case "assembly": - { - AssemblySpec assSpec = ParseAssembly(ele); - _assemblySpecs.Add(assSpec); - break; - } - default: - { - throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}"); - } - } - } - } - - (bool, ObfuscationPassType) ParseObfuscationType(string obfuscationPassTypesStr) - { - bool delta = false; - if (obfuscationPassTypesStr[0] == '+' || obfuscationPassTypesStr[0] == '-') - { - delta = true; - obfuscationPassTypesStr = obfuscationPassTypesStr.Substring(1); - } - ObfuscationPassType passType = ObfuscationPassType.None; - foreach (var passName in obfuscationPassTypesStr.Split('|')) - { - if (Enum.TryParse(passName, out var pass)) - { - passType |= pass; - } - else - { - throw new Exception($"Invalid xml file {_curLoadingConfig}, unknown pass type {passName}"); - } - } - return (delta, passType); - } - - private PassRule ParseRule(XmlElement ele) - { - var r = new PassRule(); - if (ele.HasAttribute("enable")) - { - string enablePassStr = ele.GetAttribute("enable"); - if (string.IsNullOrEmpty(enablePassStr)) - { - throw new Exception($"Invalid xml file {_curLoadingConfig}, enable attribute is empty"); - } - var (delta, passType) = ParseObfuscationType(enablePassStr); - if (delta) - { - r.addPasses = passType; - } - else - { - r.enablePasses = passType; - } - } - if (ele.HasAttribute("disable")) - { - string disablePassStr = ele.GetAttribute("disable"); - if (string.IsNullOrEmpty(disablePassStr)) - { - throw new Exception($"Invalid xml file {_curLoadingConfig}, disable attribute is empty"); - } - var (delta, passType) = ParseObfuscationType(disablePassStr); - if (delta) - { - r.removePasses = passType; - } - else - { - r.disablePasses = passType; - } - } - if (r.enablePasses != null && (r.disablePasses != null || r.addPasses != null || r.removePasses != null)) - { - throw new Exception($"Invalid xml file {_curLoadingConfig}, enable and disable can't be used together"); - } - if (r.disablePasses != null && (r.enablePasses != null || r.addPasses != null || r.removePasses != null)) - { - throw new Exception($"Invalid xml file {_curLoadingConfig}, disable and enable can't be used together"); - } - return r; - } - - private AssemblySpec ParseAssembly(XmlElement ele) - { - var assemblySpec = new AssemblySpec(); - string name = ele.GetAttribute("name"); - if (!_toObfuscatedAssemblyNames.Contains(name)) - { - throw new Exception($"Invalid xml file {_curLoadingConfig}, assembly name {name} isn't in toObfuscatedAssemblyNames"); - } - assemblySpec.name = name; - assemblySpec.nameMatcher = new NameMatcher(name); - assemblySpec.rule = ParseRule(ele); - - - var types = assemblySpec.types; - foreach (XmlNode node in ele.ChildNodes) - { - if (!(node is XmlElement childEle)) - { - continue; - } - switch (childEle.Name) - { - case "type": - { - types.Add(ParseType(childEle)); - break; - } - default: - { - throw new Exception($"Invalid xml file, unknown node {childEle.Name}"); - } - } - } - return assemblySpec; - } - - private TypeSpec ParseType(XmlElement element) - { - var typeSpec = new TypeSpec(); - - string name = element.GetAttribute("name"); - typeSpec.name = name; - typeSpec.nameMatcher = new NameMatcher(name); - typeSpec.rule = ParseRule(element); - - List fields = typeSpec.fields; - List methods = typeSpec.methods; - List properties = typeSpec.properties; - List events = typeSpec.events; - foreach (XmlNode node in element.ChildNodes) - { - if (!(node is XmlElement ele)) - { - continue; - } - switch (ele.Name) - { - case "field": - { - fields.Add(ParseField(ele)); - break; - } - case "method": - { - methods.Add(ParseMethod(ele)); - break; - } - case "property": - { - properties.Add(ParseProperty(ele)); - break; - } - case "event": - { - events.Add(ParseEvent(ele)); - break; - } - default: - { - throw new Exception($"Invalid xml file, unknown node {ele.Name}"); - } - } - } - return typeSpec; - } - - private void ParseSpecObject(XmlElement element, SpecBase obj) - { - string name = element.GetAttribute("name"); - obj.name = name; - obj.nameMatcher = new NameMatcher(name); - obj.rule = ParseRule(element); - } - - private FieldSpec ParseField(XmlElement element) - { - var fieldSpec = new FieldSpec(); - ParseSpecObject(element, fieldSpec); - return fieldSpec; - } - - private MethodSpec ParseMethod(XmlElement element) - { - var methodSpec = new MethodSpec(); - ParseSpecObject(element, methodSpec); - return methodSpec; - } - - private PropertySpec ParseProperty(XmlElement element) - { - var propertySpec = new PropertySpec(); - ParseSpecObject(element, propertySpec); - return propertySpec; - } - - private EventSpec ParseEvent(XmlElement element) - { - var eventSpec = new EventSpec(); - ParseSpecObject(element, eventSpec); - return eventSpec; - } - - private readonly Dictionary _modulePassRuleCaches = new Dictionary(); - private readonly Dictionary _typePassRuleCaches = new Dictionary(); - private readonly Dictionary _methodPassRuleCaches = new Dictionary(); - private readonly Dictionary _fieldPassRuleCaches = new Dictionary(); - private readonly Dictionary _propertyPassRuleCaches = new Dictionary(); - private readonly Dictionary _eventPassRuleCaches = new Dictionary(); - - - private (AssemblySpec, PassRule) GetAssemblySpec(ModuleDef module) - { - if (!_modulePassRuleCaches.TryGetValue(module, out var result)) - { - result = (null, _defaultPassRule); - string assName = module.Assembly.Name; - foreach (var ass in _assemblySpecs) - { - if (ass.nameMatcher.IsMatch(assName)) - { - result = (ass, ass.rule); - break; - } - } - _modulePassRuleCaches.Add(module, result); - } - return result; - } - - private (TypeSpec, PassRule) GetTypeSpec(TypeDef type) - { - if (!_typePassRuleCaches.TryGetValue(type, out var result)) - { - var assResult = GetAssemblySpec(type.Module); - result = (null, assResult.Item2); - if (assResult.Item1 != null) - { - string typeName = type.FullName; - foreach (var typeSpec in assResult.Item1.types) - { - if (typeSpec.nameMatcher.IsMatch(typeName)) - { - result = (typeSpec, typeSpec.rule); - break; - } - } - } - _typePassRuleCaches.Add(type, result); - } - return result; - } - - private (MethodSpec, PassRule) GetMethodSpec(MethodDef method) - { - if (!_methodPassRuleCaches.TryGetValue(method, out var result)) - { - var typeResult = GetTypeSpec(method.DeclaringType); - result = (null, typeResult.Item2); - if (typeResult.Item1 != null) - { - string methodName = method.Name; - foreach (var methodSpec in typeResult.Item1.methods) - { - if (methodSpec.nameMatcher.IsMatch(methodName)) - { - result = (methodSpec, methodSpec.rule); - break; - } - } - } - _methodPassRuleCaches.Add(method, result); - } - return result; - } - - private (FieldSpec, PassRule) GetFieldSpec(FieldDef field) - { - if (!_fieldPassRuleCaches.TryGetValue(field, out var result)) - { - var typeResult = GetTypeSpec(field.DeclaringType); - result = (null, typeResult.Item2); - if (typeResult.Item1 != null) - { - string fieldName = field.Name; - foreach (var fieldSpec in typeResult.Item1.fields) - { - if (fieldSpec.nameMatcher.IsMatch(fieldName)) - { - result = (fieldSpec, fieldSpec.rule); - break; - } - } - } - _fieldPassRuleCaches.Add(field, result); - } - return result; - } - - private (PropertySpec, PassRule) GetPropertySpec(PropertyDef property) - { - if (!_propertyPassRuleCaches.TryGetValue(property, out var result)) - { - var typeResult = GetTypeSpec(property.DeclaringType); - result = (null, typeResult.Item2); - if (typeResult.Item1 != null) - { - string propertyName = property.Name; - foreach (var propertySpec in typeResult.Item1.properties) - { - if (propertySpec.nameMatcher.IsMatch(propertyName)) - { - result = (propertySpec, propertySpec.rule); - break; - } - } - } - _propertyPassRuleCaches.Add(property, result); - } - return result; - } - - private (EventSpec, PassRule) GetEventSpec(EventDef eventDef) - { - if (!_eventPassRuleCaches.TryGetValue(eventDef, out var result)) - { - var typeResult = GetTypeSpec(eventDef.DeclaringType); - result = (null, typeResult.Item2); - if (typeResult.Item1 != null) - { - string eventName = eventDef.Name; - foreach (var eventSpec in typeResult.Item1.events) - { - if (eventSpec.nameMatcher.IsMatch(eventName)) - { - result = (eventSpec, eventSpec.rule); - break; - } - } - } - _eventPassRuleCaches.Add(eventDef, result); - } - return result; - } - - - public ObfuscationPassType GetAssemblyObfuscationPasses(ModuleDef module) - { - return GetAssemblySpec(module).Item2.finalPasses; - } - - public ObfuscationPassType GetTypeObfuscationPasses(TypeDef type) - { - return GetTypeSpec(type).Item2.finalPasses; - } - - public ObfuscationPassType GetMethodObfuscationPasses(MethodDef method) - { - return GetMethodSpec(method).Item2.finalPasses; - } - - public ObfuscationPassType GetFieldObfuscationPasses(FieldDef field) - { - return GetFieldSpec(field).Item2.finalPasses; - } - - public ObfuscationPassType GetPropertyObfuscationPasses(PropertyDef property) - { - return GetPropertySpec(property).Item2.finalPasses; - } - - public ObfuscationPassType GetEventObfuscationPasses(EventDef eventDef) - { - return GetEventSpec(eventDef).Item2.finalPasses; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConfigurablePassPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConfigurablePassPolicy.cs.meta deleted file mode 100644 index 9b85183e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConfigurablePassPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 41044699810a34f4780e14de084bf7d7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConstValues.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConstValues.cs deleted file mode 100644 index 90c3a3bd..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConstValues.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Text; - -namespace Obfuz.Editor -{ - public static class ConstValues - { - public const string ObfuzInternalSymbolNamePrefix = "$Obfuz$"; - - public const string ObfuzRuntimeAssemblyName = "Obfuz.Runtime"; - - public const string ObfuzIgnoreAttributeFullName = "Obfuz.ObfuzIgnoreAttribute"; - - public const string ObfuzScopeFullName = "Obfuz.ObfuzScope"; - - public const string EncryptFieldAttributeFullName = "Obfuz.EncryptFieldAttribute"; - public const string GeneratedEncryptionVirtualMachineFullName = "Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine"; - - public const string EmbeddedAttributeFullName = "Microsoft.CodeAnalysis.EmbeddedAttribute"; - - public const string MonoPInvokeCallbackAttributeName = "MonoPInvokeCallbackAttribute"; - - public const string ZluaLuaInvokeAttributeFullName = "Zlua.LuaInvokeAttribute"; - public const string ZluaLuaCallbackAttributeFullName = "Zlua.LuaCallbackAttribute"; - public const string ZluaLuaMarshalAsAttributeFullName = "Zlua.LuaMarshalAsAttribute"; - - public const string BurstCompileFullName = "Unity.Burst.BurstCompileAttribute"; - public const string DOTSCompilerGeneratedAttributeFullName = "Unity.Jobs.DOTSCompilerGeneratedAttribute"; - - public const string RuntimeInitializedOnLoadMethodAttributeFullName = "UnityEngine.RuntimeInitializeOnLoadMethodAttribute"; - public const string BlackboardEnumAttributeFullName = "Unity.Behavior.BlackboardEnumAttribute"; - - public const string CompilerGeneratedAttributeFullName = "System.Runtime.CompilerServices.CompilerGeneratedAttribute"; - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConstValues.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConstValues.cs.meta deleted file mode 100644 index 33f41601..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ConstValues.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: aee7817ed523a5e4ea42104013e8a775 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data.meta deleted file mode 100644 index d162ae8e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 3319ebe75a42f3d4d996846ca09ed099 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/ConstFieldAllocator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/ConstFieldAllocator.cs deleted file mode 100644 index 90f889d1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/ConstFieldAllocator.cs +++ /dev/null @@ -1,269 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Editor; -using Obfuz.Emit; -using Obfuz.Utils; -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine.Assertions; - -namespace Obfuz.Data -{ - public class ConstFieldAllocator : GroupByModuleEntityBase - { - private RandomCreator _randomCreator; - private IEncryptor _encryptor; - - private TypeDef _holderTypeDef; - - class ConstFieldInfo - { - public FieldDef field; - public object value; - } - - class AnyComparer : IEqualityComparer - { - public new bool Equals(object x, object y) - { - if (x is byte[] xBytes && y is byte[] yBytes) - { - return StructuralComparisons.StructuralEqualityComparer.Equals(xBytes, yBytes); - } - return x.Equals(y); - } - - public static int ComputeHashCode(object obj) - { - return HashUtil.ComputePrimitiveOrStringOrBytesHashCode(obj); - } - - public int GetHashCode(object obj) - { - return ComputeHashCode(obj); - } - } - - private readonly Dictionary _allocatedFields = new Dictionary(new AnyComparer()); - private readonly Dictionary _field2Fields = new Dictionary(); - - private readonly List _holderTypeDefs = new List(); - private bool _done; - - - public ConstFieldAllocator() - { - } - - public override void Init() - { - _randomCreator = EncryptionScope.localRandomCreator; - _encryptor = EncryptionScope.encryptor; - } - - const int maxFieldCount = 1000; - - - private TypeSig GetTypeSigOfValue(object value) - { - ModuleDef mod = Module; - if (value is int) - return mod.CorLibTypes.Int32; - if (value is long) - return mod.CorLibTypes.Int64; - if (value is float) - return mod.CorLibTypes.Single; - if (value is double) - return mod.CorLibTypes.Double; - if (value is string) - return mod.CorLibTypes.String; - if (value is byte[]) - return new SZArraySig(mod.CorLibTypes.Byte); - throw new NotSupportedException($"Unsupported type: {value.GetType()}"); - } - - private ConstFieldInfo CreateConstFieldInfo(object value) - { - ModuleDef mod = Module; - if (_holderTypeDef == null || _holderTypeDef.Fields.Count >= maxFieldCount) - { - using (var scope = new DisableTypeDefFindCacheScope(mod)) - { - ITypeDefOrRef objectTypeRef = mod.Import(typeof(object)); - _holderTypeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ConstFieldHolder${_holderTypeDefs.Count}", objectTypeRef); - mod.Types.Add(_holderTypeDef); - _holderTypeDefs.Add(_holderTypeDef); - } - } - - var field = new FieldDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}RVA_Value{_holderTypeDef.Fields.Count}", new FieldSig(GetTypeSigOfValue(value)), FieldAttributes.Static | FieldAttributes.Public); - field.DeclaringType = _holderTypeDef; - return new ConstFieldInfo - { - field = field, - value = value, - }; - } - - private FieldDef AllocateAny(object value) - { - if (_done) - { - throw new Exception("can't Allocate after done"); - } - if (!_allocatedFields.TryGetValue(value, out var field)) - { - field = CreateConstFieldInfo(value); - _allocatedFields.Add(value, field); - _field2Fields.Add(field.field, field); - } - return field.field; - } - - public FieldDef Allocate(int value) - { - return AllocateAny(value); - } - - public FieldDef Allocate(long value) - { - return AllocateAny(value); - } - - public FieldDef Allocate(float value) - { - return AllocateAny(value); - } - - public FieldDef Allocate(double value) - { - return AllocateAny(value); - } - - public FieldDef Allocate(string value) - { - return AllocateAny(value); - } - - public FieldDef Allocate(byte[] value) - { - return AllocateAny(value); - } - - - private void CreateCCtorOfRvaTypeDef(TypeDef type) - { - ModuleDef mod = Module; - var cctor = new MethodDefUser(".cctor", - MethodSig.CreateStatic(mod.CorLibTypes.Void), - MethodImplAttributes.IL | MethodImplAttributes.Managed, - MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private); - cctor.DeclaringType = type; - var body = new CilBody(); - cctor.Body = body; - var ins = body.Instructions; - - - DefaultMetadataImporter importer = this.GetDefaultModuleMetadataImporter(); - RvaDataAllocator rvaDataAllocator = GetEntity(); - // TODO. obfuscate init codes - foreach (var field in type.Fields) - { - ConstFieldInfo constInfo = _field2Fields[field]; - IRandom localRandom = _randomCreator(HashUtil.ComputePrimitiveOrStringOrBytesHashCode(constInfo.value)); - int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, _encryptor, 4); - int salt = localRandom.NextInt(); - switch (constInfo.value) - { - case int i: - { - int encryptedValue = _encryptor.Encrypt(i, ops, salt); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - ins.Add(Instruction.CreateLdcI4(rvaData.offset)); - ins.Add(Instruction.CreateLdcI4(ops)); - ins.Add(Instruction.CreateLdcI4(salt)); - ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaInt)); - break; - } - case long l: - { - long encryptedValue = _encryptor.Encrypt(l, ops, salt); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - ins.Add(Instruction.CreateLdcI4(rvaData.offset)); - ins.Add(Instruction.CreateLdcI4(ops)); - ins.Add(Instruction.CreateLdcI4(salt)); - ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaLong)); - break; - } - case float f: - { - float encryptedValue = _encryptor.Encrypt(f, ops, salt); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - ins.Add(Instruction.CreateLdcI4(rvaData.offset)); - ins.Add(Instruction.CreateLdcI4(ops)); - ins.Add(Instruction.CreateLdcI4(salt)); - ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaFloat)); - break; - } - case double d: - { - double encryptedValue = _encryptor.Encrypt(d, ops, salt); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - ins.Add(Instruction.CreateLdcI4(rvaData.offset)); - ins.Add(Instruction.CreateLdcI4(ops)); - ins.Add(Instruction.CreateLdcI4(salt)); - ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaDouble)); - break; - } - case string s: - { - byte[] encryptedValue = _encryptor.Encrypt(s, ops, salt); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - ins.Add(Instruction.CreateLdcI4(rvaData.offset)); - Assert.AreEqual(encryptedValue.Length, rvaData.size); - ins.Add(Instruction.CreateLdcI4(encryptedValue.Length)); - ins.Add(Instruction.CreateLdcI4(ops)); - ins.Add(Instruction.CreateLdcI4(salt)); - ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString)); - break; - } - case byte[] bs: - { - byte[] encryptedValue = _encryptor.Encrypt(bs, 0, bs.Length, ops, salt); - Assert.AreEqual(encryptedValue.Length, bs.Length); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - ins.Add(Instruction.CreateLdcI4(rvaData.offset)); - ins.Add(Instruction.CreateLdcI4(bs.Length)); - ins.Add(Instruction.CreateLdcI4(ops)); - ins.Add(Instruction.CreateLdcI4(salt)); - ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaBytes)); - break; - } - default: throw new NotSupportedException($"Unsupported type: {constInfo.value.GetType()}"); - } - ins.Add(Instruction.Create(OpCodes.Stsfld, field)); - } - ins.Add(Instruction.Create(OpCodes.Ret)); - } - - public override void Done() - { - if (_done) - { - throw new Exception("Already done"); - } - _done = true; - foreach (var typeDef in _holderTypeDefs) - { - CreateCCtorOfRvaTypeDef(typeDef); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/ConstFieldAllocator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/ConstFieldAllocator.cs.meta deleted file mode 100644 index 8e64e42e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/ConstFieldAllocator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e75f5cdfd47370d4ea6c4dee7e55a881 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/RvaDataAllocator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/RvaDataAllocator.cs deleted file mode 100644 index 00736502..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/RvaDataAllocator.cs +++ /dev/null @@ -1,324 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Emit; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using UnityEngine.Assertions; - -namespace Obfuz.Data -{ - public struct RvaData - { - public readonly FieldDef field; - public readonly int offset; - public readonly int size; - - public RvaData(FieldDef field, int offset, int size) - { - this.field = field; - this.offset = offset; - this.size = size; - } - } - - public class RvaDataAllocator : GroupByModuleEntityBase - { - const int maxRvaDataSize = 2 * 1024; - - // in HybridCLR version below 8.3.0, the max total static field size of a type is 16KB, so we limit the total size of RVA data to 16KB - const int maxTotalRvaDataFieldSizeInHybridCLR = 16 * 1024; - - private IRandom _random; - - class RvaField - { - public FieldDef holderDataField; - public FieldDef runtimeValueField; - public int encryptionOps; - public uint size; - public List bytes; - public int salt; - - public void FillPaddingToSize(int newSize) - { - for (int i = bytes.Count; i < newSize; i++) - { - bytes.Add(0xAB); - } - } - - public void FillPaddingToEnd() - { - // fill with random value - for (int i = bytes.Count; i < size; i++) - { - bytes.Add(0xAB); - } - } - } - - private class RvaTypeDefInfo - { - public readonly TypeDef typeDef; - public readonly int index; - public readonly List rvaFields = new List(); - - public RvaTypeDefInfo(TypeDef typeDef, int index) - { - this.typeDef = typeDef; - this.index = index; - } - } - - private RvaField _currentField; - - private RvaTypeDefInfo _currentRvaType; - private readonly List _rvaTypeDefs = new List(); - - private readonly Dictionary _dataHolderTypeBySizes = new Dictionary(); - private bool _done; - - public RvaDataAllocator() - { - } - - public override void Init() - { - _random = EncryptionScope.localRandomCreator(HashUtil.ComputeHash(Module.Name)); - } - - private (FieldDef, FieldDef) CreateDataHolderRvaField(TypeDef dataHolderType) - { - if (_currentRvaType == null || _currentRvaType.rvaFields.Count >= maxTotalRvaDataFieldSizeInHybridCLR / maxRvaDataSize - 1) - { - using (var scope = new DisableTypeDefFindCacheScope(Module)) - { - var rvaTypeDef = new TypeDefUser($"$Obfuz$RVA${_rvaTypeDefs.Count}", Module.CorLibTypes.Object.ToTypeDefOrRef()); - Module.Types.Add(rvaTypeDef); - _currentRvaType = new RvaTypeDefInfo(rvaTypeDef, _rvaTypeDefs.Count); - _rvaTypeDefs.Add(_currentRvaType); - } - } - - var holderField = new FieldDefUser($"$RVA_Data{_currentRvaType.rvaFields.Count}", new FieldSig(dataHolderType.ToTypeSig()), FieldAttributes.InitOnly | FieldAttributes.Static | FieldAttributes.HasFieldRVA); - holderField.DeclaringType = _currentRvaType.typeDef; - - var runtimeValueField = new FieldDefUser($"$RVA_Value{_currentRvaType.rvaFields.Count}", new FieldSig(new SZArraySig(Module.CorLibTypes.Byte)), FieldAttributes.Static | FieldAttributes.Public); - runtimeValueField.DeclaringType = _currentRvaType.typeDef; - return (holderField, runtimeValueField); - } - - private TypeDef GetDataHolderType(int size) - { - size = (size + 15) & ~15; // align to 16 bytes - if (_dataHolderTypeBySizes.TryGetValue(size, out var type)) - return type; - - using (var scope = new DisableTypeDefFindCacheScope(Module)) - { - var dataHolderType = new TypeDefUser($"$ObfuzRVA$DataHolder{size}", Module.Import(typeof(ValueType))); - dataHolderType.Attributes = TypeAttributes.Public | TypeAttributes.Sealed; - dataHolderType.Layout = TypeAttributes.ExplicitLayout; - dataHolderType.PackingSize = 1; - dataHolderType.ClassSize = (uint)size; - _dataHolderTypeBySizes.Add(size, dataHolderType); - Module.Types.Add(dataHolderType); - return dataHolderType; - } - } - - private static int AlignTo(int size, int alignment) - { - return (size + alignment - 1) & ~(alignment - 1); - } - - private RvaField CreateRvaField(int size) - { - TypeDef dataHolderType = GetDataHolderType(size); - var (holderDataField, runtimeValueField) = CreateDataHolderRvaField(dataHolderType); - var newRvaField = new RvaField - { - holderDataField = holderDataField, - runtimeValueField = runtimeValueField, - size = dataHolderType.ClassSize, - bytes = new List((int)dataHolderType.ClassSize), - encryptionOps = _random.NextInt(), - salt = _random.NextInt(), - }; - _currentRvaType.rvaFields.Add(newRvaField); - return newRvaField; - } - - private RvaField GetRvaField(int preservedSize, int alignment) - { - if (_done) - { - throw new Exception("can't GetRvaField after done"); - } - Assert.IsTrue(preservedSize % alignment == 0); - // for big size, create a new field - if (preservedSize >= maxRvaDataSize) - { - return CreateRvaField(preservedSize); - } - - if (_currentField != null) - { - int offset = AlignTo(_currentField.bytes.Count, alignment); - - int expectedSize = offset + preservedSize; - if (expectedSize <= _currentField.size) - { - _currentField.FillPaddingToSize(offset); - return _currentField; - } - - _currentField.FillPaddingToEnd(); - } - _currentField = CreateRvaField(maxRvaDataSize); - return _currentField; - } - - public RvaData Allocate(int value) - { - RvaField field = GetRvaField(4, 4); - int offset = field.bytes.Count; - Assert.IsTrue(offset % 4 == 0); - field.bytes.AddRange(BitConverter.GetBytes(value)); - return new RvaData(field.runtimeValueField, offset, 4); - } - - public RvaData Allocate(long value) - { - RvaField field = GetRvaField(8, 8); - int offset = field.bytes.Count; - Assert.IsTrue(offset % 8 == 0); - field.bytes.AddRange(BitConverter.GetBytes(value)); - return new RvaData(field.runtimeValueField, offset, 8); - } - - public RvaData Allocate(float value) - { - RvaField field = GetRvaField(4, 4); - int offset = field.bytes.Count; - Assert.IsTrue(offset % 4 == 0); - field.bytes.AddRange(BitConverter.GetBytes(value)); - return new RvaData(field.runtimeValueField, offset, 4); - } - - public RvaData Allocate(double value) - { - RvaField field = GetRvaField(8, 8); - int offset = field.bytes.Count; - Assert.IsTrue(offset % 8 == 0); - field.bytes.AddRange(BitConverter.GetBytes(value)); - return new RvaData(field.runtimeValueField, offset, 8); - } - - public RvaData Allocate(string value) - { - byte[] bytes = Encoding.UTF8.GetBytes(value); - return Allocate(bytes); - } - - public RvaData Allocate(byte[] value) - { - RvaField field = GetRvaField(value.Length, 1); - int offset = field.bytes.Count; - field.bytes.AddRange(value); - return new RvaData(field.runtimeValueField, offset, value.Length); - } - - - private void AddVerifyCodes(IList insts, DefaultMetadataImporter importer) - { - int verifyIntValue = 0x12345678; - EncryptionScopeInfo encryptionScope = this.EncryptionScope; - IRandom verifyRandom = encryptionScope.localRandomCreator(verifyIntValue); - int verifyOps = EncryptionUtil.GenerateEncryptionOpCodes(verifyRandom, encryptionScope.encryptor, 4); - int verifySalt = verifyRandom.NextInt(); - int encryptedVerifyIntValue = encryptionScope.encryptor.Encrypt(verifyIntValue, verifyOps, verifySalt); - - insts.Add(Instruction.Create(OpCodes.Ldc_I4, verifyIntValue)); - insts.Add(Instruction.CreateLdcI4(encryptedVerifyIntValue)); - insts.Add(Instruction.CreateLdcI4(verifyOps)); - insts.Add(Instruction.CreateLdcI4(verifySalt)); - insts.Add(Instruction.Create(OpCodes.Call, importer.DecryptInt)); - insts.Add(Instruction.Create(OpCodes.Call, importer.VerifySecretKey)); - - } - - private void CreateCCtorOfRvaTypeDef() - { - foreach (RvaTypeDefInfo rvaTypeDef in _rvaTypeDefs) - { - ModuleDef mod = rvaTypeDef.typeDef.Module; - var cctorMethod = new MethodDefUser(".cctor", - MethodSig.CreateStatic(Module.CorLibTypes.Void), - MethodImplAttributes.IL | MethodImplAttributes.Managed, - MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private); - cctorMethod.DeclaringType = rvaTypeDef.typeDef; - //_rvaTypeDef.Methods.Add(cctor); - var body = new CilBody(); - cctorMethod.Body = body; - var ins = body.Instructions; - - DefaultMetadataImporter importer = this.GetDefaultModuleMetadataImporter(); - AddVerifyCodes(ins, importer); - foreach (var field in rvaTypeDef.rvaFields) - { - // ldc - // newarr - // dup - // stsfld - // ldtoken - // RuntimeHelpers.InitializeArray(array, fieldHandle); - ins.Add(Instruction.Create(OpCodes.Ldc_I4, (int)field.size)); - ins.Add(Instruction.Create(OpCodes.Newarr, field.runtimeValueField.FieldType.Next.ToTypeDefOrRef())); - ins.Add(Instruction.Create(OpCodes.Dup)); - ins.Add(Instruction.Create(OpCodes.Dup)); - ins.Add(Instruction.Create(OpCodes.Stsfld, field.runtimeValueField)); - ins.Add(Instruction.Create(OpCodes.Ldtoken, field.holderDataField)); - ins.Add(Instruction.Create(OpCodes.Call, importer.InitializedArray)); - - // EncryptionService.DecryptBlock(array, field.encryptionOps, field.salt); - ins.Add(Instruction.CreateLdcI4(field.encryptionOps)); - ins.Add(Instruction.Create(OpCodes.Ldc_I4, field.salt)); - ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptBlock)); - - } - ins.Add(Instruction.Create(OpCodes.Ret)); - } - } - - private void SetFieldsRVA() - { - foreach (var field in _rvaTypeDefs.SelectMany(t => t.rvaFields)) - { - Assert.IsTrue(field.bytes.Count <= field.size); - if (field.bytes.Count < field.size) - { - field.FillPaddingToEnd(); - } - byte[] data = field.bytes.ToArray(); - EncryptionScope.encryptor.EncryptBlock(data, field.encryptionOps, field.salt); - field.holderDataField.InitialValue = data; - } - } - - public override void Done() - { - if (_done) - { - throw new Exception("can't call Done twice"); - } - _done = true; - SetFieldsRVA(); - CreateCCtorOfRvaTypeDef(); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/RvaDataAllocator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/RvaDataAllocator.cs.meta deleted file mode 100644 index c1f94e80..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Data/RvaDataAllocator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c00ca514f46605645bf40b0135e7e504 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit.meta deleted file mode 100644 index d13f8ab9..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a513a192808ba5f47b1ef8a3ecf02533 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/BasicBlockCollection.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/BasicBlockCollection.cs deleted file mode 100644 index bab76322..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/BasicBlockCollection.cs +++ /dev/null @@ -1,310 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Obfuz.Emit -{ - public class BasicBlock - { - public readonly List instructions = new List(); - - public readonly List inBlocks = new List(); - - public readonly List outBlocks = new List(); - - public bool inLoop; - - public void AddTargetBasicBlock(BasicBlock target) - { - if (!outBlocks.Contains(target)) - { - outBlocks.Add(target); - } - if (!target.inBlocks.Contains(this)) - { - target.inBlocks.Add(this); - } - } - } - - public class BasicBlockCollection - { - private readonly MethodDef _method; - - private readonly List _blocks = new List(); - private readonly Dictionary _inst2BlockMap = new Dictionary(); - - public IList Blocks => _blocks; - - public BasicBlockCollection(MethodDef method, bool computeInLoop) - { - _method = method; - HashSet splitPoints = BuildSplitPoint(method); - BuildBasicBlocks(method, splitPoints); - BuildInOutGraph(method); - if (computeInLoop) - { - ComputeBlocksInLoop(); - } - } - - public void ComputeBlocksInLoop() - { - var loopBlocks = FindLoopBlocks(_blocks); - foreach (var block in loopBlocks) - { - block.inLoop = true; - } - } - - public BasicBlock GetBasicBlockByInstruction(Instruction inst) - { - return _inst2BlockMap[inst]; - } - - private HashSet BuildSplitPoint(MethodDef method) - { - var insts = method.Body.Instructions; - var splitPoints = new HashSet(); - foreach (ExceptionHandler eh in method.Body.ExceptionHandlers) - { - if (eh.TryStart != null) - { - splitPoints.Add(eh.TryStart); - } - if (eh.TryEnd != null) - { - splitPoints.Add(eh.TryEnd); - } - if (eh.HandlerStart != null) - { - splitPoints.Add(eh.HandlerStart); - } - if (eh.HandlerEnd != null) - { - splitPoints.Add(eh.HandlerEnd); - } - if (eh.FilterStart != null) - { - splitPoints.Add(eh.FilterStart); - } - } - - for (int i = 0, n = insts.Count; i < n; i++) - { - Instruction curInst = insts[i]; - Instruction nextInst = i + 1 < n ? insts[i + 1] : null; - switch (curInst.OpCode.FlowControl) - { - case FlowControl.Branch: - { - if (nextInst != null) - { - splitPoints.Add(nextInst); - } - splitPoints.Add((Instruction)curInst.Operand); - break; - } - case FlowControl.Cond_Branch: - { - if (nextInst != null) - { - splitPoints.Add(nextInst); - } - if (curInst.Operand is Instruction targetInst) - { - splitPoints.Add(targetInst); - } - else if (curInst.Operand is Instruction[] targetInsts) - { - foreach (var target in targetInsts) - { - splitPoints.Add(target); - } - } - break; - } - case FlowControl.Return: - { - if (nextInst != null) - { - splitPoints.Add(nextInst); - } - break; - } - case FlowControl.Throw: - { - if (nextInst != null) - { - splitPoints.Add(nextInst); - } - break; - } - } - } - return splitPoints; - } - - - private void BuildBasicBlocks(MethodDef method, HashSet splitPoints) - { - var insts = method.Body.Instructions; - - - BasicBlock curBlock = new BasicBlock(); - foreach (Instruction inst in insts) - { - if (splitPoints.Contains(inst) && curBlock.instructions.Count > 0) - { - _blocks.Add(curBlock); - curBlock = new BasicBlock(); - } - curBlock.instructions.Add(inst); - _inst2BlockMap.Add(inst, curBlock); - } - if (curBlock.instructions.Count > 0) - { - _blocks.Add(curBlock); - } - } - - private void BuildInOutGraph(MethodDef method) - { - var insts = method.Body.Instructions; - for (int i = 0, n = _blocks.Count; i < n; i++) - { - BasicBlock curBlock = _blocks[i]; - BasicBlock nextBlock = i + 1 < n ? _blocks[i + 1] : null; - Instruction lastInst = curBlock.instructions.Last(); - switch (lastInst.OpCode.FlowControl) - { - case FlowControl.Branch: - { - Instruction targetInst = (Instruction)lastInst.Operand; - BasicBlock targetBlock = GetBasicBlockByInstruction(targetInst); - curBlock.AddTargetBasicBlock(targetBlock); - break; - } - case FlowControl.Cond_Branch: - { - if (lastInst.Operand is Instruction targetInst) - { - BasicBlock targetBlock = GetBasicBlockByInstruction(targetInst); - curBlock.AddTargetBasicBlock(targetBlock); - } - else if (lastInst.Operand is Instruction[] targetInsts) - { - foreach (var target in targetInsts) - { - BasicBlock targetBlock = GetBasicBlockByInstruction(target); - curBlock.AddTargetBasicBlock(targetBlock); - } - } - else - { - throw new Exception("Invalid operand type for conditional branch"); - } - if (nextBlock != null) - { - curBlock.AddTargetBasicBlock(nextBlock); - } - break; - } - case FlowControl.Call: - case FlowControl.Next: - { - if (nextBlock != null) - { - curBlock.AddTargetBasicBlock(nextBlock); - } - break; - } - case FlowControl.Return: - case FlowControl.Throw: - { - break; - } - default: throw new NotSupportedException($"Unsupported flow control: {lastInst.OpCode.FlowControl} in method {method.FullName}"); - } - } - } - - private static HashSet FindLoopBlocks(List allBlocks) - { - // Tarjan算法找强连通分量 - var sccList = FindStronglyConnectedComponents(allBlocks); - - // 筛选有效循环 - var loopBlocks = new HashSet(); - foreach (var scc in sccList) - { - // 有效循环需满足以下条件之一: - // 1. 分量包含多个块 - // 2. 单个块有自环(跳转自己) - if (scc.Count > 1 || - (scc.Count == 1 && scc[0].outBlocks.Contains(scc[0]))) - { - foreach (var block in scc) - { - loopBlocks.Add(block); - } - } - } - return loopBlocks; - } - - private static List> FindStronglyConnectedComponents(List allBlocks) - { - int index = 0; - var stack = new Stack(); - var indexes = new Dictionary(); - var lowLinks = new Dictionary(); - var onStack = new HashSet(); - var sccList = new List>(); - - foreach (var block in allBlocks.Where(b => !indexes.ContainsKey(b))) - { - StrongConnect(block); - } - - return sccList; - - void StrongConnect(BasicBlock v) - { - indexes[v] = index; - lowLinks[v] = index; - index++; - stack.Push(v); - onStack.Add(v); - - foreach (var w in v.outBlocks) - { - if (!indexes.ContainsKey(w)) - { - StrongConnect(w); - lowLinks[v] = System.Math.Min(lowLinks[v], lowLinks[w]); - } - else if (onStack.Contains(w)) - { - lowLinks[v] = System.Math.Min(lowLinks[v], indexes[w]); - } - } - - if (lowLinks[v] == indexes[v]) - { - var scc = new List(); - BasicBlock w; - do - { - w = stack.Pop(); - onStack.Remove(w); - scc.Add(w); - } while (!w.Equals(v)); - sccList.Add(scc); - } - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/BasicBlockCollection.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/BasicBlockCollection.cs.meta deleted file mode 100644 index dabfa3b4..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/BasicBlockCollection.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 77c19c023bb7f77489998d994a3be1bd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/DefaultMetadataImporter.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/DefaultMetadataImporter.cs deleted file mode 100644 index 6399b428..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/DefaultMetadataImporter.cs +++ /dev/null @@ -1,423 +0,0 @@ -using dnlib.DotNet; -using System; -using System.Reflection; -using UnityEngine.Assertions; - -namespace Obfuz.Emit -{ - public class EncryptionServiceMetadataImporter - { - private readonly ModuleDef _module; - private readonly Type _encryptionServiceType; - - private IMethod _encryptBlock; - private IMethod _decryptBlock; - private IMethod _encryptInt; - private IMethod _decryptInt; - private IMethod _encryptLong; - private IMethod _decryptLong; - private IMethod _encryptFloat; - private IMethod _decryptFloat; - private IMethod _encryptDouble; - private IMethod _decryptDouble; - private IMethod _encryptString; - private IMethod _decryptString; - private IMethod _encryptBytes; - private IMethod _decryptBytes; - - private IMethod _decryptFromRvaInt; - private IMethod _decryptFromRvaLong; - private IMethod _decryptFromRvaFloat; - private IMethod _decryptFromRvaDouble; - private IMethod _decryptFromRvaString; - private IMethod _decryptFromRvaBytes; - - private IMethod _decryptInitializeArray; - - public IMethod EncryptBlock => _encryptBlock; - public IMethod DecryptBlock => _decryptBlock; - - public IMethod EncryptInt => _encryptInt; - public IMethod DecryptInt => _decryptInt; - public IMethod EncryptLong => _encryptLong; - public IMethod DecryptLong => _decryptLong; - public IMethod EncryptFloat => _encryptFloat; - public IMethod DecryptFloat => _decryptFloat; - public IMethod EncryptDouble => _encryptDouble; - public IMethod DecryptDouble => _decryptDouble; - public IMethod EncryptString => _encryptString; - public IMethod DecryptString => _decryptString; - public IMethod EncryptBytes => _encryptBytes; - public IMethod DecryptBytes => _decryptBytes; - - public IMethod DecryptFromRvaInt => _decryptFromRvaInt; - public IMethod DecryptFromRvaLong => _decryptFromRvaLong; - public IMethod DecryptFromRvaFloat => _decryptFromRvaFloat; - public IMethod DecryptFromRvaDouble => _decryptFromRvaDouble; - public IMethod DecryptFromRvaBytes => _decryptFromRvaBytes; - public IMethod DecryptFromRvaString => _decryptFromRvaString; - - public IMethod DecryptInitializeArray => _decryptInitializeArray; - - public EncryptionServiceMetadataImporter(ModuleDef mod, Type encryptionServiceType) - { - _module = mod; - _encryptionServiceType = encryptionServiceType; - _encryptBlock = mod.Import(encryptionServiceType.GetMethod("EncryptBlock", new[] { typeof(byte[]), typeof(int), typeof(int) })); - Assert.IsNotNull(_encryptBlock); - _decryptBlock = mod.Import(encryptionServiceType.GetMethod("DecryptBlock", new[] { typeof(byte[]), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptBlock); - _encryptInt = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_encryptInt); - _decryptInt = mod.Import(encryptionServiceType.GetMethod("Decrypt", new[] { typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptInt); - _encryptLong = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(long), typeof(int), typeof(int) })); - Assert.IsNotNull(_encryptLong); - _decryptLong = mod.Import(encryptionServiceType.GetMethod("Decrypt", new[] { typeof(long), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptLong); - _encryptFloat = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(float), typeof(int), typeof(int) })); - Assert.IsNotNull(_encryptFloat); - _decryptFloat = mod.Import(encryptionServiceType.GetMethod("Decrypt", new[] { typeof(float), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptFloat); - _encryptDouble = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(double), typeof(int), typeof(int) })); - Assert.IsNotNull(_encryptDouble); - _decryptDouble = mod.Import(encryptionServiceType.GetMethod("Decrypt", new[] { typeof(double), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptDouble); - _encryptString = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(string), typeof(int), typeof(int) })); - Assert.IsNotNull(_encryptString); - _decryptString = mod.Import(encryptionServiceType.GetMethod("DecryptString", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptString); - _encryptBytes = mod.Import(encryptionServiceType.GetMethod("Encrypt", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_encryptBytes); - _decryptBytes = mod.Import(encryptionServiceType.GetMethod("Decrypt", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptBytes); - - _decryptFromRvaInt = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaInt", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptFromRvaInt); - _decryptFromRvaLong = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaLong", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptFromRvaLong); - _decryptFromRvaFloat = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaFloat", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptFromRvaFloat); - _decryptFromRvaDouble = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaDouble", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptFromRvaDouble); - _decryptFromRvaBytes = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaBytes", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptFromRvaBytes); - _decryptFromRvaString = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaString", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptFromRvaString); - _decryptInitializeArray = mod.Import(encryptionServiceType.GetMethod("DecryptInitializeArray", new[] { typeof(System.Array), typeof(System.RuntimeFieldHandle), typeof(int), typeof(int), typeof(int) })); - Assert.IsNotNull(_decryptInitializeArray); - } - } - - public class DefaultMetadataImporter : GroupByModuleEntityBase - { - private EncryptionServiceMetadataImporter _defaultEncryptionServiceMetadataImporter; - - - private EncryptionServiceMetadataImporter _staticDefaultEncryptionServiceMetadataImporter; - private EncryptionServiceMetadataImporter _dynamicDefaultEncryptionServiceMetadataImporter; - - public DefaultMetadataImporter() - { - } - - public override void Init() - { - ModuleDef mod = Module; - - var constUtilityType = typeof(ConstUtility); - - _castIntAsFloat = mod.Import(constUtilityType.GetMethod("CastIntAsFloat")); - Assert.IsNotNull(_castIntAsFloat, "CastIntAsFloat not found"); - _castLongAsDouble = mod.Import(constUtilityType.GetMethod("CastLongAsDouble")); - Assert.IsNotNull(_castLongAsDouble, "CastLongAsDouble not found"); - _castFloatAsInt = mod.Import(constUtilityType.GetMethod("CastFloatAsInt")); - Assert.IsNotNull(_castFloatAsInt, "CastFloatAsInt not found"); - _castDoubleAsLong = mod.Import(constUtilityType.GetMethod("CastDoubleAsLong")); - Assert.IsNotNull(_castDoubleAsLong, "CastDoubleAsLong not found"); - - _initializeArray = mod.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new[] { typeof(Array), typeof(RuntimeFieldHandle) })); - Assert.IsNotNull(_initializeArray); - _verifySecretKey = mod.Import(typeof(AssetUtility).GetMethod("VerifySecretKey", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_verifySecretKey, "VerifySecretKey not found"); - - _obfuscationTypeMapperRegisterType = mod.Import(typeof(ObfuscationTypeMapper).GetMethod("RegisterType", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string) }, null)); - Assert.IsNotNull(_obfuscationTypeMapperRegisterType, "ObfuscationTypeMapper.RegisterType not found"); - - var exprUtilityType = typeof(ExprUtility); - _addInt = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_addInt, "ExprUtility.Add(int, int) not found"); - _addLong = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(long), typeof(long) })); - Assert.IsNotNull(_addLong, "ExprUtility.Add(long, long) not found"); - _addFloat = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(float), typeof(float) })); - Assert.IsNotNull(_addFloat, "ExprUtility.Add(float, float) not found"); - _addDouble = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(double), typeof(double) })); - Assert.IsNotNull(_addDouble, "ExprUtility.Add(double, double) not found"); - _addIntPtr = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(IntPtr), typeof(IntPtr) })); - Assert.IsNotNull(_addIntPtr, "ExprUtility.Add(IntPtr, IntPtr) not found"); - _addIntPtrInt = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(IntPtr), typeof(int) })); - Assert.IsNotNull(_addIntPtrInt, "ExprUtility.Add(IntPtr, int) not found"); - - _subtractInt = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_subtractInt, "ExprUtility.Subtract(int, int) not found"); - _subtractLong = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(long), typeof(long) })); - Assert.IsNotNull(_subtractLong, "ExprUtility.Subtract(long, long) not found"); - _subtractFloat = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(float), typeof(float) })); - Assert.IsNotNull(_subtractFloat, "ExprUtility.Subtract(float, float) not found"); - _subtractDouble = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(double), typeof(double) })); - Assert.IsNotNull(_subtractDouble, "ExprUtility.Subtract(double, double) not found"); - _subtractIntPtr = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(IntPtr), typeof(IntPtr) })); - Assert.IsNotNull(_subtractIntPtr, "ExprUtility.Subtract(IntPtr, IntPtr) not found"); - _subtractIntPtrInt = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(IntPtr), typeof(int) })); - Assert.IsNotNull(_subtractIntPtrInt, "ExprUtility.Subtract(IntPtr, int) not found"); - - _multiplyInt = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_multiplyInt, "ExprUtility.Multiply(int, int) not found"); - _multiplyLong = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(long), typeof(long) })); - Assert.IsNotNull(_multiplyLong, "ExprUtility.Multiply(long, long) not found"); - _multiplyFloat = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(float), typeof(float) })); - Assert.IsNotNull(_multiplyFloat, "ExprUtility.Multiply(float, float) not found"); - _multiplyDouble = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(double), typeof(double) })); - Assert.IsNotNull(_multiplyDouble, "ExprUtility.Multiply(double, double) not found"); - _multiplyIntPtr = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(IntPtr), typeof(IntPtr) })); - Assert.IsNotNull(_multiplyIntPtr, "ExprUtility.Multiply(IntPtr, IntPtr) not found"); - _multiplyIntPtrInt = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(IntPtr), typeof(int) })); - Assert.IsNotNull(_multiplyIntPtrInt, "ExprUtility.Multiply(IntPtr, int) not found"); - - _divideInt = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_divideInt, "ExprUtility.Divide(int, int) not found"); - _divideLong = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(long), typeof(long) })); - Assert.IsNotNull(_divideLong); - _divideFloat = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(float), typeof(float) })); - Assert.IsNotNull(_divideFloat, "ExprUtility.Divide(float, float) not found"); - _divideDouble = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(double), typeof(double) })); - Assert.IsNotNull(_divideDouble, "ExprUtility.Divide(double, double) not found"); - _divideUnInt = mod.Import(exprUtilityType.GetMethod("DivideUn", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_divideUnInt, "ExprUtility.DivideUn(int, int) not found"); - _divideUnLong = mod.Import(exprUtilityType.GetMethod("DivideUn", new[] { typeof(long), typeof(long) })); - Assert.IsNotNull(_divideUnLong, "ExprUtility.DivideUn(long, long) not found"); - _remInt = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_remInt, "ExprUtility.Rem(int, int) not found"); - _remLong = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(long), typeof(long) })); - Assert.IsNotNull(_remLong, "ExprUtility.Rem(long, long) not found"); - _remFloat = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(float), typeof(float) })); - Assert.IsNotNull(_remFloat, "ExprUtility.Rem(float, float) not found"); - _remDouble = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(double), typeof(double) })); - Assert.IsNotNull(_remDouble, "ExprUtility.Rem(double, double) not found"); - _remUnInt = mod.Import(exprUtilityType.GetMethod("RemUn", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_remUnInt, "ExprUtility.RemUn(int, int) not found"); - _remUnLong = mod.Import(exprUtilityType.GetMethod("RemUn", new[] { typeof(long), typeof(long) })); - Assert.IsNotNull(_remUnLong, "ExprUtility.RemUn(long, long) not found"); - _negInt = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(int) })); - Assert.IsNotNull(_negInt, "ExprUtility.Negate(int) not found"); - _negLong = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(long) })); - Assert.IsNotNull(_negLong, "ExprUtility.Negate(long) not found"); - _negFloat = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(float) })); - Assert.IsNotNull(_negFloat, "ExprUtility.Negate(float) not found"); - _negDouble = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(double) })); - Assert.IsNotNull(_negDouble, "ExprUtility.Negate(double) not found"); - - _andInt = mod.Import(exprUtilityType.GetMethod("And", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_andInt, "ExprUtility.And(int, int) not found"); - _andLong = mod.Import(exprUtilityType.GetMethod("And", new[] { typeof(long), typeof(long) })); - Assert.IsNotNull(_andLong, "ExprUtility.And(long, long) not found"); - _orInt = mod.Import(exprUtilityType.GetMethod("Or", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_orInt, "ExprUtility.Or(int, int) not found"); - _orLong = mod.Import(exprUtilityType.GetMethod("Or", new[] { typeof(long), typeof(long) })); - Assert.IsNotNull(_orLong, "ExprUtility.Or(long, long) not found"); - _xorInt = mod.Import(exprUtilityType.GetMethod("Xor", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_xorInt, "ExprUtility.Xor(int, int) not found"); - _xorLong = mod.Import(exprUtilityType.GetMethod("Xor", new[] { typeof(long), typeof(long) })); - Assert.IsNotNull(_xorLong, "ExprUtility.Xor(long, long) not found"); - _notInt = mod.Import(exprUtilityType.GetMethod("Not", new[] { typeof(int) })); - Assert.IsNotNull(_notInt, "ExprUtility.Not(int) not found"); - _notLong = mod.Import(exprUtilityType.GetMethod("Not", new[] { typeof(long) })); - Assert.IsNotNull(_notLong, "ExprUtility.Not(long) not found"); - - _shlInt = mod.Import(exprUtilityType.GetMethod("ShiftLeft", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_shlInt, "ExprUtility.ShiftLeft(int, int) not found"); - _shlLong = mod.Import(exprUtilityType.GetMethod("ShiftLeft", new[] { typeof(long), typeof(int) })); - Assert.IsNotNull(_shlLong, "ExprUtility.ShiftLeft(long, int) not found"); - _shrInt = mod.Import(exprUtilityType.GetMethod("ShiftRight", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_shrInt, "ExprUtility.ShiftRight(int, int) not found"); - _shrLong = mod.Import(exprUtilityType.GetMethod("ShiftRight", new[] { typeof(long), typeof(int) })); - Assert.IsNotNull(_shrLong, "ExprUtility.ShiftRight(long, int) not found"); - _shrUnInt = mod.Import(exprUtilityType.GetMethod("ShiftRightUn", new[] { typeof(int), typeof(int) })); - Assert.IsNotNull(_shrUnInt, "ExprUtility.ShiftRightUn(int, int) not found"); - _shrUnLong = mod.Import(exprUtilityType.GetMethod("ShiftRightUn", new[] { typeof(long), typeof(int) })); - Assert.IsNotNull(_shrUnLong, "ExprUtility.ShiftRightUn(long, int) not found"); - - - _staticDefaultEncryptionServiceMetadataImporter = new EncryptionServiceMetadataImporter(mod, typeof(EncryptionService)); - _dynamicDefaultEncryptionServiceMetadataImporter = new EncryptionServiceMetadataImporter(mod, typeof(EncryptionService)); - if (EncryptionScopeProvider.IsDynamicSecretAssembly(mod)) - { - _defaultEncryptionServiceMetadataImporter = _dynamicDefaultEncryptionServiceMetadataImporter; - } - else - { - _defaultEncryptionServiceMetadataImporter = _staticDefaultEncryptionServiceMetadataImporter; - } - } - - public override void Done() - { - - } - - public EncryptionServiceMetadataImporter GetEncryptionServiceMetadataImporterOfModule(ModuleDef mod) - { - return EncryptionScopeProvider.IsDynamicSecretAssembly(mod) ? _dynamicDefaultEncryptionServiceMetadataImporter : _staticDefaultEncryptionServiceMetadataImporter; - } - - private ModuleDef _module; - private IMethod _castIntAsFloat; - private IMethod _castLongAsDouble; - private IMethod _castFloatAsInt; - private IMethod _castDoubleAsLong; - private IMethod _initializeArray; - private IMethod _verifySecretKey; - - private IMethod _obfuscationTypeMapperRegisterType; - - private IMethod _addInt; - private IMethod _addLong; - private IMethod _addFloat; - private IMethod _addDouble; - private IMethod _addIntPtr; - private IMethod _addIntPtrInt; - private IMethod _subtractInt; - private IMethod _subtractLong; - private IMethod _subtractFloat; - private IMethod _subtractDouble; - private IMethod _subtractIntPtr; - private IMethod _subtractIntPtrInt; - private IMethod _multiplyInt; - private IMethod _multiplyLong; - private IMethod _multiplyFloat; - private IMethod _multiplyDouble; - private IMethod _multiplyIntPtr; - private IMethod _multiplyIntPtrInt; - private IMethod _divideInt; - private IMethod _divideLong; - private IMethod _divideFloat; - private IMethod _divideDouble; - private IMethod _divideUnInt; - private IMethod _divideUnLong; - private IMethod _remInt; - private IMethod _remLong; - private IMethod _remFloat; - private IMethod _remDouble; - private IMethod _remUnInt; - private IMethod _remUnLong; - private IMethod _negInt; - private IMethod _negLong; - private IMethod _negFloat; - private IMethod _negDouble; - - private IMethod _andInt; - private IMethod _andLong; - private IMethod _orInt; - private IMethod _orLong; - private IMethod _xorInt; - private IMethod _xorLong; - private IMethod _notInt; - private IMethod _notLong; - - private IMethod _shlInt; - private IMethod _shlLong; - private IMethod _shrInt; - private IMethod _shrLong; - private IMethod _shrUnInt; - private IMethod _shrUnLong; - - public IMethod CastIntAsFloat => _castIntAsFloat; - public IMethod CastLongAsDouble => _castLongAsDouble; - public IMethod CastFloatAsInt => _castFloatAsInt; - public IMethod CastDoubleAsLong => _castDoubleAsLong; - - public IMethod InitializedArray => _initializeArray; - - public IMethod VerifySecretKey => _verifySecretKey; - - public IMethod ObfuscationTypeMapperRegisterType => _obfuscationTypeMapperRegisterType; - - public IMethod EncryptBlock => _defaultEncryptionServiceMetadataImporter.EncryptBlock; - public IMethod DecryptBlock => _defaultEncryptionServiceMetadataImporter.DecryptBlock; - - public IMethod EncryptInt => _defaultEncryptionServiceMetadataImporter.EncryptInt; - public IMethod DecryptInt => _defaultEncryptionServiceMetadataImporter.DecryptInt; - public IMethod EncryptLong => _defaultEncryptionServiceMetadataImporter.EncryptLong; - public IMethod DecryptLong => _defaultEncryptionServiceMetadataImporter.DecryptLong; - public IMethod EncryptFloat => _defaultEncryptionServiceMetadataImporter.EncryptFloat; - public IMethod DecryptFloat => _defaultEncryptionServiceMetadataImporter.DecryptFloat; - public IMethod EncryptDouble => _defaultEncryptionServiceMetadataImporter.EncryptDouble; - public IMethod DecryptDouble => _defaultEncryptionServiceMetadataImporter.DecryptDouble; - public IMethod EncryptString => _defaultEncryptionServiceMetadataImporter.EncryptString; - public IMethod DecryptString => _defaultEncryptionServiceMetadataImporter.DecryptString; - public IMethod EncryptBytes => _defaultEncryptionServiceMetadataImporter.EncryptBytes; - public IMethod DecryptBytes => _defaultEncryptionServiceMetadataImporter.DecryptBytes; - - public IMethod DecryptFromRvaInt => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaInt; - public IMethod DecryptFromRvaLong => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaLong; - public IMethod DecryptFromRvaFloat => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaFloat; - public IMethod DecryptFromRvaDouble => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaDouble; - public IMethod DecryptFromRvaBytes => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaBytes; - public IMethod DecryptFromRvaString => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaString; - - public IMethod DecryptInitializeArray => _defaultEncryptionServiceMetadataImporter.DecryptInitializeArray; - - public IMethod AddInt => _addInt; - public IMethod AddLong => _addLong; - public IMethod AddFloat => _addFloat; - public IMethod AddDouble => _addDouble; - public IMethod AddIntPtr => _addIntPtr; - public IMethod AddIntPtrInt => _addIntPtrInt; - public IMethod SubtractInt => _subtractInt; - public IMethod SubtractLong => _subtractLong; - public IMethod SubtractFloat => _subtractFloat; - public IMethod SubtractDouble => _subtractDouble; - public IMethod SubtractIntPtr => _subtractIntPtr; - public IMethod SubtractIntPtrInt => _subtractIntPtrInt; - - public IMethod MultiplyInt => _multiplyInt; - public IMethod MultiplyLong => _multiplyLong; - public IMethod MultiplyFloat => _multiplyFloat; - public IMethod MultiplyDouble => _multiplyDouble; - public IMethod MultiplyIntPtr => _multiplyIntPtr; - public IMethod MultiplyIntPtrInt => _multiplyIntPtrInt; - - public IMethod DivideInt => _divideInt; - public IMethod DivideLong => _divideLong; - public IMethod DivideFloat => _divideFloat; - public IMethod DivideDouble => _divideDouble; - public IMethod DivideUnInt => _divideUnInt; - public IMethod DivideUnLong => _divideUnLong; - public IMethod RemInt => _remInt; - public IMethod RemLong => _remLong; - public IMethod RemFloat => _remFloat; - public IMethod RemDouble => _remDouble; - public IMethod RemUnInt => _remUnInt; - public IMethod RemUnLong => _remUnLong; - public IMethod NegInt => _negInt; - public IMethod NegLong => _negLong; - public IMethod NegFloat => _negFloat; - public IMethod NegDouble => _negDouble; - public IMethod AndInt => _andInt; - public IMethod AndLong => _andLong; - public IMethod OrInt => _orInt; - public IMethod OrLong => _orLong; - public IMethod XorInt => _xorInt; - public IMethod XorLong => _xorLong; - public IMethod NotInt => _notInt; - public IMethod NotLong => _notLong; - public IMethod ShlInt => _shlInt; - public IMethod ShlLong => _shlLong; - public IMethod ShrInt => _shrInt; - public IMethod ShrLong => _shrLong; - public IMethod ShrUnInt => _shrUnInt; - public IMethod ShrUnLong => _shrUnLong; - - - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/DefaultMetadataImporter.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/DefaultMetadataImporter.cs.meta deleted file mode 100644 index c29c6a94..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/DefaultMetadataImporter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 76438ce96146edd469872feada7857ba -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EntityExtensions.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EntityExtensions.cs deleted file mode 100644 index 7bc98808..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EntityExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Obfuz.Emit -{ - public static class EntityExtensions - { - public static T GetEntity(this IGroupByModuleEntity entity) where T : IGroupByModuleEntity, new() - { - return entity.Manager.GetEntity(entity.Module); - } - - public static DefaultMetadataImporter GetDefaultModuleMetadataImporter(this IGroupByModuleEntity entity) - { - return entity.GetEntity(); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EntityExtensions.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EntityExtensions.cs.meta deleted file mode 100644 index 119466e8..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EntityExtensions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6e9557733f180764692756653eb60f88 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EvalStackCalculator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EvalStackCalculator.cs deleted file mode 100644 index a7fd4f3b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EvalStackCalculator.cs +++ /dev/null @@ -1,967 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using UnityEngine.Assertions; - -namespace Obfuz.Emit -{ - enum EvalDataType - { - None, - Int32, - Int64, - Float, - Double, - I, - Ref, - ValueType, - Token, - Unknown, - } - - struct EvalDataTypeWithSig - { - public readonly EvalDataType type; - public readonly TypeSig typeSig; - public EvalDataTypeWithSig(EvalDataType type, TypeSig typeSig) - { - this.type = type; - this.typeSig = typeSig; - } - public override string ToString() - { - return $"{type} ({typeSig})"; - } - } - - class InstructionParameterInfo - { - public readonly EvalDataType op1; - public readonly EvalDataType op2; - public readonly EvalDataType retType; - public InstructionParameterInfo(EvalDataType op1, EvalDataType op2, EvalDataType retType) - { - this.op1 = op1; - this.op2 = op2; - this.retType = retType; - } - } - - - class EvalStackState - { - public bool visited; - - public readonly List inputStackDatas = new List(); - public readonly List runStackDatas = new List(); - } - - class EvalStackCalculator - { - private readonly MethodDef _method; - private readonly BasicBlockCollection _basicBlocks; - private readonly Dictionary _instructionParameterInfos = new Dictionary(); - private readonly Dictionary _evalStackTopDataTypeAfterInstructions = new Dictionary(); - private readonly Dictionary _blockEvalStackStates; - - public EvalStackCalculator(MethodDef method) - { - _method = method; - _basicBlocks = new BasicBlockCollection(method, false); - _blockEvalStackStates = _basicBlocks.Blocks.ToDictionary(b => b, b => new EvalStackState()); - - SimulateRunAllBlocks(); - } - - public BasicBlockCollection BasicBlockCollection => _basicBlocks; - - public bool TryGetParameterInfo(Instruction inst, out InstructionParameterInfo info) - { - return _instructionParameterInfos.TryGetValue(inst, out info); - } - - public bool TryGetPushResult(Instruction inst, out EvalDataType result) - { - return _evalStackTopDataTypeAfterInstructions.TryGetValue(inst, out result); - } - - public EvalStackState GetEvalStackState(BasicBlock basicBlock) - { - return _blockEvalStackStates[basicBlock]; - } - - private void PushStack(List datas, TypeSig type) - { - type = type.RemovePinnedAndModifiers(); - switch (type.ElementType) - { - case ElementType.Void: break; - case ElementType.Boolean: - case ElementType.Char: - case ElementType.I1: - case ElementType.U1: - case ElementType.I2: - case ElementType.U2: - case ElementType.I4: - case ElementType.U4: - datas.Add(new EvalDataTypeWithSig(EvalDataType.Int32, null)); - break; - case ElementType.I8: - case ElementType.U8: - datas.Add(new EvalDataTypeWithSig(EvalDataType.Int64, null)); - break; - case ElementType.R4: - datas.Add(new EvalDataTypeWithSig(EvalDataType.Float, null)); - break; - case ElementType.R8: - datas.Add(new EvalDataTypeWithSig(EvalDataType.Double, null)); - break; - case ElementType.I: - case ElementType.U: - case ElementType.Ptr: - case ElementType.FnPtr: - case ElementType.ByRef: - datas.Add(new EvalDataTypeWithSig(EvalDataType.I, null)); - break; - case ElementType.String: - case ElementType.Class: - case ElementType.Array: - case ElementType.SZArray: - case ElementType.Object: - datas.Add(new EvalDataTypeWithSig(EvalDataType.Ref, type)); - break; - case ElementType.ValueType: - { - TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow(); - if (typeDef.IsEnum) - { - PushStack(datas, typeDef.GetEnumUnderlyingType()); - } - else - { - PushStack(datas, new EvalDataTypeWithSig(EvalDataType.ValueType, type)); - } - break; - } - case ElementType.GenericInst: - { - GenericInstSig genericInstSig = (GenericInstSig)type; - TypeDef typeDef = genericInstSig.GenericType.ToTypeDefOrRef().ResolveTypeDefThrow(); - if (!typeDef.IsValueType) - { - PushStack(datas, new EvalDataTypeWithSig(EvalDataType.Ref, type)); - } - else if (typeDef.IsEnum) - { - PushStack(datas, typeDef.GetEnumUnderlyingType()); - } - else - { - PushStack(datas, new EvalDataTypeWithSig(EvalDataType.ValueType, type)); - } - break; - } - case ElementType.TypedByRef: - { - // TypedByRef is a special type used in dynamic method invocation and reflection. - // It is treated as a reference type in the evaluation stack. - PushStack(datas, new EvalDataTypeWithSig(EvalDataType.ValueType, type)); - break; - } - case ElementType.Var: - case ElementType.MVar: - PushStack(datas, new EvalDataTypeWithSig(EvalDataType.ValueType, type)); - break; - case ElementType.ValueArray: - case ElementType.R: - case ElementType.CModOpt: - case ElementType.CModReqd: - case ElementType.Internal: - case ElementType.Module: - case ElementType.Sentinel: - PushStack(datas, EvalDataType.Unknown); - break; - - default: throw new Exception($"Unsupported type: {type} in method: {_method.FullName}."); - } - } - - private void PushStack(List datas, ITypeDefOrRef type) - { - PushStack(datas, type.ToTypeSig()); - } - - private void PushStack(List datas, EvalDataType type) - { - Assert.IsTrue(type != EvalDataType.ValueType, "Cannot push EvalDataType.Value without type sig onto the stack."); - datas.Add(new EvalDataTypeWithSig(type, null)); - } - - private void PushStack(List datas, EvalDataTypeWithSig type) - { - datas.Add(type); - } - - private void PushStackObject(List datas) - { - datas.Add(new EvalDataTypeWithSig(EvalDataType.Ref, _method.Module.CorLibTypes.Object)); - } - - private EvalDataType CalcBasicBinOpRetType(EvalDataType op1, EvalDataType op2) - { - switch (op1) - { - case EvalDataType.Int32: - { - switch (op2) - { - case EvalDataType.Int32: return EvalDataType.Int32; - case EvalDataType.Int64: return EvalDataType.Int64; - case EvalDataType.I: return EvalDataType.I; - default: throw new Exception($"Unsupported operand type: {op2} for {op1} in binary operation."); - } - } - case EvalDataType.Int64: - { - switch (op2) - { - case EvalDataType.Int32: return EvalDataType.Int64; - case EvalDataType.Int64: - case EvalDataType.I: - return EvalDataType.Int64; - default: throw new Exception($"Unsupported operand type: {op2} for {op1} in binary operation."); - } - } - case EvalDataType.I: - { - switch (op2) - { - case EvalDataType.Int32: return EvalDataType.I; - case EvalDataType.Int64: return EvalDataType.Int64; - case EvalDataType.I: return EvalDataType.I; - default: throw new Exception($"Unsupported operand type: {op2} for {op1} in binary operation."); - } - } - case EvalDataType.Float: - { - switch (op2) - { - case EvalDataType.Float: return EvalDataType.Float; - case EvalDataType.Double: return EvalDataType.Double; - default: throw new Exception($"Unsupported operand type: {op2} for {op1} in binary operation."); - } - } - case EvalDataType.Double: - { - switch (op2) - { - case EvalDataType.Float: - case EvalDataType.Double: return EvalDataType.Double; - default: throw new Exception($"Unsupported operand type: {op2} for {op1} in binary operation."); - } - } - default: throw new Exception($"Unsupported operand type: {op1} in binary operation."); - } - } - - private void SimulateRunAllBlocks() - { - bool methodHasReturnValue = !MetaUtil.IsVoidType(_method.ReturnType); - - CilBody body = _method.Body; - if (body.HasExceptionHandlers) - { - foreach (ExceptionHandler handler in body.ExceptionHandlers) - { - if (handler.IsFilter) - { - BasicBlock bb = _basicBlocks.GetBasicBlockByInstruction(handler.FilterStart); - var inputStackDatas = _blockEvalStackStates[bb].inputStackDatas; - if (inputStackDatas.Count == 0) - { - inputStackDatas.Add(new EvalDataTypeWithSig(EvalDataType.Ref, handler.CatchType.ToTypeSig())); - } - } - if (handler.IsCatch || handler.IsFilter) - { - BasicBlock bb = _basicBlocks.GetBasicBlockByInstruction(handler.HandlerStart); - var inputStackDatas = _blockEvalStackStates[bb].inputStackDatas; - if (inputStackDatas.Count == 0) - { - inputStackDatas.Add(new EvalDataTypeWithSig(EvalDataType.Ref, handler.CatchType.ToTypeSig())); - } - } - } - } - - var newPushedDatas = new List(); - IList methodTypeGenericArgument = _method.DeclaringType.GenericParameters.Count > 0 - ? (IList)_method.DeclaringType.GenericParameters.Select(p => (TypeSig)new GenericVar(p.Number)).ToList() - : null; - IList methodMethodGenericArgument = _method.GenericParameters.Count > 0 - ? (IList)_method.GenericParameters.Select(p => (TypeSig)new GenericMVar(p.Number)).ToList() - : null; - var gac = new GenericArgumentContext(methodTypeGenericArgument, methodMethodGenericArgument); - var corLibTypes = _method.Module.CorLibTypes; - - var blockWalkStack = new Stack(_basicBlocks.Blocks.Reverse()); - while (blockWalkStack.Count > 0) - { - BasicBlock block = blockWalkStack.Pop(); - EvalStackState state = _blockEvalStackStates[block]; - if (state.visited) - continue; - state.visited = true; - state.runStackDatas.AddRange(state.inputStackDatas); - List stackDatas = state.runStackDatas; - foreach (var inst in block.instructions) - { - int stackSize = stackDatas.Count; - newPushedDatas.Clear(); - switch (inst.OpCode.Code) - { - case Code.Nop: break; - case Code.Break: break; - case Code.Ldarg_0: - case Code.Ldarg_1: - case Code.Ldarg_2: - case Code.Ldarg_3: - case Code.Ldarg: - case Code.Ldarg_S: - { - PushStack(newPushedDatas, inst.GetParameter(_method.Parameters).Type); - break; - } - case Code.Ldarga: - case Code.Ldarga_S: - { - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Ldloc_0: - case Code.Ldloc_1: - case Code.Ldloc_2: - case Code.Ldloc_3: - case Code.Ldloc: - case Code.Ldloc_S: - { - PushStack(newPushedDatas, inst.GetLocal(body.Variables).Type); - break; - } - case Code.Ldloca: - case Code.Ldloca_S: - { - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Stloc_0: - case Code.Stloc_1: - case Code.Stloc_2: - case Code.Stloc_3: - case Code.Stloc: - case Code.Stloc_S: - { - Assert.IsTrue(stackSize > 0); - break; - } - case Code.Starg: - case Code.Starg_S: - { - Assert.IsTrue(stackSize > 0); - break; - } - case Code.Ldnull: - { - PushStackObject(newPushedDatas); - break; - } - case Code.Ldc_I4_M1: - case Code.Ldc_I4_0: - case Code.Ldc_I4_1: - case Code.Ldc_I4_2: - case Code.Ldc_I4_3: - case Code.Ldc_I4_4: - case Code.Ldc_I4_5: - case Code.Ldc_I4_6: - case Code.Ldc_I4_7: - case Code.Ldc_I4_8: - case Code.Ldc_I4: - case Code.Ldc_I4_S: - { - PushStack(newPushedDatas, EvalDataType.Int32); - break; - } - case Code.Ldc_I8: - { - PushStack(newPushedDatas, EvalDataType.Int64); - break; - } - case Code.Ldc_R4: - { - PushStack(newPushedDatas, EvalDataType.Float); - break; - } - case Code.Ldc_R8: - { - PushStack(newPushedDatas, EvalDataType.Double); - break; - } - case Code.Dup: - { - Assert.IsTrue(stackSize > 0); - EvalDataTypeWithSig type = stackDatas[stackSize - 1]; - PushStack(newPushedDatas, type); - PushStack(newPushedDatas, type); - break; - } - case Code.Pop: - { - break; - } - case Code.Jmp: - { - break; - } - case Code.Call: - case Code.Callvirt: - { - IMethod calledMethod = (IMethod)inst.Operand; - MethodSig methodSig = MetaUtil.GetInflatedMethodSig(calledMethod, gac); - PushStack(newPushedDatas, methodSig.RetType); - break; - } - case Code.Calli: - { - MethodSig methodSig = (MethodSig)inst.Operand; - PushStack(newPushedDatas, methodSig.RetType); - break; - } - case Code.Ret: - { - break; - } - case Code.Br: - case Code.Br_S: - case Code.Brfalse: - case Code.Brfalse_S: - case Code.Brtrue: - case Code.Brtrue_S: - case Code.Beq: - case Code.Beq_S: - case Code.Bge: - case Code.Bge_S: - case Code.Bge_Un: - case Code.Bge_Un_S: - case Code.Bgt: - case Code.Bgt_S: - case Code.Bgt_Un: - case Code.Bgt_Un_S: - case Code.Ble: - case Code.Ble_S: - case Code.Ble_Un: - case Code.Ble_Un_S: - case Code.Blt: - case Code.Blt_S: - case Code.Blt_Un: - case Code.Blt_Un_S: - case Code.Bne_Un: - case Code.Bne_Un_S: - { - // Branch instructions do not change the stack. - break; - } - case Code.Ceq: - case Code.Cgt: - case Code.Cgt_Un: - case Code.Clt: - case Code.Clt_Un: - { - Assert.IsTrue(stackSize >= 2); - EvalDataType op2 = stackDatas[stackSize - 1].type; - EvalDataType op1 = stackDatas[stackSize - 2].type; - EvalDataType ret = EvalDataType.Int32; - _instructionParameterInfos.Add(inst, new InstructionParameterInfo(op1, op2, ret)); - PushStack(newPushedDatas, ret); - break; - } - case Code.Switch: - { - // Switch instruction does not change the stack. - break; - } - case Code.Ldind_I1: - case Code.Ldind_U1: - case Code.Ldind_I2: - case Code.Ldind_U2: - case Code.Ldind_I4: - case Code.Ldind_U4: - { - Assert.IsTrue(stackSize > 0); - PushStack(newPushedDatas, EvalDataType.Int32); - break; - } - case Code.Ldind_I8: - { - Assert.IsTrue(stackSize > 0); - PushStack(newPushedDatas, EvalDataType.Int64); - break; - } - case Code.Ldind_I: - { - Assert.IsTrue(stackSize > 0); - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Ldind_Ref: - { - Assert.IsTrue(stackSize > 0); - PushStackObject(newPushedDatas); - break; - } - case Code.Ldind_R4: - { - Assert.IsTrue(stackSize > 0); - PushStack(newPushedDatas, EvalDataType.Float); - break; - } - case Code.Ldind_R8: - { - Assert.IsTrue(stackSize > 0); - PushStack(newPushedDatas, EvalDataType.Double); - break; - } - case Code.Stind_I1: - case Code.Stind_I2: - case Code.Stind_I4: - case Code.Stind_I8: - case Code.Stind_I: - case Code.Stind_R4: - case Code.Stind_R8: - case Code.Stind_Ref: - { - Assert.IsTrue(stackSize >= 2); - break; - } - - case Code.Add: - case Code.Add_Ovf: - case Code.Add_Ovf_Un: - case Code.Sub: - case Code.Sub_Ovf: - case Code.Sub_Ovf_Un: - case Code.Mul: - case Code.Mul_Ovf: - case Code.Mul_Ovf_Un: - case Code.Div: - case Code.Div_Un: - case Code.Rem: - case Code.Rem_Un: - - case Code.And: - case Code.Or: - case Code.Xor: - { - Assert.IsTrue(stackSize >= 2); - EvalDataType op2 = stackDatas[stackSize - 1].type; - EvalDataType op1 = stackDatas[stackSize - 2].type; - EvalDataType ret = CalcBasicBinOpRetType(op1, op2); - _instructionParameterInfos.Add(inst, new InstructionParameterInfo(op1, op2, ret)); - PushStack(newPushedDatas, ret); - break; - } - case Code.Shl: - case Code.Shr: - case Code.Shr_Un: - { - Assert.IsTrue(stackSize >= 2); - EvalDataType op2 = stackDatas[stackSize - 1].type; - EvalDataType op1 = stackDatas[stackSize - 2].type; - if (op1 != EvalDataType.Int32 && op1 != EvalDataType.Int64 && op1 != EvalDataType.I) - throw new Exception($"Unsupported operand type: {op1} in shift operation."); - if (op2 != EvalDataType.Int32 && op2 != EvalDataType.Int64) - throw new Exception($"Unsupported operand type: {op2} for {op1} in shift operation."); - EvalDataType ret = op1; - _instructionParameterInfos.Add(inst, new InstructionParameterInfo(op1, op2, ret)); - PushStack(newPushedDatas, ret); - break; - } - case Code.Neg: - { - Assert.IsTrue(stackSize > 0); - EvalDataType op = stackDatas[stackSize - 1].type; - EvalDataType ret = op; - switch (op) - { - case EvalDataType.Int32: - case EvalDataType.Int64: - case EvalDataType.I: - case EvalDataType.Float: - case EvalDataType.Double: - break; - default: - throw new Exception($"Unsupported operand type: {op} in unary operation."); - } - _instructionParameterInfos.Add(inst, new InstructionParameterInfo(op, EvalDataType.None, ret)); - PushStack(newPushedDatas, ret); - break; - } - case Code.Not: - { - Assert.IsTrue(stackSize > 0); - EvalDataType op = stackDatas[stackSize - 1].type; - EvalDataType ret = op; - if (op != EvalDataType.Int32 && op != EvalDataType.Int64 && op != EvalDataType.I) - throw new Exception($"Unsupported operand type: {op} in unary operation."); - _instructionParameterInfos.Add(inst, new InstructionParameterInfo(op, EvalDataType.None, ret)); - PushStack(newPushedDatas, ret); - break; - } - case Code.Conv_I1: - case Code.Conv_U1: - case Code.Conv_I2: - case Code.Conv_U2: - case Code.Conv_I4: - case Code.Conv_U4: - { - PushStack(newPushedDatas, EvalDataType.Int32); - break; - } - case Code.Conv_I8: - case Code.Conv_U8: - { - PushStack(newPushedDatas, EvalDataType.Int64); - break; - } - case Code.Conv_I: - case Code.Conv_U: - { - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Conv_R4: - { - PushStack(newPushedDatas, EvalDataType.Float); - break; - } - case Code.Conv_R8: - { - PushStack(newPushedDatas, EvalDataType.Double); - break; - } - case Code.Conv_Ovf_I1: - case Code.Conv_Ovf_I1_Un: - case Code.Conv_Ovf_U1: - case Code.Conv_Ovf_U1_Un: - case Code.Conv_Ovf_I2: - case Code.Conv_Ovf_I2_Un: - case Code.Conv_Ovf_U2: - case Code.Conv_Ovf_U2_Un: - case Code.Conv_Ovf_I4: - case Code.Conv_Ovf_I4_Un: - case Code.Conv_Ovf_U4: - case Code.Conv_Ovf_U4_Un: - { - PushStack(newPushedDatas, EvalDataType.Int32); - break; - } - case Code.Conv_Ovf_I8: - case Code.Conv_Ovf_I8_Un: - case Code.Conv_Ovf_U8: - case Code.Conv_Ovf_U8_Un: - { - PushStack(newPushedDatas, EvalDataType.Int64); - break; - } - case Code.Conv_Ovf_I: - case Code.Conv_Ovf_I_Un: - case Code.Conv_Ovf_U: - case Code.Conv_Ovf_U_Un: - { - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Conv_R_Un: - { - PushStack(newPushedDatas, EvalDataType.Double); - break; - } - case Code.Cpobj: - case Code.Initobj: - case Code.Stobj: - { - break; - } - case Code.Ldobj: - { - PushStack(newPushedDatas, (ITypeDefOrRef)inst.Operand); - break; - } - case Code.Ldstr: - { - PushStack(newPushedDatas, new EvalDataTypeWithSig(EvalDataType.Ref, corLibTypes.String)); - break; - } - case Code.Newobj: - { - IMethod ctor = (IMethod)inst.Operand; - PushStack(newPushedDatas, ctor.DeclaringType); - break; - } - case Code.Castclass: - { - PushStack(newPushedDatas, (ITypeDefOrRef)inst.Operand); - break; - } - case Code.Isinst: - { - Assert.IsTrue(stackSize > 0); - var obj = stackDatas[stackSize - 1]; - Assert.IsTrue(obj.type == EvalDataType.Ref); - PushStack(newPushedDatas, obj); - break; - } - case Code.Unbox: - { - Assert.IsTrue(stackSize > 0); - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Unbox_Any: - { - Assert.IsTrue(stackSize > 0); - PushStack(newPushedDatas, (ITypeDefOrRef)inst.Operand); - break; - } - case Code.Box: - { - Assert.IsTrue(stackSize > 0); - PushStackObject(newPushedDatas); - break; - } - case Code.Throw: - { - // Throw instruction does not change the stack. - break; - } - case Code.Rethrow: - { - // Rethrow instruction does not change the stack. - break; - } - case Code.Ldfld: - case Code.Ldsfld: - { - IField field = (IField)inst.Operand; - TypeSig fieldType = MetaUtil.InflateFieldSig(field, gac); - PushStack(newPushedDatas, fieldType); - break; - } - case Code.Ldflda: - case Code.Ldsflda: - { - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Stfld: - case Code.Stsfld: - { - break; - } - case Code.Newarr: - { - Assert.IsTrue(stackSize > 0); - PushStack(newPushedDatas, new SZArraySig(((ITypeDefOrRef)inst.Operand).ToTypeSig())); - break; - } - case Code.Ldlen: - { - Assert.IsTrue(stackSize > 0); - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Ldelema: - { - Assert.IsTrue(stackSize >= 2); - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Ldelem_I1: - case Code.Ldelem_U1: - case Code.Ldelem_I2: - case Code.Ldelem_U2: - case Code.Ldelem_I4: - case Code.Ldelem_U4: - { - Assert.IsTrue(stackSize >= 2); - PushStack(newPushedDatas, EvalDataType.Int32); - break; - } - case Code.Ldelem_I8: - { - Assert.IsTrue(stackSize >= 2); - PushStack(newPushedDatas, EvalDataType.Int64); - break; - } - case Code.Ldelem_I: - { - Assert.IsTrue(stackSize >= 2); - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Ldelem_R4: - { - Assert.IsTrue(stackSize >= 2); - PushStack(newPushedDatas, EvalDataType.Float); - break; - } - case Code.Ldelem_R8: - { - Assert.IsTrue(stackSize >= 2); - PushStack(newPushedDatas, EvalDataType.Double); - break; - } - case Code.Ldelem_Ref: - { - Assert.IsTrue(stackSize >= 2); - PushStackObject(newPushedDatas); - break; - } - case Code.Ldelem: - { - Assert.IsTrue(stackSize >= 2); - PushStack(newPushedDatas, (ITypeDefOrRef)inst.Operand); - break; - } - case Code.Stelem_I1: - case Code.Stelem_I2: - case Code.Stelem_I4: - case Code.Stelem_I8: - case Code.Stelem_I: - case Code.Stelem_R4: - case Code.Stelem_R8: - case Code.Stelem_Ref: - case Code.Stelem: - { - Assert.IsTrue(stackSize >= 3); - break; - } - case Code.Mkrefany: - { - PushStack(newPushedDatas, new EvalDataTypeWithSig(EvalDataType.ValueType, _method.Module.CorLibTypes.TypedReference)); - break; - } - case Code.Refanytype: - { - PushStack(newPushedDatas, EvalDataType.Token); - break; - } - case Code.Refanyval: - { - Assert.IsTrue(stackSize > 0); - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Ldtoken: - { - PushStack(newPushedDatas, EvalDataType.Token); - break; - } - case Code.Endfinally: - case Code.Leave: - case Code.Leave_S: - { - break; - } - case Code.Endfilter: - { - break; - } - case Code.Arglist: - { - break; - } - case Code.Ldftn: - case Code.Ldvirtftn: - { - PushStack(newPushedDatas, EvalDataType.Unknown); - break; - } - case Code.Localloc: - { - PushStack(newPushedDatas, EvalDataType.I); - break; - } - case Code.Unaligned: - case Code.Volatile: - case Code.Tailcall: - case Code.No: - case Code.Readonly: - case Code.Constrained: - { - break; - } - case Code.Cpblk: - case Code.Initblk: - { - break; - } - case Code.Sizeof: - { - PushStack(newPushedDatas, EvalDataType.Int32); - break; - } - default: throw new Exception($"not supported opcode: {inst} in method: {_method.FullName}."); - } - - inst.CalculateStackUsage(methodHasReturnValue, out var pushed, out var pops); - if (pushed != newPushedDatas.Count) - { - throw new Exception($"Instruction {inst} in method {_method.FullName} pushed {newPushedDatas.Count} items, but expected {pushed} items."); - } - if (pops == -1) - { - stackDatas.Clear(); - } - else - { - if (stackSize < pops) - { - throw new Exception($"Instruction {inst} in method {_method.FullName} pops {pops} items, but only {stackSize} items are available on the stack."); - } - stackDatas.RemoveRange(stackDatas.Count - pops, pops); - stackDatas.AddRange(newPushedDatas); - Assert.AreEqual(stackSize + pushed - pops, stackDatas.Count); - } - if (pushed > 0 && stackDatas.Count > 0) - { - _evalStackTopDataTypeAfterInstructions[inst] = stackDatas.Last().type; - } - } - foreach (BasicBlock outBb in block.outBlocks) - { - EvalStackState outState = _blockEvalStackStates[outBb]; - if (outState.visited) - { - if (stackDatas.Count != outState.inputStackDatas.Count) - { - throw new Exception($"Block {block} in method {_method.FullName} has inconsistent stack data. Expected {outState.inputStackDatas.Count}, but got {stackDatas.Count}."); - } - } - else if (outState.inputStackDatas.Count != stackDatas.Count) - { - if (outState.inputStackDatas.Count > 0) - { - throw new Exception($"Block {outBb} in method {_method.FullName} has inconsistent stack data. Expected {outState.inputStackDatas.Count}, but got {stackDatas.Count}."); - } - outState.inputStackDatas.AddRange(stackDatas); - blockWalkStack.Push(outBb); - } - } - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EvalStackCalculator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EvalStackCalculator.cs.meta deleted file mode 100644 index 0e3c9de0..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/EvalStackCalculator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f25425a3077f6db41873dee4223d0abc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/GroupByModuleEntityManager.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/GroupByModuleEntityManager.cs deleted file mode 100644 index 97e8f286..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/GroupByModuleEntityManager.cs +++ /dev/null @@ -1,89 +0,0 @@ -using dnlib.DotNet; -using System; -using System.Collections.Generic; - -namespace Obfuz.Emit -{ - public interface IGroupByModuleEntity - { - GroupByModuleEntityManager Manager { get; set; } - - ModuleDef Module { get; set; } - - public EncryptionScopeProvider EncryptionScopeProvider { get; } - - EncryptionScopeInfo EncryptionScope { get; set; } - - void Init(); - - void Done(); - } - - public abstract class GroupByModuleEntityBase : IGroupByModuleEntity - { - public GroupByModuleEntityManager Manager { get; set; } - - public ModuleDef Module { get; set; } - - public EncryptionScopeInfo EncryptionScope { get; set; } - - public EncryptionScopeProvider EncryptionScopeProvider => Manager.EncryptionScopeProvider; - - public T GetEntity() where T : IGroupByModuleEntity, new() - { - return Manager.GetEntity(Module); - } - - public abstract void Init(); - - public abstract void Done(); - } - - public class GroupByModuleEntityManager - { - private readonly Dictionary<(ModuleDef, Type), IGroupByModuleEntity> _moduleEntityManagers = new Dictionary<(ModuleDef, Type), IGroupByModuleEntity>(); - - public EncryptionScopeProvider EncryptionScopeProvider { get; set; } - - public T GetEntity(ModuleDef mod) where T : IGroupByModuleEntity, new() - { - var key = (mod, typeof(T)); - if (_moduleEntityManagers.TryGetValue(key, out var emitManager)) - { - return (T)emitManager; - } - else - { - T newEmitManager = new T(); - newEmitManager.Manager = this; - newEmitManager.Module = mod; - newEmitManager.EncryptionScope = EncryptionScopeProvider.GetScope(mod); - newEmitManager.Init(); - _moduleEntityManagers[key] = newEmitManager; - return newEmitManager; - } - } - - public List GetEntities() where T : IGroupByModuleEntity, new() - { - var managers = new List(); - foreach (var kv in _moduleEntityManagers) - { - if (kv.Key.Item2 == typeof(T)) - { - managers.Add((T)kv.Value); - } - } - return managers; - } - - public void Done() where T : IGroupByModuleEntity, new() - { - var managers = GetEntities(); - foreach (var manager in managers) - { - manager.Done(); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/GroupByModuleEntityManager.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/GroupByModuleEntityManager.cs.meta deleted file mode 100644 index a6b76025..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/GroupByModuleEntityManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0bfcb2b5a87851f469d201fc8978c109 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/LocalVariableAllocator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/LocalVariableAllocator.cs deleted file mode 100644 index 3fb0015e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/LocalVariableAllocator.cs +++ /dev/null @@ -1,74 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using System; -using System.Collections.Generic; - -namespace Obfuz.Emit -{ - class ScopeLocalVariables : IDisposable - { - private readonly LocalVariableAllocator _localVariableAllocator; - - private readonly List _allocatedVars = new List(); - - public IReadOnlyList AllocatedLocals => _allocatedVars; - - - public ScopeLocalVariables(LocalVariableAllocator localVariableAllocator) - { - _localVariableAllocator = localVariableAllocator; - } - - public Local AllocateLocal(TypeSig type) - { - var local = _localVariableAllocator.AllocateLocal(type); - _allocatedVars.Add(local); - return local; - } - - public void Dispose() - { - foreach (var local in _allocatedVars) - { - _localVariableAllocator.ReturnLocal(local); - } - } - } - - class LocalVariableAllocator - { - private readonly MethodDef _method; - private readonly List _freeLocals = new List(); - - public LocalVariableAllocator(MethodDef method) - { - _method = method; - } - - public Local AllocateLocal(TypeSig type) - { - foreach (var local in _freeLocals) - { - if (TypeEqualityComparer.Instance.Equals(local.Type, type)) - { - _freeLocals.Remove(local); - return local; - } - } - var newLocal = new Local(type); - // _freeLocals.Add(newLocal); - _method.Body.Variables.Add(newLocal); - return newLocal; - } - - public void ReturnLocal(Local local) - { - _freeLocals.Add(local); - } - - public ScopeLocalVariables CreateScope() - { - return new ScopeLocalVariables(this); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/LocalVariableAllocator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/LocalVariableAllocator.cs.meta deleted file mode 100644 index 6561078c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Emit/LocalVariableAllocator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 955da34fbde179641a94108ec53405ce -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM.meta deleted file mode 100644 index e8e65c15..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: fec4187cc1b96d5439ff908bcecd988f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/EncryptionInstructionWithOpCode.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/EncryptionInstructionWithOpCode.cs deleted file mode 100644 index 19ded458..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/EncryptionInstructionWithOpCode.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Obfuz.EncryptionVM -{ - public class EncryptionInstructionWithOpCode - { - public readonly ushort code; - - public readonly IEncryptionInstruction function; - - public EncryptionInstructionWithOpCode(ushort code, IEncryptionInstruction function) - { - this.code = code; - this.function = function; - } - - public int Encrypt(int value, int[] secretKey, int salt) - { - return function.Encrypt(value, secretKey, salt); - } - - public int Decrypt(int value, int[] secretKey, int salt) - { - return function.Decrypt(value, secretKey, salt); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/EncryptionInstructionWithOpCode.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/EncryptionInstructionWithOpCode.cs.meta deleted file mode 100644 index cd63f212..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/EncryptionInstructionWithOpCode.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ca9bd232ed2583f4bb5f330886a329e6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/IEncryptionInstruction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/IEncryptionInstruction.cs deleted file mode 100644 index 49808c43..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/IEncryptionInstruction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM -{ - public interface IEncryptionInstruction - { - int Encrypt(int value, int[] secretKey, int salt); - - int Decrypt(int value, int[] secretKey, int salt); - - void GenerateEncryptCode(List lines, string indent); - - void GenerateDecryptCode(List lines, string indent); - } - - public abstract class EncryptionInstructionBase : IEncryptionInstruction - { - public abstract int Encrypt(int value, int[] secretKey, int salt); - public abstract int Decrypt(int value, int[] secretKey, int salt); - - public abstract void GenerateEncryptCode(List lines, string indent); - public abstract void GenerateDecryptCode(List lines, string indent); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/IEncryptionInstruction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/IEncryptionInstruction.cs.meta deleted file mode 100644 index ab7f3a60..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/IEncryptionInstruction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f7b9d087de770a5488a9069ddf697c2f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions.meta deleted file mode 100644 index fa569881..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 981355cf75a9d234883b2a15c446f478 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddInstruction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddInstruction.cs deleted file mode 100644 index 2681fff0..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddInstruction.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM.Instructions -{ - public class AddInstruction : EncryptionInstructionBase - { - private readonly int _addValue; - private readonly int _opKeyIndex; - - public AddInstruction(int addValue, int opKeyIndex) - { - _addValue = addValue; - _opKeyIndex = opKeyIndex; - } - public override int Encrypt(int value, int[] secretKey, int salt) - { - return ((value + secretKey[_opKeyIndex]) ^ salt) + _addValue; - } - - public override int Decrypt(int value, int[] secretKey, int salt) - { - return ((value - _addValue) ^ salt) - secretKey[_opKeyIndex]; - } - - public override void GenerateEncryptCode(List lines, string indent) - { - lines.Add(indent + $"value = ((value + _secretKey[{_opKeyIndex}]) ^ salt) + {_addValue};"); - } - - public override void GenerateDecryptCode(List lines, string indent) - { - lines.Add(indent + $"value = ((value - {_addValue}) ^ salt) - _secretKey[{_opKeyIndex}];"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddInstruction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddInstruction.cs.meta deleted file mode 100644 index d1d20319..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddInstruction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6bdbdc5fd983f044a87e7b8ab8647aeb -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddRotateXorInstruction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddRotateXorInstruction.cs deleted file mode 100644 index 44933213..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddRotateXorInstruction.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM.Instructions -{ - public class AddRotateXorInstruction : EncryptionInstructionBase - { - // x = x + p1 + secretKey[index1]; - // x = Rotate(x, p2) - // x = x ^ p3 ^ salt; - - private readonly int _addValue; - private readonly int _index1; - private readonly int _rotateBitNum; - private readonly int _xorValue; - - public AddRotateXorInstruction(int addValue, int index1, int rotateBitNum, int xorValue) - { - _addValue = addValue; - _index1 = index1; - _rotateBitNum = rotateBitNum; - _xorValue = xorValue; - } - - public override int Encrypt(int value, int[] secretKey, int salt) - { - value += _addValue + secretKey[_index1]; - uint part1 = (uint)value << _rotateBitNum; - uint part2 = (uint)value >> (32 - _rotateBitNum); - value = (int)(part1 | part2); - value ^= _xorValue ^ salt; - return value; - } - - public override int Decrypt(int value, int[] secretKey, int salt) - { - value ^= _xorValue ^ salt; - uint value2 = (uint)value >> _rotateBitNum; - uint part1 = (uint)value << (32 - _rotateBitNum); - value = (int)(value2 | part1); - value -= _addValue + secretKey[_index1]; - return value; - } - - public override void GenerateEncryptCode(List lines, string indent) - { - lines.Add(indent + $"value += {_addValue} + _secretKey[{_index1}];"); - lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};"); - lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(part1 | part2);"); - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - } - - public override void GenerateDecryptCode(List lines, string indent) - { - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - lines.Add(indent + $"uint value2 = (uint)value >> {_rotateBitNum};"); - lines.Add(indent + $"uint part1 = (uint)value << (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(value2 | part1);"); - lines.Add(indent + $"value -= {_addValue} + _secretKey[{_index1}];"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddRotateXorInstruction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddRotateXorInstruction.cs.meta deleted file mode 100644 index 6101fdb1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddRotateXorInstruction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cda67c0dd0cadd24ea02c2988e34281a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddXorRotateInstruction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddXorRotateInstruction.cs deleted file mode 100644 index d2aa6f15..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddXorRotateInstruction.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM.Instructions -{ - public class AddXorRotateInstruction : EncryptionInstructionBase - { - // x = x + p1 + secretKey[index1]; - // x = x ^ p3 ^ salt; - // x = Rotate(x, p2) - - private readonly int _addValue; - private readonly int _index1; - private readonly int _rotateBitNum; - private readonly int _xorValue; - - public AddXorRotateInstruction(int addValue, int index1, int xorValue, int rotateBitNum) - { - _addValue = addValue; - _index1 = index1; - _rotateBitNum = rotateBitNum; - _xorValue = xorValue; - } - - public override int Encrypt(int value, int[] secretKey, int salt) - { - value += _addValue + secretKey[_index1]; - value ^= _xorValue ^ salt; - uint part1 = (uint)value << _rotateBitNum; - uint part2 = (uint)value >> (32 - _rotateBitNum); - value = (int)(part1 | part2); - return value; - } - - public override int Decrypt(int value, int[] secretKey, int salt) - { - uint value2 = (uint)value >> _rotateBitNum; - uint part1 = (uint)value << (32 - _rotateBitNum); - value = (int)(value2 | part1); - value ^= _xorValue ^ salt; - value -= _addValue + secretKey[_index1]; - return value; - } - - public override void GenerateEncryptCode(List lines, string indent) - { - lines.Add(indent + $"value += {_addValue} + _secretKey[{_index1}];"); - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};"); - lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(part1 | part2);"); - } - - public override void GenerateDecryptCode(List lines, string indent) - { - lines.Add(indent + $"uint part1 = (uint)value >> {_rotateBitNum};"); - lines.Add(indent + $"uint part2 = (uint)value << (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(part1 | part2);"); - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - lines.Add(indent + $"value -= {_addValue} + _secretKey[{_index1}];"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddXorRotateInstruction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddXorRotateInstruction.cs.meta deleted file mode 100644 index abde16f0..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/AddXorRotateInstruction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d806305e627be06469fb2d2c2cf98816 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/BitRotateInstruction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/BitRotateInstruction.cs deleted file mode 100644 index 2d9dcd14..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/BitRotateInstruction.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM.Instructions -{ - public class BitRotateInstruction : EncryptionInstructionBase - { - private readonly int _rotateBitNum; - private readonly int _opKeyIndex; - - public BitRotateInstruction(int rotateBitNum, int opKeyIndex) - { - _rotateBitNum = rotateBitNum; - _opKeyIndex = opKeyIndex; - } - - public override int Encrypt(int value, int[] secretKey, int salt) - { - uint part1 = (uint)value << _rotateBitNum; - uint part2 = (uint)value >> (32 - _rotateBitNum); - return ((int)(part1 | part2) ^ secretKey[_opKeyIndex]) + salt; - } - - public override int Decrypt(int value, int[] secretKey, int salt) - { - uint value2 = (uint)((value - salt) ^ secretKey[_opKeyIndex]); - uint part1 = value2 >> _rotateBitNum; - uint part2 = value2 << (32 - _rotateBitNum); - return (int)(part1 | part2); - } - - public override void GenerateEncryptCode(List lines, string indent) - { - lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};"); - lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = ((int)(part1 | part2) ^ _secretKey[{_opKeyIndex}]) + salt;"); - } - - public override void GenerateDecryptCode(List lines, string indent) - { - lines.Add(indent + $"uint value2 = (uint)((value - salt) ^ _secretKey[{_opKeyIndex}]);"); - lines.Add(indent + $"uint part1 = value2 >> {_rotateBitNum};"); - lines.Add(indent + $"uint part2 = value2 << (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(part1 | part2);"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/BitRotateInstruction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/BitRotateInstruction.cs.meta deleted file mode 100644 index b4b0b9a5..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/BitRotateInstruction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bccff31b9f07fcf4f821cee671f82caf -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/EncryptFunction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/EncryptFunction.cs deleted file mode 100644 index 7abafecd..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/EncryptFunction.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM.Instructions -{ - - public class EncryptFunction : EncryptionInstructionBase - { - private readonly IEncryptionInstruction[] _instructions; - - public EncryptFunction(IEncryptionInstruction[] instructions) - { - _instructions = instructions; - } - - public override int Encrypt(int value, int[] secretKey, int salt) - { - foreach (var instruction in _instructions) - { - value = instruction.Encrypt(value, secretKey, salt); - } - return value; - } - - public override int Decrypt(int value, int[] secretKey, int salt) - { - for (int i = _instructions.Length - 1; i >= 0; i--) - { - value = _instructions[i].Decrypt(value, secretKey, salt); - } - return value; - } - - public override void GenerateEncryptCode(List lines, string indent) - { - throw new NotImplementedException(); - } - - public override void GenerateDecryptCode(List lines, string indent) - { - throw new NotImplementedException(); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/EncryptFunction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/EncryptFunction.cs.meta deleted file mode 100644 index 0ee2250b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/EncryptFunction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: feafdb30f7b6d5143a89c7659bc16171 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleInstruction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleInstruction.cs deleted file mode 100644 index a788a678..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleInstruction.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM.Instructions -{ - public class MultipleInstruction : EncryptionInstructionBase - { - private readonly int _multiValue; - private readonly int _revertMultiValue; - private readonly int _opKeyIndex; - - public MultipleInstruction(int addValue, int opKeyIndex) - { - _multiValue = addValue; - _opKeyIndex = opKeyIndex; - _revertMultiValue = MathUtil.ModInverse32(addValue); - Verify(); - } - - private void Verify() - { - int a = 1122334; - UnityEngine.Assertions.Assert.AreEqual(a, a * _multiValue * _revertMultiValue); - } - - public override int Encrypt(int value, int[] secretKey, int salt) - { - return value * _multiValue + secretKey[_opKeyIndex] + salt; - } - - public override int Decrypt(int value, int[] secretKey, int salt) - { - return (value - secretKey[_opKeyIndex] - salt) * _revertMultiValue; - } - - public override void GenerateEncryptCode(List lines, string indent) - { - lines.Add(indent + $"value = value * {_multiValue} + _secretKey[{_opKeyIndex}] + salt;"); - } - - public override void GenerateDecryptCode(List lines, string indent) - { - lines.Add(indent + $"value = (value - _secretKey[{_opKeyIndex}] - salt) * {_revertMultiValue};"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleInstruction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleInstruction.cs.meta deleted file mode 100644 index 478ba088..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleInstruction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fd5fdfad694e0ae469bf6ca04c913220 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleRotateXorInstruction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleRotateXorInstruction.cs deleted file mode 100644 index 62fc609a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleRotateXorInstruction.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM.Instructions -{ - public class MultipleRotateXorInstruction : EncryptionInstructionBase - { - // x = x * p1 + secretKey[index1]; - // x = Rotate(x, p2) - // x = x ^ p3 ^ salt; - - private readonly int _multipleValue; - private readonly int _revertMultipleValue; - private readonly int _index1; - private readonly int _rotateBitNum; - private readonly int _xorValue; - - public MultipleRotateXorInstruction(int multipleValue, int index1, int rotateBitNum, int xorValue) - { - _multipleValue = multipleValue; - _revertMultipleValue = MathUtil.ModInverse32(multipleValue); - _index1 = index1; - _rotateBitNum = rotateBitNum; - _xorValue = xorValue; - } - - public override int Encrypt(int value, int[] secretKey, int salt) - { - value = value * _multipleValue + secretKey[_index1]; - uint part1 = (uint)value << _rotateBitNum; - uint part2 = (uint)value >> (32 - _rotateBitNum); - value = (int)(part1 | part2); - value ^= _xorValue ^ salt; - return value; - } - - public override int Decrypt(int value, int[] secretKey, int salt) - { - value ^= _xorValue ^ salt; - uint value2 = (uint)value >> _rotateBitNum; - uint part1 = (uint)value << (32 - _rotateBitNum); - value = (int)(value2 | part1); - value = (value - secretKey[_index1]) * _revertMultipleValue; - return value; - } - - public override void GenerateEncryptCode(List lines, string indent) - { - lines.Add(indent + $"value = value * {_multipleValue} + _secretKey[{_index1}];"); - lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};"); - lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(part1 | part2);"); - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - } - - public override void GenerateDecryptCode(List lines, string indent) - { - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - lines.Add(indent + $"uint value2 = (uint)value >> {_rotateBitNum};"); - lines.Add(indent + $"uint part1 = (uint)value << (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(value2 | part1);"); - lines.Add(indent + $"value = (value - _secretKey[{_index1}]) * {_revertMultipleValue};"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleRotateXorInstruction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleRotateXorInstruction.cs.meta deleted file mode 100644 index 7f4e53a7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleRotateXorInstruction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e3c8b55b35ff1554489fa657a714f485 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleXorRotateInstruction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleXorRotateInstruction.cs deleted file mode 100644 index a8a69326..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleXorRotateInstruction.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM.Instructions -{ - public class MultipleXorRotateInstruction : EncryptionInstructionBase - { - // x = x * p1 + secretKey[index1]; - // x = x ^ p3 ^ salt; - // x = Rotate(x, p2) - - private readonly int _multipleValue; - private readonly int _revertMultipleValue; - private readonly int _index1; - private readonly int _rotateBitNum; - private readonly int _xorValue; - - public MultipleXorRotateInstruction(int multipleValue, int index1, int xorValue, int rotateBitNum) - { - _multipleValue = multipleValue; - _revertMultipleValue = MathUtil.ModInverse32(multipleValue); - _index1 = index1; - _rotateBitNum = rotateBitNum; - _xorValue = xorValue; - } - - public override int Encrypt(int value, int[] secretKey, int salt) - { - value = value * _multipleValue + secretKey[_index1]; - value ^= _xorValue ^ salt; - uint part1 = (uint)value << _rotateBitNum; - uint part2 = (uint)value >> (32 - _rotateBitNum); - value = (int)(part1 | part2); - return value; - } - - public override int Decrypt(int value, int[] secretKey, int salt) - { - uint value2 = (uint)value >> _rotateBitNum; - uint part1 = (uint)value << (32 - _rotateBitNum); - value = (int)(value2 | part1); - value ^= _xorValue ^ salt; - value = (value - secretKey[_index1]) * _revertMultipleValue; - return value; - } - - public override void GenerateEncryptCode(List lines, string indent) - { - lines.Add(indent + $"value = value * {_multipleValue} + _secretKey[{_index1}];"); - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};"); - lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(part1 | part2);"); - } - - public override void GenerateDecryptCode(List lines, string indent) - { - lines.Add(indent + $"uint value2 = (uint)value >> {_rotateBitNum};"); - lines.Add(indent + $"uint part1 = (uint)value << (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(value2 | part1);"); - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - lines.Add(indent + $"value = (value - _secretKey[{_index1}]) * {_revertMultipleValue};"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleXorRotateInstruction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleXorRotateInstruction.cs.meta deleted file mode 100644 index 0e6a6534..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/MultipleXorRotateInstruction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: adc3dcde66795744fa4bdc753a2c599f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorAddRotateInstruction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorAddRotateInstruction.cs deleted file mode 100644 index 97cc6e43..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorAddRotateInstruction.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM.Instructions -{ - public class XorAddRotateInstruction : EncryptionInstructionBase - { - // x = x ^ p3 ^ salt; - // x = x + p1 + secretKey[index1]; - // x = Rotate(x, p2) - - private readonly int _addValue; - private readonly int _index1; - private readonly int _rotateBitNum; - private readonly int _xorValue; - - public XorAddRotateInstruction(int xorValue, int addValue, int index1, int rotateBitNum) - { - _addValue = addValue; - _index1 = index1; - _rotateBitNum = rotateBitNum; - _xorValue = xorValue; - } - - public override int Encrypt(int value, int[] secretKey, int salt) - { - value ^= _xorValue ^ salt; - value += _addValue + secretKey[_index1]; - uint part1 = (uint)value << _rotateBitNum; - uint part2 = (uint)value >> (32 - _rotateBitNum); - value = (int)(part1 | part2); - return value; - } - - public override int Decrypt(int value, int[] secretKey, int salt) - { - uint value2 = (uint)value >> _rotateBitNum; - uint part1 = (uint)value << (32 - _rotateBitNum); - value = (int)(value2 | part1); - value -= _addValue + secretKey[_index1]; - value ^= _xorValue ^ salt; - return value; - } - - public override void GenerateEncryptCode(List lines, string indent) - { - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - lines.Add(indent + $"value += {_addValue} + _secretKey[{_index1}];"); - lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};"); - lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(part1 | part2);"); - } - - public override void GenerateDecryptCode(List lines, string indent) - { - lines.Add(indent + $"uint value2 = (uint)value >> {_rotateBitNum};"); - lines.Add(indent + $"uint part1 = (uint)value << (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(value2 | part1);"); - lines.Add(indent + $"value -= {_addValue} + _secretKey[{_index1}];"); - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorAddRotateInstruction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorAddRotateInstruction.cs.meta deleted file mode 100644 index d1a6d086..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorAddRotateInstruction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ad8f4dd724d7ff845b0dd65861054d37 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorInstruction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorInstruction.cs deleted file mode 100644 index 353a4f6f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorInstruction.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM.Instructions -{ - public class XorInstruction : EncryptionInstructionBase - { - private readonly int _xorValue; - private readonly int _opKeyIndex; - - public XorInstruction(int xorValue, int opKeyIndex) - { - _xorValue = xorValue; - _opKeyIndex = opKeyIndex; - } - - public override int Encrypt(int value, int[] secretKey, int salt) - { - return ((value ^ secretKey[_opKeyIndex]) + salt) ^ _xorValue; - } - - public override int Decrypt(int value, int[] secretKey, int salt) - { - return ((value ^ _xorValue) - salt) ^ secretKey[_opKeyIndex]; - } - - public override void GenerateEncryptCode(List lines, string indent) - { - lines.Add(indent + $"value = ((value ^ _secretKey[{_opKeyIndex}]) + salt) ^ {_xorValue};"); - } - - public override void GenerateDecryptCode(List lines, string indent) - { - lines.Add(indent + $"value = ((value ^ {_xorValue}) - salt) ^ _secretKey[{_opKeyIndex}];"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorInstruction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorInstruction.cs.meta deleted file mode 100644 index e246896d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorInstruction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2f16dd868e4473b45bfa9daaf7fabaf8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorMultipleRotateInstruction.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorMultipleRotateInstruction.cs deleted file mode 100644 index ab823312..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorMultipleRotateInstruction.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM.Instructions -{ - public class XorMultipleRotateInstruction : EncryptionInstructionBase - { - // x = x ^ p3 ^ salt; - // x = x * p1 + secretKey[index1]; - // x = Rotate(x, p2) - - private readonly int _multipleValue; - private readonly int _revertMultipleValue; - private readonly int _index1; - private readonly int _rotateBitNum; - private readonly int _xorValue; - - public XorMultipleRotateInstruction(int xorValue, int multipleValue, int index1, int rotateBitNum) - { - _multipleValue = multipleValue; - _revertMultipleValue = MathUtil.ModInverse32(multipleValue); - _index1 = index1; - _rotateBitNum = rotateBitNum; - _xorValue = xorValue; - } - - public override int Encrypt(int value, int[] secretKey, int salt) - { - value ^= _xorValue ^ salt; - value = value * _multipleValue + secretKey[_index1]; - uint part1 = (uint)value << _rotateBitNum; - uint part2 = (uint)value >> (32 - _rotateBitNum); - value = (int)(part1 | part2); - return value; - } - - public override int Decrypt(int value, int[] secretKey, int salt) - { - uint value2 = (uint)value >> _rotateBitNum; - uint part1 = (uint)value << (32 - _rotateBitNum); - value = (int)(value2 | part1); - value = (value - secretKey[_index1]) * _revertMultipleValue; - value ^= _xorValue ^ salt; - return value; - } - - public override void GenerateEncryptCode(List lines, string indent) - { - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - lines.Add(indent + $"value = value * {_multipleValue} + _secretKey[{_index1}];"); - lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};"); - lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(part1 | part2);"); - } - - public override void GenerateDecryptCode(List lines, string indent) - { - lines.Add(indent + $"uint value2 = (uint)value >> {_rotateBitNum};"); - lines.Add(indent + $"uint part1 = (uint)value << (32 - {_rotateBitNum});"); - lines.Add(indent + $"value = (int)(value2 | part1);"); - lines.Add(indent + $"value = (value - _secretKey[{_index1}]) * {_revertMultipleValue};"); - lines.Add(indent + $"value ^= {_xorValue} ^ salt;"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorMultipleRotateInstruction.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorMultipleRotateInstruction.cs.meta deleted file mode 100644 index e95af06a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/Instructions/XorMultipleRotateInstruction.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3eb7e6d475cfc14459d3850c5964ba52 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachine.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachine.cs deleted file mode 100644 index 1ca1a598..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachine.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Obfuz.EncryptionVM -{ - public class VirtualMachine - { - public const int SecretKeyLength = 1024; - - public readonly int version; - public readonly string codeGenerationSecretKey; - public readonly EncryptionInstructionWithOpCode[] opCodes; - - public VirtualMachine(int version, string codeGenerationSecretKey, EncryptionInstructionWithOpCode[] opCodes) - { - this.codeGenerationSecretKey = codeGenerationSecretKey; - this.opCodes = opCodes; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachine.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachine.cs.meta deleted file mode 100644 index e932d330..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachine.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c6970e037654dcb49912783a40f3e1ba -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCodeGenerator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCodeGenerator.cs deleted file mode 100644 index f12d3688..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCodeGenerator.cs +++ /dev/null @@ -1,203 +0,0 @@ -using Obfuz.Utils; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Text.RegularExpressions; -using UnityEngine; - -namespace Obfuz.EncryptionVM -{ - public class VirtualMachineCodeGenerator - { - private readonly int _opCodeCount; - private readonly int _opCodeBits; - private readonly VirtualMachine _vm; - - public VirtualMachineCodeGenerator(string vmCodeGenerateSecretKey, int opCodeCount) - { - _opCodeCount = opCodeCount; - _opCodeBits = EncryptionUtil.GetBitCount(opCodeCount - 1); - _vm = new VirtualMachineCreator(vmCodeGenerateSecretKey).CreateVirtualMachine(opCodeCount); - } - - public VirtualMachineCodeGenerator(VirtualMachine vm) - { - _opCodeCount = vm.opCodes.Length; - _opCodeBits = EncryptionUtil.GetBitCount(_opCodeCount - 1); - _vm = vm; - } - - - public bool ValidateMatch(string outputFile) - { - if (!File.Exists(outputFile)) - { - return false; - } - string oldCode = NormalizeText(File.ReadAllText(outputFile, Encoding.UTF8)); - string newCode = NormalizeText(GenerateCode()); - return oldCode == newCode; - } - - private static string NormalizeText(string input) - { - return Regex.Replace(input, @"\s+", string.Empty); - } - - public void Generate(string outputFile) - { - FileUtil.CreateParentDir(outputFile); - - string code = GenerateCode(); - - File.WriteAllText(outputFile, code, Encoding.UTF8); - Debug.Log($"Generate EncryptionVM code to {outputFile}"); - } - - private string GenerateCode() - { - var lines = new List(); - AppendHeader(lines); - AppendEncryptCodes(lines); - AppendDecryptCodes(lines); - AppendTailer(lines); - return string.Join("\n", lines); - } - - private void AppendEncryptCodes(List lines) - { - lines.Add(@" - private int ExecuteEncrypt(int value, int opCode, int salt) - { - switch (opCode) - {"); - foreach (var opCode in _vm.opCodes) - { - lines.Add($@" case {opCode.code}: - {{ - // {opCode.function.GetType().Name}"); - AppendEncryptCode(lines, opCode.function); - lines.Add(@" return value; - }"); - } - - lines.Add(@" - default: - throw new System.Exception($""Invalid opCode:{opCode}""); - } - }"); - } - - private void AppendDecryptCodes(List lines) - { - lines.Add(@" - private int ExecuteDecrypt(int value, int opCode, int salt) - { - switch (opCode) - {"); - foreach (var opCode in _vm.opCodes) - { - lines.Add($@" case {opCode.code}: - {{ - // {opCode.function.GetType().Name}"); - AppendDecryptCode(lines, opCode.function); - lines.Add(@" return value; - }"); - } - - lines.Add(@" - default: - throw new System.Exception($""Invalid opCode:{opCode}""); - } - }"); - } - - private void AppendHeader(List lines) - { - - lines.Add($"/// This file is auto-generated by Obfuz. Do not modify it."); - lines.Add($"///"); - //lines.Add($"/// Created Time: {DateTime.Now}"); - - lines.Add($"/// Version: {_vm.version}"); - lines.Add($"/// SecretKey: {_vm.codeGenerationSecretKey}"); - lines.Add($"/// OpCodeCount: {_vm.opCodes.Length}"); - - lines.Add(@" -namespace Obfuz.EncryptionVM -{ - public class GeneratedEncryptionVirtualMachine : Obfuz.EncryptorBase - {"); - lines.Add($@" - private const int kOpCodeBits = {_opCodeBits}; - - private const int kOpCodeCount = {_opCodeCount}; - - private const int kOpCodeMask = {_opCodeCount - 1}; -"); - lines.Add(@" - - private readonly int[] _secretKey; - - public GeneratedEncryptionVirtualMachine(byte[] secretKey) - { - this._secretKey = ConvertToIntKey(secretKey); - } - - public override int OpCodeCount => kOpCodeCount; - - public override int Encrypt(int value, int opts, int salt) - { - uint uopts = (uint)opts; - uint revertOps = 0; - while (uopts != 0) - { - uint opCode = uopts & kOpCodeMask; - revertOps <<= kOpCodeBits; - revertOps |= opCode; - uopts >>= kOpCodeBits; - } - - while (revertOps != 0) - { - uint opCode = revertOps & kOpCodeMask; - value = ExecuteEncrypt(value, (int)opCode, salt); - revertOps >>= kOpCodeBits; - } - return value; - } - - public override int Decrypt(int value, int opts, int salt) - { - uint uopts = (uint)opts; - while (uopts != 0) - { - uint opCode = uopts & kOpCodeMask; - value = ExecuteDecrypt(value, (int)opCode, salt); - uopts >>= kOpCodeBits; - } - return value; - } -"); - } - - private void AppendTailer(List lines) - { - lines.Add(@" - } -} - -"); - } - - private void AppendEncryptCode(List lines, IEncryptionInstruction instruction) - { - instruction.GenerateEncryptCode(lines, " "); - } - - private void AppendDecryptCode(List lines, IEncryptionInstruction instruction) - { - instruction.GenerateDecryptCode(lines, " "); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCodeGenerator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCodeGenerator.cs.meta deleted file mode 100644 index 956402cb..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCodeGenerator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2246e9d3369eb3c45bc19ae0748d76ba -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCreator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCreator.cs deleted file mode 100644 index e0fca883..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCreator.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Obfuz.EncryptionVM.Instructions; -using Obfuz.Utils; -using System; -using System.Collections.Generic; - -namespace Obfuz.EncryptionVM -{ - public class VirtualMachineCreator - { - private readonly string _vmGenerationSecretKey; - private readonly IRandom _random; - - public const int CodeGenerationSecretKeyLength = 1024; - - public const int VirtualMachineVersion = 1; - - public VirtualMachineCreator(string vmGenerationSecretKey) - { - _vmGenerationSecretKey = vmGenerationSecretKey; - byte[] byteGenerationSecretKey = KeyGenerator.GenerateKey(vmGenerationSecretKey, CodeGenerationSecretKeyLength); - int[] intGenerationSecretKey = KeyGenerator.ConvertToIntKey(byteGenerationSecretKey); - _random = new RandomWithKey(intGenerationSecretKey, 0); - } - - private readonly List> _instructionCreators = new List> - { - (r, len) => new AddInstruction(r.NextInt(), r.NextInt(len)), - (r, len) => new XorInstruction(r.NextInt(), r.NextInt(len)), - (r, len) => new BitRotateInstruction(r.NextInt(32), r.NextInt(len)), - (r, len) => new MultipleInstruction(r.NextInt() | 0x1, r.NextInt(len)), - (r, len) => new AddRotateXorInstruction(r.NextInt(), r.NextInt(len), r.NextInt(32), r.NextInt()), - (r, len) => new AddXorRotateInstruction(r.NextInt(), r.NextInt(len), r.NextInt(), r.NextInt(32)), - (r, len) => new XorAddRotateInstruction(r.NextInt(), r.NextInt(), r.NextInt(len), r.NextInt(32)), - (r, len) => new MultipleRotateXorInstruction(r.NextInt() | 0x1, r.NextInt(len), r.NextInt(32), r.NextInt()), - (r, len) => new MultipleXorRotateInstruction(r.NextInt() | 0x1, r.NextInt(len), r.NextInt(), r.NextInt(32)), - (r, len) => new XorMultipleRotateInstruction(r.NextInt(), r.NextInt() | 0x1, r.NextInt(len), r.NextInt(32)), - }; - - private IEncryptionInstruction CreateRandomInstruction(int intSecretKeyLength) - { - return _instructionCreators[_random.NextInt(_instructionCreators.Count)](_random, intSecretKeyLength); - } - - private EncryptionInstructionWithOpCode CreateEncryptOpCode(ushort code) - { - IEncryptionInstruction inst = CreateRandomInstruction(VirtualMachine.SecretKeyLength / sizeof(int)); - return new EncryptionInstructionWithOpCode(code, inst); - } - - public VirtualMachine CreateVirtualMachine(int opCodeCount) - { - if (opCodeCount < 64) - { - throw new System.Exception("OpCode count should be >= 64"); - } - if ((opCodeCount & (opCodeCount - 1)) != 0) - { - throw new System.Exception("OpCode count should be power of 2"); - } - var opCodes = new EncryptionInstructionWithOpCode[opCodeCount]; - for (int i = 0; i < opCodes.Length; i++) - { - opCodes[i] = CreateEncryptOpCode((ushort)i); - } - return new VirtualMachine(VirtualMachineVersion, _vmGenerationSecretKey, opCodes); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCreator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCreator.cs.meta deleted file mode 100644 index 3124bb7b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineCreator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 77d95ff5cf0b3aa4e96a055e37c381ba -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineSimulator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineSimulator.cs deleted file mode 100644 index 175881f2..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineSimulator.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Obfuz.Utils; -using System.Collections.Generic; -using UnityEngine.Assertions; - -namespace Obfuz.EncryptionVM -{ - - public class VirtualMachineSimulator : EncryptorBase - { - private readonly EncryptionInstructionWithOpCode[] _opCodes; - private readonly int[] _secretKey; - - public override int OpCodeCount => _opCodes.Length; - - public VirtualMachineSimulator(VirtualMachine vm, byte[] byteSecretKey) - { - _opCodes = vm.opCodes; - _secretKey = KeyGenerator.ConvertToIntKey(byteSecretKey); - - VerifyInstructions(); - } - - private void VerifyInstructions() - { - int value = 0x11223344; - for (int i = 0; i < _opCodes.Length; i++) - { - int encryptedValue = _opCodes[i].Encrypt(value, _secretKey, i); - int decryptedValue = _opCodes[i].Decrypt(encryptedValue, _secretKey, i); - //Debug.Log($"instruction type:{_opCodes[i].function.GetType()}"); - Assert.AreEqual(value, decryptedValue); - } - - int ops = 11223344; - int salt = 789; - Assert.AreEqual(1, Decrypt(Encrypt(1, ops, salt), ops, salt)); - Assert.AreEqual(1L, Decrypt(Encrypt(1L, ops, salt), ops, salt)); - Assert.AreEqual(1.0f, Decrypt(Encrypt(1.0f, ops, salt), ops, salt)); - Assert.AreEqual(1.0, Decrypt(Encrypt(1.0, ops, salt), ops, salt)); - - byte[] strBytes = Encrypt("abcdef", ops, salt); - Assert.AreEqual("abcdef", DecryptString(strBytes, 0, strBytes.Length, ops, salt)); - var arr = new byte[100]; - for (int i = 0; i < arr.Length; i++) - { - arr[i] = (byte)i; - } - EncryptBlock(arr, ops, salt); - DecryptBlock(arr, ops, salt); - for (int i = 0; i < arr.Length; i++) - { - Assert.AreEqual(i, arr[i]); - } - } - - private List DecodeOps(uint ops) - { - var codes = new List(); - while (ops != 0) - { - uint code = ops % (uint)_opCodes.Length; - codes.Add(code); - ops /= (uint)_opCodes.Length; - } - return codes; - } - - public override int Encrypt(int value, int ops, int salt) - { - var codes = DecodeOps((uint)ops); - for (int i = codes.Count - 1; i >= 0; i--) - { - var opCode = _opCodes[codes[i]]; - value = opCode.Encrypt(value, _secretKey, salt); - } - return value; - } - - public override int Decrypt(int value, int ops, int salt) - { - var codes = DecodeOps((uint)ops); - foreach (var code in codes) - { - var opCode = _opCodes[code]; - value = opCode.Decrypt(value, _secretKey, salt); - } - return value; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineSimulator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineSimulator.cs.meta deleted file mode 100644 index 532a4985..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/EncryptionVM/VirtualMachineSimulator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4f86f4d6faf49764a915d5c675091375 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration.meta deleted file mode 100644 index 29fa1339..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f47f2abd9eb7ba8469ba5cb1bb085d33 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ConfigGarbageCodeGenerator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ConfigGarbageCodeGenerator.cs deleted file mode 100644 index 06a7aebb..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ConfigGarbageCodeGenerator.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Obfuz.Utils; -using System; -using System.Linq; -using System.Text; - -namespace Obfuz.GarbageCodeGeneration -{ - - public class ConfigGarbageCodeGenerator : SpecificGarbageCodeGeneratorBase - { - - private readonly string[] _types = new string[] - { - "bool", - "byte", - "short", - "int", - "long", - "float", - "double", - }; - - private string CreateRandomType(IRandom random) - { - return _types[random.NextInt(_types.Length)]; - } - - private string GetReadMethodNameOfType(string type) - { - switch (type) - { - case "bool": return "ReadBoolean"; - case "byte": return "ReadByte"; - case "short": return "ReadInt16"; - case "int": return "ReadInt32"; - case "long": return "ReadInt64"; - case "float": return "ReadSingle"; - case "double": return "ReadDouble"; - default: throw new ArgumentException($"Unsupported type: {type}"); - } - } - class FieldGenerationInfo - { - public int index; - public string name; - public string type; - } - - class MethodGenerationInfo - { - public int index; - public string name; - } - - protected override object CreateField(int index, IRandom random, GenerationParameters parameters) - { - return new FieldGenerationInfo - { - index = index, - name = $"x{index}", - type = CreateRandomType(random), - }; - } - - protected override object CreateMethod(int index, IRandom random, GenerationParameters parameters) - { - return new MethodGenerationInfo - { - index = index, - name = $"Load{index}", - }; - } - - protected override void GenerateUsings(StringBuilder result, IClassGenerationInfo cgi) - { - } - - protected override void GenerateField(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object field, string indent) - { - var fgi = (FieldGenerationInfo)field; - result.AppendLine($"{indent}public {fgi.type} {fgi.name};"); - } - - protected override void GenerateMethod(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object method, string indent) - { - var mgi = (MethodGenerationInfo)method; - result.AppendLine($"{indent}public void {mgi.name}(BinaryReader reader)"); - result.AppendLine($"{indent}{{"); - - string indent2 = indent + " "; - result.AppendLine($"{indent2}int a = 0;"); - result.AppendLine($"{indent2}int b = 0;"); - int maxN = 100; - var shuffledFields = cgi.Fields.ToList(); - RandomUtil.ShuffleList(shuffledFields, random); - foreach (FieldGenerationInfo fgi in shuffledFields) - { - result.AppendLine($"{indent2}this.{fgi.name} = reader.{GetReadMethodNameOfType(fgi.type)}();"); - if (random.NextInPercentage(0.5f)) - { - result.AppendLine($"{indent2}a = b * {random.NextInt(maxN)} + reader.ReadInt32();"); - result.AppendLine($"{indent2}b = a * reader.ReadInt32() + {random.NextInt(maxN)};"); - } - if (random.NextInPercentage(0.5f)) - { - result.AppendLine($"{indent2}a += {random.NextInt(0, 10000)};"); - } - if (random.NextInPercentage(0.5f)) - { - result.AppendLine($"{indent2}b += {random.NextInt(0, 10000)};"); - } - } - - result.AppendLine($"{indent}}}"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ConfigGarbageCodeGenerator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ConfigGarbageCodeGenerator.cs.meta deleted file mode 100644 index c47c0405..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ConfigGarbageCodeGenerator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 327cb4a465ff23944a5fea30bf3beeeb -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/GarbageCodeGenerator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/GarbageCodeGenerator.cs deleted file mode 100644 index 2b00c446..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/GarbageCodeGenerator.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Obfuz.Settings; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using UnityEngine; - -namespace Obfuz.GarbageCodeGeneration -{ - - public class GarbageCodeGenerator - { - private const int CodeGenerationSecretKeyLength = 1024; - - private readonly GarbageCodeGenerationSettings _settings; - private readonly int[] _intGenerationSecretKey; - - public GarbageCodeGenerator(GarbageCodeGenerationSettings settings) - { - _settings = settings; - - byte[] byteGenerationSecretKey = KeyGenerator.GenerateKey(settings.codeGenerationSecret, CodeGenerationSecretKeyLength); - _intGenerationSecretKey = KeyGenerator.ConvertToIntKey(byteGenerationSecretKey); - } - - public void Generate() - { - GenerateTask(_settings.defaultTask); - if (_settings.additionalTasks != null && _settings.additionalTasks.Length > 0) - { - foreach (var task in _settings.additionalTasks) - { - GenerateTask(task); - } - } - } - - public void CleanCodes() - { - Debug.Log($"Cleaning generated garbage codes begin."); - if (_settings.defaultTask != null) - { - FileUtil.RemoveDir(_settings.defaultTask.outputPath, true); - } - if (_settings.additionalTasks != null && _settings.additionalTasks.Length > 0) - { - foreach (var task in _settings.additionalTasks) - { - FileUtil.RemoveDir(task.outputPath, true); - } - } - } - - private void GenerateTask(GarbageCodeGenerationTask task) - { - Debug.Log($"Generating garbage code with seed: {task.codeGenerationRandomSeed}, class count: {task.classCount}, method count per class: {task.methodCountPerClass}, types: {task.garbageCodeType}, output path: {task.outputPath}"); - - if (string.IsNullOrWhiteSpace(task.outputPath)) - { - throw new Exception("outputPath of GarbageCodeGenerationTask is empty!"); - } - - var generator = CreateSpecificCodeGenerator(task.garbageCodeType); - - var parameters = new GenerationParameters - { - random = new RandomWithKey(_intGenerationSecretKey, task.codeGenerationRandomSeed), - classNamespace = task.classNamespace, - classNamePrefix = task.classNamePrefix, - classCount = task.classCount, - methodCountPerClass = task.methodCountPerClass, - fieldCountPerClass = task.fieldCountPerClass, - outputPath = task.outputPath, - }; - generator.Generate(parameters); - - Debug.Log($"Generate garbage code end."); - } - - private ISpecificGarbageCodeGenerator CreateSpecificCodeGenerator(GarbageCodeType type) - { - switch (type) - { - case GarbageCodeType.Config: return new ConfigGarbageCodeGenerator(); - case GarbageCodeType.UI: return new UIGarbageCodeGenerator(); - default: throw new NotSupportedException($"Garbage code type {type} is not supported."); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/GarbageCodeGenerator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/GarbageCodeGenerator.cs.meta deleted file mode 100644 index 4939c45d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/GarbageCodeGenerator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ff64fd1e6f7b8874db5a5228fab159f9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ISpecificGarbageCodeGenerator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ISpecificGarbageCodeGenerator.cs deleted file mode 100644 index 9deda5cc..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ISpecificGarbageCodeGenerator.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Obfuz.Settings; -using Obfuz.Utils; - -namespace Obfuz.GarbageCodeGeneration -{ - public class GenerationParameters - { - public IRandom random; - - public string classNamespace; - public string classNamePrefix; - public int classCount; - public int methodCountPerClass; - public int fieldCountPerClass; - public string outputPath; - } - - public interface ISpecificGarbageCodeGenerator - { - void Generate(GenerationParameters parameters); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ISpecificGarbageCodeGenerator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ISpecificGarbageCodeGenerator.cs.meta deleted file mode 100644 index 9cb265c7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/ISpecificGarbageCodeGenerator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 74a17802b5aab2e40a3c89e0ddbcec0d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/SpecificGarbageCodeGeneratorBase.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/SpecificGarbageCodeGeneratorBase.cs deleted file mode 100644 index c237343f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/SpecificGarbageCodeGeneratorBase.cs +++ /dev/null @@ -1,106 +0,0 @@ -using Obfuz.Utils; -using System.Collections.Generic; -using System.IO; -using System.Text; -using UnityEngine; - -namespace Obfuz.GarbageCodeGeneration -{ - public abstract class SpecificGarbageCodeGeneratorBase : ISpecificGarbageCodeGenerator - { - protected interface IClassGenerationInfo - { - string Namespace { get; set; } - - string Name { get; set; } - - IList Fields { get; set; } - - IList Methods { get; set; } - } - - protected class ClassGenerationInfo : IClassGenerationInfo - { - public string Namespace { get; set; } - public string Name { get; set; } - public IList Fields { get; set; } = new List(); - public IList Methods { get; set; } = new List(); - } - - public virtual void Generate(GenerationParameters parameters) - { - FileUtil.RecreateDir(parameters.outputPath); - - for (int i = 0; i < parameters.classCount; i++) - { - Debug.Log($"[{GetType().Name}] Generating class {i}"); - var localRandom = new RandomWithKey(((RandomWithKey)parameters.random).Key, parameters.random.NextInt()); - string outputFile = $"{parameters.outputPath}/__GeneratedGarbageClass_{i}.cs"; - var result = new StringBuilder(64 * 1024); - GenerateClass(i, localRandom, result, parameters); - File.WriteAllText(outputFile, result.ToString(), Encoding.UTF8); - Debug.Log($"[{GetType().Name}] Generated class {i} to {outputFile}"); - } - } - - protected abstract object CreateField(int index, IRandom random, GenerationParameters parameters); - - protected abstract object CreateMethod(int index, IRandom random, GenerationParameters parameters); - - protected virtual IClassGenerationInfo CreateClassGenerationInfo(string classNamespace, string className, IRandom random, GenerationParameters parameters) - { - var cgi = new ClassGenerationInfo - { - Namespace = classNamespace, - Name = className, - }; - - for (int i = 0; i < parameters.fieldCountPerClass; i++) - { - cgi.Fields.Add(CreateField(i, random, parameters)); - } - - for (int i = 0; i < parameters.methodCountPerClass; i++) - { - cgi.Methods.Add(CreateMethod(i, random, parameters)); - } - - return cgi; - } - - protected virtual void GenerateClass(int classIndex, IRandom random, StringBuilder result, GenerationParameters parameters) - { - IClassGenerationInfo cgi = CreateClassGenerationInfo(parameters.classNamespace, $"{parameters.classNamePrefix}{classIndex}", random, parameters); - result.AppendLine("using System;"); - result.AppendLine("using System.Collections.Generic;"); - result.AppendLine("using System.Linq;"); - result.AppendLine("using System.IO;"); - result.AppendLine("using UnityEngine;"); - - GenerateUsings(result, cgi); - - result.AppendLine($"namespace {cgi.Namespace}"); - result.AppendLine("{"); - result.AppendLine($" public class {cgi.Name}"); - result.AppendLine(" {"); - - string indent = " "; - foreach (object field in cgi.Fields) - { - GenerateField(result, cgi, random, field, indent); - } - foreach (object method in cgi.Methods) - { - GenerateMethod(result, cgi, random, method, indent); - } - result.AppendLine(" }"); - result.AppendLine("}"); - } - - protected abstract void GenerateUsings(StringBuilder result, IClassGenerationInfo cgi); - - protected abstract void GenerateField(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object field, string indent); - - protected abstract void GenerateMethod(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object method, string indent); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/SpecificGarbageCodeGeneratorBase.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/SpecificGarbageCodeGeneratorBase.cs.meta deleted file mode 100644 index 7696864a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/SpecificGarbageCodeGeneratorBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bae18fd49482f00439d37f28a6a78d9b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/UIGarbageCodeGenerator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/UIGarbageCodeGenerator.cs deleted file mode 100644 index 7287dce7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/UIGarbageCodeGenerator.cs +++ /dev/null @@ -1,157 +0,0 @@ -using Obfuz.Utils; -using System; -using System.Linq; -using System.Text; - -namespace Obfuz.GarbageCodeGeneration -{ - - public class UIGarbageCodeGenerator : SpecificGarbageCodeGeneratorBase - { - /* - * - * public Button b1; - public Image b2; - public RawImage b30; - public Text b3; - public Slider b4; - public ScrollRect b5; - public Scrollbar b6; - public Mask b7; - public RectMask2D b70; - public Canvas b8; - public CanvasGroup b9; - public RectTransform b10; - public Transform b11; - public GameObject b12; - */ - - private readonly string[] _types = new string[] - { - "Button", - "Image", - "RawImage", - "Text", - "Slider", - "ScrollRect", - "Scrollbar", - "Mask", - "RectMask2D", - "Canvas", - "CanvasGroup", - "RectTransform", - //"Transform", - //"GameObject", - }; - - private string CreateRandomType(IRandom random) - { - return _types[random.NextInt(_types.Length)]; - } - - private string GetReadMethodNameOfType(string type) - { - switch (type) - { - case "bool": return "ReadBoolean"; - case "byte": return "ReadByte"; - case "short": return "ReadInt16"; - case "int": return "ReadInt32"; - case "long": return "ReadInt64"; - case "float": return "ReadSingle"; - case "double": return "ReadDouble"; - default: throw new ArgumentException($"Unsupported type: {type}"); - } - } - class FieldGenerationInfo - { - public int index; - public string name; - public string type; - } - - class MethodGenerationInfo - { - public int index; - public string name; - } - - protected override object CreateField(int index, IRandom random, GenerationParameters parameters) - { - return new FieldGenerationInfo - { - index = index, - name = $"x{index}", - type = CreateRandomType(random), - }; - } - - protected override object CreateMethod(int index, IRandom random, GenerationParameters parameters) - { - return new MethodGenerationInfo - { - index = index, - name = $"Init{index}", - }; - } - - protected override void GenerateUsings(StringBuilder result, IClassGenerationInfo cgi) - { - result.AppendLine("using UnityEngine.UI;"); - } - - protected override void GenerateField(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object field, string indent) - { - var fgi = (FieldGenerationInfo)field; - result.AppendLine($"{indent}public {fgi.type} {fgi.name};"); - } - - protected override void GenerateMethod(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object method, string indent) - { - var mgi = (MethodGenerationInfo)method; - result.AppendLine($"{indent}public void {mgi.name}(GameObject go)"); - result.AppendLine($"{indent}{{"); - - string indent2 = indent + " "; - result.AppendLine($"{indent2}int a = 0;"); - result.AppendLine($"{indent2}int b = 0;"); - int maxN = 100; - var shuffledFields = cgi.Fields.ToList(); - RandomUtil.ShuffleList(shuffledFields, random); - foreach (FieldGenerationInfo fgi in shuffledFields) - { - if (random.NextInPercentage(0.5f)) - { - result.AppendLine($"{indent2}this.{fgi.name} = go.transform.Find(\"ui/{fgi.name}\").GetComponent<{fgi.type}>();"); - } - else - { - result.AppendLine($"{indent2}this.{fgi.name} = go.GetComponent<{fgi.type}>();"); - } - if (random.NextInPercentage(0.5f)) - { - result.AppendLine($"{indent2}a = b * {random.NextInt(maxN)} + go.layer;"); - result.AppendLine($"{indent2}b = a * go.layer + {random.NextInt(maxN)};"); - } - if (random.NextInPercentage(0.5f)) - { - result.AppendLine($"{indent2}a *= {random.NextInt(0, 10000)};"); - } - if (random.NextInPercentage(0.5f)) - { - result.AppendLine($"{indent2}b /= {random.NextInt(0, 10000)};"); - } - if (random.NextInPercentage(0.5f)) - { - result.AppendLine($"{indent2}a = a * b << {random.NextInt(0, 10000)};"); - } - if (random.NextInPercentage(0.5f)) - { - result.AppendLine($"{indent2}b = a / b & {random.NextInt(0, 10000)};"); - } - } - - result.AppendLine($"{indent}}}"); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/UIGarbageCodeGenerator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/UIGarbageCodeGenerator.cs.meta deleted file mode 100644 index 1dc2d282..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/GarbageCodeGeneration/UIGarbageCodeGenerator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5071c4b9c7f5aef409f3e7fdb45ecd8d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/IObfuscationPass.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/IObfuscationPass.cs deleted file mode 100644 index 84c56f71..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/IObfuscationPass.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Obfuz.ObfusPasses; - -namespace Obfuz -{ - public interface IObfuscationPass - { - ObfuscationPassType Type { get; } - - void Start(); - - void Stop(); - - void Process(); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/IObfuscationPass.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/IObfuscationPass.cs.meta deleted file mode 100644 index cd501adc..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/IObfuscationPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b7003f9503025794b8aa775d9ade335c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses.meta deleted file mode 100644 index ed7f92c1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 120b2dcffd582e84dbb92003240824d1 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/BasicBlockObfuscationPassBase.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/BasicBlockObfuscationPassBase.cs deleted file mode 100644 index 2b7deb35..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/BasicBlockObfuscationPassBase.cs +++ /dev/null @@ -1,53 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Emit; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses -{ - public abstract class BasicBlockObfuscationPassBase : ObfuscationMethodPassBase - { - protected virtual bool ComputeBlockInLoop => true; - - protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, BasicBlock block, int instructionIndex, - IList globalInstructions, List outputInstructions, List totalFinalInstructions); - - protected override void ObfuscateData(MethodDef method) - { - BasicBlockCollection bbc = new BasicBlockCollection(method, ComputeBlockInLoop); - - IList instructions = method.Body.Instructions; - - var outputInstructions = new List(); - var totalFinalInstructions = new List(); - for (int i = 0; i < instructions.Count; i++) - { - Instruction inst = instructions[i]; - BasicBlock block = bbc.GetBasicBlockByInstruction(inst); - outputInstructions.Clear(); - if (TryObfuscateInstruction(method, inst, block, i, instructions, outputInstructions, totalFinalInstructions)) - { - // current instruction may be the target of control flow instruction, so we can't remove it directly. - // we replace it with nop now, then remove it in CleanUpInstructionPass - inst.OpCode = outputInstructions[0].OpCode; - inst.Operand = outputInstructions[0].Operand; - totalFinalInstructions.Add(inst); - for (int k = 1; k < outputInstructions.Count; k++) - { - totalFinalInstructions.Add(outputInstructions[k]); - } - } - else - { - totalFinalInstructions.Add(inst); - } - } - - instructions.Clear(); - foreach (var obInst in totalFinalInstructions) - { - instructions.Add(obInst); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/BasicBlockObfuscationPassBase.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/BasicBlockObfuscationPassBase.cs.meta deleted file mode 100644 index 027d02b9..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/BasicBlockObfuscationPassBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ae83aaf003665614092aabceabff3cf8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus.meta deleted file mode 100644 index a5ed3334..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: cf68e45551825c547b137f6e5189937e -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/CallObfusPass.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/CallObfusPass.cs deleted file mode 100644 index 6a099f91..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/CallObfusPass.cs +++ /dev/null @@ -1,166 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Emit; -using Obfuz.Settings; -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.CallObfus -{ - class ObfusMethodContext - { - public MethodDef method; - public LocalVariableAllocator localVariableAllocator; - public IRandom localRandom; - public EncryptionScopeInfo encryptionScope; - } - - public class CallObfusPass : ObfuscationMethodPassBase - { - public static CallObfuscationSettingsFacade CurrentSettings { get; private set; } - - private readonly CallObfuscationSettingsFacade _settings; - private readonly SpecialWhiteListMethodCalculator _specialWhiteListMethodCache; - - private IObfuscator _dynamicProxyObfuscator; - private IObfuscationPolicy _dynamicProxyPolicy; - - public override ObfuscationPassType Type => ObfuscationPassType.CallObfus; - - public CallObfusPass(CallObfuscationSettingsFacade settings) - { - _settings = settings; - CurrentSettings = settings; - - _specialWhiteListMethodCache = new SpecialWhiteListMethodCalculator(settings.obfuscateCallToMethodInMscorlib); - } - - public override void Stop() - { - _dynamicProxyObfuscator.Done(); - } - - public override void Start() - { - var ctx = ObfuscationPassContext.Current; - _dynamicProxyObfuscator = CreateObfuscator(ctx, _settings.proxyMode); - _dynamicProxyPolicy = new ConfigurableObfuscationPolicy(ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles); - } - - private IObfuscator CreateObfuscator(ObfuscationPassContext ctx, ProxyMode mode) - { - switch (mode) - { - case ProxyMode.Dispatch: - return new DispatchProxyObfuscator(ctx.moduleEntityManager); - case ProxyMode.Delegate: - return new DelegateProxyObfuscator(ctx.moduleEntityManager); - default: - throw new System.NotSupportedException($"Unsupported proxy mode: {mode}"); - } - } - - protected override void ObfuscateData(MethodDef method) - { - BasicBlockCollection bbc = new BasicBlockCollection(method, false); - - IList instructions = method.Body.Instructions; - - var outputInstructions = new List(); - var totalFinalInstructions = new List(); - - ObfuscationPassContext ctx = ObfuscationPassContext.Current; - var encryptionScope = ctx.moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module); - var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)); - var omc = new ObfusMethodContext - { - method = method, - localVariableAllocator = new LocalVariableAllocator(method), - localRandom = localRandom, - encryptionScope = encryptionScope, - }; - Instruction lastInst = null; - for (int i = 0; i < instructions.Count; i++) - { - Instruction inst = instructions[i]; - BasicBlock block = bbc.GetBasicBlockByInstruction(inst); - outputInstructions.Clear(); - if (TryObfuscateInstruction(method, lastInst, inst, outputInstructions, omc)) - { - // current instruction may be the target of control flow instruction, so we can't remove it directly. - // we replace it with nop now, then remove it in CleanUpInstructionPass - inst.OpCode = outputInstructions[0].OpCode; - inst.Operand = outputInstructions[0].Operand; - totalFinalInstructions.Add(inst); - for (int k = 1; k < outputInstructions.Count; k++) - { - totalFinalInstructions.Add(outputInstructions[k]); - } - } - else - { - totalFinalInstructions.Add(inst); - } - lastInst = inst; - } - - instructions.Clear(); - foreach (var obInst in totalFinalInstructions) - { - instructions.Add(obInst); - } - } - - protected override bool NeedObfuscateMethod(MethodDef method) - { - return _dynamicProxyPolicy.NeedObfuscateCallInMethod(method); - } - - private bool TryObfuscateInstruction(MethodDef callerMethod, Instruction lastInst, Instruction inst, List outputInstructions, ObfusMethodContext ctx) - { - IMethod calledMethod = inst.Operand as IMethod; - if (calledMethod == null || !calledMethod.IsMethod) - { - return false; - } - if (MetaUtil.ContainsContainsGenericParameter(calledMethod)) - { - return false; - } - - bool callVir; - switch (inst.OpCode.Code) - { - case Code.Call: - { - callVir = false; - break; - } - case Code.Callvirt: - { - if (lastInst != null && lastInst.OpCode.Code == Code.Constrained) - { - return false; - } - callVir = true; - break; - } - default: return false; - } - - - if (_specialWhiteListMethodCache.IsInWhiteList(calledMethod)) - { - return false; - } - - - if (!_dynamicProxyPolicy.NeedObfuscateCalledMethod(callerMethod, calledMethod, callVir)) - { - return false; - } - - return _dynamicProxyObfuscator.Obfuscate(callerMethod, calledMethod, callVir, outputInstructions); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/CallObfusPass.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/CallObfusPass.cs.meta deleted file mode 100644 index b15eb819..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/CallObfusPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 112178b770868274fb8119a4997a3420 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs deleted file mode 100644 index 57a30e58..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs +++ /dev/null @@ -1,300 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Conf; -using Obfuz.Settings; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Xml; - -namespace Obfuz.ObfusPasses.CallObfus -{ - public class ConfigurableObfuscationPolicy : ObfuscationPolicyBase - { - class WhiteListAssembly - { - public string name; - public NameMatcher nameMatcher; - public bool? obfuscate; - public List types = new List(); - } - - class WhiteListType - { - public string name; - public NameMatcher nameMatcher; - public bool? obfuscate; - public List methods = new List(); - } - - class WhiteListMethod - { - public string name; - public NameMatcher nameMatcher; - public bool? obfuscate; - } - - class ObfuscationRule : IRule - { - public ObfuscationLevel? obfuscationLevel; - - public void InheritParent(ObfuscationRule parentRule) - { - if (obfuscationLevel == null) - obfuscationLevel = parentRule.obfuscationLevel; - } - } - - class AssemblySpec : AssemblyRuleBase - { - } - - class TypeSpec : TypeRuleBase - { - } - - class MethodSpec : MethodRuleBase - { - - } - - private static readonly ObfuscationRule s_default = new ObfuscationRule() - { - obfuscationLevel = ObfuscationLevel.Basic, - }; - - private readonly XmlAssemblyTypeMethodRuleParser _configParser; - - private ObfuscationRule _global; - private readonly List _whiteListAssemblies = new List(); - - private readonly CachedDictionary _whiteListMethodCache; - private readonly Dictionary _methodRuleCache = new Dictionary(); - - public ConfigurableObfuscationPolicy(List toObfuscatedAssemblyNames, List xmlConfigFiles) - { - _whiteListMethodCache = new CachedDictionary(MethodEqualityComparer.CompareDeclaringTypes, this.ComputeIsInWhiteList); - _configParser = new XmlAssemblyTypeMethodRuleParser(toObfuscatedAssemblyNames, - ParseObfuscationRule, ParseGlobalElement); - LoadConfigs(xmlConfigFiles); - } - - private void LoadConfigs(List configFiles) - { - _configParser.LoadConfigs(configFiles); - - if (_global == null) - { - _global = s_default; - } - else - { - _global.InheritParent(s_default); - } - _configParser.InheritParentRules(_global); - InheritWhitelistRules(); - } - - private void InheritWhitelistRules() - { - foreach (var ass in _whiteListAssemblies) - { - foreach (var type in ass.types) - { - if (type.obfuscate == null) - { - type.obfuscate = ass.obfuscate; - } - foreach (var method in type.methods) - { - if (method.obfuscate == null) - { - method.obfuscate = type.obfuscate; - } - } - } - } - } - - private void ParseGlobalElement(string configFile, XmlElement ele) - { - switch (ele.Name) - { - case "global": _global = ParseObfuscationRule(configFile, ele); break; - case "whitelist": ParseWhitelist(ele); break; - default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}"); - } - } - - private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) - { - var rule = new ObfuscationRule(); - if (ele.HasAttribute("obfuscationLevel")) - { - rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); - } - return rule; - } - - private void ParseWhitelist(XmlElement ruleEle) - { - foreach (XmlNode xmlNode in ruleEle.ChildNodes) - { - if (!(xmlNode is XmlElement childEle)) - { - continue; - } - switch (childEle.Name) - { - case "assembly": - { - var ass = ParseWhiteListAssembly(childEle); - _whiteListAssemblies.Add(ass); - break; - } - default: throw new Exception($"Invalid xml file, unknown node {childEle.Name}"); - } - } - } - - private WhiteListAssembly ParseWhiteListAssembly(XmlElement element) - { - var ass = new WhiteListAssembly(); - ass.name = element.GetAttribute("name"); - ass.nameMatcher = new NameMatcher(ass.name); - - ass.obfuscate = ConfigUtil.ParseNullableBool(element.GetAttribute("obfuscate")) ?? false; - - foreach (XmlNode node in element.ChildNodes) - { - if (!(node is XmlElement ele)) - { - continue; - } - switch (ele.Name) - { - case "type": - ass.types.Add(ParseWhiteListType(ele)); - break; - default: - throw new Exception($"Invalid xml file, unknown node {ele.Name}"); - } - } - return ass; - } - - private WhiteListType ParseWhiteListType(XmlElement element) - { - var type = new WhiteListType(); - type.name = element.GetAttribute("name"); - type.nameMatcher = new NameMatcher(type.name); - type.obfuscate = ConfigUtil.ParseNullableBool(element.GetAttribute("obfuscate")); - - foreach (XmlNode node in element.ChildNodes) - { - if (!(node is XmlElement ele)) - { - continue; - } - switch (ele.Name) - { - case "method": - { - type.methods.Add(ParseWhiteListMethod(ele)); - break; - } - default: throw new Exception($"Invalid xml file, unknown node {ele.Name}"); - } - } - - return type; - } - - private WhiteListMethod ParseWhiteListMethod(XmlElement element) - { - var method = new WhiteListMethod(); - method.name = element.GetAttribute("name"); - method.nameMatcher = new NameMatcher(method.name); - method.obfuscate = ConfigUtil.ParseNullableBool(element.GetAttribute("obfuscate")); - return method; - } - - private ObfuscationRule GetMethodObfuscationRule(MethodDef method) - { - if (!_methodRuleCache.TryGetValue(method, out var rule)) - { - rule = _configParser.GetMethodRule(method, _global); - _methodRuleCache[method] = rule; - } - return rule; - } - - public override bool NeedObfuscateCallInMethod(MethodDef method) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - return rule.obfuscationLevel != null && rule.obfuscationLevel.Value >= ObfuscationLevel.Basic; - } - - private bool ComputeIsInWhiteList(IMethod calledMethod) - { - ITypeDefOrRef declaringType = calledMethod.DeclaringType; - TypeSig declaringTypeSig = calledMethod.DeclaringType.ToTypeSig(); - declaringTypeSig = declaringTypeSig.RemovePinnedAndModifiers(); - switch (declaringTypeSig.ElementType) - { - case ElementType.ValueType: - case ElementType.Class: - { - break; - } - case ElementType.GenericInst: - { - if (MetaUtil.ContainsContainsGenericParameter(calledMethod)) - { - return true; - } - break; - } - default: return true; - } - - TypeDef typeDef = declaringType.ResolveTypeDef(); - - string assName = typeDef.Module.Assembly.Name; - string typeFullName = typeDef.FullName; - string methodName = calledMethod.Name; - foreach (var ass in _whiteListAssemblies) - { - if (!ass.nameMatcher.IsMatch(assName)) - { - continue; - } - foreach (var type in ass.types) - { - if (!type.nameMatcher.IsMatch(typeFullName)) - { - continue; - } - foreach (var method in type.methods) - { - if (method.nameMatcher.IsMatch(methodName)) - { - return !method.obfuscate.Value; - } - } - return !type.obfuscate.Value; - } - return !ass.obfuscate.Value; - } - return false; - } - - public override bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir) - { - if (_whiteListMethodCache.GetValue(calledMethod)) - { - return false; - } - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs.meta deleted file mode 100644 index c970eec6..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d9ea12b16c4b296459db8a60fb1615d6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs deleted file mode 100644 index 7b9b6e04..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs +++ /dev/null @@ -1,263 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.Settings; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Obfuz.ObfusPasses.CallObfus -{ - - struct DelegateProxyMethodData - { - public readonly FieldDef delegateInstanceField; - public readonly MethodDef delegateInvokeMethod; - - public DelegateProxyMethodData(FieldDef delegateInstanceField, MethodDef delegateInvokeMethod) - { - this.delegateInstanceField = delegateInstanceField; - this.delegateInvokeMethod = delegateInvokeMethod; - } - } - - class DelegateProxyAllocator : GroupByModuleEntityBase - { - private readonly CachedDictionary _delegateTypes; - private readonly HashSet _allocatedDelegateNames = new HashSet(); - - private TypeDef _delegateInstanceHolderType; - private bool _done; - - class CallInfo - { - public string key1; - public int key2; - public IMethod method; - public bool callVir; - - public int index; - public TypeDef delegateType; - public FieldDef delegateInstanceField; - public MethodDef delegateInvokeMethod; - public MethodDef proxyMethod; - } - private readonly Dictionary _callMethods = new Dictionary(); - - public DelegateProxyAllocator() - { - _delegateTypes = new CachedDictionary(SignatureEqualityComparer.Instance, CreateDelegateForSignature); - } - - public override void Init() - { - _delegateInstanceHolderType = CreateDelegateInstanceHolderTypeDef(); - } - - private string AllocateDelegateTypeName(MethodSig delegateInvokeSig) - { - uint hashCode = (uint)SignatureEqualityComparer.Instance.GetHashCode(delegateInvokeSig); - string typeName = $"$Obfuz$Delegate_{hashCode}"; - if (_allocatedDelegateNames.Add(typeName)) - { - return typeName; - } - for (int i = 0; ;i++) - { - typeName = $"$Obfuz$Delegate_{hashCode}_{i}"; - if (_allocatedDelegateNames.Add(typeName)) - { - return typeName; - } - } - } - - private TypeDef CreateDelegateForSignature(MethodSig delegateInvokeSig) - { - ModuleDef mod = Module; - using (var scope = new DisableTypeDefFindCacheScope(mod)) - { - - string typeName = AllocateDelegateTypeName(delegateInvokeSig); - mod.Import(typeof(MulticastDelegate)); - - TypeDef delegateType = new TypeDefUser("", typeName, mod.CorLibTypes.GetTypeRef("System", "MulticastDelegate")); - delegateType.Attributes = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public; - mod.Types.Add(delegateType); - - MethodDef ctor = new MethodDefUser( - ".ctor", - MethodSig.CreateInstance(mod.CorLibTypes.Void, mod.CorLibTypes.Object, mod.CorLibTypes.IntPtr), - MethodImplAttributes.Runtime, - MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public - ); - ctor.DeclaringType = delegateType; - - - MethodDef invokeMethod = new MethodDefUser( - "Invoke", - MethodSig.CreateInstance(delegateInvokeSig.RetType, delegateInvokeSig.Params.ToArray()), - MethodImplAttributes.Runtime, - MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.Virtual - ); - invokeMethod.DeclaringType = delegateType; - return delegateType; - } - } - - private TypeDef CreateDelegateInstanceHolderTypeDef() - { - ModuleDef mod = Module; - using (var scope = new DisableTypeDefFindCacheScope(mod)) - { - string typeName = "$Obfuz$DelegateInstanceHolder"; - TypeDef holderType = new TypeDefUser("", typeName, mod.CorLibTypes.Object.ToTypeDefOrRef()); - holderType.Attributes = TypeAttributes.Class | TypeAttributes.Public; - mod.Types.Add(holderType); - return holderType; - } - } - - private string AllocateFieldName(IMethod method, bool callVir) - { - uint hashCode = (uint)MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method); - string typeName = $"$Obfuz$Delegate$Field_{hashCode}_{callVir}"; - if (_allocatedDelegateNames.Add(typeName)) - { - return typeName; - } - for (int i = 0; ; i++) - { - typeName = $"$Obfuz$Delegate$Field_{hashCode}_{callVir}_{i}"; - if (_allocatedDelegateNames.Add(typeName)) - { - return typeName; - } - } - } - - private MethodDef CreateProxyMethod(string name, IMethod calledMethod, bool callVir, MethodSig delegateInvokeSig) - { - var proxyMethod = new MethodDefUser(name, delegateInvokeSig, MethodImplAttributes.Managed, MethodAttributes.Public | MethodAttributes.Static); - var body = new CilBody(); - proxyMethod.Body = body; - var ins = body.Instructions; - - foreach (Parameter param in proxyMethod.Parameters) - { - ins.Add(Instruction.Create(OpCodes.Ldarg, param)); - } - - ins.Add(Instruction.Create(callVir ? OpCodes.Callvirt : OpCodes.Call, calledMethod)); - ins.Add(Instruction.Create(OpCodes.Ret)); - return proxyMethod; - } - - public DelegateProxyMethodData Allocate(IMethod method, bool callVir, MethodSig delegateInvokeSig) - { - var key = new MethodKey(method, callVir); - if (!_callMethods.TryGetValue(key, out var callInfo)) - { - TypeDef delegateType = _delegateTypes.GetValue(delegateInvokeSig); - MethodDef delegateInvokeMethod = delegateType.FindMethod("Invoke"); - string fieldName = AllocateFieldName(method, callVir); - FieldDef delegateInstanceField = new FieldDefUser(fieldName, new FieldSig(delegateType.ToTypeSig()), FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.InitOnly); - string key1 = $"{method.FullName}_{callVir}"; - callInfo = new CallInfo - { - key1 = key1, - key2 = HashUtil.ComputePrimitiveOrStringOrBytesHashCode(key1) * 33445566, - method = method, - callVir = callVir, - delegateType = delegateType, - delegateInstanceField = delegateInstanceField, - delegateInvokeMethod = delegateInvokeMethod, - proxyMethod = CreateProxyMethod($"{fieldName}$Proxy", method, callVir, delegateInvokeSig), - }; - _callMethods.Add(key, callInfo); - } - return new DelegateProxyMethodData(callInfo.delegateInstanceField, callInfo.delegateInvokeMethod); - } - - public override void Done() - { - if (_done) - { - throw new Exception("Already done"); - } - _done = true; - - ModuleDef mod = Module; - - // for stable order, we sort methods by name - List callMethodList = _callMethods.Values.ToList(); - callMethodList.Sort((a, b) => a.key1.CompareTo(b.key1)); - - var cctor = new MethodDefUser(".cctor", - MethodSig.CreateStatic(mod.CorLibTypes.Void), - MethodImplAttributes.IL | MethodImplAttributes.Managed, - MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private); - cctor.DeclaringType = _delegateInstanceHolderType; - //_rvaTypeDef.Methods.Add(cctor); - var body = new CilBody(); - cctor.Body = body; - var ins = body.Instructions; - - // var arr = new array[]; - // var d = new delegate; - // arr[index] = d; - int index = 0; - ins.Add(Instruction.CreateLdcI4(callMethodList.Count)); - ins.Add(Instruction.Create(OpCodes.Newarr, mod.CorLibTypes.Object)); - foreach (CallInfo ci in callMethodList) - { - ci.index = index; - _delegateInstanceHolderType.Methods.Add(ci.proxyMethod); - ins.Add(Instruction.Create(OpCodes.Dup)); - ins.Add(Instruction.CreateLdcI4(index)); - ins.Add(Instruction.Create(OpCodes.Ldnull)); - ins.Add(Instruction.Create(OpCodes.Ldftn, ci.proxyMethod)); - MethodDef ctor = ci.delegateType.FindMethod(".ctor"); - UnityEngine.Assertions.Assert.IsNotNull(ctor, $"Delegate type {ci.delegateType.FullName} does not have a constructor."); - ins.Add(Instruction.Create(OpCodes.Newobj, ctor)); - ins.Add(Instruction.Create(OpCodes.Stelem_Ref)); - ++index; - } - - - - List callMethodList2 = callMethodList.ToList(); - callMethodList2.Sort((a, b) => a.key2.CompareTo(b.key2)); - - EncryptionScopeInfo encryptionScope = EncryptionScope; - DefaultMetadataImporter importer = this.GetDefaultModuleMetadataImporter(); - RvaDataAllocator rvaDataAllocator = this.GetEntity(); - foreach (CallInfo ci in callMethodList2) - { - _delegateInstanceHolderType.Fields.Add(ci.delegateInstanceField); - - - ins.Add(Instruction.Create(OpCodes.Dup)); - - IRandom localRandom = encryptionScope.localRandomCreator(HashUtil.ComputePrimitiveOrStringOrBytesHashCode(ci.key1)); - int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, encryptionScope.encryptor, 4); - int salt = localRandom.NextInt(); - - int encryptedValue = encryptionScope.encryptor.Encrypt(ci.index, ops, salt); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - ins.Add(Instruction.CreateLdcI4(rvaData.offset)); - ins.Add(Instruction.CreateLdcI4(ops)); - ins.Add(Instruction.CreateLdcI4(salt)); - ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaInt)); - ins.Add(Instruction.Create(OpCodes.Ldelem_Ref)); - ins.Add(Instruction.Create(OpCodes.Stsfld, ci.delegateInstanceField)); - } - - ins.Add(Instruction.Create(OpCodes.Pop)); - ins.Add(Instruction.Create(OpCodes.Ret)); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs.meta deleted file mode 100644 index d324d9aa..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 02761bacbed8a8b489ae3e7f49f0f84a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs deleted file mode 100644 index bc6ce18c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs +++ /dev/null @@ -1,83 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.Settings; -using Obfuz.Utils; -using System.Collections.Generic; -using System.Linq; - -namespace Obfuz.ObfusPasses.CallObfus -{ - - public class DelegateProxyObfuscator : ObfuscatorBase - { - private readonly GroupByModuleEntityManager _entityManager; - - public DelegateProxyObfuscator(GroupByModuleEntityManager moduleEntityManager) - { - _entityManager = moduleEntityManager; - } - - public override void Done() - { - _entityManager.Done(); - } - - private MethodSig CreateProxyMethodSig(ModuleDef module, IMethod method) - { - MethodSig methodSig = MetaUtil.ToSharedMethodSig(module.CorLibTypes, MetaUtil.GetInflatedMethodSig(method, null)); - //MethodSig methodSig = MetaUtil.GetInflatedMethodSig(method).Clone(); - //methodSig.Params - switch (MetaUtil.GetThisArgType(method)) - { - case ThisArgType.Class: - { - methodSig.Params.Insert(0, module.CorLibTypes.Object); - break; - } - case ThisArgType.ValueType: - { - methodSig.Params.Insert(0, module.CorLibTypes.IntPtr); - break; - } - } - return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray()); - } - - public override bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List obfuscatedInstructions) - { - DelegateProxyAllocator allocator = _entityManager.GetEntity(callingMethod.Module); - LocalVariableAllocator localVarAllocator = new LocalVariableAllocator(callingMethod); - MethodSig methodSig = CreateProxyMethodSig(callingMethod.Module, calledMethod); - DelegateProxyMethodData proxyData = allocator.Allocate(calledMethod, callVir, methodSig); - bool isVoidReturn = MetaUtil.IsVoidType(methodSig.RetType); - - using (var varScope = localVarAllocator.CreateScope()) - { - List localVars = new List(); - if (!isVoidReturn) - { - varScope.AllocateLocal(methodSig.RetType); - } - foreach (var p in methodSig.Params) - { - localVars.Add(varScope.AllocateLocal(p)); - } - // save args - for (int i = localVars.Count - 1; i >= 0; i--) - { - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Stloc, localVars[i])); - } - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, proxyData.delegateInstanceField)); - foreach (var local in localVars) - { - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldloc, local)); - } - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Callvirt, proxyData.delegateInvokeMethod)); - } - - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs.meta deleted file mode 100644 index 4cb75c37..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1102cd9f03de27c4b9fde3d6a87277c7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs deleted file mode 100644 index f4fe3bc8..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs +++ /dev/null @@ -1,273 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Editor; -using Obfuz.Emit; -using Obfuz.Settings; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using MethodImplAttributes = dnlib.DotNet.MethodImplAttributes; -using TypeAttributes = dnlib.DotNet.TypeAttributes; - -namespace Obfuz.ObfusPasses.CallObfus -{ - - public struct ProxyCallMethodData - { - public readonly MethodDef proxyMethod; - public readonly int encryptOps; - public readonly int salt; - public readonly int encryptedIndex; - public readonly int index; - - public ProxyCallMethodData(MethodDef proxyMethod, int encryptOps, int salt, int encryptedIndex, int index) - { - this.proxyMethod = proxyMethod; - this.encryptOps = encryptOps; - this.salt = salt; - this.encryptedIndex = encryptedIndex; - this.index = index; - } - } - - class ModuleDispatchProxyAllocator : GroupByModuleEntityBase - { - private bool _done; - private CallObfuscationSettingsFacade _settings; - - - class MethodProxyInfo - { - public MethodDef proxyMethod; - - public int index; - public int encryptedOps; - public int salt; - public int encryptedIndex; - } - - private readonly Dictionary _methodProxys = new Dictionary(); - - class CallInfo - { - public string id; - public IMethod method; - public bool callVir; - } - - class DispatchMethodInfo - { - public MethodDef methodDef; - public List methods = new List(); - } - - private readonly Dictionary> _dispatchMethods = new Dictionary>(SignatureEqualityComparer.Instance); - - - private TypeDef _proxyTypeDef; - - public ModuleDispatchProxyAllocator() - { - } - - public override void Init() - { - _settings = CallObfusPass.CurrentSettings; - } - - private TypeDef CreateProxyTypeDef() - { - ModuleDef mod = Module; - using (var scope = new DisableTypeDefFindCacheScope(mod)) - { - var typeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ProxyCall", mod.CorLibTypes.Object.ToTypeDefOrRef()); - typeDef.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed; - mod.Types.Add(typeDef); - return typeDef; - } - } - - private readonly HashSet _uniqueMethodNames = new HashSet(); - - - private string ToUniqueMethodName(string originalName) - { - if (_uniqueMethodNames.Add(originalName)) - { - return originalName; - } - for (int index = 1; ; index++) - { - string uniqueName = $"{originalName}${index}"; - if (_uniqueMethodNames.Add(uniqueName)) - { - return uniqueName; - } - } - } - - private string CreateDispatchMethodName(MethodSig methodSig, int index) - { - // use a stable name for the dispatch method, so that we can reuse it across different modules - // this is important for cross-module calls - return ToUniqueMethodName($"{ConstValues.ObfuzInternalSymbolNamePrefix}Dispatch_{HashUtil.ComputeHash(methodSig.Params) & 0xFFFF}_{HashUtil.ComputeHash(methodSig.RetType) & 0xFFFFFF}"); - } - - private MethodDef CreateDispatchMethodInfo(MethodSig methodSig, int index) - { - if (_proxyTypeDef == null) - { - _proxyTypeDef = CreateProxyTypeDef(); - } - MethodDef methodDef = new MethodDefUser(CreateDispatchMethodName(methodSig, index), methodSig, - MethodImplAttributes.IL | MethodImplAttributes.Managed, - MethodAttributes.Static | MethodAttributes.Public); - methodDef.DeclaringType = _proxyTypeDef; - return methodDef; - } - - private MethodSig CreateDispatchMethodSig(IMethod method) - { - ModuleDef mod = Module; - MethodSig methodSig = MetaUtil.ToSharedMethodSig(mod.CorLibTypes, MetaUtil.GetInflatedMethodSig(method, null)); - //MethodSig methodSig = MetaUtil.GetInflatedMethodSig(method).Clone(); - //methodSig.Params - switch (MetaUtil.GetThisArgType(method)) - { - case ThisArgType.Class: - { - methodSig.Params.Insert(0, mod.CorLibTypes.Object); - break; - } - case ThisArgType.ValueType: - { - methodSig.Params.Insert(0, mod.CorLibTypes.IntPtr); - break; - } - } - // extra param for index - methodSig.Params.Add(mod.CorLibTypes.Int32); - return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray()); - } - - private int GenerateSalt(IRandom random) - { - return random.NextInt(); - } - - private int GenerateEncryptOps(IRandom random) - { - return EncryptionUtil.GenerateEncryptionOpCodes(random, EncryptionScope.encryptor, _settings.obfuscationLevel); - } - - private DispatchMethodInfo GetDispatchMethod(IMethod method) - { - MethodSig methodSig = CreateDispatchMethodSig(method); - if (!_dispatchMethods.TryGetValue(methodSig, out var dispatchMethods)) - { - dispatchMethods = new List(); - _dispatchMethods.Add(methodSig, dispatchMethods); - } - if (dispatchMethods.Count == 0 || dispatchMethods.Last().methods.Count >= _settings.maxProxyMethodCountPerDispatchMethod) - { - var newDispatchMethodInfo = new DispatchMethodInfo - { - methodDef = CreateDispatchMethodInfo(methodSig, dispatchMethods.Count), - }; - dispatchMethods.Add(newDispatchMethodInfo); - } - return dispatchMethods.Last(); - } - - private IRandom CreateRandomForMethod(IMethod method, bool callVir) - { - int seed = MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method); - return EncryptionScope.localRandomCreator(seed); - } - - public ProxyCallMethodData Allocate(IMethod method, bool callVir) - { - if (_done) - { - throw new Exception("can't Allocate after done"); - } - var key = new MethodKey(method, callVir); - if (!_methodProxys.TryGetValue(key, out var proxyInfo)) - { - var methodDispatcher = GetDispatchMethod(method); - - int index = methodDispatcher.methods.Count; - IRandom localRandom = CreateRandomForMethod(method, callVir); - int encryptOps = GenerateEncryptOps(localRandom); - int salt = GenerateSalt(localRandom); - int encryptedIndex = EncryptionScope.encryptor.Encrypt(index, encryptOps, salt); - proxyInfo = new MethodProxyInfo() - { - proxyMethod = methodDispatcher.methodDef, - index = index, - encryptedOps = encryptOps, - salt = salt, - encryptedIndex = encryptedIndex, - }; - methodDispatcher.methods.Add(new CallInfo { id = $"{method}{(callVir ? "" : "v")}", method = method, callVir = callVir }); - _methodProxys.Add(key, proxyInfo); - } - return new ProxyCallMethodData(proxyInfo.proxyMethod, proxyInfo.encryptedOps, proxyInfo.salt, proxyInfo.encryptedIndex, proxyInfo.index); - } - - public override void Done() - { - if (_done) - { - throw new Exception("Already done"); - } - _done = true; - if (_proxyTypeDef == null) - { - return; - } - - // for stable order, we sort methods by name - var methodWithNamePairList = _proxyTypeDef.Methods.Select(m => (m, m.ToString())).ToList(); - methodWithNamePairList.Sort((a, b) => a.Item2.CompareTo(b.Item2)); - _proxyTypeDef.Methods.Clear(); - foreach (var methodPair in methodWithNamePairList) - { - methodPair.Item1.DeclaringType = _proxyTypeDef; - } - - foreach (DispatchMethodInfo dispatchMethod in _dispatchMethods.Values.SelectMany(ms => ms)) - { - var methodDef = dispatchMethod.methodDef; - var methodSig = methodDef.MethodSig; - - - var body = new CilBody(); - methodDef.Body = body; - var ins = body.Instructions; - - foreach (Parameter param in methodDef.Parameters) - { - ins.Add(Instruction.Create(OpCodes.Ldarg, param)); - } - - var switchCases = new List(); - var switchInst = Instruction.Create(OpCodes.Switch, switchCases); - ins.Add(switchInst); - var ret = Instruction.Create(OpCodes.Ret); - - // sort methods by signature to ensure stable order - //dispatchMethod.methods.Sort((a, b) => a.id.CompareTo(b.id)); - foreach (CallInfo ci in dispatchMethod.methods) - { - var callTargetMethod = Instruction.Create(ci.callVir ? OpCodes.Callvirt : OpCodes.Call, ci.method); - switchCases.Add(callTargetMethod); - ins.Add(callTargetMethod); - ins.Add(Instruction.Create(OpCodes.Br, ret)); - } - ins.Add(ret); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs.meta deleted file mode 100644 index a6a06f88..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 16b960455f093854d927c2dbd47a4826 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs deleted file mode 100644 index bc54a774..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs +++ /dev/null @@ -1,53 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.Settings; -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.CallObfus -{ - - public class DispatchProxyObfuscator : ObfuscatorBase - { - private readonly GroupByModuleEntityManager _moduleEntityManager; - - public DispatchProxyObfuscator(GroupByModuleEntityManager moduleEntityManager) - { - _moduleEntityManager = moduleEntityManager; - } - - public override void Done() - { - _moduleEntityManager.Done(); - } - - public override bool Obfuscate(MethodDef callerMethod, IMethod calledMethod, bool callVir, List obfuscatedInstructions) - { - ModuleDispatchProxyAllocator proxyCallAllocator = _moduleEntityManager.GetEntity(callerMethod.Module); - MethodSig sharedMethodSig = MetaUtil.ToSharedMethodSig(calledMethod.Module.CorLibTypes, MetaUtil.GetInflatedMethodSig(calledMethod, null)); - ProxyCallMethodData proxyCallMethodData = proxyCallAllocator.Allocate(calledMethod, callVir); - DefaultMetadataImporter importer = proxyCallAllocator.GetDefaultModuleMetadataImporter(); - - //if (needCacheCall) - //{ - // FieldDef cacheField = _constFieldAllocator.Allocate(callerMethod.Module, proxyCallMethodData.index); - // obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); - //} - //else - //{ - // obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.encryptedIndex)); - // obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.encryptOps)); - // obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.salt)); - // obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptInt)); - //} - - ConstFieldAllocator constFieldAllocator = proxyCallAllocator.GetEntity(); - FieldDef cacheField = constFieldAllocator.Allocate(proxyCallMethodData.index); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, proxyCallMethodData.proxyMethod)); - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs.meta deleted file mode 100644 index 78ae2a27..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e13ba01b03439e049af0e09367825cde -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs deleted file mode 100644 index 941291ba..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs +++ /dev/null @@ -1,19 +0,0 @@ -using dnlib.DotNet; - -namespace Obfuz.ObfusPasses.CallObfus -{ - - public interface IObfuscationPolicy - { - bool NeedObfuscateCallInMethod(MethodDef method); - - bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir); - } - - public abstract class ObfuscationPolicyBase : IObfuscationPolicy - { - public abstract bool NeedObfuscateCallInMethod(MethodDef method); - - public abstract bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs.meta deleted file mode 100644 index 96009d14..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6af3cd881fdefd14d9a55b77088dd5a4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscator.cs deleted file mode 100644 index bd26274e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscator.cs +++ /dev/null @@ -1,20 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.CallObfus -{ - public interface IObfuscator - { - bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List obfuscatedInstructions); - - void Done(); - } - - public abstract class ObfuscatorBase : IObfuscator - { - public abstract bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List obfuscatedInstructions); - - public abstract void Done(); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscator.cs.meta deleted file mode 100644 index c75fd401..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/IObfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4156317478f8b1d438ef6d5a280d409f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/MethodKey.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/MethodKey.cs deleted file mode 100644 index 99275581..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/MethodKey.cs +++ /dev/null @@ -1,30 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Utils; -using System; - -namespace Obfuz.ObfusPasses.CallObfus -{ - class MethodKey : IEquatable - { - public readonly IMethod _method; - public readonly bool _callVir; - private readonly int _hashCode; - - public MethodKey(IMethod method, bool callVir) - { - _method = method; - _callVir = callVir; - _hashCode = HashUtil.CombineHash(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method), callVir ? 1 : 0); - } - - public override int GetHashCode() - { - return _hashCode; - } - - public bool Equals(MethodKey other) - { - return MethodEqualityComparer.CompareDeclaringTypes.Equals(_method, other._method) && _callVir == other._callVir; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/MethodKey.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/MethodKey.cs.meta deleted file mode 100644 index f7a1a2a8..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/MethodKey.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1193647b317b56f4b83aa080d0a17f7a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/SpecialWhiteListMethodCalculator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/SpecialWhiteListMethodCalculator.cs deleted file mode 100644 index 5f52792b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/SpecialWhiteListMethodCalculator.cs +++ /dev/null @@ -1,122 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.CallObfus -{ - class SpecialWhiteListMethodCalculator - { - private readonly bool _obfuscateCallToMethodInMscorlib; - private readonly CachedDictionary _specialWhiteListMethodCache; - - public SpecialWhiteListMethodCalculator(bool obfuscateCallToMethodInMscorlib) - { - _obfuscateCallToMethodInMscorlib = obfuscateCallToMethodInMscorlib; - _specialWhiteListMethodCache = new CachedDictionary(MethodEqualityComparer.CompareDeclaringTypes, this.ComputeIsInWhiteList); - } - - public bool IsInWhiteList(IMethod calledMethod) - { - return _specialWhiteListMethodCache.GetValue(calledMethod); - } - - private static readonly HashSet _specialTypeFullNames = new HashSet - { - "System.Enum", - "System.Delegate", - "System.MulticastDelegate", - "Obfuz.EncryptionService`1", - }; - - private static readonly HashSet _specialMethodNames = new HashSet - { - "GetEnumerator", // List.Enumerator.GetEnumerator() - ".ctor", // constructor - }; - - private static readonly HashSet _specialMethodFullNames = new HashSet - { - "System.Reflection.MethodBase.GetCurrentMethod", - "System.Reflection.Assembly.GetCallingAssembly", - "System.Reflection.Assembly.GetExecutingAssembly", - "System.Reflection.Assembly.GetEntryAssembly", - }; - - private bool ComputeIsInWhiteList(IMethod calledMethod) - { - MethodDef calledMethodDef = calledMethod.ResolveMethodDef(); - // mono has more strict access control, calls non-public method will raise exception. - if (PlatformUtil.IsMonoBackend()) - { - if (calledMethodDef != null && (!calledMethodDef.IsPublic || !IsTypeSelfAndParentPublic(calledMethodDef.DeclaringType))) - { - return true; - } - } - - ITypeDefOrRef declaringType = calledMethod.DeclaringType; - TypeSig declaringTypeSig = calledMethod.DeclaringType.ToTypeSig(); - declaringTypeSig = declaringTypeSig.RemovePinnedAndModifiers(); - switch (declaringTypeSig.ElementType) - { - case ElementType.ValueType: - case ElementType.Class: - { - break; - } - case ElementType.GenericInst: - { - if (MetaUtil.ContainsContainsGenericParameter(calledMethod)) - { - return true; - } - break; - } - default: return true; - } - - TypeDef typeDef = declaringType.ResolveTypeDef(); - - if (!_obfuscateCallToMethodInMscorlib && typeDef.Module.IsCoreLibraryModule == true) - { - return true; - } - - if (typeDef.IsDelegate || typeDef.IsEnum) - return true; - - string fullName = typeDef.FullName; - if (_specialTypeFullNames.Contains(fullName)) - { - return true; - } - //if (fullName.StartsWith("System.Runtime.CompilerServices.")) - //{ - // return true; - //} - - string methodName = calledMethod.Name; - if (_specialMethodNames.Contains(methodName)) - { - return true; - } - - string methodFullName = $"{fullName}.{methodName}"; - if (_specialMethodFullNames.Contains(methodFullName)) - { - return true; - } - return false; - } - - private bool IsTypeSelfAndParentPublic(TypeDef type) - { - if (type.DeclaringType != null && !IsTypeSelfAndParentPublic(type.DeclaringType)) - { - return false; - } - - return type.IsPublic; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/SpecialWhiteListMethodCalculator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/SpecialWhiteListMethodCalculator.cs.meta deleted file mode 100644 index b1228ec4..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CallObfus/SpecialWhiteListMethodCalculator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 904e80c4b98911c40b6a9173ca24f3ee -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp.meta deleted file mode 100644 index 37096d79..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 2764442d8fc2b914dbc39dcfa2699698 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/CleanUpInstructionPass.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/CleanUpInstructionPass.cs deleted file mode 100644 index c95854d0..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/CleanUpInstructionPass.cs +++ /dev/null @@ -1,41 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; - -namespace Obfuz.ObfusPasses.CleanUp -{ - public class CleanUpInstructionPass : ObfuscationPassBase - { - public override ObfuscationPassType Type => ObfuscationPassType.None; - - public override void Start() - { - } - - public override void Stop() - { - - } - - public override void Process() - { - var ctx = ObfuscationPassContext.Current; - foreach (ModuleDef mod in ctx.modulesToObfuscate) - { - foreach (TypeDef type in mod.GetTypes()) - { - foreach (MethodDef method in type.Methods) - { - if (method.HasBody) - { - CilBody body = method.Body; - body.SimplifyBranches(); - body.OptimizeMacros(); - body.OptimizeBranches(); - // TODO remove dup - } - } - } - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/CleanUpInstructionPass.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/CleanUpInstructionPass.cs.meta deleted file mode 100644 index cc974323..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/CleanUpInstructionPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 78cc056cd929d70409a0f0737b571a6d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/RemoveObfuzAttributesPass.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/RemoveObfuzAttributesPass.cs deleted file mode 100644 index 6b1ac2bb..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/RemoveObfuzAttributesPass.cs +++ /dev/null @@ -1,67 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Editor; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.CleanUp -{ - public class RemoveObfuzAttributesPass : ObfuscationPassBase - { - public override ObfuscationPassType Type => ObfuscationPassType.None; - - public override void Start() - { - } - - public override void Stop() - { - - } - - - private void RemoveObfuzAttributes(IHasCustomAttribute provider) - { - CustomAttributeCollection customAttributes = provider.CustomAttributes; - if (customAttributes.Count == 0) - return; - var toRemove = new List(); - customAttributes.RemoveAll(ConstValues.ObfuzIgnoreAttributeFullName); - customAttributes.RemoveAll(ConstValues.EncryptFieldAttributeFullName); - } - - public override void Process() - { - var ctx = ObfuscationPassContext.Current; - foreach (ModuleDef mod in ctx.modulesToObfuscate) - { - RemoveObfuzAttributes(mod); - foreach (TypeDef type in mod.GetTypes()) - { - RemoveObfuzAttributes(type); - foreach (FieldDef field in type.Fields) - { - RemoveObfuzAttributes(field); - } - foreach (MethodDef method in type.Methods) - { - RemoveObfuzAttributes(method); - foreach (Parameter param in method.Parameters) - { - if (param.ParamDef != null) - { - RemoveObfuzAttributes(param.ParamDef); - } - } - } - foreach (PropertyDef property in type.Properties) - { - RemoveObfuzAttributes(property); - } - foreach (EventDef eventDef in type.Events) - { - RemoveObfuzAttributes(eventDef); - } - } - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/RemoveObfuzAttributesPass.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/RemoveObfuzAttributesPass.cs.meta deleted file mode 100644 index ff6039ec..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/CleanUp/RemoveObfuzAttributesPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6b475010a7656a0439ca8664a3d2dbc0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt.meta deleted file mode 100644 index 1fdfee0b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 18104d0c3c665ea489e566eec67f2aea -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConfigurableEncryptPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConfigurableEncryptPolicy.cs deleted file mode 100644 index 2b775b56..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConfigurableEncryptPolicy.cs +++ /dev/null @@ -1,490 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Conf; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml; - -namespace Obfuz.ObfusPasses.ConstEncrypt -{ - - public class ConfigurableEncryptPolicy : EncryptPolicyBase - { - class ObfuscationRule : IRule - { - public bool? disableEncrypt; - public bool? encryptInt; - public bool? encryptLong; - public bool? encryptFloat; - public bool? encryptDouble; - public bool? encryptArray; - public bool? encryptString; - - public bool? encryptConstInLoop; - public bool? encryptStringInLoop; - - public bool? cacheConstInLoop; - public bool? cacheConstNotInLoop; - public bool? cacheStringInLoop; - public bool? cacheStringNotInLoop; - - public void InheritParent(ObfuscationRule parentRule) - { - if (disableEncrypt == null) - disableEncrypt = parentRule.disableEncrypt; - if (encryptInt == null) - encryptInt = parentRule.encryptInt; - if (encryptLong == null) - encryptLong = parentRule.encryptLong; - if (encryptFloat == null) - encryptFloat = parentRule.encryptFloat; - if (encryptDouble == null) - encryptDouble = parentRule.encryptDouble; - if (encryptArray == null) - encryptArray = parentRule.encryptArray; - if (encryptString == null) - encryptString = parentRule.encryptString; - - if (encryptConstInLoop == null) - encryptConstInLoop = parentRule.encryptConstInLoop; - if (encryptStringInLoop == null) - encryptStringInLoop = parentRule.encryptStringInLoop; - - if (cacheConstInLoop == null) - cacheConstInLoop = parentRule.cacheConstInLoop; - if (cacheConstNotInLoop == null) - cacheConstNotInLoop = parentRule.cacheConstNotInLoop; - if (cacheStringInLoop == null) - cacheStringInLoop = parentRule.cacheStringInLoop; - if (cacheStringNotInLoop == null) - cacheStringNotInLoop = parentRule.cacheStringNotInLoop; - } - } - - class MethodSpec : MethodRuleBase - { - } - - class TypeSpec : TypeRuleBase - { - } - - class AssemblySpec : AssemblyRuleBase - { - } - - private static readonly ObfuscationRule s_default = new ObfuscationRule() - { - disableEncrypt = false, - encryptInt = true, - encryptLong = true, - encryptFloat = true, - encryptDouble = true, - encryptArray = true, - encryptString = true, - encryptConstInLoop = true, - encryptStringInLoop = true, - cacheConstInLoop = true, - cacheConstNotInLoop = false, - cacheStringInLoop = true, - cacheStringNotInLoop = true, - }; - - private ObfuscationRule _global; - - public HashSet notEncryptInts = new HashSet(); - public HashSet notEncryptLongs = new HashSet(); - public HashSet notEncryptStrings = new HashSet(); - public List> notEncryptIntRanges = new List>(); - public List> notEncryptLongRanges = new List>(); - public List> notEncryptFloatRanges = new List>(); - public List> notEncryptDoubleRanges = new List>(); - public List> notEncryptArrayLengthRanges = new List>(); - public List> notEncryptStringLengthRanges = new List>(); - - private readonly XmlAssemblyTypeMethodRuleParser _xmlParser; - - private readonly Dictionary _assemblySpecs = new Dictionary(); - private readonly Dictionary _methodRuleCache = new Dictionary(); - - public ConfigurableEncryptPolicy(List toObfuscatedAssemblyNames, List xmlConfigFiles) - { - _xmlParser = new XmlAssemblyTypeMethodRuleParser( - toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobalElement); - LoadConfigs(xmlConfigFiles); - } - - private void LoadConfigs(List configFiles) - { - _xmlParser.LoadConfigs(configFiles); - if (_global == null) - { - _global = s_default; - } - else - { - _global.InheritParent(s_default); - } - _xmlParser.InheritParentRules(_global); - } - - private void ParseGlobalElement(string configFile, XmlElement ele) - { - switch (ele.Name) - { - case "global": _global = ParseObfuscationRule(configFile, ele); break; - case "whitelist": ParseWhitelist(configFile, ele); break; - default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}"); - } - } - - private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) - { - var rule = new ObfuscationRule(); - if (ele.HasAttribute("disableEncrypt")) - { - rule.disableEncrypt = ConfigUtil.ParseBool(ele.GetAttribute("disableEncrypt")); - } - if (ele.HasAttribute("encryptInt")) - { - rule.encryptInt = ConfigUtil.ParseBool(ele.GetAttribute("encryptInt")); - } - if (ele.HasAttribute("encryptLong")) - { - rule.encryptLong = ConfigUtil.ParseBool(ele.GetAttribute("encryptLong")); - } - if (ele.HasAttribute("encryptFloat")) - { - rule.encryptFloat = ConfigUtil.ParseBool(ele.GetAttribute("encryptFloat")); - } - if (ele.HasAttribute("encryptDouble")) - { - rule.encryptDouble = ConfigUtil.ParseBool(ele.GetAttribute("encryptDouble")); - } - if (ele.HasAttribute("encryptBytes")) - { - rule.encryptArray = ConfigUtil.ParseBool(ele.GetAttribute("encryptArray")); - } - if (ele.HasAttribute("encryptString")) - { - rule.encryptString = ConfigUtil.ParseBool(ele.GetAttribute("encryptString")); - } - - if (ele.HasAttribute("encryptConstInLoop")) - { - rule.encryptConstInLoop = ConfigUtil.ParseBool(ele.GetAttribute("encryptConstInLoop")); - } - if (ele.HasAttribute("encryptStringInLoop")) - { - rule.encryptStringInLoop = ConfigUtil.ParseBool(ele.GetAttribute("encryptStringInLoop")); - } - if (ele.HasAttribute("cacheConstInLoop")) - { - rule.cacheConstInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheConstInLoop")); - } - if (ele.HasAttribute("cacheConstNotInLoop")) - { - rule.cacheConstNotInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheConstNotInLoop")); - } - if (ele.HasAttribute("cacheStringInLoop")) - { - rule.cacheStringInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheStringInLoop")); - } - if (ele.HasAttribute("cacheStringNotInLoop")) - { - rule.cacheStringNotInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheStringNotInLoop")); - } - return rule; - } - - private void ParseWhitelist(string configFile, XmlElement childEle) - { - string type = childEle.GetAttribute("type"); - if (string.IsNullOrEmpty(type)) - { - throw new Exception($"Invalid xml file, whitelist type is empty"); - } - string value = childEle.InnerText; - switch (type) - { - case "int": - { - notEncryptInts.AddRange(value.Split(',').Select(s => int.Parse(s.Trim()))); - break; - } - case "long": - { - notEncryptLongs.AddRange(value.Split(',').Select(s => long.Parse(s.Trim()))); - break; - } - case "string": - { - notEncryptStrings.AddRange(value.Split(',').Select(s => s.Trim())); - break; - } - case "int-range": - { - var parts = value.Split(','); - if (parts.Length != 2) - { - throw new Exception($"Invalid xml file, int-range {value} is invalid"); - } - notEncryptIntRanges.Add(new NumberRange(ConfigUtil.ParseNullableInt(parts[0]), ConfigUtil.ParseNullableInt(parts[1]))); - break; - } - case "long-range": - { - var parts = value.Split(','); - if (parts.Length != 2) - { - throw new Exception($"Invalid xml file, long-range {value} is invalid"); - } - notEncryptLongRanges.Add(new NumberRange(ConfigUtil.ParseNullableLong(parts[0]), ConfigUtil.ParseNullableLong(parts[1]))); - break; - } - case "float-range": - { - var parts = value.Split(','); - if (parts.Length != 2) - { - throw new Exception($"Invalid xml file, float-range {value} is invalid"); - } - notEncryptFloatRanges.Add(new NumberRange(ConfigUtil.ParseNullableFloat(parts[0]), ConfigUtil.ParseNullableFloat(parts[1]))); - break; - } - case "double-range": - { - var parts = value.Split(','); - if (parts.Length != 2) - { - throw new Exception($"Invalid xml file, double-range {value} is invalid"); - } - notEncryptDoubleRanges.Add(new NumberRange(ConfigUtil.ParseNullableDouble(parts[0]), ConfigUtil.ParseNullableDouble(parts[1]))); - break; - } - case "string-length-range": - { - var parts = value.Split(','); - if (parts.Length != 2) - { - throw new Exception($"Invalid xml file, string-length-range {value} is invalid"); - } - notEncryptStringLengthRanges.Add(new NumberRange(ConfigUtil.ParseNullableInt(parts[0]), ConfigUtil.ParseNullableInt(parts[1]))); - break; - } - case "array-length-range": - { - var parts = value.Split(','); - if (parts.Length != 2) - { - throw new Exception($"Invalid xml file, array-length-range {value} is invalid"); - } - notEncryptArrayLengthRanges.Add(new NumberRange(ConfigUtil.ParseNullableInt(parts[0]), ConfigUtil.ParseNullableInt(parts[1]))); - break; - } - default: throw new Exception($"Invalid xml file, unknown whitelist type {type} in {childEle.Name} node"); - } - } - - private ObfuscationRule GetMethodObfuscationRule(MethodDef method) - { - if (!_methodRuleCache.TryGetValue(method, out var rule)) - { - rule = _xmlParser.GetMethodRule(method, _global); - _methodRuleCache[method] = rule; - } - return rule; - } - - public override bool NeedObfuscateMethod(MethodDef method) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - return rule.disableEncrypt != true; - } - - public override ConstCachePolicy GetMethodConstCachePolicy(MethodDef method) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - return new ConstCachePolicy - { - cacheConstInLoop = rule.cacheConstInLoop.Value, - cacheConstNotInLoop = rule.cacheConstNotInLoop.Value, - cacheStringInLoop = rule.cacheStringInLoop.Value, - cacheStringNotInLoop = rule.cacheStringNotInLoop.Value, - }; - } - - public override bool NeedObfuscateInt(MethodDef method, bool currentInLoop, int value) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - if (rule.encryptInt == false) - { - return false; - } - if (currentInLoop && rule.encryptConstInLoop == false) - { - return false; - } - if (notEncryptInts.Contains(value)) - { - return false; - } - foreach (var range in notEncryptIntRanges) - { - if (range.min != null && value < range.min) - { - continue; - } - if (range.max != null && value > range.max) - { - continue; - } - return false; - } - return true; - } - - public override bool NeedObfuscateLong(MethodDef method, bool currentInLoop, long value) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - if (rule.encryptLong == false) - { - return false; - } - if (currentInLoop && rule.encryptConstInLoop == false) - { - return false; - } - if (notEncryptLongs.Contains(value)) - { - return false; - } - foreach (var range in notEncryptLongRanges) - { - if (range.min != null && value < range.min) - { - continue; - } - if (range.max != null && value > range.max) - { - continue; - } - return false; - } - return true; - } - - public override bool NeedObfuscateFloat(MethodDef method, bool currentInLoop, float value) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - if (rule.encryptFloat == false) - { - return false; - } - if (currentInLoop && rule.encryptConstInLoop == false) - { - return false; - } - foreach (var range in notEncryptFloatRanges) - { - if (range.min != null && value < range.min) - { - continue; - } - if (range.max != null && value > range.max) - { - continue; - } - return false; - } - return true; - } - - public override bool NeedObfuscateDouble(MethodDef method, bool currentInLoop, double value) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - if (rule.encryptDouble == false) - { - return false; - } - if (currentInLoop && rule.encryptConstInLoop == false) - { - return false; - } - foreach (var range in notEncryptDoubleRanges) - { - if (range.min != null && value < range.min) - { - continue; - } - if (range.max != null && value > range.max) - { - continue; - } - return false; - } - return true; - } - - public override bool NeedObfuscateString(MethodDef method, bool currentInLoop, string value) - { - if (string.IsNullOrEmpty(value)) - { - return false; - } - ObfuscationRule rule = GetMethodObfuscationRule(method); - if (rule.encryptString == false) - { - return false; - } - if (currentInLoop && rule.encryptConstInLoop == false) - { - return false; - } - if (notEncryptStrings.Contains(value)) - { - return false; - } - foreach (var range in notEncryptStringLengthRanges) - { - if (range.min != null && value.Length < range.min) - { - continue; - } - if (range.max != null && value.Length > range.max) - { - continue; - } - return false; - } - return true; - } - - public override bool NeedObfuscateArray(MethodDef method, bool currentInLoop, byte[] array) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - if (rule.encryptArray == false) - { - return false; - } - if (currentInLoop && rule.encryptConstInLoop == false) - { - return false; - } - foreach (var range in notEncryptArrayLengthRanges) - { - if (range.min != null && array.Length < range.min) - { - continue; - } - if (range.max != null && array.Length > range.max) - { - continue; - } - return false; - } - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConfigurableEncryptPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConfigurableEncryptPolicy.cs.meta deleted file mode 100644 index 73c07be9..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConfigurableEncryptPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: da25453bc1fda394097c052af7733260 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs deleted file mode 100644 index 896e08a7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs +++ /dev/null @@ -1,137 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Emit; -using Obfuz.Settings; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.ConstEncrypt -{ - - public class ConstEncryptPass : BasicBlockObfuscationPassBase - { - private readonly ConstEncryptionSettingsFacade _settings; - private IEncryptPolicy _dataObfuscatorPolicy; - private IConstEncryptor _dataObfuscator; - public override ObfuscationPassType Type => ObfuscationPassType.ConstEncrypt; - - public ConstEncryptPass(ConstEncryptionSettingsFacade settings) - { - _settings = settings; - } - - public override void Start() - { - var ctx = ObfuscationPassContext.Current; - _dataObfuscatorPolicy = new ConfigurableEncryptPolicy(ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles); - _dataObfuscator = new DefaultConstEncryptor(ctx.moduleEntityManager, _settings); - } - - public override void Stop() - { - - } - - protected override bool NeedObfuscateMethod(MethodDef method) - { - return _dataObfuscatorPolicy.NeedObfuscateMethod(method); - } - - protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, BasicBlock block, int instructionIndex, IList globalInstructions, - List outputInstructions, List totalFinalInstructions) - { - bool currentInLoop = block.inLoop; - ConstCachePolicy constCachePolicy = _dataObfuscatorPolicy.GetMethodConstCachePolicy(method); - bool needCache = currentInLoop ? constCachePolicy.cacheConstInLoop : constCachePolicy.cacheConstNotInLoop; - switch (inst.OpCode.Code) - { - case Code.Ldc_I4: - case Code.Ldc_I4_S: - case Code.Ldc_I4_0: - case Code.Ldc_I4_1: - case Code.Ldc_I4_2: - case Code.Ldc_I4_3: - case Code.Ldc_I4_4: - case Code.Ldc_I4_5: - case Code.Ldc_I4_6: - case Code.Ldc_I4_7: - case Code.Ldc_I4_8: - case Code.Ldc_I4_M1: - { - int value = inst.GetLdcI4Value(); - if (_dataObfuscatorPolicy.NeedObfuscateInt(method, currentInLoop, value)) - { - _dataObfuscator.ObfuscateInt(method, needCache, value, outputInstructions); - return true; - } - return false; - } - case Code.Ldc_I8: - { - long value = (long)inst.Operand; - if (_dataObfuscatorPolicy.NeedObfuscateLong(method, currentInLoop, value)) - { - _dataObfuscator.ObfuscateLong(method, needCache, value, outputInstructions); - return true; - } - return false; - } - case Code.Ldc_R4: - { - float value = (float)inst.Operand; - if (_dataObfuscatorPolicy.NeedObfuscateFloat(method, currentInLoop, value)) - { - _dataObfuscator.ObfuscateFloat(method, needCache, value, outputInstructions); - return true; - } - return false; - } - case Code.Ldc_R8: - { - double value = (double)inst.Operand; - if (_dataObfuscatorPolicy.NeedObfuscateDouble(method, currentInLoop, value)) - { - _dataObfuscator.ObfuscateDouble(method, needCache, value, outputInstructions); - return true; - } - return false; - } - case Code.Ldstr: - { - string value = (string)inst.Operand; - if (_dataObfuscatorPolicy.NeedObfuscateString(method, currentInLoop, value)) - { - _dataObfuscator.ObfuscateString(method, needCache, value, outputInstructions); - return true; - } - return false; - } - case Code.Call: - { - if (((IMethod)inst.Operand).FullName == "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") - { - Instruction prevInst = globalInstructions[instructionIndex - 1]; - if (prevInst.OpCode.Code == Code.Ldtoken) - { - IField rvaField = (IField)prevInst.Operand; - FieldDef ravFieldDef = rvaField.ResolveFieldDefThrow(); - if (ravFieldDef.Module != method.Module) - { - return false; - } - byte[] data = ravFieldDef.InitialValue; - if (data != null && data.Length > 0 && _dataObfuscatorPolicy.NeedObfuscateArray(method, currentInLoop, data)) - { - // don't need cache for byte array obfuscation - needCache = false; - _dataObfuscator.ObfuscateBytes(method, needCache, ravFieldDef, data, outputInstructions); - return true; - } - } - } - return false; - } - default: return false; - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs.meta deleted file mode 100644 index da7fdfbf..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: aa0e9191126d4e24c92546b6af2c52cf -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs deleted file mode 100644 index 24b3cb93..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs +++ /dev/null @@ -1,337 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.Settings; -using Obfuz.Utils; -using System.Collections.Generic; -using System.Text; -using UnityEngine.Assertions; - -namespace Obfuz.ObfusPasses.ConstEncrypt -{ - public class DefaultConstEncryptor : IConstEncryptor - { - private readonly GroupByModuleEntityManager _moduleEntityManager; - private readonly ConstEncryptionSettingsFacade _settings; - - public DefaultConstEncryptor(GroupByModuleEntityManager moduleEntityManager, ConstEncryptionSettingsFacade settings) - { - _moduleEntityManager = moduleEntityManager; - _settings = settings; - } - - private IRandom CreateRandomForValue(EncryptionScopeInfo encryptionScope, int value) - { - return encryptionScope.localRandomCreator(value); - } - - private int GenerateEncryptionOperations(EncryptionScopeInfo encryptionScope, IRandom random) - { - return EncryptionUtil.GenerateEncryptionOpCodes(random, encryptionScope.encryptor, _settings.encryptionLevel); - } - - public int GenerateSalt(IRandom random) - { - return random.NextInt(); - } - - private DefaultMetadataImporter GetModuleMetadataImporter(MethodDef method) - { - return _moduleEntityManager.GetEntity(method.Module); - } - - public void ObfuscateInt(MethodDef method, bool needCacheValue, int value, List obfuscatedInstructions) - { - EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module); - IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode()); - ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity(method.Module); - RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity(method.Module); - DefaultMetadataImporter importer = GetModuleMetadataImporter(method); - - switch (random.NextInt(5)) - { - case 0: - { - // = c = encrypted static field - FieldDef cacheField = constFieldAllocator.Allocate(value); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); - break; - } - case 1: - { - // c = a + b - int a = random.NextInt(); - int b = value - a; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Add)); - break; - } - case 2: - { - // c = a * b - int a = random.NextInt() | 0x1; - int ra = MathUtil.ModInverse32(a); - int b = ra * value; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Mul)); - break; - } - case 3: - { - // c = a ^ b - int a = random.NextInt(); - int b = a ^ value; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Xor)); - break; - } - default: - { - if (needCacheValue) - { - FieldDef cacheField = constFieldAllocator.Allocate(value); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); - return; - } - int ops = GenerateEncryptionOperations(encryptionScope, random); - int salt = GenerateSalt(random); - int encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt)); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaInt)); - break; - } - } - - - } - - public void ObfuscateLong(MethodDef method, bool needCacheValue, long value, List obfuscatedInstructions) - { - EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module); - IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode()); - ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity(method.Module); - RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity(method.Module); - DefaultMetadataImporter importer = GetModuleMetadataImporter(method); - - switch (random.NextInt(5)) - { - case 0: - { - // c = encrypted static field - FieldDef cacheField = constFieldAllocator.Allocate(value); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); - break; - } - case 1: - { - // c = a + b - long a = random.NextLong(); - long b = value - a; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Add)); - break; - } - case 2: - { - // c = a * b - long a = random.NextLong() | 0x1; - long ra = MathUtil.ModInverse64(a); - long b = ra * value; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Mul)); - break; - } - case 3: - { - // c = a ^ b - long a = random.NextLong(); - long b = a ^ value; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Xor)); - break; - } - default: - { - if (needCacheValue) - { - FieldDef cacheField = constFieldAllocator.Allocate(value); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); - return; - } - - int ops = GenerateEncryptionOperations(encryptionScope, random); - int salt = GenerateSalt(random); - long encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt)); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaLong)); - break; - } - } - - - } - - public void ObfuscateFloat(MethodDef method, bool needCacheValue, float value, List obfuscatedInstructions) - { - EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module); - IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode()); - ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity(method.Module); - RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity(method.Module); - DefaultMetadataImporter importer = GetModuleMetadataImporter(method); - - if (needCacheValue) - { - FieldDef cacheField = constFieldAllocator.Allocate(value); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); - return; - } - - - int ops = GenerateEncryptionOperations(encryptionScope, random); - int salt = GenerateSalt(random); - float encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt)); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaFloat)); - } - - public void ObfuscateDouble(MethodDef method, bool needCacheValue, double value, List obfuscatedInstructions) - { - EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module); - IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode()); - ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity(method.Module); - RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity(method.Module); - DefaultMetadataImporter importer = GetModuleMetadataImporter(method); - - if (needCacheValue) - { - FieldDef cacheField = constFieldAllocator.Allocate(value); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); - return; - } - - - int ops = GenerateEncryptionOperations(encryptionScope, random); - int salt = GenerateSalt(random); - double encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt)); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaDouble)); - } - - - class EncryptedRvaDataInfo - { - public readonly FieldDef fieldDef; - public readonly byte[] originalBytes; - public readonly byte[] encryptedBytes; - public readonly int opts; - public readonly int salt; - - public EncryptedRvaDataInfo(FieldDef fieldDef, byte[] originalBytes, byte[] encryptedBytes, int opts, int salt) - { - this.fieldDef = fieldDef; - this.originalBytes = originalBytes; - this.encryptedBytes = encryptedBytes; - this.opts = opts; - this.salt = salt; - } - } - - private readonly Dictionary _encryptedRvaFields = new Dictionary(); - - private EncryptedRvaDataInfo GetEncryptedRvaData(FieldDef fieldDef) - { - if (!_encryptedRvaFields.TryGetValue(fieldDef, out var encryptedRvaData)) - { - EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(fieldDef.Module); - IRandom random = CreateRandomForValue(encryptionScope, FieldEqualityComparer.CompareDeclaringTypes.GetHashCode(fieldDef)); - int ops = GenerateEncryptionOperations(encryptionScope, random); - int salt = GenerateSalt(random); - byte[] originalBytes = fieldDef.InitialValue; - byte[] encryptedBytes = (byte[])originalBytes.Clone(); - encryptionScope.encryptor.EncryptBlock(encryptedBytes, ops, salt); - Assert.AreNotEqual(originalBytes, encryptedBytes, "Original bytes should not be the same as encrypted bytes."); - encryptedRvaData = new EncryptedRvaDataInfo(fieldDef, originalBytes, encryptedBytes, ops, salt); - _encryptedRvaFields.Add(fieldDef, encryptedRvaData); - fieldDef.InitialValue = encryptedBytes; - byte[] decryptedBytes = (byte[])encryptedBytes.Clone(); - encryptionScope.encryptor.DecryptBlock(decryptedBytes, ops, salt); - AssertUtil.AreArrayEqual(originalBytes, decryptedBytes, "Decrypted bytes should match the original bytes after encryption and decryption."); - } - return encryptedRvaData; - } - - - public void ObfuscateBytes(MethodDef method, bool needCacheValue, FieldDef field, byte[] value, List obfuscatedInstructions) - { - EncryptedRvaDataInfo encryptedData = GetEncryptedRvaData(field); - Assert.AreEqual(value.Length, encryptedData.encryptedBytes.Length); - - DefaultMetadataImporter importer = GetModuleMetadataImporter(method); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.encryptedBytes.Length)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.opts)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.salt)); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptInitializeArray)); - } - - public void ObfuscateString(MethodDef method, bool needCacheValue, string value, List obfuscatedInstructions) - { - EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module); - IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode()); - ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity(method.Module); - RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity(method.Module); - DefaultMetadataImporter importer = GetModuleMetadataImporter(method); - - if (needCacheValue) - { - FieldDef cacheField = constFieldAllocator.Allocate(value); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); - return; - } - - int ops = GenerateEncryptionOperations(encryptionScope, random); - int salt = GenerateSalt(random); - int stringByteLength = Encoding.UTF8.GetByteCount(value); - byte[] encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); - Assert.AreEqual(stringByteLength, encryptedValue.Length); - RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); - - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); - // should use stringByteLength, can't use rvaData.size, because rvaData.size is align to 4, it's not the actual length. - obfuscatedInstructions.Add(Instruction.CreateLdcI4(stringByteLength)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt)); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString)); - } - - public void Done() - { - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs.meta deleted file mode 100644 index 1e0977a2..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4c6a0ecde97527e4694731e4d4de129a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IConstEncryptor.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IConstEncryptor.cs deleted file mode 100644 index 0b2c087c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IConstEncryptor.cs +++ /dev/null @@ -1,32 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.ConstEncrypt -{ - public interface IConstEncryptor - { - void ObfuscateInt(MethodDef method, bool needCacheValue, int value, List obfuscatedInstructions); - - void ObfuscateLong(MethodDef method, bool needCacheValue, long value, List obfuscatedInstructions); - - void ObfuscateFloat(MethodDef method, bool needCacheValue, float value, List obfuscatedInstructions); - - void ObfuscateDouble(MethodDef method, bool needCacheValue, double value, List obfuscatedInstructions); - - void ObfuscateString(MethodDef method, bool needCacheValue, string value, List obfuscatedInstructions); - - void ObfuscateBytes(MethodDef method, bool needCacheValue, FieldDef field, byte[] value, List obfuscatedInstructions); - } - - public abstract class ConstEncryptorBase : IConstEncryptor - { - public abstract void ObfuscateBytes(MethodDef method, bool needCacheValue, byte[] value, List obfuscatedInstructions); - public abstract void ObfuscateDouble(MethodDef method, bool needCacheValue, double value, List obfuscatedInstructions); - public abstract void ObfuscateFloat(MethodDef method, bool needCacheValue, float value, List obfuscatedInstructions); - public abstract void ObfuscateInt(MethodDef method, bool needCacheValue, int value, List obfuscatedInstructions); - public abstract void ObfuscateLong(MethodDef method, bool needCacheValue, long value, List obfuscatedInstructions); - public abstract void ObfuscateString(MethodDef method, bool needCacheValue, string value, List obfuscatedInstructions); - public abstract void ObfuscateBytes(MethodDef method, bool needCacheValue, FieldDef field, byte[] value, List obfuscatedInstructions); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IConstEncryptor.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IConstEncryptor.cs.meta deleted file mode 100644 index 7f8d5871..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IConstEncryptor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0ccbcdadf1913b6498eaee53abac5d0b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IEncryptPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IEncryptPolicy.cs deleted file mode 100644 index 0067cc0f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IEncryptPolicy.cs +++ /dev/null @@ -1,43 +0,0 @@ -using dnlib.DotNet; - -namespace Obfuz.ObfusPasses.ConstEncrypt -{ - public struct ConstCachePolicy - { - public bool cacheConstInLoop; - public bool cacheConstNotInLoop; - public bool cacheStringInLoop; - public bool cacheStringNotInLoop; - } - - public interface IEncryptPolicy - { - bool NeedObfuscateMethod(MethodDef method); - - ConstCachePolicy GetMethodConstCachePolicy(MethodDef method); - - bool NeedObfuscateInt(MethodDef method, bool currentInLoop, int value); - - bool NeedObfuscateLong(MethodDef method, bool currentInLoop, long value); - - bool NeedObfuscateFloat(MethodDef method, bool currentInLoop, float value); - - bool NeedObfuscateDouble(MethodDef method, bool currentInLoop, double value); - - bool NeedObfuscateString(MethodDef method, bool currentInLoop, string value); - - bool NeedObfuscateArray(MethodDef method, bool currentInLoop, byte[] array); - } - - public abstract class EncryptPolicyBase : IEncryptPolicy - { - public abstract bool NeedObfuscateMethod(MethodDef method); - public abstract ConstCachePolicy GetMethodConstCachePolicy(MethodDef method); - public abstract bool NeedObfuscateDouble(MethodDef method, bool currentInLoop, double value); - public abstract bool NeedObfuscateFloat(MethodDef method, bool currentInLoop, float value); - public abstract bool NeedObfuscateInt(MethodDef method, bool currentInLoop, int value); - public abstract bool NeedObfuscateLong(MethodDef method, bool currentInLoop, long value); - public abstract bool NeedObfuscateString(MethodDef method, bool currentInLoop, string value); - public abstract bool NeedObfuscateArray(MethodDef method, bool currentInLoop, byte[] array); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IEncryptPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IEncryptPolicy.cs.meta deleted file mode 100644 index 0a44790d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ConstEncrypt/IEncryptPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 18e57864070430a44ac561bdd7d00b2e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus.meta deleted file mode 100644 index 9013ba54..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 02fb097cf61874c41923b3ef23fee199 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs deleted file mode 100644 index b86b1e7c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs +++ /dev/null @@ -1,133 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Conf; -using Obfuz.Settings; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Xml; - -namespace Obfuz.ObfusPasses.ControlFlowObfus -{ - struct ObfuscationRuleData - { - public readonly ObfuscationLevel obfuscationLevel; - public ObfuscationRuleData(ObfuscationLevel level) - { - obfuscationLevel = level; - } - } - - interface IObfuscationPolicy - { - bool NeedObfuscate(MethodDef method); - - ObfuscationRuleData GetObfuscationRuleData(MethodDef method); - } - - abstract class ObfuscationPolicyBase : IObfuscationPolicy - { - public abstract bool NeedObfuscate(MethodDef method); - - public abstract ObfuscationRuleData GetObfuscationRuleData(MethodDef method); - } - - class ConfigurableObfuscationPolicy : ObfuscationPolicyBase - { - class ObfuscationRule : IRule - { - public ObfuscationLevel? obfuscationLevel; - - public void InheritParent(ObfuscationRule parentRule) - { - if (obfuscationLevel == null) - obfuscationLevel = parentRule.obfuscationLevel; - } - } - - class MethodSpec : MethodRuleBase - { - } - - class TypeSpec : TypeRuleBase - { - } - - class AssemblySpec : AssemblyRuleBase - { - } - - private static readonly ObfuscationRule s_default = new ObfuscationRule() - { - obfuscationLevel = ObfuscationLevel.Basic, - }; - - private ObfuscationRule _global; - - private readonly XmlAssemblyTypeMethodRuleParser _xmlParser; - - private readonly Dictionary _methodRuleCache = new Dictionary(); - - public ConfigurableObfuscationPolicy(List toObfuscatedAssemblyNames, List xmlConfigFiles) - { - _xmlParser = new XmlAssemblyTypeMethodRuleParser( - toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobal); - LoadConfigs(xmlConfigFiles); - } - - private void LoadConfigs(List configFiles) - { - _xmlParser.LoadConfigs(configFiles); - - if (_global == null) - { - _global = s_default; - } - else - { - _global.InheritParent(s_default); - } - _xmlParser.InheritParentRules(_global); - } - - private void ParseGlobal(string configFile, XmlElement ele) - { - switch (ele.Name) - { - case "global": _global = ParseObfuscationRule(configFile, ele); break; - default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}"); - } - } - - private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) - { - var rule = new ObfuscationRule(); - if (ele.HasAttribute("obfuscationLevel")) - { - rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); - } - return rule; - } - - private ObfuscationRule GetMethodObfuscationRule(MethodDef method) - { - if (!_methodRuleCache.TryGetValue(method, out var rule)) - { - rule = _xmlParser.GetMethodRule(method, _global); - _methodRuleCache[method] = rule; - } - return rule; - } - - public override bool NeedObfuscate(MethodDef method) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - return rule.obfuscationLevel.Value > ObfuscationLevel.None; - } - - public override ObfuscationRuleData GetObfuscationRuleData(MethodDef method) - { - var rule = GetMethodObfuscationRule(method); - return new ObfuscationRuleData(rule.obfuscationLevel.Value); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs.meta deleted file mode 100644 index 1203f4b8..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f6983877d8859df4882c30f75be7a70e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ControlFlowObfusPass.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ControlFlowObfusPass.cs deleted file mode 100644 index bcb04e05..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ControlFlowObfusPass.cs +++ /dev/null @@ -1,80 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.Settings; -using Obfuz.Utils; - -namespace Obfuz.ObfusPasses.ControlFlowObfus -{ - class ObfusMethodContext - { - public MethodDef method; - public LocalVariableAllocator localVariableAllocator; - public IRandom localRandom; - public EncryptionScopeInfo encryptionScope; - public DefaultMetadataImporter importer; - public ConstFieldAllocator constFieldAllocator; - public int minInstructionCountOfBasicBlockToObfuscate; - - public IRandom CreateRandom() - { - return encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)); - } - } - - internal class ControlFlowObfusPass : ObfuscationMethodPassBase - { - private readonly ControlFlowObfuscationSettingsFacade _settings; - - private IObfuscationPolicy _obfuscationPolicy; - private IObfuscator _obfuscator; - - public ControlFlowObfusPass(ControlFlowObfuscationSettingsFacade settings) - { - _settings = settings; - _obfuscator = new DefaultObfuscator(); - } - - public override ObfuscationPassType Type => ObfuscationPassType.ControlFlowObfus; - - public override void Start() - { - ObfuscationPassContext ctx = ObfuscationPassContext.Current; - _obfuscationPolicy = new ConfigurableObfuscationPolicy( - ctx.coreSettings.assembliesToObfuscate, - _settings.ruleFiles); - } - - public override void Stop() - { - - } - - protected override bool NeedObfuscateMethod(MethodDef method) - { - return _obfuscationPolicy.NeedObfuscate(method); - } - - protected override void ObfuscateData(MethodDef method) - { - //Debug.Log($"Obfuscating method: {method.FullName} with EvalStackObfusPass"); - - ObfuscationPassContext ctx = ObfuscationPassContext.Current; - GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager; - var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module); - var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method); - var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)); - var obfusMethodCtx = new ObfusMethodContext - { - method = method, - localVariableAllocator = new LocalVariableAllocator(method), - encryptionScope = encryptionScope, - constFieldAllocator = moduleEntityManager.GetEntity(method.Module), - localRandom = localRandom, - importer = moduleEntityManager.GetEntity(method.Module), - minInstructionCountOfBasicBlockToObfuscate = _settings.minInstructionCountOfBasicBlockToObfuscate, - }; - _obfuscator.Obfuscate(method, obfusMethodCtx); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ControlFlowObfusPass.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ControlFlowObfusPass.cs.meta deleted file mode 100644 index ad62fd65..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/ControlFlowObfusPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cf62db4d3137e6447bd5cb2a65f101d3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/DefaultObfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/DefaultObfuscator.cs deleted file mode 100644 index 9bd216aa..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/DefaultObfuscator.cs +++ /dev/null @@ -1,20 +0,0 @@ -using dnlib.DotNet; -using UnityEngine; - -namespace Obfuz.ObfusPasses.ControlFlowObfus -{ - class DefaultObfuscator : ObfuscatorBase - { - public override bool Obfuscate(MethodDef method, ObfusMethodContext ctx) - { - //Debug.Log($"Obfuscating method: {method.FullName} with ControlFlowObfusPass"); - var mcfc = new MethodControlFlowCalculator(method, ctx.CreateRandom(), ctx.constFieldAllocator, ctx.minInstructionCountOfBasicBlockToObfuscate); - if (!mcfc.TryObfus()) - { - //Debug.LogWarning($"not obfuscate method: {method.FullName}"); - return false; - } - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/DefaultObfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/DefaultObfuscator.cs.meta deleted file mode 100644 index 25926093..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/DefaultObfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8aa2a2e43fa066541b982dbb63452458 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/IObfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/IObfuscator.cs deleted file mode 100644 index 7909bf2c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/IObfuscator.cs +++ /dev/null @@ -1,15 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Emit; - -namespace Obfuz.ObfusPasses.ControlFlowObfus -{ - interface IObfuscator - { - bool Obfuscate(MethodDef method, ObfusMethodContext ctx); - } - - abstract class ObfuscatorBase : IObfuscator - { - public abstract bool Obfuscate(MethodDef method, ObfusMethodContext ctx); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/IObfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/IObfuscator.cs.meta deleted file mode 100644 index e909f237..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/IObfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4ada5f6005768f745a18dc8b968e1684 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/MethodControlFlowCalculator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/MethodControlFlowCalculator.cs deleted file mode 100644 index 06488c0d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/MethodControlFlowCalculator.cs +++ /dev/null @@ -1,894 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Obfuz.ObfusPasses.ControlFlowObfus -{ - class MethodControlFlowCalculator - { - class BasicBlockInputOutputArguments - { - public readonly List locals = new List(); - - public BasicBlockInputOutputArguments() - { - } - - public BasicBlockInputOutputArguments(MethodDef method, List inputStackDatas) - { - ICorLibTypes corLibTypes = method.Module.CorLibTypes; - foreach (var data in inputStackDatas) - { - Local local = new Local(GetLocalTypeSig(corLibTypes, data)); - locals.Add(local); - method.Body.Variables.Add(local); - } - } - - private TypeSig GetLocalTypeSig(ICorLibTypes corLibTypes, EvalDataTypeWithSig type) - { - switch (type.type) - { - case EvalDataType.Int32: return corLibTypes.Int32; - case EvalDataType.Int64: return corLibTypes.Int64; - case EvalDataType.Float: return corLibTypes.Single; - case EvalDataType.Double: return corLibTypes.Double; - case EvalDataType.I: return corLibTypes.IntPtr; - case EvalDataType.Ref: Assert.IsNotNull(type.typeSig); return type.typeSig; - case EvalDataType.ValueType: Assert.IsNotNull(type.typeSig); return type.typeSig; - case EvalDataType.Token: throw new System.NotSupportedException("Token type is not supported in BasicBlockInputOutputArguments"); - default: throw new System.NotSupportedException("not supported EvalDataType"); - } - } - } - - class BasicBlockInfo - { - public BlockGroup group; - - //public int order; - public bool isSaveStackBlock; - public BasicBlockInfo prev; - public BasicBlockInfo next; - - public List instructions; - public List inputStackDatas; - public List outputStackDatas; - - public List inBasicBlocks = new List(); - public List outBasicBlocks = new List(); - - public BasicBlockInputOutputArguments inputArgs; - public BasicBlockInputOutputArguments outputArgs; - - public Instruction FirstInstruction => instructions[0]; - - public Instruction LastInstruction => instructions[instructions.Count - 1]; - - public Instruction GroupFirstInstruction => group.basicBlocks[0].FirstInstruction; - - - //public void InsertNext(BasicBlockInfo nextBb) - //{ - // if (next != null) - // { - // next.prev = nextBb; - // nextBb.next = next; - // } - // nextBb.prev = this; - // next = nextBb; - //} - - public void InsertBefore(BasicBlockInfo prevBb) - { - prev.next = prevBb; - prevBb.prev = prev; - prevBb.next = this; - this.prev = prevBb; - } - - public void AddOutBasicBlock(BasicBlockInfo outBb) - { - if (!outBasicBlocks.Contains(outBb)) - { - outBasicBlocks.Add(outBb); - outBb.inBasicBlocks.Add(this); - } - } - - public void ClearInBasicBlocks() - { - foreach (var inBb in inBasicBlocks) - { - inBb.outBasicBlocks.Remove(this); - } - inBasicBlocks.Clear(); - } - - public void RetargetInBasicBlocksTo(BasicBlockInfo prevBb, Dictionary inst2bb) - { - var oldInBlocks = new List(inBasicBlocks); - ClearInBasicBlocks(); - foreach (var oldInBb in oldInBlocks) - { - oldInBb.AddOutBasicBlock(prevBb); - } - // inBB => saveBb => cur - foreach (BasicBlockInfo inBb in prevBb.inBasicBlocks) - { - if (inBb.instructions.Count == 0) - { - // empty block, no need to retarget - continue; - } - Instruction lastInst = inBb.instructions.Last(); - if (lastInst.Operand is Instruction targetInst) - { - if (inst2bb.TryGetValue(targetInst, out BasicBlockInfo targetBb) && targetBb == this) - { - // retarget to prevBb - lastInst.Operand = prevBb.FirstInstruction; - } - } - else if (lastInst.Operand is Instruction[] targetInsts) - { - for (int i = 0; i < targetInsts.Length; i++) - { - targetInst = targetInsts[i]; - if (inst2bb.TryGetValue(targetInst, out BasicBlockInfo targetBb) && targetBb == this) - { - targetInsts[i] = prevBb.FirstInstruction; - } - } - } - } - } - } - - private readonly MethodDef _method; - private readonly IRandom _random; - private readonly ConstFieldAllocator _constFieldAllocator; - private readonly int _minInstructionCountOfBasicBlockToObfuscate; - private readonly BasicBlockInfo _bbHead; - - public MethodControlFlowCalculator(MethodDef method, IRandom random, ConstFieldAllocator constFieldAllocator, int minInstructionCountOfBasicBlockToObfuscate) - { - _method = method; - _random = random; - _constFieldAllocator = constFieldAllocator; - _minInstructionCountOfBasicBlockToObfuscate = minInstructionCountOfBasicBlockToObfuscate; - - _bbHead = new BasicBlockInfo() - { - instructions = new List(), - inputStackDatas = new List(), - outputStackDatas = new List(), - }; - } - - private void BuildBasicBlockLink(EvalStackCalculator evc) - { - BasicBlockInfo prev = _bbHead; - var bb2bb = new Dictionary(); - foreach (BasicBlock bb in evc.BasicBlockCollection.Blocks) - { - EvalStackState ess = evc.GetEvalStackState(bb); - var newBB = new BasicBlockInfo - { - prev = prev, - next = null, - instructions = bb.instructions, - inputStackDatas = ess.inputStackDatas, - outputStackDatas = ess.runStackDatas, - }; - prev.next = newBB; - prev = newBB; - bb2bb.Add(bb, newBB); - } - foreach (BasicBlock bb in evc.BasicBlockCollection.Blocks) - { - BasicBlockInfo bbi = bb2bb[bb]; - foreach (var inBb in bb.inBlocks) - { - bbi.inBasicBlocks.Add(bb2bb[inBb]); - } - foreach (var outBb in bb.outBlocks) - { - bbi.outBasicBlocks.Add(bb2bb[outBb]); - } - } - - // let _bbHead point to the first basic block - //_bbHead.instructions.Add(Instruction.Create(OpCodes.Br, _bbHead.next.FirstInstruction)); - _bbHead.next.inBasicBlocks.Add(_bbHead); - _bbHead.outBasicBlocks.Add(_bbHead.next); - } - - private bool CheckNotContainsNotSupportedEvalStackData() - { - for (BasicBlockInfo cur = _bbHead; cur != null; cur = cur.next) - { - foreach (var data in cur.inputStackDatas) - { - if (data.type == EvalDataType.Unknown || data.type == EvalDataType.Token) - { - Debug.LogError($"NotSupported EvalStackData found in method: {_method.FullName}, type: {data.type}"); - return false; - } - } - } - return true; - } - - - private void WalkInputArgumentGroup(BasicBlockInfo cur, BasicBlockInputOutputArguments inputArgs) - { - if (cur.inputArgs != null) - { - Assert.AreEqual(cur.inputArgs, inputArgs, "input arguments not match"); - return; - } - cur.inputArgs = inputArgs; - foreach (BasicBlockInfo inputBB in cur.inBasicBlocks) - { - if (inputBB.outputArgs != null) - { - Assert.AreEqual(inputBB.outputArgs, inputArgs, $"Input BB {inputBB} outputArgs does not match in method: {_method.FullName}"); - continue; - } - inputBB.outputArgs = cur.inputArgs; - foreach (var outBB in inputBB.outBasicBlocks) - { - WalkInputArgumentGroup(outBB, inputArgs); - } - } - } - - private readonly BasicBlockInputOutputArguments emptyEvalStackArgs = new BasicBlockInputOutputArguments(); - - private void ComputeInputOutputArguments() - { - for (BasicBlockInfo cur = _bbHead; cur != null; cur = cur.next) - { - if (cur.inputArgs == null) - { - if (cur.inputStackDatas.Count == 0) - { - cur.inputArgs = emptyEvalStackArgs; - } - else - { - var inputArgs = new BasicBlockInputOutputArguments(_method, cur.inputStackDatas); - WalkInputArgumentGroup(cur, inputArgs); - } - } - if (cur.outputArgs == null && cur.outputStackDatas.Count == 0) - { - cur.outputArgs = emptyEvalStackArgs; - } - } - for (BasicBlockInfo cur = _bbHead; cur != null; cur = cur.next) - { - if (cur.inputArgs == null) - { - throw new System.Exception($"Input arguments for BasicBlock {cur} in method {_method.FullName} is null"); - } - if (cur.outputArgs == null) - { - if (cur.instructions.Count > 0) - { - Code lastInstCode = cur.LastInstruction.OpCode.Code; - Assert.IsTrue(lastInstCode == Code.Throw || lastInstCode == Code.Rethrow); - cur.outputStackDatas = new List(); - } - cur.outputArgs = emptyEvalStackArgs; - } - } - } - - - private BasicBlockInfo CreateSaveStackBasicBlock(BasicBlockInfo to) - { - if (to.group == null) - { - throw new Exception($"BasicBlock {to} in method {_method.FullName} does not belong to any group. This should not happen."); - } - - var saveLocalBasicBlock = new BasicBlockInfo - { - group = to.group, - isSaveStackBlock = true, - inputStackDatas = to.inputStackDatas, - inputArgs = to.inputArgs, - outputStackDatas = new List(), - outputArgs = emptyEvalStackArgs, - instructions = new List(), - }; - - var locals = to.inputArgs.locals; - if (locals.Count > 0) - { - to.instructions.InsertRange(0, locals.Select(l => Instruction.Create(OpCodes.Ldloc, l))); - - } - for (int i = locals.Count - 1; i >= 0; i--) - { - saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Stloc, locals[i])); - } - - to.inputArgs = emptyEvalStackArgs; - to.inputStackDatas = new List(); - - BlockGroup group = to.group; - group.basicBlocks.Insert(group.basicBlocks.IndexOf(to), saveLocalBasicBlock); - group.switchMachineCases.Add(new SwitchMachineCase { index = -1, prepareBlock = saveLocalBasicBlock, targetBlock = to}); - saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Ldsfld, (FieldDef)null)); - saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Br, group.switchMachineInst)); - - - return saveLocalBasicBlock; - } - - private void AdjustInputOutputEvalStack() - { - Dictionary inst2bb = BuildInstructionToBasicBlockInfoDic(); - for (BasicBlockInfo cur = _bbHead.next; cur != null; cur = cur.next) - { - if (cur.inputArgs.locals.Count == 0 && cur.instructions.Count < _minInstructionCountOfBasicBlockToObfuscate) - { - // small block, no need to save stack - continue; - } - - BasicBlockInfo saveBb = CreateSaveStackBasicBlock(cur); - cur.InsertBefore(saveBb); - cur.RetargetInBasicBlocksTo(saveBb, inst2bb); - //saveBb.AddOutBasicBlock(cur); - } - } - - private void InsertSwitchMachineBasicBlockForGroups(BlockGroup rootGroup) - { - Dictionary inst2bb = BuildInstructionToBasicBlockInfoDic(); - - InsertSwitchMachineBasicBlockForGroup(rootGroup, inst2bb); - } - - //private void ShuffleBasicBlocks0(List bbs) - //{ - // int n = bbs.Count; - // if (n <= 1) - // { - // return; - // } - - // var firstSection = new List() { bbs[0] }; - // var sectionsExcludeFirstLast = new List>(); - // List currentSection = firstSection; - // for (int i = 1; i < n; i++) - // { - // BasicBlockInfo cur = bbs[i]; - // if (cur.inputArgs.locals.Count == 0) - // { - // currentSection = new List() { cur }; - // sectionsExcludeFirstLast.Add(currentSection); - // } - // else - // { - // currentSection.Add(cur); - // } - // } - // if (sectionsExcludeFirstLast.Count <= 1) - // { - // return; - // } - // var lastSection = sectionsExcludeFirstLast.Last(); - // sectionsExcludeFirstLast.RemoveAt(sectionsExcludeFirstLast.Count - 1); - - - // RandomUtil.ShuffleList(sectionsExcludeFirstLast, _random); - - // bbs.Clear(); - // bbs.AddRange(firstSection); - // bbs.AddRange(sectionsExcludeFirstLast.SelectMany(section => section)); - // bbs.AddRange(lastSection); - // Assert.AreEqual(n, bbs.Count, "Shuffled basic blocks count should be the same as original count"); - //} - - private void ShuffleBasicBlocks(List bbs) - { - // TODO - - //int n = bbs.Count; - //BasicBlockInfo groupPrev = bbs[0].prev; - //BasicBlockInfo groupNext = bbs[n - 1].next; - ////RandomUtil.ShuffleList(bbs, _random); - //ShuffleBasicBlocks0(bbs); - //BasicBlockInfo prev = groupPrev; - //for (int i = 0; i < n; i++) - //{ - // BasicBlockInfo cur = bbs[i]; - // cur.prev = prev; - // prev.next = cur; - // prev = cur; - //} - //prev.next = groupNext; - //if (groupNext != null) - //{ - // groupNext.prev = prev; - //} - } - - private void InsertSwitchMachineBasicBlockForGroup(BlockGroup group, Dictionary inst2bb) - { - if (group.subGroups != null && group.subGroups.Count > 0) - { - foreach (var subGroup in group.subGroups) - { - InsertSwitchMachineBasicBlockForGroup(subGroup, inst2bb); - } - } - else if (group.switchMachineCases.Count > 0) - { - Assert.IsTrue(group.basicBlocks.Count > 0, "Group should contain at least one basic block"); - - BasicBlockInfo firstBlock = group.basicBlocks[0]; - var firstCase = group.switchMachineCases[0]; - //Assert.AreEqual(firstCase.prepareBlock, firstBlock, "First case prepare block should be the first basic block in group"); - - Assert.IsTrue(firstCase.targetBlock.inputArgs.locals.Count == 0); - Assert.IsTrue(firstCase.targetBlock.inputStackDatas.Count == 0); - - var instructions = new List() - { - Instruction.Create(OpCodes.Ldsfld, (FieldDef)null), - group.switchMachineInst, - Instruction.Create(OpCodes.Br, firstCase.targetBlock.FirstInstruction), - }; - if (firstCase.prepareBlock != firstBlock || firstBlock.inputStackDatas.Count != 0) - { - instructions.Insert(0, Instruction.Create(OpCodes.Br, firstBlock.FirstInstruction)); - } - - var switchMachineBb = new BasicBlockInfo() - { - group = group, - inputArgs = firstBlock.inputArgs, - outputArgs = emptyEvalStackArgs, - inputStackDatas = firstBlock.inputStackDatas, - outputStackDatas = new List(), - instructions = instructions, - }; - firstBlock.InsertBefore(switchMachineBb); - group.basicBlocks.Insert(0, switchMachineBb); - ShuffleBasicBlocks(group.basicBlocks); - - List switchTargets = (List)group.switchMachineInst.Operand; - - RandomUtil.ShuffleList(group.switchMachineCases, _random); - - for (int i = 0, n = group.switchMachineCases.Count; i < n; i++) - { - SwitchMachineCase switchMachineCase = group.switchMachineCases[i]; - switchMachineCase.index = i; - List prepareBlockInstructions = switchMachineCase.prepareBlock.instructions; - - Instruction setBranchIndexInst = prepareBlockInstructions[prepareBlockInstructions.Count - 2]; - Assert.AreEqual(setBranchIndexInst.OpCode, OpCodes.Ldsfld, "first instruction of prepareBlock should be Ldsfld"); - //setBranchIndexInst.Operand = i; - var indexField = _constFieldAllocator.Allocate(i); - setBranchIndexInst.Operand = indexField; - switchTargets.Add(switchMachineCase.targetBlock.FirstInstruction); - } - - // after shuffle - Assert.IsTrue(instructions.Count == 3 || instructions.Count == 4, "Switch machine basic block should contain 3 or 4 instructions"); - Assert.AreEqual(Code.Ldsfld, instructions[instructions.Count - 3].OpCode.Code, "First instruction should be Ldsfld"); - instructions[instructions.Count - 3].Operand = _constFieldAllocator.Allocate(firstCase.index); - } - } - - private bool IsPrevBasicBlockControlFlowNextToThis(BasicBlockInfo cur) - { - Instruction lastInst = cur.prev.LastInstruction; - switch (lastInst.OpCode.FlowControl) - { - case FlowControl.Cond_Branch: - case FlowControl.Call: - case FlowControl.Next: - case FlowControl.Break: - { - return true; - } - default: return false; - } - } - - private void InsertBrInstructionForConjoinedBasicBlocks() - { - for (BasicBlockInfo cur = _bbHead.next.next; cur != null; cur = cur.next) - { - if (cur.group == cur.prev.group && IsPrevBasicBlockControlFlowNextToThis(cur)) - { - cur.prev.instructions.Add(Instruction.Create(OpCodes.Br, cur.FirstInstruction)); - } - } - } - - private Dictionary BuildInstructionToBasicBlockInfoDic() - { - var inst2bb = new Dictionary(); - for (BasicBlockInfo cur = _bbHead.next; cur != null; cur = cur.next) - { - foreach (var inst in cur.instructions) - { - inst2bb[inst] = cur; - } - } - return inst2bb; - } - - - private class SwitchMachineCase - { - public int index; - public BasicBlockInfo prepareBlock; - public BasicBlockInfo targetBlock; - } - - private class BlockGroup - { - public BlockGroup parent; - - public List instructions; - - public List subGroups; - - public List basicBlocks; - - public Instruction switchMachineInst; - public List switchMachineCases; - - public BlockGroup(List instructions, Dictionary inst2group) - { - this.instructions = instructions; - UpdateInstructionGroup(inst2group); - } - - public BlockGroup(BlockGroup parent, List instructions, Dictionary inst2group) - { - this.instructions = instructions; - UpdateInstructionGroup(parent, inst2group); - } - - public BlockGroup RootParent => parent == null ? this : parent.RootParent; - - public void SetParent(BlockGroup newParent) - { - if (parent != null) - { - Assert.IsTrue(parent != newParent, "Parent group should not be the same as new parent"); - Assert.IsTrue(parent.subGroups.Contains(this), "Parent group should already contain this group"); - parent.subGroups.Remove(this); - } - parent = newParent; - if (newParent.subGroups == null) - { - newParent.subGroups = new List(); - } - Assert.IsFalse(newParent.subGroups.Contains(this), "New parent group should not already contain this group"); - newParent.subGroups.Add(this); - } - - private void UpdateInstructionGroup(Dictionary inst2group) - { - foreach (var inst in instructions) - { - if (inst2group.TryGetValue(inst, out BlockGroup existGroup)) - { - if (this != existGroup) - { - BlockGroup rootParent = existGroup.RootParent; - if (rootParent != this) - { - rootParent.SetParent(this); - } - } - } - else - { - inst2group[inst] = this; - } - } - } - - private void UpdateInstructionGroup(BlockGroup parentGroup, Dictionary inst2group) - { - foreach (var inst in instructions) - { - BlockGroup existGroup = inst2group[inst]; - Assert.AreEqual(parentGroup, existGroup, "Instruction group parent should be the same as parent group"); - inst2group[inst] = this; - } - SetParent(parentGroup); - } - - public void SplitInstructionsNotInAnySubGroupsToIndividualGroups(Dictionary inst2group) - { - if (subGroups == null || subGroups.Count == 0 || instructions.Count == 0) - { - return; - } - - foreach (var subGroup in subGroups) - { - subGroup.SplitInstructionsNotInAnySubGroupsToIndividualGroups(inst2group); - } - - var finalGroupList = new List(); - var curGroupInstructions = new List(); - - var firstInst2SubGroup = subGroups.ToDictionary(g => g.instructions[0]); - foreach (var inst in instructions) - { - BlockGroup group = inst2group[inst]; - if (group == this) - { - curGroupInstructions.Add(inst); - } - else - { - if (curGroupInstructions.Count > 0) - { - finalGroupList.Add(new BlockGroup(this, curGroupInstructions, inst2group)); - curGroupInstructions = new List(); - } - if (firstInst2SubGroup.TryGetValue(inst, out var subGroup)) - { - finalGroupList.Add(subGroup); - } - } - } - if (curGroupInstructions.Count > 0) - { - finalGroupList.Add(new BlockGroup(this, curGroupInstructions, inst2group)); - } - this.subGroups = finalGroupList; - } - - public void ComputeBasicBlocks(Dictionary inst2bb) - { - if (subGroups == null || subGroups.Count == 0) - { - basicBlocks = new List(); - foreach (var inst in instructions) - { - BasicBlockInfo block = inst2bb[inst]; - if (block.group != null) - { - if (block.group != this) - { - throw new Exception("BasicBlockInfo group should be the same as this BlockGroup"); - } - } - else - { - block.group = this; - basicBlocks.Add(block); - } - } - switchMachineInst = Instruction.Create(OpCodes.Switch, new List()); - switchMachineCases = new List(); - return; - } - foreach (var subGroup in subGroups) - { - subGroup.ComputeBasicBlocks(inst2bb); - } - } - } - - private class TryBlockGroup : BlockGroup - { - public TryBlockGroup(List instructions, Dictionary inst2group) : base(instructions, inst2group) - { - } - } - - private class ExceptionHandlerGroup : BlockGroup - { - public readonly ExceptionHandler exceptionHandler; - - public ExceptionHandlerGroup(ExceptionHandler exceptionHandler, List instructions, Dictionary inst2group) : base(instructions, inst2group) - { - this.exceptionHandler = exceptionHandler; - } - } - - private class ExceptionFilterGroup : BlockGroup - { - public readonly ExceptionHandler exceptionHandler; - - public ExceptionFilterGroup(ExceptionHandler exceptionHandler, List instructions, Dictionary inst2group) : base(instructions, inst2group) - { - this.exceptionHandler = exceptionHandler; - } - } - - private class ExceptionHandlerWithFilterGroup : BlockGroup - { - public readonly ExceptionHandler exceptionHandler; - //public readonly ExceptionFilterGroup filterGroup; - //public readonly ExceptionHandlerGroup handlerGroup; - public ExceptionHandlerWithFilterGroup(ExceptionHandler exceptionHandler, List filterInstructions, List handlerInstructions, List allInstructions, Dictionary inst2group) : base(allInstructions, inst2group) - { - this.exceptionHandler = exceptionHandler; - var filterGroup = new ExceptionFilterGroup(exceptionHandler, filterInstructions, inst2group); - var handlerGroup = new ExceptionHandlerGroup(exceptionHandler, handlerInstructions, inst2group); - } - } - - class TryBlockInfo - { - public Instruction tryStart; - public Instruction tryEnd; - public TryBlockGroup blockGroup; - } - - private Dictionary BuildInstruction2Index() - { - IList instructions = _method.Body.Instructions; - var inst2Index = new Dictionary(instructions.Count); - for (int i = 0; i < instructions.Count; i++) - { - Instruction inst = instructions[i]; - inst2Index.Add(inst, i); - } - return inst2Index; - } - - private BlockGroup SplitBasicBlockGroup() - { - Dictionary inst2Index = BuildInstruction2Index(); - var inst2blockGroup = new Dictionary(); - - List instructions = (List)_method.Body.Instructions; - - var tryBlocks = new List(); - foreach (var ex in _method.Body.ExceptionHandlers) - { - TryBlockInfo tryBlock = tryBlocks.Find(tryBlocks => tryBlocks.tryStart == ex.TryStart && tryBlocks.tryEnd == ex.TryEnd); - if (tryBlock == null) - { - int startIndex = inst2Index[ex.TryStart]; - int endIndex = ex.TryEnd != null ? inst2Index[ex.TryEnd] : inst2Index.Count; - TryBlockGroup blockGroup = new TryBlockGroup(instructions.GetRange(startIndex, endIndex - startIndex), inst2blockGroup); - tryBlock = new TryBlockInfo - { - tryStart = ex.TryStart, - tryEnd = ex.TryEnd, - blockGroup = blockGroup, - }; - tryBlocks.Add(tryBlock); - } - if (ex.FilterStart != null) - { - int filterStartIndex = inst2Index[ex.FilterStart]; - int filterEndIndex = ex.HandlerStart != null ? inst2Index[ex.HandlerStart] : inst2Index.Count; - int handlerStartIndex = filterEndIndex; - int handlerEndIndex = ex.HandlerEnd != null ? inst2Index[ex.HandlerEnd] : inst2Index.Count; - var filterHandlerGroup = new ExceptionHandlerWithFilterGroup(ex, - instructions.GetRange(filterStartIndex, filterEndIndex - filterStartIndex), - instructions.GetRange(handlerStartIndex, handlerEndIndex - handlerStartIndex), - instructions.GetRange(filterStartIndex, handlerEndIndex - filterStartIndex), inst2blockGroup); - } - else - { - int handlerStartIndex = inst2Index[ex.HandlerStart]; - int handlerEndIndex = ex.HandlerEnd != null ? inst2Index[ex.HandlerEnd] : inst2Index.Count; - ExceptionHandlerGroup handlerGroup = new ExceptionHandlerGroup(ex, instructions.GetRange(handlerStartIndex, handlerEndIndex - handlerStartIndex), inst2blockGroup); - } - } - var rootGroup = new BlockGroup(new List(instructions), inst2blockGroup); - rootGroup.SplitInstructionsNotInAnySubGroupsToIndividualGroups(inst2blockGroup); - - rootGroup.ComputeBasicBlocks(BuildInstructionToBasicBlockInfoDic()); - return rootGroup; - } - - private void FixInstructionTargets() - { - var inst2bb = BuildInstructionToBasicBlockInfoDic(); - foreach (var ex in _method.Body.ExceptionHandlers) - { - if (ex.TryStart != null) - { - ex.TryStart = inst2bb[ex.TryStart].GroupFirstInstruction; - } - if (ex.TryEnd != null) - { - ex.TryEnd = inst2bb[ex.TryEnd].GroupFirstInstruction; - } - if (ex.HandlerStart != null) - { - ex.HandlerStart = inst2bb[ex.HandlerStart].GroupFirstInstruction; - } - if (ex.HandlerEnd != null) - { - ex.HandlerEnd = inst2bb[ex.HandlerEnd].GroupFirstInstruction; - } - if (ex.FilterStart != null) - { - ex.FilterStart = inst2bb[ex.FilterStart].GroupFirstInstruction; - } - } - //foreach (var inst in inst2bb.Keys) - //{ - // if (inst.Operand is Instruction targetInst) - // { - // inst.Operand = inst2bb[targetInst].FirstInstruction; - // } - // else if (inst.Operand is Instruction[] targetInsts) - // { - // for (int i = 0; i < targetInsts.Length; i++) - // { - // targetInsts[i] = inst2bb[targetInsts[i]].FirstInstruction; - // } - // } - //} - } - - private void BuildInstructions() - { - IList methodInstructions = _method.Body.Instructions; - methodInstructions.Clear(); - for (BasicBlockInfo cur = _bbHead.next; cur != null; cur = cur.next) - { - foreach (Instruction inst in cur.instructions) - { - methodInstructions.Add(inst); - } - } - _method.Body.InitLocals = true; - //_method.Body.MaxStack = Math.Max(_method.Body.MaxStack , (ushort)1); // TODO: set to a reasonable value - //_method.Body.KeepOldMaxStack = true; - //_method.Body.UpdateInstructionOffsets(); - } - - public bool TryObfus() - { - // TODO: TEMP - //if (_method.Body.HasExceptionHandlers) - //{ - // return false; - //} - var evc = new EvalStackCalculator(_method); - BuildBasicBlockLink(evc); - if (!CheckNotContainsNotSupportedEvalStackData()) - { - Debug.LogError($"Method {_method.FullName} contains unsupported EvalStackData, obfuscation skipped."); - return false; - } - BlockGroup rootGroup = SplitBasicBlockGroup(); - if (rootGroup.basicBlocks != null && rootGroup.basicBlocks.Count == 1) - { - return false; - } - ComputeInputOutputArguments(); - AdjustInputOutputEvalStack(); - InsertBrInstructionForConjoinedBasicBlocks(); - InsertSwitchMachineBasicBlockForGroups(rootGroup); - - FixInstructionTargets(); - BuildInstructions(); - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/MethodControlFlowCalculator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/MethodControlFlowCalculator.cs.meta deleted file mode 100644 index 059febf0..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ControlFlowObfus/MethodControlFlowCalculator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 144b6474de40382498899f8b1c7f92a3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus.meta deleted file mode 100644 index a52d43d3..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 4e82ef0b94e10314cbba0daabfdefe32 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs deleted file mode 100644 index 2284324f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs +++ /dev/null @@ -1,147 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Conf; -using Obfuz.Settings; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Xml; - -namespace Obfuz.ObfusPasses.EvalStackObfus -{ - struct ObfuscationRuleData - { - public readonly ObfuscationLevel obfuscationLevel; - public readonly float obfuscationPercentage; - public ObfuscationRuleData(ObfuscationLevel level, float percentage) - { - obfuscationLevel = level; - obfuscationPercentage = percentage; - } - } - - interface IObfuscationPolicy - { - bool NeedObfuscate(MethodDef method); - - ObfuscationRuleData GetObfuscationRuleData(MethodDef method); - } - - abstract class ObfuscationPolicyBase : IObfuscationPolicy - { - public abstract bool NeedObfuscate(MethodDef method); - - public abstract ObfuscationRuleData GetObfuscationRuleData(MethodDef method); - } - - class ConfigurableObfuscationPolicy : ObfuscationPolicyBase - { - class ObfuscationRule : IRule - { - public ObfuscationLevel? obfuscationLevel; - public float? obfuscationPercentage; - - public void InheritParent(ObfuscationRule parentRule) - { - if (obfuscationLevel == null) - obfuscationLevel = parentRule.obfuscationLevel; - if (obfuscationPercentage == null) - obfuscationPercentage = parentRule.obfuscationPercentage; - } - } - - class MethodSpec : MethodRuleBase - { - } - - class TypeSpec : TypeRuleBase - { - } - - class AssemblySpec : AssemblyRuleBase - { - } - - private static readonly ObfuscationRule s_default = new ObfuscationRule() - { - obfuscationLevel = ObfuscationLevel.Basic, - obfuscationPercentage = 0.05f, - }; - - private ObfuscationRule _global; - - private readonly XmlAssemblyTypeMethodRuleParser _xmlParser; - - private readonly Dictionary _methodRuleCache = new Dictionary(); - - public ConfigurableObfuscationPolicy(List toObfuscatedAssemblyNames, List xmlConfigFiles) - { - _xmlParser = new XmlAssemblyTypeMethodRuleParser( - toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobal); - LoadConfigs(xmlConfigFiles); - } - - private void LoadConfigs(List configFiles) - { - _xmlParser.LoadConfigs(configFiles); - - if (_global == null) - { - _global = s_default; - } - else - { - _global.InheritParent(s_default); - } - if (_global.obfuscationPercentage.Value > 0.1f) - { - UnityEngine.Debug.LogWarning($"EvalStackObfus significantly increases the size of the obfuscated hot-update DLL. It is recommended to keep the obfuscationPercentage ≤ 0.1 (currently set to {_global.obfuscationPercentage.Value})."); - } - _xmlParser.InheritParentRules(_global); - } - - private void ParseGlobal(string configFile, XmlElement ele) - { - switch (ele.Name) - { - case "global": _global = ParseObfuscationRule(configFile, ele); break; - default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}"); - } - } - - private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) - { - var rule = new ObfuscationRule(); - if (ele.HasAttribute("obfuscationLevel")) - { - rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); - } - if (ele.HasAttribute("obfuscationPercentage")) - { - rule.obfuscationPercentage = float.Parse(ele.GetAttribute("obfuscationPercentage")); - } - return rule; - } - - private ObfuscationRule GetMethodObfuscationRule(MethodDef method) - { - if (!_methodRuleCache.TryGetValue(method, out var rule)) - { - rule = _xmlParser.GetMethodRule(method, _global); - _methodRuleCache[method] = rule; - } - return rule; - } - - public override bool NeedObfuscate(MethodDef method) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - return rule.obfuscationLevel.Value > ObfuscationLevel.None; - } - - public override ObfuscationRuleData GetObfuscationRuleData(MethodDef method) - { - var rule = GetMethodObfuscationRule(method); - return new ObfuscationRuleData(rule.obfuscationLevel.Value, rule.obfuscationPercentage.Value); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs.meta deleted file mode 100644 index e9520c4e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8a2603d51f31a134d90599d33664f6c7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/DefaultObfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/DefaultObfuscator.cs deleted file mode 100644 index d9b91838..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/DefaultObfuscator.cs +++ /dev/null @@ -1,225 +0,0 @@ -using dnlib.DotNet.Emit; -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.EvalStackObfus -{ - class DefaultObfuscator : ObfuscatorBase - { - public override bool ObfuscateInt(Instruction inst, List outputInsts, ObfusMethodContext ctx) - { - IRandom random = ctx.localRandom; - switch (random.NextInt(4)) - { - case 0: - { - // x = x + a - int a = 0; - float constProbability = 0f; - ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - return true; - } - case 1: - { - // x = x * a * ra - int a = random.NextInt() | 0x1; // Ensure a is not zero - int ra = MathUtil.ModInverse32(a); - float constProbability = 0.5f; - ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstInt(ra, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - return true; - } - case 2: - { - // x = (x * a + b) * ra - (b * ra) - int a = random.NextInt() | 0x1; // Ensure a is not zero - int ra = MathUtil.ModInverse32(a); - int b = random.NextInt(); - int b_ra = -b * ra; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstInt(b, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstInt(ra, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstInt(b_ra, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - return true; - } - case 3: - { - // x = ((x + a) * b + c) * rb - (a*b + c) * rb - int a = random.NextInt(); - int b = random.NextInt() | 0x1; // Ensure b is not zero - int rb = MathUtil.ModInverse32(b); - int c = random.NextInt(); - int r = -(a * b + c) * rb; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstInt(b, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstInt(c, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstInt(rb, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstInt(r, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - return true; - } - default: return false; - } - } - - public override bool ObfuscateLong(Instruction inst, List outputInsts, ObfusMethodContext ctx) - { - IRandom random = ctx.localRandom; - switch (random.NextInt(4)) - { - case 0: - { - // x = x + a - long a = 0; - float constProbability = 0f; - ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - return true; - } - case 1: - { - // x = x * a * ra - long a = random.NextLong() | 0x1L; // Ensure a is not zero - long ra = MathUtil.ModInverse64(a); - float constProbability = 0.5f; - ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstLong(ra, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - return true; - } - case 2: - { - // x = (x * a + b) * ra - (b * ra) - long a = random.NextLong() | 0x1L; // Ensure a is not zero - long ra = MathUtil.ModInverse64(a); - long b = random.NextLong(); - long b_ra = -b * ra; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstLong(b, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstLong(ra, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstLong(b_ra, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - return true; - } - case 3: - { - // x = ((x + a) * b + c) * rb - (a*b + c) * rb - long a = random.NextLong(); - long b = random.NextLong() | 0x1L; // Ensure b is not zero - long rb = MathUtil.ModInverse64(b); - long c = random.NextLong(); - long r = -(a * b + c) * rb; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstLong(b, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstLong(c, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstLong(rb, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstLong(r, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - return true; - } - default: return false; - } - } - - public override bool ObfuscateFloat(Instruction inst, List outputInsts, ObfusMethodContext ctx) - { - IRandom random = ctx.localRandom; - switch (random.NextInt(3)) - { - case 0: - { - // x = x + 0f - float a = 0.0f; - float constProbability = 0f; - ConstObfusUtil.LoadConstFloat(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - return true; - } - case 1: - { - // x = x * 1f; - float a = 1.0f; - float constProbability = 0f; - ConstObfusUtil.LoadConstFloat(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - return true; - } - case 2: - { - // x = (x + a) * b; a = 0.0f, b = 1.0f - float a = 0.0f; - float b = 1.0f; - float constProbability = 0f; - ConstObfusUtil.LoadConstFloat(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstFloat(b, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - return true; - } - default: return false; - } - } - - public override bool ObfuscateDouble(Instruction inst, List outputInsts, ObfusMethodContext ctx) - { - IRandom random = ctx.localRandom; - switch (random.NextInt(3)) - { - case 0: - { - // x = x + 0.0 - double a = 0.0; - float constProbability = 0f; - ConstObfusUtil.LoadConstDouble(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - return true; - } - case 1: - { - // x = x * 1.0; - double a = 1.0; - float constProbability = 0f; - ConstObfusUtil.LoadConstDouble(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - return true; - } - case 2: - { - // x = (x + a) * b; a = 0.0, b = 1.0 - double a = 0.0; - double b = 1.0; - float constProbability = 0f; - ConstObfusUtil.LoadConstDouble(a, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstDouble(b, random, constProbability, ctx.constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - return true; - } - default: return false; - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/DefaultObfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/DefaultObfuscator.cs.meta deleted file mode 100644 index d6a01e4e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/DefaultObfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5200244f403139c40b578b2e845508f2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/EvalStackObfusPass.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/EvalStackObfusPass.cs deleted file mode 100644 index 27697ad7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/EvalStackObfusPass.cs +++ /dev/null @@ -1,114 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.Settings; -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.EvalStackObfus -{ - class ObfusMethodContext - { - public MethodDef method; - public EvalStackCalculator evalStackCalculator; - public LocalVariableAllocator localVariableAllocator; - public IRandom localRandom; - public EncryptionScopeInfo encryptionScope; - public DefaultMetadataImporter importer; - public ConstFieldAllocator constFieldAllocator; - public float obfuscationPercentage; - } - - internal class EvalStackObfusPass : ObfuscationMethodPassBase - { - private readonly EvalStackObfuscationSettingsFacade _settings; - - private IObfuscationPolicy _obfuscationPolicy; - private IObfuscator _obfuscator; - - public EvalStackObfusPass(EvalStackObfuscationSettingsFacade settings) - { - _settings = settings; - _obfuscator = new DefaultObfuscator(); - } - - public override ObfuscationPassType Type => ObfuscationPassType.EvalStackObfus; - - public override void Start() - { - ObfuscationPassContext ctx = ObfuscationPassContext.Current; - _obfuscationPolicy = new ConfigurableObfuscationPolicy( - ctx.coreSettings.assembliesToObfuscate, - _settings.ruleFiles); - } - - public override void Stop() - { - - } - - protected override bool NeedObfuscateMethod(MethodDef method) - { - return _obfuscationPolicy.NeedObfuscate(method); - } - - protected bool TryObfuscateInstruction(Instruction inst, EvalDataType dataType, List outputInstructions, ObfusMethodContext ctx) - { - switch (dataType) - { - case EvalDataType.Int32: return _obfuscator.ObfuscateInt(inst, outputInstructions, ctx); - case EvalDataType.Int64: return _obfuscator.ObfuscateLong(inst, outputInstructions, ctx); - case EvalDataType.Float: return _obfuscator.ObfuscateFloat(inst, outputInstructions, ctx); - case EvalDataType.Double: return _obfuscator.ObfuscateDouble(inst, outputInstructions, ctx); - default: return false; - } - } - - protected override void ObfuscateData(MethodDef method) - { - //Debug.Log($"Obfuscating method: {method.FullName} with EvalStackObfusPass"); - IList instructions = method.Body.Instructions; - var outputInstructions = new List(); - var totalFinalInstructions = new List(); - - ObfuscationPassContext ctx = ObfuscationPassContext.Current; - var calc = new EvalStackCalculator(method); - - GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager; - var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module); - var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method); - var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)); - var obfusMethodCtx = new ObfusMethodContext - { - method = method, - evalStackCalculator = calc, - localVariableAllocator = new LocalVariableAllocator(method), - encryptionScope = encryptionScope, - constFieldAllocator = moduleEntityManager.GetEntity(method.Module), - localRandom = localRandom, - importer = moduleEntityManager.GetEntity(method.Module), - obfuscationPercentage = ruleData.obfuscationPercentage, - }; - for (int i = 0; i < instructions.Count; i++) - { - Instruction inst = instructions[i]; - totalFinalInstructions.Add(inst); - if (calc.TryGetPushResult(inst, out EvalDataType dataType) && localRandom.NextInPercentage(ruleData.obfuscationPercentage)) - { - outputInstructions.Clear(); - if (TryObfuscateInstruction(inst, dataType, outputInstructions, obfusMethodCtx)) - { - totalFinalInstructions.AddRange(outputInstructions); - } - } - } - - instructions.Clear(); - foreach (var obInst in totalFinalInstructions) - { - instructions.Add(obInst); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/EvalStackObfusPass.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/EvalStackObfusPass.cs.meta deleted file mode 100644 index 63a3a0c5..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/EvalStackObfusPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9fa7d3313f260794da2cc36dadaf4fb4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/IObfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/IObfuscator.cs deleted file mode 100644 index 79f8ff09..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/IObfuscator.cs +++ /dev/null @@ -1,24 +0,0 @@ -using dnlib.DotNet.Emit; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.EvalStackObfus -{ - interface IObfuscator - { - bool ObfuscateInt(Instruction inst, List outputInsts, ObfusMethodContext ctx); - - bool ObfuscateLong(Instruction inst, List outputInsts, ObfusMethodContext ctx); - - bool ObfuscateFloat(Instruction inst, List outputInsts, ObfusMethodContext ctx); - - bool ObfuscateDouble(Instruction inst, List outputInsts, ObfusMethodContext ctx); - } - - abstract class ObfuscatorBase : IObfuscator - { - public abstract bool ObfuscateInt(Instruction inst, List outputInsts, ObfusMethodContext ctx); - public abstract bool ObfuscateLong(Instruction inst, List outputInsts, ObfusMethodContext ctx); - public abstract bool ObfuscateFloat(Instruction inst, List outputInsts, ObfusMethodContext ctx); - public abstract bool ObfuscateDouble(Instruction inst, List outputInsts, ObfusMethodContext ctx); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/IObfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/IObfuscator.cs.meta deleted file mode 100644 index a782f110..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/EvalStackObfus/IObfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 17a9f3181d9711f4ca1d0cfb9e813bb0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus.meta deleted file mode 100644 index 24080ec4..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 9fdb2c243b1ea0f489e67233fda287c9 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs deleted file mode 100644 index 73929f1e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs +++ /dev/null @@ -1,143 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Conf; -using Obfuz.Settings; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Xml; - -namespace Obfuz.ObfusPasses.ExprObfus -{ - struct ObfuscationRuleData - { - public readonly ObfuscationLevel obfuscationLevel; - public readonly float obfuscationPercentage; - public ObfuscationRuleData(ObfuscationLevel level, float percentage) - { - obfuscationLevel = level; - obfuscationPercentage = percentage; - } - } - - interface IObfuscationPolicy - { - bool NeedObfuscate(MethodDef method); - - ObfuscationRuleData GetObfuscationRuleData(MethodDef method); - } - - abstract class ObfuscationPolicyBase : IObfuscationPolicy - { - public abstract bool NeedObfuscate(MethodDef method); - - public abstract ObfuscationRuleData GetObfuscationRuleData(MethodDef method); - } - - class ConfigurableObfuscationPolicy : ObfuscationPolicyBase - { - class ObfuscationRule : IRule - { - public ObfuscationLevel? obfuscationLevel; - public float? obfuscationPercentage; - - public void InheritParent(ObfuscationRule parentRule) - { - if (obfuscationLevel == null) - obfuscationLevel = parentRule.obfuscationLevel; - if (obfuscationPercentage == null) - obfuscationPercentage = parentRule.obfuscationPercentage; - } - } - - class MethodSpec : MethodRuleBase - { - } - - class TypeSpec : TypeRuleBase - { - } - - class AssemblySpec : AssemblyRuleBase - { - } - - private static readonly ObfuscationRule s_default = new ObfuscationRule() - { - obfuscationLevel = ObfuscationLevel.Basic, - obfuscationPercentage = 0.3f, - }; - - private ObfuscationRule _global; - - private readonly XmlAssemblyTypeMethodRuleParser _xmlParser; - - private readonly Dictionary _methodRuleCache = new Dictionary(); - - public ConfigurableObfuscationPolicy(List toObfuscatedAssemblyNames, List xmlConfigFiles) - { - _xmlParser = new XmlAssemblyTypeMethodRuleParser( - toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobal); - LoadConfigs(xmlConfigFiles); - } - - private void LoadConfigs(List configFiles) - { - _xmlParser.LoadConfigs(configFiles); - - if (_global == null) - { - _global = s_default; - } - else - { - _global.InheritParent(s_default); - } - _xmlParser.InheritParentRules(_global); - } - - private void ParseGlobal(string configFile, XmlElement ele) - { - switch (ele.Name) - { - case "global": _global = ParseObfuscationRule(configFile, ele); break; - default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}"); - } - } - - private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) - { - var rule = new ObfuscationRule(); - if (ele.HasAttribute("obfuscationLevel")) - { - rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); - } - if (ele.HasAttribute("obfuscationPercentage")) - { - rule.obfuscationPercentage = float.Parse(ele.GetAttribute("obfuscationPercentage")); - } - return rule; - } - - private ObfuscationRule GetMethodObfuscationRule(MethodDef method) - { - if (!_methodRuleCache.TryGetValue(method, out var rule)) - { - rule = _xmlParser.GetMethodRule(method, _global); - _methodRuleCache[method] = rule; - } - return rule; - } - - public override bool NeedObfuscate(MethodDef method) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - return rule.obfuscationLevel.Value > ObfuscationLevel.None; - } - - public override ObfuscationRuleData GetObfuscationRuleData(MethodDef method) - { - var rule = GetMethodObfuscationRule(method); - return new ObfuscationRuleData(rule.obfuscationLevel.Value, rule.obfuscationPercentage.Value); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs.meta deleted file mode 100644 index 2e67a4f5..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5f820a225c981b8499016958e6c69747 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ExprObfusPass.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ExprObfusPass.cs deleted file mode 100644 index 1a540e64..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ExprObfusPass.cs +++ /dev/null @@ -1,173 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.ObfusPasses.ExprObfus.Obfuscators; -using Obfuz.Settings; -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.ExprObfus -{ - class ObfusMethodContext - { - public MethodDef method; - public EvalStackCalculator evalStackCalculator; - public LocalVariableAllocator localVariableAllocator; - public IRandom localRandom; - public EncryptionScopeInfo encryptionScope; - public DefaultMetadataImporter importer; - public ConstFieldAllocator constFieldAllocator; - public float obfuscationPercentage; - } - - class ExprObfusPass : ObfuscationMethodPassBase - { - private readonly ExprObfuscationSettingsFacade _settings; - private readonly IObfuscator _basicObfuscator; - private readonly IObfuscator _advancedObfuscator; - private readonly IObfuscator _mostAdvancedObfuscator; - - private IObfuscationPolicy _obfuscationPolicy; - - public ExprObfusPass(ExprObfuscationSettingsFacade settings) - { - _settings = settings; - _basicObfuscator = new BasicObfuscator(); - _advancedObfuscator = new AdvancedObfuscator(); - _mostAdvancedObfuscator = new MostAdvancedObfuscator(); - } - - public override ObfuscationPassType Type => ObfuscationPassType.ExprObfus; - - public override void Start() - { - ObfuscationPassContext ctx = ObfuscationPassContext.Current; - _obfuscationPolicy = new ConfigurableObfuscationPolicy( - ctx.coreSettings.assembliesToObfuscate, - _settings.ruleFiles); - } - - private IObfuscator GetObfuscator(ObfuscationLevel level) - { - switch (level) - { - case ObfuscationLevel.None: return null; - case ObfuscationLevel.Basic: return _basicObfuscator; - case ObfuscationLevel.Advanced: return _advancedObfuscator; - case ObfuscationLevel.MostAdvanced: return _mostAdvancedObfuscator; - default: throw new System.ArgumentOutOfRangeException(nameof(level), level, "Unknown obfuscation level"); - } - } - - public override void Stop() - { - - } - - protected override bool NeedObfuscateMethod(MethodDef method) - { - return _obfuscationPolicy.NeedObfuscate(method); - } - - protected bool TryObfuscateInstruction(IObfuscator obfuscator, InstructionParameterInfo pi, Instruction inst, List outputInstructions, ObfusMethodContext ctx) - { - //Debug.Log($"Obfuscating instruction: {inst} in method: {ctx.method.FullName}"); - IRandom localRandom = ctx.localRandom; - float obfuscationPercentage = ctx.obfuscationPercentage; - switch (inst.OpCode.Code) - { - case Code.Neg: - { - return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBasicUnaryOp(inst, pi.op1, pi.retType, outputInstructions, ctx); - } - case Code.Add: - case Code.Sub: - case Code.Mul: - case Code.Div: - case Code.Div_Un: - case Code.Rem: - case Code.Rem_Un: - { - return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBasicBinOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx); - } - case Code.And: - case Code.Or: - case Code.Xor: - { - return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBinBitwiseOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx); - } - case Code.Not: - { - return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateUnaryBitwiseOp(inst, pi.op1, pi.retType, outputInstructions, ctx); - } - case Code.Shl: - case Code.Shr: - case Code.Shr_Un: - { - return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBitShiftOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx); - } - } - return false; - } - - protected override void ObfuscateData(MethodDef method) - { - //Debug.Log($"Obfuscating method: {method.FullName} with ExprObfusPass"); - IList instructions = method.Body.Instructions; - var outputInstructions = new List(); - var totalFinalInstructions = new List(); - - ObfuscationPassContext ctx = ObfuscationPassContext.Current; - var calc = new EvalStackCalculator(method); - - GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager; - var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module); - var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method); - var obfuscator = GetObfuscator(ruleData.obfuscationLevel); - var obfusMethodCtx = new ObfusMethodContext - { - method = method, - evalStackCalculator = calc, - localVariableAllocator = new LocalVariableAllocator(method), - encryptionScope = encryptionScope, - constFieldAllocator = moduleEntityManager.GetEntity(method.Module), - localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)), - importer = moduleEntityManager.GetEntity(method.Module), - obfuscationPercentage = ruleData.obfuscationPercentage, - }; - for (int i = 0; i < instructions.Count; i++) - { - Instruction inst = instructions[i]; - bool add = false; - if (calc.TryGetParameterInfo(inst, out InstructionParameterInfo pi)) - { - outputInstructions.Clear(); - if (TryObfuscateInstruction(obfuscator, pi, inst, outputInstructions, obfusMethodCtx)) - { - // current instruction may be the target of control flow instruction, so we can't remove it directly. - // we replace it with nop now, then remove it in CleanUpInstructionPass - inst.OpCode = outputInstructions[0].OpCode; - inst.Operand = outputInstructions[0].Operand; - totalFinalInstructions.Add(inst); - for (int k = 1; k < outputInstructions.Count; k++) - { - totalFinalInstructions.Add(outputInstructions[k]); - } - add = true; - } - } - if (!add) - { - totalFinalInstructions.Add(inst); - } - } - - instructions.Clear(); - foreach (var obInst in totalFinalInstructions) - { - instructions.Add(obInst); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ExprObfusPass.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ExprObfusPass.cs.meta deleted file mode 100644 index f108ce32..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/ExprObfusPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 477e081ffc0072e4fa1a06100269e4a3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/IObfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/IObfuscator.cs deleted file mode 100644 index 605f6438..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/IObfuscator.cs +++ /dev/null @@ -1,28 +0,0 @@ -using dnlib.DotNet.Emit; -using Obfuz.Emit; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.ExprObfus -{ - interface IObfuscator - { - bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List outputInsts, ObfusMethodContext ctx); - - bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx); - - bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List outputInsts, ObfusMethodContext ctx); - - bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx); - - bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx); - } - - abstract class ObfuscatorBase : IObfuscator - { - public abstract bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List outputInsts, ObfusMethodContext ctx); - public abstract bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx); - public abstract bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List outputInsts, ObfusMethodContext ctx); - public abstract bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx); - public abstract bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/IObfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/IObfuscator.cs.meta deleted file mode 100644 index a72c8645..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/IObfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a88981a87bcd9e84b883e39c81cfbf44 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators.meta deleted file mode 100644 index dde5f438..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 4c5dc8736831c9f4b934c69f7894a412 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/AdvancedObfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/AdvancedObfuscator.cs deleted file mode 100644 index f055962a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/AdvancedObfuscator.cs +++ /dev/null @@ -1,110 +0,0 @@ -using dnlib.DotNet.Emit; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators -{ - class AdvancedObfuscator : BasicObfuscator - { - protected bool GenerateIdentityTransformForArgument(Instruction inst, EvalDataType op, List outputInsts, ObfusMethodContext ctx) - { - IRandom random = ctx.localRandom; - ConstFieldAllocator constFieldAllocator = ctx.constFieldAllocator; - switch (op) - { - case EvalDataType.Int32: - { - // = x + y = x + (y * a + b) * ra + (-b * ra) - int a = random.NextInt() | 0x1; - int ra = MathUtil.ModInverse32(a); - int b = random.NextInt(); - int b_ra = -b * ra; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstInt(a, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstInt(b, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstInt(ra, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstInt(b_ra, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - outputInsts.Add(inst.Clone()); - return true; - } - case EvalDataType.Int64: - { - // = x + y = x + (y * a + b) * ra + (-b * ra) - long a = random.NextLong() | 0x1L; - long ra = MathUtil.ModInverse64(a); - long b = random.NextLong(); - long b_ra = -b * ra; - float constProbability = 0.5f; - ConstObfusUtil.LoadConstLong(a, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstLong(b, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstLong(ra, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - ConstObfusUtil.LoadConstLong(b_ra, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - outputInsts.Add(inst.Clone()); - return true; - } - case EvalDataType.Float: - { - // = x + y = x + (y + a) * b; a = 0.0f, b = 1.0f - float a = 0.0f; - float b = 1.0f; - float constProbability = 0f; - ConstObfusUtil.LoadConstFloat(a, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstFloat(b, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - outputInsts.Add(inst.Clone()); - return true; - } - case EvalDataType.Double: - { - // = x + y = x + (y + a) * b; a = 0.0, b = 1.0 - double a = 0.0; - double b = 1.0; - float constProbability = 0f; - ConstObfusUtil.LoadConstDouble(a, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Add)); - ConstObfusUtil.LoadConstDouble(b, random, constProbability, constFieldAllocator, outputInsts); - outputInsts.Add(Instruction.Create(OpCodes.Mul)); - outputInsts.Add(inst.Clone()); - return true; - } - default: return false; - } - } - - public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - return GenerateIdentityTransformForArgument(inst, op, outputInsts, ctx) || base.ObfuscateBasicUnaryOp(inst, op, ret, outputInsts, ctx); - } - - public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - return GenerateIdentityTransformForArgument(inst, op2, outputInsts, ctx) || base.ObfuscateBasicBinOp(inst, op1, op2, ret, outputInsts, ctx); - } - - public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - return GenerateIdentityTransformForArgument(inst, op, outputInsts, ctx) || base.ObfuscateUnaryBitwiseOp(inst, op, ret, outputInsts, ctx); - } - - public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - return GenerateIdentityTransformForArgument(inst, op2, outputInsts, ctx) || base.ObfuscateBinBitwiseOp(inst, op1, op2, ret, outputInsts, ctx); - } - - public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - return GenerateIdentityTransformForArgument(inst, op2, outputInsts, ctx) || base.ObfuscateBitShiftOp(inst, op1, op2, ret, outputInsts, ctx); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/AdvancedObfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/AdvancedObfuscator.cs.meta deleted file mode 100644 index 06cf2c52..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/AdvancedObfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ef717515402ca2f41a52db7ea1300f32 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/BasicObfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/BasicObfuscator.cs deleted file mode 100644 index 56e110e4..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/BasicObfuscator.cs +++ /dev/null @@ -1,282 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Emit; -using System.Collections.Generic; -using UnityEngine; - -namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators -{ - - class BasicObfuscator : ObfuscatorBase - { - private IMethod GetUnaryOpMethod(DefaultMetadataImporter importer, Code code, EvalDataType op1) - { - switch (code) - { - case Code.Neg: - { - switch (op1) - { - case EvalDataType.Int32: return importer.NegInt; - case EvalDataType.Int64: return importer.NegLong; - case EvalDataType.Float: return importer.NegFloat; - case EvalDataType.Double: return importer.NegDouble; - default: return null; - } - } - case Code.Not: - { - switch (op1) - { - case EvalDataType.Int32: return importer.NotInt; - case EvalDataType.Int64: return importer.NotLong; - default: return null; - } - } - default: return null; - } - } - - private IMethod GetBinaryOpMethod(DefaultMetadataImporter importer, Code code, EvalDataType op1, EvalDataType op2) - { - switch (code) - { - case Code.Add: - { - switch (op1) - { - case EvalDataType.Int32: return op2 == op1 ? importer.AddInt : null; - case EvalDataType.Int64: return op2 == op1 ? importer.AddLong : null; - case EvalDataType.Float: return op2 == op1 ? importer.AddFloat : null; - case EvalDataType.Double: return op2 == op1 ? importer.AddDouble : null; - case EvalDataType.I: - { - switch (op2) - { - case EvalDataType.I: return importer.AddIntPtr; - case EvalDataType.Int32: return importer.AddIntPtrInt; - default: return null; - } - } - default: return null; - } - } - case Code.Sub: - { - switch (op1) - { - case EvalDataType.Int32: return op2 == op1 ? importer.SubtractInt : null; - case EvalDataType.Int64: return op2 == op1 ? importer.SubtractLong : null; - case EvalDataType.Float: return op2 == op1 ? importer.SubtractFloat : null; - case EvalDataType.Double: return op2 == op1 ? importer.SubtractDouble : null; - case EvalDataType.I: - { - switch (op2) - { - case EvalDataType.I: return importer.SubtractIntPtr; - case EvalDataType.Int32: return importer.SubtractIntPtrInt; - default: return null; - } - } - default: return null; - } - } - case Code.Mul: - { - switch (op1) - { - case EvalDataType.Int32: return op2 == op1 ? importer.MultiplyInt : null; - case EvalDataType.Int64: return op2 == op1 ? importer.MultiplyLong : null; - case EvalDataType.Float: return op2 == op1 ? importer.MultiplyFloat : null; - case EvalDataType.Double: return op2 == op1 ? importer.MultiplyDouble : null; - case EvalDataType.I: - { - switch (op2) - { - case EvalDataType.I: return importer.MultiplyIntPtr; - case EvalDataType.Int32: return importer.MultiplyIntPtrInt; - default: return null; - } - } - default: return null; - } - } - case Code.Div: - { - switch (op1) - { - case EvalDataType.Int32: return importer.DivideInt; - case EvalDataType.Int64: return importer.DivideLong; - case EvalDataType.Float: return importer.DivideFloat; - case EvalDataType.Double: return importer.DivideDouble; - default: return null; - } - } - case Code.Div_Un: - { - switch (op1) - { - case EvalDataType.Int32: return importer.DivideUnInt; - case EvalDataType.Int64: return importer.DivideUnLong; - default: return null; - } - } - case Code.Rem: - { - switch (op1) - { - case EvalDataType.Int32: return importer.RemInt; - case EvalDataType.Int64: return importer.RemLong; - case EvalDataType.Float: return importer.RemFloat; - case EvalDataType.Double: return importer.RemDouble; - default: return null; - } - } - case Code.Rem_Un: - { - switch (op1) - { - case EvalDataType.Int32: return importer.RemUnInt; - case EvalDataType.Int64: return importer.RemUnLong; - default: return null; - } - } - case Code.Neg: - { - switch (op1) - { - case EvalDataType.Int32: return importer.NegInt; - case EvalDataType.Int64: return importer.NegLong; - case EvalDataType.Float: return importer.NegFloat; - case EvalDataType.Double: return importer.NegDouble; - default: return null; - } - } - case Code.And: - { - switch (op1) - { - case EvalDataType.Int32: return importer.AndInt; - case EvalDataType.Int64: return importer.AndLong; - default: return null; - } - } - case Code.Or: - { - switch (op1) - { - case EvalDataType.Int32: return importer.OrInt; - case EvalDataType.Int64: return importer.OrLong; - default: return null; - } - } - case Code.Xor: - { - switch (op1) - { - case EvalDataType.Int32: return importer.XorInt; - case EvalDataType.Int64: return importer.XorLong; - default: return null; - } - } - case Code.Not: - { - switch (op1) - { - case EvalDataType.Int32: return importer.NotInt; - case EvalDataType.Int64: return importer.NotLong; - default: return null; - } - } - case Code.Shl: - { - switch (op1) - { - case EvalDataType.Int32: return importer.ShlInt; - case EvalDataType.Int64: return importer.ShlLong; - default: return null; - } - } - case Code.Shr: - { - switch (op1) - { - case EvalDataType.Int32: return importer.ShrInt; - case EvalDataType.Int64: return importer.ShrLong; - default: return null; - } - } - case Code.Shr_Un: - { - switch (op1) - { - case EvalDataType.Int32: return importer.ShrUnInt; - case EvalDataType.Int64: return importer.ShrUnLong; - default: return null; - } - } - default: return null; - } - } - - public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - IMethod opMethod = GetUnaryOpMethod(ctx.importer, inst.OpCode.Code, op); - if (opMethod == null) - { - Debug.LogWarning($"BasicObfuscator: Cannot obfuscate unary operation {inst.OpCode.Code} with different operand types: op={op}. This is a limitation of the BasicObfuscator."); - return false; - } - outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod)); - return true; - } - - public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2); - if (opMethod == null) - { - Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator."); - return false; - } - outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod)); - return true; - } - - public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - IMethod opMethod = GetUnaryOpMethod(ctx.importer, inst.OpCode.Code, op); - if (opMethod == null) - { - Debug.LogWarning($"BasicObfuscator: Cannot obfuscate unary operation {inst.OpCode.Code} with different operand types: op={op}. This is a limitation of the BasicObfuscator."); - return false; - } - outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod)); - return true; - } - - public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2); - if (opMethod == null) - { - Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator."); - return false; - } - outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod)); - return true; - } - - public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2); - if (opMethod == null) - { - Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with operand type {op2}. This is a limitation of the BasicObfuscator."); - return false; - } - outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod)); - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/BasicObfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/BasicObfuscator.cs.meta deleted file mode 100644 index dd49d805..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/BasicObfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 578caeae17526b54c9ff1979d897feb7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/MostAdvancedObfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/MostAdvancedObfuscator.cs deleted file mode 100644 index 1ff1a70b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/MostAdvancedObfuscator.cs +++ /dev/null @@ -1,83 +0,0 @@ -using dnlib.DotNet.Emit; -using Obfuz.Emit; -using System.Collections.Generic; -using System.Linq; - -namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators -{ - class MostAdvancedObfuscator : AdvancedObfuscator - { - private readonly BasicObfuscator _basicObfuscator = new BasicObfuscator(); - - public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - if (!base.ObfuscateBasicUnaryOp(inst, op, ret, outputInsts, ctx)) - { - return false; - } - if (outputInsts.Last().OpCode.Code != inst.OpCode.Code) - { - return false; - } - outputInsts.RemoveAt(outputInsts.Count - 1); - return _basicObfuscator.ObfuscateBasicUnaryOp(inst, op, ret, outputInsts, ctx); - } - - public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - if (!base.ObfuscateBasicBinOp(inst, op1, op2, ret, outputInsts, ctx)) - { - return false; - } - if (outputInsts.Last().OpCode.Code != inst.OpCode.Code) - { - return false; - } - outputInsts.RemoveAt(outputInsts.Count - 1); - return _basicObfuscator.ObfuscateBasicBinOp(inst, op1, op2, ret, outputInsts, ctx); - } - - public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - if (!base.ObfuscateUnaryBitwiseOp(inst, op, ret, outputInsts, ctx)) - { - return false; - } - - if (outputInsts.Last().OpCode.Code != inst.OpCode.Code) - { - return false; - } - outputInsts.RemoveAt(outputInsts.Count - 1); - return _basicObfuscator.ObfuscateUnaryBitwiseOp(inst, op, ret, outputInsts, ctx); - } - - public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - if (!base.ObfuscateBinBitwiseOp(inst, op1, op2, ret, outputInsts, ctx)) - { - return false; - } - if (outputInsts.Last().OpCode.Code != inst.OpCode.Code) - { - return false; - } - outputInsts.RemoveAt(outputInsts.Count - 1); - return _basicObfuscator.ObfuscateBinBitwiseOp(inst, op1, op2, ret, outputInsts, ctx); - } - - public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List outputInsts, ObfusMethodContext ctx) - { - if (!base.ObfuscateBitShiftOp(inst, op1, op2, ret, outputInsts, ctx)) - { - return false; - } - if (outputInsts.Last().OpCode.Code != inst.OpCode.Code) - { - return false; - } - outputInsts.RemoveAt(outputInsts.Count - 1); - return _basicObfuscator.ObfuscateBitShiftOp(inst, op1, op2, ret, outputInsts, ctx); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/MostAdvancedObfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/MostAdvancedObfuscator.cs.meta deleted file mode 100644 index fb1660a3..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ExprObfus/Obfuscators/MostAdvancedObfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: af5946ac6cb0a8b4fa75321439785133 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt.meta deleted file mode 100644 index 24c7b1d7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0b789725c4848bd4fb4b3ce1f2e2a9c9 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/ConfigurableEncryptPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/ConfigurableEncryptPolicy.cs deleted file mode 100644 index 31d977e7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/ConfigurableEncryptPolicy.cs +++ /dev/null @@ -1,45 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Conf; -using Obfuz.Utils; -using System.Collections.Generic; -using System.Xml; - -namespace Obfuz.ObfusPasses.FieldEncrypt -{ - public class ConfigurableEncryptPolicy : EncryptPolicyBase - { - class ObfuscationRule - { - - } - - private readonly XmlFieldRuleParser _configParser; - private readonly ObfuzIgnoreScopeComputeCache _obfuzIgnoreScopeComputeCache; - - public ConfigurableEncryptPolicy(ObfuzIgnoreScopeComputeCache obfuzIgnoreScopeComputeCache, List toObfuscatedAssemblyNames, List configFiles) - { - _obfuzIgnoreScopeComputeCache = obfuzIgnoreScopeComputeCache; - _configParser = new XmlFieldRuleParser(toObfuscatedAssemblyNames, ParseRule, null); - _configParser.LoadConfigs(configFiles); - } - - private ObfuscationRule ParseRule(string configFile, XmlElement ele) - { - return new ObfuscationRule(); - } - - public override bool NeedEncrypt(FieldDef field) - { - if (MetaUtil.HasEncryptFieldAttribute(field)) - { - return true; - } - if (_obfuzIgnoreScopeComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(field, field.DeclaringType, ObfuzScope.Field)) - { - return false; - } - var rule = _configParser.GetFieldRule(field); - return rule != null; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/ConfigurableEncryptPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/ConfigurableEncryptPolicy.cs.meta deleted file mode 100644 index bcc4d60c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/ConfigurableEncryptPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6b17fa09ce58526459f2b9e375c31cad -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/DefaultFieldEncryptor.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/DefaultFieldEncryptor.cs deleted file mode 100644 index bc8bbe9a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/DefaultFieldEncryptor.cs +++ /dev/null @@ -1,201 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Emit; -using Obfuz.Settings; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using UnityEngine.Assertions; - -namespace Obfuz.ObfusPasses.FieldEncrypt -{ - public class DefaultFieldEncryptor : FieldEncryptorBase - { - private readonly GroupByModuleEntityManager _moduleEntityManager; - private readonly FieldEncryptionSettingsFacade _settings; - - public DefaultFieldEncryptor(GroupByModuleEntityManager moduleEntityManager, FieldEncryptionSettingsFacade settings) - { - _moduleEntityManager = moduleEntityManager; - _settings = settings; - } - - class FieldEncryptInfo - { - public int encryptOps; - public int salt; - public ElementType fieldType; - public long xorValueForZero; - } - - private readonly Dictionary _fieldEncryptInfoCache = new Dictionary(); - - - private long CalcXorValueForZero(IEncryptor encryptor, ElementType type, int encryptOps, int salt) - { - switch (type) - { - case ElementType.I4: - case ElementType.U4: - case ElementType.R4: - return encryptor.Encrypt(0, encryptOps, salt); - case ElementType.I8: - case ElementType.U8: - case ElementType.R8: - return encryptor.Encrypt(0L, encryptOps, salt); - default: - throw new NotSupportedException($"Unsupported field type: {type} for encryption"); - } - } - - - private IRandom CreateRandomForField(RandomCreator randomCreator, FieldDef field) - { - return randomCreator(FieldEqualityComparer.CompareDeclaringTypes.GetHashCode(field)); - } - - private int GenerateEncryptionOperations(IRandom random, IEncryptor encryptor) - { - return EncryptionUtil.GenerateEncryptionOpCodes(random, encryptor, _settings.encryptionLevel); - } - - public int GenerateSalt(IRandom random) - { - return random.NextInt(); - } - - private FieldEncryptInfo GetFieldEncryptInfo(FieldDef field) - { - if (_fieldEncryptInfoCache.TryGetValue(field, out var info)) - { - return info; - } - EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(field.Module); - - IRandom random = CreateRandomForField(encryptionScope.localRandomCreator, field); - IEncryptor encryptor = encryptionScope.encryptor; - int encryptOps = GenerateEncryptionOperations(random, encryptor); - int salt = GenerateSalt(random); - ElementType fieldType = field.FieldSig.Type.RemovePinnedAndModifiers().ElementType; - long xorValueForZero = CalcXorValueForZero(encryptor, fieldType, encryptOps, salt); - - info = new FieldEncryptInfo - { - encryptOps = encryptOps, - salt = salt, - fieldType = fieldType, - xorValueForZero = xorValueForZero, - }; - _fieldEncryptInfoCache[field] = info; - return info; - } - - public override void Encrypt(MethodDef method, FieldDef field, List outputInstructions, Instruction currentInstruction) - { - DefaultMetadataImporter importer = _moduleEntityManager.GetEntity(method.Module); - EncryptionServiceMetadataImporter encryptionServiceMetadataImporter = importer.GetEncryptionServiceMetadataImporterOfModule(field.Module); - FieldEncryptInfo fei = GetFieldEncryptInfo(field); - if (fei.fieldType == ElementType.I4 || fei.fieldType == ElementType.U4 || fei.fieldType == ElementType.R4) - { - // value has been put on stack - - if (fei.fieldType == ElementType.R4) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, importer.CastFloatAsInt)); - } - // encrypt - outputInstructions.Add(Instruction.CreateLdcI4(fei.encryptOps)); - outputInstructions.Add(Instruction.CreateLdcI4(fei.salt)); - outputInstructions.Add(Instruction.Create(OpCodes.Call, encryptionServiceMetadataImporter.EncryptInt)); - // xor - outputInstructions.Add(Instruction.CreateLdcI4((int)fei.xorValueForZero)); - outputInstructions.Add(Instruction.Create(OpCodes.Xor)); - - if (fei.fieldType == ElementType.R4) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, importer.CastIntAsFloat)); - } - } - else if (fei.fieldType == ElementType.I8 || fei.fieldType == ElementType.U8 || fei.fieldType == ElementType.R8) - { - // value has been put on stack - if (fei.fieldType == ElementType.R8) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, importer.CastDoubleAsLong)); - } - - // encrypt - outputInstructions.Add(Instruction.CreateLdcI4(fei.encryptOps)); - outputInstructions.Add(Instruction.CreateLdcI4(fei.salt)); - outputInstructions.Add(Instruction.Create(OpCodes.Call, encryptionServiceMetadataImporter.EncryptLong)); - // xor - outputInstructions.Add(Instruction.Create(OpCodes.Ldc_I8, fei.xorValueForZero)); - outputInstructions.Add(Instruction.Create(OpCodes.Xor)); - if (fei.fieldType == ElementType.R8) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, importer.CastLongAsDouble)); - } - } - else - { - Assert.IsTrue(false, $"Unsupported field type: {fei.fieldType} for encryption"); - } - - outputInstructions.Add(currentInstruction.Clone()); - } - - public override void Decrypt(MethodDef method, FieldDef field, List outputInstructions, Instruction currentInstruction) - { - outputInstructions.Add(currentInstruction.Clone()); - DefaultMetadataImporter importer = _moduleEntityManager.GetEntity(method.Module); - EncryptionServiceMetadataImporter encryptionServiceMetadataImporter = importer.GetEncryptionServiceMetadataImporterOfModule(field.Module); - FieldEncryptInfo fei = GetFieldEncryptInfo(field); - if (fei.fieldType == ElementType.I4 || fei.fieldType == ElementType.U4 || fei.fieldType == ElementType.R4) - { - // value has been put on stack - // xor - if (fei.fieldType == ElementType.R4) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, importer.CastFloatAsInt)); - } - outputInstructions.Add(Instruction.CreateLdcI4((int)fei.xorValueForZero)); - outputInstructions.Add(Instruction.Create(OpCodes.Xor)); - - // decrypt - outputInstructions.Add(Instruction.CreateLdcI4(fei.encryptOps)); - outputInstructions.Add(Instruction.CreateLdcI4(fei.salt)); - outputInstructions.Add(Instruction.Create(OpCodes.Call, encryptionServiceMetadataImporter.DecryptInt)); - - if (fei.fieldType == ElementType.R4) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, importer.CastIntAsFloat)); - } - } - else if (fei.fieldType == ElementType.I8 || fei.fieldType == ElementType.U8 || fei.fieldType == ElementType.R8) - { - // value has been put on stack - // xor - if (fei.fieldType == ElementType.R8) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, importer.CastDoubleAsLong)); - } - outputInstructions.Add(Instruction.Create(OpCodes.Ldc_I8, fei.xorValueForZero)); - outputInstructions.Add(Instruction.Create(OpCodes.Xor)); - - // decrypt - outputInstructions.Add(Instruction.CreateLdcI4(fei.encryptOps)); - outputInstructions.Add(Instruction.CreateLdcI4(fei.salt)); - outputInstructions.Add(Instruction.Create(OpCodes.Call, encryptionServiceMetadataImporter.DecryptLong)); - - if (fei.fieldType == ElementType.R8) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, importer.CastLongAsDouble)); - } - } - else - { - Assert.IsTrue(false, $"Unsupported field type: {fei.fieldType} for decryption"); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/DefaultFieldEncryptor.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/DefaultFieldEncryptor.cs.meta deleted file mode 100644 index 905f446b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/DefaultFieldEncryptor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b6707a66ae63e2c498d55088c6e8ef4a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/FieldEncryptPass.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/FieldEncryptPass.cs deleted file mode 100644 index 3f82faf5..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/FieldEncryptPass.cs +++ /dev/null @@ -1,102 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Settings; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.FieldEncrypt -{ - - public class FieldEncryptPass : InstructionObfuscationPassBase - { - private FieldEncryptionSettingsFacade _settings; - private IEncryptPolicy _encryptionPolicy; - private IFieldEncryptor _memoryEncryptor; - - public override ObfuscationPassType Type => ObfuscationPassType.FieldEncrypt; - - public FieldEncryptPass(FieldEncryptionSettingsFacade settings) - { - _settings = settings; - } - - protected override bool ForceProcessAllAssembliesAndIgnoreAllPolicy => true; - - public override void Start() - { - var ctx = ObfuscationPassContext.Current; - _memoryEncryptor = new DefaultFieldEncryptor(ctx.moduleEntityManager, _settings); - _encryptionPolicy = new ConfigurableEncryptPolicy(ctx.obfuzIgnoreScopeComputeCache, ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles); - } - - public override void Stop() - { - - } - - protected override bool NeedObfuscateMethod(MethodDef method) - { - return true; - } - - private bool IsSupportedFieldType(TypeSig type) - { - type = type.RemovePinnedAndModifiers(); - switch (type.ElementType) - { - case ElementType.I4: - case ElementType.I8: - case ElementType.U4: - case ElementType.U8: - case ElementType.R4: - case ElementType.R8: - return true; - default: return false; - } - } - - protected override bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList instructions, int instructionIndex, List outputInstructions, List totalFinalInstructions) - { - Code code = inst.OpCode.Code; - if (!(inst.Operand is IField field) || !field.IsField) - { - return false; - } - FieldDef fieldDef = field.ResolveFieldDefThrow(); - if (!IsSupportedFieldType(fieldDef.FieldSig.Type) || !_encryptionPolicy.NeedEncrypt(fieldDef)) - { - return false; - } - switch (code) - { - case Code.Ldfld: - { - _memoryEncryptor.Decrypt(callingMethod, fieldDef, outputInstructions, inst); - break; - } - case Code.Stfld: - { - _memoryEncryptor.Encrypt(callingMethod, fieldDef, outputInstructions, inst); - break; - } - case Code.Ldsfld: - { - _memoryEncryptor.Decrypt(callingMethod, fieldDef, outputInstructions, inst); - break; - } - case Code.Stsfld: - { - _memoryEncryptor.Encrypt(callingMethod, fieldDef, outputInstructions, inst); - break; - } - case Code.Ldflda: - case Code.Ldsflda: - { - throw new System.Exception($"You shouldn't get reference to memory encryption field: {field}"); - } - default: return false; - } - //Debug.Log($"memory encrypt field: {field}"); - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/FieldEncryptPass.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/FieldEncryptPass.cs.meta deleted file mode 100644 index 1e60f28c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/FieldEncryptPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f3da24d0f1f1fc7449cbd0e7ddd03aa2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IEncryptPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IEncryptPolicy.cs deleted file mode 100644 index ee7dd534..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IEncryptPolicy.cs +++ /dev/null @@ -1,14 +0,0 @@ -using dnlib.DotNet; - -namespace Obfuz.ObfusPasses.FieldEncrypt -{ - public interface IEncryptPolicy - { - bool NeedEncrypt(FieldDef field); - } - - public abstract class EncryptPolicyBase : IEncryptPolicy - { - public abstract bool NeedEncrypt(FieldDef field); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IEncryptPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IEncryptPolicy.cs.meta deleted file mode 100644 index d5c10473..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IEncryptPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a48d0500d0737404cad9c9ef23a9467c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IFieldEncryptor.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IFieldEncryptor.cs deleted file mode 100644 index 0b6d5821..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IFieldEncryptor.cs +++ /dev/null @@ -1,26 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.FieldEncrypt -{ - public class MemoryEncryptionContext - { - public ModuleDef module; - - public Instruction currentInstruction; - } - - public interface IFieldEncryptor - { - void Encrypt(MethodDef method, FieldDef field, List outputInstructions, Instruction currentInstruction); - - void Decrypt(MethodDef method, FieldDef field, List outputInstructions, Instruction currentInstruction); - } - - public abstract class FieldEncryptorBase : IFieldEncryptor - { - public abstract void Encrypt(MethodDef method, FieldDef field, List outputInstructions, Instruction currentInstruction); - public abstract void Decrypt(MethodDef method, FieldDef field, List outputInstructions, Instruction currentInstruction); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IFieldEncryptor.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IFieldEncryptor.cs.meta deleted file mode 100644 index dca50715..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/FieldEncrypt/IFieldEncryptor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8a3ec14fca5169d479529d21b2eeada1 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct.meta deleted file mode 100644 index 97e300cc..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bb4f71e54c6a07341883ba0c642505c1 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct/InstinctPass.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct/InstinctPass.cs deleted file mode 100644 index f7b32753..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct/InstinctPass.cs +++ /dev/null @@ -1,138 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Editor; -using Obfuz.Emit; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine.Assertions; - -namespace Obfuz.ObfusPasses.Instinct -{ - - public class InstinctPass : InstructionObfuscationPassBase - { - public override ObfuscationPassType Type => ObfuscationPassType.None; - - protected override bool ForceProcessAllAssembliesAndIgnoreAllPolicy => true; - - public InstinctPass() - { - } - - public override void Start() - { - } - - public override void Stop() - { - - } - - protected override bool NeedObfuscateMethod(MethodDef method) - { - return true; - } - - private string GetTypeName(TypeSig type) - { - type = type.RemovePinnedAndModifiers(); - switch (type.ElementType) - { - case ElementType.Class: - case ElementType.ValueType: - { - return type.ReflectionName; - } - case ElementType.GenericInst: - { - type = ((GenericInstSig)type).GenericType; - return type.ReflectionName; - } - default: return type.ReflectionName; - } - } - - private string GetTypeFullName(TypeSig type) - { - type = type.RemovePinnedAndModifiers(); - - switch (type.ElementType) - { - case ElementType.Class: - case ElementType.ValueType: - { - return type.ReflectionFullName; - } - case ElementType.GenericInst: - { - GenericInstSig genericInstSig = (GenericInstSig)type; - var typeName = new StringBuilder(genericInstSig.GenericType.ReflectionFullName); - typeName.Append("<").Append(string.Join(",", genericInstSig.GenericArguments.Select(GetTypeFullName))).Append(">"); - return typeName.ToString(); - } - default: return type.ReflectionFullName; - } - } - - protected override bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList instructions, int instructionIndex, List outputInstructions, List totalFinalInstructions) - { - Code code = inst.OpCode.Code; - if (!(inst.Operand is IMethod method) || !method.IsMethod) - { - return false; - } - MethodDef methodDef = method.ResolveMethodDef(); - if (methodDef == null || methodDef.DeclaringType.Name != "ObfuscationInstincts" || methodDef.DeclaringType.DefinitionAssembly.Name != ConstValues.ObfuzRuntimeAssemblyName) - { - return false; - } - - ObfuscationPassContext ctx = ObfuscationPassContext.Current; - var importer = ctx.moduleEntityManager.GetEntity(callingMethod.Module); - - string methodName = methodDef.Name; - switch (methodName) - { - case "FullNameOf": - case "NameOf": - case "RegisterReflectionType": - { - MethodSpec methodSpec = (MethodSpec)method; - GenericInstMethodSig gims = methodSpec.GenericInstMethodSig; - Assert.AreEqual(1, gims.GenericArguments.Count, "FullNameOf should have exactly one generic argument"); - TypeSig type = gims.GenericArguments[0]; - switch (methodName) - { - case "FullNameOf": - { - string typeFullName = GetTypeFullName(type); - outputInstructions.Add(Instruction.Create(OpCodes.Ldstr, typeFullName)); - break; - } - case "NameOf": - { - string typeName = GetTypeName(type); - outputInstructions.Add(Instruction.Create(OpCodes.Ldstr, typeName)); - break; - } - case "RegisterReflectionType": - { - string typeFullName = GetTypeFullName(type); - outputInstructions.Add(Instruction.Create(OpCodes.Ldstr, typeFullName)); - var finalMethod = new MethodSpecUser((IMethodDefOrRef)importer.ObfuscationTypeMapperRegisterType, gims); - outputInstructions.Add(Instruction.Create(OpCodes.Call, finalMethod)); - break; - } - default: throw new NotSupportedException($"Unsupported instinct method: {methodDef.FullName}"); - } - break; - } - default: throw new NotSupportedException($"Unsupported instinct method: {methodDef.FullName}"); - } - //Debug.Log($"memory encrypt field: {field}"); - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct/InstinctPass.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct/InstinctPass.cs.meta deleted file mode 100644 index ca21ae47..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/Instinct/InstinctPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 08027d16e09664c40b561715ef9326fc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/InstructionObfuscationPassBase.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/InstructionObfuscationPassBase.cs deleted file mode 100644 index 424c0d20..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/InstructionObfuscationPassBase.cs +++ /dev/null @@ -1,46 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses -{ - public abstract class InstructionObfuscationPassBase : ObfuscationMethodPassBase - { - protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList instructions, int instructionIndex, - List outputInstructions, List totalFinalInstructions); - - protected override void ObfuscateData(MethodDef method) - { - IList instructions = method.Body.Instructions; - var outputInstructions = new List(); - var totalFinalInstructions = new List(); - for (int i = 0; i < instructions.Count; i++) - { - Instruction inst = instructions[i]; - outputInstructions.Clear(); - if (TryObfuscateInstruction(method, inst, instructions, i, outputInstructions, totalFinalInstructions)) - { - // current instruction may be the target of control flow instruction, so we can't remove it directly. - // we replace it with nop now, then remove it in CleanUpInstructionPass - inst.OpCode = outputInstructions[0].OpCode; - inst.Operand = outputInstructions[0].Operand; - totalFinalInstructions.Add(inst); - for (int k = 1; k < outputInstructions.Count; k++) - { - totalFinalInstructions.Add(outputInstructions[k]); - } - } - else - { - totalFinalInstructions.Add(inst); - } - } - - instructions.Clear(); - foreach (var obInst in totalFinalInstructions) - { - instructions.Add(obInst); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/InstructionObfuscationPassBase.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/InstructionObfuscationPassBase.cs.meta deleted file mode 100644 index ba2497af..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/InstructionObfuscationPassBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e0cad4b764050f44f8c9b225056a4f49 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationMethodPassBase.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationMethodPassBase.cs deleted file mode 100644 index 7a2e0942..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationMethodPassBase.cs +++ /dev/null @@ -1,47 +0,0 @@ -using dnlib.DotNet; -using System.Linq; - -namespace Obfuz.ObfusPasses -{ - public abstract class ObfuscationMethodPassBase : ObfuscationPassBase - { - protected virtual bool ForceProcessAllAssembliesAndIgnoreAllPolicy => false; - - protected abstract bool NeedObfuscateMethod(MethodDef method); - - protected abstract void ObfuscateData(MethodDef method); - - public override void Process() - { - var ctx = ObfuscationPassContext.Current; - var modules = ForceProcessAllAssembliesAndIgnoreAllPolicy ? ctx.allObfuscationRelativeModules : ctx.modulesToObfuscate; - ObfuscationMethodWhitelist whiteList = ctx.whiteList; - ConfigurablePassPolicy passPolicy = ctx.passPolicy; - foreach (ModuleDef mod in modules) - { - if (!ForceProcessAllAssembliesAndIgnoreAllPolicy && whiteList.IsInWhiteList(mod)) - { - continue; - } - // ToArray to avoid modify list exception - foreach (TypeDef type in mod.GetTypes().ToArray()) - { - if (!ForceProcessAllAssembliesAndIgnoreAllPolicy && whiteList.IsInWhiteList(type)) - { - continue; - } - // ToArray to avoid modify list exception - foreach (MethodDef method in type.Methods.ToArray()) - { - if (!method.HasBody || (!ForceProcessAllAssembliesAndIgnoreAllPolicy && (ctx.whiteList.IsInWhiteList(method) || !Support(passPolicy.GetMethodObfuscationPasses(method)) || !NeedObfuscateMethod(method)))) - { - continue; - } - // TODO if isGeneratedBy Obfuscator, continue - ObfuscateData(method); - } - } - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationMethodPassBase.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationMethodPassBase.cs.meta deleted file mode 100644 index 0be4d9f9..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationMethodPassBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 84b0592af70b0cc41b546cf8ac39f889 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassBase.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassBase.cs deleted file mode 100644 index 48e23ec8..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassBase.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Obfuz.ObfusPasses -{ - public abstract class ObfuscationPassBase : IObfuscationPass - { - public abstract ObfuscationPassType Type { get; } - - public bool Support(ObfuscationPassType passType) - { - return passType.HasFlag(Type); - } - - public abstract void Start(); - - public abstract void Stop(); - - public abstract void Process(); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassBase.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassBase.cs.meta deleted file mode 100644 index 335ee271..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2f3e7e1d2a3ad3a4fb1a81e97730b5a4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassType.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassType.cs deleted file mode 100644 index b5deb968..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassType.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace Obfuz.ObfusPasses -{ - [Flags] - public enum ObfuscationPassType - { - None = 0, - - ConstEncrypt = 0x1, - FieldEncrypt = 0x2, - - SymbolObfus = 0x100, - CallObfus = 0x200, - ExprObfus = 0x400, - ControlFlowObfus = 0x800, - EvalStackObfus = 0x1000, - - AllObfus = SymbolObfus | CallObfus | ExprObfus | ControlFlowObfus | EvalStackObfus, - AllEncrypt = ConstEncrypt | FieldEncrypt, - - MethodBodyObfusOrEncrypt = ConstEncrypt | CallObfus | ExprObfus | ControlFlowObfus | EvalStackObfus, - - All = ~0, - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassType.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassType.cs.meta deleted file mode 100644 index b03ea206..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/ObfuscationPassType.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5addd02f6f3dc0a4d888a0f74bd5ce4d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus.meta deleted file mode 100644 index 331b3d15..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b746569f7c0d9754fa6f2925538eddbd -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/INameMaker.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/INameMaker.cs deleted file mode 100644 index 6f95ffdb..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/INameMaker.cs +++ /dev/null @@ -1,37 +0,0 @@ -using dnlib.DotNet; - -namespace Obfuz.ObfusPasses.SymbolObfus -{ - public interface INameMaker - { - void AddPreservedName(TypeDef typeDef, string name); - - void AddPreservedNamespace(TypeDef typeDef, string name); - - void AddPreservedName(MethodDef methodDef, string name); - - void AddPreservedName(FieldDef fieldDef, string name); - - void AddPreservedName(PropertyDef propertyDef, string name); - - void AddPreservedName(EventDef eventDef, string name); - - bool IsNamePreserved(VirtualMethodGroup virtualMethodGroup, string name); - - string GetNewName(TypeDef typeDef, string originalName); - - string GetNewNamespace(TypeDef typeDef, string originalNamespace, bool reuse); - - string GetNewName(MethodDef methodDef, string originalName); - - string GetNewName(VirtualMethodGroup virtualMethodGroup, string originalName); - - string GetNewName(ParamDef param, string originalName); - - string GetNewName(FieldDef fieldDef, string originalName); - - string GetNewName(PropertyDef propertyDef, string originalName); - - string GetNewName(EventDef eventDef, string originalName); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/INameMaker.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/INameMaker.cs.meta deleted file mode 100644 index 80621974..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/INameMaker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0c24d29f654d00b44bb6aa3b4bf222dd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/IObfuscationPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/IObfuscationPolicy.cs deleted file mode 100644 index 2a39e451..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/IObfuscationPolicy.cs +++ /dev/null @@ -1,17 +0,0 @@ -using dnlib.DotNet; - -namespace Obfuz.ObfusPasses.SymbolObfus -{ - public interface IObfuscationPolicy - { - bool NeedRename(TypeDef typeDef); - - bool NeedRename(MethodDef methodDef); - - bool NeedRename(FieldDef fieldDef); - - bool NeedRename(PropertyDef propertyDef); - - bool NeedRename(EventDef eventDef); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/IObfuscationPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/IObfuscationPolicy.cs.meta deleted file mode 100644 index ffe0fee1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/IObfuscationPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bd640b26c1d868544a7a91a0f986fdde -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers.meta deleted file mode 100644 index 9cd6e532..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c970ffd992fbc154aaa37a2c48c24d5c -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/DebugNameMaker.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/DebugNameMaker.cs deleted file mode 100644 index 038281e4..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/DebugNameMaker.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Text; - -namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers -{ - public class DebugNameMaker : NameMakerBase - { - private class DebugNameScope : INameScope - { - - public bool AddPreservedName(string name) - { - return true; - } - - public string GetNewName(string originalName, bool reuse) - { - return $"${originalName}"; - } - - public bool IsNamePreserved(string name) - { - return false; - } - } - - protected override INameScope CreateNameScope() - { - return new DebugNameScope(); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/DebugNameMaker.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/DebugNameMaker.cs.meta deleted file mode 100644 index 11b505b8..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/DebugNameMaker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: abc1adfad5c7754499ceed4d4646eb58 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/INameScope.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/INameScope.cs deleted file mode 100644 index c6ca426f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/INameScope.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers -{ - public interface INameScope - { - bool AddPreservedName(string name); - - bool IsNamePreserved(string name); - - string GetNewName(string originalName, bool reuse); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/INameScope.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/INameScope.cs.meta deleted file mode 100644 index 4c632535..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/INameScope.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6c3884d338faf564eab48d58f02adc39 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerBase.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerBase.cs deleted file mode 100644 index 1cd72c95..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerBase.cs +++ /dev/null @@ -1,116 +0,0 @@ -using dnlib.DotNet; -using System.Collections.Generic; -using UnityEngine.Assertions; - -namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers -{ - public abstract class NameMakerBase : INameMaker - { - - private readonly Dictionary _nameScopes = new Dictionary(); - - private readonly object _namespaceScope = new object(); - private readonly object _typeNameScope = new object(); - private readonly object _methodNameScope = new object(); - private readonly object _fieldNameScope = new object(); - - protected abstract INameScope CreateNameScope(); - - protected INameScope GetNameScope(object key) - { - if (!_nameScopes.TryGetValue(key, out var nameScope)) - { - nameScope = CreateNameScope(); - _nameScopes[key] = nameScope; - } - return nameScope; - } - - public void AddPreservedName(TypeDef typeDef, string name) - { - GetNameScope(_typeNameScope).AddPreservedName(name); - } - - public void AddPreservedName(MethodDef methodDef, string name) - { - GetNameScope(_methodNameScope).AddPreservedName(name); - } - - public void AddPreservedName(FieldDef fieldDef, string name) - { - GetNameScope(_fieldNameScope).AddPreservedName(name); - } - - public void AddPreservedName(PropertyDef propertyDef, string name) - { - GetNameScope(propertyDef.DeclaringType).AddPreservedName(name); - } - - public void AddPreservedName(EventDef eventDef, string name) - { - GetNameScope(eventDef.DeclaringType).AddPreservedName(name); - } - - public void AddPreservedNamespace(TypeDef typeDef, string name) - { - GetNameScope(_namespaceScope).AddPreservedName(name); - } - - public bool IsNamePreserved(VirtualMethodGroup virtualMethodGroup, string name) - { - var scope = GetNameScope(_methodNameScope); - return scope.IsNamePreserved(name); - } - - private string GetDefaultNewName(object scope, string originName) - { - return GetNameScope(scope).GetNewName(originName, false); - } - - public string GetNewNamespace(TypeDef typeDef, string originalNamespace, bool reuse) - { - if (string.IsNullOrEmpty(originalNamespace)) - { - return string.Empty; - } - return GetNameScope(_namespaceScope).GetNewName(originalNamespace, reuse); - } - - public string GetNewName(TypeDef typeDef, string originalName) - { - return GetDefaultNewName(_typeNameScope, originalName); - } - - public string GetNewName(MethodDef methodDef, string originalName) - { - Assert.IsFalse(methodDef.IsVirtual); - return GetDefaultNewName(_methodNameScope, originalName); - } - - public string GetNewName(VirtualMethodGroup virtualMethodGroup, string originalName) - { - var scope = GetNameScope(_methodNameScope); - return scope.GetNewName(originalName, false); - } - - public virtual string GetNewName(ParamDef param, string originalName) - { - return "1"; - } - - public string GetNewName(FieldDef fieldDef, string originalName) - { - return GetDefaultNewName(_fieldNameScope, originalName); - } - - public string GetNewName(PropertyDef propertyDef, string originalName) - { - return GetDefaultNewName(propertyDef.DeclaringType, originalName); - } - - public string GetNewName(EventDef eventDef, string originalName) - { - return GetDefaultNewName(eventDef.DeclaringType, originalName); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerBase.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerBase.cs.meta deleted file mode 100644 index d3ca8a02..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 205da3a8ebfd4ae4ba72d27db4b92d3f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerFactory.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerFactory.cs deleted file mode 100644 index 08f3267d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerFactory.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers -{ - public static class NameMakerFactory - { - public static INameMaker CreateDebugNameMaker() - { - return new DebugNameMaker(); - } - - public static INameMaker CreateNameMakerBaseASCIICharSet(string namePrefix) - { - var words = new List(); - for (int i = 0; i < 26; i++) - { - words.Add(((char)('a' + i)).ToString()); - words.Add(((char)('A' + i)).ToString()); - } - return new WordSetNameMaker(namePrefix, words); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerFactory.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerFactory.cs.meta deleted file mode 100644 index e1fb22c4..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameMakerFactory.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: afa0e87123ec9854b806098330c4980a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScope.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScope.cs deleted file mode 100644 index 189ccf03..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScope.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; -using System.Text; - -namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers -{ - - public class NameScope : NameScopeBase - { - private readonly string _namePrefix; - private readonly List _wordSet; - private int _nextIndex; - - public NameScope(string namePrefix, List wordSet) - { - _namePrefix = namePrefix; - _wordSet = wordSet; - _nextIndex = 0; - } - - protected override void BuildNewName(StringBuilder nameBuilder, string originalName, string lastName) - { - nameBuilder.Append(_namePrefix); - for (int i = _nextIndex++; ;) - { - nameBuilder.Append(_wordSet[i % _wordSet.Count]); - i = i / _wordSet.Count; - if (i == 0) - { - break; - } - } - - // keep generic type name pattern {name}`{n}, if not, il2cpp may raise exception in typeof(G) when G contains a field likes `T a`. - int index = originalName.LastIndexOf('`'); - if (index != -1) - { - nameBuilder.Append(originalName.Substring(index)); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScope.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScope.cs.meta deleted file mode 100644 index e2242370..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScope.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a35c5c4b49c98a84f94b690c26900c33 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScopeBase.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScopeBase.cs deleted file mode 100644 index daa8cc8b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScopeBase.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Collections.Generic; -using System.Text; - -namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers -{ - public abstract class NameScopeBase : INameScope - { - - private readonly Dictionary _nameMap = new Dictionary(); - - private readonly HashSet _preservedNames = new HashSet(); - - - public bool AddPreservedName(string name) - { - if (!string.IsNullOrEmpty(name)) - { - return _preservedNames.Add(name); - } - return false; - } - - public bool IsNamePreserved(string name) - { - return _preservedNames.Contains(name); - } - - - protected abstract void BuildNewName(StringBuilder nameBuilder, string originalName, string lastName); - - private string CreateNewName(string originalName) - { - var nameBuilder = new StringBuilder(); - string lastName = null; - while (true) - { - nameBuilder.Clear(); - BuildNewName(nameBuilder, originalName, lastName); - string newName = nameBuilder.ToString(); - lastName = newName; - if (_preservedNames.Add(newName)) - { - return newName; - } - } - } - - public string GetNewName(string originalName, bool reuse) - { - if (!reuse) - { - return CreateNewName(originalName); - } - if (_nameMap.TryGetValue(originalName, out var newName)) - { - return newName; - } - newName = CreateNewName(originalName); - _nameMap[originalName] = newName; - return newName; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScopeBase.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScopeBase.cs.meta deleted file mode 100644 index 17853c8a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/NameScopeBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 26e6ae1f35e7f094c844cf1567b88a19 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/WordSetNameMaker.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/WordSetNameMaker.cs deleted file mode 100644 index f6edddb1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/WordSetNameMaker.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers -{ - - public class WordSetNameMaker : NameMakerBase - { - private readonly string _namePrefix; - private readonly List _wordSet; - - public WordSetNameMaker(string namePrefix, List wordSet) - { - _namePrefix = namePrefix; - _wordSet = wordSet; - } - - protected override INameScope CreateNameScope() - { - return new NameScope(_namePrefix, _wordSet); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/WordSetNameMaker.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/WordSetNameMaker.cs.meta deleted file mode 100644 index 23706b3d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/NameMakers/WordSetNameMaker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 47c92aea40a66e34b92f9eb5c0d380ca -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies.meta deleted file mode 100644 index c16875c9..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 98e496436c90c0a4f82711af059471c7 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CacheRenamePolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CacheRenamePolicy.cs deleted file mode 100644 index 7b84d727..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CacheRenamePolicy.cs +++ /dev/null @@ -1,67 +0,0 @@ -using dnlib.DotNet; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.SymbolObfus.Policies -{ - public class CacheRenamePolicy : ObfuscationPolicyBase - { - private readonly IObfuscationPolicy _underlyingPolicy; - - private readonly Dictionary _computeCache = new Dictionary(); - - public CacheRenamePolicy(IObfuscationPolicy underlyingPolicy) - { - _underlyingPolicy = underlyingPolicy; - } - - public override bool NeedRename(TypeDef typeDef) - { - if (!_computeCache.TryGetValue(typeDef, out var value)) - { - value = _underlyingPolicy.NeedRename(typeDef); - _computeCache[typeDef] = value; - } - return value; - } - - public override bool NeedRename(MethodDef methodDef) - { - if (!_computeCache.TryGetValue(methodDef, out var value)) - { - value = _underlyingPolicy.NeedRename(methodDef); - _computeCache[methodDef] = value; - } - return value; - } - - public override bool NeedRename(FieldDef fieldDef) - { - if (!_computeCache.TryGetValue(fieldDef, out var value)) - { - value = _underlyingPolicy.NeedRename(fieldDef); - _computeCache[fieldDef] = value; - } - return value; - } - - public override bool NeedRename(PropertyDef propertyDef) - { - if (!_computeCache.TryGetValue(propertyDef, out var value)) - { - value = _underlyingPolicy.NeedRename(propertyDef); - _computeCache[propertyDef] = value; - } - return value; - } - - public override bool NeedRename(EventDef eventDef) - { - if (!_computeCache.TryGetValue(eventDef, out var value)) - { - value = _underlyingPolicy.NeedRename(eventDef); - _computeCache[eventDef] = value; - } - return value; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CacheRenamePolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CacheRenamePolicy.cs.meta deleted file mode 100644 index ab4330f7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CacheRenamePolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c319b2ad62ad8794f9a8bc234c856d7f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CombineRenamePolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CombineRenamePolicy.cs deleted file mode 100644 index a84a5877..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CombineRenamePolicy.cs +++ /dev/null @@ -1,40 +0,0 @@ -using dnlib.DotNet; -using System.Linq; - -namespace Obfuz.ObfusPasses.SymbolObfus.Policies -{ - public class CombineRenamePolicy : IObfuscationPolicy - { - private readonly IObfuscationPolicy[] _policies; - - public CombineRenamePolicy(params IObfuscationPolicy[] policies) - { - _policies = policies; - } - - public bool NeedRename(TypeDef typeDef) - { - return _policies.All(policy => policy.NeedRename(typeDef)); - } - - public bool NeedRename(MethodDef methodDef) - { - return _policies.All(policy => policy.NeedRename(methodDef)); - } - - public bool NeedRename(FieldDef fieldDef) - { - return _policies.All(policy => policy.NeedRename(fieldDef)); - } - - public bool NeedRename(PropertyDef propertyDef) - { - return _policies.All(policy => policy.NeedRename(propertyDef)); - } - - public bool NeedRename(EventDef eventDef) - { - return _policies.All(policy => policy.NeedRename(eventDef)); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CombineRenamePolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CombineRenamePolicy.cs.meta deleted file mode 100644 index fcf6ea9d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/CombineRenamePolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 97be4546adeb71947bf644949c3a9e82 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ConfigurableRenamePolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ConfigurableRenamePolicy.cs deleted file mode 100644 index 955c30d0..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ConfigurableRenamePolicy.cs +++ /dev/null @@ -1,792 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml; -using UnityEngine; - -namespace Obfuz.ObfusPasses.SymbolObfus.Policies -{ - - public class ConfigurableRenamePolicy : ObfuscationPolicyBase - { - enum ModifierType - { - None = 0x0, - Private = 0x1, - Protected = 0x2, - Public = 0x3, - } - - class MethodRuleSpec - { - public NameMatcher nameMatcher; - public ModifierType? modifierType; - public bool? obfuscateName; - } - - class FieldRuleSpec - { - public NameMatcher nameMatcher; - public ModifierType? modifierType; - public bool? obfuscateName; - } - - class PropertyRuleSpec - { - public NameMatcher nameMatcher; - public ModifierType? modifierType; - public bool? obfuscateName; - public ObfuzScope? applyToMembers; - } - - class EventRuleSpec - { - public NameMatcher nameMatcher; - public ModifierType? modifierType; - public bool? obfuscateName; - public ObfuzScope? applyToMembers; - } - - class TypeRuleSpec - { - public NameMatcher nameMatcher; - public ModifierType? modifierType; - public ClassType? classType; - public List inheritTypes; - public List hasCustomAttributes; - public bool? obfuscateName; - public ObfuzScope? applyToMembers; - public bool applyToNestedTypes; - - public List fields; - public List methods; - public List properties; - public List events; - } - - class AssemblyRuleSpec - { - public string assemblyName; - public List types; - } - - private readonly Dictionary> _assemblyRuleSpecs = new Dictionary>(); - - private AssemblyRuleSpec ParseAssembly(XmlElement ele) - { - string assemblyName = ele.GetAttribute("name"); - if (string.IsNullOrEmpty(assemblyName)) - { - throw new Exception($"Invalid xml file, assembly name is empty"); - } - if (!_obfuscationAssemblyNames.Contains(assemblyName)) - { - throw new Exception($"unknown assembly name:{assemblyName}, not in ObfuzSettings.obfuscationAssemblyNames"); - } - var rule = new AssemblyRuleSpec() - { - assemblyName = assemblyName, - types = new List(), - }; - - foreach (XmlNode node in ele.ChildNodes) - { - if (!(node is XmlElement childElement)) - { - continue; - } - if (childElement.Name != "type") - { - throw new Exception($"Invalid xml file, unknown node {childElement.Name}"); - } - TypeRuleSpec type = ParseType(childElement); - rule.types.Add(type); - } - return rule; - } - - private enum ClassType - { - None = 0x0, - Class = 0x1, - Struct = 0x2, - Interface = 0x4, - Enum = 0x8, - Delegate = 0x10, - } - - private ClassType? ParseClassType(string classType) - { - if (string.IsNullOrEmpty(classType)) - { - return null; - } - - ClassType type = ClassType.None; - foreach (var s in classType.Split(',')) - { - switch (s) - { - case "class": type |= ClassType.Class; break; - case "struct": type |= ClassType.Struct; break; - case "interface": type |= ClassType.Interface; break; - case "enum": type |= ClassType.Enum; break; - case "delegate": type |= ClassType.Delegate; break; - default: throw new Exception($"Invalid class type {s}"); - } - } - return type; - } - - private ModifierType? ParseModifierType(string modifierType) - { - if (string.IsNullOrEmpty(modifierType)) - { - return null; - } - ModifierType type = ModifierType.None; - foreach (var s in modifierType.Split(',')) - { - switch (s) - { - case "public": type |= ModifierType.Public; break; - case "protected": type |= ModifierType.Protected; break; - case "private": type |= ModifierType.Private; break; - default: throw new Exception($"Invalid modifier type {s}"); - } - } - return type; - } - - - private ObfuzScope? ParseApplyToMembersScope(string membersScopeStr) - { - if (string.IsNullOrWhiteSpace(membersScopeStr)) - { - return null; - } - ObfuzScope scope = ObfuzScope.None; - - foreach (string s in membersScopeStr.Split(',')) - { - var s2 = s.Trim().ToLowerInvariant(); - switch (s2) - { - case "none": break; - case "field": scope |= ObfuzScope.Field; break; - case "eventname": scope |= ObfuzScope.EventName; break; - case "eventaddremovefirename": scope |= ObfuzScope.EventAddRemoveFireName; break; - case "event": scope |= ObfuzScope.Event; break; - case "methodname": scope |= ObfuzScope.MethodName; break; - case "method": scope |= ObfuzScope.MethodName; break; - case "propertyname": scope |= ObfuzScope.PropertyName; break; - case "propertygettersettername": scope |= ObfuzScope.PropertyGetterSetterName; break; - case "property": scope |= ObfuzScope.Property; break; - case "all": - case "*": scope |= ObfuzScope.All; break; - default: - { - throw new Exception($"Invalid applyToMembers scope {s2}"); - } - } - } - - return scope; - } - - private List ParseTypes(string inheritStr) - { - if (string.IsNullOrWhiteSpace(inheritStr)) - { - return null; - } - var inheritTypes = new List(); - foreach (var s in inheritStr.Split(',')) - { - var trimmed = s.Trim(); - if (!string.IsNullOrEmpty(trimmed)) - { - inheritTypes.Add(trimmed); - } - } - return inheritTypes; - } - - private TypeRuleSpec ParseType(XmlElement element) - { - var rule = new TypeRuleSpec(); - - rule.nameMatcher = new NameMatcher(element.GetAttribute("name")); - rule.obfuscateName = ConfigUtil.ParseNullableBool(element.GetAttribute("obName")); - rule.applyToMembers = ParseApplyToMembersScope(element.GetAttribute("applyToMembers")); - rule.applyToNestedTypes = ConfigUtil.ParseNullableBool(element.GetAttribute("applyToNestedTypes")) ?? true; - rule.modifierType = ParseModifierType(element.GetAttribute("modifier")); - rule.classType = ParseClassType(element.GetAttribute("classType")); - rule.inheritTypes = ParseTypes(element.GetAttribute("inherit")); - rule.hasCustomAttributes = ParseTypes(element.GetAttribute("hasCustomAttributes")); - - //rule.nestTypeRuleSpecs = new List(); - rule.fields = new List(); - rule.methods = new List(); - rule.properties = new List(); - rule.events = new List(); - foreach (XmlNode node in element.ChildNodes) - { - if (!(node is XmlElement childElement)) - { - continue; - } - switch (childElement.Name) - { - case "field": - { - var fieldRuleSpec = new FieldRuleSpec(); - fieldRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name")); - fieldRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier")); - fieldRuleSpec.obfuscateName = ConfigUtil.ParseNullableBool(childElement.GetAttribute("obName")); - rule.fields.Add(fieldRuleSpec); - break; - } - case "method": - { - var methodRuleSpec = new MethodRuleSpec(); - methodRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name")); - methodRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier")); - methodRuleSpec.obfuscateName = ConfigUtil.ParseNullableBool(childElement.GetAttribute("obName")); - rule.methods.Add(methodRuleSpec); - break; - } - case "property": - { - var propertyRulerSpec = new PropertyRuleSpec(); - propertyRulerSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name")); - propertyRulerSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier")); - propertyRulerSpec.obfuscateName = ConfigUtil.ParseNullableBool(childElement.GetAttribute("obName")); - propertyRulerSpec.applyToMembers = ParseApplyToMembersScope(childElement.GetAttribute("applyToMembers")); - rule.properties.Add(propertyRulerSpec); - break; - } - case "event": - { - var eventRuleSpec = new EventRuleSpec(); - eventRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name")); - eventRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier")); - eventRuleSpec.obfuscateName = ConfigUtil.ParseNullableBool(childElement.GetAttribute("obName")); - eventRuleSpec.applyToMembers = ParseApplyToMembersScope(childElement.GetAttribute("applyToMembers")); - rule.events.Add(eventRuleSpec); - break; - } - default: throw new Exception($"Invalid xml file, unknown node {childElement.Name} in type node"); - } - } - return rule; - } - - private void LoadXmls(List xmlFiles) - { - var rawAssemblySpecElements = new List(); - foreach (string file in xmlFiles) - { - LoadRawXml(file, rawAssemblySpecElements); - } - ResolveAssemblySpecs(rawAssemblySpecElements); - } - - private void ResolveAssemblySpecs(List rawAssemblySpecElements) - { - foreach (XmlElement ele in rawAssemblySpecElements) - { - var assemblyRule = ParseAssembly(ele); - if (!_assemblyRuleSpecs.TryGetValue(assemblyRule.assemblyName, out var existAssemblyRules)) - { - existAssemblyRules = new List(); - _assemblyRuleSpecs.Add(assemblyRule.assemblyName, existAssemblyRules); - } - existAssemblyRules.Add(assemblyRule); - } - } - - private void LoadRawXml(string xmlFile, List rawAssemblyElements) - { - Debug.Log($"ObfuscateRule::LoadXml {xmlFile}"); - var doc = new XmlDocument(); - doc.Load(xmlFile); - var root = doc.DocumentElement; - if (root.Name != "obfuz") - { - throw new Exception($"Invalid xml file {xmlFile}, root name should be 'obfuz'"); - } - foreach (XmlNode node in root.ChildNodes) - { - if (!(node is XmlElement element)) - { - continue; - } - switch (element.Name) - { - case "assembly": - { - rawAssemblyElements.Add(element); - break; - } - default: - { - throw new Exception($"Invalid xml file {xmlFile}, unknown node {element.Name}"); - } - } - } - } - - private ModifierType ComputeModifierType(TypeAttributes visibility) - { - if (visibility == TypeAttributes.NotPublic || visibility == TypeAttributes.NestedPrivate) - { - return ModifierType.Private; - } - if (visibility == TypeAttributes.Public || visibility == TypeAttributes.NestedPublic) - { - return ModifierType.Public; - } - return ModifierType.Protected; - } - - private ModifierType ComputeModifierType(FieldAttributes access) - { - if (access == FieldAttributes.Private || access == FieldAttributes.PrivateScope) - { - return ModifierType.Private; - } - if (access == FieldAttributes.Public) - { - return ModifierType.Public; - } - return ModifierType.Protected; - } - - //private ModifierType ComputeModifierType(MethodAttributes access) - //{ - // if (access == MethodAttributes.Private || access == MethodAttributes.PrivateScope) - // { - // return ModifierType.Private; - // } - // if (access == MethodAttributes.Public) - // { - // return ModifierType.Public; - // } - // return ModifierType.Protected; - //} - - private bool MatchModifier(ModifierType? modifierType, TypeDef typeDef) - { - return modifierType == null || (modifierType & ComputeModifierType(typeDef.Visibility)) != 0; - } - - private bool MatchModifier(ModifierType? modifierType, FieldDef fieldDef) - { - return modifierType == null || (modifierType & ComputeModifierType(fieldDef.Access)) != 0; - } - - private bool MatchModifier(ModifierType? modifierType, MethodDef methodDef) - { - return modifierType == null || (modifierType & ComputeModifierType((FieldAttributes)methodDef.Access)) != 0; - } - - private bool MatchModifier(ModifierType? modifierType, PropertyDef propertyDef) - { - return modifierType == null || (modifierType & ComputeModifierType((FieldAttributes)propertyDef.Attributes)) != 0; - } - - private bool MatchModifier(ModifierType? modifierType, EventDef eventDef) - { - return modifierType == null || (modifierType & ComputeModifierType((FieldAttributes)eventDef.Attributes)) != 0; - } - - private class MethodComputeCache - { - public bool obfuscateName = true; - public bool obfuscateParam = true; - public bool obfuscateBody = true; - } - - private class RuleResult - { - public bool? obfuscateName; - } - - private readonly Dictionary _typeSpecCache = new Dictionary(); - private readonly Dictionary _methodSpecCache = new Dictionary(); - private readonly Dictionary _fieldSpecCache = new Dictionary(); - private readonly Dictionary _propertySpecCache = new Dictionary(); - private readonly Dictionary _eventSpecCache = new Dictionary(); - - - private readonly HashSet _obfuscationAssemblyNames; - private readonly List _assembliesToObfuscate; - - public ConfigurableRenamePolicy(List obfuscationAssemblyNames, List assembliesToObfuscate, List xmlFiles) - { - _obfuscationAssemblyNames = new HashSet(obfuscationAssemblyNames); - _assembliesToObfuscate = assembliesToObfuscate; - LoadXmls(xmlFiles); - BuildRuleResultCaches(); - } - - private bool MatchClassType(ClassType? classType, TypeDef typeDef) - { - if (classType == null) - { - return true; - } - if (typeDef.IsInterface && (classType & ClassType.Interface) != 0) - { - return true; - } - if (typeDef.IsEnum && (classType & ClassType.Enum) != 0) - { - return true; - } - if (typeDef.IsDelegate && (classType & ClassType.Delegate) != 0) - { - return true; - } - if (typeDef.IsValueType && !typeDef.IsEnum && (classType & ClassType.Struct) != 0) - { - return true; - } - if (!typeDef.IsValueType && !typeDef.IsInterface && !typeDef.IsDelegate && (classType & ClassType.Class) != 0) - { - return true; - } - return false; - } - - - private RuleResult GetOrCreateTypeRuleResult(TypeDef typeDef) - { - if (!_typeSpecCache.TryGetValue(typeDef, out var ruleResult)) - { - ruleResult = new RuleResult(); - _typeSpecCache.Add(typeDef, ruleResult); - } - return ruleResult; - } - - private RuleResult GetOrCreateFieldRuleResult(FieldDef field) - { - if (!_fieldSpecCache.TryGetValue(field, out var ruleResult)) - { - ruleResult = new RuleResult(); - _fieldSpecCache.Add(field, ruleResult); - } - return ruleResult; - } - - private RuleResult GetOrCreateMethodRuleResult(MethodDef method) - { - if (!_methodSpecCache.TryGetValue(method, out var ruleResult)) - { - ruleResult = new RuleResult(); - _methodSpecCache.Add(method, ruleResult); - } - return ruleResult; - } - - private RuleResult GetOrCreatePropertyRuleResult(PropertyDef property) - { - if (!_propertySpecCache.TryGetValue(property, out var ruleResult)) - { - ruleResult = new RuleResult(); - _propertySpecCache.Add(property, ruleResult); - } - return ruleResult; - } - - private RuleResult GetOrCreateEventRuleResult(EventDef eventDef) - { - if (!_eventSpecCache.TryGetValue(eventDef, out var ruleResult)) - { - ruleResult = new RuleResult(); - _eventSpecCache.Add(eventDef, ruleResult); - } - return ruleResult; - } - - private void BuildTypeRuleResult(TypeRuleSpec typeSpec, TypeDef typeDef, RuleResult typeRuleResult) - { - string typeName = typeDef.FullName; - - if (typeSpec.obfuscateName != null) - { - typeRuleResult.obfuscateName = typeSpec.obfuscateName; - } - - foreach (var fieldDef in typeDef.Fields) - { - RuleResult fieldRuleResult = GetOrCreateFieldRuleResult(fieldDef); - if (typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.Field) != 0 && typeSpec.obfuscateName != null) - { - fieldRuleResult.obfuscateName = typeSpec.obfuscateName; - } - foreach (var fieldSpec in typeSpec.fields) - { - if (fieldSpec.nameMatcher.IsMatch(fieldDef.Name) && MatchModifier(fieldSpec.modifierType, fieldDef)) - { - if (fieldSpec.obfuscateName != null) - { - fieldRuleResult.obfuscateName = fieldSpec.obfuscateName; - } - } - } - } - - foreach (MethodDef methodDef in typeDef.Methods) - { - RuleResult methodRuleResult = GetOrCreateMethodRuleResult(methodDef); - if (typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.Method) != 0 && typeSpec.obfuscateName != null) - { - methodRuleResult.obfuscateName = typeSpec.obfuscateName; - } - } - - foreach (var eventDef in typeDef.Events) - { - RuleResult eventRuleResult = GetOrCreateEventRuleResult(eventDef); - if (typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.EventName) != 0 && typeSpec.obfuscateName != null) - { - eventRuleResult.obfuscateName = typeSpec.obfuscateName; - } - foreach (var eventSpec in typeSpec.events) - { - if (!eventSpec.nameMatcher.IsMatch(eventDef.Name) || !MatchModifier(eventSpec.modifierType, eventDef)) - { - continue; - } - if (typeSpec.obfuscateName != null && typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.EventAddRemoveFireName) != 0) - { - if (eventDef.AddMethod != null) - { - GetOrCreateMethodRuleResult(eventDef.AddMethod).obfuscateName = typeSpec.obfuscateName; - } - if (eventDef.RemoveMethod != null) - { - GetOrCreateMethodRuleResult(eventDef.RemoveMethod).obfuscateName = typeSpec.obfuscateName; - } - if (eventDef.InvokeMethod != null) - { - GetOrCreateMethodRuleResult(eventDef.InvokeMethod).obfuscateName = typeSpec.obfuscateName; - } - } - if (eventSpec.obfuscateName != null) - { - eventRuleResult.obfuscateName = eventSpec.obfuscateName; - if (eventSpec.applyToMembers != null && (eventSpec.applyToMembers & ObfuzScope.EventAddRemoveFireName) != 0) - { - if (eventDef.AddMethod != null) - { - GetOrCreateMethodRuleResult(eventDef.AddMethod).obfuscateName = eventSpec.obfuscateName; - } - if (eventDef.RemoveMethod != null) - { - GetOrCreateMethodRuleResult(eventDef.RemoveMethod).obfuscateName = eventSpec.obfuscateName; - } - if (eventDef.InvokeMethod != null) - { - GetOrCreateMethodRuleResult(eventDef.InvokeMethod).obfuscateName = eventSpec.obfuscateName; - } - } - } - } - } - - foreach (var propertyDef in typeDef.Properties) - { - RuleResult propertyRuleResult = GetOrCreatePropertyRuleResult(propertyDef); - if (typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.PropertyName) != 0 && typeSpec.obfuscateName != null) - { - propertyRuleResult.obfuscateName = typeSpec.obfuscateName; - } - foreach (var propertySpec in typeSpec.properties) - { - if (!propertySpec.nameMatcher.IsMatch(propertyDef.Name) || !MatchModifier(propertySpec.modifierType, propertyDef)) - { - continue; - } - if (typeSpec.obfuscateName != null && typeSpec.applyToMembers != null && (typeSpec.applyToMembers & ObfuzScope.PropertyGetterSetterName) != 0) - { - if (propertyDef.GetMethod != null) - { - GetOrCreateMethodRuleResult(propertyDef.GetMethod).obfuscateName = typeSpec.obfuscateName; - } - if (propertyDef.SetMethod != null) - { - GetOrCreateMethodRuleResult(propertyDef.SetMethod).obfuscateName = typeSpec.obfuscateName; - } - } - if (propertySpec.obfuscateName != null) - { - propertyRuleResult.obfuscateName = propertySpec.obfuscateName; - if (propertySpec.applyToMembers != null && (propertySpec.applyToMembers & ObfuzScope.PropertyGetterSetterName) != 0) - { - if (propertyDef.GetMethod != null) - { - GetOrCreateMethodRuleResult(propertyDef.GetMethod).obfuscateName = propertySpec.obfuscateName; - } - if (propertyDef.SetMethod != null) - { - GetOrCreateMethodRuleResult(propertyDef.SetMethod).obfuscateName = propertySpec.obfuscateName; - } - } - } - } - } - foreach (MethodDef methodDef in typeDef.Methods) - { - RuleResult methodRuleResult = GetOrCreateMethodRuleResult(methodDef); - foreach (MethodRuleSpec methodSpec in typeSpec.methods) - { - if (!methodSpec.nameMatcher.IsMatch(methodDef.Name) || !MatchModifier(methodSpec.modifierType, methodDef)) - { - continue; - } - if (methodSpec.obfuscateName != null) - { - methodRuleResult.obfuscateName = methodSpec.obfuscateName; - } - } - } - - if (typeSpec.applyToNestedTypes) - { - foreach (TypeDef nestedType in typeDef.NestedTypes) - { - var nestedRuleResult = GetOrCreateTypeRuleResult(nestedType); - BuildTypeRuleResult(typeSpec, nestedType, nestedRuleResult); - } - } - } - - private bool MatchInheritTypes(List inheritTypes, TypeDef typeDef) - { - if (inheritTypes == null || inheritTypes.Count == 0) - { - return true; - } - TypeDef currentType = typeDef; - while (currentType != null) - { - if (inheritTypes.Contains(currentType.FullName)) - { - return true; - } - foreach (var interfaceType in currentType.Interfaces) - { - if (inheritTypes.Contains(interfaceType.Interface.FullName)) - { - return true; - } - } - currentType = MetaUtil.GetBaseTypeDef(currentType); - } - return false; - } - - private bool MatchCustomAttributes(List customAttributes, TypeDef typeDef) - { - if (customAttributes == null || customAttributes.Count == 0) - { - return true; - } - foreach (string customAttributeName in customAttributes) - { - if (typeDef.CustomAttributes.Find(customAttributeName) != null) - { - return true; - } - } - return false; - } - - private IEnumerable GetMatchTypes(ModuleDef mod, List types, TypeRuleSpec typeSpec) - { - if (typeSpec.nameMatcher.IsWildcardPattern) - { - foreach (var typeDef in types) - { - if (!typeSpec.nameMatcher.IsMatch(typeDef.FullName) - || !MatchModifier(typeSpec.modifierType, typeDef) - || !MatchClassType(typeSpec.classType, typeDef) - || !MatchInheritTypes(typeSpec.inheritTypes, typeDef) - || !MatchCustomAttributes(typeSpec.hasCustomAttributes, typeDef)) - { - continue; - } - yield return typeDef; - } - } - else - { - TypeDef typeDef = mod.FindNormal(typeSpec.nameMatcher.NameOrPattern); - if (typeDef != null - && MatchModifier(typeSpec.modifierType, typeDef) - && MatchClassType(typeSpec.classType, typeDef) - && MatchInheritTypes(typeSpec.inheritTypes, typeDef) - && MatchCustomAttributes(typeSpec.hasCustomAttributes, typeDef)) - { - yield return typeDef; - } - } - } - - private void BuildRuleResultCaches() - { - foreach (AssemblyRuleSpec assSpec in _assemblyRuleSpecs.Values.SelectMany(arr => arr)) - { - ModuleDef module = _assembliesToObfuscate.FirstOrDefault(m => m.Assembly.Name == assSpec.assemblyName); - if (module == null) - { - continue; - } - List types = module.GetTypes().ToList(); - foreach (TypeRuleSpec typeSpec in assSpec.types) - { - foreach (var typeDef in GetMatchTypes(module, types, typeSpec)) - { - var ruleResult = GetOrCreateTypeRuleResult(typeDef); - if (typeSpec.obfuscateName != null) - { - ruleResult.obfuscateName = typeSpec.obfuscateName; - } - BuildTypeRuleResult(typeSpec, typeDef, ruleResult); - } - } - } - } - - public override bool NeedRename(TypeDef typeDef) - { - return GetOrCreateTypeRuleResult(typeDef).obfuscateName != false; - } - - public override bool NeedRename(MethodDef methodDef) - { - return GetOrCreateMethodRuleResult(methodDef).obfuscateName != false; - } - - public override bool NeedRename(FieldDef fieldDef) - { - return GetOrCreateFieldRuleResult(fieldDef).obfuscateName != false; - } - - public override bool NeedRename(PropertyDef propertyDef) - { - return GetOrCreatePropertyRuleResult(propertyDef).obfuscateName != false; - } - - public override bool NeedRename(EventDef eventDef) - { - return GetOrCreateEventRuleResult(eventDef).obfuscateName != false; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ConfigurableRenamePolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ConfigurableRenamePolicy.cs.meta deleted file mode 100644 index e6b4feea..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ConfigurableRenamePolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9c063bc949939fe44972c3d99870527e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ObfuscationPolicyBase.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ObfuscationPolicyBase.cs deleted file mode 100644 index 6a271ad0..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ObfuscationPolicyBase.cs +++ /dev/null @@ -1,33 +0,0 @@ -using dnlib.DotNet; - -namespace Obfuz.ObfusPasses.SymbolObfus.Policies -{ - public abstract class ObfuscationPolicyBase : IObfuscationPolicy - { - - public virtual bool NeedRename(TypeDef typeDef) - { - return true; - } - - public virtual bool NeedRename(MethodDef methodDef) - { - return true; - } - - public virtual bool NeedRename(FieldDef fieldDef) - { - return true; - } - - public virtual bool NeedRename(PropertyDef propertyDef) - { - return true; - } - - public virtual bool NeedRename(EventDef eventDef) - { - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ObfuscationPolicyBase.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ObfuscationPolicyBase.cs.meta deleted file mode 100644 index 2d0bf054..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/ObfuscationPolicyBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6ab98107a2ef9624b9b8a53061f682c3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SupportPassPolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SupportPassPolicy.cs deleted file mode 100644 index 132ed15a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SupportPassPolicy.cs +++ /dev/null @@ -1,45 +0,0 @@ -using dnlib.DotNet; - -namespace Obfuz.ObfusPasses.SymbolObfus.Policies -{ - internal class SupportPassPolicy : ObfuscationPolicyBase - { - private readonly ConfigurablePassPolicy _policy; - - - private bool Support(ObfuscationPassType passType) - { - return passType.HasFlag(ObfuscationPassType.SymbolObfus); - } - - public SupportPassPolicy(ConfigurablePassPolicy policy) - { - _policy = policy; - } - - public override bool NeedRename(TypeDef typeDef) - { - return Support(_policy.GetTypeObfuscationPasses(typeDef)); - } - - public override bool NeedRename(MethodDef methodDef) - { - return Support(_policy.GetMethodObfuscationPasses(methodDef)); - } - - public override bool NeedRename(FieldDef fieldDef) - { - return Support(_policy.GetFieldObfuscationPasses(fieldDef)); - } - - public override bool NeedRename(PropertyDef propertyDef) - { - return Support(_policy.GetPropertyObfuscationPasses(propertyDef)); - } - - public override bool NeedRename(EventDef eventDef) - { - return Support(_policy.GetEventObfuscationPasses(eventDef)); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SupportPassPolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SupportPassPolicy.cs.meta deleted file mode 100644 index bf7d3b8d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SupportPassPolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 584dd4d4e9b9fa64090611d84b50980b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SystemRenamePolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SystemRenamePolicy.cs deleted file mode 100644 index 68d4ea2f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SystemRenamePolicy.cs +++ /dev/null @@ -1,120 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Editor; -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.SymbolObfus.Policies -{ - public class SystemRenamePolicy : ObfuscationPolicyBase - { - private readonly ObfuzIgnoreScopeComputeCache _obfuzIgnoreScopeComputeCache; - - public SystemRenamePolicy(ObfuzIgnoreScopeComputeCache obfuzIgnoreScopeComputeCache) - { - _obfuzIgnoreScopeComputeCache = obfuzIgnoreScopeComputeCache; - } - - private readonly HashSet _fullIgnoreTypeFullNames = new HashSet - { - ConstValues.ObfuzIgnoreAttributeFullName, - ConstValues.ObfuzScopeFullName, - ConstValues.EncryptFieldAttributeFullName, - ConstValues.EmbeddedAttributeFullName, - ConstValues.ZluaLuaInvokeAttributeFullName, - ConstValues.ZluaLuaCallbackAttributeFullName, - ConstValues.ZluaLuaMarshalAsAttributeFullName, - ConstValues.BurstCompileFullName, - }; - - - private readonly HashSet _fullIgnoreTypeNames = new HashSet - { - ConstValues.MonoPInvokeCallbackAttributeName, - }; - - private bool IsFullIgnoreObfuscatedType(TypeDef typeDef) - { - return _fullIgnoreTypeFullNames.Contains(typeDef.FullName) || _fullIgnoreTypeNames.Contains(typeDef.Name) || MetaUtil.HasMicrosoftCodeAnalysisEmbeddedAttribute(typeDef); - } - - public override bool NeedRename(TypeDef typeDef) - { - string name = typeDef.Name; - if (name == "") - { - return false; - } - if (IsFullIgnoreObfuscatedType(typeDef)) - { - return false; - } - - if (_obfuzIgnoreScopeComputeCache.HasSelfOrEnclosingOrInheritObfuzIgnoreScope(typeDef, ObfuzScope.TypeName)) - { - return false; - } - return true; - } - - public override bool NeedRename(MethodDef methodDef) - { - if (methodDef.DeclaringType.IsDelegate || IsFullIgnoreObfuscatedType(methodDef.DeclaringType)) - { - return false; - } - if (methodDef.Name == ".ctor" || methodDef.Name == ".cctor") - { - return false; - } - - if (_obfuzIgnoreScopeComputeCache.HasSelfOrInheritPropertyOrEventOrOrTypeDefIgnoreMethodName(methodDef)) - { - return false; - } - return true; - } - - public override bool NeedRename(FieldDef fieldDef) - { - if (fieldDef.DeclaringType.IsDelegate || IsFullIgnoreObfuscatedType(fieldDef.DeclaringType)) - { - return false; - } - if (_obfuzIgnoreScopeComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(fieldDef, fieldDef.DeclaringType, ObfuzScope.Field)) - { - return false; - } - if (fieldDef.DeclaringType.IsEnum && !fieldDef.IsStatic) - { - return false; - } - return true; - } - - public override bool NeedRename(PropertyDef propertyDef) - { - if (propertyDef.DeclaringType.IsDelegate || IsFullIgnoreObfuscatedType(propertyDef.DeclaringType)) - { - return false; - } - if (_obfuzIgnoreScopeComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(propertyDef, propertyDef.DeclaringType, ObfuzScope.PropertyName)) - { - return false; - } - return true; - } - - public override bool NeedRename(EventDef eventDef) - { - if (eventDef.DeclaringType.IsDelegate || IsFullIgnoreObfuscatedType(eventDef.DeclaringType)) - { - return false; - } - if (_obfuzIgnoreScopeComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(eventDef, eventDef.DeclaringType, ObfuzScope.EventName)) - { - return false; - } - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SystemRenamePolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SystemRenamePolicy.cs.meta deleted file mode 100644 index b7d45e3e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/SystemRenamePolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7b7b98f2ff075c04aa9bd989f8797f00 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/UnityRenamePolicy.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/UnityRenamePolicy.cs deleted file mode 100644 index 594c5a1c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/UnityRenamePolicy.cs +++ /dev/null @@ -1,264 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Utils; -using System.Collections.Generic; -using System.Linq; - -namespace Obfuz.ObfusPasses.SymbolObfus.Policies -{ - - public class UnityRenamePolicy : ObfuscationPolicyBase - { - private static HashSet s_monoBehaviourEvents = new HashSet { - - // MonoBehaviour events - "Awake", - "FixedUpdate", - "LateUpdate", - "OnAnimatorIK", - - "OnAnimatorMove", - "OnApplicationFocus", - "OnApplicationPause", - "OnApplicationQuit", - "OnAudioFilterRead", - - "OnBecameVisible", - "OnBecameInvisible", - - "OnCollisionEnter", - "OnCollisionEnter2D", - "OnCollisionExit", - "OnCollisionExit2D", - "OnCollisionStay", - "OnCollisionStay2D", - "OnConnectedToServer", - "OnControllerColliderHit", - - "OnDrawGizmos", - "OnDrawGizmosSelected", - "OnDestroy", - "OnDisable", - "OnDisconnectedFromServer", - - "OnEnable", - - "OnFailedToConnect", - "OnFailedToConnectToMasterServer", - - "OnGUI", - - "OnJointBreak", - "OnJointBreak2D", - - "OnMasterServerEvent", - "OnMouseDown", - "OnMouseDrag", - "OnMouseEnter", - "OnMouseExit", - "OnMouseOver", - "OnMouseUp", - "OnMouseUpAsButton", - - "OnNetworkInstantiate", - - "OnParticleSystemStopped", - "OnParticleTrigger", - "OnParticleUpdateJobScheduled", - "OnPlayerConnected", - "OnPlayerDisconnected", - "OnPostRender", - "OnPreCull", - "OnPreRender", - "OnRenderImage", - "OnRenderObject", - - "OnSerializeNetworkView", - "OnServerInitialized", - - "OnTransformChildrenChanged", - "OnTransformParentChanged", - "OnTriggerEnter", - "OnTriggerEnter2D", - "OnTriggerExit", - "OnTriggerExit2D", - "OnTriggerStay", - "OnTriggerStay2D", - - "OnValidate", - "OnWillRenderObject", - "Reset", - "Start", - "Update", - - // Animator/StateMachineBehaviour - "OnStateEnter", - "OnStateExit", - "OnStateMove", - "OnStateUpdate", - "OnStateIK", - "OnStateMachineEnter", - "OnStateMachineExit", - - // ParticleSystem - "OnParticleTrigger", - "OnParticleCollision", - "OnParticleSystemStopped", - - // UGUI/EventSystems - "OnPointerClick", - "OnPointerDown", - "OnPointerUp", - "OnPointerEnter", - "OnPointerExit", - "OnDrag", - "OnBeginDrag", - "OnEndDrag", - "OnDrop", - "OnScroll", - "OnSelect", - "OnDeselect", - "OnMove", - "OnSubmit", - "OnCancel", -}; - - private readonly CachedDictionary _computeDeclaringTypeDisableAllMemberRenamingCache; - private readonly CachedDictionary _isSerializableCache; - private readonly CachedDictionary _isInheritFromMonoBehaviourCache; - private readonly CachedDictionary _isScriptOrSerializableTypeCache; - - public UnityRenamePolicy() - { - _computeDeclaringTypeDisableAllMemberRenamingCache = new CachedDictionary(ComputeDeclaringTypeDisableAllMemberRenaming); - _isSerializableCache = new CachedDictionary(MetaUtil.IsSerializableType); - _isInheritFromMonoBehaviourCache = new CachedDictionary(MetaUtil.IsInheritFromMonoBehaviour); - _isScriptOrSerializableTypeCache = new CachedDictionary(MetaUtil.IsScriptOrSerializableType); - } - - private bool IsUnitySourceGeneratedAssemblyType(TypeDef typeDef) - { - if (typeDef.Name.StartsWith("UnitySourceGeneratedAssemblyMonoScriptTypes_")) - { - return true; - } - if (typeDef.FullName == "Unity.Entities.CodeGeneratedRegistry.AssemblyTypeRegistry") - { - return true; - } - if (typeDef.Name.StartsWith("__JobReflectionRegistrationOutput")) - { - return true; - } - if (MetaUtil.HasDOTSCompilerGeneratedAttribute(typeDef)) - { - return true; - } - if (typeDef.DeclaringType != null) - { - return IsUnitySourceGeneratedAssemblyType(typeDef.DeclaringType); - } - return false; - } - - private bool ComputeDeclaringTypeDisableAllMemberRenaming(TypeDef typeDef) - { - if (typeDef.IsEnum && MetaUtil.HasBlackboardEnumAttribute(typeDef)) - { - return true; - } - if (IsUnitySourceGeneratedAssemblyType(typeDef)) - { - return true; - } - if (MetaUtil.IsInheritFromDOTSTypes(typeDef)) - { - return true; - } - return false; - } - - public override bool NeedRename(TypeDef typeDef) - { - if (_isScriptOrSerializableTypeCache.GetValue(typeDef)) - { - return false; - } - if (_computeDeclaringTypeDisableAllMemberRenamingCache.GetValue(typeDef)) - { - return false; - } - if (MetaUtil.HasBurstCompileAttribute(typeDef)) - { - return false; - } - if (typeDef.Methods.Any(m => MetaUtil.HasRuntimeInitializeOnLoadMethodAttribute(m))) - { - return false; - } - return true; - } - - public override bool NeedRename(MethodDef methodDef) - { - TypeDef typeDef = methodDef.DeclaringType; - if (s_monoBehaviourEvents.Contains(methodDef.Name) && _isInheritFromMonoBehaviourCache.GetValue(typeDef)) - { - return false; - } - if (_computeDeclaringTypeDisableAllMemberRenamingCache.GetValue(typeDef)) - { - return false; - } - if (MetaUtil.HasRuntimeInitializeOnLoadMethodAttribute(methodDef)) - { - return false; - } - if (MetaUtil.HasBurstCompileAttribute(methodDef) || MetaUtil.HasBurstCompileAttribute(methodDef.DeclaringType) || MetaUtil.HasDOTSCompilerGeneratedAttribute(methodDef)) - { - return false; - } - return true; - } - - public override bool NeedRename(FieldDef fieldDef) - { - TypeDef typeDef = fieldDef.DeclaringType; - if (_isScriptOrSerializableTypeCache.GetValue(typeDef)) - { - if (typeDef.IsEnum) - { - return false; - } - if (fieldDef.IsPublic && !fieldDef.IsStatic) - { - return false; - } - if (!fieldDef.IsStatic && MetaUtil.IsSerializableField(fieldDef)) - { - return false; - } - } - if (_computeDeclaringTypeDisableAllMemberRenamingCache.GetValue(typeDef)) - { - return false; - } - return true; - } - - public override bool NeedRename(PropertyDef propertyDef) - { - TypeDef typeDef = propertyDef.DeclaringType; - if (_isSerializableCache.GetValue(typeDef)) - { - bool isGetterPublic = propertyDef.GetMethod != null && propertyDef.GetMethod.IsPublic && !propertyDef.GetMethod.IsStatic; - bool isSetterPublic = propertyDef.SetMethod != null && propertyDef.SetMethod.IsPublic && !propertyDef.SetMethod.IsStatic; - - if (isGetterPublic || isSetterPublic) - { - return false; - } - } - return true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/UnityRenamePolicy.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/UnityRenamePolicy.cs.meta deleted file mode 100644 index f8f6f99a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/Policies/UnityRenamePolicy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4357f35c667599246b2481b093f41f04 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/ReflectionCompatibilityDetector.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/ReflectionCompatibilityDetector.cs deleted file mode 100644 index 8d644bbe..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/ReflectionCompatibilityDetector.cs +++ /dev/null @@ -1,306 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace Obfuz.ObfusPasses.SymbolObfus -{ - public class ReflectionCompatibilityDetector - { - private readonly HashSet _assembliesToObfuscate; - private readonly List _obfuscatedAndNotObfuscatedModules; - private readonly IObfuscationPolicy _renamePolicy; - - public ReflectionCompatibilityDetector(List assembliesToObfuscate, List obfuscatedAndNotObfuscatedModules, IObfuscationPolicy renamePolicy) - { - _assembliesToObfuscate = new HashSet(assembliesToObfuscate); - _obfuscatedAndNotObfuscatedModules = obfuscatedAndNotObfuscatedModules; - _renamePolicy = renamePolicy; - } - - public void Analyze() - { - foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules) - { - foreach (TypeDef type in mod.GetTypes()) - { - foreach (MethodDef method in type.Methods) - { - AnalyzeMethod(method); - } - } - } - } - - private MethodDef _curCallingMethod; - private IList _curInstructions; - private int _curInstIndex; - - private void AnalyzeMethod(MethodDef method) - { - if (!method.HasBody) - { - return; - } - _curCallingMethod = method; - _curInstructions = method.Body.Instructions; - _curInstIndex = 0; - for (int n = _curInstructions.Count; _curInstIndex < n; _curInstIndex++) - { - var inst = _curInstructions[_curInstIndex]; - switch (inst.OpCode.Code) - { - case Code.Call: - { - AnalyzeCall(inst.Operand as IMethod); - break; - } - case Code.Callvirt: - { - ITypeDefOrRef constrainedType = null; - if (_curInstIndex > 0) - { - var prevInst = _curInstructions[_curInstIndex - 1]; - if (prevInst.OpCode.Code == Code.Constrained) - { - constrainedType = prevInst.Operand as ITypeDefOrRef; - } - } - AnalyzeCallvir(inst.Operand as IMethod, constrainedType); - break; - } - } - } - } - - private ITypeDefOrRef FindLatestTypeOf(int backwardFindInstructionCount) - { - // find sequence ldtoken ; - for (int i = 2; i <= backwardFindInstructionCount; i++) - { - int index = _curInstIndex - i; - if (index < 0) - { - return null; - } - Instruction inst1 = _curInstructions[index]; - Instruction inst2 = _curInstructions[index + 1]; - if (inst1.OpCode.Code == Code.Ldtoken && inst2.OpCode.Code == Code.Call) - { - if (!(inst1.Operand is ITypeDefOrRef typeDefOrRef)) - { - continue; - } - IMethod method = inst2.Operand as IMethod; - if (method.Name == "GetTypeFromHandle" && method.DeclaringType.FullName == "System.Type") - { - // Ldtoken ; Call System.Type.GetTypeFromHandle(System.RuntimeTypeHandle handle) - return typeDefOrRef; - } - } - } - return null; - } - - private void AnalyzeCall(IMethod calledMethod) - { - TypeDef callType = calledMethod.DeclaringType.ResolveTypeDef(); - if (callType == null) - { - return; - } - switch (callType.FullName) - { - case "System.Enum": - { - AnalyzeEnum(calledMethod, callType); - break; - } - case "System.Type": - { - AnalyzeGetType(calledMethod, callType); - break; - } - case "System.Reflection.Assembly": - { - if (calledMethod.Name == "GetType") - { - AnalyzeGetType(calledMethod, callType); - } - break; - } - } - } - - - private bool IsAnyEnumItemRenamed(TypeDef typeDef) - { - return _assembliesToObfuscate.Contains(typeDef.Module) && typeDef.Fields.Any(f => _renamePolicy.NeedRename(f)); - } - - private void AnalyzeCallvir(IMethod calledMethod, ITypeDefOrRef constrainedType) - { - TypeDef callType = calledMethod.DeclaringType.ResolveTypeDef(); - if (callType == null) - { - return; - } - string calledMethodName = calledMethod.Name; - switch (callType.FullName) - { - case "System.Object": - { - if (calledMethodName == "ToString") - { - if (constrainedType != null) - { - TypeDef enumTypeDef = constrainedType.ResolveTypeDef(); - if (enumTypeDef != null && enumTypeDef.IsEnum && IsAnyEnumItemRenamed(enumTypeDef)) - { - Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: {enumTypeDef.FullName}.ToString() the enum members are renamed."); - } - } - } - break; - } - case "System.Type": - { - AnalyzeGetType(calledMethod, callType); - break; - } - } - } - - private TypeSig GetMethodGenericParameter(IMethod method) - { - if (method is MethodSpec ms) - { - return ms.GenericInstMethodSig.GenericArguments.FirstOrDefault(); - } - else - { - return null; - } - } - - private void AnalyzeEnum(IMethod method, TypeDef typeDef) - { - const int extraSearchInstructionCount = 3; - TypeSig parseTypeSig = GetMethodGenericParameter(method); - TypeDef parseType = parseTypeSig?.ToTypeDefOrRef().ResolveTypeDef(); - switch (method.Name) - { - case "Parse": - { - if (parseTypeSig != null) - { - // Enum.Parse(string name) or Enum.Parse(string name, bool caseInsensitive) - if (parseType != null) - { - if (IsAnyEnumItemRenamed(parseType)) - { - Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.Parse field of T:{parseType.FullName} is renamed."); - } - } - else - { - Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.Parse field of T should not be renamed."); - } - } - else - { - // Enum.Parse(Type type, string name) or Enum.Parse(Type type, string name, bool ignoreCase) - TypeDef enumType = FindLatestTypeOf(method.GetParamCount() + extraSearchInstructionCount)?.ResolveTypeDef(); - if (enumType != null && enumType.IsEnum && IsAnyEnumItemRenamed(enumType)) - { - Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.Parse field of argument type:{enumType.FullName} is renamed."); - } - else - { - Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.Parse field of argument `type` should not be renamed."); - } - } - break; - } - case "TryParse": - { - if (parseTypeSig != null) - { - // Enum.TryParse(string name, out T result) or Enum.TryParse(string name, bool ignoreCase, out T result) - if (parseType != null) - { - if (IsAnyEnumItemRenamed(parseType)) - { - Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.TryParse field of T:{parseType.FullName} is renamed."); - } - } - else - { - Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.TryParse field of T should not be renamed."); - } - } - else - { - throw new Exception("impossible"); - } - break; - } - case "GetName": - { - // Enum.GetName(Type type, object value) - TypeDef enumType = FindLatestTypeOf(method.GetParamCount() + extraSearchInstructionCount)?.ResolveTypeDef(); - if (enumType != null && enumType.IsEnum && IsAnyEnumItemRenamed(enumType)) - { - Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.GetName field of type:{enumType.FullName} is renamed."); - } - else - { - Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.GetName field of argument `type` should not be renamed."); - } - break; - } - case "GetNames": - { - // Enum.GetNames(Type type) - TypeDef enumType = FindLatestTypeOf(method.GetParamCount() + extraSearchInstructionCount)?.ResolveTypeDef(); - if (enumType != null && enumType.IsEnum && IsAnyEnumItemRenamed(enumType)) - { - Debug.LogError($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.GetNames field of type:{enumType.FullName} is renamed."); - } - else - { - Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Enum.GetNames field of argument `type` should not be renamed."); - } - break; - } - } - } - - private void AnalyzeGetType(IMethod method, TypeDef declaringType) - { - switch (method.Name) - { - case "GetType": - { - Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: Type.GetType argument `typeName` should not be renamed."); - break; - } - case "GetField": - case "GetFields": - case "GetMethod": - case "GetMethods": - case "GetProperty": - case "GetProperties": - case "GetEvent": - case "GetEvents": - case "GetMembers": - { - Debug.LogWarning($"[ReflectionCompatibilityDetector] Reflection compatibility issue in {_curCallingMethod}: called method:{method} the members of type should not be renamed."); - break; - } - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/ReflectionCompatibilityDetector.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/ReflectionCompatibilityDetector.cs.meta deleted file mode 100644 index f5212e11..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/ReflectionCompatibilityDetector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b98c97a4d1db5d945bce0fdd2bd09202 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/RenameRecordMap.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/RenameRecordMap.cs deleted file mode 100644 index 65486951..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/RenameRecordMap.cs +++ /dev/null @@ -1,742 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Xml; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Obfuz.ObfusPasses.SymbolObfus -{ - - public class RenameRecordMap - { - private enum RenameStatus - { - NotRenamed, - Renamed, - } - - private class RenameRecord - { - public RenameStatus status; - public string signature; - public string oldName; - public string newName; - public string oldStackTraceSignature; // only for MethodDef - public object renameMappingData; - } - - private class RenameMappingField - { - public RenameStatus status; - public string signature; - public string newName; - } - - private class RenameMappingMethod - { - public RenameStatus status; - public string signature; - public string newName; - public string oldStackTraceSignature; - public string newStackTraceSignature; - } - - private class RenameMappingMethodParam - { - public RenameStatus status; - public int index; - public string newName; - } - - private class RenameMappingProperty - { - public RenameStatus status; - public string signature; - public string newName; - } - - private class RenameMappingEvent - { - public RenameStatus status; - public string signature; - public string newName; - } - - private class RenameMappingType - { - public RenameStatus status; - public string oldFullName; - public string newFullName; - - public Dictionary fields = new Dictionary(); - public Dictionary methods = new Dictionary(); - public Dictionary properties = new Dictionary(); - public Dictionary events = new Dictionary(); - } - - private class RenameMappingAssembly - { - public string assName; - - public Dictionary types = new Dictionary(); - } - - private readonly string _mappingFile; - private readonly bool _debug; - private readonly bool _keepUnknownSymbolInSymbolMappingFile; - private readonly Dictionary _assemblies = new Dictionary(); - - - private readonly Dictionary _modRenames = new Dictionary(); - private readonly Dictionary _typeRenames = new Dictionary(); - private readonly Dictionary _methodRenames = new Dictionary(); - private readonly Dictionary _fieldRenames = new Dictionary(); - private readonly Dictionary _propertyRenames = new Dictionary(); - private readonly Dictionary _eventRenames = new Dictionary(); - private readonly Dictionary _virtualMethodGroups = new Dictionary(); - - - public RenameRecordMap(string mappingFile, bool debug, bool keepUnknownSymbolInSymbolMappingFile) - { - _mappingFile = mappingFile; - _debug = debug; - _keepUnknownSymbolInSymbolMappingFile = keepUnknownSymbolInSymbolMappingFile; - } - - public void Init(List assemblies, INameMaker nameMaker) - { - LoadXmlMappingFile(_mappingFile); - foreach (ModuleDef mod in assemblies) - { - string name = mod.Assembly.Name; - - RenameMappingAssembly rma = _assemblies.GetValueOrDefault(name); - - _modRenames.Add(mod, new RenameRecord - { - status = RenameStatus.NotRenamed, - signature = name, - oldName = name, - newName = null, - renameMappingData = rma, - }); - - foreach (TypeDef type in mod.GetTypes()) - { - nameMaker.AddPreservedName(type, name); - nameMaker.AddPreservedNamespace(type, type.Namespace); - string fullTypeName = type.FullName; - RenameMappingType rmt = rma?.types.GetValueOrDefault(fullTypeName); - if (rmt != null && rmt.status == RenameStatus.Renamed) - { - var (newNamespace, newName) = MetaUtil.SplitNamespaceAndName(rmt.newFullName); - nameMaker.AddPreservedNamespace(type, newNamespace); - nameMaker.AddPreservedName(type, newName); - } - - _typeRenames.Add(type, new RenameRecord - { - status = RenameStatus.NotRenamed, - signature = fullTypeName, - oldName = fullTypeName, - newName = null, - renameMappingData = rmt, - }); - foreach (MethodDef method in type.Methods) - { - nameMaker.AddPreservedName(method, method.Name); - string methodSig = TypeSigUtil.ComputeMethodDefSignature(method); - - RenameMappingMethod rmm = rmt?.methods.GetValueOrDefault(methodSig); - if (rmm != null && rmm.status == RenameStatus.Renamed) - { - nameMaker.AddPreservedName(method, rmm.newName); - } - _methodRenames.Add(method, new RenameRecord - { - status = RenameStatus.NotRenamed, - signature = methodSig, - oldName = method.Name, - newName = null, - renameMappingData = rmm, - oldStackTraceSignature = MetaUtil.CreateMethodDefIl2CppStackTraceSignature(method), - }); - } - foreach (FieldDef field in type.Fields) - { - nameMaker.AddPreservedName(field, field.Name); - string fieldSig = TypeSigUtil.ComputeFieldDefSignature(field); - RenameMappingField rmf = rmt?.fields.GetValueOrDefault(fieldSig); - if (rmf != null && rmf.status == RenameStatus.Renamed) - { - nameMaker.AddPreservedName(field, rmf.newName); - } - _fieldRenames.Add(field, new RenameRecord - { - status = RenameStatus.NotRenamed, - signature = fieldSig, - oldName = field.Name, - newName = null, - renameMappingData = rmf, - }); - } - foreach (PropertyDef property in type.Properties) - { - nameMaker.AddPreservedName(property, property.Name); - string propertySig = TypeSigUtil.ComputePropertyDefSignature(property); - RenameMappingProperty rmp = rmt?.properties.GetValueOrDefault(propertySig); - if (rmp != null && rmp.status == RenameStatus.Renamed) - { - nameMaker.AddPreservedName(property, rmp.newName); - } - _propertyRenames.Add(property, new RenameRecord - { - status = RenameStatus.NotRenamed, - signature = propertySig, - oldName = property.Name, - newName = null, - renameMappingData = rmp, - }); - } - foreach (EventDef eventDef in type.Events) - { - nameMaker.AddPreservedName(eventDef, eventDef.Name); - string eventSig = TypeSigUtil.ComputeEventDefSignature(eventDef); - RenameMappingEvent rme = rmt?.events.GetValueOrDefault(eventSig); - if (rme != null && rme.status == RenameStatus.Renamed) - { - nameMaker.AddPreservedName(eventDef, rme.newName); - } - _eventRenames.Add(eventDef, new RenameRecord - { - status = RenameStatus.NotRenamed, - signature = eventSig, - oldName = eventDef.Name, - newName = null, - renameMappingData = rme, - }); - } - } - } - } - - private void LoadXmlMappingFile(string mappingFile) - { - if (string.IsNullOrEmpty(mappingFile) || !File.Exists(mappingFile)) - { - return; - } - if (_debug) - { - Debug.Log($"skip loading debug mapping file: {Path.GetFullPath(mappingFile)}"); - return; - } - var doc = new XmlDocument(); - doc.Load(mappingFile); - var root = doc.DocumentElement; - foreach (XmlNode node in root.ChildNodes) - { - if (!(node is XmlElement element)) - { - continue; - } - LoadAssemblyMapping(element); - } - } - - private void LoadAssemblyMapping(XmlElement ele) - { - if (ele.Name != "assembly") - { - throw new System.Exception($"Invalid node name: {ele.Name}. Expected 'assembly'."); - } - - var assemblyName = ele.Attributes["name"].Value; - var rma = new RenameMappingAssembly - { - assName = assemblyName, - }; - foreach (XmlNode node in ele.ChildNodes) - { - if (!(node is XmlElement element)) - { - continue; - } - if (element.Name != "type") - { - throw new System.Exception($"Invalid node name: {element.Name}. Expected 'type'."); - } - LoadTypeMapping(element, rma); - } - _assemblies.Add(assemblyName, rma); - } - - private void LoadTypeMapping(XmlElement ele, RenameMappingAssembly ass) - { - var typeName = ele.Attributes["fullName"].Value; - var newTypeName = ele.Attributes["newFullName"].Value; - var rmt = new RenameMappingType - { - oldFullName = typeName, - newFullName = newTypeName, - status = (RenameStatus)System.Enum.Parse(typeof(RenameStatus), ele.Attributes["status"].Value), - }; - foreach (XmlNode node in ele.ChildNodes) - { - if (!(node is XmlElement c)) - { - continue; - } - switch (node.Name) - { - case "field": LoadFieldMapping(c, rmt); break; - case "event": LoadEventMapping(c, rmt); break; - case "property": LoadPropertyMapping(c, rmt); break; - case "method": LoadMethodMapping(c, rmt); break; - default: throw new System.Exception($"Invalid node name:{node.Name}"); - } - } - ass.types.Add(typeName, rmt); - } - - private void LoadMethodMapping(XmlElement ele, RenameMappingType type) - { - string signature = ele.Attributes["signature"].Value; - string newName = ele.Attributes["newName"].Value; - string oldStackTraceSignature = ele.Attributes["oldStackTraceSignature"].Value; - string newStackTraceSignature = ele.Attributes["newStackTraceSignature"].Value; - var rmm = new RenameMappingMethod - { - signature = signature, - newName = newName, - status = RenameStatus.Renamed, - oldStackTraceSignature = oldStackTraceSignature, - newStackTraceSignature = newStackTraceSignature, - }; - type.methods.Add(signature, rmm); - } - - private void LoadFieldMapping(XmlElement ele, RenameMappingType type) - { - string signature = ele.Attributes["signature"].Value; - string newName = ele.Attributes["newName"].Value; - var rmf = new RenameMappingField - { - signature = signature, - newName = newName, - status = RenameStatus.Renamed, - }; - type.fields.Add(signature, rmf); - } - - private void LoadPropertyMapping(XmlElement ele, RenameMappingType type) - { - string signature = ele.Attributes["signature"].Value; - string newName = ele.Attributes["newName"].Value; - var rmp = new RenameMappingProperty - { - signature = signature, - newName = newName, - status = RenameStatus.Renamed, - }; - type.properties.Add(signature, rmp); - } - - private void LoadEventMapping(XmlElement ele, RenameMappingType type) - { - string signature = ele.Attributes["signature"].Value; - string newName = ele.Attributes["newName"].Value; - var rme = new RenameMappingEvent - { - signature = signature, - newName = newName, - status = RenameStatus.Renamed, - }; - type.events.Add(signature, rme); - } - - private List GetSortedValueList(Dictionary dic, Comparison comparer) - { - var list = dic.Values.ToList(); - list.Sort(comparer); - return list; - } - - public void WriteXmlMappingFile() - { - if (string.IsNullOrEmpty(_mappingFile)) - { - return; - } - var doc = new XmlDocument(); - var root = doc.CreateElement("mapping"); - doc.AppendChild(root); - - var totalAssNames = new HashSet(_modRenames.Keys.Select(m => m.Assembly.Name.ToString()).Concat(_assemblies.Keys)).ToList(); - totalAssNames.Sort((a, b) => a.CompareTo(b)); - foreach (string assName in totalAssNames) - { - ModuleDef mod = _modRenames.Keys.FirstOrDefault(m => m.Assembly.Name == assName); - var assemblyNode = doc.CreateElement("assembly"); - assemblyNode.SetAttribute("name", assName); - root.AppendChild(assemblyNode); - if (mod != null) - { - var types = mod.GetTypes().ToDictionary(t => _typeRenames.TryGetValue(t, out var rec) ? rec.oldName : t.FullName, t => t); - if (_assemblies.TryGetValue(assName, out var ass)) - { - var totalTypeNames = new HashSet(types.Keys.Concat(ass.types.Keys)).ToList(); - totalTypeNames.Sort((a, b) => a.CompareTo((b))); - foreach (string typeName in totalTypeNames) - { - if (types.TryGetValue(typeName, out TypeDef typeDef)) - { - WriteTypeMapping(assemblyNode, typeDef); - } - else if (_keepUnknownSymbolInSymbolMappingFile) - { - WriteTypeMapping(assemblyNode, typeName, ass.types[typeName]); - } - } - } - else - { - var sortedTypes = new SortedDictionary(types); - foreach (TypeDef type in sortedTypes.Values) - { - WriteTypeMapping(assemblyNode, type); - } - } - } - else - { - RenameMappingAssembly ass = _assemblies[assName]; - - var sortedTypes = GetSortedValueList(ass.types, (a, b) => a.oldFullName.CompareTo(b.oldFullName)); - foreach (var type in sortedTypes) - { - WriteTypeMapping(assemblyNode, type.oldFullName, type); - } - } - } - Directory.CreateDirectory(Path.GetDirectoryName(_mappingFile)); - doc.Save(_mappingFile); - Debug.Log($"Mapping file saved to {Path.GetFullPath(_mappingFile)}"); - } - - private void WriteTypeMapping(XmlElement assNode, TypeDef type) - { - _typeRenames.TryGetValue(type, out var record); - var typeNode = assNode.OwnerDocument.CreateElement("type"); - typeNode.SetAttribute("fullName", record?.signature ?? type.FullName); - typeNode.SetAttribute("newFullName", record != null && record.status == RenameStatus.Renamed ? record.newName : ""); - typeNode.SetAttribute("status", record != null ? record.status.ToString() : RenameStatus.NotRenamed.ToString()); - if (record != null && record.status == RenameStatus.Renamed) - { - Assert.IsFalse(string.IsNullOrWhiteSpace(record.newName), "New name for type cannot be null or empty when status is Renamed."); - } - - foreach (FieldDef field in type.Fields) - { - WriteFieldMapping(typeNode, field); - } - foreach (PropertyDef property in type.Properties) - { - WritePropertyMapping(typeNode, property); - } - foreach (EventDef eventDef in type.Events) - { - WriteEventMapping(typeNode, eventDef); - } - foreach (MethodDef method in type.Methods) - { - WriteMethodMapping(typeNode, method); - } - if ((record != null && record.status == RenameStatus.Renamed) || typeNode.ChildNodes.Count > 0) - { - assNode.AppendChild(typeNode); - } - } - - private void WriteTypeMapping(XmlElement assNode, string fullName, RenameMappingType type) - { - var typeNode = assNode.OwnerDocument.CreateElement("type"); - typeNode.SetAttribute("fullName", fullName); - typeNode.SetAttribute("newFullName", type.status == RenameStatus.Renamed ? type.newFullName : ""); - typeNode.SetAttribute("status", type.status.ToString()); - - foreach (var e in type.fields) - { - string signature = e.Key; - RenameMappingField field = e.Value; - WriteFieldMapping(typeNode, e.Key, e.Value); - } - foreach (var e in type.properties) - { - WritePropertyMapping(typeNode, e.Key, e.Value); - } - foreach (var e in type.events) - { - WriteEventMapping(typeNode, e.Key, e.Value); - } - foreach (var e in type.methods) - { - WriteMethodMapping(typeNode, e.Key, e.Value); - } - - assNode.AppendChild(typeNode); - } - - private void WriteFieldMapping(XmlElement typeEle, FieldDef field) - { - if (!_fieldRenames.TryGetValue(field, out var record) || record.status == RenameStatus.NotRenamed) - { - return; - } - var fieldNode = typeEle.OwnerDocument.CreateElement("field"); - fieldNode.SetAttribute("signature", record?.signature); - fieldNode.SetAttribute("newName", record.newName); - //fieldNode.SetAttribute("status", record.status.ToString()); - typeEle.AppendChild(fieldNode); - } - - private void WriteFieldMapping(XmlElement typeEle, string signature, RenameMappingField field) - { - var fieldNode = typeEle.OwnerDocument.CreateElement("field"); - fieldNode.SetAttribute("signature", signature); - fieldNode.SetAttribute("newName", field.newName); - //fieldNode.SetAttribute("status", record.status.ToString()); - typeEle.AppendChild(fieldNode); - } - - private void WritePropertyMapping(XmlElement typeEle, PropertyDef property) - { - if (!_propertyRenames.TryGetValue(property, out var record) || record.status == RenameStatus.NotRenamed) - { - return; - } - var propertyNode = typeEle.OwnerDocument.CreateElement("property"); - propertyNode.SetAttribute("signature", record.signature); - propertyNode.SetAttribute("newName", record.newName); - //propertyNode.SetAttribute("status", record.status.ToString()); - typeEle.AppendChild(propertyNode); - } - - private void WritePropertyMapping(XmlElement typeEle, string signature, RenameMappingProperty property) - { - var propertyNode = typeEle.OwnerDocument.CreateElement("property"); - propertyNode.SetAttribute("signature", signature); - propertyNode.SetAttribute("newName", property.newName); - //propertyNode.SetAttribute("status", record.status.ToString()); - typeEle.AppendChild(propertyNode); - } - - private void WriteEventMapping(XmlElement typeEle, EventDef eventDef) - { - if (!_eventRenames.TryGetValue(eventDef, out var record) || record.status == RenameStatus.NotRenamed) - { - return; - } - var eventNode = typeEle.OwnerDocument.CreateElement("event"); - eventNode.SetAttribute("signature", record.signature); - eventNode.SetAttribute("newName", record.newName); - typeEle.AppendChild(eventNode); - } - - private void WriteEventMapping(XmlElement typeEle, string signature, RenameMappingEvent eventDef) - { - var eventNode = typeEle.OwnerDocument.CreateElement("event"); - eventNode.SetAttribute("signature", signature); - eventNode.SetAttribute("newName", eventDef.newName); - typeEle.AppendChild(eventNode); - } - - private void WriteMethodMapping(XmlElement typeEle, MethodDef method) - { - if (!_methodRenames.TryGetValue(method, out var record) || record.status == RenameStatus.NotRenamed) - { - return; - } - var methodNode = typeEle.OwnerDocument.CreateElement("method"); - methodNode.SetAttribute("signature", record.signature); - methodNode.SetAttribute("newName", record.newName); - methodNode.SetAttribute("oldStackTraceSignature", record.oldStackTraceSignature); - methodNode.SetAttribute("newStackTraceSignature", MetaUtil.CreateMethodDefIl2CppStackTraceSignature(method)); - //methodNode.SetAttribute("status", record != null ? record.status.ToString() : RenameStatus.NotRenamed.ToString()); - typeEle.AppendChild(methodNode); - } - - private void WriteMethodMapping(XmlElement typeEle, string signature, RenameMappingMethod method) - { - var methodNode = typeEle.OwnerDocument.CreateElement("method"); - methodNode.SetAttribute("signature", signature); - methodNode.SetAttribute("newName", method.newName); - methodNode.SetAttribute("oldStackTraceSignature", method.oldStackTraceSignature); - methodNode.SetAttribute("newStackTraceSignature", method.newStackTraceSignature); - typeEle.AppendChild(methodNode); - } - - public void AddRename(ModuleDef mod, string newName) - { - RenameRecord record = _modRenames[mod]; - record.status = RenameStatus.Renamed; - record.newName = newName; - } - - public void AddRename(TypeDef type, string newName) - { - RenameRecord record = _typeRenames[type]; - record.status = RenameStatus.Renamed; - record.newName = newName; - } - - public void AddRename(MethodDef method, string newName) - { - if (_methodRenames.TryGetValue(method, out RenameRecord record)) - { - record.status = RenameStatus.Renamed; - record.newName = newName; - return; - } - else - { - string methodSig = TypeSigUtil.ComputeMethodDefSignature(method); - _methodRenames.Add(method, new RenameRecord - { - status = RenameStatus.Renamed, - signature = methodSig, - oldName = method.Name, - newName = newName, - renameMappingData = null, - oldStackTraceSignature = MetaUtil.CreateMethodDefIl2CppStackTraceSignature(method), - }); - } - } - - public void InitAndAddRename(VirtualMethodGroup methodGroup, string newName) - { - RenameRecord methodRecord = methodGroup.methods.Where(m => _methodRenames.ContainsKey(m)).Select(m => _methodRenames[m]).FirstOrDefault(); - MethodDef firstMethod = methodGroup.methods[0]; - _virtualMethodGroups.Add(methodGroup, new RenameRecord - { - status = RenameStatus.Renamed, - signature = methodRecord != null ? methodRecord.signature : TypeSigUtil.ComputeMethodDefSignature(firstMethod), - oldName = methodRecord != null ? methodRecord.oldName : (string)firstMethod.Name, - newName = newName, - }); - } - - public void AddRename(FieldDef field, string newName) - { - RenameRecord record = _fieldRenames[field]; - record.status = RenameStatus.Renamed; - record.newName = newName; - } - - public void AddRename(PropertyDef property, string newName) - { - RenameRecord record = _propertyRenames[property]; - record.status = RenameStatus.Renamed; - record.newName = newName; - } - - public void AddRename(EventDef eventDef, string newName) - { - RenameRecord record = _eventRenames[eventDef]; - record.status = RenameStatus.Renamed; - record.newName = newName; - } - - public bool TryGetExistRenameMapping(TypeDef type, out string newNamespace, out string newName) - { - if (_typeRenames.TryGetValue(type, out var record) && record.renameMappingData != null) - { - var rmt = (RenameMappingType)record.renameMappingData; - if (rmt.status == RenameStatus.Renamed) - { - Assert.IsFalse(string.IsNullOrWhiteSpace(rmt.newFullName)); - (newNamespace, newName) = MetaUtil.SplitNamespaceAndName(rmt.newFullName); - return true; - } - } - newNamespace = null; - newName = null; - return false; - } - - public bool TryGetExistRenameMapping(MethodDef method, out string newName) - { - if (_methodRenames.TryGetValue(method, out var record) && record.renameMappingData != null) - { - RenameMappingMethod rmm = (RenameMappingMethod)record.renameMappingData; - if (rmm.status == RenameStatus.Renamed) - { - newName = ((RenameMappingMethod)record.renameMappingData).newName; - return true; - } - } - newName = null; - return false; - } - - public bool TryGetExistRenameMapping(FieldDef field, out string newName) - { - if (_fieldRenames.TryGetValue(field, out var record) && record.renameMappingData != null) - { - RenameMappingField rmm = (RenameMappingField)record.renameMappingData; - if (rmm.status == RenameStatus.Renamed) - { - newName = ((RenameMappingField)record.renameMappingData).newName; - return true; - } - } - newName = null; - return false; - } - - public bool TryGetExistRenameMapping(PropertyDef property, out string newName) - { - if (_propertyRenames.TryGetValue(property, out var record) && record.renameMappingData != null) - { - RenameMappingProperty rmm = (RenameMappingProperty)record.renameMappingData; - if (rmm.status == RenameStatus.Renamed) - { - newName = ((RenameMappingProperty)record.renameMappingData).newName; - return true; - } - } - newName = null; - return false; - } - - public bool TryGetExistRenameMapping(EventDef eventDef, out string newName) - { - if (_eventRenames.TryGetValue(eventDef, out var record) && record.renameMappingData != null) - { - RenameMappingEvent rmm = (RenameMappingEvent)record.renameMappingData; - if (rmm.status == RenameStatus.Renamed) - { - newName = ((RenameMappingEvent)record.renameMappingData).newName; - return true; - } - } - newName = null; - return false; - } - - public bool TryGetRename(VirtualMethodGroup group, out string newName) - { - if (_virtualMethodGroups.TryGetValue(group, out var record)) - { - newName = record.newName; - return true; - } - newName = null; - return false; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/RenameRecordMap.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/RenameRecordMap.cs.meta deleted file mode 100644 index 2a91341f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/RenameRecordMap.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a3ffbd28624d87c4382f62eb4fc19c70 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolObfusPass.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolObfusPass.cs deleted file mode 100644 index eb7970aa..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolObfusPass.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Obfuz.Settings; - -namespace Obfuz.ObfusPasses.SymbolObfus -{ - public class SymbolObfusPass : ObfuscationPassBase - { - private SymbolRename _symbolRename; - - public override ObfuscationPassType Type => ObfuscationPassType.SymbolObfus; - - public SymbolObfusPass(SymbolObfuscationSettingsFacade settings) - { - _symbolRename = new SymbolRename(settings); - } - - public override void Start() - { - _symbolRename.Init(); - } - - public override void Stop() - { - _symbolRename.Save(); - } - - public override void Process() - { - _symbolRename.Process(); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolObfusPass.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolObfusPass.cs.meta deleted file mode 100644 index a86c04b1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolObfusPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a4c9a37b51ade6b46a299be7ad2155d6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolRename.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolRename.cs deleted file mode 100644 index 1ceddfa7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolRename.cs +++ /dev/null @@ -1,864 +0,0 @@ -using dnlib.DotNet; -using Obfuz.ObfusPasses.SymbolObfus.NameMakers; -using Obfuz.ObfusPasses.SymbolObfus.Policies; -using Obfuz.Settings; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; - -namespace Obfuz.ObfusPasses.SymbolObfus -{ - public class SymbolRename - { - private readonly bool _useConsistentNamespaceObfuscation; - private readonly bool _detectReflectionCompatibility; - private readonly List _obfuscationRuleFiles; - private readonly string _mappingXmlPath; - - private AssemblyCache _assemblyCache; - - private List _toObfuscatedModules; - private List _obfuscatedAndNotObfuscatedModules; - private HashSet _toObfuscatedModuleSet; - private HashSet _nonObfuscatedButReferencingObfuscatedModuleSet; - private IObfuscationPolicy _renamePolicy; - private INameMaker _nameMaker; - private readonly Dictionary> _customAttributeArgumentsWithTypeByMods = new Dictionary>(); - private readonly RenameRecordMap _renameRecordMap; - private readonly VirtualMethodGroupCalculator _virtualMethodGroupCalculator; - private readonly List _customPolicies = new List(); - - class CustomAttributeInfo - { - public CustomAttributeCollection customAttributes; - public int index; - public List arguments; - public List namedArguments; - } - - public SymbolRename(SymbolObfuscationSettingsFacade settings) - { - _useConsistentNamespaceObfuscation = settings.useConsistentNamespaceObfuscation; - _detectReflectionCompatibility = settings.detectReflectionCompatibility; - _mappingXmlPath = settings.symbolMappingFile; - _obfuscationRuleFiles = settings.ruleFiles.ToList(); - _renameRecordMap = new RenameRecordMap(settings.symbolMappingFile, settings.debug, settings.keepUnknownSymbolInSymbolMappingFile); - _virtualMethodGroupCalculator = new VirtualMethodGroupCalculator(); - _nameMaker = settings.debug ? NameMakerFactory.CreateDebugNameMaker() : NameMakerFactory.CreateNameMakerBaseASCIICharSet(settings.obfuscatedNamePrefix); - - foreach (var customPolicyType in settings.customRenamePolicyTypes) - { - if (Activator.CreateInstance(customPolicyType, new object[] { this }) is IObfuscationPolicy customPolicy) - { - _customPolicies.Add(customPolicy); - } - else - { - Debug.LogWarning($"Custom rename policy type {customPolicyType} is not a valid IObfuscationPolicy"); - } - } - } - - public void Init() - { - var ctx = ObfuscationPassContext.Current; - _assemblyCache = ctx.assemblyCache; - _toObfuscatedModules = ctx.modulesToObfuscate; - _obfuscatedAndNotObfuscatedModules = ctx.allObfuscationRelativeModules; - _toObfuscatedModuleSet = new HashSet(ctx.modulesToObfuscate); - _nonObfuscatedButReferencingObfuscatedModuleSet = new HashSet(ctx.allObfuscationRelativeModules.Where(m => !_toObfuscatedModuleSet.Contains(m))); - - var obfuscateRuleConfig = new ConfigurableRenamePolicy(ctx.coreSettings.assembliesToObfuscate, ctx.modulesToObfuscate, _obfuscationRuleFiles); - var totalRenamePolicies = new List - { - new SupportPassPolicy(ctx.passPolicy), - new SystemRenamePolicy(ctx.obfuzIgnoreScopeComputeCache), - new UnityRenamePolicy(), - obfuscateRuleConfig, - }; - totalRenamePolicies.AddRange(_customPolicies); - - _renamePolicy = new CacheRenamePolicy(new CombineRenamePolicy(totalRenamePolicies.ToArray())); - BuildCustomAttributeArguments(); - } - - private void CollectCArgumentWithTypeOf(IHasCustomAttribute meta, List customAttributes) - { - int index = 0; - foreach (CustomAttribute ca in meta.CustomAttributes) - { - List arguments = null; - if (ca.ConstructorArguments.Any(a => MetaUtil.MayRenameCustomDataType(a.Type.ElementType))) - { - arguments = ca.ConstructorArguments.ToList(); - } - List namedArguments = ca.NamedArguments.Count > 0 ? ca.NamedArguments.ToList() : null; - if (arguments != null || namedArguments != null) - { - customAttributes.Add(new CustomAttributeInfo - { - customAttributes = meta.CustomAttributes, - index = index, - arguments = arguments, - namedArguments = namedArguments - }); - } - ++index; - } - } - - private void BuildCustomAttributeArguments() - { - foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules) - { - var customAttributes = new List(); - CollectCArgumentWithTypeOf(mod, customAttributes); - foreach (TypeDef type in mod.GetTypes()) - { - CollectCArgumentWithTypeOf(type, customAttributes); - foreach (FieldDef field in type.Fields) - { - CollectCArgumentWithTypeOf(field, customAttributes); - } - foreach (MethodDef method in type.Methods) - { - CollectCArgumentWithTypeOf(method, customAttributes); - foreach (Parameter param in method.Parameters) - { - if (param.ParamDef != null) - { - CollectCArgumentWithTypeOf(param.ParamDef, customAttributes); - } - } - } - foreach (PropertyDef property in type.Properties) - { - CollectCArgumentWithTypeOf(property, customAttributes); - } - foreach (EventDef eventDef in type.Events) - { - CollectCArgumentWithTypeOf(eventDef, customAttributes); - } - } - - _customAttributeArgumentsWithTypeByMods.Add(mod, customAttributes); - } - } - - private void PrecomputeNeedRename() - { - foreach (ModuleDef mod in _toObfuscatedModules) - { - foreach (TypeDef type in mod.GetTypes()) - { - _renamePolicy.NeedRename(type); - foreach (var field in type.Fields) - { - _renamePolicy.NeedRename(field); - } - foreach (var method in type.Methods) - { - _renamePolicy.NeedRename(method); - } - foreach (var property in type.Properties) - { - _renamePolicy.NeedRename(property); - } - foreach (var eventDef in type.Events) - { - _renamePolicy.NeedRename(eventDef); - } - } - } - } - - public void Process() - { - _renameRecordMap.Init(_toObfuscatedModules, _nameMaker); - PrecomputeNeedRename(); - if (_detectReflectionCompatibility) - { - var reflectionCompatibilityDetector = new ReflectionCompatibilityDetector(_toObfuscatedModules, _obfuscatedAndNotObfuscatedModules, _renamePolicy); - reflectionCompatibilityDetector.Analyze(); - } - RenameTypes(); - RenameFields(); - RenameMethods(); - RenameProperties(); - RenameEvents(); - } - - class RefTypeDefMetas - { - public readonly List typeRefs = new List(); - - public readonly List customAttributes = new List(); - } - - private void BuildRefTypeDefMetasMap(Dictionary refTypeDefMetasMap) - { - foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules) - { - foreach (TypeRef typeRef in mod.GetTypeRefs()) - { - if (typeRef.DefinitionAssembly.IsCorLib()) - { - continue; - } - TypeDef typeDef = typeRef.ResolveThrow(); - if (!refTypeDefMetasMap.TryGetValue(typeDef, out var typeDefMetas)) - { - typeDefMetas = new RefTypeDefMetas(); - refTypeDefMetasMap.Add(typeDef, typeDefMetas); - } - typeDefMetas.typeRefs.Add(typeRef); - } - } - - foreach (CustomAttributeInfo cai in _customAttributeArgumentsWithTypeByMods.Values.SelectMany(cas => cas)) - { - CustomAttribute ca = cai.customAttributes[cai.index]; - TypeDef typeDef = MetaUtil.GetTypeDefOrGenericTypeBaseThrowException(ca.Constructor.DeclaringType); - if (!refTypeDefMetasMap.TryGetValue(typeDef, out var typeDefMetas)) - { - typeDefMetas = new RefTypeDefMetas(); - refTypeDefMetasMap.Add(typeDef, typeDefMetas); - } - typeDefMetas.customAttributes.Add(ca); - } - } - - private void RetargetTypeRefInCustomAttributes() - { - foreach (CustomAttributeInfo cai in _customAttributeArgumentsWithTypeByMods.Values.SelectMany(cas => cas)) - { - CustomAttribute ca = cai.customAttributes[cai.index]; - bool anyChange = false; - if (cai.arguments != null) - { - for (int i = 0; i < cai.arguments.Count; i++) - { - CAArgument oldArg = cai.arguments[i]; - if (MetaUtil.TryRetargetTypeRefInArgument(oldArg, out CAArgument newArg)) - { - anyChange = true; - cai.arguments[i] = newArg; - } - } - } - if (cai.namedArguments != null) - { - for (int i = 0; i < cai.namedArguments.Count; i++) - { - if (MetaUtil.TryRetargetTypeRefInNamedArgument(cai.namedArguments[i])) - { - anyChange = true; - } - } - } - if (anyChange) - { - cai.customAttributes[cai.index] = new CustomAttribute(ca.Constructor, - cai.arguments != null ? cai.arguments : ca.ConstructorArguments, - cai.namedArguments != null ? cai.namedArguments : ca.NamedArguments); - } - } - } - - private readonly Dictionary _refTypeRefMetasMap = new Dictionary(); - - private void RenameTypes() - { - //Debug.Log("RenameTypes begin"); - - RetargetTypeRefInCustomAttributes(); - - BuildRefTypeDefMetasMap(_refTypeRefMetasMap); - _assemblyCache.EnableTypeDefCache = false; - - foreach (ModuleDef mod in _toObfuscatedModules) - { - foreach (TypeDef type in mod.GetTypes()) - { - if (_renamePolicy.NeedRename(type)) - { - Rename(type, _refTypeRefMetasMap.GetValueOrDefault(type)); - } - } - } - - // clean cache - _assemblyCache.EnableTypeDefCache = true; - //Debug.Log("Rename Types end"); - } - - - class RefFieldMetas - { - public readonly List fieldRefs = new List(); - public readonly List customAttributes = new List(); - } - - - private void BuildHierarchyFields(TypeDef type, List fields) - { - while (type != null) - { - fields.AddRange(type.Fields); - type = MetaUtil.GetBaseTypeDef(type); - } - } - - private IEnumerable WalkAllMethodInstructionOperand(ModuleDef mod) - { - foreach (TypeDef type in mod.GetTypes()) - { - foreach (MethodDef method in type.Methods) - { - if (!method.HasBody) - { - continue; - } - foreach (var instr in method.Body.Instructions) - { - if (instr.Operand is T memberRef) - { - yield return memberRef; - } - } - } - } - } - - private void BuildRefFieldMetasMap(Dictionary refFieldMetasMap) - { - foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules) - { - foreach (MemberRef memberRef in WalkAllMethodInstructionOperand(mod)) - { - IMemberRefParent parent = memberRef.Class; - TypeDef parentTypeDef = MetaUtil.GetMemberRefTypeDefParentOrNull(parent); - if (parentTypeDef == null) - { - continue; - } - foreach (FieldDef field in parentTypeDef.Fields) - { - if (field.Name == memberRef.Name && TypeEqualityComparer.Instance.Equals(field.FieldSig.Type, memberRef.FieldSig.Type)) - { - if (!refFieldMetasMap.TryGetValue(field, out var fieldMetas)) - { - fieldMetas = new RefFieldMetas(); - refFieldMetasMap.Add(field, fieldMetas); - } - fieldMetas.fieldRefs.Add(memberRef); - break; - } - } - } - } - foreach (var e in _refTypeRefMetasMap) - { - TypeDef typeDef = e.Key; - var hierarchyFields = new List(); - BuildHierarchyFields(typeDef, hierarchyFields); - RefTypeDefMetas typeDefMetas = e.Value; - foreach (CustomAttribute ca in typeDefMetas.customAttributes) - { - foreach (var arg in ca.NamedArguments) - { - if (arg.IsProperty) - { - continue; - } - foreach (FieldDef field in hierarchyFields) - { - // FIXME. field of Generic Base Type may not be same - if (field.Name == arg.Name && TypeEqualityComparer.Instance.Equals(field.FieldType, arg.Type)) - { - if (!refFieldMetasMap.TryGetValue(field, out var fieldMetas)) - { - fieldMetas = new RefFieldMetas(); - refFieldMetasMap.Add(field, fieldMetas); - } - fieldMetas.customAttributes.Add(ca); - break; - } - } - } - } - } - } - - private void RenameFields() - { - //Debug.Log("Rename fields begin"); - var refFieldMetasMap = new Dictionary(); - BuildRefFieldMetasMap(refFieldMetasMap); - - foreach (ModuleDef mod in _toObfuscatedModules) - { - foreach (TypeDef type in mod.GetTypes()) - { - foreach (FieldDef field in type.Fields) - { - if (_renamePolicy.NeedRename(field)) - { - Rename(field, refFieldMetasMap.GetValueOrDefault(field)); - } - } - } - } - //Debug.Log("Rename fields end"); - } - - class RefMethodMetas - { - public readonly List memberRefs = new List(); - } - - private void RenameMethodRef(MemberRef memberRef, Dictionary refMethodMetasMap) - { - if (!memberRef.IsMethodRef) - { - return; - } - - IMemberRefParent parent = memberRef.Class; - TypeDef parentTypeDef = MetaUtil.GetMemberRefTypeDefParentOrNull(parent); - if (parentTypeDef == null) - { - return; - } - foreach (MethodDef methodDef in parentTypeDef.Methods) - { - if (methodDef.Name == memberRef.Name && new SigComparer(default).Equals(methodDef.MethodSig, memberRef.MethodSig)) - { - if (!refMethodMetasMap.TryGetValue(methodDef, out var refMethodMetas)) - { - refMethodMetas = new RefMethodMetas(); - refMethodMetasMap.Add(methodDef, refMethodMetas); - } - refMethodMetas.memberRefs.Add(memberRef); - break; - } - } - } - - - private void RenameMethodRefOrMethodSpec(IMethod method, Dictionary refMethodMetasMap) - { - if (method is MemberRef memberRef) - { - RenameMethodRef(memberRef, refMethodMetasMap); - } - else if (method is MethodSpec methodSpec) - { - if (methodSpec.Method is MemberRef memberRef2) - { - RenameMethodRef(memberRef2, refMethodMetasMap); - } - } - } - - private void BuildRefMethodMetasMap(Dictionary refMethodMetasMap) - { - foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules) - { - foreach (IMethod method in WalkAllMethodInstructionOperand(mod)) - { - RenameMethodRefOrMethodSpec(method, refMethodMetasMap); - } - - foreach (var type in mod.GetTypes()) - { - foreach (MethodDef method in type.Methods) - { - if (method.HasOverrides) - { - foreach (MethodOverride methodOverride in method.Overrides) - { - RenameMethodRefOrMethodSpec(methodOverride.MethodDeclaration, refMethodMetasMap); - RenameMethodRefOrMethodSpec(methodOverride.MethodBody, refMethodMetasMap); - } - } - } - } - foreach (var e in _refTypeRefMetasMap) - { - TypeDef typeDef = e.Key; - var hierarchyFields = new List(); - BuildHierarchyFields(typeDef, hierarchyFields); - RefTypeDefMetas typeDefMetas = e.Value; - foreach (CustomAttribute ca in typeDefMetas.customAttributes) - { - if (ca.Constructor is IMethod method) - { - RenameMethodRefOrMethodSpec(method, refMethodMetasMap); - } - } - } - } - } - - private void RenameMethods() - { - //Debug.Log("Rename methods begin"); - //Debug.Log("Rename not virtual methods begin"); - var virtualMethods = new List(); - var refMethodMetasMap = new Dictionary(); - BuildRefMethodMetasMap(refMethodMetasMap); - foreach (ModuleDef mod in _toObfuscatedModules) - { - foreach (TypeDef type in mod.GetTypes()) - { - foreach (MethodDef method in type.Methods) - { - if (method.IsVirtual) - { - continue; - } - if (_renamePolicy.NeedRename(method)) - { - Rename(method, refMethodMetasMap.GetValueOrDefault(method)); - } - } - } - } - - foreach (ModuleDef mod in _obfuscatedAndNotObfuscatedModules) - { - foreach (TypeDef type in mod.GetTypes()) - { - _virtualMethodGroupCalculator.CalculateType(type); - foreach (MethodDef method in type.Methods) - { - if (method.IsVirtual) - { - virtualMethods.Add(method); - } - } - } - } - - //Debug.Log("Rename not virtual methods end"); - - - //Debug.Log("Rename virtual methods begin"); - var visitedVirtualMethods = new HashSet(); - var groupNeedRenames = new Dictionary(); - foreach (var method in virtualMethods) - { - if (!visitedVirtualMethods.Add(method)) - { - continue; - } - VirtualMethodGroup group = _virtualMethodGroupCalculator.GetMethodGroup(method); - if (!groupNeedRenames.TryGetValue(group, out var needRename)) - { - var rootBeInheritedTypes = group.GetRootBeInheritedTypes(); - // - if the group contains no obfuscated methods - // - if the group contains method defined in non-obfuscated module but referencing obfuscated module and virtual method in obfuscated type overrides virtual method from non-obfuscated type - if (!group.methods.Any(m => _toObfuscatedModuleSet.Contains(m.DeclaringType.Module)) || group.methods.Any(m => _nonObfuscatedButReferencingObfuscatedModuleSet.Contains(m.Module) && rootBeInheritedTypes.Contains(m.DeclaringType))) - { - needRename = false; - } - else - { - needRename = group.methods.All(m => _obfuscatedAndNotObfuscatedModules.Contains(m.Module) && _renamePolicy.NeedRename(m)); - } - groupNeedRenames.Add(group, needRename); - if (needRename) - { - bool conflict = false; - string newVirtualMethodName = null; - foreach (MethodDef m in group.methods) - { - if (_renameRecordMap.TryGetExistRenameMapping(m, out var existVirtualMethodName)) - { - if (newVirtualMethodName == null) - { - newVirtualMethodName = existVirtualMethodName; - } - else if (newVirtualMethodName != existVirtualMethodName) - { - Debug.LogWarning($"Virtual method rename conflict. {m} => {existVirtualMethodName} != {newVirtualMethodName}"); - conflict = true; - break; - } - } - } - if (newVirtualMethodName == null || conflict /*|| _nameMaker.IsNamePreserved(group, newVirtualMethodName)*/) - { - newVirtualMethodName = _nameMaker.GetNewName(group, method.Name); - } - _renameRecordMap.InitAndAddRename(group, newVirtualMethodName); - } - } - if (!needRename) - { - continue; - } - if (_renameRecordMap.TryGetRename(group, out var newName)) - { - Rename(method, refMethodMetasMap.GetValueOrDefault(method), newName); - } - else - { - throw new Exception($"group:{group} method:{method} not found in rename record map"); - } - } - //Debug.Log("Rename virtual methods end"); - //Debug.Log("Rename methods end"); - } - - class RefPropertyMetas - { - public List customAttributes = new List(); - } - - private void BuildHierarchyProperties(TypeDef type, List properties) - { - while (type != null) - { - properties.AddRange(type.Properties); - type = MetaUtil.GetBaseTypeDef(type); - } - } - - private void BuildRefPropertyMetasMap(Dictionary refPropertyMetasMap) - { - foreach (var e in _refTypeRefMetasMap) - { - TypeDef typeDef = e.Key; - var hierarchyProperties = new List(); - BuildHierarchyProperties(typeDef, hierarchyProperties); - RefTypeDefMetas typeDefMetas = e.Value; - foreach (CustomAttribute ca in typeDefMetas.customAttributes) - { - foreach (var arg in ca.NamedArguments) - { - if (arg.IsField) - { - continue; - } - foreach (PropertyDef field in hierarchyProperties) - { - // FIXME. field of Generic Base Type may not be same - if (field.Name == arg.Name && TypeEqualityComparer.Instance.Equals(arg.Type, field.PropertySig.RetType)) - { - if (!refPropertyMetasMap.TryGetValue(field, out var fieldMetas)) - { - fieldMetas = new RefPropertyMetas(); - refPropertyMetasMap.Add(field, fieldMetas); - } - fieldMetas.customAttributes.Add(ca); - break; - } - } - } - } - } - } - - private void RenameProperties() - { - //Debug.Log("Rename properties begin"); - var refPropertyMetasMap = new Dictionary(); - BuildRefPropertyMetasMap(refPropertyMetasMap); - foreach (ModuleDef mod in _toObfuscatedModules) - { - foreach (TypeDef type in mod.GetTypes()) - { - foreach (PropertyDef property in type.Properties) - { - if (_renamePolicy.NeedRename(property)) - { - Rename(property, refPropertyMetasMap.GetValueOrDefault(property)); - } - } - } - } - //Debug.Log("Rename properties end"); - } - - private void RenameEvents() - { - //Debug.Log("Rename events begin"); - foreach (ModuleDef mod in _toObfuscatedModules) - { - foreach (TypeDef type in mod.GetTypes()) - { - foreach (EventDef eventDef in type.Events) - { - if (_renamePolicy.NeedRename(eventDef)) - { - Rename(eventDef); - } - } - } - } - //Debug.Log("Rename events begin"); - } - - private void Rename(TypeDef type, RefTypeDefMetas refTypeDefMeta) - { - string moduleName = MetaUtil.GetModuleNameWithoutExt(type.Module.Name); - string oldFullName = type.FullName; - string oldNamespace = type.Namespace; - - string oldName = type.Name; - - string newNamespace; - string newName; - if (_renameRecordMap.TryGetExistRenameMapping(type, out var nns, out var nn)) - { - newNamespace = nns; - newName = nn; - } - else - { - newNamespace = _nameMaker.GetNewNamespace(type, oldNamespace, _useConsistentNamespaceObfuscation); - newName = _nameMaker.GetNewName(type, oldName); - } - - if (refTypeDefMeta != null) - { - foreach (TypeRef typeRef in refTypeDefMeta.typeRefs) - { - Assert.AreEqual(typeRef.FullName, oldFullName); - Assert.IsTrue(typeRef.DefinitionAssembly.Name == moduleName); - if (!string.IsNullOrEmpty(oldNamespace)) - { - typeRef.Namespace = newNamespace; - } - typeRef.Name = newName; - //Debug.Log($"rename assembly:{typeRef.Module.Name} reference {oldFullName} => {typeRef.FullName}"); - } - } - type.Name = newName; - type.Namespace = newNamespace; - string newFullName = type.FullName; - _renameRecordMap.AddRename(type, newFullName); - //Debug.Log($"rename typedef. assembly:{type.Module.Name} oldName:{oldFullName} => newName:{newFullName}"); - } - - private void Rename(FieldDef field, RefFieldMetas fieldMetas) - { - string oldName = field.Name; - string newName = _renameRecordMap.TryGetExistRenameMapping(field, out var nn) ? nn : _nameMaker.GetNewName(field, oldName); - if (fieldMetas != null) - { - foreach (var memberRef in fieldMetas.fieldRefs) - { - memberRef.Name = newName; - //Debug.Log($"rename assembly:{memberRef.Module.Name} reference {field.FullName} => {memberRef.FullName}"); - } - foreach (var ca in fieldMetas.customAttributes) - { - foreach (var arg in ca.NamedArguments) - { - if (arg.Name == oldName) - { - arg.Name = newName; - } - } - } - } - //Debug.Log($"rename field. {field} => {newName}"); - _renameRecordMap.AddRename(field, newName); - field.Name = newName; - - } - - private void Rename(MethodDef method, RefMethodMetas refMethodMetas) - { - string oldName = method.Name; - string newName = _renameRecordMap.TryGetExistRenameMapping(method, out var nn) ? nn : _nameMaker.GetNewName(method, oldName); - Rename(method, refMethodMetas, newName); - } - - private void Rename(MethodDef method, RefMethodMetas refMethodMetas, string newName) - { - ModuleDefMD mod = (ModuleDefMD)method.DeclaringType.Module; - RenameMethodParams(method); - RenameMethodBody(method); - if (refMethodMetas != null) - { - foreach (MemberRef memberRef in refMethodMetas.memberRefs) - { - string oldMethodFullName = memberRef.ToString(); - memberRef.Name = newName; - //Debug.Log($"rename assembly:{memberRef.Module.Name} method:{oldMethodFullName} => {memberRef}"); - } - } - _renameRecordMap.AddRename(method, newName); - method.Name = newName; - } - - private void RenameMethodBody(MethodDef method) - { - if (method.Body == null) - { - return; - } - } - - private void RenameMethodParams(MethodDef method) - { - foreach (Parameter param in method.Parameters) - { - if (param.ParamDef != null) - { - Rename(param.ParamDef); - } - } - } - - private void Rename(ParamDef param) - { - string newName = _nameMaker.GetNewName(param, param.Name); - param.Name = newName; - } - - private void Rename(EventDef eventDef) - { - string oldName = eventDef.Name; - string newName = _renameRecordMap.TryGetExistRenameMapping(eventDef, out var nn) ? nn : _nameMaker.GetNewName(eventDef, eventDef.Name); - _renameRecordMap.AddRename(eventDef, newName); - eventDef.Name = newName; - } - - private void Rename(PropertyDef property, RefPropertyMetas refPropertyMetas) - { - string oldName = property.Name; - string newName = _renameRecordMap.TryGetExistRenameMapping(property, out var nn) ? nn : _nameMaker.GetNewName(property, oldName); - - if (refPropertyMetas != null) - { - foreach (var ca in refPropertyMetas.customAttributes) - { - foreach (var arg in ca.NamedArguments) - { - if (arg.Name == oldName) - { - arg.Name = newName; - } - } - } - } - _renameRecordMap.AddRename(property, newName); - property.Name = newName; - } - - public void Save() - { - Directory.CreateDirectory(Path.GetDirectoryName(_mappingXmlPath)); - _renameRecordMap.WriteXmlMappingFile(); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolRename.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolRename.cs.meta deleted file mode 100644 index 739a842b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/SymbolRename.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ec29be12f08e90741a59970f029c2eec -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/VirtualMethodGroupCalculator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/VirtualMethodGroupCalculator.cs deleted file mode 100644 index ac6b4546..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/VirtualMethodGroupCalculator.cs +++ /dev/null @@ -1,299 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.SymbolObfus -{ - - public class VirtualMethodGroup - { - public List methods; - - private HashSet _nameScopes; - - private HashSet _rootNameScope; - - public HashSet GetNameConflictTypeScopes() - { - if (_nameScopes != null) - { - return _nameScopes; - } - - _nameScopes = new HashSet(); - foreach (var method in methods) - { - TypeDef cur = method.DeclaringType; - while (cur != null) - { - _nameScopes.Add(cur); - cur = MetaUtil.GetBaseTypeDef(cur); - } - } - return _nameScopes; - } - - public HashSet GetRootBeInheritedTypes() - { - if (_rootNameScope != null) - { - return _rootNameScope; - } - _rootNameScope = new HashSet(); - var nameScopes = GetNameConflictTypeScopes(); - foreach (var type in nameScopes) - { - TypeDef parentType = MetaUtil.GetBaseTypeDef(type); - if (parentType == null || !nameScopes.Contains(parentType)) - { - _rootNameScope.Add(type); - } - } - return _rootNameScope; - } - - public IEnumerable GetNameDeclaringTypeScopes() - { - foreach (var method in methods) - { - yield return method.DeclaringType; - } - } - } - - public class VirtualMethodGroupCalculator - { - - private class TypeFlatMethods - { - public HashSet flatMethods = new HashSet(); - - - private bool IsFinalTypeSig(TypeSig type) - { - switch (type.ElementType) - { - case ElementType.Void: - case ElementType.Boolean: - case ElementType.Char: - case ElementType.I1: - case ElementType.I2: - case ElementType.I4: - case ElementType.I8: - case ElementType.U1: - case ElementType.U2: - case ElementType.U4: - case ElementType.U8: - case ElementType.R4: - case ElementType.R8: - case ElementType.String: - case ElementType.Object: - case ElementType.Class: - case ElementType.ValueType: - return true; - default: return false; - } - } - - private bool IsVarType(TypeSig t) - { - return t.ElementType == ElementType.MVar || t.ElementType == ElementType.Var; - } - - private bool IsClassOrValueType(TypeSig t) - { - return t.ElementType == ElementType.Class || t.ElementType == ElementType.ValueType; - } - - private bool IsLooseTypeSigMatch(TypeSig t1, TypeSig t2) - { - t1 = t1.RemovePinnedAndModifiers(); - t2 = t2.RemovePinnedAndModifiers(); - - if (t1.ElementType != t2.ElementType) - { - return IsVarType(t1) || IsVarType(t2); - } - - switch (t1.ElementType) - { - case ElementType.Void: - case ElementType.Boolean: - case ElementType.Char: - case ElementType.I1: - case ElementType.I2: - case ElementType.I4: - case ElementType.I8: - case ElementType.U1: - case ElementType.U2: - case ElementType.U4: - case ElementType.U8: - case ElementType.R4: - case ElementType.R8: - case ElementType.I: - case ElementType.U: - case ElementType.R: - case ElementType.String: - case ElementType.Object: - case ElementType.TypedByRef: - return true; - case ElementType.Class: - case ElementType.ValueType: - { - return t1.AssemblyQualifiedName == t2.AssemblyQualifiedName; - } - case ElementType.Ptr: - case ElementType.ByRef: - case ElementType.SZArray: - { - break; - } - case ElementType.Array: - { - var a1 = (ArraySig)t1; - var a2 = (ArraySig)t2; - if (a1.Rank != a2.Rank) - { - return false; - } - break; - } - case ElementType.Var: - case ElementType.MVar: - { - //var v1 = (GenericSig)t1; - //var v2 = (GenericSig)t2; - //return v1.Number == v2.Number; - return true; - } - default: return true; - } - if (t1.Next != null && t2.Next != null) - { - return IsLooseTypeSigMatch(t1.Next, t2.Next); - } - return true; - } - - private bool IsLooseMatch(MethodDef method1, MethodDef method2) - { - if (method1.Name != method2.Name) - { - return false; - } - if (method1.GetParamCount() != method2.GetParamCount()) - { - return false; - } - if (!IsLooseTypeSigMatch(method1.ReturnType, method2.ReturnType)) - { - return false; - } - for (int i = 0, n = method1.GetParamCount(); i < n; i++) - { - if (!IsLooseTypeSigMatch(method1.GetParam(i), method2.GetParam(i))) - { - return false; - } - } - - return true; - } - - public bool TryFindMatchVirtualMethod(MethodDef method, out MethodDef matchMethodDef) - { - foreach (var parentOrInterfaceMethod in flatMethods) - { - if (IsLooseMatch(method, parentOrInterfaceMethod)) - { - matchMethodDef = parentOrInterfaceMethod; - return true; - } - } - matchMethodDef = null; - return false; - } - } - - - private readonly Dictionary _methodGroups = new Dictionary(); - private readonly Dictionary _visitedTypes = new Dictionary(); - - - - public VirtualMethodGroup GetMethodGroup(MethodDef methodDef) - { - if (_methodGroups.TryGetValue(methodDef, out var group)) - { - return group; - } - return null; - } - - public void CalculateType(TypeDef typeDef) - { - if (_visitedTypes.ContainsKey(typeDef)) - { - return; - } - - var typeMethods = new TypeFlatMethods(); - - var interfaceMethods = new List(); - if (typeDef.BaseType != null) - { - TypeDef baseTypeDef = MetaUtil.GetTypeDefOrGenericTypeBaseThrowException(typeDef.BaseType); - CalculateType(baseTypeDef); - typeMethods.flatMethods.AddRange(_visitedTypes[baseTypeDef].flatMethods); - foreach (var intfType in typeDef.Interfaces) - { - TypeDef intfTypeDef = MetaUtil.GetTypeDefOrGenericTypeBaseThrowException(intfType.Interface); - CalculateType(intfTypeDef); - //typeMethods.flatMethods.AddRange(_visitedTypes[intfTypeDef].flatMethods); - interfaceMethods.AddRange(_visitedTypes[intfTypeDef].flatMethods); - } - } - foreach (MethodDef method in interfaceMethods) - { - if (typeMethods.TryFindMatchVirtualMethod(method, out var matchMethodDef)) - { - // merge group - var group = _methodGroups[matchMethodDef]; - var matchGroup = _methodGroups[method]; - if (group != matchGroup) - { - foreach (var m in matchGroup.methods) - { - group.methods.Add(m); - _methodGroups[m] = group; - } - } - } - typeMethods.flatMethods.Add(method); - } - - foreach (MethodDef method in typeDef.Methods) - { - if (!method.IsVirtual) - { - continue; - } - if (typeMethods.TryFindMatchVirtualMethod(method, out var matchMethodDef)) - { - var group = _methodGroups[matchMethodDef]; - group.methods.Add(method); - _methodGroups.Add(method, group); - } - else - { - _methodGroups.Add(method, new VirtualMethodGroup() { methods = new List { method } }); - } - if (method.IsNewSlot) - { - typeMethods.flatMethods.Add(method); - } - } - _visitedTypes.Add(typeDef, typeMethods); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/VirtualMethodGroupCalculator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/VirtualMethodGroupCalculator.cs.meta deleted file mode 100644 index 097106aa..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfusPasses/SymbolObfus/VirtualMethodGroupCalculator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 649aeb6306500a04f8b7a3e01f5aaf0d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationMethodWhitelist.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationMethodWhitelist.cs deleted file mode 100644 index 4fe07f3e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationMethodWhitelist.cs +++ /dev/null @@ -1,110 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Editor; -using Obfuz.Utils; -using System.Linq; -using UnityEngine; - -namespace Obfuz -{ - public class ObfuscationMethodWhitelist - { - private readonly ObfuzIgnoreScopeComputeCache _obfuzComputeCache; - private readonly BurstCompileComputeCache _burstCompileComputeCache; - - public ObfuscationMethodWhitelist(ObfuzIgnoreScopeComputeCache obfuzComputeCache, BurstCompileComputeCache burstCompileComputeCache) - { - _obfuzComputeCache = obfuzComputeCache; - _burstCompileComputeCache = burstCompileComputeCache; - } - - public bool IsInWhiteList(ModuleDef module) - { - string modName = module.Assembly.Name; - if (modName == ConstValues.ObfuzRuntimeAssemblyName) - { - return true; - } - //if (MetaUtil.HasObfuzIgnoreScope(module)) - //{ - // return true; - //} - return false; - } - - private bool DoesMethodContainsRuntimeInitializeOnLoadMethodAttributeAndLoadTypeGreaterEqualAfterAssembliesLoaded(MethodDef method) - { - CustomAttribute ca = method.CustomAttributes.Find(ConstValues.RuntimeInitializedOnLoadMethodAttributeFullName); - if (ca != null && ca.ConstructorArguments.Count > 0) - { - RuntimeInitializeLoadType loadType = (RuntimeInitializeLoadType)ca.ConstructorArguments[0].Value; - if (loadType >= RuntimeInitializeLoadType.AfterAssembliesLoaded) - { - return true; - } - } - return false; - } - - public bool IsInWhiteList(MethodDef method) - { - TypeDef typeDef = method.DeclaringType; - //if (IsInWhiteList(typeDef)) - //{ - // return true; - //} - if (method.Name.StartsWith(ConstValues.ObfuzInternalSymbolNamePrefix)) - { - return true; - } - if (_obfuzComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(method, typeDef, ObfuzScope.MethodBody)) - { - return true; - } - CustomAttribute ca = method.CustomAttributes.Find(ConstValues.RuntimeInitializedOnLoadMethodAttributeFullName); - if (DoesMethodContainsRuntimeInitializeOnLoadMethodAttributeAndLoadTypeGreaterEqualAfterAssembliesLoaded(method)) - { - return true; - } - if (method.CustomAttributes.Find(ConstValues.BurstCompileFullName) != null || _burstCompileComputeCache.IsBurstCompileMethodOrReferencedByBurstCompileMethod(method)) - { - return true; - } - - // don't obfuscate cctor when it has RuntimeInitializeOnLoadMethodAttribute with load type AfterAssembliesLoaded - if (method.IsStatic && method.Name == ".cctor" && typeDef.Methods.Any(m => DoesMethodContainsRuntimeInitializeOnLoadMethodAttributeAndLoadTypeGreaterEqualAfterAssembliesLoaded(m))) - { - return true; - } - return false; - } - - public bool IsInWhiteList(TypeDef type) - { - if (type.Name.StartsWith(ConstValues.ObfuzInternalSymbolNamePrefix)) - { - return true; - } - if (IsInWhiteList(type.Module)) - { - return true; - } - if (type.CustomAttributes.Find(ConstValues.BurstCompileFullName) != null) - { - return true; - } - if (_obfuzComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(type, type.DeclaringType, ObfuzScope.TypeName)) - { - return true; - } - //if (type.DeclaringType != null && IsInWhiteList(type.DeclaringType)) - //{ - // return true; - //} - if (type.FullName == ConstValues.GeneratedEncryptionVirtualMachineFullName) - { - return true; - } - return false; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationMethodWhitelist.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationMethodWhitelist.cs.meta deleted file mode 100644 index 0ef3bf32..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationMethodWhitelist.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8824d47fdc31cef41a899294491c8844 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationPassContext.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationPassContext.cs deleted file mode 100644 index 7f2f60f1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationPassContext.cs +++ /dev/null @@ -1,70 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz -{ - public delegate IRandom RandomCreator(int seed); - - public class EncryptionScopeInfo - { - public readonly IEncryptor encryptor; - public readonly RandomCreator localRandomCreator; - - public EncryptionScopeInfo(IEncryptor encryptor, RandomCreator localRandomCreator) - { - this.encryptor = encryptor; - this.localRandomCreator = localRandomCreator; - } - } - - public class EncryptionScopeProvider - { - private readonly EncryptionScopeInfo _defaultStaticScope; - private readonly EncryptionScopeInfo _defaultDynamicScope; - private readonly HashSet _dynamicSecretAssemblyNames; - - public EncryptionScopeProvider(EncryptionScopeInfo defaultStaticScope, EncryptionScopeInfo defaultDynamicScope, HashSet dynamicSecretAssemblyNames) - { - _defaultStaticScope = defaultStaticScope; - _defaultDynamicScope = defaultDynamicScope; - _dynamicSecretAssemblyNames = dynamicSecretAssemblyNames; - } - - public EncryptionScopeInfo GetScope(ModuleDef module) - { - if (_dynamicSecretAssemblyNames.Contains(module.Assembly.Name)) - { - return _defaultDynamicScope; - } - else - { - return _defaultStaticScope; - } - } - - public bool IsDynamicSecretAssembly(ModuleDef module) - { - return _dynamicSecretAssemblyNames.Contains(module.Assembly.Name); - } - } - - public class ObfuscationPassContext - { - public static ObfuscationPassContext Current { get; set; } - - public CoreSettingsFacade coreSettings; - - public GroupByModuleEntityManager moduleEntityManager; - - public AssemblyCache assemblyCache; - public List modulesToObfuscate; - public List allObfuscationRelativeModules; - public ObfuzIgnoreScopeComputeCache obfuzIgnoreScopeComputeCache; - - public ObfuscationMethodWhitelist whiteList; - public ConfigurablePassPolicy passPolicy; - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationPassContext.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationPassContext.cs.meta deleted file mode 100644 index 827ddc44..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscationPassContext.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 196d07f0366ce4b46bf0333fa4918d40 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuscator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuscator.cs deleted file mode 100644 index 95a5f83f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuscator.cs +++ /dev/null @@ -1,352 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.EncryptionVM; -using Obfuz.ObfusPasses.CleanUp; -using Obfuz.ObfusPasses.Instinct; -using Obfuz.ObfusPasses.SymbolObfus; -using Obfuz.Unity; -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEngine; - -namespace Obfuz -{ - - public class Obfuscator - { - private readonly CoreSettingsFacade _coreSettings; - private readonly List _allObfuscationRelativeAssemblyNames; - private readonly HashSet _assembliesUsingDynamicSecretKeys; - private readonly CombinedAssemblyResolver _assemblyResolver; - - private readonly ConfigurablePassPolicy _passPolicy; - - private readonly Pipeline _pipeline1 = new Pipeline(); - private readonly Pipeline _pipeline2 = new Pipeline(); - - private ObfuscationPassContext _ctx; - - public Obfuscator(ObfuscatorBuilder builder) - { - CheckSettings(builder.CoreSettingsFacade); - _coreSettings = builder.CoreSettingsFacade; - - _allObfuscationRelativeAssemblyNames = _coreSettings.assembliesToObfuscate - .Concat(_coreSettings.nonObfuscatedButReferencingObfuscatedAssemblies) - .ToList(); - _assembliesUsingDynamicSecretKeys = new HashSet(_coreSettings.assembliesUsingDynamicSecretKeys); - - _assemblyResolver = new CombinedAssemblyResolver(new PathAssemblyResolver(_coreSettings.assemblySearchPaths.ToArray()), new UnityProjectManagedAssemblyResolver(_coreSettings.buildTarget)); - _passPolicy = new ConfigurablePassPolicy(_coreSettings.assembliesToObfuscate, _coreSettings.enabledObfuscationPasses, _coreSettings.obfuscationPassRuleConfigFiles); - - _pipeline1.AddPass(new InstinctPass()); - foreach (var pass in _coreSettings.obfuscationPasses) - { - if (pass is SymbolObfusPass symbolObfusPass) - { - _pipeline2.AddPass(pass); - } - else - { - _pipeline1.AddPass(pass); - } - } - _pipeline1.AddPass(new CleanUpInstructionPass()); - _pipeline2.AddPass(new RemoveObfuzAttributesPass()); - } - - private void CheckSettings(CoreSettingsFacade settings) - { - var totalAssemblies = new HashSet(); - foreach (var assName in settings.assembliesToObfuscate) - { - if (string.IsNullOrWhiteSpace(assName)) - { - throw new Exception($"the name of some assembly in assembliesToObfuscate is empty! Please check your settings."); - } - if (!totalAssemblies.Add(assName)) - { - throw new Exception($"the name of assembly `{assName}` in assembliesToObfuscate is duplicated! Please check your settings."); - } - } - foreach (var assName in settings.nonObfuscatedButReferencingObfuscatedAssemblies) - { - if (string.IsNullOrWhiteSpace(assName)) - { - throw new Exception($"the name of some assembly in nonObfuscatedButReferencingObfuscatedAssemblies is empty! Please check your settings."); - } - if (!totalAssemblies.Add(assName)) - { - throw new Exception($"the name of assembly `{assName}` in nonObfuscatedButReferencingObfuscatedAssemblies is duplicated! Please check your settings."); - } - } - } - - public void Run() - { - Debug.Log($"Obfuscator begin"); - var sw = new System.Diagnostics.Stopwatch(); - sw.Start(); - FileUtil.RecreateDir(_coreSettings.obfuscatedAssemblyOutputPath); - FileUtil.RecreateDir(_coreSettings.obfuscatedAssemblyTempOutputPath); - RunPipeline(_pipeline1); - _assemblyResolver.InsertFirst(new PathAssemblyResolver(_coreSettings.obfuscatedAssemblyTempOutputPath)); - RunPipeline(_pipeline2); - FileUtil.CopyDir(_coreSettings.obfuscatedAssemblyTempOutputPath, _coreSettings.obfuscatedAssemblyOutputPath, true); - sw.Stop(); - Debug.Log($"Obfuscator end. cost time: {sw.ElapsedMilliseconds} ms"); - } - - private void RunPipeline(Pipeline pipeline) - { - if (pipeline.Empty) - { - return; - } - OnPreObfuscation(pipeline); - DoObfuscation(pipeline); - OnPostObfuscation(pipeline); - } - - private IEncryptor CreateEncryptionVirtualMachine(byte[] secretKey) - { - var vmCreator = new VirtualMachineCreator(_coreSettings.encryptionVmGenerationSecretKey); - var vm = vmCreator.CreateVirtualMachine(_coreSettings.encryptionVmOpCodeCount); - var vmGenerator = new VirtualMachineCodeGenerator(vm); - - string encryptionVmCodeFile = _coreSettings.encryptionVmCodeFile; - if (!File.Exists(encryptionVmCodeFile)) - { - throw new Exception($"EncryptionVm CodeFile:`{encryptionVmCodeFile}` not exists! Please run `Obfuz/GenerateVm` to generate it!"); - } - if (!vmGenerator.ValidateMatch(encryptionVmCodeFile)) - { - throw new Exception($"EncryptionVm CodeFile:`{encryptionVmCodeFile}` not match with encryptionVM settings! Please run `Obfuz/GenerateVm` to update it!"); - } - var vms = new VirtualMachineSimulator(vm, secretKey); - - var generatedVmTypes = ReflectionUtil.FindTypesInCurrentAppDomain("Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine"); - if (generatedVmTypes.Count == 0) - { - throw new Exception($"class Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine not found in any assembly! Please run `Obfuz/GenerateVm` to generate it!"); - } - if (generatedVmTypes.Count > 1) - { - throw new Exception($"class Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine found in multiple assemblies! Please retain only one!"); - } - - var gvmInstance = (IEncryptor)Activator.CreateInstance(generatedVmTypes[0], new object[] { secretKey }); - - VerifyVm(vm, vms, gvmInstance); - - return vms; - } - - private void VerifyVm(VirtualMachine vm, VirtualMachineSimulator vms, IEncryptor gvm) - { - int testInt = 11223344; - long testLong = 1122334455667788L; - float testFloat = 1234f; - double testDouble = 1122334455.0; - string testString = "hello,world"; - for (int i = 0; i < vm.opCodes.Length; i++) - { - int ops = i * vm.opCodes.Length + i; - //int salt = i; - //int ops = -1135538782; - int salt = -879409147; - { - int encryptedIntOfVms = vms.Encrypt(testInt, ops, salt); - int decryptedIntOfVms = vms.Decrypt(encryptedIntOfVms, ops, salt); - if (decryptedIntOfVms != testInt) - { - throw new Exception($"VirtualMachineSimulator decrypt failed! opCode:{i}, originalValue:{testInt} decryptedValue:{decryptedIntOfVms}"); - } - int encryptedValueOfGvm = gvm.Encrypt(testInt, ops, salt); - int decryptedValueOfGvm = gvm.Decrypt(encryptedValueOfGvm, ops, salt); - if (encryptedValueOfGvm != encryptedIntOfVms) - { - throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testInt} encryptedValue VirtualMachineSimulator:{encryptedIntOfVms} GeneratedEncryptionVirtualMachine:{encryptedValueOfGvm}"); - } - if (decryptedValueOfGvm != testInt) - { - throw new Exception($"GeneratedEncryptionVirtualMachine decrypt failed! opCode:{i}, originalValue:{testInt} decryptedValue:{decryptedValueOfGvm}"); - } - } - { - long encryptedLongOfVms = vms.Encrypt(testLong, ops, salt); - long decryptedLongOfVms = vms.Decrypt(encryptedLongOfVms, ops, salt); - if (decryptedLongOfVms != testLong) - { - throw new Exception($"VirtualMachineSimulator decrypt long failed! opCode:{i}, originalValue:{testLong} decryptedValue:{decryptedLongOfVms}"); - } - long encryptedValueOfGvm = gvm.Encrypt(testLong, ops, salt); - long decryptedValueOfGvm = gvm.Decrypt(encryptedValueOfGvm, ops, salt); - if (encryptedValueOfGvm != encryptedLongOfVms) - { - throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testLong} encryptedValue VirtualMachineSimulator:{encryptedLongOfVms} GeneratedEncryptionVirtualMachine:{encryptedValueOfGvm}"); - } - if (decryptedValueOfGvm != testLong) - { - throw new Exception($"GeneratedEncryptionVirtualMachine decrypt long failed! opCode:{i}, originalValue:{testLong} decryptedValue:{decryptedValueOfGvm}"); - } - } - { - float encryptedFloatOfVms = vms.Encrypt(testFloat, ops, salt); - float decryptedFloatOfVms = vms.Decrypt(encryptedFloatOfVms, ops, salt); - if (decryptedFloatOfVms != testFloat) - { - throw new Exception("encryptedFloat not match"); - } - float encryptedValueOfGvm = gvm.Encrypt(testFloat, ops, salt); - float decryptedValueOfGvm = gvm.Decrypt(encryptedFloatOfVms, ops, salt); - if (encryptedFloatOfVms != encryptedValueOfGvm) - { - throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testFloat} encryptedValue"); - } - if (decryptedValueOfGvm != testFloat) - { - throw new Exception($"GeneratedEncryptionVirtualMachine decrypt float failed! opCode:{i}, originalValue:{testFloat}"); - } - } - { - double encryptedFloatOfVms = vms.Encrypt(testDouble, ops, salt); - double decryptedFloatOfVms = vms.Decrypt(encryptedFloatOfVms, ops, salt); - if (decryptedFloatOfVms != testDouble) - { - throw new Exception("encryptedFloat not match"); - } - double encryptedValueOfGvm = gvm.Encrypt(testDouble, ops, salt); - double decryptedValueOfGvm = gvm.Decrypt(encryptedFloatOfVms, ops, salt); - if (encryptedFloatOfVms != encryptedValueOfGvm) - { - throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testDouble} encryptedValue"); - } - if (decryptedValueOfGvm != testDouble) - { - throw new Exception($"GeneratedEncryptionVirtualMachine decrypt float failed! opCode:{i}, originalValue:{testDouble}"); - } - } - - { - byte[] encryptedStrOfVms = vms.Encrypt(testString, ops, salt); - string decryptedStrOfVms = vms.DecryptString(encryptedStrOfVms, 0, encryptedStrOfVms.Length, ops, salt); - if (decryptedStrOfVms != testString) - { - throw new Exception($"VirtualMachineSimulator decrypt string failed! opCode:{i}, originalValue:{testString} decryptedValue:{decryptedStrOfVms}"); - } - byte[] encryptedStrOfGvm = gvm.Encrypt(testString, ops, salt); - string decryptedStrOfGvm = gvm.DecryptString(encryptedStrOfGvm, 0, encryptedStrOfGvm.Length, ops, salt); - if (!encryptedStrOfGvm.SequenceEqual(encryptedStrOfVms)) - { - throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testString} encryptedValue VirtualMachineSimulator:{encryptedStrOfVms} GeneratedEncryptionVirtualMachine:{encryptedStrOfGvm}"); - } - if (decryptedStrOfGvm != testString) - { - throw new Exception($"GeneratedEncryptionVirtualMachine decrypt string failed! opCode:{i}, originalValue:{testString} decryptedValue:{decryptedStrOfGvm}"); - } - } - } - } - - private EncryptionScopeInfo CreateEncryptionScope(byte[] byteSecret) - { - int[] intSecretKey = KeyGenerator.ConvertToIntKey(byteSecret); - IEncryptor encryption = CreateEncryptionVirtualMachine(byteSecret); - RandomCreator localRandomCreator = (seed) => new RandomWithKey(intSecretKey, _coreSettings.randomSeed ^ seed); - return new EncryptionScopeInfo(encryption, localRandomCreator); - } - - private EncryptionScopeProvider CreateEncryptionScopeProvider() - { - var defaultStaticScope = CreateEncryptionScope(_coreSettings.defaultStaticSecretKey); - var defaultDynamicScope = CreateEncryptionScope(_coreSettings.defaultDynamicSecretKey); - foreach (string dynamicAssName in _assembliesUsingDynamicSecretKeys) - { - if (!_coreSettings.assembliesToObfuscate.Contains(dynamicAssName)) - { - throw new Exception($"Dynamic secret assembly `{dynamicAssName}` should be in the assembliesToObfuscate list!"); - } - } - return new EncryptionScopeProvider(defaultStaticScope, defaultDynamicScope, _assembliesUsingDynamicSecretKeys); - } - - private void OnPreObfuscation(Pipeline pipeline) - { - AssemblyCache assemblyCache = new AssemblyCache(_assemblyResolver); - List modulesToObfuscate = new List(); - List allObfuscationRelativeModules = new List(); - LoadAssemblies(assemblyCache, modulesToObfuscate, allObfuscationRelativeModules); - - EncryptionScopeProvider encryptionScopeProvider = CreateEncryptionScopeProvider(); - var moduleEntityManager = new GroupByModuleEntityManager() - { - EncryptionScopeProvider = encryptionScopeProvider, - }; - var obfuzIgnoreScopeComputeCache = new ObfuzIgnoreScopeComputeCache(); - _ctx = new ObfuscationPassContext - { - coreSettings = _coreSettings, - assemblyCache = assemblyCache, - modulesToObfuscate = modulesToObfuscate, - allObfuscationRelativeModules = allObfuscationRelativeModules, - - moduleEntityManager = moduleEntityManager, - - obfuzIgnoreScopeComputeCache = obfuzIgnoreScopeComputeCache, - - whiteList = new ObfuscationMethodWhitelist(obfuzIgnoreScopeComputeCache, new BurstCompileComputeCache(modulesToObfuscate, allObfuscationRelativeModules)), - passPolicy = _passPolicy, - }; - ObfuscationPassContext.Current = _ctx; - pipeline.Start(); - } - - private void LoadAssemblies(AssemblyCache assemblyCache, List modulesToObfuscate, List allObfuscationRelativeModules) - { - foreach (string assName in _allObfuscationRelativeAssemblyNames) - { - ModuleDefMD mod = assemblyCache.TryLoadModule(assName); - if (mod == null) - { - Debug.Log($"assembly: {assName} not found! ignore."); - continue; - } - if (_coreSettings.assembliesToObfuscate.Contains(assName)) - { - modulesToObfuscate.Add(mod); - } - allObfuscationRelativeModules.Add(mod); - } - } - - private void WriteAssemblies() - { - foreach (ModuleDef mod in _ctx.allObfuscationRelativeModules) - { - string assNameWithExt = mod.Name; - string outputFile = $"{_coreSettings.obfuscatedAssemblyTempOutputPath}/{assNameWithExt}"; - mod.Write(outputFile); - Debug.Log($"save module. name:{mod.Assembly.Name} output:{outputFile}"); - } - } - - private void DoObfuscation(Pipeline pipeline) - { - pipeline.Run(); - } - - private void OnPostObfuscation(Pipeline pipeline) - { - pipeline.Stop(); - - _ctx.moduleEntityManager.Done(); - _ctx.moduleEntityManager.Done(); - WriteAssemblies(); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuscator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuscator.cs.meta deleted file mode 100644 index 08291f34..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuscator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ca9c4e108bde2184885e599f2bd19a00 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscatorBuilder.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscatorBuilder.cs deleted file mode 100644 index 35e29ee7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscatorBuilder.cs +++ /dev/null @@ -1,207 +0,0 @@ -using Obfuz.EncryptionVM; -using Obfuz.ObfusPasses; -using Obfuz.ObfusPasses.CallObfus; -using Obfuz.ObfusPasses.ConstEncrypt; -using Obfuz.ObfusPasses.ControlFlowObfus; -using Obfuz.ObfusPasses.EvalStackObfus; -using Obfuz.ObfusPasses.ExprObfus; -using Obfuz.ObfusPasses.FieldEncrypt; -using Obfuz.ObfusPasses.SymbolObfus; -using Obfuz.Settings; -using Obfuz.Utils; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditor; - -namespace Obfuz -{ - - public class CoreSettingsFacade - { - public BuildTarget buildTarget; - - public byte[] defaultStaticSecretKey; - public byte[] defaultDynamicSecretKey; - public List assembliesUsingDynamicSecretKeys; - public int randomSeed; - - public string encryptionVmGenerationSecretKey; - public int encryptionVmOpCodeCount; - public string encryptionVmCodeFile; - - public List assembliesToObfuscate; - public List nonObfuscatedButReferencingObfuscatedAssemblies; - public List assemblySearchPaths; - public string obfuscatedAssemblyOutputPath; - public string obfuscatedAssemblyTempOutputPath; - - public ObfuscationPassType enabledObfuscationPasses; - public List obfuscationPassRuleConfigFiles; - public List obfuscationPasses; - } - - public class ObfuscatorBuilder - { - private CoreSettingsFacade _coreSettingsFacade; - - public CoreSettingsFacade CoreSettingsFacade => _coreSettingsFacade; - - public void InsertTopPriorityAssemblySearchPaths(List assemblySearchPaths) - { - _coreSettingsFacade.assemblySearchPaths.InsertRange(0, assemblySearchPaths); - } - - public ObfuscatorBuilder AddPass(IObfuscationPass pass) - { - _coreSettingsFacade.obfuscationPasses.Add(pass); - return this; - } - - public Obfuscator Build() - { - return new Obfuscator(this); - } - - public static List BuildUnityAssemblySearchPaths(bool searchPathIncludeUnityEditorDll = false) - { - string applicationContentsPath = EditorApplication.applicationContentsPath; - var searchPaths = new List - { -#if UNITY_2021_1_OR_NEWER -#if UNITY_STANDALONE_WIN || (UNITY_EDITOR_WIN && UNITY_SERVER) || UNITY_WSA || UNITY_LUMIN - "MonoBleedingEdge/lib/mono/unityaot-win32", - "MonoBleedingEdge/lib/mono/unityaot-win32/Facades", -#elif UNITY_STANDALONE_OSX || (UNITY_EDITOR_OSX && UNITY_SERVER) || UNITY_IOS || UNITY_TVOS - "MonoBleedingEdge/lib/mono/unityaot-macos", - "MonoBleedingEdge/lib/mono/unityaot-macos/Facades", -#else - "MonoBleedingEdge/lib/mono/unityaot-linux", - "MonoBleedingEdge/lib/mono/unityaot-linux/Facades", -#endif -#else - "MonoBleedingEdge/lib/mono/unityaot", - "MonoBleedingEdge/lib/mono/unityaot/Facades", -#endif - -#if UNITY_STANDALONE_WIN || (UNITY_EDITOR_WIN && UNITY_SERVER) - "PlaybackEngines/windowsstandalonesupport/Variations/il2cpp/Managed", -#elif UNITY_STANDALONE_OSX || (UNITY_EDITOR_OSX && UNITY_SERVER) - "PlaybackEngines/MacStandaloneSupport/Variations/il2cpp/Managed", -#elif UNITY_STANDALONE_LINUX || (UNITY_EDITOR_LINUX && UNITY_SERVER) - "PlaybackEngines/LinuxStandaloneSupport/Variations/il2cpp/Managed", -#elif UNITY_ANDROID - "PlaybackEngines/AndroidPlayer/Variations/il2cpp/Managed", -#elif UNITY_IOS - "PlaybackEngines/iOSSupport/Variations/il2cpp/Managed", -#elif UNITY_MINIGAME || UNITY_WEIXINMINIGAME -#if TUANJIE_1_1_OR_NEWER - "PlaybackEngines/WeixinMiniGameSupport/Variations/il2cpp/nondevelopment/Data/Managed", -#else - "PlaybackEngines/WeixinMiniGameSupport/Variations/nondevelopment/Data/Managed", -#endif -#elif UNITY_OPENHARMONY - "PlaybackEngines/OpenHarmonyPlayer/Variations/il2cpp/Managed", -#elif UNITY_WEBGL - "PlaybackEngines/WebGLSupport/Variations/nondevelopment/Data/Managed", -#elif UNITY_TVOS - "PlaybackEngines/AppleTVSupport/Variations/il2cpp/Managed", -#elif UNITY_WSA - "PlaybackEngines/WSASupport/Variations/il2cpp/Managed", -#elif UNITY_LUMIN - "PlaybackEngines/LuminSupport/Variations/il2cpp/Managed", -#else -#error "Unsupported platform, please report to us" -#endif - }; - - if (searchPathIncludeUnityEditorDll) - { - searchPaths.Add("Managed/UnityEngine"); - } - - var resultPaths = new List(); - foreach (var path in searchPaths) - { - string candidatePath1 = Path.Combine(applicationContentsPath, path); - if (Directory.Exists(candidatePath1)) - { - resultPaths.Add(candidatePath1); - } - if (path.StartsWith("PlaybackEngines")) - { - string candidatePath2 = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(applicationContentsPath)), path); - if (Directory.Exists(candidatePath2)) - { - resultPaths.Add(candidatePath2); - } - } - } - return resultPaths; - } - - public static ObfuscatorBuilder FromObfuzSettings(ObfuzSettings settings, BuildTarget target, bool searchPathIncludeUnityEditorInstallLocation, bool searchPathIncludeUnityEditorDll = false) - { - List searchPaths = searchPathIncludeUnityEditorInstallLocation ? - BuildUnityAssemblySearchPaths(searchPathIncludeUnityEditorDll).Concat(settings.assemblySettings.additionalAssemblySearchPaths).ToList() - : settings.assemblySettings.additionalAssemblySearchPaths.ToList(); - foreach (var path in searchPaths) - { - bool exists = Directory.Exists(path); - UnityEngine.Debug.Log($"search path:{path} exists:{exists}"); - } - var builder = new ObfuscatorBuilder - { - _coreSettingsFacade = new CoreSettingsFacade() - { - buildTarget = target, - defaultStaticSecretKey = KeyGenerator.GenerateKey(settings.secretSettings.defaultStaticSecretKey, VirtualMachine.SecretKeyLength), - defaultDynamicSecretKey = KeyGenerator.GenerateKey(settings.secretSettings.defaultDynamicSecretKey, VirtualMachine.SecretKeyLength), - assembliesUsingDynamicSecretKeys = settings.secretSettings.assembliesUsingDynamicSecretKeys.ToList(), - randomSeed = settings.secretSettings.randomSeed, - encryptionVmGenerationSecretKey = settings.encryptionVMSettings.codeGenerationSecretKey, - encryptionVmOpCodeCount = settings.encryptionVMSettings.encryptionOpCodeCount, - encryptionVmCodeFile = settings.encryptionVMSettings.codeOutputPath, - assembliesToObfuscate = settings.assemblySettings.GetAssembliesToObfuscate(), - nonObfuscatedButReferencingObfuscatedAssemblies = settings.assemblySettings.nonObfuscatedButReferencingObfuscatedAssemblies.ToList(), - assemblySearchPaths = searchPaths, - obfuscatedAssemblyOutputPath = settings.GetObfuscatedAssemblyOutputPath(target), - obfuscatedAssemblyTempOutputPath = settings.GetObfuscatedAssemblyTempOutputPath(target), - enabledObfuscationPasses = settings.obfuscationPassSettings.enabledPasses, - obfuscationPassRuleConfigFiles = settings.obfuscationPassSettings.ruleFiles?.ToList() ?? new List(), - obfuscationPasses = new List(), - }, - }; - ObfuscationPassType obfuscationPasses = settings.obfuscationPassSettings.enabledPasses; - if (obfuscationPasses.HasFlag(ObfuscationPassType.ConstEncrypt)) - { - builder.AddPass(new ConstEncryptPass(settings.constEncryptSettings.ToFacade())); - } - if (obfuscationPasses.HasFlag(ObfuscationPassType.ExprObfus)) - { - builder.AddPass(new ExprObfusPass(settings.exprObfusSettings.ToFacade())); - } - if (obfuscationPasses.HasFlag(ObfuscationPassType.EvalStackObfus)) - { - builder.AddPass(new EvalStackObfusPass(settings.evalStackObfusSettings.ToFacade())); - } - if (obfuscationPasses.HasFlag(ObfuscationPassType.FieldEncrypt)) - { - builder.AddPass(new FieldEncryptPass(settings.fieldEncryptSettings.ToFacade())); - } - if (obfuscationPasses.HasFlag(ObfuscationPassType.CallObfus)) - { - builder.AddPass(new CallObfusPass(settings.callObfusSettings.ToFacade())); - } - if (obfuscationPasses.HasFlag(ObfuscationPassType.ControlFlowObfus)) - { - builder.AddPass(new ControlFlowObfusPass(settings.controlFlowObfusSettings.ToFacade())); - } - if (obfuscationPasses.HasFlag(ObfuscationPassType.SymbolObfus)) - { - builder.AddPass(new SymbolObfusPass(settings.symbolObfusSettings.ToFacade())); - } - return builder; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscatorBuilder.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscatorBuilder.cs.meta deleted file mode 100644 index 261993be..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/ObfuscatorBuilder.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 77e279242d764ed4d996db96f35e8570 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuz.Editor.asmdef b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuz.Editor.asmdef deleted file mode 100644 index e1b3933b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuz.Editor.asmdef +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "Obfuz.Editor", - "rootNamespace": "", - "references": [ - "GUID:4140bd2e2764f1f47ab93125ecb61942" - ], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": true, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} \ No newline at end of file diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuz.Editor.asmdef.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuz.Editor.asmdef.meta deleted file mode 100644 index d010c098..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Obfuz.Editor.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 66e09fc524ec6594b8d6ca1d91aa1a41 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Pipeline.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Pipeline.cs deleted file mode 100644 index e0869b41..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Pipeline.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics; - -namespace Obfuz -{ - public class Pipeline - { - private readonly List _passes = new List(); - - public bool Empty => _passes.Count == 0; - - public Pipeline AddPass(IObfuscationPass pass) - { - _passes.Add(pass); - return this; - } - - public void Start() - { - foreach (var pass in _passes) - { - pass.Start(); - } - } - - public void Stop() - { - - foreach (var pass in _passes) - { - pass.Stop(); - } - } - - public void Run() - { - var sw = new Stopwatch(); - foreach (var pass in _passes) - { - sw.Restart(); - pass.Process(); - sw.Stop(); - UnityEngine.Debug.Log($"Pass: {pass.GetType().Name} process cost time: {sw.ElapsedMilliseconds}ms"); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Pipeline.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Pipeline.cs.meta deleted file mode 100644 index fd3558ce..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Pipeline.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0915452219e923d428b9a408cf413844 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings.meta deleted file mode 100644 index 64d3c0a6..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 4939d1f80df50b34c85ffc8fbe530887 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/AssemblySettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/AssemblySettings.cs deleted file mode 100644 index 97923519..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/AssemblySettings.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Obfuz.Editor; -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Obfuz.Settings -{ - [Serializable] - public class AssemblySettings - { - - [Tooltip("name of assemblies to obfuscate, please don't add 'Obfuz.Runtime'")] - public string[] assembliesToObfuscate; - - [Tooltip("name of assemblies not obfuscated but reference assemblies to obfuscated ")] - public string[] nonObfuscatedButReferencingObfuscatedAssemblies; - - [Tooltip("additional assembly search paths")] - public string[] additionalAssemblySearchPaths; - - [Tooltip("obfuscate Obfuz.Runtime")] - public bool obfuscateObfuzRuntime = true; - - public List GetAssembliesToObfuscate() - { - var asses = new List(assembliesToObfuscate ?? Array.Empty()); - if (obfuscateObfuzRuntime && !asses.Contains(ConstValues.ObfuzRuntimeAssemblyName)) - { - asses.Add(ConstValues.ObfuzRuntimeAssemblyName); - } - return asses; - } - - public List GetObfuscationRelativeAssemblyNames() - { - var asses = GetAssembliesToObfuscate(); - asses.AddRange(nonObfuscatedButReferencingObfuscatedAssemblies ?? Array.Empty()); - return asses; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/AssemblySettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/AssemblySettings.cs.meta deleted file mode 100644 index 8a139403..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/AssemblySettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 735c01fddc6f0c54a83e1feb9a60e13a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/BuildPipelineSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/BuildPipelineSettings.cs deleted file mode 100644 index 8d167fad..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/BuildPipelineSettings.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using UnityEngine; - -namespace Obfuz.Settings -{ - [Serializable] - public class BuildPipelineSettings - { - [Tooltip("enable Obfuz")] - public bool enable = true; - - [Tooltip("callback order of LinkXmlProcessor")] - public int linkXmlProcessCallbackOrder = 10000; - - [Tooltip("callback order of ObfuscationProcess")] - public int obfuscationProcessCallbackOrder = 10000; - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/BuildPipelineSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/BuildPipelineSettings.cs.meta deleted file mode 100644 index 64ce1ddb..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/BuildPipelineSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 68737b215ecfe344a93d56007e186432 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/CallObfuscationSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/CallObfuscationSettings.cs deleted file mode 100644 index a7ee139a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/CallObfuscationSettings.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace Obfuz.Settings -{ - public enum ProxyMode - { - Dispatch, - Delegate, - } - - public class CallObfuscationSettingsFacade - { - public ProxyMode proxyMode; - public int obfuscationLevel; - public int maxProxyMethodCountPerDispatchMethod; - public bool obfuscateCallToMethodInMscorlib; - public List ruleFiles; - } - - [Serializable] - public class CallObfuscationSettings - { - public ProxyMode proxyMode = ProxyMode.Dispatch; - - [Tooltip("The obfuscation level for the obfuscation. Higher levels provide more security but may impact performance.")] - [Range(1, 4)] - public int obfuscationLevel = 1; - - [Tooltip("The maximum number of proxy methods that can be generated per dispatch method. This helps to limit the complexity of the generated code and improve performance.")] - public int maxProxyMethodCountPerDispatchMethod = 100; - - [Tooltip("Whether to obfuscate calls to methods in mscorlib. Enable this option will impact performance.")] - public bool obfuscateCallToMethodInMscorlib; - - [Tooltip("rule config xml files")] - public string[] ruleFiles; - - public CallObfuscationSettingsFacade ToFacade() - { - return new CallObfuscationSettingsFacade - { - proxyMode = proxyMode, - obfuscationLevel = obfuscationLevel, - maxProxyMethodCountPerDispatchMethod = maxProxyMethodCountPerDispatchMethod, - obfuscateCallToMethodInMscorlib = obfuscateCallToMethodInMscorlib, - ruleFiles = ruleFiles?.ToList() ?? new List(), - }; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/CallObfuscationSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/CallObfuscationSettings.cs.meta deleted file mode 100644 index ce268f1e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/CallObfuscationSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ae4ddc19ecf8d9940b444f5b66c23efa -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ConstEncryptionSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ConstEncryptionSettings.cs deleted file mode 100644 index 6baffbc1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ConstEncryptionSettings.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace Obfuz.Settings -{ - public class ConstEncryptionSettingsFacade - { - public int encryptionLevel; - public List ruleFiles; - } - - [Serializable] - public class ConstEncryptionSettings - { - [Tooltip("The encryption level for the obfuscation. Higher levels provide more security but may impact performance.")] - [Range(1, 4)] - public int encryptionLevel = 1; - - [Tooltip("config xml files")] - public string[] ruleFiles; - - public ConstEncryptionSettingsFacade ToFacade() - { - return new ConstEncryptionSettingsFacade - { - ruleFiles = ruleFiles?.ToList() ?? new List(), - encryptionLevel = encryptionLevel, - }; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ConstEncryptionSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ConstEncryptionSettings.cs.meta deleted file mode 100644 index d5cef401..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ConstEncryptionSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2b189f76d7da58e4b9403b4fe87265b4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ControlFlowObfuscationSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ControlFlowObfuscationSettings.cs deleted file mode 100644 index 67474b1b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ControlFlowObfuscationSettings.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Obfuz.Settings -{ - - public class ControlFlowObfuscationSettingsFacade - { - public int minInstructionCountOfBasicBlockToObfuscate; - public List ruleFiles; - } - - [Serializable] - public class ControlFlowObfuscationSettings - { - public int minInstructionCountOfBasicBlockToObfuscate = 3; - - [Tooltip("rule config xml files")] - public string[] ruleFiles; - - public ControlFlowObfuscationSettingsFacade ToFacade() - { - return new ControlFlowObfuscationSettingsFacade - { - minInstructionCountOfBasicBlockToObfuscate = minInstructionCountOfBasicBlockToObfuscate, - ruleFiles = new List(ruleFiles ?? Array.Empty()), - }; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ControlFlowObfuscationSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ControlFlowObfuscationSettings.cs.meta deleted file mode 100644 index 8d8b0f28..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ControlFlowObfuscationSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d40d2fb33f081b2458505c7566b1bc8f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EncryptionVMSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EncryptionVMSettings.cs deleted file mode 100644 index 50159587..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EncryptionVMSettings.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using UnityEngine; - -namespace Obfuz.Settings -{ - [Serializable] - public class EncryptionVMSettings - { - [Tooltip("secret key for generating encryption virtual machine source code")] - public string codeGenerationSecretKey = "Obfuz"; - - [Tooltip("encryption OpCode count, should be power of 2 and >= 64")] - public int encryptionOpCodeCount = 256; - - [Tooltip("encryption virtual machine source code output path")] - public string codeOutputPath = "Assets/Obfuz/GeneratedEncryptionVirtualMachine.cs"; - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EncryptionVMSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EncryptionVMSettings.cs.meta deleted file mode 100644 index 0257381b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EncryptionVMSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f0e626d510710c540bdc36b4dca93340 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EvalStackObfuscationSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EvalStackObfuscationSettings.cs deleted file mode 100644 index b880f534..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EvalStackObfuscationSettings.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Obfuz.Settings -{ - - public class EvalStackObfuscationSettingsFacade - { - public List ruleFiles; - } - - [Serializable] - public class EvalStackObfuscationSettings - { - [Tooltip("rule config xml files")] - public string[] ruleFiles; - - public EvalStackObfuscationSettingsFacade ToFacade() - { - return new EvalStackObfuscationSettingsFacade - { - ruleFiles = new List(ruleFiles ?? Array.Empty()), - }; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EvalStackObfuscationSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EvalStackObfuscationSettings.cs.meta deleted file mode 100644 index 8e4d8d59..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/EvalStackObfuscationSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3c985896b3a4ef84292cb0cfbc79dc10 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ExprObfuscationSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ExprObfuscationSettings.cs deleted file mode 100644 index c4d0f750..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ExprObfuscationSettings.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Obfuz.Settings -{ - - public class ExprObfuscationSettingsFacade - { - public List ruleFiles; - } - - [Serializable] - public class ExprObfuscationSettings - { - [Tooltip("rule config xml files")] - public string[] ruleFiles; - - public ExprObfuscationSettingsFacade ToFacade() - { - return new ExprObfuscationSettingsFacade - { - ruleFiles = new List(ruleFiles ?? Array.Empty()), - }; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ExprObfuscationSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ExprObfuscationSettings.cs.meta deleted file mode 100644 index 55fb66c9..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ExprObfuscationSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d63d19f2b1a9f7c4b9812577d215c367 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/FieldEncryptionSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/FieldEncryptionSettings.cs deleted file mode 100644 index 460eca1d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/FieldEncryptionSettings.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace Obfuz.Settings -{ - public class FieldEncryptionSettingsFacade - { - public int encryptionLevel; - public List ruleFiles; - } - - [Serializable] - public class FieldEncryptionSettings - { - [Tooltip("The encryption level for the obfuscation. Higher levels provide more security but may impact performance.")] - [Range(1, 4)] - public int encryptionLevel = 1; - - [Tooltip("rule config xml files")] - public string[] ruleFiles; - - public FieldEncryptionSettingsFacade ToFacade() - { - return new FieldEncryptionSettingsFacade - { - ruleFiles = ruleFiles?.ToList() ?? new List(), - encryptionLevel = encryptionLevel, - }; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/FieldEncryptionSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/FieldEncryptionSettings.cs.meta deleted file mode 100644 index fbc0e2ed..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/FieldEncryptionSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 56cff1f5683d9114e8f13cee917ea582 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/GarbageCodeGenerationSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/GarbageCodeGenerationSettings.cs deleted file mode 100644 index b17748f1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/GarbageCodeGenerationSettings.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; - -namespace Obfuz.Settings -{ - public enum GarbageCodeType - { - None, - Config, - UI, - } - - [Serializable] - public class GarbageCodeGenerationTask - { - public int codeGenerationRandomSeed; - - public string classNamespace = "__GarbageCode"; - - public string classNamePrefix = "__GeneratedGarbageClass"; - - public int classCount = 100; - - public int methodCountPerClass = 10; - - public int fieldCountPerClass = 50; - - public GarbageCodeType garbageCodeType = GarbageCodeType.Config; - - public string outputPath = "Assets/Obfuz/GarbageCode"; - } - - [Serializable] - public class GarbageCodeGenerationSettings - { - public string codeGenerationSecret = "Garbage Code"; - - public GarbageCodeGenerationTask defaultTask; - - public GarbageCodeGenerationTask[] additionalTasks; - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/GarbageCodeGenerationSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/GarbageCodeGenerationSettings.cs.meta deleted file mode 100644 index 326444eb..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/GarbageCodeGenerationSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 220b44e477cfa2848bd287c38db4fd21 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationLevel.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationLevel.cs deleted file mode 100644 index b3f57020..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationLevel.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Obfuz.Settings -{ - public enum ObfuscationLevel - { - None = 0, - Basic = 1, - Advanced = 2, - MostAdvanced = 3 - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationLevel.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationLevel.cs.meta deleted file mode 100644 index c6567f4e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationLevel.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dd8e1281c6c9bcd419fecc67980cb673 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationPassSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationPassSettings.cs deleted file mode 100644 index 837c8b0c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationPassSettings.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Obfuz.ObfusPasses; -using System; -using UnityEngine; - -namespace Obfuz.Settings -{ - [Serializable] - public class ObfuscationPassSettings - { - [Tooltip("enable obfuscation pass")] - public ObfuscationPassType enabledPasses = ObfuscationPassType.All; - - [Tooltip("rule config xml files")] - public string[] ruleFiles; - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationPassSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationPassSettings.cs.meta deleted file mode 100644 index 147fed67..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuscationPassSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9cb41a6fb7293ce47807e432d80f2b2a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs deleted file mode 100644 index 19fbe3cb..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System.IO; -using UnityEditor; -using UnityEditorInternal; -using UnityEngine; - -namespace Obfuz.Settings -{ - - public class ObfuzSettings : ScriptableObject - { - [Tooltip("build pipeline settings")] - public BuildPipelineSettings buildPipelineSettings; - - [Tooltip("assembly settings")] - public AssemblySettings assemblySettings; - - [Tooltip("obfuscation pass settings")] - public ObfuscationPassSettings obfuscationPassSettings; - - [Tooltip("secret settings")] - public SecretSettings secretSettings; - - [Tooltip("encryption virtual machine settings")] - public EncryptionVMSettings encryptionVMSettings; - - [Tooltip("symbol obfuscation settings")] - public SymbolObfuscationSettings symbolObfusSettings; - - [Tooltip("const encryption settings")] - public ConstEncryptionSettings constEncryptSettings; - - [Tooltip("eval stack obfuscation settings")] - public EvalStackObfuscationSettings evalStackObfusSettings; - - [Tooltip("field encryption settings")] - public FieldEncryptionSettings fieldEncryptSettings; - - [Tooltip("call obfuscation settings")] - public CallObfuscationSettings callObfusSettings; - - [Tooltip("expression obfuscation settings")] - public ExprObfuscationSettings exprObfusSettings; - - [Tooltip("control flow obfuscation settings")] - public ControlFlowObfuscationSettings controlFlowObfusSettings; - - [Tooltip("garbage code generator settings")] - public GarbageCodeGenerationSettings garbageCodeGenerationSettings; - - [Tooltip("polymorphic dll settings")] - public PolymorphicDllSettings polymorphicDllSettings; - - public string ObfuzRootDir => $"Library/Obfuz"; - - public string GetObfuscatedAssemblyOutputPath(BuildTarget target) - { - return $"{ObfuzRootDir}/{target}/ObfuscatedAssemblies"; - } - - public string GetOriginalAssemblyBackupDir(BuildTarget target) - { - return $"{ObfuzRootDir}/{target}/OriginalAssemblies"; - } - - public string GetObfuscatedAssemblyTempOutputPath(BuildTarget target) - { - return $"{ObfuzRootDir}/{target}/TempObfuscatedAssemblies"; - } - - public string GetObfuscatedLinkXmlPath(BuildTarget target) - { - return $"{ObfuzRootDir}/{target}/link.xml"; - } - - private static ObfuzSettings s_Instance; - - public static ObfuzSettings Instance - { - get - { - if (!s_Instance) - { - LoadOrCreate(); - } - return s_Instance; - } - } - - protected static string SettingsPath => "ProjectSettings/Obfuz.asset"; - - private static ObfuzSettings LoadOrCreate() - { - string filePath = SettingsPath; - var arr = InternalEditorUtility.LoadSerializedFileAndForget(filePath); - //Debug.Log($"typeof arr:{arr?.GetType()} arr[0]:{(arr != null && arr.Length > 0 ? arr[0].GetType(): null)}"); - - if (arr != null && arr.Length > 0 && arr[0] is ObfuzSettings obfuzSettings) - { - s_Instance = obfuzSettings; - } - else - { - s_Instance = s_Instance ?? CreateInstance(); - } - return s_Instance; - } - - public static void Save() - { - if (!s_Instance) - { - return; - } - - string filePath = SettingsPath; - string directoryName = Path.GetDirectoryName(filePath); - Directory.CreateDirectory(directoryName); - UnityEngine.Object[] obj = new ObfuzSettings[1] { s_Instance }; - InternalEditorUtility.SaveToSerializedFileAndForget(obj, filePath, true); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs.meta deleted file mode 100644 index 8bad58fc..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c414eef017e565c4db1442ec64ec52fe -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettingsProvider.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettingsProvider.cs deleted file mode 100644 index 2b0afced..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettingsProvider.cs +++ /dev/null @@ -1,123 +0,0 @@ -using UnityEditor; -using UnityEngine.UIElements; - -namespace Obfuz.Settings -{ - public class ObfuzSettingsProvider : SettingsProvider - { - - private static ObfuzSettingsProvider s_provider; - - [SettingsProvider] - public static SettingsProvider CreateMyCustomSettingsProvider() - { - if (s_provider == null) - { - s_provider = new ObfuzSettingsProvider(); - using (var so = new SerializedObject(ObfuzSettings.Instance)) - { - s_provider.keywords = GetSearchKeywordsFromSerializedObject(so); - } - } - return s_provider; - } - - - private SerializedObject _serializedObject; - private SerializedProperty _buildPipelineSettings; - - private SerializedProperty _assemblySettings; - private SerializedProperty _obfuscationPassSettings; - private SerializedProperty _secretSettings; - private SerializedProperty _encryptionVMSettings; - - private SerializedProperty _symbolObfusSettings; - private SerializedProperty _constEncryptSettings; - private SerializedProperty _evalStackObfusSettings; - private SerializedProperty _fieldEncryptSettings; - private SerializedProperty _callObfusSettings; - private SerializedProperty _exprObfusSettings; - private SerializedProperty _controlFlowObfusSettings; - - private SerializedProperty _garbageCodeGenerationSettings; - - private SerializedProperty _polymorphicDllSettings; - - public ObfuzSettingsProvider() : base("Project/Obfuz", SettingsScope.Project) - { - } - - public override void OnActivate(string searchContext, VisualElement rootElement) - { - InitGUI(); - } - - public override void OnDeactivate() - { - base.OnDeactivate(); - ObfuzSettings.Save(); - } - - private void InitGUI() - { - var setting = ObfuzSettings.Instance; - _serializedObject?.Dispose(); - _serializedObject = new SerializedObject(setting); - _buildPipelineSettings = _serializedObject.FindProperty("buildPipelineSettings"); - - _assemblySettings = _serializedObject.FindProperty("assemblySettings"); - _obfuscationPassSettings = _serializedObject.FindProperty("obfuscationPassSettings"); - _secretSettings = _serializedObject.FindProperty("secretSettings"); - - _encryptionVMSettings = _serializedObject.FindProperty("encryptionVMSettings"); - - _symbolObfusSettings = _serializedObject.FindProperty("symbolObfusSettings"); - _constEncryptSettings = _serializedObject.FindProperty("constEncryptSettings"); - _evalStackObfusSettings = _serializedObject.FindProperty("evalStackObfusSettings"); - _exprObfusSettings = _serializedObject.FindProperty("exprObfusSettings"); - _fieldEncryptSettings = _serializedObject.FindProperty("fieldEncryptSettings"); - _callObfusSettings = _serializedObject.FindProperty("callObfusSettings"); - _controlFlowObfusSettings = _serializedObject.FindProperty("controlFlowObfusSettings"); - - _garbageCodeGenerationSettings = _serializedObject.FindProperty("garbageCodeGenerationSettings"); - - _polymorphicDllSettings = _serializedObject.FindProperty("polymorphicDllSettings"); - } - - public override void OnGUI(string searchContext) - { - if (_serializedObject == null || !_serializedObject.targetObject) - { - InitGUI(); - } - _serializedObject.Update(); - EditorGUI.BeginChangeCheck(); - - EditorGUILayout.PropertyField(_buildPipelineSettings); - - EditorGUILayout.PropertyField(_assemblySettings); - EditorGUILayout.PropertyField(_obfuscationPassSettings); - EditorGUILayout.PropertyField(_secretSettings); - - EditorGUILayout.PropertyField(_encryptionVMSettings); - - EditorGUILayout.PropertyField(_symbolObfusSettings); - EditorGUILayout.PropertyField(_constEncryptSettings); - EditorGUILayout.PropertyField(_evalStackObfusSettings); - EditorGUILayout.PropertyField(_exprObfusSettings); - EditorGUILayout.PropertyField(_fieldEncryptSettings); - EditorGUILayout.PropertyField(_callObfusSettings); - EditorGUILayout.PropertyField(_controlFlowObfusSettings); - - EditorGUILayout.PropertyField(_garbageCodeGenerationSettings); - - EditorGUILayout.PropertyField(_polymorphicDllSettings); - - if (EditorGUI.EndChangeCheck()) - { - _serializedObject.ApplyModifiedProperties(); - ObfuzSettings.Save(); - } - } - } -} \ No newline at end of file diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettingsProvider.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettingsProvider.cs.meta deleted file mode 100644 index 471477b1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettingsProvider.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9f020d09993a1aa41bae3258ec33d5fc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/PolymorphicDllSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/PolymorphicDllSettings.cs deleted file mode 100644 index e2d1180e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/PolymorphicDllSettings.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using UnityEngine; - -namespace Obfuz.Settings -{ - [Serializable] - public class PolymorphicDllSettings - { - [Tooltip("enable polymorphic DLL generation")] - public bool enable = true; - - [Tooltip("secret key for generating polymorphic DLL source code")] - public string codeGenerationSecretKey = "obfuz-polymorphic-key"; - - [Tooltip("disable load standard dotnet dll")] - public bool disableLoadStandardDll = false; - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/PolymorphicDllSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/PolymorphicDllSettings.cs.meta deleted file mode 100644 index f1885893..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/PolymorphicDllSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ecab9aab707d08949b2d602a4d61084a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SecretSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SecretSettings.cs deleted file mode 100644 index 9a9f6947..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SecretSettings.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using UnityEngine; - -namespace Obfuz.Settings -{ - [Serializable] - public class SecretSettings - { - - [Tooltip("default static secret key")] - public string defaultStaticSecretKey = "Code Philosophy-Static"; - - [Tooltip("default dynamic secret key")] - public string defaultDynamicSecretKey = "Code Philosophy-Dynamic"; - - [Tooltip("default static secret key output path")] - public string staticSecretKeyOutputPath = $"Assets/Resources/Obfuz/defaultStaticSecretKey.bytes"; - - [Tooltip("default dynamic secret key output path")] - public string dynamicSecretKeyOutputPath = $"Assets/Resources/Obfuz/defaultDynamicSecretKey.bytes"; - - [Tooltip("random seed")] - public int randomSeed = 0; - - [Tooltip("name of assemblies those use dynamic secret key")] - public string[] assembliesUsingDynamicSecretKeys; - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SecretSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SecretSettings.cs.meta deleted file mode 100644 index 7e26a78a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SecretSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7ac4fe2a6df113444b67412254452a00 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SymbolObfuscationSettings.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SymbolObfuscationSettings.cs deleted file mode 100644 index f661c4d7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SymbolObfuscationSettings.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace Obfuz.Settings -{ - public class SymbolObfuscationSettingsFacade - { - public bool debug; - public string obfuscatedNamePrefix; - public bool useConsistentNamespaceObfuscation; - public bool detectReflectionCompatibility; - public bool keepUnknownSymbolInSymbolMappingFile; - public string symbolMappingFile; - public List ruleFiles; - public List customRenamePolicyTypes; - } - - [Serializable] - public class SymbolObfuscationSettings - { - public bool debug; - - [Tooltip("prefix for obfuscated name to avoid name confliction with original name")] - public string obfuscatedNamePrefix = "$"; - - [Tooltip("obfuscate same namespace to one name")] - public bool useConsistentNamespaceObfuscation = true; - - [Tooltip("detect reflection compatibility, if true, will detect if the obfuscated name is compatibility with reflection, such as Type.GetType(), Enum.Parse(), etc.")] - public bool detectReflectionCompatibility = true; - - [Tooltip("keep unknown symbol in symbol mapping file, if false, unknown symbol will be removed from mapping file")] - public bool keepUnknownSymbolInSymbolMappingFile = true; - - [Tooltip("symbol mapping file path")] - public string symbolMappingFile = "Assets/Obfuz/SymbolObfus/symbol-mapping.xml"; - - [Tooltip("debug symbol mapping file path, used for debugging purposes")] - public string debugSymbolMappingFile = "Assets/Obfuz/SymbolObfus/symbol-mapping-debug.xml"; - - [Tooltip("rule files")] - public string[] ruleFiles; - - [Tooltip("custom rename policy types")] - public string[] customRenamePolicyTypes; - - public string GetSymbolMappingFile() - { - return debug ? debugSymbolMappingFile : symbolMappingFile; - } - - public SymbolObfuscationSettingsFacade ToFacade() - { - return new SymbolObfuscationSettingsFacade - { - debug = debug, - obfuscatedNamePrefix = obfuscatedNamePrefix, - useConsistentNamespaceObfuscation = useConsistentNamespaceObfuscation, - detectReflectionCompatibility = detectReflectionCompatibility, - keepUnknownSymbolInSymbolMappingFile = keepUnknownSymbolInSymbolMappingFile, - symbolMappingFile = GetSymbolMappingFile(), - ruleFiles = ruleFiles?.ToList() ?? new List(), - customRenamePolicyTypes = customRenamePolicyTypes?.Select(typeName => ReflectionUtil.FindUniqueTypeInCurrentAppDomain(typeName)).ToList() ?? new List(), - }; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SymbolObfuscationSettings.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SymbolObfuscationSettings.cs.meta deleted file mode 100644 index 58779d69..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Settings/SymbolObfuscationSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2484a8a12a689df46b5eb7fc4ccac81f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity.meta deleted file mode 100644 index 8456b1dc..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bc9b206fbf6a69f4c99a6ec9b0b27c69 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs deleted file mode 100644 index 23f27653..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs +++ /dev/null @@ -1,149 +0,0 @@ -using Obfuz.Settings; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Xml; -using UnityEditor; -using UnityEditor.Build; -using UnityEditor.Build.Reporting; -using UnityEditor.UnityLinker; -using UnityEngine; -using FileUtil = Obfuz.Utils.FileUtil; - -namespace Obfuz.Unity -{ - public class LinkXmlProcess : IUnityLinkerProcessor - { - public int callbackOrder => ObfuzSettings.Instance.buildPipelineSettings.linkXmlProcessCallbackOrder; - - public string GenerateAdditionalLinkXmlFile(BuildReport report, UnityLinkerBuildPipelineData data) - { - return GenerateAdditionalLinkXmlFile(data.target); - } - -#if !UNITY_2021_2_OR_NEWER - - public void OnBeforeRun(BuildReport report, UnityLinkerBuildPipelineData data) - { - - } - - public void OnAfterRun(BuildReport report, UnityLinkerBuildPipelineData data) - { - - } -#endif - - public static string GenerateAdditionalLinkXmlFile(BuildTarget target) - { - ObfuzSettings settings = ObfuzSettings.Instance; - string symbolMappingFile = settings.symbolObfusSettings.GetSymbolMappingFile(); - if (!File.Exists(symbolMappingFile)) - { - Debug.LogWarning($"Symbol mapping file not found: {symbolMappingFile}. Skipping link.xml generation."); - return null; - } - string linkXmlPath = settings.GetObfuscatedLinkXmlPath(target); - FileUtil.CreateParentDir(linkXmlPath); - - var writer = System.Xml.XmlWriter.Create(linkXmlPath, - new System.Xml.XmlWriterSettings { Encoding = Encoding.UTF8, Indent = true }); - try - { - var symbolMapping = new LiteSymbolMappingReader(symbolMappingFile); - string[] linkGuids = AssetDatabase.FindAssets("t:TextAsset"); - var linkXmlPaths = linkGuids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)) - .Where(f => Path.GetFileName(f) == "link.xml") - .ToArray(); - - var assembliesToObfuscated = new HashSet(settings.assemblySettings.GetAssembliesToObfuscate()); - - writer.WriteStartDocument(); - writer.WriteStartElement("linker"); - - // Preserve Obfuz.Runtime assembly - writer.WriteStartElement("assembly"); - writer.WriteAttributeString("fullname", "Obfuz.Runtime"); - writer.WriteAttributeString("preserve", "all"); - writer.WriteEndElement(); - - foreach (string linkPath in linkXmlPaths) - { - TransformLinkXml(linkPath, symbolMapping, assembliesToObfuscated, writer); - } - writer.WriteEndElement(); - writer.WriteEndDocument(); - } - finally - { - writer.Close(); - } - Debug.Log($"LinkXmlProcess write {Path.GetFullPath(linkXmlPath)}"); - return Path.GetFullPath(linkXmlPath); - } - - private static void TransformLinkXml(string xmlFile, LiteSymbolMappingReader symbolMapping, HashSet assembliesToObfuscated, XmlWriter writer) - { - Debug.Log($"LinkXmlProcess transform link.xml:{xmlFile}"); - var doc = new XmlDocument(); - doc.Load(xmlFile); - var root = doc.DocumentElement; - foreach (XmlNode assNode in root.ChildNodes) - { - if (!(assNode is XmlElement assElement)) - { - continue; - } - if (assElement.Name == "assembly") - { - string assemblyName = assElement.GetAttribute("fullname"); - if (string.IsNullOrEmpty(assemblyName)) - { - throw new Exception($"Invalid node name: {assElement.Name}. attribute 'fullname' missing."); - } - if (!assembliesToObfuscated.Contains(assemblyName)) - { - continue; // Skip assemblies that are not to be obfuscated - } - writer.WriteStartElement("assembly"); - writer.WriteAttributeString("fullname", assemblyName); - if (assElement.HasAttribute("preserve")) - { - writer.WriteAttributeString("preserve", assElement.GetAttribute("preserve")); - } - - foreach (XmlNode typeNode in assElement.ChildNodes) - { - if (typeNode is XmlElement typeElement) - { - if (typeElement.Name == "type") - { - string typeName = typeElement.GetAttribute("fullname"); - if (string.IsNullOrEmpty(typeName)) - { - throw new Exception($"Invalid node name: {typeElement.Name}. attribute 'fullname' missing."); - } - if (!symbolMapping.TryGetNewTypeName(assemblyName, typeName, out string newTypeName)) - { - continue; - } - - writer.WriteStartElement("type"); - writer.WriteAttributeString("fullname", newTypeName); - if (typeElement.HasAttribute("preserve")) - { - writer.WriteAttributeString("preserve", typeElement.GetAttribute("preserve")); - } - writer.WriteEndElement(); - } - } - } - - writer.WriteEndElement(); - } - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs.meta deleted file mode 100644 index 7ddd2b48..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 66881cca1e4a78c44b4c9fcd7f8b4fb9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs deleted file mode 100644 index c04c6838..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs +++ /dev/null @@ -1,116 +0,0 @@ - -using System.Collections.Generic; -using System.Xml; - -namespace Obfuz.Unity -{ - - public class LiteSymbolMappingReader - { - class TypeMappingInfo - { - public string oldFullName; - public string newFullName; - - //public Dictionary MethodMappings = new Dictionary(); - } - - class AssemblyMappingInfo - { - public Dictionary TypeMappings = new Dictionary(); - public Dictionary MethodMappings = new Dictionary(); - } - - private readonly Dictionary _assemblies = new Dictionary(); - - public LiteSymbolMappingReader(string mappingFile) - { - LoadXmlMappingFile(mappingFile); - } - - private void LoadXmlMappingFile(string mappingFile) - { - var doc = new XmlDocument(); - doc.Load(mappingFile); - var root = doc.DocumentElement; - foreach (XmlNode node in root.ChildNodes) - { - if (!(node is XmlElement element)) - { - continue; - } - LoadAssemblyMapping(element); - } - } - - private void LoadAssemblyMapping(XmlElement ele) - { - if (ele.Name != "assembly") - { - throw new System.Exception($"Invalid node name: {ele.Name}. Expected 'assembly'."); - } - string assName = ele.GetAttribute("name"); - if (string.IsNullOrEmpty(assName)) - { - throw new System.Exception($"Invalid node name: {ele.Name}. attribute 'name' missing."); - } - if (!_assemblies.TryGetValue(assName, out var assemblyMappingInfo)) - { - assemblyMappingInfo = new AssemblyMappingInfo(); - _assemblies[assName] = assemblyMappingInfo; - } - - foreach (XmlNode node in ele.ChildNodes) - { - if (!(node is XmlElement element)) - { - continue; - } - if (element.Name == "type") - { - LoadTypeMapping(element, assemblyMappingInfo); - } - } - } - - private void LoadTypeMapping(XmlElement ele, AssemblyMappingInfo assemblyMappingInfo) - { - string oldFullName = ele.GetAttribute("fullName"); - string newFullName = ele.GetAttribute("newFullName"); - string status = ele.GetAttribute("status"); - if (status == "Renamed") - { - if (string.IsNullOrEmpty(oldFullName) || string.IsNullOrEmpty(newFullName)) - { - throw new System.Exception($"Invalid node name: {ele.Name}. attributes 'fullName' or 'newFullName' missing."); - } - assemblyMappingInfo.TypeMappings[oldFullName] = newFullName; - } - //foreach (XmlNode node in ele.ChildNodes) - //{ - // if (!(node is XmlElement c)) - // { - // continue; - // } - // if (node.Name == "method") - // { - // LoadMethodMapping(c); - // } - //} - } - - public bool TryGetNewTypeName(string assemblyName, string oldFullName, out string newFullName) - { - newFullName = null; - if (_assemblies.TryGetValue(assemblyName, out var assemblyMappingInfo)) - { - if (assemblyMappingInfo.TypeMappings.TryGetValue(oldFullName, out newFullName)) - { - return true; - } - } - return false; - } - - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs.meta deleted file mode 100644 index 4abd760e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8429e75dcc6a7e742a3cabaa3e8491c5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationBeginEventArgs.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationBeginEventArgs.cs deleted file mode 100644 index b8f2397e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationBeginEventArgs.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Obfuz.Unity -{ - public class ObfuscationBeginEventArgs - { - public string scriptAssembliesPath; - public string obfuscatedScriptAssembliesPath; - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationBeginEventArgs.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationBeginEventArgs.cs.meta deleted file mode 100644 index a2d5e11a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationBeginEventArgs.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8e3d38018839d4844bf1e15631946e65 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationEndEventArgs.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationEndEventArgs.cs deleted file mode 100644 index ac2fa76a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationEndEventArgs.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Obfuz.Unity -{ - public class ObfuscationEndEventArgs - { - public bool success; - public string originalScriptAssembliesPath; - public string obfuscatedScriptAssembliesPath; - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationEndEventArgs.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationEndEventArgs.cs.meta deleted file mode 100644 index fe376819..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationEndEventArgs.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6b198ad99d0a9c145b1bc2b29b25b8ac -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationProcess.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationProcess.cs deleted file mode 100644 index 8dd48a3d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationProcess.cs +++ /dev/null @@ -1,144 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Settings; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditor; -using UnityEditor.Build; -using UnityEditor.Build.Reporting; -using UnityEngine; -using FileUtil = Obfuz.Utils.FileUtil; - -namespace Obfuz.Unity -{ - -#if UNITY_2019_1_OR_NEWER - public class ObfuscationProcess : IPostBuildPlayerScriptDLLs - { - public int callbackOrder => ObfuzSettings.Instance.buildPipelineSettings.obfuscationProcessCallbackOrder; - - public static event Action OnObfuscationBegin; - - public static event Action OnObfuscationEnd; - - public void OnPostBuildPlayerScriptDLLs(BuildReport report) - { -#if !UNITY_2022_1_OR_NEWER - RunObfuscate(report.files); -#else - RunObfuscate(report.GetFiles()); -#endif - } - - private static void BackupOriginalDlls(string srcDir, string dstDir, HashSet dllNames) - { - FileUtil.RecreateDir(dstDir); - foreach (string dllName in dllNames) - { - string srcFile = Path.Combine(srcDir, dllName + ".dll"); - string dstFile = Path.Combine(dstDir, dllName + ".dll"); - if (File.Exists(srcFile)) - { - File.Copy(srcFile, dstFile, true); - Debug.Log($"BackupOriginalDll {srcFile} -> {dstFile}"); - } - } - } - - public static void ValidateReferences(string stagingAreaTempManagedDllDir, HashSet assembliesToObfuscated, HashSet obfuscationRelativeAssemblyNames) - { - var modCtx = ModuleDef.CreateModuleContext(); - var asmResolver = (AssemblyResolver)modCtx.AssemblyResolver; - - foreach (string assFile in Directory.GetFiles(stagingAreaTempManagedDllDir, "*.dll", SearchOption.AllDirectories)) - { - ModuleDefMD mod = ModuleDefMD.Load(File.ReadAllBytes(assFile), modCtx); - string modName = mod.Assembly.Name; - foreach (AssemblyRef assRef in mod.GetAssemblyRefs()) - { - string refAssName = assRef.Name; - if (assembliesToObfuscated.Contains(refAssName) && !obfuscationRelativeAssemblyNames.Contains(modName)) - { - throw new BuildFailedException($"assembly:{modName} references to obfuscated assembly:{refAssName}, but it's not been added to ObfuzSettings.AssemblySettings.NonObfuscatedButReferencingObfuscatedAssemblies."); - } - } - mod.Dispose(); - } - } - - private static void RunObfuscate(BuildFile[] files) - { - ObfuzSettings settings = ObfuzSettings.Instance; - if (!settings.buildPipelineSettings.enable) - { - Debug.Log("Obfuscation is disabled."); - return; - } - - Debug.Log("Obfuscation begin..."); - var buildTarget = EditorUserBuildSettings.activeBuildTarget; - - var obfuscationRelativeAssemblyNames = new HashSet(settings.assemblySettings.GetObfuscationRelativeAssemblyNames()); - string stagingAreaTempManagedDllDir = Path.GetDirectoryName(files.First(file => file.path.EndsWith(".dll")).path); - string backupPlayerScriptAssembliesPath = settings.GetOriginalAssemblyBackupDir(buildTarget); - BackupOriginalDlls(stagingAreaTempManagedDllDir, backupPlayerScriptAssembliesPath, obfuscationRelativeAssemblyNames); - - string applicationContentsPath = EditorApplication.applicationContentsPath; - - var obfuscatorBuilder = ObfuscatorBuilder.FromObfuzSettings(settings, buildTarget, false); - - var assemblySearchDirs = new List - { - stagingAreaTempManagedDllDir, - }; - obfuscatorBuilder.InsertTopPriorityAssemblySearchPaths(assemblySearchDirs); - - ValidateReferences(stagingAreaTempManagedDllDir, new HashSet(obfuscatorBuilder.CoreSettingsFacade.assembliesToObfuscate), obfuscationRelativeAssemblyNames); - - - OnObfuscationBegin?.Invoke(new ObfuscationBeginEventArgs - { - scriptAssembliesPath = stagingAreaTempManagedDllDir, - obfuscatedScriptAssembliesPath = obfuscatorBuilder.CoreSettingsFacade.obfuscatedAssemblyOutputPath, - }); - bool succ = false; - - try - { - Obfuscator obfuz = obfuscatorBuilder.Build(); - obfuz.Run(); - - foreach (var dllName in obfuscationRelativeAssemblyNames) - { - string src = $"{obfuscatorBuilder.CoreSettingsFacade.obfuscatedAssemblyOutputPath}/{dllName}.dll"; - string dst = $"{stagingAreaTempManagedDllDir}/{dllName}.dll"; - - if (!File.Exists(src)) - { - Debug.LogWarning($"obfuscation assembly not found! skip copy. path:{src}"); - continue; - } - File.Copy(src, dst, true); - Debug.Log($"obfuscate dll:{dst}"); - } - succ = true; - } - catch (Exception e) - { - succ = false; - Debug.LogException(e); - Debug.LogError($"Obfuscation failed."); - } - OnObfuscationEnd?.Invoke(new ObfuscationEndEventArgs - { - success = succ, - originalScriptAssembliesPath = backupPlayerScriptAssembliesPath, - obfuscatedScriptAssembliesPath = stagingAreaTempManagedDllDir, - }); - - Debug.Log("Obfuscation end."); - } - } -#endif -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationProcess.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationProcess.cs.meta deleted file mode 100644 index de6b391f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuscationProcess.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fc7a8b1e20c66164699de44d0a302cb7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuzMenu.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuzMenu.cs deleted file mode 100644 index be1147d1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuzMenu.cs +++ /dev/null @@ -1,88 +0,0 @@ -using Obfuz.EncryptionVM; -using Obfuz.GarbageCodeGeneration; -using Obfuz.Settings; -using Obfuz.Utils; -using System.IO; -using UnityEditor; -using UnityEngine; -using FileUtil = Obfuz.Utils.FileUtil; - -namespace Obfuz.Unity -{ - public static class ObfuzMenu - { - - [MenuItem("Obfuz/Settings...", priority = 1)] - public static void OpenSettings() => SettingsService.OpenProjectSettings("Project/Obfuz"); - - [MenuItem("Obfuz/GenerateEncryptionVM", priority = 62)] - public static void GenerateEncryptionVM() - { - EncryptionVMSettings settings = ObfuzSettings.Instance.encryptionVMSettings; - var generator = new VirtualMachineCodeGenerator(settings.codeGenerationSecretKey, settings.encryptionOpCodeCount); - generator.Generate(settings.codeOutputPath); - AssetDatabase.Refresh(); - } - - [MenuItem("Obfuz/GenerateSecretKeyFile", priority = 63)] - public static void SaveSecretFile() - { - SecretSettings settings = ObfuzSettings.Instance.secretSettings; - - var staticSecretBytes = KeyGenerator.GenerateKey(settings.defaultStaticSecretKey, VirtualMachine.SecretKeyLength); - SaveKey(staticSecretBytes, settings.staticSecretKeyOutputPath); - Debug.Log($"Save static secret key to {settings.staticSecretKeyOutputPath}"); - var dynamicSecretBytes = KeyGenerator.GenerateKey(settings.defaultDynamicSecretKey, VirtualMachine.SecretKeyLength); - SaveKey(dynamicSecretBytes, settings.dynamicSecretKeyOutputPath); - Debug.Log($"Save dynamic secret key to {settings.dynamicSecretKeyOutputPath}"); - AssetDatabase.Refresh(); - } - - [MenuItem("Obfuz/GarbageCode/GenerateCodes", priority = 100)] - public static void GenerateGarbageCodes() - { - Debug.Log($"Generating garbage codes begin."); - GarbageCodeGenerationSettings settings = ObfuzSettings.Instance.garbageCodeGenerationSettings; - var generator = new GarbageCodeGenerator(settings); - generator.Generate(); - AssetDatabase.Refresh(); - Debug.Log($"Generating garbage codes end."); - } - - [MenuItem("Obfuz/GarbageCode/CleanGeneratedCodes", priority = 101)] - public static void CleanGeneratedGarbageCodes() - { - Debug.Log($"Clean generated garbage codes begin."); - GarbageCodeGenerationSettings settings = ObfuzSettings.Instance.garbageCodeGenerationSettings; - var generator = new GarbageCodeGenerator(settings); - generator.CleanCodes(); - AssetDatabase.Refresh(); - Debug.Log($"Clean generated garbage codes end."); - } - - private static void SaveKey(byte[] secret, string secretOutputPath) - { - FileUtil.CreateParentDir(secretOutputPath); - File.WriteAllBytes(secretOutputPath, secret); - } - - [MenuItem("Obfuz/Documents/Quick Start")] - public static void OpenQuickStart() => Application.OpenURL("https://www.obfuz.com/docs/beginner/quickstart"); - - [MenuItem("Obfuz/Documents/FAQ")] - public static void OpenFAQ() => Application.OpenURL("https://www.obfuz.com/docs/help/faq"); - - [MenuItem("Obfuz/Documents/Common Errors")] - public static void OpenCommonErrors() => Application.OpenURL("https://www.obfuz.com/docs/help/commonerrors"); - - [MenuItem("Obfuz/Documents/Bug Report")] - public static void OpenBugReport() => Application.OpenURL("https://www.obfuz.com/docs/help/issue"); - - [MenuItem("Obfuz/Documents/GitHub")] - public static void OpenGitHub() => Application.OpenURL("https://github.com/focus-creative-games/obfuz"); - - [MenuItem("Obfuz/Documents/About")] - public static void OpenAbout() => Application.OpenURL("https://www.obfuz.com/docs/intro"); - } - -} \ No newline at end of file diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuzMenu.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuzMenu.cs.meta deleted file mode 100644 index ae1f6f80..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/ObfuzMenu.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ce8d804a6c4640e45a3d5c98b30c0c31 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/UnityProjectManagedAssemblyResolver.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/UnityProjectManagedAssemblyResolver.cs deleted file mode 100644 index 9d838aee..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/UnityProjectManagedAssemblyResolver.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Obfuz.Utils; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditor; -using UnityEngine; - -namespace Obfuz.Unity -{ - public class UnityProjectManagedAssemblyResolver : AssemblyResolverBase - { - private readonly Dictionary _managedAssemblyNameToPaths = new Dictionary(); - - public UnityProjectManagedAssemblyResolver(BuildTarget target) - { - string[] dllGuids = AssetDatabase.FindAssets("t:DefaultAsset"); - var dllPaths = dllGuids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)) - .Where(f => f.EndsWith(".dll")) - .Where(dllPath => - { - PluginImporter importer = AssetImporter.GetAtPath(dllPath) as PluginImporter; - if (importer == null || importer.isNativePlugin) - { - return false; - } - if (!importer.GetCompatibleWithAnyPlatform() && !importer.GetCompatibleWithPlatform(target)) - { - return false; - } - return true; - }).ToArray(); - - foreach (string dllPath in dllPaths) - { - Debug.Log($"UnityProjectManagedAssemblyResolver find managed dll:{dllPath}"); - string assName = Path.GetFileNameWithoutExtension(dllPath); - if (_managedAssemblyNameToPaths.TryGetValue(assName, out var existAssPath)) - { - Debug.LogWarning($"UnityProjectManagedAssemblyResolver find duplicate assembly1:{existAssPath} assembly2:{dllPath}"); - } - else - { - _managedAssemblyNameToPaths.Add(Path.GetFileNameWithoutExtension(dllPath), dllPath); - } - } - } - - public override string ResolveAssembly(string assemblyName) - { - if (_managedAssemblyNameToPaths.TryGetValue(assemblyName, out string assemblyPath)) - { - return assemblyPath; - } - return null; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/UnityProjectManagedAssemblyResolver.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/UnityProjectManagedAssemblyResolver.cs.meta deleted file mode 100644 index ac1c4aa1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Unity/UnityProjectManagedAssemblyResolver.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 20abbffaf6419c448883ffaa21949753 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils.meta deleted file mode 100644 index 8a3e253d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ade28aaad1116b143a4027071e71010f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyCache.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyCache.cs deleted file mode 100644 index 0c3eeaa4..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyCache.cs +++ /dev/null @@ -1,88 +0,0 @@ -using dnlib.DotNet; -using System.Collections.Generic; -using System.IO; - -namespace Obfuz.Utils -{ - - public class AssemblyCache - { - private readonly IAssemblyResolver _assemblyPathResolver; - private readonly ModuleContext _modCtx; - private readonly AssemblyResolver _asmResolver; - private bool _enableTypeDefCache; - - - public ModuleContext ModCtx => _modCtx; - - public Dictionary LoadedModules { get; } = new Dictionary(); - - public AssemblyCache(IAssemblyResolver assemblyResolver) - { - _enableTypeDefCache = true; - _assemblyPathResolver = assemblyResolver; - _modCtx = ModuleDef.CreateModuleContext(); - _asmResolver = (AssemblyResolver)_modCtx.AssemblyResolver; - _asmResolver.EnableTypeDefCache = _enableTypeDefCache; - _asmResolver.UseGAC = false; - } - - public bool EnableTypeDefCache - { - get => _enableTypeDefCache; - set - { - _enableTypeDefCache = value; - _asmResolver.EnableTypeDefCache = value; - foreach (var mod in LoadedModules.Values) - { - mod.EnableTypeDefFindCache = value; - } - } - } - - - public ModuleDefMD TryLoadModule(string moduleName) - { - string dllPath = _assemblyPathResolver.ResolveAssembly(moduleName); - if (string.IsNullOrEmpty(dllPath)) - { - return null; - } - return LoadModule(moduleName); - } - - public ModuleDefMD LoadModule(string moduleName) - { - // Debug.Log($"load module:{moduleName}"); - if (LoadedModules.TryGetValue(moduleName, out var mod)) - { - return mod; - } - string assemblyPath = _assemblyPathResolver.ResolveAssembly(moduleName); - if (string.IsNullOrEmpty(assemblyPath)) - { - throw new FileNotFoundException($"Assembly {moduleName} not found"); - } - mod = DoLoadModule(assemblyPath); - LoadedModules.Add(moduleName, mod); - - - foreach (var refAsm in mod.GetAssemblyRefs()) - { - LoadModule(refAsm.Name); - } - - return mod; - } - - private ModuleDefMD DoLoadModule(string dllPath) - { - //Debug.Log($"do load module:{dllPath}"); - ModuleDefMD mod = ModuleDefMD.Load(File.ReadAllBytes(dllPath), _modCtx); - mod.EnableTypeDefFindCache = _enableTypeDefCache; - _asmResolver.AddToCache(mod); - return mod; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyCache.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyCache.cs.meta deleted file mode 100644 index bb922298..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyCache.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ce64ad992f9807d4994d4f41a54b170b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyResolverBase.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyResolverBase.cs deleted file mode 100644 index 73aa7e6a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyResolverBase.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Obfuz.Utils -{ - public abstract class AssemblyResolverBase : IAssemblyResolver - { - public abstract string ResolveAssembly(string assemblyName); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyResolverBase.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyResolverBase.cs.meta deleted file mode 100644 index 4a7f4a0e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssemblyResolverBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c7332848ca18498459e6248d06bc5b31 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssertUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssertUtil.cs deleted file mode 100644 index 112899a7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssertUtil.cs +++ /dev/null @@ -1,28 +0,0 @@ -using UnityEngine.Assertions; - -namespace Obfuz.Utils -{ - public static class AssertUtil - { - private static bool IsArrayEqual(byte[] a, byte[] b) - { - if (a.Length != b.Length) - { - return false; - } - for (int i = 0; i < a.Length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - return true; - } - - public static void AreArrayEqual(byte[] expected, byte[] actual, string message) - { - Assert.IsTrue(IsArrayEqual(expected, actual), message); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssertUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssertUtil.cs.meta deleted file mode 100644 index e0097382..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/AssertUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: aba0c82c527b6494ab5c9c67c25656ed -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/BurstCompileComputeCache.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/BurstCompileComputeCache.cs deleted file mode 100644 index f2f22884..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/BurstCompileComputeCache.cs +++ /dev/null @@ -1,90 +0,0 @@ -using dnlib.DotNet; -using System.Collections.Generic; - -namespace Obfuz.Utils -{ - public class BurstCompileComputeCache - { - private readonly List _modulesToObfuscate; - private readonly List _allObfuscationRelativeModules; - - private readonly HashSet _burstCompileMethods = new HashSet(); - private readonly HashSet _burstCompileRelativeMethods = new HashSet(); - public BurstCompileComputeCache(List modulesToObfuscate, List allObfuscationRelativeModules) - { - _modulesToObfuscate = modulesToObfuscate; - _allObfuscationRelativeModules = allObfuscationRelativeModules; - Build(); - } - - - private void BuildBurstCompileMethods() - { - foreach (var module in _allObfuscationRelativeModules) - { - foreach (var type in module.GetTypes()) - { - bool hasBurstCompileAttribute = MetaUtil.HasBurstCompileAttribute(type); - foreach (var method in type.Methods) - { - if (hasBurstCompileAttribute || MetaUtil.HasBurstCompileAttribute(method)) - { - _burstCompileMethods.Add(method); - } - } - } - } - } - - private void CollectBurstCompileReferencedMethods() - { - var modulesToObfuscateSet = new HashSet(_modulesToObfuscate); - var allObfuscationRelativeModulesSet = new HashSet(_allObfuscationRelativeModules); - - var pendingWalking = new Queue(_burstCompileMethods); - var visitedMethods = new HashSet(); - while (pendingWalking.Count > 0) - { - var method = pendingWalking.Dequeue(); - - if (!visitedMethods.Add(method)) - { - continue; // Skip already visited methods - } - if (modulesToObfuscateSet.Contains(method.Module)) - { - _burstCompileRelativeMethods.Add(method); - } - if (!method.HasBody) - { - continue; - } - // Check for calls to other methods - foreach (var instruction in method.Body.Instructions) - { - if (instruction.OpCode.Code == dnlib.DotNet.Emit.Code.Call || - instruction.OpCode.Code == dnlib.DotNet.Emit.Code.Callvirt) - { - MethodDef calledMethod = ((IMethod)instruction.Operand).ResolveMethodDef(); - if (calledMethod == null || !allObfuscationRelativeModulesSet.Contains(calledMethod.Module) || visitedMethods.Contains(calledMethod)) - { - continue; // Skip if the method could not be resolved - } - pendingWalking.Enqueue(calledMethod); - } - } - } - } - - private void Build() - { - BuildBurstCompileMethods(); - CollectBurstCompileReferencedMethods(); - } - - public bool IsBurstCompileMethodOrReferencedByBurstCompileMethod(MethodDef method) - { - return _burstCompileRelativeMethods.Contains(method); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/BurstCompileComputeCache.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/BurstCompileComputeCache.cs.meta deleted file mode 100644 index 07dd6517..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/BurstCompileComputeCache.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 37efeee0ad0b5c34e84bd1b7b401672a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CachedDictionary.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CachedDictionary.cs deleted file mode 100644 index 1e0f1d02..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CachedDictionary.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Obfuz.Utils -{ - public class CachedDictionary - { - private readonly Func _valueFactory; - private readonly Dictionary _cache; - - public CachedDictionary(Func valueFactory) - { - _cache = new Dictionary(); - _valueFactory = valueFactory; - } - - public CachedDictionary(IEqualityComparer equalityComparer, Func valueFactory) - { - _cache = new Dictionary(equalityComparer); - _valueFactory = valueFactory; - } - - public V GetValue(K key) - { - if (!_cache.TryGetValue(key, out var value)) - { - value = _valueFactory(key); - _cache[key] = value; - } - return value; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CachedDictionary.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CachedDictionary.cs.meta deleted file mode 100644 index 115dde01..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CachedDictionary.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 66494da674feeb741b889590cb663d4e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CollectionExtensions.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CollectionExtensions.cs deleted file mode 100644 index 6753fe5d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CollectionExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; - -namespace Obfuz.Utils -{ - public static class CollectionExtensions - { - public static void AddRange(this HashSet values, IEnumerable newValues) - { - foreach (var value in newValues) - { - values.Add(value); - } - } - - public static V GetValueOrDefault(this Dictionary dic, K key) - { - return dic.TryGetValue(key, out V v) ? v : default(V); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CollectionExtensions.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CollectionExtensions.cs.meta deleted file mode 100644 index ba4aa2ac..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CollectionExtensions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 58fc4438f86bc174aba662f1d7058f45 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CombinedAssemblyResolver.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CombinedAssemblyResolver.cs deleted file mode 100644 index fd1c9443..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CombinedAssemblyResolver.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Obfuz.Utils -{ - public class CombinedAssemblyResolver : AssemblyResolverBase - { - private readonly List _resolvers; - - public CombinedAssemblyResolver(params IAssemblyResolver[] resolvers) - { - _resolvers = resolvers.ToList(); - } - - public override string ResolveAssembly(string assemblyName) - { - foreach (var resolver in _resolvers) - { - var assemblyPath = resolver.ResolveAssembly(assemblyName); - if (assemblyPath != null) - { - return assemblyPath; - } - } - return null; - } - - public void InsertFirst(IAssemblyResolver resolver) - { - _resolvers.Insert(0, resolver); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CombinedAssemblyResolver.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CombinedAssemblyResolver.cs.meta deleted file mode 100644 index dd9890d7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/CombinedAssemblyResolver.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1576f3534f31509458104d2a7ebcd9cc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConfigUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConfigUtil.cs deleted file mode 100644 index bc2c5492..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConfigUtil.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Obfuz.Settings; -using System; - -namespace Obfuz.Utils -{ - public static class ConfigUtil - { - - public static bool ParseBool(string str) - { - switch (str.ToLowerInvariant()) - { - case "1": - case "true": return true; - case "0": - case "false": return false; - default: throw new Exception($"Invalid bool value {str}"); - } - } - - public static bool? ParseNullableBool(string str) - { - if (string.IsNullOrEmpty(str)) - { - return null; - } - switch (str.ToLowerInvariant()) - { - case "1": - case "true": return true; - case "0": - case "false": return false; - default: throw new Exception($"Invalid bool value {str}"); - } - } - - public static int? ParseNullableInt(string str) - { - if (string.IsNullOrEmpty(str)) - { - return null; - } - return int.Parse(str); - } - - public static long? ParseNullableLong(string str) - { - if (string.IsNullOrEmpty(str)) - { - return null; - } - return long.Parse(str); - } - - public static float? ParseNullableFloat(string str) - { - if (string.IsNullOrEmpty(str)) - { - return null; - } - return float.Parse(str); - } - - public static double? ParseNullableDouble(string str) - { - if (string.IsNullOrEmpty(str)) - { - return null; - } - return double.Parse(str); - } - - public static ObfuscationLevel ParseObfuscationLevel(string str) - { - return (ObfuscationLevel)Enum.Parse(typeof(ObfuscationLevel), str); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConfigUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConfigUtil.cs.meta deleted file mode 100644 index bba160a6..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConfigUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ff35a8e07f37adf4483eaf5cc5da5c78 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConstObfusUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConstObfusUtil.cs deleted file mode 100644 index 67c64d05..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConstObfusUtil.cs +++ /dev/null @@ -1,177 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Data; -using System.Collections.Generic; - -namespace Obfuz.Utils -{ - internal static class ConstObfusUtil - { - public static void LoadConstInt(int a, IRandom random, float constProbability, ConstFieldAllocator constFieldAllocator, List outputInsts) - { - Instruction inst; - if (random.NextInPercentage(constProbability)) - { - inst = Instruction.Create(OpCodes.Ldc_I4, a); - } - else - { - FieldDef field = constFieldAllocator.Allocate(a); - inst = Instruction.Create(OpCodes.Ldsfld, field); - } - outputInsts.Add(inst); - } - - public static void LoadConstLong(long a, IRandom random, float constProbability, ConstFieldAllocator constFieldAllocator, List outputInsts) - { - Instruction inst; - if (random.NextInPercentage(constProbability)) - { - inst = Instruction.Create(OpCodes.Ldc_I8, a); - } - else - { - FieldDef field = constFieldAllocator.Allocate(a); - inst = Instruction.Create(OpCodes.Ldsfld, field); - } - outputInsts.Add(inst); - } - - public static void LoadConstFloat(float a, IRandom random, float constProbability, ConstFieldAllocator constFieldAllocator, List outputInsts) - { - Instruction inst; - if (random.NextInPercentage(constProbability)) - { - inst = Instruction.Create(OpCodes.Ldc_R4, a); - } - else - { - FieldDef field = constFieldAllocator.Allocate(a); - inst = Instruction.Create(OpCodes.Ldsfld, field); - } - outputInsts.Add(inst); - } - - public static void LoadConstDouble(double a, IRandom random, float constProbability, ConstFieldAllocator constFieldAllocator, List outputInsts) - { - Instruction inst; - if (random.NextInPercentage(constProbability)) - { - inst = Instruction.Create(OpCodes.Ldc_R8, a); - } - else - { - FieldDef field = constFieldAllocator.Allocate(a); - inst = Instruction.Create(OpCodes.Ldsfld, field); - } - outputInsts.Add(inst); - } - - - public static void LoadConstTwoInt(int a, int b, IRandom random, float constProbability, ConstFieldAllocator constFieldAllocator, List outputInsts) - { - if (random.NextInPercentage(constProbability)) - { - outputInsts.Add(Instruction.Create(OpCodes.Ldc_I4, a)); - - // at most one ldc instruction - FieldDef field = constFieldAllocator.Allocate(b); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - } - else - { - FieldDef field = constFieldAllocator.Allocate(a); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - - if (random.NextInPercentage(constProbability)) - { - // at most one ldc instruction - outputInsts.Add(Instruction.Create(OpCodes.Ldc_I4, b)); - } - else - { - field = constFieldAllocator.Allocate(b); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - } - } - } - - public static void LoadConstTwoLong(long a, long b, IRandom random, float constProbability, ConstFieldAllocator constFieldAllocator, List outputInsts) - { - if (random.NextInPercentage(constProbability)) - { - outputInsts.Add(Instruction.Create(OpCodes.Ldc_I8, a)); - // at most one ldc instruction - FieldDef field = constFieldAllocator.Allocate(b); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - } - else - { - FieldDef field = constFieldAllocator.Allocate(a); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - if (random.NextInPercentage(constProbability)) - { - // at most one ldc instruction - outputInsts.Add(Instruction.Create(OpCodes.Ldc_I8, b)); - } - else - { - field = constFieldAllocator.Allocate(b); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - } - } - } - - public static void LoadConstTwoFloat(float a, float b, IRandom random, float constProbability, ConstFieldAllocator constFieldAllocator, List outputInsts) - { - if (random.NextInPercentage(constProbability)) - { - outputInsts.Add(Instruction.Create(OpCodes.Ldc_R4, a)); - // at most one ldc instruction - FieldDef field = constFieldAllocator.Allocate(b); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - } - else - { - FieldDef field = constFieldAllocator.Allocate(a); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - if (random.NextInPercentage(constProbability)) - { - // at most one ldc instruction - outputInsts.Add(Instruction.Create(OpCodes.Ldc_R4, b)); - } - else - { - field = constFieldAllocator.Allocate(b); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - } - } - } - - public static void LoadConstTwoDouble(double a, double b, IRandom random, float constProbability, ConstFieldAllocator constFieldAllocator, List outputInsts) - { - if (random.NextInPercentage(constProbability)) - { - outputInsts.Add(Instruction.Create(OpCodes.Ldc_R8, a)); - // at most one ldc instruction - FieldDef field = constFieldAllocator.Allocate(b); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - } - else - { - FieldDef field = constFieldAllocator.Allocate(a); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - if (random.NextInPercentage(constProbability)) - { - // at most one ldc instruction - outputInsts.Add(Instruction.Create(OpCodes.Ldc_R8, b)); - } - else - { - field = constFieldAllocator.Allocate(b); - outputInsts.Add(Instruction.Create(OpCodes.Ldsfld, field)); - } - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConstObfusUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConstObfusUtil.cs.meta deleted file mode 100644 index 1646815d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ConstObfusUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4330e358b953be54c9f1ada2ff34156d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/DisableTypeDefFindCacheScope.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/DisableTypeDefFindCacheScope.cs deleted file mode 100644 index 30ccef2d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/DisableTypeDefFindCacheScope.cs +++ /dev/null @@ -1,21 +0,0 @@ -using dnlib.DotNet; -using System; - -namespace Obfuz.Utils -{ - public class DisableTypeDefFindCacheScope : IDisposable - { - private readonly ModuleDef _module; - - public DisableTypeDefFindCacheScope(ModuleDef module) - { - _module = module; - _module.EnableTypeDefFindCache = false; - } - - public void Dispose() - { - _module.EnableTypeDefFindCache = true; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/DisableTypeDefFindCacheScope.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/DisableTypeDefFindCacheScope.cs.meta deleted file mode 100644 index 349b119e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/DisableTypeDefFindCacheScope.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 89640cb831c78f8429c861fb49bae0e7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/EncryptionUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/EncryptionUtil.cs deleted file mode 100644 index d2f956ff..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/EncryptionUtil.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using UnityEngine; - -namespace Obfuz.Utils -{ - public static class EncryptionUtil - { - public static int GetBitCount(int value) - { - int count = 0; - while (value > 0) - { - count++; - value >>= 1; - } - return count; - } - - public static int GenerateEncryptionOpCodes(IRandom random, IEncryptor encryptor, int encryptionLevel) - { - if (encryptionLevel <= 0 || encryptionLevel > 4) - { - throw new ArgumentException($"Invalid encryption level: {encryptionLevel}, should be in range [1,4]"); - } - int vmOpCodeCount = encryptor.OpCodeCount; - long ops = 0; - for (int i = 0; i < encryptionLevel; i++) - { - long newOps = ops * vmOpCodeCount; - // don't use 0 - int op = random.NextInt(1, vmOpCodeCount); - newOps |= (uint)op; - if (newOps > uint.MaxValue) - { - Debug.LogWarning($"OpCode overflow. encryptionLevel:{encryptionLevel}, vmOpCodeCount:{vmOpCodeCount}"); - } - else - { - ops = newOps; - } - } - return (int)ops; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/EncryptionUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/EncryptionUtil.cs.meta deleted file mode 100644 index 5c82b2ba..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/EncryptionUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0b8fc4c92fa6f0b40a9734b347cd265c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/FileUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/FileUtil.cs deleted file mode 100644 index f7c38ee4..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/FileUtil.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.IO; -using System.Threading; - -namespace Obfuz.Utils -{ - public static class FileUtil - { - public static void CreateParentDir(string path) - { - Directory.CreateDirectory(Path.GetDirectoryName(path)); - } - - public static void RemoveDir(string dir, bool log = false) - { - if (log) - { - UnityEngine.Debug.Log($"removeDir dir:{dir}"); - } - - int maxTryCount = 5; - for (int i = 0; i < maxTryCount; ++i) - { - try - { - if (!Directory.Exists(dir)) - { - return; - } - foreach (var file in Directory.GetFiles(dir)) - { - File.SetAttributes(file, FileAttributes.Normal); - File.Delete(file); - } - foreach (var subDir in Directory.GetDirectories(dir)) - { - RemoveDir(subDir); - } - Directory.Delete(dir, true); - break; - } - catch (Exception e) - { - UnityEngine.Debug.LogError($"removeDir:{dir} with exception:{e}. try count:{i}"); - Thread.Sleep(100); - } - } - } - - public static void RecreateDir(string dir) - { - if (Directory.Exists(dir)) - { - RemoveDir(dir, true); - } - Directory.CreateDirectory(dir); - } - - private static void CopyWithCheckLongFile(string srcFile, string dstFile) - { - var maxPathLength = 255; -#if UNITY_EDITOR_OSX - maxPathLength = 1024; -#endif - if (srcFile.Length > maxPathLength) - { - UnityEngine.Debug.LogError($"srcFile:{srcFile} path is too long. skip copy!"); - return; - } - if (dstFile.Length > maxPathLength) - { - UnityEngine.Debug.LogError($"dstFile:{dstFile} path is too long. skip copy!"); - return; - } - File.Copy(srcFile, dstFile); - } - - public static void CopyDir(string src, string dst, bool log = false) - { - if (log) - { - UnityEngine.Debug.Log($"copyDir {src} => {dst}"); - } - RemoveDir(dst); - Directory.CreateDirectory(dst); - foreach (var file in Directory.GetFiles(src)) - { - CopyWithCheckLongFile(file, $"{dst}/{Path.GetFileName(file)}"); - } - foreach (var subDir in Directory.GetDirectories(src)) - { - CopyDir(subDir, $"{dst}/{Path.GetFileName(subDir)}"); - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/FileUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/FileUtil.cs.meta deleted file mode 100644 index c8523ce5..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/FileUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b6385af8bd061b142a3d7dcf41ab7e79 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/GenericArgumentContext.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/GenericArgumentContext.cs deleted file mode 100644 index 52328adb..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/GenericArgumentContext.cs +++ /dev/null @@ -1,111 +0,0 @@ -using dnlib.DotNet; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Obfuz.Utils -{ - public sealed class GenericArgumentContext - { - public readonly List typeArgsStack; - public readonly List methodArgsStack; - - public GenericArgumentContext(IList typeArgsStack, IList methodArgsStack) - { - this.typeArgsStack = typeArgsStack?.ToList(); - this.methodArgsStack = methodArgsStack?.ToList(); - } - - public TypeSig Resolve(TypeSig typeSig) - { - if (!typeSig.ContainsGenericParameter) - { - return typeSig; - } - typeSig = typeSig.RemovePinnedAndModifiers(); - switch (typeSig.ElementType) - { - case ElementType.Ptr: return new PtrSig(Resolve(typeSig.Next)); - case ElementType.ByRef: return new ByRefSig(Resolve(typeSig.Next)); - - case ElementType.SZArray: return new SZArraySig(Resolve(typeSig.Next)); - case ElementType.Array: - { - var ara = (ArraySig)typeSig; - return new ArraySig(Resolve(typeSig.Next), ara.Rank, ara.Sizes, ara.LowerBounds); - } - - case ElementType.Var: - { - GenericVar genericVar = (GenericVar)typeSig; - var newSig = Resolve(typeArgsStack, genericVar.Number); - if (newSig == null) - { - throw new Exception(); - } - return newSig; - } - - case ElementType.MVar: - { - GenericMVar genericVar = (GenericMVar)typeSig; - var newSig = Resolve(methodArgsStack, genericVar.Number); - if (newSig == null) - { - throw new Exception(); - } - return newSig; - } - case ElementType.GenericInst: - { - var gia = (GenericInstSig)typeSig; - return new GenericInstSig(gia.GenericType, gia.GenericArguments.Select(ga => Resolve(ga)).ToList()); - } - - case ElementType.FnPtr: - { - var fptr = (FnPtrSig)typeSig; - var cs = fptr.Signature; - CallingConventionSig ccs; - switch (cs) - { - case MethodSig ms: - { - ccs = new MethodSig(ms.GetCallingConvention(), ms.GenParamCount, Resolve(ms.RetType), ms.Params.Select(p => Resolve(p)).ToList()); - break; - } - case PropertySig ps: - { - ccs = new PropertySig(ps.HasThis, Resolve(ps.RetType)); - break; - } - case GenericInstMethodSig gims: - { - ccs = new GenericInstMethodSig(gims.GenericArguments.Select(ga => Resolve(ga)).ToArray()); - break; - } - default: throw new NotSupportedException(cs.ToString()); - } - return new FnPtrSig(ccs); - } - - case ElementType.ValueArray: - { - var vas = (ValueArraySig)typeSig; - return new ValueArraySig(Resolve(vas.Next), vas.Size); - } - default: return typeSig; - } - } - - private TypeSig Resolve(List args, uint number) - { - if (args == null) - { - throw new ArgumentNullException(nameof(args)); - } - return args[(int)number]; - } - } - -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/GenericArgumentContext.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/GenericArgumentContext.cs.meta deleted file mode 100644 index fd13834f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/GenericArgumentContext.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cdefb4e144f6a98418c7bd02eab51039 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/HashUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/HashUtil.cs deleted file mode 100644 index 3e128292..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/HashUtil.cs +++ /dev/null @@ -1,67 +0,0 @@ -using dnlib.DotNet; -using System.Collections; -using System.Collections.Generic; - -namespace Obfuz.Utils -{ - public static class HashUtil - { - public static int CombineHash(int hash1, int hash2) - { - return hash1 * 1566083941 + hash2; - } - - public static int ComputeHash(TypeSig sig) - { - return TypeEqualityComparer.Instance.GetHashCode(sig); - } - - public static int ComputeHash(IList sigs) - { - int hash = 135781321; - TypeEqualityComparer tc = TypeEqualityComparer.Instance; - foreach (var sig in sigs) - { - hash = hash * 1566083941 + tc.GetHashCode(sig); - } - return hash; - } - - public static unsafe int ComputeHash(string s) - { - fixed (char* ptr = s) - { - int num = 352654597; - int num2 = num; - int* ptr2 = (int*)ptr; - int num3; - for (num3 = s.Length; num3 > 2; num3 -= 4) - { - num = ((num << 5) + num + (num >> 27)) ^ *ptr2; - num2 = ((num2 << 5) + num2 + (num2 >> 27)) ^ ptr2[1]; - ptr2 += 2; - } - - if (num3 > 0) - { - num = ((num << 5) + num + (num >> 27)) ^ *ptr2; - } - - return num + num2 * 1566083941; - } - } - - public static int ComputePrimitiveOrStringOrBytesHashCode(object obj) - { - if (obj is byte[] bytes) - { - return StructuralComparisons.StructuralEqualityComparer.GetHashCode(bytes); - } - if (obj is string s) - { - return HashUtil.ComputeHash(s); - } - return obj.GetHashCode(); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/HashUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/HashUtil.cs.meta deleted file mode 100644 index d89f8f0d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/HashUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0b4cd05dd413bfa4ebb9fcbe591b1486 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IAssemblyResolver.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IAssemblyResolver.cs deleted file mode 100644 index 9e048793..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IAssemblyResolver.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Obfuz.Utils -{ - public interface IAssemblyResolver - { - string ResolveAssembly(string assemblyName); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IAssemblyResolver.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IAssemblyResolver.cs.meta deleted file mode 100644 index 917a107e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IAssemblyResolver.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e0254d9726a78e146af99a61641b47d3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IRandom.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IRandom.cs deleted file mode 100644 index e37ca145..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IRandom.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Obfuz.Utils -{ - public interface IRandom - { - int NextInt(int min, int max); - - int NextInt(int max); - - int NextInt(); - - long NextLong(); - - float NextFloat(); - - bool NextInPercentage(float percentage); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IRandom.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IRandom.cs.meta deleted file mode 100644 index 086b0737..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/IRandom.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 959c821ff51056c4ebca3f89aeeff03d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/KeyGenerator.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/KeyGenerator.cs deleted file mode 100644 index ea5a6816..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/KeyGenerator.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Security.Cryptography; -using System.Text; - -namespace Obfuz.Utils -{ - public static class KeyGenerator - { - public static byte[] GenerateKey(string initialString, int keyLength) - { - byte[] initialBytes = Encoding.UTF8.GetBytes(initialString); - using (var sha512 = SHA512.Create()) - { - byte[] hash = sha512.ComputeHash(initialBytes); - byte[] key = new byte[keyLength]; - int bytesCopied = 0; - while (bytesCopied < key.Length) - { - if (bytesCopied > 0) - { - // 再次哈希之前的哈希值以生成更多数据 - hash = sha512.ComputeHash(hash); - } - int bytesToCopy = Math.Min(hash.Length, key.Length - bytesCopied); - Buffer.BlockCopy(hash, 0, key, bytesCopied, bytesToCopy); - bytesCopied += bytesToCopy; - } - return key; - } - } - - public static int[] ConvertToIntKey(byte[] key) - { - return EncryptorBase.ConvertToIntKey(key); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/KeyGenerator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/KeyGenerator.cs.meta deleted file mode 100644 index 7d11ff06..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/KeyGenerator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5441ac16fd88a8848af862be23bd2ecb -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MathUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MathUtil.cs deleted file mode 100644 index dad6d2ef..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MathUtil.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; - -namespace Obfuz.Utils -{ - - internal static class MathUtil - { - //public static int ModInverseOdd32(int sa) - //{ - // uint a = (uint)sa; - // if (a % 2 == 0) - // throw new ArgumentException("Input must be an odd number.", nameof(a)); - - // uint x = 1; // 初始解:x₀ = 1 (mod 2) - // for (int i = 0; i < 5; i++) // 迭代5次(2^1 → 2^32) - // { - // int shift = 2 << i; // 当前模数为 2^(2^(i+1)) - // ulong mod = 1UL << shift; // 使用 ulong 避免溢出 - // ulong ax = (ulong)a * x; // 计算 a*x(64位避免截断) - // ulong term = (2 - ax) % mod; - // x = (uint)((x * term) % mod); // 更新 x,结果截断为 uint - // } - // return (int)x; // 最终解为 x₅ mod 2^32 - //} - - public static int ModInverse32(int sa) - { - uint x = (uint)sa; - if ((x & 1) == 0) - throw new ArgumentException("x must be odd (coprime with 2^32)"); - - uint inv = x; - inv = inv * (2 - x * inv); // 1 - inv = inv * (2 - x * inv); // 2 - inv = inv * (2 - x * inv); // 3 - inv = inv * (2 - x * inv); // 4 - inv = inv * (2 - x * inv); // 5 - return (int)inv; - } - - public static long ModInverse64(long sx) - { - ulong x = (ulong)sx; - if ((x & 1) == 0) - throw new ArgumentException("x must be odd (coprime with 2^64)"); - - ulong inv = x; - inv *= 2 - x * inv; // 1 - inv *= 2 - x * inv; // 2 - inv *= 2 - x * inv; // 3 - inv *= 2 - x * inv; // 4 - inv *= 2 - x * inv; // 5 - inv *= 2 - x * inv; // 6 - - return (long)inv; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MathUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MathUtil.cs.meta deleted file mode 100644 index 4dc5598c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MathUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8d5962b5e88adac40a2b1c65a8d304bc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MetaUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MetaUtil.cs deleted file mode 100644 index ac48fcac..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MetaUtil.cs +++ /dev/null @@ -1,922 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Editor; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using UnityEngine.Assertions; - -namespace Obfuz.Utils -{ - - public static class MetaUtil - { - public static string GetModuleNameWithoutExt(string moduleName) - { - return Path.GetFileNameWithoutExtension(moduleName); - } - - public static (string, string) SplitNamespaceAndName(string fullName) - { - int index = fullName.LastIndexOf('/'); - if (index == -1) - { - int index2 = fullName.IndexOf('.'); - return index2 >= 0 ? (fullName.Substring(0, index2), fullName.Substring(index2 + 1)) : ("", fullName); - } - return ("", fullName.Substring(index + 1)); - } - - public static bool IsVoidType(TypeSig type) - { - return type.RemovePinnedAndModifiers().ElementType == ElementType.Void; - } - - public static TypeDef GetBaseTypeDef(TypeDef type) - { - ITypeDefOrRef baseType = type.BaseType; - if (baseType == null) - { - return null; - } - TypeDef baseTypeDef = baseType.ResolveTypeDef(); - if (baseTypeDef != null) - { - return baseTypeDef; - } - if (baseType is TypeSpec baseTypeSpec) - { - GenericInstSig genericIns = baseTypeSpec.TypeSig.ToGenericInstSig(); - return genericIns.GenericType.TypeDefOrRef.ResolveTypeDefThrow(); - } - else - { - throw new Exception($"GetBaseTypeDef: {type} fail"); - } - } - - public static TypeDef GetTypeDefOrGenericTypeBaseThrowException(ITypeDefOrRef type) - { - if (type.IsTypeDef) - { - return (TypeDef)type; - } - if (type.IsTypeRef) - { - return type.ResolveTypeDefThrow(); - } - if (type.IsTypeSpec) - { - GenericInstSig gis = type.TryGetGenericInstSig(); - return gis.GenericType.ToTypeDefOrRef().ResolveTypeDefThrow(); - } - throw new NotSupportedException($"{type}"); - } - - public static TypeDef GetTypeDefOrGenericTypeBaseOrNull(ITypeDefOrRef type) - { - if (type.IsTypeDef) - { - return (TypeDef)type; - } - if (type.IsTypeRef) - { - return type.ResolveTypeDefThrow(); - } - if (type.IsTypeSpec) - { - GenericInstSig gis = type.TryGetGenericInstSig(); - if (gis == null) - { - return null; - } - return gis.GenericType.ToTypeDefOrRef().ResolveTypeDefThrow(); - } - return null; - } - - public static TypeDef GetMemberRefTypeDefParentOrNull(IMemberRefParent parent) - { - if (parent is TypeDef typeDef) - { - return typeDef; - } - if (parent is TypeRef typeRef) - { - return typeRef.ResolveTypeDefThrow(); - } - if (parent is TypeSpec typeSpec) - { - GenericInstSig gis = typeSpec.TryGetGenericInstSig(); - if (gis == null) - { - return null; - } - return gis.GenericType.TypeDefOrRef.ResolveTypeDefThrow(); - } - return null; - } - - public static bool IsInheritFromDOTSTypes(TypeDef typeDef) - { - TypeDef cur = typeDef; - while (true) - { - if (cur.Namespace.StartsWith("Unity.Entities") || - //cur.Namespace.StartsWith("Unity.Jobs") || - cur.Namespace.StartsWith("Unity.Burst")) - { - return true; - } - foreach (var interfaceType in cur.Interfaces) - { - TypeDef interfaceTypeDef = interfaceType.Interface.ResolveTypeDef(); - if (interfaceTypeDef != null && (interfaceTypeDef.Namespace.StartsWith("Unity.Entities") || - //interfaceTypeDef.Namespace.StartsWith("Unity.Jobs") || - interfaceTypeDef.Namespace.StartsWith("Unity.Burst"))) - { - return true; - } - } - - cur = GetBaseTypeDef(cur); - if (cur == null) - { - return false; - } - } - } - - public static bool IsInheritFromMonoBehaviour(TypeDef typeDef) - { - TypeDef cur = typeDef; - while (true) - { - cur = GetBaseTypeDef(cur); - if (cur == null) - { - return false; - } - if (cur.Name == "MonoBehaviour" && cur.Namespace == "UnityEngine" && cur.Module.Name == "UnityEngine.CoreModule.dll") - { - return true; - } - } - } - - - public static bool IsScriptType(TypeDef type) - { - for (TypeDef parentType = GetBaseTypeDef(type); parentType != null; parentType = GetBaseTypeDef(parentType)) - { - if ((parentType.Name == "MonoBehaviour" || parentType.Name == "ScriptableObject") - && parentType.Namespace == "UnityEngine" - && parentType.Module.Assembly.Name == "UnityEngine.CoreModule") - { - return true; - } - } - - return false; - } - - public static bool IsSerializableType(TypeDef type) - { - return type.IsSerializable; - } - - public static bool IsScriptOrSerializableType(TypeDef type) - { - return type.IsSerializable || IsScriptType(type); - } - - public static bool IsSerializableTypeSig(TypeSig typeSig) - { - typeSig = typeSig.RemovePinnedAndModifiers(); - switch (typeSig.ElementType) - { - case ElementType.Boolean: - case ElementType.Char: - case ElementType.I1: - case ElementType.U1: - case ElementType.I2: - case ElementType.U2: - case ElementType.I4: - case ElementType.U4: - case ElementType.I8: - case ElementType.U8: - case ElementType.R4: - case ElementType.R8: - case ElementType.String: - return true; - case ElementType.Class: - return IsScriptOrSerializableType(typeSig.ToTypeDefOrRef().ResolveTypeDefThrow()); - case ElementType.ValueType: - { - TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow(); - if (typeDef.IsEnum) - { - return true; - } - return typeDef.IsSerializable; - } - case ElementType.GenericInst: - { - GenericInstSig genericIns = typeSig.ToGenericInstSig(); - TypeDef typeDef = genericIns.GenericType.ToTypeDefOrRef().ResolveTypeDefThrow(); - return typeDef.FullName == "System.Collections.Generic.List`1" && IsSerializableTypeSig(genericIns.GenericArguments[0]); - } - case ElementType.SZArray: - { - return IsSerializableTypeSig(typeSig.RemovePinnedAndModifiers().Next); - } - default: - return false; - } - } - - public static bool IsSerializableField(FieldDef field) - { - if (field.IsStatic) - { - return false; - } - var fieldSig = field.FieldSig.Type; - if (field.IsPublic) - { - return IsSerializableTypeSig(fieldSig); - } - if (field.CustomAttributes.Any(c => c.TypeFullName == "UnityEngine.SerializeField")) - { - //UnityEngine.Debug.Assert(IsSerializableTypeSig(fieldSig)); - return true; - } - return false; - } - - public static bool MayRenameCustomDataType(ElementType type) - { - return type == ElementType.Class || type == ElementType.ValueType || type == ElementType.Object || type == ElementType.SZArray; - } - - public static TypeSig RetargetTypeRefInTypeSig(TypeSig type) - { - TypeSig next = type.Next; - TypeSig newNext = next != null ? RetargetTypeRefInTypeSig(next) : null; - if (type.IsModifier || type.IsPinned) - { - if (next == newNext) - { - return type; - } - if (type is CModReqdSig cmrs) - { - return new CModReqdSig(cmrs.Modifier, newNext); - } - if (type is CModOptSig cmos) - { - return new CModOptSig(cmos.Modifier, newNext); - } - if (type is PinnedSig ps) - { - return new PinnedSig(newNext); - } - throw new System.NotSupportedException(type.ToString()); - } - switch (type.ElementType) - { - case ElementType.Ptr: - { - if (next == newNext) - { - return type; - } - return new PtrSig(newNext); - } - case ElementType.ValueType: - case ElementType.Class: - { - var vts = type as ClassOrValueTypeSig; - if (vts.TypeDefOrRef is TypeDef typeDef) - { - return type; - } - TypeRef typeRef = (TypeRef)vts.TypeDefOrRef; - if (typeRef.DefinitionAssembly.IsCorLib()) - { - return type; - } - typeDef = typeRef.ResolveTypeDefThrow(); - return type.IsClassSig ? (TypeSig)new ClassSig(typeDef) : new ValueTypeSig(typeDef); - } - case ElementType.Array: - { - if (next == newNext) - { - return type; - } - return new ArraySig(newNext); - } - case ElementType.SZArray: - { - if (next == newNext) - { - return type; - } - return new SZArraySig(newNext); - } - case ElementType.GenericInst: - { - var gis = type as GenericInstSig; - ClassOrValueTypeSig genericType = gis.GenericType; - ClassOrValueTypeSig newGenericType = (ClassOrValueTypeSig)RetargetTypeRefInTypeSig(genericType); - bool anyChange = genericType != newGenericType; - var genericArgs = new List(); - foreach (var arg in gis.GenericArguments) - { - TypeSig newArg = RetargetTypeRefInTypeSig(arg); - anyChange |= newArg != arg; - genericArgs.Add(newArg); - } - if (!anyChange) - { - return type; - } - return new GenericInstSig(newGenericType, genericArgs); - } - case ElementType.FnPtr: - { - var fp = type as FnPtrSig; - MethodSig methodSig = fp.MethodSig; - TypeSig newReturnType = RetargetTypeRefInTypeSig(methodSig.RetType); - bool anyChange = newReturnType != methodSig.RetType; - var newArgs = new List(); - foreach (TypeSig arg in methodSig.Params) - { - TypeSig newArg = RetargetTypeRefInTypeSig(arg); - anyChange |= newArg != newReturnType; - } - if (!anyChange) - { - return type; - } - var newParamsAfterSentinel = new List(); - foreach (TypeSig arg in methodSig.ParamsAfterSentinel) - { - TypeSig newArg = RetargetTypeRefInTypeSig(arg); - anyChange |= newArg != arg; - newParamsAfterSentinel.Add(newArg); - } - - var newMethodSig = new MethodSig(methodSig.CallingConvention, methodSig.GenParamCount, newReturnType, newArgs, newParamsAfterSentinel); - return new FnPtrSig(newMethodSig); - } - case ElementType.ByRef: - { - if (next == newNext) - { - return type; - } - return new ByRefSig(newNext); - } - default: - { - return type; - } - } - } - - - public static object RetargetTypeRefInTypeSigOfValue(object oldValue) - { - if (oldValue == null) - { - return null; - } - string typeName = oldValue.GetType().FullName; - if (oldValue.GetType().IsPrimitive) - { - return oldValue; - } - if (oldValue is string || oldValue is UTF8String) - { - return oldValue; - } - if (oldValue is TypeSig typeSig) - { - return RetargetTypeRefInTypeSig(typeSig); - } - if (oldValue is CAArgument caValue) - { - TypeSig newType = RetargetTypeRefInTypeSig(caValue.Type); - object newValue = RetargetTypeRefInTypeSigOfValue(caValue.Value); - if (newType != caValue.Type || newValue != caValue.Value) - { - return new CAArgument(newType, newValue); - } - return oldValue; - } - if (oldValue is List oldArr) - { - bool anyChange = false; - var newArr = new List(); - foreach (CAArgument oldArg in oldArr) - { - if (TryRetargetTypeRefInArgument(oldArg, out var newArg)) - { - anyChange = true; - newArr.Add(newArg); - } - else - { - newArr.Add(oldArg); - } - } - return anyChange ? newArr : oldArr; - } - throw new NotSupportedException($"type:{oldValue.GetType()} value:{oldValue}"); - } - - - - public static bool TryRetargetTypeRefInArgument(CAArgument oldArg, out CAArgument newArg) - { - TypeSig newType = RetargetTypeRefInTypeSig(oldArg.Type); - object newValue = RetargetTypeRefInTypeSigOfValue(oldArg.Value); - if (newType != oldArg.Type || oldArg.Value != newValue) - { - newArg = new CAArgument(newType, newValue); - return true; - } - newArg = default; - return false; - } - - public static bool TryRetargetTypeRefInNamedArgument(CANamedArgument arg) - { - bool anyChange = false; - TypeSig newType = RetargetTypeRefInTypeSig(arg.Type); - if (newType != arg.Type) - { - anyChange = true; - arg.Type = newType; - } - if (TryRetargetTypeRefInArgument(arg.Argument, out var newArg)) - { - arg.Argument = newArg; - anyChange = true; - } - return anyChange; - } - - //public static bool ContainsContainsGenericParameter1(MethodDef method) - //{ - // Assert.IsTrue(!(method.DeclaringType.ContainsGenericParameter || method.MethodSig.ContainsGenericParameter)); - // return false; - //} - - public static bool ContainsContainsGenericParameter1(MethodSpec methodSpec) - { - if (methodSpec.GenericInstMethodSig.ContainsGenericParameter) - { - return true; - } - IMethodDefOrRef method = methodSpec.Method; - if (method.IsMethodDef) - { - return false;// ContainsContainsGenericParameter1((MethodDef)method); - } - if (method.IsMemberRef) - { - return ContainsContainsGenericParameter1((MemberRef)method); - } - throw new Exception($"unknown method: {method}"); - } - - public static bool ContainsContainsGenericParameter1(MemberRef memberRef) - { - IMemberRefParent parent = memberRef.Class; - if (parent is TypeSpec typeSpec) - { - return typeSpec.ContainsGenericParameter; - } - return false; - } - - public static bool ContainsContainsGenericParameter(IMethod method) - { - Assert.IsTrue(method.IsMethod); - if (method is MethodDef methodDef) - { - return false; - } - - if (method is MethodSpec methodSpec) - { - return ContainsContainsGenericParameter1(methodSpec); - } - if (method is MemberRef memberRef) - { - return ContainsContainsGenericParameter1(memberRef); - } - throw new Exception($"unknown method: {method}"); - } - - - - public static TypeSig Inflate(TypeSig sig, GenericArgumentContext ctx) - { - if (ctx == null || !sig.ContainsGenericParameter) - { - return sig; - } - return ctx.Resolve(sig); - } - - public static IList TryInflate(IList sig, GenericArgumentContext ctx) - { - if (sig == null || ctx == null) - { - return sig; - } - return sig.Select(s => Inflate(s, ctx)).ToList() ?? null; - } - - - public static MethodSig InflateMethodSig(MethodSig methodSig, GenericArgumentContext genericArgumentContext) - { - var newReturnType = Inflate(methodSig.RetType, genericArgumentContext); - var newParams = new List(); - foreach (var param in methodSig.Params) - { - newParams.Add(Inflate(param, genericArgumentContext)); - } - var newParamsAfterSentinel = new List(); - if (methodSig.ParamsAfterSentinel != null) - { - throw new NotSupportedException($"methodSig.ParamsAfterSentinel is not supported: {methodSig}"); - //foreach (var param in methodSig.ParamsAfterSentinel) - //{ - // newParamsAfterSentinel.Add(Inflate(param, genericArgumentContext)); - //} - } - return new MethodSig(methodSig.CallingConvention, methodSig.GenParamCount, newReturnType, newParams, null); - } - - public static IList GetGenericArguments(IMemberRefParent type) - { - if (type is TypeDef typeDef) - { - return null; - } - if (type is TypeRef typeRef) - { - return null; - } - if (type is TypeSpec typeSpec) - { - GenericInstSig genericInstSig = typeSpec.TypeSig.ToGenericInstSig(); - return genericInstSig?.GenericArguments; - } - throw new NotSupportedException($"type:{type}"); - } - - public static GenericArgumentContext GetInflatedMemberRefGenericArgument(IMemberRefParent type, GenericArgumentContext ctx) - { - if (type is TypeDef typeDef) - { - return null; - } - if (type is TypeRef typeRef) - { - return null; - } - if (type is TypeSpec typeSpec) - { - GenericInstSig genericInstSig = typeSpec.TypeSig.ToGenericInstSig(); - if (genericInstSig == null) - { - return ctx; - } - return new GenericArgumentContext(TryInflate(genericInstSig.GenericArguments, ctx), null); - } - throw new NotSupportedException($"type:{type}"); - } - - public static MethodSig GetInflatedMethodSig(IMethod method, GenericArgumentContext ctx) - { - if (method is MethodDef methodDef) - { - return methodDef.MethodSig; - } - if (method is MemberRef memberRef) - { - return InflateMethodSig(memberRef.MethodSig, GetInflatedMemberRefGenericArgument(memberRef.Class, ctx)); - } - if (method is MethodSpec methodSpec) - { - var genericInstMethodSig = methodSpec.GenericInstMethodSig; - if (methodSpec.Method is MethodDef methodDef2) - { - return InflateMethodSig(methodDef2.MethodSig, new GenericArgumentContext(null, TryInflate(genericInstMethodSig.GenericArguments, ctx))); - } - if (methodSpec.Method is MemberRef memberRef2) - { - return InflateMethodSig(memberRef2.MethodSig, new GenericArgumentContext( - GetInflatedMemberRefGenericArgument(memberRef2.Class, ctx)?.typeArgsStack, - TryInflate(genericInstMethodSig.GenericArguments, ctx))); - } - - } - throw new NotSupportedException($" method: {method}"); - } - - public static TypeSig InflateFieldSig(IField field, GenericArgumentContext ctx) - { - if (field is FieldDef fieldDef) - { - return fieldDef.FieldType; - } - if (field is MemberRef memberRef) - { - return Inflate(memberRef.FieldSig.Type, new GenericArgumentContext(TryInflate(GetGenericArguments(memberRef.Class), ctx), null)); - } - - throw new Exception($"unknown field:{field}"); - } - - public static ThisArgType GetThisArgType(IMethod method) - { - if (!method.MethodSig.HasThis) - { - return ThisArgType.None; - } - if (method is MethodDef methodDef) - { - return methodDef.DeclaringType.IsValueType ? ThisArgType.ValueType : ThisArgType.Class; - } - if (method is MemberRef memberRef) - { - TypeDef typeDef = MetaUtil.GetMemberRefTypeDefParentOrNull(memberRef.Class); - if (typeDef == null) - { - return ThisArgType.Class; - } - return typeDef.IsValueType ? ThisArgType.ValueType : ThisArgType.Class; - } - if (method is MethodSpec methodSpec) - { - return GetThisArgType(methodSpec.Method); - } - throw new NotSupportedException($" method: {method}"); - } - - public static MethodSig ToSharedMethodSig(ICorLibTypes corTypes, MethodSig methodSig) - { - var newReturnType = methodSig.RetType; - var newParams = new List(); - foreach (var param in methodSig.Params) - { - newParams.Add(ToShareTypeSig(corTypes, param)); - } - if (methodSig.ParamsAfterSentinel != null) - { - //foreach (var param in methodSig.ParamsAfterSentinel) - //{ - // newParamsAfterSentinel.Add(ToShareTypeSig(corTypes, param)); - //} - throw new NotSupportedException($"methodSig.ParamsAfterSentinel is not supported: {methodSig}"); - } - return new MethodSig(methodSig.CallingConvention, methodSig.GenParamCount, newReturnType, newParams, null); - } - - public static TypeSig ToShareTypeSig(ICorLibTypes corTypes, TypeSig typeSig) - { - var a = typeSig.RemovePinnedAndModifiers(); - switch (a.ElementType) - { - case ElementType.Void: return corTypes.Void; - case ElementType.Boolean: return corTypes.Byte; - case ElementType.Char: return corTypes.UInt16; - case ElementType.I1: return corTypes.SByte; - case ElementType.U1: return corTypes.Byte; - case ElementType.I2: return corTypes.Int16; - case ElementType.U2: return corTypes.UInt16; - case ElementType.I4: return corTypes.Int32; - case ElementType.U4: return corTypes.UInt32; - case ElementType.I8: return corTypes.Int64; - case ElementType.U8: return corTypes.UInt64; - case ElementType.R4: return corTypes.Single; - case ElementType.R8: return corTypes.Double; - case ElementType.String: return corTypes.Object; - case ElementType.TypedByRef: return corTypes.TypedReference; - case ElementType.I: return corTypes.IntPtr; - case ElementType.U: return corTypes.UIntPtr; - case ElementType.Object: return corTypes.Object; - case ElementType.Sentinel: return typeSig; - case ElementType.Ptr: return corTypes.UIntPtr; - case ElementType.ByRef: return corTypes.UIntPtr; - case ElementType.SZArray: return typeSig; - case ElementType.Array: return typeSig; - case ElementType.ValueType: - { - TypeDef typeDef = a.ToTypeDefOrRef().ResolveTypeDef(); - if (typeDef == null) - { - throw new Exception($"type:{a} definition could not be found"); - } - if (typeDef.IsEnum) - { - return ToShareTypeSig(corTypes, typeDef.GetEnumUnderlyingType()); - } - return typeSig; - } - case ElementType.Var: - case ElementType.MVar: - case ElementType.Class: return corTypes.Object; - case ElementType.GenericInst: - { - var gia = (GenericInstSig)a; - TypeDef typeDef = gia.GenericType.ToTypeDefOrRef().ResolveTypeDef(); - if (typeDef == null) - { - throw new Exception($"type:{a} definition could not be found"); - } - if (typeDef.IsEnum) - { - return ToShareTypeSig(corTypes, typeDef.GetEnumUnderlyingType()); - } - if (!typeDef.IsValueType) - { - return corTypes.Object; - } - // il2cpp will raise error when try to share generic value type - return typeSig; - //return new GenericInstSig(gia.GenericType, gia.GenericArguments.Select(ga => ToShareTypeSig(corTypes, ga)).ToList()); - } - case ElementType.FnPtr: return corTypes.UIntPtr; - case ElementType.ValueArray: return typeSig; - case ElementType.Module: return typeSig; - default: - throw new NotSupportedException(typeSig.ToString()); - } - } - - - public static void AppendIl2CppStackTraceNameOfTypeSig(StringBuilder sb, TypeSig typeSig) - { - typeSig = typeSig.RemovePinnedAndModifiers(); - - switch (typeSig.ElementType) - { - case ElementType.Void: sb.Append("Void"); break; - case ElementType.Boolean: sb.Append("Boolean"); break; - case ElementType.Char: sb.Append("Char"); break; - case ElementType.I1: sb.Append("SByte"); break; - case ElementType.U1: sb.Append("Byte"); break; - case ElementType.I2: sb.Append("Int16"); break; - case ElementType.U2: sb.Append("UInt16"); break; - case ElementType.I4: sb.Append("Int32"); break; - case ElementType.U4: sb.Append("UInt32"); break; - case ElementType.I8: sb.Append("Int64"); break; - case ElementType.U8: sb.Append("UInt64"); break; - case ElementType.R4: sb.Append("Single"); break; - case ElementType.R8: sb.Append("Double"); break; - case ElementType.String: sb.Append("String"); break; - case ElementType.Ptr: AppendIl2CppStackTraceNameOfTypeSig(sb, typeSig.Next); sb.Append("*"); break; - case ElementType.ByRef: AppendIl2CppStackTraceNameOfTypeSig(sb, typeSig.Next); sb.Append("&"); break; - case ElementType.ValueType: - case ElementType.Class: - { - var classOrValueTypeSig = (ClassOrValueTypeSig)typeSig; - TypeDef typeDef = classOrValueTypeSig.TypeDefOrRef.ResolveTypeDef(); - if (typeDef == null) - { - throw new Exception($"type:{classOrValueTypeSig} definition could not be found"); - } - sb.Append(typeDef.Name); - break; - } - case ElementType.GenericInst: - { - var genericInstSig = (GenericInstSig)typeSig; - AppendIl2CppStackTraceNameOfTypeSig(sb, genericInstSig.GenericType); - break; - } - case ElementType.Var: - case ElementType.MVar: - { - var varSig = (GenericSig)typeSig; - sb.Append(varSig.GenericParam.Name); - break; - } - case ElementType.I: sb.Append("IntPtr"); break; - case ElementType.U: sb.Append("UIntPtr"); break; - case ElementType.FnPtr: sb.Append("IntPtr"); break; - case ElementType.Object: sb.Append("Object"); break; - case ElementType.SZArray: - { - var szArraySig = (SZArraySig)typeSig; - AppendIl2CppStackTraceNameOfTypeSig(sb, szArraySig.Next); - sb.Append("[]"); - break; - } - case ElementType.Array: - { - var arraySig = (ArraySig)typeSig; - AppendIl2CppStackTraceNameOfTypeSig(sb, arraySig.Next); - sb.Append("["); - for (int i = 0; i < arraySig.Rank - 1; i++) - { - sb.Append(","); - } - sb.Append("]"); - break; - } - case ElementType.TypedByRef: sb.Append("TypedReference"); break; - default: - throw new NotSupportedException(typeSig.ToString()); - } - } - - public static TypeDef GetRootDeclaringType(TypeDef type) - { - TypeDef cur = type; - while (true) - { - TypeDef declaringType = cur.DeclaringType; - if (declaringType == null) - { - return cur; - } - cur = declaringType; - } - } - - public static string CreateMethodDefIl2CppStackTraceSignature(MethodDef method) - { - var result = new StringBuilder(); - TypeDef declaringType = method.DeclaringType; - - string namespaze = GetRootDeclaringType(declaringType).Namespace; - if (!string.IsNullOrEmpty(namespaze)) - { - result.Append(namespaze); - result.Append("."); - } - result.Append(declaringType.Name); - result.Append(":"); - result.Append(method.Name); - result.Append("("); - - int index = 0; - foreach (TypeSig p in method.GetParams()) - { - if (index > 0) - { - result.Append(", "); - } - AppendIl2CppStackTraceNameOfTypeSig(result, p); - ++index; - } - result.Append(")"); - return result.ToString(); - } - - public static bool HasCompilerGeneratedAttribute(IHasCustomAttribute obj) - { - return obj.CustomAttributes.Find(ConstValues.CompilerGeneratedAttributeFullName) != null; - } - - public static bool HasEncryptFieldAttribute(IHasCustomAttribute obj) - { - return obj.CustomAttributes.Find(ConstValues.EncryptFieldAttributeFullName) != null; - } - - public static bool HasRuntimeInitializeOnLoadMethodAttribute(MethodDef method) - { - return method.CustomAttributes.Find(ConstValues.RuntimeInitializedOnLoadMethodAttributeFullName) != null; - } - - public static bool HasBlackboardEnumAttribute(TypeDef typeDef) - { - return typeDef.CustomAttributes.Find(ConstValues.BlackboardEnumAttributeFullName) != null; - } - - public static bool HasBurstCompileAttribute(IHasCustomAttribute obj) - { - return obj.CustomAttributes.Find(ConstValues.BurstCompileFullName) != null; - } - - public static bool HasDOTSCompilerGeneratedAttribute(IHasCustomAttribute obj) - { - return obj.CustomAttributes.Find(ConstValues.DOTSCompilerGeneratedAttributeFullName) != null; - } - - public static bool HasMicrosoftCodeAnalysisEmbeddedAttribute(IHasCustomAttribute obj) - { - return obj.CustomAttributes.Find(ConstValues.EmbeddedAttributeFullName) != null; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MetaUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MetaUtil.cs.meta deleted file mode 100644 index 9ebbd424..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/MetaUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ded544371a7eb524caa1ccef3daebe55 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NameMatcher.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NameMatcher.cs deleted file mode 100644 index 8f6d5d68..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NameMatcher.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Text.RegularExpressions; - -namespace Obfuz.Utils -{ - public class NameMatcher - { - private readonly string _str; - private readonly Regex _regex; - - public string NameOrPattern => _str; - - public bool IsWildcardPattern => _regex != null; - - public NameMatcher(string nameOrPattern) - { - if (string.IsNullOrEmpty(nameOrPattern)) - { - nameOrPattern = "*"; - } - _str = nameOrPattern; - _regex = nameOrPattern.Contains("*") || nameOrPattern.Contains("?") ? new Regex(WildcardToRegex(nameOrPattern)) : null; - } - - public static string WildcardToRegex(string pattern) - { - return "^" + Regex.Escape(pattern). - Replace("\\*", ".*"). - Replace("\\?", ".") + "$"; - } - - public bool IsMatch(string name) - { - if (_regex != null) - { - return _regex.IsMatch(name); - } - else - { - return _str == name; - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NameMatcher.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NameMatcher.cs.meta deleted file mode 100644 index 6abe4e16..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NameMatcher.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c3a646fe086ecbd4a8dbf36a395ada71 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NumberRange.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NumberRange.cs deleted file mode 100644 index 90d55e0b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NumberRange.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Obfuz.Utils -{ - public class NumberRange where T : struct - { - public readonly T? min; - public readonly T? max; - - public NumberRange(T? min, T? max) - { - this.min = min; - this.max = max; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NumberRange.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NumberRange.cs.meta deleted file mode 100644 index f1b17e16..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/NumberRange.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4d147a6853ce57c4d88529fb73823435 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ObfuzIgnoreScopeComputeCache.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ObfuzIgnoreScopeComputeCache.cs deleted file mode 100644 index 162cfdeb..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ObfuzIgnoreScopeComputeCache.cs +++ /dev/null @@ -1,243 +0,0 @@ -using dnlib.DotNet; -using Obfuz.Editor; -using System.Linq; - -namespace Obfuz.Utils -{ - public class ObfuzIgnoreScopeComputeCache - { - private readonly CachedDictionary _selfObfuzIgnoreScopeCache; - private readonly CachedDictionary _enclosingObfuzIgnoreScopeCache; - private readonly CachedDictionary _selfObfuzIgnoreApplyToChildTypesScopeCache; - private readonly CachedDictionary _inheritedObfuzIgnoreScopeCache; - - public ObfuzIgnoreScopeComputeCache() - { - _selfObfuzIgnoreScopeCache = new CachedDictionary(GetObfuzIgnoreScope); - _enclosingObfuzIgnoreScopeCache = new CachedDictionary(GetEnclosingObfuzIgnoreScope); - _selfObfuzIgnoreApplyToChildTypesScopeCache = new CachedDictionary(GetObfuzIgnoreScopeApplyToChildTypes); - _inheritedObfuzIgnoreScopeCache = new CachedDictionary(GetInheritObfuzIgnoreScope); - } - - private ObfuzScope? GetObfuzIgnoreScope(IHasCustomAttribute obj) - { - var ca = obj.CustomAttributes.FirstOrDefault(c => c.AttributeType.FullName == ConstValues.ObfuzIgnoreAttributeFullName); - if (ca == null) - { - return null; - } - var scope = (ObfuzScope)ca.ConstructorArguments[0].Value; - return scope; - } - - private ObfuzScope? GetEnclosingObfuzIgnoreScope(TypeDef typeDef) - { - TypeDef cur = typeDef.DeclaringType; - while (cur != null) - { - var ca = cur.CustomAttributes?.FirstOrDefault(c => c.AttributeType.FullName == ConstValues.ObfuzIgnoreAttributeFullName); - if (ca != null) - { - var scope = (ObfuzScope)ca.ConstructorArguments[0].Value; - CANamedArgument inheritByNestedTypesArg = ca.GetNamedArgument("ApplyToNestedTypes", false); - bool inheritByNestedTypes = inheritByNestedTypesArg == null || (bool)inheritByNestedTypesArg.Value; - return inheritByNestedTypes ? (ObfuzScope?)scope : null; - } - cur = cur.DeclaringType; - } - return null; - } - - private ObfuzScope? GetObfuzIgnoreScopeApplyToChildTypes(TypeDef cur) - { - if (cur.Module.IsCoreLibraryModule == true) - { - return null; - } - var ca = cur.CustomAttributes?.FirstOrDefault(c => c.AttributeType.FullName == ConstValues.ObfuzIgnoreAttributeFullName); - if (ca != null) - { - var scope = (ObfuzScope)ca.ConstructorArguments[0].Value; - CANamedArgument inheritByChildTypesArg = ca.GetNamedArgument("ApplyToChildTypes", false); - bool inheritByChildTypes = inheritByChildTypesArg != null && (bool)inheritByChildTypesArg.Value; - if (inheritByChildTypes) - { - return scope; - } - } - return null; - } - - private ObfuzScope? GetInheritObfuzIgnoreScope(TypeDef typeDef) - { - TypeDef cur = typeDef; - for (; cur != null; cur = MetaUtil.GetBaseTypeDef(cur)) - { - ObfuzScope? scope = _selfObfuzIgnoreApplyToChildTypesScopeCache.GetValue(cur); - if (scope != null) - { - return scope; - } - foreach (var interfaceType in cur.Interfaces) - { - TypeDef interfaceTypeDef = interfaceType.Interface.ResolveTypeDef(); - if (interfaceTypeDef != null) - { - ObfuzScope? interfaceScope = _selfObfuzIgnoreApplyToChildTypesScopeCache.GetValue(interfaceTypeDef); - if (interfaceScope != null) - { - return interfaceScope; - } - } - } - } - return null; - } - - //private ObfuzScope? GetSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope((IHasCustomAttribute obj, TypeDef declaringType) objAndDeclaringType, ObfuzScope targetScope) - //{ - // ObfuzScope? scope = _selfObfuzIgnoreScopeCache.GetValue(objAndDeclaringType.obj); - // if (scope != null) - // { - // return scope; - // } - // if (objAndDeclaringType.declaringType == null) - // { - // return null; - // } - // ObfuzScope? declaringOrEnclosingScope = _selfObfuzIgnoreScopeCache.GetValue(declaringType) ?? _enclosingObfuzIgnoreScopeCache.GetValue(declaringType) ?? _inheritedObfuzIgnoreScopeCache.GetValue(declaringType); - // return declaringOrEnclosingScope != null && (declaringOrEnclosingScope & targetScope) != 0; - //} - - //private bool HasObfuzIgnoreScope(IHasCustomAttribute obj, ObfuzScope targetScope) - //{ - // ObfuzScope? objScope = _selfObfuzIgnoreScopeCache.GetValue(obj); - // return objScope != null && (objScope & targetScope) != 0; - //} - - //private bool HasDeclaringOrEnclosingOrInheritObfuzIgnoreScope(TypeDef typeDef, ObfuzScope targetScope) - //{ - // if (typeDef == null) - // { - // return false; - // } - // ObfuzScope? declaringOrEnclosingScope = _selfObfuzIgnoreScopeCache.GetValue(typeDef) ?? _enclosingObfuzIgnoreScopeCache.GetValue(typeDef) ?? _inheritedObfuzIgnoreScopeCache.GetValue(typeDef); - // return declaringOrEnclosingScope != null && (declaringOrEnclosingScope & targetScope) != 0; - //} - - public ObfuzScope? GetSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(IHasCustomAttribute obj, TypeDef declaringType) - { - ObfuzScope? scope = _selfObfuzIgnoreScopeCache.GetValue(obj); - if (scope != null) - { - return scope; - } - if (declaringType == null) - { - return null; - } - ObfuzScope? declaringOrEnclosingScope = _selfObfuzIgnoreScopeCache.GetValue(declaringType) ?? _enclosingObfuzIgnoreScopeCache.GetValue(declaringType) ?? _inheritedObfuzIgnoreScopeCache.GetValue(declaringType); - return declaringOrEnclosingScope; - } - - public bool HasSelfOrEnclosingOrInheritObfuzIgnoreScope(TypeDef typeDef, ObfuzScope targetScope) - { - ObfuzScope? scope = _selfObfuzIgnoreScopeCache.GetValue(typeDef) ?? _enclosingObfuzIgnoreScopeCache.GetValue(typeDef) ?? _inheritedObfuzIgnoreScopeCache.GetValue(typeDef); - return scope != null && (scope & targetScope) != 0; - } - - public bool HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(IHasCustomAttribute obj, TypeDef declaringType, ObfuzScope targetScope) - { - ObfuzScope? scope = _selfObfuzIgnoreScopeCache.GetValue(obj); - if (scope != null) - { - return (scope & targetScope) != 0; - } - if (declaringType == null) - { - return false; - } - ObfuzScope? declaringOrEnclosingScope = _selfObfuzIgnoreScopeCache.GetValue(declaringType) ?? _enclosingObfuzIgnoreScopeCache.GetValue(declaringType) ?? _inheritedObfuzIgnoreScopeCache.GetValue(declaringType); - return declaringOrEnclosingScope != null && (declaringOrEnclosingScope & targetScope) != 0; - } - - public bool HasSelfOrInheritPropertyOrEventOrOrTypeDefObfuzIgnoreScope(MethodDef obj, ObfuzScope targetScope) - { - ObfuzScope? scope = _selfObfuzIgnoreScopeCache.GetValue(obj); - if (scope != null && (scope & targetScope) != 0) - { - return true; - } - - TypeDef declaringType = obj.DeclaringType; - ObfuzScope? declaringOrEnclosingScope = _selfObfuzIgnoreScopeCache.GetValue(declaringType) ?? _enclosingObfuzIgnoreScopeCache.GetValue(declaringType) ?? _inheritedObfuzIgnoreScopeCache.GetValue(declaringType); - - foreach (var propertyDef in declaringType.Properties) - { - if (propertyDef.GetMethod == obj || propertyDef.SetMethod == obj) - { - ObfuzScope? finalScope = _selfObfuzIgnoreScopeCache.GetValue(propertyDef); - if (finalScope != null && (finalScope & targetScope) != 0) - { - return true; - } - break; - } - } - - foreach (var eventDef in declaringType.Events) - { - if (eventDef.AddMethod == obj || eventDef.RemoveMethod == obj) - { - ObfuzScope? finalScope = _selfObfuzIgnoreScopeCache.GetValue(eventDef); - if (finalScope != null && (finalScope & targetScope) != 0) - { - return true; - } - break; - } - } - - return declaringOrEnclosingScope != null && (declaringOrEnclosingScope & targetScope) != 0; - } - - public bool HasSelfOrInheritPropertyOrEventOrOrTypeDefIgnoreMethodName(MethodDef obj) - { - ObfuzScope? scope = _selfObfuzIgnoreScopeCache.GetValue(obj); - if (scope != null && (scope & ObfuzScope.MethodName) != 0) - { - return true; - } - - TypeDef declaringType = obj.DeclaringType; - - foreach (var propertyDef in declaringType.Properties) - { - if (propertyDef.GetMethod == obj || propertyDef.SetMethod == obj) - { - ObfuzScope? finalScope = GetObfuzIgnoreScope(propertyDef); - if (finalScope != null && (finalScope & ObfuzScope.PropertyGetterSetterName) != 0) - { - return true; - } - break; - } - } - - foreach (var eventDef in declaringType.Events) - { - if (eventDef.AddMethod == obj || eventDef.RemoveMethod == obj) - { - ObfuzScope? finalScope = GetObfuzIgnoreScope(eventDef); - if (finalScope != null && (finalScope & ObfuzScope.EventAddRemoveFireName) != 0) - { - return true; - } - break; - } - } - - return HasSelfOrEnclosingOrInheritObfuzIgnoreScope(declaringType, ObfuzScope.MethodName | ObfuzScope.PropertyGetterSetterName | ObfuzScope.EventAddRemoveFireName); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ObfuzIgnoreScopeComputeCache.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ObfuzIgnoreScopeComputeCache.cs.meta deleted file mode 100644 index fdc7e014..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ObfuzIgnoreScopeComputeCache.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2f64b9a72981c0e45a03501db02e6538 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PathAssemblyResolver.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PathAssemblyResolver.cs deleted file mode 100644 index d2e02e8f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PathAssemblyResolver.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.IO; - -namespace Obfuz.Utils -{ - public class PathAssemblyResolver : AssemblyResolverBase - { - private readonly string[] _searchPaths; - - public PathAssemblyResolver(params string[] searchPaths) - { - _searchPaths = searchPaths; - } - - public override string ResolveAssembly(string assemblyName) - { - foreach (var path in _searchPaths) - { - string assPath = Path.Combine(path, assemblyName + ".dll"); - if (File.Exists(assPath)) - { - //Debug.Log($"resolve {assemblyName} at {assPath}"); - return assPath; - } - } - return null; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PathAssemblyResolver.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PathAssemblyResolver.cs.meta deleted file mode 100644 index 1ae9c58f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PathAssemblyResolver.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5a7681737885f604e885ee39d0bedd74 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PlatformUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PlatformUtil.cs deleted file mode 100644 index 94f41e75..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PlatformUtil.cs +++ /dev/null @@ -1,13 +0,0 @@ -using UnityEditor; - -namespace Obfuz.Utils -{ - public static class PlatformUtil - { - public static bool IsMonoBackend() - { - return PlayerSettings.GetScriptingBackend(EditorUserBuildSettings.selectedBuildTargetGroup) - == ScriptingImplementation.Mono2x; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PlatformUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PlatformUtil.cs.meta deleted file mode 100644 index ec195e6d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/PlatformUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 85d01014c084c56498d292d3b16351d2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomUtil.cs deleted file mode 100644 index 0f542995..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomUtil.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; - -namespace Obfuz.Utils -{ - static class RandomUtil - { - public static void ShuffleList(List list, IRandom random) - { - int n = list.Count; - for (int i = n - 1; i > 0; i--) - { - int j = random.NextInt(i + 1); - T temp = list[i]; - list[i] = list[j]; - list[j] = temp; - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomUtil.cs.meta deleted file mode 100644 index 961f1be9..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d482c078394711d428e627843d2481d7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomWithKey.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomWithKey.cs deleted file mode 100644 index e66bfc64..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomWithKey.cs +++ /dev/null @@ -1,63 +0,0 @@ -namespace Obfuz.Utils -{ - public class RandomWithKey : IRandom - { - private const long a = 1664525; - private const long c = 1013904223; - private const long m = 4294967296; // 2^32 - - private readonly int[] _key; - - private int _nextIndex; - - private int _seed; - - public RandomWithKey(int[] key, int seed) - { - _key = key; - _seed = seed; - } - - public int[] Key => _key; - - public int NextInt(int min, int max) - { - return min + NextInt(max - min); - } - - public int NextInt(int max) - { - return (int)((uint)NextInt() % (uint)max); - } - - private int GetNextSalt() - { - if (_nextIndex >= _key.Length) - { - _nextIndex = 0; - } - return _key[_nextIndex++]; - } - - public int NextInt() - { - _seed = (int)((a * _seed + c) % m); - return _seed ^ GetNextSalt(); - } - - public long NextLong() - { - return ((long)NextInt() << 32) | (uint)NextInt(); - } - - public float NextFloat() - { - return (float)((double)(uint)NextInt() / uint.MaxValue); - } - - public bool NextInPercentage(float percentage) - { - return NextFloat() < percentage; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomWithKey.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomWithKey.cs.meta deleted file mode 100644 index 41b7f75e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/RandomWithKey.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6e16d7eb75fe2354d96eca5bb01358a4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ReflectionUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ReflectionUtil.cs deleted file mode 100644 index f15140da..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ReflectionUtil.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Obfuz.Utils -{ - public static class ReflectionUtil - { - public static List FindTypesInCurrentAppDomain(string fullName) - { - return AppDomain.CurrentDomain.GetAssemblies() - .Select(assembly => assembly.GetType(fullName)) - .Where(type => type != null) - .ToList(); - } - - public static Type FindUniqueTypeInCurrentAppDomain(string fullName) - { - var foundTypes = FindTypesInCurrentAppDomain(fullName); - if (foundTypes.Count == 0) - { - throw new Exception($"class {fullName} not found in any assembly!"); - } - if (foundTypes.Count > 1) - { - throw new Exception($"class {fullName} found in multiple assemblies! Please retain only one!"); - } - return foundTypes[0]; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ReflectionUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ReflectionUtil.cs.meta deleted file mode 100644 index 05d723b9..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ReflectionUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6fac8216afeffb746b1b67d1f16883b8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ThisArgType.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ThisArgType.cs deleted file mode 100644 index 3f008ccc..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ThisArgType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Obfuz.Utils -{ - public enum ThisArgType - { - None, - ValueType, - Class, - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ThisArgType.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ThisArgType.cs.meta deleted file mode 100644 index c73587a7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/ThisArgType.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5d5a6303cdb66374f95187ca31b5e82f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/TypeSigUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/TypeSigUtil.cs deleted file mode 100644 index 5b80674f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/TypeSigUtil.cs +++ /dev/null @@ -1,219 +0,0 @@ -using dnlib.DotNet; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Obfuz.Utils -{ - public static class TypeSigUtil - { - public static string ComputeTypeDefSignature(TypeDef type) - { - return type.FullName; - } - - public static string ComputeMethodDefSignature(MethodDef method) - { - var result = new StringBuilder(); - ComputeTypeSigName(method.MethodSig.RetType, result); - result.Append(" "); - result.Append(method.DeclaringType.FullName); - result.Append("::"); - if (method.IsStatic) - { - result.Append("@"); - } - result.Append(method.Name); - if (method.HasGenericParameters) - { - result.Append($"`{method.GenericParameters.Count}"); - } - result.Append("("); - for (int i = 0; i < method.Parameters.Count; i++) - { - if (i > 0) - { - result.Append(", "); - } - ComputeTypeSigName(method.Parameters[i].Type, result); - } - result.Append(")"); - return result.ToString(); - } - - public static string ComputeFieldDefSignature(FieldDef field) - { - var result = new StringBuilder(); - ComputeTypeSigName(field.FieldSig.Type, result); - result.Append(" "); - result.Append(field.Name); - return result.ToString(); - } - - public static string ComputePropertyDefSignature(PropertyDef property) - { - var result = new StringBuilder(); - - PropertySig propertySig = property.PropertySig; - ComputeTypeSigName(propertySig.RetType, result); - result.Append(" "); - result.Append(property.Name); - - IList parameters = propertySig.Params; - if (parameters.Count > 0) - { - result.Append("("); - - for (int i = 0; i < parameters.Count; i++) - { - if (i > 0) - { - result.Append(", "); - } - ComputeTypeSigName(parameters[i], result); - } - result.Append(")"); - } - - return result.ToString(); - } - - public static string ComputeEventDefSignature(EventDef eventDef) - { - var result = new StringBuilder(); - ComputeTypeSigName(eventDef.EventType.ToTypeSig(), result); - result.Append(" "); - result.Append(eventDef.Name); - return result.ToString(); - } - - public static string ComputeMethodSpecSignature(TypeSig type) - { - var sb = new StringBuilder(); - ComputeTypeSigName(type, sb); - return sb.ToString(); - } - - public static void ComputeTypeSigName(TypeSig type, StringBuilder result) - { - type = type.RemovePinnedAndModifiers(); - switch (type.ElementType) - { - case ElementType.Void: result.Append("void"); break; - case ElementType.Boolean: result.Append("bool"); break; - case ElementType.Char: result.Append("char"); break; - case ElementType.I1: result.Append("sbyte"); break; - case ElementType.U1: result.Append("byte"); break; - case ElementType.I2: result.Append("short"); break; - case ElementType.U2: result.Append("ushort"); break; - case ElementType.I4: result.Append("int"); break; - case ElementType.U4: result.Append("uint"); break; - case ElementType.I8: result.Append("long"); break; - case ElementType.U8: result.Append("ulong"); break; - case ElementType.R4: result.Append("float"); break; - case ElementType.R8: result.Append("double"); break; - case ElementType.String: result.Append("string"); break; - case ElementType.Ptr: - ComputeTypeSigName(((PtrSig)type).Next, result); - result.Append("*"); - break; - case ElementType.ByRef: - ComputeTypeSigName(((ByRefSig)type).Next, result); - result.Append("&"); - break; - case ElementType.ValueType: - case ElementType.Class: - { - var valueOrClassType = type.ToClassOrValueTypeSig(); - var typeDef = valueOrClassType.ToTypeDefOrRef().ResolveTypeDefThrow(); - if (typeDef.Module.IsCoreLibraryModule != true) - { - result.Append($"[{typeDef.Module.Assembly.Name}]"); - } - result.Append(typeDef.FullName); - break; - } - case ElementType.GenericInst: - { - var genInst = (GenericInstSig)type; - ComputeTypeSigName(genInst.GenericType, result); - result.Append("<"); - for (int i = 0; i < genInst.GenericArguments.Count; i++) - { - if (i > 0) - { - result.Append(","); - } - ComputeTypeSigName(genInst.GenericArguments[i], result); - } - result.Append(">"); - break; - } - case ElementType.SZArray: - ComputeTypeSigName(((SZArraySig)type).Next, result); - result.Append("[]"); - break; - case ElementType.Array: - { - var arraySig = (ArraySig)type; - ComputeTypeSigName(arraySig.Next, result); - result.Append("["); - for (int i = 0; i < arraySig.Rank; i++) - { - if (i > 0) - { - result.Append(","); - } - //result.Append(arraySig.Sizes[i]); - } - result.Append("]"); - break; - } - case ElementType.FnPtr: - { - var fnPtr = (FnPtrSig)type; - result.Append("("); - MethodSig ms = fnPtr.MethodSig; - ComputeTypeSigName(ms.RetType, result); - result.Append("("); - for (int i = 0; i < ms.Params.Count; i++) - { - if (i > 0) - { - result.Append(","); - } - ComputeTypeSigName(ms.Params[i], result); - } - result.Append(")*"); - break; - } - case ElementType.TypedByRef: - result.Append("typedref"); - break; - case ElementType.I: - result.Append("nint"); - break; - case ElementType.U: - result.Append("nuint"); - break; - case ElementType.Object: - result.Append("object"); - break; - case ElementType.Var: - { - var var = (GenericVar)type; - result.Append($"!{var.Number}"); - break; - } - case ElementType.MVar: - { - var mvar = (GenericMVar)type; - result.Append($"!!{mvar.Number}"); - break; - } - default: throw new NotSupportedException($"[ComputeTypeSigName] not support :{type}"); - - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/TypeSigUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/TypeSigUtil.cs.meta deleted file mode 100644 index fd925122..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Editor/Utils/TypeSigUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 83e1214102577b449a933438c41c97bf -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/LICENSE b/UnityProject/Packages/com.code-philosophy.obfuz/LICENSE deleted file mode 100644 index 093e5999..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 Code Philosophy(代码哲学) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/LICENSE.meta b/UnityProject/Packages/com.code-philosophy.obfuz/LICENSE.meta deleted file mode 100644 index 3bb31e64..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/LICENSE.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 4431597180c05fb46839ded925d40a19 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Plugins.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Plugins.meta deleted file mode 100644 index 074840ee..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Plugins.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f8b2842c597aa4249b275ef7cb2200ec -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Plugins/dnlib.dll b/UnityProject/Packages/com.code-philosophy.obfuz/Plugins/dnlib.dll deleted file mode 100644 index d6c2fd994cd746dcbe3c355d4e98c0839d81f519..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1263616 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

b|r)=+1PvhhKsWm3>q;s8dZUo2gSxD%)PC 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

P>{7QMz$Mw8scaSd;Mv5m;+ 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�h63;$!#Q+Omq}8 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ǚ|n$@FP#E-rTB?Ygp5n39C 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�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

phmfm6o~M}0xP#n+9B^BZ+=7H2;L<^g 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�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

l6uZ5i#8~iv?r_ffcmaSly+o?%ty4A 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Ï$ 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⁣&&G>V= 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

Exz<7!7uHihcr?9 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

|HOm`cEO0=6e$M*?ON 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 fPAmuY={uj_X$uUlB4> 2]; - Buffer.BlockCopy(data, offset, result, 0, byteLength); - return result; - } - - public static void InitializeArray(Array array, byte[] data, int offset, int length) - { - Buffer.BlockCopy(data, offset, array, 0, length); - } - - public static unsafe int CastFloatAsInt(float value) - { - int* intValue = (int*)&value; - return *intValue; - } - - public static unsafe float CastIntAsFloat(int value) - { - float* floatValue = (float*)&value; - return *floatValue; - } - - public static unsafe long CastDoubleAsLong(double value) - { - long* longValue = (long*)&value; - return *longValue; - } - - public static unsafe double CastLongAsDouble(long value) - { - double* doubleValue = (double*)&value; - return *doubleValue; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ConstUtility.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ConstUtility.cs.meta deleted file mode 100644 index f474205a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ConstUtility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 48bd592d1a1339643be1fafe4b97c941 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptFieldAttribute.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptFieldAttribute.cs deleted file mode 100644 index 715853e6..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptFieldAttribute.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Obfuz -{ - [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)] - public class EncryptFieldAttribute : Attribute - { - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptFieldAttribute.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptFieldAttribute.cs.meta deleted file mode 100644 index a76ea9d1..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptFieldAttribute.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 30f22110938816d4cb7e9cc9a176fd1e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionScope.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionScope.cs deleted file mode 100644 index 9e50ae8a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionScope.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Obfuz -{ - public interface IEncryptionScope - { - - } - - public abstract class EncryptionScopeBase : IEncryptionScope - { - public void ForcePreserveAOT() - { - EncryptionService.Encrypt(0, 0, 0); - } - } - - public struct DefaultDynamicEncryptionScope : IEncryptionScope - { - public void ForcePreserveAOT() - { - EncryptionService.Encrypt(0, 0, 0); - } - } - - public struct DefaultStaticEncryptionScope : IEncryptionScope - { - public void ForcePreserveAOT() - { - EncryptionService.Encrypt(0, 0, 0); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionScope.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionScope.cs.meta deleted file mode 100644 index 064f8750..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionScope.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1d729fe7cb7d0bc43a69f1ba09f99061 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionService.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionService.cs deleted file mode 100644 index 546b05ed..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionService.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; - -namespace Obfuz -{ - - public static class EncryptionService where T : IEncryptionScope - { - // for compatibility with Mono because Mono will raise FieldAccessException when try access private field - public static IEncryptor _encryptor; - - public static IEncryptor Encryptor - { - get => _encryptor; - set { _encryptor = value; } - } - - public static void EncryptBlock(byte[] data, int ops, int salt) - { - _encryptor.EncryptBlock(data, ops, salt); - } - - public static void DecryptBlock(byte[] data, int ops, int salt) - { - _encryptor.DecryptBlock(data, ops, salt); - } - - public static int Encrypt(int value, int opts, int salt) - { - return _encryptor.Encrypt(value, opts, salt); - } - - public static int Decrypt(int value, int opts, int salt) - { - return _encryptor.Decrypt(value, opts, salt); - } - - public static long Encrypt(long value, int opts, int salt) - { - return _encryptor.Encrypt(value, opts, salt); - } - - public static long Decrypt(long value, int opts, int salt) - { - return _encryptor.Decrypt(value, opts, salt); - } - - public static float Encrypt(float value, int opts, int salt) - { - return _encryptor.Encrypt(value, opts, salt); - } - - public static float Decrypt(float value, int opts, int salt) - { - return _encryptor.Decrypt(value, opts, salt); - } - - public static double Encrypt(double value, int opts, int salt) - { - return _encryptor.Encrypt(value, opts, salt); - } - - public static double Decrypt(double value, int opts, int salt) - { - return _encryptor.Decrypt(value, opts, salt); - } - - public static byte[] Encrypt(byte[] value, int offset, int length, int opts, int salt) - { - return _encryptor.Encrypt(value, offset, length, opts, salt); - } - - public static byte[] Decrypt(byte[] value, int offset, int byteLength, int ops, int salt) - { - return _encryptor.Decrypt(value, offset, byteLength, ops, salt); - } - - public static byte[] Encrypt(string value, int ops, int salt) - { - return _encryptor.Encrypt(value, ops, salt); - } - - public static string DecryptString(byte[] value, int offset, int stringBytesLength, int ops, int salt) - { - return _encryptor.DecryptString(value, offset, stringBytesLength, ops, salt); - } - - - public static int DecryptFromRvaInt(byte[] data, int offset, int ops, int salt) - { - int encryptedValue = BitConverter.ToInt32(data, offset); - return Decrypt(encryptedValue, ops, salt); - } - - public static long DecryptFromRvaLong(byte[] data, int offset, int ops, int salt) - { - long encryptedValue = BitConverter.ToInt64(data, offset); - return Decrypt(encryptedValue, ops, salt); - } - - public static float DecryptFromRvaFloat(byte[] data, int offset, int ops, int salt) - { - float encryptedValue = BitConverter.ToSingle(data, offset); - return Decrypt(encryptedValue, ops, salt); - } - - public static double DecryptFromRvaDouble(byte[] data, int offset, int ops, int salt) - { - double encryptedValue = BitConverter.ToDouble(data, offset); - return Decrypt(encryptedValue, ops, salt); - } - - public static string DecryptFromRvaString(byte[] data, int offset, int length, int ops, int salt) - { - return DecryptString(data, offset, length, ops, salt); - } - - public static byte[] DecryptFromRvaBytes(byte[] data, int offset, int bytesLength, int ops, int salt) - { - return Decrypt(data, offset, bytesLength, ops, salt); - } - - public static void DecryptInitializeArray(System.Array arr, System.RuntimeFieldHandle field, int length, int ops, int salt) - { - _encryptor.DecryptInitializeArray(arr, field, length, ops, salt); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionService.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionService.cs.meta deleted file mode 100644 index d7364ef7..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptionService.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bbbeb7501a0d84542828cb1aa7103d1b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptorBase.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptorBase.cs deleted file mode 100644 index 3fe2b305..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptorBase.cs +++ /dev/null @@ -1,362 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Text; -using Unity.Collections.LowLevel.Unsafe; -using UnityEngine.Assertions; - -namespace Obfuz -{ - public abstract class EncryptorBase : IEncryptor - { - public abstract int OpCodeCount { get; } - - public static int[] ConvertToIntKey(byte[] key) - { - Assert.AreEqual(0, key.Length % 4); - int align4Length = key.Length / 4; - int[] intKey = new int[align4Length]; - Buffer.BlockCopy(key, 0, intKey, 0, key.Length); - return intKey; - } - - public abstract int Encrypt(int value, int opts, int salt); - public abstract int Decrypt(int value, int opts, int salt); - - public virtual long Encrypt(long value, int opts, int salt) - { - int low = (int)value; - int high = (int)(value >> 32); - int encryptedLow = Encrypt(low, opts, salt); - int encryptedHigh = Encrypt(high, opts, salt); - return ((long)encryptedHigh << 32) | (uint)encryptedLow; - } - - public virtual long Decrypt(long value, int opts, int salt) - { - int low = (int)value; - int high = (int)(value >> 32); - int decryptedLow = Decrypt(low, opts, salt); - int decryptedHigh = Decrypt(high, opts, salt); - return ((long)decryptedHigh << 32) | (uint)decryptedLow; - } - - public virtual unsafe float Encrypt(float value, int opts, int salt) - { - if (float.IsNaN(value) || float.IsInfinity(value)) - { - return value; - } - ref int intValue = ref *(int*)&value; - int xorValue = ((1 << 23) - 1) & Decrypt(0xABCD, opts, salt); - intValue ^= xorValue; - return value; - } - - public virtual unsafe float Decrypt(float value, int opts, int salt) - { - if (float.IsNaN(value) || float.IsInfinity(value)) - { - return value; - } - ref int intValue = ref *(int*)&value; - int xorValue = ((1 << 23) - 1) & Decrypt(0xABCD, opts, salt); - intValue ^= xorValue; - return value; - } - - public virtual unsafe double Encrypt(double value, int opts, int salt) - { - if (double.IsNaN(value) || double.IsInfinity(value)) - { - return value; - } - ref long longValue = ref *(long*)&value; - long xorValue = ((1L << 52) - 1) & Decrypt(0xAABBCCDDL, opts, salt); - longValue ^= xorValue; - return value; - } - - public virtual unsafe double Decrypt(double value, int opts, int salt) - { - if (double.IsNaN(value) || double.IsInfinity(value)) - { - return value; - } - ref long longValue = ref *(long*)&value; - long xorValue = ((1L << 52) - 1) & Decrypt(0xAABBCCDDL, opts, salt); - longValue ^= xorValue; - return value; - } - - public virtual unsafe byte[] Encrypt(byte[] value, int offset, int length, int ops, int salt) - { - if (length == 0) - { - return Array.Empty(); - } - - var encryptedBytes = new byte[length]; - int intArrLength = length >> 2; - - // align to 4 - if ((offset & 0x3) != 0) - { - Buffer.BlockCopy(value, offset, encryptedBytes, 0, length); - - // encrypt int - - fixed (byte* dstBytePtr = &encryptedBytes[0]) - { - int* dstIntPtr = (int*)dstBytePtr; - int last = 0; - for (int i = 0; i < intArrLength; i++) - { - last ^= Encrypt(dstIntPtr[i], ops, salt); - dstIntPtr[i] = last; - } - } - for (int i = intArrLength * 4; i < length; i++) - { - encryptedBytes[i] = (byte)(encryptedBytes[i] ^ salt); - } - } - else - { - // encrypt int - fixed (byte* srcBytePtr = &value[offset]) - { - fixed (byte* dstBytePtr = &encryptedBytes[0]) - { - int* srcIntPtr = (int*)srcBytePtr; - int* dstIntPtr = (int*)dstBytePtr; - - int last = 0; - for (int i = 0; i < intArrLength; i++) - { - last ^= Encrypt(srcIntPtr[i], ops, salt); - dstIntPtr[i] = last; - } - } - } - for (int i = intArrLength * 4; i < length; i++) - { - encryptedBytes[i] = (byte)(value[offset + i] ^ salt); - } - } - return encryptedBytes; - } - - public unsafe virtual byte[] Decrypt(byte[] value, int offset, int length, int ops, int salt) - { - if (length == 0) - { - return Array.Empty(); - } - var decryptedBytes = new byte[length]; - int intArrLength = length >> 2; - - // align to 4 - if ((offset & 0x3) != 0) - { - Buffer.BlockCopy(value, offset, decryptedBytes, 0, length); - - // encrypt int - - fixed (byte* dstBytePtr = &decryptedBytes[0]) - { - int* dstIntPtr = (int*)dstBytePtr; - int last = 0; - for (int i = 0; i < intArrLength; i++) - { - int oldLast = last; - last = dstIntPtr[i]; - dstIntPtr[i] = Decrypt(last ^ oldLast, ops, salt); - } - } - for (int i = intArrLength * 4; i < length; i++) - { - decryptedBytes[i] = (byte)(decryptedBytes[i] ^ salt); - } - } - else - { - // encrypt int - fixed (byte* srcBytePtr = &value[offset]) - { - fixed (byte* dstBytePtr = &decryptedBytes[0]) - { - int* srcIntPtr = (int*)srcBytePtr; - int* dstIntPtr = (int*)dstBytePtr; - int last = 0; - for (int i = 0; i < intArrLength; i++) - { - int oldLast = last; - last = srcIntPtr[i]; - dstIntPtr[i] = Decrypt(last ^ oldLast, ops, salt); - } - } - } - for (int i = intArrLength * 4; i < length; i++) - { - decryptedBytes[i] = (byte)(value[offset + i] ^ salt); - } - } - return decryptedBytes; - } - - public virtual byte[] Encrypt(string value, int ops, int salt) - { - if (value.Length == 0) - { - return Array.Empty(); - } - byte[] bytes = Encoding.UTF8.GetBytes(value); - return Encrypt(bytes, 0, bytes.Length, ops, salt); - } - - public virtual string DecryptString(byte[] value, int offset, int length, int ops, int salt) - { - if (length == 0) - { - return string.Empty; - } - byte[] bytes = Decrypt(value, offset, length, ops, salt); - return Encoding.UTF8.GetString(bytes); - } - - public virtual unsafe void EncryptBlock(byte[] data, int ops, int salt) - { - int length = data.Length; - int intArrLength = length >> 2; - - fixed (byte* dstBytePtr = &data[0]) - { - int* dstIntPtr = (int*)dstBytePtr; - int last = 0; - for (int i = 0; i < intArrLength; i++) - { - last ^= Encrypt(dstIntPtr[i], ops, salt); - dstIntPtr[i] = last; - } - } - for (int i = intArrLength * 4; i < length; i++) - { - data[i] = (byte)(data[i] ^ salt); - } - } - - public virtual unsafe void DecryptBlock(byte[] data, int ops, int salt) - { - fixed (byte* dataPtr = &data[0]) - { - DecryptBlock(dataPtr, data.Length, ops, salt); - } - } - - private unsafe void DecryptBlock(byte* data, int length, int ops, int salt) - { - int intArrLength = length >> 2; - - int* dstIntPtr = (int*)data; - int last = 0; - for (int i = 0; i < intArrLength; i++) - { - int oldLast = last; - last = dstIntPtr[i]; - dstIntPtr[i] = Decrypt(oldLast ^ last, ops, salt); - } - for (int i = intArrLength * 4; i < length; i++) - { - data[i] = (byte)(data[i] ^ salt); - } - } - - public virtual unsafe void DecryptInitializeArray(System.Array arr, System.RuntimeFieldHandle field, int length, int ops, int salt) - { - //Assert.AreEqual(Marshal.SizeOf(arr.GetType().GetElementType()), arr.Length); - RuntimeHelpers.InitializeArray(arr, field); - if (arr is byte[] byteArr) - { - fixed (byte* dataPtr = &byteArr[0]) - { - DecryptBlock(dataPtr, length, ops, salt); - } - } - else if (arr is int[] intArr) - { - fixed (int* dataPtr = &intArr[0]) - { - DecryptBlock((byte*)dataPtr, length, ops, salt); - } - } - else if (arr is long[] longArr) - { - fixed (long* dataPtr = &longArr[0]) - { - DecryptBlock((byte*)dataPtr, length, ops, salt); - } - } - else if (arr is sbyte[] sbyteArr) - { - fixed (sbyte* dataPtr = &sbyteArr[0]) - { - DecryptBlock((byte*)dataPtr, length, ops, salt); - } - } - else if (arr is short[] shortArr) - { - fixed (short* dataPtr = &shortArr[0]) - { - DecryptBlock((byte*)dataPtr, length, ops, salt); - } - } - else if (arr is ushort[] ushortArr) - { - fixed (ushort* dataPtr = &ushortArr[0]) - { - DecryptBlock((byte*)dataPtr, length, ops, salt); - } - } - else if (arr is uint[] uintArr) - { - fixed (uint* dataPtr = &uintArr[0]) - { - DecryptBlock((byte*)dataPtr, length, ops, salt); - } - } - else if (arr is ulong[] ulongArr) - { - fixed (ulong* dataPtr = &ulongArr[0]) - { - DecryptBlock((byte*)dataPtr, length, ops, salt); - } - } - else if (arr is float[] floatArr) - { - fixed (float* dataPtr = &floatArr[0]) - { - DecryptBlock((byte*)dataPtr, length, ops, salt); - } - } - else if (arr is double[] doubleArr) - { - fixed (double* dataPtr = &doubleArr[0]) - { - DecryptBlock((byte*)dataPtr, length, ops, salt); - } - } - else - { - void* dataPtr = UnsafeUtility.PinGCArrayAndGetDataAddress(arr, out ulong handle); - try - { - DecryptBlock((byte*)dataPtr, length, ops, salt); - } - finally - { - UnsafeUtility.ReleaseGCObject(handle); - } - } - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptorBase.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptorBase.cs.meta deleted file mode 100644 index e81d5219..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/EncryptorBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d1d4c5725e7ad624ba8e55ecb63bb440 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ExprUtility.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ExprUtility.cs deleted file mode 100644 index ff037e00..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ExprUtility.cs +++ /dev/null @@ -1,247 +0,0 @@ -using System; - -namespace Obfuz -{ - public static class ExprUtility - { - public static int Add(int a, int b) - { - return a + b; - } - - public static long Add(long a, long b) - { - return a + b; - } - - public static float Add(float a, float b) - { - return a + b; - } - - public static double Add(double a, double b) - { - return a + b; - } - - public static IntPtr Add(IntPtr a, IntPtr b) - { - return (IntPtr)((long)a + (long)b); - } - - public static IntPtr Add(IntPtr a, int b) - { - return a + b; - } - - public static int Subtract(int a, int b) - { - return a - b; - } - - public static long Subtract(long a, long b) - { - return a - b; - } - - public static float Subtract(float a, float b) - { - return a - b; - } - - public static double Subtract(double a, double b) - { - return a - b; - } - - public static IntPtr Subtract(IntPtr a, IntPtr b) - { - return (IntPtr)((long)a - (long)b); - } - - public static IntPtr Subtract(IntPtr a, int b) - { - return a - b; - } - - public static int Multiply(int a, int b) - { - return a * b; - } - - public static long Multiply(long a, long b) - { - return a * b; - } - - public static float Multiply(float a, float b) - { - return a * b; - } - - public static double Multiply(double a, double b) - { - return a * b; - } - - public static IntPtr Multiply(IntPtr a, IntPtr b) - { - return (IntPtr)((long)a * (long)b); - } - - public static IntPtr Multiply(IntPtr a, int b) - { - return (IntPtr)((long)a * b); - } - - public static int Divide(int a, int b) - { - return a / b; - } - - public static long Divide(long a, long b) - { - return a / b; - } - - public static float Divide(float a, float b) - { - return a / b; - } - - public static double Divide(double a, double b) - { - return a / b; - } - - public static int DivideUn(int a, int b) - { - return (int)((uint)a / (uint)b); - } - - public static long DivideUn(long a, long b) - { - return (long)((ulong)a / (ulong)b); - } - - public static int Rem(int a, int b) - { - return a % b; - } - - public static long Rem(long a, long b) - { - return a % b; - } - - public static float Rem(float a, float b) - { - return a % b; - } - - public static double Rem(double a, double b) - { - return a % b; - } - - public static int RemUn(int a, int b) - { - return (int)((uint)a % (uint)b); - } - - public static long RemUn(long a, long b) - { - return (long)((ulong)a % (ulong)b); - } - - public static int Negate(int a) - { - return -a; - } - - public static long Negate(long a) - { - return -a; - } - - public static float Negate(float a) - { - return -a; - } - - public static double Negate(double a) - { - return -a; - } - - public static int And(int a, int b) - { - return a & b; - } - - public static long And(long a, long b) - { - return a & b; - } - - public static int Or(int a, int b) - { - return a | b; - } - - public static long Or(long a, long b) - { - return a | b; - } - - public static int Xor(int a, int b) - { - return a ^ b; - } - - public static long Xor(long a, long b) - { - return a ^ b; - } - - public static int Not(int a) - { - return ~a; - } - - public static long Not(long a) - { - return ~a; - } - - public static int ShiftLeft(int a, int b) - { - return a << b; - } - - public static long ShiftLeft(long a, int b) - { - return a << b; - } - - public static int ShiftRight(int a, int b) - { - return a >> b; - } - - public static long ShiftRight(long a, int b) - { - return a >> b; - } - - public static int ShiftRightUn(int a, int b) - { - return (int)((uint)a >> b); - } - - public static long ShiftRightUn(long a, int b) - { - return (long)((ulong)a >> b); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ExprUtility.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ExprUtility.cs.meta deleted file mode 100644 index 4f7c95b8..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ExprUtility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9aba5050818a0224696fcf73752fb225 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/IEncryptor.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/IEncryptor.cs deleted file mode 100644 index 63a609e9..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/IEncryptor.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Obfuz -{ - public interface IEncryptor - { - int OpCodeCount { get; } - - void EncryptBlock(byte[] data, int ops, int salt); - void DecryptBlock(byte[] data, int ops, int salt); - - int Encrypt(int value, int opts, int salt); - int Decrypt(int value, int opts, int salt); - - long Encrypt(long value, int opts, int salt); - long Decrypt(long value, int opts, int salt); - - float Encrypt(float value, int opts, int salt); - float Decrypt(float value, int opts, int salt); - - double Encrypt(double value, int opts, int salt); - double Decrypt(double value, int opts, int salt); - - byte[] Encrypt(byte[] value, int offset, int length, int opts, int salt); - byte[] Decrypt(byte[] value, int offset, int byteLength, int ops, int salt); - - byte[] Encrypt(string value, int ops, int salt); - string DecryptString(byte[] value, int offset, int stringBytesLength, int ops, int salt); - - void DecryptInitializeArray(System.Array arr, System.RuntimeFieldHandle field, int length, int ops, int salt); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/IEncryptor.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/IEncryptor.cs.meta deleted file mode 100644 index 41418218..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/IEncryptor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3078fa59ff0af6b4cbbee25e20bc41c1 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/NullEncryptor.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/NullEncryptor.cs deleted file mode 100644 index 20dca52c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/NullEncryptor.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Text; - -namespace Obfuz -{ - public class NullEncryptor : EncryptorBase - { - private readonly byte[] _key; - - public override int OpCodeCount => 256; - - public NullEncryptor(byte[] key) - { - _key = key; - } - - public override int Encrypt(int value, int opts, int salt) - { - return value; - } - - public override int Decrypt(int value, int opts, int salt) - { - return value; - } - - public override long Encrypt(long value, int opts, int salt) - { - return value; - } - - public override long Decrypt(long value, int opts, int salt) - { - return value; - } - - public override float Encrypt(float value, int opts, int salt) - { - return value; - } - - public override float Decrypt(float value, int opts, int salt) - { - return value; - } - - public override double Encrypt(double value, int opts, int salt) - { - return value; - } - - public override double Decrypt(double value, int opts, int salt) - { - return value; - } - - public override byte[] Encrypt(byte[] value, int offset, int length, int opts, int salt) - { - if (length == 0) - { - return Array.Empty(); - } - var encryptedBytes = new byte[length]; - Buffer.BlockCopy(value, offset, encryptedBytes, 0, length); - return encryptedBytes; - } - - public override byte[] Decrypt(byte[] value, int offset, int length, int ops, int salt) - { - if (length == 0) - { - return Array.Empty(); - } - byte[] byteArr = new byte[length]; - Buffer.BlockCopy(value, 0, byteArr, 0, length); - return byteArr; - } - - public override byte[] Encrypt(string value, int ops, int salt) - { - return Encoding.UTF8.GetBytes(value); - } - - public override string DecryptString(byte[] value, int offset, int length, int ops, int salt) - { - return Encoding.UTF8.GetString(value, offset, length); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/NullEncryptor.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/NullEncryptor.cs.meta deleted file mode 100644 index b490d290..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/NullEncryptor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c53481f2ec513be4783a5ae2f76dc6e7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationInstincts.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationInstincts.cs deleted file mode 100644 index 45641f0a..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationInstincts.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace Obfuz -{ - public static class ObfuscationInstincts - { - ///

- /// Returns the original full name before obfuscated of the type T - /// - /// - /// - public static string FullNameOf() - { - return typeof(T).FullName; - } - - /// - /// Returns the original name before obfuscated of the type T - /// - /// - /// - public static string NameOf() - { - return typeof(T).Name; - } - - /// - /// register original type name to type mapping. - /// - /// - public static void RegisterReflectionType() - { - ObfuscationTypeMapper.RegisterType(typeof(T).FullName); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationInstincts.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationInstincts.cs.meta deleted file mode 100644 index 48d653ff..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationInstincts.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 84320ab4adc4cbc49bf5e8f4009b4a96 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationTypeMapper.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationTypeMapper.cs deleted file mode 100644 index a85927ca..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationTypeMapper.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace Obfuz -{ - public static class ObfuscationTypeMapper - { - private static readonly Dictionary _type2OriginalFullName = new Dictionary(); - private static readonly Dictionary> _originalFullName2Types = new Dictionary>(); - - internal static void RegisterType(string originalFullName) - { - RegisterType(typeof(T), originalFullName); - } - - internal static void RegisterType(Type type, string originalFullName) - { - if (_type2OriginalFullName.ContainsKey(type)) - { - throw new ArgumentException($"Type '{type.FullName}' is already registered with original name '{_type2OriginalFullName[type]}'."); - } - _type2OriginalFullName.Add(type, originalFullName); - Assembly assembly = type.Assembly; - if (!_originalFullName2Types.TryGetValue(assembly, out var originalFullName2Types)) - { - originalFullName2Types = new Dictionary(); - _originalFullName2Types[assembly] = originalFullName2Types; - } - if (originalFullName2Types.ContainsKey(originalFullName)) - { - throw new ArgumentException($"Original full name '{originalFullName}' is already registered with type '{originalFullName2Types[originalFullName].FullName}'."); - } - originalFullName2Types.Add(originalFullName, type); - } - - public static string GetOriginalTypeFullName(Type type) - { - return _type2OriginalFullName.TryGetValue(type, out string originalFullName) - ? originalFullName - : throw new KeyNotFoundException($"Type '{type.FullName}' not found in the obfuscation mapping."); - } - - public static string GetOriginalTypeFullNameOrCurrent(Type type) - { - if (_type2OriginalFullName.TryGetValue(type, out string originalFullName)) - { - return originalFullName; - } - return type.FullName; - } - - public static Type GetTypeByOriginalFullName(Assembly assembly, string originalFullName) - { - if (_originalFullName2Types.TryGetValue(assembly, out var n2t)) - { - if (n2t.TryGetValue(originalFullName, out Type type)) - { - return type; - } - } - return null; - } - - public static void Clear() - { - _type2OriginalFullName.Clear(); - _originalFullName2Types.Clear(); - } - } - -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationTypeMapper.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationTypeMapper.cs.meta deleted file mode 100644 index f496249d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuscationTypeMapper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: db6168acedd85984fa2c197fee1b0c15 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/Obfuz.Runtime.asmdef b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/Obfuz.Runtime.asmdef deleted file mode 100644 index 4ee1d16d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/Obfuz.Runtime.asmdef +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Obfuz.Runtime", - "rootNamespace": "", - "references": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": true, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} \ No newline at end of file diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/Obfuz.Runtime.asmdef.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/Obfuz.Runtime.asmdef.meta deleted file mode 100644 index 4868da27..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/Obfuz.Runtime.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 4140bd2e2764f1f47ab93125ecb61942 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzIgnoreAttribute.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzIgnoreAttribute.cs deleted file mode 100644 index 4aac1b88..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzIgnoreAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace Obfuz -{ - - [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)] - public class ObfuzIgnoreAttribute : Attribute - { - public ObfuzScope Scope { get; set; } - - public bool ApplyToNestedTypes { get; set; } = true; - - public bool ApplyToChildTypes { get; set; } = false; - - public ObfuzIgnoreAttribute(ObfuzScope scope = ObfuzScope.All) - { - this.Scope = scope; - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzIgnoreAttribute.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzIgnoreAttribute.cs.meta deleted file mode 100644 index bc8fb89b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzIgnoreAttribute.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c2b4cf04729157b4dab504167ab5f703 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzScope.cs b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzScope.cs deleted file mode 100644 index e3079900..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzScope.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace Obfuz -{ - [Flags] - public enum ObfuzScope - { - None = 0x0, - TypeName = 0x1, - Field = 0x2, - MethodName = 0x4, - MethodParameter = 0x8, - MethodBody = 0x10, - Method = MethodName | MethodParameter | MethodBody, - PropertyName = 0x20, - PropertyGetterSetterName = 0x40, - Property = PropertyName | PropertyGetterSetterName, - EventName = 0x100, - EventAddRemoveFireName = 0x200, - Event = EventName | PropertyGetterSetterName, - Module = 0x1000, - All = TypeName | Field | Method | Property | Event, - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzScope.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzScope.cs.meta deleted file mode 100644 index 1fec67df..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/Runtime/ObfuzScope.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3c7e51fe12f206347b08a4b0be48605d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz/package.json b/UnityProject/Packages/com.code-philosophy.obfuz/package.json deleted file mode 100644 index 28a66a96..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "com.code-philosophy.obfuz", - "version": "2.0.0", - "displayName": "Obfuz", - "description": "Obfuz is an open-source Unity code obfuscation tool designed to provide Unity developers with a powerful, secure, and user-friendly code protection solution.", - "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.obfuz/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/UnityProject/Packages/com.code-philosophy.obfuz/package.json.meta b/UnityProject/Packages/com.code-philosophy.obfuz/package.json.meta deleted file mode 100644 index 74168f7e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz/package.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 63433d029d2e08c46abd56175e308a15 -PackageManifestImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor.meta b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor.meta deleted file mode 100644 index ec942396..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 067341936b8cb2242be3bdc83f3ca3cd -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/ObfuscateUtil.cs b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/ObfuscateUtil.cs deleted file mode 100644 index c68a9237..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/ObfuscateUtil.cs +++ /dev/null @@ -1,118 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.PolymorphicWriter; -using HybridCLR.Editor; -using Obfuz; -using Obfuz.Settings; -using Obfuz.Unity; -using System; -using System.Collections.Generic; -using System.IO; -using UnityEditor; -using UnityEngine; - -namespace Obfuz4HybridCLR -{ - public static class ObfuscateUtil - { - public static string PackageName { get; } = "com.code-philosophy.obfuz4hybridclr"; - - public static string TemplatePathInPackage => $"Packages/{PackageName}/Templates~"; - - 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(); - } - - public static void GeneratePolymorphicDll(string originalDllPath, string outputDllPath) - { - ModuleDef oldMod = ModuleDefMD.Load(originalDllPath); - var obfuzSettings = ObfuzSettings.Instance; - - var opt = new NewDllModuleWriterOptions(oldMod) - { - MetadataWriter = new PolymorphicMetadataWriter(obfuzSettings.polymorphicDllSettings.codeGenerationSecretKey), - }; - PolymorphicModuleWriter writer = new PolymorphicModuleWriter(oldMod, opt); - writer.Write(outputDllPath); - Debug.Log($"GeneratePolymorphicDll {originalDllPath} => {outputDllPath}"); - } - - public static void GeneratePolymorphicCodes(string libil2cppDir) - { - PolymorphicDllSettings settings = ObfuzSettings.Instance.polymorphicDllSettings; - if (!settings.enable) - { - UnityEngine.Debug.LogWarning("Polymorphic code generation is disabled in Obfuz settings."); - return; - } - var options = new PolymorphicCodeGenerator.Options - { - GenerationSecretKey = settings.codeGenerationSecretKey, - Libil2cppDir = libil2cppDir, - TemplateDir = ObfuscateUtil.TemplatePathInPackage, - DisableLoadStandardDll = settings.disableLoadStandardDll, - }; - var generator = new PolymorphicCodeGenerator(options); - generator.Generate(); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/ObfuscateUtil.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/ObfuscateUtil.cs.meta deleted file mode 100644 index 3702fddd..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/ObfuscateUtil.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b7f5fe18513bcdd4c8960d908e88402e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Obfuz4HybridCLR.asmdef b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Obfuz4HybridCLR.asmdef deleted file mode 100644 index 2af5cd54..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Obfuz4HybridCLR.asmdef +++ /dev/null @@ -1,19 +0,0 @@ -{ - "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/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Obfuz4HybridCLR.asmdef.meta b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Obfuz4HybridCLR.asmdef.meta deleted file mode 100644 index cc375a6e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Obfuz4HybridCLR.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 3743e71edcd5bd8499007797ef02cbfb -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic.meta b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic.meta deleted file mode 100644 index 6a8a5899..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 52d353fb8d6d94c4aa03452a2cd9773f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/PolymorphicCodeGenerator.cs b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/PolymorphicCodeGenerator.cs deleted file mode 100644 index 23d9c225..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/PolymorphicCodeGenerator.cs +++ /dev/null @@ -1,224 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using dnlib.DotNet.PolymorphicWriter; -using HybridCLR.Editor.Template; - -public class PolymorphicCodeGenerator -{ - public class Options - { - public string GenerationSecretKey { get; set; } - - public string Libil2cppDir { get; set; } - - public string TemplateDir { get; set; } - - public bool DisableLoadStandardDll { get; set; } = true; - } - - private readonly string _libil2cppDir; - private readonly string _metadataDir; - private readonly string _templateDir; - - private readonly string _generationSecretKey; - private readonly bool _disableLoadStandardImage; - - private readonly PolymorphicMetadataWriter writer; - - public PolymorphicCodeGenerator(Options options) - { - _libil2cppDir = options.Libil2cppDir; - _metadataDir = Path.Combine(_libil2cppDir, "hybridclr", "metadata"); - _templateDir = options.TemplateDir; - - _generationSecretKey = options.GenerationSecretKey; - _disableLoadStandardImage = options.DisableLoadStandardDll; - - writer = new PolymorphicMetadataWriter(_generationSecretKey); - } - - private void CopyMetadataReaderHeader() - { - string srcFile = $"{_templateDir}/MetadataReader.h.tpl"; - string dstFile = $"{_metadataDir}/MetadataReader.h"; - File.Copy(srcFile, dstFile, true); - UnityEngine.Debug.Log($"Copy MetadataReader header from {srcFile} to {dstFile}"); - } - - private void GeneratePolymorphicDefs() - { - string tplFile = $"{_templateDir}/PolymorphicDefs.h.tpl"; - var frr = new FileRegionReplace(File.ReadAllText(tplFile, Encoding.UTF8)); - var lines = new List(); - lines.Add($"#define POLYMORPHIC_IMAGE_SIGNATURE \"{writer.ImageSignature}\""); - lines.Add($"\tconstexpr uint32_t kPolymorphicImageVersion = {writer.FormatVersion};"); - lines.Add($"\tconstexpr uint32_t kFormatVariantVersion = {writer.FormatVariant};"); - string codes = string.Join("\n", lines); - frr.Replace("POLYMORPHIC_DEFINES", codes); - - string outputFile = $"{_metadataDir}/PolymorphicDefs.h"; - frr.Commit(outputFile); - } - - private void GeneratePolymorphicDatas() - { - string tplFile = $"{_templateDir}/PolymorphicDatas.h.tpl"; - var frr = new FileRegionReplace(File.ReadAllText(tplFile, Encoding.UTF8)); - List lines = new List(); - var sb = new StringBuilder(); - foreach (var type in writer.GetPolymorphicTypes()) - { - var polymorphicType = writer.GetPolymorphicClassDef(type); - lines.Add($"\tstruct {type.Name}"); - lines.Add("\t{"); - foreach (var field in polymorphicType.Fields) - { - lines.Add($"\t\t{field.fieldWriter.CppTypeName} {field.name};"); - } - - lines.Add("\t\tvoid Read(MetadataReader& reader)"); - lines.Add("\t\t{"); - - foreach (var field in polymorphicType.Fields) - { - lines.Add($"\t\t\t{field.fieldWriter.GetMarshalCode(field.name, "reader")};"); - } - lines.Add("\t\t}"); - lines.Add("\t};"); - lines.Add(""); - } - - string codes = string.Join("\n", lines); - frr.Replace("POLYMORPHIC_DATA", codes); - - - string outputFile = $"{_metadataDir}/PolymorphicDatas.h"; - frr.Commit(outputFile); - } - - private void GeneratePolymorphicRawImageHeader() - { - string tplFile = $"{_templateDir}/PolymorphicRawImage.h.tpl"; - var frr = new FileRegionReplace(File.ReadAllText(tplFile, Encoding.UTF8)); - - - var tableMetaInfoMap = TableMetaInfos.tableMetaInfos.ToDictionary(t => "Raw" + t.csharpTypeName + "Row"); - List lines = new List(); - foreach (Type rowType in writer.GetPolymorphicTableRowTypes()) - { - TableMetaInfo table = tableMetaInfoMap[rowType.Name]; - - lines.Add($"\t\tvirtual Tb{table.cppTypeName} Read{table.cppTypeName}(uint32_t rawIndex) override;"); - } - - frr.Replace("READ_TABLES_OVERRIDES", string.Join("\n", lines)); - - string outputFile = $"{_metadataDir}/PolymorphicRawImage.h"; - frr.Commit(outputFile); - } - - private void GeneratePolymorphicRawImageSource() - { - string tplFile = $"{_templateDir}/PolymorphicRawImage.cpp.tpl"; - var frr = new FileRegionReplace(File.ReadAllText(tplFile, Encoding.UTF8)); - - var tableMetaInfoMap = TableMetaInfos.tableMetaInfos.ToDictionary(t => "Raw" + t.csharpTypeName + "Row"); - { - List lines = new List(); - - foreach (Type rowType in writer.GetAllTableRowTypes()) - { - TableMetaInfo table = tableMetaInfoMap[rowType.Name]; - PolymorphicClassDef polymorphicClassDef = writer.CreateTableRowClassDefForCodeGeneration(rowType); - lines.Add("\t\t{"); - lines.Add($"\t\t\tauto& table = _tableRowMetas[(int)TableType::{table.cppEnumName}];"); - foreach (var fieldDef in polymorphicClassDef.Fields) - { - FieldMetaInfo field = table.fields.First(f => f.csharpName == fieldDef.name); - lines.Add($"\t\t\ttable.push_back({{{field.cppRowSize}}});"); - } - lines.Add("\t\t}"); - } - string codes = string.Join("\n", lines); - frr.Replace("TABLE_ROW_METADS", codes); - } - { - List lines = new List(); - foreach (Type rowType in writer.GetPolymorphicTableRowTypes()) - { - TableMetaInfo table = tableMetaInfoMap[rowType.Name]; - PolymorphicClassDef polymorphicClassDef = writer.CreateTableRowClassDefForCodeGeneration(rowType); - - lines.Add($"\tTb{table.cppTypeName} PolymorphicRawImage::Read{table.cppTypeName}(uint32_t rawIndex)"); - lines.Add("\t{"); - lines.Add($"\t\tIL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::{table.cppEnumName}).rowNum);"); - lines.Add($"\t\tconst byte* rowPtr = GetTableRowPtr(TableType::{table.cppEnumName}, rawIndex);"); - lines.Add($"\t\tauto& rowSchema = GetRowSchema(TableType::{table.cppEnumName});"); - lines.Add($"\t\tTb{table.cppTypeName} data;"); - for (int i = 0; i < polymorphicClassDef.Fields.Count; i++) - { - var fieldDef = polymorphicClassDef.Fields[i]; - FieldMetaInfo field = table.fields.First(f => f.csharpName == fieldDef.name); - lines.Add($"\t\tdata.{field.cppName} = ReadColumn(rowPtr, rowSchema[{i}]);"); - } - lines.Add("\t\treturn data;"); - lines.Add("\t}"); - } - - frr.Replace("READ_TABLES_IMPLEMENTATIONS", string.Join("\n", lines)); - } - string outputFile = $"{_metadataDir}/PolymorphicRawImage.cpp"; - frr.Commit(outputFile); - } - - private void GenerateRawImageInit() - { - string tplFile = $"{_metadataDir}/Image.cpp"; - var frr = new FileRegionReplace(File.ReadAllText(tplFile, Encoding.UTF8)); - - { - List lines = new List(); - lines.Add(@"#include ""PolymorphicRawImage.h"""); - - frr.Replace("INCLUDE_RAW_IMAGE_HEADERS", string.Join("\n", lines)); - } - { - List lines = new List(); - - lines.Add("\t\tif (std::strncmp((const char*)imageData, \"CODEPHPY\", 8) == 0)"); - lines.Add("\t\t{"); - lines.Add("\t\t\t_rawImage = new PolymorphicRawImage();"); - lines.Add("\t\t}"); - lines.Add("\t\telse"); - lines.Add("\t\t{"); - if (_disableLoadStandardImage) - { - lines.Add("\t\t\treturn LoadImageErrorCode::UNKNOWN_IMAGE_FORMAT;"); - } - else - { - lines.Add("\t\t\t_rawImage = new RawImage();"); - } - lines.Add("\t\t}"); - lines.Add("\t\treturn LoadImageErrorCode::OK;"); - - frr.Replace("INIT_RAW_IMAGE", string.Join("\n", lines)); - } - - - frr.Commit(tplFile); - } - - public void Generate() - { - CopyMetadataReaderHeader(); - GeneratePolymorphicDefs(); - GeneratePolymorphicDatas(); - GeneratePolymorphicRawImageHeader(); - GeneratePolymorphicRawImageSource(); - GenerateRawImageInit(); - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/PolymorphicCodeGenerator.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/PolymorphicCodeGenerator.cs.meta deleted file mode 100644 index 6d7baece..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/PolymorphicCodeGenerator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b66b21680bfc8744682ea6536aa2ec77 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/TableMetaInfos.cs b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/TableMetaInfos.cs deleted file mode 100644 index 440cb7b8..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/TableMetaInfos.cs +++ /dev/null @@ -1,300 +0,0 @@ -using System.Collections.Generic; - -class FieldMetaInfo { - public readonly string csharpName; - public readonly string cppName; - public readonly string cppRowSize; - public FieldMetaInfo(string csharpName, string cppName, string cppRowSize) { - this.csharpName = csharpName; - this.cppName = cppName; - this.cppRowSize = cppRowSize; - } - - public FieldMetaInfo(string csharpName, string cppRowSize) : this(csharpName, csharpName.Substring(0, 1).ToLower() + csharpName.Substring(1), cppRowSize) { - } -} - -class TableMetaInfo { - public readonly string csharpTypeName; - public readonly string cppTypeName; - public readonly string cppEnumName; - public readonly List fields; - - public TableMetaInfo(string csharpTypeName, string cppTypeName, string cppEnumName, List fields) { - this.csharpTypeName = csharpTypeName; - this.cppTypeName = cppTypeName; - this.cppEnumName = cppEnumName; - this.fields = fields; - } - - - public TableMetaInfo(string csharpTypeName, List fields) : this(csharpTypeName, csharpTypeName, csharpTypeName.ToUpper(), fields) { - } -} - -class TableMetaInfos { - public static readonly List tableMetaInfos = new List { - new TableMetaInfo("Module", new List { - new FieldMetaInfo("Generation", "2"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - new FieldMetaInfo("Mvid", "ComputGUIDIndexByte()"), - new FieldMetaInfo("EncId", "ComputGUIDIndexByte()"), - new FieldMetaInfo("EncBaseId", "ComputGUIDIndexByte()"), - }), - new TableMetaInfo("TypeRef", new List { - new FieldMetaInfo("ResolutionScope", "ComputTableIndexByte(TableType::MODULE, TableType::MODULEREF, TableType::ASSEMBLYREF, TableType::TYPEREF, TagBits::ResoulutionScope)"), - new FieldMetaInfo("Name", "typeName", "ComputStringIndexByte()"), - new FieldMetaInfo("Namespace", "typeNamespace", "ComputStringIndexByte()"), - }), - new TableMetaInfo("TypeDef", new List { - new FieldMetaInfo("Flags", "4"), - new FieldMetaInfo("Name", "typeName", "ComputStringIndexByte()"), - new FieldMetaInfo("Namespace", "typeNamespace", "ComputStringIndexByte()"), - new FieldMetaInfo("Extends", "ComputTableIndexByte(TableType::TYPEDEF, TableType::TYPEREF, TableType::TYPESPEC, TagBits::TypeDefOrRef)"), - new FieldMetaInfo("FieldList", "ComputTableIndexByte(TableType::FIELD)"), - new FieldMetaInfo("MethodList", "ComputTableIndexByte(TableType::METHOD)"), - }), - new TableMetaInfo("FieldPtr", new List { - new FieldMetaInfo("Field", "ComputTableIndexByte(TableType::FIELD)"), - }), - new TableMetaInfo("Field", new List { - new FieldMetaInfo("Flags", "2"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - new FieldMetaInfo("Signature", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("MethodPtr", new List { - new FieldMetaInfo("Method", "ComputTableIndexByte(TableType::METHOD)"), - }), - new TableMetaInfo("Method", new List { - new FieldMetaInfo("RVA", "rva", "4"), - new FieldMetaInfo("ImplFlags", "2"), - new FieldMetaInfo("Flags", "2"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - new FieldMetaInfo("Signature", "ComputBlobIndexByte()"), - new FieldMetaInfo("ParamList", "ComputTableIndexByte(TableType::PARAM)"), - }), - new TableMetaInfo("ParamPtr", new List { - new FieldMetaInfo("Param", "ComputTableIndexByte(TableType::PARAM)"), - }), - new TableMetaInfo("Param", new List { - new FieldMetaInfo("Flags", "2"), - new FieldMetaInfo("Sequence", "2"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - }), - new TableMetaInfo("InterfaceImpl", new List { - new FieldMetaInfo("Class", "classIdx", "ComputTableIndexByte(TableType::TYPEDEF)"), - new FieldMetaInfo("Interface", "interfaceIdx", "ComputTableIndexByte(TableType::TYPEDEF, TableType::TYPEREF, TableType::TYPESPEC, TagBits::TypeDefOrRef)"), - }), - new TableMetaInfo("MemberRef", new List { - new FieldMetaInfo("Class", "classIdx", "ComputTableIndexByte(TableType::METHOD, TableType::MODULEREF, TableType::TYPEDEF, TableType::TYPEREF, TagBits::MemberRefParent)"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - new FieldMetaInfo("Signature", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("Constant", new List { - new FieldMetaInfo("Type", "1"), - new FieldMetaInfo("Padding", "1"), - new FieldMetaInfo("Parent", "ComputTableIndexByte(TableType::PARAM, TableType::FIELD, TableType::PROPERTY, TagBits::HasConstant)"), - new FieldMetaInfo("Value", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("CustomAttribute", new List { - new FieldMetaInfo("Parent", "ComputTableIndexByte(HasCustomAttributeAssociateTables, sizeof(HasCustomAttributeAssociateTables) / sizeof(TableType), TagBits::HasCustomAttribute)"), - new FieldMetaInfo("Type", "ComputTableIndexByte(TableType::METHOD, TableType::MEMBERREF, TagBits::CustomAttributeType)"), - new FieldMetaInfo("Value", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("FieldMarshal", new List { - new FieldMetaInfo("Parent", "ComputTableIndexByte(TableType::FIELD, TableType::PARAM, TagBits::HasFieldMarshal)"), - new FieldMetaInfo("NativeType", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("DeclSecurity", new List { - new FieldMetaInfo("Action", "2"), - new FieldMetaInfo("Parent", "ComputTableIndexByte(TableType::TYPEDEF, TableType::METHOD, TableType::ASSEMBLY, TagBits::HasDeclSecurity)"), - new FieldMetaInfo("PermissionSet", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("ClassLayout", new List { - new FieldMetaInfo("PackingSize", "2"), - new FieldMetaInfo("ClassSize", "4"), - new FieldMetaInfo("Parent", "ComputTableIndexByte(TableType::TYPEDEF)"), - }), - new TableMetaInfo("FieldLayout", new List { - new FieldMetaInfo("OffSet", "offset", "4"), - new FieldMetaInfo("Field", "ComputTableIndexByte(TableType::FIELD)"), - }), - new TableMetaInfo("StandAloneSig", new List { - new FieldMetaInfo("Signature", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("EventMap", new List { - new FieldMetaInfo("Parent", "ComputTableIndexByte(TableType::TYPEDEF)"), - new FieldMetaInfo("EventList", "ComputTableIndexByte(TableType::EVENT)"), - }), - new TableMetaInfo("EventPtr", new List { - new FieldMetaInfo("Event", "ComputTableIndexByte(TableType::EVENT)"), - }), - new TableMetaInfo("Event", new List { - new FieldMetaInfo("EventFlags", "2"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - new FieldMetaInfo("EventType", "ComputTableIndexByte(TableType::TYPEDEF, TableType::TYPEREF, TableType::TYPESPEC, TagBits::TypeDefOrRef)"), - }), - new TableMetaInfo("PropertyMap", new List { - new FieldMetaInfo("Parent", "ComputTableIndexByte(TableType::TYPEDEF)"), - new FieldMetaInfo("PropertyList", "ComputTableIndexByte(TableType::PROPERTY)"), - }), - new TableMetaInfo("PropertyPtr", new List { - new FieldMetaInfo("Property", "ComputTableIndexByte(TableType::PROPERTY)"), - }), - new TableMetaInfo("Property", new List { - new FieldMetaInfo("PropFlags", "flags", "2"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - new FieldMetaInfo("Type", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("MethodSemantics", new List { - new FieldMetaInfo("Semantic", "semantics", "2"), - new FieldMetaInfo("Method", "ComputTableIndexByte(TableType::METHOD)"), - new FieldMetaInfo("Association", "ComputTableIndexByte(TableType::EVENT, TableType::PROPERTY, TagBits::HasSemantics)"), - }), - new TableMetaInfo("MethodImpl", new List { - new FieldMetaInfo("Class", "classIdx", "ComputTableIndexByte(TableType::TYPEDEF)"), - new FieldMetaInfo("MethodBody", "ComputTableIndexByte(TableType::METHOD, TableType::MEMBERREF, TagBits::MethodDefOrRef)"), - new FieldMetaInfo("MethodDeclaration", "ComputTableIndexByte(TableType::METHOD, TableType::MEMBERREF, TagBits::MethodDefOrRef)"), - }), - new TableMetaInfo("ModuleRef", new List { - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - }), - new TableMetaInfo("TypeSpec", new List { - new FieldMetaInfo("Signature", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("ImplMap", new List { - new FieldMetaInfo("MappingFlags", "2"), - new FieldMetaInfo("MemberForwarded", "ComputTableIndexByte(TableType::FIELD, TableType::METHOD, TagBits::MemberForwarded)"), - new FieldMetaInfo("ImportName", "ComputStringIndexByte()"), - new FieldMetaInfo("ImportScope", "ComputTableIndexByte(TableType::MODULEREF)"), - }), - new TableMetaInfo("FieldRVA", new List { - new FieldMetaInfo("RVA", "rva", "4"), - new FieldMetaInfo("Field", "ComputTableIndexByte(TableType::FIELD)"), - }), - new TableMetaInfo("ENCLog","EncLog", "ENCLOG", new List { - new FieldMetaInfo("Token", "4"), - new FieldMetaInfo("FuncCode", "4"), - }), - new TableMetaInfo("ENCMap", "EncMap", "ENCMAP", new List { - new FieldMetaInfo("Token", "4"), - }), - new TableMetaInfo("Assembly", new List { - new FieldMetaInfo("HashAlgId", "4"), - new FieldMetaInfo("MajorVersion", "2"), - new FieldMetaInfo("MinorVersion", "2"), - new FieldMetaInfo("BuildNumber", "2"), - new FieldMetaInfo("RevisionNumber", "2"), - new FieldMetaInfo("Flags", "4"), - new FieldMetaInfo("PublicKey", "ComputBlobIndexByte()"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - new FieldMetaInfo("Locale", "ComputStringIndexByte()"), - }), - new TableMetaInfo("AssemblyProcessor", new List { - new FieldMetaInfo("Processor", "4"), - }), - new TableMetaInfo("AssemblyOS", new List { - new FieldMetaInfo("OSPlatformId", "osPlatformId", "4"), - new FieldMetaInfo("OSMajorVersion", "osMajorVersion", "4"), - new FieldMetaInfo("OSMinorVersion", "osMinorVersion", "4"), - }), - new TableMetaInfo("AssemblyRef", new List { - new FieldMetaInfo("MajorVersion", "2"), - new FieldMetaInfo("MinorVersion", "2"), - new FieldMetaInfo("BuildNumber", "2"), - new FieldMetaInfo("RevisionNumber", "2"), - new FieldMetaInfo("Flags", "4"), - new FieldMetaInfo("PublicKeyOrToken", "ComputBlobIndexByte()"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - new FieldMetaInfo("Locale", "ComputStringIndexByte()"), - new FieldMetaInfo("HashValue", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("AssemblyRefProcessor", new List { - new FieldMetaInfo("AssemblyRef", "4"), - new FieldMetaInfo("Processor", "ComputTableIndexByte(TableType::ASSEMBLYREF)"), - }), - new TableMetaInfo("AssemblyRefOS", new List { - new FieldMetaInfo("OSPlatformId", "osPlatformId", "4"), - new FieldMetaInfo("OSMajorVersion", "osMajorVersion", "4"), - new FieldMetaInfo("OSMinorVersion", "osMinorVersion", "4"), - new FieldMetaInfo("AssemblyRef", "ComputTableIndexByte(TableType::ASSEMBLYREF)"), - }), - new TableMetaInfo("File", new List { - new FieldMetaInfo("Flags", "4"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - new FieldMetaInfo("HashValue", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("ExportedType", new List { - new FieldMetaInfo("Flags", "4"), - new FieldMetaInfo("TypeDefId", "4"), - new FieldMetaInfo("TypeName", "ComputStringIndexByte()"), - new FieldMetaInfo("TypeNamespace", "ComputStringIndexByte()"), - new FieldMetaInfo("Implementation", "ComputTableIndexByte(TableType::FILE, TableType::EXPORTEDTYPE, TableType::ASSEMBLY, TagBits::Implementation)"), - }), - new TableMetaInfo("ManifestResource", new List { - new FieldMetaInfo("Offset", "4"), - new FieldMetaInfo("Flags", "4"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - new FieldMetaInfo("Implementation", "ComputTableIndexByte(TableType::FILE, TableType::ASSEMBLYREF, TagBits::Implementation)"), - }), - new TableMetaInfo("NestedClass", new List { - new FieldMetaInfo("NestedClass", "ComputTableIndexByte(TableType::TYPEDEF)"), - new FieldMetaInfo("EnclosingClass", "ComputTableIndexByte(TableType::TYPEDEF)"), - }), - new TableMetaInfo("GenericParam", new List { - new FieldMetaInfo("Number", "2"), - new FieldMetaInfo("Flags", "2"), - new FieldMetaInfo("Owner", "ComputTableIndexByte(TableType::TYPEDEF, TableType::METHOD, TagBits::TypeOrMethodDef)"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - }), - new TableMetaInfo("MethodSpec", new List { - new FieldMetaInfo("Method", "ComputTableIndexByte(TableType::METHOD, TableType::MEMBERREF, TagBits::MethodDefOrRef)"), - new FieldMetaInfo("Instantiation", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("GenericParamConstraint", new List { - new FieldMetaInfo("Owner", "ComputTableIndexByte(TableType::GENERICPARAM)"), - new FieldMetaInfo("Constraint", "ComputTableIndexByte(TableType::TYPEDEF, TableType::TYPEREF, TableType::TYPESPEC, TagBits::TypeDefOrRef)"), - }), - - new TableMetaInfo("Document", new List { - new FieldMetaInfo("Name", "ComputBlobIndexByte()"), - new FieldMetaInfo("HashAlgorithm", "ComputGUIDIndexByte()"), - new FieldMetaInfo("Hash", "ComputBlobIndexByte()"), - new FieldMetaInfo("Language", "ComputGUIDIndexByte()"), - }), - new TableMetaInfo("MethodDebugInformation", new List { - new FieldMetaInfo("Document", "ComputTableIndexByte(TableType::DOCUMENT)"), - new FieldMetaInfo("SequencePoints", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("LocalScope", new List { - new FieldMetaInfo("Method", "ComputTableIndexByte(TableType::METHOD)"), - new FieldMetaInfo("ImportScope", "ComputTableIndexByte(TableType::IMPORTSCOPE)"), - new FieldMetaInfo("VariableList", "variables", "ComputTableIndexByte(TableType::LOCALVARIABLE)"), - new FieldMetaInfo("ConstantList", "constants", "ComputTableIndexByte(TableType::LOCALCONSTANT)"), - new FieldMetaInfo("StartOffset", "4"), - new FieldMetaInfo("Length", "4"), - }), - new TableMetaInfo("LocalVariable", new List { - new FieldMetaInfo("Attributes", "2"), - new FieldMetaInfo("Index", "2"), - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - }), - new TableMetaInfo("LocalConstant", new List { - new FieldMetaInfo("Name", "ComputStringIndexByte()"), - new FieldMetaInfo("Signature", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("ImportScope", new List { - new FieldMetaInfo("Parent", "ComputTableIndexByte(TableType::IMPORTSCOPE)"), - new FieldMetaInfo("Imports", "ComputBlobIndexByte()"), - }), - new TableMetaInfo("StateMachineMethod", new List { - new FieldMetaInfo("MoveNextMethod", "ComputTableIndexByte(TableType::METHOD)"), - new FieldMetaInfo("KickoffMethod", "ComputTableIndexByte(TableType::METHOD)"), - }), - new TableMetaInfo("CustomDebugInformation", new List { - new FieldMetaInfo("Parent", "ComputTableIndexByte(HasCustomDebugInformation, sizeof(HasCustomDebugInformation) / sizeof(TableType), TagBits::HasCustomDebugInformation)"), - new FieldMetaInfo("Kind", "ComputGUIDIndexByte()"), - new FieldMetaInfo("Value", "ComputBlobIndexByte()"), - }), - }; -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/TableMetaInfos.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/TableMetaInfos.cs.meta deleted file mode 100644 index a3a2a88f..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/Polymorphic/TableMetaInfos.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ef98af767d086bd428f52503188789b1 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/PrebuildCommandExt.cs b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/PrebuildCommandExt.cs deleted file mode 100644 index 85ce25b5..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/PrebuildCommandExt.cs +++ /dev/null @@ -1,164 +0,0 @@ -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; -using HybridCLR.Editor.AOT; -using Analyzer2 = HybridCLR.Editor.AOT.Analyzer; - -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(); - GeneratePolymorphicCodesWhenEnable(); - LinkGeneratorCommand.GenerateLinkXml(target); - StripAOTDllCommand.GenerateStripedAOTDlls(target); - - string obfuscatedHotUpdateDllPath = GetObfuscatedHotUpdateAssemblyOutputPath(target); - ObfuscateUtil.ObfuscateHotUpdateAssemblies(target, obfuscatedHotUpdateDllPath); - GenerateMethodBridgeAndReversePInvokeWrapper(target, obfuscatedHotUpdateDllPath); - GenerateAOTGenericReference(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); - } - - [MenuItem("HybridCLR/ObfuzExtension/GeneratePolymorphicCodes")] - public static void GeneratePolymorphicCodes() - { - ObfuscateUtil.GeneratePolymorphicCodes($"{SettingsUtil.LocalIl2CppDir}/libil2cpp"); - } - - private static void GeneratePolymorphicCodesWhenEnable() - { - PolymorphicDllSettings settings = ObfuzSettings.Instance.polymorphicDllSettings; - if (!settings.enable) - { - UnityEngine.Debug.LogWarning("Polymorphic code generation is disabled."); - return; - } - GeneratePolymorphicCodes(); - } - - 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(); - } - - public static void GenerateAOTGenericReference(BuildTarget target, string obfuscatedHotUpdateDllPath) - { - var gs = SettingsUtil.HybridCLRSettings; - List hotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; - - AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector( - CreateObfuscatedHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames, ObfuzSettings.Instance.assemblySettings.GetAssembliesToObfuscate(), obfuscatedHotUpdateDllPath), hotUpdateDllNames); - var analyzer = new Analyzer2(new Analyzer2.Options - { - MaxIterationCount = Math.Min(20, gs.maxGenericReferenceIteration), - Collector = collector, - }); - - analyzer.Run(); - - var writer = new GenericReferenceWriter(); - writer.Write(analyzer.AotGenericTypes.ToList(), analyzer.AotGenericMethods.ToList(), $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}"); - AssetDatabase.Refresh(); - } - } -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/PrebuildCommandExt.cs.meta b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/PrebuildCommandExt.cs.meta deleted file mode 100644 index 2bcd1c79..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Editor/PrebuildCommandExt.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: afc965e1afdfc8e47b8a70be7a93cf25 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/LICENSE b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/LICENSE deleted file mode 100644 index 093e5999..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 Code Philosophy(代码哲学) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/LICENSE.meta b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/LICENSE.meta deleted file mode 100644 index dd09461e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/LICENSE.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 3036602f815e31341b4445f0e331b58e -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/README.md b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/README.md deleted file mode 100644 index d52e8ba0..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# obfuz4hybridclr -obfuz4hybridclr is a obfuz extension for HybridCLR. diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/README.md.meta b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/README.md.meta deleted file mode 100644 index c8633d1e..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/README.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 3ab25e7bb5a8e7d4fb3ba4614f2e3822 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/MetadataReader.h.tpl b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/MetadataReader.h.tpl deleted file mode 100644 index 0a630027..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/MetadataReader.h.tpl +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -#include "MetadataUtil.h" - -namespace hybridclr -{ -namespace metadata -{ - struct ByteSpan - { - const byte* data; - uint32_t length; - ByteSpan() : data(nullptr), length(0) {} - ByteSpan(const byte* data, uint32_t length) : data(data), length(length) {} - }; - - class MetadataReader - { - private: - const byte* _data; - public: - MetadataReader(const byte* data) : _data(data) {} - int16_t ReadInt16() - { - int16_t value = GetI2LittleEndian(_data); - _data += 2; - return value; - } - - bool ReadBool() - { - return *(_data++) != 0; - } - - uint8_t ReadUInt8() - { - return *(_data++); - } - - uint16_t ReadUInt16() - { - uint16_t value = GetU2LittleEndian(_data); - _data += 2; - return value; - } - - int32_t ReadInt32() - { - int32_t value = GetI4LittleEndian(_data); - _data += 4; - return value; - } - - uint32_t ReadUInt32() - { - uint32_t value = GetU4LittleEndian(_data); - _data += 4; - return value; - } - - int64_t ReadInt64() - { - int64_t value = GetI8LittleEndian(_data); - _data += 8; - return value; - } - - uint64_t ReadUInt64() - { - uint64_t value = GetU8LittleEndian(_data); - _data += 8; - return value; - } - - const byte* ReadFixedBytes(int32_t byteCount) - { - const byte* value = _data; - _data += byteCount; - return value; - } - - ByteSpan ReadBytes() - { - uint32_t byteCount = ReadUInt32(); - const byte* buffer = _data; - _data += byteCount; - return ByteSpan(buffer, byteCount); - } - - const byte* CurrentDataPtr() const - { - return _data; - } - }; -} -} \ No newline at end of file diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicDatas.h.tpl b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicDatas.h.tpl deleted file mode 100644 index bb91b78b..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicDatas.h.tpl +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once -#include "MetadataReader.h" - -namespace hybridclr -{ -namespace metadata -{ - //!!!{{POLYMORPHIC_DATA - struct HeaderBaseData - { - uint32_t metadataSize; - uint32_t sectionCount; - const byte* dummyData; - uint32_t metadataRva; - uint32_t entryPointToken; - void Read(MetadataReader& reader) - { - metadataSize = reader.ReadUInt32(); - sectionCount = reader.ReadUInt32(); - dummyData = reader.ReadFixedBytes(8); - metadataRva = reader.ReadUInt32(); - entryPointToken = reader.ReadUInt32(); - } - }; - - struct SectionData - { - uint32_t rva; - uint32_t fileOffset; - uint32_t virtualSize; - uint32_t fileLength; - void Read(MetadataReader& reader) - { - rva = reader.ReadUInt32(); - fileOffset = reader.ReadUInt32(); - virtualSize = reader.ReadUInt32(); - fileLength = reader.ReadUInt32(); - } - }; - - struct MetadataHeaderBaseData - { - uint32_t signature; - uint8_t reserved2; - ByteSpan versionString; - uint16_t majorVersion; - uint16_t heapsCount; - uint32_t reserved1; - uint8_t storageFlags; - uint16_t minorVersion; - void Read(MetadataReader& reader) - { - signature = reader.ReadUInt32(); - reserved2 = reader.ReadUInt8(); - versionString = reader.ReadBytes(); - majorVersion = reader.ReadUInt16(); - heapsCount = reader.ReadUInt16(); - reserved1 = reader.ReadUInt32(); - storageFlags = reader.ReadUInt8(); - minorVersion = reader.ReadUInt16(); - } - }; - - struct TablesHeapHeaderBaseData - { - uint64_t validMask; - uint32_t reserved1; - uint8_t streamFlags; - uint8_t majorVersion; - uint64_t sortedMask; - uint8_t minorVersion; - uint8_t log2Rid; - void Read(MetadataReader& reader) - { - validMask = reader.ReadUInt64(); - reserved1 = reader.ReadUInt32(); - streamFlags = reader.ReadUInt8(); - majorVersion = reader.ReadUInt8(); - sortedMask = reader.ReadUInt64(); - minorVersion = reader.ReadUInt8(); - log2Rid = reader.ReadUInt8(); - } - }; - - - //!!!}}POLYMORPHIC_DATA -} -} \ No newline at end of file diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicDefs.h.tpl b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicDefs.h.tpl deleted file mode 100644 index a88b8a7d..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicDefs.h.tpl +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include "MetadataReader.h" - -namespace hybridclr -{ -namespace metadata -{ - //!!!{{POLYMORPHIC_DEFINES -#define POLYMORPHIC_IMAGE_SIGNATURE "CODEPHPY" - constexpr uint32_t kPolymorphicImageVersion = 1; - constexpr uint32_t kFormatVariantVersion = 0; - - //!!!}}POLYMORPHIC_DEFINES - - struct PolymorphicImageHeaderData - { - const byte* signature; - uint32_t formatVersion; - uint32_t formatVariant; - void Read(MetadataReader& reader) - { - signature = reader.ReadFixedBytes(8); - formatVersion = reader.ReadUInt32(); - formatVariant = reader.ReadUInt32(); - } - }; -} -} \ No newline at end of file diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicRawImage.cpp.tpl b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicRawImage.cpp.tpl deleted file mode 100644 index ef091f5c..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicRawImage.cpp.tpl +++ /dev/null @@ -1,897 +0,0 @@ -#include "PolymorphicRawImage.h" - -#include - -#include "PolymorphicDefs.h" -#include "PolymorphicDatas.h" - -namespace hybridclr -{ -namespace metadata -{ - - struct RawSectionHeader - { - uint32_t fileOffset; - uint32_t fileLength; - uint32_t rva; - uint32_t virtualSize; - }; - - LoadImageErrorCode PolymorphicRawImage::LoadCLIHeader(uint32_t& entryPointToken, uint32_t& metadataRva, uint32_t& metadataSize) - { - if (_imageLength < 0x100) - { - return LoadImageErrorCode::BAD_IMAGE; - } - - MetadataReader reader(_imageData); - - PolymorphicImageHeaderData imageHeaderData = {}; - imageHeaderData.Read(reader); - - const char* sig = (const char*)_imageData; - if (std::strncmp((const char*)imageHeaderData.signature, POLYMORPHIC_IMAGE_SIGNATURE, sizeof(POLYMORPHIC_IMAGE_SIGNATURE) - 1)) - { - return LoadImageErrorCode::BAD_IMAGE; - } - if (imageHeaderData.formatVersion != kPolymorphicImageVersion) - { - return LoadImageErrorCode::UNSUPPORT_FORMAT_VERSION; - } - if (imageHeaderData.formatVariant != kFormatVariantVersion) - { - return LoadImageErrorCode::UNMATCH_FORMAT_VARIANT; - } - - //reader.ReadFixedBytes(polymorphic::kImageHeaderDummyDataSize); // Skip dummy data - - PolymorphicHeaderBaseData headerBaseData = {}; - headerBaseData.Read(reader); - - const size_t kEntryPointTokenOffset = 16; - entryPointToken = headerBaseData.entryPointToken; - metadataRva = headerBaseData.metadataRva; - metadataSize = headerBaseData.metadataSize; - - uint32_t sectionCount = headerBaseData.sectionCount; - for (uint32_t i = 0; i < sectionCount; i++) - { - PolymorphicSectionData sectionData = {}; - sectionData.Read(reader); - _sections.push_back({ sectionData.rva, sectionData.rva + sectionData.virtualSize, sectionData.fileOffset - sectionData.rva }); - } - return LoadImageErrorCode::OK; - } - - LoadImageErrorCode PolymorphicRawImage::LoadStreamHeaders(uint32_t metadataRva, uint32_t metadataSize) - { - uint32_t metaOffset; - if (!TranslateRVAToImageOffset(metadataRva, metaOffset)) - { - return LoadImageErrorCode::BAD_IMAGE; - } - if (metaOffset >= _imageLength) - { - return LoadImageErrorCode::BAD_IMAGE; - } - - const byte* ptrMetaData = _imageData + metaOffset; - MetadataReader reader(ptrMetaData); - - PolymorphicMetadataHeaderBaseData metadataHeader = {}; - metadataHeader.Read(reader); - if (metadataHeader.signature != 0x424A5342) - { - return LoadImageErrorCode::BAD_IMAGE; - } - - uint16_t numStreamHeader = metadataHeader.heapsCount; - const StreamHeader* ptrStreamHeaders = (const StreamHeader*)(reader.CurrentDataPtr()); - - const StreamHeader* curSH = ptrStreamHeaders; - const size_t maxStreamNameSize = 16; - for (int i = 0; i < numStreamHeader; i++) - { - //std::cout << "name:" << (char*)curSH->name << ", offset:" << curSH->offset << ", size:" << curSH->size << std::endl; - - if (curSH->offset >= metadataSize) - { - return LoadImageErrorCode::BAD_IMAGE; - } - CliStream* rs = nullptr; - CliStream nonStandardStream; - CliStream pdbStream; - if (!std::strncmp(curSH->name, "#~", maxStreamNameSize)) - { - rs = &_streamTables; - } - else if (!std::strncmp(curSH->name, "#Strings", maxStreamNameSize)) - { - rs = &_streamStringHeap; - } - else if (!std::strncmp(curSH->name, "#US", maxStreamNameSize)) - { - rs = &_streamUS; - } - else if (!std::strncmp(curSH->name, "#GUID", maxStreamNameSize)) - { - rs = &_streamGuidHeap; - if (curSH->size % 16 != 0) - { - return LoadImageErrorCode::BAD_IMAGE; - } - } - else if (!std::strncmp(curSH->name, "#Blob", maxStreamNameSize)) - { - rs = &_streamBlobHeap; - } - else if (!std::strncmp(curSH->name, "#-", maxStreamNameSize)) - { - rs = &nonStandardStream; - } - else if (!std::strncmp(curSH->name, "#Pdb", maxStreamNameSize)) - { - rs = &pdbStream; - } - else - { - //std::cerr << "unknown stream name:" << curSH->name << std::endl; - return LoadImageErrorCode::BAD_IMAGE; - } - rs->data = ptrMetaData + curSH->offset; - rs->size = curSH->size; - rs->name = curSH->name; - size_t sizeOfStream = 8 + (std::strlen(curSH->name) / 4 + 1) * 4; - curSH = (const StreamHeader*)((byte*)curSH + sizeOfStream); - } - return LoadImageErrorCode::OK; - } - - LoadImageErrorCode PolymorphicRawImage::LoadTables() - { - MetadataReader reader(_streamTables.data); - - PolymorphicTablesHeapHeaderBaseData heapHeader = {}; - heapHeader.Read(reader); - - if (heapHeader.reserved1 != 0 || heapHeader.majorVersion != 2 || heapHeader.minorVersion != 0) - { - return LoadImageErrorCode::BAD_IMAGE; - } - if ((heapHeader.streamFlags & ~0x7)) - { - return LoadImageErrorCode::BAD_IMAGE; - } - _4byteStringIndex = heapHeader.streamFlags & 0x1; - _4byteGUIDIndex = heapHeader.streamFlags & 0x2; - _4byteBlobIndex = heapHeader.streamFlags & 0x4; - - uint64_t validMask = ((uint64_t)1 << TABLE_NUM) - 1; - if (heapHeader.validMask & ~validMask) - { - return LoadImageErrorCode::BAD_IMAGE; - } - // sorted include not exist table, so check is not need. - //if (heapHeader.sorted & ~validMask) - //{ - // return LoadImageErrorCode::BAD_IMAGE; - //} - - uint32_t validTableNum = GetNotZeroBitCount(heapHeader.validMask); - //std::cout << "valid table num:" << validTableNum << std::endl; - //printf("#~ size:%0x\n", _streamTables.size); - const uint32_t* tableRowNums = (uint32_t*)(reader.CurrentDataPtr()); - const byte* tableDataBegin = (const byte*)(tableRowNums + validTableNum); - - { - int curValidTableIndex = 0; - for (int i = 0; i <= MAX_TABLE_INDEX; i++) - { - uint64_t mask = (uint64_t)1 << i; - _tables[i] = {}; - if (heapHeader.validMask & mask) - { - uint32_t rowNum = tableRowNums[curValidTableIndex]; - _tables[i].rowNum = rowNum; - ++curValidTableIndex; - } - } - } - - BuildTableRowMetas(); - - int curValidTableIndex = 0; - const byte* curTableData = tableDataBegin; - for (int i = 0; i <= MAX_TABLE_INDEX; i++) - { - uint64_t mask = (uint64_t)1 << i; - bool sorted = heapHeader.sortedMask & mask; - if (heapHeader.validMask & mask) - { - uint32_t rowNum = tableRowNums[curValidTableIndex]; - uint32_t totalSize = 0; - auto& table = _tableRowMetas[i]; - for (auto& col : table) - { - col.offset = totalSize; - totalSize += col.size; - } - uint32_t metaDataRowSize = totalSize; - //uint64_t offset = curTableData - _imageData; - _tables[i] = { curTableData, metaDataRowSize, rowNum, true, sorted }; - curTableData += metaDataRowSize * rowNum; - //std::cout << "table:" << i << " ," << curValidTableIndex << ", row_size:" << metaDataRowSize << ", row_num:" << rowNum << std::endl; - //printf("table:[%d][%d] offset:%0llx row_size:%d row_count:%d\n", i, curValidTableIndex, offset, metaDataRowSize, rowNum); - ++curValidTableIndex; - } - else - { - _tables[i] = { nullptr, 0, 0, false, sorted }; - } - } - - return LoadImageErrorCode::OK; - } - - void PolymorphicRawImage::BuildTableRowMetas() - { - //!!!{{TABLE_ROW_METADS - { - auto& table = _tableRowMetas[(int)TableType::MODULE]; - table.push_back({2}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputGUIDIndexByte()}); - table.push_back({ComputGUIDIndexByte()}); - table.push_back({ComputGUIDIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::TYPEREF]; - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputTableIndexByte(TableType::MODULE, TableType::MODULEREF, TableType::ASSEMBLYREF, TableType::TYPEREF, TagBits::ResoulutionScope)}); - } - { - auto& table = _tableRowMetas[(int)TableType::TYPEDEF]; - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputTableIndexByte(TableType::FIELD)}); - table.push_back({ComputTableIndexByte(TableType::TYPEDEF, TableType::TYPEREF, TableType::TYPESPEC, TagBits::TypeDefOrRef)}); - table.push_back({4}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputTableIndexByte(TableType::METHOD)}); - } - { - auto& table = _tableRowMetas[(int)TableType::FIELDPTR]; - table.push_back({ComputTableIndexByte(TableType::FIELD)}); - } - { - auto& table = _tableRowMetas[(int)TableType::FIELD]; - table.push_back({ComputBlobIndexByte()}); - table.push_back({2}); - table.push_back({ComputStringIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::METHODPTR]; - table.push_back({ComputTableIndexByte(TableType::METHOD)}); - } - { - auto& table = _tableRowMetas[(int)TableType::METHOD]; - table.push_back({ComputBlobIndexByte()}); - table.push_back({2}); - table.push_back({2}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputTableIndexByte(TableType::PARAM)}); - table.push_back({4}); - } - { - auto& table = _tableRowMetas[(int)TableType::PARAMPTR]; - table.push_back({ComputTableIndexByte(TableType::PARAM)}); - } - { - auto& table = _tableRowMetas[(int)TableType::PARAM]; - table.push_back({2}); - table.push_back({ComputStringIndexByte()}); - table.push_back({2}); - } - { - auto& table = _tableRowMetas[(int)TableType::INTERFACEIMPL]; - table.push_back({ComputTableIndexByte(TableType::TYPEDEF)}); - table.push_back({ComputTableIndexByte(TableType::TYPEDEF, TableType::TYPEREF, TableType::TYPESPEC, TagBits::TypeDefOrRef)}); - } - { - auto& table = _tableRowMetas[(int)TableType::MEMBERREF]; - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputBlobIndexByte()}); - table.push_back({ComputTableIndexByte(TableType::METHOD, TableType::MODULEREF, TableType::TYPEDEF, TableType::TYPEREF, TagBits::MemberRefParent)}); - } - { - auto& table = _tableRowMetas[(int)TableType::CONSTANT]; - table.push_back({1}); - table.push_back({1}); - table.push_back({ComputTableIndexByte(TableType::PARAM, TableType::FIELD, TableType::PROPERTY, TagBits::HasConstant)}); - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::CUSTOMATTRIBUTE]; - table.push_back({ComputTableIndexByte(HasCustomAttributeAssociateTables, sizeof(HasCustomAttributeAssociateTables) / sizeof(TableType), TagBits::HasCustomAttribute)}); - table.push_back({ComputTableIndexByte(TableType::METHOD, TableType::MEMBERREF, TagBits::CustomAttributeType)}); - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::FIELDMARSHAL]; - table.push_back({ComputTableIndexByte(TableType::FIELD, TableType::PARAM, TagBits::HasFieldMarshal)}); - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::DECLSECURITY]; - table.push_back({2}); - table.push_back({ComputTableIndexByte(TableType::TYPEDEF, TableType::METHOD, TableType::ASSEMBLY, TagBits::HasDeclSecurity)}); - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::CLASSLAYOUT]; - table.push_back({4}); - table.push_back({2}); - table.push_back({ComputTableIndexByte(TableType::TYPEDEF)}); - } - { - auto& table = _tableRowMetas[(int)TableType::FIELDLAYOUT]; - table.push_back({ComputTableIndexByte(TableType::FIELD)}); - table.push_back({4}); - } - { - auto& table = _tableRowMetas[(int)TableType::STANDALONESIG]; - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::EVENTMAP]; - table.push_back({ComputTableIndexByte(TableType::TYPEDEF)}); - table.push_back({ComputTableIndexByte(TableType::EVENT)}); - } - { - auto& table = _tableRowMetas[(int)TableType::EVENTPTR]; - table.push_back({ComputTableIndexByte(TableType::EVENT)}); - } - { - auto& table = _tableRowMetas[(int)TableType::EVENT]; - table.push_back({ComputTableIndexByte(TableType::TYPEDEF, TableType::TYPEREF, TableType::TYPESPEC, TagBits::TypeDefOrRef)}); - table.push_back({ComputStringIndexByte()}); - table.push_back({2}); - } - { - auto& table = _tableRowMetas[(int)TableType::PROPERTYMAP]; - table.push_back({ComputTableIndexByte(TableType::PROPERTY)}); - table.push_back({ComputTableIndexByte(TableType::TYPEDEF)}); - } - { - auto& table = _tableRowMetas[(int)TableType::PROPERTYPTR]; - table.push_back({ComputTableIndexByte(TableType::PROPERTY)}); - } - { - auto& table = _tableRowMetas[(int)TableType::PROPERTY]; - table.push_back({2}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::METHODSEMANTICS]; - table.push_back({ComputTableIndexByte(TableType::EVENT, TableType::PROPERTY, TagBits::HasSemantics)}); - table.push_back({ComputTableIndexByte(TableType::METHOD)}); - table.push_back({2}); - } - { - auto& table = _tableRowMetas[(int)TableType::METHODIMPL]; - table.push_back({ComputTableIndexByte(TableType::METHOD, TableType::MEMBERREF, TagBits::MethodDefOrRef)}); - table.push_back({ComputTableIndexByte(TableType::METHOD, TableType::MEMBERREF, TagBits::MethodDefOrRef)}); - table.push_back({ComputTableIndexByte(TableType::TYPEDEF)}); - } - { - auto& table = _tableRowMetas[(int)TableType::MODULEREF]; - table.push_back({ComputStringIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::TYPESPEC]; - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::IMPLMAP]; - table.push_back({2}); - table.push_back({ComputTableIndexByte(TableType::MODULEREF)}); - table.push_back({ComputTableIndexByte(TableType::FIELD, TableType::METHOD, TagBits::MemberForwarded)}); - table.push_back({ComputStringIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::FIELDRVA]; - table.push_back({ComputTableIndexByte(TableType::FIELD)}); - table.push_back({4}); - } - { - auto& table = _tableRowMetas[(int)TableType::ENCLOG]; - table.push_back({4}); - table.push_back({4}); - } - { - auto& table = _tableRowMetas[(int)TableType::ENCMAP]; - table.push_back({4}); - } - { - auto& table = _tableRowMetas[(int)TableType::ASSEMBLY]; - table.push_back({2}); - table.push_back({4}); - table.push_back({2}); - table.push_back({2}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputBlobIndexByte()}); - table.push_back({2}); - table.push_back({4}); - } - { - auto& table = _tableRowMetas[(int)TableType::ASSEMBLYPROCESSOR]; - table.push_back({4}); - } - { - auto& table = _tableRowMetas[(int)TableType::ASSEMBLYOS]; - table.push_back({4}); - table.push_back({4}); - table.push_back({4}); - } - { - auto& table = _tableRowMetas[(int)TableType::ASSEMBLYREF]; - table.push_back({4}); - table.push_back({2}); - table.push_back({2}); - table.push_back({ComputBlobIndexByte()}); - table.push_back({ComputBlobIndexByte()}); - table.push_back({2}); - table.push_back({2}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputStringIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::ASSEMBLYREFPROCESSOR]; - table.push_back({ComputTableIndexByte(TableType::ASSEMBLYREF)}); - table.push_back({4}); - } - { - auto& table = _tableRowMetas[(int)TableType::ASSEMBLYREFOS]; - table.push_back({4}); - table.push_back({4}); - table.push_back({4}); - table.push_back({ComputTableIndexByte(TableType::ASSEMBLYREF)}); - } - { - auto& table = _tableRowMetas[(int)TableType::FILE]; - table.push_back({4}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::EXPORTEDTYPE]; - table.push_back({4}); - table.push_back({4}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputTableIndexByte(TableType::FILE, TableType::EXPORTEDTYPE, TableType::ASSEMBLY, TagBits::Implementation)}); - } - { - auto& table = _tableRowMetas[(int)TableType::MANIFESTRESOURCE]; - table.push_back({4}); - table.push_back({4}); - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputTableIndexByte(TableType::FILE, TableType::ASSEMBLYREF, TagBits::Implementation)}); - } - { - auto& table = _tableRowMetas[(int)TableType::NESTEDCLASS]; - table.push_back({ComputTableIndexByte(TableType::TYPEDEF)}); - table.push_back({ComputTableIndexByte(TableType::TYPEDEF)}); - } - { - auto& table = _tableRowMetas[(int)TableType::GENERICPARAM]; - table.push_back({2}); - table.push_back({2}); - table.push_back({ComputTableIndexByte(TableType::TYPEDEF, TableType::METHOD, TagBits::TypeOrMethodDef)}); - table.push_back({ComputStringIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::METHODSPEC]; - table.push_back({ComputTableIndexByte(TableType::METHOD, TableType::MEMBERREF, TagBits::MethodDefOrRef)}); - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::GENERICPARAMCONSTRAINT]; - table.push_back({ComputTableIndexByte(TableType::TYPEDEF, TableType::TYPEREF, TableType::TYPESPEC, TagBits::TypeDefOrRef)}); - table.push_back({ComputTableIndexByte(TableType::GENERICPARAM)}); - } - { - auto& table = _tableRowMetas[(int)TableType::DOCUMENT]; - table.push_back({ComputBlobIndexByte()}); - table.push_back({ComputGUIDIndexByte()}); - table.push_back({ComputBlobIndexByte()}); - table.push_back({ComputGUIDIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::METHODDEBUGINFORMATION]; - table.push_back({ComputTableIndexByte(TableType::DOCUMENT)}); - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::LOCALSCOPE]; - table.push_back({ComputTableIndexByte(TableType::METHOD)}); - table.push_back({ComputTableIndexByte(TableType::IMPORTSCOPE)}); - table.push_back({ComputTableIndexByte(TableType::LOCALVARIABLE)}); - table.push_back({ComputTableIndexByte(TableType::LOCALCONSTANT)}); - table.push_back({4}); - table.push_back({4}); - } - { - auto& table = _tableRowMetas[(int)TableType::LOCALVARIABLE]; - table.push_back({2}); - table.push_back({2}); - table.push_back({ComputStringIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::LOCALCONSTANT]; - table.push_back({ComputStringIndexByte()}); - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::IMPORTSCOPE]; - table.push_back({ComputTableIndexByte(TableType::IMPORTSCOPE)}); - table.push_back({ComputBlobIndexByte()}); - } - { - auto& table = _tableRowMetas[(int)TableType::STATEMACHINEMETHOD]; - table.push_back({ComputTableIndexByte(TableType::METHOD)}); - table.push_back({ComputTableIndexByte(TableType::METHOD)}); - } - { - auto& table = _tableRowMetas[(int)TableType::CUSTOMDEBUGINFORMATION]; - table.push_back({ComputTableIndexByte(HasCustomDebugInformation, sizeof(HasCustomDebugInformation) / sizeof(TableType), TagBits::HasCustomDebugInformation)}); - table.push_back({ComputGUIDIndexByte()}); - table.push_back({ComputBlobIndexByte()}); - } - - //!!!}}TABLE_ROW_METADS - - for (int i = 0; i < TABLE_NUM; i++) - { - auto& table = _tableRowMetas[i]; - if (table.empty()) - { - IL2CPP_ASSERT(_tables[i].rowNum == 0 && _tables[i].rowMetaDataSize == 0); - } - else - { - uint32_t totalSize = 0; - for (auto& col : table) - { - col.offset = totalSize; - totalSize += col.size; - } - uint32_t computSize = ComputTableRowMetaDataSize((TableType)i); - IL2CPP_ASSERT(totalSize == computSize); - } - } - } - - //!!!{{READ_TABLES_IMPLEMENTATIONS - TbTypeRef PolymorphicRawImage::ReadTypeRef(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::TYPEREF).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::TYPEREF, rawIndex); - auto& rowSchema = GetRowSchema(TableType::TYPEREF); - TbTypeRef data; - data.typeNamespace = ReadColumn(rowPtr, rowSchema[0]); - data.typeName = ReadColumn(rowPtr, rowSchema[1]); - data.resolutionScope = ReadColumn(rowPtr, rowSchema[2]); - return data; - } - TbTypeDef PolymorphicRawImage::ReadTypeDef(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::TYPEDEF).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::TYPEDEF, rawIndex); - auto& rowSchema = GetRowSchema(TableType::TYPEDEF); - TbTypeDef data; - data.typeName = ReadColumn(rowPtr, rowSchema[0]); - data.fieldList = ReadColumn(rowPtr, rowSchema[1]); - data.extends = ReadColumn(rowPtr, rowSchema[2]); - data.flags = ReadColumn(rowPtr, rowSchema[3]); - data.typeNamespace = ReadColumn(rowPtr, rowSchema[4]); - data.methodList = ReadColumn(rowPtr, rowSchema[5]); - return data; - } - TbField PolymorphicRawImage::ReadField(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::FIELD).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::FIELD, rawIndex); - auto& rowSchema = GetRowSchema(TableType::FIELD); - TbField data; - data.signature = ReadColumn(rowPtr, rowSchema[0]); - data.flags = ReadColumn(rowPtr, rowSchema[1]); - data.name = ReadColumn(rowPtr, rowSchema[2]); - return data; - } - TbMethod PolymorphicRawImage::ReadMethod(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::METHOD).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::METHOD, rawIndex); - auto& rowSchema = GetRowSchema(TableType::METHOD); - TbMethod data; - data.signature = ReadColumn(rowPtr, rowSchema[0]); - data.flags = ReadColumn(rowPtr, rowSchema[1]); - data.implFlags = ReadColumn(rowPtr, rowSchema[2]); - data.name = ReadColumn(rowPtr, rowSchema[3]); - data.paramList = ReadColumn(rowPtr, rowSchema[4]); - data.rva = ReadColumn(rowPtr, rowSchema[5]); - return data; - } - TbParam PolymorphicRawImage::ReadParam(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::PARAM).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::PARAM, rawIndex); - auto& rowSchema = GetRowSchema(TableType::PARAM); - TbParam data; - data.flags = ReadColumn(rowPtr, rowSchema[0]); - data.name = ReadColumn(rowPtr, rowSchema[1]); - data.sequence = ReadColumn(rowPtr, rowSchema[2]); - return data; - } - TbInterfaceImpl PolymorphicRawImage::ReadInterfaceImpl(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::INTERFACEIMPL).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::INTERFACEIMPL, rawIndex); - auto& rowSchema = GetRowSchema(TableType::INTERFACEIMPL); - TbInterfaceImpl data; - data.classIdx = ReadColumn(rowPtr, rowSchema[0]); - data.interfaceIdx = ReadColumn(rowPtr, rowSchema[1]); - return data; - } - TbMemberRef PolymorphicRawImage::ReadMemberRef(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::MEMBERREF).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::MEMBERREF, rawIndex); - auto& rowSchema = GetRowSchema(TableType::MEMBERREF); - TbMemberRef data; - data.name = ReadColumn(rowPtr, rowSchema[0]); - data.signature = ReadColumn(rowPtr, rowSchema[1]); - data.classIdx = ReadColumn(rowPtr, rowSchema[2]); - return data; - } - TbConstant PolymorphicRawImage::ReadConstant(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::CONSTANT).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::CONSTANT, rawIndex); - auto& rowSchema = GetRowSchema(TableType::CONSTANT); - TbConstant data; - data.padding = ReadColumn(rowPtr, rowSchema[0]); - data.type = ReadColumn(rowPtr, rowSchema[1]); - data.parent = ReadColumn(rowPtr, rowSchema[2]); - data.value = ReadColumn(rowPtr, rowSchema[3]); - return data; - } - TbCustomAttribute PolymorphicRawImage::ReadCustomAttribute(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::CUSTOMATTRIBUTE).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::CUSTOMATTRIBUTE, rawIndex); - auto& rowSchema = GetRowSchema(TableType::CUSTOMATTRIBUTE); - TbCustomAttribute data; - data.parent = ReadColumn(rowPtr, rowSchema[0]); - data.type = ReadColumn(rowPtr, rowSchema[1]); - data.value = ReadColumn(rowPtr, rowSchema[2]); - return data; - } - TbClassLayout PolymorphicRawImage::ReadClassLayout(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::CLASSLAYOUT).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::CLASSLAYOUT, rawIndex); - auto& rowSchema = GetRowSchema(TableType::CLASSLAYOUT); - TbClassLayout data; - data.classSize = ReadColumn(rowPtr, rowSchema[0]); - data.packingSize = ReadColumn(rowPtr, rowSchema[1]); - data.parent = ReadColumn(rowPtr, rowSchema[2]); - return data; - } - TbFieldLayout PolymorphicRawImage::ReadFieldLayout(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::FIELDLAYOUT).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::FIELDLAYOUT, rawIndex); - auto& rowSchema = GetRowSchema(TableType::FIELDLAYOUT); - TbFieldLayout data; - data.field = ReadColumn(rowPtr, rowSchema[0]); - data.offset = ReadColumn(rowPtr, rowSchema[1]); - return data; - } - TbStandAloneSig PolymorphicRawImage::ReadStandAloneSig(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::STANDALONESIG).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::STANDALONESIG, rawIndex); - auto& rowSchema = GetRowSchema(TableType::STANDALONESIG); - TbStandAloneSig data; - data.signature = ReadColumn(rowPtr, rowSchema[0]); - return data; - } - TbEventMap PolymorphicRawImage::ReadEventMap(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::EVENTMAP).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::EVENTMAP, rawIndex); - auto& rowSchema = GetRowSchema(TableType::EVENTMAP); - TbEventMap data; - data.parent = ReadColumn(rowPtr, rowSchema[0]); - data.eventList = ReadColumn(rowPtr, rowSchema[1]); - return data; - } - TbEvent PolymorphicRawImage::ReadEvent(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::EVENT).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::EVENT, rawIndex); - auto& rowSchema = GetRowSchema(TableType::EVENT); - TbEvent data; - data.eventType = ReadColumn(rowPtr, rowSchema[0]); - data.name = ReadColumn(rowPtr, rowSchema[1]); - data.eventFlags = ReadColumn(rowPtr, rowSchema[2]); - return data; - } - TbPropertyMap PolymorphicRawImage::ReadPropertyMap(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::PROPERTYMAP).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::PROPERTYMAP, rawIndex); - auto& rowSchema = GetRowSchema(TableType::PROPERTYMAP); - TbPropertyMap data; - data.propertyList = ReadColumn(rowPtr, rowSchema[0]); - data.parent = ReadColumn(rowPtr, rowSchema[1]); - return data; - } - TbProperty PolymorphicRawImage::ReadProperty(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::PROPERTY).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::PROPERTY, rawIndex); - auto& rowSchema = GetRowSchema(TableType::PROPERTY); - TbProperty data; - data.flags = ReadColumn(rowPtr, rowSchema[0]); - data.name = ReadColumn(rowPtr, rowSchema[1]); - data.type = ReadColumn(rowPtr, rowSchema[2]); - return data; - } - TbMethodSemantics PolymorphicRawImage::ReadMethodSemantics(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::METHODSEMANTICS).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::METHODSEMANTICS, rawIndex); - auto& rowSchema = GetRowSchema(TableType::METHODSEMANTICS); - TbMethodSemantics data; - data.association = ReadColumn(rowPtr, rowSchema[0]); - data.method = ReadColumn(rowPtr, rowSchema[1]); - data.semantics = ReadColumn(rowPtr, rowSchema[2]); - return data; - } - TbMethodImpl PolymorphicRawImage::ReadMethodImpl(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::METHODIMPL).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::METHODIMPL, rawIndex); - auto& rowSchema = GetRowSchema(TableType::METHODIMPL); - TbMethodImpl data; - data.methodDeclaration = ReadColumn(rowPtr, rowSchema[0]); - data.methodBody = ReadColumn(rowPtr, rowSchema[1]); - data.classIdx = ReadColumn(rowPtr, rowSchema[2]); - return data; - } - TbModuleRef PolymorphicRawImage::ReadModuleRef(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::MODULEREF).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::MODULEREF, rawIndex); - auto& rowSchema = GetRowSchema(TableType::MODULEREF); - TbModuleRef data; - data.name = ReadColumn(rowPtr, rowSchema[0]); - return data; - } - TbTypeSpec PolymorphicRawImage::ReadTypeSpec(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::TYPESPEC).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::TYPESPEC, rawIndex); - auto& rowSchema = GetRowSchema(TableType::TYPESPEC); - TbTypeSpec data; - data.signature = ReadColumn(rowPtr, rowSchema[0]); - return data; - } - TbImplMap PolymorphicRawImage::ReadImplMap(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::IMPLMAP).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::IMPLMAP, rawIndex); - auto& rowSchema = GetRowSchema(TableType::IMPLMAP); - TbImplMap data; - data.mappingFlags = ReadColumn(rowPtr, rowSchema[0]); - data.importScope = ReadColumn(rowPtr, rowSchema[1]); - data.memberForwarded = ReadColumn(rowPtr, rowSchema[2]); - data.importName = ReadColumn(rowPtr, rowSchema[3]); - return data; - } - TbFieldRVA PolymorphicRawImage::ReadFieldRVA(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::FIELDRVA).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::FIELDRVA, rawIndex); - auto& rowSchema = GetRowSchema(TableType::FIELDRVA); - TbFieldRVA data; - data.field = ReadColumn(rowPtr, rowSchema[0]); - data.rva = ReadColumn(rowPtr, rowSchema[1]); - return data; - } - TbAssembly PolymorphicRawImage::ReadAssembly(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::ASSEMBLY).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::ASSEMBLY, rawIndex); - auto& rowSchema = GetRowSchema(TableType::ASSEMBLY); - TbAssembly data; - data.minorVersion = ReadColumn(rowPtr, rowSchema[0]); - data.hashAlgId = ReadColumn(rowPtr, rowSchema[1]); - data.buildNumber = ReadColumn(rowPtr, rowSchema[2]); - data.revisionNumber = ReadColumn(rowPtr, rowSchema[3]); - data.locale = ReadColumn(rowPtr, rowSchema[4]); - data.name = ReadColumn(rowPtr, rowSchema[5]); - data.publicKey = ReadColumn(rowPtr, rowSchema[6]); - data.majorVersion = ReadColumn(rowPtr, rowSchema[7]); - data.flags = ReadColumn(rowPtr, rowSchema[8]); - return data; - } - TbAssemblyRef PolymorphicRawImage::ReadAssemblyRef(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::ASSEMBLYREF).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::ASSEMBLYREF, rawIndex); - auto& rowSchema = GetRowSchema(TableType::ASSEMBLYREF); - TbAssemblyRef data; - data.flags = ReadColumn(rowPtr, rowSchema[0]); - data.majorVersion = ReadColumn(rowPtr, rowSchema[1]); - data.buildNumber = ReadColumn(rowPtr, rowSchema[2]); - data.publicKeyOrToken = ReadColumn(rowPtr, rowSchema[3]); - data.hashValue = ReadColumn(rowPtr, rowSchema[4]); - data.revisionNumber = ReadColumn(rowPtr, rowSchema[5]); - data.minorVersion = ReadColumn(rowPtr, rowSchema[6]); - data.locale = ReadColumn(rowPtr, rowSchema[7]); - data.name = ReadColumn(rowPtr, rowSchema[8]); - return data; - } - TbNestedClass PolymorphicRawImage::ReadNestedClass(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::NESTEDCLASS).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::NESTEDCLASS, rawIndex); - auto& rowSchema = GetRowSchema(TableType::NESTEDCLASS); - TbNestedClass data; - data.enclosingClass = ReadColumn(rowPtr, rowSchema[0]); - data.nestedClass = ReadColumn(rowPtr, rowSchema[1]); - return data; - } - TbGenericParam PolymorphicRawImage::ReadGenericParam(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::GENERICPARAM).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::GENERICPARAM, rawIndex); - auto& rowSchema = GetRowSchema(TableType::GENERICPARAM); - TbGenericParam data; - data.flags = ReadColumn(rowPtr, rowSchema[0]); - data.number = ReadColumn(rowPtr, rowSchema[1]); - data.owner = ReadColumn(rowPtr, rowSchema[2]); - data.name = ReadColumn(rowPtr, rowSchema[3]); - return data; - } - TbMethodSpec PolymorphicRawImage::ReadMethodSpec(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::METHODSPEC).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::METHODSPEC, rawIndex); - auto& rowSchema = GetRowSchema(TableType::METHODSPEC); - TbMethodSpec data; - data.method = ReadColumn(rowPtr, rowSchema[0]); - data.instantiation = ReadColumn(rowPtr, rowSchema[1]); - return data; - } - TbGenericParamConstraint PolymorphicRawImage::ReadGenericParamConstraint(uint32_t rawIndex) - { - IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(TableType::GENERICPARAMCONSTRAINT).rowNum); - const byte* rowPtr = GetTableRowPtr(TableType::GENERICPARAMCONSTRAINT, rawIndex); - auto& rowSchema = GetRowSchema(TableType::GENERICPARAMCONSTRAINT); - TbGenericParamConstraint data; - data.constraint = ReadColumn(rowPtr, rowSchema[0]); - data.owner = ReadColumn(rowPtr, rowSchema[1]); - return data; - } - - //!!!}}READ_TABLES_IMPLEMENTATIONS -} -} \ No newline at end of file diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicRawImage.h.tpl b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicRawImage.h.tpl deleted file mode 100644 index a48517b5..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/Templates~/PolymorphicRawImage.h.tpl +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "DotNetRawImageBase.h" - -namespace hybridclr -{ -namespace metadata -{ - - class PolymorphicRawImage : public DotNetRawImageBase - { - public: - PolymorphicRawImage() : DotNetRawImageBase() - { - - } - - LoadImageErrorCode LoadCLIHeader(uint32_t& entryPointToken, uint32_t& metadataRva, uint32_t& metadataSize) override; - virtual LoadImageErrorCode LoadStreamHeaders(uint32_t metadataRva, uint32_t metadataSize) override; - virtual LoadImageErrorCode LoadTables() override; - virtual void BuildTableRowMetas() override; - - //!!!{{READ_TABLES_OVERRIDES - virtual TbTypeRef ReadTypeRef(uint32_t rawIndex) override; - virtual TbTypeDef ReadTypeDef(uint32_t rawIndex) override; - virtual TbField ReadField(uint32_t rawIndex) override; - virtual TbMethod ReadMethod(uint32_t rawIndex) override; - virtual TbParam ReadParam(uint32_t rawIndex) override; - virtual TbInterfaceImpl ReadInterfaceImpl(uint32_t rawIndex) override; - virtual TbMemberRef ReadMemberRef(uint32_t rawIndex) override; - virtual TbConstant ReadConstant(uint32_t rawIndex) override; - virtual TbCustomAttribute ReadCustomAttribute(uint32_t rawIndex) override; - virtual TbClassLayout ReadClassLayout(uint32_t rawIndex) override; - virtual TbFieldLayout ReadFieldLayout(uint32_t rawIndex) override; - virtual TbStandAloneSig ReadStandAloneSig(uint32_t rawIndex) override; - virtual TbEventMap ReadEventMap(uint32_t rawIndex) override; - virtual TbEvent ReadEvent(uint32_t rawIndex) override; - virtual TbPropertyMap ReadPropertyMap(uint32_t rawIndex) override; - virtual TbProperty ReadProperty(uint32_t rawIndex) override; - virtual TbMethodSemantics ReadMethodSemantics(uint32_t rawIndex) override; - virtual TbMethodImpl ReadMethodImpl(uint32_t rawIndex) override; - virtual TbModuleRef ReadModuleRef(uint32_t rawIndex) override; - virtual TbTypeSpec ReadTypeSpec(uint32_t rawIndex) override; - virtual TbImplMap ReadImplMap(uint32_t rawIndex) override; - virtual TbFieldRVA ReadFieldRVA(uint32_t rawIndex) override; - virtual TbAssembly ReadAssembly(uint32_t rawIndex) override; - virtual TbAssemblyRef ReadAssemblyRef(uint32_t rawIndex) override; - virtual TbNestedClass ReadNestedClass(uint32_t rawIndex) override; - virtual TbGenericParam ReadGenericParam(uint32_t rawIndex) override; - virtual TbMethodSpec ReadMethodSpec(uint32_t rawIndex) override; - virtual TbGenericParamConstraint ReadGenericParamConstraint(uint32_t rawIndex) override; - - //!!!}}READ_TABLES_OVERRIDES - private: - - }; -} -} diff --git a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/package.json b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/package.json deleted file mode 100644 index 290afcd3..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "com.code-philosophy.obfuz4hybridclr", - "version": "1.0.0-beta.1", - "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/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/package.json.meta b/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/package.json.meta deleted file mode 100644 index 5577b3b3..00000000 --- a/UnityProject/Packages/com.code-philosophy.obfuz4hybridclr/package.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 9ac66e213a764b840b2533ee30123717 -PackageManifestImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Packages/manifest.json b/UnityProject/Packages/manifest.json index f2dda69d..9901e369 100644 --- a/UnityProject/Packages/manifest.json +++ b/UnityProject/Packages/manifest.json @@ -1,5 +1,7 @@ { "dependencies": { + "com.code-philosophy.obfuz": "https://gitee.com/focus-creative-games/obfuz.git", + "com.code-philosophy.obfuz4hybridclr": "https://gitee.com/focus-creative-games/obfuz4hybridclr.git", "com.unity.ide.rider": "3.0.34", "com.unity.ide.visualstudio": "2.0.22", "com.unity.ide.vscode": "1.2.5", diff --git a/UnityProject/Packages/packages-lock.json b/UnityProject/Packages/packages-lock.json index 069ff254..a9cecd8d 100644 --- a/UnityProject/Packages/packages-lock.json +++ b/UnityProject/Packages/packages-lock.json @@ -7,16 +7,18 @@ "dependencies": {} }, "com.code-philosophy.obfuz": { - "version": "file:com.code-philosophy.obfuz", + "version": "https://gitee.com/focus-creative-games/obfuz.git", "depth": 0, - "source": "embedded", - "dependencies": {} + "source": "git", + "dependencies": {}, + "hash": "6ec1a74d577b6aa6cf16e6588aaf989ca035913a" }, "com.code-philosophy.obfuz4hybridclr": { - "version": "file:com.code-philosophy.obfuz4hybridclr", + "version": "https://gitee.com/focus-creative-games/obfuz4hybridclr.git", "depth": 0, - "source": "embedded", - "dependencies": {} + "source": "git", + "dependencies": {}, + "hash": "be024a3b35d038d61fe8edb4807f14a443bc7751" }, "com.cysharp.unitask": { "version": "file:UniTask", diff --git a/UnityProject/ProjectSettings/Obfuz.asset b/UnityProject/ProjectSettings/Obfuz.asset index 560de562..185fbf72 100644 --- a/UnityProject/ProjectSettings/Obfuz.asset +++ b/UnityProject/ProjectSettings/Obfuz.asset @@ -18,10 +18,12 @@ MonoBehaviour: obfuscationProcessCallbackOrder: 10000 assemblySettings: assembliesToObfuscate: - - TEngine.Runtime - - Assembly-CSharp + - GameLogic + - GameProto nonObfuscatedButReferencingObfuscatedAssemblies: + - TEngine.Runtime - Launcher + - Assembly-CSharp additionalAssemblySearchPaths: [] obfuscateObfuzRuntime: 1 obfuscationPassSettings: