From dcbcaa098ea99959209fc92f4c227aa0f7b1d2bb Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 8 Dec 2012 01:12:20 +0100 Subject: [PATCH] Work around a bug in EF --- .../Eazfuscator_NET/Deobfuscator.cs | 47 +++++++++++++++++++ .../Eazfuscator_NET/StringDecrypter.cs | 6 +++ 2 files changed, 53 insertions(+) diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/Deobfuscator.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/Deobfuscator.cs index d1a1b365..e95669fc 100644 --- a/de4dot.code/deobfuscators/Eazfuscator_NET/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/Eazfuscator_NET/Deobfuscator.cs @@ -17,8 +17,10 @@ along with de4dot. If not, see . */ +using System; using System.Collections.Generic; using dot10.DotNet; +using dot10.DotNet.Emit; using de4dot.blocks; using de4dot.code.renamer; @@ -163,9 +165,54 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { addResourceToBeRemoved(resourceMethodsRestorer.Resource, "GetManifestResourceStream type resource"); fixInterfaces(); + stringDecrypterBugWorkaround(); base.deobfuscateEnd(); } + void stringDecrypterBugWorkaround() { + // There's a bug in Eazfuscator.NET when the VM and string encryption features are + // enabled. The string decrypter's initialization code checks to make sure it's not + // called by eg. a dynamic method. When it's called from the VM code, it is + // called by MethodBase.Invoke() and the string decrypter antis set in causing it + // to fail. + // One way to work around this is to make sure the string decrypter has been called + // once. That way, any VM code calling it won't trigger a failure. + // We can put this code in ::.cctor() since it gets executed before any + // other code. + // Note that we can't call the string decrypter from ::.cctor() since + // its DeclaringType property will return null (since it's the global type). We + // must call another created class which calls the string decrypter. + + // You must use --dont-rename --keep-types --preserve-tokens and decrypt strings + if (!Operations.KeepObfuscatorTypes || Operations.DecryptStrings == OpDecryptString.None || + (Operations.RenamerFlags & (RenamerFlags.RenameNamespaces | RenamerFlags.RenameTypes)) != 0) + return; + + if (stringDecrypter.ValidStringDecrypterValue == null) + return; + + var newType = module.UpdateRowId(new TypeDefUser(Guid.NewGuid().ToString("B"), module.CorLibTypes.Object.TypeDefOrRef)); + module.Types.Add(newType); + var newMethod = module.UpdateRowId(new MethodDefUser("x", MethodSig.CreateStatic(module.CorLibTypes.Void), 0, MethodAttributes.Static | MethodAttributes.HideBySig)); + newType.Methods.Add(newMethod); + newMethod.Body = new CilBody(); + newMethod.Body.MaxStack = 1; + newMethod.Body.Instructions.Add(Instruction.CreateLdcI4(stringDecrypter.ValidStringDecrypterValue.Value)); + newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Call, stringDecrypter.Method)); + newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Pop)); + newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); + + var cctor = module.GlobalType.FindOrCreateStaticConstructor(); + var blocks = new Blocks(cctor); + var block = blocks.MethodBlocks.getAllBlocks()[0]; + block.insert(0, Instruction.Create(OpCodes.Call, newMethod)); + + IList allInstructions; + IList allExceptionHandlers; + blocks.getCode(out allInstructions, out allExceptionHandlers); + DotNetUtils.restoreBody(cctor, allInstructions, allExceptionHandlers); + } + public override IEnumerable getStringDecrypterMethods() { var list = new List(); if (stringDecrypter.Method != null) diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs index 2813e55d..05ccc01f 100644 --- a/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs +++ b/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs @@ -45,6 +45,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { StreamHelperType streamHelperType; EfConstantsReader stringMethodConsts; bool isV32OrLater; + int? validStringDecrypterValue; class StreamHelperType { public TypeDef type; @@ -76,6 +77,10 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { } } + public int? ValidStringDecrypterValue { + get { return validStringDecrypterValue;} + } + public TypeDef Type { get { return stringType; } } @@ -391,6 +396,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { } public string decrypt(int val) { + validStringDecrypterValue = val; while (true) { int offset = magic1 ^ i3 ^ val ^ i6; reader.BaseStream.Position = offset;