From 7b3dcf8e05eea34727d9a8dc8335d6d576977737 Mon Sep 17 00:00:00 2001 From: de4dot Date: Tue, 29 May 2012 11:13:39 +0200 Subject: [PATCH] Refactor proxy call fixer classes --- de4dot.code/de4dot.code.csproj | 14 +- .../deobfuscators/Babel_NET/Deobfuscator.cs | 14 +- ...oxyDelegateFinder.cs => ProxyCallFixer.cs} | 10 +- .../deobfuscators/CliSecure/Deobfuscator.cs | 16 +- ...oxyDelegateFinder.cs => ProxyCallFixer.cs} | 6 +- .../deobfuscators/CodeVeil/Deobfuscator.cs | 28 +- ...oxyDelegateFinder.cs => ProxyCallFixer.cs} | 9 +- .../CryptoObfuscator/Deobfuscator.cs | 14 +- ...oxyDelegateFinder.cs => ProxyCallFixer.cs} | 10 +- de4dot.code/deobfuscators/DeobfuscatorBase.cs | 10 +- .../deobfuscators/Goliath_NET/Deobfuscator.cs | 10 +- ...oxyDelegateFinder.cs => ProxyCallFixer.cs} | 11 +- ...ateFinderBase.cs => ProxyCallFixerBase.cs} | 337 +++++++++++------- .../SmartAssembly/Deobfuscator.cs | 14 +- ...oxyDelegateFinder.cs => ProxyCallFixer.cs} | 6 +- 15 files changed, 303 insertions(+), 206 deletions(-) rename de4dot.code/deobfuscators/Babel_NET/{ProxyDelegateFinder.cs => ProxyCallFixer.cs} (94%) rename de4dot.code/deobfuscators/CliSecure/{ProxyDelegateFinder.cs => ProxyCallFixer.cs} (93%) rename de4dot.code/deobfuscators/CodeVeil/{ProxyDelegateFinder.cs => ProxyCallFixer.cs} (96%) rename de4dot.code/deobfuscators/CryptoObfuscator/{ProxyDelegateFinder.cs => ProxyCallFixer.cs} (94%) rename de4dot.code/deobfuscators/Goliath_NET/{ProxyDelegateFinder.cs => ProxyCallFixer.cs} (93%) rename de4dot.code/deobfuscators/{ProxyDelegateFinderBase.cs => ProxyCallFixerBase.cs} (63%) rename de4dot.code/deobfuscators/SmartAssembly/{ProxyDelegateFinder.cs => ProxyCallFixer.cs} (95%) diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 892af111..42ecf34c 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -69,7 +69,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -105,7 +105,7 @@ - + @@ -118,7 +118,7 @@ - + @@ -181,7 +181,7 @@ - + @@ -212,13 +212,13 @@ - + - + diff --git a/de4dot.code/deobfuscators/Babel_NET/Deobfuscator.cs b/de4dot.code/deobfuscators/Babel_NET/Deobfuscator.cs index 1a809fab..1e88501c 100644 --- a/de4dot.code/deobfuscators/Babel_NET/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/Babel_NET/Deobfuscator.cs @@ -80,7 +80,7 @@ namespace de4dot.code.deobfuscators.Babel_NET { Int64ValueInliner int64ValueInliner; SingleValueInliner singleValueInliner; DoubleValueInliner doubleValueInliner; - ProxyDelegateFinder proxyDelegateFinder; + ProxyCallFixer proxyCallFixer; MethodsDecrypter methodsDecrypter; internal class Options : OptionsBase { @@ -118,7 +118,7 @@ namespace de4dot.code.deobfuscators.Babel_NET { toInt32(assemblyResolver.Detected) + toInt32(stringDecrypter.Detected) + toInt32(constantsDecrypter.Detected) + - toInt32(proxyDelegateFinder.Detected) + + toInt32(proxyCallFixer.Detected) + toInt32(methodsDecrypter.Detected) + toInt32(hasMetadataStream("Babel")); if (sum > 0) @@ -139,8 +139,8 @@ namespace de4dot.code.deobfuscators.Babel_NET { stringDecrypter.find(); constantsDecrypter = new ConstantsDecrypter(module, initializedDataCreator); constantsDecrypter.find(); - proxyDelegateFinder = new ProxyDelegateFinder(module); - proxyDelegateFinder.findDelegateCreator(); + proxyCallFixer = new ProxyCallFixer(module); + proxyCallFixer.findDelegateCreator(); methodsDecrypter = new MethodsDecrypter(module, DeobfuscatedFile.DeobfuscatorContext); methodsDecrypter.find(); } @@ -215,7 +215,7 @@ namespace de4dot.code.deobfuscators.Babel_NET { doubleValueInliner.add(constantsDecrypter.DoubleDecrypter, (method, args) => constantsDecrypter.decryptDouble((int)args[0])); } - proxyDelegateFinder.find(); + proxyCallFixer.find(); } void dumpEmbeddedAssemblies() { @@ -238,7 +238,7 @@ namespace de4dot.code.deobfuscators.Babel_NET { } public override void deobfuscateMethodEnd(Blocks blocks) { - proxyDelegateFinder.deobfuscate(blocks); + proxyCallFixer.deobfuscate(blocks); if (options.DecryptConstants) { int32ValueInliner.decrypt(blocks); int64ValueInliner.decrypt(blocks); @@ -255,7 +255,7 @@ namespace de4dot.code.deobfuscators.Babel_NET { addTypeToBeRemoved(stringDecrypter.Type, "String decrypter type"); } - removeProxyDelegates(proxyDelegateFinder); + removeProxyDelegates(proxyCallFixer); base.deobfuscateEnd(); } diff --git a/de4dot.code/deobfuscators/Babel_NET/ProxyDelegateFinder.cs b/de4dot.code/deobfuscators/Babel_NET/ProxyCallFixer.cs similarity index 94% rename from de4dot.code/deobfuscators/Babel_NET/ProxyDelegateFinder.cs rename to de4dot.code/deobfuscators/Babel_NET/ProxyCallFixer.cs index 4257cf02..be93a2ea 100644 --- a/de4dot.code/deobfuscators/Babel_NET/ProxyDelegateFinder.cs +++ b/de4dot.code/deobfuscators/Babel_NET/ProxyCallFixer.cs @@ -24,10 +24,10 @@ using Mono.Cecil.Cil; using de4dot.blocks; namespace de4dot.code.deobfuscators.Babel_NET { - class ProxyDelegateFinder : ProxyDelegateFinderBase { + class ProxyCallFixer : ProxyCallFixer2 { MethodDefinitionAndDeclaringTypeDict methodToType = new MethodDefinitionAndDeclaringTypeDict(); - public ProxyDelegateFinder(ModuleDefinition module) + public ProxyCallFixer(ModuleDefinition module) : base(module) { } @@ -95,7 +95,8 @@ namespace de4dot.code.deobfuscators.Babel_NET { return null; } - protected override void onFoundProxyDelegate(TypeDefinition type) { + protected override Dictionary getFieldToMethodDictionary(TypeDefinition type) { + var dict = new Dictionary(); foreach (var method in type.Methods) { if (!method.IsStatic || !method.HasBody || method.Name == ".cctor") continue; @@ -106,10 +107,11 @@ namespace de4dot.code.deobfuscators.Babel_NET { if (instr.OpCode.Code != Code.Ldsfld) continue; - add(method, (FieldDefinition)instr.Operand); + dict[(FieldDefinition)instr.Operand] = method; break; } } + return dict; } protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) { diff --git a/de4dot.code/deobfuscators/CliSecure/Deobfuscator.cs b/de4dot.code/deobfuscators/CliSecure/Deobfuscator.cs index 6c42f0d7..05c96375 100644 --- a/de4dot.code/deobfuscators/CliSecure/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/CliSecure/Deobfuscator.cs @@ -79,7 +79,7 @@ namespace de4dot.code.deobfuscators.CliSecure { string obfuscatorName = DeobfuscatorInfo.THE_NAME; List cliSecureAttributes = new List(); - ProxyDelegateFinder proxyDelegateFinder; + ProxyCallFixer proxyCallFixer; CliSecureRtType cliSecureRtType; StringDecrypter stringDecrypter; ResourceDecrypter resourceDecrypter; @@ -167,7 +167,7 @@ namespace de4dot.code.deobfuscators.CliSecure { int sum = toInt32(cliSecureRtType.Detected) + toInt32(stringDecrypter.Detected) + - toInt32(proxyDelegateFinder.Detected) + + toInt32(proxyCallFixer.Detected) + toInt32(resourceDecrypter.Detected) + toInt32(csvm.Detected); if (sum > 0) @@ -186,8 +186,8 @@ namespace de4dot.code.deobfuscators.CliSecure { stringDecrypter.find(); resourceDecrypter = new ResourceDecrypter(module); resourceDecrypter.find(); - proxyDelegateFinder = new ProxyDelegateFinder(module); - proxyDelegateFinder.findDelegateCreator(); + proxyCallFixer = new ProxyCallFixer(module); + proxyCallFixer.findDelegateCreator(); csvm = new vm.Csvm(DeobfuscatedFile.DeobfuscatorContext, module); csvm.find(); } @@ -228,7 +228,7 @@ namespace de4dot.code.deobfuscators.CliSecure { newOne.cliSecureRtType = new CliSecureRtType(module, cliSecureRtType); newOne.stringDecrypter = new StringDecrypter(module, stringDecrypter); newOne.resourceDecrypter = new ResourceDecrypter(module, resourceDecrypter); - newOne.proxyDelegateFinder = new ProxyDelegateFinder(module, proxyDelegateFinder); + newOne.proxyCallFixer = new ProxyCallFixer(module, proxyCallFixer); newOne.csvm = new vm.Csvm(DeobfuscatedFile.DeobfuscatorContext, module, csvm); return newOne; } @@ -261,7 +261,7 @@ namespace de4dot.code.deobfuscators.CliSecure { this.addTypeToBeRemoved(type, "Obfuscator type"); } - proxyDelegateFinder.find(); + proxyCallFixer.find(); staticStringInliner.add(stringDecrypter.Method, (method, args) => stringDecrypter.decrypt((string)args[0])); DeobfuscatedFile.stringDecryptersAdded(); @@ -288,7 +288,7 @@ namespace de4dot.code.deobfuscators.CliSecure { } public override void deobfuscateMethodEnd(Blocks blocks) { - proxyDelegateFinder.deobfuscate(blocks); + proxyCallFixer.deobfuscate(blocks); removeStackFrameHelperCode(blocks); base.deobfuscateMethodEnd(blocks); } @@ -296,7 +296,7 @@ namespace de4dot.code.deobfuscators.CliSecure { public override void deobfuscateEnd() { if (options.SetInitLocals) setInitLocals(); - removeProxyDelegates(proxyDelegateFinder); + removeProxyDelegates(proxyCallFixer); if (options.RemoveStackFrameHelper) { if (stackFrameHelper.ExceptionLoggerRemover.NumRemovedExceptionLoggers > 0) addTypeToBeRemoved(stackFrameHelper.Type, "StackFrameHelper type"); diff --git a/de4dot.code/deobfuscators/CliSecure/ProxyDelegateFinder.cs b/de4dot.code/deobfuscators/CliSecure/ProxyCallFixer.cs similarity index 93% rename from de4dot.code/deobfuscators/CliSecure/ProxyDelegateFinder.cs rename to de4dot.code/deobfuscators/CliSecure/ProxyCallFixer.cs index f239f4eb..2f0cb42c 100644 --- a/de4dot.code/deobfuscators/CliSecure/ProxyDelegateFinder.cs +++ b/de4dot.code/deobfuscators/CliSecure/ProxyCallFixer.cs @@ -24,14 +24,14 @@ using Mono.Cecil.Cil; using de4dot.blocks; namespace de4dot.code.deobfuscators.CliSecure { - class ProxyDelegateFinder : ProxyDelegateFinderBase { + class ProxyCallFixer : ProxyCallFixer1 { IList memberReferences; - public ProxyDelegateFinder(ModuleDefinition module) + public ProxyCallFixer(ModuleDefinition module) : base(module) { } - public ProxyDelegateFinder(ModuleDefinition module, ProxyDelegateFinder oldOne) + public ProxyCallFixer(ModuleDefinition module, ProxyCallFixer oldOne) : base(module) { foreach (var method in oldOne.delegateCreatorMethods) setDelegateCreatorMethod(lookup(method, "Could not find delegate creator method")); diff --git a/de4dot.code/deobfuscators/CodeVeil/Deobfuscator.cs b/de4dot.code/deobfuscators/CodeVeil/Deobfuscator.cs index fed5197f..56f26a1d 100644 --- a/de4dot.code/deobfuscators/CodeVeil/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/CodeVeil/Deobfuscator.cs @@ -59,7 +59,7 @@ namespace de4dot.code.deobfuscators.CodeVeil { MainType mainType; MethodsDecrypter methodsDecrypter; - ProxyDelegateFinder proxyDelegateFinder; + ProxyCallFixer proxyCallFixer; StringDecrypter stringDecrypter; AssemblyResolver assemblyResolver; TypeDefinition killType; @@ -92,7 +92,7 @@ namespace de4dot.code.deobfuscators.CodeVeil { int sum = toInt32(mainType.Detected) + toInt32(methodsDecrypter.Detected) + toInt32(stringDecrypter.Detected) + - toInt32(proxyDelegateFinder.Detected); + toInt32(proxyCallFixer.Detected); if (sum > 0) val += 100 + 10 * (sum - 1); @@ -103,8 +103,8 @@ namespace de4dot.code.deobfuscators.CodeVeil { findKillType(); mainType = new MainType(module); mainType.find(); - proxyDelegateFinder = new ProxyDelegateFinder(module, mainType); - proxyDelegateFinder.findDelegateCreator(); + proxyCallFixer = new ProxyCallFixer(module, mainType); + proxyCallFixer.findDelegateCreator(); methodsDecrypter = new MethodsDecrypter(mainType); methodsDecrypter.find(); stringDecrypter = new StringDecrypter(module, mainType); @@ -167,7 +167,7 @@ namespace de4dot.code.deobfuscators.CodeVeil { newOne.mainType = new MainType(module, mainType); newOne.methodsDecrypter = new MethodsDecrypter(mainType, methodsDecrypter); newOne.stringDecrypter = new StringDecrypter(module, newOne.mainType, stringDecrypter); - newOne.proxyDelegateFinder = new ProxyDelegateFinder(module, newOne.mainType, proxyDelegateFinder); + newOne.proxyCallFixer = new ProxyCallFixer(module, newOne.mainType, proxyCallFixer); newOne.killType = DeobUtils.lookup(module, killType, "Could not find KILL type"); return newOne; } @@ -199,8 +199,8 @@ namespace de4dot.code.deobfuscators.CodeVeil { removeTamperDetection(); - proxyDelegateFinder.initialize(); - proxyDelegateFinder.find(); + proxyCallFixer.initialize(); + proxyCallFixer.find(); resourceDecrypter = new ResourceDecrypter(module); resourceDecrypter.initialize(); @@ -232,7 +232,7 @@ namespace de4dot.code.deobfuscators.CodeVeil { } public override void deobfuscateMethodBegin(Blocks blocks) { - proxyDelegateFinder.deobfuscate(blocks); + proxyCallFixer.deobfuscate(blocks); base.deobfuscateMethodBegin(blocks); } @@ -243,7 +243,7 @@ namespace de4dot.code.deobfuscators.CodeVeil { } public override void deobfuscateEnd() { - bool canRemoveProxyTypes = proxyDelegateFinder.CanRemoveTypes; + bool canRemoveProxyTypes = proxyCallFixer.CanRemoveTypes; if (CanRemoveStringDecrypterType) addTypeToBeRemoved(stringDecrypter.Type, "String decrypter type"); @@ -251,7 +251,7 @@ namespace de4dot.code.deobfuscators.CodeVeil { if (!mainType.Detected) { } else if (mainType.Version >= ObfuscatorVersion.V5_0) { - if (!proxyDelegateFinder.FoundProxyType || canRemoveProxyTypes) + if (!proxyCallFixer.FoundProxyType || canRemoveProxyTypes) addTypeToBeRemoved(mainType.Type, "Main CV type"); } else { @@ -264,11 +264,11 @@ namespace de4dot.code.deobfuscators.CodeVeil { } } - removeProxyDelegates(proxyDelegateFinder, canRemoveProxyTypes); + removeProxyDelegates(proxyCallFixer, canRemoveProxyTypes); if (canRemoveProxyTypes) { - addTypeToBeRemoved(proxyDelegateFinder.IlGeneratorType, "Obfuscator proxy method ILGenerator type"); - addTypeToBeRemoved(proxyDelegateFinder.FieldInfoType, "Obfuscator proxy method FieldInfo type"); - addTypeToBeRemoved(proxyDelegateFinder.MethodInfoType, "Obfuscator proxy method MethodInfo type"); + addTypeToBeRemoved(proxyCallFixer.IlGeneratorType, "Obfuscator proxy method ILGenerator type"); + addTypeToBeRemoved(proxyCallFixer.FieldInfoType, "Obfuscator proxy method FieldInfo type"); + addTypeToBeRemoved(proxyCallFixer.MethodInfoType, "Obfuscator proxy method MethodInfo type"); } addMethodsToBeRemoved(InvalidMethodsFinder.findAll(module), "Anti-reflection method"); diff --git a/de4dot.code/deobfuscators/CodeVeil/ProxyDelegateFinder.cs b/de4dot.code/deobfuscators/CodeVeil/ProxyCallFixer.cs similarity index 96% rename from de4dot.code/deobfuscators/CodeVeil/ProxyDelegateFinder.cs rename to de4dot.code/deobfuscators/CodeVeil/ProxyCallFixer.cs index 2768b42d..76fe61fb 100644 --- a/de4dot.code/deobfuscators/CodeVeil/ProxyDelegateFinder.cs +++ b/de4dot.code/deobfuscators/CodeVeil/ProxyCallFixer.cs @@ -26,7 +26,7 @@ using Mono.Cecil.Metadata; using de4dot.blocks; namespace de4dot.code.deobfuscators.CodeVeil { - class ProxyDelegateFinder : ProxyDelegateFinderBase { + class ProxyCallFixer : ProxyCallFixer1 { MainType mainType; Info info = new Info(); BinaryReader reader; @@ -73,12 +73,12 @@ namespace de4dot.code.deobfuscators.CodeVeil { get { return info.methodInfoType; } } - public ProxyDelegateFinder(ModuleDefinition module, MainType mainType) + public ProxyCallFixer(ModuleDefinition module, MainType mainType) : base(module) { this.mainType = mainType; } - public ProxyDelegateFinder(ModuleDefinition module, MainType mainType, ProxyDelegateFinder oldOne) + public ProxyCallFixer(ModuleDefinition module, MainType mainType, ProxyCallFixer oldOne) : base(module, oldOne) { this.mainType = mainType; info.proxyType = lookup(oldOne.info.proxyType, "Could not find proxyType"); @@ -112,9 +112,6 @@ namespace de4dot.code.deobfuscators.CodeVeil { return null; } - protected override void onFoundProxyDelegate(TypeDefinition type) { - } - protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) { byte flags = reader.ReadByte(); diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs b/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs index 63c2cc4b..cc0ab3f3 100644 --- a/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs @@ -64,7 +64,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { bool foundObfuscatedSymbols = false; bool foundObfuscatorUserString = false; - ProxyDelegateFinder proxyDelegateFinder; + ProxyCallFixer proxyCallFixer; ResourceDecrypter resourceDecrypter; ResourceResolver resourceResolver; AssemblyResolver assemblyResolver; @@ -103,7 +103,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { int sum = toInt32(stringDecrypter.Detected) + toInt32(tamperDetection.Detected) + - toInt32(proxyDelegateFinder.Detected); + toInt32(proxyCallFixer.Detected); if (sum > 0) val += 100 + 10 * (sum - 1); if (foundCryptoObfuscatorAttribute || foundObfuscatedSymbols || foundObfuscatorUserString) @@ -123,8 +123,8 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { if (checkCryptoObfuscator()) foundObfuscatedSymbols = true; - proxyDelegateFinder = new ProxyDelegateFinder(module); - proxyDelegateFinder.findDelegateCreator(); + proxyCallFixer = new ProxyCallFixer(module); + proxyCallFixer.findDelegateCreator(); stringDecrypter = new StringDecrypter(module); stringDecrypter.find(); tamperDetection = new TamperDetection(module); @@ -191,18 +191,18 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { addTypeToBeRemoved(tamperDetection.Type, "Tamper detection type"); addTypeToBeRemoved(antiDebugger.Type, "Anti-debugger type"); - proxyDelegateFinder.find(); + proxyCallFixer.find(); dumpEmbeddedAssemblies(); } public override void deobfuscateMethodEnd(Blocks blocks) { - proxyDelegateFinder.deobfuscate(blocks); + proxyCallFixer.deobfuscate(blocks); base.deobfuscateMethodEnd(blocks); } public override void deobfuscateEnd() { - removeProxyDelegates(proxyDelegateFinder); + removeProxyDelegates(proxyCallFixer); if (CanRemoveStringDecrypterType) { addResourceToBeRemoved(stringDecrypter.Resource, "Encrypted strings"); addTypeToBeRemoved(stringDecrypter.Type, "String decrypter type"); diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/ProxyDelegateFinder.cs b/de4dot.code/deobfuscators/CryptoObfuscator/ProxyCallFixer.cs similarity index 94% rename from de4dot.code/deobfuscators/CryptoObfuscator/ProxyDelegateFinder.cs rename to de4dot.code/deobfuscators/CryptoObfuscator/ProxyCallFixer.cs index 72e427c3..7035939b 100644 --- a/de4dot.code/deobfuscators/CryptoObfuscator/ProxyDelegateFinder.cs +++ b/de4dot.code/deobfuscators/CryptoObfuscator/ProxyCallFixer.cs @@ -24,10 +24,10 @@ using Mono.Cecil.Cil; using de4dot.blocks; namespace de4dot.code.deobfuscators.CryptoObfuscator { - class ProxyDelegateFinder : ProxyDelegateFinderBase { + class ProxyCallFixer : ProxyCallFixer2 { Dictionary methodToType = new Dictionary(); - public ProxyDelegateFinder(ModuleDefinition module) + public ProxyCallFixer(ModuleDefinition module) : base(module) { } @@ -73,7 +73,8 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { return null; } - protected override void onFoundProxyDelegate(TypeDefinition type) { + protected override Dictionary getFieldToMethodDictionary(TypeDefinition type) { + var dict = new Dictionary(); foreach (var method in type.Methods) { if (!method.IsStatic || !method.HasBody || method.Name == ".cctor") continue; @@ -84,10 +85,11 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { if (instr.OpCode.Code != Code.Ldsfld) continue; - add(method, (FieldDefinition)instr.Operand); + dict[(FieldDefinition)instr.Operand] = method; break; } } + return dict; } protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) { diff --git a/de4dot.code/deobfuscators/DeobfuscatorBase.cs b/de4dot.code/deobfuscators/DeobfuscatorBase.cs index 3c209ded..8358a16b 100644 --- a/de4dot.code/deobfuscators/DeobfuscatorBase.cs +++ b/de4dot.code/deobfuscators/DeobfuscatorBase.cs @@ -663,14 +663,14 @@ namespace de4dot.code.deobfuscators { } } - protected void removeProxyDelegates(ProxyDelegateFinderBase proxyDelegateFinder, bool removeCreators = true) { - if (proxyDelegateFinder.Errors != 0) { + protected void removeProxyDelegates(ProxyCallFixerBase proxyCallFixer, bool removeCreators = true) { + if (proxyCallFixer.Errors != 0) { Log.v("Not removing proxy delegates and creator type since errors were detected."); return; } - addTypesToBeRemoved(proxyDelegateFinder.DelegateTypes, "Proxy delegate type"); - if (removeCreators && proxyDelegateFinder.RemovedDelegateCreatorCalls > 0) - addTypesToBeRemoved(proxyDelegateFinder.DelegateCreatorTypes, "Proxy delegate creator type"); + addTypesToBeRemoved(proxyCallFixer.DelegateTypes, "Proxy delegate type"); + if (removeCreators && proxyCallFixer.RemovedDelegateCreatorCalls > 0) + addTypesToBeRemoved(proxyCallFixer.DelegateCreatorTypes, "Proxy delegate creator type"); } protected Resource getResource(IEnumerable strings) { diff --git a/de4dot.code/deobfuscators/Goliath_NET/Deobfuscator.cs b/de4dot.code/deobfuscators/Goliath_NET/Deobfuscator.cs index cf97615a..ec9ff2f0 100644 --- a/de4dot.code/deobfuscators/Goliath_NET/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/Goliath_NET/Deobfuscator.cs @@ -80,7 +80,7 @@ namespace de4dot.code.deobfuscators.Goliath_NET { Options options; string obfuscatorName = DeobfuscatorInfo.THE_NAME; - ProxyDelegateFinder proxyDelegateFinder; + ProxyCallFixer proxyCallFixer; LocalsRestorer localsRestorer; LogicalExpressionFixer logicalExpressionFixer; StringDecrypter stringDecrypter; @@ -177,8 +177,8 @@ namespace de4dot.code.deobfuscators.Goliath_NET { public override void deobfuscateBegin() { base.deobfuscateBegin(); - proxyDelegateFinder = new ProxyDelegateFinder(module); - proxyDelegateFinder.find(); + proxyCallFixer = new ProxyCallFixer(module); + proxyCallFixer.find(); localsRestorer = new LocalsRestorer(module); if (options.RestoreLocals) localsRestorer.find(); @@ -220,7 +220,7 @@ namespace de4dot.code.deobfuscators.Goliath_NET { } public override void deobfuscateMethodBegin(Blocks blocks) { - proxyDelegateFinder.deobfuscate(blocks); + proxyCallFixer.deobfuscate(blocks); base.deobfuscateMethodBegin(blocks); } @@ -239,7 +239,7 @@ namespace de4dot.code.deobfuscators.Goliath_NET { } public override void deobfuscateEnd() { - removeProxyDelegates(proxyDelegateFinder); + removeProxyDelegates(proxyCallFixer); removeInlinedMethods(); addTypesToBeRemoved(localsRestorer.Types, "Method locals obfuscation type"); diff --git a/de4dot.code/deobfuscators/Goliath_NET/ProxyDelegateFinder.cs b/de4dot.code/deobfuscators/Goliath_NET/ProxyCallFixer.cs similarity index 93% rename from de4dot.code/deobfuscators/Goliath_NET/ProxyDelegateFinder.cs rename to de4dot.code/deobfuscators/Goliath_NET/ProxyCallFixer.cs index bdf6ae4a..8c289333 100644 --- a/de4dot.code/deobfuscators/Goliath_NET/ProxyDelegateFinder.cs +++ b/de4dot.code/deobfuscators/Goliath_NET/ProxyCallFixer.cs @@ -24,8 +24,8 @@ using Mono.Cecil.Cil; using de4dot.blocks; namespace de4dot.code.deobfuscators.Goliath_NET { - class ProxyDelegateFinder : ProxyDelegateFinderBase { - public ProxyDelegateFinder(ModuleDefinition module) + class ProxyCallFixer : ProxyCallFixer2 { + public ProxyCallFixer(ModuleDefinition module) : base(module) { } @@ -61,8 +61,7 @@ namespace de4dot.code.deobfuscators.Goliath_NET { Log.indent(); foreach (var info in infos) { var di = info.delegateInfo; - add(info.method, di.field); - addDelegateInfo(di); + add(info.method, di); Log.v("Field: {0}, Opcode: {1}, Method: {2} ({3:X8})", Utils.removeNewlines(di.field.Name), di.callOpcode, @@ -137,8 +136,8 @@ namespace de4dot.code.deobfuscators.Goliath_NET { throw new System.NotImplementedException(); } - protected override void onFoundProxyDelegate(TypeDefinition type) { - throw new System.NotImplementedException(); + protected override Dictionary getFieldToMethodDictionary(TypeDefinition type) { + throw new NotImplementedException(); } protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) { diff --git a/de4dot.code/deobfuscators/ProxyDelegateFinderBase.cs b/de4dot.code/deobfuscators/ProxyCallFixerBase.cs similarity index 63% rename from de4dot.code/deobfuscators/ProxyDelegateFinderBase.cs rename to de4dot.code/deobfuscators/ProxyCallFixerBase.cs index 5ae6da04..861c724a 100644 --- a/de4dot.code/deobfuscators/ProxyDelegateFinderBase.cs +++ b/de4dot.code/deobfuscators/ProxyCallFixerBase.cs @@ -24,13 +24,11 @@ using Mono.Cecil.Cil; using de4dot.blocks; namespace de4dot.code.deobfuscators { - abstract class ProxyDelegateFinderBase { + abstract class ProxyCallFixerBase { protected ModuleDefinition module; protected List delegateCreatorMethods = new List(); protected Dictionary delegateTypesDict = new Dictionary(); - FieldDefinitionAndDeclaringTypeDict fieldToDelegateInfo = new FieldDefinitionAndDeclaringTypeDict(); - Dictionary proxyMethodToField = new Dictionary(); - int errors = 0; + protected int errors = 0; public int Errors { get { return errors; } @@ -64,26 +62,19 @@ namespace de4dot.code.deobfuscators { get { return delegateCreatorMethods.Count != 0; } } - public ProxyDelegateFinderBase(ModuleDefinition module) { + protected ProxyCallFixerBase(ModuleDefinition module) { this.module = module; } - public ProxyDelegateFinderBase(ModuleDefinition module, ProxyDelegateFinderBase oldOne) { + protected ProxyCallFixerBase(ModuleDefinition module, ProxyCallFixerBase oldOne) { this.module = module; foreach (var method in oldOne.delegateCreatorMethods) delegateCreatorMethods.Add(lookup(method, "Could not find delegate creator method")); foreach (var kv in oldOne.delegateTypesDict) delegateTypesDict[lookup(kv.Key, "Could not find delegate type")] = kv.Value; - foreach (var key in oldOne.fieldToDelegateInfo.getKeys()) - fieldToDelegateInfo.add(lookup(key, "Could not find field"), copy(oldOne.fieldToDelegateInfo.find(key))); - foreach (var kv in oldOne.proxyMethodToField) { - var key = lookup(kv.Key, "Could not find proxy method"); - var value = lookup(kv.Value, "Could not find proxy field"); - proxyMethodToField[key] = value; - } } - DelegateInfo copy(DelegateInfo di) { + 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); @@ -93,7 +84,7 @@ namespace de4dot.code.deobfuscators { return DeobUtils.lookup(module, def, errorMessage); } - public void setDelegateCreatorMethod(MethodDefinition delegateCreatorMethod) { + protected void setDelegateCreatorMethod(MethodDefinition delegateCreatorMethod) { if (delegateCreatorMethod == null) return; delegateCreatorMethods.Add(delegateCreatorMethod); @@ -116,6 +107,97 @@ namespace de4dot.code.deobfuscators { } } + 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; } + } + + public void deobfuscate(Blocks blocks) { + if (blocks.Method.DeclaringType != null && delegateTypesDict.ContainsKey(blocks.Method.DeclaringType)) + return; + var allBlocks = blocks.MethodBlocks.getAllBlocks(); + int loops = ProxyCallIsObfuscated ? 50 : 1; + for (int i = 0; i < loops; i++) { + if (!deobfuscate(blocks, allBlocks)) + break; + } + deobfuscateEnd(blocks, allBlocks); + } + + protected abstract bool deobfuscate(Blocks blocks, IList allBlocks); + + protected virtual void deobfuscateEnd(Blocks blocks, IList allBlocks) { + } + + protected static void add(Dictionary> removeInfos, Block block, int index, DelegateInfo di) { + List list; + if (!removeInfos.TryGetValue(block, out list)) + removeInfos[block] = list = new List(); + list.Add(new RemoveInfo { + Index = index, + DelegateInfo = di, + }); + } + + protected static bool fixProxyCalls(Dictionary> removeInfos) { + foreach (var block in removeInfos.Keys) { + var list = removeInfos[block]; + var removeIndexes = new List(list.Count); + foreach (var info in list) { + if (info.IsCall) { + var opcode = info.DelegateInfo.callOpcode; + var newInstr = Instruction.Create(opcode, info.DelegateInfo.methodRef); + block.replace(info.Index, 1, newInstr); + } + else + removeIndexes.Add(info.Index); + } + block.remove(removeIndexes); + } + + return removeInfos.Count > 0; + } + } + + // Fixes proxy calls that call the delegate inline in the code, eg.: + // ldsfld delegate_instance + // ...push args... + // call Invoke + abstract class ProxyCallFixer1 : ProxyCallFixerBase { + FieldDefinitionAndDeclaringTypeDict fieldToDelegateInfo = new FieldDefinitionAndDeclaringTypeDict(); + + protected ProxyCallFixer1(ModuleDefinition module) + : base(module) { + } + + protected ProxyCallFixer1(ModuleDefinition module, ProxyCallFixer1 oldOne) + : base(module, oldOne) { + foreach (var key in oldOne.fieldToDelegateInfo.getKeys()) + fieldToDelegateInfo.add(lookup(key, "Could not find field"), copy(oldOne.fieldToDelegateInfo.find(key))); + } + + protected void addDelegateInfo(DelegateInfo di) { + fieldToDelegateInfo.add(di.field, di); + } + + DelegateInfo getDelegateInfo(FieldReference field) { + if (field == null) + return null; + return fieldToDelegateInfo.find(field); + } + public void find() { if (delegateCreatorMethods.Count == 0) return; @@ -134,7 +216,6 @@ namespace de4dot.code.deobfuscators { Log.v("Found proxy delegate: {0} ({1:X8})", Utils.removeNewlines(type), type.MetadataToken.ToUInt32()); RemovedDelegateCreatorCalls++; - onFoundProxyDelegate(type); Log.indent(); foreach (var field in type.Fields) { @@ -159,125 +240,41 @@ namespace de4dot.code.deobfuscators { } } - protected void addDelegateInfo(DelegateInfo di) { - fieldToDelegateInfo.add(di.field, di); - } - - 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; - } - - DelegateInfo getDelegateInfo(FieldReference field) { - if (field == null) - return null; - return fieldToDelegateInfo.find(field); - } - - class BlockInstr { - public Block Block { get; set; } - public int Index { get; set; } - } - - 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; } - } - - public void deobfuscate(Blocks blocks) { - if (blocks.Method.DeclaringType != null && delegateTypesDict.ContainsKey(blocks.Method.DeclaringType)) - return; - var allBlocks = blocks.MethodBlocks.getAllBlocks(); - int loops = ProxyCallIsObfuscated ? 50 : 1; - for (int i = 0; i < loops; i++) { - if (!deobfuscate(blocks, allBlocks)) - break; - } - fixBrokenCalls(blocks.Method, allBlocks); - } - - bool deobfuscate(Blocks blocks, IList allBlocks) { + protected override bool deobfuscate(Blocks blocks, IList allBlocks) { var removeInfos = new Dictionary>(); 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.Ldsfld) { - var di = getDelegateInfo(instr.Operand as FieldReference); - if (di == null) - continue; + if (instr.OpCode != OpCodes.Ldsfld) + continue; - var visited = new Dictionary(); - var callInfo = findProxyCall(di, block, i, visited, 1); - if (callInfo != null) { - add(removeInfos, block, i, null); - add(removeInfos, callInfo.Block, callInfo.Index, di); - } - else { - errors++; - Log.w("Could not fix proxy call. Method: {0} ({1:X8}), Proxy type: {2} ({3:X8})", - Utils.removeNewlines(blocks.Method), - blocks.Method.MetadataToken.ToInt32(), - Utils.removeNewlines(di.field.DeclaringType), - di.field.DeclaringType.MetadataToken.ToInt32()); - } + var di = getDelegateInfo(instr.Operand as FieldReference); + if (di == null) + continue; + + var visited = new Dictionary(); + var callInfo = findProxyCall(di, block, i, visited, 1); + if (callInfo != null) { + add(removeInfos, block, i, null); + add(removeInfos, callInfo.Block, callInfo.Index, di); } - 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); + else { + errors++; + Log.w("Could not fix proxy call. Method: {0} ({1:X8}), Proxy type: {2} ({3:X8})", + Utils.removeNewlines(blocks.Method), + blocks.Method.MetadataToken.ToInt32(), + Utils.removeNewlines(di.field.DeclaringType), + di.field.DeclaringType.MetadataToken.ToInt32()); } } } - foreach (var block in removeInfos.Keys) { - var list = removeInfos[block]; - var removeIndexes = new List(list.Count); - foreach (var info in list) { - if (info.IsCall) { - var opcode = info.DelegateInfo.callOpcode; - var newInstr = Instruction.Create(opcode, info.DelegateInfo.methodRef); - block.replace(info.Index, 1, newInstr); - } - else - removeIndexes.Add(info.Index); - } - block.remove(removeIndexes); - } - - return removeInfos.Count > 0; - } - - void add(Dictionary> removeInfos, Block block, int index, DelegateInfo di) { - List list; - if (!removeInfos.TryGetValue(block, out list)) - removeInfos[block] = list = new List(); - list.Add(new RemoveInfo { - Index = index, - DelegateInfo = di, - }); + return fixProxyCalls(removeInfos); } BlockInstr findProxyCall(DelegateInfo di, Block block, int index, Dictionary visited, int stack) { @@ -325,6 +322,10 @@ namespace de4dot.code.deobfuscators { return null; } + protected override void deobfuscateEnd(Blocks blocks, IList allBlocks) { + fixBrokenCalls(blocks.Method, allBlocks); + } + // The obfuscator could be buggy and call a proxy delegate without pushing the // instance field. SA has done it, so let's fix it. void fixBrokenCalls(MethodDefinition obfuscatedMethod, IList allBlocks) { @@ -356,4 +357,100 @@ namespace de4dot.code.deobfuscators { } } } + + // Fixes proxy calls that call a static method which then calls + // Invoke() on a delegate instance, eg.: + // ...push args... + // call static method + abstract class ProxyCallFixer2 : ProxyCallFixerBase { + MethodDefinitionAndDeclaringTypeDict proxyMethodToDelegateInfo = new MethodDefinitionAndDeclaringTypeDict(); + + protected ProxyCallFixer2(ModuleDefinition module) + : base(module) { + } + + protected ProxyCallFixer2(ModuleDefinition module, ProxyCallFixer2 oldOne) + : base(module, oldOne) { + 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)); + } + } + + public void find() { + if (delegateCreatorMethods.Count == 0) + return; + + Log.v("Finding all proxy delegates"); + foreach (var type in getDelegateTypes()) { + var cctor = DotNetUtils.getMethod(type, ".cctor"); + if (cctor == null || !cctor.HasBody) + continue; + if (!type.HasFields) + continue; + + object context = checkCctor(type, cctor); + if (context == null) + continue; + + Log.v("Found proxy delegate: {0} ({1:X8})", Utils.removeNewlines(type), type.MetadataToken.ToUInt32()); + RemovedDelegateCreatorCalls++; + var fieldToMethod = getFieldToMethodDictionary(type); + + Log.indent(); + foreach (var field in type.Fields) { + MethodDefinition proxyMethod; + if (!fieldToMethod.TryGetValue(field, out proxyMethod)) + continue; + + MethodReference calledMethod; + OpCode callOpcode; + getCallInfo(context, field, out calledMethod, out callOpcode); + + if (calledMethod == null) + continue; + add(proxyMethod, new DelegateInfo(field, calledMethod, callOpcode)); + Log.v("Field: {0}, Opcode: {1}, Method: {2} ({3:X8})", + Utils.removeNewlines(field.Name), + callOpcode, + Utils.removeNewlines(calledMethod), + calledMethod.MetadataToken.ToUInt32()); + } + Log.deIndent(); + delegateTypesDict[type] = true; + } + } + + protected void add(MethodDefinition method, DelegateInfo di) { + proxyMethodToDelegateInfo.add(method, di); + } + + protected abstract object checkCctor(TypeDefinition type, MethodDefinition cctor); + protected abstract Dictionary getFieldToMethodDictionary(TypeDefinition type); + protected abstract void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode); + + protected override bool deobfuscate(Blocks blocks, IList allBlocks) { + var removeInfos = new Dictionary>(); + + 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; + + var method = instr.Operand as MethodReference; + if (method == null) + continue; + var di = proxyMethodToDelegateInfo.find(method); + if (di == null) + continue; + add(removeInfos, block, i, di); + } + } + + return fixProxyCalls(removeInfos); + } + } } diff --git a/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs b/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs index eb1c0534..bc9e49dd 100644 --- a/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs @@ -88,7 +88,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly { ResourceResolver resourceResolver; MemoryManagerInfo memoryManagerInfo; - ProxyDelegateFinder proxyDelegateFinder; + ProxyCallFixer proxyCallFixer; AutomatedErrorReportingFinder automatedErrorReportingFinder; TamperProtectionRemover tamperProtectionRemover; @@ -142,8 +142,8 @@ namespace de4dot.code.deobfuscators.SmartAssembly { findSmartAssemblyAttributes(); memoryManagerInfo = new MemoryManagerInfo(module); memoryManagerInfo.find(); - proxyDelegateFinder = new ProxyDelegateFinder(module, DeobfuscatedFile); - proxyDelegateFinder.findDelegateCreator(module); + proxyCallFixer = new ProxyCallFixer(module, DeobfuscatedFile); + proxyCallFixer.findDelegateCreator(module); if (!foundVersion) guessVersion(); @@ -187,7 +187,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly { if (poweredByAttributeString == "Powered by {smartassembly}") { // It's SA 1.x - 4.x - if (proxyDelegateFinder.Detected || hasEmptyClassesInEveryNamespace()) { + if (proxyCallFixer.Detected || hasEmptyClassesInEveryNamespace()) { ObfuscatorName = "SmartAssembly 4.x"; approxVersion = new Version(4, 0, 0, 0); return; @@ -303,7 +303,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly { } initDecrypters(); - proxyDelegateFinder.find(); + proxyCallFixer.find(); } void initDecrypters() { @@ -430,7 +430,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly { } public override void deobfuscateMethodEnd(Blocks blocks) { - proxyDelegateFinder.deobfuscate(blocks); + proxyCallFixer.deobfuscate(blocks); removeAutomatedErrorReportingCode(blocks); removeTamperProtection(blocks); removeStringsInitCode(blocks); @@ -439,7 +439,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly { public override void deobfuscateEnd() { canRemoveTypes = findBigType() == null; - removeProxyDelegates(proxyDelegateFinder, canRemoveTypes); + removeProxyDelegates(proxyCallFixer, canRemoveTypes); removeMemoryManagerStuff(); removeTamperProtectionStuff(); removeStringDecryptionStuff(); diff --git a/de4dot.code/deobfuscators/SmartAssembly/ProxyDelegateFinder.cs b/de4dot.code/deobfuscators/SmartAssembly/ProxyCallFixer.cs similarity index 95% rename from de4dot.code/deobfuscators/SmartAssembly/ProxyDelegateFinder.cs rename to de4dot.code/deobfuscators/SmartAssembly/ProxyCallFixer.cs index 93f383c7..5245ad3b 100644 --- a/de4dot.code/deobfuscators/SmartAssembly/ProxyDelegateFinder.cs +++ b/de4dot.code/deobfuscators/SmartAssembly/ProxyCallFixer.cs @@ -24,7 +24,7 @@ using Mono.Cecil.Cil; using de4dot.blocks; namespace de4dot.code.deobfuscators.SmartAssembly { - class ProxyDelegateFinder : ProxyDelegateFinderBase { + class ProxyCallFixer : ProxyCallFixer1 { static readonly Dictionary specialCharsDict = new Dictionary(); static readonly char[] specialChars = new char[] { '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', @@ -40,12 +40,12 @@ namespace de4dot.code.deobfuscators.SmartAssembly { IList memberReferences; ISimpleDeobfuscator simpleDeobfuscator; - static ProxyDelegateFinder() { + static ProxyCallFixer() { for (int i = 0; i < specialChars.Length; i++) specialCharsDict[specialChars[i]] = i; } - public ProxyDelegateFinder(ModuleDefinition module, ISimpleDeobfuscator simpleDeobfuscator) + public ProxyCallFixer(ModuleDefinition module, ISimpleDeobfuscator simpleDeobfuscator) : base(module) { this.memberReferences = new List(module.GetMemberReferences()); this.simpleDeobfuscator = simpleDeobfuscator;