Compare commits

..

No commits in common. "main" and "v1.0.0-rc" have entirely different histories.

173 changed files with 990 additions and 8283 deletions

View File

@ -11,7 +11,6 @@
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";
@ -20,13 +19,5 @@
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

@ -10,8 +10,13 @@ using UnityEngine.Assertions;
namespace Obfuz.Data namespace Obfuz.Data
{ {
public class ConstFieldAllocator : GroupByModuleEntityBase public class ModuleConstFieldAllocator : IGroupByModuleEntity
{ {
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;
@ -52,14 +57,19 @@ namespace Obfuz.Data
private bool _done; private bool _done;
public ConstFieldAllocator() public ModuleConstFieldAllocator(EncryptionScopeProvider encryptionScopeProvider, RvaDataAllocator rvaDataAllocator, GroupByModuleEntityManager moduleEntityManager)
{ {
_encryptionScopeProvider = encryptionScopeProvider;
_rvaDataAllocator = rvaDataAllocator;
_moduleEntityManager = moduleEntityManager;
} }
public override void Init() public void Init(ModuleDef mod)
{ {
_randomCreator = EncryptionScope.localRandomCreator; _module = mod;
_encryptor = EncryptionScope.encryptor; _encryptionScope = _encryptionScopeProvider.GetScope(mod);
_randomCreator = _encryptionScope.localRandomCreator;
_encryptor = _encryptionScope.encryptor;
} }
const int maxFieldCount = 1000; const int maxFieldCount = 1000;
@ -67,37 +77,35 @@ 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 mod.CorLibTypes.Int32; return _module.CorLibTypes.Int32;
if (value is long) if (value is long)
return mod.CorLibTypes.Int64; return _module.CorLibTypes.Int64;
if (value is float) if (value is float)
return mod.CorLibTypes.Single; return _module.CorLibTypes.Single;
if (value is double) if (value is double)
return mod.CorLibTypes.Double; return _module.CorLibTypes.Double;
if (value is string) if (value is string)
return mod.CorLibTypes.String; return _module.CorLibTypes.String;
if (value is byte[]) if (value is byte[])
return new SZArraySig(mod.CorLibTypes.Byte); return new SZArraySig(_module.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(mod)) using (var scope = new DisableTypeDefFindCacheScope(_module))
{ {
ITypeDefOrRef objectTypeRef = mod.Import(typeof(object)); ITypeDefOrRef objectTypeRef = _module.Import(typeof(object));
_holderTypeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ConstFieldHolder${_holderTypeDefs.Count}", objectTypeRef); _holderTypeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ConstFieldHolder${_holderTypeDefs.Count}", objectTypeRef);
mod.Types.Add(_holderTypeDef); _module.Types.Add(_holderTypeDef);
_holderTypeDefs.Add(_holderTypeDef); _holderTypeDefs.Add(_holderTypeDef);
} }
} }
var field = new FieldDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}RVA_Value{_holderTypeDef.Fields.Count}", new FieldSig(GetTypeSigOfValue(value)), FieldAttributes.Static | FieldAttributes.Public); var field = new FieldDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}RVA_Value{_holderTypeDef.Fields.Count}", new FieldSig(GetTypeSigOfValue(value)), FieldAttributes.Static | FieldAttributes.Public | FieldAttributes.InitOnly);
field.DeclaringType = _holderTypeDef; field.DeclaringType = _holderTypeDef;
return new ConstFieldInfo return new ConstFieldInfo
{ {
@ -151,35 +159,41 @@ 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(mod.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);
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();
RvaDataAllocator rvaDataAllocator = GetEntity<RvaDataAllocator>(); DefaultMetadataImporter importer = GetModuleMetadataImporter();
// 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, EncryptionScopeInfo.MaxEncryptionLevel, false); int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, _encryptor, 4);
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(encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(_module, 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));
@ -190,7 +204,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(encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(_module, 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));
@ -201,7 +215,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(encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(_module, 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));
@ -212,7 +226,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(encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(_module, 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));
@ -223,7 +237,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(encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(_module, 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);
@ -237,7 +251,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(encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(_module, 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));
@ -253,7 +267,7 @@ namespace Obfuz.Data
ins.Add(Instruction.Create(OpCodes.Ret)); ins.Add(Instruction.Create(OpCodes.Ret));
} }
public override void Done() public void Done()
{ {
if (_done) if (_done)
{ {
@ -266,4 +280,61 @@ 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;
}
private 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

@ -4,7 +4,6 @@ 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;
@ -24,13 +23,16 @@ namespace Obfuz.Data
} }
} }
public class RvaDataAllocator : GroupByModuleEntityBase public class ModuleRvaDataAllocator : GroupByModuleEntityBase
{ {
const int maxRvaDataSize = 2 * 1024; // randomized
const int maxRvaDataSize = 0x1000;
// 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 ModuleDef _module;
const int maxTotalRvaDataFieldSizeInHybridCLR = 16 * 1024; private readonly EncryptionScopeProvider _encryptionScopeProvider;
private readonly GroupByModuleEntityManager _moduleEntityManager;
private EncryptionScopeInfo _encryptionScope;
private IRandom _random; private IRandom _random;
class RvaField class RvaField
@ -60,72 +62,64 @@ namespace Obfuz.Data
} }
} }
private class RvaTypeDefInfo private readonly List<RvaField> _rvaFields = new List<RvaField>();
{
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 readonly List<RvaTypeDefInfo> _rvaTypeDefs = new List<RvaTypeDefInfo>(); private TypeDef _rvaTypeDef;
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 RvaDataAllocator() public ModuleRvaDataAllocator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager)
{ {
_encryptionScopeProvider = encryptionScopeProvider;
_moduleEntityManager = moduleEntityManager;
} }
public override void Init() public override void Init(ModuleDef mod)
{ {
_random = EncryptionScope.localRandomCreator(HashUtil.ComputeHash(Module.Name)); _module = mod;
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
_random = _encryptionScope.localRandomCreator(HashUtil.ComputeHash(mod.Name));
} }
private (FieldDef, FieldDef) CreateDataHolderRvaField(TypeDef dataHolderType) private (FieldDef, FieldDef) CreateDataHolderRvaField(TypeDef dataHolderType)
{ {
if (_currentRvaType == null || _currentRvaType.rvaFields.Count >= maxTotalRvaDataFieldSizeInHybridCLR / maxRvaDataSize - 1) if (_rvaTypeDef == null)
{ {
using (var scope = new DisableTypeDefFindCacheScope(Module)) using (var scope = new DisableTypeDefFindCacheScope(_module))
{ {
var rvaTypeDef = new TypeDefUser($"$Obfuz$RVA${_rvaTypeDefs.Count}", Module.CorLibTypes.Object.ToTypeDefOrRef()); ITypeDefOrRef objectTypeRef = _module.Import(typeof(object));
Module.Types.Add(rvaTypeDef); _rvaTypeDef = new TypeDefUser("$Obfuz$RVA$", objectTypeRef);
_currentRvaType = new RvaTypeDefInfo(rvaTypeDef, _rvaTypeDefs.Count); _module.Types.Add(_rvaTypeDef);
_rvaTypeDefs.Add(_currentRvaType);
} }
} }
var holderField = new FieldDefUser($"$RVA_Data{_currentRvaType.rvaFields.Count}", new FieldSig(dataHolderType.ToTypeSig()), FieldAttributes.InitOnly | FieldAttributes.Static | FieldAttributes.HasFieldRVA);
holderField.DeclaringType = _currentRvaType.typeDef;
var runtimeValueField = new FieldDefUser($"$RVA_Value{_currentRvaType.rvaFields.Count}", new FieldSig(new SZArraySig(Module.CorLibTypes.Byte)), FieldAttributes.Static | FieldAttributes.Public); var holderField = new FieldDefUser($"$RVA_Data{_rvaFields.Count}", new FieldSig(dataHolderType.ToTypeSig()), FieldAttributes.InitOnly | FieldAttributes.Static | FieldAttributes.HasFieldRVA);
runtimeValueField.DeclaringType = _currentRvaType.typeDef; holderField.DeclaringType = _rvaTypeDef;
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 16 bytes size = (size + 15) & ~15; // align to 6 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;
} }
} }
@ -148,7 +142,7 @@ namespace Obfuz.Data
encryptionOps = _random.NextInt(), encryptionOps = _random.NextInt(),
salt = _random.NextInt(), salt = _random.NextInt(),
}; };
_currentRvaType.rvaFields.Add(newRvaField); _rvaFields.Add(newRvaField);
return newRvaField; return newRvaField;
} }
@ -236,11 +230,10 @@ 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;
EncryptionScopeInfo encryptionScope = this.EncryptionScope; IRandom verifyRandom = _encryptionScope.localRandomCreator(verifyIntValue);
IRandom verifyRandom = encryptionScope.localRandomCreator(verifyIntValue); int verifyOps = EncryptionUtil.GenerateEncryptionOpCodes(verifyRandom, _encryptionScope.encryptor, 4);
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));
@ -253,22 +246,24 @@ namespace Obfuz.Data
private void CreateCCtorOfRvaTypeDef() private void CreateCCtorOfRvaTypeDef()
{ {
foreach (RvaTypeDefInfo rvaTypeDef in _rvaTypeDefs) if (_rvaTypeDef == null)
{ {
ModuleDef mod = rvaTypeDef.typeDef.Module; return;
}
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.typeDef; cctorMethod.DeclaringType = _rvaTypeDef;
//_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 = this.GetDefaultModuleMetadataImporter(); DefaultMetadataImporter importer = _moduleEntityManager.GetDefaultModuleMetadataImporter(mod, _encryptionScopeProvider);
AddVerifyCodes(ins, importer); AddVerifyCodes(ins, importer);
foreach (var field in rvaTypeDef.rvaFields) foreach (var field in _rvaFields)
{ {
// ldc // ldc
// newarr // newarr
@ -292,11 +287,10 @@ 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 _rvaTypeDefs.SelectMany(t => t.rvaFields)) foreach (var field in _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)
@ -304,12 +298,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 override void Done() public void Done()
{ {
if (_done) if (_done)
{ {
@ -320,4 +314,59 @@ 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

@ -38,20 +38,13 @@ namespace Obfuz.Emit
public IList<BasicBlock> Blocks => _blocks; public IList<BasicBlock> Blocks => _blocks;
public BasicBlockCollection(MethodDef method, bool computeInLoop) public BasicBlockCollection(MethodDef method)
{ {
_method = method; _method = method;
HashSet<Instruction> splitPoints = BuildSplitPoint(method); HashSet<Instruction> splitPoints = BuildSplitPoint(method);
BuildBasicBlocks(method, splitPoints); BuildBasicBlocks(method, splitPoints);
BuildInOutGraph(method); BuildInOutGraph(method);
if (computeInLoop)
{
ComputeBlocksInLoop();
}
}
public void ComputeBlocksInLoop()
{
var loopBlocks = FindLoopBlocks(_blocks); var loopBlocks = FindLoopBlocks(_blocks);
foreach (var block in loopBlocks) foreach (var block in loopBlocks)
{ {
@ -104,7 +97,6 @@ namespace Obfuz.Emit
{ {
splitPoints.Add(nextInst); splitPoints.Add(nextInst);
} }
splitPoints.Add((Instruction)curInst.Operand);
break; break;
} }
case FlowControl.Cond_Branch: case FlowControl.Cond_Branch:
@ -212,21 +204,11 @@ namespace Obfuz.Emit
} }
break; break;
} }
case FlowControl.Call:
case FlowControl.Next:
{
if (nextBlock != null)
{
curBlock.AddTargetBasicBlock(nextBlock);
}
break;
}
case FlowControl.Return: case FlowControl.Return:
case FlowControl.Throw: case FlowControl.Throw:
{ {
break; break;
} }
default: throw new NotSupportedException($"Unsupported flow control: {lastInst.OpCode.FlowControl} in method {method.FullName}");
} }
} }
} }

View File

@ -111,20 +111,23 @@ namespace Obfuz.Emit
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() public DefaultMetadataImporter(EncryptionScopeProvider encryptionScopeProvider)
{ {
_encryptionScopeProvider = encryptionScopeProvider;
} }
public override void Init() public override void Init(ModuleDef mod)
{ {
ModuleDef mod = Module; _module = mod;
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
var constUtilityType = typeof(ConstUtility); var constUtilityType = typeof(ConstUtility);
_castIntAsFloat = mod.Import(constUtilityType.GetMethod("CastIntAsFloat")); _castIntAsFloat = mod.Import(constUtilityType.GetMethod("CastIntAsFloat"));
@ -138,119 +141,15 @@ 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(AssertUtility).GetMethod("VerifySecretKey", new[] { typeof(int), typeof(int) })); _verifySecretKey = mod.Import(typeof(AssetUtility).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));
Assert.IsNotNull(_obfuscationTypeMapperRegisterType, "ObfuscationTypeMapper.RegisterType not found"); Assert.IsNotNull(_obfuscationTypeMapperRegisterType, "ObfuscationTypeMapper.RegisterType not found");
var exprUtilityType = typeof(ExprUtility);
_addInt = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_addInt, "ExprUtility.Add(int, int) not found");
_addLong = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_addLong, "ExprUtility.Add(long, long) not found");
_addFloat = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(float), typeof(float) }));
Assert.IsNotNull(_addFloat, "ExprUtility.Add(float, float) not found");
_addDouble = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_addDouble, "ExprUtility.Add(double, double) not found");
_addIntPtr = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(IntPtr), typeof(IntPtr) }));
Assert.IsNotNull(_addIntPtr, "ExprUtility.Add(IntPtr, IntPtr) not found");
_addIntPtrInt = mod.Import(exprUtilityType.GetMethod("Add", new[] { typeof(IntPtr), typeof(int) }));
Assert.IsNotNull(_addIntPtrInt, "ExprUtility.Add(IntPtr, int) not found");
_subtractInt = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_subtractInt, "ExprUtility.Subtract(int, int) not found");
_subtractLong = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_subtractLong, "ExprUtility.Subtract(long, long) not found");
_subtractFloat = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(float), typeof(float) }));
Assert.IsNotNull(_subtractFloat, "ExprUtility.Subtract(float, float) not found");
_subtractDouble = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_subtractDouble, "ExprUtility.Subtract(double, double) not found");
_subtractIntPtr = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(IntPtr), typeof(IntPtr) }));
Assert.IsNotNull(_subtractIntPtr, "ExprUtility.Subtract(IntPtr, IntPtr) not found");
_subtractIntPtrInt = mod.Import(exprUtilityType.GetMethod("Subtract", new[] { typeof(IntPtr), typeof(int) }));
Assert.IsNotNull(_subtractIntPtrInt, "ExprUtility.Subtract(IntPtr, int) not found");
_multiplyInt = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_multiplyInt, "ExprUtility.Multiply(int, int) not found");
_multiplyLong = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_multiplyLong, "ExprUtility.Multiply(long, long) not found");
_multiplyFloat = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(float), typeof(float) }));
Assert.IsNotNull(_multiplyFloat, "ExprUtility.Multiply(float, float) not found");
_multiplyDouble = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_multiplyDouble, "ExprUtility.Multiply(double, double) not found");
_multiplyIntPtr = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(IntPtr), typeof(IntPtr) }));
Assert.IsNotNull(_multiplyIntPtr, "ExprUtility.Multiply(IntPtr, IntPtr) not found");
_multiplyIntPtrInt = mod.Import(exprUtilityType.GetMethod("Multiply", new[] { typeof(IntPtr), typeof(int) }));
Assert.IsNotNull(_multiplyIntPtrInt, "ExprUtility.Multiply(IntPtr, int) not found");
_divideInt = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_divideInt, "ExprUtility.Divide(int, int) not found");
_divideLong = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_divideLong);
_divideFloat = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(float), typeof(float) }));
Assert.IsNotNull(_divideFloat, "ExprUtility.Divide(float, float) not found");
_divideDouble = mod.Import(exprUtilityType.GetMethod("Divide", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_divideDouble, "ExprUtility.Divide(double, double) not found");
_divideUnInt = mod.Import(exprUtilityType.GetMethod("DivideUn", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_divideUnInt, "ExprUtility.DivideUn(int, int) not found");
_divideUnLong = mod.Import(exprUtilityType.GetMethod("DivideUn", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_divideUnLong, "ExprUtility.DivideUn(long, long) not found");
_remInt = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_remInt, "ExprUtility.Rem(int, int) not found");
_remLong = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_remLong, "ExprUtility.Rem(long, long) not found");
_remFloat = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(float), typeof(float) }));
Assert.IsNotNull(_remFloat, "ExprUtility.Rem(float, float) not found");
_remDouble = mod.Import(exprUtilityType.GetMethod("Rem", new[] { typeof(double), typeof(double) }));
Assert.IsNotNull(_remDouble, "ExprUtility.Rem(double, double) not found");
_remUnInt = mod.Import(exprUtilityType.GetMethod("RemUn", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_remUnInt, "ExprUtility.RemUn(int, int) not found");
_remUnLong = mod.Import(exprUtilityType.GetMethod("RemUn", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_remUnLong, "ExprUtility.RemUn(long, long) not found");
_negInt = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(int) }));
Assert.IsNotNull(_negInt, "ExprUtility.Negate(int) not found");
_negLong = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(long) }));
Assert.IsNotNull(_negLong, "ExprUtility.Negate(long) not found");
_negFloat = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(float) }));
Assert.IsNotNull(_negFloat, "ExprUtility.Negate(float) not found");
_negDouble = mod.Import(exprUtilityType.GetMethod("Negate", new[] { typeof(double) }));
Assert.IsNotNull(_negDouble, "ExprUtility.Negate(double) not found");
_andInt = mod.Import(exprUtilityType.GetMethod("And", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_andInt, "ExprUtility.And(int, int) not found");
_andLong = mod.Import(exprUtilityType.GetMethod("And", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_andLong, "ExprUtility.And(long, long) not found");
_orInt = mod.Import(exprUtilityType.GetMethod("Or", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_orInt, "ExprUtility.Or(int, int) not found");
_orLong = mod.Import(exprUtilityType.GetMethod("Or", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_orLong, "ExprUtility.Or(long, long) not found");
_xorInt = mod.Import(exprUtilityType.GetMethod("Xor", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_xorInt, "ExprUtility.Xor(int, int) not found");
_xorLong = mod.Import(exprUtilityType.GetMethod("Xor", new[] { typeof(long), typeof(long) }));
Assert.IsNotNull(_xorLong, "ExprUtility.Xor(long, long) not found");
_notInt = mod.Import(exprUtilityType.GetMethod("Not", new[] { typeof(int) }));
Assert.IsNotNull(_notInt, "ExprUtility.Not(int) not found");
_notLong = mod.Import(exprUtilityType.GetMethod("Not", new[] { typeof(long) }));
Assert.IsNotNull(_notLong, "ExprUtility.Not(long) not found");
_shlInt = mod.Import(exprUtilityType.GetMethod("ShiftLeft", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_shlInt, "ExprUtility.ShiftLeft(int, int) not found");
_shlLong = mod.Import(exprUtilityType.GetMethod("ShiftLeft", new[] { typeof(long), typeof(int) }));
Assert.IsNotNull(_shlLong, "ExprUtility.ShiftLeft(long, int) not found");
_shrInt = mod.Import(exprUtilityType.GetMethod("ShiftRight", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_shrInt, "ExprUtility.ShiftRight(int, int) not found");
_shrLong = mod.Import(exprUtilityType.GetMethod("ShiftRight", new[] { typeof(long), typeof(int) }));
Assert.IsNotNull(_shrLong, "ExprUtility.ShiftRight(long, int) not found");
_shrUnInt = mod.Import(exprUtilityType.GetMethod("ShiftRightUn", new[] { typeof(int), typeof(int) }));
Assert.IsNotNull(_shrUnInt, "ExprUtility.ShiftRightUn(int, int) not found");
_shrUnLong = mod.Import(exprUtilityType.GetMethod("ShiftRightUn", new[] { typeof(long), typeof(int) }));
Assert.IsNotNull(_shrUnLong, "ExprUtility.ShiftRightUn(long, int) not found");
_staticDefaultEncryptionServiceMetadataImporter = new EncryptionServiceMetadataImporter(mod, typeof(EncryptionService<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;
} }
@ -260,14 +159,9 @@ 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;
@ -280,57 +174,6 @@ namespace Obfuz.Emit
private IMethod _obfuscationTypeMapperRegisterType; private IMethod _obfuscationTypeMapperRegisterType;
private IMethod _addInt;
private IMethod _addLong;
private IMethod _addFloat;
private IMethod _addDouble;
private IMethod _addIntPtr;
private IMethod _addIntPtrInt;
private IMethod _subtractInt;
private IMethod _subtractLong;
private IMethod _subtractFloat;
private IMethod _subtractDouble;
private IMethod _subtractIntPtr;
private IMethod _subtractIntPtrInt;
private IMethod _multiplyInt;
private IMethod _multiplyLong;
private IMethod _multiplyFloat;
private IMethod _multiplyDouble;
private IMethod _multiplyIntPtr;
private IMethod _multiplyIntPtrInt;
private IMethod _divideInt;
private IMethod _divideLong;
private IMethod _divideFloat;
private IMethod _divideDouble;
private IMethod _divideUnInt;
private IMethod _divideUnLong;
private IMethod _remInt;
private IMethod _remLong;
private IMethod _remFloat;
private IMethod _remDouble;
private IMethod _remUnInt;
private IMethod _remUnLong;
private IMethod _negInt;
private IMethod _negLong;
private IMethod _negFloat;
private IMethod _negDouble;
private IMethod _andInt;
private IMethod _andLong;
private IMethod _orInt;
private IMethod _orLong;
private IMethod _xorInt;
private IMethod _xorLong;
private IMethod _notInt;
private IMethod _notLong;
private IMethod _shlInt;
private IMethod _shlLong;
private IMethod _shrInt;
private IMethod _shrLong;
private IMethod _shrUnInt;
private IMethod _shrUnLong;
public IMethod CastIntAsFloat => _castIntAsFloat; public IMethod CastIntAsFloat => _castIntAsFloat;
public IMethod CastLongAsDouble => _castLongAsDouble; public IMethod CastLongAsDouble => _castLongAsDouble;
public IMethod CastFloatAsInt => _castFloatAsInt; public IMethod CastFloatAsInt => _castFloatAsInt;
@ -366,58 +209,5 @@ namespace Obfuz.Emit
public IMethod DecryptFromRvaString => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaString; public IMethod DecryptFromRvaString => _defaultEncryptionServiceMetadataImporter.DecryptFromRvaString;
public IMethod DecryptInitializeArray => _defaultEncryptionServiceMetadataImporter.DecryptInitializeArray; public IMethod DecryptInitializeArray => _defaultEncryptionServiceMetadataImporter.DecryptInitializeArray;
public IMethod AddInt => _addInt;
public IMethod AddLong => _addLong;
public IMethod AddFloat => _addFloat;
public IMethod AddDouble => _addDouble;
public IMethod AddIntPtr => _addIntPtr;
public IMethod AddIntPtrInt => _addIntPtrInt;
public IMethod SubtractInt => _subtractInt;
public IMethod SubtractLong => _subtractLong;
public IMethod SubtractFloat => _subtractFloat;
public IMethod SubtractDouble => _subtractDouble;
public IMethod SubtractIntPtr => _subtractIntPtr;
public IMethod SubtractIntPtrInt => _subtractIntPtrInt;
public IMethod MultiplyInt => _multiplyInt;
public IMethod MultiplyLong => _multiplyLong;
public IMethod MultiplyFloat => _multiplyFloat;
public IMethod MultiplyDouble => _multiplyDouble;
public IMethod MultiplyIntPtr => _multiplyIntPtr;
public IMethod MultiplyIntPtrInt => _multiplyIntPtrInt;
public IMethod DivideInt => _divideInt;
public IMethod DivideLong => _divideLong;
public IMethod DivideFloat => _divideFloat;
public IMethod DivideDouble => _divideDouble;
public IMethod DivideUnInt => _divideUnInt;
public IMethod DivideUnLong => _divideUnLong;
public IMethod RemInt => _remInt;
public IMethod RemLong => _remLong;
public IMethod RemFloat => _remFloat;
public IMethod RemDouble => _remDouble;
public IMethod RemUnInt => _remUnInt;
public IMethod RemUnLong => _remUnLong;
public IMethod NegInt => _negInt;
public IMethod NegLong => _negLong;
public IMethod NegFloat => _negFloat;
public IMethod NegDouble => _negDouble;
public IMethod AndInt => _andInt;
public IMethod AndLong => _andLong;
public IMethod OrInt => _orInt;
public IMethod OrLong => _orLong;
public IMethod XorInt => _xorInt;
public IMethod XorLong => _xorLong;
public IMethod NotInt => _notInt;
public IMethod NotLong => _notLong;
public IMethod ShlInt => _shlInt;
public IMethod ShlLong => _shlLong;
public IMethod ShrInt => _shrInt;
public IMethod ShrLong => _shrLong;
public IMethod ShrUnInt => _shrUnInt;
public IMethod ShrUnLong => _shrUnLong;
} }
} }

View File

@ -1,15 +0,0 @@
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

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -6,46 +6,19 @@ namespace Obfuz.Emit
{ {
public interface IGroupByModuleEntity public interface IGroupByModuleEntity
{ {
GroupByModuleEntityManager Manager { get; set; } void Init(ModuleDef mod);
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 GroupByModuleEntityManager Manager { get; set; } public abstract void Init(ModuleDef mod);
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 EncryptionScopeProvider EncryptionScopeProvider { get; set; } public T GetEntity<T>(ModuleDef mod, Func<T> creator = null) where T : IGroupByModuleEntity
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))
@ -54,17 +27,22 @@ namespace Obfuz.Emit
} }
else else
{ {
T newEmitManager = new T(); T newEmitManager;
newEmitManager.Manager = this; if (creator != null)
newEmitManager.Module = mod; {
newEmitManager.EncryptionScope = EncryptionScopeProvider.GetScope(mod); newEmitManager = creator();
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, new() public List<T> GetEntities<T>() where T : IGroupByModuleEntity
{ {
var managers = new List<T>(); var managers = new List<T>();
foreach (var kv in _moduleEntityManagers) foreach (var kv in _moduleEntityManagers)
@ -77,13 +55,9 @@ namespace Obfuz.Emit
return managers; return managers;
} }
public void Done<T>() where T : IGroupByModuleEntity, new() public DefaultMetadataImporter GetDefaultModuleMetadataImporter(ModuleDef module, EncryptionScopeProvider encryptionScopeProvider)
{ {
var managers = GetEntities<T>(); return GetEntity<DefaultMetadataImporter>(module, () => new DefaultMetadataImporter(encryptionScopeProvider));
foreach (var manager in managers)
{
manager.Done();
}
} }
} }
} }

View File

@ -1,74 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
namespace Obfuz.Emit
{
class ScopeLocalVariables : IDisposable
{
private readonly LocalVariableAllocator _localVariableAllocator;
private readonly List<Local> _allocatedVars = new List<Local>();
public IReadOnlyList<Local> AllocatedLocals => _allocatedVars;
public ScopeLocalVariables(LocalVariableAllocator localVariableAllocator)
{
_localVariableAllocator = localVariableAllocator;
}
public Local AllocateLocal(TypeSig type)
{
var local = _localVariableAllocator.AllocateLocal(type);
_allocatedVars.Add(local);
return local;
}
public void Dispose()
{
foreach (var local in _allocatedVars)
{
_localVariableAllocator.ReturnLocal(local);
}
}
}
class LocalVariableAllocator
{
private readonly MethodDef _method;
private readonly List<Local> _freeLocals = new List<Local>();
public LocalVariableAllocator(MethodDef method)
{
_method = method;
}
public Local AllocateLocal(TypeSig type)
{
foreach (var local in _freeLocals)
{
if (TypeEqualityComparer.Instance.Equals(local.Type, type))
{
_freeLocals.Remove(local);
return local;
}
}
var newLocal = new Local(type);
// _freeLocals.Add(newLocal);
_method.Body.Variables.Add(newLocal);
return newLocal;
}
public void ReturnLocal(Local local)
{
_freeLocals.Add(local);
}
public ScopeLocalVariables CreateScope()
{
return new ScopeLocalVariables(this);
}
}
}

View File

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

View File

@ -1,4 +1,5 @@
using Obfuz.Utils; using NUnit.Framework;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions
@ -13,14 +14,31 @@ namespace Obfuz.EncryptionVM.Instructions
{ {
_multiValue = addValue; _multiValue = addValue;
_opKeyIndex = opKeyIndex; _opKeyIndex = opKeyIndex;
_revertMultiValue = MathUtil.ModInverse32(addValue); _revertMultiValue = (int)ModInverseOdd((uint)addValue);
Verify(); Verify();
} }
private void Verify() private void Verify()
{ {
int a = 1122334; int a = 1122334;
UnityEngine.Assertions.Assert.AreEqual(a, a * _multiValue * _revertMultiValue); Assert.AreEqual(a, a * _multiValue * _revertMultiValue);
}
public static uint ModInverseOdd(uint a)
{
if (a % 2 == 0)
throw new ArgumentException("Input must be an odd number.", nameof(a));
uint x = 1; // 初始解x₀ = 1 (mod 2)
for (int i = 0; i < 5; i++) // 迭代5次2^1 → 2^32
{
int shift = 2 << i; // 当前模数为 2^(2^(i+1))
ulong mod = 1UL << shift; // 使用 ulong 避免溢出
ulong ax = (ulong)a * x; // 计算 a*x64位避免截断
ulong term = (2 - ax) % mod;
x = (uint)((x * term) % mod); // 更新 x结果截断为 uint
}
return x; // 最终解为 x₅ mod 2^32
} }
public override int Encrypt(int value, int[] secretKey, int salt) public override int Encrypt(int value, int[] secretKey, int salt)

View File

@ -1,5 +1,4 @@
using Obfuz.Utils; using System.Collections.Generic;
using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions
{ {
@ -18,7 +17,7 @@ namespace Obfuz.EncryptionVM.Instructions
public MultipleRotateXorInstruction(int multipleValue, int index1, int rotateBitNum, int xorValue) public MultipleRotateXorInstruction(int multipleValue, int index1, int rotateBitNum, int xorValue)
{ {
_multipleValue = multipleValue; _multipleValue = multipleValue;
_revertMultipleValue = MathUtil.ModInverse32(multipleValue); _revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue);
_index1 = index1; _index1 = index1;
_rotateBitNum = rotateBitNum; _rotateBitNum = rotateBitNum;
_xorValue = xorValue; _xorValue = xorValue;

View File

@ -1,5 +1,4 @@
using Obfuz.Utils; using System.Collections.Generic;
using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions
{ {
@ -18,7 +17,7 @@ namespace Obfuz.EncryptionVM.Instructions
public MultipleXorRotateInstruction(int multipleValue, int index1, int xorValue, int rotateBitNum) public MultipleXorRotateInstruction(int multipleValue, int index1, int xorValue, int rotateBitNum)
{ {
_multipleValue = multipleValue; _multipleValue = multipleValue;
_revertMultipleValue = MathUtil.ModInverse32(multipleValue); _revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue);
_index1 = index1; _index1 = index1;
_rotateBitNum = rotateBitNum; _rotateBitNum = rotateBitNum;
_xorValue = xorValue; _xorValue = xorValue;

View File

@ -1,5 +1,4 @@
using Obfuz.Utils; using System.Collections.Generic;
using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions
{ {
@ -18,7 +17,7 @@ namespace Obfuz.EncryptionVM.Instructions
public XorMultipleRotateInstruction(int xorValue, int multipleValue, int index1, int rotateBitNum) public XorMultipleRotateInstruction(int xorValue, int multipleValue, int index1, int rotateBitNum)
{ {
_multipleValue = multipleValue; _multipleValue = multipleValue;
_revertMultipleValue = MathUtil.ModInverse32(multipleValue); _revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue);
_index1 = index1; _index1 = index1;
_rotateBitNum = rotateBitNum; _rotateBitNum = rotateBitNum;
_xorValue = xorValue; _xorValue = xorValue;

View File

@ -52,6 +52,7 @@ namespace Obfuz.EncryptionVM
File.WriteAllText(outputFile, code, Encoding.UTF8); File.WriteAllText(outputFile, code, Encoding.UTF8);
Debug.Log($"Generate EncryptionVM code to {outputFile}"); Debug.Log($"Generate EncryptionVM code to {outputFile}");
UnityEditor.AssetDatabase.Refresh();
} }
private string GenerateCode() private string GenerateCode()

View File

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

View File

@ -1,117 +0,0 @@
using Obfuz.Utils;
using System;
using System.Linq;
using System.Text;
namespace Obfuz.GarbageCodeGeneration
{
public class ConfigGarbageCodeGenerator : SpecificGarbageCodeGeneratorBase
{
private readonly string[] _types = new string[]
{
"bool",
"byte",
"short",
"int",
"long",
"float",
"double",
};
private string CreateRandomType(IRandom random)
{
return _types[random.NextInt(_types.Length)];
}
private string GetReadMethodNameOfType(string type)
{
switch (type)
{
case "bool": return "ReadBoolean";
case "byte": return "ReadByte";
case "short": return "ReadInt16";
case "int": return "ReadInt32";
case "long": return "ReadInt64";
case "float": return "ReadSingle";
case "double": return "ReadDouble";
default: throw new ArgumentException($"Unsupported type: {type}");
}
}
class FieldGenerationInfo
{
public int index;
public string name;
public string type;
}
class MethodGenerationInfo
{
public int index;
public string name;
}
protected override object CreateField(int index, IRandom random, GenerationParameters parameters)
{
return new FieldGenerationInfo
{
index = index,
name = $"x{index}",
type = CreateRandomType(random),
};
}
protected override object CreateMethod(int index, IRandom random, GenerationParameters parameters)
{
return new MethodGenerationInfo
{
index = index,
name = $"Load{index}",
};
}
protected override void GenerateUsings(StringBuilder result, IClassGenerationInfo cgi)
{
}
protected override void GenerateField(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object field, string indent)
{
var fgi = (FieldGenerationInfo)field;
result.AppendLine($"{indent}public {fgi.type} {fgi.name};");
}
protected override void GenerateMethod(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object method, string indent)
{
var mgi = (MethodGenerationInfo)method;
result.AppendLine($"{indent}public void {mgi.name}(BinaryReader reader)");
result.AppendLine($"{indent}{{");
string indent2 = indent + " ";
result.AppendLine($"{indent2}int a = 0;");
result.AppendLine($"{indent2}int b = 0;");
int maxN = 100;
var shuffledFields = cgi.Fields.ToList();
RandomUtil.ShuffleList(shuffledFields, random);
foreach (FieldGenerationInfo fgi in shuffledFields)
{
result.AppendLine($"{indent2}this.{fgi.name} = reader.{GetReadMethodNameOfType(fgi.type)}();");
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}a = b * {random.NextInt(maxN)} + reader.ReadInt32();");
result.AppendLine($"{indent2}b = a * reader.ReadInt32() + {random.NextInt(maxN)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}a += {random.NextInt(0, 10000)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}b += {random.NextInt(0, 10000)};");
}
}
result.AppendLine($"{indent}}}");
}
}
}

View File

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

View File

@ -1,88 +0,0 @@
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using UnityEngine;
namespace Obfuz.GarbageCodeGeneration
{
public class GarbageCodeGenerator
{
private const int CodeGenerationSecretKeyLength = 1024;
private readonly GarbageCodeGenerationSettings _settings;
private readonly int[] _intGenerationSecretKey;
public GarbageCodeGenerator(GarbageCodeGenerationSettings settings)
{
_settings = settings;
byte[] byteGenerationSecretKey = KeyGenerator.GenerateKey(settings.codeGenerationSecret, CodeGenerationSecretKeyLength);
_intGenerationSecretKey = KeyGenerator.ConvertToIntKey(byteGenerationSecretKey);
}
public void Generate()
{
GenerateTask(_settings.defaultTask);
if (_settings.additionalTasks != null && _settings.additionalTasks.Length > 0)
{
foreach (var task in _settings.additionalTasks)
{
GenerateTask(task);
}
}
}
public void CleanCodes()
{
Debug.Log($"Cleaning generated garbage codes begin.");
if (_settings.defaultTask != null)
{
FileUtil.RemoveDir(_settings.defaultTask.outputPath, true);
}
if (_settings.additionalTasks != null && _settings.additionalTasks.Length > 0)
{
foreach (var task in _settings.additionalTasks)
{
FileUtil.RemoveDir(task.outputPath, true);
}
}
}
private void GenerateTask(GarbageCodeGenerationTask task)
{
Debug.Log($"Generating garbage code with seed: {task.codeGenerationRandomSeed}, class count: {task.classCount}, method count per class: {task.methodCountPerClass}, types: {task.garbageCodeType}, output path: {task.outputPath}");
if (string.IsNullOrWhiteSpace(task.outputPath))
{
throw new Exception("outputPath of GarbageCodeGenerationTask is empty!");
}
var generator = CreateSpecificCodeGenerator(task.garbageCodeType);
var parameters = new GenerationParameters
{
random = new RandomWithKey(_intGenerationSecretKey, task.codeGenerationRandomSeed),
classNamespace = task.classNamespace,
classNamePrefix = task.classNamePrefix,
classCount = task.classCount,
methodCountPerClass = task.methodCountPerClass,
fieldCountPerClass = task.fieldCountPerClass,
outputPath = task.outputPath,
};
generator.Generate(parameters);
Debug.Log($"Generate garbage code end.");
}
private ISpecificGarbageCodeGenerator CreateSpecificCodeGenerator(GarbageCodeType type)
{
switch (type)
{
case GarbageCodeType.Config: return new ConfigGarbageCodeGenerator();
case GarbageCodeType.UI: return new UIGarbageCodeGenerator();
default: throw new NotSupportedException($"Garbage code type {type} is not supported.");
}
}
}
}

View File

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

View File

@ -1,21 +0,0 @@
using Obfuz.Utils;
namespace Obfuz.GarbageCodeGeneration
{
public class GenerationParameters
{
public IRandom random;
public string classNamespace;
public string classNamePrefix;
public int classCount;
public int methodCountPerClass;
public int fieldCountPerClass;
public string outputPath;
}
public interface ISpecificGarbageCodeGenerator
{
void Generate(GenerationParameters parameters);
}
}

View File

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

View File

@ -1,106 +0,0 @@
using Obfuz.Utils;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
namespace Obfuz.GarbageCodeGeneration
{
public abstract class SpecificGarbageCodeGeneratorBase : ISpecificGarbageCodeGenerator
{
protected interface IClassGenerationInfo
{
string Namespace { get; set; }
string Name { get; set; }
IList<object> Fields { get; set; }
IList<object> Methods { get; set; }
}
protected class ClassGenerationInfo : IClassGenerationInfo
{
public string Namespace { get; set; }
public string Name { get; set; }
public IList<object> Fields { get; set; } = new List<object>();
public IList<object> Methods { get; set; } = new List<object>();
}
public virtual void Generate(GenerationParameters parameters)
{
FileUtil.RecreateDir(parameters.outputPath);
for (int i = 0; i < parameters.classCount; i++)
{
Debug.Log($"[{GetType().Name}] Generating class {i}");
var localRandom = new RandomWithKey(((RandomWithKey)parameters.random).Key, parameters.random.NextInt());
string outputFile = $"{parameters.outputPath}/__GeneratedGarbageClass_{i}.cs";
var result = new StringBuilder(64 * 1024);
GenerateClass(i, localRandom, result, parameters);
File.WriteAllText(outputFile, result.ToString(), Encoding.UTF8);
Debug.Log($"[{GetType().Name}] Generated class {i} to {outputFile}");
}
}
protected abstract object CreateField(int index, IRandom random, GenerationParameters parameters);
protected abstract object CreateMethod(int index, IRandom random, GenerationParameters parameters);
protected virtual IClassGenerationInfo CreateClassGenerationInfo(string classNamespace, string className, IRandom random, GenerationParameters parameters)
{
var cgi = new ClassGenerationInfo
{
Namespace = classNamespace,
Name = className,
};
for (int i = 0; i < parameters.fieldCountPerClass; i++)
{
cgi.Fields.Add(CreateField(i, random, parameters));
}
for (int i = 0; i < parameters.methodCountPerClass; i++)
{
cgi.Methods.Add(CreateMethod(i, random, parameters));
}
return cgi;
}
protected virtual void GenerateClass(int classIndex, IRandom random, StringBuilder result, GenerationParameters parameters)
{
IClassGenerationInfo cgi = CreateClassGenerationInfo(parameters.classNamespace, $"{parameters.classNamePrefix}{classIndex}", random, parameters);
result.AppendLine("using System;");
result.AppendLine("using System.Collections.Generic;");
result.AppendLine("using System.Linq;");
result.AppendLine("using System.IO;");
result.AppendLine("using UnityEngine;");
GenerateUsings(result, cgi);
result.AppendLine($"namespace {cgi.Namespace}");
result.AppendLine("{");
result.AppendLine($" public class {cgi.Name}");
result.AppendLine(" {");
string indent = " ";
foreach (object field in cgi.Fields)
{
GenerateField(result, cgi, random, field, indent);
}
foreach (object method in cgi.Methods)
{
GenerateMethod(result, cgi, random, method, indent);
}
result.AppendLine(" }");
result.AppendLine("}");
}
protected abstract void GenerateUsings(StringBuilder result, IClassGenerationInfo cgi);
protected abstract void GenerateField(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object field, string indent);
protected abstract void GenerateMethod(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object method, string indent);
}
}

View File

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

View File

@ -1,157 +0,0 @@
using Obfuz.Utils;
using System;
using System.Linq;
using System.Text;
namespace Obfuz.GarbageCodeGeneration
{
public class UIGarbageCodeGenerator : SpecificGarbageCodeGeneratorBase
{
/*
*
* public Button b1;
public Image b2;
public RawImage b30;
public Text b3;
public Slider b4;
public ScrollRect b5;
public Scrollbar b6;
public Mask b7;
public RectMask2D b70;
public Canvas b8;
public CanvasGroup b9;
public RectTransform b10;
public Transform b11;
public GameObject b12;
*/
private readonly string[] _types = new string[]
{
"Button",
"Image",
"RawImage",
"Text",
"Slider",
"ScrollRect",
"Scrollbar",
"Mask",
"RectMask2D",
"Canvas",
"CanvasGroup",
"RectTransform",
//"Transform",
//"GameObject",
};
private string CreateRandomType(IRandom random)
{
return _types[random.NextInt(_types.Length)];
}
private string GetReadMethodNameOfType(string type)
{
switch (type)
{
case "bool": return "ReadBoolean";
case "byte": return "ReadByte";
case "short": return "ReadInt16";
case "int": return "ReadInt32";
case "long": return "ReadInt64";
case "float": return "ReadSingle";
case "double": return "ReadDouble";
default: throw new ArgumentException($"Unsupported type: {type}");
}
}
class FieldGenerationInfo
{
public int index;
public string name;
public string type;
}
class MethodGenerationInfo
{
public int index;
public string name;
}
protected override object CreateField(int index, IRandom random, GenerationParameters parameters)
{
return new FieldGenerationInfo
{
index = index,
name = $"x{index}",
type = CreateRandomType(random),
};
}
protected override object CreateMethod(int index, IRandom random, GenerationParameters parameters)
{
return new MethodGenerationInfo
{
index = index,
name = $"Init{index}",
};
}
protected override void GenerateUsings(StringBuilder result, IClassGenerationInfo cgi)
{
result.AppendLine("using UnityEngine.UI;");
}
protected override void GenerateField(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object field, string indent)
{
var fgi = (FieldGenerationInfo)field;
result.AppendLine($"{indent}public {fgi.type} {fgi.name};");
}
protected override void GenerateMethod(StringBuilder result, IClassGenerationInfo cgi, IRandom random, object method, string indent)
{
var mgi = (MethodGenerationInfo)method;
result.AppendLine($"{indent}public void {mgi.name}(GameObject go)");
result.AppendLine($"{indent}{{");
string indent2 = indent + " ";
result.AppendLine($"{indent2}int a = 0;");
result.AppendLine($"{indent2}int b = 0;");
int maxN = 100;
var shuffledFields = cgi.Fields.ToList();
RandomUtil.ShuffleList(shuffledFields, random);
foreach (FieldGenerationInfo fgi in shuffledFields)
{
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}this.{fgi.name} = go.transform.Find(\"ui/{fgi.name}\").GetComponent<{fgi.type}>();");
}
else
{
result.AppendLine($"{indent2}this.{fgi.name} = go.GetComponent<{fgi.type}>();");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}a = b * {random.NextInt(maxN)} + go.layer;");
result.AppendLine($"{indent2}b = a * go.layer + {random.NextInt(maxN)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}a *= {random.NextInt(0, 10000)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}b /= {random.NextInt(0, 10000)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}a = a * b << {random.NextInt(0, 10000)};");
}
if (random.NextInPercentage(0.5f))
{
result.AppendLine($"{indent2}b = a / b & {random.NextInt(0, 10000)};");
}
}
result.AppendLine($"{indent}}}");
}
}
}

View File

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

View File

@ -2,19 +2,53 @@
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Emit; using Obfuz.Emit;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Obfuz.ObfusPasses namespace Obfuz.ObfusPasses
{ {
public abstract class BasicBlockObfuscationPassBase : ObfuscationMethodPassBase public abstract class BasicBlockObfuscationPassBase : ObfuscationPassBase
{ {
protected virtual bool ComputeBlockInLoop => true; protected abstract bool NeedObfuscateMethod(MethodDef method);
public override void Process()
{
var ctx = ObfuscationPassContext.Current;
ObfuscationMethodWhitelist whiteList = ctx.whiteList;
ConfigurablePassPolicy passPolicy = ctx.passPolicy;
foreach (ModuleDef mod in ctx.modulesToObfuscate)
{
if (whiteList.IsInWhiteList(mod))
{
continue;
}
// ToArray to avoid modify list exception
foreach (TypeDef type in mod.GetTypes().ToArray())
{
if (whiteList.IsInWhiteList(type))
{
continue;
}
// ToArray to avoid modify list exception
foreach (MethodDef method in type.Methods.ToArray())
{
if (!method.HasBody || ctx.whiteList.IsInWhiteList(method) || !Support(passPolicy.GetMethodObfuscationPasses(method)) || !NeedObfuscateMethod(method))
{
continue;
}
// TODO if isGeneratedBy Obfuscator, continue
ObfuscateData(method);
}
}
}
}
protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, BasicBlock block, int instructionIndex, protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, BasicBlock block, int instructionIndex,
IList<Instruction> globalInstructions, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions); IList<Instruction> globalInstructions, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions);
protected override void ObfuscateData(MethodDef method) private void ObfuscateData(MethodDef method)
{ {
BasicBlockCollection bbc = new BasicBlockCollection(method, ComputeBlockInLoop); BasicBlockCollection bbc = new BasicBlockCollection(method);
IList<Instruction> instructions = method.Body.Instructions; IList<Instruction> instructions = method.Body.Instructions;

View File

@ -7,21 +7,9 @@ using System.Collections.Generic;
namespace Obfuz.ObfusPasses.CallObfus namespace Obfuz.ObfusPasses.CallObfus
{ {
class ObfusMethodContext public class CallObfusPass : BasicBlockObfuscationPassBase
{ {
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;
@ -30,7 +18,6 @@ namespace Obfuz.ObfusPasses.CallObfus
public CallObfusPass(CallObfuscationSettingsFacade settings) public CallObfusPass(CallObfuscationSettingsFacade settings)
{ {
_settings = settings; _settings = settings;
CurrentSettings = settings;
} }
public override void Stop() public override void Stop()
@ -41,82 +28,17 @@ 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) 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)
@ -138,7 +60,7 @@ namespace Obfuz.ObfusPasses.CallObfus
} }
case Code.Callvirt: case Code.Callvirt:
{ {
if (lastInst != null && lastInst.OpCode.Code == Code.Constrained) if (instructionIndex > 0 && globalInstructions[instructionIndex - 1].OpCode.Code == Code.Constrained)
{ {
return false; return false;
} }
@ -148,19 +70,15 @@ namespace Obfuz.ObfusPasses.CallObfus
default: return false; default: return false;
} }
if (!_dynamicProxyPolicy.NeedObfuscateCalledMethod(callerMethod, calledMethod, callVir, block.inLoop))
if (_specialWhiteListMethodCache.IsInWhiteList(calledMethod))
{ {
return false; return false;
} }
ObfuscationCachePolicy cachePolicy = _dynamicProxyPolicy.GetMethodObfuscationCachePolicy(callerMethod);
if (!_dynamicProxyPolicy.NeedObfuscateCalledMethod(callerMethod, calledMethod, callVir)) bool cachedCallIndex = block.inLoop ? cachePolicy.cacheInLoop : cachePolicy.cacheNotInLoop;
{ _dynamicProxyObfuscator.Obfuscate(callerMethod, calledMethod, callVir, cachedCallIndex, outputInstructions);
return false; return true;
}
return _dynamicProxyObfuscator.Obfuscate(callerMethod, calledMethod, callVir, outputInstructions);
} }
} }
} }

View File

@ -12,7 +12,6 @@ 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;
@ -31,11 +30,38 @@ namespace Obfuz.ObfusPasses.CallObfus
} }
} }
class ModuleDispatchProxyAllocator : GroupByModuleEntityBase class ModuleCallProxyAllocator : IGroupByModuleEntity
{ {
private bool _done; private ModuleDef _module;
private CallObfuscationSettingsFacade _settings; private readonly EncryptionScopeProvider _encryptionScopeProvider;
private readonly CallObfuscationSettingsFacade _settings;
private EncryptionScopeInfo _encryptionScope;
private bool _done;
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
{ {
@ -67,23 +93,25 @@ namespace Obfuz.ObfusPasses.CallObfus
private TypeDef _proxyTypeDef; private TypeDef _proxyTypeDef;
public ModuleDispatchProxyAllocator() public ModuleCallProxyAllocator(EncryptionScopeProvider encryptionScopeProvider, CallObfuscationSettingsFacade settings)
{ {
_encryptionScopeProvider = encryptionScopeProvider;
_settings = settings;
} }
public override void Init() public void Init(ModuleDef mod)
{ {
_settings = CallObfusPass.CurrentSettings; _module = mod;
_encryptionScope = _encryptionScopeProvider.GetScope(mod);
} }
private TypeDef CreateProxyTypeDef() private TypeDef CreateProxyTypeDef()
{ {
ModuleDef mod = Module; using (var scope = new DisableTypeDefFindCacheScope(_module))
using (var scope = new DisableTypeDefFindCacheScope(mod))
{ {
var typeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ProxyCall", mod.CorLibTypes.Object.ToTypeDefOrRef()); var typeDef = new TypeDefUser($"{ConstValues.ObfuzInternalSymbolNamePrefix}ProxyCall", _module.CorLibTypes.Object.ToTypeDefOrRef());
typeDef.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed; typeDef.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed;
mod.Types.Add(typeDef); _module.Types.Add(typeDef);
return typeDef; return typeDef;
} }
} }
@ -129,25 +157,24 @@ namespace Obfuz.ObfusPasses.CallObfus
private MethodSig CreateDispatchMethodSig(IMethod method) private MethodSig CreateDispatchMethodSig(IMethod method)
{ {
ModuleDef mod = Module; MethodSig methodSig = MetaUtil.ToSharedMethodSig(_module.CorLibTypes, MetaUtil.GetInflatedMethodSig(method));
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, mod.CorLibTypes.Object); methodSig.Params.Insert(0, _module.CorLibTypes.Object);
break; break;
} }
case ThisArgType.ValueType: case ThisArgType.ValueType:
{ {
methodSig.Params.Insert(0, mod.CorLibTypes.IntPtr); methodSig.Params.Insert(0, _module.CorLibTypes.IntPtr);
break; break;
} }
} }
// extra param for index // extra param for index
methodSig.Params.Add(mod.CorLibTypes.Int32); methodSig.Params.Add(_module.CorLibTypes.Int32);
return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray()); return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray());
} }
@ -158,7 +185,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)
@ -183,7 +210,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)
@ -201,7 +228,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,
@ -216,7 +243,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 override void Done() public void Done()
{ {
if (_done) if (_done)
{ {
@ -270,4 +297,37 @@ 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

@ -1,6 +1,5 @@
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;
@ -35,12 +34,29 @@ namespace Obfuz.ObfusPasses.CallObfus
class ObfuscationRule : IRule<ObfuscationRule> class ObfuscationRule : IRule<ObfuscationRule>
{ {
public ObfuscationLevel? obfuscationLevel; public bool? disableObfuscation;
public bool? obfuscateCallInLoop;
public bool? cacheCallIndexInLoop;
public bool? cacheCallIndexNotLoop;
public void InheritParent(ObfuscationRule parentRule) public void InheritParent(ObfuscationRule parentRule)
{ {
if (obfuscationLevel == null) if (disableObfuscation == 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;
}
} }
} }
@ -59,7 +75,10 @@ namespace Obfuz.ObfusPasses.CallObfus
private static readonly ObfuscationRule s_default = new ObfuscationRule() private static readonly ObfuscationRule s_default = new ObfuscationRule()
{ {
obfuscationLevel = ObfuscationLevel.Basic, disableObfuscation = false,
obfuscateCallInLoop = true,
cacheCallIndexInLoop = true,
cacheCallIndexNotLoop = false,
}; };
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _configParser; private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _configParser;
@ -67,12 +86,11 @@ namespace Obfuz.ObfusPasses.CallObfus
private ObfuscationRule _global; private ObfuscationRule _global;
private readonly List<WhiteListAssembly> _whiteListAssemblies = new List<WhiteListAssembly>(); private readonly List<WhiteListAssembly> _whiteListAssemblies = new List<WhiteListAssembly>();
private readonly CachedDictionary<IMethod, bool> _whiteListMethodCache; private readonly Dictionary<IMethod, bool> _whiteListMethodCache = new Dictionary<IMethod, bool>(MethodEqualityComparer.CompareDeclaringTypes);
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>(); private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles) public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
{ {
_whiteListMethodCache = new CachedDictionary<IMethod, bool>(MethodEqualityComparer.CompareDeclaringTypes, this.ComputeIsInWhiteList);
_configParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(toObfuscatedAssemblyNames, _configParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(toObfuscatedAssemblyNames,
ParseObfuscationRule, ParseGlobalElement); ParseObfuscationRule, ParseGlobalElement);
LoadConfigs(xmlConfigFiles); LoadConfigs(xmlConfigFiles);
@ -128,9 +146,21 @@ 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("obfuscationLevel")) if (ele.HasAttribute("disableObfuscation"))
{ {
rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); rule.disableObfuscation = ConfigUtil.ParseBool(ele.GetAttribute("disableObfuscation"));
}
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;
} }
@ -222,7 +252,7 @@ namespace Obfuz.ObfusPasses.CallObfus
{ {
if (!_methodRuleCache.TryGetValue(method, out var rule)) if (!_methodRuleCache.TryGetValue(method, out var rule))
{ {
rule = _configParser.GetMethodRule(method, _global); rule = _configParser.GetMethodRule(method, s_default);
_methodRuleCache[method] = rule; _methodRuleCache[method] = rule;
} }
return rule; return rule;
@ -231,7 +261,44 @@ 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.obfuscationLevel != null && rule.obfuscationLevel.Value >= ObfuscationLevel.Basic; return rule.disableObfuscation != true;
}
public override ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method)
{
ObfuscationRule rule = GetMethodObfuscationRule(method);
return new ObfuscationCachePolicy()
{
cacheInLoop = rule.cacheCallIndexInLoop.Value,
cacheNotInLoop = rule.cacheCallIndexNotLoop.Value,
};
}
private bool IsSpecialNotObfuscatedMethod(TypeDef typeDef, IMethod method)
{
if (typeDef.IsDelegate || typeDef.IsEnum)
return true;
string methodName = method.Name;
// doesn't proxy call if the method is a constructor
if (methodName == ".ctor")
{
return true;
}
if (typeDef.Name == "EncryptionService`1")
{
return true;
}
// special handle
// don't proxy call for List<T>.Enumerator GetEnumerator()
if (methodName == "GetEnumerator")
{
return true;
}
return false;
} }
private bool ComputeIsInWhiteList(IMethod calledMethod) private bool ComputeIsInWhiteList(IMethod calledMethod)
@ -259,6 +326,11 @@ namespace Obfuz.ObfusPasses.CallObfus
TypeDef typeDef = declaringType.ResolveTypeDef(); TypeDef typeDef = declaringType.ResolveTypeDef();
if (IsSpecialNotObfuscatedMethod(typeDef, calledMethod))
{
return true;
}
string assName = typeDef.Module.Assembly.Name; string assName = typeDef.Module.Assembly.Name;
string typeFullName = typeDef.FullName; string typeFullName = typeDef.FullName;
string methodName = calledMethod.Name; string methodName = calledMethod.Name;
@ -288,9 +360,44 @@ namespace Obfuz.ObfusPasses.CallObfus
return false; return false;
} }
public override bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir) private bool IsInWhiteList(IMethod method)
{ {
if (_whiteListMethodCache.GetValue(calledMethod)) if (!_whiteListMethodCache.TryGetValue(method, out var isWhiteList))
{
isWhiteList = ComputeIsInWhiteList(method);
_whiteListMethodCache.Add(method, isWhiteList);
}
return isWhiteList;
}
private bool IsTypeSelfAndParentPublic(TypeDef type)
{
if (type.DeclaringType != null && !IsTypeSelfAndParentPublic(type.DeclaringType))
{
return false;
}
return type.IsPublic;
}
public override bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop)
{
if (IsInWhiteList(calledMethod))
{
return false;
}
// mono has more strict access control, calls non-public method will raise exception.
if (PlatformUtil.IsMonoBackend())
{
MethodDef calledMethodDef = calledMethod.ResolveMethodDef();
if (calledMethodDef != null && (!calledMethodDef.IsPublic || !IsTypeSelfAndParentPublic(calledMethodDef.DeclaringType)))
{
return false;
}
}
ObfuscationRule rule = GetMethodObfuscationRule(callerMethod);
if (currentInLoop && rule.obfuscateCallInLoop == false)
{ {
return false; return false;
} }

View File

@ -0,0 +1,53 @@
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));
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

@ -1,265 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Obfuz.ObfusPasses.CallObfus
{
struct DelegateProxyMethodData
{
public readonly FieldDef delegateInstanceField;
public readonly MethodDef delegateInvokeMethod;
public DelegateProxyMethodData(FieldDef delegateInstanceField, MethodDef delegateInvokeMethod)
{
this.delegateInstanceField = delegateInstanceField;
this.delegateInvokeMethod = delegateInvokeMethod;
}
}
class DelegateProxyAllocator : GroupByModuleEntityBase
{
private readonly CachedDictionary<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

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

View File

@ -1,81 +0,0 @@
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

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

View File

@ -1,52 +0,0 @@
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

@ -3,17 +3,27 @@
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);
bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir); ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method);
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 bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir); public abstract ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method);
public abstract bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop);
} }
} }

View File

@ -6,15 +6,14 @@ namespace Obfuz.ObfusPasses.CallObfus
{ {
public interface IObfuscator public interface IObfuscator
{ {
bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions); void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List<Instruction> obfuscatedInstructions);
void Done(); void Done();
} }
public abstract class ObfuscatorBase : IObfuscator public abstract class ObfuscatorBase : IObfuscator
{ {
public abstract bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions); public abstract void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List<Instruction> obfuscatedInstructions);
public abstract void Done(); public abstract void Done();
} }
} }

View File

@ -1,30 +0,0 @@
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

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

View File

@ -1,125 +0,0 @@
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

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

View File

@ -23,7 +23,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.moduleEntityManager, _settings); _dataObfuscator = new DefaultConstEncryptor(ctx.encryptionScopeProvider, ctx.rvaDataAllocator, ctx.constFieldAllocator, ctx.moduleEntityManager, _settings);
} }
public override void Stop() public override void Stop()

View File

@ -1,22 +1,28 @@
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(GroupByModuleEntityManager moduleEntityManager, ConstEncryptionSettingsFacade settings) public DefaultConstEncryptor(EncryptionScopeProvider encryptionScopeProvider, RvaDataAllocator rvaDataAllocator, ConstFieldAllocator constFieldAllocator, GroupByModuleEntityManager moduleEntityManager, ConstEncryptionSettingsFacade settings)
{ {
_encryptionScopeProvider = encryptionScopeProvider;
_rvaDataAllocator = rvaDataAllocator;
_constFieldAllocator = constFieldAllocator;
_moduleEntityManager = moduleEntityManager; _moduleEntityManager = moduleEntityManager;
_settings = settings; _settings = settings;
} }
@ -38,176 +44,74 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
private DefaultMetadataImporter GetModuleMetadataImporter(MethodDef method) private DefaultMetadataImporter GetModuleMetadataImporter(MethodDef method)
{ {
return _moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module); return _moduleEntityManager.GetDefaultModuleMetadataImporter(method.Module, _encryptionScopeProvider);
} }
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 = _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);
switch (random.NextInt(5))
{
case 0:
{
// = c = encrypted static field
FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
break;
}
case 1:
{
// c = a + b
int a = random.NextInt();
int b = value - a;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Add));
break;
}
case 2:
{
// c = a * b
int a = random.NextInt() | 0x1;
int ra = MathUtil.ModInverse32(a);
int b = ra * value;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Mul));
break;
}
case 3:
{
// c = a ^ b
int a = random.NextInt();
int b = a ^ value;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoInt(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Xor));
break;
}
default:
{ {
if (needCacheValue) if (needCacheValue)
{ {
FieldDef cacheField = constFieldAllocator.Allocate(value); FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, 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 encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); int encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, 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));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaInt)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaInt));
break;
}
}
} }
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 = _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);
switch (random.NextInt(5))
{
case 0:
{
// c = encrypted static field
FieldDef cacheField = constFieldAllocator.Allocate(value);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField));
break;
}
case 1:
{
// c = a + b
long a = random.NextLong();
long b = value - a;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Add));
break;
}
case 2:
{
// c = a * b
long a = random.NextLong() | 0x1;
long ra = MathUtil.ModInverse64(a);
long b = ra * value;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Mul));
break;
}
case 3:
{
// c = a ^ b
long a = random.NextLong();
long b = a ^ value;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstTwoLong(a, b, random, constProbability, constFieldAllocator, obfuscatedInstructions);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Xor));
break;
}
default:
{ {
if (needCacheValue) if (needCacheValue)
{ {
FieldDef cacheField = constFieldAllocator.Allocate(value); FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, 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);
long encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt); long encryptedValue = encryptionScope.encryptor.Encrypt(value, ops, salt);
RvaData rvaData = rvaDataAllocator.Allocate(encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, 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));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaLong)); obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaLong));
break;
}
}
} }
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(value); FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, 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(encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, 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,25 +121,21 @@ 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(value); FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, 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(encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, 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));
@ -268,7 +168,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
{ {
if (!_encryptedRvaFields.TryGetValue(fieldDef, out var encryptedRvaData)) if (!_encryptedRvaFields.TryGetValue(fieldDef, out var encryptedRvaData))
{ {
EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(fieldDef.Module); EncryptionScopeInfo encryptionScope = _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);
@ -281,7 +181,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
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);
AssertUtil.AreArrayEqual(originalBytes, decryptedBytes, "Decrypted bytes should match the original bytes after encryption and decryption."); Assert.AreEqual(originalBytes, decryptedBytes, "Decrypted bytes should match the original bytes after encryption and decryption.");
} }
return encryptedRvaData; return encryptedRvaData;
} }
@ -301,26 +201,23 @@ 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(value); FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, 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(encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, 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,8 +0,0 @@
fileFormatVersion: 2
guid: 02fb097cf61874c41923b3ef23fee199
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,133 +0,0 @@
using dnlib.DotNet;
using Obfuz.Conf;
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Xml;
namespace Obfuz.ObfusPasses.ControlFlowObfus
{
struct ObfuscationRuleData
{
public readonly ObfuscationLevel obfuscationLevel;
public ObfuscationRuleData(ObfuscationLevel level)
{
obfuscationLevel = level;
}
}
interface IObfuscationPolicy
{
bool NeedObfuscate(MethodDef method);
ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
abstract class ObfuscationPolicyBase : IObfuscationPolicy
{
public abstract bool NeedObfuscate(MethodDef method);
public abstract ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
class ConfigurableObfuscationPolicy : ObfuscationPolicyBase
{
class ObfuscationRule : IRule<ObfuscationRule>
{
public ObfuscationLevel? obfuscationLevel;
public void InheritParent(ObfuscationRule parentRule)
{
if (obfuscationLevel == null)
obfuscationLevel = parentRule.obfuscationLevel;
}
}
class MethodSpec : MethodRuleBase<ObfuscationRule>
{
}
class TypeSpec : TypeRuleBase<MethodSpec, ObfuscationRule>
{
}
class AssemblySpec : AssemblyRuleBase<TypeSpec, MethodSpec, ObfuscationRule>
{
}
private static readonly ObfuscationRule s_default = new ObfuscationRule()
{
obfuscationLevel = ObfuscationLevel.Basic,
};
private ObfuscationRule _global;
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _xmlParser;
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
{
_xmlParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(
toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobal);
LoadConfigs(xmlConfigFiles);
}
private void LoadConfigs(List<string> configFiles)
{
_xmlParser.LoadConfigs(configFiles);
if (_global == null)
{
_global = s_default;
}
else
{
_global.InheritParent(s_default);
}
_xmlParser.InheritParentRules(_global);
}
private void ParseGlobal(string configFile, XmlElement ele)
{
switch (ele.Name)
{
case "global": _global = ParseObfuscationRule(configFile, ele); break;
default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
}
}
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
{
var rule = new ObfuscationRule();
if (ele.HasAttribute("obfuscationLevel"))
{
rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
}
return rule;
}
private ObfuscationRule GetMethodObfuscationRule(MethodDef method)
{
if (!_methodRuleCache.TryGetValue(method, out var rule))
{
rule = _xmlParser.GetMethodRule(method, _global);
_methodRuleCache[method] = rule;
}
return rule;
}
public override bool NeedObfuscate(MethodDef method)
{
ObfuscationRule rule = GetMethodObfuscationRule(method);
return rule.obfuscationLevel.Value > ObfuscationLevel.None;
}
public override ObfuscationRuleData GetObfuscationRuleData(MethodDef method)
{
var rule = GetMethodObfuscationRule(method);
return new ObfuscationRuleData(rule.obfuscationLevel.Value);
}
}
}

View File

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

View File

@ -1,80 +0,0 @@
using dnlib.DotNet;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Settings;
using Obfuz.Utils;
namespace Obfuz.ObfusPasses.ControlFlowObfus
{
class ObfusMethodContext
{
public MethodDef method;
public LocalVariableAllocator localVariableAllocator;
public IRandom localRandom;
public EncryptionScopeInfo encryptionScope;
public DefaultMetadataImporter importer;
public ConstFieldAllocator constFieldAllocator;
public int minInstructionCountOfBasicBlockToObfuscate;
public IRandom CreateRandom()
{
return encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method));
}
}
internal class ControlFlowObfusPass : ObfuscationMethodPassBase
{
private readonly ControlFlowObfuscationSettingsFacade _settings;
private IObfuscationPolicy _obfuscationPolicy;
private IObfuscator _obfuscator;
public ControlFlowObfusPass(ControlFlowObfuscationSettingsFacade settings)
{
_settings = settings;
_obfuscator = new DefaultObfuscator();
}
public override ObfuscationPassType Type => ObfuscationPassType.ControlFlowObfus;
public override void Start()
{
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
_obfuscationPolicy = new ConfigurableObfuscationPolicy(
ctx.coreSettings.assembliesToObfuscate,
_settings.ruleFiles);
}
public override void Stop()
{
}
protected override bool NeedObfuscateMethod(MethodDef method)
{
return _obfuscationPolicy.NeedObfuscate(method);
}
protected override void ObfuscateData(MethodDef method)
{
//Debug.Log($"Obfuscating method: {method.FullName} with EvalStackObfusPass");
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager;
var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method);
var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method));
var obfusMethodCtx = new ObfusMethodContext
{
method = method,
localVariableAllocator = new LocalVariableAllocator(method),
encryptionScope = encryptionScope,
constFieldAllocator = moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module),
localRandom = localRandom,
importer = moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module),
minInstructionCountOfBasicBlockToObfuscate = _settings.minInstructionCountOfBasicBlockToObfuscate,
};
_obfuscator.Obfuscate(method, obfusMethodCtx);
}
}
}

View File

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

View File

@ -1,19 +0,0 @@
using dnlib.DotNet;
namespace Obfuz.ObfusPasses.ControlFlowObfus
{
class DefaultObfuscator : ObfuscatorBase
{
public override bool Obfuscate(MethodDef method, ObfusMethodContext ctx)
{
//Debug.Log($"Obfuscating method: {method.FullName} with ControlFlowObfusPass");
var mcfc = new MethodControlFlowCalculator(method, ctx.CreateRandom(), ctx.constFieldAllocator, ctx.minInstructionCountOfBasicBlockToObfuscate);
if (!mcfc.TryObfus())
{
//Debug.LogWarning($"not obfuscate method: {method.FullName}");
return false;
}
return true;
}
}
}

View File

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

View File

@ -1,14 +0,0 @@
using dnlib.DotNet;
namespace Obfuz.ObfusPasses.ControlFlowObfus
{
interface IObfuscator
{
bool Obfuscate(MethodDef method, ObfusMethodContext ctx);
}
abstract class ObfuscatorBase : IObfuscator
{
public abstract bool Obfuscate(MethodDef method, ObfusMethodContext ctx);
}
}

View File

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

View File

@ -1,947 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Assertions;
namespace Obfuz.ObfusPasses.ControlFlowObfus
{
class MethodControlFlowCalculator
{
class BasicBlockInputOutputArguments
{
public readonly List<Local> locals = new List<Local>();
public BasicBlockInputOutputArguments()
{
}
public BasicBlockInputOutputArguments(MethodDef method, List<EvalDataTypeWithSig> inputStackDatas)
{
ICorLibTypes corLibTypes = method.Module.CorLibTypes;
foreach (var data in inputStackDatas)
{
Local local = new Local(GetLocalTypeSig(corLibTypes, data));
locals.Add(local);
method.Body.Variables.Add(local);
}
}
private TypeSig GetLocalTypeSig(ICorLibTypes corLibTypes, EvalDataTypeWithSig type)
{
TypeSig typeSig = type.typeSig;
switch (type.type)
{
case EvalDataType.Int32: return corLibTypes.Int32;
case EvalDataType.Int64: return corLibTypes.Int64;
case EvalDataType.Float: return corLibTypes.Single;
case EvalDataType.Double: return corLibTypes.Double;
case EvalDataType.I: return typeSig ?? corLibTypes.IntPtr;
case EvalDataType.Ref: return typeSig == null || MetaUtil.IsValueType(typeSig) ? corLibTypes.Object : typeSig;
case EvalDataType.ValueType: Assert.IsNotNull(typeSig); return typeSig;
case EvalDataType.Token: throw new System.NotSupportedException("Token type is not supported in BasicBlockInputOutputArguments");
default: throw new System.NotSupportedException("not supported EvalDataType");
}
}
}
class BasicBlockInfo
{
public BlockGroup group;
//public int order;
public bool isSaveStackBlock;
public BasicBlockInfo prev;
public BasicBlockInfo next;
public List<Instruction> instructions;
public List<EvalDataTypeWithSig> inputStackDatas;
public List<EvalDataTypeWithSig> outputStackDatas;
public List<BasicBlockInfo> inBasicBlocks = new List<BasicBlockInfo>();
public List<BasicBlockInfo> outBasicBlocks = new List<BasicBlockInfo>();
public BasicBlockInputOutputArguments inputArgs;
public BasicBlockInputOutputArguments outputArgs;
public Instruction FirstInstruction => instructions[0];
public Instruction LastInstruction => instructions[instructions.Count - 1];
public Instruction GroupFirstInstruction => group.basicBlocks[0].FirstInstruction;
//public void InsertNext(BasicBlockInfo nextBb)
//{
// if (next != null)
// {
// next.prev = nextBb;
// nextBb.next = next;
// }
// nextBb.prev = this;
// next = nextBb;
//}
public void InsertBefore(BasicBlockInfo prevBb)
{
prev.next = prevBb;
prevBb.prev = prev;
prevBb.next = this;
this.prev = prevBb;
}
public void AddOutBasicBlock(BasicBlockInfo outBb)
{
if (!outBasicBlocks.Contains(outBb))
{
outBasicBlocks.Add(outBb);
outBb.inBasicBlocks.Add(this);
}
}
public void ClearInBasicBlocks()
{
foreach (var inBb in inBasicBlocks)
{
inBb.outBasicBlocks.Remove(this);
}
inBasicBlocks.Clear();
}
public void RetargetInBasicBlocksTo(BasicBlockInfo prevBb, Dictionary<Instruction, BasicBlockInfo> inst2bb)
{
var oldInBlocks = new List<BasicBlockInfo>(inBasicBlocks);
ClearInBasicBlocks();
foreach (var oldInBb in oldInBlocks)
{
oldInBb.AddOutBasicBlock(prevBb);
}
// inBB => saveBb => cur
foreach (BasicBlockInfo inBb in prevBb.inBasicBlocks)
{
if (inBb.instructions.Count == 0)
{
// empty block, no need to retarget
continue;
}
Instruction lastInst = inBb.instructions.Last();
if (lastInst.Operand is Instruction targetInst)
{
if (inst2bb.TryGetValue(targetInst, out BasicBlockInfo targetBb) && targetBb == this)
{
// retarget to prevBb
lastInst.Operand = prevBb.FirstInstruction;
}
}
else if (lastInst.Operand is Instruction[] targetInsts)
{
for (int i = 0; i < targetInsts.Length; i++)
{
targetInst = targetInsts[i];
if (inst2bb.TryGetValue(targetInst, out BasicBlockInfo targetBb) && targetBb == this)
{
targetInsts[i] = prevBb.FirstInstruction;
}
}
}
}
}
}
private readonly MethodDef _method;
private readonly IRandom _random;
private readonly ConstFieldAllocator _constFieldAllocator;
private readonly int _minInstructionCountOfBasicBlockToObfuscate;
private readonly BasicBlockInfo _bbHead;
public MethodControlFlowCalculator(MethodDef method, IRandom random, ConstFieldAllocator constFieldAllocator, int minInstructionCountOfBasicBlockToObfuscate)
{
_method = method;
_random = random;
_constFieldAllocator = constFieldAllocator;
_minInstructionCountOfBasicBlockToObfuscate = minInstructionCountOfBasicBlockToObfuscate;
_bbHead = new BasicBlockInfo()
{
instructions = new List<Instruction>(),
inputStackDatas = new List<EvalDataTypeWithSig>(),
outputStackDatas = new List<EvalDataTypeWithSig>(),
};
}
private void BuildBasicBlockLink(EvalStackCalculator evc)
{
BasicBlockInfo prev = _bbHead;
var bb2bb = new Dictionary<BasicBlock, BasicBlockInfo>();
foreach (BasicBlock bb in evc.BasicBlockCollection.Blocks)
{
EvalStackState ess = evc.GetEvalStackState(bb);
var newBB = new BasicBlockInfo
{
prev = prev,
next = null,
instructions = bb.instructions,
inputStackDatas = ess.inputStackDatas,
outputStackDatas = ess.runStackDatas,
};
prev.next = newBB;
prev = newBB;
bb2bb.Add(bb, newBB);
}
foreach (BasicBlock bb in evc.BasicBlockCollection.Blocks)
{
BasicBlockInfo bbi = bb2bb[bb];
foreach (var inBb in bb.inBlocks)
{
bbi.inBasicBlocks.Add(bb2bb[inBb]);
}
foreach (var outBb in bb.outBlocks)
{
bbi.outBasicBlocks.Add(bb2bb[outBb]);
}
}
// let _bbHead point to the first basic block
//_bbHead.instructions.Add(Instruction.Create(OpCodes.Br, _bbHead.next.FirstInstruction));
_bbHead.next.inBasicBlocks.Add(_bbHead);
_bbHead.outBasicBlocks.Add(_bbHead.next);
}
private bool CheckNotContainsNotSupportedEvalStackData()
{
for (BasicBlockInfo cur = _bbHead; cur != null; cur = cur.next)
{
foreach (var data in cur.inputStackDatas)
{
if (data.type == EvalDataType.Unknown || data.type == EvalDataType.Token)
{
Debug.LogError($"NotSupported EvalStackData found in method: {_method.FullName}, type: {data.type}");
return false;
}
}
}
return true;
}
private void WalkInputArgumentGroup(BasicBlockInfo cur, BasicBlockInputOutputArguments inputArgs)
{
if (cur.inputArgs != null)
{
Assert.AreEqual(cur.inputArgs, inputArgs, "input arguments not match");
return;
}
cur.inputArgs = inputArgs;
foreach (BasicBlockInfo inputBB in cur.inBasicBlocks)
{
if (inputBB.outputArgs != null)
{
Assert.AreEqual(inputBB.outputArgs, inputArgs, $"Input BB {inputBB} outputArgs does not match in method: {_method.FullName}");
continue;
}
inputBB.outputArgs = cur.inputArgs;
foreach (var outBB in inputBB.outBasicBlocks)
{
WalkInputArgumentGroup(outBB, inputArgs);
}
}
}
private readonly BasicBlockInputOutputArguments emptyEvalStackArgs = new BasicBlockInputOutputArguments();
private void ComputeInputOutputArguments()
{
for (BasicBlockInfo cur = _bbHead; cur != null; cur = cur.next)
{
if (cur.inputArgs == null)
{
if (cur.inputStackDatas.Count == 0)
{
cur.inputArgs = emptyEvalStackArgs;
}
else
{
var inputArgs = new BasicBlockInputOutputArguments(_method, cur.inputStackDatas);
WalkInputArgumentGroup(cur, inputArgs);
}
}
if (cur.outputArgs == null && cur.outputStackDatas.Count == 0)
{
cur.outputArgs = emptyEvalStackArgs;
}
}
for (BasicBlockInfo cur = _bbHead; cur != null; cur = cur.next)
{
if (cur.inputArgs == null)
{
throw new System.Exception($"Input arguments for BasicBlock {cur} in method {_method.FullName} is null");
}
if (cur.outputArgs == null)
{
if (cur.instructions.Count > 0)
{
Code lastInstCode = cur.LastInstruction.OpCode.Code;
Assert.IsTrue(lastInstCode == Code.Throw || lastInstCode == Code.Rethrow);
cur.outputStackDatas = new List<EvalDataTypeWithSig>();
}
cur.outputArgs = emptyEvalStackArgs;
}
}
}
private BasicBlockInfo CreateSaveStackBasicBlock(BasicBlockInfo to)
{
if (to.group == null)
{
throw new Exception($"BasicBlock {to} in method {_method.FullName} does not belong to any group. This should not happen.");
}
var saveLocalBasicBlock = new BasicBlockInfo
{
group = to.group,
isSaveStackBlock = true,
inputStackDatas = to.inputStackDatas,
inputArgs = to.inputArgs,
outputStackDatas = new List<EvalDataTypeWithSig>(),
outputArgs = emptyEvalStackArgs,
instructions = new List<Instruction>(),
};
var locals = to.inputArgs.locals;
if (locals.Count > 0)
{
to.instructions.InsertRange(0, locals.Select(l => Instruction.Create(OpCodes.Ldloc, l)));
}
for (int i = locals.Count - 1; i >= 0; i--)
{
saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Stloc, locals[i]));
}
to.inputArgs = emptyEvalStackArgs;
to.inputStackDatas = new List<EvalDataTypeWithSig>();
BlockGroup group = to.group;
group.basicBlocks.Insert(group.basicBlocks.IndexOf(to), saveLocalBasicBlock);
group.switchMachineCases.Add(new SwitchMachineCase { index = -1, prepareBlock = saveLocalBasicBlock, targetBlock = to });
saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Ldsfld, (FieldDef)null));
saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Stloc, GlobalSwitchIndexLocal));
saveLocalBasicBlock.instructions.Add(Instruction.Create(OpCodes.Br, group.switchMachineEntryInst));
return saveLocalBasicBlock;
}
private void AdjustInputOutputEvalStack()
{
Dictionary<Instruction, BasicBlockInfo> inst2bb = BuildInstructionToBasicBlockInfoDic();
for (BasicBlockInfo cur = _bbHead.next; cur != null; cur = cur.next)
{
if (cur.inputArgs.locals.Count == 0 && cur.instructions.Count < _minInstructionCountOfBasicBlockToObfuscate)
{
// small block, no need to save stack
continue;
}
BasicBlockInfo saveBb = CreateSaveStackBasicBlock(cur);
cur.InsertBefore(saveBb);
cur.RetargetInBasicBlocksTo(saveBb, inst2bb);
//saveBb.AddOutBasicBlock(cur);
}
}
private void InsertSwitchMachineBasicBlockForGroups(BlockGroup rootGroup)
{
Dictionary<Instruction, BasicBlockInfo> inst2bb = BuildInstructionToBasicBlockInfoDic();
InsertSwitchMachineBasicBlockForGroup(rootGroup, inst2bb);
}
private void ShuffleBasicBlocks0(List<BasicBlockInfo> bbs)
{
if (bbs.Count <= 2)
{
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 sectionsExcludeFirstLast = new List<List<BasicBlockInfo>>();
//List<BasicBlockInfo> currentSection = firstSection;
//for (int i = 1; i < n; i++)
//{
// BasicBlockInfo cur = bbs[i];
// if (cur.inputArgs.locals.Count == 0)
// {
// currentSection = new List<BasicBlockInfo>() { cur };
// sectionsExcludeFirstLast.Add(currentSection);
// }
// else
// {
// currentSection.Add(cur);
// }
//}
//if (sectionsExcludeFirstLast.Count <= 1)
//{
// return;
//}
//var lastSection = sectionsExcludeFirstLast.Last();
//sectionsExcludeFirstLast.RemoveAt(sectionsExcludeFirstLast.Count - 1);
//RandomUtil.ShuffleList(sectionsExcludeFirstLast, _random);
//bbs.Clear();
//bbs.AddRange(firstSection);
//bbs.AddRange(sectionsExcludeFirstLast.SelectMany(section => section));
//bbs.AddRange(lastSection);
//Assert.AreEqual(n, bbs.Count, "Shuffled basic blocks count should be the same as original count");
}
private void ShuffleBasicBlocks(List<BasicBlockInfo> bbs)
{
// TODO
int n = bbs.Count;
BasicBlockInfo groupPrev = bbs[0].prev;
BasicBlockInfo groupNext = bbs[n - 1].next;
//RandomUtil.ShuffleList(bbs, _random);
ShuffleBasicBlocks0(bbs);
BasicBlockInfo prev = groupPrev;
for (int i = 0; i < n; i++)
{
BasicBlockInfo cur = bbs[i];
cur.prev = prev;
prev.next = cur;
prev = cur;
}
prev.next = groupNext;
if (groupNext != null)
{
groupNext.prev = prev;
}
}
private 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)
{
if (group.subGroups != null && group.subGroups.Count > 0)
{
foreach (var subGroup in group.subGroups)
{
InsertSwitchMachineBasicBlockForGroup(subGroup, inst2bb);
}
}
else if (group.switchMachineCases.Count > 0)
{
Assert.IsTrue(group.basicBlocks.Count > 0, "Group should contain at least one basic block");
BasicBlockInfo firstBlock = group.basicBlocks[0];
var firstCase = group.switchMachineCases[0];
//Assert.AreEqual(firstCase.prepareBlock, firstBlock, "First case prepare block should be the first basic block in group");
Assert.IsTrue(firstCase.targetBlock.inputArgs.locals.Count == 0);
Assert.IsTrue(firstCase.targetBlock.inputStackDatas.Count == 0);
var instructions = new List<Instruction>()
{
Instruction.Create(OpCodes.Ldsfld, (FieldDef)null),
Instruction.Create(OpCodes.Stloc, GlobalSwitchIndexLocal),
group.switchMachineEntryInst,
group.switchMachineInst,
Instruction.Create(OpCodes.Br, firstCase.targetBlock.FirstInstruction),
};
if (firstCase.prepareBlock != firstBlock || firstBlock.inputStackDatas.Count != 0)
{
instructions.Insert(0, Instruction.Create(OpCodes.Br, firstBlock.FirstInstruction));
}
var switchMachineBb = new BasicBlockInfo()
{
group = group,
inputArgs = firstBlock.inputArgs,
outputArgs = emptyEvalStackArgs,
inputStackDatas = firstBlock.inputStackDatas,
outputStackDatas = new List<EvalDataTypeWithSig>(),
instructions = instructions,
};
firstBlock.InsertBefore(switchMachineBb);
group.basicBlocks.Insert(0, switchMachineBb);
ShuffleBasicBlocks(group.basicBlocks);
List<Instruction> switchTargets = (List<Instruction>)group.switchMachineInst.Operand;
RandomUtil.ShuffleList(group.switchMachineCases, _random);
for (int i = 0, n = group.switchMachineCases.Count; i < n; i++)
{
SwitchMachineCase switchMachineCase = group.switchMachineCases[i];
switchMachineCase.index = i;
List<Instruction> prepareBlockInstructions = switchMachineCase.prepareBlock.instructions;
Instruction setBranchIndexInst = prepareBlockInstructions[prepareBlockInstructions.Count - 3];
Assert.AreEqual(setBranchIndexInst.OpCode, OpCodes.Ldsfld, "first instruction of prepareBlock should be Ldsfld");
//setBranchIndexInst.Operand = i;
var indexField = _constFieldAllocator.Allocate(i);
setBranchIndexInst.Operand = indexField;
switchTargets.Add(switchMachineCase.targetBlock.FirstInstruction);
}
// after shuffle
//Assert.IsTrue(instructions.Count == 4 || instructions.Count == 5, "Switch machine basic block should contain 4 or 5 instructions");
Instruction loadFirstIndex = instructions[instructions.Count - 5];
Assert.AreEqual(Code.Ldsfld, loadFirstIndex.OpCode.Code, "First instruction should be Ldsfld");
loadFirstIndex.Operand = _constFieldAllocator.Allocate(firstCase.index);
}
}
private bool IsPrevBasicBlockControlFlowNextToThis(BasicBlockInfo cur)
{
Instruction lastInst = cur.prev.LastInstruction;
switch (lastInst.OpCode.FlowControl)
{
case FlowControl.Cond_Branch:
case FlowControl.Call:
case FlowControl.Next:
case FlowControl.Break:
{
return true;
}
default: return false;
}
}
private void InsertBrInstructionForConjoinedBasicBlocks()
{
for (BasicBlockInfo cur = _bbHead.next.next; cur != null; cur = cur.next)
{
if (cur.group == cur.prev.group && IsPrevBasicBlockControlFlowNextToThis(cur))
{
cur.prev.instructions.Add(Instruction.Create(OpCodes.Br, cur.FirstInstruction));
}
}
}
private Dictionary<Instruction, BasicBlockInfo> BuildInstructionToBasicBlockInfoDic()
{
var inst2bb = new Dictionary<Instruction, BasicBlockInfo>();
for (BasicBlockInfo cur = _bbHead.next; cur != null; cur = cur.next)
{
foreach (var inst in cur.instructions)
{
inst2bb[inst] = cur;
}
}
return inst2bb;
}
private class SwitchMachineCase
{
public int index;
public BasicBlockInfo prepareBlock;
public BasicBlockInfo targetBlock;
}
private class BlockGroup
{
public BlockGroup parent;
public List<Instruction> instructions;
public List<BlockGroup> subGroups;
public List<BasicBlockInfo> basicBlocks;
public Instruction switchMachineEntryInst;
public Instruction switchMachineInst;
public List<SwitchMachineCase> switchMachineCases;
public BlockGroup(List<Instruction> instructions, Dictionary<Instruction, BlockGroup> inst2group)
{
this.instructions = instructions;
UpdateInstructionGroup(inst2group);
}
public BlockGroup(BlockGroup parent, List<Instruction> instructions, Dictionary<Instruction, BlockGroup> inst2group)
{
this.instructions = instructions;
UpdateInstructionGroup(parent, inst2group);
}
public BlockGroup RootParent => parent == null ? this : parent.RootParent;
public void SetParent(BlockGroup newParent)
{
if (parent != null)
{
Assert.IsTrue(parent != newParent, "Parent group should not be the same as new parent");
Assert.IsTrue(parent.subGroups.Contains(this), "Parent group should already contain this group");
parent.subGroups.Remove(this);
}
parent = newParent;
if (newParent.subGroups == null)
{
newParent.subGroups = new List<BlockGroup>();
}
Assert.IsFalse(newParent.subGroups.Contains(this), "New parent group should not already contain this group");
newParent.subGroups.Add(this);
}
private void UpdateInstructionGroup(Dictionary<Instruction, BlockGroup> inst2group)
{
foreach (var inst in instructions)
{
if (inst2group.TryGetValue(inst, out BlockGroup existGroup))
{
if (this != existGroup)
{
BlockGroup rootParent = existGroup.RootParent;
if (rootParent != this)
{
rootParent.SetParent(this);
}
}
}
else
{
inst2group[inst] = this;
}
}
}
private void UpdateInstructionGroup(BlockGroup parentGroup, Dictionary<Instruction, BlockGroup> inst2group)
{
foreach (var inst in instructions)
{
BlockGroup existGroup = inst2group[inst];
Assert.AreEqual(parentGroup, existGroup, "Instruction group parent should be the same as parent group");
inst2group[inst] = this;
}
SetParent(parentGroup);
}
public void SplitInstructionsNotInAnySubGroupsToIndividualGroups(Dictionary<Instruction, BlockGroup> inst2group)
{
if (subGroups == null || subGroups.Count == 0 || instructions.Count == 0)
{
return;
}
foreach (var subGroup in subGroups)
{
subGroup.SplitInstructionsNotInAnySubGroupsToIndividualGroups(inst2group);
}
var finalGroupList = new List<BlockGroup>();
var curGroupInstructions = new List<Instruction>();
var firstInst2SubGroup = subGroups.ToDictionary(g => g.instructions[0]);
foreach (var inst in instructions)
{
BlockGroup group = inst2group[inst];
if (group == this)
{
curGroupInstructions.Add(inst);
}
else
{
if (curGroupInstructions.Count > 0)
{
finalGroupList.Add(new BlockGroup(this, curGroupInstructions, inst2group));
curGroupInstructions = new List<Instruction>();
}
if (firstInst2SubGroup.TryGetValue(inst, out var subGroup))
{
finalGroupList.Add(subGroup);
}
}
}
if (curGroupInstructions.Count > 0)
{
finalGroupList.Add(new BlockGroup(this, curGroupInstructions, inst2group));
}
this.subGroups = finalGroupList;
}
public void ComputeBasicBlocks(Dictionary<Instruction, BasicBlockInfo> inst2bb, Func<Local> switchIndexLocalGetter)
{
if (subGroups == null || subGroups.Count == 0)
{
basicBlocks = new List<BasicBlockInfo>();
foreach (var inst in instructions)
{
BasicBlockInfo block = inst2bb[inst];
if (block.group != null)
{
if (block.group != this)
{
throw new Exception("BasicBlockInfo group should be the same as this BlockGroup");
}
}
else
{
block.group = this;
basicBlocks.Add(block);
}
}
switchMachineEntryInst = Instruction.Create(OpCodes.Ldloc, switchIndexLocalGetter());
switchMachineInst = Instruction.Create(OpCodes.Switch, new List<Instruction>());
switchMachineCases = new List<SwitchMachineCase>();
return;
}
foreach (var subGroup in subGroups)
{
subGroup.ComputeBasicBlocks(inst2bb, switchIndexLocalGetter);
}
}
}
private class TryBlockGroup : BlockGroup
{
public TryBlockGroup(List<Instruction> instructions, Dictionary<Instruction, BlockGroup> inst2group) : base(instructions, inst2group)
{
}
}
private class ExceptionHandlerGroup : BlockGroup
{
public readonly ExceptionHandler exceptionHandler;
public ExceptionHandlerGroup(ExceptionHandler exceptionHandler, List<Instruction> instructions, Dictionary<Instruction, BlockGroup> inst2group) : base(instructions, inst2group)
{
this.exceptionHandler = exceptionHandler;
}
}
private class ExceptionFilterGroup : BlockGroup
{
public readonly ExceptionHandler exceptionHandler;
public ExceptionFilterGroup(ExceptionHandler exceptionHandler, List<Instruction> instructions, Dictionary<Instruction, BlockGroup> inst2group) : base(instructions, inst2group)
{
this.exceptionHandler = exceptionHandler;
}
}
private class ExceptionHandlerWithFilterGroup : BlockGroup
{
public readonly ExceptionHandler exceptionHandler;
//public readonly ExceptionFilterGroup filterGroup;
//public readonly ExceptionHandlerGroup handlerGroup;
public ExceptionHandlerWithFilterGroup(ExceptionHandler exceptionHandler, List<Instruction> filterInstructions, List<Instruction> handlerInstructions, List<Instruction> allInstructions, Dictionary<Instruction, BlockGroup> inst2group) : base(allInstructions, inst2group)
{
this.exceptionHandler = exceptionHandler;
var filterGroup = new ExceptionFilterGroup(exceptionHandler, filterInstructions, inst2group);
var handlerGroup = new ExceptionHandlerGroup(exceptionHandler, handlerInstructions, inst2group);
}
}
class TryBlockInfo
{
public Instruction tryStart;
public Instruction tryEnd;
public TryBlockGroup blockGroup;
}
private Dictionary<Instruction, int> BuildInstruction2Index()
{
IList<Instruction> instructions = _method.Body.Instructions;
var inst2Index = new Dictionary<Instruction, int>(instructions.Count);
for (int i = 0; i < instructions.Count; i++)
{
Instruction inst = instructions[i];
inst2Index.Add(inst, i);
}
return inst2Index;
}
private BlockGroup SplitBasicBlockGroup()
{
Dictionary<Instruction, int> inst2Index = BuildInstruction2Index();
var inst2blockGroup = new Dictionary<Instruction, BlockGroup>();
List<Instruction> instructions = (List<Instruction>)_method.Body.Instructions;
var tryBlocks = new List<TryBlockInfo>();
foreach (var ex in _method.Body.ExceptionHandlers)
{
TryBlockInfo tryBlock = tryBlocks.Find(block => block.tryStart == ex.TryStart && block.tryEnd == ex.TryEnd);
if (tryBlock == null)
{
int startIndex = inst2Index[ex.TryStart];
int endIndex = ex.TryEnd != null ? inst2Index[ex.TryEnd] : inst2Index.Count;
TryBlockGroup blockGroup = new TryBlockGroup(instructions.GetRange(startIndex, endIndex - startIndex), inst2blockGroup);
tryBlock = new TryBlockInfo
{
tryStart = ex.TryStart,
tryEnd = ex.TryEnd,
blockGroup = blockGroup,
};
tryBlocks.Add(tryBlock);
}
if (ex.FilterStart != null)
{
int filterStartIndex = inst2Index[ex.FilterStart];
int filterEndIndex = ex.HandlerStart != null ? inst2Index[ex.HandlerStart] : inst2Index.Count;
int handlerStartIndex = filterEndIndex;
int handlerEndIndex = ex.HandlerEnd != null ? inst2Index[ex.HandlerEnd] : inst2Index.Count;
var filterHandlerGroup = new ExceptionHandlerWithFilterGroup(ex,
instructions.GetRange(filterStartIndex, filterEndIndex - filterStartIndex),
instructions.GetRange(handlerStartIndex, handlerEndIndex - handlerStartIndex),
instructions.GetRange(filterStartIndex, handlerEndIndex - filterStartIndex), inst2blockGroup);
}
else
{
int handlerStartIndex = inst2Index[ex.HandlerStart];
int handlerEndIndex = ex.HandlerEnd != null ? inst2Index[ex.HandlerEnd] : inst2Index.Count;
ExceptionHandlerGroup handlerGroup = new ExceptionHandlerGroup(ex, instructions.GetRange(handlerStartIndex, handlerEndIndex - handlerStartIndex), inst2blockGroup);
}
}
var rootGroup = new BlockGroup(new List<Instruction>(instructions), inst2blockGroup);
rootGroup.SplitInstructionsNotInAnySubGroupsToIndividualGroups(inst2blockGroup);
rootGroup.ComputeBasicBlocks(BuildInstructionToBasicBlockInfoDic(), () => GlobalSwitchIndexLocal);
return rootGroup;
}
private void FixInstructionTargets()
{
var inst2bb = BuildInstructionToBasicBlockInfoDic();
foreach (var ex in _method.Body.ExceptionHandlers)
{
if (ex.TryStart != null)
{
ex.TryStart = inst2bb[ex.TryStart].GroupFirstInstruction;
}
if (ex.TryEnd != null)
{
ex.TryEnd = inst2bb[ex.TryEnd].GroupFirstInstruction;
}
if (ex.HandlerStart != null)
{
ex.HandlerStart = inst2bb[ex.HandlerStart].GroupFirstInstruction;
}
if (ex.HandlerEnd != null)
{
ex.HandlerEnd = inst2bb[ex.HandlerEnd].GroupFirstInstruction;
}
if (ex.FilterStart != null)
{
ex.FilterStart = inst2bb[ex.FilterStart].GroupFirstInstruction;
}
}
//foreach (var inst in inst2bb.Keys)
//{
// if (inst.Operand is Instruction targetInst)
// {
// inst.Operand = inst2bb[targetInst].FirstInstruction;
// }
// else if (inst.Operand is Instruction[] targetInsts)
// {
// for (int i = 0; i < targetInsts.Length; i++)
// {
// targetInsts[i] = inst2bb[targetInsts[i]].FirstInstruction;
// }
// }
//}
}
private void BuildInstructions()
{
IList<Instruction> methodInstructions = _method.Body.Instructions;
methodInstructions.Clear();
for (BasicBlockInfo cur = _bbHead.next; cur != null; cur = cur.next)
{
foreach (Instruction inst in cur.instructions)
{
methodInstructions.Add(inst);
}
}
_method.Body.InitLocals = true;
//_method.Body.MaxStack = Math.Max(_method.Body.MaxStack , (ushort)1); // TODO: set to a reasonable value
//_method.Body.KeepOldMaxStack = true;
//_method.Body.UpdateInstructionOffsets();
}
public bool TryObfus()
{
// TODO: TEMP
//if (_method.Body.HasExceptionHandlers)
//{
// return false;
//}
if (_method.HasGenericParameters || _method.DeclaringType.HasGenericParameters)
{
return false;
}
var evc = new EvalStackCalculator(_method);
BuildBasicBlockLink(evc);
if (!CheckNotContainsNotSupportedEvalStackData())
{
Debug.LogError($"Method {_method.FullName} contains unsupported EvalStackData, obfuscation skipped.");
return false;
}
BlockGroup rootGroup = SplitBasicBlockGroup();
if (rootGroup.basicBlocks != null && rootGroup.basicBlocks.Count == 1)
{
return false;
}
ComputeInputOutputArguments();
AdjustInputOutputEvalStack();
InsertBrInstructionForConjoinedBasicBlocks();
InsertSwitchMachineBasicBlockForGroups(rootGroup);
FixInstructionTargets();
BuildInstructions();
return true;
}
}
}

View File

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

View File

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

View File

@ -1,147 +0,0 @@
using dnlib.DotNet;
using Obfuz.Conf;
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Xml;
namespace Obfuz.ObfusPasses.EvalStackObfus
{
struct ObfuscationRuleData
{
public readonly ObfuscationLevel obfuscationLevel;
public readonly float obfuscationPercentage;
public ObfuscationRuleData(ObfuscationLevel level, float percentage)
{
obfuscationLevel = level;
obfuscationPercentage = percentage;
}
}
interface IObfuscationPolicy
{
bool NeedObfuscate(MethodDef method);
ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
abstract class ObfuscationPolicyBase : IObfuscationPolicy
{
public abstract bool NeedObfuscate(MethodDef method);
public abstract ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
class ConfigurableObfuscationPolicy : ObfuscationPolicyBase
{
class ObfuscationRule : IRule<ObfuscationRule>
{
public ObfuscationLevel? obfuscationLevel;
public float? obfuscationPercentage;
public void InheritParent(ObfuscationRule parentRule)
{
if (obfuscationLevel == null)
obfuscationLevel = parentRule.obfuscationLevel;
if (obfuscationPercentage == null)
obfuscationPercentage = parentRule.obfuscationPercentage;
}
}
class MethodSpec : MethodRuleBase<ObfuscationRule>
{
}
class TypeSpec : TypeRuleBase<MethodSpec, ObfuscationRule>
{
}
class AssemblySpec : AssemblyRuleBase<TypeSpec, MethodSpec, ObfuscationRule>
{
}
private static readonly ObfuscationRule s_default = new ObfuscationRule()
{
obfuscationLevel = ObfuscationLevel.Basic,
obfuscationPercentage = 0.05f,
};
private ObfuscationRule _global;
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _xmlParser;
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
{
_xmlParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(
toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobal);
LoadConfigs(xmlConfigFiles);
}
private void LoadConfigs(List<string> configFiles)
{
_xmlParser.LoadConfigs(configFiles);
if (_global == null)
{
_global = s_default;
}
else
{
_global.InheritParent(s_default);
}
if (_global.obfuscationPercentage.Value > 0.1f)
{
UnityEngine.Debug.LogWarning($"EvalStackObfus significantly increases the size of the obfuscated hot-update DLL. It is recommended to keep the obfuscationPercentage ≤ 0.1 (currently set to {_global.obfuscationPercentage.Value}).");
}
_xmlParser.InheritParentRules(_global);
}
private void ParseGlobal(string configFile, XmlElement ele)
{
switch (ele.Name)
{
case "global": _global = ParseObfuscationRule(configFile, ele); break;
default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
}
}
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
{
var rule = new ObfuscationRule();
if (ele.HasAttribute("obfuscationLevel"))
{
rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
}
if (ele.HasAttribute("obfuscationPercentage"))
{
rule.obfuscationPercentage = float.Parse(ele.GetAttribute("obfuscationPercentage"));
}
return rule;
}
private ObfuscationRule GetMethodObfuscationRule(MethodDef method)
{
if (!_methodRuleCache.TryGetValue(method, out var rule))
{
rule = _xmlParser.GetMethodRule(method, _global);
_methodRuleCache[method] = rule;
}
return rule;
}
public override bool NeedObfuscate(MethodDef method)
{
ObfuscationRule rule = GetMethodObfuscationRule(method);
return rule.obfuscationLevel.Value > ObfuscationLevel.None;
}
public override ObfuscationRuleData GetObfuscationRuleData(MethodDef method)
{
var rule = GetMethodObfuscationRule(method);
return new ObfuscationRuleData(rule.obfuscationLevel.Value, rule.obfuscationPercentage.Value);
}
}
}

View File

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

View File

@ -1,225 +0,0 @@
using dnlib.DotNet.Emit;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.EvalStackObfus
{
class DefaultObfuscator : ObfuscatorBase
{
public override bool ObfuscateInt(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IRandom random = ctx.localRandom;
switch (random.NextInt(4))
{
case 0:
{
// x = x + a
int a = 0;
float constProbability = 0f;
ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 1:
{
// x = x * a * ra
int a = random.NextInt() | 0x1; // Ensure a is not zero
int ra = MathUtil.ModInverse32(a);
float constProbability = 0.5f;
ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
case 2:
{
// x = (x * a + b) * ra - (b * ra)
int a = random.NextInt() | 0x1; // Ensure a is not zero
int ra = MathUtil.ModInverse32(a);
int b = random.NextInt();
int b_ra = -b * ra;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstInt(ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(b_ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 3:
{
// x = ((x + a) * b + c) * rb - (a*b + c) * rb
int a = random.NextInt();
int b = random.NextInt() | 0x1; // Ensure b is not zero
int rb = MathUtil.ModInverse32(b);
int c = random.NextInt();
int r = -(a * b + c) * rb;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstInt(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstInt(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(c, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstInt(rb, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(r, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
default: return false;
}
}
public override bool ObfuscateLong(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IRandom random = ctx.localRandom;
switch (random.NextInt(4))
{
case 0:
{
// x = x + a
long a = 0;
float constProbability = 0f;
ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 1:
{
// x = x * a * ra
long a = random.NextLong() | 0x1L; // Ensure a is not zero
long ra = MathUtil.ModInverse64(a);
float constProbability = 0.5f;
ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
case 2:
{
// x = (x * a + b) * ra - (b * ra)
long a = random.NextLong() | 0x1L; // Ensure a is not zero
long ra = MathUtil.ModInverse64(a);
long b = random.NextLong();
long b_ra = -b * ra;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstLong(ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(b_ra, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 3:
{
// x = ((x + a) * b + c) * rb - (a*b + c) * rb
long a = random.NextLong();
long b = random.NextLong() | 0x1L; // Ensure b is not zero
long rb = MathUtil.ModInverse64(b);
long c = random.NextLong();
long r = -(a * b + c) * rb;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstLong(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstLong(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(c, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstLong(rb, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(r, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
default: return false;
}
}
public override bool ObfuscateFloat(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IRandom random = ctx.localRandom;
switch (random.NextInt(3))
{
case 0:
{
// x = x + 0f
float a = 0.0f;
float constProbability = 0f;
ConstObfusUtil.LoadConstFloat(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 1:
{
// x = x * 1f;
float a = 1.0f;
float constProbability = 0f;
ConstObfusUtil.LoadConstFloat(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
case 2:
{
// x = (x + a) * b; a = 0.0f, b = 1.0f
float a = 0.0f;
float b = 1.0f;
float constProbability = 0f;
ConstObfusUtil.LoadConstFloat(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstFloat(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
default: return false;
}
}
public override bool ObfuscateDouble(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IRandom random = ctx.localRandom;
switch (random.NextInt(3))
{
case 0:
{
// x = x + 0.0
double a = 0.0;
float constProbability = 0f;
ConstObfusUtil.LoadConstDouble(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case 1:
{
// x = x * 1.0;
double a = 1.0;
float constProbability = 0f;
ConstObfusUtil.LoadConstDouble(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
case 2:
{
// x = (x + a) * b; a = 0.0, b = 1.0
double a = 0.0;
double b = 1.0;
float constProbability = 0f;
ConstObfusUtil.LoadConstDouble(a, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstDouble(b, random, constProbability, ctx.constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
default: return false;
}
}
}
}

View File

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

View File

@ -1,114 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.EvalStackObfus
{
class ObfusMethodContext
{
public MethodDef method;
public EvalStackCalculator evalStackCalculator;
public LocalVariableAllocator localVariableAllocator;
public IRandom localRandom;
public EncryptionScopeInfo encryptionScope;
public DefaultMetadataImporter importer;
public ConstFieldAllocator constFieldAllocator;
public float obfuscationPercentage;
}
internal class EvalStackObfusPass : ObfuscationMethodPassBase
{
private readonly EvalStackObfuscationSettingsFacade _settings;
private IObfuscationPolicy _obfuscationPolicy;
private IObfuscator _obfuscator;
public EvalStackObfusPass(EvalStackObfuscationSettingsFacade settings)
{
_settings = settings;
_obfuscator = new DefaultObfuscator();
}
public override ObfuscationPassType Type => ObfuscationPassType.EvalStackObfus;
public override void Start()
{
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
_obfuscationPolicy = new ConfigurableObfuscationPolicy(
ctx.coreSettings.assembliesToObfuscate,
_settings.ruleFiles);
}
public override void Stop()
{
}
protected override bool NeedObfuscateMethod(MethodDef method)
{
return _obfuscationPolicy.NeedObfuscate(method);
}
protected bool TryObfuscateInstruction(Instruction inst, EvalDataType dataType, List<Instruction> outputInstructions, ObfusMethodContext ctx)
{
switch (dataType)
{
case EvalDataType.Int32: return _obfuscator.ObfuscateInt(inst, outputInstructions, ctx);
case EvalDataType.Int64: return _obfuscator.ObfuscateLong(inst, outputInstructions, ctx);
case EvalDataType.Float: return _obfuscator.ObfuscateFloat(inst, outputInstructions, ctx);
case EvalDataType.Double: return _obfuscator.ObfuscateDouble(inst, outputInstructions, ctx);
default: return false;
}
}
protected override void ObfuscateData(MethodDef method)
{
//Debug.Log($"Obfuscating method: {method.FullName} with EvalStackObfusPass");
IList<Instruction> instructions = method.Body.Instructions;
var outputInstructions = new List<Instruction>();
var totalFinalInstructions = new List<Instruction>();
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var calc = new EvalStackCalculator(method);
GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager;
var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method);
var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method));
var obfusMethodCtx = new ObfusMethodContext
{
method = method,
evalStackCalculator = calc,
localVariableAllocator = new LocalVariableAllocator(method),
encryptionScope = encryptionScope,
constFieldAllocator = moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module),
localRandom = localRandom,
importer = moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module),
obfuscationPercentage = ruleData.obfuscationPercentage,
};
for (int i = 0; i < instructions.Count; i++)
{
Instruction inst = instructions[i];
totalFinalInstructions.Add(inst);
if (calc.TryGetPushResult(inst, out EvalDataType dataType) && localRandom.NextInPercentage(ruleData.obfuscationPercentage))
{
outputInstructions.Clear();
if (TryObfuscateInstruction(inst, dataType, outputInstructions, obfusMethodCtx))
{
totalFinalInstructions.AddRange(outputInstructions);
}
}
}
instructions.Clear();
foreach (var obInst in totalFinalInstructions)
{
instructions.Add(obInst);
}
}
}
}

View File

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

View File

@ -1,24 +0,0 @@
using dnlib.DotNet.Emit;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.EvalStackObfus
{
interface IObfuscator
{
bool ObfuscateInt(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateLong(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateFloat(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateDouble(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
}
abstract class ObfuscatorBase : IObfuscator
{
public abstract bool ObfuscateInt(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateLong(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateFloat(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateDouble(Instruction inst, List<Instruction> outputInsts, ObfusMethodContext ctx);
}
}

View File

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

View File

@ -1,143 +0,0 @@
using dnlib.DotNet;
using Obfuz.Conf;
using Obfuz.Settings;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Xml;
namespace Obfuz.ObfusPasses.ExprObfus
{
struct ObfuscationRuleData
{
public readonly ObfuscationLevel obfuscationLevel;
public readonly float obfuscationPercentage;
public ObfuscationRuleData(ObfuscationLevel level, float percentage)
{
obfuscationLevel = level;
obfuscationPercentage = percentage;
}
}
interface IObfuscationPolicy
{
bool NeedObfuscate(MethodDef method);
ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
abstract class ObfuscationPolicyBase : IObfuscationPolicy
{
public abstract bool NeedObfuscate(MethodDef method);
public abstract ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
}
class ConfigurableObfuscationPolicy : ObfuscationPolicyBase
{
class ObfuscationRule : IRule<ObfuscationRule>
{
public ObfuscationLevel? obfuscationLevel;
public float? obfuscationPercentage;
public void InheritParent(ObfuscationRule parentRule)
{
if (obfuscationLevel == null)
obfuscationLevel = parentRule.obfuscationLevel;
if (obfuscationPercentage == null)
obfuscationPercentage = parentRule.obfuscationPercentage;
}
}
class MethodSpec : MethodRuleBase<ObfuscationRule>
{
}
class TypeSpec : TypeRuleBase<MethodSpec, ObfuscationRule>
{
}
class AssemblySpec : AssemblyRuleBase<TypeSpec, MethodSpec, ObfuscationRule>
{
}
private static readonly ObfuscationRule s_default = new ObfuscationRule()
{
obfuscationLevel = ObfuscationLevel.Basic,
obfuscationPercentage = 0.3f,
};
private ObfuscationRule _global;
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _xmlParser;
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
{
_xmlParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(
toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobal);
LoadConfigs(xmlConfigFiles);
}
private void LoadConfigs(List<string> configFiles)
{
_xmlParser.LoadConfigs(configFiles);
if (_global == null)
{
_global = s_default;
}
else
{
_global.InheritParent(s_default);
}
_xmlParser.InheritParentRules(_global);
}
private void ParseGlobal(string configFile, XmlElement ele)
{
switch (ele.Name)
{
case "global": _global = ParseObfuscationRule(configFile, ele); break;
default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
}
}
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
{
var rule = new ObfuscationRule();
if (ele.HasAttribute("obfuscationLevel"))
{
rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
}
if (ele.HasAttribute("obfuscationPercentage"))
{
rule.obfuscationPercentage = float.Parse(ele.GetAttribute("obfuscationPercentage"));
}
return rule;
}
private ObfuscationRule GetMethodObfuscationRule(MethodDef method)
{
if (!_methodRuleCache.TryGetValue(method, out var rule))
{
rule = _xmlParser.GetMethodRule(method, _global);
_methodRuleCache[method] = rule;
}
return rule;
}
public override bool NeedObfuscate(MethodDef method)
{
ObfuscationRule rule = GetMethodObfuscationRule(method);
return rule.obfuscationLevel.Value > ObfuscationLevel.None;
}
public override ObfuscationRuleData GetObfuscationRuleData(MethodDef method)
{
var rule = GetMethodObfuscationRule(method);
return new ObfuscationRuleData(rule.obfuscationLevel.Value, rule.obfuscationPercentage.Value);
}
}
}

View File

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

View File

@ -1,63 +1,16 @@
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.ObfusPasses.ExprObfus.Obfuscators;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;
namespace Obfuz.ObfusPasses.ExprObfus namespace Obfuz.ObfusPasses.ExprObfus
{ {
class ObfusMethodContext public class ExprObfusPass : InstructionObfuscationPassBase
{ {
public MethodDef method;
public EvalStackCalculator evalStackCalculator;
public LocalVariableAllocator localVariableAllocator;
public IRandom localRandom;
public EncryptionScopeInfo encryptionScope;
public DefaultMetadataImporter importer;
public ConstFieldAllocator constFieldAllocator;
public float obfuscationPercentage;
}
class ExprObfusPass : ObfuscationMethodPassBase
{
private readonly ExprObfuscationSettingsFacade _settings;
private readonly IObfuscator _basicObfuscator;
private readonly IObfuscator _advancedObfuscator;
private readonly IObfuscator _mostAdvancedObfuscator;
private IObfuscationPolicy _obfuscationPolicy;
public ExprObfusPass(ExprObfuscationSettingsFacade settings)
{
_settings = settings;
_basicObfuscator = new BasicObfuscator();
_advancedObfuscator = new AdvancedObfuscator();
_mostAdvancedObfuscator = new MostAdvancedObfuscator();
}
public override ObfuscationPassType Type => ObfuscationPassType.ExprObfus; public override ObfuscationPassType Type => ObfuscationPassType.ExprObfus;
public override void Start() public override void Start()
{ {
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
_obfuscationPolicy = new ConfigurableObfuscationPolicy(
ctx.coreSettings.assembliesToObfuscate,
_settings.ruleFiles);
}
private IObfuscator GetObfuscator(ObfuscationLevel level)
{
switch (level)
{
case ObfuscationLevel.None: return null;
case ObfuscationLevel.Basic: return _basicObfuscator;
case ObfuscationLevel.Advanced: return _advancedObfuscator;
case ObfuscationLevel.MostAdvanced: return _mostAdvancedObfuscator;
default: throw new System.ArgumentOutOfRangeException(nameof(level), level, "Unknown obfuscation level");
}
} }
public override void Stop() public override void Stop()
@ -67,107 +20,12 @@ namespace Obfuz.ObfusPasses.ExprObfus
protected override bool NeedObfuscateMethod(MethodDef method) protected override bool NeedObfuscateMethod(MethodDef method)
{ {
return _obfuscationPolicy.NeedObfuscate(method);
}
protected bool TryObfuscateInstruction(IObfuscator obfuscator, InstructionParameterInfo pi, Instruction inst, List<Instruction> outputInstructions, ObfusMethodContext ctx)
{
//Debug.Log($"Obfuscating instruction: {inst} in method: {ctx.method.FullName}");
IRandom localRandom = ctx.localRandom;
float obfuscationPercentage = ctx.obfuscationPercentage;
switch (inst.OpCode.Code)
{
case Code.Neg:
{
return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBasicUnaryOp(inst, pi.op1, pi.retType, outputInstructions, ctx);
}
case Code.Add:
case Code.Sub:
case Code.Mul:
case Code.Div:
case Code.Div_Un:
case Code.Rem:
case Code.Rem_Un:
{
return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBasicBinOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx);
}
case Code.And:
case Code.Or:
case Code.Xor:
{
return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBinBitwiseOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx);
}
case Code.Not:
{
return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateUnaryBitwiseOp(inst, pi.op1, pi.retType, outputInstructions, ctx);
}
case Code.Shl:
case Code.Shr:
case Code.Shr_Un:
{
return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBitShiftOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx);
}
}
return false; return false;
} }
protected override void ObfuscateData(MethodDef method) protected override bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
{ {
//Debug.Log($"Obfuscating method: {method.FullName} with ExprObfusPass"); return false;
IList<Instruction> instructions = method.Body.Instructions;
var outputInstructions = new List<Instruction>();
var totalFinalInstructions = new List<Instruction>();
ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var calc = new EvalStackCalculator(method);
GroupByModuleEntityManager moduleEntityManager = ctx.moduleEntityManager;
var encryptionScope = moduleEntityManager.EncryptionScopeProvider.GetScope(method.Module);
var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method);
var obfuscator = GetObfuscator(ruleData.obfuscationLevel);
var obfusMethodCtx = new ObfusMethodContext
{
method = method,
evalStackCalculator = calc,
localVariableAllocator = new LocalVariableAllocator(method),
encryptionScope = encryptionScope,
constFieldAllocator = moduleEntityManager.GetEntity<ConstFieldAllocator>(method.Module),
localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)),
importer = moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module),
obfuscationPercentage = ruleData.obfuscationPercentage,
};
for (int i = 0; i < instructions.Count; i++)
{
Instruction inst = instructions[i];
bool add = false;
if (calc.TryGetParameterInfo(inst, out InstructionParameterInfo pi))
{
outputInstructions.Clear();
if (TryObfuscateInstruction(obfuscator, pi, inst, outputInstructions, obfusMethodCtx))
{
// current instruction may be the target of control flow instruction, so we can't remove it directly.
// we replace it with nop now, then remove it in CleanUpInstructionPass
inst.OpCode = outputInstructions[0].OpCode;
inst.Operand = outputInstructions[0].Operand;
totalFinalInstructions.Add(inst);
for (int k = 1; k < outputInstructions.Count; k++)
{
totalFinalInstructions.Add(outputInstructions[k]);
}
add = true;
}
}
if (!add)
{
totalFinalInstructions.Add(inst);
}
}
instructions.Clear();
foreach (var obInst in totalFinalInstructions)
{
instructions.Add(obInst);
}
} }
} }
} }

View File

@ -1,28 +0,0 @@
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.ExprObfus
{
interface IObfuscator
{
bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
}
abstract class ObfuscatorBase : IObfuscator
{
public abstract bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
}
}

View File

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

View File

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

View File

@ -1,110 +0,0 @@
using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit;
using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{
class AdvancedObfuscator : BasicObfuscator
{
protected bool GenerateIdentityTransformForArgument(Instruction inst, EvalDataType op, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IRandom random = ctx.localRandom;
ConstFieldAllocator constFieldAllocator = ctx.constFieldAllocator;
switch (op)
{
case EvalDataType.Int32:
{
// = x + y = x + (y * a + b) * ra + (-b * ra)
int a = random.NextInt() | 0x1;
int ra = MathUtil.ModInverse32(a);
int b = random.NextInt();
int b_ra = -b * ra;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstInt(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstInt(ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstInt(b_ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
outputInsts.Add(inst.Clone());
return true;
}
case EvalDataType.Int64:
{
// = x + y = x + (y * a + b) * ra + (-b * ra)
long a = random.NextLong() | 0x1L;
long ra = MathUtil.ModInverse64(a);
long b = random.NextLong();
long b_ra = -b * ra;
float constProbability = 0.5f;
ConstObfusUtil.LoadConstLong(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstLong(ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
ConstObfusUtil.LoadConstLong(b_ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
outputInsts.Add(inst.Clone());
return true;
}
case EvalDataType.Float:
{
// = x + y = x + (y + a) * b; a = 0.0f, b = 1.0f
float a = 0.0f;
float b = 1.0f;
float constProbability = 0f;
ConstObfusUtil.LoadConstFloat(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstFloat(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
outputInsts.Add(inst.Clone());
return true;
}
case EvalDataType.Double:
{
// = x + y = x + (y + a) * b; a = 0.0, b = 1.0
double a = 0.0;
double b = 1.0;
float constProbability = 0f;
ConstObfusUtil.LoadConstDouble(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
ConstObfusUtil.LoadConstDouble(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
outputInsts.Add(inst.Clone());
return true;
}
default: return false;
}
}
public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return GenerateIdentityTransformForArgument(inst, op, outputInsts, ctx) || base.ObfuscateBasicUnaryOp(inst, op, ret, outputInsts, ctx);
}
public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return GenerateIdentityTransformForArgument(inst, op2, outputInsts, ctx) || base.ObfuscateBasicBinOp(inst, op1, op2, ret, outputInsts, ctx);
}
public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return GenerateIdentityTransformForArgument(inst, op, outputInsts, ctx) || base.ObfuscateUnaryBitwiseOp(inst, op, ret, outputInsts, ctx);
}
public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return GenerateIdentityTransformForArgument(inst, op2, outputInsts, ctx) || base.ObfuscateBinBitwiseOp(inst, op1, op2, ret, outputInsts, ctx);
}
public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return GenerateIdentityTransformForArgument(inst, op2, outputInsts, ctx) || base.ObfuscateBitShiftOp(inst, op1, op2, ret, outputInsts, ctx);
}
}
}

View File

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

View File

@ -1,282 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using System.Collections.Generic;
using UnityEngine;
namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{
class BasicObfuscator : ObfuscatorBase
{
private IMethod GetUnaryOpMethod(DefaultMetadataImporter importer, Code code, EvalDataType op1)
{
switch (code)
{
case Code.Neg:
{
switch (op1)
{
case EvalDataType.Int32: return importer.NegInt;
case EvalDataType.Int64: return importer.NegLong;
case EvalDataType.Float: return importer.NegFloat;
case EvalDataType.Double: return importer.NegDouble;
default: return null;
}
}
case Code.Not:
{
switch (op1)
{
case EvalDataType.Int32: return importer.NotInt;
case EvalDataType.Int64: return importer.NotLong;
default: return null;
}
}
default: return null;
}
}
private IMethod GetBinaryOpMethod(DefaultMetadataImporter importer, Code code, EvalDataType op1, EvalDataType op2)
{
switch (code)
{
case Code.Add:
{
switch (op1)
{
case EvalDataType.Int32: return op2 == op1 ? importer.AddInt : null;
case EvalDataType.Int64: return op2 == op1 ? importer.AddLong : null;
case EvalDataType.Float: return op2 == op1 ? importer.AddFloat : null;
case EvalDataType.Double: return op2 == op1 ? importer.AddDouble : null;
case EvalDataType.I:
{
switch (op2)
{
case EvalDataType.I: return importer.AddIntPtr;
case EvalDataType.Int32: return importer.AddIntPtrInt;
default: return null;
}
}
default: return null;
}
}
case Code.Sub:
{
switch (op1)
{
case EvalDataType.Int32: return op2 == op1 ? importer.SubtractInt : null;
case EvalDataType.Int64: return op2 == op1 ? importer.SubtractLong : null;
case EvalDataType.Float: return op2 == op1 ? importer.SubtractFloat : null;
case EvalDataType.Double: return op2 == op1 ? importer.SubtractDouble : null;
case EvalDataType.I:
{
switch (op2)
{
case EvalDataType.I: return importer.SubtractIntPtr;
case EvalDataType.Int32: return importer.SubtractIntPtrInt;
default: return null;
}
}
default: return null;
}
}
case Code.Mul:
{
switch (op1)
{
case EvalDataType.Int32: return op2 == op1 ? importer.MultiplyInt : null;
case EvalDataType.Int64: return op2 == op1 ? importer.MultiplyLong : null;
case EvalDataType.Float: return op2 == op1 ? importer.MultiplyFloat : null;
case EvalDataType.Double: return op2 == op1 ? importer.MultiplyDouble : null;
case EvalDataType.I:
{
switch (op2)
{
case EvalDataType.I: return importer.MultiplyIntPtr;
case EvalDataType.Int32: return importer.MultiplyIntPtrInt;
default: return null;
}
}
default: return null;
}
}
case Code.Div:
{
switch (op1)
{
case EvalDataType.Int32: return importer.DivideInt;
case EvalDataType.Int64: return importer.DivideLong;
case EvalDataType.Float: return importer.DivideFloat;
case EvalDataType.Double: return importer.DivideDouble;
default: return null;
}
}
case Code.Div_Un:
{
switch (op1)
{
case EvalDataType.Int32: return importer.DivideUnInt;
case EvalDataType.Int64: return importer.DivideUnLong;
default: return null;
}
}
case Code.Rem:
{
switch (op1)
{
case EvalDataType.Int32: return importer.RemInt;
case EvalDataType.Int64: return importer.RemLong;
case EvalDataType.Float: return importer.RemFloat;
case EvalDataType.Double: return importer.RemDouble;
default: return null;
}
}
case Code.Rem_Un:
{
switch (op1)
{
case EvalDataType.Int32: return importer.RemUnInt;
case EvalDataType.Int64: return importer.RemUnLong;
default: return null;
}
}
case Code.Neg:
{
switch (op1)
{
case EvalDataType.Int32: return importer.NegInt;
case EvalDataType.Int64: return importer.NegLong;
case EvalDataType.Float: return importer.NegFloat;
case EvalDataType.Double: return importer.NegDouble;
default: return null;
}
}
case Code.And:
{
switch (op1)
{
case EvalDataType.Int32: return importer.AndInt;
case EvalDataType.Int64: return importer.AndLong;
default: return null;
}
}
case Code.Or:
{
switch (op1)
{
case EvalDataType.Int32: return importer.OrInt;
case EvalDataType.Int64: return importer.OrLong;
default: return null;
}
}
case Code.Xor:
{
switch (op1)
{
case EvalDataType.Int32: return importer.XorInt;
case EvalDataType.Int64: return importer.XorLong;
default: return null;
}
}
case Code.Not:
{
switch (op1)
{
case EvalDataType.Int32: return importer.NotInt;
case EvalDataType.Int64: return importer.NotLong;
default: return null;
}
}
case Code.Shl:
{
switch (op1)
{
case EvalDataType.Int32: return importer.ShlInt;
case EvalDataType.Int64: return importer.ShlLong;
default: return null;
}
}
case Code.Shr:
{
switch (op1)
{
case EvalDataType.Int32: return importer.ShrInt;
case EvalDataType.Int64: return importer.ShrLong;
default: return null;
}
}
case Code.Shr_Un:
{
switch (op1)
{
case EvalDataType.Int32: return importer.ShrUnInt;
case EvalDataType.Int64: return importer.ShrUnLong;
default: return null;
}
}
default: return null;
}
}
public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IMethod opMethod = GetUnaryOpMethod(ctx.importer, inst.OpCode.Code, op);
if (opMethod == null)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate unary operation {inst.OpCode.Code} with different operand types: op={op}. This is a limitation of the BasicObfuscator.");
return false;
}
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
return true;
}
public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2);
if (opMethod == null)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator.");
return false;
}
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
return true;
}
public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IMethod opMethod = GetUnaryOpMethod(ctx.importer, inst.OpCode.Code, op);
if (opMethod == null)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate unary operation {inst.OpCode.Code} with different operand types: op={op}. This is a limitation of the BasicObfuscator.");
return false;
}
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
return true;
}
public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2);
if (opMethod == null)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator.");
return false;
}
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
return true;
}
public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
IMethod opMethod = GetBinaryOpMethod(ctx.importer, inst.OpCode.Code, op1, op2);
if (opMethod == null)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with operand type {op2}. This is a limitation of the BasicObfuscator.");
return false;
}
outputInsts.Add(Instruction.Create(OpCodes.Call, opMethod));
return true;
}
}
}

View File

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

View File

@ -1,83 +0,0 @@
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using System.Collections.Generic;
using System.Linq;
namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{
class MostAdvancedObfuscator : AdvancedObfuscator
{
private readonly BasicObfuscator _basicObfuscator = new BasicObfuscator();
public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (!base.ObfuscateBasicUnaryOp(inst, op, ret, outputInsts, ctx))
{
return false;
}
if (outputInsts.Last().OpCode.Code != inst.OpCode.Code)
{
return false;
}
outputInsts.RemoveAt(outputInsts.Count - 1);
return _basicObfuscator.ObfuscateBasicUnaryOp(inst, op, ret, outputInsts, ctx);
}
public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (!base.ObfuscateBasicBinOp(inst, op1, op2, ret, outputInsts, ctx))
{
return false;
}
if (outputInsts.Last().OpCode.Code != inst.OpCode.Code)
{
return false;
}
outputInsts.RemoveAt(outputInsts.Count - 1);
return _basicObfuscator.ObfuscateBasicBinOp(inst, op1, op2, ret, outputInsts, ctx);
}
public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (!base.ObfuscateUnaryBitwiseOp(inst, op, ret, outputInsts, ctx))
{
return false;
}
if (outputInsts.Last().OpCode.Code != inst.OpCode.Code)
{
return false;
}
outputInsts.RemoveAt(outputInsts.Count - 1);
return _basicObfuscator.ObfuscateUnaryBitwiseOp(inst, op, ret, outputInsts, ctx);
}
public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (!base.ObfuscateBinBitwiseOp(inst, op1, op2, ret, outputInsts, ctx))
{
return false;
}
if (outputInsts.Last().OpCode.Code != inst.OpCode.Code)
{
return false;
}
outputInsts.RemoveAt(outputInsts.Count - 1);
return _basicObfuscator.ObfuscateBinBitwiseOp(inst, op1, op2, ret, outputInsts, ctx);
}
public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (!base.ObfuscateBitShiftOp(inst, op1, op2, ret, outputInsts, ctx))
{
return false;
}
if (outputInsts.Last().OpCode.Code != inst.OpCode.Code)
{
return false;
}
outputInsts.RemoveAt(outputInsts.Count - 1);
return _basicObfuscator.ObfuscateBitShiftOp(inst, op1, op2, ret, outputInsts, ctx);
}
}
}

View File

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

View File

@ -11,15 +11,22 @@ 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(GroupByModuleEntityManager moduleEntityManager, FieldEncryptionSettingsFacade settings) public DefaultFieldEncryptor(EncryptionScopeProvider encryptionScopeProvider, 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;
@ -70,7 +77,7 @@ namespace Obfuz.ObfusPasses.FieldEncrypt
{ {
return info; return info;
} }
EncryptionScopeInfo encryptionScope = _moduleEntityManager.EncryptionScopeProvider.GetScope(field.Module); EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(field.Module);
IRandom random = CreateRandomForField(encryptionScope.localRandomCreator, field); IRandom random = CreateRandomForField(encryptionScope.localRandomCreator, field);
IEncryptor encryptor = encryptionScope.encryptor; IEncryptor encryptor = encryptionScope.encryptor;
@ -92,7 +99,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 = _moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module); DefaultMetadataImporter importer = GetMetadataImporter(method);
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)
@ -147,7 +154,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 = _moduleEntityManager.GetEntity<DefaultMetadataImporter>(method.Module); DefaultMetadataImporter importer = GetMetadataImporter(method);
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

@ -24,7 +24,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.moduleEntityManager, _settings); _memoryEncryptor = new DefaultFieldEncryptor(ctx.encryptionScopeProvider, 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

@ -2,9 +2,11 @@
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Editor; using Obfuz.Editor;
using Obfuz.Emit; using Obfuz.Emit;
using Obfuz.Settings;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Security;
using System.Text; using System.Text;
using UnityEngine.Assertions; using UnityEngine.Assertions;
@ -38,7 +40,7 @@ namespace Obfuz.ObfusPasses.Instinct
private string GetTypeName(TypeSig type) private string GetTypeName(TypeSig type)
{ {
type = type.RemovePinnedAndModifiers(); type = type.RemovePinnedAndModifiers();
switch (type.ElementType) switch(type.ElementType)
{ {
case ElementType.Class: case ElementType.Class:
case ElementType.ValueType: case ElementType.ValueType:
@ -90,7 +92,7 @@ namespace Obfuz.ObfusPasses.Instinct
} }
ObfuscationPassContext ctx = ObfuscationPassContext.Current; ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var importer = ctx.moduleEntityManager.GetEntity<DefaultMetadataImporter>(callingMethod.Module); var importer = ctx.moduleEntityManager.GetDefaultModuleMetadataImporter(callingMethod.Module, ctx.encryptionScopeProvider);
string methodName = methodDef.Name; string methodName = methodDef.Name;
switch (methodName) switch (methodName)

View File

@ -1,15 +1,54 @@
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Obfuz.ObfusPasses namespace Obfuz.ObfusPasses
{ {
public abstract class InstructionObfuscationPassBase : ObfuscationMethodPassBase public abstract class InstructionObfuscationPassBase : ObfuscationPassBase
{ {
protected virtual bool ForceProcessAllAssembliesAndIgnoreAllPolicy => false;
protected abstract bool NeedObfuscateMethod(MethodDef method);
public override void Process()
{
var ctx = ObfuscationPassContext.Current;
var modules = ForceProcessAllAssembliesAndIgnoreAllPolicy ? ctx.allObfuscationRelativeModules : ctx.modulesToObfuscate;
ObfuscationMethodWhitelist whiteList = ctx.whiteList;
ConfigurablePassPolicy passPolicy = ctx.passPolicy;
foreach (ModuleDef mod in modules)
{
if (!ForceProcessAllAssembliesAndIgnoreAllPolicy && whiteList.IsInWhiteList(mod))
{
continue;
}
// ToArray to avoid modify list exception
foreach (TypeDef type in mod.GetTypes().ToArray())
{
if (!ForceProcessAllAssembliesAndIgnoreAllPolicy && whiteList.IsInWhiteList(type))
{
continue;
}
// ToArray to avoid modify list exception
foreach (MethodDef method in type.Methods.ToArray())
{
if (!method.HasBody || (!ForceProcessAllAssembliesAndIgnoreAllPolicy && (ctx.whiteList.IsInWhiteList(method) || !Support(passPolicy.GetMethodObfuscationPasses(method)) || !NeedObfuscateMethod(method))))
{
continue;
}
// TODO if isGeneratedBy Obfuscator, continue
ObfuscateData(method);
}
}
}
}
protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex, protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex,
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions); List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions);
protected override void ObfuscateData(MethodDef method) private void ObfuscateData(MethodDef method)
{ {
IList<Instruction> instructions = method.Body.Instructions; IList<Instruction> instructions = method.Body.Instructions;
var outputInstructions = new List<Instruction>(); var outputInstructions = new List<Instruction>();

View File

@ -1,47 +0,0 @@
using dnlib.DotNet;
using System.Linq;
namespace Obfuz.ObfusPasses
{
public abstract class ObfuscationMethodPassBase : ObfuscationPassBase
{
protected virtual bool ForceProcessAllAssembliesAndIgnoreAllPolicy => false;
protected abstract bool NeedObfuscateMethod(MethodDef method);
protected abstract void ObfuscateData(MethodDef method);
public override void Process()
{
var ctx = ObfuscationPassContext.Current;
var modules = ForceProcessAllAssembliesAndIgnoreAllPolicy ? ctx.allObfuscationRelativeModules : ctx.modulesToObfuscate;
ObfuscationMethodWhitelist whiteList = ctx.whiteList;
ConfigurablePassPolicy passPolicy = ctx.passPolicy;
foreach (ModuleDef mod in modules)
{
if (!ForceProcessAllAssembliesAndIgnoreAllPolicy && whiteList.IsInWhiteList(mod))
{
continue;
}
// ToArray to avoid modify list exception
foreach (TypeDef type in mod.GetTypes().ToArray())
{
if (!ForceProcessAllAssembliesAndIgnoreAllPolicy && whiteList.IsInWhiteList(type))
{
continue;
}
// ToArray to avoid modify list exception
foreach (MethodDef method in type.Methods.ToArray())
{
if (!method.HasBody || (!ForceProcessAllAssembliesAndIgnoreAllPolicy && (ctx.whiteList.IsInWhiteList(method) || !Support(passPolicy.GetMethodObfuscationPasses(method)) || !NeedObfuscateMethod(method))))
{
continue;
}
// TODO if isGeneratedBy Obfuscator, continue
ObfuscateData(method);
}
}
}
}
}
}

View File

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

View File

@ -14,15 +14,11 @@ namespace Obfuz.ObfusPasses
CallObfus = 0x200, CallObfus = 0x200,
ExprObfus = 0x400, ExprObfus = 0x400,
ControlFlowObfus = 0x800, ControlFlowObfus = 0x800,
EvalStackObfus = 0x1000,
RemoveConstField = 0x100000, AllObfus = SymbolObfus | CallObfus | ExprObfus | ControlFlowObfus,
WaterMark = 0x200000,
AllObfus = SymbolObfus | CallObfus | ExprObfus | ControlFlowObfus | EvalStackObfus,
AllEncrypt = ConstEncrypt | FieldEncrypt, AllEncrypt = ConstEncrypt | FieldEncrypt,
MethodBodyObfusOrEncrypt = ConstEncrypt | CallObfus | ExprObfus | ControlFlowObfus | EvalStackObfus, MethodBodyObfusOrEncrypt = ConstEncrypt | CallObfus | ExprObfus | ControlFlowObfus,
All = ~0, All = ~0,
} }

View File

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

View File

@ -1,34 +0,0 @@
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

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

View File

@ -1,14 +0,0 @@
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

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

View File

@ -1,73 +0,0 @@
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

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

View File

@ -1,29 +1,28 @@
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers using System.Text;
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers
{ {
public class DebugNameMaker : NameMakerBase public class DebugNameMaker : NameMakerBase
{ {
private class DebugNameScope : INameScope private class TestNameScope : NameScopeBase
{ {
private int _nextIndex;
public bool AddPreservedName(string name) protected override void BuildNewName(StringBuilder nameBuilder, string originalName, string lastName)
{ {
return true; if (string.IsNullOrEmpty(lastName))
{
nameBuilder.Append($"${originalName}");
} }
else
public string GetNewName(string originalName, bool reuse)
{ {
return $"${originalName}"; nameBuilder.Append($"${originalName}{_nextIndex++}");
} }
public bool IsNamePreserved(string name)
{
return false;
} }
} }
protected override INameScope CreateNameScope() protected override INameScope CreateNameScope()
{ {
return new DebugNameScope(); return new TestNameScope();
} }
} }
} }

View File

@ -1,5 +1,6 @@
using dnlib.DotNet; using dnlib.DotNet;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using UnityEngine.Assertions; using UnityEngine.Assertions;
namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers namespace Obfuz.ObfusPasses.SymbolObfus.NameMakers

View File

@ -16,7 +16,7 @@ namespace Obfuz.ObfusPasses.SymbolObfus.Policies
None = 0x0, None = 0x0,
Private = 0x1, Private = 0x1,
Protected = 0x2, Protected = 0x2,
Public = 0x4, Public = 0x3,
} }
class MethodRuleSpec class MethodRuleSpec
@ -395,34 +395,12 @@ namespace Obfuz.ObfusPasses.SymbolObfus.Policies
private bool MatchModifier(ModifierType? modifierType, PropertyDef propertyDef) private bool MatchModifier(ModifierType? modifierType, PropertyDef propertyDef)
{ {
FieldAttributes access = default; return modifierType == null || (modifierType & ComputeModifierType((FieldAttributes)propertyDef.Attributes)) != 0;
if (propertyDef.GetMethod != null)
{
access |= (FieldAttributes)propertyDef.GetMethod.Access;
}
if (propertyDef.SetMethod != null)
{
access |= (FieldAttributes)propertyDef.SetMethod.Access;
}
return modifierType == null || (modifierType & ComputeModifierType(access)) != 0;
} }
private bool MatchModifier(ModifierType? modifierType, EventDef eventDef) private bool MatchModifier(ModifierType? modifierType, EventDef eventDef)
{ {
FieldAttributes access = default; return modifierType == null || (modifierType & ComputeModifierType((FieldAttributes)eventDef.Attributes)) != 0;
if (eventDef.AddMethod != null)
{
access |= (FieldAttributes)eventDef.AddMethod.Access;
}
if (eventDef.RemoveMethod != null)
{
access |= (FieldAttributes)eventDef.RemoveMethod.Access;
}
if (eventDef.InvokeMethod != null)
{
access |= (FieldAttributes)eventDef.InvokeMethod.Access;
}
return modifierType == null || (modifierType & ComputeModifierType(access)) != 0;
} }
private class MethodComputeCache private class MethodComputeCache

View File

@ -2,6 +2,7 @@
using Obfuz.Editor; using Obfuz.Editor;
using Obfuz.Utils; using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Obfuz.ObfusPasses.SymbolObfus.Policies namespace Obfuz.ObfusPasses.SymbolObfus.Policies
{ {
@ -23,7 +24,6 @@ namespace Obfuz.ObfusPasses.SymbolObfus.Policies
ConstValues.ZluaLuaInvokeAttributeFullName, ConstValues.ZluaLuaInvokeAttributeFullName,
ConstValues.ZluaLuaCallbackAttributeFullName, ConstValues.ZluaLuaCallbackAttributeFullName,
ConstValues.ZluaLuaMarshalAsAttributeFullName, ConstValues.ZluaLuaMarshalAsAttributeFullName,
ConstValues.BurstCompileFullName,
}; };

View File

@ -123,14 +123,14 @@ namespace Obfuz.ObfusPasses.SymbolObfus.Policies
}; };
private readonly CachedDictionary<TypeDef, bool> _computeDeclaringTypeDisableAllMemberRenamingCache; private readonly CachedDictionary<TypeDef, bool> _computeDeclaringTypeDisableAllMemberRenamingCache;
private readonly CachedDictionary<TypeDef, bool> _isSerializableCache; private readonly CachedDictionary<TypeDef, bool> _isInheritScriptCache;
private readonly CachedDictionary<TypeDef, bool> _isInheritFromMonoBehaviourCache; private readonly CachedDictionary<TypeDef, bool> _isInheritFromMonoBehaviourCache;
private readonly CachedDictionary<TypeDef, bool> _isScriptOrSerializableTypeCache; private readonly CachedDictionary<TypeDef, bool> _isScriptOrSerializableTypeCache;
public UnityRenamePolicy() public UnityRenamePolicy()
{ {
_computeDeclaringTypeDisableAllMemberRenamingCache = new CachedDictionary<TypeDef, bool>(ComputeDeclaringTypeDisableAllMemberRenaming); _computeDeclaringTypeDisableAllMemberRenamingCache = new CachedDictionary<TypeDef, bool>(ComputeDeclaringTypeDisableAllMemberRenaming);
_isSerializableCache = new CachedDictionary<TypeDef, bool>(MetaUtil.IsSerializableType); _isInheritScriptCache = new CachedDictionary<TypeDef, bool>(MetaUtil.IsScriptType);
_isInheritFromMonoBehaviourCache = new CachedDictionary<TypeDef, bool>(MetaUtil.IsInheritFromMonoBehaviour); _isInheritFromMonoBehaviourCache = new CachedDictionary<TypeDef, bool>(MetaUtil.IsInheritFromMonoBehaviour);
_isScriptOrSerializableTypeCache = new CachedDictionary<TypeDef, bool>(MetaUtil.IsScriptOrSerializableType); _isScriptOrSerializableTypeCache = new CachedDictionary<TypeDef, bool>(MetaUtil.IsScriptOrSerializableType);
} }
@ -153,6 +153,10 @@ namespace Obfuz.ObfusPasses.SymbolObfus.Policies
{ {
return true; return true;
} }
if (MetaUtil.HasBurstCompileAttribute(typeDef))
{
return true;
}
if (typeDef.DeclaringType != null) if (typeDef.DeclaringType != null)
{ {
return IsUnitySourceGeneratedAssemblyType(typeDef.DeclaringType); return IsUnitySourceGeneratedAssemblyType(typeDef.DeclaringType);
@ -187,10 +191,6 @@ namespace Obfuz.ObfusPasses.SymbolObfus.Policies
{ {
return false; return false;
} }
if (MetaUtil.HasBurstCompileAttribute(typeDef))
{
return false;
}
if (typeDef.Methods.Any(m => MetaUtil.HasRuntimeInitializeOnLoadMethodAttribute(m))) if (typeDef.Methods.Any(m => MetaUtil.HasRuntimeInitializeOnLoadMethodAttribute(m)))
{ {
return false; return false;
@ -213,7 +213,7 @@ namespace Obfuz.ObfusPasses.SymbolObfus.Policies
{ {
return false; return false;
} }
if (MetaUtil.HasBurstCompileAttribute(methodDef) || MetaUtil.HasBurstCompileAttribute(methodDef.DeclaringType) || MetaUtil.HasDOTSCompilerGeneratedAttribute(methodDef)) if (MetaUtil.HasBurstCompileAttribute(methodDef) || MetaUtil.HasDOTSCompilerGeneratedAttribute(methodDef))
{ {
return false; return false;
} }
@ -242,13 +242,17 @@ namespace Obfuz.ObfusPasses.SymbolObfus.Policies
{ {
return false; return false;
} }
if (MetaUtil.HasBurstCompileAttribute(fieldDef))
{
return false;
}
return true; return true;
} }
public override bool NeedRename(PropertyDef propertyDef) public override bool NeedRename(PropertyDef propertyDef)
{ {
TypeDef typeDef = propertyDef.DeclaringType; TypeDef typeDef = propertyDef.DeclaringType;
if (_isSerializableCache.GetValue(typeDef)) if (_isScriptOrSerializableTypeCache.GetValue(typeDef))
{ {
bool isGetterPublic = propertyDef.GetMethod != null && propertyDef.GetMethod.IsPublic && !propertyDef.GetMethod.IsStatic; bool isGetterPublic = propertyDef.GetMethod != null && propertyDef.GetMethod.IsPublic && !propertyDef.GetMethod.IsStatic;
bool isSetterPublic = propertyDef.SetMethod != null && propertyDef.SetMethod.IsPublic && !propertyDef.SetMethod.IsStatic; bool isSetterPublic = propertyDef.SetMethod != null && propertyDef.SetMethod.IsPublic && !propertyDef.SetMethod.IsStatic;

View File

@ -1,42 +0,0 @@
using dnlib.DotNet;
using Obfuz.Settings;
using Obfuz.Utils;
using System.Collections.Generic;
using System.Threading;
namespace Obfuz.ObfusPasses.SymbolObfus
{
public class ReflectionCompatibilityDetectionPass : ObfuscationPassBase
{
private readonly SymbolObfuscationSettingsFacade _settings;
public override ObfuscationPassType Type => ObfuscationPassType.SymbolObfus;
public ReflectionCompatibilityDetectionPass(SymbolObfuscationSettingsFacade settings)
{
_settings = settings;
}
public override void Start()
{
}
public override void Stop()
{
}
public override void Process()
{
var ctx = ObfuscationPassContext.Current;
var assemblyCache = ctx.assemblyCache;
var toObfuscatedModules = ctx.modulesToObfuscate;
var obfuscatedAndNotObfuscatedModules = ctx.allObfuscationRelativeModules;
var toObfuscatedModuleSet = new HashSet<ModuleDef>(ctx.modulesToObfuscate);
var renamePolicy = SymbolRename.CreateDefaultRenamePolicy(_settings.ruleFiles, _settings.customRenamePolicyTypes);
var reflectionCompatibilityDetector = new ReflectionCompatibilityDetector(ctx.modulesToObfuscate, ctx.allObfuscationRelativeModules, renamePolicy);
reflectionCompatibilityDetector.Analyze();
}
}
}

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