Remove old cflow deobfuscator code

This commit is contained in:
de4dot 2011-10-21 20:35:13 +02:00
parent 9063a62325
commit 2ff8a0ea7a
7 changed files with 5 additions and 415 deletions

View File

@ -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<int>();
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)

View File

@ -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<ScopeBlock> getAllScopeBlocks(ScopeBlock scopeBlock) {
var list = new List<ScopeBlock>();
list.Add(scopeBlock);

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.blocks {
abstract class CondBranchDeobfuscator {
ScopeBlock scopeBlock;
IEnumerable<Block> blocks;
public CondBranchDeobfuscator(ScopeBlock scopeBlock, IEnumerable<Block> 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<Block>();
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>(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<Instr> 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<Block> blocks)
: base(scopeBlock, blocks) {
}
protected override bool isTaken(int value) {
return value == 0;
}
}
class BrTrueDeobfuscator : CondBranchDeobfuscator {
public BrTrueDeobfuscator(ScopeBlock scopeBlock, IEnumerable<Block> blocks)
: base(scopeBlock, blocks) {
}
protected override bool isTaken(int value) {
return value != 0;
}
}
}

View File

@ -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) {

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using Mono.Cecil.Cil;
namespace de4dot.blocks {
class SwitchControlFlowDeobfuscator {
Blocks blocks;
Dictionary<Block, bool> foundBlocks = new Dictionary<Block, bool>();
class SwitchObfuscationInfo {
public Block switchBlock;
public VariableDefinition stateVar;
Func<Instr, VariableDefinition> getLocalVar;
Dictionary<Block, bool> switchTargetBlocks = new Dictionary<Block, bool>();
public IEnumerable<Block> SwitchTargetBlocks {
get { return switchTargetBlocks.Keys; }
}
internal SwitchObfuscationInfo(Func<Instr, VariableDefinition> 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<Block>(switchTargetBlocks.Keys)) {
foreach (var block in new List<Block>(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<Block>(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;
}
}
}

View File

@ -48,7 +48,6 @@
<Compile Include="cflow\Value.cs" />
<Compile Include="cflow\ValueStack.cs" />
<Compile Include="CodeGenerator.cs" />
<Compile Include="CondBranchDeobfuscator.cs" />
<Compile Include="cflow\BlocksCflowDeobfuscator.cs" />
<Compile Include="DeadBlocksRemover.cs" />
<Compile Include="DotNetUtils.cs" />
@ -62,7 +61,6 @@
<Compile Include="MethodBlocks.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ScopeBlock.cs" />
<Compile Include="SwitchControlFlowDeobfuscator.cs" />
<Compile Include="TryBlock.cs" />
<Compile Include="TryHandlerBlock.cs" />
<Compile Include="Utils.cs" />

View File

@ -464,8 +464,6 @@ namespace de4dot {
}
deobfuscateStrings(blocks);
deob.deobfuscateMethodEnd(blocks);
if (options.ControlFlowDeobfuscation)
blocks.deobfuscateLeaveObfuscation();
IList<Instruction> allInstructions;
IList<ExceptionHandler> 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) {