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\AntiDebugger.cs" />
|
||||||
<Compile Include="deobfuscators\CryptoObfuscator\AssemblyResolver.cs" />
|
<Compile Include="deobfuscators\CryptoObfuscator\AssemblyResolver.cs" />
|
||||||
<Compile Include="deobfuscators\CryptoObfuscator\Deobfuscator.cs" />
|
<Compile Include="deobfuscators\CryptoObfuscator\Deobfuscator.cs" />
|
||||||
|
<Compile Include="deobfuscators\CryptoObfuscator\ProxyDelegateFinder.cs" />
|
||||||
<Compile Include="deobfuscators\CryptoObfuscator\ResourceDecrypter.cs" />
|
<Compile Include="deobfuscators\CryptoObfuscator\ResourceDecrypter.cs" />
|
||||||
<Compile Include="deobfuscators\CryptoObfuscator\ResourceResolver.cs" />
|
<Compile Include="deobfuscators\CryptoObfuscator\ResourceResolver.cs" />
|
||||||
<Compile Include="deobfuscators\CryptoObfuscator\StringDecrypter.cs" />
|
<Compile Include="deobfuscators\CryptoObfuscator\StringDecrypter.cs" />
|
||||||
|
|
|
@ -20,22 +20,50 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Mono.Cecil;
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.deobfuscators.CliSecure {
|
namespace de4dot.deobfuscators.CliSecure {
|
||||||
class ProxyDelegateFinder : ProxyDelegateFinderBase {
|
class ProxyDelegateFinder : ProxyDelegateFinderBase {
|
||||||
|
IList<MemberReference> memberReferences;
|
||||||
|
|
||||||
public ProxyDelegateFinder(ModuleDefinition module)
|
public ProxyDelegateFinder(ModuleDefinition module)
|
||||||
: base(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;
|
var name = field.Name;
|
||||||
isVirtual = false;
|
callOpcode = OpCodes.Call;
|
||||||
if (name.EndsWith("%", StringComparison.Ordinal)) {
|
if (name.EndsWith("%", StringComparison.Ordinal)) {
|
||||||
isVirtual = true;
|
callOpcode = OpCodes.Callvirt;
|
||||||
name = name.TrimEnd(new char[] { '%' });
|
name = name.TrimEnd(new char[] { '%' });
|
||||||
}
|
}
|
||||||
byte[] value = Convert.FromBase64String(name);
|
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 foundCryptoObfuscatorAttribute = false;
|
||||||
bool foundObfuscatedSymbols = false;
|
bool foundObfuscatedSymbols = false;
|
||||||
|
|
||||||
|
ProxyDelegateFinder proxyDelegateFinder;
|
||||||
ResourceDecrypter resourceDecrypter;
|
ResourceDecrypter resourceDecrypter;
|
||||||
ResourceResolver resourceResolver;
|
ResourceResolver resourceResolver;
|
||||||
AssemblyResolver assemblyResolver;
|
AssemblyResolver assemblyResolver;
|
||||||
|
@ -102,6 +103,8 @@ namespace de4dot.deobfuscators.CryptoObfuscator {
|
||||||
val += 10;
|
val += 10;
|
||||||
if (tamperDetection.Detected)
|
if (tamperDetection.Detected)
|
||||||
val += 10;
|
val += 10;
|
||||||
|
if (proxyDelegateFinder.Detected)
|
||||||
|
val += 10;
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
@ -117,6 +120,8 @@ namespace de4dot.deobfuscators.CryptoObfuscator {
|
||||||
if (checkCryptoObfuscator())
|
if (checkCryptoObfuscator())
|
||||||
foundObfuscatedSymbols = true;
|
foundObfuscatedSymbols = true;
|
||||||
|
|
||||||
|
proxyDelegateFinder = new ProxyDelegateFinder(module);
|
||||||
|
proxyDelegateFinder.findDelegateCreator(module);
|
||||||
stringDecrypter = new StringDecrypter(module);
|
stringDecrypter = new StringDecrypter(module);
|
||||||
stringDecrypter.find();
|
stringDecrypter.find();
|
||||||
tamperDetection = new TamperDetection(module);
|
tamperDetection = new TamperDetection(module);
|
||||||
|
@ -182,9 +187,21 @@ namespace de4dot.deobfuscators.CryptoObfuscator {
|
||||||
addTypeToBeRemoved(antiDebugger.AntiDebuggerType, "Anti-debugger type");
|
addTypeToBeRemoved(antiDebugger.AntiDebuggerType, "Anti-debugger type");
|
||||||
addTypeToBeRemoved(stringDecrypter.StringDecrypterType, "String decrypter type");
|
addTypeToBeRemoved(stringDecrypter.StringDecrypterType, "String decrypter type");
|
||||||
|
|
||||||
|
proxyDelegateFinder.find();
|
||||||
|
|
||||||
dumpEmbeddedAssemblies();
|
dumpEmbeddedAssemblies();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void deobfuscateMethodEnd(Blocks blocks) {
|
||||||
|
proxyDelegateFinder.deobfuscate(blocks);
|
||||||
|
base.deobfuscateMethodEnd(blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void deobfuscateEnd() {
|
||||||
|
removeProxyDelegates(proxyDelegateFinder);
|
||||||
|
base.deobfuscateEnd();
|
||||||
|
}
|
||||||
|
|
||||||
void decryptResources() {
|
void decryptResources() {
|
||||||
var rsrc = resourceResolver.mergeResources();
|
var rsrc = resourceResolver.mergeResources();
|
||||||
if (rsrc == null)
|
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) {
|
protected void removeProxyDelegates(ProxyDelegateFinderBase proxyDelegateFinder) {
|
||||||
addTypesToBeRemoved(proxyDelegateFinder.DelegateTypes, "Proxy delegate type");
|
addTypesToBeRemoved(proxyDelegateFinder.DelegateTypes, "Proxy delegate type");
|
||||||
if (proxyDelegateFinder.RemovedDelegateCreatorCalls > 0)
|
if (proxyDelegateFinder.RemovedDelegateCreatorCalls > 0)
|
||||||
addTypeToBeRemoved(proxyDelegateFinder.DelegateCreatorMethod.DeclaringType, "Proxy delegate creator type");
|
addTypesToBeRemoved(proxyDelegateFinder.DelegateCreatorTypes, "Proxy delegate creator type");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TypeDefinition getModuleType() {
|
protected TypeDefinition getModuleType() {
|
||||||
|
|
|
@ -25,46 +25,60 @@ using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.deobfuscators {
|
namespace de4dot.deobfuscators {
|
||||||
abstract class ProxyDelegateFinderBase {
|
abstract class ProxyDelegateFinderBase {
|
||||||
ModuleDefinition module;
|
protected ModuleDefinition module;
|
||||||
IList<MemberReference> memberReferences;
|
List<MethodDefinition> delegateCreatorMethods = new List<MethodDefinition>();
|
||||||
MethodDefinition delegateCreatorMethod;
|
|
||||||
Dictionary<TypeDefinition, bool> delegateTypesDict = new Dictionary<TypeDefinition, bool>();
|
Dictionary<TypeDefinition, bool> delegateTypesDict = new Dictionary<TypeDefinition, bool>();
|
||||||
Dictionary<FieldReferenceAndDeclaringTypeKey, DelegateInfo> fieldToDelegateInfo = new Dictionary<FieldReferenceAndDeclaringTypeKey, DelegateInfo>();
|
Dictionary<FieldReferenceAndDeclaringTypeKey, DelegateInfo> fieldToDelegateInfo = new Dictionary<FieldReferenceAndDeclaringTypeKey, DelegateInfo>();
|
||||||
|
Dictionary<MethodDefinition, FieldDefinition> proxyMethodToField = new Dictionary<MethodDefinition, FieldDefinition>();
|
||||||
|
|
||||||
class DelegateInfo {
|
class DelegateInfo {
|
||||||
public MethodReference methodRef; // Method we should call
|
public MethodReference methodRef; // Method we should call
|
||||||
public FieldDefinition field; // Field holding the Delegate instance
|
public FieldDefinition field; // Field holding the Delegate instance
|
||||||
public bool isVirtual;
|
public OpCode callOpcode;
|
||||||
public DelegateInfo(FieldDefinition field, MethodReference methodRef, bool isVirtual) {
|
public DelegateInfo(FieldDefinition field, MethodReference methodRef, OpCode callOpcode) {
|
||||||
this.field = field;
|
this.field = field;
|
||||||
this.methodRef = methodRef;
|
this.methodRef = methodRef;
|
||||||
this.isVirtual = isVirtual;
|
this.callOpcode = callOpcode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int RemovedDelegateCreatorCalls { get; set; }
|
public int RemovedDelegateCreatorCalls { get; set; }
|
||||||
|
|
||||||
public IEnumerable<TypeDefinition> DelegateTypes {
|
public IEnumerable<TypeDefinition> DelegateTypes {
|
||||||
get { return delegateTypesDict.Keys; }
|
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 {
|
public bool Detected {
|
||||||
get { return delegateCreatorMethod != null; }
|
get { return delegateCreatorMethods.Count != 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProxyDelegateFinderBase(ModuleDefinition module) {
|
public ProxyDelegateFinderBase(ModuleDefinition module) {
|
||||||
this.module = module;
|
this.module = module;
|
||||||
this.memberReferences = new List<MemberReference>(module.GetMemberReferences());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDelegateCreatorMethod(MethodDefinition delegateCreatorMethod) {
|
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() {
|
public void find() {
|
||||||
if (delegateCreatorMethod == null)
|
if (delegateCreatorMethods.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Log.v("Finding all proxy delegates");
|
Log.v("Finding all proxy delegates");
|
||||||
|
@ -77,47 +91,44 @@ namespace de4dot.deobfuscators {
|
||||||
if (!type.HasFields)
|
if (!type.HasFields)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var instrs = cctor.Body.Instructions;
|
object context = checkCctor(type, cctor);
|
||||||
if (instrs.Count != 3)
|
if (context == null)
|
||||||
continue;
|
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());
|
Log.v("Found proxy delegate: {0} ({1:X8})", type, type.MetadataToken.ToUInt32());
|
||||||
RemovedDelegateCreatorCalls++;
|
RemovedDelegateCreatorCalls++;
|
||||||
|
onFoundProxyDelegate(type);
|
||||||
|
|
||||||
Log.indent();
|
Log.indent();
|
||||||
foreach (var field in type.Fields) {
|
foreach (var field in type.Fields) {
|
||||||
if (!field.IsStatic || field.IsPublic)
|
if (!field.IsStatic || field.IsPublic)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int methodIndex;
|
MethodReference calledMethod;
|
||||||
bool isVirtual;
|
OpCode callOpcode;
|
||||||
getCallInfo(field, out methodIndex, out isVirtual);
|
getCallInfo(context, field, out calledMethod, out callOpcode);
|
||||||
if (methodIndex >= memberReferences.Count)
|
|
||||||
throw new ApplicationException(string.Format("methodIndex ({0}) >= memberReferences.Count ({1})", methodIndex, memberReferences.Count));
|
|
||||||
|
|
||||||
var methodRef = memberReferences[methodIndex] as MethodReference;
|
if (calledMethod == null)
|
||||||
if (methodRef == null)
|
throw new ApplicationException("calledMethod is null");
|
||||||
throw new ApplicationException("methodRef is null");
|
fieldToDelegateInfo[new FieldReferenceAndDeclaringTypeKey(field)] = new DelegateInfo(field, calledMethod, callOpcode);
|
||||||
fieldToDelegateInfo[new FieldReferenceAndDeclaringTypeKey(field)] = new DelegateInfo(field, methodRef, isVirtual);
|
Log.v("Field: {0}, Opcode: {1}, Method: {2} ({3:X8})", field.Name, callOpcode, calledMethod, calledMethod.MetadataToken.ToUInt32());
|
||||||
Log.v("Field: {0}, Virtual: {1}, Method: {2}, RID: {3}", field.Name, isVirtual, methodRef, methodIndex + 1);
|
|
||||||
}
|
}
|
||||||
Log.deIndent();
|
Log.deIndent();
|
||||||
delegateTypesDict[type] = true;
|
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) {
|
MethodDefinition findMethod(TypeDefinition type, string name) {
|
||||||
if (!type.HasMethods)
|
if (!type.HasMethods)
|
||||||
|
@ -158,23 +169,35 @@ namespace de4dot.deobfuscators {
|
||||||
foreach (var block in allBlocks) {
|
foreach (var block in allBlocks) {
|
||||||
var instrs = block.Instructions;
|
var instrs = block.Instructions;
|
||||||
for (int i = 0; i < instrs.Count; i++) {
|
for (int i = 0; i < instrs.Count; i++) {
|
||||||
var ldsfld = instrs[i];
|
var instr = instrs[i];
|
||||||
if (ldsfld.OpCode != OpCodes.Ldsfld)
|
if (instr.OpCode == OpCodes.Ldsfld) {
|
||||||
continue;
|
var di = getDelegateInfo(instr.Operand as FieldReference);
|
||||||
var di = getDelegateInfo(ldsfld.Operand as FieldReference);
|
if (di == null)
|
||||||
if (di == null)
|
continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
var visited = new Dictionary<Block, bool>();
|
var visited = new Dictionary<Block, bool>();
|
||||||
var callInfo = findProxyCall(di, block, i, visited, 1);
|
var callInfo = findProxyCall(di, block, i, visited, 1);
|
||||||
if (callInfo != null) {
|
if (callInfo != null) {
|
||||||
add(removeInfos, block, i, null);
|
add(removeInfos, block, i, null);
|
||||||
add(removeInfos, callInfo.Block, callInfo.Index, di);
|
add(removeInfos, callInfo.Block, callInfo.Index, di);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log.w("Could not fix proxy call. Method: {0} ({1:X8}), Proxy type: {2} ({3:X8})",
|
||||||
|
blocks.Method, blocks.Method.MetadataToken.ToInt32(),
|
||||||
|
di.field.DeclaringType, di.field.DeclaringType.MetadataToken.ToInt32());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if (instr.OpCode == OpCodes.Call) {
|
||||||
Log.w("Could not fix proxy call. Method: {0} ({1:X8}), Proxy type: {2} ({3:X8})",
|
var method = instr.Operand as MethodDefinition;
|
||||||
blocks.Method, blocks.Method.MetadataToken.ToInt32(),
|
if (method == null)
|
||||||
di.field.DeclaringType, di.field.DeclaringType.MetadataToken.ToInt32());
|
continue;
|
||||||
|
FieldDefinition field;
|
||||||
|
if (!proxyMethodToField.TryGetValue(method, out field))
|
||||||
|
continue;
|
||||||
|
var di = getDelegateInfo(field);
|
||||||
|
if (di == null)
|
||||||
|
continue;
|
||||||
|
add(removeInfos, block, i, di);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,7 +207,7 @@ namespace de4dot.deobfuscators {
|
||||||
var removeIndexes = new List<int>(list.Count);
|
var removeIndexes = new List<int>(list.Count);
|
||||||
foreach (var info in list) {
|
foreach (var info in list) {
|
||||||
if (info.IsCall) {
|
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);
|
var newInstr = Instruction.Create(opcode, info.DelegateInfo.methodRef);
|
||||||
block.replace(info.Index, 1, newInstr);
|
block.replace(info.Index, 1, newInstr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Mono.Cecil;
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.deobfuscators.SmartAssembly {
|
namespace de4dot.deobfuscators.SmartAssembly {
|
||||||
|
@ -35,6 +37,8 @@ namespace de4dot.deobfuscators.SmartAssembly {
|
||||||
'\x9E', '\x9F',
|
'\x9E', '\x9F',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
IList<MemberReference> memberReferences;
|
||||||
|
|
||||||
static ProxyDelegateFinder() {
|
static ProxyDelegateFinder() {
|
||||||
for (int i = 0; i < specialChars.Length; i++)
|
for (int i = 0; i < specialChars.Length; i++)
|
||||||
specialCharsDict[specialChars[i]] = i;
|
specialCharsDict[specialChars[i]] = i;
|
||||||
|
@ -42,17 +46,38 @@ namespace de4dot.deobfuscators.SmartAssembly {
|
||||||
|
|
||||||
public ProxyDelegateFinder(ModuleDefinition module)
|
public ProxyDelegateFinder(ModuleDefinition module)
|
||||||
: base(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) {
|
||||||
isVirtual = false;
|
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;
|
string name = field.Name;
|
||||||
|
|
||||||
methodIndex = 0;
|
int methodIndex = 0;
|
||||||
for (int i = name.Length - 1; i >= 0; i--) {
|
for (int i = name.Length - 1; i >= 0; i--) {
|
||||||
char c = name[i];
|
char c = name[i];
|
||||||
if (c == '~') {
|
if (c == '~') {
|
||||||
isVirtual = true;
|
callOpcode = OpCodes.Callvirt;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +85,9 @@ namespace de4dot.deobfuscators.SmartAssembly {
|
||||||
if (specialCharsDict.TryGetValue(c, out val))
|
if (specialCharsDict.TryGetValue(c, out val))
|
||||||
methodIndex = methodIndex * specialChars.Length + 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) {
|
public void findDelegateCreator(ModuleDefinition module) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user