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;