From 17cee8fe45d3b9ce70f8ca442671f29fcde5509d Mon Sep 17 00:00:00 2001 From: de4dot Date: Mon, 11 Jun 2012 21:19:36 +0200 Subject: [PATCH] Move code to a new BranchEmulator class --- blocks/blocks.csproj | 1 + blocks/cflow/BlockCflowDeobfuscator.cs | 214 ++------------------- blocks/cflow/BranchEmulator.cs | 248 +++++++++++++++++++++++++ 3 files changed, 263 insertions(+), 200 deletions(-) create mode 100644 blocks/cflow/BranchEmulator.cs diff --git a/blocks/blocks.csproj b/blocks/blocks.csproj index 1e3daa86..eff0ba86 100644 --- a/blocks/blocks.csproj +++ b/blocks/blocks.csproj @@ -40,6 +40,7 @@ + diff --git a/blocks/cflow/BlockCflowDeobfuscator.cs b/blocks/cflow/BlockCflowDeobfuscator.cs index d0626866..efc31a05 100644 --- a/blocks/cflow/BlockCflowDeobfuscator.cs +++ b/blocks/cflow/BlockCflowDeobfuscator.cs @@ -18,14 +18,18 @@ */ using System; -using System.Collections.Generic; -using Mono.Cecil; using Mono.Cecil.Cil; namespace de4dot.blocks.cflow { - class BlockCflowDeobfuscator : BlockDeobfuscator { + class BlockCflowDeobfuscator : BlockDeobfuscator, IBranchHandler { Block block; - InstructionEmulator instructionEmulator = new InstructionEmulator(); + InstructionEmulator instructionEmulator; + BranchEmulator branchEmulator; + + public BlockCflowDeobfuscator() { + instructionEmulator = new InstructionEmulator(); + branchEmulator = new BranchEmulator(instructionEmulator, this); + } protected override bool deobfuscate(Block block) { this.block = block; @@ -47,48 +51,7 @@ namespace de4dot.blocks.cflow { return false; } - switch (block.LastInstr.OpCode.Code) { - case Code.Beq: - case Code.Beq_S: return emulate_Beq(); - case Code.Bge: - case Code.Bge_S: return emulate_Bge(); - case Code.Bge_Un: - case Code.Bge_Un_S: return emulate_Bge_Un(); - case Code.Bgt: - case Code.Bgt_S: return emulate_Bgt(); - case Code.Bgt_Un: - case Code.Bgt_Un_S: return emulate_Bgt_Un(); - case Code.Ble: - case Code.Ble_S: return emulate_Ble(); - case Code.Ble_Un: - case Code.Ble_Un_S: return emulate_Ble_Un(); - case Code.Blt: - case Code.Blt_S: return emulate_Blt(); - case Code.Blt_Un: - case Code.Blt_Un_S: return emulate_Blt_Un(); - case Code.Bne_Un: - case Code.Bne_Un_S: return emulate_Bne_Un(); - case Code.Brfalse: - case Code.Brfalse_S:return emulate_Brfalse(); - case Code.Brtrue: - case Code.Brtrue_S: return emulate_Brtrue(); - case Code.Switch: return emulate_Switch(); - - default: - return false; - } - } - - bool emulateBranch(int stackArgs, Bool3 cond) { - if (cond == Bool3.Unknown) - return false; - return emulateBranch(stackArgs, cond == Bool3.True); - } - - bool emulateBranch(int stackArgs, bool isTaken) { - popPushedArgs(stackArgs); - block.replaceBccWithBranch(isTaken); - return true; + return branchEmulator.emulate(block.LastInstr.Instruction); } void popPushedArgs(int stackArgs) { @@ -98,162 +61,13 @@ namespace de4dot.blocks.cflow { block.insert(block.Instructions.Count - 1, Instruction.Create(OpCodes.Pop)); } - bool emulate_Beq() { - var val2 = instructionEmulator.pop(); - var val1 = instructionEmulator.pop(); - - if (val1.isInt32() && val2.isInt32()) - return emulateBranch(2, Int32Value.compareEq((Int32Value)val1, (Int32Value)val2)); - else if (val1.isInt64() && val2.isInt64()) - return emulateBranch(2, Int64Value.compareEq((Int64Value)val1, (Int64Value)val2)); - else if (val1.isNull() && val2.isNull()) - return emulateBranch(2, true); - else - return false; + void IBranchHandler.handleNormal(int stackArgs, bool isTaken) { + popPushedArgs(stackArgs); + block.replaceBccWithBranch(isTaken); } - bool emulate_Bne_Un() { - var val2 = instructionEmulator.pop(); - var val1 = instructionEmulator.pop(); - - if (val1.isInt32() && val2.isInt32()) - return emulateBranch(2, Int32Value.compareNeq((Int32Value)val1, (Int32Value)val2)); - else if (val1.isInt64() && val2.isInt64()) - return emulateBranch(2, Int64Value.compareNeq((Int64Value)val1, (Int64Value)val2)); - else if (val1.isNull() && val2.isNull()) - return emulateBranch(2, false); - else - return false; - } - - bool emulate_Bge() { - var val2 = instructionEmulator.pop(); - var val1 = instructionEmulator.pop(); - - if (val1.isInt32() && val2.isInt32()) - return emulateBranch(2, Int32Value.compareGe((Int32Value)val1, (Int32Value)val2)); - else if (val1.isInt64() && val2.isInt64()) - return emulateBranch(2, Int64Value.compareGe((Int64Value)val1, (Int64Value)val2)); - else - return false; - } - - bool emulate_Bge_Un() { - var val2 = instructionEmulator.pop(); - var val1 = instructionEmulator.pop(); - - if (val1.isInt32() && val2.isInt32()) - return emulateBranch(2, Int32Value.compareGe_Un((Int32Value)val1, (Int32Value)val2)); - else if (val1.isInt64() && val2.isInt64()) - return emulateBranch(2, Int64Value.compareGe_Un((Int64Value)val1, (Int64Value)val2)); - else - return false; - } - - bool emulate_Bgt() { - var val2 = instructionEmulator.pop(); - var val1 = instructionEmulator.pop(); - - if (val1.isInt32() && val2.isInt32()) - return emulateBranch(2, Int32Value.compareGt((Int32Value)val1, (Int32Value)val2)); - else if (val1.isInt64() && val2.isInt64()) - return emulateBranch(2, Int64Value.compareGt((Int64Value)val1, (Int64Value)val2)); - else - return false; - } - - bool emulate_Bgt_Un() { - var val2 = instructionEmulator.pop(); - var val1 = instructionEmulator.pop(); - - if (val1.isInt32() && val2.isInt32()) - return emulateBranch(2, Int32Value.compareGt_Un((Int32Value)val1, (Int32Value)val2)); - else if (val1.isInt64() && val2.isInt64()) - return emulateBranch(2, Int64Value.compareGt_Un((Int64Value)val1, (Int64Value)val2)); - else - return false; - } - - bool emulate_Ble() { - var val2 = instructionEmulator.pop(); - var val1 = instructionEmulator.pop(); - - if (val1.isInt32() && val2.isInt32()) - return emulateBranch(2, Int32Value.compareLe((Int32Value)val1, (Int32Value)val2)); - else if (val1.isInt64() && val2.isInt64()) - return emulateBranch(2, Int64Value.compareLe((Int64Value)val1, (Int64Value)val2)); - else - return false; - } - - bool emulate_Ble_Un() { - var val2 = instructionEmulator.pop(); - var val1 = instructionEmulator.pop(); - - if (val1.isInt32() && val2.isInt32()) - return emulateBranch(2, Int32Value.compareLe_Un((Int32Value)val1, (Int32Value)val2)); - else if (val1.isInt64() && val2.isInt64()) - return emulateBranch(2, Int64Value.compareLe_Un((Int64Value)val1, (Int64Value)val2)); - else - return false; - } - - bool emulate_Blt() { - var val2 = instructionEmulator.pop(); - var val1 = instructionEmulator.pop(); - - if (val1.isInt32() && val2.isInt32()) - return emulateBranch(2, Int32Value.compareLt((Int32Value)val1, (Int32Value)val2)); - else if (val1.isInt64() && val2.isInt64()) - return emulateBranch(2, Int64Value.compareLt((Int64Value)val1, (Int64Value)val2)); - else - return false; - } - - bool emulate_Blt_Un() { - var val2 = instructionEmulator.pop(); - var val1 = instructionEmulator.pop(); - - if (val1.isInt32() && val2.isInt32()) - return emulateBranch(2, Int32Value.compareLt_Un((Int32Value)val1, (Int32Value)val2)); - else if (val1.isInt64() && val2.isInt64()) - return emulateBranch(2, Int64Value.compareLt_Un((Int64Value)val1, (Int64Value)val2)); - else - return false; - } - - bool emulate_Brfalse() { - var val1 = instructionEmulator.pop(); - - if (val1.isInt32()) - return emulateBranch(1, Int32Value.compareFalse((Int32Value)val1)); - else if (val1.isInt64()) - return emulateBranch(1, Int64Value.compareFalse((Int64Value)val1)); - else if (val1.isNull()) - return emulateBranch(1, true); - else - return false; - } - - bool emulate_Brtrue() { - var val1 = instructionEmulator.pop(); - - if (val1.isInt32()) - return emulateBranch(1, Int32Value.compareTrue((Int32Value)val1)); - else if (val1.isInt64()) - return emulateBranch(1, Int64Value.compareTrue((Int64Value)val1)); - else if (val1.isNull()) - return emulateBranch(1, false); - else - return false; - } - - bool emulate_Switch() { - var val1 = instructionEmulator.pop(); - - if (!val1.isInt32()) - return false; - var target = CflowUtils.getSwitchTarget(block.Targets, block.FallThrough, (Int32Value)val1); + bool IBranchHandler.handleSwitch(Int32Value switchIndex) { + var target = CflowUtils.getSwitchTarget(block.Targets, block.FallThrough, switchIndex); if (target == null) return false; diff --git a/blocks/cflow/BranchEmulator.cs b/blocks/cflow/BranchEmulator.cs new file mode 100644 index 00000000..3964cb75 --- /dev/null +++ b/blocks/cflow/BranchEmulator.cs @@ -0,0 +1,248 @@ +/* + 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 Mono.Cecil.Cil; + +namespace de4dot.blocks.cflow { + public interface IBranchHandler { + // stackArgs is the number of args used by the branch instruction (1 or 2) + void handleNormal(int stackArgs, bool isTaken); + + // Returns true if the switch target was found (even if it was the fall-through) + bool handleSwitch(Int32Value switchIndex); + } + + public class BranchEmulator { + IBranchHandler branchHandler; + InstructionEmulator instructionEmulator; + + public BranchEmulator(InstructionEmulator instructionEmulator, IBranchHandler branchHandler) { + this.instructionEmulator = instructionEmulator; + this.branchHandler = branchHandler; + } + + public bool emulate(Instruction instr) { + switch (instr.OpCode.Code) { + case Code.Br: + case Code.Br_S: return emulate_Br(); + case Code.Beq: + case Code.Beq_S: return emulate_Beq(); + case Code.Bge: + case Code.Bge_S: return emulate_Bge(); + case Code.Bge_Un: + case Code.Bge_Un_S: return emulate_Bge_Un(); + case Code.Bgt: + case Code.Bgt_S: return emulate_Bgt(); + case Code.Bgt_Un: + case Code.Bgt_Un_S: return emulate_Bgt_Un(); + case Code.Ble: + case Code.Ble_S: return emulate_Ble(); + case Code.Ble_Un: + case Code.Ble_Un_S: return emulate_Ble_Un(); + case Code.Blt: + case Code.Blt_S: return emulate_Blt(); + case Code.Blt_Un: + case Code.Blt_Un_S: return emulate_Blt_Un(); + case Code.Bne_Un: + case Code.Bne_Un_S: return emulate_Bne_Un(); + case Code.Brfalse: + case Code.Brfalse_S:return emulate_Brfalse(); + case Code.Brtrue: + case Code.Brtrue_S: return emulate_Brtrue(); + case Code.Switch: return emulate_Switch(); + + default: + return false; + } + } + + bool emulateBranch(int stackArgs, Bool3 cond) { + if (cond == Bool3.Unknown) + return false; + return emulateBranch(stackArgs, cond == Bool3.True); + } + + bool emulateBranch(int stackArgs, bool isTaken) { + branchHandler.handleNormal(stackArgs, isTaken); + return true; + } + + bool emulate_Br() { + return emulateBranch(0, true); + } + + bool emulate_Beq() { + var val2 = instructionEmulator.pop(); + var val1 = instructionEmulator.pop(); + + if (val1.isInt32() && val2.isInt32()) + return emulateBranch(2, Int32Value.compareEq((Int32Value)val1, (Int32Value)val2)); + else if (val1.isInt64() && val2.isInt64()) + return emulateBranch(2, Int64Value.compareEq((Int64Value)val1, (Int64Value)val2)); + else if (val1.isNull() && val2.isNull()) + return emulateBranch(2, true); + else + return false; + } + + bool emulate_Bne_Un() { + var val2 = instructionEmulator.pop(); + var val1 = instructionEmulator.pop(); + + if (val1.isInt32() && val2.isInt32()) + return emulateBranch(2, Int32Value.compareNeq((Int32Value)val1, (Int32Value)val2)); + else if (val1.isInt64() && val2.isInt64()) + return emulateBranch(2, Int64Value.compareNeq((Int64Value)val1, (Int64Value)val2)); + else if (val1.isNull() && val2.isNull()) + return emulateBranch(2, false); + else + return false; + } + + bool emulate_Bge() { + var val2 = instructionEmulator.pop(); + var val1 = instructionEmulator.pop(); + + if (val1.isInt32() && val2.isInt32()) + return emulateBranch(2, Int32Value.compareGe((Int32Value)val1, (Int32Value)val2)); + else if (val1.isInt64() && val2.isInt64()) + return emulateBranch(2, Int64Value.compareGe((Int64Value)val1, (Int64Value)val2)); + else + return false; + } + + bool emulate_Bge_Un() { + var val2 = instructionEmulator.pop(); + var val1 = instructionEmulator.pop(); + + if (val1.isInt32() && val2.isInt32()) + return emulateBranch(2, Int32Value.compareGe_Un((Int32Value)val1, (Int32Value)val2)); + else if (val1.isInt64() && val2.isInt64()) + return emulateBranch(2, Int64Value.compareGe_Un((Int64Value)val1, (Int64Value)val2)); + else + return false; + } + + bool emulate_Bgt() { + var val2 = instructionEmulator.pop(); + var val1 = instructionEmulator.pop(); + + if (val1.isInt32() && val2.isInt32()) + return emulateBranch(2, Int32Value.compareGt((Int32Value)val1, (Int32Value)val2)); + else if (val1.isInt64() && val2.isInt64()) + return emulateBranch(2, Int64Value.compareGt((Int64Value)val1, (Int64Value)val2)); + else + return false; + } + + bool emulate_Bgt_Un() { + var val2 = instructionEmulator.pop(); + var val1 = instructionEmulator.pop(); + + if (val1.isInt32() && val2.isInt32()) + return emulateBranch(2, Int32Value.compareGt_Un((Int32Value)val1, (Int32Value)val2)); + else if (val1.isInt64() && val2.isInt64()) + return emulateBranch(2, Int64Value.compareGt_Un((Int64Value)val1, (Int64Value)val2)); + else + return false; + } + + bool emulate_Ble() { + var val2 = instructionEmulator.pop(); + var val1 = instructionEmulator.pop(); + + if (val1.isInt32() && val2.isInt32()) + return emulateBranch(2, Int32Value.compareLe((Int32Value)val1, (Int32Value)val2)); + else if (val1.isInt64() && val2.isInt64()) + return emulateBranch(2, Int64Value.compareLe((Int64Value)val1, (Int64Value)val2)); + else + return false; + } + + bool emulate_Ble_Un() { + var val2 = instructionEmulator.pop(); + var val1 = instructionEmulator.pop(); + + if (val1.isInt32() && val2.isInt32()) + return emulateBranch(2, Int32Value.compareLe_Un((Int32Value)val1, (Int32Value)val2)); + else if (val1.isInt64() && val2.isInt64()) + return emulateBranch(2, Int64Value.compareLe_Un((Int64Value)val1, (Int64Value)val2)); + else + return false; + } + + bool emulate_Blt() { + var val2 = instructionEmulator.pop(); + var val1 = instructionEmulator.pop(); + + if (val1.isInt32() && val2.isInt32()) + return emulateBranch(2, Int32Value.compareLt((Int32Value)val1, (Int32Value)val2)); + else if (val1.isInt64() && val2.isInt64()) + return emulateBranch(2, Int64Value.compareLt((Int64Value)val1, (Int64Value)val2)); + else + return false; + } + + bool emulate_Blt_Un() { + var val2 = instructionEmulator.pop(); + var val1 = instructionEmulator.pop(); + + if (val1.isInt32() && val2.isInt32()) + return emulateBranch(2, Int32Value.compareLt_Un((Int32Value)val1, (Int32Value)val2)); + else if (val1.isInt64() && val2.isInt64()) + return emulateBranch(2, Int64Value.compareLt_Un((Int64Value)val1, (Int64Value)val2)); + else + return false; + } + + bool emulate_Brfalse() { + var val1 = instructionEmulator.pop(); + + if (val1.isInt32()) + return emulateBranch(1, Int32Value.compareFalse((Int32Value)val1)); + else if (val1.isInt64()) + return emulateBranch(1, Int64Value.compareFalse((Int64Value)val1)); + else if (val1.isNull()) + return emulateBranch(1, true); + else + return false; + } + + bool emulate_Brtrue() { + var val1 = instructionEmulator.pop(); + + if (val1.isInt32()) + return emulateBranch(1, Int32Value.compareTrue((Int32Value)val1)); + else if (val1.isInt64()) + return emulateBranch(1, Int64Value.compareTrue((Int64Value)val1)); + else if (val1.isNull()) + return emulateBranch(1, false); + else + return false; + } + + bool emulate_Switch() { + var val1 = instructionEmulator.pop(); + + if (!val1.isInt32()) + return false; + return branchHandler.handleSwitch((Int32Value)val1); + } + } +}