部分完成 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": "",
|
||||
"references": [
|
||||
"GUID:7e4de3067c2ab5c43a03ac49273dfb68",
|
||||
|
|
|
@ -16,6 +16,14 @@ namespace Obfuz.DynamicProxy
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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 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.Emit;
|
||||
using Obfuz.Utils;
|
||||
using Obfuz.Virtualization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -13,18 +14,20 @@ namespace Obfuz.DynamicProxy
|
|||
{
|
||||
public class DynamicProxyPass : MethodBodyObfuscationPassBase
|
||||
{
|
||||
private readonly IRandom _random;
|
||||
private readonly IDynamicProxyPolicy _dynamicProxyPolicy;
|
||||
private readonly IDynamicProxyObfuscator _dynamicProxyObfuscator;
|
||||
|
||||
public DynamicProxyPass()
|
||||
{
|
||||
_random = new RandomWithKey(new byte[] { 0x1, 0x2, 0x3, 0x4 }, 0x5);
|
||||
_dynamicProxyPolicy = new ConfigDynamicProxyPolicy();
|
||||
_dynamicProxyObfuscator = new DefaultDynamicProxyObfuscator();
|
||||
_dynamicProxyObfuscator = new DefaultDynamicProxyObfuscator(_random);
|
||||
}
|
||||
|
||||
public override void Stop(ObfuscatorContext ctx)
|
||||
{
|
||||
|
||||
_dynamicProxyObfuscator.Done();
|
||||
}
|
||||
|
||||
public override void Start(ObfuscatorContext ctx)
|
||||
|
@ -39,13 +42,21 @@ namespace Obfuz.DynamicProxy
|
|||
|
||||
protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList<Instruction> instructions, int instructionIndex,
|
||||
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
||||
{
|
||||
IMethod calledMethod = inst.Operand as IMethod;
|
||||
if (calledMethod == null || !calledMethod.IsMethod)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (MetaUtil.ContainsContainsGenericParameter(calledMethod))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (inst.OpCode.Code)
|
||||
{
|
||||
case Code.Call:
|
||||
{
|
||||
IMethod calledMethod = (IMethod)inst.Operand;
|
||||
if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, false))
|
||||
{
|
||||
return false;
|
||||
|
@ -59,7 +70,6 @@ namespace Obfuz.DynamicProxy
|
|||
{
|
||||
return false;
|
||||
}
|
||||
IMethod calledMethod = (IMethod)inst.Operand;
|
||||
if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, true))
|
||||
{
|
||||
return false;
|
|
@ -11,5 +11,7 @@ namespace Obfuz.DynamicProxy
|
|||
public interface IDynamicProxyObfuscator
|
||||
{
|
||||
void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
|
||||
|
||||
void Done();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using dnlib.DotNet;
|
||||
using Obfuz.Rename;
|
||||
using Obfuz.Utils;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using dnlib.DotNet;
|
||||
using Obfuz.Rename;
|
||||
using Obfuz.Utils;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using dnlib.DotNet;
|
||||
using Obfuz.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using dnlib.DotNet;
|
||||
using Obfuz.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Obfuz
|
||||
namespace Obfuz.Utils
|
||||
{
|
||||
public static class MetaUtil
|
||||
{
|
||||
|
@ -420,5 +421,223 @@ namespace Obfuz
|
|||
}
|
||||
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)
|
||||
{
|
||||
_dataObfuscator.Stop();
|
||||
_dataObfuscator.Done();
|
||||
}
|
||||
|
||||
protected override bool NeedObfuscateMethod(MethodDef method)
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace Obfuz.Virtualization
|
|||
//obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldstr, value));
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
public void Done()
|
||||
{
|
||||
_rvaDataAllocator.Done();
|
||||
_constFieldAllocator.Done();
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace Obfuz.Virtualization
|
|||
void ObfuscateString(MethodDef method, string value, List<Instruction> obfuscatedInstructions);
|
||||
|
||||
void ObfuscateBytes(MethodDef method, Array value, List<Instruction> obfuscatedInstructions);
|
||||
void Stop();
|
||||
|
||||
void Done();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue