From 98936364f729ed5030d91a2d4fd23c39c3424896 Mon Sep 17 00:00:00 2001 From: de4dot Date: Tue, 18 Oct 2011 08:17:21 +0200 Subject: [PATCH] Add code to emulate switch and ldelem --- blocks/Block.cs | 6 ++++ blocks/cflow/BlockControlFlowDeobfuscator.cs | 32 ++++++++++++++++++-- blocks/cflow/InstructionEmulator.cs | 8 ++--- blocks/cflow/Int32Value.cs | 2 +- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/blocks/Block.cs b/blocks/Block.cs index efc30ccc..665c94fe 100644 --- a/blocks/Block.cs +++ b/blocks/Block.cs @@ -173,6 +173,12 @@ namespace de4dot.blocks { replaceLastInstrsWithBranch(1, target); } + public void replaceSwitchWithBranch(Block target) { + if (LastInstr.OpCode.Code != Code.Switch) + throw new ApplicationException("Last instruction is not a switch"); + replaceLastInstrsWithBranch(1, target); + } + public void removeDeadBlock() { if (sources.Count != 0) throw new ApplicationException("Trying to remove a non-dead block"); diff --git a/blocks/cflow/BlockControlFlowDeobfuscator.cs b/blocks/cflow/BlockControlFlowDeobfuscator.cs index acb457fd..e97ccce2 100644 --- a/blocks/cflow/BlockControlFlowDeobfuscator.cs +++ b/blocks/cflow/BlockControlFlowDeobfuscator.cs @@ -65,6 +65,7 @@ namespace de4dot.blocks.cflow { 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; @@ -78,13 +79,16 @@ namespace de4dot.blocks.cflow { } bool emulateBranch(int stackArgs, bool isTaken) { + popPushedArgs(stackArgs); + block.replaceBccWithBranch(isTaken); + return true; + } + + void popPushedArgs(int stackArgs) { // Pop the arguments to the bcc instruction. The dead code remover will get rid of the // pop and any pushed arguments. Insert the pops just before the bcc instr. for (int i = 0; i < stackArgs; i++) block.insert(block.Instructions.Count - 1, Instruction.Create(OpCodes.Pop)); - - block.replaceBccWithBranch(isTaken); - return true; } bool emulate_Beq() { @@ -236,5 +240,27 @@ namespace de4dot.blocks.cflow { else return false; } + + bool emulate_Switch() { + var val1 = instructionEmulator.pop(); + + if (val1.valueType != ValueType.Int32) + return false; + + var int1 = (Int32Value)val1; + if (!int1.allBitsValid()) + return false; + + int index = int1.value; + var targets = block.Targets; + Block newTarget; + if (targets == null || index < 0 || index >= targets.Count) + newTarget = block.FallThrough; + else + newTarget = targets[index]; + popPushedArgs(1); + block.replaceSwitchWithBranch(newTarget); + return true; + } } } diff --git a/blocks/cflow/InstructionEmulator.cs b/blocks/cflow/InstructionEmulator.cs index 4328bd2a..bf114aef 100644 --- a/blocks/cflow/InstructionEmulator.cs +++ b/blocks/cflow/InstructionEmulator.cs @@ -230,11 +230,11 @@ namespace de4dot.blocks.cflow { case Code.Castclass: emulate_Castclass(instr); break; case Code.Isinst: emulate_Isinst(instr); break; - case Code.Add_Ovf: emulateIntOps2(); break; + case Code.Add_Ovf: emulateIntOps2(); break; case Code.Add_Ovf_Un: emulateIntOps2(); break; - case Code.Sub_Ovf: emulateIntOps2(); break; + case Code.Sub_Ovf: emulateIntOps2(); break; case Code.Sub_Ovf_Un: emulateIntOps2(); break; - case Code.Mul_Ovf: emulateIntOps2(); break; + case Code.Mul_Ovf: emulateIntOps2(); break; case Code.Mul_Ovf_Un: emulateIntOps2(); break; case Code.Conv_Ovf_I1: @@ -261,6 +261,7 @@ namespace de4dot.blocks.cflow { case Code.Ldelem_U1: valueStack.pop(2); valueStack.push(Int32Value.createUnknownUInt8()); break; case Code.Ldelem_U2: valueStack.pop(2); valueStack.push(Int32Value.createUnknownUInt16()); break; case Code.Ldelem_U4: valueStack.pop(2); valueStack.push(Int32Value.createUnknown()); break; + case Code.Ldelem_Any:valueStack.pop(2); valueStack.push(getUnknownValue(instr.Operand as TypeReference)); break; case Code.Ldind_I1: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; case Code.Ldind_I2: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; @@ -327,7 +328,6 @@ namespace de4dot.blocks.cflow { case Code.Initobj: case Code.Jmp: case Code.Ldelema: - case Code.Ldelem_Any: case Code.Ldelem_I: case Code.Ldelem_R4: case Code.Ldelem_R8: diff --git a/blocks/cflow/Int32Value.cs b/blocks/cflow/Int32Value.cs index ce2fc529..1de51bd8 100644 --- a/blocks/cflow/Int32Value.cs +++ b/blocks/cflow/Int32Value.cs @@ -41,7 +41,7 @@ namespace de4dot.blocks.cflow { return validMask != NO_UNKNOWN_BITS; } - bool allBitsValid() { + public bool allBitsValid() { return !hasUnknownBits(); }