parent
f3762f05ce
commit
db26f5d3ce
|
@ -0,0 +1,233 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine.Assertions;
|
||||||
|
|
||||||
|
namespace Obfuz.Emit
|
||||||
|
{
|
||||||
|
public class ModuleConstFieldAllocator
|
||||||
|
{
|
||||||
|
private readonly ModuleDef _module;
|
||||||
|
private readonly IRandom _random;
|
||||||
|
|
||||||
|
private TypeDef _holderTypeDef;
|
||||||
|
|
||||||
|
class ConstFieldInfo
|
||||||
|
{
|
||||||
|
public FieldDef field;
|
||||||
|
public object value;
|
||||||
|
}
|
||||||
|
private readonly Dictionary<object, ConstFieldInfo> _allocatedFields = new Dictionary<object, ConstFieldInfo>();
|
||||||
|
private readonly Dictionary<FieldDef, ConstFieldInfo> _field2Fields = new Dictionary<FieldDef, ConstFieldInfo>();
|
||||||
|
|
||||||
|
private readonly List<TypeDef> _holderTypeDefs = new List<TypeDef>();
|
||||||
|
|
||||||
|
|
||||||
|
public ModuleConstFieldAllocator(ModuleDef mod, IRandom random)
|
||||||
|
{
|
||||||
|
_module = mod;
|
||||||
|
_random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int maxFieldCount = 1000;
|
||||||
|
|
||||||
|
|
||||||
|
private TypeSig GetTypeSigOfValue(object value)
|
||||||
|
{
|
||||||
|
if (value is int)
|
||||||
|
return _module.CorLibTypes.Int32;
|
||||||
|
if (value is long)
|
||||||
|
return _module.CorLibTypes.Int64;
|
||||||
|
if (value is float)
|
||||||
|
return _module.CorLibTypes.Single;
|
||||||
|
if (value is double)
|
||||||
|
return _module.CorLibTypes.Double;
|
||||||
|
if (value is string)
|
||||||
|
return _module.CorLibTypes.String;
|
||||||
|
if (value is byte[])
|
||||||
|
return new SZArraySig(_module.CorLibTypes.Byte);
|
||||||
|
throw new NotSupportedException($"Unsupported type: {value.GetType()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConstFieldInfo CreateConstFieldInfo(object value)
|
||||||
|
{
|
||||||
|
if (_holderTypeDef == null || _holderTypeDef.Fields.Count >= maxFieldCount)
|
||||||
|
{
|
||||||
|
_module.EnableTypeDefFindCache = false;
|
||||||
|
ITypeDefOrRef objectTypeRef = _module.Import(typeof(object));
|
||||||
|
_holderTypeDef = new TypeDefUser("$Obfuz$ConstFieldHolder$", objectTypeRef);
|
||||||
|
_module.Types.Add(_holderTypeDef);
|
||||||
|
_holderTypeDefs.Add(_holderTypeDef);
|
||||||
|
_module.EnableTypeDefFindCache = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var field = new FieldDefUser($"$RVA_Value{_holderTypeDef.Fields.Count}", new FieldSig(GetTypeSigOfValue(value)), FieldAttributes.Static | FieldAttributes.Private | FieldAttributes.InitOnly);
|
||||||
|
field.DeclaringType = _holderTypeDef;
|
||||||
|
return new ConstFieldInfo
|
||||||
|
{
|
||||||
|
field = field,
|
||||||
|
value = value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldDef AllocateAny(object value)
|
||||||
|
{
|
||||||
|
if (!_allocatedFields.TryGetValue(value, out var field))
|
||||||
|
{
|
||||||
|
field = CreateConstFieldInfo(value);
|
||||||
|
_allocatedFields.Add(value, field);
|
||||||
|
_field2Fields.Add(field.field, field);
|
||||||
|
}
|
||||||
|
return field.field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDef Allocate(int value)
|
||||||
|
{
|
||||||
|
return AllocateAny(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDef Allocate(long value)
|
||||||
|
{
|
||||||
|
return AllocateAny(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDef Allocate(float value)
|
||||||
|
{
|
||||||
|
return AllocateAny(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDef Allocate(double value)
|
||||||
|
{
|
||||||
|
return AllocateAny(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDef Allocate(string value)
|
||||||
|
{
|
||||||
|
return AllocateAny(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//public FieldDef Allocate(byte[] value)
|
||||||
|
//{
|
||||||
|
// throw new NotImplementedException();
|
||||||
|
//}
|
||||||
|
|
||||||
|
private void CreateCCtorOfRvaTypeDef(TypeDef type)
|
||||||
|
{
|
||||||
|
var cctor = new MethodDefUser(".cctor",
|
||||||
|
MethodSig.CreateStatic(_module.CorLibTypes.Void),
|
||||||
|
MethodImplAttributes.IL | MethodImplAttributes.Managed,
|
||||||
|
MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private);
|
||||||
|
cctor.DeclaringType = type;
|
||||||
|
//_rvaTypeDef.Methods.Add(cctor);
|
||||||
|
var body = new CilBody();
|
||||||
|
cctor.Body = body;
|
||||||
|
var ins = body.Instructions;
|
||||||
|
|
||||||
|
//IMethod method = _module.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new[] { typeof(Array), typeof(RuntimeFieldHandle) }));
|
||||||
|
//Assert.IsNotNull(method);
|
||||||
|
|
||||||
|
// TODO. obfuscate init codes
|
||||||
|
foreach (var field in type.Fields)
|
||||||
|
{
|
||||||
|
ConstFieldInfo constInfo = _field2Fields[field];
|
||||||
|
switch (constInfo.value)
|
||||||
|
{
|
||||||
|
case int i:
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Ldc_I4, i));
|
||||||
|
break;
|
||||||
|
case long l:
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Ldc_I8, l));
|
||||||
|
break;
|
||||||
|
case float f:
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Ldc_R4, f));
|
||||||
|
break;
|
||||||
|
case double d:
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Ldc_R8, d));
|
||||||
|
break;
|
||||||
|
case string s:
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Ldstr, s));
|
||||||
|
break;
|
||||||
|
//case byte[] b:
|
||||||
|
// ins.Add(Instruction.Create(OpCodes.Ldlen, b.Length));
|
||||||
|
// break;
|
||||||
|
default: throw new NotSupportedException($"Unsupported type: {constInfo.value.GetType()}");
|
||||||
|
}
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Stsfld, field));
|
||||||
|
}
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Done()
|
||||||
|
{
|
||||||
|
foreach (var typeDef in _holderTypeDefs)
|
||||||
|
{
|
||||||
|
CreateCCtorOfRvaTypeDef(typeDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ConstFieldAllocator
|
||||||
|
{
|
||||||
|
private readonly IRandom _random;
|
||||||
|
|
||||||
|
private readonly Dictionary<ModuleDef, ModuleConstFieldAllocator> _moduleAllocators = new Dictionary<ModuleDef, ModuleConstFieldAllocator>();
|
||||||
|
|
||||||
|
public ConstFieldAllocator(IRandom random)
|
||||||
|
{
|
||||||
|
_random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModuleConstFieldAllocator GetModuleAllocator(ModuleDef mod)
|
||||||
|
{
|
||||||
|
if (!_moduleAllocators.TryGetValue(mod, out var moduleAllocator))
|
||||||
|
{
|
||||||
|
moduleAllocator = new ModuleConstFieldAllocator(mod, _random);
|
||||||
|
_moduleAllocators[mod] = moduleAllocator;
|
||||||
|
}
|
||||||
|
return moduleAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, string value)
|
||||||
|
{
|
||||||
|
return GetModuleAllocator(mod).Allocate(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Done()
|
||||||
|
{
|
||||||
|
foreach (var moduleAllocator in _moduleAllocators.Values)
|
||||||
|
{
|
||||||
|
moduleAllocator.Done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//public FieldDef Allocate(ModuleDef mod, byte[] value)
|
||||||
|
//{
|
||||||
|
// return GetModuleAllocator(mod).Allocate(value);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,5 +11,6 @@ namespace Obfuz.Virtualization
|
||||||
public MethodDef method;
|
public MethodDef method;
|
||||||
public List<Instruction> output;
|
public List<Instruction> output;
|
||||||
public RvaDataAllocator rvaDataAllocator;
|
public RvaDataAllocator rvaDataAllocator;
|
||||||
|
public ConstFieldAllocator constFieldAllocator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
using System;
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Obfuz.Virtualization
|
namespace Obfuz.Virtualization
|
||||||
|
@ -8,36 +11,34 @@ namespace Obfuz.Virtualization
|
||||||
|
|
||||||
public override void Compile(CompileContext ctx)
|
public override void Compile(CompileContext ctx)
|
||||||
{
|
{
|
||||||
|
ModuleDef mod = ctx.method.Module;
|
||||||
|
var output = ctx.output;
|
||||||
|
FieldDef field;
|
||||||
switch (Type)
|
switch (Type)
|
||||||
{
|
{
|
||||||
//case DataNodeType.Byte:
|
|
||||||
//{
|
|
||||||
// // create ldloc.i4
|
|
||||||
// break;
|
|
||||||
//}
|
|
||||||
case DataNodeType.Int32:
|
case DataNodeType.Int32:
|
||||||
{
|
{
|
||||||
// create ldloc.i4
|
field = ctx.constFieldAllocator.Allocate(mod, IntValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DataNodeType.Int64:
|
case DataNodeType.Int64:
|
||||||
{
|
{
|
||||||
// create ldloc.i8
|
field = ctx.constFieldAllocator.Allocate(mod, LongValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DataNodeType.Float32:
|
case DataNodeType.Float32:
|
||||||
{
|
{
|
||||||
// create ldloc.r4
|
field = ctx.constFieldAllocator.Allocate(mod, FloatValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DataNodeType.Float64:
|
case DataNodeType.Float64:
|
||||||
{
|
{
|
||||||
// create ldloc.r8
|
field = ctx.constFieldAllocator.Allocate(mod, DoubleValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DataNodeType.String:
|
case DataNodeType.String:
|
||||||
{
|
{
|
||||||
// create ldstr
|
field = ctx.constFieldAllocator.Allocate(mod, StringValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DataNodeType.Bytes:
|
case DataNodeType.Bytes:
|
||||||
|
@ -45,13 +46,15 @@ namespace Obfuz.Virtualization
|
||||||
// ldsfld
|
// ldsfld
|
||||||
// ldtoken
|
// ldtoken
|
||||||
// RuntimeHelpers.InitializeArray(array, fieldHandle);
|
// RuntimeHelpers.InitializeArray(array, fieldHandle);
|
||||||
break;
|
//break;
|
||||||
|
throw new NotSupportedException("Bytes not supported");
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw new NotImplementedException($"Type:{Type} not implemented");
|
throw new NotImplementedException($"Type:{Type} not implemented");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
output.Add(Instruction.Create(OpCodes.Ldsfld, field));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,14 @@ namespace Obfuz.Virtualization
|
||||||
private readonly IRandom _random;
|
private readonly IRandom _random;
|
||||||
private readonly RandomDataNodeCreator _nodeCreator;
|
private readonly RandomDataNodeCreator _nodeCreator;
|
||||||
private readonly RvaDataAllocator _rvaDataAllocator;
|
private readonly RvaDataAllocator _rvaDataAllocator;
|
||||||
|
private readonly ConstFieldAllocator _constFieldAllocator;
|
||||||
|
|
||||||
public DefaultDataObfuscator()
|
public DefaultDataObfuscator()
|
||||||
{
|
{
|
||||||
_random = new RandomWithKey(new byte[] { 0x1, 0x2, 0x3, 0x4 }, 0x5);
|
_random = new RandomWithKey(new byte[] { 0x1, 0x2, 0x3, 0x4 }, 0x5);
|
||||||
_nodeCreator = new RandomDataNodeCreator(_random);
|
_nodeCreator = new RandomDataNodeCreator(_random);
|
||||||
_rvaDataAllocator = new RvaDataAllocator(_random);
|
_rvaDataAllocator = new RvaDataAllocator(_random);
|
||||||
|
_constFieldAllocator = new ConstFieldAllocator(_random);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompileNode(IDataNode node, MethodDef method, List<Instruction> obfuscatedInstructions)
|
private void CompileNode(IDataNode node, MethodDef method, List<Instruction> obfuscatedInstructions)
|
||||||
|
@ -27,6 +29,7 @@ namespace Obfuz.Virtualization
|
||||||
method = method,
|
method = method,
|
||||||
output = obfuscatedInstructions,
|
output = obfuscatedInstructions,
|
||||||
rvaDataAllocator = _rvaDataAllocator,
|
rvaDataAllocator = _rvaDataAllocator,
|
||||||
|
constFieldAllocator = _constFieldAllocator,
|
||||||
};
|
};
|
||||||
node.Compile(ctx);
|
node.Compile(ctx);
|
||||||
}
|
}
|
||||||
|
@ -67,14 +70,15 @@ namespace Obfuz.Virtualization
|
||||||
|
|
||||||
public void ObfuscateString(MethodDef method, string value, List<Instruction> obfuscatedInstructions)
|
public void ObfuscateString(MethodDef method, string value, List<Instruction> obfuscatedInstructions)
|
||||||
{
|
{
|
||||||
//IDataNode node = _nodeCreator.CreateRandom(DataNodeType.String, value);
|
IDataNode node = _nodeCreator.CreateRandom(DataNodeType.String, value);
|
||||||
//CompileNode(node, method, obfuscatedInstructions);
|
CompileNode(node, method, obfuscatedInstructions);
|
||||||
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldstr, value));
|
//obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldstr, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
_rvaDataAllocator.Done();
|
_rvaDataAllocator.Done();
|
||||||
|
_constFieldAllocator.Done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.Virtualization.Functions
|
||||||
|
{
|
||||||
|
public class ConstFieldDataCreator : NodeCreatorBase
|
||||||
|
{
|
||||||
|
public override IDataNode CreateExpr(DataNodeType type, object value, CreateExpressionOptions options)
|
||||||
|
{
|
||||||
|
return new ConstFieldDataNode { Type = type, Value = value };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static UnityEngine.Networking.UnityWebRequest;
|
|
||||||
|
|
||||||
namespace Obfuz.Virtualization.Functions
|
namespace Obfuz.Virtualization.Functions
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,6 +32,12 @@ namespace Obfuz.Virtualization
|
||||||
};
|
};
|
||||||
_functions.Add(DataNodeType.Float32, floatFuncs);
|
_functions.Add(DataNodeType.Float32, floatFuncs);
|
||||||
_functions.Add(DataNodeType.Float64, floatFuncs);
|
_functions.Add(DataNodeType.Float64, floatFuncs);
|
||||||
|
|
||||||
|
var stringFuncs = new List<IFunction>()
|
||||||
|
{
|
||||||
|
new ConstFieldDataCreator(),
|
||||||
|
};
|
||||||
|
_functions.Add(DataNodeType.String, stringFuncs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IDataNode CreateRandom(DataNodeType type, object value, CreateExpressionOptions options)
|
public override IDataNode CreateRandom(DataNodeType type, object value, CreateExpressionOptions options)
|
||||||
|
|
Loading…
Reference in New Issue