- 支持string混淆

- 新增 ConstFieldDataNodeCreator及Allocator
backup
walon 2025-04-23 13:01:13 +08:00
parent f3762f05ce
commit db26f5d3ce
7 changed files with 278 additions and 16 deletions

View File

@ -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);
//}
}
}

View File

@ -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;
} }
} }

View File

@ -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));
} }
} }
} }

View File

@ -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();
} }
} }
} }

View File

@ -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 };
}
}
}

View File

@ -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
{ {

View File

@ -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)