Port Spices.Net deobfuscator

This commit is contained in:
de4dot 2012-11-14 19:29:29 +01:00
parent 445b68f4f5
commit 475c597a60
5 changed files with 88 additions and 79 deletions

View File

@ -250,11 +250,11 @@
<None Include="deobfuscators\SmartAssembly\StringDecrypterInfo.cs" />
<None Include="deobfuscators\SmartAssembly\StringEncoderClassFinder.cs" />
<None Include="deobfuscators\SmartAssembly\TamperProtectionRemover.cs" />
<None Include="deobfuscators\Spices_Net\Deobfuscator.cs" />
<None Include="deobfuscators\Spices_Net\QclzDecompressor.cs" />
<None Include="deobfuscators\Spices_Net\ResourceNamesRestorer.cs" />
<None Include="deobfuscators\Spices_Net\SpicesMethodCallInliner.cs" />
<None Include="deobfuscators\Spices_Net\StringDecrypter.cs" />
<Compile Include="deobfuscators\Spices_Net\Deobfuscator.cs" />
<Compile Include="deobfuscators\Spices_Net\QclzDecompressor.cs" />
<Compile Include="deobfuscators\Spices_Net\ResourceNamesRestorer.cs" />
<Compile Include="deobfuscators\Spices_Net\SpicesMethodCallInliner.cs" />
<Compile Include="deobfuscators\Spices_Net\StringDecrypter.cs" />
<Compile Include="deobfuscators\StringCounts.cs" />
<Compile Include="deobfuscators\TypesRestorer.cs" />
<Compile Include="deobfuscators\Unknown\Deobfuscator.cs" />

View File

@ -24,11 +24,11 @@ using de4dot.blocks;
namespace de4dot.code.deobfuscators.Spices_Net {
class ResourceNamesRestorer {
ModuleDefinition module;
ModuleDefMD module;
TypeDef resourceManagerType;
TypeDef componentResourceManagerType;
MethodDefinitionAndDeclaringTypeDict<MethodReference> resourceManagerCtors = new MethodDefinitionAndDeclaringTypeDict<MethodReference>();
MethodDefinitionAndDeclaringTypeDict<MethodReference> componentManagerCtors = new MethodDefinitionAndDeclaringTypeDict<MethodReference>();
MethodDefinitionAndDeclaringTypeDict<IMethod> resourceManagerCtors = new MethodDefinitionAndDeclaringTypeDict<IMethod>();
MethodDefinitionAndDeclaringTypeDict<IMethod> componentManagerCtors = new MethodDefinitionAndDeclaringTypeDict<IMethod>();
public TypeDef ResourceManagerType {
get { return resourceManagerType; }
@ -38,7 +38,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
get { return componentResourceManagerType; }
}
public ResourceNamesRestorer(ModuleDefinition module) {
public ResourceNamesRestorer(ModuleDefMD module) {
this.module = module;
}
@ -54,7 +54,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
initializeCtors(componentResourceManagerType, componentManagerCtors);
}
static void initializeCtors(TypeDef manager, MethodDefinitionAndDeclaringTypeDict<MethodReference> ctors) {
void initializeCtors(TypeDef manager, MethodDefinitionAndDeclaringTypeDict<IMethod> ctors) {
if (manager == null)
return;
@ -62,10 +62,8 @@ namespace de4dot.code.deobfuscators.Spices_Net {
if (ctor.Name != ".ctor")
continue;
var newCtor = new MethodReference(ctor.Name, ctor.MethodReturnType.ReturnType, manager.BaseType);
newCtor.HasThis = true;
foreach (var param in ctor.Parameters)
newCtor.Parameters.Add(new ParameterDefinition(param.ParameterType));
var newCtor = new MemberRefUser(module, ctor.Name, ctor.MethodSig.Clone(), manager.BaseType);
module.UpdateRowId(newCtor);
ctors.add(ctor, newCtor);
}
}
@ -75,9 +73,9 @@ namespace de4dot.code.deobfuscators.Spices_Net {
return false;
if (type.HasProperties || type.HasEvents || type.HasFields)
return false;
if (type.Interfaces.Count > 0)
if (type.InterfaceImpls.Count > 0)
return false;
var method = DotNetUtils.getMethod(type, "GetResourceFileName");
var method = type.FindMethod("GetResourceFileName");
if (!DotNetUtils.isMethod(method, "System.String", "(System.Globalization.CultureInfo)"))
return false;
@ -90,7 +88,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
var numToResource = new Dictionary<uint, Resource>(module.Resources.Count);
foreach (var resource in module.Resources) {
var name = resource.Name;
var name = resource.Name.String;
int index = name.LastIndexOf('.');
string ext;
if (index < 0)
@ -106,12 +104,12 @@ namespace de4dot.code.deobfuscators.Spices_Net {
foreach (var type in module.GetTypes()) {
rename(numToResource, "", type.FullName);
rename(numToResource, "", type.FullName + ".g");
rename(numToResource, type.Namespace, type.Name);
rename(numToResource, type.Namespace, type.Name + ".g");
rename(numToResource, type.Namespace.String, type.Name.String);
rename(numToResource, type.Namespace.String, type.Name.String + ".g");
}
if (module.Assembly != null)
rename(numToResource, "", module.Assembly.Name.Name + ".g");
rename(numToResource, "", module.Assembly.Name.String + ".g");
}
static void rename(Dictionary<uint, Resource> numToResource, string ns, string name) {
@ -121,14 +119,14 @@ namespace de4dot.code.deobfuscators.Spices_Net {
if (!numToResource.TryGetValue(hash, out resource))
return;
int index = resource.Name.LastIndexOf('.');
int index = resource.Name.String.LastIndexOf('.');
string resourceNamespace, newName;
if (index < 0) {
resourceNamespace = "";
newName = resourceName;
}
else {
resourceNamespace = resource.Name.Substring(0, index);
resourceNamespace = resource.Name.String.Substring(0, index);
newName = resourceNamespace + "." + resourceName;
}
if (resourceNamespace != ns)
@ -137,7 +135,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
Logger.v("Restoring resource name: '{0}' => '{1}'",
Utils.removeNewlines(resource.Name),
Utils.removeNewlines(newName));
resource.Name = newName;
resource.Name = new UTF8String(newName);
numToResource.Remove(hash);
}
@ -153,13 +151,16 @@ namespace de4dot.code.deobfuscators.Spices_Net {
}
public void deobfuscate(Blocks blocks) {
if (resourceManagerType == null && componentResourceManagerType == null)
return;
foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var instr = instrs[i];
if (instr.OpCode.Code != Code.Newobj)
continue;
var ctor = instr.Operand as MethodReference;
var ctor = instr.Operand as IMethod;
if (ctor == null)
continue;
var newCtor = resourceManagerCtors.find(ctor);

View File

@ -20,29 +20,28 @@
using System.Collections.Generic;
using dot10.DotNet;
using dot10.DotNet.Emit;
using Mono.Cecil.Metadata;
using de4dot.blocks;
using de4dot.blocks.cflow;
namespace de4dot.code.deobfuscators.Spices_Net {
class SpicesMethodCallInliner : MethodCallInliner {
ModuleDefinition module;
ModuleDefMD module;
TypeDefinitionDict<bool> methodsTypes = new TypeDefinitionDict<bool>();
MethodDefinitionAndDeclaringTypeDict<MethodDef> classMethods = new MethodDefinitionAndDeclaringTypeDict<MethodDef>();
public SpicesMethodCallInliner(ModuleDefinition module)
public SpicesMethodCallInliner(ModuleDefMD module)
: base(false) {
this.module = module;
}
protected override bool isCompatibleType(int paramIndex, TypeReference origType, TypeReference newType) {
if (MemberReferenceHelper.compareTypes(origType, newType))
protected override bool isCompatibleType(int paramIndex, IType origType, IType newType) {
if (new SigComparer().Equals(origType, newType))
return true;
if (paramIndex == -1) {
if (newType.IsValueType || origType.IsValueType)
if (isValueType(newType) || isValueType(origType))
return false;
}
return newType.EType == ElementType.Object;
return newType.FullName == "System.Object";
}
public bool checkCanInline(MethodDef method) {
@ -61,7 +60,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
void restoreMethodBodies() {
var methodToOrigMethods = new MethodDefinitionAndDeclaringTypeDict<List<MethodDef>>();
foreach (var t in module.Types) {
var types = new List<TypeDef>(TypeDef.GetTypes(new List<TypeDef> { t }));
var types = new List<TypeDef>(AllTypesHelper.Types(new List<TypeDef> { t }));
foreach (var type in types) {
if (methodsTypes.find(type))
continue;
@ -103,7 +102,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
calledMethod = null;
if (method.Body == null)
return false;
if (method.Body.Variables.Count > 0)
if (method.Body.LocalList.Count > 0)
return false;
if (method.Body.ExceptionHandlers.Count > 0)
return false;
@ -114,7 +113,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
return false;
if (!calledMethod.IsStatic)
return false;
if (calledMethod.GenericParameters.Count > 0)
if (calledMethod.GenericParams.Count > 0)
return false;
if (calledMethod.Body == null || calledMethod.Body.Instructions.Count == 0)
return false;
@ -128,7 +127,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
var instrs = instanceMethod.Body.Instructions;
int index;
for (index = 0; index < instrs.Count; index++) {
if (DotNetUtils.getArgIndex(instrs[index]) != index)
if (instrs[index].GetParameterIndex() != index)
break;
}
var call = instrs[index++];
@ -155,17 +154,17 @@ namespace de4dot.code.deobfuscators.Spices_Net {
static bool checkMethodsType(TypeDef type) {
if (!type.IsNested)
return false;
if ((type.Attributes & ~TypeAttributes.BeforeFieldInit) != TypeAttributes.NestedAssembly)
if ((type.Flags & ~TypeAttributes.BeforeFieldInit) != TypeAttributes.NestedAssembly)
return false;
if (type.HasProperties || type.HasEvents || type.HasFields || type.HasNestedTypes)
return false;
if (type.GenericParameters.Count > 0)
if (type.GenericParams.Count > 0)
return false;
if (type.IsValueType || type.IsInterface)
return false;
if (type.BaseType == null || type.BaseType.EType != ElementType.Object)
if (type.BaseType == null || type.BaseType.FullName != "System.Object")
return false;
if (type.Interfaces.Count > 0)
if (type.InterfaceImpls.Count > 0)
return false;
if (!checkMethods(type))
return false;
@ -181,16 +180,16 @@ namespace de4dot.code.deobfuscators.Spices_Net {
if (method.Name == ".cctor")
return false;
if (method.Name == ".ctor") {
if (method.Parameters.Count != 0)
if (method.MethodSig.GetParamCount() != 0)
return false;
foundCtor = true;
continue;
}
if (method.Attributes != (MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig))
if (method.Flags != (MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig))
return false;
if (method.HasPInvokeInfo || method.PInvokeInfo != null)
if (method.ImplMap != null)
return false;
if (method.GenericParameters.Count > 0)
if (method.GenericParams.Count > 0)
return false;
numMethods++;
@ -236,7 +235,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
var call = instrs[i];
if (call.OpCode.Code != Code.Call)
continue;
var realInstanceMethod = classMethods.find(call.Operand as MethodReference);
var realInstanceMethod = classMethods.find(call.Operand as IMethod);
if (realInstanceMethod == null)
continue;
call.Operand = realInstanceMethod;

View File

@ -22,12 +22,11 @@ using System.Collections.Generic;
using System.Text;
using dot10.DotNet;
using dot10.DotNet.Emit;
using Mono.Cecil.Metadata;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Spices_Net {
class StringDecrypter {
ModuleDefinition module;
ModuleDefMD module;
TypeDef decrypterType;
FieldDef encryptedDataField;
StringDataFlags stringDataFlags;
@ -60,12 +59,12 @@ namespace de4dot.code.deobfuscators.Spices_Net {
get {
if (encryptedDataField == null)
return null;
var type = encryptedDataField.FieldType as TypeDef;
var type = encryptedDataField.FieldSig.GetFieldType().TryGetTypeDef();
if (type == null || type.Fields.Count != 1 || type.Fields[0] != encryptedDataField)
return null;
if (type.HasMethods || type.HasEvents || type.HasProperties || type.HasNestedTypes)
return null;
if (type.Interfaces.Count > 0)
if (type.InterfaceImpls.Count > 0)
return null;
return type;
@ -84,7 +83,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
get { return methodToInfo.getValues(); }
}
public StringDecrypter(ModuleDefinition module) {
public StringDecrypter(ModuleDefMD module) {
this.module = module;
}
@ -96,13 +95,13 @@ namespace de4dot.code.deobfuscators.Spices_Net {
continue;
if (type.Fields.Count != 2)
continue;
if ((type.Attributes & ~TypeAttributes.Sealed) != 0)
if ((type.Flags & ~TypeAttributes.Sealed) != 0)
continue;
if (type.BaseType == null || type.BaseType.FullName != "System.Object")
continue;
if (hasInstanceMethods(type))
continue;
var cctor = DotNetUtils.getMethod(type, ".cctor");
var cctor = type.FindClassConstructor();
if (cctor == null)
continue;
@ -125,7 +124,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
foreach (var method in type.Methods) {
if (!method.IsStatic)
return true;
if (method.PInvokeInfo != null)
if (method.ImplMap != null)
return true;
}
return false;
@ -136,7 +135,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
var instructions = cctor.Body.Instructions;
for (int i = 0; i < instructions.Count; i++) {
var ldci4 = instructions[i];
if (!DotNetUtils.isLdcI4(ldci4))
if (!ldci4.IsLdcI4())
continue;
var instrs = DotNetUtils.getInstructions(instructions, i + 1, OpCodes.Newarr, OpCodes.Dup, OpCodes.Ldtoken, OpCodes.Call);
@ -166,11 +165,12 @@ namespace de4dot.code.deobfuscators.Spices_Net {
StringDataFlags getStringDataFlags(MethodDef method) {
if (method == null || method.Body == null)
return 0;
if (method.Parameters.Count != 1)
var sig = method.MethodSig;
if (sig == null || sig.Params.Count != 1)
return 0;
if (!checkClass(method.Parameters[0].ParameterType, "System.Byte[]"))
if (!checkClass(sig.Params[0], "System.Byte[]"))
return 0;
if (!checkClass(method.MethodReturnType.ReturnType, "System.Byte[]"))
if (!checkClass(sig.RetType, "System.Byte[]"))
return 0;
StringDataFlags flags = 0;
@ -194,9 +194,10 @@ namespace de4dot.code.deobfuscators.Spices_Net {
var calledMethod = instr.Operand as MethodDef;
if (calledMethod == null)
continue;
if (calledMethod.MethodReturnType.ReturnType.EType == ElementType.Void)
var sig = calledMethod.MethodSig;
if (sig == null || sig.RetType.GetElementType() == ElementType.Void)
continue;
if (calledMethod.Parameters.Count != 0)
if (sig.Params.Count != 0)
continue;
if (!get3DesKeyIv(calledMethod, ref key, ref iv))
continue;
@ -211,13 +212,15 @@ namespace de4dot.code.deobfuscators.Spices_Net {
return false;
var instrs = method.Body.Instructions;
var arrays = ArrayFinder.getArrays(method, module.TypeSystem.Byte);
var arrays = ArrayFinder.getArrays(method, module.CorLibTypes.Byte);
if (arrays.Count != 1 && arrays.Count != 2)
return false;
key = arrays[0];
if (arrays.Count == 1)
iv = module.Assembly.Name.PublicKeyToken;
if (arrays.Count == 1) {
var pkt = PublicKeyBase.ToPublicKeyToken(module.Assembly.PublicKey);
iv = pkt == null ? null : pkt.Data;
}
else
iv = arrays[1];
return true;
@ -230,18 +233,21 @@ namespace de4dot.code.deobfuscators.Spices_Net {
var called = instr.Operand as MethodDef;
if (called == null)
continue;
if (called.MethodReturnType.ReturnType.EType != ElementType.I4)
var sig = called.MethodSig;
if (sig == null)
continue;
var parameters = called.Parameters;
if (sig.RetType.GetElementType() != ElementType.I4)
continue;
var parameters = sig.Params;
if (parameters.Count != 4)
continue;
if (!checkClass(parameters[0].ParameterType, "System.Byte[]"))
if (!checkClass(parameters[0], "System.Byte[]"))
continue;
if (parameters[1].ParameterType.EType != ElementType.I4)
if (parameters[1].GetElementType() != ElementType.I4)
continue;
if (!checkClass(parameters[2].ParameterType, "System.Byte[]"))
if (!checkClass(parameters[2], "System.Byte[]"))
continue;
if (parameters[3].ParameterType.EType != ElementType.I4)
if (parameters[3].GetElementType() != ElementType.I4)
continue;
return true;
@ -257,21 +263,24 @@ namespace de4dot.code.deobfuscators.Spices_Net {
return false;
}
static bool checkClass(TypeReference type, string fullName) {
return type != null && (type.EType == ElementType.Object || type.FullName == fullName);
static bool checkClass(TypeSig type, string fullName) {
return type != null && (type.ElementType == ElementType.Object || type.FullName == fullName);
}
static bool isStringType(TypeReference type) {
return type != null && (type.EType == ElementType.Object || type.EType == ElementType.String);
static bool isStringType(TypeSig type) {
return type != null && (type.ElementType == ElementType.Object || type.ElementType == ElementType.String);
}
bool initializeDecrypterInfos(TypeDef type) {
foreach (var method in type.Methods) {
if (!method.IsStatic || method.Body == null)
continue;
if (method.Parameters.Count != 0)
var sig = method.MethodSig;
if (sig == null)
continue;
if (!isStringType(method.MethodReturnType.ReturnType))
if (sig.Params.Count != 0)
continue;
if (!isStringType(sig.RetType))
continue;
var info = createInfo(method);
@ -289,11 +298,11 @@ namespace de4dot.code.deobfuscators.Spices_Net {
for (int i = 0; i < instrs.Count - 1; i++) {
var ldci4_1 = instrs[i];
var ldci4_2 = instrs[i + 1];
if (!DotNetUtils.isLdcI4(ldci4_1) || !DotNetUtils.isLdcI4(ldci4_2))
if (!ldci4_1.IsLdcI4() || !ldci4_2.IsLdcI4())
continue;
int offset = DotNetUtils.getLdcI4Value(ldci4_1);
int length = DotNetUtils.getLdcI4Value(ldci4_2);
int offset = ldci4_1.GetLdcI4Value();
int length = ldci4_2.GetLdcI4Value();
return new DecrypterInfo(method, offset, length);
}
@ -313,7 +322,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
}
if ((stringDataFlags & StringDataFlags.Encrypted2) != 0) {
var k = module.Assembly.Name.PublicKey;
var k = module.Assembly.PublicKey.Data;
int mask = (byte)(~k.Length);
for (int i = 0; i < decryptedData.Length; i++)
decryptedData[i] ^= k[i & mask];
@ -331,7 +340,7 @@ namespace de4dot.code.deobfuscators.Spices_Net {
return;
encryptedDataField.InitialValue = new byte[1];
encryptedDataField.FieldType = module.TypeSystem.Byte;
encryptedDataField.FieldSig.Type = module.CorLibTypes.Byte;
}
public string decrypt(MethodDef method) {

View File

@ -59,8 +59,8 @@ namespace de4dot.cui {
new de4dot.code.deobfuscators.Skater_NET.DeobfuscatorInfo(),
#if PORT
new de4dot.code.deobfuscators.SmartAssembly.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Spices_Net.DeobfuscatorInfo(),
#endif
new de4dot.code.deobfuscators.Spices_Net.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Xenocode.DeobfuscatorInfo(),
};
}