From 2ff8a0ea7a4e58a91518ee68da9eca19875c0e07 Mon Sep 17 00:00:00 2001 From: de4dot Date: Fri, 21 Oct 2011 20:35:13 +0200 Subject: [PATCH] Remove old cflow deobfuscator code --- blocks/Block.cs | 36 ------ blocks/Blocks.cs | 20 ---- blocks/CondBranchDeobfuscator.cs | 104 ----------------- blocks/ScopeBlock.cs | 107 ------------------ blocks/SwitchControlFlowDeobfuscator.cs | 143 ------------------------ blocks/blocks.csproj | 2 - de4dot.code/ObfuscatedFile.cs | 8 +- 7 files changed, 5 insertions(+), 415 deletions(-) delete mode 100644 blocks/CondBranchDeobfuscator.cs delete mode 100644 blocks/SwitchControlFlowDeobfuscator.cs diff --git a/blocks/Block.cs b/blocks/Block.cs index 5f0d449b..92a9a19b 100644 --- a/blocks/Block.cs +++ b/blocks/Block.cs @@ -112,42 +112,6 @@ namespace de4dot.blocks { remove(index, 1); } - // Removes all instructions that do nothing, nop and eg. ldc/pop, etc. - public bool removeNops() { - bool removed = false; - - bool keepLooping = true; - while (keepLooping) { - var instrsToRemove = new List(); - for (int i = 0; i < Instructions.Count; i++) { - var instr = Instructions[i]; - if (instr.OpCode.Code == Code.Nop) { - // The nop instruction is auto created when we access LastInstr so - // make we don't get an infinite loop. - if (Instructions.Count != 1) - instrsToRemove.Add(i); - continue; - } - if (i + 1 >= Instructions.Count) - continue; - var next = Instructions[i + 1]; - if (instr.isSimpleLoad() && next.isPop()) { - instrsToRemove.Add(i); - instrsToRemove.Add(i + 1); - i++; - continue; - } - } - keepLooping = instrsToRemove.Count != 0; - if (keepLooping) { - removed = true; - remove(instrsToRemove); - } - } - - return removed; - } - // Replace the last instructions with a branch to target public void replaceLastInstrsWithBranch(int numInstrs, Block target) { if (numInstrs < 0 || numInstrs > instructions.Count) diff --git a/blocks/Blocks.cs b/blocks/Blocks.cs index c1027862..00159489 100644 --- a/blocks/Blocks.cs +++ b/blocks/Blocks.cs @@ -47,26 +47,6 @@ namespace de4dot.blocks { methodBlocks = new InstructionListParser(body.Instructions, body.ExceptionHandlers).parse(); } - public void deobfuscateLeaveObfuscation() { - foreach (var scopeBlock in getAllScopeBlocks(methodBlocks)) - scopeBlock.deobfuscateLeaveObfuscation(); - } - - public int deobfuscate() { - foreach (var scopeBlock in getAllScopeBlocks(methodBlocks)) - scopeBlock.deobfuscate(this); - - int numDeadBlocks = removeDeadBlocks(); - - foreach (var scopeBlock in getAllScopeBlocks(methodBlocks)) { - scopeBlock.mergeBlocks(); - scopeBlock.repartitionBlocks(); - scopeBlock.deobfuscateLeaveObfuscation(); - } - - return numDeadBlocks; - } - IEnumerable getAllScopeBlocks(ScopeBlock scopeBlock) { var list = new List(); list.Add(scopeBlock); diff --git a/blocks/CondBranchDeobfuscator.cs b/blocks/CondBranchDeobfuscator.cs deleted file mode 100644 index eae23edd..00000000 --- a/blocks/CondBranchDeobfuscator.cs +++ /dev/null @@ -1,104 +0,0 @@ -/* - Copyright (C) 2011 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.Cil; -using de4dot.blocks; - -namespace de4dot.blocks { - abstract class CondBranchDeobfuscator { - ScopeBlock scopeBlock; - IEnumerable blocks; - - public CondBranchDeobfuscator(ScopeBlock scopeBlock, IEnumerable blocks) { - this.scopeBlock = scopeBlock; - this.blocks = blocks; - } - - protected abstract bool isTaken(int value); - - public bool deobfuscate() { - bool removed = false; - - int value = 0; - var deadBlocks = new List(); - foreach (var block in blocks) { - if (block.Instructions.Count > 1) { - if (getLdcValue(block.Instructions, block.Instructions.Count - 2, ref value)) { - removed = true; - if (isTaken(value)) { - deadBlocks.Add(block.FallThrough); - block.replaceLastInstrsWithBranch(2, block.Targets[0]); - } - else { - deadBlocks.Add(block.Targets[0]); - block.replaceLastInstrsWithBranch(2, block.FallThrough); - } - } - } - else { - foreach (var source in new List(block.Sources)) { - int count = source.Instructions.Count; - if (count > 0 && getLdcValue(source.Instructions, count - 1, ref value)) { - removed = true; - if (isTaken(value)) - source.replaceLastNonBranchWithBranch(1, block.Targets[0]); - else - source.replaceLastNonBranchWithBranch(1, block.FallThrough); - } - } - deadBlocks.Add(block); - } - } - scopeBlock.removeDeadBlocks(deadBlocks); - - return removed; - } - - bool getLdcValue(IList instrs, int i, ref int value) { - var instr = instrs[i]; - if (instr.OpCode != OpCodes.Dup) - return scopeBlock.getLdcValue(instr, out value); - - if (i == 0) - return false; - return scopeBlock.getLdcValue(instrs[i - 1], out value); - } - } - - class BrFalseDeobfuscator : CondBranchDeobfuscator { - public BrFalseDeobfuscator(ScopeBlock scopeBlock, IEnumerable blocks) - : base(scopeBlock, blocks) { - } - - protected override bool isTaken(int value) { - return value == 0; - } - } - - class BrTrueDeobfuscator : CondBranchDeobfuscator { - public BrTrueDeobfuscator(ScopeBlock scopeBlock, IEnumerable blocks) - : base(scopeBlock, blocks) { - } - - protected override bool isTaken(int value) { - return value != 0; - } - } -} diff --git a/blocks/ScopeBlock.cs b/blocks/ScopeBlock.cs index edf7b6d9..add35eeb 100644 --- a/blocks/ScopeBlock.cs +++ b/blocks/ScopeBlock.cs @@ -81,106 +81,6 @@ namespace de4dot.blocks { return blocks; } - public void deobfuscateLeaveObfuscation() { - foreach (var block in findBlocks()) - deobfuscateLeaveObfuscation(block); - } - - void deobfuscateLeaveObfuscation(Block block) { - var instrs = block.Instructions; - int index = instrs.Count - 1; - if (index <= 0) - return; - var lastInstr = instrs[index]; - if (!lastInstr.isLeave() && lastInstr.OpCode != OpCodes.Endfinally && lastInstr.OpCode != OpCodes.Rethrow) - return; - - int end = index; - int start = end; - if (start <= 0) - return; - while (start > 0) { - var instr = instrs[--start]; - - bool valid = false; - switch (instr.OpCode.Code) { - case Code.Dup: - case Code.Ldarg: - case Code.Ldarg_0: - case Code.Ldarg_1: - case Code.Ldarg_2: - case Code.Ldarg_3: - case Code.Ldarga: - case Code.Ldarga_S: - case Code.Ldarg_S: - case Code.Ldc_I4: - case Code.Ldc_I4_0: - case Code.Ldc_I4_1: - case Code.Ldc_I4_2: - case Code.Ldc_I4_3: - case Code.Ldc_I4_4: - case Code.Ldc_I4_5: - case Code.Ldc_I4_6: - case Code.Ldc_I4_7: - case Code.Ldc_I4_8: - case Code.Ldc_I4_M1: - case Code.Ldc_I4_S: - case Code.Ldc_I8: - case Code.Ldc_R4: - case Code.Ldc_R8: - case Code.Ldftn: - case Code.Ldloc: - case Code.Ldloc_0: - case Code.Ldloc_1: - case Code.Ldloc_2: - case Code.Ldloc_3: - case Code.Ldloca: - case Code.Ldloca_S: - case Code.Ldloc_S: - case Code.Ldnull: - case Code.Ldsfld: - case Code.Ldsflda: - case Code.Ldstr: - case Code.Ldtoken: - case Code.Nop: - valid = true; - break; - } - if (!valid) { - start++; - break; - } - } - - int num = end - start; - if (num > 0) - block.remove(start, num); - } - - public void deobfuscate(Blocks blocks) { - while (true) { - mergeBlocks(); - - bool removed = false; - removed |= removeNops(); - removed |= deobfuscateConditionalBranches(); - if (!removed) - break; - } - - var switchDeobfuscator = new SwitchControlFlowDeobfuscator(blocks); - switchDeobfuscator.deobfuscate(this); - } - - bool removeNops() { - bool removed = false; - - foreach (var block in findBlocks()) - removed |= block.removeNops(); - - return removed; - } - internal bool getLdcValue(Instr instr, out int value) { if (Code.Ldc_I4_0 <= instr.OpCode.Code && instr.OpCode.Code <= Code.Ldc_I4_8) value = instr.OpCode.Code - Code.Ldc_I4_0; @@ -197,13 +97,6 @@ namespace de4dot.blocks { return true; } - bool deobfuscateConditionalBranches() { - bool removed = false; - removed |= new BrFalseDeobfuscator(this, findBlocks((block) => block.LastInstr.isBrfalse())).deobfuscate(); - removed |= new BrTrueDeobfuscator(this, findBlocks((block) => block.LastInstr.isBrtrue())).deobfuscate(); - return removed; - } - // Remove the block if it's a dead block. If it has refs to other dead blocks, those // are also removed. public void removeDeadBlock(Block block) { diff --git a/blocks/SwitchControlFlowDeobfuscator.cs b/blocks/SwitchControlFlowDeobfuscator.cs deleted file mode 100644 index 9fc8b339..00000000 --- a/blocks/SwitchControlFlowDeobfuscator.cs +++ /dev/null @@ -1,143 +0,0 @@ -/* - Copyright (C) 2011 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; -using System.Collections.Generic; -using Mono.Cecil.Cil; - -namespace de4dot.blocks { - class SwitchControlFlowDeobfuscator { - Blocks blocks; - Dictionary foundBlocks = new Dictionary(); - - class SwitchObfuscationInfo { - public Block switchBlock; - public VariableDefinition stateVar; - Func getLocalVar; - Dictionary switchTargetBlocks = new Dictionary(); - - public IEnumerable SwitchTargetBlocks { - get { return switchTargetBlocks.Keys; } - } - - internal SwitchObfuscationInfo(Func getLocalVar) { - this.getLocalVar = getLocalVar; - } - - void findAllSwitchTargetBlocks() { - addSwitchTargetBlock(switchBlock); - } - - void addSwitchTargetBlock(Block block) { - if (switchTargetBlocks.ContainsKey(block)) - return; - switchTargetBlocks[block] = true; - foreach (var source in block.Sources) { - if (isNopBlock(source)) - addSwitchTargetBlock(source); - } - } - - bool isNopBlock(Block block) { - foreach (var instr in block.Instructions) { - if (instr.OpCode.Code != Code.Nop && instr.OpCode.Code != Code.Br && instr.OpCode.Code != Code.Br_S) - return false; - } - - return true; - } - - public void fixSwitchBranches(ScopeBlock scopeBlock) { - findAllSwitchTargetBlocks(); - foreach (var switchTargetBlock in new List(switchTargetBlocks.Keys)) { - foreach (var block in new List(switchTargetBlock.Sources)) { - int numInstrs; - Block switchTarget; - if (getSwitchIndex(block, out numInstrs, out switchTarget)) - block.replaceLastInstrsWithBranch(numInstrs, switchTarget); - } - } - } - - bool getSwitchIndex(Block block, out int numInstrs, out Block switchTarget) { - numInstrs = -1; - switchTarget = null; - - if (block.Instructions.Count < 2) - return false; - - int count = block.Instructions.Count; - if (!block.Instructions[count - 2].isLdcI4()) - return false; - if (!block.Instructions[count - 1].isStloc() || getLocalVar(block.Instructions[count - 1]) != stateVar) - return false; - if (!block.isFallThrough() || !switchTargetBlocks.ContainsKey(block.FallThrough)) - return false; - - int switchIndex = (int)block.Instructions[count - 2].getLdcI4Value(); - if (switchIndex < 0 || switchIndex >= switchBlock.Targets.Count) - return false; - - numInstrs = 2; - switchTarget = switchBlock.Targets[switchIndex]; - - return true; - } - } - - public SwitchControlFlowDeobfuscator(Blocks blocks) { - this.blocks = blocks; - } - - public void deobfuscate(ScopeBlock scopeBlock) { - while (true) { - var switchObfuscationInfo = new SwitchObfuscationInfo((instr) => getLocalVar(instr)); - if (!findSwitchObfuscation(scopeBlock, switchObfuscationInfo)) - break; - switchObfuscationInfo.fixSwitchBranches(scopeBlock); - scopeBlock.removeDeadBlocks(new List(switchObfuscationInfo.SwitchTargetBlocks)); - scopeBlock.mergeBlocks(); - } - } - - VariableDefinition getLocalVar(Instr instr) { - return Instr.getLocalVar(blocks.Locals, instr); - } - - bool findSwitchObfuscation(ScopeBlock scopeBlock, SwitchObfuscationInfo switchObfuscationInfo) { - foreach (var bb in scopeBlock.getBaseBlocks()) { - var block = bb as Block; - if (block == null || foundBlocks.ContainsKey(block)) - continue; - - if (block.Instructions.Count != 2 || !block.Instructions[0].isLdloc() || block.Instructions[1].OpCode != OpCodes.Switch) - continue; - switchObfuscationInfo.switchBlock = block; - switchObfuscationInfo.stateVar = getLocalVar(block.Instructions[0]); - var typeName = switchObfuscationInfo.stateVar.VariableType.FullName; - if (typeName != "System.Int32" && typeName != "System.UInt32") - continue; - - foundBlocks[block] = true; - return true; - } - return false; - } - } -} diff --git a/blocks/blocks.csproj b/blocks/blocks.csproj index 48087935..dcce1e7e 100644 --- a/blocks/blocks.csproj +++ b/blocks/blocks.csproj @@ -48,7 +48,6 @@ - @@ -62,7 +61,6 @@ - diff --git a/de4dot.code/ObfuscatedFile.cs b/de4dot.code/ObfuscatedFile.cs index 9eeed7e2..64e5ea64 100644 --- a/de4dot.code/ObfuscatedFile.cs +++ b/de4dot.code/ObfuscatedFile.cs @@ -464,8 +464,6 @@ namespace de4dot { } deobfuscateStrings(blocks); deob.deobfuscateMethodEnd(blocks); - if (options.ControlFlowDeobfuscation) - blocks.deobfuscateLeaveObfuscation(); IList allInstructions; IList allExceptionHandlers; @@ -737,7 +735,11 @@ namespace de4dot { if (check(method, SimpleDeobFlags.HasDeobfuscated)) return; - deobfuscate(method, "Deobfuscating control flow", (blocks) => blocks.deobfuscate()); + deobfuscate(method, "Deobfuscating control flow", (blocks) => { + var cflowDeobfuscator = new BlocksCflowDeobfuscator(); + cflowDeobfuscator.init(blocks); + cflowDeobfuscator.deobfuscate(); + }); } void ISimpleDeobfuscator.decryptStrings(MethodDefinition method, IDeobfuscator theDeob) {