de4dot-cex/de4dot.code/deobfuscators/MethodStack.cs

329 lines
8.3 KiB
C#
Raw Permalink Normal View History

2012-04-05 23:11:24 +08:00
/*
2015-10-30 05:45:26 +08:00
Copyright (C) 2011-2015 de4dot@gmail.com
2012-04-05 23:11:24 +08:00
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 dnlib.DotNet;
using dnlib.DotNet.Emit;
2012-04-05 23:11:24 +08:00
using de4dot.blocks;
namespace de4dot.code.deobfuscators {
public class PushedArgs {
2012-04-05 23:11:24 +08:00
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);
}
2013-01-19 20:03:57 +08:00
public void Add(Instruction instr) {
2012-04-05 23:11:24 +08:00
args[nextIndex--] = instr;
}
2013-01-19 20:03:57 +08:00
public void Set(int i, Instruction instr) {
2012-04-05 23:11:24 +08:00
args[i] = instr;
}
2013-01-19 20:03:57 +08:00
public Instruction Get(int i) {
2012-04-05 23:11:24 +08:00
if (0 <= i && i < args.Count)
return args[i];
return null;
}
2013-01-19 20:03:57 +08:00
public Instruction GetEnd(int i) {
return Get(args.Count - 1 - i);
2012-04-05 23:11:24 +08:00
}
2013-01-19 20:03:57 +08:00
public void FixDups() {
2012-04-05 23:11:24 +08:00
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;
}
}
}
public static class MethodStack {
2012-04-05 23:11:24 +08:00
// May not return all args. The args are returned in reverse order.
2013-01-19 20:03:57 +08:00
public static PushedArgs GetPushedArgInstructions(IList<Instruction> instructions, int index) {
2012-04-05 23:11:24 +08:00
try {
int pushes, pops;
2012-11-01 23:42:02 +08:00
instructions[index].CalculateStackUsage(false, out pushes, out pops);
2012-04-05 23:11:24 +08:00
if (pops != -1)
2013-01-19 20:03:57 +08:00
return GetPushedArgInstructions(instructions, index, pops);
2012-04-05 23:11:24 +08:00
}
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.
2013-01-19 20:03:57 +08:00
static PushedArgs GetPushedArgInstructions(IList<Instruction> instructions, int index, int numArgs) {
2012-04-05 23:11:24 +08:00
var pushedArgs = new PushedArgs(numArgs);
Instruction instr;
int skipPushes = 0;
while (index >= 0 && pushedArgs.CanAddMore) {
2013-01-19 20:03:57 +08:00
instr = GetPreviousInstruction(instructions, ref index);
2012-04-05 23:11:24 +08:00
if (instr == null)
break;
int pushes, pops;
2012-11-01 23:42:02 +08:00
instr.CalculateStackUsage(false, out pushes, out pops);
2012-04-05 23:11:24 +08:00
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)
2013-01-19 20:03:57 +08:00
pushedArgs.Add(instr);
2012-04-05 23:11:24 +08:00
skipPushes += pops;
}
}
2013-01-19 20:03:57 +08:00
instr = pushedArgs.Get(0);
2012-04-05 23:11:24 +08:00
if (instr != null && instr.OpCode.Code == Code.Dup) {
2013-01-19 20:03:57 +08:00
instr = GetPreviousInstruction(instructions, ref index);
2012-04-05 23:11:24 +08:00
if (instr != null) {
int pushes, pops;
2012-11-01 23:42:02 +08:00
instr.CalculateStackUsage(false, out pushes, out pops);
2012-04-05 23:11:24 +08:00
if (pushes == 1 && pops == 0)
2013-01-19 20:03:57 +08:00
pushedArgs.Set(0, instr);
2012-04-05 23:11:24 +08:00
}
}
2013-01-19 20:03:57 +08:00
pushedArgs.FixDups();
2012-04-05 23:11:24 +08:00
return pushedArgs;
}
2013-01-19 20:03:57 +08:00
public static TypeSig GetLoadedType(MethodDef method, IList<Instruction> instructions, int instrIndex) {
2012-04-05 23:11:24 +08:00
bool wasNewobj;
2013-01-19 20:03:57 +08:00
return GetLoadedType(method, instructions, instrIndex, 0, out wasNewobj);
2012-04-05 23:11:24 +08:00
}
2013-01-19 20:03:57 +08:00
public static TypeSig GetLoadedType(MethodDef method, IList<Instruction> instructions, int instrIndex, int argIndexFromEnd) {
2012-04-05 23:11:24 +08:00
bool wasNewobj;
2013-01-19 20:03:57 +08:00
return GetLoadedType(method, instructions, instrIndex, argIndexFromEnd, out wasNewobj);
2012-04-05 23:11:24 +08:00
}
2013-01-19 20:03:57 +08:00
public static TypeSig GetLoadedType(MethodDef method, IList<Instruction> instructions, int instrIndex, out bool wasNewobj) {
return GetLoadedType(method, instructions, instrIndex, 0, out wasNewobj);
2012-04-05 23:11:24 +08:00
}
2013-01-19 20:03:57 +08:00
public static TypeSig GetLoadedType(MethodDef method, IList<Instruction> instructions, int instrIndex, int argIndexFromEnd, out bool wasNewobj) {
2012-04-05 23:11:24 +08:00
wasNewobj = false;
2013-01-19 20:03:57 +08:00
var pushedArgs = MethodStack.GetPushedArgInstructions(instructions, instrIndex);
var pushInstr = pushedArgs.GetEnd(argIndexFromEnd);
2012-04-05 23:11:24 +08:00
if (pushInstr == null)
return null;
2012-11-01 23:42:02 +08:00
TypeSig type;
Local local;
2012-11-17 06:50:52 +08:00
var corLibTypes = method.DeclaringType.Module.CorLibTypes;
2012-04-05 23:11:24 +08:00
switch (pushInstr.OpCode.Code) {
case Code.Ldstr:
2012-11-01 23:42:02 +08:00
type = corLibTypes.String;
2012-04-05 23:11:24 +08:00
break;
2012-04-07 04:07:52 +08:00
case Code.Conv_I:
case Code.Conv_Ovf_I:
case Code.Conv_Ovf_I_Un:
2012-11-01 23:42:02 +08:00
type = corLibTypes.IntPtr;
2012-04-07 04:07:52 +08:00
break;
case Code.Conv_U:
case Code.Conv_Ovf_U:
case Code.Conv_Ovf_U_Un:
2012-11-01 23:42:02 +08:00
type = corLibTypes.UIntPtr;
2012-04-07 04:07:52 +08:00
break;
case Code.Conv_I8:
case Code.Conv_Ovf_I8:
case Code.Conv_Ovf_I8_Un:
2012-11-01 23:42:02 +08:00
type = corLibTypes.Int64;
2012-04-07 04:07:52 +08:00
break;
case Code.Conv_U8:
case Code.Conv_Ovf_U8:
case Code.Conv_Ovf_U8_Un:
2012-11-01 23:42:02 +08:00
type = corLibTypes.UInt64;
2012-04-07 04:07:52 +08:00
break;
case Code.Conv_R8:
case Code.Ldc_R8:
case Code.Ldelem_R8:
case Code.Ldind_R8:
2012-11-01 23:42:02 +08:00
type = corLibTypes.Double;
2012-04-07 04:07:52 +08:00
break;
2012-04-05 23:11:24 +08:00
case Code.Call:
case Code.Calli:
case Code.Callvirt:
2012-11-01 23:42:02 +08:00
var calledMethod = pushInstr.Operand as IMethod;
2012-04-05 23:11:24 +08:00
if (calledMethod == null)
return null;
type = calledMethod.MethodSig.GetRetType();
2012-04-05 23:11:24 +08:00
break;
case Code.Newarr:
2012-11-01 23:42:02 +08:00
var type2 = pushInstr.Operand as ITypeDefOrRef;
if (type2 == null)
2012-04-05 23:11:24 +08:00
return null;
2012-11-01 23:42:02 +08:00
type = new SZArraySig(type2.ToTypeSig());
2012-04-05 23:11:24 +08:00
wasNewobj = true;
break;
case Code.Newobj:
2012-11-01 23:42:02 +08:00
var ctor = pushInstr.Operand as IMethod;
2012-04-05 23:11:24 +08:00
if (ctor == null)
return null;
2012-11-01 23:42:02 +08:00
type = ctor.DeclaringType.ToTypeSig();
2012-04-05 23:11:24 +08:00
wasNewobj = true;
break;
case Code.Castclass:
case Code.Isinst:
case Code.Unbox_Any:
2012-11-01 23:42:02 +08:00
case Code.Ldelem:
2012-04-07 04:07:52 +08:00
case Code.Ldobj:
2012-11-01 23:42:02 +08:00
type = (pushInstr.Operand as ITypeDefOrRef).ToTypeSig();
2012-04-05 23:11:24 +08:00
break;
case Code.Ldarg:
case Code.Ldarg_S:
case Code.Ldarg_0:
case Code.Ldarg_1:
case Code.Ldarg_2:
case Code.Ldarg_3:
2012-11-01 23:42:02 +08:00
type = pushInstr.GetArgumentType(method.MethodSig, method.DeclaringType);
2012-04-05 23:11:24 +08:00
break;
case Code.Ldloc:
case Code.Ldloc_S:
case Code.Ldloc_0:
case Code.Ldloc_1:
case Code.Ldloc_2:
case Code.Ldloc_3:
local = pushInstr.GetLocal(method.Body.Variables);
2012-04-05 23:11:24 +08:00
if (local == null)
return null;
2012-11-01 23:42:02 +08:00
type = local.Type.RemovePinned();
2012-04-05 23:11:24 +08:00
break;
2012-04-06 22:08:09 +08:00
case Code.Ldloca:
case Code.Ldloca_S:
2012-11-01 23:42:02 +08:00
local = pushInstr.Operand as Local;
2012-04-06 22:08:09 +08:00
if (local == null)
return null;
2013-01-19 20:03:57 +08:00
type = CreateByRefType(local.Type.RemovePinned());
2012-04-06 22:08:09 +08:00
break;
case Code.Ldarga:
case Code.Ldarga_S:
2013-01-19 20:03:57 +08:00
type = CreateByRefType(pushInstr.GetArgumentType(method.MethodSig, method.DeclaringType));
2012-04-06 22:08:09 +08:00
break;
2012-04-05 23:11:24 +08:00
case Code.Ldfld:
case Code.Ldsfld:
2012-11-01 23:42:02 +08:00
var field = pushInstr.Operand as IField;
if (field == null || field.FieldSig == null)
2012-04-07 04:07:52 +08:00
return null;
type = field.FieldSig.GetFieldType();
2012-04-07 04:07:52 +08:00
break;
case Code.Ldflda:
case Code.Ldsflda:
2012-11-01 23:42:02 +08:00
var field2 = pushInstr.Operand as IField;
if (field2 == null || field2.FieldSig == null)
2012-04-05 23:11:24 +08:00
return null;
2013-01-19 20:03:57 +08:00
type = CreateByRefType(field2.FieldSig.GetFieldType());
2012-04-05 23:11:24 +08:00
break;
case Code.Ldelema:
2012-04-07 04:07:52 +08:00
case Code.Unbox:
2013-01-19 20:03:57 +08:00
type = CreateByRefType(pushInstr.Operand as ITypeDefOrRef);
break;
2012-04-05 23:11:24 +08:00
default:
return null;
}
2012-04-06 22:25:25 +08:00
return type;
2012-04-05 23:11:24 +08:00
}
2013-01-19 20:03:57 +08:00
static ByRefSig CreateByRefType(ITypeDefOrRef elementType) {
if (elementType == null)
return null;
2012-11-01 23:42:02 +08:00
return new ByRefSig(elementType.ToTypeSig());
}
2013-01-19 20:03:57 +08:00
static ByRefSig CreateByRefType(TypeSig elementType) {
2012-11-01 23:42:02 +08:00
if (elementType == null)
return null;
return new ByRefSig(elementType);
}
2013-01-19 20:03:57 +08:00
static Instruction GetPreviousInstruction(IList<Instruction> instructions, ref int instrIndex) {
2012-04-05 23:11:24 +08:00
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;
}
}
}
}
}