部分完成 ProxyCall
parent
b604810171
commit
f513b9f414
|
@ -1,14 +0,0 @@
|
||||||
using dnlib.DotNet.Emit;
|
|
||||||
using dnlib.DotNet;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Obfuz.DynamicProxy
|
|
||||||
{
|
|
||||||
public class DefaultDynamicProxyObfuscator : DynamicProxyObfuscatorBase
|
|
||||||
{
|
|
||||||
public override void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions)
|
|
||||||
{
|
|
||||||
// Default implementation does nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
using dnlib.DotNet;
|
|
||||||
using Obfuz.Utils;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz.Emit
|
|
||||||
{
|
|
||||||
public struct DynamicProxyMethodData
|
|
||||||
{
|
|
||||||
public MethodDef proxyMethod;
|
|
||||||
public int methodId;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ModuleDynamicProxyMethodAllocator
|
|
||||||
{
|
|
||||||
private readonly ModuleDef _module;
|
|
||||||
private readonly IRandom _random;
|
|
||||||
|
|
||||||
public ModuleDynamicProxyMethodAllocator(ModuleDef module, IRandom random)
|
|
||||||
{
|
|
||||||
_module = module;
|
|
||||||
_random = random;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DynamicProxyMethodData Allocate(IMethod method)
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Done()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DynamicProxyMethodAllocator
|
|
||||||
{
|
|
||||||
private readonly IRandom _random;
|
|
||||||
|
|
||||||
private readonly Dictionary<ModuleDef, ModuleDynamicProxyMethodAllocator> _moduleAllocators = new Dictionary<ModuleDef, ModuleDynamicProxyMethodAllocator>();
|
|
||||||
|
|
||||||
public DynamicProxyMethodAllocator(IRandom random)
|
|
||||||
{
|
|
||||||
_random = random;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DynamicProxyMethodData Allocate(ModuleDef mod, IMethod method)
|
|
||||||
{
|
|
||||||
if (!_moduleAllocators.TryGetValue(mod, out var allocator))
|
|
||||||
{
|
|
||||||
allocator = new ModuleDynamicProxyMethodAllocator(mod, _random);
|
|
||||||
_moduleAllocators.Add(mod, allocator);
|
|
||||||
}
|
|
||||||
return allocator.Allocate(method);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Done()
|
|
||||||
{
|
|
||||||
foreach (var allocator in _moduleAllocators.Values)
|
|
||||||
{
|
|
||||||
allocator.Done();
|
|
||||||
}
|
|
||||||
_moduleAllocators.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
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 MethodImplAttributes = dnlib.DotNet.MethodImplAttributes;
|
||||||
|
using TypeAttributes = dnlib.DotNet.TypeAttributes;
|
||||||
|
|
||||||
|
namespace Obfuz.Emit
|
||||||
|
{
|
||||||
|
public struct ProxyCallMethodData
|
||||||
|
{
|
||||||
|
public MethodDef proxyMethod;
|
||||||
|
public int secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModuleDynamicProxyMethodAllocator
|
||||||
|
{
|
||||||
|
private readonly ModuleDef _module;
|
||||||
|
private readonly IRandom _random;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
public MethodDef proxyMethod;
|
||||||
|
public int secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<MethodKey, MethodProxyInfo> _methodProxys = new Dictionary<MethodKey, MethodProxyInfo>();
|
||||||
|
|
||||||
|
|
||||||
|
const int maxProxyMethodPerDispatchMethod = 1000;
|
||||||
|
class DispatchMethodInfo
|
||||||
|
{
|
||||||
|
public MethodDef methodDef;
|
||||||
|
public int secret;
|
||||||
|
public List<IMethod> methods = new List<IMethod>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<MethodSig, List<DispatchMethodInfo>> _dispatchMethods = new Dictionary<MethodSig, List<DispatchMethodInfo>>(SignatureEqualityComparer.Instance);
|
||||||
|
|
||||||
|
|
||||||
|
private TypeDef _proxyTypeDef;
|
||||||
|
|
||||||
|
public ModuleDynamicProxyMethodAllocator(ModuleDef module, IRandom random)
|
||||||
|
{
|
||||||
|
_module = module;
|
||||||
|
_random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeDef CreateProxyTypeDef()
|
||||||
|
{
|
||||||
|
var typeDef = new TypeDefUser("$Obfuz$ProxyCall", _module.CorLibTypes.Object.ToTypeDefOrRef());
|
||||||
|
typeDef.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed;
|
||||||
|
_module.EnableTypeDefFindCache = false;
|
||||||
|
_module.Types.Add(typeDef);
|
||||||
|
_module.EnableTypeDefFindCache = true;
|
||||||
|
return typeDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodDef CreateDispatchMethodInfo(MethodSig methodSig)
|
||||||
|
{
|
||||||
|
if (_proxyTypeDef == null)
|
||||||
|
{
|
||||||
|
_proxyTypeDef = CreateProxyTypeDef();
|
||||||
|
}
|
||||||
|
MethodDef methodDef = new MethodDefUser($"$Obfuz$ProxyCall$Dispatch${_proxyTypeDef.Methods.Count}", methodSig,
|
||||||
|
MethodImplAttributes.IL | MethodImplAttributes.Managed,
|
||||||
|
MethodAttributes.Static | MethodAttributes.Private);
|
||||||
|
methodDef.DeclaringType = _proxyTypeDef;
|
||||||
|
return methodDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodSig CreateDispatchMethodSig(IMethod method)
|
||||||
|
{
|
||||||
|
MethodSig methodSig = MetaUtil.ToSharedMethodSig(_module.CorLibTypes, MetaUtil.GetInflatedMethodSig(method));
|
||||||
|
// extra param for secret
|
||||||
|
methodSig.Params.Add(_module.CorLibTypes.Int32);
|
||||||
|
return methodSig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DispatchMethodInfo GetDispatchMethod(IMethod method)
|
||||||
|
{
|
||||||
|
MethodSig methodSig = CreateDispatchMethodSig(method);
|
||||||
|
if (!_dispatchMethods.TryGetValue(methodSig, out var dispatchMethods))
|
||||||
|
{
|
||||||
|
dispatchMethods = new List<DispatchMethodInfo>();
|
||||||
|
_dispatchMethods.Add(methodSig, dispatchMethods);
|
||||||
|
}
|
||||||
|
if (dispatchMethods.Count == 0 || dispatchMethods.Last().methods.Count >= maxProxyMethodPerDispatchMethod)
|
||||||
|
{
|
||||||
|
var newDispatchMethodInfo = new DispatchMethodInfo
|
||||||
|
{
|
||||||
|
methodDef = CreateDispatchMethodInfo(methodSig),
|
||||||
|
secret = 0,
|
||||||
|
};
|
||||||
|
dispatchMethods.Add(newDispatchMethodInfo);
|
||||||
|
}
|
||||||
|
return dispatchMethods.Last();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxyCallMethodData Allocate(IMethod method, bool callVir)
|
||||||
|
{
|
||||||
|
var key = new MethodKey(method, callVir);
|
||||||
|
if (!_methodProxys.TryGetValue(key, out var proxyInfo))
|
||||||
|
{
|
||||||
|
var methodDispatcher = GetDispatchMethod(method);
|
||||||
|
proxyInfo = new MethodProxyInfo()
|
||||||
|
{
|
||||||
|
proxyMethod = methodDispatcher.methodDef,
|
||||||
|
secret = methodDispatcher.methods.Count,
|
||||||
|
};
|
||||||
|
methodDispatcher.methods.Add(method);
|
||||||
|
_methodProxys.Add(key, proxyInfo);
|
||||||
|
}
|
||||||
|
return new ProxyCallMethodData { proxyMethod = proxyInfo.proxyMethod, secret = proxyInfo.secret };
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Done()
|
||||||
|
{
|
||||||
|
foreach (DispatchMethodInfo dispatchMethod in _dispatchMethods.Values.SelectMany(ms => ms))
|
||||||
|
{
|
||||||
|
var methodDef = dispatchMethod.methodDef;
|
||||||
|
var secret = dispatchMethod.secret;
|
||||||
|
var methodSig = methodDef.MethodSig;
|
||||||
|
|
||||||
|
|
||||||
|
var body = new CilBody();
|
||||||
|
methodDef.Body = body;
|
||||||
|
var ins = body.Instructions;
|
||||||
|
ins.Add(Instruction.Create(OpCodes.Ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProxyCallAllocator
|
||||||
|
{
|
||||||
|
private readonly IRandom _random;
|
||||||
|
|
||||||
|
private readonly Dictionary<ModuleDef, ModuleDynamicProxyMethodAllocator> _moduleAllocators = new Dictionary<ModuleDef, ModuleDynamicProxyMethodAllocator>();
|
||||||
|
|
||||||
|
public ProxyCallAllocator(IRandom random)
|
||||||
|
{
|
||||||
|
_random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxyCallMethodData Allocate(ModuleDef mod, IMethod method, bool callVir)
|
||||||
|
{
|
||||||
|
if (!_moduleAllocators.TryGetValue(mod, out var allocator))
|
||||||
|
{
|
||||||
|
allocator = new ModuleDynamicProxyMethodAllocator(mod, _random);
|
||||||
|
_moduleAllocators.Add(mod, allocator);
|
||||||
|
}
|
||||||
|
return allocator.Allocate(method, callVir);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Done()
|
||||||
|
{
|
||||||
|
foreach (var allocator in _moduleAllocators.Values)
|
||||||
|
{
|
||||||
|
allocator.Done();
|
||||||
|
}
|
||||||
|
_moduleAllocators.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "Obfuz",
|
"name": "Obfuz.Editor",
|
||||||
"rootNamespace": "",
|
"rootNamespace": "",
|
||||||
"references": [
|
"references": [
|
||||||
"GUID:7e4de3067c2ab5c43a03ac49273dfb68",
|
"GUID:7e4de3067c2ab5c43a03ac49273dfb68",
|
||||||
|
|
|
@ -16,6 +16,14 @@ namespace Obfuz.DynamicProxy
|
||||||
|
|
||||||
public override bool NeedDynamicProxyCalledMethod(IMethod method, bool callVir)
|
public override bool NeedDynamicProxyCalledMethod(IMethod method, bool callVir)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
ITypeDefOrRef declaringType = method.DeclaringType;
|
||||||
|
TypeDef typeDef = declaringType.ResolveTypeDef();
|
||||||
|
// doesn't proxy call if the method is a delegate
|
||||||
|
if (typeDef != null && typeDef.IsDelegate)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using Obfuz.Emit;
|
||||||
|
|
||||||
|
namespace Obfuz.DynamicProxy
|
||||||
|
{
|
||||||
|
public class DefaultDynamicProxyObfuscator : DynamicProxyObfuscatorBase
|
||||||
|
{
|
||||||
|
private readonly IRandom _random;
|
||||||
|
private readonly ProxyCallAllocator _proxyCallAllocator;
|
||||||
|
|
||||||
|
public DefaultDynamicProxyObfuscator(IRandom random)
|
||||||
|
{
|
||||||
|
_random = random;
|
||||||
|
_proxyCallAllocator = new ProxyCallAllocator(random);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Done()
|
||||||
|
{
|
||||||
|
_proxyCallAllocator.Done();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions)
|
||||||
|
{
|
||||||
|
MethodSig sharedMethodSig = MetaUtil.ToSharedMethodSig(calledMethod.Module.CorLibTypes, MetaUtil.GetInflatedMethodSig(calledMethod));
|
||||||
|
ProxyCallMethodData proxyCallMethodData = _proxyCallAllocator.Allocate(callingMethod.Module, calledMethod, callVir);
|
||||||
|
obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.secret));
|
||||||
|
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, proxyCallMethodData.proxyMethod));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,5 +7,6 @@ namespace Obfuz.DynamicProxy
|
||||||
public abstract class DynamicProxyObfuscatorBase : IDynamicProxyObfuscator
|
public abstract class DynamicProxyObfuscatorBase : IDynamicProxyObfuscator
|
||||||
{
|
{
|
||||||
public abstract void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
|
public abstract void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
|
||||||
|
public abstract void Done();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet;
|
||||||
using dnlib.DotNet.Emit;
|
using dnlib.DotNet.Emit;
|
||||||
|
using Obfuz.Utils;
|
||||||
using Obfuz.Virtualization;
|
using Obfuz.Virtualization;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -13,18 +14,20 @@ namespace Obfuz.DynamicProxy
|
||||||
{
|
{
|
||||||
public class DynamicProxyPass : MethodBodyObfuscationPassBase
|
public class DynamicProxyPass : MethodBodyObfuscationPassBase
|
||||||
{
|
{
|
||||||
|
private readonly IRandom _random;
|
||||||
private readonly IDynamicProxyPolicy _dynamicProxyPolicy;
|
private readonly IDynamicProxyPolicy _dynamicProxyPolicy;
|
||||||
private readonly IDynamicProxyObfuscator _dynamicProxyObfuscator;
|
private readonly IDynamicProxyObfuscator _dynamicProxyObfuscator;
|
||||||
|
|
||||||
public DynamicProxyPass()
|
public DynamicProxyPass()
|
||||||
{
|
{
|
||||||
|
_random = new RandomWithKey(new byte[] { 0x1, 0x2, 0x3, 0x4 }, 0x5);
|
||||||
_dynamicProxyPolicy = new ConfigDynamicProxyPolicy();
|
_dynamicProxyPolicy = new ConfigDynamicProxyPolicy();
|
||||||
_dynamicProxyObfuscator = new DefaultDynamicProxyObfuscator();
|
_dynamicProxyObfuscator = new DefaultDynamicProxyObfuscator(_random);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Stop(ObfuscatorContext ctx)
|
public override void Stop(ObfuscatorContext ctx)
|
||||||
{
|
{
|
||||||
|
_dynamicProxyObfuscator.Done();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Start(ObfuscatorContext ctx)
|
public override void Start(ObfuscatorContext ctx)
|
||||||
|
@ -40,12 +43,20 @@ namespace Obfuz.DynamicProxy
|
||||||
protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList<Instruction> instructions, int instructionIndex,
|
protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList<Instruction> instructions, int instructionIndex,
|
||||||
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
||||||
{
|
{
|
||||||
return false;
|
IMethod calledMethod = inst.Operand as IMethod;
|
||||||
|
if (calledMethod == null || !calledMethod.IsMethod)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (MetaUtil.ContainsContainsGenericParameter(calledMethod))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
switch (inst.OpCode.Code)
|
switch (inst.OpCode.Code)
|
||||||
{
|
{
|
||||||
case Code.Call:
|
case Code.Call:
|
||||||
{
|
{
|
||||||
IMethod calledMethod = (IMethod)inst.Operand;
|
|
||||||
if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, false))
|
if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, false))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -59,7 +70,6 @@ namespace Obfuz.DynamicProxy
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
IMethod calledMethod = (IMethod)inst.Operand;
|
|
||||||
if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, true))
|
if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, true))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
|
@ -11,5 +11,7 @@ namespace Obfuz.DynamicProxy
|
||||||
public interface IDynamicProxyObfuscator
|
public interface IDynamicProxyObfuscator
|
||||||
{
|
{
|
||||||
void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
|
void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
|
||||||
|
|
||||||
|
void Done();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet;
|
||||||
using Obfuz.Rename;
|
using Obfuz.Rename;
|
||||||
|
using Obfuz.Utils;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet;
|
||||||
using Obfuz.Rename;
|
using Obfuz.Rename;
|
||||||
|
using Obfuz.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.Utils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces generic type/method var with its generic argument
|
||||||
|
/// </summary>
|
||||||
|
public sealed class GenericArgumentContext
|
||||||
|
{
|
||||||
|
List<TypeSig> typeArgsStack;
|
||||||
|
List<TypeSig> methodArgsStack;
|
||||||
|
|
||||||
|
public GenericArgumentContext(IList<TypeSig> typeArgsStack, IList<TypeSig> methodArgsStack)
|
||||||
|
{
|
||||||
|
this.typeArgsStack = typeArgsStack?.ToList();
|
||||||
|
this.methodArgsStack = methodArgsStack?.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces a generic type/method var with its generic argument (if any). If
|
||||||
|
/// <paramref name="typeSig"/> isn't a generic type/method var or if it can't
|
||||||
|
/// be resolved, it itself is returned. Else the resolved type is returned.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typeSig">Type signature</param>
|
||||||
|
/// <returns>New <see cref="TypeSig"/> which is never <c>null</c> unless
|
||||||
|
/// <paramref name="typeSig"/> is <c>null</c></returns>
|
||||||
|
public TypeSig Resolve(TypeSig typeSig)
|
||||||
|
{
|
||||||
|
if (!typeSig.ContainsGenericParameter)
|
||||||
|
{
|
||||||
|
return typeSig;
|
||||||
|
}
|
||||||
|
typeSig = typeSig.RemovePinnedAndModifiers();
|
||||||
|
switch (typeSig.ElementType)
|
||||||
|
{
|
||||||
|
case ElementType.Ptr: return new PtrSig(Resolve(typeSig.Next));
|
||||||
|
case ElementType.ByRef: return new PtrSig(Resolve(typeSig.Next));
|
||||||
|
|
||||||
|
case ElementType.SZArray: return new PtrSig(Resolve(typeSig.Next));
|
||||||
|
case ElementType.Array:
|
||||||
|
{
|
||||||
|
var ara = (ArraySig)typeSig;
|
||||||
|
return new ArraySig(Resolve(typeSig.Next), ara.Rank, ara.Sizes, ara.LowerBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
case ElementType.Var:
|
||||||
|
{
|
||||||
|
GenericVar genericVar = (GenericVar)typeSig;
|
||||||
|
var newSig = Resolve(typeArgsStack, genericVar.Number, true);
|
||||||
|
if (newSig == null)
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
return newSig;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ElementType.MVar:
|
||||||
|
{
|
||||||
|
GenericMVar genericVar = (GenericMVar)typeSig;
|
||||||
|
var newSig = Resolve(methodArgsStack, genericVar.Number, true);
|
||||||
|
if (newSig == null)
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
return newSig;
|
||||||
|
}
|
||||||
|
case ElementType.GenericInst:
|
||||||
|
{
|
||||||
|
var gia = (GenericInstSig)typeSig;
|
||||||
|
return new GenericInstSig(gia.GenericType, gia.GenericArguments.Select(ga => Resolve(ga)).ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
case ElementType.FnPtr:
|
||||||
|
{
|
||||||
|
var fptr = (FnPtrSig)typeSig;
|
||||||
|
var cs = fptr.Signature;
|
||||||
|
CallingConventionSig ccs;
|
||||||
|
switch (cs)
|
||||||
|
{
|
||||||
|
case MethodSig ms:
|
||||||
|
{
|
||||||
|
ccs = new MethodSig(ms.GetCallingConvention(), ms.GenParamCount, Resolve(ms.RetType), ms.Params.Select(p => Resolve(p)).ToList());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PropertySig ps:
|
||||||
|
{
|
||||||
|
ccs = new PropertySig(ps.HasThis, Resolve(ps.RetType));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GenericInstMethodSig gims:
|
||||||
|
{
|
||||||
|
ccs = new GenericInstMethodSig(gims.GenericArguments.Select(ga => Resolve(ga)).ToArray());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new NotSupportedException(cs.ToString());
|
||||||
|
}
|
||||||
|
return new FnPtrSig(ccs);
|
||||||
|
}
|
||||||
|
|
||||||
|
case ElementType.ValueArray:
|
||||||
|
{
|
||||||
|
var vas = (ValueArraySig)typeSig;
|
||||||
|
return new ValueArraySig(Resolve(vas.Next), vas.Size);
|
||||||
|
}
|
||||||
|
default: return typeSig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeSig Resolve(List<TypeSig> args, uint number, bool isTypeVar)
|
||||||
|
{
|
||||||
|
var typeSig = args[(int)number];
|
||||||
|
var gvar = typeSig as GenericSig;
|
||||||
|
if (gvar is null || gvar.IsTypeVar != isTypeVar)
|
||||||
|
return typeSig;
|
||||||
|
return gvar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz
|
||||||
|
{
|
||||||
|
public static class HashUtil
|
||||||
|
{
|
||||||
|
public static int CombineHash(int hash1, int hash2)
|
||||||
|
{
|
||||||
|
return hash1 * 1566083941 + hash2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ComputeHash(List<TypeSig> sigs)
|
||||||
|
{
|
||||||
|
int hash = 135781321;
|
||||||
|
TypeEqualityComparer tc = TypeEqualityComparer.Instance;
|
||||||
|
foreach (var sig in sigs)
|
||||||
|
{
|
||||||
|
hash = hash * 1566083941 + tc.GetHashCode(sig);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,8 +5,9 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine.Assertions;
|
||||||
|
|
||||||
namespace Obfuz
|
namespace Obfuz.Utils
|
||||||
{
|
{
|
||||||
public static class MetaUtil
|
public static class MetaUtil
|
||||||
{
|
{
|
||||||
|
@ -165,9 +166,9 @@ namespace Obfuz
|
||||||
case ElementType.R4:
|
case ElementType.R4:
|
||||||
case ElementType.R8:
|
case ElementType.R8:
|
||||||
case ElementType.String:
|
case ElementType.String:
|
||||||
return true;
|
return true;
|
||||||
case ElementType.Class:
|
case ElementType.Class:
|
||||||
return IsScriptOrSerializableType(typeSig.ToTypeDefOrRef().ResolveTypeDefThrow());
|
return IsScriptOrSerializableType(typeSig.ToTypeDefOrRef().ResolveTypeDefThrow());
|
||||||
case ElementType.ValueType:
|
case ElementType.ValueType:
|
||||||
{
|
{
|
||||||
TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow();
|
TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow();
|
||||||
|
@ -420,5 +421,223 @@ namespace Obfuz
|
||||||
}
|
}
|
||||||
return anyChange;
|
return anyChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//public static bool ContainsContainsGenericParameter1(MethodDef method)
|
||||||
|
//{
|
||||||
|
// Assert.IsTrue(!(method.DeclaringType.ContainsGenericParameter || method.MethodSig.ContainsGenericParameter));
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
|
||||||
|
public static bool ContainsContainsGenericParameter1(MethodSpec methodSpec)
|
||||||
|
{
|
||||||
|
if (methodSpec.GenericInstMethodSig.ContainsGenericParameter)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
IMethodDefOrRef method = methodSpec.Method;
|
||||||
|
if (method.IsMethodDef)
|
||||||
|
{
|
||||||
|
return false;// ContainsContainsGenericParameter1((MethodDef)method);
|
||||||
|
}
|
||||||
|
if (method.IsMemberRef)
|
||||||
|
{
|
||||||
|
return ContainsContainsGenericParameter1((MemberRef)method);
|
||||||
|
}
|
||||||
|
throw new Exception($"unknown method: {method}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ContainsContainsGenericParameter1(MemberRef memberRef)
|
||||||
|
{
|
||||||
|
IMemberRefParent parent = memberRef.Class;
|
||||||
|
if (parent is TypeSpec typeSpec)
|
||||||
|
{
|
||||||
|
return typeSpec.ContainsGenericParameter;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ContainsContainsGenericParameter(IMethod method)
|
||||||
|
{
|
||||||
|
Assert.IsTrue(method.IsMethod);
|
||||||
|
if (method is MethodDef methodDef)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method is MethodSpec methodSpec)
|
||||||
|
{
|
||||||
|
return ContainsContainsGenericParameter1(methodSpec);
|
||||||
|
}
|
||||||
|
if (method is MemberRef memberRef)
|
||||||
|
{
|
||||||
|
return ContainsContainsGenericParameter1(memberRef);
|
||||||
|
}
|
||||||
|
throw new Exception($"unknown method: {method}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static TypeSig Inflate(TypeSig sig, GenericArgumentContext ctx)
|
||||||
|
{
|
||||||
|
if (!sig.ContainsGenericParameter)
|
||||||
|
{
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
|
return ctx.Resolve(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static MethodSig InflateMethodSig(MethodSig methodSig, GenericArgumentContext genericArgumentContext)
|
||||||
|
{
|
||||||
|
var newReturnType = Inflate(methodSig.RetType, genericArgumentContext);
|
||||||
|
var newParams = new List<TypeSig>();
|
||||||
|
foreach (var param in methodSig.Params)
|
||||||
|
{
|
||||||
|
newParams.Add(Inflate(param, genericArgumentContext));
|
||||||
|
}
|
||||||
|
var newParamsAfterSentinel = new List<TypeSig>();
|
||||||
|
if (methodSig.ParamsAfterSentinel != null)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException($"methodSig.ParamsAfterSentinel is not supported: {methodSig}");
|
||||||
|
//foreach (var param in methodSig.ParamsAfterSentinel)
|
||||||
|
//{
|
||||||
|
// newParamsAfterSentinel.Add(Inflate(param, genericArgumentContext));
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
return new MethodSig(methodSig.CallingConvention, methodSig.GenParamCount, newReturnType, newParams, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IList<TypeSig> GetGenericArguments(IMemberRefParent type)
|
||||||
|
{
|
||||||
|
if (type is TypeDef typeDef)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (type is TypeRef typeRef)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (type is TypeSpec typeSpec)
|
||||||
|
{
|
||||||
|
GenericInstSig genericInstSig = typeSpec.TypeSig.ToGenericInstSig();
|
||||||
|
return genericInstSig?.GenericArguments;
|
||||||
|
}
|
||||||
|
throw new NotSupportedException($"type:{type}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodSig GetInflatedMethodSig(IMethod method)
|
||||||
|
{
|
||||||
|
if (method is MethodDef methodDef)
|
||||||
|
{
|
||||||
|
return methodDef.MethodSig;
|
||||||
|
}
|
||||||
|
if (method is MemberRef memberRef)
|
||||||
|
{
|
||||||
|
return InflateMethodSig(memberRef.MethodSig, new GenericArgumentContext(GetGenericArguments(memberRef.Class), null));
|
||||||
|
}
|
||||||
|
if (method is MethodSpec methodSpec)
|
||||||
|
{
|
||||||
|
var genericInstMethodSig = methodSpec.GenericInstMethodSig;
|
||||||
|
if (methodSpec.Method is MethodDef methodDef2)
|
||||||
|
{
|
||||||
|
return InflateMethodSig(methodDef2.MethodSig, new GenericArgumentContext(null, genericInstMethodSig.GenericArguments));
|
||||||
|
}
|
||||||
|
if (methodSpec.Method is MemberRef memberRef2)
|
||||||
|
{
|
||||||
|
return InflateMethodSig(memberRef2.MethodSig, new GenericArgumentContext(GetGenericArguments(memberRef2.Class), genericInstMethodSig.GenericArguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
throw new NotSupportedException($" method: {method}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodSig ToSharedMethodSig(ICorLibTypes corTypes, MethodSig methodSig)
|
||||||
|
{
|
||||||
|
var newReturnType = ToShareTypeSig(corTypes, methodSig.RetType);
|
||||||
|
var newParams = new List<TypeSig>();
|
||||||
|
foreach (var param in methodSig.Params)
|
||||||
|
{
|
||||||
|
newParams.Add(ToShareTypeSig(corTypes, param));
|
||||||
|
}
|
||||||
|
if (methodSig.ParamsAfterSentinel != null)
|
||||||
|
{
|
||||||
|
//foreach (var param in methodSig.ParamsAfterSentinel)
|
||||||
|
//{
|
||||||
|
// newParamsAfterSentinel.Add(ToShareTypeSig(corTypes, param));
|
||||||
|
//}
|
||||||
|
throw new NotSupportedException($"methodSig.ParamsAfterSentinel is not supported: {methodSig}");
|
||||||
|
}
|
||||||
|
return new MethodSig(methodSig.CallingConvention, methodSig.GenParamCount, newReturnType, newParams, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TypeSig ToShareTypeSig(ICorLibTypes corTypes, TypeSig typeSig)
|
||||||
|
{
|
||||||
|
var a = typeSig.RemovePinnedAndModifiers();
|
||||||
|
switch (a.ElementType)
|
||||||
|
{
|
||||||
|
case ElementType.Void: return corTypes.Void;
|
||||||
|
case ElementType.Boolean: return corTypes.Byte;
|
||||||
|
case ElementType.Char: return corTypes.UInt16;
|
||||||
|
case ElementType.I1: return corTypes.SByte;
|
||||||
|
case ElementType.U1: return corTypes.Byte;
|
||||||
|
case ElementType.I2: return corTypes.Int16;
|
||||||
|
case ElementType.U2: return corTypes.UInt16;
|
||||||
|
case ElementType.I4: return corTypes.Int32;
|
||||||
|
case ElementType.U4: return corTypes.UInt32;
|
||||||
|
case ElementType.I8: return corTypes.Int64;
|
||||||
|
case ElementType.U8: return corTypes.UInt64;
|
||||||
|
case ElementType.R4: return corTypes.Single;
|
||||||
|
case ElementType.R8: return corTypes.Double;
|
||||||
|
case ElementType.String: return corTypes.Object;
|
||||||
|
case ElementType.TypedByRef: return corTypes.TypedReference;
|
||||||
|
case ElementType.I: return corTypes.IntPtr;
|
||||||
|
case ElementType.U: return corTypes.UIntPtr;
|
||||||
|
case ElementType.Object: return corTypes.Object;
|
||||||
|
case ElementType.Sentinel: return typeSig;
|
||||||
|
case ElementType.Ptr: return corTypes.UIntPtr;
|
||||||
|
case ElementType.ByRef: return corTypes.UIntPtr;
|
||||||
|
case ElementType.SZArray: return corTypes.Object;
|
||||||
|
case ElementType.Array: return corTypes.Object;
|
||||||
|
case ElementType.ValueType:
|
||||||
|
{
|
||||||
|
TypeDef typeDef = a.ToTypeDefOrRef().ResolveTypeDef();
|
||||||
|
if (typeDef == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"type:{a} definition could not be found");
|
||||||
|
}
|
||||||
|
if (typeDef.IsEnum)
|
||||||
|
{
|
||||||
|
return ToShareTypeSig(corTypes, typeDef.GetEnumUnderlyingType());
|
||||||
|
}
|
||||||
|
return typeSig;
|
||||||
|
}
|
||||||
|
case ElementType.Var:
|
||||||
|
case ElementType.MVar:
|
||||||
|
case ElementType.Class: return corTypes.Object;
|
||||||
|
case ElementType.GenericInst:
|
||||||
|
{
|
||||||
|
var gia = (GenericInstSig)a;
|
||||||
|
TypeDef typeDef = gia.GenericType.ToTypeDefOrRef().ResolveTypeDef();
|
||||||
|
if (typeDef == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"type:{a} definition could not be found");
|
||||||
|
}
|
||||||
|
if (typeDef.IsEnum)
|
||||||
|
{
|
||||||
|
return ToShareTypeSig(corTypes, typeDef.GetEnumUnderlyingType());
|
||||||
|
}
|
||||||
|
if (!typeDef.IsValueType)
|
||||||
|
{
|
||||||
|
return corTypes.Object;
|
||||||
|
}
|
||||||
|
return new GenericInstSig(gia.GenericType, gia.GenericArguments.Select(ga => ToShareTypeSig(corTypes, ga)).ToList());
|
||||||
|
}
|
||||||
|
case ElementType.FnPtr: return corTypes.UIntPtr;
|
||||||
|
case ElementType.ValueArray: return typeSig;
|
||||||
|
case ElementType.Module: return typeSig;
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException(typeSig.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace Obfuz.Virtualization
|
||||||
|
|
||||||
public override void Stop(ObfuscatorContext ctx)
|
public override void Stop(ObfuscatorContext ctx)
|
||||||
{
|
{
|
||||||
_dataObfuscator.Stop();
|
_dataObfuscator.Done();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool NeedObfuscateMethod(MethodDef method)
|
protected override bool NeedObfuscateMethod(MethodDef method)
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace Obfuz.Virtualization
|
||||||
//obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldstr, value));
|
//obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldstr, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Done()
|
||||||
{
|
{
|
||||||
_rvaDataAllocator.Done();
|
_rvaDataAllocator.Done();
|
||||||
_constFieldAllocator.Done();
|
_constFieldAllocator.Done();
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace Obfuz.Virtualization
|
||||||
void ObfuscateString(MethodDef method, string value, List<Instruction> obfuscatedInstructions);
|
void ObfuscateString(MethodDef method, string value, List<Instruction> obfuscatedInstructions);
|
||||||
|
|
||||||
void ObfuscateBytes(MethodDef method, Array value, List<Instruction> obfuscatedInstructions);
|
void ObfuscateBytes(MethodDef method, Array value, List<Instruction> obfuscatedInstructions);
|
||||||
void Stop();
|
|
||||||
|
void Done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue