Move code to a new class

This commit is contained in:
de4dot 2012-04-05 17:11:24 +02:00
parent 1ead27107b
commit 0adbb3e70a
3 changed files with 268 additions and 218 deletions

View File

@ -169,6 +169,7 @@
<Compile Include="deobfuscators\MaxtoCode\FileDecrypter.cs" />
<Compile Include="deobfuscators\MaxtoCode\MainType.cs" />
<Compile Include="deobfuscators\MethodCollection.cs" />
<Compile Include="deobfuscators\MethodStack.cs" />
<Compile Include="deobfuscators\QuickLZ.cs" />
<Compile Include="deobfuscators\RandomNameChecker.cs" />
<Compile Include="deobfuscators\Skater_NET\Deobfuscator.cs" />

View File

@ -0,0 +1,258 @@
/*
Copyright (C) 2011-2012 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;
using de4dot.blocks;
namespace de4dot.code.deobfuscators {
class PushedArgs {
List<Instruction> args;
int nextIndex;
public bool CanAddMore {
get { return nextIndex >= 0; }
}
public int NumValidArgs {
get { return args.Count - (nextIndex + 1); }
}
public PushedArgs(int numArgs) {
nextIndex = numArgs - 1;
args = new List<Instruction>(numArgs);
for (int i = 0; i < numArgs; i++)
args.Add(null);
}
public void add(Instruction instr) {
args[nextIndex--] = instr;
}
public void set(int i, Instruction instr) {
args[i] = instr;
}
public Instruction get(int i) {
if (0 <= i && i < args.Count)
return args[i];
return null;
}
public Instruction getEnd(int i) {
return get(args.Count - 1 - i);
}
public void fixDups() {
Instruction prev = null, instr;
for (int i = 0; i < NumValidArgs; i++, prev = instr) {
instr = args[i];
if (instr == null || prev == null)
continue;
if (instr.OpCode.Code != Code.Dup)
continue;
args[i] = prev;
instr = prev;
}
}
}
static class MethodStack {
// May not return all args. The args are returned in reverse order.
public static PushedArgs getPushedArgInstructions(IList<Instruction> instructions, int index) {
try {
int pushes, pops;
DotNetUtils.calculateStackUsage(instructions[index], false, out pushes, out pops);
if (pops != -1)
return getPushedArgInstructions(instructions, index, pops);
}
catch (System.NullReferenceException) {
// Here if eg. invalid metadata token in a call instruction (operand is null)
}
return new PushedArgs(0);
}
// May not return all args. The args are returned in reverse order.
static PushedArgs getPushedArgInstructions(IList<Instruction> instructions, int index, int numArgs) {
var pushedArgs = new PushedArgs(numArgs);
Instruction instr;
int skipPushes = 0;
while (index >= 0 && pushedArgs.CanAddMore) {
instr = getPreviousInstruction(instructions, ref index);
if (instr == null)
break;
int pushes, pops;
DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops);
if (pops == -1)
break;
if (instr.OpCode.Code == Code.Dup) {
pushes = 1;
pops = 0;
}
if (pushes > 1)
break;
if (skipPushes > 0) {
skipPushes -= pushes;
if (skipPushes < 0)
break;
skipPushes += pops;
}
else {
if (pushes == 1)
pushedArgs.add(instr);
skipPushes += pops;
}
}
instr = pushedArgs.get(0);
if (instr != null && instr.OpCode.Code == Code.Dup) {
instr = getPreviousInstruction(instructions, ref index);
if (instr != null) {
int pushes, pops;
DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops);
if (pushes == 1 && pops == 0)
pushedArgs.set(0, instr);
}
}
pushedArgs.fixDups();
return pushedArgs;
}
public static TypeReference getLoadedType(MethodDefinition method, IList<Instruction> instructions, int instrIndex) {
bool wasNewobj;
return getLoadedType(method, instructions, instrIndex, 0, out wasNewobj);
}
public static TypeReference getLoadedType(MethodDefinition method, IList<Instruction> instructions, int instrIndex, int argIndexFromEnd) {
bool wasNewobj;
return getLoadedType(method, instructions, instrIndex, argIndexFromEnd, out wasNewobj);
}
public static TypeReference getLoadedType(MethodDefinition method, IList<Instruction> instructions, int instrIndex, out bool wasNewobj) {
return getLoadedType(method, instructions, instrIndex, 0, out wasNewobj);
}
public static TypeReference getLoadedType(MethodDefinition method, IList<Instruction> instructions, int instrIndex, int argIndexFromEnd, out bool wasNewobj) {
wasNewobj = false;
var pushedArgs = MethodStack.getPushedArgInstructions(instructions, instrIndex);
var pushInstr = pushedArgs.getEnd(argIndexFromEnd);
if (pushInstr == null)
return null;
TypeReference fieldType;
switch (pushInstr.OpCode.Code) {
case Code.Ldstr:
fieldType = method.Module.TypeSystem.String;
break;
case Code.Call:
case Code.Calli:
case Code.Callvirt:
var calledMethod = pushInstr.Operand as MethodReference;
if (calledMethod == null)
return null;
fieldType = calledMethod.MethodReturnType.ReturnType;
break;
case Code.Newarr:
fieldType = pushInstr.Operand as TypeReference;
if (fieldType == null)
return null;
fieldType = new ArrayType(fieldType);
wasNewobj = true;
break;
case Code.Newobj:
var ctor = pushInstr.Operand as MethodReference;
if (ctor == null)
return null;
fieldType = ctor.DeclaringType;
wasNewobj = true;
break;
case Code.Castclass:
case Code.Isinst:
fieldType = pushInstr.Operand as TypeReference;
break;
case Code.Ldarg:
case Code.Ldarg_S:
case Code.Ldarg_0:
case Code.Ldarg_1:
case Code.Ldarg_2:
case Code.Ldarg_3:
fieldType = DotNetUtils.getArgType(method, pushInstr);
break;
case Code.Ldloc:
case Code.Ldloc_S:
case Code.Ldloc_0:
case Code.Ldloc_1:
case Code.Ldloc_2:
case Code.Ldloc_3:
var local = DotNetUtils.getLocalVar(method.Body.Variables, pushInstr);
if (local == null)
return null;
fieldType = local.VariableType;
break;
case Code.Ldfld:
case Code.Ldsfld:
var field2 = pushInstr.Operand as FieldReference;
if (field2 == null)
return null;
fieldType = field2.FieldType;
break;
case Code.Ldelema:
fieldType = pushInstr.Operand as TypeReference;
break;
default:
return null;
}
return fieldType;
}
static Instruction getPreviousInstruction(IList<Instruction> instructions, ref int instrIndex) {
while (true) {
instrIndex--;
if (instrIndex < 0)
return null;
var instr = instructions[instrIndex];
if (instr.OpCode.Code == Code.Nop)
continue;
if (instr.OpCode.OpCodeType == OpCodeType.Prefix)
continue;
switch (instr.OpCode.FlowControl) {
case FlowControl.Next:
case FlowControl.Call:
return instr;
default:
return null;
}
}
}
}
}

View File

@ -214,57 +214,6 @@ namespace de4dot.code.deobfuscators {
return Utils.compareInt32(a.arg.Sequence, b.arg.Sequence);
}
class PushedArgs {
List<Instruction> args;
int nextIndex;
public bool CanAddMore {
get { return nextIndex >= 0; }
}
public int NumValidArgs {
get { return args.Count - (nextIndex + 1); }
}
public PushedArgs(int numArgs) {
nextIndex = numArgs - 1;
args = new List<Instruction>(numArgs);
for (int i = 0; i < numArgs; i++)
args.Add(null);
}
public void add(Instruction instr) {
args[nextIndex--] = instr;
}
public void set(int i, Instruction instr) {
args[i] = instr;
}
public Instruction get(int i) {
if (0 <= i && i < args.Count)
return args[i];
return null;
}
public Instruction getEnd(int i) {
return get(args.Count - 1 - i);
}
public void fixDups() {
Instruction prev = null, instr;
for (int i = 0; i < NumValidArgs; i++, prev = instr) {
instr = args[i];
if (instr == null || prev == null)
continue;
if (instr.OpCode.Code != Code.Dup)
continue;
args[i] = prev;
instr = prev;
}
}
}
void deobfuscateMethod(MethodDefinition method) {
if (!method.IsStatic || method.Body == null)
return;
@ -302,7 +251,7 @@ namespace de4dot.code.deobfuscators {
case Code.Calli:
case Code.Callvirt:
case Code.Newobj:
pushedArgs = getPushedArgInstructions(instructions, i);
pushedArgs = MethodStack.getPushedArgInstructions(instructions, i);
var calledMethod = instr.Operand as MethodReference;
if (calledMethod == null)
break;
@ -327,7 +276,7 @@ namespace de4dot.code.deobfuscators {
break;
case Code.Castclass:
pushedArgs = getPushedArgInstructions(instructions, i);
pushedArgs = MethodStack.getPushedArgInstructions(instructions, i);
if (pushedArgs.NumValidArgs < 1)
break;
addMethodArgType(getParameter(methodParams, pushedArgs.getEnd(0)), instr.Operand as TypeReference);
@ -339,21 +288,21 @@ namespace de4dot.code.deobfuscators {
case Code.Stloc_1:
case Code.Stloc_2:
case Code.Stloc_3:
pushedArgs = getPushedArgInstructions(instructions, i);
pushedArgs = MethodStack.getPushedArgInstructions(instructions, i);
if (pushedArgs.NumValidArgs < 1)
break;
addMethodArgType(getParameter(methodParams, pushedArgs.getEnd(0)), DotNetUtils.getLocalVar(method.Body.Variables, instr));
break;
case Code.Stsfld:
pushedArgs = getPushedArgInstructions(instructions, i);
pushedArgs = MethodStack.getPushedArgInstructions(instructions, i);
if (pushedArgs.NumValidArgs < 1)
break;
addMethodArgType(getParameter(methodParams, pushedArgs.getEnd(0)), instr.Operand as FieldReference);
break;
case Code.Stfld:
pushedArgs = getPushedArgInstructions(instructions, i);
pushedArgs = MethodStack.getPushedArgInstructions(instructions, i);
if (pushedArgs.NumValidArgs >= 1) {
var field = instr.Operand as FieldReference;
addMethodArgType(getParameter(methodParams, pushedArgs.getEnd(0)), field);
@ -364,7 +313,7 @@ namespace de4dot.code.deobfuscators {
case Code.Ldfld:
case Code.Ldflda:
pushedArgs = getPushedArgInstructions(instructions, i);
pushedArgs = MethodStack.getPushedArgInstructions(instructions, i);
if (pushedArgs.NumValidArgs < 1)
break;
addMethodArgType(getParameter(methodParams, pushedArgs.getEnd(0)), instr.Operand as FieldReference);
@ -478,69 +427,6 @@ namespace de4dot.code.deobfuscators {
return true;
}
// May not return all args. The args are returned in reverse order.
PushedArgs getPushedArgInstructions(IList<Instruction> instructions, int index) {
try {
int pushes, pops;
DotNetUtils.calculateStackUsage(instructions[index], false, out pushes, out pops);
if (pops != -1)
return getPushedArgInstructions(instructions, index, pops);
}
catch (System.NullReferenceException) {
// Here if eg. invalid metadata token in a call instruction (operand is null)
}
return new PushedArgs(0);
}
// May not return all args. The args are returned in reverse order.
PushedArgs getPushedArgInstructions(IList<Instruction> instructions, int index, int numArgs) {
var pushedArgs = new PushedArgs(numArgs);
Instruction instr;
int skipPushes = 0;
while (index >= 0 && pushedArgs.CanAddMore) {
instr = getPreviousInstruction(instructions, ref index);
if (instr == null)
break;
int pushes, pops;
DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops);
if (pops == -1)
break;
if (instr.OpCode.Code == Code.Dup) {
pushes = 1;
pops = 0;
}
if (pushes > 1)
break;
if (skipPushes > 0) {
skipPushes -= pushes;
if (skipPushes < 0)
break;
skipPushes += pops;
}
else {
if (pushes == 1)
pushedArgs.add(instr);
skipPushes += pops;
}
}
instr = pushedArgs.get(0);
if (instr != null && instr.OpCode.Code == Code.Dup) {
instr = getPreviousInstruction(instructions, ref index);
if (instr != null) {
int pushes, pops;
DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops);
if (pushes == 1 && pops == 0)
pushedArgs.set(0, instr);
}
}
pushedArgs.fixDups();
return pushedArgs;
}
bool deobfuscateFields() {
foreach (var info in fieldWrites.Values)
info.clear();
@ -573,7 +459,7 @@ namespace de4dot.code.deobfuscators {
case Code.Calli:
case Code.Callvirt:
case Code.Newobj:
var pushedArgs = getPushedArgInstructions(instructions, i);
var pushedArgs = MethodStack.getPushedArgInstructions(instructions, i);
var calledMethod = instr.Operand as MethodReference;
if (calledMethod == null)
continue;
@ -618,84 +504,9 @@ namespace de4dot.code.deobfuscators {
}
TypeReference getLoadedType(MethodDefinition method, IList<Instruction> instructions, int instrIndex, out bool wasNewobj) {
wasNewobj = false;
var pushedArgs = getPushedArgInstructions(instructions, instrIndex);
var pushInstr = pushedArgs.getEnd(0);
if (pushInstr == null)
var fieldType = MethodStack.getLoadedType(method, instructions, instrIndex, out wasNewobj);
if (fieldType == null || !isValidType(fieldType))
return null;
TypeReference fieldType;
switch (pushInstr.OpCode.Code) {
case Code.Ldstr:
fieldType = module.TypeSystem.String;
break;
case Code.Call:
case Code.Calli:
case Code.Callvirt:
var calledMethod = pushInstr.Operand as MethodReference;
if (calledMethod == null)
return null;
fieldType = calledMethod.MethodReturnType.ReturnType;
break;
case Code.Newarr:
fieldType = pushInstr.Operand as TypeReference;
if (fieldType == null)
return null;
fieldType = new ArrayType(fieldType);
wasNewobj = true;
break;
case Code.Newobj:
var ctor = pushInstr.Operand as MethodReference;
if (ctor == null)
return null;
fieldType = ctor.DeclaringType;
wasNewobj = true;
break;
case Code.Castclass:
case Code.Isinst:
fieldType = pushInstr.Operand as TypeReference;
break;
case Code.Ldarg:
case Code.Ldarg_S:
case Code.Ldarg_0:
case Code.Ldarg_1:
case Code.Ldarg_2:
case Code.Ldarg_3:
fieldType = DotNetUtils.getArgType(method, pushInstr);
break;
case Code.Ldloc:
case Code.Ldloc_S:
case Code.Ldloc_0:
case Code.Ldloc_1:
case Code.Ldloc_2:
case Code.Ldloc_3:
var local = DotNetUtils.getLocalVar(method.Body.Variables, pushInstr);
if (local == null)
return null;
fieldType = local.VariableType;
break;
case Code.Ldfld:
case Code.Ldsfld:
var field2 = pushInstr.Operand as FieldReference;
if (field2 == null)
return null;
fieldType = field2.FieldType;
break;
default:
return null;
}
if (!isValidType(fieldType))
return null;
return fieldType;
}
@ -744,25 +555,5 @@ namespace de4dot.code.deobfuscators {
return a;
return null; //TODO:
}
static Instruction getPreviousInstruction(IList<Instruction> instructions, ref int instrIndex) {
while (true) {
instrIndex--;
if (instrIndex < 0)
return null;
var instr = instructions[instrIndex];
if (instr.OpCode.Code == Code.Nop)
continue;
if (instr.OpCode.OpCodeType == OpCodeType.Prefix)
continue;
switch (instr.OpCode.FlowControl) {
case FlowControl.Next:
case FlowControl.Call:
return instr;
default:
return null;
}
}
}
}
}