/* 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 . */ using System; using System.Collections.Generic; using Mono.Cecil; using Mono.Cecil.Cil; namespace de4dot.blocks.cflow { public class InstructionEmulator { ValueStack valueStack = new ValueStack(); IList parameterDefinitions; IList variableDefinitions; List args = new List(); List locals = new List(); int argBase; public InstructionEmulator() { } public InstructionEmulator(bool hasThis, bool initLocals, IList parameterDefinitions, IList variableDefinitions) { init(hasThis, initLocals, parameterDefinitions, variableDefinitions); } public void init(bool hasThis, bool initLocals, IList parameterDefinitions, IList variableDefinitions) { this.parameterDefinitions = parameterDefinitions; this.variableDefinitions = variableDefinitions; valueStack.init(); args.Clear(); argBase = 0; if (hasThis) { argBase = 1; args.Add(new UnknownValue()); } foreach (var arg in parameterDefinitions) args.Add(getUnknownValue(arg.ParameterType)); if (initLocals) { locals.Clear(); foreach (var local in variableDefinitions) locals.Add(getDefaultValue(local.VariableType)); } else { locals.Clear(); foreach (var local in variableDefinitions) locals.Add(getUnknownValue(local.VariableType)); } } static Value getDefaultValue(TypeReference typeReference) { if (typeReference == null) return new UnknownValue(); if (!typeReference.IsValueType) return NullValue.Instance; else if (DotNetUtils.isAssembly(typeReference.Scope, "mscorlib")) { switch (typeReference.FullName) { case "System.Boolean": case "System.SByte": case "System.Byte": case "System.Int16": case "System.UInt16": case "System.Int32": case "System.UInt32": return new Int32Value(0); case "System.Int64": case "System.UInt64": return new Int64Value(0); case "System.Single": case "System.Double": return new Real8Value(0); } } return new UnknownValue(); } static Value getUnknownValue(TypeReference typeReference) { if (typeReference == null) return new UnknownValue(); if (DotNetUtils.isAssembly(typeReference.Scope, "mscorlib")) { switch (typeReference.FullName) { case "System.Boolean": return Int32Value.createUnknownBool(); case "System.SByte": return Int32Value.createUnknown(); case "System.Byte": return Int32Value.createUnknownUInt8(); case "System.Int16": return Int32Value.createUnknown(); case "System.UInt16": return Int32Value.createUnknownUInt16(); case "System.Int32": return Int32Value.createUnknown(); case "System.UInt32": return Int32Value.createUnknown(); case "System.Int64": return Int64Value.createUnknown(); case "System.UInt64": return Int64Value.createUnknown(); } } return new UnknownValue(); } static Value truncateValue(Value value, TypeReference typeReference) { if (typeReference == null) return value; if (DotNetUtils.isAssembly(typeReference.Scope, "mscorlib")) { switch (typeReference.FullName) { case "System.Boolean": if (value.isInt32()) return ((Int32Value)value).toBoolean(); return Int32Value.createUnknownBool(); case "System.SByte": if (value.isInt32()) return ((Int32Value)value).toInt8(); return Int32Value.createUnknown(); case "System.Byte": if (value.isInt32()) return ((Int32Value)value).toUInt8(); return Int32Value.createUnknownUInt8(); case "System.Int16": if (value.isInt32()) return ((Int32Value)value).toInt16(); return Int32Value.createUnknown(); case "System.UInt16": if (value.isInt32()) return ((Int32Value)value).toUInt16(); return Int32Value.createUnknownUInt16(); case "System.Int32": case "System.UInt32": if (value.isInt32()) return value; return Int32Value.createUnknown(); case "System.Int64": case "System.UInt64": if (value.isInt64()) return value; return Int64Value.createUnknown(); } } return value; } static Value getValue(List list, int i) { if (0 <= i && i < list.Count) return list[i]; return new UnknownValue(); } public Value getArg(int i) { return getValue(args, i); } int index(ParameterDefinition arg) { return arg.Index + argBase; } public Value getArg(ParameterDefinition arg) { return getArg(index(arg)); } TypeReference getArgType(int index) { index -= argBase; if (0 <= index && index < parameterDefinitions.Count) return parameterDefinitions[index].ParameterType; return null; } void setArg(int index, Value value) { if (0 <= index && index < args.Count) args[index] = truncateValue(value, getArgType(index)); } Value getUnknownArg(int index) { return getUnknownValue(getArgType(index)); } public Value getLocal(int i) { return getValue(locals, i); } public Value getLocal(VariableDefinition local) { return getLocal(local.Index); } void setLocal(int index, Value value) { if (0 <= index && index < locals.Count) locals[index] = truncateValue(value, variableDefinitions[index].VariableType); } Value getUnknownLocal(int index) { if (0 <= index && index < variableDefinitions.Count) return getUnknownValue(variableDefinitions[index].VariableType); return new UnknownValue(); } public void push(Value value) { valueStack.push(value); } public Value pop() { return valueStack.pop(); } public void emulate(IEnumerable instructions) { foreach (var instr in instructions) emulate(instr.Instruction); } public void emulate(Instruction instr) { switch (instr.OpCode.Code) { case Code.Starg: case Code.Starg_S: emulate_Starg((ParameterDefinition)instr.Operand); break; case Code.Stloc: case Code.Stloc_S: emulate_Stloc(((VariableDefinition)instr.Operand).Index); break; case Code.Stloc_0: emulate_Stloc(0); break; case Code.Stloc_1: emulate_Stloc(1); break; case Code.Stloc_2: emulate_Stloc(2); break; case Code.Stloc_3: emulate_Stloc(3); break; case Code.Ldarg: case Code.Ldarg_S: valueStack.push(getArg((ParameterDefinition)instr.Operand)); break; case Code.Ldarg_0: valueStack.push(getArg(0)); break; case Code.Ldarg_1: valueStack.push(getArg(1)); break; case Code.Ldarg_2: valueStack.push(getArg(2)); break; case Code.Ldarg_3: valueStack.push(getArg(3)); break; case Code.Ldloc: case Code.Ldloc_S: valueStack.push(getLocal((VariableDefinition)instr.Operand)); break; case Code.Ldloc_0: valueStack.push(getLocal(0)); break; case Code.Ldloc_1: valueStack.push(getLocal(1)); break; case Code.Ldloc_2: valueStack.push(getLocal(2)); break; case Code.Ldloc_3: valueStack.push(getLocal(3)); break; case Code.Ldarga: case Code.Ldarga_S: emulate_Ldarga((ParameterDefinition)instr.Operand); break; case Code.Ldloca: case Code.Ldloca_S: emulate_Ldloca(((VariableDefinition)instr.Operand).Index); break; case Code.Dup: valueStack.copyTop(); break; case Code.Ldc_I4: valueStack.push(new Int32Value((int)instr.Operand)); break; case Code.Ldc_I4_S: valueStack.push(new Int32Value((sbyte)instr.Operand)); break; case Code.Ldc_I8: valueStack.push(new Int64Value((long)instr.Operand)); break; case Code.Ldc_R4: valueStack.push(new Real8Value((float)instr.Operand)); break; case Code.Ldc_R8: valueStack.push(new Real8Value((double)instr.Operand)); break; case Code.Ldc_I4_0: valueStack.push(new Int32Value(0)); break; case Code.Ldc_I4_1: valueStack.push(new Int32Value(1)); break; case Code.Ldc_I4_2: valueStack.push(new Int32Value(2)); break; case Code.Ldc_I4_3: valueStack.push(new Int32Value(3)); break; case Code.Ldc_I4_4: valueStack.push(new Int32Value(4)); break; case Code.Ldc_I4_5: valueStack.push(new Int32Value(5)); break; case Code.Ldc_I4_6: valueStack.push(new Int32Value(6)); break; case Code.Ldc_I4_7: valueStack.push(new Int32Value(7)); break; case Code.Ldc_I4_8: valueStack.push(new Int32Value(8)); break; case Code.Ldc_I4_M1:valueStack.push(new Int32Value(-1)); break; case Code.Ldnull: valueStack.push(NullValue.Instance); break; case Code.Ldstr: valueStack.push(new StringValue((string)instr.Operand)); break; case Code.Box: valueStack.push(new BoxedValue(valueStack.pop())); break; case Code.Conv_U1: emulate_Conv_U1(instr); break; case Code.Conv_U2: emulate_Conv_U2(instr); break; case Code.Conv_U4: emulate_Conv_U4(instr); break; case Code.Conv_U8: emulate_Conv_U8(instr); break; case Code.Conv_I1: emulate_Conv_I1(instr); break; case Code.Conv_I2: emulate_Conv_I2(instr); break; case Code.Conv_I4: emulate_Conv_I4(instr); break; case Code.Conv_I8: emulate_Conv_I8(instr); break; case Code.Add: emulate_Add(instr); break; case Code.Sub: emulate_Sub(instr); break; case Code.Mul: emulate_Mul(instr); break; case Code.Div: emulate_Div(instr); break; case Code.Div_Un: emulate_Div_Un(instr); break; case Code.Rem: emulate_Rem(instr); break; case Code.Rem_Un: emulate_Rem_Un(instr); break; case Code.Neg: emulate_Neg(instr); break; case Code.And: emulate_And(instr); break; case Code.Or: emulate_Or(instr); break; case Code.Xor: emulate_Xor(instr); break; case Code.Not: emulate_Not(instr); break; case Code.Shl: emulate_Shl(instr); break; case Code.Shr: emulate_Shr(instr); break; case Code.Shr_Un: emulate_Shr_Un(instr); break; case Code.Ceq: emulate_Ceq(instr); break; case Code.Cgt: emulate_Cgt(instr); break; case Code.Cgt_Un: emulate_Cgt_Un(instr); break; case Code.Clt: emulate_Clt(instr); break; case Code.Clt_Un: emulate_Clt_Un(instr); break; case Code.Unbox_Any:emulate_Unbox_Any(instr); break; case Code.Call: emulate_Call(instr); break; case Code.Callvirt: emulate_Callvirt(instr); break; case Code.Castclass: emulate_Castclass(instr); break; case Code.Isinst: emulate_Isinst(instr); break; case Code.Add_Ovf: emulateIntOps2(); break; case Code.Add_Ovf_Un: emulateIntOps2(); break; case Code.Sub_Ovf: emulateIntOps2(); break; case Code.Sub_Ovf_Un: emulateIntOps2(); break; case Code.Mul_Ovf: emulateIntOps2(); break; case Code.Mul_Ovf_Un: emulateIntOps2(); break; case Code.Conv_Ovf_I1: case Code.Conv_Ovf_I1_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; case Code.Conv_Ovf_I2: case Code.Conv_Ovf_I2_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; case Code.Conv_Ovf_I4: case Code.Conv_Ovf_I4_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; case Code.Conv_Ovf_I8: case Code.Conv_Ovf_I8_Un: valueStack.pop(); valueStack.push(Int64Value.createUnknown()); break; case Code.Conv_Ovf_U1: case Code.Conv_Ovf_U1_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknownUInt8()); break; case Code.Conv_Ovf_U2: case Code.Conv_Ovf_U2_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknownUInt16()); break; case Code.Conv_Ovf_U4: case Code.Conv_Ovf_U4_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; case Code.Conv_Ovf_U8: case Code.Conv_Ovf_U8_Un: valueStack.pop(); valueStack.push(Int64Value.createUnknown()); break; case Code.Ldelem_I1: valueStack.pop(2); valueStack.push(Int32Value.createUnknown()); break; case Code.Ldelem_I2: valueStack.pop(2); valueStack.push(Int32Value.createUnknown()); break; case Code.Ldelem_I4: valueStack.pop(2); valueStack.push(Int32Value.createUnknown()); break; case Code.Ldelem_I8: valueStack.pop(2); valueStack.push(Int64Value.createUnknown()); break; case Code.Ldelem_U1: valueStack.pop(2); valueStack.push(Int32Value.createUnknownUInt8()); break; case Code.Ldelem_U2: valueStack.pop(2); valueStack.push(Int32Value.createUnknownUInt16()); break; case Code.Ldelem_U4: valueStack.pop(2); valueStack.push(Int32Value.createUnknown()); break; case Code.Ldelem_Any:valueStack.pop(2); valueStack.push(getUnknownValue(instr.Operand as TypeReference)); break; case Code.Ldind_I1: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; case Code.Ldind_I2: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; case Code.Ldind_I4: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; case Code.Ldind_I8: valueStack.pop(); valueStack.push(Int64Value.createUnknown()); break; case Code.Ldind_U1: valueStack.pop(); valueStack.push(Int32Value.createUnknownUInt8()); break; case Code.Ldind_U2: valueStack.pop(); valueStack.push(Int32Value.createUnknownUInt16()); break; case Code.Ldind_U4: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; case Code.Ldlen: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break; case Code.Sizeof: valueStack.push(Int32Value.createUnknown()); break; case Code.Ldfld: emulate_Ldfld(instr); break; case Code.Ldsfld: emulate_Ldsfld(instr); break; case Code.Unbox: case Code.Conv_R_Un: case Code.Conv_R4: case Code.Conv_R8: case Code.Arglist: case Code.Beq: case Code.Beq_S: case Code.Bge: case Code.Bge_S: case Code.Bge_Un: case Code.Bge_Un_S: case Code.Bgt: case Code.Bgt_S: case Code.Bgt_Un: case Code.Bgt_Un_S: case Code.Ble: case Code.Ble_S: case Code.Ble_Un: case Code.Ble_Un_S: case Code.Blt: case Code.Blt_S: case Code.Blt_Un: case Code.Blt_Un_S: case Code.Bne_Un: case Code.Bne_Un_S: case Code.Brfalse: case Code.Brfalse_S: case Code.Brtrue: case Code.Brtrue_S: case Code.Br: case Code.Br_S: case Code.Break: case Code.Calli: case Code.Ckfinite: case Code.Constrained: case Code.Conv_I: case Code.Conv_Ovf_I: case Code.Conv_Ovf_I_Un: case Code.Conv_Ovf_U: case Code.Conv_Ovf_U_Un: case Code.Conv_U: case Code.Cpblk: case Code.Cpobj: case Code.Endfilter: case Code.Endfinally: case Code.Initblk: case Code.Initobj: case Code.Jmp: case Code.Ldelema: case Code.Ldelem_I: case Code.Ldelem_R4: case Code.Ldelem_R8: case Code.Ldelem_Ref: case Code.Ldflda: case Code.Ldftn: case Code.Ldind_I: case Code.Ldind_R4: case Code.Ldind_R8: case Code.Ldind_Ref: case Code.Ldobj: case Code.Ldsflda: case Code.Ldtoken: case Code.Ldvirtftn: case Code.Leave: case Code.Leave_S: case Code.Localloc: case Code.Mkrefany: case Code.Newarr: case Code.Newobj: case Code.No: case Code.Nop: case Code.Pop: case Code.Readonly: case Code.Refanytype: case Code.Refanyval: case Code.Ret: case Code.Rethrow: case Code.Stelem_Any: case Code.Stelem_I: case Code.Stelem_I1: case Code.Stelem_I2: case Code.Stelem_I4: case Code.Stelem_I8: case Code.Stelem_R4: case Code.Stelem_R8: case Code.Stelem_Ref: case Code.Stfld: case Code.Stind_I: case Code.Stind_I1: case Code.Stind_I2: case Code.Stind_I4: case Code.Stind_I8: case Code.Stind_R4: case Code.Stind_R8: case Code.Stind_Ref: case Code.Stobj: case Code.Stsfld: case Code.Switch: case Code.Tail: case Code.Throw: case Code.Unaligned: case Code.Volatile: default: updateStack(instr); break; } } void updateStack(Instruction instr) { int pushes, pops; DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops); if (pops == -1) valueStack.clear(); else { valueStack.pop(pops); valueStack.push(pushes); } } void emulate_Conv_U1(Instruction instr) { var val1 = valueStack.pop(); switch (val1.valueType) { case ValueType.Int32: valueStack.push(Int32Value.Conv_U1((Int32Value)val1)); break; case ValueType.Int64: valueStack.push(Int32Value.Conv_U1((Int64Value)val1)); break; case ValueType.Real8: valueStack.push(Int32Value.Conv_U1((Real8Value)val1)); break; default: valueStack.push(Int32Value.createUnknownUInt8()); break; } } void emulate_Conv_I1(Instruction instr) { var val1 = valueStack.pop(); switch (val1.valueType) { case ValueType.Int32: valueStack.push(Int32Value.Conv_I1((Int32Value)val1)); break; case ValueType.Int64: valueStack.push(Int32Value.Conv_I1((Int64Value)val1)); break; case ValueType.Real8: valueStack.push(Int32Value.Conv_I1((Real8Value)val1)); break; default: valueStack.push(Int32Value.createUnknown()); break; } } void emulate_Conv_U2(Instruction instr) { var val1 = valueStack.pop(); switch (val1.valueType) { case ValueType.Int32: valueStack.push(Int32Value.Conv_U2((Int32Value)val1)); break; case ValueType.Int64: valueStack.push(Int32Value.Conv_U2((Int64Value)val1)); break; case ValueType.Real8: valueStack.push(Int32Value.Conv_U2((Real8Value)val1)); break; default: valueStack.push(Int32Value.createUnknownUInt16()); break; } } void emulate_Conv_I2(Instruction instr) { var val1 = valueStack.pop(); switch (val1.valueType) { case ValueType.Int32: valueStack.push(Int32Value.Conv_I2((Int32Value)val1)); break; case ValueType.Int64: valueStack.push(Int32Value.Conv_I2((Int64Value)val1)); break; case ValueType.Real8: valueStack.push(Int32Value.Conv_I2((Real8Value)val1)); break; default: valueStack.push(Int32Value.createUnknown()); break; } } void emulate_Conv_U4(Instruction instr) { var val1 = valueStack.pop(); switch (val1.valueType) { case ValueType.Int32: valueStack.push(Int32Value.Conv_U4((Int32Value)val1)); break; case ValueType.Int64: valueStack.push(Int32Value.Conv_U4((Int64Value)val1)); break; case ValueType.Real8: valueStack.push(Int32Value.Conv_U4((Real8Value)val1)); break; default: valueStack.push(Int32Value.createUnknown()); break; } } void emulate_Conv_I4(Instruction instr) { var val1 = valueStack.pop(); switch (val1.valueType) { case ValueType.Int32: valueStack.push(Int32Value.Conv_I4((Int32Value)val1)); break; case ValueType.Int64: valueStack.push(Int32Value.Conv_I4((Int64Value)val1)); break; case ValueType.Real8: valueStack.push(Int32Value.Conv_I4((Real8Value)val1)); break; default: valueStack.push(Int32Value.createUnknown()); break; } } void emulate_Conv_U8(Instruction instr) { var val1 = valueStack.pop(); switch (val1.valueType) { case ValueType.Int32: valueStack.push(Int64Value.Conv_U8((Int32Value)val1)); break; case ValueType.Int64: valueStack.push(Int64Value.Conv_U8((Int64Value)val1)); break; case ValueType.Real8: valueStack.push(Int64Value.Conv_U8((Real8Value)val1)); break; default: valueStack.push(Int64Value.createUnknown()); break; } } void emulate_Conv_I8(Instruction instr) { var val1 = valueStack.pop(); switch (val1.valueType) { case ValueType.Int32: valueStack.push(Int64Value.Conv_I8((Int32Value)val1)); break; case ValueType.Int64: valueStack.push(Int64Value.Conv_I8((Int64Value)val1)); break; case ValueType.Real8: valueStack.push(Int64Value.Conv_I8((Real8Value)val1)); break; default: valueStack.push(Int64Value.createUnknown()); break; } } void emulate_Add(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Add((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Add((Int64Value)val1, (Int64Value)val2)); else if (val1.isReal8() && val2.isReal8()) valueStack.push(Real8Value.Add((Real8Value)val1, (Real8Value)val2)); else valueStack.pushUnknown(); } void emulate_Sub(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Sub((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Sub((Int64Value)val1, (Int64Value)val2)); else if (val1.isReal8() && val2.isReal8()) valueStack.push(Real8Value.Sub((Real8Value)val1, (Real8Value)val2)); else valueStack.pushUnknown(); } void emulate_Mul(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Mul((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Mul((Int64Value)val1, (Int64Value)val2)); else if (val1.isReal8() && val2.isReal8()) valueStack.push(Real8Value.Mul((Real8Value)val1, (Real8Value)val2)); else valueStack.pushUnknown(); } void emulate_Div(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Div((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Div((Int64Value)val1, (Int64Value)val2)); else if (val1.isReal8() && val2.isReal8()) valueStack.push(Real8Value.Div((Real8Value)val1, (Real8Value)val2)); else valueStack.pushUnknown(); } void emulate_Div_Un(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Div_Un((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Div_Un((Int64Value)val1, (Int64Value)val2)); else valueStack.pushUnknown(); } void emulate_Rem(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Rem((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Rem((Int64Value)val1, (Int64Value)val2)); else if (val1.isReal8() && val2.isReal8()) valueStack.push(Real8Value.Rem((Real8Value)val1, (Real8Value)val2)); else valueStack.pushUnknown(); } void emulate_Rem_Un(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Rem_Un((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Rem_Un((Int64Value)val1, (Int64Value)val2)); else valueStack.pushUnknown(); } void emulate_Neg(Instruction instr) { var val1 = valueStack.pop(); if (val1.isInt32()) valueStack.push(Int32Value.Neg((Int32Value)val1)); else if (val1.isInt64()) valueStack.push(Int64Value.Neg((Int64Value)val1)); else if (val1.isReal8()) valueStack.push(Real8Value.Neg((Real8Value)val1)); else valueStack.pushUnknown(); } void emulate_And(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.And((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.And((Int64Value)val1, (Int64Value)val2)); else valueStack.pushUnknown(); } void emulate_Or(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Or((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Or((Int64Value)val1, (Int64Value)val2)); else valueStack.pushUnknown(); } void emulate_Xor(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Xor((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Xor((Int64Value)val1, (Int64Value)val2)); else valueStack.pushUnknown(); } void emulate_Not(Instruction instr) { var val1 = valueStack.pop(); if (val1.isInt32()) valueStack.push(Int32Value.Not((Int32Value)val1)); else if (val1.isInt64()) valueStack.push(Int64Value.Not((Int64Value)val1)); else valueStack.pushUnknown(); } void emulate_Shl(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Shl((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt32()) valueStack.push(Int64Value.Shl((Int64Value)val1, (Int32Value)val2)); else valueStack.pushUnknown(); } void emulate_Shr(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Shr((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt32()) valueStack.push(Int64Value.Shr((Int64Value)val1, (Int32Value)val2)); else valueStack.pushUnknown(); } void emulate_Shr_Un(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Shr_Un((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt32()) valueStack.push(Int64Value.Shr_Un((Int64Value)val1, (Int32Value)val2)); else valueStack.pushUnknown(); } void emulate_Ceq(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Ceq((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Ceq((Int64Value)val1, (Int64Value)val2)); else if (val1.isNull() && val2.isNull()) valueStack.push(new Int32Value(1)); else valueStack.push(Int32Value.createUnknownBool()); } void emulate_Cgt(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Cgt((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Cgt((Int64Value)val1, (Int64Value)val2)); else valueStack.push(Int32Value.createUnknownBool()); } void emulate_Cgt_Un(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Cgt_Un((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Cgt_Un((Int64Value)val1, (Int64Value)val2)); else valueStack.push(Int32Value.createUnknownBool()); } void emulate_Clt(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Clt((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Clt((Int64Value)val1, (Int64Value)val2)); else valueStack.push(Int32Value.createUnknownBool()); } void emulate_Clt_Un(Instruction instr) { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.Clt_Un((Int32Value)val1, (Int32Value)val2)); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.Clt_Un((Int64Value)val1, (Int64Value)val2)); else valueStack.push(Int32Value.createUnknownBool()); } void emulate_Unbox_Any(Instruction instr) { var val1 = valueStack.pop(); if (val1.isBoxed()) valueStack.push(((BoxedValue)val1).value); else valueStack.pushUnknown(); } void emulate_Starg(ParameterDefinition arg) { setArg(index(arg), valueStack.pop()); } void emulate_Stloc(int index) { setLocal(index, valueStack.pop()); } void emulate_Ldarga(ParameterDefinition arg) { valueStack.pushUnknown(); setArg(index(arg), getUnknownArg(index(arg))); } void emulate_Ldloca(int index) { valueStack.pushUnknown(); setLocal(index, getUnknownLocal(index)); } void emulate_Call(Instruction instr) { emulate_Call(instr, (MethodReference)instr.Operand); } void emulate_Callvirt(Instruction instr) { emulate_Call(instr, (MethodReference)instr.Operand); } void emulate_Call(Instruction instr, MethodReference method) { int pushes, pops; DotNetUtils.calculateStackUsage(instr, false, out pushes, out pops); valueStack.pop(pops); if (pushes == 1) valueStack.push(getUnknownValue(method.MethodReturnType.ReturnType)); else valueStack.push(pushes); } void emulate_Castclass(Instruction instr) { var val1 = valueStack.pop(); if (val1.isNull()) valueStack.push(val1); else valueStack.pushUnknown(); } void emulate_Isinst(Instruction instr) { var val1 = valueStack.pop(); if (val1.isNull()) valueStack.push(val1); else valueStack.pushUnknown(); } void emulate_Ldfld(Instruction instr) { var val1 = valueStack.pop(); emulateLoadField(instr.Operand as FieldReference); } void emulate_Ldsfld(Instruction instr) { emulateLoadField(instr.Operand as FieldReference); } void emulateLoadField(FieldReference fieldReference) { if (fieldReference != null) valueStack.push(getUnknownValue(fieldReference.FieldType)); else valueStack.pushUnknown(); } void emulateIntOps2() { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if (val1.isInt32() && val2.isInt32()) valueStack.push(Int32Value.createUnknown()); else if (val1.isInt64() && val2.isInt64()) valueStack.push(Int64Value.createUnknown()); else valueStack.pushUnknown(); } } }