From 237732e98ebe8f0637535ae889699ffdb71a65fc Mon Sep 17 00:00:00 2001 From: de4dot Date: Thu, 5 Apr 2012 20:45:16 +0200 Subject: [PATCH] Refactor --- de4dot.code/deobfuscators/TypesRestorer.cs | 176 +++++++++++++++------ 1 file changed, 125 insertions(+), 51 deletions(-) diff --git a/de4dot.code/deobfuscators/TypesRestorer.cs b/de4dot.code/deobfuscators/TypesRestorer.cs index 82972859..db7525f0 100644 --- a/de4dot.code/deobfuscators/TypesRestorer.cs +++ b/de4dot.code/deobfuscators/TypesRestorer.cs @@ -17,6 +17,7 @@ along with de4dot. If not, see . */ +using System; using System.Collections.Generic; using Mono.Cecil; using Mono.Cecil.Cil; @@ -27,7 +28,7 @@ namespace de4dot.code.deobfuscators { // Restore the type of all fields / parameters that have had their type turned into object. // This thing requires a lot more code than I have time to do now (similar to symbol renaming) // so it will be a basic implementation only. - class TypesRestorer { + abstract class TypesRestorerBase { ModuleDefinition module; List allMethods; Dictionary> argInfos = new Dictionary>(); @@ -109,7 +110,7 @@ namespace de4dot.code.deobfuscators { } } - public TypesRestorer(ModuleDefinition module) { + public TypesRestorerBase(ModuleDefinition module) { this.module = module; } @@ -131,19 +132,42 @@ namespace de4dot.code.deobfuscators { public void deobfuscate() { allMethods = new List(); - foreach (var type in module.GetTypes()) - allMethods.AddRange(type.Methods); + addAllMethods(); + addAllFields(); + + deobfuscateLoop(); + + restoreFieldTypes(); + restoreMethodTypes(); + } + + void addAllMethods() { + foreach (var type in module.GetTypes()) + addMethods(type.Methods); + } + + void addMethods(IEnumerable methods) { + allMethods.AddRange(methods); + } + + void addMethod(MethodDefinition method) { + allMethods.Add(method); + } + + void addAllFields() { foreach (var type in module.GetTypes()) { foreach (var field in type.Fields) { - if (!MemberReferenceHelper.isSystemObject(field.FieldType)) + if (!isUnknownType(field)) continue; var key = new FieldReferenceAndDeclaringTypeKey(field); fieldWrites[key] = new TypeInfo(field); } } + } + void deobfuscateLoop() { for (int i = 0; i < 10; i++) { bool changed = false; changed |= deobfuscateFields(); @@ -151,37 +175,49 @@ namespace de4dot.code.deobfuscators { if (!changed) break; } + } + void restoreFieldTypes() { var fields = new List(updatedFields.Values); - if (fields.Count > 0) { - Log.v("Changing field types from object -> real type"); - fields.Sort((a, b) => Utils.compareInt32(a.token, b.token)); - Log.indent(); - foreach (var updatedField in fields) - Log.v("Field {0:X8}: type {1} ({2:X8})", updatedField.token, Utils.removeNewlines(updatedField.newFieldType.FullName), updatedField.newFieldType.MetadataToken.ToInt32()); - Log.deIndent(); - } + if (fields.Count == 0) + return; + Log.v("Changing field types to real type"); + fields.Sort((a, b) => Utils.compareInt32(a.token, b.token)); + Log.indent(); + foreach (var updatedField in fields) + Log.v("Field {0:X8}: type {1} ({2:X8})", updatedField.token, Utils.removeNewlines(updatedField.newFieldType.FullName), updatedField.newFieldType.MetadataToken.ToInt32()); + Log.deIndent(); + } + + void restoreMethodTypes() { var methods = new List(updatedMethods.Values); - if (methods.Count > 0) { - Log.v("Changing method args and return types from object -> real type"); - methods.Sort((a, b) => Utils.compareInt32(a.token, b.token)); + if (methods.Count == 0) + return; + + Log.v("Changing method args and return types to real type"); + methods.Sort((a, b) => Utils.compareInt32(a.token, b.token)); + Log.indent(); + foreach (var updatedMethod in methods) { + Log.v("Method {0:X8}", updatedMethod.token); Log.indent(); - foreach (var updatedMethod in methods) { - Log.v("Method {0:X8}", updatedMethod.token); - Log.indent(); - if (updatedMethod.newReturnType != null) - Log.v("ret: {0} ({1:X8})", Utils.removeNewlines(updatedMethod.newReturnType.FullName), updatedMethod.newReturnType.MetadataToken.ToInt32()); - for (int i = 0; i < updatedMethod.newArgTypes.Length; i++) { - var updatedArg = updatedMethod.newArgTypes[i]; - if (updatedArg == null) - continue; - Log.v("arg {0}: {1} ({2:X8})", i, Utils.removeNewlines(updatedArg.FullName), updatedArg.MetadataToken.ToInt32()); - } - Log.deIndent(); + if (updatedMethod.newReturnType != null) { + Log.v("ret: {0} ({1:X8})", + Utils.removeNewlines(updatedMethod.newReturnType.FullName), + updatedMethod.newReturnType.MetadataToken.ToInt32()); + } + for (int i = 0; i < updatedMethod.newArgTypes.Length; i++) { + var updatedArg = updatedMethod.newArgTypes[i]; + if (updatedArg == null) + continue; + Log.v("arg {0}: {1} ({2:X8})", + i, + Utils.removeNewlines(updatedArg.FullName), + updatedArg.MetadataToken.ToInt32()); } Log.deIndent(); } + Log.deIndent(); } bool deobfuscateMethods() { @@ -218,13 +254,11 @@ namespace de4dot.code.deobfuscators { if (!method.IsStatic || method.Body == null) return; - bool fixReturnType = MemberReferenceHelper.isSystemObject(method.MethodReturnType.ReturnType); + bool fixReturnType = isUnknownType(method.MethodReturnType); argInfos.Clear(); foreach (var arg in method.Parameters) { - if (arg.ParameterType == null || arg.ParameterType.IsValueType) - continue; - if (!MemberReferenceHelper.isSystemObject(arg.ParameterType)) + if (!isUnknownType(arg)) continue; argInfos[arg] = new TypeInfo(arg); } @@ -241,7 +275,7 @@ namespace de4dot.code.deobfuscators { if (!fixReturnType) break; bool wasNewobj; - var type = getLoadedType(method, instructions, i, out wasNewobj); + var type = getLoadedType(method, method, instructions, i, out wasNewobj); if (type == null) break; methodReturnInfo.add(type); @@ -392,29 +426,29 @@ namespace de4dot.code.deobfuscators { } } - bool addMethodArgType(MethodDefinition method, ParameterDefinition methodParam, FieldReference field) { + bool addMethodArgType(IGenericParameterProvider gpp, ParameterDefinition methodParam, FieldReference field) { if (field == null) return false; - return addMethodArgType(method, methodParam, field.FieldType); + return addMethodArgType(gpp, methodParam, field.FieldType); } - bool addMethodArgType(MethodDefinition method, ParameterDefinition methodParam, VariableDefinition otherLocal) { + bool addMethodArgType(IGenericParameterProvider gpp, ParameterDefinition methodParam, VariableDefinition otherLocal) { if (otherLocal == null) return false; - return addMethodArgType(method, methodParam, otherLocal.VariableType); + return addMethodArgType(gpp, methodParam, otherLocal.VariableType); } - bool addMethodArgType(MethodDefinition method, ParameterDefinition methodParam, ParameterDefinition otherParam) { + bool addMethodArgType(IGenericParameterProvider gpp, ParameterDefinition methodParam, ParameterDefinition otherParam) { if (otherParam == null) return false; - return addMethodArgType(method, methodParam, otherParam.ParameterType); + return addMethodArgType(gpp, methodParam, otherParam.ParameterType); } - bool addMethodArgType(MethodDefinition method, ParameterDefinition methodParam, TypeReference type) { + bool addMethodArgType(IGenericParameterProvider gpp, ParameterDefinition methodParam, TypeReference type) { if (methodParam == null || type == null) return false; - if (!isValidType(method, type)) + if (!isValidType(gpp, type)) return false; TypeInfo info; @@ -449,7 +483,7 @@ namespace de4dot.code.deobfuscators { if (!fieldWrites.TryGetValue(new FieldReferenceAndDeclaringTypeKey(field), out info)) continue; bool wasNewobj; - fieldType = getLoadedType(method, instructions, i, out wasNewobj); + fieldType = getLoadedType(info.arg.DeclaringType, method, instructions, i, out wasNewobj); if (fieldType == null) continue; info.add(fieldType, wasNewobj); @@ -476,7 +510,7 @@ namespace de4dot.code.deobfuscators { if (!fieldWrites.TryGetValue(new FieldReferenceAndDeclaringTypeKey(field), out info)) continue; fieldType = calledMethodArgs[calledMethodArgs.Count - 1 - j]; - if (!isValidType(method, fieldType)) + if (!isValidType(info.arg.DeclaringType, fieldType)) continue; info.add(fieldType); } @@ -503,20 +537,16 @@ namespace de4dot.code.deobfuscators { return changed; } - TypeReference getLoadedType(MethodDefinition method, IList instructions, int instrIndex, out bool wasNewobj) { + TypeReference getLoadedType(IGenericParameterProvider gpp, MethodDefinition method, IList instructions, int instrIndex, out bool wasNewobj) { var fieldType = MethodStack.getLoadedType(method, instructions, instrIndex, out wasNewobj); - if (fieldType == null || !isValidType(method, fieldType)) + if (fieldType == null || !isValidType(gpp, fieldType)) return null; return fieldType; } - static bool isValidType(MethodDefinition method, TypeReference type) { + protected virtual bool isValidType(IGenericParameterProvider gpp, TypeReference type) { if (type == null) return false; - if (type.IsValueType) - return false; - if (MemberReferenceHelper.isSystemObject(type)) - return false; if (type.EType == ElementType.Void) return false; @@ -531,7 +561,17 @@ namespace de4dot.code.deobfuscators { case CecilType.GenericParameter: var gp = (GenericParameter)type; - if (method.DeclaringType != gp.Owner && method != gp.Owner) + var methodRef = gpp as MethodReference; + var typeRef = gpp as TypeReference; + if (methodRef != null) { + if (methodRef.DeclaringType != gp.Owner && methodRef != gp.Owner) + return false; + } + else if (typeRef != null) { + if (typeRef != gp.Owner) + return false; + } + else return false; break; @@ -553,6 +593,8 @@ namespace de4dot.code.deobfuscators { return type != null; } + protected abstract bool isUnknownType(object o); + static TypeReference getCommonBaseClass(ModuleDefinition module, TypeReference a, TypeReference b) { if (DotNetUtils.isDelegate(a) && DotNetUtils.derivesFromDelegate(DotNetUtils.getType(module, b))) return b; @@ -561,4 +603,36 @@ namespace de4dot.code.deobfuscators { return null; //TODO: } } + + class TypesRestorer : TypesRestorerBase { + public TypesRestorer(ModuleDefinition module) + : base(module) { + } + + protected override bool isValidType(IGenericParameterProvider gpp, TypeReference type) { + if (type == null) + return false; + if (type.IsValueType) + return false; + if (MemberReferenceHelper.isSystemObject(type)) + return false; + return base.isValidType(gpp, type); + } + + protected override bool isUnknownType(object o) { + var arg = o as ParameterDefinition; + if (arg != null) + return MemberReferenceHelper.isSystemObject(arg.ParameterType); + + var field = o as FieldDefinition; + if (field != null) + return MemberReferenceHelper.isSystemObject(field.FieldType); + + var retType = o as MethodReturnType; + if (retType != null) + return MemberReferenceHelper.isSystemObject(retType.ReturnType); + + throw new ApplicationException(string.Format("Unknown type: {0}", o.GetType())); + } + } }