Start work on new cflow deobfuscator
This commit is contained in:
parent
b6a994700c
commit
05065d6ac7
|
@ -168,6 +168,11 @@ namespace de4dot.blocks {
|
|||
replaceLastInstrsWithBranch(numInstrs, target);
|
||||
}
|
||||
|
||||
public void replaceBccWithBranch(bool isTaken) {
|
||||
Block target = isTaken ? targets[0] : fallThrough;
|
||||
replaceLastInstrsWithBranch(1, target);
|
||||
}
|
||||
|
||||
public void removeDeadBlock() {
|
||||
if (sources.Count != 0)
|
||||
throw new ApplicationException("Trying to remove a non-dead block");
|
||||
|
|
123
blocks/Blocks.cs
123
blocks/Blocks.cs
|
@ -74,131 +74,10 @@ namespace de4dot.blocks {
|
|||
return list;
|
||||
}
|
||||
|
||||
int removeDeadBlocks() {
|
||||
public int removeDeadBlocks() {
|
||||
return new DeadBlocksRemover(methodBlocks).remove();
|
||||
}
|
||||
|
||||
class DeadBlocksRemover {
|
||||
MethodBlocks methodBlocks;
|
||||
Dictionary<BaseBlock, bool> checkedBaseBlocks = new Dictionary<BaseBlock, bool>();
|
||||
Dictionary<ScopeBlock, bool> checkedScopeBlocks = new Dictionary<ScopeBlock, bool>();
|
||||
Stack<BaseBlock> baseBlocksToCheck = new Stack<BaseBlock>();
|
||||
Stack<ScopeBlock> scopeBlocksToCheck = new Stack<ScopeBlock>();
|
||||
|
||||
public DeadBlocksRemover(MethodBlocks methodBlocks) {
|
||||
this.methodBlocks = methodBlocks;
|
||||
}
|
||||
|
||||
public int remove() {
|
||||
addScopeBlock(methodBlocks);
|
||||
processAll();
|
||||
return removeDeadBlocks();
|
||||
}
|
||||
|
||||
class ScopeBlockInfo {
|
||||
public ScopeBlock scopeBlock;
|
||||
public IList<BaseBlock> deadBlocks = new List<BaseBlock>();
|
||||
public ScopeBlockInfo(ScopeBlock scopeBlock) {
|
||||
this.scopeBlock = scopeBlock;
|
||||
}
|
||||
}
|
||||
|
||||
int removeDeadBlocks() {
|
||||
int numDeadBlocks = 0;
|
||||
|
||||
var infos = new Dictionary<ScopeBlock, ScopeBlockInfo>();
|
||||
var deadBlocksDict = new Dictionary<BaseBlock, bool>();
|
||||
foreach (var baseBlock in findDeadBlocks()) {
|
||||
deadBlocksDict[baseBlock] = true;
|
||||
ScopeBlock parent = (ScopeBlock)baseBlock.Parent;
|
||||
ScopeBlockInfo info;
|
||||
if (!infos.TryGetValue(parent, out info))
|
||||
infos[parent] = info = new ScopeBlockInfo(parent);
|
||||
info.deadBlocks.Add(baseBlock);
|
||||
numDeadBlocks++;
|
||||
}
|
||||
|
||||
foreach (var info in infos.Values)
|
||||
info.scopeBlock.removeAllDeadBlocks(info.deadBlocks, deadBlocksDict);
|
||||
|
||||
return numDeadBlocks;
|
||||
}
|
||||
|
||||
IList<BaseBlock> findDeadBlocks() {
|
||||
var deadBlocks = new List<BaseBlock>();
|
||||
|
||||
foreach (var bb in methodBlocks.getAllBaseBlocks()) {
|
||||
if (!checkedBaseBlocks.ContainsKey(bb))
|
||||
deadBlocks.Add(bb);
|
||||
}
|
||||
|
||||
return deadBlocks;
|
||||
}
|
||||
|
||||
void addScopeBlock(ScopeBlock scopeBlock) {
|
||||
scopeBlocksToCheck.Push(scopeBlock);
|
||||
}
|
||||
|
||||
void processAll() {
|
||||
bool didSomething;
|
||||
do {
|
||||
didSomething = false;
|
||||
while (baseBlocksToCheck.Count > 0) {
|
||||
processBaseBlock(baseBlocksToCheck.Pop());
|
||||
didSomething = true;
|
||||
}
|
||||
while (scopeBlocksToCheck.Count > 0) {
|
||||
processScopeBlock(scopeBlocksToCheck.Pop());
|
||||
didSomething = true;
|
||||
}
|
||||
} while (didSomething);
|
||||
}
|
||||
|
||||
void processBaseBlock(BaseBlock baseBlock) {
|
||||
if (baseBlock == null || checkedBaseBlocks.ContainsKey(baseBlock))
|
||||
return;
|
||||
checkedBaseBlocks[baseBlock] = true;
|
||||
|
||||
if (baseBlock is Block) {
|
||||
var block = (Block)baseBlock;
|
||||
foreach (var block2 in block.getTargets())
|
||||
addBaseBlock(block2);
|
||||
}
|
||||
else if (baseBlock is ScopeBlock) {
|
||||
var scopeBlock = (ScopeBlock)baseBlock;
|
||||
addScopeBlock(scopeBlock);
|
||||
if (scopeBlock.BaseBlocks != null && scopeBlock.BaseBlocks.Count > 0)
|
||||
addBaseBlock(scopeBlock.BaseBlocks[0]);
|
||||
}
|
||||
else
|
||||
throw new ApplicationException(string.Format("Unknown BaseBlock type {0}", baseBlock.GetType()));
|
||||
}
|
||||
|
||||
// Add a block to be processed later, including all its enclosing ScopeBlocks.
|
||||
void addBaseBlock(BaseBlock baseBlock) {
|
||||
for (BaseBlock bb = baseBlock; bb != null; bb = bb.Parent)
|
||||
baseBlocksToCheck.Push(bb);
|
||||
}
|
||||
|
||||
void processScopeBlock(ScopeBlock scopeBlock) {
|
||||
if (scopeBlock == null || checkedScopeBlocks.ContainsKey(scopeBlock))
|
||||
return;
|
||||
checkedScopeBlocks[scopeBlock] = true;
|
||||
addBaseBlock(scopeBlock);
|
||||
|
||||
if (scopeBlock is TryBlock) {
|
||||
var tryBlock = (TryBlock)scopeBlock;
|
||||
foreach (var handler in tryBlock.TryHandlerBlocks)
|
||||
addScopeBlock(handler);
|
||||
}
|
||||
else if (scopeBlock is TryHandlerBlock) {
|
||||
var tryHandlerBlock = (TryHandlerBlock)scopeBlock;
|
||||
addScopeBlock(tryHandlerBlock.FilterHandlerBlock);
|
||||
addScopeBlock(tryHandlerBlock.HandlerBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void getCode(out IList<Instruction> allInstructions, out IList<ExceptionHandler> allExceptionHandlers) {
|
||||
new CodeGenerator(methodBlocks).getCode(out allInstructions, out allExceptionHandlers);
|
||||
}
|
||||
|
|
144
blocks/DeadBlocksRemover.cs
Normal file
144
blocks/DeadBlocksRemover.cs
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
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;
|
||||
|
||||
namespace de4dot.blocks {
|
||||
class DeadBlocksRemover {
|
||||
MethodBlocks methodBlocks;
|
||||
Dictionary<BaseBlock, bool> checkedBaseBlocks = new Dictionary<BaseBlock, bool>();
|
||||
Dictionary<ScopeBlock, bool> checkedScopeBlocks = new Dictionary<ScopeBlock, bool>();
|
||||
Stack<BaseBlock> baseBlocksToCheck = new Stack<BaseBlock>();
|
||||
Stack<ScopeBlock> scopeBlocksToCheck = new Stack<ScopeBlock>();
|
||||
|
||||
public DeadBlocksRemover(MethodBlocks methodBlocks) {
|
||||
this.methodBlocks = methodBlocks;
|
||||
}
|
||||
|
||||
public int remove() {
|
||||
addScopeBlock(methodBlocks);
|
||||
processAll();
|
||||
return removeDeadBlocks();
|
||||
}
|
||||
|
||||
class ScopeBlockInfo {
|
||||
public ScopeBlock scopeBlock;
|
||||
public IList<BaseBlock> deadBlocks = new List<BaseBlock>();
|
||||
public ScopeBlockInfo(ScopeBlock scopeBlock) {
|
||||
this.scopeBlock = scopeBlock;
|
||||
}
|
||||
}
|
||||
|
||||
int removeDeadBlocks() {
|
||||
int numDeadBlocks = 0;
|
||||
|
||||
var infos = new Dictionary<ScopeBlock, ScopeBlockInfo>();
|
||||
var deadBlocksDict = new Dictionary<BaseBlock, bool>();
|
||||
foreach (var baseBlock in findDeadBlocks()) {
|
||||
deadBlocksDict[baseBlock] = true;
|
||||
ScopeBlock parent = (ScopeBlock)baseBlock.Parent;
|
||||
ScopeBlockInfo info;
|
||||
if (!infos.TryGetValue(parent, out info))
|
||||
infos[parent] = info = new ScopeBlockInfo(parent);
|
||||
info.deadBlocks.Add(baseBlock);
|
||||
numDeadBlocks++;
|
||||
}
|
||||
|
||||
foreach (var info in infos.Values)
|
||||
info.scopeBlock.removeAllDeadBlocks(info.deadBlocks, deadBlocksDict);
|
||||
|
||||
return numDeadBlocks;
|
||||
}
|
||||
|
||||
IList<BaseBlock> findDeadBlocks() {
|
||||
var deadBlocks = new List<BaseBlock>();
|
||||
|
||||
foreach (var bb in methodBlocks.getAllBaseBlocks()) {
|
||||
if (!checkedBaseBlocks.ContainsKey(bb))
|
||||
deadBlocks.Add(bb);
|
||||
}
|
||||
|
||||
return deadBlocks;
|
||||
}
|
||||
|
||||
void addScopeBlock(ScopeBlock scopeBlock) {
|
||||
scopeBlocksToCheck.Push(scopeBlock);
|
||||
}
|
||||
|
||||
void processAll() {
|
||||
bool didSomething;
|
||||
do {
|
||||
didSomething = false;
|
||||
while (baseBlocksToCheck.Count > 0) {
|
||||
processBaseBlock(baseBlocksToCheck.Pop());
|
||||
didSomething = true;
|
||||
}
|
||||
while (scopeBlocksToCheck.Count > 0) {
|
||||
processScopeBlock(scopeBlocksToCheck.Pop());
|
||||
didSomething = true;
|
||||
}
|
||||
} while (didSomething);
|
||||
}
|
||||
|
||||
void processBaseBlock(BaseBlock baseBlock) {
|
||||
if (baseBlock == null || checkedBaseBlocks.ContainsKey(baseBlock))
|
||||
return;
|
||||
checkedBaseBlocks[baseBlock] = true;
|
||||
|
||||
if (baseBlock is Block) {
|
||||
var block = (Block)baseBlock;
|
||||
foreach (var block2 in block.getTargets())
|
||||
addBaseBlock(block2);
|
||||
}
|
||||
else if (baseBlock is ScopeBlock) {
|
||||
var scopeBlock = (ScopeBlock)baseBlock;
|
||||
addScopeBlock(scopeBlock);
|
||||
if (scopeBlock.BaseBlocks != null && scopeBlock.BaseBlocks.Count > 0)
|
||||
addBaseBlock(scopeBlock.BaseBlocks[0]);
|
||||
}
|
||||
else
|
||||
throw new ApplicationException(string.Format("Unknown BaseBlock type {0}", baseBlock.GetType()));
|
||||
}
|
||||
|
||||
// Add a block to be processed later, including all its enclosing ScopeBlocks.
|
||||
void addBaseBlock(BaseBlock baseBlock) {
|
||||
for (BaseBlock bb = baseBlock; bb != null; bb = bb.Parent)
|
||||
baseBlocksToCheck.Push(bb);
|
||||
}
|
||||
|
||||
void processScopeBlock(ScopeBlock scopeBlock) {
|
||||
if (scopeBlock == null || checkedScopeBlocks.ContainsKey(scopeBlock))
|
||||
return;
|
||||
checkedScopeBlocks[scopeBlock] = true;
|
||||
addBaseBlock(scopeBlock);
|
||||
|
||||
if (scopeBlock is TryBlock) {
|
||||
var tryBlock = (TryBlock)scopeBlock;
|
||||
foreach (var handler in tryBlock.TryHandlerBlocks)
|
||||
addScopeBlock(handler);
|
||||
}
|
||||
else if (scopeBlock is TryHandlerBlock) {
|
||||
var tryHandlerBlock = (TryHandlerBlock)scopeBlock;
|
||||
addScopeBlock(tryHandlerBlock.FilterHandlerBlock);
|
||||
addScopeBlock(tryHandlerBlock.HandlerBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -483,26 +483,44 @@ namespace de4dot.blocks {
|
|||
return !MemberReferenceHelper.verifyType(method.MethodReturnType.ReturnType, "mscorlib", "System.Void");
|
||||
}
|
||||
|
||||
public static void updateStack(Instruction instr, ref int stack) {
|
||||
if (instr.OpCode.FlowControl == FlowControl.Call) {
|
||||
public static void updateStack(Instruction instr, ref int stack, bool methodHasReturnValue) {
|
||||
int pushes, pops;
|
||||
calculateStackUsage(instr, methodHasReturnValue, out pushes, out pops);
|
||||
if (pops == -1)
|
||||
stack = 0;
|
||||
else
|
||||
stack += pushes - pops;
|
||||
}
|
||||
|
||||
// Sets pops to -1 if the stack is supposed to be cleared
|
||||
public static void calculateStackUsage(Instruction instr, bool methodHasReturnValue, out int pushes, out int pops) {
|
||||
if (instr.OpCode.FlowControl == FlowControl.Call)
|
||||
calculateStackUsage_call(instr, out pushes, out pops);
|
||||
else
|
||||
calculateStackUsage_nonCall(instr, methodHasReturnValue, out pushes, out pops);
|
||||
}
|
||||
|
||||
static void calculateStackUsage_call(Instruction instr, out int pushes, out int pops) {
|
||||
pushes = 0;
|
||||
pops = 0;
|
||||
|
||||
var method = (IMethodSignature)instr.Operand;
|
||||
if (hasReturnValue(method))
|
||||
stack++;
|
||||
if (method.HasThis && instr.OpCode.Code == Code.Newobj)
|
||||
stack++;
|
||||
if (hasReturnValue(method) || (instr.OpCode.Code == Code.Newobj && method.HasThis))
|
||||
pushes++;
|
||||
|
||||
if (method.HasParameters)
|
||||
stack -= method.Parameters.Count;
|
||||
pops += method.Parameters.Count;
|
||||
if (method.HasThis && instr.OpCode.Code != Code.Newobj)
|
||||
stack--;
|
||||
}
|
||||
else
|
||||
updateStack_nonCall(instr, ref stack);
|
||||
pops++;
|
||||
}
|
||||
|
||||
static void updateStack_nonCall(Instruction instr, ref int stack) {
|
||||
// Sets pops to -1 if the stack is supposed to be cleared
|
||||
static void calculateStackUsage_nonCall(Instruction instr, bool methodHasReturnValue, out int pushes, out int pops) {
|
||||
StackBehaviour stackBehavior;
|
||||
|
||||
pushes = 0;
|
||||
pops = 0;
|
||||
|
||||
stackBehavior = instr.OpCode.StackBehaviourPush;
|
||||
switch (stackBehavior) {
|
||||
case StackBehaviour.Push0:
|
||||
|
@ -514,11 +532,11 @@ namespace de4dot.blocks {
|
|||
case StackBehaviour.Pushr4:
|
||||
case StackBehaviour.Pushr8:
|
||||
case StackBehaviour.Pushref:
|
||||
stack++;
|
||||
pushes++;
|
||||
break;
|
||||
|
||||
case StackBehaviour.Push1_push1:
|
||||
stack += 2;
|
||||
pushes += 2;
|
||||
break;
|
||||
|
||||
case StackBehaviour.Varpush: // only call, calli, callvirt which are handled elsewhere
|
||||
|
@ -534,7 +552,7 @@ namespace de4dot.blocks {
|
|||
case StackBehaviour.Pop1:
|
||||
case StackBehaviour.Popi:
|
||||
case StackBehaviour.Popref:
|
||||
stack--;
|
||||
pops++;
|
||||
break;
|
||||
|
||||
case StackBehaviour.Pop1_pop1:
|
||||
|
@ -545,7 +563,7 @@ namespace de4dot.blocks {
|
|||
case StackBehaviour.Popi_popr8:
|
||||
case StackBehaviour.Popref_pop1:
|
||||
case StackBehaviour.Popref_popi:
|
||||
stack -= 2;
|
||||
pops += 2;
|
||||
break;
|
||||
|
||||
case StackBehaviour.Popi_popi_popi:
|
||||
|
@ -554,16 +572,16 @@ namespace de4dot.blocks {
|
|||
case StackBehaviour.Popref_popi_popr4:
|
||||
case StackBehaviour.Popref_popi_popr8:
|
||||
case StackBehaviour.Popref_popi_popref:
|
||||
stack -= 3;
|
||||
pops += 3;
|
||||
break;
|
||||
|
||||
case StackBehaviour.PopAll:
|
||||
stack = 0;
|
||||
pops = -1;
|
||||
break;
|
||||
|
||||
case StackBehaviour.Varpop: // call, calli, callvirt, newobj (all handled elsewhere), and ret
|
||||
// It's RET. Ignore decrementing stack once if method returns something
|
||||
// since it's not important and we don't know whether it returns anything.
|
||||
if (methodHasReturnValue)
|
||||
pops++;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -583,8 +601,14 @@ namespace de4dot.blocks {
|
|||
}
|
||||
|
||||
public static string getFullAssemblyName(IMetadataScope scope) {
|
||||
//TODO: Returning scope.Name is probably best since the method could fail.
|
||||
var asmRef = getAssemblyNameReference(scope);
|
||||
return asmRef.FullName;
|
||||
}
|
||||
|
||||
public static bool isAssembly(IMetadataScope scope, string assemblySimpleName) {
|
||||
return scope.Name == assemblySimpleName ||
|
||||
scope.Name.StartsWith(assemblySimpleName + ",", StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace de4dot.blocks {
|
|||
|
||||
int stack = stackStart;
|
||||
foreach (var instr in block.Instructions)
|
||||
DotNetUtils.updateStack(instr.Instruction, ref stack);
|
||||
DotNetUtils.updateStack(instr.Instruction, ref stack, false);
|
||||
stackEnd = stack;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,8 +35,14 @@
|
|||
<Compile Include="Block.cs" />
|
||||
<Compile Include="Blocks.cs" />
|
||||
<Compile Include="BlocksSorter.cs" />
|
||||
<Compile Include="cflow\BlockControlFlowDeobfuscator.cs" />
|
||||
<Compile Include="cflow\InstructionEmulator.cs" />
|
||||
<Compile Include="cflow\Value.cs" />
|
||||
<Compile Include="cflow\ValueStack.cs" />
|
||||
<Compile Include="CodeGenerator.cs" />
|
||||
<Compile Include="CondBranchDeobfuscator.cs" />
|
||||
<Compile Include="cflow\BlocksControlFlowDeobfuscator.cs" />
|
||||
<Compile Include="DeadBlocksRemover.cs" />
|
||||
<Compile Include="DotNetUtils.cs" />
|
||||
<Compile Include="FilterHandlerBlock.cs" />
|
||||
<Compile Include="ForwardScanOrder.cs" />
|
||||
|
|
564
blocks/cflow/BlockControlFlowDeobfuscator.cs
Normal file
564
blocks/cflow/BlockControlFlowDeobfuscator.cs
Normal file
|
@ -0,0 +1,564 @@
|
|||
/*
|
||||
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;
|
||||
using Mono.Cecil.Cil;
|
||||
|
||||
namespace de4dot.blocks.cflow {
|
||||
class BlockControlFlowDeobfuscator {
|
||||
Block block;
|
||||
InstructionEmulator instructionEmulator = new InstructionEmulator();
|
||||
|
||||
public void init(Block block, IList<ParameterDefinition> args, IList<VariableDefinition> locals) {
|
||||
this.block = block;
|
||||
instructionEmulator.init(false, args, locals);
|
||||
}
|
||||
|
||||
// Returns true if code was updated, false otherwise
|
||||
public bool deobfuscate() {
|
||||
var instructions = block.Instructions;
|
||||
if (instructions.Count == 0)
|
||||
return false;
|
||||
for (int i = 0; i < instructions.Count - 1; i++) {
|
||||
instructionEmulator.emulate(instructions[i].Instruction);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulateBranch(int stackArgs, bool isTaken) {
|
||||
// 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() {
|
||||
var val2 = instructionEmulator.pop();
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: If it's an unknown int32/64, push 1 if val1 is same ref as val2
|
||||
|
||||
if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
var int2 = (Int32Value)val2;
|
||||
return emulateBranch(2, int1.value == int2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
var long2 = (Int64Value)val2;
|
||||
return emulateBranch(2, long1.value == long2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
|
||||
var real1 = (Real8Value)val1;
|
||||
var real2 = (Real8Value)val2;
|
||||
return emulateBranch(2, real1.value == real2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Null && val2.valueType == ValueType.Null) {
|
||||
return emulateBranch(2, true);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_Bne_Un() {
|
||||
var val2 = instructionEmulator.pop();
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: If it's an unknown int32/64, push 1 if val1 is same ref as val2
|
||||
|
||||
if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
var int2 = (Int32Value)val2;
|
||||
return emulateBranch(2, (uint)int1.value != (uint)int2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
var long2 = (Int64Value)val2;
|
||||
return emulateBranch(2, (ulong)long1.value != (ulong)long2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
|
||||
var real1 = (Real8Value)val1;
|
||||
var real2 = (Real8Value)val2;
|
||||
return emulateBranch(2, real1.value != real2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Null && val2.valueType == ValueType.Null) {
|
||||
return emulateBranch(2, false);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_Bge() {
|
||||
var val2 = instructionEmulator.pop();
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: Support floats
|
||||
|
||||
if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
var int2 = (Int32Value)val2;
|
||||
return emulateBranch(2, int1.value >= int2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
var long2 = (Int64Value)val2;
|
||||
return emulateBranch(2, long1.value >= long2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
if (int1.value == int.MaxValue)
|
||||
return emulateBranch(2, true); // max >= x => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int32) {
|
||||
var int2 = (Int32Value)val2;
|
||||
if (int2.value == int.MinValue)
|
||||
return emulateBranch(2, true); // x >= min => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
if (long1.value == long.MaxValue)
|
||||
return emulateBranch(2, true); // max >= x => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int64) {
|
||||
var long2 = (Int64Value)val2;
|
||||
if (long2.value == long.MinValue)
|
||||
return emulateBranch(2, true); // x >= min => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_Bge_Un() {
|
||||
var val2 = instructionEmulator.pop();
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: Support floats
|
||||
|
||||
if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
var int2 = (Int32Value)val2;
|
||||
return emulateBranch(2, (uint)int1.value >= (uint)int2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
var long2 = (Int64Value)val2;
|
||||
return emulateBranch(2, (ulong)long1.value >= (ulong)long2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
if ((uint)int1.value == uint.MaxValue)
|
||||
return emulateBranch(2, true); // max >= x => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int32) {
|
||||
var int2 = (Int32Value)val2;
|
||||
if ((uint)int2.value == uint.MinValue)
|
||||
return emulateBranch(2, true); // x >= min => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
if ((ulong)long1.value == ulong.MaxValue)
|
||||
return emulateBranch(2, true); // max >= x => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int64) {
|
||||
var long2 = (Int64Value)val2;
|
||||
if ((ulong)long2.value == ulong.MinValue)
|
||||
return emulateBranch(2, true); // x >= min => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_Bgt() {
|
||||
var val2 = instructionEmulator.pop();
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: Support floats
|
||||
|
||||
if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
var int2 = (Int32Value)val2;
|
||||
return emulateBranch(2, int1.value > int2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
var long2 = (Int64Value)val2;
|
||||
return emulateBranch(2, long1.value > long2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
if (int1.value == int.MinValue)
|
||||
return emulateBranch(2, false); // min > x => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int32) {
|
||||
var int2 = (Int32Value)val2;
|
||||
if (int2.value == int.MaxValue)
|
||||
return emulateBranch(2, false); // x > max => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
if (long1.value == long.MinValue)
|
||||
return emulateBranch(2, false); // min > x => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int64) {
|
||||
var long2 = (Int64Value)val2;
|
||||
if (long2.value == long.MaxValue)
|
||||
return emulateBranch(2, false); // x > max => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_Bgt_Un() {
|
||||
var val2 = instructionEmulator.pop();
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: Support floats
|
||||
|
||||
if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
var int2 = (Int32Value)val2;
|
||||
return emulateBranch(2, (uint)int1.value > (uint)int2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
var long2 = (Int64Value)val2;
|
||||
return emulateBranch(2, (ulong)long1.value > (ulong)long2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
if ((uint)int1.value == uint.MinValue)
|
||||
return emulateBranch(2, false); // min > x => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int32) {
|
||||
var int2 = (Int32Value)val2;
|
||||
if ((uint)int2.value == uint.MaxValue)
|
||||
return emulateBranch(2, false); // x > max => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
if ((ulong)long1.value == ulong.MinValue)
|
||||
return emulateBranch(2, false); // min > x => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int64) {
|
||||
var long2 = (Int64Value)val2;
|
||||
if ((ulong)long2.value == ulong.MaxValue)
|
||||
return emulateBranch(2, false); // x > max => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_Ble() {
|
||||
var val2 = instructionEmulator.pop();
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: Support floats
|
||||
|
||||
if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
var int2 = (Int32Value)val2;
|
||||
return emulateBranch(2, int1.value <= int2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
var long2 = (Int64Value)val2;
|
||||
return emulateBranch(2, long1.value <= long2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
if (int1.value == int.MinValue)
|
||||
return emulateBranch(2, true); // min <= x => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int32) {
|
||||
var int2 = (Int32Value)val2;
|
||||
if (int2.value == int.MaxValue)
|
||||
return emulateBranch(2, true); // x <= max => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
if (long1.value == long.MinValue)
|
||||
return emulateBranch(2, true); // min <= x => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int64) {
|
||||
var long2 = (Int64Value)val2;
|
||||
if (long2.value == long.MaxValue)
|
||||
return emulateBranch(2, true); // x <= max => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_Ble_Un() {
|
||||
var val2 = instructionEmulator.pop();
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: Support floats
|
||||
|
||||
if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
var int2 = (Int32Value)val2;
|
||||
return emulateBranch(2, (uint)int1.value <= (uint)int2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
var long2 = (Int64Value)val2;
|
||||
return emulateBranch(2, (ulong)long1.value <= (ulong)long2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
if ((uint)int1.value == uint.MinValue)
|
||||
return emulateBranch(2, true); // min <= x => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int32) {
|
||||
var int2 = (Int32Value)val2;
|
||||
if ((uint)int2.value == uint.MaxValue)
|
||||
return emulateBranch(2, true); // x <= max => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
if ((ulong)long1.value == ulong.MinValue)
|
||||
return emulateBranch(2, true); // min <= x => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int64) {
|
||||
var long2 = (Int64Value)val2;
|
||||
if ((ulong)long2.value == ulong.MaxValue)
|
||||
return emulateBranch(2, true); // x <= max => true
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_Blt() {
|
||||
var val2 = instructionEmulator.pop();
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: Support floats
|
||||
|
||||
if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
var int2 = (Int32Value)val2;
|
||||
return emulateBranch(2, int1.value < int2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
var long2 = (Int64Value)val2;
|
||||
return emulateBranch(2, long1.value < long2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
if (int1.value == int.MaxValue)
|
||||
return emulateBranch(2, false); // max < x => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int32) {
|
||||
var int2 = (Int32Value)val2;
|
||||
if (int2.value == int.MinValue)
|
||||
return emulateBranch(2, false); // x < min => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
if (long1.value == long.MaxValue)
|
||||
return emulateBranch(2, false); // max < x => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int64) {
|
||||
var long2 = (Int64Value)val2;
|
||||
if (long2.value == long.MinValue)
|
||||
return emulateBranch(2, false); // x < min => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_Blt_Un() {
|
||||
var val2 = instructionEmulator.pop();
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: Support floats
|
||||
|
||||
if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
var int2 = (Int32Value)val2;
|
||||
return emulateBranch(2, (uint)int1.value < (uint)int2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
var long2 = (Int64Value)val2;
|
||||
return emulateBranch(2, (ulong)long1.value < (ulong)long2.value);
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int32) {
|
||||
var int1 = (Int32Value)val1;
|
||||
if ((uint)int1.value == uint.MaxValue)
|
||||
return emulateBranch(2, false); // max < x => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int32) {
|
||||
var int2 = (Int32Value)val2;
|
||||
if ((uint)int2.value == uint.MinValue)
|
||||
return emulateBranch(2, false); // x < min => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val1.valueType == ValueType.Int64) {
|
||||
var long1 = (Int64Value)val1;
|
||||
if ((ulong)long1.value == ulong.MaxValue)
|
||||
return emulateBranch(2, false); // max < x => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (val2.valueType == ValueType.Int64) {
|
||||
var long2 = (Int64Value)val2;
|
||||
if ((ulong)long2.value == ulong.MinValue)
|
||||
return emulateBranch(2, false); // x < min => false
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_Brfalse() {
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: Support floats
|
||||
|
||||
if (val1.valueType == ValueType.Int32)
|
||||
return emulateBranch(1, ((Int32Value)val1).value == 0);
|
||||
else if (val1.valueType == ValueType.Int64)
|
||||
return emulateBranch(1, ((Int64Value)val1).value == 0);
|
||||
else if (val1.valueType == ValueType.Null)
|
||||
return emulateBranch(1, true);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool emulate_Brtrue() {
|
||||
var val1 = instructionEmulator.pop();
|
||||
|
||||
//TODO: Support floats
|
||||
|
||||
if (val1.valueType == ValueType.Int32)
|
||||
return emulateBranch(1, ((Int32Value)val1).value != 0);
|
||||
else if (val1.valueType == ValueType.Int64)
|
||||
return emulateBranch(1, ((Int64Value)val1).value != 0);
|
||||
else if (val1.valueType == ValueType.Null)
|
||||
return emulateBranch(1, false);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
67
blocks/cflow/BlocksControlFlowDeobfuscator.cs
Normal file
67
blocks/cflow/BlocksControlFlowDeobfuscator.cs
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
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;
|
||||
|
||||
namespace de4dot.blocks.cflow {
|
||||
public class BlocksControlFlowDeobfuscator {
|
||||
BlockControlFlowDeobfuscator blockControlFlowDeobfuscator = new BlockControlFlowDeobfuscator();
|
||||
Blocks blocks;
|
||||
int numRemovedDeadBlocks;
|
||||
|
||||
public int NumberOfRemovedDeadBlocks {
|
||||
get { return numRemovedDeadBlocks; }
|
||||
}
|
||||
|
||||
public void init(Blocks blocks) {
|
||||
this.blocks = blocks;
|
||||
numRemovedDeadBlocks = 0;
|
||||
}
|
||||
|
||||
public void deobfuscate() {
|
||||
bool changed;
|
||||
do {
|
||||
changed = false;
|
||||
removeDeadBlocks();
|
||||
mergeBlocks();
|
||||
foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
|
||||
//TODO: Only do this if it's a bcc block. switch blocks should use other code.
|
||||
blockControlFlowDeobfuscator.init(block, blocks.Method.Parameters, blocks.Locals);
|
||||
changed |= blockControlFlowDeobfuscator.deobfuscate();
|
||||
}
|
||||
} while (changed);
|
||||
}
|
||||
|
||||
void removeDeadBlocks() {
|
||||
numRemovedDeadBlocks += new DeadBlocksRemover(blocks.MethodBlocks).remove();
|
||||
}
|
||||
|
||||
void mergeBlocks() {
|
||||
foreach (var scopeBlock in getAllScopeBlocks(blocks.MethodBlocks))
|
||||
scopeBlock.mergeBlocks();
|
||||
}
|
||||
|
||||
IEnumerable<ScopeBlock> getAllScopeBlocks(ScopeBlock scopeBlock) {
|
||||
var list = new List<ScopeBlock>();
|
||||
list.Add(scopeBlock);
|
||||
list.AddRange(scopeBlock.getAllScopeBlocks());
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
1336
blocks/cflow/InstructionEmulator.cs
Normal file
1336
blocks/cflow/InstructionEmulator.cs
Normal file
File diff suppressed because it is too large
Load Diff
126
blocks/cflow/Value.cs
Normal file
126
blocks/cflow/Value.cs
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
namespace de4dot.blocks.cflow {
|
||||
enum ValueType : byte {
|
||||
Unknown,
|
||||
Null,
|
||||
Boxed,
|
||||
Int32,
|
||||
Int64,
|
||||
Real8,
|
||||
String,
|
||||
}
|
||||
|
||||
abstract class Value {
|
||||
public readonly ValueType valueType;
|
||||
|
||||
protected Value(ValueType valueType) {
|
||||
this.valueType = valueType;
|
||||
}
|
||||
}
|
||||
|
||||
class UnknownValue : Value {
|
||||
public UnknownValue()
|
||||
: base(ValueType.Unknown) {
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
class NullValue : Value {
|
||||
// There's only one type of null
|
||||
public static readonly NullValue Instance = new NullValue();
|
||||
|
||||
NullValue()
|
||||
: base(ValueType.Null) {
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return "null";
|
||||
}
|
||||
}
|
||||
|
||||
class BoxedValue : Value {
|
||||
public readonly Value value;
|
||||
|
||||
public BoxedValue(Value value)
|
||||
: base(ValueType.Boxed) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return string.Format("box({0})", value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
class Int32Value : Value {
|
||||
public readonly int value;
|
||||
|
||||
public Int32Value(int value)
|
||||
: base(ValueType.Int32) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
class Int64Value : Value {
|
||||
public readonly long value;
|
||||
|
||||
public Int64Value(long value)
|
||||
: base(ValueType.Int64) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return value.ToString() + "L";
|
||||
}
|
||||
}
|
||||
|
||||
class Real8Value : Value {
|
||||
public readonly double value;
|
||||
|
||||
public Real8Value(double value)
|
||||
: base(ValueType.Real8) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return value.ToString() + "D";
|
||||
}
|
||||
}
|
||||
|
||||
class StringValue : Value {
|
||||
public readonly string value;
|
||||
|
||||
public StringValue(string value)
|
||||
: base(ValueType.String) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return string.Format("\"{0}\"", value);
|
||||
}
|
||||
}
|
||||
}
|
96
blocks/cflow/ValueStack.cs
Normal file
96
blocks/cflow/ValueStack.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
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.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace de4dot.blocks.cflow {
|
||||
class ValueStack {
|
||||
List<Value> stack = new List<Value>();
|
||||
|
||||
public void init() {
|
||||
stack.Clear();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
stack.Clear();
|
||||
}
|
||||
|
||||
public void push(Value value) {
|
||||
stack.Add(value);
|
||||
}
|
||||
|
||||
public Value peek() {
|
||||
if (stack.Count == 0)
|
||||
return new UnknownValue();
|
||||
return stack[stack.Count - 1];
|
||||
}
|
||||
|
||||
public Value pop() {
|
||||
Value value = peek();
|
||||
if (stack.Count != 0)
|
||||
stack.RemoveAt(stack.Count - 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
public void push(int count) {
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
for (int i = 0; i < count; i++)
|
||||
pushUnknown();
|
||||
}
|
||||
|
||||
public void pushUnknown() {
|
||||
push(new UnknownValue());
|
||||
}
|
||||
|
||||
public void pop(int count) {
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
if (count >= stack.Count)
|
||||
stack.Clear();
|
||||
else if (count > 0)
|
||||
stack.RemoveRange(stack.Count - count, count);
|
||||
}
|
||||
|
||||
public void copyTop() {
|
||||
push(peek());
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
if (stack.Count == 0)
|
||||
return "<empty>";
|
||||
|
||||
var sb = new StringBuilder();
|
||||
const int maxValues = 5;
|
||||
for (int i = 0; i < maxValues; i++) {
|
||||
int index = stack.Count - i - 1;
|
||||
if (index < 0)
|
||||
break;
|
||||
if (i > 0)
|
||||
sb.Append(", ");
|
||||
sb.Append(stack[index].ToString());
|
||||
}
|
||||
if (maxValues < stack.Count)
|
||||
sb.Append(", ...");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ using Mono.Cecil;
|
|||
using Mono.Cecil.Cil;
|
||||
using de4dot.deobfuscators;
|
||||
using de4dot.blocks;
|
||||
using de4dot.blocks.cflow;
|
||||
using de4dot.AssemblyClient;
|
||||
|
||||
namespace de4dot {
|
||||
|
@ -441,6 +442,7 @@ namespace de4dot {
|
|||
|
||||
Log.v("Deobfuscating methods");
|
||||
var methodPrinter = new MethodPrinter();
|
||||
var cflowObfuscator = new BlocksControlFlowDeobfuscator();
|
||||
foreach (var method in allMethods) {
|
||||
Log.v("Deobfuscating {0} ({1:X8})", method, method.MetadataToken.ToUInt32());
|
||||
Log.indent();
|
||||
|
@ -450,7 +452,9 @@ namespace de4dot {
|
|||
|
||||
deob.deobfuscateMethodBegin(blocks);
|
||||
if (options.ControlFlowDeobfuscation) {
|
||||
int numDeadBlocks = blocks.deobfuscate();
|
||||
cflowObfuscator.init(blocks);
|
||||
cflowObfuscator.deobfuscate();
|
||||
int numDeadBlocks = cflowObfuscator.NumberOfRemovedDeadBlocks;
|
||||
if (numDeadBlocks > 0)
|
||||
Log.v("Removed {0} dead block(s)", numDeadBlocks);
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@ namespace de4dot.deobfuscators {
|
|||
if (stack <= 0)
|
||||
return null;
|
||||
var instr = instrs[i];
|
||||
DotNetUtils.updateStack(instr.Instruction, ref stack);
|
||||
DotNetUtils.updateStack(instr.Instruction, ref stack, false);
|
||||
if (stack < 0)
|
||||
return null;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user