Port the remaining classes in blocks

This commit is contained in:
de4dot 2012-10-31 18:52:50 +01:00
parent 301a2fab97
commit 8022a445a9
20 changed files with 181 additions and 119 deletions

View File

@ -23,6 +23,10 @@ using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Mono.Cecil.Metadata; using Mono.Cecil.Metadata;
//TODO: Remove these
using DN = dot10.DotNet;
using DNE = dot10.DotNet.Emit;
namespace de4dot.blocks { namespace de4dot.blocks {
public enum FrameworkType { public enum FrameworkType {
Unknown, Unknown,
@ -635,6 +639,11 @@ namespace de4dot.blocks {
return newMethod; return newMethod;
} }
// Copies most things but not everything
public static DN.MethodDef clone(DN.MethodDef method) {
return null; //TODO:
}
public static Instruction clone(Instruction instr) { public static Instruction clone(Instruction instr) {
return new Instruction { return new Instruction {
Offset = instr.Offset, Offset = instr.Offset,
@ -707,6 +716,22 @@ namespace de4dot.blocks {
bodyExceptionHandlers.Add(eh); bodyExceptionHandlers.Add(eh);
} }
public static void restoreBody(DN.MethodDef method, IEnumerable<DNE.Instruction> instructions, IEnumerable<DNE.ExceptionHandler> exceptionHandlers) {
if (method == null || method.CilBody == null)
return;
var bodyInstrs = method.CilBody.Instructions;
bodyInstrs.Clear();
foreach (var instr in instructions)
bodyInstrs.Add(instr);
var bodyExceptionHandlers = method.CilBody.ExceptionHandlers;
bodyExceptionHandlers.Clear();
foreach (var eh in exceptionHandlers)
bodyExceptionHandlers.Add(eh);
}
public static void copyBodyFromTo(MethodDefinition fromMethod, MethodDefinition toMethod) { public static void copyBodyFromTo(MethodDefinition fromMethod, MethodDefinition toMethod) {
if (fromMethod == toMethod) if (fromMethod == toMethod)
return; return;
@ -1035,6 +1060,16 @@ namespace de4dot.blocks {
return args; return args;
} }
public static List<DN.IType> getArgs(DN.IMethod method) {
var sig = method.MethodSig;
var args = new List<DN.IType>(sig.Params.Count + 1);
if (sig.HasThis && !sig.ExplicitThis)
args.Add(method.DeclaringType);
foreach (var arg in sig.Params)
args.Add(arg);
return args;
}
public static TypeReference getArgType(MethodReference method, Instruction instr) { public static TypeReference getArgType(MethodReference method, Instruction instr) {
return getArgType(getArgs(method), instr); return getArgType(getArgs(method), instr);
} }
@ -1056,6 +1091,16 @@ namespace de4dot.blocks {
return count; return count;
} }
public static int getArgsCount(DN.IMethod method) {
var sig = method.MethodSig;
if (sig == null)
return 0;
int count = sig.Params.Count;
if (sig.HasThis && !sig.ExplicitThis)
count++;
return count;
}
public static Instruction createLdci4(int value) { public static Instruction createLdci4(int value) {
if (value == -1) return Instruction.Create(OpCodes.Ldc_I4_M1); if (value == -1) return Instruction.Create(OpCodes.Ldc_I4_M1);
if (value == 0) return Instruction.Create(OpCodes.Ldc_I4_0); if (value == 0) return Instruction.Create(OpCodes.Ldc_I4_0);
@ -1113,6 +1158,25 @@ namespace de4dot.blocks {
return null; return null;
} }
public static DNE.Instruction getInstruction(IList<DNE.Instruction> instructions, ref int index) {
for (int i = 0; i < 10; i++) {
if (index < 0 || index >= instructions.Count)
return null;
var instr = instructions[index++];
if (instr.OpCode.Code == DNE.Code.Nop)
continue;
if (instr.OpCode.OpCodeType == DNE.OpCodeType.Prefix)
continue;
if (instr == null || (instr.OpCode.Code != DNE.Code.Br && instr.OpCode.Code != DNE.Code.Br_S))
return instr;
instr = instr.Operand as DNE.Instruction;
if (instr == null)
return null;
index = instructions.IndexOf(instr);
}
return null;
}
public static PropertyDefinition createPropertyDefinition(string name, TypeReference propType, MethodDefinition getter, MethodDefinition setter) { public static PropertyDefinition createPropertyDefinition(string name, TypeReference propType, MethodDefinition getter, MethodDefinition setter) {
return new PropertyDefinition(name, PropertyAttributes.None, propType) { return new PropertyDefinition(name, PropertyAttributes.None, propType) {
MetadataToken = nextPropertyToken(), MetadataToken = nextPropertyToken(),

View File

@ -18,8 +18,6 @@
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace de4dot.blocks { namespace de4dot.blocks {
public class FilterHandlerBlock : ScopeBlock { public class FilterHandlerBlock : ScopeBlock {

View File

@ -19,8 +19,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace de4dot.blocks { namespace de4dot.blocks {
// This class makes sure that each block that is entered with a non-empty stack has at // This class makes sure that each block that is entered with a non-empty stack has at

View File

@ -18,8 +18,6 @@
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace de4dot.blocks { namespace de4dot.blocks {
// This is the block inside catch(xxx) { }. // This is the block inside catch(xxx) { }.

View File

@ -38,26 +38,26 @@
<Compile Include="Block.cs" /> <Compile Include="Block.cs" />
<Compile Include="Blocks.cs" /> <Compile Include="Blocks.cs" />
<Compile Include="BlocksSorter.cs" /> <Compile Include="BlocksSorter.cs" />
<None Include="cflow\BlockCflowDeobfuscator.cs" /> <Compile Include="cflow\BlockCflowDeobfuscator.cs" />
<None Include="cflow\BlockDeobfuscator.cs" /> <Compile Include="cflow\BlockDeobfuscator.cs" />
<None Include="cflow\BlocksCflowDeobfuscator.cs" /> <Compile Include="cflow\BlocksCflowDeobfuscator.cs" />
<None Include="cflow\BranchEmulator.cs" /> <Compile Include="cflow\BranchEmulator.cs" />
<None Include="cflow\CachedCflowDeobfuscator.cs" /> <Compile Include="cflow\CachedCflowDeobfuscator.cs" />
<None Include="cflow\CflowDeobfuscator.cs" /> <Compile Include="cflow\CflowDeobfuscator.cs" />
<None Include="cflow\CflowUtils.cs" /> <Compile Include="cflow\CflowUtils.cs" />
<None Include="cflow\ConstantsFolder.cs" /> <Compile Include="cflow\ConstantsFolder.cs" />
<None Include="cflow\DeadCodeRemover.cs" /> <Compile Include="cflow\DeadCodeRemover.cs" />
<None Include="cflow\DeadStoreRemover.cs" /> <Compile Include="cflow\DeadStoreRemover.cs" />
<None Include="cflow\IBlocksDeobfuscator.cs" /> <Compile Include="cflow\IBlocksDeobfuscator.cs" />
<None Include="cflow\ICflowDeobfuscator.cs" /> <Compile Include="cflow\ICflowDeobfuscator.cs" />
<Compile Include="cflow\InstructionEmulator.cs" /> <Compile Include="cflow\InstructionEmulator.cs" />
<Compile Include="cflow\Int32Value.cs" /> <Compile Include="cflow\Int32Value.cs" />
<Compile Include="cflow\Int64Value.cs" /> <Compile Include="cflow\Int64Value.cs" />
<None Include="cflow\MethodCallInliner.cs" /> <Compile Include="cflow\MethodCallInliner.cs" />
<None Include="cflow\MethodCallInlinerBase.cs" /> <Compile Include="cflow\MethodCallInlinerBase.cs" />
<Compile Include="cflow\Real8Value.cs" /> <Compile Include="cflow\Real8Value.cs" />
<None Include="cflow\StLdlocFixer.cs" /> <Compile Include="cflow\StLdlocFixer.cs" />
<None Include="cflow\SwitchCflowDeobfuscator.cs" /> <Compile Include="cflow\SwitchCflowDeobfuscator.cs" />
<Compile Include="cflow\Value.cs" /> <Compile Include="cflow\Value.cs" />
<Compile Include="cflow\ValueStack.cs" /> <Compile Include="cflow\ValueStack.cs" />
<Compile Include="CodeGenerator.cs" /> <Compile Include="CodeGenerator.cs" />

View File

@ -18,7 +18,7 @@
*/ */
using System; using System;
using Mono.Cecil.Cil; using dot10.DotNet.Emit;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
class BlockCflowDeobfuscator : BlockDeobfuscator, IBranchHandler { class BlockCflowDeobfuscator : BlockDeobfuscator, IBranchHandler {
@ -33,7 +33,7 @@ namespace de4dot.blocks.cflow {
protected override bool deobfuscate(Block block) { protected override bool deobfuscate(Block block) {
this.block = block; this.block = block;
if (!DotNetUtils.isConditionalBranch(block.LastInstr.OpCode.Code) && block.LastInstr.OpCode.Code != Code.Switch) if (!block.LastInstr.isConditionalBranch() && block.LastInstr.OpCode.Code != Code.Switch)
return false; return false;
instructionEmulator.init(blocks); instructionEmulator.init(blocks);

View File

@ -18,8 +18,7 @@
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil; using dot10.DotNet.Emit;
using Mono.Cecil.Cil;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
public class BlocksCflowDeobfuscator { public class BlocksCflowDeobfuscator {

View File

@ -17,7 +17,7 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>. along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/ */
using Mono.Cecil.Cil; using dot10.DotNet.Emit;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
public interface IBranchHandler { public interface IBranchHandler {

View File

@ -18,14 +18,14 @@
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil; using dot10.DotNet;
using Mono.Cecil.Cil; using dot10.DotNet.Emit;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
// Only deobfuscates a method once. A copy of the method (now deobfuscated) is returned. // Only deobfuscates a method once. A copy of the method (now deobfuscated) is returned.
public class CachedCflowDeobfuscator { public class CachedCflowDeobfuscator {
BlocksCflowDeobfuscator cflowDeobfuscator = new BlocksCflowDeobfuscator(); BlocksCflowDeobfuscator cflowDeobfuscator = new BlocksCflowDeobfuscator();
Dictionary<MethodDefinition, MethodDefinition> deobfuscated = new Dictionary<MethodDefinition, MethodDefinition>(); Dictionary<MethodDef, MethodDef> deobfuscated = new Dictionary<MethodDef, MethodDef>();
public CachedCflowDeobfuscator() { public CachedCflowDeobfuscator() {
} }
@ -43,12 +43,12 @@ namespace de4dot.blocks.cflow {
cflowDeobfuscator.add(blocksDeobfuscator); cflowDeobfuscator.add(blocksDeobfuscator);
} }
public MethodDefinition deobfuscate(MethodDefinition method) { public MethodDef deobfuscate(MethodDef method) {
MethodDefinition deobfuscatedMethod; MethodDef deobfuscatedMethod;
if (deobfuscated.TryGetValue(method, out deobfuscatedMethod)) if (deobfuscated.TryGetValue(method, out deobfuscatedMethod))
return deobfuscatedMethod; return deobfuscatedMethod;
if (method.Body == null || method.Body.Instructions.Count == 0) { if (method.CilBody == null || method.CilBody.Instructions.Count == 0) {
deobfuscated[method] = method; deobfuscated[method] = method;
return method; return method;
} }

View File

@ -18,8 +18,8 @@
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil; using dot10.DotNet;
using Mono.Cecil.Cil; using dot10.DotNet.Emit;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
public class CflowDeobfuscator : ICflowDeobfuscator { public class CflowDeobfuscator : ICflowDeobfuscator {
@ -32,18 +32,18 @@ namespace de4dot.blocks.cflow {
cflowDeobfuscator.add(blocksDeobfuscator); cflowDeobfuscator.add(blocksDeobfuscator);
} }
public void deobfuscate(MethodDefinition method) { public void deobfuscate(MethodDef method) {
deobfuscate(method, (blocks) => { deobfuscate(method, (blocks) => {
cflowDeobfuscator.init(blocks); cflowDeobfuscator.init(blocks);
cflowDeobfuscator.deobfuscate(); cflowDeobfuscator.deobfuscate();
}); });
} }
static bool hasNonEmptyBody(MethodDefinition method) { static bool hasNonEmptyBody(MethodDef method) {
return method.Body != null && method.Body.Instructions.Count > 0; return method.CilBody != null && method.CilBody.Instructions.Count > 0;
} }
void deobfuscate(MethodDefinition method, Action<Blocks> handler) { void deobfuscate(MethodDef method, Action<Blocks> handler) {
if (hasNonEmptyBody(method)) { if (hasNonEmptyBody(method)) {
var blocks = new Blocks(method); var blocks = new Blocks(method);

View File

@ -19,19 +19,19 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil; using dot10.DotNet;
using Mono.Cecil.Cil; using dot10.DotNet.Emit;
using de4dot.blocks; using de4dot.blocks;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
// Very simple constants folder which is all that's needed at the moment // Very simple constants folder which is all that's needed at the moment
class ConstantsFolder : BlockDeobfuscator { class ConstantsFolder : BlockDeobfuscator {
InstructionEmulator instructionEmulator = new InstructionEmulator(); InstructionEmulator instructionEmulator = new InstructionEmulator();
List<ParameterDefinition> args; IList<Parameter> args;
protected override void init(List<Block> allBlocks) { protected override void init(List<Block> allBlocks) {
base.init(allBlocks); base.init(allBlocks);
args = DotNetUtils.getParameters(blocks.Method); args = blocks.Method.Parameters;
} }
protected override bool deobfuscate(Block block) { protected override bool deobfuscate(Block block) {
@ -49,7 +49,7 @@ namespace de4dot.blocks.cflow {
case Code.Ldarg_2: case Code.Ldarg_2:
case Code.Ldarg_3: case Code.Ldarg_3:
case Code.Ldarg_S: case Code.Ldarg_S:
changed |= fixLoadInstruction(block, i, instructionEmulator.getArg(DotNetUtils.getParameter(args, instr.Instruction))); changed |= fixLoadInstruction(block, i, instructionEmulator.getArg(instr.Instruction.GetParameter(args)));
break; break;
case Code.Ldloc: case Code.Ldloc:
@ -58,17 +58,17 @@ namespace de4dot.blocks.cflow {
case Code.Ldloc_2: case Code.Ldloc_2:
case Code.Ldloc_3: case Code.Ldloc_3:
case Code.Ldloc_S: case Code.Ldloc_S:
changed |= fixLoadInstruction(block, i, instructionEmulator.getLocal(DotNetUtils.getLocalVar(blocks.Locals, instr.Instruction))); changed |= fixLoadInstruction(block, i, instructionEmulator.getLocal(instr.Instruction.GetLocal(blocks.Locals)));
break; break;
case Code.Ldarga: case Code.Ldarga:
case Code.Ldarga_S: case Code.Ldarga_S:
instructionEmulator.makeArgUnknown((ParameterDefinition)instr.Operand); instructionEmulator.makeArgUnknown((Parameter)instr.Operand);
break; break;
case Code.Ldloca: case Code.Ldloca:
case Code.Ldloca_S: case Code.Ldloca_S:
instructionEmulator.makeLocalUnknown((VariableDefinition)instr.Operand); instructionEmulator.makeLocalUnknown((Local)instr.Operand);
break; break;
} }
@ -89,7 +89,7 @@ namespace de4dot.blocks.cflow {
var intValue = (Int32Value)value; var intValue = (Int32Value)value;
if (!intValue.allBitsValid()) if (!intValue.allBitsValid())
return false; return false;
block.Instructions[index] = new Instr(DotNetUtils.createLdci4(intValue.value)); block.Instructions[index] = new Instr(Instruction.CreateLdcI4(intValue.value));
return true; return true;
} }
else if (value.isInt64()) { else if (value.isInt64()) {

View File

@ -18,7 +18,7 @@
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil.Cil; using dot10.DotNet.Emit;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
// Removes dead code that is the result of one of our optimizations, or created by the // Removes dead code that is the result of one of our optimizations, or created by the
@ -185,7 +185,7 @@ namespace de4dot.blocks.cflow {
case Code.Ldc_I8: case Code.Ldc_I8:
case Code.Ldc_R4: case Code.Ldc_R4:
case Code.Ldc_R8: case Code.Ldc_R8:
case Code.Ldelem_Any: case Code.Ldelem:
case Code.Ldelem_I: case Code.Ldelem_I:
case Code.Ldelem_I1: case Code.Ldelem_I1:
case Code.Ldelem_I2: case Code.Ldelem_I2:
@ -237,7 +237,6 @@ namespace de4dot.blocks.cflow {
case Code.Mul_Ovf_Un: case Code.Mul_Ovf_Un:
case Code.Neg: case Code.Neg:
case Code.Newarr: case Code.Newarr:
case Code.No:
case Code.Nop: case Code.Nop:
case Code.Not: case Code.Not:
case Code.Or: case Code.Or:
@ -257,7 +256,7 @@ namespace de4dot.blocks.cflow {
case Code.Sub_Ovf: case Code.Sub_Ovf:
case Code.Sub_Ovf_Un: case Code.Sub_Ovf_Un:
case Code.Switch: case Code.Switch:
case Code.Tail: case Code.Tailcall:
case Code.Throw: case Code.Throw:
case Code.Unaligned: case Code.Unaligned:
case Code.Unbox: case Code.Unbox:
@ -276,7 +275,7 @@ namespace de4dot.blocks.cflow {
case Code.Newobj: case Code.Newobj:
case Code.Starg: case Code.Starg:
case Code.Starg_S: case Code.Starg_S:
case Code.Stelem_Any: case Code.Stelem:
case Code.Stelem_I: case Code.Stelem_I:
case Code.Stelem_I1: case Code.Stelem_I1:
case Code.Stelem_I2: case Code.Stelem_I2:
@ -380,7 +379,7 @@ namespace de4dot.blocks.cflow {
} }
static void calculateStackUsage(Instruction instr, bool methodHasReturnValue, out int pushes, out int pops) { static void calculateStackUsage(Instruction instr, bool methodHasReturnValue, out int pushes, out int pops) {
DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops); instr.CalculateStackUsage(false, out pushes, out pops);
} }
} }
} }

View File

@ -19,7 +19,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil.Cil; using dot10.DotNet.Emit;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
// Removes dead stores by replacing the stloc with a pop. Other optimizations will notice it's // Removes dead stores by replacing the stloc with a pop. Other optimizations will notice it's
@ -80,7 +80,7 @@ namespace de4dot.blocks.cflow {
void findLoadStores() { void findLoadStores() {
foreach (var block in allBlocks) { foreach (var block in allBlocks) {
foreach (var instr in block.Instructions) { foreach (var instr in block.Instructions) {
VariableDefinition local; Local local;
AccessFlags flags; AccessFlags flags;
switch (instr.OpCode.Code) { switch (instr.OpCode.Code) {
case Code.Ldloc: case Code.Ldloc:
@ -105,7 +105,7 @@ namespace de4dot.blocks.cflow {
case Code.Ldloca_S: case Code.Ldloca_S:
case Code.Ldloca: case Code.Ldloca:
local = instr.Operand as VariableDefinition; local = instr.Operand as Local;
flags = AccessFlags.Read | AccessFlags.Write; flags = AccessFlags.Read | AccessFlags.Write;
break; break;
@ -128,7 +128,7 @@ namespace de4dot.blocks.cflow {
var instructions = block.Instructions; var instructions = block.Instructions;
for (int i = 0; i < instructions.Count; i++) { for (int i = 0; i < instructions.Count; i++) {
var instr = instructions[i]; var instr = instructions[i];
VariableDefinition local; Local local;
switch (instr.OpCode.Code) { switch (instr.OpCode.Code) {
case Code.Stloc: case Code.Stloc:
case Code.Stloc_S: case Code.Stloc_S:

View File

@ -17,10 +17,10 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>. along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/ */
using Mono.Cecil; using dot10.DotNet;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
public interface ICflowDeobfuscator { public interface ICflowDeobfuscator {
void deobfuscate(MethodDefinition method); void deobfuscate(MethodDef method);
} }
} }

View File

@ -42,11 +42,9 @@ namespace de4dot.blocks.cflow {
init(method); init(method);
} }
#if PORT
public void init(Blocks blocks) { public void init(Blocks blocks) {
init(blocks.Method); init(blocks.Method);
} }
#endif
public void init(MethodDef method) { public void init(MethodDef method) {
this.parameterDefs = method.Parameters; this.parameterDefs = method.Parameters;
@ -234,7 +232,6 @@ namespace de4dot.blocks.cflow {
return valueStack.peek(); return valueStack.peek();
} }
#if PORT
public void emulate(IEnumerable<Instr> instructions) { public void emulate(IEnumerable<Instr> instructions) {
foreach (var instr in instructions) foreach (var instr in instructions)
emulate(instr.Instruction); emulate(instr.Instruction);
@ -244,7 +241,6 @@ namespace de4dot.blocks.cflow {
for (int i = start; i < end; i++) for (int i = start; i < end; i++)
emulate(instructions[i].Instruction); emulate(instructions[i].Instruction);
} }
#endif
public void emulate(Instruction instr) { public void emulate(Instruction instr) {
switch (instr.OpCode.Code) { switch (instr.OpCode.Code) {

View File

@ -18,8 +18,8 @@
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil; using dot10.DotNet;
using Mono.Cecil.Cil; using dot10.DotNet.Emit;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
public class MethodCallInliner : MethodCallInlinerBase { public class MethodCallInliner : MethodCallInlinerBase {
@ -40,12 +40,12 @@ namespace de4dot.blocks.cflow {
return changed; return changed;
} }
protected virtual bool canInline(MethodDefinition method) { protected virtual bool canInline(MethodDef method) {
if (method.GenericParameters.Count > 0) if (method.GenericParams.Count > 0)
return false; return false;
if (method == blocks.Method) if (method == blocks.Method)
return false; return false;
if (!MemberReferenceHelper.compareTypes(method.DeclaringType, blocks.Method.DeclaringType)) if (!new SigComparer().Equals(method.DeclaringType, blocks.Method.DeclaringType))
return false; return false;
if (method.IsStatic) if (method.IsStatic)
@ -56,13 +56,13 @@ namespace de4dot.blocks.cflow {
} }
bool inlineMethod(Instruction callInstr, int instrIndex) { bool inlineMethod(Instruction callInstr, int instrIndex) {
var methodToInline = callInstr.Operand as MethodDefinition; var methodToInline = callInstr.Operand as MethodDef;
if (methodToInline == null) if (methodToInline == null)
return false; return false;
if (!canInline(methodToInline)) if (!canInline(methodToInline))
return false; return false;
var body = methodToInline.Body; var body = methodToInline.CilBody;
if (body == null) if (body == null)
return false; return false;
@ -113,10 +113,10 @@ namespace de4dot.blocks.cflow {
} }
} }
protected override bool isCompatibleType(int paramIndex, TypeReference origType, TypeReference newType) { protected override bool isCompatibleType(int paramIndex, IType origType, IType newType) {
if (MemberReferenceHelper.compareTypes(origType, newType)) if (new SigComparer().Equals(origType, newType))
return true; return true;
if (newType.IsValueType || origType.IsValueType) if (isValueType(newType) || isValueType(origType))
return false; return false;
return newType.FullName == "System.Object"; return newType.FullName == "System.Object";
} }

View File

@ -18,8 +18,8 @@
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil; using dot10.DotNet;
using Mono.Cecil.Cil; using dot10.DotNet.Emit;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
public abstract class MethodCallInlinerBase : IBlocksDeobfuscator { public abstract class MethodCallInlinerBase : IBlocksDeobfuscator {
@ -60,7 +60,7 @@ namespace de4dot.blocks.cflow {
this.patchIndex = patchIndex; this.patchIndex = patchIndex;
this.afterIndex = afterIndex; this.afterIndex = afterIndex;
this.lastInstr = lastInstr; this.lastInstr = lastInstr;
this.clonedInstr = new Instr(DotNetUtils.clone(lastInstr)); this.clonedInstr = new Instr(lastInstr.Clone());
} }
public void patch(Block block) { public void patch(Block block) {
@ -68,7 +68,7 @@ namespace de4dot.blocks.cflow {
} }
} }
protected bool inlineLoadMethod(int patchIndex, MethodDefinition methodToInline, Instruction loadInstr, int instrIndex) { protected bool inlineLoadMethod(int patchIndex, MethodDef methodToInline, Instruction loadInstr, int instrIndex) {
if (!isReturn(methodToInline, instrIndex)) if (!isReturn(methodToInline, instrIndex))
return false; return false;
@ -76,19 +76,19 @@ namespace de4dot.blocks.cflow {
for (int i = 0; i < methodArgsCount; i++) for (int i = 0; i < methodArgsCount; i++)
block.insert(patchIndex++, Instruction.Create(OpCodes.Pop)); block.insert(patchIndex++, Instruction.Create(OpCodes.Pop));
block.Instructions[patchIndex] = new Instr(DotNetUtils.clone(loadInstr)); block.Instructions[patchIndex] = new Instr(loadInstr.Clone());
return true; return true;
} }
protected bool inlineOtherMethod(int patchIndex, MethodDefinition methodToInline, Instruction instr, int instrIndex) { protected bool inlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex) {
return inlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, 0); return inlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, 0);
} }
protected bool inlineOtherMethod(int patchIndex, MethodDefinition methodToInline, Instruction instr, int instrIndex, int popLastArgs) { protected bool inlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex, int popLastArgs) {
return patchMethod(methodToInline, tryInlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, popLastArgs)); return patchMethod(methodToInline, tryInlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, popLastArgs));
} }
protected bool patchMethod(MethodDefinition methodToInline, InstructionPatcher patcher) { protected bool patchMethod(MethodDef methodToInline, InstructionPatcher patcher) {
if (patcher == null) if (patcher == null)
return false; return false;
@ -99,11 +99,11 @@ namespace de4dot.blocks.cflow {
return true; return true;
} }
protected InstructionPatcher tryInlineOtherMethod(int patchIndex, MethodDefinition methodToInline, Instruction instr, int instrIndex) { protected InstructionPatcher tryInlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex) {
return tryInlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, 0); return tryInlineOtherMethod(patchIndex, methodToInline, instr, instrIndex, 0);
} }
protected InstructionPatcher tryInlineOtherMethod(int patchIndex, MethodDefinition methodToInline, Instruction instr, int instrIndex, int popLastArgs) { protected InstructionPatcher tryInlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex, int popLastArgs) {
int loadIndex = 0; int loadIndex = 0;
int methodArgsCount = DotNetUtils.getArgsCount(methodToInline); int methodArgsCount = DotNetUtils.getArgsCount(methodToInline);
bool foundLdarga = false; bool foundLdarga = false;
@ -128,10 +128,10 @@ namespace de4dot.blocks.cflow {
if (!isLdarg) if (!isLdarg)
break; break;
if (DotNetUtils.getArgIndex(instr) != loadIndex) if (instr.GetParameterIndex() != loadIndex)
return null; return null;
loadIndex++; loadIndex++;
instr = DotNetUtils.getInstruction(methodToInline.Body.Instructions, ref instrIndex); instr = DotNetUtils.getInstruction(methodToInline.CilBody.Instructions, ref instrIndex);
} }
if (instr == null || loadIndex != methodArgsCount - popLastArgs) if (instr == null || loadIndex != methodArgsCount - popLastArgs)
return null; return null;
@ -140,11 +140,11 @@ namespace de4dot.blocks.cflow {
if (foundLdarga) if (foundLdarga)
return null; return null;
var callInstr = instr; var callInstr = instr;
var calledMethod = callInstr.Operand as MethodReference; var calledMethod = callInstr.Operand as IMethod;
if (calledMethod == null) if (calledMethod == null)
return null; return null;
if (!isCompatibleType(-1, calledMethod.MethodReturnType.ReturnType, methodToInline.MethodReturnType.ReturnType)) if (!isCompatibleType(-1, calledMethod.MethodSig.RetType, methodToInline.MethodSig.RetType))
return null; return null;
if (!checkSameMethods(calledMethod, methodToInline, popLastArgs)) if (!checkSameMethods(calledMethod, methodToInline, popLastArgs))
@ -156,19 +156,19 @@ namespace de4dot.blocks.cflow {
if (foundLdarga) if (foundLdarga)
return null; return null;
var newobjInstr = instr; var newobjInstr = instr;
var ctor = newobjInstr.Operand as MethodReference; var ctor = newobjInstr.Operand as IMethod;
if (ctor == null) if (ctor == null)
return null; return null;
if (!isCompatibleType(-1, ctor.DeclaringType, methodToInline.MethodReturnType.ReturnType)) if (!isCompatibleType(-1, ctor.DeclaringType, methodToInline.MethodSig.RetType))
return null; return null;
var methodArgs = DotNetUtils.getArgs(methodToInline); var methodArgs = methodToInline.Parameters;
var calledMethodArgs = DotNetUtils.getArgs(ctor); var calledMethodArgs = DotNetUtils.getArgs(ctor);
if (methodArgs.Count + 1 - popLastArgs != calledMethodArgs.Count) if (methodArgs.Length + 1 - popLastArgs != calledMethodArgs.Count)
return null; return null;
for (int i = 1; i < calledMethodArgs.Count; i++) { for (int i = 1; i < calledMethodArgs.Count; i++) {
if (!isCompatibleType(i, calledMethodArgs[i], methodArgs[i - 1])) if (!isCompatibleType(i, calledMethodArgs[i], methodArgs[i - 1].Type))
return null; return null;
} }
@ -186,25 +186,26 @@ namespace de4dot.blocks.cflow {
return null; return null;
} }
protected virtual bool isReturn(MethodDefinition methodToInline, int instrIndex) { protected virtual bool isReturn(MethodDef methodToInline, int instrIndex) {
var instr = DotNetUtils.getInstruction(methodToInline.Body.Instructions, ref instrIndex); var instr = DotNetUtils.getInstruction(methodToInline.CilBody.Instructions, ref instrIndex);
return instr != null && instr.OpCode.Code == Code.Ret; return instr != null && instr.OpCode.Code == Code.Ret;
} }
protected bool checkSameMethods(MethodReference method, MethodDefinition methodToInline) { protected bool checkSameMethods(IMethod method, MethodDef methodToInline) {
return checkSameMethods(method, methodToInline, 0); return checkSameMethods(method, methodToInline, 0);
} }
protected bool checkSameMethods(MethodReference method, MethodDefinition methodToInline, int ignoreLastMethodToInlineArgs) { protected bool checkSameMethods(IMethod method, MethodDef methodToInline, int ignoreLastMethodToInlineArgs) {
var methodToInlineArgs = DotNetUtils.getArgs(methodToInline); var methodToInlineArgs = methodToInline.Parameters;
var methodArgs = DotNetUtils.getArgs(method); var methodArgs = DotNetUtils.getArgs(method);
if (methodToInlineArgs.Count - ignoreLastMethodToInlineArgs != methodArgs.Count) bool hasImplicitThis = method.MethodSig.HasThis && !method.MethodSig.ExplicitThis;
if (methodToInlineArgs.Length - ignoreLastMethodToInlineArgs != methodArgs.Count)
return false; return false;
for (int i = 0; i < methodArgs.Count; i++) { for (int i = 0; i < methodArgs.Count; i++) {
var methodArg = methodArgs[i]; var methodArg = methodArgs[i];
var methodToInlineArg = methodToInlineArgs[i]; var methodToInlineArg = methodToInlineArgs[i].Type;
if (!isCompatibleType(i, methodArg, methodToInlineArg)) { if (!isCompatibleType(i, methodArg, methodToInlineArg)) {
if (i != 0 || !method.HasImplicitThis) if (i != 0 || !hasImplicitThis)
return false; return false;
if (!isCompatibleValueThisPtr(methodArg, methodToInlineArg)) if (!isCompatibleValueThisPtr(methodArg, methodToInlineArg))
return false; return false;
@ -214,17 +215,24 @@ namespace de4dot.blocks.cflow {
return true; return true;
} }
protected virtual bool isCompatibleType(int paramIndex, TypeReference origType, TypeReference newType) { protected virtual bool isCompatibleType(int paramIndex, IType origType, IType newType) {
return MemberReferenceHelper.compareTypes(origType, newType); return new SigComparer().Equals(origType, newType);
} }
static bool isCompatibleValueThisPtr(TypeReference origType, TypeReference newType) { static bool isCompatibleValueThisPtr(IType origType, IType newType) {
var newByRef = newType as ByReferenceType; var newByRef = newType as ByRefSig;
if (newByRef == null) if (newByRef == null)
return false; return false;
if (!newByRef.ElementType.IsValueType || !origType.IsValueType) if (!isValueType(newByRef.Next) || !isValueType(origType))
return false; return false;
return MemberReferenceHelper.compareTypes(origType, newByRef.ElementType); return new SigComparer().Equals(origType, newByRef.Next);
}
protected static bool isValueType(IType type) {
if (type == null)
return false;
//TODO:
return false;
} }
} }
} }

View File

@ -18,12 +18,13 @@
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil.Cil; using dot10.DotNet;
using dot10.DotNet.Emit;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
// Replace stloc + ldloc with dup + stloc // Replace stloc + ldloc with dup + stloc
class StLdlocFixer : BlockDeobfuscator { class StLdlocFixer : BlockDeobfuscator {
IList<VariableDefinition> locals; IList<Local> locals;
protected override void init(List<Block> allBlocks) { protected override void init(List<Block> allBlocks) {
base.init(allBlocks); base.init(allBlocks);
@ -49,7 +50,7 @@ namespace de4dot.blocks.cflow {
if (!instructions[i + 1].isLdloc()) if (!instructions[i + 1].isLdloc())
break; break;
var local = Instr.getLocalVar(locals, instr); var local = Instr.getLocalVar(locals, instr);
if (local.VariableType.FullName != "System.Boolean") if (local.Type.ElementType != ElementType.Boolean)
continue; continue;
if (local != Instr.getLocalVar(locals, instructions[i + 1])) if (local != Instr.getLocalVar(locals, instructions[i + 1]))
break; break;

View File

@ -19,7 +19,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil.Cil; using dot10.DotNet;
using dot10.DotNet.Emit;
namespace de4dot.blocks.cflow { namespace de4dot.blocks.cflow {
class SwitchCflowDeobfuscator : BlockDeobfuscator { class SwitchCflowDeobfuscator : BlockDeobfuscator {
@ -64,7 +65,7 @@ namespace de4dot.blocks.cflow {
} }
bool isSwitchType2(Block switchBlock) { bool isSwitchType2(Block switchBlock) {
VariableDefinition local = null; Local local = null;
foreach (var instr in switchBlock.Instructions) { foreach (var instr in switchBlock.Instructions) {
if (!instr.isLdloc()) if (!instr.isLdloc())
continue; continue;
@ -178,7 +179,7 @@ namespace de4dot.blocks.cflow {
// swblk: // swblk:
// ldloc N // ldloc N
// switch (......) // switch (......)
bool deobfuscateLdloc(IList<Block> switchTargets, Block switchFallThrough, Block block, VariableDefinition switchVariable) { bool deobfuscateLdloc(IList<Block> switchTargets, Block switchFallThrough, Block block, Local switchVariable) {
bool changed = false; bool changed = false;
foreach (var source in new List<Block>(block.Sources)) { foreach (var source in new List<Block>(block.Sources)) {
if (isBranchBlock(source)) { if (isBranchBlock(source)) {
@ -366,18 +367,18 @@ namespace de4dot.blocks.cflow {
return changed; return changed;
} }
static Block createBlock(Dictionary<VariableDefinition, int> consts, Block fallThrough) { static Block createBlock(Dictionary<Local, int> consts, Block fallThrough) {
var block = new Block(); var block = new Block();
foreach (var kv in consts) { foreach (var kv in consts) {
block.Instructions.Add(new Instr(DotNetUtils.createLdci4(kv.Value))); block.Instructions.Add(new Instr(Instruction.CreateLdcI4(kv.Value)));
block.Instructions.Add(new Instr(Instruction.Create(OpCodes.Stloc, kv.Key))); block.Instructions.Add(new Instr(Instruction.Create(OpCodes.Stloc, kv.Key)));
} }
fallThrough.Parent.add(block); fallThrough.Parent.add(block);
return block; return block;
} }
Dictionary<VariableDefinition, int> getBccLocalConstants(Block block) { Dictionary<Local, int> getBccLocalConstants(Block block) {
var dict = new Dictionary<VariableDefinition, int>(); var dict = new Dictionary<Local, int>();
var instrs = block.Instructions; var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) { for (int i = 0; i < instrs.Count; i++) {
var instr = instrs[i]; var instr = instrs[i];
@ -397,7 +398,7 @@ namespace de4dot.blocks.cflow {
dict.Remove(local); dict.Remove(local);
} }
else if (instr.OpCode.Code == Code.Ldloca || instr.OpCode.Code == Code.Ldloca_S) { else if (instr.OpCode.Code == Code.Ldloca || instr.OpCode.Code == Code.Ldloca_S) {
var local = instr.Operand as VariableDefinition; var local = instr.Operand as Local;
if (local != null) if (local != null)
dict.Remove(local); dict.Remove(local);
} }

2
dot10

@ -1 +1 @@
Subproject commit 526604c81df777accde4e45327cffcba954c356c Subproject commit e543043aff5f9f14484038d0d7bb3850b8d1d2c9