Compare commits

...

74 Commits
dev ... main

Author SHA1 Message Date
walon 0b6b8a92c0 fix: rename all parameter names to `1` may lead burst compile error, change to $"_{param.Sequence}" 2026-09-11 12:03:17 +08:00
walon aefec5c024 fix: don't rename inherit enclosing types and nested types of types with `[BurstCompile]` 2026-09-11 12:01:30 +08:00
walon 67f3dd4cf3 fix: disable Watermark pass because it will lead il2cpp.exe run failed if insert instructions at some special instructions(.e.g, insert instruction between ldtoken and call System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray). 2026-09-07 22:30:06 +08:00
walon 79c81e234c fix: remove RuntimeHelpers.InitializeArray dependency from ConstEncrypt DecryptInitializeArray
DecryptInitializeArray now takes encrypted byte[] + offset instead of RuntimeFieldHandle,
copies via Buffer.BlockCopy, and loads payload through RvaDataAllocator. Avoids Unity
6000.5+ IL2CPP C2664 on RuntimeFieldHandle vs Il2CppFieldRvaData. see issue-34
2026-09-07 22:26:01 +08:00
walon fa2345017a fix: fix VirtualMethodGroupCalculator.TypeFlatMethods::IsLooseTypeSigMatch treats type and forward type as different type by type.AssemblyQualifiedName which leads same-virtual-slot virtual methods are grouped to different virtual method group. see [issue-32](https://github.com/focus-creative-games/obfuz/issues/32) 2026-07-19 13:02:21 +08:00
walon 977779c8b7 fix(SymbolObfus): still rename parameter names of .ctor and ..ctor even they aren't renamed 2026-07-03 10:02:55 +08:00
EP-Toushirou 7b06f0fed8 new: add support for 6000.3.x;
fix: fix deprecated warning of PlayerSettings.GetScriptingBackend(BuildTargetGroup) in Unity 6000
2026-02-27 12:36:49 +08:00
walon 3615bbcce9 fix: fix resolving type in Obfuz.Runtime failed when no to-obfuscated dll references to Obfuz.Runtime 2025-12-26 21:25:08 +08:00
walon 1ff3b5c324 new: 新增PS5平台支持 2025-11-24 18:40:22 +08:00
walon 5932a6f9a6 升级版本为v3.1.0 2025-10-29 20:54:00 +08:00
walon 6c543d233a add copyright header to all cs files. 2025-10-29 20:40:37 +08:00
walon 81e0b412a3 修正README-EN.md文件名拼写错误 2025-10-25 22:43:52 +08:00
walon 4bdf21349c format: 修正VirtualMachineCodeGenerator生成的代码的格式化问题 2025-10-16 22:39:04 +08:00
walon c9ea564544 fix: 修复SplitBasicBlockGroup计算带filter的异常handler时,先计算整个异常块再计算filter和handler块的顺序bug,正确方式为先计算filter和handler,再计算整体 2025-10-16 22:28:05 +08:00
walon b582c1f24b 发布正式版本到v3.0.0 2025-10-09 19:42:07 +08:00
walon b40a063582 fix: 修复ScriptObject中事件函数名默认未被禁用混淆的bug 2025-10-08 22:25:01 +08:00
walon 747ee88fd3 fix: 修复 EvalStackCalculator::ReduceBaseType计算boxed值类型和class类型的base type失败的bug 2025-09-14 09:15:58 +08:00
walon 403764e7af fix: 修复符号混淆规则文件中modifier条件对property和event没有生效的bug。由于property和event本身并不存在Access Attributes,实际上是由它们所包含的method的Access属性`或`计算而来。 2025-09-10 18:20:29 +08:00
walon e12a0e26dc new: 新增CompatibilitySettings,允许指定生成与mono或il2cpp兼容的混淆代码 2025-09-10 11:15:05 +08:00
walon daff29ea94 fix: 修复当原始dll中包含resource文件(如mscorlib)时,ObfuscateUtil.GeneratePolymorphicDll执行出现异常的bug 2025-09-07 18:32:02 +08:00
walon eeff4a75ca fix: 修复 EvalStackCalculator计算 eval data的reduce type时未import来自其他程序集的共享基类的bug 2025-09-06 17:50:09 +08:00
walon b0699ecf5c 修复EvalStackCalculator计算input eval stack data类型时没有对多个inbound basic block的input计算共享类型的bug 2025-09-06 12:26:02 +08:00
walon 5557b27724 typo: AssetUtility -> AssertUtility 2025-08-29 21:55:24 +08:00
walon 59b1166ff3 fix: 修复 ReflectionCompatibilityDetector处理Unity 6000新增的Enum.TryParse(Type,bool, out object)函数时抛出异常的bug
refactor: 将 ReflectionCompatibilityDetector移到独立的ReflectionCompatibilityDetectionPass
2025-08-27 20:15:20 +08:00
walon 4ad3ed76dc fix: 修复 ConstFieldAllocator和 RvaDataAllocator的encryption level固定取4导致EncryptionVirtualMachine的Opcode个数超过256时打印了大量"OpCode overflow"警告日志的问题 2025-08-26 20:58:09 +08:00
walon 2576236960 暂时对泛型禁用控制流混淆 2025-08-12 14:19:32 +08:00
walon c3c53b2797 修复 EvalDataTypeWithSig计算ldarga等取引用的指令的栈数据类型未包含具体类型的bug 2025-08-12 14:19:11 +08:00
walon 0889f730fd - 修复EvalStackCalculator计算Ref类型栈变量全部归结来IntPtr类型,导致il2cpp生成代码出错的bug
- 修复MethodControlFlowCalculator将box后的值类型变量类型定义为值类型的bug,正确应该是object
2025-08-12 12:46:34 +08:00
walon 87cd3caf44 change: 禁用EvalStackObfus pass,因为它的性价比太低了。如果将来无法优化,则会被移除 2025-08-07 21:32:00 +08:00
walon 8dd6352028 fix: 修复类型上包含[ObufzIgnore(ObfuzScope.TypeName)]导致类型内所有函数体不混淆的bug 2025-08-07 18:55:17 +08:00
walon 739fcb24c5 WatermarkPass不对DOTS函数注入水印指令 2025-08-06 18:27:15 +08:00
walon 246a49f8ba fix: 修复WatermarkPass某些情况下导致栈不平衡的bug 2025-08-06 15:21:23 +08:00
walon 1ec6e2f426 将ObfuscationTypeMapper::RegisterType函数由internal改为public 2025-08-06 10:57:01 +08:00
walon b68571de7e fix: 修复在Unity 2019上的编译错误 2025-08-05 14:20:46 +08:00
walon 50fe1e1179 更新英文README 2025-08-04 11:32:10 +08:00
walon d52a9e7016 Code Clean Up 2025-08-03 12:37:44 +08:00
walon f5c2fe94ea WatermarkPass不打印注入日志 2025-08-02 23:22:26 +08:00
walon 54bcae5178 代码水印注入特征IL指令 2025-08-02 23:15:17 +08:00
walon cfb544426b 更新README中关于代码水印的说明 2025-08-02 21:53:37 +08:00
walon 1e027e6299 feature: 支持代码水印 2025-08-02 21:52:35 +08:00
walon 4db68f707b MethodControlFlowCalculator对InputArgs为0的BasicBlock随机化打乱顺序 2025-08-01 11:32:33 +08:00
walon c596b58d3e 优化 MethodControlFlowCalculator生成的指令有可能违反IL控制流规则的问题 2025-08-01 10:57:53 +08:00
walon ddb144eac8 feature: 新增 RemoveConstField pass 2025-08-01 09:19:24 +08:00
walon 1a240c47ac 修复ModifierType::Public枚举项值的错误 2025-07-31 20:06:04 +08:00
walon 2e48164ae9 修复EvalStackCalculator计算isinst和castclass指令的返回值的类型未转换为token所引用的类型的bug 2025-07-31 12:14:18 +08:00
walon 9b6e6375f6 更新README 2025-07-29 10:14:58 +08:00
walon 38ad0de746 禁用obfuz时LinkXmlProcess::GenerateAdditionalLinkXmlFile返回null 2025-07-28 10:46:17 +08:00
walon 6ec1a74d57 README中添加多态DLL说明 2025-07-26 13:40:16 +08:00
walon d6d9cde741 升级版本到v3.0.0-beta 2025-07-26 10:32:53 +08:00
walon 87f086e310 支持多态dll文件结构 2025-07-25 20:47:38 +08:00
walon 69b91575db 发布正式版本v2.0.0 2025-07-24 11:10:23 +08:00
walon 0985b3d06e 修复$$Obfuz$RVA$的所有rva字段累计长度超出16k引发的在hybridclr下运行出错的问题。此问题是hybridclr的bug,因为ldslfd之类指令要求offset小于16k。 2025-07-23 20:56:38 +08:00
walon d4133f1e8a 移除不必要的对NUnit.Framework的引用 2025-07-23 19:34:42 +08:00
walon 3bcf204f69 ExprObfus的BasicObfuscator支持混淆参数类型为IntPtr的表达式 2025-07-21 11:37:29 +08:00
walon 905351789e fix: 修复静态与成员函数在包含this参数后如果参数完全相同则计算出MethodDefSignature相同导致RenameRecordMap加载symbol-mapping文件时signature冲突的bug 2025-07-21 09:35:40 +08:00
walon 3bcb093467 由于EvalStackObfus会显著增加混淆后的程序集大小(当obfuscationPercentage=1.0时大约增加了5倍),将默认obfuscationPercentage改为0.05,并且在global obfuscationPercentage超过0.1时打印警告 2025-07-14 18:12:54 +08:00
walon 49194ca1af 升级版本到v2.0.0-rc.1 2025-07-14 11:49:07 +08:00
walon 6a4f84a9b0 不混淆被BurstCompile函数直接或者间接调用的函数的代码,但仍然混淆函数名。 2025-07-14 11:45:15 +08:00
walon 083ddd3035 对于标记`[BurstCompile]`的类型,除了类型名和函数名以外的仍然混淆 2025-07-11 19:08:25 +08:00
walon 2887231df7 禁止混淆带`[BurstCompile]`的函数 2025-07-11 18:03:25 +08:00
walon c3238c54a9 更新README 2025-07-03 21:23:34 +08:00
walon f908b648c1 修复LinkXmlProcess::GenerateAdditionalLinkXmlFile返回的link.xml为相对路径,没有生效的bug 2025-07-03 12:41:06 +08:00
walon 29debc44bf 升级版本到v2.0.0-beta.1 2025-07-03 12:10:05 +08:00
walon 9cbb105405 LinkXmlProcess中保留整个Obfuz.Runtime 2025-07-03 12:09:56 +08:00
walon e3d9d7a08e 重构GroupByModuleEntityManager代码 2025-07-02 18:57:53 +08:00
walon 4b0c5d7521 CallObufs新增Delegate Proxy支持 2025-07-01 18:46:09 +08:00
walon 9b9eb6d12d 重构CallObfusPass代码 2025-06-30 20:02:49 +08:00
walon 52d9ee1349 修复dnlib插件在非Editor模式下也能被引用的问题 2025-06-30 18:25:53 +08:00
walon bf3f6e4534 ObfuscatorBuilder::FromObfuzSettings新增searchPathIncludeUnityEditorDll参数,允许将UnityEditor相关dll也加入到搜索路径 2025-06-28 20:51:54 +08:00
walon 655c2fe07f `ObfuzSettings.enable`字段移到`BuildPipelineSettings`中 2025-06-28 20:38:27 +08:00
walon 02ed0608e4 添加BuildPipelineSettings,支持自定义 LinkXmlProcess和 ObfuscationProcess的 callbackOrder。 2025-06-28 20:20:08 +08:00
walon 59db0dfaab 更新说明 2025-06-28 20:08:00 +08:00
walon 2b8e51b12d 调整一些类型名 2025-06-28 19:01:57 +08:00
walon df181ed5c1 更新版本号为v2.0.0-alpha 2025-06-28 13:51:45 +08:00
211 changed files with 7485 additions and 1869 deletions

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Utils; using Obfuz.Utils;
using System; using System;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Utils; using Obfuz.Utils;
using System; using System;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.ObfusPasses; using Obfuz.ObfusPasses;
using Obfuz.Utils; using Obfuz.Utils;

View File

@ -1,3 +1,23 @@
// Copyright 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.
namespace Obfuz.Editor namespace Obfuz.Editor
{ {
public static class ConstValues public static class ConstValues
@ -11,6 +31,7 @@
public const string ObfuzScopeFullName = "Obfuz.ObfuzScope"; public const string ObfuzScopeFullName = "Obfuz.ObfuzScope";
public const string EncryptFieldAttributeFullName = "Obfuz.EncryptFieldAttribute"; public const string EncryptFieldAttributeFullName = "Obfuz.EncryptFieldAttribute";
public const string GeneratedEncryptionVirtualMachineFullName = "Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine";
public const string EmbeddedAttributeFullName = "Microsoft.CodeAnalysis.EmbeddedAttribute"; public const string EmbeddedAttributeFullName = "Microsoft.CodeAnalysis.EmbeddedAttribute";
@ -19,5 +40,13 @@
public const string ZluaLuaInvokeAttributeFullName = "Zlua.LuaInvokeAttribute"; public const string ZluaLuaInvokeAttributeFullName = "Zlua.LuaInvokeAttribute";
public const string ZluaLuaCallbackAttributeFullName = "Zlua.LuaCallbackAttribute"; public const string ZluaLuaCallbackAttributeFullName = "Zlua.LuaCallbackAttribute";
public const string ZluaLuaMarshalAsAttributeFullName = "Zlua.LuaMarshalAsAttribute"; 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";
} }
} }

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Editor; using Obfuz.Editor;
@ -10,13 +30,8 @@ using UnityEngine.Assertions;
namespace Obfuz.Data namespace Obfuz.Data
{ {
public class ModuleConstFieldAllocator : IGroupByModuleEntity public class ConstFieldAllocator : GroupByModuleEntityBase
{ {
private ModuleDef _module;
private readonly EncryptionScopeProvider _encryptionScopeProvider;
private readonly RvaDataAllocator _rvaDataAllocator;
private readonly GroupByModuleEntityManager _moduleEntityManager;
private EncryptionScopeInfo _encryptionScope;
private RandomCreator _randomCreator; private RandomCreator _randomCreator;
private IEncryptor _encryptor; private IEncryptor _encryptor;
@ -57,19 +72,14 @@ namespace Obfuz.Data
private bool _done; private bool _done;
public ModuleConstFieldAllocator(EncryptionScopeProvider encryptionScopeProvider, RvaDataAllocator rvaDataAllocator, GroupByModuleEntityManager moduleEntityManager) public ConstFieldAllocator()
{ {
_encryptionScopeProvider = encryptionScopeProvider;
_rvaDataAllocator = rvaDataAllocator;
_moduleEntityManager = moduleEntityManager;
} }
public void Init(ModuleDef mod) public override void Init()
{ {
_module = mod; _randomCreator = EncryptionScope.localRandomCreator;
_encryptionScope = _encryptionScopeProvider.GetScope(mod); _encryptor = EncryptionScope.encryptor;
_randomCreator = _encryptionScope.localRandomCreator;
_encryptor = _encryptionScope.encryptor;
} }
const int maxFieldCount = 1000; const int maxFieldCount = 1000;
@ -77,30 +87,32 @@ namespace Obfuz.Data
private TypeSig GetTypeSigOfValue(object value) private TypeSig GetTypeSigOfValue(object value)
{ {
ModuleDef mod = Module;
if (value is int) if (value is int)
return _module.CorLibTypes.Int32; return mod.CorLibTypes.Int32;
if (value is long) if (value is long)
return _module.CorLibTypes.Int64; return mod.CorLibTypes.Int64;
if (value is float) if (value is float)
return _module.CorLibTypes.Single; return mod.CorLibTypes.Single;
if (value is double) if (value is double)
return _module.CorLibTypes.Double; return mod.CorLibTypes.Double;
if (value is string) if (value is string)
return _module.CorLibTypes.String; return mod.CorLibTypes.String;
if (value is byte[]) if (value is byte[])
return new SZArraySig(_module.CorLibTypes.Byte); return new SZArraySig(mod.CorLibTypes.Byte);
throw new NotSupportedException($"Unsupported type: {value.GetType()}"); throw new NotSupportedException($"Unsupported type: {value.GetType()}");
} }
private ConstFieldInfo CreateConstFieldInfo(object value) private ConstFieldInfo CreateConstFieldInfo(object value)
{ {
ModuleDef mod = Module;
if (_holderTypeDef == null || _holderTypeDef.Fields.Count >= maxFieldCount) if (_holderTypeDef == null || _holderTypeDef.Fields.Count >= maxFieldCount)
{ {
using (var scope = new DisableTypeDefFindCacheScope(_module)) using (var scope = new DisableTypeDefFindCacheScope(mod))
{ {
ITypeDefOrRef objectTypeRef = _module.Import(typeof(object)); ITypeDefOrRef objectTypeRef = mod.Import(typeof(object));
_holderTypeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ConstFieldHolder${_holderTypeDefs.Count}", objectTypeRef); _holderTypeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ConstFieldHolder${_holderTypeDefs.Count}", objectTypeRef);
_module.Types.Add(_holderTypeDef); mod.Types.Add(_holderTypeDef);
_holderTypeDefs.Add(_holderTypeDef); _holderTypeDefs.Add(_holderTypeDef);
} }
} }
@ -159,41 +171,35 @@ namespace Obfuz.Data
return AllocateAny(value); return AllocateAny(value);
} }
private DefaultMetadataImporter GetModuleMetadataImporter()
{
return _moduleEntityManager.GetDefaultModuleMetadataImporter(_module, _encryptionScopeProvider);
}
private void CreateCCtorOfRvaTypeDef(TypeDef type) private void CreateCCtorOfRvaTypeDef(TypeDef type)
{ {
ModuleDef mod = Module;
var cctor = new MethodDefUser(".cctor", var cctor = new MethodDefUser(".cctor",
MethodSig.CreateStatic(_module.CorLibTypes.Void), MethodSig.CreateStatic(mod.CorLibTypes.Void),
MethodImplAttributes.IL | MethodImplAttributes.Managed, MethodImplAttributes.IL | MethodImplAttributes.Managed,
MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private); MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private);
cctor.DeclaringType = type; cctor.DeclaringType = type;
//_rvaTypeDef.Methods.Add(cctor);
var body = new CilBody(); var body = new CilBody();
cctor.Body = body; cctor.Body = body;
var ins = body.Instructions; var ins = body.Instructions;
//IMethod method = _module.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new[] { typeof(Array), typeof(RuntimeFieldHandle) }));
//Assert.IsNotNull(method);
DefaultMetadataImporter importer = this.GetDefaultModuleMetadataImporter();
DefaultMetadataImporter importer = GetModuleMetadataImporter(); RvaDataAllocator rvaDataAllocator = GetEntity<RvaDataAllocator>();
// TODO. obfuscate init codes // TODO. obfuscate init codes
foreach (var field in type.Fields) foreach (var field in type.Fields)
{ {
ConstFieldInfo constInfo = _field2Fields[field]; ConstFieldInfo constInfo = _field2Fields[field];
IRandom localRandom = _randomCreator(HashUtil.ComputePrimitiveOrStringOrBytesHashCode(constInfo.value)); IRandom localRandom = _randomCreator(HashUtil.ComputePrimitiveOrStringOrBytesHashCode(constInfo.value));
int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, _encryptor, 4); int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, _encryptor, EncryptionScopeInfo.MaxEncryptionLevel, false);
int salt = localRandom.NextInt(); int salt = localRandom.NextInt();
switch (constInfo.value) switch (constInfo.value)
{ {
case int i: case int i:
{ {
int encryptedValue = _encryptor.Encrypt(i, ops, salt); int encryptedValue = _encryptor.Encrypt(i, ops, salt);
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
ins.Add(Instruction.CreateLdcI4(rvaData.offset)); ins.Add(Instruction.CreateLdcI4(rvaData.offset));
ins.Add(Instruction.CreateLdcI4(ops)); ins.Add(Instruction.CreateLdcI4(ops));
@ -204,7 +210,7 @@ namespace Obfuz.Data
case long l: case long l:
{ {
long encryptedValue = _encryptor.Encrypt(l, ops, salt); long encryptedValue = _encryptor.Encrypt(l, ops, salt);
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
ins.Add(Instruction.CreateLdcI4(rvaData.offset)); ins.Add(Instruction.CreateLdcI4(rvaData.offset));
ins.Add(Instruction.CreateLdcI4(ops)); ins.Add(Instruction.CreateLdcI4(ops));
@ -215,7 +221,7 @@ namespace Obfuz.Data
case float f: case float f:
{ {
float encryptedValue = _encryptor.Encrypt(f, ops, salt); float encryptedValue = _encryptor.Encrypt(f, ops, salt);
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
ins.Add(Instruction.CreateLdcI4(rvaData.offset)); ins.Add(Instruction.CreateLdcI4(rvaData.offset));
ins.Add(Instruction.CreateLdcI4(ops)); ins.Add(Instruction.CreateLdcI4(ops));
@ -226,7 +232,7 @@ namespace Obfuz.Data
case double d: case double d:
{ {
double encryptedValue = _encryptor.Encrypt(d, ops, salt); double encryptedValue = _encryptor.Encrypt(d, ops, salt);
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
ins.Add(Instruction.CreateLdcI4(rvaData.offset)); ins.Add(Instruction.CreateLdcI4(rvaData.offset));
ins.Add(Instruction.CreateLdcI4(ops)); ins.Add(Instruction.CreateLdcI4(ops));
@ -237,7 +243,7 @@ namespace Obfuz.Data
case string s: case string s:
{ {
byte[] encryptedValue = _encryptor.Encrypt(s, ops, salt); byte[] encryptedValue = _encryptor.Encrypt(s, ops, salt);
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
ins.Add(Instruction.CreateLdcI4(rvaData.offset)); ins.Add(Instruction.CreateLdcI4(rvaData.offset));
Assert.AreEqual(encryptedValue.Length, rvaData.size); Assert.AreEqual(encryptedValue.Length, rvaData.size);
@ -251,7 +257,7 @@ namespace Obfuz.Data
{ {
byte[] encryptedValue = _encryptor.Encrypt(bs, 0, bs.Length, ops, salt); byte[] encryptedValue = _encryptor.Encrypt(bs, 0, bs.Length, ops, salt);
Assert.AreEqual(encryptedValue.Length, bs.Length); Assert.AreEqual(encryptedValue.Length, bs.Length);
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
ins.Add(Instruction.CreateLdcI4(rvaData.offset)); ins.Add(Instruction.CreateLdcI4(rvaData.offset));
ins.Add(Instruction.CreateLdcI4(bs.Length)); ins.Add(Instruction.CreateLdcI4(bs.Length));
@ -267,7 +273,7 @@ namespace Obfuz.Data
ins.Add(Instruction.Create(OpCodes.Ret)); ins.Add(Instruction.Create(OpCodes.Ret));
} }
public void Done() public override void Done()
{ {
if (_done) if (_done)
{ {
@ -280,61 +286,4 @@ namespace Obfuz.Data
} }
} }
} }
public class ConstFieldAllocator
{
private readonly EncryptionScopeProvider _encryptionScopeProvider;
private readonly RvaDataAllocator _rvaDataAllocator;
private readonly GroupByModuleEntityManager _moduleEntityManager;
public ConstFieldAllocator(EncryptionScopeProvider encryptionScopeProvider, RvaDataAllocator rvaDataAllocator, GroupByModuleEntityManager moduleEntityManager)
{
_encryptionScopeProvider = encryptionScopeProvider;
_rvaDataAllocator = rvaDataAllocator;
_moduleEntityManager = moduleEntityManager;
}
public ModuleConstFieldAllocator GetModuleAllocator(ModuleDef mod)
{
return _moduleEntityManager.GetEntity<ModuleConstFieldAllocator>(mod, () => new ModuleConstFieldAllocator(_encryptionScopeProvider, _rvaDataAllocator, _moduleEntityManager));
}
public FieldDef Allocate(ModuleDef mod, int value)
{
return GetModuleAllocator(mod).Allocate(value);
}
public FieldDef Allocate(ModuleDef mod, long value)
{
return GetModuleAllocator(mod).Allocate(value);
}
public FieldDef Allocate(ModuleDef mod, float value)
{
return GetModuleAllocator(mod).Allocate(value);
}
public FieldDef Allocate(ModuleDef mod, double value)
{
return GetModuleAllocator(mod).Allocate(value);
}
public FieldDef Allocate(ModuleDef mod, byte[] value)
{
return GetModuleAllocator(mod).Allocate(value);
}
public FieldDef Allocate(ModuleDef mod, string value)
{
return GetModuleAllocator(mod).Allocate(value);
}
public void Done()
{
foreach (var moduleAllocator in _moduleEntityManager.GetEntities<ModuleConstFieldAllocator>())
{
moduleAllocator.Done();
}
}
}
} }

View File

@ -1,9 +1,30 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Emit; using Obfuz.Emit;
using Obfuz.Utils; using Obfuz.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using UnityEngine.Assertions; using UnityEngine.Assertions;
@ -23,16 +44,13 @@ namespace Obfuz.Data
} }
} }
public class ModuleRvaDataAllocator : GroupByModuleEntityBase public class RvaDataAllocator : GroupByModuleEntityBase
{ {
// randomized const int maxRvaDataSize = 2 * 1024;
const int maxRvaDataSize = 0x1000;
private ModuleDef _module; // 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
private readonly EncryptionScopeProvider _encryptionScopeProvider; const int maxTotalRvaDataFieldSizeInHybridCLR = 16 * 1024;
private readonly GroupByModuleEntityManager _moduleEntityManager;
private EncryptionScopeInfo _encryptionScope;
private IRandom _random; private IRandom _random;
class RvaField class RvaField
@ -62,64 +80,72 @@ namespace Obfuz.Data
} }
} }
private readonly List<RvaField> _rvaFields = new List<RvaField>(); private class RvaTypeDefInfo
{
public readonly TypeDef typeDef;
public readonly int index;
public readonly List<RvaField> rvaFields = new List<RvaField>();
public RvaTypeDefInfo(TypeDef typeDef, int index)
{
this.typeDef = typeDef;
this.index = index;
}
}
private RvaField _currentField; private RvaField _currentField;
private RvaTypeDefInfo _currentRvaType;
private TypeDef _rvaTypeDef; private readonly List<RvaTypeDefInfo> _rvaTypeDefs = new List<RvaTypeDefInfo>();
private readonly Dictionary<int, TypeDef> _dataHolderTypeBySizes = new Dictionary<int, TypeDef>(); private readonly Dictionary<int, TypeDef> _dataHolderTypeBySizes = new Dictionary<int, TypeDef>();
private bool _done; private bool _done;
public ModuleRvaDataAllocator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager) public RvaDataAllocator()
{ {
_encryptionScopeProvider = encryptionScopeProvider;
_moduleEntityManager = moduleEntityManager;
} }
public override void Init(ModuleDef mod) public override void Init()
{ {
_module = mod; _random = EncryptionScope.localRandomCreator(HashUtil.ComputeHash(Module.Name));
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
_random = _encryptionScope.localRandomCreator(HashUtil.ComputeHash(mod.Name));
} }
private (FieldDef, FieldDef) CreateDataHolderRvaField(TypeDef dataHolderType) private (FieldDef, FieldDef) CreateDataHolderRvaField(TypeDef dataHolderType)
{ {
if (_rvaTypeDef == null) if (_currentRvaType == null || _currentRvaType.rvaFields.Count >= maxTotalRvaDataFieldSizeInHybridCLR / maxRvaDataSize - 1)
{ {
using (var scope = new DisableTypeDefFindCacheScope(_module)) using (var scope = new DisableTypeDefFindCacheScope(Module))
{ {
ITypeDefOrRef objectTypeRef = _module.Import(typeof(object)); var rvaTypeDef = new TypeDefUser($"$Obfuz$RVA${_rvaTypeDefs.Count}", Module.CorLibTypes.Object.ToTypeDefOrRef());
_rvaTypeDef = new TypeDefUser("$Obfuz$RVA$", objectTypeRef); Module.Types.Add(rvaTypeDef);
_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 holderField = new FieldDefUser($"$RVA_Data{_rvaFields.Count}", new FieldSig(dataHolderType.ToTypeSig()), FieldAttributes.InitOnly | FieldAttributes.Static | FieldAttributes.HasFieldRVA); var runtimeValueField = new FieldDefUser($"$RVA_Value{_currentRvaType.rvaFields.Count}", new FieldSig(new SZArraySig(Module.CorLibTypes.Byte)), FieldAttributes.Static | FieldAttributes.Public);
holderField.DeclaringType = _rvaTypeDef; runtimeValueField.DeclaringType = _currentRvaType.typeDef;
var runtimeValueField = new FieldDefUser($"$RVA_Value{_rvaFields.Count}", new FieldSig(new SZArraySig(_module.CorLibTypes.Byte)), FieldAttributes.Static | FieldAttributes.Public);
runtimeValueField.DeclaringType = _rvaTypeDef;
return (holderField, runtimeValueField); return (holderField, runtimeValueField);
} }
private TypeDef GetDataHolderType(int size) private TypeDef GetDataHolderType(int size)
{ {
size = (size + 15) & ~15; // align to 6 bytes size = (size + 15) & ~15; // align to 16 bytes
if (_dataHolderTypeBySizes.TryGetValue(size, out var type)) if (_dataHolderTypeBySizes.TryGetValue(size, out var type))
return type; return type;
using (var scope = new DisableTypeDefFindCacheScope(_module)) using (var scope = new DisableTypeDefFindCacheScope(Module))
{ {
var dataHolderType = new TypeDefUser($"$ObfuzRVA$DataHolder{size}", _module.Import(typeof(ValueType))); var dataHolderType = new TypeDefUser($"$ObfuzRVA$DataHolder{size}", Module.Import(typeof(ValueType)));
dataHolderType.Attributes = TypeAttributes.Public | TypeAttributes.Sealed; dataHolderType.Attributes = TypeAttributes.Public | TypeAttributes.Sealed;
dataHolderType.Layout = TypeAttributes.ExplicitLayout; dataHolderType.Layout = TypeAttributes.ExplicitLayout;
dataHolderType.PackingSize = 1; dataHolderType.PackingSize = 1;
dataHolderType.ClassSize = (uint)size; dataHolderType.ClassSize = (uint)size;
_dataHolderTypeBySizes.Add(size, dataHolderType); _dataHolderTypeBySizes.Add(size, dataHolderType);
_module.Types.Add(dataHolderType); Module.Types.Add(dataHolderType);
return dataHolderType; return dataHolderType;
} }
} }
@ -142,7 +168,7 @@ namespace Obfuz.Data
encryptionOps = _random.NextInt(), encryptionOps = _random.NextInt(),
salt = _random.NextInt(), salt = _random.NextInt(),
}; };
_rvaFields.Add(newRvaField); _currentRvaType.rvaFields.Add(newRvaField);
return newRvaField; return newRvaField;
} }
@ -230,10 +256,11 @@ namespace Obfuz.Data
private void AddVerifyCodes(IList<Instruction> insts, DefaultMetadataImporter importer) private void AddVerifyCodes(IList<Instruction> insts, DefaultMetadataImporter importer)
{ {
int verifyIntValue = 0x12345678; int verifyIntValue = 0x12345678;
IRandom verifyRandom = _encryptionScope.localRandomCreator(verifyIntValue); EncryptionScopeInfo encryptionScope = this.EncryptionScope;
int verifyOps = EncryptionUtil.GenerateEncryptionOpCodes(verifyRandom, _encryptionScope.encryptor, 4); IRandom verifyRandom = encryptionScope.localRandomCreator(verifyIntValue);
int verifyOps = EncryptionUtil.GenerateEncryptionOpCodes(verifyRandom, encryptionScope.encryptor, EncryptionScopeInfo.MaxEncryptionLevel, false);
int verifySalt = verifyRandom.NextInt(); int verifySalt = verifyRandom.NextInt();
int encryptedVerifyIntValue = _encryptionScope.encryptor.Encrypt(verifyIntValue, verifyOps, verifySalt); int encryptedVerifyIntValue = encryptionScope.encryptor.Encrypt(verifyIntValue, verifyOps, verifySalt);
insts.Add(Instruction.Create(OpCodes.Ldc_I4, verifyIntValue)); insts.Add(Instruction.Create(OpCodes.Ldc_I4, verifyIntValue));
insts.Add(Instruction.CreateLdcI4(encryptedVerifyIntValue)); insts.Add(Instruction.CreateLdcI4(encryptedVerifyIntValue));
@ -246,24 +273,22 @@ namespace Obfuz.Data
private void CreateCCtorOfRvaTypeDef() private void CreateCCtorOfRvaTypeDef()
{ {
if (_rvaTypeDef == null) foreach (RvaTypeDefInfo rvaTypeDef in _rvaTypeDefs)
{ {
return; ModuleDef mod = rvaTypeDef.typeDef.Module;
}
ModuleDef mod = _rvaTypeDef.Module;
var cctorMethod = new MethodDefUser(".cctor", var cctorMethod = new MethodDefUser(".cctor",
MethodSig.CreateStatic(_module.CorLibTypes.Void), MethodSig.CreateStatic(Module.CorLibTypes.Void),
MethodImplAttributes.IL | MethodImplAttributes.Managed, MethodImplAttributes.IL | MethodImplAttributes.Managed,
MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private); MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private);
cctorMethod.DeclaringType = _rvaTypeDef; cctorMethod.DeclaringType = rvaTypeDef.typeDef;
//_rvaTypeDef.Methods.Add(cctor); //_rvaTypeDef.Methods.Add(cctor);
var body = new CilBody(); var body = new CilBody();
cctorMethod.Body = body; cctorMethod.Body = body;
var ins = body.Instructions; var ins = body.Instructions;
DefaultMetadataImporter importer = _moduleEntityManager.GetDefaultModuleMetadataImporter(mod, _encryptionScopeProvider); DefaultMetadataImporter importer = this.GetDefaultModuleMetadataImporter();
AddVerifyCodes(ins, importer); AddVerifyCodes(ins, importer);
foreach (var field in _rvaFields) foreach (var field in rvaTypeDef.rvaFields)
{ {
// ldc // ldc
// newarr // newarr
@ -287,10 +312,11 @@ namespace Obfuz.Data
} }
ins.Add(Instruction.Create(OpCodes.Ret)); ins.Add(Instruction.Create(OpCodes.Ret));
} }
}
private void SetFieldsRVA() private void SetFieldsRVA()
{ {
foreach (var field in _rvaFields) foreach (var field in _rvaTypeDefs.SelectMany(t => t.rvaFields))
{ {
Assert.IsTrue(field.bytes.Count <= field.size); Assert.IsTrue(field.bytes.Count <= field.size);
if (field.bytes.Count < field.size) if (field.bytes.Count < field.size)
@ -298,12 +324,12 @@ namespace Obfuz.Data
field.FillPaddingToEnd(); field.FillPaddingToEnd();
} }
byte[] data = field.bytes.ToArray(); byte[] data = field.bytes.ToArray();
_encryptionScope.encryptor.EncryptBlock(data, field.encryptionOps, field.salt); EncryptionScope.encryptor.EncryptBlock(data, field.encryptionOps, field.salt);
field.holderDataField.InitialValue = data; field.holderDataField.InitialValue = data;
} }
} }
public void Done() public override void Done()
{ {
if (_done) if (_done)
{ {
@ -314,59 +340,4 @@ namespace Obfuz.Data
CreateCCtorOfRvaTypeDef(); CreateCCtorOfRvaTypeDef();
} }
} }
public class RvaDataAllocator
{
private readonly EncryptionScopeProvider _encryptionScopeProvider;
private readonly GroupByModuleEntityManager _moduleEntityManager;
public RvaDataAllocator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager)
{
_encryptionScopeProvider = encryptionScopeProvider;
_moduleEntityManager = moduleEntityManager;
}
private ModuleRvaDataAllocator GetModuleRvaDataAllocator(ModuleDef mod)
{
return _moduleEntityManager.GetEntity<ModuleRvaDataAllocator>(mod, () => new ModuleRvaDataAllocator(_encryptionScopeProvider, _moduleEntityManager));
}
public RvaData Allocate(ModuleDef mod, int value)
{
return GetModuleRvaDataAllocator(mod).Allocate(value);
}
public RvaData Allocate(ModuleDef mod, long value)
{
return GetModuleRvaDataAllocator(mod).Allocate(value);
}
public RvaData Allocate(ModuleDef mod, float value)
{
return GetModuleRvaDataAllocator(mod).Allocate(value);
}
public RvaData Allocate(ModuleDef mod, double value)
{
return GetModuleRvaDataAllocator(mod).Allocate(value);
}
public RvaData Allocate(ModuleDef mod, string value)
{
return GetModuleRvaDataAllocator(mod).Allocate(value);
}
public RvaData Allocate(ModuleDef mod, byte[] value)
{
return GetModuleRvaDataAllocator(mod).Allocate(value);
}
public void Done()
{
foreach (var allocator in _moduleEntityManager.GetEntities<ModuleRvaDataAllocator>())
{
allocator.Done();
}
}
}
} }

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using System; using System;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using System; using System;
using System.Reflection; using System.Reflection;
@ -104,30 +124,27 @@ namespace Obfuz.Emit
Assert.IsNotNull(_decryptFromRvaBytes); Assert.IsNotNull(_decryptFromRvaBytes);
_decryptFromRvaString = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaString", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) })); _decryptFromRvaString = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaString", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptFromRvaString); Assert.IsNotNull(_decryptFromRvaString);
_decryptInitializeArray = mod.Import(encryptionServiceType.GetMethod("DecryptInitializeArray", new[] { typeof(System.Array), typeof(System.RuntimeFieldHandle), typeof(int), typeof(int), typeof(int) })); _decryptInitializeArray = mod.Import(encryptionServiceType.GetMethod("DecryptInitializeArray", new[] { typeof(System.Array), typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptInitializeArray); Assert.IsNotNull(_decryptInitializeArray);
} }
} }
public class DefaultMetadataImporter : GroupByModuleEntityBase public class DefaultMetadataImporter : GroupByModuleEntityBase
{ {
private readonly EncryptionScopeProvider _encryptionScopeProvider;
private EncryptionScopeInfo _encryptionScope;
private EncryptionServiceMetadataImporter _defaultEncryptionServiceMetadataImporter; private EncryptionServiceMetadataImporter _defaultEncryptionServiceMetadataImporter;
private EncryptionServiceMetadataImporter _staticDefaultEncryptionServiceMetadataImporter; private EncryptionServiceMetadataImporter _staticDefaultEncryptionServiceMetadataImporter;
private EncryptionServiceMetadataImporter _dynamicDefaultEncryptionServiceMetadataImporter; private EncryptionServiceMetadataImporter _dynamicDefaultEncryptionServiceMetadataImporter;
public DefaultMetadataImporter(EncryptionScopeProvider encryptionScopeProvider) public DefaultMetadataImporter()
{ {
_encryptionScopeProvider = encryptionScopeProvider;
} }
public override void Init(ModuleDef mod) public override void Init()
{ {
_module = mod; ModuleDef mod = Module;
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
var constUtilityType = typeof(ConstUtility); var constUtilityType = typeof(ConstUtility);
_castIntAsFloat = mod.Import(constUtilityType.GetMethod("CastIntAsFloat")); _castIntAsFloat = mod.Import(constUtilityType.GetMethod("CastIntAsFloat"));
@ -141,7 +158,7 @@ namespace Obfuz.Emit
_initializeArray = mod.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new[] { typeof(Array), typeof(RuntimeFieldHandle) })); _initializeArray = mod.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new[] { typeof(Array), typeof(RuntimeFieldHandle) }));
Assert.IsNotNull(_initializeArray); Assert.IsNotNull(_initializeArray);
_verifySecretKey = mod.Import(typeof(AssetUtility).GetMethod("VerifySecretKey", new[] { typeof(int), typeof(int) })); _verifySecretKey = mod.Import(typeof(AssertUtility).GetMethod("VerifySecretKey", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_verifySecretKey, "VerifySecretKey not found"); Assert.IsNotNull(_verifySecretKey, "VerifySecretKey not found");
_obfuscationTypeMapperRegisterType = mod.Import(typeof(ObfuscationTypeMapper).GetMethod("RegisterType", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string) }, null)); _obfuscationTypeMapperRegisterType = mod.Import(typeof(ObfuscationTypeMapper).GetMethod("RegisterType", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string) }, null));
@ -156,6 +173,11 @@ namespace Obfuz.Emit
Assert.IsNotNull(_addFloat, "ExprUtility.Add(float, float) not found"); Assert.IsNotNull(_addFloat, "ExprUtility.Add(float, float) not found");
_addDouble = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(double), typeof(double) })); _addDouble = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_addDouble, "ExprUtility.Add(double, double) not found"); 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) })); _subtractInt = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_subtractInt, "ExprUtility.Subtract(int, int) not found"); Assert.IsNotNull(_subtractInt, "ExprUtility.Subtract(int, int) not found");
_subtractLong = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(long), typeof(long) })); _subtractLong = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(long), typeof(long) }));
@ -164,6 +186,11 @@ namespace Obfuz.Emit
Assert.IsNotNull(_subtractFloat, "ExprUtility.Subtract(float, float) not found"); Assert.IsNotNull(_subtractFloat, "ExprUtility.Subtract(float, float) not found");
_subtractDouble = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(double), typeof(double) })); _subtractDouble = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_subtractDouble, "ExprUtility.Subtract(double, double) not found"); 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) })); _multiplyInt = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_multiplyInt, "ExprUtility.Multiply(int, int) not found"); Assert.IsNotNull(_multiplyInt, "ExprUtility.Multiply(int, int) not found");
_multiplyLong = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(long), typeof(long) })); _multiplyLong = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(long), typeof(long) }));
@ -172,6 +199,11 @@ namespace Obfuz.Emit
Assert.IsNotNull(_multiplyFloat, "ExprUtility.Multiply(float, float) not found"); Assert.IsNotNull(_multiplyFloat, "ExprUtility.Multiply(float, float) not found");
_multiplyDouble = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(double), typeof(double) })); _multiplyDouble = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_multiplyDouble, "ExprUtility.Multiply(double, double) not found"); 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) })); _divideInt = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_divideInt, "ExprUtility.Divide(int, int) not found"); Assert.IsNotNull(_divideInt, "ExprUtility.Divide(int, int) not found");
_divideLong = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(long), typeof(long) })); _divideLong = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(long), typeof(long) }));
@ -238,7 +270,7 @@ namespace Obfuz.Emit
_staticDefaultEncryptionServiceMetadataImporter = new EncryptionServiceMetadataImporter(mod, typeof(EncryptionService<DefaultStaticEncryptionScope>)); _staticDefaultEncryptionServiceMetadataImporter = new EncryptionServiceMetadataImporter(mod, typeof(EncryptionService<DefaultStaticEncryptionScope>));
_dynamicDefaultEncryptionServiceMetadataImporter = new EncryptionServiceMetadataImporter(mod, typeof(EncryptionService<DefaultDynamicEncryptionScope>)); _dynamicDefaultEncryptionServiceMetadataImporter = new EncryptionServiceMetadataImporter(mod, typeof(EncryptionService<DefaultDynamicEncryptionScope>));
if (_encryptionScopeProvider.IsDynamicSecretAssembly(mod)) if (EncryptionScopeProvider.IsDynamicSecretAssembly(mod))
{ {
_defaultEncryptionServiceMetadataImporter = _dynamicDefaultEncryptionServiceMetadataImporter; _defaultEncryptionServiceMetadataImporter = _dynamicDefaultEncryptionServiceMetadataImporter;
} }
@ -248,9 +280,14 @@ namespace Obfuz.Emit
} }
} }
public override void Done()
{
}
public EncryptionServiceMetadataImporter GetEncryptionServiceMetadataImporterOfModule(ModuleDef mod) public EncryptionServiceMetadataImporter GetEncryptionServiceMetadataImporterOfModule(ModuleDef mod)
{ {
return _encryptionScopeProvider.IsDynamicSecretAssembly(mod) ? _dynamicDefaultEncryptionServiceMetadataImporter : _staticDefaultEncryptionServiceMetadataImporter; return EncryptionScopeProvider.IsDynamicSecretAssembly(mod) ? _dynamicDefaultEncryptionServiceMetadataImporter : _staticDefaultEncryptionServiceMetadataImporter;
} }
private ModuleDef _module; private ModuleDef _module;
@ -267,14 +304,20 @@ namespace Obfuz.Emit
private IMethod _addLong; private IMethod _addLong;
private IMethod _addFloat; private IMethod _addFloat;
private IMethod _addDouble; private IMethod _addDouble;
private IMethod _addIntPtr;
private IMethod _addIntPtrInt;
private IMethod _subtractInt; private IMethod _subtractInt;
private IMethod _subtractLong; private IMethod _subtractLong;
private IMethod _subtractFloat; private IMethod _subtractFloat;
private IMethod _subtractDouble; private IMethod _subtractDouble;
private IMethod _subtractIntPtr;
private IMethod _subtractIntPtrInt;
private IMethod _multiplyInt; private IMethod _multiplyInt;
private IMethod _multiplyLong; private IMethod _multiplyLong;
private IMethod _multiplyFloat; private IMethod _multiplyFloat;
private IMethod _multiplyDouble; private IMethod _multiplyDouble;
private IMethod _multiplyIntPtr;
private IMethod _multiplyIntPtrInt;
private IMethod _divideInt; private IMethod _divideInt;
private IMethod _divideLong; private IMethod _divideLong;
private IMethod _divideFloat; private IMethod _divideFloat;
@ -348,14 +391,22 @@ namespace Obfuz.Emit
public IMethod AddLong => _addLong; public IMethod AddLong => _addLong;
public IMethod AddFloat => _addFloat; public IMethod AddFloat => _addFloat;
public IMethod AddDouble => _addDouble; public IMethod AddDouble => _addDouble;
public IMethod AddIntPtr => _addIntPtr;
public IMethod AddIntPtrInt => _addIntPtrInt;
public IMethod SubtractInt => _subtractInt; public IMethod SubtractInt => _subtractInt;
public IMethod SubtractLong => _subtractLong; public IMethod SubtractLong => _subtractLong;
public IMethod SubtractFloat => _subtractFloat; public IMethod SubtractFloat => _subtractFloat;
public IMethod SubtractDouble => _subtractDouble; public IMethod SubtractDouble => _subtractDouble;
public IMethod SubtractIntPtr => _subtractIntPtr;
public IMethod SubtractIntPtrInt => _subtractIntPtrInt;
public IMethod MultiplyInt => _multiplyInt; public IMethod MultiplyInt => _multiplyInt;
public IMethod MultiplyLong => _multiplyLong; public IMethod MultiplyLong => _multiplyLong;
public IMethod MultiplyFloat => _multiplyFloat; public IMethod MultiplyFloat => _multiplyFloat;
public IMethod MultiplyDouble => _multiplyDouble; public IMethod MultiplyDouble => _multiplyDouble;
public IMethod MultiplyIntPtr => _multiplyIntPtr;
public IMethod MultiplyIntPtrInt => _multiplyIntPtrInt;
public IMethod DivideInt => _divideInt; public IMethod DivideInt => _divideInt;
public IMethod DivideLong => _divideLong; public IMethod DivideLong => _divideLong;
public IMethod DivideFloat => _divideFloat; public IMethod DivideFloat => _divideFloat;

View File

@ -0,0 +1,35 @@
// Copyright 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.
namespace Obfuz.Emit
{
public static class EntityExtensions
{
public static T GetEntity<T>(this IGroupByModuleEntity entity) where T : IGroupByModuleEntity, new()
{
return entity.Manager.GetEntity<T>(entity.Module);
}
public static DefaultMetadataImporter GetDefaultModuleMetadataImporter(this IGroupByModuleEntity entity)
{
return entity.GetEntity<DefaultMetadataImporter>();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6e9557733f180764692756653eb60f88
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,9 +1,29 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Utils; using Obfuz.Utils;
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using UnityEngine.Assertions; using UnityEngine.Assertions;
@ -63,6 +83,7 @@ namespace Obfuz.Emit
class EvalStackCalculator class EvalStackCalculator
{ {
private readonly MethodDef _method; private readonly MethodDef _method;
private readonly ICorLibTypes _corLibTypes;
private readonly BasicBlockCollection _basicBlocks; private readonly BasicBlockCollection _basicBlocks;
private readonly Dictionary<Instruction, InstructionParameterInfo> _instructionParameterInfos = new Dictionary<Instruction, InstructionParameterInfo>(); private readonly Dictionary<Instruction, InstructionParameterInfo> _instructionParameterInfos = new Dictionary<Instruction, InstructionParameterInfo>();
private readonly Dictionary<Instruction, EvalDataType> _evalStackTopDataTypeAfterInstructions = new Dictionary<Instruction, EvalDataType>(); private readonly Dictionary<Instruction, EvalDataType> _evalStackTopDataTypeAfterInstructions = new Dictionary<Instruction, EvalDataType>();
@ -71,6 +92,7 @@ namespace Obfuz.Emit
public EvalStackCalculator(MethodDef method) public EvalStackCalculator(MethodDef method)
{ {
_method = method; _method = method;
_corLibTypes = method.Module.CorLibTypes;
_basicBlocks = new BasicBlockCollection(method, false); _basicBlocks = new BasicBlockCollection(method, false);
_blockEvalStackStates = _basicBlocks.Blocks.ToDictionary(b => b, b => new EvalStackState()); _blockEvalStackStates = _basicBlocks.Blocks.ToDictionary(b => b, b => new EvalStackState());
@ -125,7 +147,7 @@ namespace Obfuz.Emit
case ElementType.Ptr: case ElementType.Ptr:
case ElementType.FnPtr: case ElementType.FnPtr:
case ElementType.ByRef: case ElementType.ByRef:
datas.Add(new EvalDataTypeWithSig(EvalDataType.I, null)); datas.Add(new EvalDataTypeWithSig(EvalDataType.I, type));
break; break;
case ElementType.String: case ElementType.String:
case ElementType.Class: case ElementType.Class:
@ -206,11 +228,21 @@ namespace Obfuz.Emit
datas.Add(type); datas.Add(type);
} }
private void PushStackObject(List<EvalDataTypeWithSig> datas) private void PushStackObject(List<EvalDataTypeWithSig> datas, TypeSig type)
{ {
datas.Add(new EvalDataTypeWithSig(EvalDataType.Ref, _method.Module.CorLibTypes.Object)); PushStack(datas, new EvalDataTypeWithSig(EvalDataType.Ref, type));
} }
private void PushStackPointer(List<EvalDataTypeWithSig> datas, TypeSig type)
{
PushStack(datas, new EvalDataTypeWithSig(EvalDataType.I, type));
}
//private void PushStackObject(List<EvalDataTypeWithSig> datas)
//{
// datas.Add(new EvalDataTypeWithSig(EvalDataType.Ref, _method.Module.CorLibTypes.Object));
//}
private EvalDataType CalcBasicBinOpRetType(EvalDataType op1, EvalDataType op2) private EvalDataType CalcBasicBinOpRetType(EvalDataType op1, EvalDataType op2)
{ {
switch (op1) switch (op1)
@ -270,7 +302,7 @@ namespace Obfuz.Emit
private void SimulateRunAllBlocks() private void SimulateRunAllBlocks()
{ {
bool methodHasReturnValue = _method.ReturnType.RemovePinnedAndModifiers().ElementType != ElementType.Void; bool methodHasReturnValue = !MetaUtil.IsVoidType(_method.ReturnType);
CilBody body = _method.Body; CilBody body = _method.Body;
if (body.HasExceptionHandlers) if (body.HasExceptionHandlers)
@ -283,7 +315,7 @@ namespace Obfuz.Emit
var inputStackDatas = _blockEvalStackStates[bb].inputStackDatas; var inputStackDatas = _blockEvalStackStates[bb].inputStackDatas;
if (inputStackDatas.Count == 0) if (inputStackDatas.Count == 0)
{ {
inputStackDatas.Add(new EvalDataTypeWithSig(EvalDataType.Ref, handler.CatchType.ToTypeSig())); PushStackObject(inputStackDatas, handler.CatchType.ToTypeSig());
} }
} }
if (handler.IsCatch || handler.IsFilter) if (handler.IsCatch || handler.IsFilter)
@ -292,7 +324,7 @@ namespace Obfuz.Emit
var inputStackDatas = _blockEvalStackStates[bb].inputStackDatas; var inputStackDatas = _blockEvalStackStates[bb].inputStackDatas;
if (inputStackDatas.Count == 0) if (inputStackDatas.Count == 0)
{ {
inputStackDatas.Add(new EvalDataTypeWithSig(EvalDataType.Ref, handler.CatchType.ToTypeSig())); PushStackObject(inputStackDatas, handler.CatchType.ToTypeSig());
} }
} }
} }
@ -339,7 +371,7 @@ namespace Obfuz.Emit
case Code.Ldarga: case Code.Ldarga:
case Code.Ldarga_S: case Code.Ldarga_S:
{ {
PushStack(newPushedDatas, EvalDataType.I); PushStackPointer(newPushedDatas, new ByRefSig(inst.GetParameter(_method.Parameters).Type));
break; break;
} }
case Code.Ldloc_0: case Code.Ldloc_0:
@ -355,7 +387,7 @@ namespace Obfuz.Emit
case Code.Ldloca: case Code.Ldloca:
case Code.Ldloca_S: case Code.Ldloca_S:
{ {
PushStack(newPushedDatas, EvalDataType.I); PushStackPointer(newPushedDatas, new ByRefSig(inst.GetLocal(body.Variables).Type));
break; break;
} }
case Code.Stloc_0: case Code.Stloc_0:
@ -376,7 +408,7 @@ namespace Obfuz.Emit
} }
case Code.Ldnull: case Code.Ldnull:
{ {
PushStackObject(newPushedDatas); PushStackObject(newPushedDatas, corLibTypes.Object);
break; break;
} }
case Code.Ldc_I4_M1: case Code.Ldc_I4_M1:
@ -513,13 +545,13 @@ namespace Obfuz.Emit
case Code.Ldind_I: case Code.Ldind_I:
{ {
Assert.IsTrue(stackSize > 0); Assert.IsTrue(stackSize > 0);
PushStack(newPushedDatas, EvalDataType.I); PushStackPointer(newPushedDatas, corLibTypes.IntPtr);
break; break;
} }
case Code.Ldind_Ref: case Code.Ldind_Ref:
{ {
Assert.IsTrue(stackSize > 0); Assert.IsTrue(stackSize > 0);
PushStackObject(newPushedDatas); PushStackObject(newPushedDatas, stackDatas[stackSize - 1].typeSig?.RemovePinnedAndModifiers().Next ?? corLibTypes.Object);
break; break;
} }
case Code.Ldind_R4: case Code.Ldind_R4:
@ -639,7 +671,7 @@ namespace Obfuz.Emit
case Code.Conv_I: case Code.Conv_I:
case Code.Conv_U: case Code.Conv_U:
{ {
PushStack(newPushedDatas, EvalDataType.I); PushStackPointer(newPushedDatas, corLibTypes.IntPtr);
break; break;
} }
case Code.Conv_R4: case Code.Conv_R4:
@ -681,7 +713,7 @@ namespace Obfuz.Emit
case Code.Conv_Ovf_U: case Code.Conv_Ovf_U:
case Code.Conv_Ovf_U_Un: case Code.Conv_Ovf_U_Un:
{ {
PushStack(newPushedDatas, EvalDataType.I); PushStackPointer(newPushedDatas, corLibTypes.IntPtr);
break; break;
} }
case Code.Conv_R_Un: case Code.Conv_R_Un:
@ -702,7 +734,7 @@ namespace Obfuz.Emit
} }
case Code.Ldstr: case Code.Ldstr:
{ {
PushStack(newPushedDatas, new EvalDataTypeWithSig(EvalDataType.Ref, corLibTypes.String)); PushStackObject(newPushedDatas, corLibTypes.String);
break; break;
} }
case Code.Newobj: case Code.Newobj:
@ -713,21 +745,24 @@ namespace Obfuz.Emit
} }
case Code.Castclass: case Code.Castclass:
{ {
PushStack(newPushedDatas, (ITypeDefOrRef)inst.Operand); Assert.IsTrue(stackSize > 0);
var obj = stackDatas[stackSize - 1];
//Assert.IsTrue(obj.type == EvalDataType.Ref);
PushStackObject(newPushedDatas, ((ITypeDefOrRef)inst.Operand).ToTypeSig());
break; break;
} }
case Code.Isinst: case Code.Isinst:
{ {
Assert.IsTrue(stackSize > 0); Assert.IsTrue(stackSize > 0);
var obj = stackDatas[stackSize - 1]; var obj = stackDatas[stackSize - 1];
Assert.IsTrue(obj.type == EvalDataType.Ref); //Assert.IsTrue(obj.type == EvalDataType.Ref);
PushStack(newPushedDatas, obj); PushStackObject(newPushedDatas, ((ITypeDefOrRef)inst.Operand).ToTypeSig());
break; break;
} }
case Code.Unbox: case Code.Unbox:
{ {
Assert.IsTrue(stackSize > 0); Assert.IsTrue(stackSize > 0);
PushStack(newPushedDatas, EvalDataType.I); PushStackPointer(newPushedDatas, corLibTypes.IntPtr);
break; break;
} }
case Code.Unbox_Any: case Code.Unbox_Any:
@ -739,7 +774,8 @@ namespace Obfuz.Emit
case Code.Box: case Code.Box:
{ {
Assert.IsTrue(stackSize > 0); Assert.IsTrue(stackSize > 0);
PushStackObject(newPushedDatas); //PushStack(newPushedDatas, (ITypeDefOrRef)inst.Operand);
PushStackObject(newPushedDatas, ((ITypeDefOrRef)inst.Operand).ToTypeSig());
break; break;
} }
case Code.Throw: case Code.Throw:
@ -763,7 +799,9 @@ namespace Obfuz.Emit
case Code.Ldflda: case Code.Ldflda:
case Code.Ldsflda: case Code.Ldsflda:
{ {
PushStack(newPushedDatas, EvalDataType.I); IField field = (IField)inst.Operand;
TypeSig fieldType = MetaUtil.InflateFieldSig(field, gac);
PushStackPointer(newPushedDatas, new ByRefSig(fieldType));
break; break;
} }
case Code.Stfld: case Code.Stfld:
@ -809,7 +847,7 @@ namespace Obfuz.Emit
case Code.Ldelem_I: case Code.Ldelem_I:
{ {
Assert.IsTrue(stackSize >= 2); Assert.IsTrue(stackSize >= 2);
PushStack(newPushedDatas, EvalDataType.I); PushStackPointer(newPushedDatas, corLibTypes.IntPtr);
break; break;
} }
case Code.Ldelem_R4: case Code.Ldelem_R4:
@ -827,7 +865,7 @@ namespace Obfuz.Emit
case Code.Ldelem_Ref: case Code.Ldelem_Ref:
{ {
Assert.IsTrue(stackSize >= 2); Assert.IsTrue(stackSize >= 2);
PushStackObject(newPushedDatas); PushStackObject(newPushedDatas, stackDatas[stackSize - 2].typeSig.RemovePinnedAndModifiers().Next ?? corLibTypes.Object);
break; break;
} }
case Code.Ldelem: case Code.Ldelem:
@ -862,7 +900,7 @@ namespace Obfuz.Emit
case Code.Refanyval: case Code.Refanyval:
{ {
Assert.IsTrue(stackSize > 0); Assert.IsTrue(stackSize > 0);
PushStack(newPushedDatas, EvalDataType.I); PushStackPointer(newPushedDatas, corLibTypes.IntPtr);
break; break;
} }
case Code.Ldtoken: case Code.Ldtoken:
@ -892,7 +930,7 @@ namespace Obfuz.Emit
} }
case Code.Localloc: case Code.Localloc:
{ {
PushStack(newPushedDatas, EvalDataType.I); PushStackPointer(newPushedDatas, corLibTypes.IntPtr);
break; break;
} }
case Code.Unaligned: case Code.Unaligned:
@ -941,27 +979,468 @@ namespace Obfuz.Emit
_evalStackTopDataTypeAfterInstructions[inst] = stackDatas.Last().type; _evalStackTopDataTypeAfterInstructions[inst] = stackDatas.Last().type;
} }
} }
ReduceOutputArgsToBaseType(block, stackDatas);
foreach (BasicBlock outBb in block.outBlocks) foreach (BasicBlock outBb in block.outBlocks)
{ {
EvalStackState outState = _blockEvalStackStates[outBb]; EvalStackState outState = _blockEvalStackStates[outBb];
if (outState.visited) 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); blockWalkStack.Push(outBb);
} }
} }
} }
} }
private void ReduceOutputArgsToBaseType(BasicBlock block, List<EvalDataTypeWithSig> stackDatas)
{
foreach (BasicBlock outBb in block.outBlocks)
{
if (outBb == block)
{
continue;
}
EvalStackState outState = _blockEvalStackStates[outBb];
if (outState.inputStackDatas.Count == stackDatas.Count)
{
ReduceOutputArgsToBaseType(stackDatas, outState.inputStackDatas);
}
else
{
if (outState.inputStackDatas.Count > 0 || outState.visited)
{
throw new Exception($"Block {outBb} in method {_method.FullName} has inconsistent stack data. Expected {outState.inputStackDatas.Count}, but got {stackDatas.Count}.");
}
}
}
foreach (BasicBlock outBb in block.outBlocks)
{
if (outBb == block)
{
continue;
}
EvalStackState outState = _blockEvalStackStates[outBb];
outState.inputStackDatas.Clear();
outState.inputStackDatas.AddRange(stackDatas);
}
}
private TypeSig ReduceBaseType(TypeSig type1, TypeSig type2, bool forceRefType)
{
if (TypeEqualityComparer.Instance.Equals(type1, type2))
{
return type1;
}
type1 = type1.RemovePinnedAndModifiers();
type2 = type2.RemovePinnedAndModifiers();
ElementType t1 = type1.ElementType;
ElementType t2 = type2.ElementType;
if (t1 > t2)
{
(t1, t2) = (t2, t1);
(type1, type2) = (type2, type1);
}
switch (t1)
{
case ElementType.Void:
case ElementType.TypedByRef:
case ElementType.ValueArray:
{
if (t1 != t2)
{
break;
}
return type1;
}
case ElementType.R4:
case ElementType.R8:
case ElementType.R:
{
if (t1 == t2)
{
return type1;
}
if (forceRefType)
{
switch (t2)
{
case ElementType.Class:
case ElementType.GenericInst:
return type2;
default: return _corLibTypes.Object;
}
}
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:
{
switch (t2)
{
case ElementType.Boolean:
case ElementType.Char:
case ElementType.I1:
case ElementType.U1:
case ElementType.I2:
case ElementType.U2:
case ElementType.I4:
case ElementType.U4:
{
return _corLibTypes.Int32;
}
case ElementType.I:
case ElementType.U:
case ElementType.I8:
case ElementType.U8:
{
return type2;
}
default:
{
if (forceRefType)
{
switch (t2)
{
case ElementType.Class:
case ElementType.GenericInst:
return type2;
default: return _corLibTypes.Object;
}
}
break;
}
}
break;
}
case ElementType.I8:
case ElementType.U8:
{
switch (t2)
{
case ElementType.I:
case ElementType.U:
case ElementType.I8:
case ElementType.U8:
{
return type1;
}
default:
{
if (forceRefType)
{
switch (t2)
{
case ElementType.Class:
case ElementType.GenericInst:
return type2;
default: return _corLibTypes.Object;
}
}
break;
}
}
break;
}
case ElementType.I:
case ElementType.U:
{
switch (t2)
{
case ElementType.I:
case ElementType.U:
{
return type1;
}
case ElementType.FnPtr:
{
return type2;
}
default:
{
if (forceRefType)
{
switch (t2)
{
case ElementType.Class:
case ElementType.GenericInst:
return type2;
default: return _corLibTypes.Object;
}
}
break;
}
}
break;
}
case ElementType.String:
{
if (t1 == t2)
{
return type1;
}
return _corLibTypes.Object;
}
case ElementType.Ptr:
{
switch (t2)
{
case ElementType.Ptr: return new PtrSig(ReduceBaseType(type1.Next, type2.Next, false));
case ElementType.ByRef: return new ByRefSig(ReduceBaseType(type1.Next, type2.Next, false));
case ElementType.I:
case ElementType.U: return type1;
}
break;
}
case ElementType.ByRef:
{
switch (t2)
{
case ElementType.ByRef: return new ByRefSig(ReduceBaseType(type1.Next, type2.Next, false));
case ElementType.I:
case ElementType.U: return type1;
}
break;
}
case ElementType.ValueType:
{
if (forceRefType)
{
return type2;
}
break;
}
case ElementType.Class:
{
switch (t2)
{
case ElementType.Class:
{
TypeDef typeDef1 = type1.ToTypeDefOrRef().ResolveTypeDefThrow();
TypeDef typeDef2 = type2.ToTypeDefOrRef().ResolveTypeDefThrow();
while (typeDef2 != null)
{
if (MetaUtil.IsAssignableFrom(typeDef1, typeDef2))
{
return _method.Module.Import(typeDef2).ToTypeSig();
}
typeDef2 = typeDef2.BaseType?.ResolveTypeDefThrow();
}
return _corLibTypes.Object;
}
case ElementType.Array:
case ElementType.SZArray:
{
TypeDef typeDef1 = type1.ToTypeDefOrRef().ResolveTypeDefThrow();
if (typeDef1.Namespace.StartsWith("System"))
{
switch (typeDef1.Name.ToString())
{
case "Array":
case "ICloneable":
case "IList":
case "IList`1":
case "ICollection":
case "ICollection`1":
case "IEnumerable":
case "IEnumerable`1":
case "IStructuralComparable":
case "IStructuralEquatable":
{
return type1;
}
}
}
return _corLibTypes.Object;
}
case ElementType.GenericInst:
{
return type2;
}
case ElementType.Var:
case ElementType.Object:
case ElementType.MVar:
{
return _corLibTypes.Object;
}
}
break;
}
case ElementType.Array:
{
switch (t2)
{
case ElementType.Array:
return new ArraySig(ReduceBaseType(type1.Next, type2.Next, false));
case ElementType.SZArray:
return _method.Module.ImportAsTypeSig(typeof(Array));
case ElementType.GenericInst:
{
var gis = (GenericInstSig)type2;
switch (gis.GenericType.GetName())
{
case "IList`1":
case "ICollection`1":
return type2;
}
return _corLibTypes.Object;
}
case ElementType.Object:
{
return _corLibTypes.Object;
}
}
break;
}
case ElementType.GenericInst:
{
var gis = (GenericInstSig)type1;
switch (t2)
{
case ElementType.Object:
{
return _corLibTypes.Object;
}
case ElementType.MVar:
{
return type2;
}
case ElementType.SZArray:
{
switch (gis.GenericType.GetName())
{
case "IList`1":
case "ICollection`1":
{
return type1;
}
// FIXME
default: return _corLibTypes.Object;
}
}
case ElementType.GenericInst:
{
// FIXME
return type1;
}
}
break;
}
case ElementType.FnPtr:
{
switch (t2)
{
case ElementType.FnPtr:
{
// FIXME
return type1;
}
}
break;
}
case ElementType.Object:
{
return type1;
}
case ElementType.SZArray:
{
switch (t2)
{
case ElementType.SZArray:
return new SZArraySig(ReduceBaseType(type1.Next, type2.Next, false));
case ElementType.MVar:
return _corLibTypes.Object;
}
break;
}
case ElementType.Var:
case ElementType.MVar:
{
if (t1 == t2)
{
// FIXME!!!
return type1;
}
if (t2 == ElementType.Class || t2 == ElementType.GenericInst)
{
return type2;
}
return _corLibTypes.Object;
}
}
UnityEngine.Debug.LogError($"reduce base type of {type1} and {type2} is unsupported");
return type1;
}
private EvalDataTypeWithSig ReduceBaseType(EvalDataTypeWithSig type1, EvalDataTypeWithSig type2)
{
if (type1.type != type2.type)
{
throw new Exception($"Method {_method.FullName} has inconsistent stack data. Expected {type1.type}, but got {type2.type}.");
}
switch (type1.type)
{
case EvalDataType.Int32:
case EvalDataType.Int64:
case EvalDataType.Float:
case EvalDataType.Double:
case EvalDataType.Token:
case EvalDataType.Unknown:
{
return type1;
}
case EvalDataType.I:
case EvalDataType.Ref:
{
if (type1.typeSig == null)
{
return type2;
}
if (type2.typeSig == null)
{
return type1;
}
if (TypeEqualityComparer.Instance.Equals(type1.typeSig, type2.typeSig))
{
return type1;
}
return new EvalDataTypeWithSig(type1.type, ReduceBaseType(type1.typeSig, type2.typeSig, type1.type == EvalDataType.Ref));
}
case EvalDataType.ValueType:
{
if (!TypeEqualityComparer.Instance.Equals(type1.typeSig, type2.typeSig))
{
throw new Exception($"Method {_method.FullName} has inconsistent stack data. Expected {type1.typeSig}, but got {type2.typeSig}.");
}
return type1;
}
default: throw new Exception($"not supported EvalDataType: {type1.type} in method: {_method.FullName}.");
}
}
private void ReduceOutputArgsToBaseType(List<EvalDataTypeWithSig> stackDatasRet, List<EvalDataTypeWithSig> stackDatasNew)
{
if (stackDatasNew.Count == 0)
{
return;
}
if (stackDatasRet.Count != stackDatasNew.Count)
{
throw new Exception($"Method {_method.FullName} has inconsistent stack data. Expected {stackDatasRet.Count}, but got {stackDatasNew.Count}.");
}
for (int i = 0; i < stackDatasRet.Count; i++)
{
EvalDataTypeWithSig oldType = stackDatasRet[i];
EvalDataTypeWithSig newType = stackDatasNew[i];
stackDatasRet[i] = ReduceBaseType(oldType, newType);
}
}
} }
} }

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -6,19 +26,46 @@ namespace Obfuz.Emit
{ {
public interface IGroupByModuleEntity public interface IGroupByModuleEntity
{ {
void Init(ModuleDef mod); GroupByModuleEntityManager Manager { get; set; }
ModuleDef Module { get; set; }
EncryptionScopeProvider EncryptionScopeProvider { get; }
EncryptionScopeInfo EncryptionScope { get; set; }
void Init();
void Done();
} }
public abstract class GroupByModuleEntityBase : IGroupByModuleEntity public abstract class GroupByModuleEntityBase : IGroupByModuleEntity
{ {
public abstract void Init(ModuleDef mod); public GroupByModuleEntityManager Manager { get; set; }
public ModuleDef Module { get; set; }
public EncryptionScopeInfo EncryptionScope { get; set; }
public EncryptionScopeProvider EncryptionScopeProvider => Manager.EncryptionScopeProvider;
public T GetEntity<T>() where T : IGroupByModuleEntity, new()
{
return Manager.GetEntity<T>(Module);
}
public abstract void Init();
public abstract void Done();
} }
public class GroupByModuleEntityManager public class GroupByModuleEntityManager
{ {
private readonly Dictionary<(ModuleDef, Type), IGroupByModuleEntity> _moduleEntityManagers = new Dictionary<(ModuleDef, Type), IGroupByModuleEntity>(); private readonly Dictionary<(ModuleDef, Type), IGroupByModuleEntity> _moduleEntityManagers = new Dictionary<(ModuleDef, Type), IGroupByModuleEntity>();
public T GetEntity<T>(ModuleDef mod, Func<T> creator = null) where T : IGroupByModuleEntity public EncryptionScopeProvider EncryptionScopeProvider { get; set; }
public T GetEntity<T>(ModuleDef mod) where T : IGroupByModuleEntity, new()
{ {
var key = (mod, typeof(T)); var key = (mod, typeof(T));
if (_moduleEntityManagers.TryGetValue(key, out var emitManager)) if (_moduleEntityManagers.TryGetValue(key, out var emitManager))
@ -27,22 +74,17 @@ namespace Obfuz.Emit
} }
else else
{ {
T newEmitManager; T newEmitManager = new T();
if (creator != null) newEmitManager.Manager = this;
{ newEmitManager.Module = mod;
newEmitManager = creator(); newEmitManager.EncryptionScope = EncryptionScopeProvider.GetScope(mod);
} newEmitManager.Init();
else
{
newEmitManager = (T)Activator.CreateInstance(typeof(T));
}
newEmitManager.Init(mod);
_moduleEntityManagers[key] = newEmitManager; _moduleEntityManagers[key] = newEmitManager;
return newEmitManager; return newEmitManager;
} }
} }
public List<T> GetEntities<T>() where T : IGroupByModuleEntity public List<T> GetEntities<T>() where T : IGroupByModuleEntity, new()
{ {
var managers = new List<T>(); var managers = new List<T>();
foreach (var kv in _moduleEntityManagers) foreach (var kv in _moduleEntityManagers)
@ -55,9 +97,13 @@ namespace Obfuz.Emit
return managers; return managers;
} }
public DefaultMetadataImporter GetDefaultModuleMetadataImporter(ModuleDef module, EncryptionScopeProvider encryptionScopeProvider) public void Done<T>() where T : IGroupByModuleEntity, new()
{ {
return GetEntity<DefaultMetadataImporter>(module, () => new DefaultMetadataImporter(encryptionScopeProvider)); var managers = GetEntities<T>();
foreach (var manager in managers)
{
manager.Done();
}
} }
} }
} }

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using System; using System;
@ -11,6 +31,8 @@ namespace Obfuz.Emit
private readonly List<Local> _allocatedVars = new List<Local>(); private readonly List<Local> _allocatedVars = new List<Local>();
public IReadOnlyList<Local> AllocatedLocals => _allocatedVars;
public ScopeLocalVariables(LocalVariableAllocator localVariableAllocator) public ScopeLocalVariables(LocalVariableAllocator localVariableAllocator)
{ {
@ -63,5 +85,10 @@ namespace Obfuz.Emit
{ {
_freeLocals.Add(local); _freeLocals.Add(local);
} }
public ScopeLocalVariables CreateScope()
{
return new ScopeLocalVariables(this);
}
} }
} }

View File

@ -1,3 +1,23 @@
// Copyright 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.
namespace Obfuz.EncryptionVM namespace Obfuz.EncryptionVM
{ {
public class EncryptionInstructionWithOpCode public class EncryptionInstructionWithOpCode

View File

@ -1,3 +1,23 @@
// Copyright 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.
using System.Collections.Generic; using System.Collections.Generic;
namespace Obfuz.EncryptionVM namespace Obfuz.EncryptionVM

View File

@ -1,3 +1,23 @@
// Copyright 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.
using System.Collections.Generic; using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions

View File

@ -1,3 +1,23 @@
// Copyright 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.
using System.Collections.Generic; using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions

View File

@ -1,3 +1,23 @@
// Copyright 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.
using System.Collections.Generic; using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions

View File

@ -1,3 +1,23 @@
// Copyright 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.
using System.Collections.Generic; using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions

View File

@ -1,3 +1,23 @@
// Copyright 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.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,5 +1,24 @@
using NUnit.Framework; // Copyright 2025 Code Philosophy
using Obfuz.Utils; //
// 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.
using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions
@ -21,7 +40,7 @@ namespace Obfuz.EncryptionVM.Instructions
private void Verify() private void Verify()
{ {
int a = 1122334; int a = 1122334;
Assert.AreEqual(a, a * _multiValue * _revertMultiValue); UnityEngine.Assertions.Assert.AreEqual(a, a * _multiValue * _revertMultiValue);
} }
public override int Encrypt(int value, int[] secretKey, int salt) public override int Encrypt(int value, int[] secretKey, int salt)

View File

@ -1,3 +1,23 @@
// Copyright 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.
using Obfuz.Utils; using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using Obfuz.Utils; using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using System.Collections.Generic; using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions

View File

@ -1,3 +1,23 @@
// Copyright 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.
using System.Collections.Generic; using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions

View File

@ -1,3 +1,23 @@
// Copyright 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.
using Obfuz.Utils; using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,3 +1,23 @@
// Copyright 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.
namespace Obfuz.EncryptionVM namespace Obfuz.EncryptionVM
{ {
public class VirtualMachine public class VirtualMachine

View File

@ -1,3 +1,23 @@
// Copyright 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.
using Obfuz.Utils; using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -82,8 +102,7 @@ namespace Obfuz.EncryptionVM
} }
lines.Add(@" lines.Add(@"
default: default: throw new System.Exception($""Invalid opCode:{opCode}"");
throw new System.Exception($""Invalid opCode:{opCode}"");
} }
}"); }");
} }
@ -106,8 +125,7 @@ namespace Obfuz.EncryptionVM
} }
lines.Add(@" lines.Add(@"
default: default: throw new System.Exception($""Invalid opCode:{opCode}"");
throw new System.Exception($""Invalid opCode:{opCode}"");
} }
}"); }");
} }

View File

@ -1,3 +1,23 @@
// Copyright 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.
using Obfuz.EncryptionVM.Instructions; using Obfuz.EncryptionVM.Instructions;
using Obfuz.Utils; using Obfuz.Utils;
using System; using System;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using Obfuz.Utils; using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine.Assertions; using UnityEngine.Assertions;

View File

@ -1,9 +1,25 @@
using dnlib.DotNet; // Copyright 2025 Code Philosophy
using NUnit.Framework; //
using Obfuz.Settings; // Permission is hereby granted, free of charge, to any person obtaining a copy
using Obfuz.Utils; // 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.
using Obfuz.Utils;
using System; using System;
using System.Collections;
using System.Linq; using System.Linq;
using System.Text; using System.Text;

View File

@ -1,10 +1,26 @@
// Copyright 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.
using Obfuz.Settings; using Obfuz.Settings;
using Obfuz.Utils; using Obfuz.Utils;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
namespace Obfuz.GarbageCodeGeneration namespace Obfuz.GarbageCodeGeneration
@ -14,10 +30,10 @@ namespace Obfuz.GarbageCodeGeneration
{ {
private const int CodeGenerationSecretKeyLength = 1024; private const int CodeGenerationSecretKeyLength = 1024;
private readonly GarbageCodeGeneratorSettings _settings; private readonly GarbageCodeGenerationSettings _settings;
private readonly int[] _intGenerationSecretKey; private readonly int[] _intGenerationSecretKey;
public GarbageCodeGenerator(GarbageCodeGeneratorSettings settings) public GarbageCodeGenerator(GarbageCodeGenerationSettings settings)
{ {
_settings = settings; _settings = settings;
@ -55,14 +71,14 @@ namespace Obfuz.GarbageCodeGeneration
private void GenerateTask(GarbageCodeGenerationTask task) 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.garbageCodeTypes}, output path: {task.outputPath}"); 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)) if (string.IsNullOrWhiteSpace(task.outputPath))
{ {
throw new Exception("outputPath of GarbageCodeGenerationTask is empty!"); throw new Exception("outputPath of GarbageCodeGenerationTask is empty!");
} }
var generator = CreateSpecificCodeGenerator(task.garbageCodeTypes); var generator = CreateSpecificCodeGenerator(task.garbageCodeType);
var parameters = new GenerationParameters var parameters = new GenerationParameters
{ {

View File

@ -1,5 +1,24 @@
using Obfuz.Settings; // Copyright 2025 Code Philosophy
using Obfuz.Utils; //
// 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.
using Obfuz.Utils;
namespace Obfuz.GarbageCodeGeneration namespace Obfuz.GarbageCodeGeneration
{ {

View File

@ -1,3 +1,23 @@
// Copyright 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.
using Obfuz.Utils; using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;

View File

@ -1,9 +1,25 @@
using dnlib.DotNet; // Copyright 2025 Code Philosophy
using NUnit.Framework; //
using Obfuz.Settings; // Permission is hereby granted, free of charge, to any person obtaining a copy
using Obfuz.Utils; // 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.
using Obfuz.Utils;
using System; using System;
using System.Collections;
using System.Linq; using System.Linq;
using System.Text; using System.Text;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using Obfuz.ObfusPasses; using Obfuz.ObfusPasses;
namespace Obfuz namespace Obfuz

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Emit; using Obfuz.Emit;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Emit; using Obfuz.Emit;
@ -7,19 +27,30 @@ using System.Collections.Generic;
namespace Obfuz.ObfusPasses.CallObfus namespace Obfuz.ObfusPasses.CallObfus
{ {
public class CallObfusPass : BasicBlockObfuscationPassBase 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 CallObfuscationSettingsFacade _settings;
private SpecialWhiteListMethodCalculator _specialWhiteListMethodCache;
private IObfuscator _dynamicProxyObfuscator; private IObfuscator _dynamicProxyObfuscator;
private IObfuscationPolicy _dynamicProxyPolicy; private IObfuscationPolicy _dynamicProxyPolicy;
private readonly CachedDictionary<IMethod, bool> _specialwhiteListMethodCache;
public override ObfuscationPassType Type => ObfuscationPassType.CallObfus; public override ObfuscationPassType Type => ObfuscationPassType.CallObfus;
public CallObfusPass(CallObfuscationSettingsFacade settings) public CallObfusPass(CallObfuscationSettingsFacade settings)
{ {
_settings = settings; _settings = settings;
_specialwhiteListMethodCache = new CachedDictionary<IMethod, bool>(MethodEqualityComparer.CompareDeclaringTypes, this.ComputeIsInWhiteList); CurrentSettings = settings;
} }
public override void Stop() public override void Stop()
@ -30,117 +61,82 @@ namespace Obfuz.ObfusPasses.CallObfus
public override void Start() public override void Start()
{ {
var ctx = ObfuscationPassContext.Current; var ctx = ObfuscationPassContext.Current;
_dynamicProxyObfuscator = new DefaultCallProxyObfuscator(ctx.encryptionScopeProvider, ctx.constFieldAllocator, ctx.moduleEntityManager, _settings);
_specialWhiteListMethodCache = new SpecialWhiteListMethodCalculator(ctx.coreSettings.targetRuntime, _settings.obfuscateCallToMethodInMscorlib);
_dynamicProxyObfuscator = CreateObfuscator(ctx, _settings.proxyMode);
_dynamicProxyPolicy = new ConfigurableObfuscationPolicy(ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles); _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<Instruction> instructions = method.Body.Instructions;
var outputInstructions = new List<Instruction>();
var totalFinalInstructions = new List<Instruction>();
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) protected override bool NeedObfuscateMethod(MethodDef method)
{ {
return _dynamicProxyPolicy.NeedObfuscateCallInMethod(method); return _dynamicProxyPolicy.NeedObfuscateCallInMethod(method);
} }
private bool TryObfuscateInstruction(MethodDef callerMethod, Instruction lastInst, Instruction inst, List<Instruction> outputInstructions, ObfusMethodContext ctx)
private static readonly HashSet<string> _specialTypeFullNames = new HashSet<string>
{
"System.Enum",
"System.Delegate",
"System.MulticastDelegate",
"Obfuz.EncryptionService`1",
};
private static readonly HashSet<string> _specialMethodNames = new HashSet<string>
{
"GetEnumerator", // List<T>.Enumerator.GetEnumerator()
".ctor", // constructor
};
private static readonly HashSet<string> _specialMethodFullNames = new HashSet<string>
{
"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 (!_settings.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;
}
protected override bool TryObfuscateInstruction(MethodDef callerMethod, Instruction inst, BasicBlock block,
int instructionIndex, IList<Instruction> globalInstructions, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
{ {
IMethod calledMethod = inst.Operand as IMethod; IMethod calledMethod = inst.Operand as IMethod;
if (calledMethod == null || !calledMethod.IsMethod) if (calledMethod == null || !calledMethod.IsMethod)
@ -162,7 +158,7 @@ namespace Obfuz.ObfusPasses.CallObfus
} }
case Code.Callvirt: case Code.Callvirt:
{ {
if (instructionIndex > 0 && globalInstructions[instructionIndex - 1].OpCode.Code == Code.Constrained) if (lastInst != null && lastInst.OpCode.Code == Code.Constrained)
{ {
return false; return false;
} }
@ -173,21 +169,18 @@ namespace Obfuz.ObfusPasses.CallObfus
} }
if (_specialwhiteListMethodCache.GetValue(calledMethod)) if (_specialWhiteListMethodCache.IsInWhiteList(calledMethod))
{ {
return false; return false;
} }
if (!_dynamicProxyPolicy.NeedObfuscateCalledMethod(callerMethod, calledMethod, callVir, block.inLoop)) if (!_dynamicProxyPolicy.NeedObfuscateCalledMethod(callerMethod, calledMethod, callVir))
{ {
return false; return false;
} }
ObfuscationCachePolicy cachePolicy = _dynamicProxyPolicy.GetMethodObfuscationCachePolicy(callerMethod); return _dynamicProxyObfuscator.Obfuscate(callerMethod, calledMethod, callVir, outputInstructions);
bool cachedCallIndex = block.inLoop ? cachePolicy.cacheInLoop : cachePolicy.cacheNotInLoop;
_dynamicProxyObfuscator.Obfuscate(callerMethod, calledMethod, callVir, cachedCallIndex, outputInstructions);
return true;
} }
} }
} }

View File

@ -1,5 +1,26 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Conf; using Obfuz.Conf;
using Obfuz.Settings;
using Obfuz.Utils; using Obfuz.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -34,29 +55,12 @@ namespace Obfuz.ObfusPasses.CallObfus
class ObfuscationRule : IRule<ObfuscationRule> class ObfuscationRule : IRule<ObfuscationRule>
{ {
public bool? disableObfuscation; public ObfuscationLevel? obfuscationLevel;
public bool? obfuscateCallInLoop;
public bool? cacheCallIndexInLoop;
public bool? cacheCallIndexNotLoop;
public void InheritParent(ObfuscationRule parentRule) public void InheritParent(ObfuscationRule parentRule)
{ {
if (disableObfuscation == null) if (obfuscationLevel == null)
{ obfuscationLevel = parentRule.obfuscationLevel;
disableObfuscation = parentRule.disableObfuscation;
}
if (obfuscateCallInLoop == null)
{
obfuscateCallInLoop = parentRule.obfuscateCallInLoop;
}
if (cacheCallIndexInLoop == null)
{
cacheCallIndexInLoop = parentRule.cacheCallIndexInLoop;
}
if (cacheCallIndexNotLoop == null)
{
cacheCallIndexNotLoop = parentRule.cacheCallIndexNotLoop;
}
} }
} }
@ -75,10 +79,7 @@ namespace Obfuz.ObfusPasses.CallObfus
private static readonly ObfuscationRule s_default = new ObfuscationRule() private static readonly ObfuscationRule s_default = new ObfuscationRule()
{ {
disableObfuscation = false, obfuscationLevel = ObfuscationLevel.Basic,
obfuscateCallInLoop = true,
cacheCallIndexInLoop = true,
cacheCallIndexNotLoop = true,
}; };
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _configParser; private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _configParser;
@ -147,21 +148,9 @@ namespace Obfuz.ObfusPasses.CallObfus
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
{ {
var rule = new ObfuscationRule(); var rule = new ObfuscationRule();
if (ele.HasAttribute("disableObfuscation")) if (ele.HasAttribute("obfuscationLevel"))
{ {
rule.disableObfuscation = ConfigUtil.ParseBool(ele.GetAttribute("disableObfuscation")); rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
}
if (ele.HasAttribute("obfuscateCallInLoop"))
{
rule.obfuscateCallInLoop = ConfigUtil.ParseBool(ele.GetAttribute("obfuscateCallInLoop"));
}
if (ele.HasAttribute("cacheCallIndexInLoop"))
{
rule.cacheCallIndexInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheCallIndexInLoop"));
}
if (ele.HasAttribute("cacheCallIndexNotLoop"))
{
rule.cacheCallIndexNotLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheCallIndexNotLoop"));
} }
return rule; return rule;
} }
@ -262,17 +251,7 @@ namespace Obfuz.ObfusPasses.CallObfus
public override bool NeedObfuscateCallInMethod(MethodDef method) public override bool NeedObfuscateCallInMethod(MethodDef method)
{ {
ObfuscationRule rule = GetMethodObfuscationRule(method); ObfuscationRule rule = GetMethodObfuscationRule(method);
return rule.disableObfuscation != true; return rule.obfuscationLevel != null && rule.obfuscationLevel.Value >= ObfuscationLevel.Basic;
}
public override ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method)
{
ObfuscationRule rule = GetMethodObfuscationRule(method);
return new ObfuscationCachePolicy()
{
cacheInLoop = rule.cacheCallIndexInLoop.Value,
cacheNotInLoop = rule.cacheCallIndexNotLoop.Value,
};
} }
private bool ComputeIsInWhiteList(IMethod calledMethod) private bool ComputeIsInWhiteList(IMethod calledMethod)
@ -329,18 +308,12 @@ namespace Obfuz.ObfusPasses.CallObfus
return false; return false;
} }
public override bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop) public override bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir)
{ {
if (_whiteListMethodCache.GetValue(calledMethod)) if (_whiteListMethodCache.GetValue(calledMethod))
{ {
return false; return false;
} }
ObfuscationRule rule = GetMethodObfuscationRule(callerMethod);
if (currentInLoop && rule.obfuscateCallInLoop == false)
{
return false;
}
return true; return true;
} }
} }

View File

@ -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 DefaultCallProxyObfuscator : ObfuscatorBase
{
private readonly EncryptionScopeProvider _encryptionScopeProvider;
private readonly ConstFieldAllocator _constFieldAllocator;
private readonly CallProxyAllocator _proxyCallAllocator;
private readonly GroupByModuleEntityManager _moduleEntityManager;
public DefaultCallProxyObfuscator(EncryptionScopeProvider encryptionScopeProvider, ConstFieldAllocator constFieldAllocator, GroupByModuleEntityManager moduleEntityManager, CallObfuscationSettingsFacade settings)
{
_encryptionScopeProvider = encryptionScopeProvider;
_constFieldAllocator = constFieldAllocator;
_moduleEntityManager = moduleEntityManager;
_proxyCallAllocator = new CallProxyAllocator(encryptionScopeProvider, moduleEntityManager, settings);
}
public override void Done()
{
_proxyCallAllocator.Done();
}
public override void Obfuscate(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List<Instruction> obfuscatedInstructions)
{
MethodSig sharedMethodSig = MetaUtil.ToSharedMethodSig(calledMethod.Module.CorLibTypes, MetaUtil.GetInflatedMethodSig(calledMethod, null));
ProxyCallMethodData proxyCallMethodData = _proxyCallAllocator.Allocate(callerMethod.Module, calledMethod, callVir);
DefaultMetadataImporter importer = _moduleEntityManager.GetDefaultModuleMetadataImporter(callerMethod.Module, _encryptionScopeProvider);
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));
}
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, proxyCallMethodData.proxyMethod));
}
}
}

View File

@ -0,0 +1,285 @@
// Copyright 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.
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<MethodSig, TypeDef> _delegateTypes;
private readonly HashSet<string> _allocatedDelegateNames = new HashSet<string>();
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<MethodKey, CallInfo> _callMethods = new Dictionary<MethodKey, CallInfo>();
private CallObfuscationSettingsFacade _settings;
public DelegateProxyAllocator()
{
_delegateTypes = new CachedDictionary<MethodSig, TypeDef>(SignatureEqualityComparer.Instance, CreateDelegateForSignature);
}
public override void Init()
{
_delegateInstanceHolderType = CreateDelegateInstanceHolderTypeDef();
_settings = CallObfusPass.CurrentSettings;
}
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<CallInfo> 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<CallInfo> callMethodList2 = callMethodList.ToList();
callMethodList2.Sort((a, b) => a.key2.CompareTo(b.key2));
EncryptionScopeInfo encryptionScope = EncryptionScope;
DefaultMetadataImporter importer = this.GetDefaultModuleMetadataImporter();
RvaDataAllocator rvaDataAllocator = this.GetEntity<RvaDataAllocator>();
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, _settings.obfuscationLevel);
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));
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 02761bacbed8a8b489ae3e7f49f0f84a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,101 @@
// Copyright 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.
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Emit;
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<DelegateProxyAllocator>();
}
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<Instruction> obfuscatedInstructions)
{
DelegateProxyAllocator allocator = _entityManager.GetEntity<DelegateProxyAllocator>(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<Local> localVars = new List<Local>();
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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1102cd9f03de27c4b9fde3d6a87277c7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Editor; using Obfuz.Editor;
@ -12,6 +32,7 @@ using TypeAttributes = dnlib.DotNet.TypeAttributes;
namespace Obfuz.ObfusPasses.CallObfus namespace Obfuz.ObfusPasses.CallObfus
{ {
public struct ProxyCallMethodData public struct ProxyCallMethodData
{ {
public readonly MethodDef proxyMethod; public readonly MethodDef proxyMethod;
@ -30,38 +51,11 @@ namespace Obfuz.ObfusPasses.CallObfus
} }
} }
class ModuleCallProxyAllocator : IGroupByModuleEntity class ModuleDispatchProxyAllocator : GroupByModuleEntityBase
{ {
private ModuleDef _module;
private readonly EncryptionScopeProvider _encryptionScopeProvider;
private readonly CallObfuscationSettingsFacade _settings;
private EncryptionScopeInfo _encryptionScope;
private bool _done; private bool _done;
private CallObfuscationSettingsFacade _settings;
class MethodKey : IEquatable<MethodKey>
{
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;
}
}
class MethodProxyInfo class MethodProxyInfo
{ {
@ -93,25 +87,23 @@ namespace Obfuz.ObfusPasses.CallObfus
private TypeDef _proxyTypeDef; private TypeDef _proxyTypeDef;
public ModuleCallProxyAllocator(EncryptionScopeProvider encryptionScopeProvider, CallObfuscationSettingsFacade settings) public ModuleDispatchProxyAllocator()
{ {
_encryptionScopeProvider = encryptionScopeProvider;
_settings = settings;
} }
public void Init(ModuleDef mod) public override void Init()
{ {
_module = mod; _settings = CallObfusPass.CurrentSettings;
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
} }
private TypeDef CreateProxyTypeDef() private TypeDef CreateProxyTypeDef()
{ {
using (var scope = new DisableTypeDefFindCacheScope(_module)) ModuleDef mod = Module;
using (var scope = new DisableTypeDefFindCacheScope(mod))
{ {
var typeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ProxyCall", _module.CorLibTypes.Object.ToTypeDefOrRef()); var typeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ProxyCall", mod.CorLibTypes.Object.ToTypeDefOrRef());
typeDef.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed; typeDef.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed;
_module.Types.Add(typeDef); mod.Types.Add(typeDef);
return typeDef; return typeDef;
} }
} }
@ -157,24 +149,25 @@ namespace Obfuz.ObfusPasses.CallObfus
private MethodSig CreateDispatchMethodSig(IMethod method) private MethodSig CreateDispatchMethodSig(IMethod method)
{ {
MethodSig methodSig = MetaUtil.ToSharedMethodSig(_module.CorLibTypes, MetaUtil.GetInflatedMethodSig(method, null)); ModuleDef mod = Module;
MethodSig methodSig = MetaUtil.ToSharedMethodSig(mod.CorLibTypes, MetaUtil.GetInflatedMethodSig(method, null));
//MethodSig methodSig = MetaUtil.GetInflatedMethodSig(method).Clone(); //MethodSig methodSig = MetaUtil.GetInflatedMethodSig(method).Clone();
//methodSig.Params //methodSig.Params
switch (MetaUtil.GetThisArgType(method)) switch (MetaUtil.GetThisArgType(method))
{ {
case ThisArgType.Class: case ThisArgType.Class:
{ {
methodSig.Params.Insert(0, _module.CorLibTypes.Object); methodSig.Params.Insert(0, mod.CorLibTypes.Object);
break; break;
} }
case ThisArgType.ValueType: case ThisArgType.ValueType:
{ {
methodSig.Params.Insert(0, _module.CorLibTypes.IntPtr); methodSig.Params.Insert(0, mod.CorLibTypes.IntPtr);
break; break;
} }
} }
// extra param for index // extra param for index
methodSig.Params.Add(_module.CorLibTypes.Int32); methodSig.Params.Add(mod.CorLibTypes.Int32);
return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray()); return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray());
} }
@ -185,7 +178,7 @@ namespace Obfuz.ObfusPasses.CallObfus
private int GenerateEncryptOps(IRandom random) private int GenerateEncryptOps(IRandom random)
{ {
return EncryptionUtil.GenerateEncryptionOpCodes(random, _encryptionScope.encryptor, _settings.obfuscationLevel); return EncryptionUtil.GenerateEncryptionOpCodes(random, EncryptionScope.encryptor, _settings.obfuscationLevel);
} }
private DispatchMethodInfo GetDispatchMethod(IMethod method) private DispatchMethodInfo GetDispatchMethod(IMethod method)
@ -210,7 +203,7 @@ namespace Obfuz.ObfusPasses.CallObfus
private IRandom CreateRandomForMethod(IMethod method, bool callVir) private IRandom CreateRandomForMethod(IMethod method, bool callVir)
{ {
int seed = MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method); int seed = MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method);
return _encryptionScope.localRandomCreator(seed); return EncryptionScope.localRandomCreator(seed);
} }
public ProxyCallMethodData Allocate(IMethod method, bool callVir) public ProxyCallMethodData Allocate(IMethod method, bool callVir)
@ -228,7 +221,7 @@ namespace Obfuz.ObfusPasses.CallObfus
IRandom localRandom = CreateRandomForMethod(method, callVir); IRandom localRandom = CreateRandomForMethod(method, callVir);
int encryptOps = GenerateEncryptOps(localRandom); int encryptOps = GenerateEncryptOps(localRandom);
int salt = GenerateSalt(localRandom); int salt = GenerateSalt(localRandom);
int encryptedIndex = _encryptionScope.encryptor.Encrypt(index, encryptOps, salt); int encryptedIndex = EncryptionScope.encryptor.Encrypt(index, encryptOps, salt);
proxyInfo = new MethodProxyInfo() proxyInfo = new MethodProxyInfo()
{ {
proxyMethod = methodDispatcher.methodDef, proxyMethod = methodDispatcher.methodDef,
@ -243,7 +236,7 @@ namespace Obfuz.ObfusPasses.CallObfus
return new ProxyCallMethodData(proxyInfo.proxyMethod, proxyInfo.encryptedOps, proxyInfo.salt, proxyInfo.encryptedIndex, proxyInfo.index); return new ProxyCallMethodData(proxyInfo.proxyMethod, proxyInfo.encryptedOps, proxyInfo.salt, proxyInfo.encryptedIndex, proxyInfo.index);
} }
public void Done() public override void Done()
{ {
if (_done) if (_done)
{ {
@ -297,37 +290,4 @@ namespace Obfuz.ObfusPasses.CallObfus
} }
} }
} }
public class CallProxyAllocator
{
private readonly EncryptionScopeProvider _encryptionScopeProvider;
private GroupByModuleEntityManager _moduleEntityManager;
private readonly CallObfuscationSettingsFacade _settings;
public CallProxyAllocator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager, CallObfuscationSettingsFacade settings)
{
_encryptionScopeProvider = encryptionScopeProvider;
_moduleEntityManager = moduleEntityManager;
_settings = settings;
}
private ModuleCallProxyAllocator GetModuleAllocator(ModuleDef mod)
{
return _moduleEntityManager.GetEntity<ModuleCallProxyAllocator>(mod, () => new ModuleCallProxyAllocator(_encryptionScopeProvider, _settings));
}
public ProxyCallMethodData Allocate(ModuleDef mod, IMethod method, bool callVir)
{
ModuleCallProxyAllocator allocator = GetModuleAllocator(mod);
return allocator.Allocate(method, callVir);
}
public void Done()
{
foreach (var allocator in _moduleEntityManager.GetEntities<ModuleCallProxyAllocator>())
{
allocator.Done();
}
}
}
} }

View File

@ -0,0 +1,72 @@
// Copyright 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.
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
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<ModuleDispatchProxyAllocator>();
}
public override bool Obfuscate(MethodDef callerMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions)
{
ModuleDispatchProxyAllocator proxyCallAllocator = _moduleEntityManager.GetEntity<ModuleDispatchProxyAllocator>(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<ConstFieldAllocator>();
FieldDef cacheField = constFieldAllocator.Allocate(proxyCallMethodData.index);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, proxyCallMethodData.proxyMethod));
return true;
}
}
}

View File

@ -1,29 +1,39 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
namespace Obfuz.ObfusPasses.CallObfus namespace Obfuz.ObfusPasses.CallObfus
{ {
public struct ObfuscationCachePolicy
{
public bool cacheInLoop;
public bool cacheNotInLoop;
}
public interface IObfuscationPolicy public interface IObfuscationPolicy
{ {
bool NeedObfuscateCallInMethod(MethodDef method); bool NeedObfuscateCallInMethod(MethodDef method);
ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method); bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir);
bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop);
} }
public abstract class ObfuscationPolicyBase : IObfuscationPolicy public abstract class ObfuscationPolicyBase : IObfuscationPolicy
{ {
public abstract bool NeedObfuscateCallInMethod(MethodDef method); public abstract bool NeedObfuscateCallInMethod(MethodDef method);
public abstract ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method); public abstract bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir);
public abstract bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop);
} }
} }

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using System.Collections.Generic; using System.Collections.Generic;
@ -6,14 +26,15 @@ namespace Obfuz.ObfusPasses.CallObfus
{ {
public interface IObfuscator public interface IObfuscator
{ {
void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List<Instruction> obfuscatedInstructions); bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
void Done(); void Done();
} }
public abstract class ObfuscatorBase : IObfuscator public abstract class ObfuscatorBase : IObfuscator
{ {
public abstract void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List<Instruction> obfuscatedInstructions); public abstract bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
public abstract void Done(); public abstract void Done();
} }
} }

View File

@ -0,0 +1,50 @@
// Copyright 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.
using dnlib.DotNet;
using Obfuz.Utils;
using System;
namespace Obfuz.ObfusPasses.CallObfus
{
class MethodKey : IEquatable<MethodKey>
{
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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1193647b317b56f4b83aa080d0a17f7a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,145 @@
// Copyright 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.
using dnlib.DotNet;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.CallObfus
{
class SpecialWhiteListMethodCalculator
{
private readonly RuntimeType _targetRuntime;
private readonly bool _obfuscateCallToMethodInMscorlib;
private readonly CachedDictionary<IMethod, bool> _specialWhiteListMethodCache;
public SpecialWhiteListMethodCalculator(RuntimeType targetRuntime, bool obfuscateCallToMethodInMscorlib)
{
_targetRuntime = targetRuntime;
_obfuscateCallToMethodInMscorlib = obfuscateCallToMethodInMscorlib;
_specialWhiteListMethodCache = new CachedDictionary<IMethod, bool>(MethodEqualityComparer.CompareDeclaringTypes, this.ComputeIsInWhiteList);
}
public bool IsInWhiteList(IMethod calledMethod)
{
return _specialWhiteListMethodCache.GetValue(calledMethod);
}
private static readonly HashSet<string> _specialTypeFullNames = new HashSet<string>
{
"System.Enum",
"System.Delegate",
"System.MulticastDelegate",
"Obfuz.EncryptionService`1",
};
private static readonly HashSet<string> _specialMethodNames = new HashSet<string>
{
"GetEnumerator", // List<T>.Enumerator.GetEnumerator()
".ctor", // constructor
};
private static readonly HashSet<string> _specialMethodFullNames = new HashSet<string>
{
"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 (_targetRuntime == RuntimeType.Mono)
{
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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 904e80c4b98911c40b6a9173ca24f3ee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Editor; using Obfuz.Editor;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Conf; using Obfuz.Conf;
using Obfuz.Utils; using Obfuz.Utils;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Emit; using Obfuz.Emit;
@ -23,7 +43,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
{ {
var ctx = ObfuscationPassContext.Current; var ctx = ObfuscationPassContext.Current;
_dataObfuscatorPolicy = new ConfigurableEncryptPolicy(ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles); _dataObfuscatorPolicy = new ConfigurableEncryptPolicy(ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles);
_dataObfuscator = new DefaultConstEncryptor(ctx.encryptionScopeProvider, ctx.rvaDataAllocator, ctx.constFieldAllocator, ctx.moduleEntityManager, _settings); _dataObfuscator = new DefaultConstEncryptor(ctx.moduleEntityManager, _settings);
} }
public override void Stop() public override void Stop()
@ -123,6 +143,9 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
{ {
// don't need cache for byte array obfuscation // don't need cache for byte array obfuscation
needCache = false; needCache = false;
// Drop ldtoken RuntimeFieldHandle; DecryptInitializeArray now loads from RvaDataAllocator byte[].
prevInst.OpCode = OpCodes.Nop;
prevInst.Operand = null;
_dataObfuscator.ObfuscateBytes(method, needCache, ravFieldDef, data, outputInstructions); _dataObfuscator.ObfuscateBytes(method, needCache, ravFieldDef, data, outputInstructions);
return true; return true;
} }

View File

@ -1,28 +1,42 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using NUnit.Framework;
using Obfuz.Data; using Obfuz.Data;
using Obfuz.Emit; using Obfuz.Emit;
using Obfuz.Settings; using Obfuz.Settings;
using Obfuz.Utils; using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using UnityEngine.Assertions;
namespace Obfuz.ObfusPasses.ConstEncrypt namespace Obfuz.ObfusPasses.ConstEncrypt
{ {
public class DefaultConstEncryptor : IConstEncryptor public class DefaultConstEncryptor : IConstEncryptor
{ {
private readonly EncryptionScopeProvider _encryptionScopeProvider;
private readonly RvaDataAllocator _rvaDataAllocator;
private readonly ConstFieldAllocator _constFieldAllocator;
private readonly GroupByModuleEntityManager _moduleEntityManager; private readonly GroupByModuleEntityManager _moduleEntityManager;
private readonly ConstEncryptionSettingsFacade _settings; private readonly ConstEncryptionSettingsFacade _settings;
public DefaultConstEncryptor(EncryptionScopeProvider encryptionScopeProvider, RvaDataAllocator rvaDataAllocator, ConstFieldAllocator constFieldAllocator, GroupByModuleEntityManager moduleEntityManager, ConstEncryptionSettingsFacade settings) public DefaultConstEncryptor(GroupByModuleEntityManager moduleEntityManager, ConstEncryptionSettingsFacade settings)
{ {
_encryptionScopeProvider = encryptionScopeProvider;
_rvaDataAllocator = rvaDataAllocator;
_constFieldAllocator = constFieldAllocator;
_moduleEntityManager = moduleEntityManager; _moduleEntityManager = moduleEntityManager;
_settings = settings; _settings = settings;
} }
@ -44,20 +58,23 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
private DefaultMetadataImporter GetModuleMetadataImporter(MethodDef method) private DefaultMetadataImporter GetModuleMetadataImporter(MethodDef method)
{ {
return _moduleEntityManager.GetDefaultModuleMetadataImporter(method.Module, _encryptionScopeProvider); return _moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module);
} }
public void ObfuscateInt(MethodDef method, bool needCacheValue, int value, List<Instruction> obfuscatedInstructions) public void ObfuscateInt(MethodDef method, bool needCacheValue, int value, List<Instruction> obfuscatedInstructions)
{ {
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(method.Module); EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode()); IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
ModuleConstFieldAllocator moduleConstFieldAllocator = _constFieldAllocator.GetModuleAllocator(method.Module); ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module);
RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity<RvaDataAllocator>(method.Module);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
switch (random.NextInt(5)) switch (random.NextInt(5))
{ {
case 0: case 0:
{ {
// = c = encrypted static field // = c = encrypted static field
FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value); FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
break; break;
} }
@ -67,7 +84,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
int a = random.NextInt(); int a = random.NextInt();
int b = value - a; int b = value - a;
float constProbability = 0.5f; float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, moduleConstFieldAllocator, obfuscatedInstructions); ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Add)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Add));
break; break;
} }
@ -78,7 +95,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
int ra = MathUtil.ModInverse32(a); int ra = MathUtil.ModInverse32(a);
int b = ra * value; int b = ra * value;
float constProbability = 0.5f; float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, moduleConstFieldAllocator, obfuscatedInstructions); ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Mul)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Mul));
break; break;
} }
@ -88,7 +105,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
int a = random.NextInt(); int a = random.NextInt();
int b = a ^ value; int b = a ^ value;
float constProbability = 0.5f; float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, moduleConstFieldAllocator, obfuscatedInstructions); ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Xor)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Xor));
break; break;
} }
@ -96,16 +113,14 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
{ {
if (needCacheValue) if (needCacheValue)
{ {
FieldDef cacheField = moduleConstFieldAllocator.Allocate(value); FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
return; return;
} }
int ops = GenerateEncryptionOperations(encryptionScope, random); int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random); int salt = GenerateSalt(random);
int encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); int encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue); RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
@ -120,16 +135,18 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
public void ObfuscateLong(MethodDef method, bool needCacheValue, long value, List<Instruction> obfuscatedInstructions) public void ObfuscateLong(MethodDef method, bool needCacheValue, long value, List<Instruction> obfuscatedInstructions)
{ {
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(method.Module); EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode()); IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
ModuleConstFieldAllocator moduleConstFieldAllocator = _constFieldAllocator.GetModuleAllocator(method.Module); ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module);
RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity<RvaDataAllocator>(method.Module);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
switch (random.NextInt(5)) switch (random.NextInt(5))
{ {
case 0: case 0:
{ {
// c = encrypted static field // c = encrypted static field
FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value); FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
break; break;
} }
@ -139,7 +156,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
long a = random.NextLong(); long a = random.NextLong();
long b = value - a; long b = value - a;
float constProbability = 0.5f; float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, moduleConstFieldAllocator, obfuscatedInstructions); ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Add)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Add));
break; break;
} }
@ -150,7 +167,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
long ra = MathUtil.ModInverse64(a); long ra = MathUtil.ModInverse64(a);
long b = ra * value; long b = ra * value;
float constProbability = 0.5f; float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, moduleConstFieldAllocator, obfuscatedInstructions); ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Mul)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Mul));
break; break;
} }
@ -160,7 +177,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
long a = random.NextLong(); long a = random.NextLong();
long b = a ^ value; long b = a ^ value;
float constProbability = 0.5f; float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, moduleConstFieldAllocator, obfuscatedInstructions); ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Xor)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Xor));
break; break;
} }
@ -168,7 +185,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
{ {
if (needCacheValue) if (needCacheValue)
{ {
FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value); FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
return; return;
} }
@ -176,9 +193,8 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
int ops = GenerateEncryptionOperations(encryptionScope, random); int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random); int salt = GenerateSalt(random);
long encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); long encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue); RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
@ -193,21 +209,25 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
public void ObfuscateFloat(MethodDef method, bool needCacheValue, float value, List<Instruction> obfuscatedInstructions) public void ObfuscateFloat(MethodDef method, bool needCacheValue, float value, List<Instruction> obfuscatedInstructions)
{ {
EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module);
RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity<RvaDataAllocator>(method.Module);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
if (needCacheValue) if (needCacheValue)
{ {
FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value); FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
return; return;
} }
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
int ops = GenerateEncryptionOperations(encryptionScope, random); int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random); int salt = GenerateSalt(random);
float encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); float encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue); RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
@ -217,21 +237,25 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
public void ObfuscateDouble(MethodDef method, bool needCacheValue, double value, List<Instruction> obfuscatedInstructions) public void ObfuscateDouble(MethodDef method, bool needCacheValue, double value, List<Instruction> obfuscatedInstructions)
{ {
EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module);
RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity<RvaDataAllocator>(method.Module);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
if (needCacheValue) if (needCacheValue)
{ {
FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value); FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
return; return;
} }
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
int ops = GenerateEncryptionOperations(encryptionScope, random); int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random); int salt = GenerateSalt(random);
double encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); double encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue); RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
@ -242,15 +266,15 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
class EncryptedRvaDataInfo class EncryptedRvaDataInfo
{ {
public readonly FieldDef fieldDef; public readonly RvaData rvaData;
public readonly byte[] originalBytes; public readonly byte[] originalBytes;
public readonly byte[] encryptedBytes; public readonly byte[] encryptedBytes;
public readonly int opts; public readonly int opts;
public readonly int salt; public readonly int salt;
public EncryptedRvaDataInfo(FieldDef fieldDef, byte[] originalBytes, byte[] encryptedBytes, int opts, int salt) public EncryptedRvaDataInfo(RvaData rvaData, byte[] originalBytes, byte[] encryptedBytes, int opts, int salt)
{ {
this.fieldDef = fieldDef; this.rvaData = rvaData;
this.originalBytes = originalBytes; this.originalBytes = originalBytes;
this.encryptedBytes = encryptedBytes; this.encryptedBytes = encryptedBytes;
this.opts = opts; this.opts = opts;
@ -264,7 +288,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
{ {
if (!_encryptedRvaFields.TryGetValue(fieldDef, out var encryptedRvaData)) if (!_encryptedRvaFields.TryGetValue(fieldDef, out var encryptedRvaData))
{ {
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(fieldDef.Module); EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(fieldDef.Module);
IRandom random = CreateRandomForValue(encryptionScope, FieldEqualityComparer.CompareDeclaringTypes.GetHashCode(fieldDef)); IRandom random = CreateRandomForValue(encryptionScope, FieldEqualityComparer.CompareDeclaringTypes.GetHashCode(fieldDef));
int ops = GenerateEncryptionOperations(encryptionScope, random); int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random); int salt = GenerateSalt(random);
@ -272,12 +296,15 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
byte[] encryptedBytes = (byte[])originalBytes.Clone(); byte[] encryptedBytes = (byte[])originalBytes.Clone();
encryptionScope.encryptor.EncryptBlock(encryptedBytes, ops, salt); encryptionScope.encryptor.EncryptBlock(encryptedBytes, ops, salt);
Assert.AreNotEqual(originalBytes, encryptedBytes, "Original bytes should not be the same as encrypted bytes."); Assert.AreNotEqual(originalBytes, encryptedBytes, "Original bytes should not be the same as encrypted bytes.");
encryptedRvaData = new EncryptedRvaDataInfo(fieldDef, originalBytes, encryptedBytes, ops, salt); RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity<RvaDataAllocator>(fieldDef.Module);
RvaData rvaData = rvaDataAllocator.Allocate(encryptedBytes);
encryptedRvaData = new EncryptedRvaDataInfo(rvaData, originalBytes, encryptedBytes, ops, salt);
_encryptedRvaFields.Add(fieldDef, encryptedRvaData); _encryptedRvaFields.Add(fieldDef, encryptedRvaData);
// Keep ciphertext in the original RVA field so plaintext is not shipped; runtime loads via RvaDataAllocator.
fieldDef.InitialValue = encryptedBytes; fieldDef.InitialValue = encryptedBytes;
byte[] decryptedBytes = (byte[])encryptedBytes.Clone(); byte[] decryptedBytes = (byte[])encryptedBytes.Clone();
encryptionScope.encryptor.DecryptBlock(decryptedBytes, ops, salt); encryptionScope.encryptor.DecryptBlock(decryptedBytes, ops, salt);
Assert.AreEqual(originalBytes, decryptedBytes, "Decrypted bytes should match the original bytes after encryption and decryption."); AssertUtil.AreArrayEqual(originalBytes, decryptedBytes, "Decrypted bytes should match the original bytes after encryption and decryption.");
} }
return encryptedRvaData; return encryptedRvaData;
} }
@ -289,6 +316,8 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
Assert.AreEqual(value.Length, encryptedData.encryptedBytes.Length); Assert.AreEqual(value.Length, encryptedData.encryptedBytes.Length);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method); DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, encryptedData.rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.rvaData.offset));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.encryptedBytes.Length)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.encryptedBytes.Length));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.opts)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.opts));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.salt)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.salt));
@ -297,23 +326,26 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
public void ObfuscateString(MethodDef method, bool needCacheValue, string value, List<Instruction> obfuscatedInstructions) public void ObfuscateString(MethodDef method, bool needCacheValue, string value, List<Instruction> obfuscatedInstructions)
{ {
EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
ConstFieldAllocator constFieldAllocator = _moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module);
RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity<RvaDataAllocator>(method.Module);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
if (needCacheValue) if (needCacheValue)
{ {
FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value); FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
return; return;
} }
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(method.Module);
IRandom random = CreateRandomForValue(encryptionScope, value.GetHashCode());
int ops = GenerateEncryptionOperations(encryptionScope, random); int ops = GenerateEncryptionOperations(encryptionScope, random);
int salt = GenerateSalt(random); int salt = GenerateSalt(random);
int stringByteLength = Encoding.UTF8.GetByteCount(value); int stringByteLength = Encoding.UTF8.GetByteCount(value);
byte[] encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); byte[] encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
Assert.AreEqual(stringByteLength, encryptedValue.Length); Assert.AreEqual(stringByteLength, encryptedValue.Length);
RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue); RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); 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. // should use stringByteLength, can't use rvaData.size, because rvaData.size is align to 4, it's not the actual length.

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
namespace Obfuz.ObfusPasses.ConstEncrypt namespace Obfuz.ObfusPasses.ConstEncrypt

View File

@ -1,6 +1,27 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Conf; using Obfuz.Conf;
using Obfuz.Settings; using Obfuz.Settings;
using Obfuz.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Xml; using System.Xml;
@ -97,17 +118,12 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
} }
} }
private ObfuscationLevel ParseObfuscationLevel(string str)
{
return (ObfuscationLevel)Enum.Parse(typeof(ObfuscationLevel), str);
}
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
{ {
var rule = new ObfuscationRule(); var rule = new ObfuscationRule();
if (ele.HasAttribute("obfuscationLevel")) if (ele.HasAttribute("obfuscationLevel"))
{ {
rule.obfuscationLevel = ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
} }
return rule; return rule;
} }

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Data; using Obfuz.Data;
using Obfuz.Emit; using Obfuz.Emit;
@ -13,7 +33,7 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
public IRandom localRandom; public IRandom localRandom;
public EncryptionScopeInfo encryptionScope; public EncryptionScopeInfo encryptionScope;
public DefaultMetadataImporter importer; public DefaultMetadataImporter importer;
public ModuleConstFieldAllocator constFieldAllocator; public ConstFieldAllocator constFieldAllocator;
public int minInstructionCountOfBasicBlockToObfuscate; public int minInstructionCountOfBasicBlockToObfuscate;
public IRandom CreateRandom() public IRandom CreateRandom()
@ -60,7 +80,8 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
//Debug.Log($"Obfuscating method: {method.FullName} with EvalStackObfusPass"); //Debug.Log($"Obfuscating method: {method.FullName} with EvalStackObfusPass");
ObfuscationPassContext ctx = ObfuscationPassContext.Current; ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var encryptionScope = ctx.encryptionScopeProvider.GetScope(method.Module); GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager;
var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method); var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method);
var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)); var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method));
var obfusMethodCtx = new ObfusMethodContext var obfusMethodCtx = new ObfusMethodContext
@ -68,9 +89,9 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
method = method, method = method,
localVariableAllocator = new LocalVariableAllocator(method), localVariableAllocator = new LocalVariableAllocator(method),
encryptionScope = encryptionScope, encryptionScope = encryptionScope,
constFieldAllocator = ctx.constFieldAllocator.GetModuleAllocator(method.Module), constFieldAllocator = moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module),
localRandom = localRandom, localRandom = localRandom,
importer = ctx.moduleEntityManager.GetDefaultModuleMetadataImporter(method.Module, ctx.encryptionScopeProvider), importer = moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module),
minInstructionCountOfBasicBlockToObfuscate = _settings.minInstructionCountOfBasicBlockToObfuscate, minInstructionCountOfBasicBlockToObfuscate = _settings.minInstructionCountOfBasicBlockToObfuscate,
}; };
_obfuscator.Obfuscate(method, obfusMethodCtx); _obfuscator.Obfuscate(method, obfusMethodCtx);

View File

@ -1,5 +1,24 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using UnityEngine;
namespace Obfuz.ObfusPasses.ControlFlowObfus namespace Obfuz.ObfusPasses.ControlFlowObfus
{ {
@ -11,7 +30,7 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
var mcfc = new MethodControlFlowCalculator(method, ctx.CreateRandom(), ctx.constFieldAllocator, ctx.minInstructionCountOfBasicBlockToObfuscate); var mcfc = new MethodControlFlowCalculator(method, ctx.CreateRandom(), ctx.constFieldAllocator, ctx.minInstructionCountOfBasicBlockToObfuscate);
if (!mcfc.TryObfus()) if (!mcfc.TryObfus())
{ {
Debug.LogWarning($"not obfuscate method: {method.FullName}"); //Debug.LogWarning($"not obfuscate method: {method.FullName}");
return false; return false;
} }
return true; return true;

View File

@ -1,5 +1,24 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Emit;
namespace Obfuz.ObfusPasses.ControlFlowObfus namespace Obfuz.ObfusPasses.ControlFlowObfus
{ {

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Data; using Obfuz.Data;
@ -6,7 +26,6 @@ using Obfuz.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.ConstrainedExecution;
using UnityEngine; using UnityEngine;
using UnityEngine.Assertions; using UnityEngine.Assertions;
@ -35,15 +54,16 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
private TypeSig GetLocalTypeSig(ICorLibTypes corLibTypes, EvalDataTypeWithSig type) private TypeSig GetLocalTypeSig(ICorLibTypes corLibTypes, EvalDataTypeWithSig type)
{ {
TypeSig typeSig = type.typeSig;
switch (type.type) switch (type.type)
{ {
case EvalDataType.Int32: return corLibTypes.Int32; case EvalDataType.Int32: return corLibTypes.Int32;
case EvalDataType.Int64: return corLibTypes.Int64; case EvalDataType.Int64: return corLibTypes.Int64;
case EvalDataType.Float: return corLibTypes.Single; case EvalDataType.Float: return corLibTypes.Single;
case EvalDataType.Double: return corLibTypes.Double; case EvalDataType.Double: return corLibTypes.Double;
case EvalDataType.I: return corLibTypes.IntPtr; case EvalDataType.I: return typeSig ?? corLibTypes.IntPtr;
case EvalDataType.Ref: Assert.IsNotNull(type.typeSig); return type.typeSig; case EvalDataType.Ref: return typeSig == null || MetaUtil.IsValueType(typeSig) ? corLibTypes.Object : typeSig;
case EvalDataType.ValueType: Assert.IsNotNull(type.typeSig); return type.typeSig; case EvalDataType.ValueType: Assert.IsNotNull(typeSig); return typeSig;
case EvalDataType.Token: throw new System.NotSupportedException("Token type is not supported in BasicBlockInputOutputArguments"); case EvalDataType.Token: throw new System.NotSupportedException("Token type is not supported in BasicBlockInputOutputArguments");
default: throw new System.NotSupportedException("not supported EvalDataType"); default: throw new System.NotSupportedException("not supported EvalDataType");
} }
@ -155,11 +175,11 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
private readonly MethodDef _method; private readonly MethodDef _method;
private readonly IRandom _random; private readonly IRandom _random;
private readonly ModuleConstFieldAllocator _constFieldAllocator; private readonly ConstFieldAllocator _constFieldAllocator;
private readonly int _minInstructionCountOfBasicBlockToObfuscate; private readonly int _minInstructionCountOfBasicBlockToObfuscate;
private readonly BasicBlockInfo _bbHead; private readonly BasicBlockInfo _bbHead;
public MethodControlFlowCalculator(MethodDef method, IRandom random, ModuleConstFieldAllocator constFieldAllocator, int minInstructionCountOfBasicBlockToObfuscate) public MethodControlFlowCalculator(MethodDef method, IRandom random, ConstFieldAllocator constFieldAllocator, int minInstructionCountOfBasicBlockToObfuscate)
{ {
_method = method; _method = method;
_random = random; _random = random;
@ -331,7 +351,8 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
group.basicBlocks.Insert(group.basicBlocks.IndexOf(to), saveLocalBasicBlock); group.basicBlocks.Insert(group.basicBlocks.IndexOf(to), saveLocalBasicBlock);
group.switchMachineCases.Add(new SwitchMachineCase { index = -1, prepareBlock = saveLocalBasicBlock, targetBlock = to }); 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.Ldsfld, (FieldDef)null));
saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Br, group.switchMachineInst)); saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Stloc, GlobalSwitchIndexLocal));
saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Br, group.switchMachineEntryInst));
return saveLocalBasicBlock; return saveLocalBasicBlock;
@ -362,13 +383,40 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
InsertSwitchMachineBasicBlockForGroup(rootGroup, inst2bb); InsertSwitchMachineBasicBlockForGroup(rootGroup, inst2bb);
} }
//private void ShuffleBasicBlocks0(List<BasicBlockInfo> bbs) private void ShuffleBasicBlocks0(List<BasicBlockInfo> bbs)
//{ {
// int n = bbs.Count; if (bbs.Count <= 2)
// if (n <= 1) {
// { return;
// return; }
// }
var subBlocksExcludeFirstLast = bbs.GetRange(1, bbs.Count - 2);
var blocksInputArgsCountZero = new List<BasicBlockInfo>();
var blocksInputArgsCountNonZero = new List<BasicBlockInfo>();
foreach (var bb in subBlocksExcludeFirstLast)
{
if (bb.inputArgs.locals.Count == 0)
{
blocksInputArgsCountZero.Add(bb);
}
else
{
blocksInputArgsCountNonZero.Add(bb);
}
}
RandomUtil.ShuffleList(blocksInputArgsCountZero, _random);
int index = 1;
foreach (var bb in blocksInputArgsCountZero)
{
bbs[index++] = bb;
}
foreach (var bb in blocksInputArgsCountNonZero)
{
bbs[index++] = bb;
}
Assert.AreEqual(bbs.Count - 1, index, "Shuffled basic blocks count should be the same as original count minus first and last blocks");
//var firstSection = new List<BasicBlockInfo>() { bbs[0] }; //var firstSection = new List<BasicBlockInfo>() { bbs[0] };
//var sectionsExcludeFirstLast = new List<List<BasicBlockInfo>>(); //var sectionsExcludeFirstLast = new List<List<BasicBlockInfo>>();
@ -401,30 +449,45 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
//bbs.AddRange(sectionsExcludeFirstLast.SelectMany(section => section)); //bbs.AddRange(sectionsExcludeFirstLast.SelectMany(section => section));
//bbs.AddRange(lastSection); //bbs.AddRange(lastSection);
//Assert.AreEqual(n, bbs.Count, "Shuffled basic blocks count should be the same as original count"); //Assert.AreEqual(n, bbs.Count, "Shuffled basic blocks count should be the same as original count");
//} }
private void ShuffleBasicBlocks(List<BasicBlockInfo> bbs) private void ShuffleBasicBlocks(List<BasicBlockInfo> bbs)
{ {
// TODO // TODO
//int n = bbs.Count; int n = bbs.Count;
//BasicBlockInfo groupPrev = bbs[0].prev; BasicBlockInfo groupPrev = bbs[0].prev;
//BasicBlockInfo groupNext = bbs[n - 1].next; BasicBlockInfo groupNext = bbs[n - 1].next;
////RandomUtil.ShuffleList(bbs, _random); //RandomUtil.ShuffleList(bbs, _random);
//ShuffleBasicBlocks0(bbs); ShuffleBasicBlocks0(bbs);
//BasicBlockInfo prev = groupPrev; BasicBlockInfo prev = groupPrev;
//for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
//{ {
// BasicBlockInfo cur = bbs[i]; BasicBlockInfo cur = bbs[i];
// cur.prev = prev; cur.prev = prev;
// prev.next = cur; prev.next = cur;
// prev = cur; prev = cur;
//} }
//prev.next = groupNext; prev.next = groupNext;
//if (groupNext != null) if (groupNext != null)
//{ {
// groupNext.prev = prev; groupNext.prev = prev;
//} }
}
private Local _globalSwitchIndexLocal;
Local GlobalSwitchIndexLocal
{
get
{
if (_globalSwitchIndexLocal == null)
{
_globalSwitchIndexLocal = new Local(_method.Module.CorLibTypes.Int32);
_method.Body.Variables.Add(_globalSwitchIndexLocal);
}
return _globalSwitchIndexLocal;
}
} }
private void InsertSwitchMachineBasicBlockForGroup(BlockGroup group, Dictionary<Instruction, BasicBlockInfo> inst2bb) private void InsertSwitchMachineBasicBlockForGroup(BlockGroup group, Dictionary<Instruction, BasicBlockInfo> inst2bb)
@ -450,6 +513,8 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
var instructions = new List<Instruction>() var instructions = new List<Instruction>()
{ {
Instruction.Create(OpCodes.Ldsfld, (FieldDef)null), Instruction.Create(OpCodes.Ldsfld, (FieldDef)null),
Instruction.Create(OpCodes.Stloc, GlobalSwitchIndexLocal),
group.switchMachineEntryInst,
group.switchMachineInst, group.switchMachineInst,
Instruction.Create(OpCodes.Br, firstCase.targetBlock.FirstInstruction), Instruction.Create(OpCodes.Br, firstCase.targetBlock.FirstInstruction),
}; };
@ -481,7 +546,7 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
switchMachineCase.index = i; switchMachineCase.index = i;
List<Instruction> prepareBlockInstructions = switchMachineCase.prepareBlock.instructions; List<Instruction> prepareBlockInstructions = switchMachineCase.prepareBlock.instructions;
Instruction setBranchIndexInst = prepareBlockInstructions[prepareBlockInstructions.Count - 2]; Instruction setBranchIndexInst = prepareBlockInstructions[prepareBlockInstructions.Count - 3];
Assert.AreEqual(setBranchIndexInst.OpCode, OpCodes.Ldsfld, "first instruction of prepareBlock should be Ldsfld"); Assert.AreEqual(setBranchIndexInst.OpCode, OpCodes.Ldsfld, "first instruction of prepareBlock should be Ldsfld");
//setBranchIndexInst.Operand = i; //setBranchIndexInst.Operand = i;
var indexField = _constFieldAllocator.Allocate(i); var indexField = _constFieldAllocator.Allocate(i);
@ -490,9 +555,10 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
} }
// after shuffle // after shuffle
Assert.IsTrue(instructions.Count == 3 || instructions.Count == 4, "Switch machine basic block should contain 3 or 4 instructions"); //Assert.IsTrue(instructions.Count == 4 || instructions.Count == 5, "Switch machine basic block should contain 4 or 5 instructions");
Assert.AreEqual(Code.Ldsfld, instructions[instructions.Count - 3].OpCode.Code, "First instruction should be Ldsfld"); Instruction loadFirstIndex = instructions[instructions.Count - 5];
instructions[instructions.Count - 3].Operand = _constFieldAllocator.Allocate(firstCase.index); Assert.AreEqual(Code.Ldsfld, loadFirstIndex.OpCode.Code, "First instruction should be Ldsfld");
loadFirstIndex.Operand = _constFieldAllocator.Allocate(firstCase.index);
} }
} }
@ -554,6 +620,7 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
public List<BasicBlockInfo> basicBlocks; public List<BasicBlockInfo> basicBlocks;
public Instruction switchMachineEntryInst;
public Instruction switchMachineInst; public Instruction switchMachineInst;
public List<SwitchMachineCase> switchMachineCases; public List<SwitchMachineCase> switchMachineCases;
@ -664,7 +731,7 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
this.subGroups = finalGroupList; this.subGroups = finalGroupList;
} }
public void ComputeBasicBlocks(Dictionary<Instruction, BasicBlockInfo> inst2bb) public void ComputeBasicBlocks(Dictionary<Instruction, BasicBlockInfo> inst2bb, Func<Local> switchIndexLocalGetter)
{ {
if (subGroups == null || subGroups.Count == 0) if (subGroups == null || subGroups.Count == 0)
{ {
@ -685,13 +752,14 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
basicBlocks.Add(block); basicBlocks.Add(block);
} }
} }
switchMachineEntryInst = Instruction.Create(OpCodes.Ldloc, switchIndexLocalGetter());
switchMachineInst = Instruction.Create(OpCodes.Switch, new List<Instruction>()); switchMachineInst = Instruction.Create(OpCodes.Switch, new List<Instruction>());
switchMachineCases = new List<SwitchMachineCase>(); switchMachineCases = new List<SwitchMachineCase>();
return; return;
} }
foreach (var subGroup in subGroups) foreach (var subGroup in subGroups)
{ {
subGroup.ComputeBasicBlocks(inst2bb); subGroup.ComputeBasicBlocks(inst2bb, switchIndexLocalGetter);
} }
} }
} }
@ -726,13 +794,13 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
private class ExceptionHandlerWithFilterGroup : BlockGroup private class ExceptionHandlerWithFilterGroup : BlockGroup
{ {
public readonly ExceptionHandler exceptionHandler; public readonly ExceptionHandler exceptionHandler;
//public readonly ExceptionFilterGroup filterGroup; public readonly ExceptionFilterGroup filterGroup;
//public readonly ExceptionHandlerGroup handlerGroup; public readonly ExceptionHandlerGroup handlerGroup;
public ExceptionHandlerWithFilterGroup(ExceptionHandler exceptionHandler, List<Instruction> filterInstructions, List<Instruction> handlerInstructions, List<Instruction> allInstructions, Dictionary<Instruction, BlockGroup> inst2group) : base(allInstructions, inst2group) public ExceptionHandlerWithFilterGroup(ExceptionHandler exceptionHandler, ExceptionFilterGroup filterGroup, ExceptionHandlerGroup handlerGroup, List<Instruction> instructions, Dictionary<Instruction, BlockGroup> inst2group) : base(instructions, inst2group)
{ {
this.exceptionHandler = exceptionHandler; this.exceptionHandler = exceptionHandler;
var filterGroup = new ExceptionFilterGroup(exceptionHandler, filterInstructions, inst2group); this.filterGroup = filterGroup;
var handlerGroup = new ExceptionHandlerGroup(exceptionHandler, handlerInstructions, inst2group); this.handlerGroup = handlerGroup;
} }
} }
@ -765,7 +833,7 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
var tryBlocks = new List<TryBlockInfo>(); var tryBlocks = new List<TryBlockInfo>();
foreach (var ex in _method.Body.ExceptionHandlers) foreach (var ex in _method.Body.ExceptionHandlers)
{ {
TryBlockInfo tryBlock = tryBlocks.Find(tryBlocks => tryBlocks.tryStart == ex.TryStart && tryBlocks.tryEnd == ex.TryEnd); TryBlockInfo tryBlock = tryBlocks.Find(block => block.tryStart == ex.TryStart && block.tryEnd == ex.TryEnd);
if (tryBlock == null) if (tryBlock == null)
{ {
int startIndex = inst2Index[ex.TryStart]; int startIndex = inst2Index[ex.TryStart];
@ -785,9 +853,10 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
int filterEndIndex = ex.HandlerStart != null ? inst2Index[ex.HandlerStart] : inst2Index.Count; int filterEndIndex = ex.HandlerStart != null ? inst2Index[ex.HandlerStart] : inst2Index.Count;
int handlerStartIndex = filterEndIndex; int handlerStartIndex = filterEndIndex;
int handlerEndIndex = ex.HandlerEnd != null ? inst2Index[ex.HandlerEnd] : inst2Index.Count; int handlerEndIndex = ex.HandlerEnd != null ? inst2Index[ex.HandlerEnd] : inst2Index.Count;
var filterHandlerGroup = new ExceptionHandlerWithFilterGroup(ex,
instructions.GetRange(filterStartIndex, filterEndIndex - filterStartIndex), var filterGroup = new ExceptionFilterGroup(ex, instructions.GetRange(filterStartIndex, filterEndIndex - filterStartIndex), inst2blockGroup);
instructions.GetRange(handlerStartIndex, handlerEndIndex - handlerStartIndex), var handlerGroup = new ExceptionHandlerGroup(ex, instructions.GetRange(handlerStartIndex, handlerEndIndex - handlerStartIndex), inst2blockGroup);
var filterHandlerGroup = new ExceptionHandlerWithFilterGroup(ex, filterGroup, handlerGroup,
instructions.GetRange(filterStartIndex, handlerEndIndex - filterStartIndex), inst2blockGroup); instructions.GetRange(filterStartIndex, handlerEndIndex - filterStartIndex), inst2blockGroup);
} }
else else
@ -800,7 +869,7 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
var rootGroup = new BlockGroup(new List<Instruction>(instructions), inst2blockGroup); var rootGroup = new BlockGroup(new List<Instruction>(instructions), inst2blockGroup);
rootGroup.SplitInstructionsNotInAnySubGroupsToIndividualGroups(inst2blockGroup); rootGroup.SplitInstructionsNotInAnySubGroupsToIndividualGroups(inst2blockGroup);
rootGroup.ComputeBasicBlocks(BuildInstructionToBasicBlockInfoDic()); rootGroup.ComputeBasicBlocks(BuildInstructionToBasicBlockInfoDic(), () => GlobalSwitchIndexLocal);
return rootGroup; return rootGroup;
} }
@ -870,6 +939,10 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus
//{ //{
// return false; // return false;
//} //}
if (_method.HasGenericParameters || _method.DeclaringType.HasGenericParameters)
{
return false;
}
var evc = new EvalStackCalculator(_method); var evc = new EvalStackCalculator(_method);
BuildBasicBlockLink(evc); BuildBasicBlockLink(evc);
if (!CheckNotContainsNotSupportedEvalStackData()) if (!CheckNotContainsNotSupportedEvalStackData())

View File

@ -1,6 +1,27 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Conf; using Obfuz.Conf;
using Obfuz.Settings; using Obfuz.Settings;
using Obfuz.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Xml; using System.Xml;
@ -63,7 +84,7 @@ namespace Obfuz.ObfusPasses.EvalStackObfus
private static readonly ObfuscationRule s_default = new ObfuscationRule() private static readonly ObfuscationRule s_default = new ObfuscationRule()
{ {
obfuscationLevel = ObfuscationLevel.Basic, obfuscationLevel = ObfuscationLevel.Basic,
obfuscationPercentage = 0.5f, obfuscationPercentage = 0.05f,
}; };
private ObfuscationRule _global; private ObfuscationRule _global;
@ -91,6 +112,10 @@ namespace Obfuz.ObfusPasses.EvalStackObfus
{ {
_global.InheritParent(s_default); _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); _xmlParser.InheritParentRules(_global);
} }
@ -103,17 +128,12 @@ namespace Obfuz.ObfusPasses.EvalStackObfus
} }
} }
private ObfuscationLevel ParseObfuscationLevel(string str)
{
return (ObfuscationLevel)Enum.Parse(typeof(ObfuscationLevel), str);
}
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
{ {
var rule = new ObfuscationRule(); var rule = new ObfuscationRule();
if (ele.HasAttribute("obfuscationLevel")) if (ele.HasAttribute("obfuscationLevel"))
{ {
rule.obfuscationLevel = ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
} }
if (ele.HasAttribute("obfuscationPercentage")) if (ele.HasAttribute("obfuscationPercentage"))
{ {

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Utils; using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Data; using Obfuz.Data;
@ -16,7 +36,7 @@ namespace Obfuz.ObfusPasses.EvalStackObfus
public IRandom localRandom; public IRandom localRandom;
public EncryptionScopeInfo encryptionScope; public EncryptionScopeInfo encryptionScope;
public DefaultMetadataImporter importer; public DefaultMetadataImporter importer;
public ModuleConstFieldAllocator constFieldAllocator; public ConstFieldAllocator constFieldAllocator;
public float obfuscationPercentage; public float obfuscationPercentage;
} }
@ -74,7 +94,9 @@ namespace Obfuz.ObfusPasses.EvalStackObfus
ObfuscationPassContext ctx = ObfuscationPassContext.Current; ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var calc = new EvalStackCalculator(method); var calc = new EvalStackCalculator(method);
var encryptionScope = ctx.encryptionScopeProvider.GetScope(method.Module);
GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager;
var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method); var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method);
var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)); var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method));
var obfusMethodCtx = new ObfusMethodContext var obfusMethodCtx = new ObfusMethodContext
@ -83,9 +105,9 @@ namespace Obfuz.ObfusPasses.EvalStackObfus
evalStackCalculator = calc, evalStackCalculator = calc,
localVariableAllocator = new LocalVariableAllocator(method), localVariableAllocator = new LocalVariableAllocator(method),
encryptionScope = encryptionScope, encryptionScope = encryptionScope,
constFieldAllocator = ctx.constFieldAllocator.GetModuleAllocator(method.Module), constFieldAllocator = moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module),
localRandom = localRandom, localRandom = localRandom,
importer = ctx.moduleEntityManager.GetDefaultModuleMetadataImporter(method.Module, ctx.encryptionScopeProvider), importer = moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module),
obfuscationPercentage = ruleData.obfuscationPercentage, obfuscationPercentage = ruleData.obfuscationPercentage,
}; };
for (int i = 0; i < instructions.Count; i++) for (int i = 0; i < instructions.Count; i++)

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,6 +1,27 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Conf; using Obfuz.Conf;
using Obfuz.Settings; using Obfuz.Settings;
using Obfuz.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Xml; using System.Xml;
@ -103,17 +124,12 @@ namespace Obfuz.ObfusPasses.ExprObfus
} }
} }
private ObfuscationLevel ParseObfuscationLevel(string str)
{
return (ObfuscationLevel)Enum.Parse(typeof(ObfuscationLevel), str);
}
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
{ {
var rule = new ObfuscationRule(); var rule = new ObfuscationRule();
if (ele.HasAttribute("obfuscationLevel")) if (ele.HasAttribute("obfuscationLevel"))
{ {
rule.obfuscationLevel = ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
} }
if (ele.HasAttribute("obfuscationPercentage")) if (ele.HasAttribute("obfuscationPercentage"))
{ {

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Data; using Obfuz.Data;
@ -17,7 +37,7 @@ namespace Obfuz.ObfusPasses.ExprObfus
public IRandom localRandom; public IRandom localRandom;
public EncryptionScopeInfo encryptionScope; public EncryptionScopeInfo encryptionScope;
public DefaultMetadataImporter importer; public DefaultMetadataImporter importer;
public ModuleConstFieldAllocator constFieldAllocator; public ConstFieldAllocator constFieldAllocator;
public float obfuscationPercentage; public float obfuscationPercentage;
} }
@ -120,7 +140,9 @@ namespace Obfuz.ObfusPasses.ExprObfus
ObfuscationPassContext ctx = ObfuscationPassContext.Current; ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var calc = new EvalStackCalculator(method); var calc = new EvalStackCalculator(method);
var encryptionScope = ctx.encryptionScopeProvider.GetScope(method.Module);
GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager;
var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method); var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method);
var obfuscator = GetObfuscator(ruleData.obfuscationLevel); var obfuscator = GetObfuscator(ruleData.obfuscationLevel);
var obfusMethodCtx = new ObfusMethodContext var obfusMethodCtx = new ObfusMethodContext
@ -129,9 +151,9 @@ namespace Obfuz.ObfusPasses.ExprObfus
evalStackCalculator = calc, evalStackCalculator = calc,
localVariableAllocator = new LocalVariableAllocator(method), localVariableAllocator = new LocalVariableAllocator(method),
encryptionScope = encryptionScope, encryptionScope = encryptionScope,
constFieldAllocator = ctx.constFieldAllocator.GetModuleAllocator(method.Module), constFieldAllocator = moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module),
localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)), localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)),
importer = ctx.moduleEntityManager.GetDefaultModuleMetadataImporter(method.Module, ctx.encryptionScopeProvider), importer = moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module),
obfuscationPercentage = ruleData.obfuscationPercentage, obfuscationPercentage = ruleData.obfuscationPercentage,
}; };
for (int i = 0; i < instructions.Count; i++) for (int i = 0; i < instructions.Count; i++)

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Emit; using Obfuz.Emit;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Data; using Obfuz.Data;
using Obfuz.Emit; using Obfuz.Emit;
@ -11,7 +31,7 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
protected bool GenerateIdentityTransformForArgument(Instruction inst, EvalDataType op, List<Instruction> outputInsts, ObfusMethodContext ctx) protected bool GenerateIdentityTransformForArgument(Instruction inst, EvalDataType op, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
IRandom random = ctx.localRandom; IRandom random = ctx.localRandom;
ModuleConstFieldAllocator constFieldAllocator = ctx.constFieldAllocator; ConstFieldAllocator constFieldAllocator = ctx.constFieldAllocator;
switch (op) switch (op)
{ {
case EvalDataType.Int32: case EvalDataType.Int32:

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Emit; using Obfuz.Emit;
@ -9,7 +29,35 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
class BasicObfuscator : ObfuscatorBase class BasicObfuscator : ObfuscatorBase
{ {
private IMethod GetMethod(DefaultMetadataImporter importer, Code code, EvalDataType op1) 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) switch (code)
{ {
@ -17,10 +65,19 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{ {
switch (op1) switch (op1)
{ {
case EvalDataType.Int32: return importer.AddInt; case EvalDataType.Int32: return op2 == op1 ? importer.AddInt : null;
case EvalDataType.Int64: return importer.AddLong; case EvalDataType.Int64: return op2 == op1 ? importer.AddLong : null;
case EvalDataType.Float: return importer.AddFloat; case EvalDataType.Float: return op2 == op1 ? importer.AddFloat : null;
case EvalDataType.Double: return importer.AddDouble; 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; default: return null;
} }
} }
@ -28,10 +85,19 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{ {
switch (op1) switch (op1)
{ {
case EvalDataType.Int32: return importer.SubtractInt; case EvalDataType.Int32: return op2 == op1 ? importer.SubtractInt : null;
case EvalDataType.Int64: return importer.SubtractLong; case EvalDataType.Int64: return op2 == op1 ? importer.SubtractLong : null;
case EvalDataType.Float: return importer.SubtractFloat; case EvalDataType.Float: return op2 == op1 ? importer.SubtractFloat : null;
case EvalDataType.Double: return importer.SubtractDouble; 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; default: return null;
} }
} }
@ -39,10 +105,19 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{ {
switch (op1) switch (op1)
{ {
case EvalDataType.Int32: return importer.MultiplyInt; case EvalDataType.Int32: return op2 == op1 ? importer.MultiplyInt : null;
case EvalDataType.Int64: return importer.MultiplyLong; case EvalDataType.Int64: return op2 == op1 ? importer.MultiplyLong : null;
case EvalDataType.Float: return importer.MultiplyFloat; case EvalDataType.Float: return op2 == op1 ? importer.MultiplyFloat : null;
case EvalDataType.Double: return importer.MultiplyDouble; 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; default: return null;
} }
} }
@ -166,9 +241,10 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx) public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
IMethod opMethod = GetMethod(ctx.importer, inst.OpCode.Code, op); IMethod opMethod = GetUnaryOpMethod(ctx.importer, inst.OpCode.Code, op);
if (opMethod == null) 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; return false;
} }
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod)); outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
@ -177,14 +253,10 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx) public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
if (op1 != op2) IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2);
{
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;
}
IMethod opMethod = GetMethod(ctx.importer, inst.OpCode.Code, op1);
if (opMethod == null) 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; return false;
} }
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod)); outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
@ -193,9 +265,10 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx) public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
IMethod opMethod = GetMethod(ctx.importer, inst.OpCode.Code, op); IMethod opMethod = GetUnaryOpMethod(ctx.importer, inst.OpCode.Code, op);
if (opMethod == null) 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; return false;
} }
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod)); outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
@ -204,14 +277,10 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx) public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
if (op1 != op2) IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2);
{
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;
}
IMethod opMethod = GetMethod(ctx.importer, inst.OpCode.Code, op1);
if (opMethod == null) 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; return false;
} }
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod)); outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
@ -220,14 +289,10 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx) public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
if (op2 != EvalDataType.Int32) IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2);
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with operand type {op2}. This is a limitation of the BasicObfuscator.");
return false;
}
IMethod opMethod = GetMethod(ctx.importer, inst.OpCode.Code, op1);
if (opMethod == null) 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; return false;
} }
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod)); outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Emit; using Obfuz.Emit;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Conf; using Obfuz.Conf;
using Obfuz.Utils; using Obfuz.Utils;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Emit; using Obfuz.Emit;
@ -11,22 +31,15 @@ namespace Obfuz.ObfusPasses.FieldEncrypt
{ {
public class DefaultFieldEncryptor : FieldEncryptorBase public class DefaultFieldEncryptor : FieldEncryptorBase
{ {
private readonly EncryptionScopeProvider _encryptionScopeProvider;
private readonly GroupByModuleEntityManager _moduleEntityManager; private readonly GroupByModuleEntityManager _moduleEntityManager;
private readonly FieldEncryptionSettingsFacade _settings; private readonly FieldEncryptionSettingsFacade _settings;
public DefaultFieldEncryptor(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager, FieldEncryptionSettingsFacade settings) public DefaultFieldEncryptor(GroupByModuleEntityManager moduleEntityManager, FieldEncryptionSettingsFacade settings)
{ {
_encryptionScopeProvider = encryptionScopeProvider;
_moduleEntityManager = moduleEntityManager; _moduleEntityManager = moduleEntityManager;
_settings = settings; _settings = settings;
} }
private DefaultMetadataImporter GetMetadataImporter(MethodDef method)
{
return _moduleEntityManager.GetDefaultModuleMetadataImporter(method.Module, _encryptionScopeProvider);
}
class FieldEncryptInfo class FieldEncryptInfo
{ {
public int encryptOps; public int encryptOps;
@ -77,7 +90,7 @@ namespace Obfuz.ObfusPasses.FieldEncrypt
{ {
return info; return info;
} }
EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(field.Module); EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(field.Module);
IRandom random = CreateRandomForField(encryptionScope.localRandomCreator, field); IRandom random = CreateRandomForField(encryptionScope.localRandomCreator, field);
IEncryptor encryptor = encryptionScope.encryptor; IEncryptor encryptor = encryptionScope.encryptor;
@ -99,7 +112,7 @@ namespace Obfuz.ObfusPasses.FieldEncrypt
public override void Encrypt(MethodDef method, FieldDef field, List<Instruction> outputInstructions, Instruction currentInstruction) public override void Encrypt(MethodDef method, FieldDef field, List<Instruction> outputInstructions, Instruction currentInstruction)
{ {
DefaultMetadataImporter importer = GetMetadataImporter(method); DefaultMetadataImporter importer = _moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module);
EncryptionServiceMetadataImporter encryptionServiceMetadataImporter = importer.GetEncryptionServiceMetadataImporterOfModule(field.Module); EncryptionServiceMetadataImporter encryptionServiceMetadataImporter = importer.GetEncryptionServiceMetadataImporterOfModule(field.Module);
FieldEncryptInfo fei = GetFieldEncryptInfo(field); FieldEncryptInfo fei = GetFieldEncryptInfo(field);
if (fei.fieldType == ElementType.I4 || fei.fieldType == ElementType.U4 || fei.fieldType == ElementType.R4) if (fei.fieldType == ElementType.I4 || fei.fieldType == ElementType.U4 || fei.fieldType == ElementType.R4)
@ -154,7 +167,7 @@ namespace Obfuz.ObfusPasses.FieldEncrypt
public override void Decrypt(MethodDef method, FieldDef field, List<Instruction> outputInstructions, Instruction currentInstruction) public override void Decrypt(MethodDef method, FieldDef field, List<Instruction> outputInstructions, Instruction currentInstruction)
{ {
outputInstructions.Add(currentInstruction.Clone()); outputInstructions.Add(currentInstruction.Clone());
DefaultMetadataImporter importer = GetMetadataImporter(method); DefaultMetadataImporter importer = _moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module);
EncryptionServiceMetadataImporter encryptionServiceMetadataImporter = importer.GetEncryptionServiceMetadataImporterOfModule(field.Module); EncryptionServiceMetadataImporter encryptionServiceMetadataImporter = importer.GetEncryptionServiceMetadataImporterOfModule(field.Module);
FieldEncryptInfo fei = GetFieldEncryptInfo(field); FieldEncryptInfo fei = GetFieldEncryptInfo(field);
if (fei.fieldType == ElementType.I4 || fei.fieldType == ElementType.U4 || fei.fieldType == ElementType.R4) if (fei.fieldType == ElementType.I4 || fei.fieldType == ElementType.U4 || fei.fieldType == ElementType.R4)

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Settings; using Obfuz.Settings;
@ -24,7 +44,7 @@ namespace Obfuz.ObfusPasses.FieldEncrypt
public override void Start() public override void Start()
{ {
var ctx = ObfuscationPassContext.Current; var ctx = ObfuscationPassContext.Current;
_memoryEncryptor = new DefaultFieldEncryptor(ctx.encryptionScopeProvider, ctx.moduleEntityManager, _settings); _memoryEncryptor = new DefaultFieldEncryptor(ctx.moduleEntityManager, _settings);
_encryptionPolicy = new ConfigurableEncryptPolicy(ctx.obfuzIgnoreScopeComputeCache, ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles); _encryptionPolicy = new ConfigurableEncryptPolicy(ctx.obfuzIgnoreScopeComputeCache, ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles);
} }

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
namespace Obfuz.ObfusPasses.FieldEncrypt namespace Obfuz.ObfusPasses.FieldEncrypt

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,6 +1,27 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Editor; using Obfuz.Editor;
using Obfuz.Emit;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -89,7 +110,7 @@ namespace Obfuz.ObfusPasses.Instinct
} }
ObfuscationPassContext ctx = ObfuscationPassContext.Current; ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var importer = ctx.moduleEntityManager.GetDefaultModuleMetadataImporter(callingMethod.Module, ctx.encryptionScopeProvider); var importer = ctx.moduleEntityManager.GetEntity<DefaultMetadataImporter>(callingMethod.Module);
string methodName = methodDef.Name; string methodName = methodDef.Name;
switch (methodName) switch (methodName)

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using System.Linq; using System.Linq;

View File

@ -1,3 +1,23 @@
// Copyright 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.
namespace Obfuz.ObfusPasses namespace Obfuz.ObfusPasses
{ {
public abstract class ObfuscationPassBase : IObfuscationPass public abstract class ObfuscationPassBase : IObfuscationPass

View File

@ -1,3 +1,23 @@
// Copyright 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.
using System; using System;
namespace Obfuz.ObfusPasses namespace Obfuz.ObfusPasses
@ -16,6 +36,9 @@ namespace Obfuz.ObfusPasses
ControlFlowObfus = 0x800, ControlFlowObfus = 0x800,
EvalStackObfus = 0x1000, EvalStackObfus = 0x1000,
RemoveConstField = 0x100000,
WaterMark = 0x200000,
AllObfus = SymbolObfus | CallObfus | ExprObfus | ControlFlowObfus | EvalStackObfus, AllObfus = SymbolObfus | CallObfus | ExprObfus | ControlFlowObfus | EvalStackObfus,
AllEncrypt = ConstEncrypt | FieldEncrypt, AllEncrypt = ConstEncrypt | FieldEncrypt,

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d2c28a04d2997bc4d91a4c7693983d12
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,54 @@
// Copyright 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.
using dnlib.DotNet;
using Obfuz.Conf;
using System.Collections.Generic;
using System.Xml;
namespace Obfuz.ObfusPasses.RemoveConstField
{
public class ConfigurableRemoveConstFieldPolicy : RemoveConstFieldBase
{
class ObfuscationRule
{
}
private readonly XmlFieldRuleParser<ObfuscationRule> _configParser;
public ConfigurableRemoveConstFieldPolicy(List<string> toObfuscatedAssemblyNames, List<string> configFiles)
{
_configParser = new XmlFieldRuleParser<ObfuscationRule>(toObfuscatedAssemblyNames, ParseRule, null);
_configParser.LoadConfigs(configFiles);
}
private ObfuscationRule ParseRule(string configFile, XmlElement ele)
{
return new ObfuscationRule();
}
public override bool NeedPreserved(FieldDef field)
{
var rule = _configParser.GetFieldRule(field);
return rule != null;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e3b708559fbf755419d7daf4ddce72f2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,34 @@
// Copyright 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.
using dnlib.DotNet;
namespace Obfuz.ObfusPasses.RemoveConstField
{
public interface IRemoveConstFieldPolicy
{
bool NeedPreserved(FieldDef field);
}
public abstract class RemoveConstFieldBase : IRemoveConstFieldPolicy
{
public abstract bool NeedPreserved(FieldDef field);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5fad0b7ef9225b24cacc94f8dcaee26d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,93 @@
// Copyright 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.
using dnlib.DotNet;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Linq;
namespace Obfuz.ObfusPasses.RemoveConstField
{
public class RemoveConstFieldPass : ObfuscationPassBase
{
private RemoveConstFieldSettingsFacade _settings;
private ObfuzIgnoreScopeComputeCache _obfuzIgnoreScopeComputeCache;
private IRemoveConstFieldPolicy _removeConstFieldPolicy;
public override ObfuscationPassType Type => ObfuscationPassType.RemoveConstField;
public RemoveConstFieldPass(RemoveConstFieldSettingsFacade settings)
{
_settings = settings;
}
public override void Start()
{
var ctx = ObfuscationPassContext.Current;
_obfuzIgnoreScopeComputeCache = ctx.obfuzIgnoreScopeComputeCache;
_removeConstFieldPolicy = new ConfigurableRemoveConstFieldPolicy(ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles);
}
public override void Stop()
{
}
public override void Process()
{
var ctx = ObfuscationPassContext.Current;
var modules = ctx.modulesToObfuscate;
ConfigurablePassPolicy passPolicy = ctx.passPolicy;
foreach (ModuleDef mod in modules)
{
// ToArray to avoid modify list exception
foreach (TypeDef type in mod.GetTypes())
{
if (type.IsEnum)
{
continue;
}
foreach (FieldDef field in type.Fields.ToArray())
{
if (!field.IsLiteral)
{
continue;
}
if (!Support(passPolicy.GetFieldObfuscationPasses(field)))
{
continue;
}
if (_obfuzIgnoreScopeComputeCache.HasSelfOrDeclaringOrEnclosingOrInheritObfuzIgnoreScope(field, field.DeclaringType, ObfuzScope.Field))
{
continue;
}
if (_removeConstFieldPolicy.NeedPreserved(field))
{
continue;
}
field.DeclaringType = null;
//Debug.Log($"Remove const field {field.FullName} in type {type.FullName} in module {mod.Name}");
}
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3188de094ab4cdd47b55c2f622251cf5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
namespace Obfuz.ObfusPasses.SymbolObfus namespace Obfuz.ObfusPasses.SymbolObfus

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
namespace Obfuz.ObfusPasses.SymbolObfus namespace Obfuz.ObfusPasses.SymbolObfus

View File

@ -1,6 +1,24 @@
using System.Text; // Copyright 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.
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
{ {
public class DebugNameMaker : NameMakerBase public class DebugNameMaker : NameMakerBase
{ {

View File

@ -1,3 +1,23 @@
// Copyright 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.
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
{ {
public interface INameScope public interface INameScope

View File

@ -1,3 +1,23 @@
// Copyright 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.
using dnlib.DotNet; using dnlib.DotNet;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine.Assertions; using UnityEngine.Assertions;
@ -95,7 +115,7 @@ namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
public virtual string GetNewName(ParamDef param, string originalName) public virtual string GetNewName(ParamDef param, string originalName)
{ {
return "1"; return $"_{param.Sequence}";
} }
public string GetNewName(FieldDef fieldDef, string originalName) public string GetNewName(FieldDef fieldDef, string originalName)

View File

@ -1,3 +1,23 @@
// Copyright 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.
using System.Collections.Generic; using System.Collections.Generic;
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers

View File

@ -1,3 +1,23 @@
// Copyright 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.
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;

Some files were not shown because too many files have changed in this diff Show More