de4dot-cex/de4dot.code/deobfuscators/ProxyCallFixerBase.cs

767 lines
25 KiB
C#
Raw Permalink Normal View History

2011-09-22 10:55:30 +08:00
/*
2015-10-30 05:45:26 +08:00
Copyright (C) 2011-2015 de4dot@gmail.com
2011-09-22 10:55:30 +08:00
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 dnlib.DotNet;
using dnlib.DotNet.Emit;
2011-09-22 10:55:30 +08:00
using de4dot.blocks;
namespace de4dot.code.deobfuscators {
public abstract class ProxyCallFixerBase {
2012-11-01 21:39:39 +08:00
protected ModuleDefMD module;
protected List<MethodDef> delegateCreatorMethods = new List<MethodDef>();
protected Dictionary<TypeDef, bool> delegateTypesDict = new Dictionary<TypeDef, bool>();
2012-05-29 17:13:39 +08:00
protected int errors = 0;
public int Errors {
get { return errors; }
}
2011-09-22 10:55:30 +08:00
2011-12-28 20:33:10 +08:00
protected class DelegateInfo {
2012-11-01 21:39:39 +08:00
public IMethod methodRef; // Method we should call
public FieldDef field; // Field holding the Delegate instance
2011-10-23 19:43:32 +08:00
public OpCode callOpcode;
2012-11-01 21:39:39 +08:00
public DelegateInfo(FieldDef field, IMethod methodRef, OpCode callOpcode) {
2011-09-22 10:55:30 +08:00
this.field = field;
this.methodRef = methodRef;
2011-10-23 19:43:32 +08:00
this.callOpcode = callOpcode;
2011-09-22 10:55:30 +08:00
}
}
public int RemovedDelegateCreatorCalls { get; set; }
2011-10-23 19:43:32 +08:00
2012-11-01 21:39:39 +08:00
public IEnumerable<TypeDef> DelegateTypes {
2011-09-22 10:55:30 +08:00
get { return delegateTypesDict.Keys; }
}
2011-10-23 19:43:32 +08:00
2012-11-01 21:39:39 +08:00
public IEnumerable<TypeDef> DelegateCreatorTypes {
2011-10-23 19:43:32 +08:00
get {
foreach (var method in delegateCreatorMethods)
yield return method.DeclaringType;
}
2011-09-22 10:55:30 +08:00
}
2012-11-01 21:39:39 +08:00
public virtual IEnumerable<Tuple<MethodDef, string>> OtherMethods {
get { return new List<Tuple<MethodDef, string>>(); }
2012-07-27 14:02:27 +08:00
}
2011-09-22 10:55:30 +08:00
public bool Detected {
2011-10-23 19:43:32 +08:00
get { return delegateCreatorMethods.Count != 0; }
2011-09-22 10:55:30 +08:00
}
2012-11-01 21:39:39 +08:00
protected ProxyCallFixerBase(ModuleDefMD module) {
2011-09-22 10:55:30 +08:00
this.module = module;
}
2012-11-01 21:39:39 +08:00
protected ProxyCallFixerBase(ModuleDefMD module, ProxyCallFixerBase oldOne) {
this.module = module;
foreach (var method in oldOne.delegateCreatorMethods)
2013-01-19 20:03:57 +08:00
delegateCreatorMethods.Add(Lookup(method, "Could not find delegate creator method"));
foreach (var kv in oldOne.delegateTypesDict)
2013-01-19 20:03:57 +08:00
delegateTypesDict[Lookup(kv.Key, "Could not find delegate type")] = kv.Value;
}
2013-01-19 20:03:57 +08:00
protected DelegateInfo Copy(DelegateInfo di) {
var method = Lookup(di.methodRef, "Could not find method ref");
var field = Lookup(di.field, "Could not find delegate field");
return new DelegateInfo(field, method, di.callOpcode);
}
2013-01-19 20:03:57 +08:00
protected T Lookup<T>(T def, string errorMessage) where T : class, ICodedToken {
return DeobUtils.Lookup(module, def, errorMessage);
}
2013-01-19 20:03:57 +08:00
protected void SetDelegateCreatorMethod(MethodDef delegateCreatorMethod) {
2011-10-23 19:43:32 +08:00
if (delegateCreatorMethod == null)
return;
delegateCreatorMethods.Add(delegateCreatorMethod);
}
2013-01-19 20:03:57 +08:00
protected bool IsDelegateCreatorMethod(MethodDef method) {
2011-10-23 19:43:32 +08:00
foreach (var m in delegateCreatorMethods) {
if (m == method)
return true;
}
return false;
2011-09-22 10:55:30 +08:00
}
2013-01-19 20:03:57 +08:00
protected virtual IEnumerable<TypeDef> GetDelegateTypes() {
foreach (var type in module.Types) {
if (type.BaseType == null || type.BaseType.FullName != "System.MulticastDelegate")
continue;
yield return type;
}
}
2012-05-29 17:13:39 +08:00
protected class BlockInstr {
public Block Block { get; set; }
public int Index { get; set; }
}
protected class RemoveInfo {
public int Index { get; set; }
public DelegateInfo DelegateInfo { get; set; }
public bool IsCall {
get { return DelegateInfo != null; }
}
}
protected virtual bool ProxyCallIsObfuscated {
get { return false; }
}
2013-01-19 20:03:57 +08:00
public void Deobfuscate(Blocks blocks) {
2012-05-29 17:13:39 +08:00
if (blocks.Method.DeclaringType != null && delegateTypesDict.ContainsKey(blocks.Method.DeclaringType))
return;
2013-01-19 20:03:57 +08:00
var allBlocks = blocks.MethodBlocks.GetAllBlocks();
2012-05-29 17:13:39 +08:00
int loops = ProxyCallIsObfuscated ? 50 : 1;
for (int i = 0; i < loops; i++) {
2013-01-19 20:03:57 +08:00
if (!Deobfuscate(blocks, allBlocks))
2012-05-29 17:13:39 +08:00
break;
}
2013-01-19 20:03:57 +08:00
DeobfuscateEnd(blocks, allBlocks);
2012-05-29 17:13:39 +08:00
}
2013-01-19 20:03:57 +08:00
protected abstract bool Deobfuscate(Blocks blocks, IList<Block> allBlocks);
2012-05-29 17:13:39 +08:00
2013-01-19 20:03:57 +08:00
protected virtual void DeobfuscateEnd(Blocks blocks, IList<Block> allBlocks) {
2012-05-29 17:13:39 +08:00
}
2013-01-19 20:03:57 +08:00
protected static void Add(Dictionary<Block, List<RemoveInfo>> removeInfos, Block block, int index, DelegateInfo di) {
2012-05-29 17:13:39 +08:00
List<RemoveInfo> list;
if (!removeInfos.TryGetValue(block, out list))
removeInfos[block] = list = new List<RemoveInfo>();
list.Add(new RemoveInfo {
Index = index,
DelegateInfo = di,
});
}
protected bool FixProxyCalls(MethodDef method, Dictionary<Block, List<RemoveInfo>> removeInfos) {
var gpContext = GenericParamContext.Create(method);
2012-05-29 17:13:39 +08:00
foreach (var block in removeInfos.Keys) {
var list = removeInfos[block];
var removeIndexes = new List<int>(list.Count);
foreach (var info in list) {
if (info.IsCall) {
var opcode = info.DelegateInfo.callOpcode;
var newInstr = Instruction.Create(opcode, ReResolve(info.DelegateInfo.methodRef, gpContext));
2013-01-19 20:03:57 +08:00
block.Replace(info.Index, 1, newInstr);
2012-05-29 17:13:39 +08:00
}
else
removeIndexes.Add(info.Index);
}
2012-11-18 10:02:12 +08:00
if (removeIndexes.Count > 0)
2013-01-19 20:03:57 +08:00
block.Remove(removeIndexes);
2012-05-29 17:13:39 +08:00
}
return removeInfos.Count > 0;
}
IMethod ReResolve(IMethod method, GenericParamContext gpContext) {
if (method.IsMethodSpec || method.IsMemberRef)
method = module.ResolveToken(method.MDToken.Raw, gpContext) as IMethod ?? method;
return method;
}
2012-05-29 17:13:39 +08:00
}
// Fixes proxy calls that call the delegate inline in the code, eg.:
// ldsfld delegate_instance
// ...push args...
// call Invoke
public abstract class ProxyCallFixer1 : ProxyCallFixerBase {
2012-11-22 16:14:51 +08:00
FieldDefAndDeclaringTypeDict<DelegateInfo> fieldToDelegateInfo = new FieldDefAndDeclaringTypeDict<DelegateInfo>();
2012-05-29 17:13:39 +08:00
2012-11-01 21:39:39 +08:00
protected ProxyCallFixer1(ModuleDefMD module)
2012-05-29 17:13:39 +08:00
: base(module) {
}
2012-11-01 21:39:39 +08:00
protected ProxyCallFixer1(ModuleDefMD module, ProxyCallFixer1 oldOne)
2012-05-29 17:13:39 +08:00
: base(module, oldOne) {
2013-01-19 20:03:57 +08:00
foreach (var key in oldOne.fieldToDelegateInfo.GetKeys())
fieldToDelegateInfo.Add(Lookup(key, "Could not find field"), Copy(oldOne.fieldToDelegateInfo.Find(key)));
2012-05-29 17:13:39 +08:00
}
2013-01-19 20:03:57 +08:00
protected void AddDelegateInfo(DelegateInfo di) {
fieldToDelegateInfo.Add(di.field, di);
2012-05-29 17:13:39 +08:00
}
2013-01-19 20:03:57 +08:00
protected DelegateInfo GetDelegateInfo(IField field) {
2012-05-29 17:13:39 +08:00
if (field == null)
return null;
2013-01-19 20:03:57 +08:00
return fieldToDelegateInfo.Find(field);
2012-05-29 17:13:39 +08:00
}
2013-01-19 20:03:57 +08:00
public void Find() {
2011-10-23 19:43:32 +08:00
if (delegateCreatorMethods.Count == 0)
2011-09-22 10:55:30 +08:00
return;
Logger.v("Finding all proxy delegates");
2013-01-19 20:03:57 +08:00
foreach (var tmp in GetDelegateTypes()) {
2012-07-07 06:58:18 +08:00
var type = tmp;
2012-11-17 06:50:52 +08:00
var cctor = type.FindStaticConstructor();
if (cctor == null || !cctor.HasBody)
2011-09-22 10:55:30 +08:00
continue;
if (!type.HasFields)
continue;
2013-01-19 20:03:57 +08:00
object context = CheckCctor(ref type, cctor);
2011-10-23 19:43:32 +08:00
if (context == null)
2011-09-22 10:55:30 +08:00
continue;
2013-01-19 20:03:57 +08:00
Logger.v("Found proxy delegate: {0} ({1:X8})", Utils.RemoveNewlines(type), type.MDToken.ToUInt32());
2011-09-22 10:55:30 +08:00
RemovedDelegateCreatorCalls++;
2011-10-23 19:43:32 +08:00
2013-01-19 20:03:57 +08:00
Logger.Instance.Indent();
2011-09-22 10:55:30 +08:00
foreach (var field in type.Fields) {
if (!field.IsStatic)
2011-09-22 10:55:30 +08:00
continue;
2012-11-01 21:39:39 +08:00
IMethod calledMethod;
2011-10-23 19:43:32 +08:00
OpCode callOpcode;
2013-01-19 20:03:57 +08:00
GetCallInfo(context, field, out calledMethod, out callOpcode);
2011-10-23 19:43:32 +08:00
if (calledMethod == null)
continue;
2013-01-19 20:03:57 +08:00
AddDelegateInfo(new DelegateInfo(field, calledMethod, callOpcode));
Logger.v("Field: {0}, Opcode: {1}, Method: {2} ({3:X8})",
2013-01-19 20:03:57 +08:00
Utils.RemoveNewlines(field.Name),
callOpcode,
2013-01-19 20:03:57 +08:00
Utils.RemoveNewlines(calledMethod),
2012-11-01 21:39:39 +08:00
calledMethod.MDToken.Raw);
2011-09-22 10:55:30 +08:00
}
2013-01-19 20:03:57 +08:00
Logger.Instance.DeIndent();
2011-09-22 10:55:30 +08:00
delegateTypesDict[type] = true;
}
}
2013-01-19 20:03:57 +08:00
protected abstract object CheckCctor(ref TypeDef type, MethodDef cctor);
protected abstract void GetCallInfo(object context, FieldDef field, out IMethod calledMethod, out OpCode callOpcode);
2011-10-23 19:43:32 +08:00
2013-01-19 20:03:57 +08:00
protected override bool Deobfuscate(Blocks blocks, IList<Block> allBlocks) {
2011-09-22 10:55:30 +08:00
var removeInfos = new Dictionary<Block, List<RemoveInfo>>();
foreach (var block in allBlocks) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
2011-10-23 19:43:32 +08:00
var instr = instrs[i];
2012-05-29 17:13:39 +08:00
if (instr.OpCode != OpCodes.Ldsfld)
continue;
2013-01-19 20:03:57 +08:00
var di = GetDelegateInfo(instr.Operand as IField);
2012-05-29 17:13:39 +08:00
if (di == null)
continue;
2013-01-19 20:03:57 +08:00
var callInfo = FindProxyCall(di, block, i);
2012-05-29 17:13:39 +08:00
if (callInfo != null) {
2013-01-19 20:03:57 +08:00
Add(removeInfos, block, i, null);
Add(removeInfos, callInfo.Block, callInfo.Index, di);
2011-09-22 10:55:30 +08:00
}
2012-05-29 17:13:39 +08:00
else {
errors++;
Logger.w("Could not fix proxy call. Method: {0} ({1:X8}), Proxy type: {2} ({3:X8})",
2013-01-19 20:03:57 +08:00
Utils.RemoveNewlines(blocks.Method),
2012-11-01 21:39:39 +08:00
blocks.Method.MDToken.ToInt32(),
2013-01-19 20:03:57 +08:00
Utils.RemoveNewlines(di.field.DeclaringType),
2012-11-01 21:39:39 +08:00
di.field.DeclaringType.MDToken.ToInt32());
2011-09-22 10:55:30 +08:00
}
}
}
return FixProxyCalls(blocks.Method, removeInfos);
2011-09-22 10:55:30 +08:00
}
2013-01-19 20:03:57 +08:00
protected virtual BlockInstr FindProxyCall(DelegateInfo di, Block block, int index) {
return FindProxyCall(di, block, index, new Dictionary<Block, bool>(), 1);
2012-05-30 01:13:43 +08:00
}
2013-01-19 20:03:57 +08:00
BlockInstr FindProxyCall(DelegateInfo di, Block block, int index, Dictionary<Block, bool> visited, int stack) {
2011-09-22 10:55:30 +08:00
if (visited.ContainsKey(block))
return null;
if (index <= 0)
visited[block] = true;
var instrs = block.Instructions;
for (int i = index + 1; i < instrs.Count; i++) {
if (stack <= 0)
return null;
var instr = instrs[i];
2012-11-01 21:39:39 +08:00
instr.Instruction.UpdateStack(ref stack, false);
2011-09-22 10:55:30 +08:00
if (stack < 0)
return null;
if (instr.OpCode != OpCodes.Call && instr.OpCode != OpCodes.Callvirt) {
if (stack <= 0)
return null;
2011-09-22 10:55:30 +08:00
continue;
}
2012-11-01 21:39:39 +08:00
var calledMethod = instr.Operand as IMethod;
if (calledMethod == null)
return null;
2013-01-19 20:03:57 +08:00
if (stack != (DotNetUtils.HasReturnValue(calledMethod) ? 1 : 0))
2011-09-22 10:55:30 +08:00
continue;
if (calledMethod.Name != "Invoke")
return null;
2011-09-22 10:55:30 +08:00
return new BlockInstr {
Block = block,
Index = i,
};
}
if (stack <= 0)
return null;
2013-01-19 20:03:57 +08:00
foreach (var target in block.GetTargets()) {
var info = FindProxyCall(di, target, -1, visited, stack);
2011-09-22 10:55:30 +08:00
if (info != null)
return info;
}
return null;
}
2013-01-19 20:03:57 +08:00
protected override void DeobfuscateEnd(Blocks blocks, IList<Block> allBlocks) {
FixBrokenCalls(blocks.Method, allBlocks);
2012-05-29 17:13:39 +08:00
}
2011-09-22 10:55:30 +08:00
// The obfuscator could be buggy and call a proxy delegate without pushing the
// instance field. SA has done it, so let's fix it.
2013-01-19 20:03:57 +08:00
void FixBrokenCalls(MethodDef obfuscatedMethod, IList<Block> allBlocks) {
2011-09-22 10:55:30 +08:00
foreach (var block in allBlocks) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var call = instrs[i];
if (call.OpCode != OpCodes.Call && call.OpCode != OpCodes.Callvirt)
continue;
2012-11-01 21:39:39 +08:00
var methodRef = call.Operand as IMethod;
if (methodRef == null || methodRef.Name != "Invoke")
2011-09-22 10:55:30 +08:00
continue;
2013-01-19 20:03:57 +08:00
MethodDef method = DotNetUtils.GetMethod2(module, methodRef);
2012-11-01 21:39:39 +08:00
if (method == null || method.DeclaringType == null)
2011-09-22 10:55:30 +08:00
continue;
2012-11-01 21:39:39 +08:00
if (!delegateTypesDict.ContainsKey(method.DeclaringType))
2011-09-22 10:55:30 +08:00
continue;
// Oooops!!! The obfuscator is buggy. Well, let's hope it is, or it's my code. ;)
Logger.w("Holy obfuscator bugs, Batman! Found a proxy delegate call with no instance push in {0:X8}. Replacing it with a throw...", obfuscatedMethod.MDToken.ToInt32());
2013-01-19 20:03:57 +08:00
block.Insert(i, OpCodes.Ldnull.ToInstruction());
block.Replace(i + 1, 1, OpCodes.Throw.ToInstruction());
2011-09-22 10:55:30 +08:00
i++;
}
}
}
}
2012-05-29 17:13:39 +08:00
// Fixes proxy calls that call a static method which then calls
// Invoke() on a delegate instance, eg.:
// ...push args...
// call static method
public abstract class ProxyCallFixer2 : ProxyCallFixerBase {
2012-11-22 16:14:51 +08:00
MethodDefAndDeclaringTypeDict<DelegateInfo> proxyMethodToDelegateInfo = new MethodDefAndDeclaringTypeDict<DelegateInfo>();
2012-05-29 17:13:39 +08:00
2012-11-01 21:39:39 +08:00
protected ProxyCallFixer2(ModuleDefMD module)
2012-05-29 17:13:39 +08:00
: base(module) {
}
2012-11-01 21:39:39 +08:00
protected ProxyCallFixer2(ModuleDefMD module, ProxyCallFixer2 oldOne)
2012-05-29 17:13:39 +08:00
: base(module, oldOne) {
2013-01-19 20:03:57 +08:00
foreach (var oldMethod in oldOne.proxyMethodToDelegateInfo.GetKeys()) {
var oldDi = oldOne.proxyMethodToDelegateInfo.Find(oldMethod);
var method = Lookup(oldMethod, "Could not find proxy method");
proxyMethodToDelegateInfo.Add(method, Copy(oldDi));
2012-05-29 17:13:39 +08:00
}
}
2013-01-19 20:03:57 +08:00
public void Find() {
2012-05-29 17:13:39 +08:00
if (delegateCreatorMethods.Count == 0)
return;
Logger.v("Finding all proxy delegates");
2013-01-19 20:03:57 +08:00
Find2();
2012-07-31 13:13:07 +08:00
}
2013-01-19 20:03:57 +08:00
protected void Find2() {
foreach (var type in GetDelegateTypes()) {
2012-11-17 06:50:52 +08:00
var cctor = type.FindStaticConstructor();
if (cctor == null || !cctor.HasBody)
2012-05-29 17:13:39 +08:00
continue;
if (!type.HasFields)
continue;
2013-01-19 20:03:57 +08:00
object context = CheckCctor(type, cctor);
2012-05-29 17:13:39 +08:00
if (context == null)
continue;
2013-01-19 20:03:57 +08:00
Logger.v("Found proxy delegate: {0} ({1:X8})", Utils.RemoveNewlines(type), type.MDToken.ToUInt32());
2012-05-29 17:13:39 +08:00
RemovedDelegateCreatorCalls++;
2013-01-19 20:03:57 +08:00
var fieldToMethod = GetFieldToMethodDictionary(type);
2012-05-29 17:13:39 +08:00
2013-01-19 20:03:57 +08:00
Logger.Instance.Indent();
2012-05-29 17:13:39 +08:00
foreach (var field in type.Fields) {
2012-11-01 21:39:39 +08:00
MethodDef proxyMethod;
2012-05-29 17:13:39 +08:00
if (!fieldToMethod.TryGetValue(field, out proxyMethod))
continue;
2012-11-01 21:39:39 +08:00
IMethod calledMethod;
2012-05-29 17:13:39 +08:00
OpCode callOpcode;
2013-01-19 20:03:57 +08:00
GetCallInfo(context, field, out calledMethod, out callOpcode);
2012-05-29 17:13:39 +08:00
if (calledMethod == null)
continue;
2013-01-19 20:03:57 +08:00
Add(proxyMethod, new DelegateInfo(field, calledMethod, callOpcode));
Logger.v("Field: {0}, Opcode: {1}, Method: {2} ({3:X8})",
2013-01-19 20:03:57 +08:00
Utils.RemoveNewlines(field.Name),
2012-05-29 17:13:39 +08:00
callOpcode,
2013-01-19 20:03:57 +08:00
Utils.RemoveNewlines(calledMethod),
2012-11-01 21:39:39 +08:00
calledMethod.MDToken.ToUInt32());
2012-05-29 17:13:39 +08:00
}
2013-01-19 20:03:57 +08:00
Logger.Instance.DeIndent();
2012-05-29 17:13:39 +08:00
delegateTypesDict[type] = true;
}
}
2013-01-19 20:03:57 +08:00
protected void Add(MethodDef method, DelegateInfo di) {
proxyMethodToDelegateInfo.Add(method, di);
2012-05-29 17:13:39 +08:00
}
2013-01-19 20:03:57 +08:00
protected abstract object CheckCctor(TypeDef type, MethodDef cctor);
protected abstract void GetCallInfo(object context, FieldDef field, out IMethod calledMethod, out OpCode callOpcode);
2012-05-29 17:13:39 +08:00
2013-01-19 20:03:57 +08:00
Dictionary<FieldDef, MethodDef> GetFieldToMethodDictionary(TypeDef type) {
2012-11-01 21:39:39 +08:00
var dict = new Dictionary<FieldDef, MethodDef>();
foreach (var method in type.Methods) {
if (!method.IsStatic || !method.HasBody || method.Name == ".cctor")
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;
2012-11-01 21:39:39 +08:00
var field = instr.Operand as FieldDef;
if (field == null)
continue;
dict[field] = method;
break;
}
}
return dict;
}
2013-01-19 20:03:57 +08:00
protected override bool Deobfuscate(Blocks blocks, IList<Block> allBlocks) {
2012-05-29 17:13:39 +08:00
var removeInfos = new Dictionary<Block, List<RemoveInfo>>();
foreach (var block in allBlocks) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var instr = instrs[i];
if (instr.OpCode != OpCodes.Call)
continue;
2012-11-01 21:39:39 +08:00
var method = instr.Operand as IMethod;
2012-05-29 17:13:39 +08:00
if (method == null)
continue;
2013-01-19 20:03:57 +08:00
var di = proxyMethodToDelegateInfo.Find(method);
2012-05-29 17:13:39 +08:00
if (di == null)
continue;
2013-01-19 20:03:57 +08:00
Add(removeInfos, block, i, di);
2012-05-29 17:13:39 +08:00
}
}
return FixProxyCalls(blocks.Method, removeInfos);
2012-05-29 17:13:39 +08:00
}
}
2012-05-30 01:13:43 +08:00
// Fixes proxy calls that call a static method with the instance of
2012-07-07 06:58:18 +08:00
// a delegate as the last arg, which then calls the Invoke method.
2012-05-30 01:13:43 +08:00
// ...push args...
// ldsfld delegate instance
// call static method
public abstract class ProxyCallFixer3 : ProxyCallFixer1 {
2012-11-01 21:39:39 +08:00
protected ProxyCallFixer3(ModuleDefMD module)
2012-05-30 01:13:43 +08:00
: base(module) {
}
2012-11-01 21:39:39 +08:00
protected ProxyCallFixer3(ModuleDefMD module, ProxyCallFixer3 oldOne)
2012-05-30 01:13:43 +08:00
: base(module, oldOne) {
}
2013-01-19 20:03:57 +08:00
protected override BlockInstr FindProxyCall(DelegateInfo di, Block block, int index) {
2012-05-30 01:13:43 +08:00
index++;
if (index >= block.Instructions.Count)
return null;
2013-01-19 20:03:57 +08:00
var calledMethod = GetCalledMethod(block.Instructions[index]);
2012-05-30 01:13:43 +08:00
if (calledMethod == null)
return null;
return new BlockInstr {
Block = block,
Index = index,
};
}
2013-01-19 20:03:57 +08:00
static IMethod GetCalledMethod(Instr instr) {
2012-05-30 01:13:43 +08:00
if (instr.OpCode.Code != Code.Call)
return null;
2012-11-01 21:39:39 +08:00
return instr.Operand as IMethod;
2012-05-30 01:13:43 +08:00
}
}
//
// Combines the above 1st and 2nd templates
//
public abstract class ProxyCallFixer4 : ProxyCallFixerBase
{
FieldDefAndDeclaringTypeDict<DelegateInfo> fieldToDelegateInfo = new FieldDefAndDeclaringTypeDict<DelegateInfo>();
MethodDefAndDeclaringTypeDict<DelegateInfo> proxyMethodToDelegateInfo = new MethodDefAndDeclaringTypeDict<DelegateInfo>();
protected ProxyCallFixer4(ModuleDefMD module)
: base(module)
{
}
protected ProxyCallFixer4(ModuleDefMD module, ProxyCallFixer4 oldOne)
: base(module, oldOne)
{
foreach (var key in oldOne.fieldToDelegateInfo.GetKeys())
fieldToDelegateInfo.Add(Lookup(key, "Could not find field"), Copy(oldOne.fieldToDelegateInfo.Find(key)));
foreach (var oldMethod in oldOne.proxyMethodToDelegateInfo.GetKeys())
{
var oldDi = oldOne.proxyMethodToDelegateInfo.Find(oldMethod);
var method = Lookup(oldMethod, "Could not find proxy method");
proxyMethodToDelegateInfo.Add(method, Copy(oldDi));
}
}
protected void AddDelegateInfo(DelegateInfo di)
{
fieldToDelegateInfo.Add(di.field, di);
}
protected DelegateInfo GetDelegateInfo(IField field)
{
if (field == null)
return null;
return fieldToDelegateInfo.Find(field);
}
public void Find()
{
if (delegateCreatorMethods.Count == 0)
return;
Logger.v("Finding all proxy delegates");
foreach (var type in GetDelegateTypes())
{
var cctor = type.FindStaticConstructor();
if (cctor == null || !cctor.HasBody)
continue;
if (!type.HasFields)
continue;
object context = CheckCctor(type, cctor);
if (context == null)
continue;
Logger.v("Found proxy delegate: {0} ({1:X8})", Utils.RemoveNewlines(type), type.MDToken.ToUInt32());
RemovedDelegateCreatorCalls++;
var fieldToMethod = GetFieldToMethodDictionary(type);
Logger.Instance.Indent();
foreach (var field in type.Fields)
{
MethodDef proxyMethod;
bool supportType1 = fieldToMethod.TryGetValue(field, out proxyMethod);
bool supportType2 = field.IsStatic;
if (!supportType1 && !supportType2)
continue;
IMethod calledMethod;
OpCode callOpcode;
GetCallInfo(context, field, out calledMethod, out callOpcode);
if (calledMethod == null)
continue;
if (supportType1)
{
Add2(proxyMethod, new DelegateInfo(field, calledMethod, callOpcode));
}
if (supportType2)
{
AddDelegateInfo(new DelegateInfo(field, calledMethod, callOpcode));
}
Logger.v("Field: {0}, Opcode: {1}, Method: {2} ({3:X8})",
Utils.RemoveNewlines(field.Name),
callOpcode,
Utils.RemoveNewlines(calledMethod),
calledMethod.MDToken.Raw);
}
Logger.Instance.DeIndent();
delegateTypesDict[type] = true;
}
}
protected void Add2(MethodDef method, DelegateInfo di)
{
proxyMethodToDelegateInfo.Add(method, di);
}
protected abstract object CheckCctor(TypeDef type, MethodDef cctor);
protected abstract void GetCallInfo(object context, FieldDef field, out IMethod calledMethod, out OpCode callOpcode);
Dictionary<FieldDef, MethodDef> GetFieldToMethodDictionary(TypeDef type)
{
var dict = new Dictionary<FieldDef, MethodDef>();
foreach (var method in type.Methods)
{
if (!method.IsStatic || !method.HasBody || method.Name == ".cctor")
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;
var field = instr.Operand as FieldDef;
if (field == null)
continue;
dict[field] = method;
break;
}
}
return dict;
}
protected override bool Deobfuscate(Blocks blocks, IList<Block> allBlocks)
{
var removeInfos = new Dictionary<Block, List<RemoveInfo>>();
foreach (var block in allBlocks)
{
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++)
{
var instr = instrs[i];
if (instr.OpCode == OpCodes.Call)
{
var method = instr.Operand as IMethod;
if (method == null)
continue;
var di = proxyMethodToDelegateInfo.Find(method);
if (di == null)
continue;
Add(removeInfos, block, i, di);
}
else if (instr.OpCode == OpCodes.Ldsfld)
{
var di = GetDelegateInfo(instr.Operand as IField);
if (di == null)
continue;
var callInfo = FindProxyCall(di, block, i);
if (callInfo != null)
{
Add(removeInfos, block, i, null);
Add(removeInfos, callInfo.Block, callInfo.Index, di);
}
else
{
errors++;
Logger.w("Could not fix proxy call. Method: {0} ({1:X8}), Proxy type: {2} ({3:X8})",
Utils.RemoveNewlines(blocks.Method),
blocks.Method.MDToken.ToInt32(),
Utils.RemoveNewlines(di.field.DeclaringType),
di.field.DeclaringType.MDToken.ToInt32());
}
}
}
}
return FixProxyCalls(blocks.Method, removeInfos);
}
protected virtual BlockInstr FindProxyCall(DelegateInfo di, Block block, int index)
{
return FindProxyCall(di, block, index, new Dictionary<Block, bool>(), 1);
}
BlockInstr FindProxyCall(DelegateInfo di, Block block, int index, Dictionary<Block, bool> visited, int stack)
{
if (visited.ContainsKey(block))
return null;
if (index <= 0)
visited[block] = true;
var instrs = block.Instructions;
for (int i = index + 1; i < instrs.Count; i++)
{
if (stack <= 0)
return null;
var instr = instrs[i];
instr.Instruction.UpdateStack(ref stack, false);
if (stack < 0)
return null;
if (instr.OpCode != OpCodes.Call && instr.OpCode != OpCodes.Callvirt)
{
if (stack <= 0)
return null;
continue;
}
var calledMethod = instr.Operand as IMethod;
if (calledMethod == null)
return null;
if (stack != (DotNetUtils.HasReturnValue(calledMethod) ? 1 : 0))
continue;
if (calledMethod.Name != "Invoke")
return null;
return new BlockInstr
{
Block = block,
Index = i,
};
}
if (stack <= 0)
return null;
foreach (var target in block.GetTargets())
{
var info = FindProxyCall(di, target, -1, visited, stack);
if (info != null)
return info;
}
return null;
}
}
2011-09-22 10:55:30 +08:00
}