Add proxy delegate fixer
This commit is contained in:
parent
32bb14fa5a
commit
f776148574
|
@ -60,6 +60,7 @@
|
|||
<Compile Include="deobfuscators\CryptoObfuscator\AntiDebugger.cs" />
|
||||
<Compile Include="deobfuscators\CryptoObfuscator\AssemblyResolver.cs" />
|
||||
<Compile Include="deobfuscators\CryptoObfuscator\Deobfuscator.cs" />
|
||||
<Compile Include="deobfuscators\CryptoObfuscator\ProxyDelegateFinder.cs" />
|
||||
<Compile Include="deobfuscators\CryptoObfuscator\ResourceDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\CryptoObfuscator\ResourceResolver.cs" />
|
||||
<Compile Include="deobfuscators\CryptoObfuscator\StringDecrypter.cs" />
|
||||
|
|
|
@ -20,22 +20,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.deobfuscators.CliSecure {
|
||||
class ProxyDelegateFinder : ProxyDelegateFinderBase {
|
||||
IList<MemberReference> memberReferences;
|
||||
|
||||
public ProxyDelegateFinder(ModuleDefinition module)
|
||||
: base(module) {
|
||||
this.memberReferences = new List<MemberReference>(module.GetMemberReferences());
|
||||
}
|
||||
|
||||
protected override void getCallInfo(FieldDefinition field, out int methodIndex, out bool isVirtual) {
|
||||
protected override object checkCctor(TypeDefinition type, MethodDefinition cctor) {
|
||||
var instrs = cctor.Body.Instructions;
|
||||
if (instrs.Count != 3)
|
||||
return null;
|
||||
if (!DotNetUtils.isLdcI4(instrs[0].OpCode.Code))
|
||||
return null;
|
||||
if (instrs[1].OpCode != OpCodes.Call || !isDelegateCreatorMethod(instrs[1].Operand as MethodDefinition))
|
||||
return null;
|
||||
if (instrs[2].OpCode != OpCodes.Ret)
|
||||
return null;
|
||||
|
||||
int delegateToken = 0x02000001 + DotNetUtils.getLdcI4Value(instrs[0]);
|
||||
if (type.MetadataToken.ToInt32() != delegateToken) {
|
||||
Log.w("Delegate token is not current type");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new object();
|
||||
}
|
||||
|
||||
protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) {
|
||||
var name = field.Name;
|
||||
isVirtual = false;
|
||||
callOpcode = OpCodes.Call;
|
||||
if (name.EndsWith("%", StringComparison.Ordinal)) {
|
||||
isVirtual = true;
|
||||
callOpcode = OpCodes.Callvirt;
|
||||
name = name.TrimEnd(new char[] { '%' });
|
||||
}
|
||||
byte[] value = Convert.FromBase64String(name);
|
||||
methodIndex = BitConverter.ToInt32(value, 0); // 0-based memberRef index
|
||||
int methodIndex = BitConverter.ToInt32(value, 0); // 0-based memberRef index
|
||||
if (methodIndex >= memberReferences.Count)
|
||||
throw new ApplicationException(string.Format("methodIndex ({0}) >= memberReferences.Count ({1})", methodIndex, memberReferences.Count));
|
||||
calledMethod = memberReferences[methodIndex] as MethodReference;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ namespace de4dot.deobfuscators.CryptoObfuscator {
|
|||
bool foundCryptoObfuscatorAttribute = false;
|
||||
bool foundObfuscatedSymbols = false;
|
||||
|
||||
ProxyDelegateFinder proxyDelegateFinder;
|
||||
ResourceDecrypter resourceDecrypter;
|
||||
ResourceResolver resourceResolver;
|
||||
AssemblyResolver assemblyResolver;
|
||||
|
@ -102,6 +103,8 @@ namespace de4dot.deobfuscators.CryptoObfuscator {
|
|||
val += 10;
|
||||
if (tamperDetection.Detected)
|
||||
val += 10;
|
||||
if (proxyDelegateFinder.Detected)
|
||||
val += 10;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -117,6 +120,8 @@ namespace de4dot.deobfuscators.CryptoObfuscator {
|
|||
if (checkCryptoObfuscator())
|
||||
foundObfuscatedSymbols = true;
|
||||
|
||||
proxyDelegateFinder = new ProxyDelegateFinder(module);
|
||||
proxyDelegateFinder.findDelegateCreator(module);
|
||||
stringDecrypter = new StringDecrypter(module);
|
||||
stringDecrypter.find();
|
||||
tamperDetection = new TamperDetection(module);
|
||||
|
@ -182,9 +187,21 @@ namespace de4dot.deobfuscators.CryptoObfuscator {
|
|||
addTypeToBeRemoved(antiDebugger.AntiDebuggerType, "Anti-debugger type");
|
||||
addTypeToBeRemoved(stringDecrypter.StringDecrypterType, "String decrypter type");
|
||||
|
||||
proxyDelegateFinder.find();
|
||||
|
||||
dumpEmbeddedAssemblies();
|
||||
}
|
||||
|
||||
public override void deobfuscateMethodEnd(Blocks blocks) {
|
||||
proxyDelegateFinder.deobfuscate(blocks);
|
||||
base.deobfuscateMethodEnd(blocks);
|
||||
}
|
||||
|
||||
public override void deobfuscateEnd() {
|
||||
removeProxyDelegates(proxyDelegateFinder);
|
||||
base.deobfuscateEnd();
|
||||
}
|
||||
|
||||
void decryptResources() {
|
||||
var rsrc = resourceResolver.mergeResources();
|
||||
if (rsrc == null)
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.deobfuscators.CryptoObfuscator {
|
||||
class ProxyDelegateFinder : ProxyDelegateFinderBase {
|
||||
Dictionary<MethodDefinition, ProxyCreatorType> methodToType = new Dictionary<MethodDefinition, ProxyCreatorType>();
|
||||
|
||||
public ProxyDelegateFinder(ModuleDefinition module)
|
||||
: base(module) {
|
||||
}
|
||||
|
||||
enum ProxyCreatorType {
|
||||
None,
|
||||
CallOrCallvirt,
|
||||
CallCtor,
|
||||
Newobj,
|
||||
}
|
||||
|
||||
class Context {
|
||||
public int typeToken;
|
||||
public int methodToken;
|
||||
public int declaringTypeToken;
|
||||
public ProxyCreatorType proxyCreatorType;
|
||||
public Context(int typeToken, int methodToken, int declaringTypeToken, ProxyCreatorType proxyCreatorType) {
|
||||
this.typeToken = typeToken;
|
||||
this.methodToken = methodToken;
|
||||
this.declaringTypeToken = declaringTypeToken;
|
||||
this.proxyCreatorType = proxyCreatorType;
|
||||
}
|
||||
}
|
||||
|
||||
protected override object checkCctor(TypeDefinition type, MethodDefinition cctor) {
|
||||
var instructions = cctor.Body.Instructions;
|
||||
for (int i = 0; i < instructions.Count; i++) {
|
||||
var instrs = DotNetUtils.getInstructions(instructions, i, OpCodes.Ldc_I4, OpCodes.Ldc_I4, OpCodes.Ldc_I4, OpCodes.Call);
|
||||
if (instrs == null)
|
||||
continue;
|
||||
|
||||
int typeToken = (int)instrs[0].Operand;
|
||||
int methodToken = (int)instrs[1].Operand;
|
||||
int declaringTypeToken = (int)instrs[2].Operand;
|
||||
var createMethod = instrs[3].Operand as MethodDefinition;
|
||||
|
||||
ProxyCreatorType proxyCreatorType;
|
||||
if (!methodToType.TryGetValue(createMethod, out proxyCreatorType))
|
||||
continue;
|
||||
|
||||
return new Context(typeToken, methodToken, declaringTypeToken, proxyCreatorType);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override void onFoundProxyDelegate(TypeDefinition type) {
|
||||
foreach (var method in type.Methods) {
|
||||
if (!method.IsStatic || !method.HasBody || method.Name == ".ctor")
|
||||
continue;
|
||||
|
||||
var instructions = method.Body.Instructions;
|
||||
for (int i = 0; i < instructions.Count; i++) {
|
||||
var instr = instructions[i];
|
||||
if (instr.OpCode.Code != Code.Ldsfld)
|
||||
continue;
|
||||
|
||||
add(method, (FieldDefinition)instr.Operand);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) {
|
||||
var ctx = (Context)context;
|
||||
|
||||
switch (ctx.proxyCreatorType) {
|
||||
case ProxyCreatorType.CallOrCallvirt:
|
||||
callOpcode = field.IsFamilyOrAssembly ? OpCodes.Callvirt : OpCodes.Call;
|
||||
break;
|
||||
case ProxyCreatorType.CallCtor:
|
||||
callOpcode = OpCodes.Call;
|
||||
break;
|
||||
case ProxyCreatorType.Newobj:
|
||||
callOpcode = OpCodes.Newobj;
|
||||
break;
|
||||
default:
|
||||
throw new ApplicationException(string.Format("Invalid proxy creator type: {0}", ctx.proxyCreatorType));
|
||||
}
|
||||
|
||||
calledMethod = module.LookupToken(ctx.methodToken) as MethodReference;
|
||||
}
|
||||
|
||||
public void findDelegateCreator(ModuleDefinition module) {
|
||||
foreach (var type in module.Types) {
|
||||
var createMethod = getProxyCreateMethod(type);
|
||||
if (createMethod == null)
|
||||
continue;
|
||||
|
||||
var proxyCreatorType = getProxyCreatorType(type, createMethod);
|
||||
if (proxyCreatorType == ProxyCreatorType.None)
|
||||
continue;
|
||||
methodToType[createMethod] = proxyCreatorType;
|
||||
setDelegateCreatorMethod(createMethod);
|
||||
}
|
||||
}
|
||||
|
||||
MethodDefinition getProxyCreateMethod(TypeDefinition type) {
|
||||
if (type.Fields.Count != 1)
|
||||
return null;
|
||||
if (DotNetUtils.findFieldType(type, "System.ModuleHandle", true) == null)
|
||||
return null;
|
||||
|
||||
MethodDefinition createMethod = null;
|
||||
foreach (var m in type.Methods) {
|
||||
if (m.Name == ".ctor" || m.Name == ".cctor")
|
||||
continue;
|
||||
if (createMethod == null || DotNetUtils.isMethod(m, "System.Void", "(System.Int32,System.Int32,System.Int32)")) {
|
||||
createMethod = m;
|
||||
continue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (!createMethod.HasBody)
|
||||
return null;
|
||||
if (type.HasEvents || type.HasProperties)
|
||||
return null;
|
||||
if (!findLdci4(createMethod, 0xFFFFFF))
|
||||
return null;
|
||||
|
||||
return createMethod;
|
||||
}
|
||||
|
||||
bool findLdci4(MethodDefinition method, int value) {
|
||||
foreach (var instr in method.Body.Instructions) {
|
||||
if (instr.OpCode.Code == Code.Ldc_I4 && (int)instr.Operand == value)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxyCreatorType getProxyCreatorType(TypeDefinition type, MethodDefinition createMethod) {
|
||||
int numCalls = 0, numCallvirts = 0, numNewobjs = 0;
|
||||
foreach (var instr in createMethod.Body.Instructions) {
|
||||
if (instr.OpCode.Code != Code.Ldsfld)
|
||||
continue;
|
||||
var field = instr.Operand as FieldReference;
|
||||
if (field == null)
|
||||
continue;
|
||||
switch (field.FullName) {
|
||||
case "System.Reflection.Emit.OpCode System.Reflection.Emit.OpCodes::Call":
|
||||
numCalls++;
|
||||
break;
|
||||
case "System.Reflection.Emit.OpCode System.Reflection.Emit.OpCodes::Callvirt":
|
||||
numCallvirts++;
|
||||
break;
|
||||
case "System.Reflection.Emit.OpCode System.Reflection.Emit.OpCodes::Newobj":
|
||||
numNewobjs++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (numCalls == 1 && numCallvirts == 1 && numNewobjs == 0)
|
||||
return ProxyCreatorType.CallOrCallvirt;
|
||||
if (numCalls == 1 && numCallvirts == 0 && numNewobjs == 0)
|
||||
return ProxyCreatorType.CallCtor;
|
||||
if (numCalls == 0 && numCallvirts == 0 && numNewobjs == 1)
|
||||
return ProxyCreatorType.Newobj;
|
||||
return ProxyCreatorType.None;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -470,7 +470,7 @@ namespace de4dot.deobfuscators {
|
|||
protected void removeProxyDelegates(ProxyDelegateFinderBase proxyDelegateFinder) {
|
||||
addTypesToBeRemoved(proxyDelegateFinder.DelegateTypes, "Proxy delegate type");
|
||||
if (proxyDelegateFinder.RemovedDelegateCreatorCalls > 0)
|
||||
addTypeToBeRemoved(proxyDelegateFinder.DelegateCreatorMethod.DeclaringType, "Proxy delegate creator type");
|
||||
addTypesToBeRemoved(proxyDelegateFinder.DelegateCreatorTypes, "Proxy delegate creator type");
|
||||
}
|
||||
|
||||
protected TypeDefinition getModuleType() {
|
||||
|
|
|
@ -25,46 +25,60 @@ using de4dot.blocks;
|
|||
|
||||
namespace de4dot.deobfuscators {
|
||||
abstract class ProxyDelegateFinderBase {
|
||||
ModuleDefinition module;
|
||||
IList<MemberReference> memberReferences;
|
||||
MethodDefinition delegateCreatorMethod;
|
||||
protected ModuleDefinition module;
|
||||
List<MethodDefinition> delegateCreatorMethods = new List<MethodDefinition>();
|
||||
Dictionary<TypeDefinition, bool> delegateTypesDict = new Dictionary<TypeDefinition, bool>();
|
||||
Dictionary<FieldReferenceAndDeclaringTypeKey, DelegateInfo> fieldToDelegateInfo = new Dictionary<FieldReferenceAndDeclaringTypeKey, DelegateInfo>();
|
||||
Dictionary<MethodDefinition, FieldDefinition> proxyMethodToField = new Dictionary<MethodDefinition, FieldDefinition>();
|
||||
|
||||
class DelegateInfo {
|
||||
public MethodReference methodRef; // Method we should call
|
||||
public FieldDefinition field; // Field holding the Delegate instance
|
||||
public bool isVirtual;
|
||||
public DelegateInfo(FieldDefinition field, MethodReference methodRef, bool isVirtual) {
|
||||
public OpCode callOpcode;
|
||||
public DelegateInfo(FieldDefinition field, MethodReference methodRef, OpCode callOpcode) {
|
||||
this.field = field;
|
||||
this.methodRef = methodRef;
|
||||
this.isVirtual = isVirtual;
|
||||
this.callOpcode = callOpcode;
|
||||
}
|
||||
}
|
||||
|
||||
public int RemovedDelegateCreatorCalls { get; set; }
|
||||
|
||||
public IEnumerable<TypeDefinition> DelegateTypes {
|
||||
get { return delegateTypesDict.Keys; }
|
||||
}
|
||||
public MethodDefinition DelegateCreatorMethod {
|
||||
get { return delegateCreatorMethod; }
|
||||
|
||||
public IEnumerable<TypeDefinition> DelegateCreatorTypes {
|
||||
get {
|
||||
foreach (var method in delegateCreatorMethods)
|
||||
yield return method.DeclaringType;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Detected {
|
||||
get { return delegateCreatorMethod != null; }
|
||||
get { return delegateCreatorMethods.Count != 0; }
|
||||
}
|
||||
|
||||
public ProxyDelegateFinderBase(ModuleDefinition module) {
|
||||
this.module = module;
|
||||
this.memberReferences = new List<MemberReference>(module.GetMemberReferences());
|
||||
}
|
||||
|
||||
public void setDelegateCreatorMethod(MethodDefinition delegateCreatorMethod) {
|
||||
this.delegateCreatorMethod = delegateCreatorMethod;
|
||||
if (delegateCreatorMethod == null)
|
||||
return;
|
||||
delegateCreatorMethods.Add(delegateCreatorMethod);
|
||||
}
|
||||
|
||||
protected bool isDelegateCreatorMethod(MethodDefinition method) {
|
||||
foreach (var m in delegateCreatorMethods) {
|
||||
if (m == method)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void find() {
|
||||
if (delegateCreatorMethod == null)
|
||||
if (delegateCreatorMethods.Count == 0)
|
||||
return;
|
||||
|
||||
Log.v("Finding all proxy delegates");
|
||||
|
@ -77,47 +91,44 @@ namespace de4dot.deobfuscators {
|
|||
if (!type.HasFields)
|
||||
continue;
|
||||
|
||||
var instrs = cctor.Body.Instructions;
|
||||
if (instrs.Count != 3)
|
||||
object context = checkCctor(type, cctor);
|
||||
if (context == null)
|
||||
continue;
|
||||
if (!DotNetUtils.isLdcI4(instrs[0].OpCode.Code))
|
||||
continue;
|
||||
if (instrs[1].OpCode != OpCodes.Call || instrs[1].Operand != delegateCreatorMethod)
|
||||
continue;
|
||||
if (instrs[2].OpCode != OpCodes.Ret)
|
||||
continue;
|
||||
|
||||
int delegateToken = 0x02000001 + DotNetUtils.getLdcI4Value(instrs[0]);
|
||||
if (type.MetadataToken.ToInt32() != delegateToken) {
|
||||
Log.w("Delegate token is not current type");
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.v("Found proxy delegate: {0} ({1:X8})", type, type.MetadataToken.ToUInt32());
|
||||
RemovedDelegateCreatorCalls++;
|
||||
onFoundProxyDelegate(type);
|
||||
|
||||
Log.indent();
|
||||
foreach (var field in type.Fields) {
|
||||
if (!field.IsStatic || field.IsPublic)
|
||||
continue;
|
||||
|
||||
int methodIndex;
|
||||
bool isVirtual;
|
||||
getCallInfo(field, out methodIndex, out isVirtual);
|
||||
if (methodIndex >= memberReferences.Count)
|
||||
throw new ApplicationException(string.Format("methodIndex ({0}) >= memberReferences.Count ({1})", methodIndex, memberReferences.Count));
|
||||
MethodReference calledMethod;
|
||||
OpCode callOpcode;
|
||||
getCallInfo(context, field, out calledMethod, out callOpcode);
|
||||
|
||||
var methodRef = memberReferences[methodIndex] as MethodReference;
|
||||
if (methodRef == null)
|
||||
throw new ApplicationException("methodRef is null");
|
||||
fieldToDelegateInfo[new FieldReferenceAndDeclaringTypeKey(field)] = new DelegateInfo(field, methodRef, isVirtual);
|
||||
Log.v("Field: {0}, Virtual: {1}, Method: {2}, RID: {3}", field.Name, isVirtual, methodRef, methodIndex + 1);
|
||||
if (calledMethod == null)
|
||||
throw new ApplicationException("calledMethod is null");
|
||||
fieldToDelegateInfo[new FieldReferenceAndDeclaringTypeKey(field)] = new DelegateInfo(field, calledMethod, callOpcode);
|
||||
Log.v("Field: {0}, Opcode: {1}, Method: {2} ({3:X8})", field.Name, callOpcode, calledMethod, calledMethod.MetadataToken.ToUInt32());
|
||||
}
|
||||
Log.deIndent();
|
||||
delegateTypesDict[type] = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void getCallInfo(FieldDefinition field, out int methodIndex, out bool isVirtual);
|
||||
protected virtual void onFoundProxyDelegate(TypeDefinition type) {
|
||||
}
|
||||
|
||||
protected abstract object checkCctor(TypeDefinition type, MethodDefinition cctor);
|
||||
protected abstract void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode);
|
||||
|
||||
protected void add(MethodDefinition proxyMethod, FieldDefinition proxyField) {
|
||||
if (proxyMethod == null || proxyField == null)
|
||||
return;
|
||||
proxyMethodToField[proxyMethod] = proxyField;
|
||||
}
|
||||
|
||||
MethodDefinition findMethod(TypeDefinition type, string name) {
|
||||
if (!type.HasMethods)
|
||||
|
@ -158,10 +169,9 @@ namespace de4dot.deobfuscators {
|
|||
foreach (var block in allBlocks) {
|
||||
var instrs = block.Instructions;
|
||||
for (int i = 0; i < instrs.Count; i++) {
|
||||
var ldsfld = instrs[i];
|
||||
if (ldsfld.OpCode != OpCodes.Ldsfld)
|
||||
continue;
|
||||
var di = getDelegateInfo(ldsfld.Operand as FieldReference);
|
||||
var instr = instrs[i];
|
||||
if (instr.OpCode == OpCodes.Ldsfld) {
|
||||
var di = getDelegateInfo(instr.Operand as FieldReference);
|
||||
if (di == null)
|
||||
continue;
|
||||
|
||||
|
@ -177,6 +187,19 @@ namespace de4dot.deobfuscators {
|
|||
di.field.DeclaringType, di.field.DeclaringType.MetadataToken.ToInt32());
|
||||
}
|
||||
}
|
||||
else if (instr.OpCode == OpCodes.Call) {
|
||||
var method = instr.Operand as MethodDefinition;
|
||||
if (method == null)
|
||||
continue;
|
||||
FieldDefinition field;
|
||||
if (!proxyMethodToField.TryGetValue(method, out field))
|
||||
continue;
|
||||
var di = getDelegateInfo(field);
|
||||
if (di == null)
|
||||
continue;
|
||||
add(removeInfos, block, i, di);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var block in removeInfos.Keys) {
|
||||
|
@ -184,7 +207,7 @@ namespace de4dot.deobfuscators {
|
|||
var removeIndexes = new List<int>(list.Count);
|
||||
foreach (var info in list) {
|
||||
if (info.IsCall) {
|
||||
var opcode = info.DelegateInfo.isVirtual ? OpCodes.Callvirt : OpCodes.Call;
|
||||
var opcode = info.DelegateInfo.callOpcode;
|
||||
var newInstr = Instruction.Create(opcode, info.DelegateInfo.methodRef);
|
||||
block.replace(info.Index, 1, newInstr);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.deobfuscators.SmartAssembly {
|
||||
|
@ -35,6 +37,8 @@ namespace de4dot.deobfuscators.SmartAssembly {
|
|||
'\x9E', '\x9F',
|
||||
};
|
||||
|
||||
IList<MemberReference> memberReferences;
|
||||
|
||||
static ProxyDelegateFinder() {
|
||||
for (int i = 0; i < specialChars.Length; i++)
|
||||
specialCharsDict[specialChars[i]] = i;
|
||||
|
@ -42,17 +46,38 @@ namespace de4dot.deobfuscators.SmartAssembly {
|
|||
|
||||
public ProxyDelegateFinder(ModuleDefinition module)
|
||||
: base(module) {
|
||||
this.memberReferences = new List<MemberReference>(module.GetMemberReferences());
|
||||
}
|
||||
|
||||
protected override void getCallInfo(FieldDefinition field, out int methodIndex, out bool isVirtual) {
|
||||
isVirtual = false;
|
||||
protected override object checkCctor(TypeDefinition type, MethodDefinition cctor) {
|
||||
var instrs = cctor.Body.Instructions;
|
||||
if (instrs.Count != 3)
|
||||
return null;
|
||||
if (!DotNetUtils.isLdcI4(instrs[0].OpCode.Code))
|
||||
return null;
|
||||
if (instrs[1].OpCode != OpCodes.Call || !isDelegateCreatorMethod(instrs[1].Operand as MethodDefinition))
|
||||
return null;
|
||||
if (instrs[2].OpCode != OpCodes.Ret)
|
||||
return null;
|
||||
|
||||
int delegateToken = 0x02000001 + DotNetUtils.getLdcI4Value(instrs[0]);
|
||||
if (type.MetadataToken.ToInt32() != delegateToken) {
|
||||
Log.w("Delegate token is not current type");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new object();
|
||||
}
|
||||
|
||||
protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) {
|
||||
callOpcode = OpCodes.Call;
|
||||
string name = field.Name;
|
||||
|
||||
methodIndex = 0;
|
||||
int methodIndex = 0;
|
||||
for (int i = name.Length - 1; i >= 0; i--) {
|
||||
char c = name[i];
|
||||
if (c == '~') {
|
||||
isVirtual = true;
|
||||
callOpcode = OpCodes.Callvirt;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -60,6 +85,9 @@ namespace de4dot.deobfuscators.SmartAssembly {
|
|||
if (specialCharsDict.TryGetValue(c, out val))
|
||||
methodIndex = methodIndex * specialChars.Length + val;
|
||||
}
|
||||
if (methodIndex >= memberReferences.Count)
|
||||
throw new ApplicationException(string.Format("methodIndex ({0}) >= memberReferences.Count ({1})", methodIndex, memberReferences.Count));
|
||||
calledMethod = memberReferences[methodIndex] as MethodReference;
|
||||
}
|
||||
|
||||
public void findDelegateCreator(ModuleDefinition module) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user