From 0adbb3e70a1c08ec5306ce3b85eb326a8d1c6e5f Mon Sep 17 00:00:00 2001 From: de4dot Date: Thu, 5 Apr 2012 17:11:24 +0200 Subject: [PATCH] Move code to a new class --- de4dot.code/de4dot.code.csproj | 1 + de4dot.code/deobfuscators/MethodStack.cs | 258 +++++++++++++++++++++ de4dot.code/deobfuscators/TypesRestorer.cs | 227 +----------------- 3 files changed, 268 insertions(+), 218 deletions(-) create mode 100644 de4dot.code/deobfuscators/MethodStack.cs diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index f2557242..80749f97 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -169,6 +169,7 @@ + diff --git a/de4dot.code/deobfuscators/MethodStack.cs b/de4dot.code/deobfuscators/MethodStack.cs new file mode 100644 index 00000000..0b56256d --- /dev/null +++ b/de4dot.code/deobfuscators/MethodStack.cs @@ -0,0 +1,258 @@ +/* + Copyright (C) 2011-2012 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 Mono.Cecil; +using Mono.Cecil.Cil; +using de4dot.blocks; + +namespace de4dot.code.deobfuscators { + class PushedArgs { + List args; + int nextIndex; + + public bool CanAddMore { + get { return nextIndex >= 0; } + } + + public int NumValidArgs { + get { return args.Count - (nextIndex + 1); } + } + + public PushedArgs(int numArgs) { + nextIndex = numArgs - 1; + args = new List(numArgs); + for (int i = 0; i < numArgs; i++) + args.Add(null); + } + + public void add(Instruction instr) { + args[nextIndex--] = instr; + } + + public void set(int i, Instruction instr) { + args[i] = instr; + } + + public Instruction get(int i) { + if (0 <= i && i < args.Count) + return args[i]; + return null; + } + + public Instruction getEnd(int i) { + return get(args.Count - 1 - i); + } + + public void fixDups() { + Instruction prev = null, instr; + for (int i = 0; i < NumValidArgs; i++, prev = instr) { + instr = args[i]; + if (instr == null || prev == null) + continue; + if (instr.OpCode.Code != Code.Dup) + continue; + args[i] = prev; + instr = prev; + } + } + } + + static class MethodStack { + // May not return all args. The args are returned in reverse order. + public static PushedArgs getPushedArgInstructions(IList instructions, int index) { + try { + int pushes, pops; + DotNetUtils.calculateStackUsage(instructions[index], false, out pushes, out pops); + if (pops != -1) + return getPushedArgInstructions(instructions, index, pops); + } + catch (System.NullReferenceException) { + // Here if eg. invalid metadata token in a call instruction (operand is null) + } + return new PushedArgs(0); + } + + // May not return all args. The args are returned in reverse order. + static PushedArgs getPushedArgInstructions(IList instructions, int index, int numArgs) { + var pushedArgs = new PushedArgs(numArgs); + + Instruction instr; + int skipPushes = 0; + while (index >= 0 && pushedArgs.CanAddMore) { + instr = getPreviousInstruction(instructions, ref index); + if (instr == null) + break; + + int pushes, pops; + DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops); + if (pops == -1) + break; + if (instr.OpCode.Code == Code.Dup) { + pushes = 1; + pops = 0; + } + if (pushes > 1) + break; + + if (skipPushes > 0) { + skipPushes -= pushes; + if (skipPushes < 0) + break; + skipPushes += pops; + } + else { + if (pushes == 1) + pushedArgs.add(instr); + skipPushes += pops; + } + } + instr = pushedArgs.get(0); + if (instr != null && instr.OpCode.Code == Code.Dup) { + instr = getPreviousInstruction(instructions, ref index); + if (instr != null) { + int pushes, pops; + DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops); + if (pushes == 1 && pops == 0) + pushedArgs.set(0, instr); + } + } + pushedArgs.fixDups(); + + return pushedArgs; + } + + public static TypeReference getLoadedType(MethodDefinition method, IList instructions, int instrIndex) { + bool wasNewobj; + return getLoadedType(method, instructions, instrIndex, 0, out wasNewobj); + } + + public static TypeReference getLoadedType(MethodDefinition method, IList instructions, int instrIndex, int argIndexFromEnd) { + bool wasNewobj; + return getLoadedType(method, instructions, instrIndex, argIndexFromEnd, out wasNewobj); + } + + public static TypeReference getLoadedType(MethodDefinition method, IList instructions, int instrIndex, out bool wasNewobj) { + return getLoadedType(method, instructions, instrIndex, 0, out wasNewobj); + } + + public static TypeReference getLoadedType(MethodDefinition method, IList instructions, int instrIndex, int argIndexFromEnd, out bool wasNewobj) { + wasNewobj = false; + var pushedArgs = MethodStack.getPushedArgInstructions(instructions, instrIndex); + var pushInstr = pushedArgs.getEnd(argIndexFromEnd); + if (pushInstr == null) + return null; + + TypeReference fieldType; + switch (pushInstr.OpCode.Code) { + case Code.Ldstr: + fieldType = method.Module.TypeSystem.String; + break; + + case Code.Call: + case Code.Calli: + case Code.Callvirt: + var calledMethod = pushInstr.Operand as MethodReference; + if (calledMethod == null) + return null; + fieldType = calledMethod.MethodReturnType.ReturnType; + break; + + case Code.Newarr: + fieldType = pushInstr.Operand as TypeReference; + if (fieldType == null) + return null; + fieldType = new ArrayType(fieldType); + wasNewobj = true; + break; + + case Code.Newobj: + var ctor = pushInstr.Operand as MethodReference; + if (ctor == null) + return null; + fieldType = ctor.DeclaringType; + wasNewobj = true; + break; + + case Code.Castclass: + case Code.Isinst: + fieldType = pushInstr.Operand as TypeReference; + break; + + case Code.Ldarg: + case Code.Ldarg_S: + case Code.Ldarg_0: + case Code.Ldarg_1: + case Code.Ldarg_2: + case Code.Ldarg_3: + fieldType = DotNetUtils.getArgType(method, pushInstr); + break; + + case Code.Ldloc: + case Code.Ldloc_S: + case Code.Ldloc_0: + case Code.Ldloc_1: + case Code.Ldloc_2: + case Code.Ldloc_3: + var local = DotNetUtils.getLocalVar(method.Body.Variables, pushInstr); + if (local == null) + return null; + fieldType = local.VariableType; + break; + + case Code.Ldfld: + case Code.Ldsfld: + var field2 = pushInstr.Operand as FieldReference; + if (field2 == null) + return null; + fieldType = field2.FieldType; + break; + + case Code.Ldelema: + fieldType = pushInstr.Operand as TypeReference; + break; + + default: + return null; + } + + return fieldType; + } + + static Instruction getPreviousInstruction(IList instructions, ref int instrIndex) { + while (true) { + instrIndex--; + if (instrIndex < 0) + return null; + var instr = instructions[instrIndex]; + if (instr.OpCode.Code == Code.Nop) + continue; + if (instr.OpCode.OpCodeType == OpCodeType.Prefix) + continue; + switch (instr.OpCode.FlowControl) { + case FlowControl.Next: + case FlowControl.Call: + return instr; + default: + return null; + } + } + } + } +} diff --git a/de4dot.code/deobfuscators/TypesRestorer.cs b/de4dot.code/deobfuscators/TypesRestorer.cs index 7328913d..46ffe4b7 100644 --- a/de4dot.code/deobfuscators/TypesRestorer.cs +++ b/de4dot.code/deobfuscators/TypesRestorer.cs @@ -214,57 +214,6 @@ namespace de4dot.code.deobfuscators { return Utils.compareInt32(a.arg.Sequence, b.arg.Sequence); } - class PushedArgs { - List args; - int nextIndex; - - public bool CanAddMore { - get { return nextIndex >= 0; } - } - - public int NumValidArgs { - get { return args.Count - (nextIndex + 1); } - } - - public PushedArgs(int numArgs) { - nextIndex = numArgs - 1; - args = new List(numArgs); - for (int i = 0; i < numArgs; i++) - args.Add(null); - } - - public void add(Instruction instr) { - args[nextIndex--] = instr; - } - - public void set(int i, Instruction instr) { - args[i] = instr; - } - - public Instruction get(int i) { - if (0 <= i && i < args.Count) - return args[i]; - return null; - } - - public Instruction getEnd(int i) { - return get(args.Count - 1 - i); - } - - public void fixDups() { - Instruction prev = null, instr; - for (int i = 0; i < NumValidArgs; i++, prev = instr) { - instr = args[i]; - if (instr == null || prev == null) - continue; - if (instr.OpCode.Code != Code.Dup) - continue; - args[i] = prev; - instr = prev; - } - } - } - void deobfuscateMethod(MethodDefinition method) { if (!method.IsStatic || method.Body == null) return; @@ -302,7 +251,7 @@ namespace de4dot.code.deobfuscators { case Code.Calli: case Code.Callvirt: case Code.Newobj: - pushedArgs = getPushedArgInstructions(instructions, i); + pushedArgs = MethodStack.getPushedArgInstructions(instructions, i); var calledMethod = instr.Operand as MethodReference; if (calledMethod == null) break; @@ -327,7 +276,7 @@ namespace de4dot.code.deobfuscators { break; case Code.Castclass: - pushedArgs = getPushedArgInstructions(instructions, i); + pushedArgs = MethodStack.getPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs < 1) break; addMethodArgType(getParameter(methodParams, pushedArgs.getEnd(0)), instr.Operand as TypeReference); @@ -339,21 +288,21 @@ namespace de4dot.code.deobfuscators { case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: - pushedArgs = getPushedArgInstructions(instructions, i); + pushedArgs = MethodStack.getPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs < 1) break; addMethodArgType(getParameter(methodParams, pushedArgs.getEnd(0)), DotNetUtils.getLocalVar(method.Body.Variables, instr)); break; case Code.Stsfld: - pushedArgs = getPushedArgInstructions(instructions, i); + pushedArgs = MethodStack.getPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs < 1) break; addMethodArgType(getParameter(methodParams, pushedArgs.getEnd(0)), instr.Operand as FieldReference); break; case Code.Stfld: - pushedArgs = getPushedArgInstructions(instructions, i); + pushedArgs = MethodStack.getPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs >= 1) { var field = instr.Operand as FieldReference; addMethodArgType(getParameter(methodParams, pushedArgs.getEnd(0)), field); @@ -364,7 +313,7 @@ namespace de4dot.code.deobfuscators { case Code.Ldfld: case Code.Ldflda: - pushedArgs = getPushedArgInstructions(instructions, i); + pushedArgs = MethodStack.getPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs < 1) break; addMethodArgType(getParameter(methodParams, pushedArgs.getEnd(0)), instr.Operand as FieldReference); @@ -478,69 +427,6 @@ namespace de4dot.code.deobfuscators { return true; } - // May not return all args. The args are returned in reverse order. - PushedArgs getPushedArgInstructions(IList instructions, int index) { - try { - int pushes, pops; - DotNetUtils.calculateStackUsage(instructions[index], false, out pushes, out pops); - if (pops != -1) - return getPushedArgInstructions(instructions, index, pops); - } - catch (System.NullReferenceException) { - // Here if eg. invalid metadata token in a call instruction (operand is null) - } - return new PushedArgs(0); - } - - // May not return all args. The args are returned in reverse order. - PushedArgs getPushedArgInstructions(IList instructions, int index, int numArgs) { - var pushedArgs = new PushedArgs(numArgs); - - Instruction instr; - int skipPushes = 0; - while (index >= 0 && pushedArgs.CanAddMore) { - instr = getPreviousInstruction(instructions, ref index); - if (instr == null) - break; - - int pushes, pops; - DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops); - if (pops == -1) - break; - if (instr.OpCode.Code == Code.Dup) { - pushes = 1; - pops = 0; - } - if (pushes > 1) - break; - - if (skipPushes > 0) { - skipPushes -= pushes; - if (skipPushes < 0) - break; - skipPushes += pops; - } - else { - if (pushes == 1) - pushedArgs.add(instr); - skipPushes += pops; - } - } - instr = pushedArgs.get(0); - if (instr != null && instr.OpCode.Code == Code.Dup) { - instr = getPreviousInstruction(instructions, ref index); - if (instr != null) { - int pushes, pops; - DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops); - if (pushes == 1 && pops == 0) - pushedArgs.set(0, instr); - } - } - pushedArgs.fixDups(); - - return pushedArgs; - } - bool deobfuscateFields() { foreach (var info in fieldWrites.Values) info.clear(); @@ -573,7 +459,7 @@ namespace de4dot.code.deobfuscators { case Code.Calli: case Code.Callvirt: case Code.Newobj: - var pushedArgs = getPushedArgInstructions(instructions, i); + var pushedArgs = MethodStack.getPushedArgInstructions(instructions, i); var calledMethod = instr.Operand as MethodReference; if (calledMethod == null) continue; @@ -618,84 +504,9 @@ namespace de4dot.code.deobfuscators { } TypeReference getLoadedType(MethodDefinition method, IList instructions, int instrIndex, out bool wasNewobj) { - wasNewobj = false; - var pushedArgs = getPushedArgInstructions(instructions, instrIndex); - var pushInstr = pushedArgs.getEnd(0); - if (pushInstr == null) + var fieldType = MethodStack.getLoadedType(method, instructions, instrIndex, out wasNewobj); + if (fieldType == null || !isValidType(fieldType)) return null; - - TypeReference fieldType; - switch (pushInstr.OpCode.Code) { - case Code.Ldstr: - fieldType = module.TypeSystem.String; - break; - - case Code.Call: - case Code.Calli: - case Code.Callvirt: - var calledMethod = pushInstr.Operand as MethodReference; - if (calledMethod == null) - return null; - fieldType = calledMethod.MethodReturnType.ReturnType; - break; - - case Code.Newarr: - fieldType = pushInstr.Operand as TypeReference; - if (fieldType == null) - return null; - fieldType = new ArrayType(fieldType); - wasNewobj = true; - break; - - case Code.Newobj: - var ctor = pushInstr.Operand as MethodReference; - if (ctor == null) - return null; - fieldType = ctor.DeclaringType; - wasNewobj = true; - break; - - case Code.Castclass: - case Code.Isinst: - fieldType = pushInstr.Operand as TypeReference; - break; - - case Code.Ldarg: - case Code.Ldarg_S: - case Code.Ldarg_0: - case Code.Ldarg_1: - case Code.Ldarg_2: - case Code.Ldarg_3: - fieldType = DotNetUtils.getArgType(method, pushInstr); - break; - - case Code.Ldloc: - case Code.Ldloc_S: - case Code.Ldloc_0: - case Code.Ldloc_1: - case Code.Ldloc_2: - case Code.Ldloc_3: - var local = DotNetUtils.getLocalVar(method.Body.Variables, pushInstr); - if (local == null) - return null; - fieldType = local.VariableType; - break; - - case Code.Ldfld: - case Code.Ldsfld: - var field2 = pushInstr.Operand as FieldReference; - if (field2 == null) - return null; - fieldType = field2.FieldType; - break; - - default: - return null; - } - - if (!isValidType(fieldType)) - return null; - return fieldType; } @@ -744,25 +555,5 @@ namespace de4dot.code.deobfuscators { return a; return null; //TODO: } - - static Instruction getPreviousInstruction(IList instructions, ref int instrIndex) { - while (true) { - instrIndex--; - if (instrIndex < 0) - return null; - var instr = instructions[instrIndex]; - if (instr.OpCode.Code == Code.Nop) - continue; - if (instr.OpCode.OpCodeType == OpCodeType.Prefix) - continue; - switch (instr.OpCode.FlowControl) { - case FlowControl.Next: - case FlowControl.Call: - return instr; - default: - return null; - } - } - } } }