Remove old cflow deobfuscator code
This commit is contained in:
parent
9063a62325
commit
2ff8a0ea7a
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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" />
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user