Support generic decrypter methods

This commit is contained in:
de4dot 2012-07-28 04:22:17 +02:00
parent a2c8e99b3f
commit cb6a3ac503
19 changed files with 84 additions and 65 deletions

View File

@ -21,6 +21,7 @@ using System;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Metadata;
using de4dot.blocks;
namespace de4dot.code {
@ -183,7 +184,7 @@ namespace de4dot.code {
protected abstract void inlineAllCalls();
// Returns null if method is not a method we should inline
protected abstract CallResult createCallResult(MethodReference method, Block block, int callInstrIndex);
protected abstract CallResult createCallResult(MethodReference method, GenericInstanceMethod gim, Block block, int callInstrIndex);
public int decrypt(Blocks theBlocks) {
if (!HasHandlers)
@ -232,7 +233,11 @@ namespace de4dot.code {
if (method == null)
continue;
var callResult = createCallResult(method, block, i);
MethodReference elementMethod = method;
var gim = method as GenericInstanceMethod;
if (gim != null)
elementMethod = gim.ElementMethod;
var callResult = createCallResult(elementMethod, gim, block, i);
if (callResult == null)
continue;
@ -255,6 +260,8 @@ namespace de4dot.code {
return false;
if (arg is int)
arg = fixIntArg(methodArgs[i].ParameterType, (int)arg);
else if (arg is long)
arg = fixIntArg(methodArgs[i].ParameterType, (long)arg);
args[i] = arg;
}
@ -263,18 +270,18 @@ namespace de4dot.code {
return true;
}
object fixIntArg(TypeReference type, int value) {
if (type.IsPrimitive) {
switch (type.FullName) {
case "System.Boolean": return value != 0;
case "System.Char": return (char)value;
case "System.Byte": return (byte)value;
case "System.SByte": return (sbyte)value;
case "System.Int16": return (short)value;
case "System.UInt16": return (ushort)value;
case "System.Int32": return (int)value;
case "System.UInt32": return (uint)value;
}
object fixIntArg(TypeReference type, long value) {
switch (type.EType) {
case ElementType.Boolean: return value != 0;
case ElementType.Char: return (char)value;
case ElementType.I1: return (sbyte)value;
case ElementType.U1: return (byte)value;
case ElementType.I2: return (short)value;
case ElementType.U2: return (ushort)value;
case ElementType.I4: return (int)value;
case ElementType.U4: return (uint)value;
case ElementType.I8: return (long)value;
case ElementType.U8: return (ulong)value;
}
throw new ApplicationException(string.Format("Wrong type {0}", type));
}
@ -360,6 +367,7 @@ namespace de4dot.code {
}
void inlineReturnValues() {
callResults = removeNulls(callResults);
callResults.Sort((a, b) => {
int i1 = allBlocks.FindIndex((x) => a.block == x);
int i2 = allBlocks.FindIndex((x) => b.block == x);
@ -372,6 +380,15 @@ namespace de4dot.code {
inlineReturnValues(callResults);
}
static List<CallResult> removeNulls(List<CallResult> inList) {
var outList = new List<CallResult>(inList.Count);
foreach (var callResult in inList) {
if (callResult.returnValue != null)
outList.Add(callResult);
}
return outList;
}
protected abstract void inlineReturnValues(IList<CallResult> callResults);
}
}

View File

@ -68,9 +68,11 @@ namespace de4dot.code {
class MyCallResult : CallResult {
public int methodId;
public MyCallResult(Block block, int callEndIndex, int methodId)
public GenericInstanceMethod gim;
public MyCallResult(Block block, int callEndIndex, int methodId, GenericInstanceMethod gim)
: base(block, callEndIndex) {
this.methodId = methodId;
this.gim = gim;
}
}
@ -91,11 +93,11 @@ namespace de4dot.code {
}
}
protected override CallResult createCallResult(MethodReference method, Block block, int callInstrIndex) {
protected override CallResult createCallResult(MethodReference method, GenericInstanceMethod gim, Block block, int callInstrIndex) {
int methodId;
if (!methodTokenToId.TryGetValue(method.MetadataToken.ToInt32(), out methodId))
return null;
return new MyCallResult(block, callInstrIndex, methodId);
return new MyCallResult(block, callInstrIndex, methodId, gim);
}
protected override void inlineAllCalls() {
@ -119,18 +121,14 @@ namespace de4dot.code {
if (decryptedStrings.Length != args.Length)
throw new ApplicationException("Invalid decrypted strings array length");
AssemblyData.SimpleData.unpack(decryptedStrings);
for (int i = 0; i < list.Count; i++) {
var s = decryptedStrings[i];
if (s == null)
throw new ApplicationException(string.Format("Decrypted string is null. Method: {0}", list[i].getMethodReference()));
list[i].returnValue = (string)s;
}
for (int i = 0; i < list.Count; i++)
list[i].returnValue = (string)decryptedStrings[i];
}
}
}
class StaticStringInliner : StringInlinerBase {
MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, object[], string>> stringDecrypters = new MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, object[], string>>();
MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, GenericInstanceMethod, object[], string>> stringDecrypters = new MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, GenericInstanceMethod, object[], string>>();
public override bool HasHandlers {
get { return stringDecrypters.Count != 0; }
@ -142,13 +140,15 @@ namespace de4dot.code {
class MyCallResult : CallResult {
public MethodReference methodReference;
public MyCallResult(Block block, int callEndIndex, MethodReference method)
public GenericInstanceMethod gim;
public MyCallResult(Block block, int callEndIndex, MethodReference method, GenericInstanceMethod gim)
: base(block, callEndIndex) {
this.methodReference = method;
this.gim = gim;
}
}
public void add(MethodDefinition method, Func<MethodDefinition, object[], string> handler) {
public void add(MethodDefinition method, Func<MethodDefinition, GenericInstanceMethod, object[], string> handler) {
if (method != null)
stringDecrypters.add(method, handler);
}
@ -157,14 +157,14 @@ namespace de4dot.code {
foreach (var tmp in callResults) {
var callResult = (MyCallResult)tmp;
var handler = stringDecrypters.find(callResult.methodReference);
callResult.returnValue = handler((MethodDefinition)callResult.methodReference, callResult.args);
callResult.returnValue = handler((MethodDefinition)callResult.methodReference, callResult.gim, callResult.args);
}
}
protected override CallResult createCallResult(MethodReference method, Block block, int callInstrIndex) {
protected override CallResult createCallResult(MethodReference method, GenericInstanceMethod gim, Block block, int callInstrIndex) {
if (stringDecrypters.find(method) == null)
return null;
return new MyCallResult(block, callInstrIndex, method);
return new MyCallResult(block, callInstrIndex, method, gim);
}
}
}

View File

@ -207,7 +207,7 @@ namespace de4dot.code.deobfuscators.Babel_NET {
if (Operations.DecryptStrings != OpDecryptString.None) {
if (stringDecrypter.Resource != null)
Log.v("Adding string decrypter. Resource: {0}", Utils.toCsharpString(stringDecrypter.Resource.Name));
staticStringInliner.add(stringDecrypter.DecryptMethod, (method, args) => {
staticStringInliner.add(stringDecrypter.DecryptMethod, (method, gim, args) => {
return stringDecrypter.decrypt(args);
});
DeobfuscatedFile.stringDecryptersAdded();
@ -232,13 +232,13 @@ namespace de4dot.code.deobfuscators.Babel_NET {
addTypeToBeRemoved(constantsDecrypter.Type, "Constants decrypter type");
addResourceToBeRemoved(constantsDecrypter.Resource, "Encrypted constants");
int32ValueInliner = new Int32ValueInliner();
int32ValueInliner.add(constantsDecrypter.Int32Decrypter, (method, args) => constantsDecrypter.decryptInt32((int)args[0]));
int32ValueInliner.add(constantsDecrypter.Int32Decrypter, (method, gim, args) => constantsDecrypter.decryptInt32((int)args[0]));
int64ValueInliner = new Int64ValueInliner();
int64ValueInliner.add(constantsDecrypter.Int64Decrypter, (method, args) => constantsDecrypter.decryptInt64((int)args[0]));
int64ValueInliner.add(constantsDecrypter.Int64Decrypter, (method, gim, args) => constantsDecrypter.decryptInt64((int)args[0]));
singleValueInliner = new SingleValueInliner();
singleValueInliner.add(constantsDecrypter.SingleDecrypter, (method, args) => constantsDecrypter.decryptSingle((int)args[0]));
singleValueInliner.add(constantsDecrypter.SingleDecrypter, (method, gim, args) => constantsDecrypter.decryptSingle((int)args[0]));
doubleValueInliner = new DoubleValueInliner();
doubleValueInliner.add(constantsDecrypter.DoubleDecrypter, (method, args) => constantsDecrypter.decryptDouble((int)args[0]));
doubleValueInliner.add(constantsDecrypter.DoubleDecrypter, (method, gim, args) => constantsDecrypter.decryptDouble((int)args[0]));
}
proxyCallFixer.find();

View File

@ -263,7 +263,7 @@ namespace de4dot.code.deobfuscators.CliSecure {
proxyCallFixer.find();
staticStringInliner.add(stringDecrypter.Method, (method, args) => stringDecrypter.decrypt((string)args[0]));
staticStringInliner.add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.decrypt((string)args[0]));
DeobfuscatedFile.stringDecryptersAdded();
if (options.DecryptMethods) {

View File

@ -130,7 +130,7 @@ namespace de4dot.code.deobfuscators.CodeFort {
public override void deobfuscateBegin() {
base.deobfuscateBegin();
staticStringInliner.add(stringDecrypter.Method, (method, args) => stringDecrypter.decrypt((string)args[0]));
staticStringInliner.add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.decrypt((string)args[0]));
DeobfuscatedFile.stringDecryptersAdded();
proxyCallFixer.find();

View File

@ -185,7 +185,7 @@ namespace de4dot.code.deobfuscators.CodeVeil {
if (Operations.DecryptStrings != OpDecryptString.None) {
stringDecrypter.initialize();
staticStringInliner.add(stringDecrypter.DecryptMethod, (method, args) => {
staticStringInliner.add(stringDecrypter.DecryptMethod, (method, gim, args) => {
return stringDecrypter.decrypt((int)args[0]);
});
DeobfuscatedFile.stringDecryptersAdded();

View File

@ -222,7 +222,7 @@ namespace de4dot.code.deobfuscators.CodeWall {
return;
stringDecrypter.initialize(DeobfuscatedFile);
foreach (var info in stringDecrypter.Infos)
staticStringInliner.add(info.Method, (method, args) => stringDecrypter.decrypt(method, (int)args[0], (int)args[1], (int)args[2]));
staticStringInliner.add(info.Method, (method, gim, args) => stringDecrypter.decrypt(method, (int)args[0], (int)args[1], (int)args[2]));
DeobfuscatedFile.stringDecryptersAdded();
hasInitializedStringDecrypter = true;
}

View File

@ -184,7 +184,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
decryptResources();
stringDecrypter.init(resourceDecrypter);
if (stringDecrypter.Method != null) {
staticStringInliner.add(stringDecrypter.Method, (method, args) => {
staticStringInliner.add(stringDecrypter.Method, (method, gim, args) => {
return stringDecrypter.decrypt((int)args[0]);
});
DeobfuscatedFile.stringDecryptersAdded();
@ -196,13 +196,13 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
if (options.DecryptConstants) {
constantsDecrypter.init(resourceDecrypter);
int32ValueInliner = new Int32ValueInliner();
int32ValueInliner.add(constantsDecrypter.Int32Decrypter, (method, args) => constantsDecrypter.decryptInt32((int)args[0]));
int32ValueInliner.add(constantsDecrypter.Int32Decrypter, (method, gim, args) => constantsDecrypter.decryptInt32((int)args[0]));
int64ValueInliner = new Int64ValueInliner();
int64ValueInliner.add(constantsDecrypter.Int64Decrypter, (method, args) => constantsDecrypter.decryptInt64((int)args[0]));
int64ValueInliner.add(constantsDecrypter.Int64Decrypter, (method, gim, args) => constantsDecrypter.decryptInt64((int)args[0]));
singleValueInliner = new SingleValueInliner();
singleValueInliner.add(constantsDecrypter.SingleDecrypter, (method, args) => constantsDecrypter.decryptSingle((int)args[0]));
singleValueInliner.add(constantsDecrypter.SingleDecrypter, (method, gim, args) => constantsDecrypter.decryptSingle((int)args[0]));
doubleValueInliner = new DoubleValueInliner();
doubleValueInliner.add(constantsDecrypter.DoubleDecrypter, (method, args) => constantsDecrypter.decryptDouble((int)args[0]));
doubleValueInliner.add(constantsDecrypter.DoubleDecrypter, (method, gim, args) => constantsDecrypter.decryptDouble((int)args[0]));
addTypeToBeRemoved(constantsDecrypter.Type, "Constants decrypter type");
addResourceToBeRemoved(constantsDecrypter.Resource, "Encrypted constants");
}

View File

@ -214,7 +214,7 @@ done:
}
foreach (var method in stringDecrypter.DecrypterMethods) {
staticStringInliner.add(method, (method2, args) => {
staticStringInliner.add(method, (method2, gim, args) => {
return stringDecrypter.decrypt(method2, args);
});
}

View File

@ -115,7 +115,7 @@ namespace de4dot.code.deobfuscators.Dotfuscator {
public override void deobfuscateBegin() {
base.deobfuscateBegin();
foreach (var info in stringDecrypter.StringDecrypterInfos)
staticStringInliner.add(info.method, (method, args) => stringDecrypter.decrypt(method, (string)args[0], (int)args[1]));
staticStringInliner.add(info.method, (method, gim, args) => stringDecrypter.decrypt(method, (string)args[0], (int)args[1]));
DeobfuscatedFile.stringDecryptersAdded();
}

View File

@ -115,7 +115,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
base.deobfuscateBegin();
stringDecrypter.initialize(DeobfuscatedFile);
staticStringInliner.add(stringDecrypter.Method, (method2, args) => {
staticStringInliner.add(stringDecrypter.Method, (method2, gim, args) => {
return stringDecrypter.decrypt((int)args[0]);
});
DeobfuscatedFile.stringDecryptersAdded();

View File

@ -191,7 +191,7 @@ namespace de4dot.code.deobfuscators.Goliath_NET {
if (options.DecryptIntegers) {
int32ValueInliner = new Int32ValueInliner();
foreach (var method in integerDecrypter.getMethods()) {
int32ValueInliner.add(method, (method2, args) => {
int32ValueInliner.add(method, (method2, gim, args) => {
return integerDecrypter.decrypt(method2);
});
}
@ -200,14 +200,14 @@ namespace de4dot.code.deobfuscators.Goliath_NET {
if (options.DecryptArrays) {
arrayValueInliner = new ArrayValueInliner(module, initializedDataCreator);
foreach (var method in arrayDecrypter.getMethods()) {
arrayValueInliner.add(method, (method2, args) => {
arrayValueInliner.add(method, (method2, gim, args) => {
return arrayDecrypter.decrypt(method2);
});
}
}
foreach (var method in stringDecrypter.getMethods()) {
staticStringInliner.add(method, (method2, args) => {
staticStringInliner.add(method, (method2, gim, args) => {
return stringDecrypter.decrypt(method2);
});
DeobfuscatedFile.stringDecryptersAdded();

View File

@ -130,7 +130,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
stringDecrypter.find();
if (stringDecrypter.Detected) {
stringDecrypter.initialize(getEncoding(options.StringCodePage));
staticStringInliner.add(stringDecrypter.Method, (method, args) => stringDecrypter.decrypt((uint)args[0]));
staticStringInliner.add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.decrypt((uint)args[0]));
DeobfuscatedFile.stringDecryptersAdded();
}

View File

@ -417,11 +417,11 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
Log.v("Adding string decrypter. Resource: {0}", Utils.toCsharpString(info.StringsResource.Name));
var decrypter = new StringDecrypter(info);
if (decrypter.CanDecrypt) {
staticStringInliner.add(DotNetUtils.getMethod(info.GetStringDelegate, "Invoke"), (method, args) => {
staticStringInliner.add(DotNetUtils.getMethod(info.GetStringDelegate, "Invoke"), (method, gim, args) => {
var fieldDefinition = DotNetUtils.getField(module, (FieldReference)args[0]);
return decrypter.decrypt(fieldDefinition.MetadataToken.ToInt32(), (int)args[1]);
});
staticStringInliner.add(info.StringDecrypterMethod, (method, args) => {
staticStringInliner.add(info.StringDecrypterMethod, (method, gim, args) => {
return decrypter.decrypt(0, (int)args[0]);
});
}

View File

@ -163,7 +163,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
stringDecrypter.initialize();
foreach (var info in stringDecrypter.DecrypterInfos) {
staticStringInliner.add(info.method, (method2, args) => {
staticStringInliner.add(info.method, (method2, gim, args) => {
return stringDecrypter.decrypt(method2);
});
}

View File

@ -25,13 +25,15 @@ using de4dot.blocks;
namespace de4dot.code.deobfuscators {
abstract class ValueInlinerBase<TValue> : MethodReturnValueInliner {
MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, object[], TValue>> decrypterMethods = new MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, object[], TValue>>();
MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, GenericInstanceMethod, object[], object>> decrypterMethods = new MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, GenericInstanceMethod, object[], object>>();
class MyCallResult : CallResult {
public MethodReference methodReference;
public MyCallResult(Block block, int callEndIndex, MethodReference method)
public GenericInstanceMethod gim;
public MyCallResult(Block block, int callEndIndex, MethodReference method, GenericInstanceMethod gim)
: base(block, callEndIndex) {
this.methodReference = method;
this.gim = gim;
}
}
@ -43,7 +45,7 @@ namespace de4dot.code.deobfuscators {
get { return decrypterMethods.getKeys(); }
}
public void add(MethodDefinition method, Func<MethodDefinition, object[], TValue> handler) {
public void add(MethodDefinition method, Func<MethodDefinition, GenericInstanceMethod, object[], object> handler) {
if (method == null)
return;
if (decrypterMethods.find(method) != null)
@ -56,14 +58,14 @@ namespace de4dot.code.deobfuscators {
foreach (var tmp in callResults) {
var callResult = (MyCallResult)tmp;
var handler = decrypterMethods.find(callResult.methodReference);
callResult.returnValue = handler((MethodDefinition)callResult.methodReference, callResult.args);
callResult.returnValue = (TValue)handler((MethodDefinition)callResult.methodReference, callResult.gim, callResult.args);
}
}
protected override CallResult createCallResult(MethodReference method, Block block, int callInstrIndex) {
protected override CallResult createCallResult(MethodReference method, GenericInstanceMethod gim, Block block, int callInstrIndex) {
if (decrypterMethods.find(method) == null)
return null;
return new MyCallResult(block, callInstrIndex, method);
return new MyCallResult(block, callInstrIndex, method, gim);
}
}

View File

@ -101,7 +101,7 @@ namespace de4dot.code.deobfuscators.Xenocode {
public override void deobfuscateBegin() {
base.deobfuscateBegin();
staticStringInliner.add(stringDecrypter.Method, (method, args) => stringDecrypter.decrypt((string)args[0], (int)args[1]));
staticStringInliner.add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.decrypt((string)args[0], (int)args[1]));
DeobfuscatedFile.stringDecryptersAdded();
}

View File

@ -253,10 +253,10 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v3 {
antiStrongName = new AntiStrongName();
staticStringInliner.add(decrypterType.StringDecrypter1, (method2, args) => {
staticStringInliner.add(decrypterType.StringDecrypter1, (method2, gim, args) => {
return decrypterType.decrypt1((string)args[0]);
});
staticStringInliner.add(decrypterType.StringDecrypter2, (method2, args) => {
staticStringInliner.add(decrypterType.StringDecrypter2, (method2, gim, args) => {
return decrypterType.decrypt2((string)args[0]);
});
DeobfuscatedFile.stringDecryptersAdded();

View File

@ -426,18 +426,18 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
emptyClass = new EmptyClass(module);
if (options.DecryptBools) {
booleanValueInliner.add(booleanDecrypter.Method, (method, args) => {
booleanValueInliner.add(booleanDecrypter.Method, (method, gim, args) => {
return booleanDecrypter.decrypt((int)args[0]);
});
}
foreach (var info in stringDecrypter.DecrypterInfos) {
staticStringInliner.add(info.method, (method2, args) => {
staticStringInliner.add(info.method, (method2, gim, args) => {
return stringDecrypter.decrypt(method2, (int)args[0]);
});
}
if (stringDecrypter.OtherStringDecrypter != null) {
staticStringInliner.add(stringDecrypter.OtherStringDecrypter, (method2, args) => {
staticStringInliner.add(stringDecrypter.OtherStringDecrypter, (method2, gim, args) => {
return stringDecrypter.decrypt((string)args[0]);
});
}