diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index 881d9378..278f80bd 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -131,6 +131,7 @@
+
diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/CoMethodCallInliner.cs b/de4dot.code/deobfuscators/CryptoObfuscator/CoMethodCallInliner.cs
index 312196f4..d632ff43 100644
--- a/de4dot.code/deobfuscators/CryptoObfuscator/CoMethodCallInliner.cs
+++ b/de4dot.code/deobfuscators/CryptoObfuscator/CoMethodCallInliner.cs
@@ -37,7 +37,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
return false;
if (method.HasGenericParameters)
return false;
- if (!inlinedMethodTypes.IsValidMethodType(method.DeclaringType))
+ if (!InlinedMethodTypes.IsValidMethodType(method.DeclaringType))
return false;
return true;
diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs b/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs
index 874c4632..851c6ae3 100644
--- a/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs
+++ b/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs
@@ -32,12 +32,14 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
BoolOption removeTamperProtection;
BoolOption decryptConstants;
BoolOption inlineMethods;
+ BoolOption fixLdnull;
public DeobfuscatorInfo()
: base(DEFAULT_REGEX) {
removeTamperProtection = new BoolOption(null, MakeArgName("tamper"), "Remove tamper protection code", true);
decryptConstants = new BoolOption(null, MakeArgName("consts"), "Decrypt constants", true);
inlineMethods = new BoolOption(null, MakeArgName("inline"), "Inline short methods", true);
+ fixLdnull = new BoolOption(null, MakeArgName("ldnull"), "Restore ldnull instructions", true);
}
public override string Name {
@@ -54,6 +56,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
RemoveTamperProtection = removeTamperProtection.get(),
DecryptConstants = decryptConstants.get(),
InlineMethods = inlineMethods.get(),
+ FixLdnull = fixLdnull.get(),
});
}
@@ -62,6 +65,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
removeTamperProtection,
decryptConstants,
inlineMethods,
+ fixLdnull,
};
}
}
@@ -93,6 +97,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
public bool RemoveTamperProtection { get; set; }
public bool DecryptConstants { get; set; }
public bool InlineMethods { get; set; }
+ public bool FixLdnull { get; set; }
}
public override string Type {
@@ -275,13 +280,14 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
}
public override void DeobfuscateEnd() {
+ if (options.FixLdnull)
+ new LdnullFixer(module, inlinedMethodTypes).Restore();
RemoveProxyDelegates(proxyCallFixer);
if (CanRemoveStringDecrypterType) {
AddResourceToBeRemoved(stringDecrypter.Resource, "Encrypted strings");
AddTypeToBeRemoved(stringDecrypter.Type, "String decrypter type");
}
- if (options.InlineMethods)
- AddTypesToBeRemoved(inlinedMethodTypes.Types, "Inlined methods types");
+ AddTypesToBeRemoved(inlinedMethodTypes.Types, "Inlined methods type");
base.DeobfuscateEnd();
}
diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/InlinedMethodTypes.cs b/de4dot.code/deobfuscators/CryptoObfuscator/InlinedMethodTypes.cs
index fce00acc..929c80f9 100644
--- a/de4dot.code/deobfuscators/CryptoObfuscator/InlinedMethodTypes.cs
+++ b/de4dot.code/deobfuscators/CryptoObfuscator/InlinedMethodTypes.cs
@@ -39,7 +39,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
}
}
- bool IsValidType(TypeDef type) {
+ static bool IsValidType(TypeDef type) {
if (type == null)
return false;
@@ -62,7 +62,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
return true;
}
- public bool IsValidMethodType(TypeDef type) {
+ public static bool IsValidMethodType(TypeDef type) {
if (!IsValidType(type))
return false;
@@ -74,6 +74,18 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
return true;
}
+ public static bool IsValidFieldType(TypeDef type) {
+ if (!IsValidType(type))
+ return false;
+
+ if (type.HasMethods)
+ return false;
+ if (type.Fields.Count != 1)
+ return false;
+
+ return true;
+ }
+
public void Add(TypeDef type) {
if (type == null || types.ContainsKey(type))
return;
diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/LdnullFixer.cs b/de4dot.code/deobfuscators/CryptoObfuscator/LdnullFixer.cs
new file mode 100644
index 00000000..3337153b
--- /dev/null
+++ b/de4dot.code/deobfuscators/CryptoObfuscator/LdnullFixer.cs
@@ -0,0 +1,126 @@
+/*
+ Copyright (C) 2011-2013 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 .
+*/
+
+using System.Collections.Generic;
+using de4dot.blocks;
+using dnlib.DotNet;
+using dnlib.DotNet.Emit;
+
+namespace de4dot.code.deobfuscators.CryptoObfuscator {
+ class LdnullFixer {
+ readonly ModuleDef module;
+ readonly InlinedMethodTypes inlinedMethodTypes;
+
+ public LdnullFixer(ModuleDef module, InlinedMethodTypes inlinedMethodTypes) {
+ this.module = module;
+ this.inlinedMethodTypes = inlinedMethodTypes;
+ }
+
+ public void Restore() {
+ var fields = FindFieldTypes(FindFieldTypes());
+ Restore(fields);
+ foreach (var field in fields.Keys)
+ inlinedMethodTypes.Add(field.DeclaringType);
+ }
+
+ FieldDefAndDeclaringTypeDict FindFieldTypes() {
+ var dict = new FieldDefAndDeclaringTypeDict();
+
+ foreach (var type in module.GetTypes()) {
+ foreach (var method in type.Methods) {
+ var body = method.Body;
+ if (body == null)
+ continue;
+ foreach (var instr in body.Instructions) {
+ if (instr.OpCode.Code != Code.Ldsfld)
+ continue;
+ var field = instr.Operand as FieldDef;
+ if (field == null)
+ continue;
+ var declType = field.DeclaringType;
+ if (declType == null)
+ continue;
+ if (!InlinedMethodTypes.IsValidFieldType(declType))
+ continue;
+ dict.Add(field, field);
+ }
+ }
+ }
+
+ return dict;
+ }
+
+ Dictionary FindFieldTypes(FieldDefAndDeclaringTypeDict fields) {
+ var validFields = new Dictionary(fields.Count);
+ foreach (var field in fields.GetKeys())
+ validFields.Add(field, false);
+
+ foreach (var type in module.GetTypes()) {
+ if (validFields.Count == 0)
+ break;
+
+ foreach (var method in type.Methods) {
+ var body = method.Body;
+ if (body == null)
+ continue;
+ foreach (var instr in body.Instructions) {
+ if (instr.OpCode.Code == Code.Ldsfld)
+ continue;
+ var field = instr.Operand as IField;
+ if (field == null)
+ continue;
+
+ var validType = fields.Find(field);
+ if (validType == null)
+ continue;
+
+ validFields.Remove(validType);
+ }
+ }
+ }
+
+ return validFields;
+ }
+
+ int Restore(Dictionary nullFields) {
+ int numRestored = 0;
+ foreach (var type in module.GetTypes()) {
+ foreach (var method in type.Methods) {
+ var body = method.Body;
+ if (body == null)
+ continue;
+ foreach (var instr in body.Instructions) {
+ if (instr.OpCode.Code != Code.Ldsfld)
+ continue;
+ var field = instr.Operand as FieldDef;
+ if (field == null)
+ continue;
+ if (!nullFields.ContainsKey(field))
+ continue;
+
+ instr.OpCode = OpCodes.Ldnull;
+ instr.Operand = null;
+ numRestored++;
+ }
+ }
+ }
+ return numRestored;
+ }
+ }
+}