diff --git a/de4dot.blocks/cflow/CflowUtils.cs b/de4dot.blocks/cflow/CflowUtils.cs index 1f644bf1..401f75d1 100644 --- a/de4dot.blocks/cflow/CflowUtils.cs +++ b/de4dot.blocks/cflow/CflowUtils.cs @@ -25,7 +25,7 @@ namespace de4dot.blocks.cflow { if (!intValue.AllBitsValid()) return null; - int index = intValue.value; + int index = intValue.Value; if (targets == null || index < 0 || index >= targets.Count) return fallThrough; else diff --git a/de4dot.blocks/cflow/ConstantsFolder.cs b/de4dot.blocks/cflow/ConstantsFolder.cs index a0c7b5a7..9a600dfa 100644 --- a/de4dot.blocks/cflow/ConstantsFolder.cs +++ b/de4dot.blocks/cflow/ConstantsFolder.cs @@ -89,14 +89,14 @@ namespace de4dot.blocks.cflow { var intValue = (Int32Value)value; if (!intValue.AllBitsValid()) return false; - block.Instructions[index] = new Instr(Instruction.CreateLdcI4(intValue.value)); + block.Instructions[index] = new Instr(Instruction.CreateLdcI4(intValue.Value)); return true; } else if (value.IsInt64()) { var intValue = (Int64Value)value; if (!intValue.AllBitsValid()) return false; - block.Instructions[index] = new Instr(OpCodes.Ldc_I8.ToInstruction(intValue.value)); + block.Instructions[index] = new Instr(OpCodes.Ldc_I8.ToInstruction(intValue.Value)); return true; } return false; diff --git a/de4dot.blocks/cflow/InstructionEmulator.cs b/de4dot.blocks/cflow/InstructionEmulator.cs index 9dd11a1a..450eca08 100644 --- a/de4dot.blocks/cflow/InstructionEmulator.cs +++ b/de4dot.blocks/cflow/InstructionEmulator.cs @@ -168,7 +168,7 @@ namespace de4dot.blocks.cflow { case ElementType.R4: if (value.IsReal8()) - return new Real8Value((float)((Real8Value)value).value); + return ((Real8Value)value).ToSingle(); return new UnknownValue(); case ElementType.R8: @@ -324,8 +324,8 @@ namespace de4dot.blocks.cflow { 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(Int32Value.zero); break; - case Code.Ldc_I4_1: valueStack.Push(Int32Value.one); break; + case Code.Ldc_I4_0: valueStack.Push(Int32Value.Zero); break; + case Code.Ldc_I4_1: valueStack.Push(Int32Value.One); 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; @@ -374,29 +374,29 @@ namespace de4dot.blocks.cflow { 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.Add_Ovf: Emulate_Add_Ovf(instr); break; + case Code.Add_Ovf_Un: Emulate_Add_Ovf_Un(instr); break; + case Code.Sub_Ovf: Emulate_Sub_Ovf(instr); break; + case Code.Sub_Ovf_Un: Emulate_Sub_Ovf_Un(instr); break; + case Code.Mul_Ovf: Emulate_Mul_Ovf(instr); break; + case Code.Mul_Ovf_Un: Emulate_Mul_Ovf_Un(instr); 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.Conv_Ovf_I1: Emulate_Conv_Ovf_I1(instr); break; + case Code.Conv_Ovf_I1_Un: Emulate_Conv_Ovf_I1_Un(instr); break; + case Code.Conv_Ovf_I2: Emulate_Conv_Ovf_I2(instr); break; + case Code.Conv_Ovf_I2_Un: Emulate_Conv_Ovf_I2_Un(instr); break; + case Code.Conv_Ovf_I4: Emulate_Conv_Ovf_I4(instr); break; + case Code.Conv_Ovf_I4_Un: Emulate_Conv_Ovf_I4_Un(instr); break; + case Code.Conv_Ovf_I8: Emulate_Conv_Ovf_I8(instr); break; + case Code.Conv_Ovf_I8_Un: Emulate_Conv_Ovf_I8_Un(instr); break; + case Code.Conv_Ovf_U1: Emulate_Conv_Ovf_U1(instr); break; + case Code.Conv_Ovf_U1_Un: Emulate_Conv_Ovf_U1_Un(instr); break; + case Code.Conv_Ovf_U2: Emulate_Conv_Ovf_U2(instr); break; + case Code.Conv_Ovf_U2_Un: Emulate_Conv_Ovf_U2_Un(instr); break; + case Code.Conv_Ovf_U4: Emulate_Conv_Ovf_U4(instr); break; + case Code.Conv_Ovf_U4_Un: Emulate_Conv_Ovf_U4_Un(instr); break; + case Code.Conv_Ovf_U8: Emulate_Conv_Ovf_U8(instr); break; + case Code.Conv_Ovf_U8_Un: Emulate_Conv_Ovf_U8_Un(instr); 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; @@ -622,6 +622,166 @@ namespace de4dot.blocks.cflow { } } + void Emulate_Conv_Ovf_I1(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I1((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I1((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I1((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknown()); break; + } + } + + void Emulate_Conv_Ovf_I1_Un(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I1_Un((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I1_Un((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I1_Un((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknown()); break; + } + } + + void Emulate_Conv_Ovf_I2(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I2((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I2((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I2((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknown()); break; + } + } + + void Emulate_Conv_Ovf_I2_Un(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I2_Un((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I2_Un((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I2_Un((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknown()); break; + } + } + + void Emulate_Conv_Ovf_I4(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I4((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I4((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I4((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknown()); break; + } + } + + void Emulate_Conv_Ovf_I4_Un(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I4_Un((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I4_Un((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I4_Un((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknown()); break; + } + } + + void Emulate_Conv_Ovf_I8(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I8((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I8((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I8((Real8Value)val1)); break; + default: valueStack.Push(Int64Value.CreateUnknown()); break; + } + } + + void Emulate_Conv_Ovf_I8_Un(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I8_Un((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I8_Un((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I8_Un((Real8Value)val1)); break; + default: valueStack.Push(Int64Value.CreateUnknown()); break; + } + } + + void Emulate_Conv_Ovf_U1(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U1((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U1((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U1((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknownUInt8()); break; + } + } + + void Emulate_Conv_Ovf_U1_Un(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U1_Un((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U1_Un((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U1_Un((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknownUInt8()); break; + } + } + + void Emulate_Conv_Ovf_U2(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U2((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U2((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U2((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknownUInt16()); break; + } + } + + void Emulate_Conv_Ovf_U2_Un(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U2_Un((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U2_Un((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U2_Un((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknownUInt16()); break; + } + } + + void Emulate_Conv_Ovf_U4(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U4((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U4((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U4((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknown()); break; + } + } + + void Emulate_Conv_Ovf_U4_Un(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U4_Un((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U4_Un((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U4_Un((Real8Value)val1)); break; + default: valueStack.Push(Int32Value.CreateUnknown()); break; + } + } + + void Emulate_Conv_Ovf_U8(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U8((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U8((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U8((Real8Value)val1)); break; + default: valueStack.Push(Int64Value.CreateUnknown()); break; + } + } + + void Emulate_Conv_Ovf_U8_Un(Instruction instr) { + var val1 = valueStack.Pop(); + switch (val1.valueType) { + case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U8_Un((Int32Value)val1)); break; + case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U8_Un((Int64Value)val1)); break; + case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U8_Un((Real8Value)val1)); break; + default: valueStack.Push(Int64Value.CreateUnknown()); break; + } + } + void Emulate_Add(Instruction instr) { var val2 = valueStack.Pop(); var val1 = valueStack.Pop(); @@ -729,6 +889,90 @@ namespace de4dot.blocks.cflow { valueStack.PushUnknown(); } + void Emulate_Add_Ovf(Instruction instr) { + var val2 = valueStack.Pop(); + var val1 = valueStack.Pop(); + + if (val1.IsInt32() && val2.IsInt32()) + valueStack.Push(Int32Value.Add_Ovf((Int32Value)val1, (Int32Value)val2)); + else if (val1.IsInt64() && val2.IsInt64()) + valueStack.Push(Int64Value.Add_Ovf((Int64Value)val1, (Int64Value)val2)); + else if (val1.IsReal8() && val2.IsReal8()) + valueStack.Push(Real8Value.Add_Ovf((Real8Value)val1, (Real8Value)val2)); + else + valueStack.PushUnknown(); + } + + void Emulate_Add_Ovf_Un(Instruction instr) { + var val2 = valueStack.Pop(); + var val1 = valueStack.Pop(); + + if (val1.IsInt32() && val2.IsInt32()) + valueStack.Push(Int32Value.Add_Ovf_Un((Int32Value)val1, (Int32Value)val2)); + else if (val1.IsInt64() && val2.IsInt64()) + valueStack.Push(Int64Value.Add_Ovf_Un((Int64Value)val1, (Int64Value)val2)); + else if (val1.IsReal8() && val2.IsReal8()) + valueStack.Push(Real8Value.Add_Ovf_Un((Real8Value)val1, (Real8Value)val2)); + else + valueStack.PushUnknown(); + } + + void Emulate_Sub_Ovf(Instruction instr) { + var val2 = valueStack.Pop(); + var val1 = valueStack.Pop(); + + if (val1.IsInt32() && val2.IsInt32()) + valueStack.Push(Int32Value.Sub_Ovf((Int32Value)val1, (Int32Value)val2)); + else if (val1.IsInt64() && val2.IsInt64()) + valueStack.Push(Int64Value.Sub_Ovf((Int64Value)val1, (Int64Value)val2)); + else if (val1.IsReal8() && val2.IsReal8()) + valueStack.Push(Real8Value.Sub_Ovf((Real8Value)val1, (Real8Value)val2)); + else + valueStack.PushUnknown(); + } + + void Emulate_Sub_Ovf_Un(Instruction instr) { + var val2 = valueStack.Pop(); + var val1 = valueStack.Pop(); + + if (val1.IsInt32() && val2.IsInt32()) + valueStack.Push(Int32Value.Sub_Ovf_Un((Int32Value)val1, (Int32Value)val2)); + else if (val1.IsInt64() && val2.IsInt64()) + valueStack.Push(Int64Value.Sub_Ovf_Un((Int64Value)val1, (Int64Value)val2)); + else if (val1.IsReal8() && val2.IsReal8()) + valueStack.Push(Real8Value.Sub_Ovf_Un((Real8Value)val1, (Real8Value)val2)); + else + valueStack.PushUnknown(); + } + + void Emulate_Mul_Ovf(Instruction instr) { + var val2 = valueStack.Pop(); + var val1 = valueStack.Pop(); + + if (val1.IsInt32() && val2.IsInt32()) + valueStack.Push(Int32Value.Mul_Ovf((Int32Value)val1, (Int32Value)val2)); + else if (val1.IsInt64() && val2.IsInt64()) + valueStack.Push(Int64Value.Mul_Ovf((Int64Value)val1, (Int64Value)val2)); + else if (val1.IsReal8() && val2.IsReal8()) + valueStack.Push(Real8Value.Mul_Ovf((Real8Value)val1, (Real8Value)val2)); + else + valueStack.PushUnknown(); + } + + void Emulate_Mul_Ovf_Un(Instruction instr) { + var val2 = valueStack.Pop(); + var val1 = valueStack.Pop(); + + if (val1.IsInt32() && val2.IsInt32()) + valueStack.Push(Int32Value.Mul_Ovf_Un((Int32Value)val1, (Int32Value)val2)); + else if (val1.IsInt64() && val2.IsInt64()) + valueStack.Push(Int64Value.Mul_Ovf_Un((Int64Value)val1, (Int64Value)val2)); + else if (val1.IsReal8() && val2.IsReal8()) + valueStack.Push(Real8Value.Mul_Ovf_Un((Real8Value)val1, (Real8Value)val2)); + else + valueStack.PushUnknown(); + } + void Emulate_And(Instruction instr) { var val2 = valueStack.Pop(); var val1 = valueStack.Pop(); @@ -821,7 +1065,7 @@ namespace de4dot.blocks.cflow { else if (val1.IsInt64() && val2.IsInt64()) valueStack.Push(Int64Value.Ceq((Int64Value)val1, (Int64Value)val2)); else if (val1.IsNull() && val2.IsNull()) - valueStack.Push(Int32Value.one); + valueStack.Push(Int32Value.One); else valueStack.Push(Int32Value.CreateUnknownBool()); } diff --git a/de4dot.blocks/cflow/Int32Value.cs b/de4dot.blocks/cflow/Int32Value.cs index f885bf6a..bb838288 100644 --- a/de4dot.blocks/cflow/Int32Value.cs +++ b/de4dot.blocks/cflow/Int32Value.cs @@ -21,27 +21,27 @@ using System; namespace de4dot.blocks.cflow { public class Int32Value : Value { - public static readonly Int32Value zero = new Int32Value(0); - public static readonly Int32Value one = new Int32Value(1); + public static readonly Int32Value Zero = new Int32Value(0); + public static readonly Int32Value One = new Int32Value(1); - const uint NO_UNKNOWN_BITS = uint.MaxValue; - public readonly int value; - public readonly uint validMask; + internal const uint NO_UNKNOWN_BITS = uint.MaxValue; + public readonly int Value; + public readonly uint ValidMask; public Int32Value(int value) : base(ValueType.Int32) { - this.value = value; - this.validMask = NO_UNKNOWN_BITS; + this.Value = value; + this.ValidMask = NO_UNKNOWN_BITS; } public Int32Value(int value, uint validMask) : base(ValueType.Int32) { - this.value = value; - this.validMask = validMask; + this.Value = value; + this.ValidMask = validMask; } public bool HasUnknownBits() { - return validMask != NO_UNKNOWN_BITS; + return ValidMask != NO_UNKNOWN_BITS; } public bool AllBitsValid() { @@ -49,13 +49,17 @@ namespace de4dot.blocks.cflow { } bool IsBitValid(int n) { - return IsBitValid(validMask, n); + return IsBitValid(ValidMask, n); } static bool IsBitValid(uint validMask, int n) { return (validMask & (1U << n)) != 0; } + bool AreBitsValid(uint bitsToTest) { + return (ValidMask & bitsToTest) == bitsToTest; + } + public static Int32Value CreateUnknownBool() { return new Int32Value(0, NO_UNKNOWN_BITS << 1); } @@ -77,11 +81,11 @@ namespace de4dot.blocks.cflow { } public bool IsNonZero() { - return (value & validMask) != 0; + return ((uint)Value & ValidMask) != 0; } public bool HasValue(int value) { - return AllBitsValid() && this.value == value; + return AllBitsValid() && this.Value == value; } public bool HasValue(uint value) { @@ -113,11 +117,11 @@ namespace de4dot.blocks.cflow { } public static Int32Value Conv_U1(Int32Value a) { - return Conv_U1(a.value, a.validMask); + return Conv_U1(a.Value, a.ValidMask); } public static Int32Value Conv_U1(Int64Value a) { - return Conv_U1((int)a.value, (uint)a.validMask); + return Conv_U1((int)a.Value, (uint)a.ValidMask); } public static Int32Value Conv_U1(int value, uint validMask) { @@ -127,15 +131,17 @@ namespace de4dot.blocks.cflow { } public static Int32Value Conv_U1(Real8Value a) { - return new Int32Value((int)(byte)a.value); + if (!a.IsValid) + return CreateUnknownUInt8(); + return new Int32Value((int)(byte)a.Value); } public static Int32Value Conv_I1(Int32Value a) { - return Conv_I1(a.value, a.validMask); + return Conv_I1(a.Value, a.ValidMask); } public static Int32Value Conv_I1(Int64Value a) { - return Conv_I1((int)a.value, (uint)a.validMask); + return Conv_I1((int)a.Value, (uint)a.ValidMask); } public static Int32Value Conv_I1(int value, uint validMask) { @@ -148,15 +154,17 @@ namespace de4dot.blocks.cflow { } public static Int32Value Conv_I1(Real8Value a) { - return new Int32Value((int)(sbyte)a.value); + if (!a.IsValid) + return CreateUnknown(); + return new Int32Value((int)(sbyte)a.Value); } public static Int32Value Conv_U2(Int32Value a) { - return Conv_U2(a.value, a.validMask); + return Conv_U2(a.Value, a.ValidMask); } public static Int32Value Conv_U2(Int64Value a) { - return Conv_U2((int)a.value, (uint)a.validMask); + return Conv_U2((int)a.Value, (uint)a.ValidMask); } public static Int32Value Conv_U2(int value, uint validMask) { @@ -166,15 +174,17 @@ namespace de4dot.blocks.cflow { } public static Int32Value Conv_U2(Real8Value a) { - return new Int32Value((int)(ushort)a.value); + if (!a.IsValid) + return CreateUnknownUInt16(); + return new Int32Value((int)(ushort)a.Value); } public static Int32Value Conv_I2(Int32Value a) { - return Conv_I2(a.value, a.validMask); + return Conv_I2(a.Value, a.ValidMask); } public static Int32Value Conv_I2(Int64Value a) { - return Conv_I2((int)a.value, (uint)a.validMask); + return Conv_I2((int)a.Value, (uint)a.ValidMask); } public static Int32Value Conv_I2(int value, uint validMask) { @@ -187,7 +197,9 @@ namespace de4dot.blocks.cflow { } public static Int32Value Conv_I2(Real8Value a) { - return new Int32Value((int)(short)a.value); + if (!a.IsValid) + return CreateUnknown(); + return new Int32Value((int)(short)a.Value); } public static Int32Value Conv_U4(Int32Value a) { @@ -195,11 +207,13 @@ namespace de4dot.blocks.cflow { } public static Int32Value Conv_U4(Int64Value a) { - return new Int32Value((int)(uint)a.value, (uint)a.validMask); + return new Int32Value((int)(uint)a.Value, (uint)a.ValidMask); } public static Int32Value Conv_U4(Real8Value a) { - return new Int32Value((int)(uint)a.value); + if (!a.IsValid) + return CreateUnknown(); + return new Int32Value((int)(uint)a.Value); } public static Int32Value Conv_I4(Int32Value a) { @@ -207,34 +221,137 @@ namespace de4dot.blocks.cflow { } public static Int32Value Conv_I4(Int64Value a) { - return new Int32Value((int)a.value, (uint)a.validMask); + return new Int32Value((int)a.Value, (uint)a.ValidMask); } public static Int32Value Conv_I4(Real8Value a) { - return new Int32Value((int)a.value); + if (!a.IsValid) + return CreateUnknown(); + return new Int32Value((int)a.Value); + } + + bool CheckSign(uint mask) { + return ((uint)Value & mask) == 0 || ((uint)Value & mask) == mask; + } + + public static Int32Value Conv_Ovf_I1(Int32Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) || + !a.CheckSign(NO_UNKNOWN_BITS << 7)) + return CreateUnknown(); + return Conv_I1(a); + } + + public static Int32Value Conv_Ovf_I1_Un(Int32Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) || + (uint)a.Value > sbyte.MaxValue) + return CreateUnknown(); + return Conv_I1(a); + } + + public static Int32Value Conv_Ovf_I2(Int32Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) || + !a.CheckSign(NO_UNKNOWN_BITS << 15)) + return CreateUnknown(); + return Conv_I2(a); + } + + public static Int32Value Conv_Ovf_I2_Un(Int32Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) || + (uint)a.Value > short.MaxValue) + return CreateUnknown(); + return Conv_I2(a); + } + + public static Int32Value Conv_Ovf_I4(Int32Value a) { + return a; + } + + public static Int32Value Conv_Ovf_I4_Un(Int32Value a) { + if (!IsBitValid(a.ValidMask, 31) || a.Value < 0) + return CreateUnknown(); + return a; + } + + public static Int64Value Conv_Ovf_I8(Int32Value a) { + ulong validMask = a.ValidMask; + if (IsBitValid(a.ValidMask, 31)) + validMask |= Int64Value.NO_UNKNOWN_BITS << 32; + return new Int64Value(a.Value, validMask); + } + + public static Int64Value Conv_Ovf_I8_Un(Int32Value a) { + return new Int64Value((long)(uint)a.Value, a.ValidMask | (Int64Value.NO_UNKNOWN_BITS << 32)); + } + + public static Int32Value Conv_Ovf_U1(Int32Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) || + a.Value < 0 || a.Value > byte.MaxValue) + return CreateUnknownUInt8(); + return Conv_U1(a); + } + + public static Int32Value Conv_Ovf_U1_Un(Int32Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 8) || + (uint)a.Value > byte.MaxValue) + return CreateUnknownUInt8(); + return Conv_U1(a); + } + + public static Int32Value Conv_Ovf_U2(Int32Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) || + a.Value < 0 || a.Value > ushort.MaxValue) + return CreateUnknownUInt16(); + return Conv_U2(a); + } + + public static Int32Value Conv_Ovf_U2_Un(Int32Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 16) || + (uint)a.Value > ushort.MaxValue) + return CreateUnknownUInt16(); + return Conv_U2(a); + } + + public static Int32Value Conv_Ovf_U4(Int32Value a) { + if (!IsBitValid(a.ValidMask, 31) || a.Value < 0) + return CreateUnknown(); + return a; + } + + public static Int32Value Conv_Ovf_U4_Un(Int32Value a) { + return a; + } + + public static Int64Value Conv_Ovf_U8(Int32Value a) { + if (!IsBitValid(a.ValidMask, 31) || a.Value < 0) + return Int64Value.CreateUnknown(); + return new Int64Value(a.Value, (ulong)a.ValidMask | (Int64Value.NO_UNKNOWN_BITS << 32)); + } + + public static Int64Value Conv_Ovf_U8_Un(Int32Value a) { + return new Int64Value((long)(uint)a.Value, a.ValidMask | (Int64Value.NO_UNKNOWN_BITS << 32)); } public static Int32Value Add(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return new Int32Value(a.value + b.value); + return new Int32Value(a.Value + b.Value); if (ReferenceEquals(a, b)) - return new Int32Value(a.value << 1, (a.validMask << 1) | 1); + return new Int32Value(a.Value << 1, (a.ValidMask << 1) | 1); return CreateUnknown(); } public static Int32Value Sub(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return new Int32Value(a.value - b.value); + return new Int32Value(a.Value - b.Value); if (ReferenceEquals(a, b)) - return zero; + return Zero; return CreateUnknown(); } public static Int32Value Mul(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return new Int32Value(a.value * b.value); + return new Int32Value(a.Value * b.Value); if (a.IsZero() || b.IsZero()) - return zero; + return Zero; if (a.HasValue(1)) return b; if (b.HasValue(1)) @@ -245,14 +362,14 @@ namespace de4dot.blocks.cflow { public static Int32Value Div(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) { try { - return new Int32Value(a.value / b.value); + return new Int32Value(a.Value / b.Value); } catch (ArithmeticException) { return CreateUnknown(); } } if (ReferenceEquals(a, b) && a.IsNonZero()) - return one; + return One; if (b.HasValue(1)) return a; return CreateUnknown(); @@ -261,14 +378,14 @@ namespace de4dot.blocks.cflow { public static Int32Value Div_Un(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) { try { - return new Int32Value((int)((uint)a.value / (uint)b.value)); + return new Int32Value((int)((uint)a.Value / (uint)b.Value)); } catch (ArithmeticException) { return CreateUnknown(); } } if (ReferenceEquals(a, b) && a.IsNonZero()) - return one; + return One; if (b.HasValue(1)) return a; return CreateUnknown(); @@ -277,150 +394,219 @@ namespace de4dot.blocks.cflow { public static Int32Value Rem(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) { try { - return new Int32Value(a.value % b.value); + return new Int32Value(a.Value % b.Value); } catch (ArithmeticException) { return CreateUnknown(); } } if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1)) - return zero; + return Zero; return CreateUnknown(); } public static Int32Value Rem_Un(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) { try { - return new Int32Value((int)((uint)a.value % (uint)b.value)); + return new Int32Value((int)((uint)a.Value % (uint)b.Value)); } catch (ArithmeticException) { return CreateUnknown(); } } if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1)) - return zero; + return Zero; return CreateUnknown(); } public static Int32Value Neg(Int32Value a) { if (a.AllBitsValid()) - return new Int32Value(-a.value); + return new Int32Value(-a.Value); + return CreateUnknown(); + } + + public static Int32Value Add_Ovf(Int32Value a, Int32Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + try { + return new Int32Value(checked(a.Value + b.Value)); + } + catch (OverflowException) { + } + } + return CreateUnknown(); + } + + public static Int32Value Add_Ovf_Un(Int32Value a, Int32Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + uint aa = (uint)a.Value, bb = (uint)b.Value; + try { + return new Int32Value((int)checked(aa + bb)); + } + catch (OverflowException) { + } + } + return CreateUnknown(); + } + + public static Int32Value Sub_Ovf(Int32Value a, Int32Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + try { + return new Int32Value(checked(a.Value - b.Value)); + } + catch (OverflowException) { + } + } + return CreateUnknown(); + } + + public static Int32Value Sub_Ovf_Un(Int32Value a, Int32Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + uint aa = (uint)a.Value, bb = (uint)b.Value; + try { + return new Int32Value((int)checked(aa - bb)); + } + catch (OverflowException) { + } + } + return CreateUnknown(); + } + + public static Int32Value Mul_Ovf(Int32Value a, Int32Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + try { + return new Int32Value(checked(a.Value * b.Value)); + } + catch (OverflowException) { + } + } + return CreateUnknown(); + } + + public static Int32Value Mul_Ovf_Un(Int32Value a, Int32Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + uint aa = (uint)a.Value, bb = (uint)b.Value; + try { + return new Int32Value((int)checked(aa * bb)); + } + catch (OverflowException) { + } + } return CreateUnknown(); } public static Int32Value And(Int32Value a, Int32Value b) { - int av = a.value, bv = b.value; - uint am = a.validMask, bm = b.validMask; - return new Int32Value(av & bv, (uint)((am & bm) | ((av & am) ^ am) | ((bv & bm) ^ bm))); + int av = a.Value, bv = b.Value; + uint am = a.ValidMask, bm = b.ValidMask; + return new Int32Value(av & bv, (am & bm) | (((uint)av & am) ^ am) | (((uint)bv & bm) ^ bm)); } public static Int32Value Or(Int32Value a, Int32Value b) { - int av = a.value, bv = b.value; - uint am = a.validMask, bm = b.validMask; - return new Int32Value(av | bv, (uint)((am & bm) | (av & am) | (bv & bm))); + int av = a.Value, bv = b.Value; + uint am = a.ValidMask, bm = b.ValidMask; + return new Int32Value(av | bv, (am & bm) | ((uint)av & am) | ((uint)bv & bm)); } public static Int32Value Xor(Int32Value a, Int32Value b) { if (ReferenceEquals(a, b)) - return zero; - int av = a.value, bv = b.value; - uint am = a.validMask, bm = b.validMask; - return new Int32Value(av ^ bv, (uint)(am & bm)); + return Zero; + int av = a.Value, bv = b.Value; + uint am = a.ValidMask, bm = b.ValidMask; + return new Int32Value(av ^ bv, am & bm); } public static Int32Value Not(Int32Value a) { - return new Int32Value(~a.value, a.validMask); + return new Int32Value(~a.Value, a.ValidMask); } public static Int32Value Shl(Int32Value a, Int32Value b) { if (b.HasUnknownBits()) return CreateUnknown(); - if (b.value == 0) + if (b.Value == 0) return a; - if (b.value < 0 || b.value >= sizeof(int) * 8) + if (b.Value < 0 || b.Value >= sizeof(int) * 8) return CreateUnknown(); - int shift = b.value; - uint validMask = (a.validMask << shift) | (uint.MaxValue >> (sizeof(int) * 8 - shift)); - return new Int32Value(a.value << shift, validMask); + int shift = b.Value; + uint validMask = (a.ValidMask << shift) | (uint.MaxValue >> (sizeof(int) * 8 - shift)); + return new Int32Value(a.Value << shift, validMask); } public static Int32Value Shr(Int32Value a, Int32Value b) { if (b.HasUnknownBits()) return CreateUnknown(); - if (b.value == 0) + if (b.Value == 0) return a; - if (b.value < 0 || b.value >= sizeof(int) * 8) + if (b.Value < 0 || b.Value >= sizeof(int) * 8) return CreateUnknown(); - int shift = b.value; - uint validMask = a.validMask >> shift; + int shift = b.Value; + uint validMask = a.ValidMask >> shift; if (a.IsBitValid(sizeof(int) * 8 - 1)) validMask |= (uint.MaxValue << (sizeof(int) * 8 - shift)); - return new Int32Value(a.value >> shift, validMask); + return new Int32Value(a.Value >> shift, validMask); } public static Int32Value Shr_Un(Int32Value a, Int32Value b) { if (b.HasUnknownBits()) return CreateUnknown(); - if (b.value == 0) + if (b.Value == 0) return a; - if (b.value < 0 || b.value >= sizeof(int) * 8) + if (b.Value < 0 || b.Value >= sizeof(int) * 8) return CreateUnknown(); - int shift = b.value; - uint validMask = (a.validMask >> shift) | (uint.MaxValue << (sizeof(int) * 8 - shift)); - return new Int32Value((int)((uint)a.value >> shift), validMask); + int shift = b.Value; + uint validMask = (a.ValidMask >> shift) | (uint.MaxValue << (sizeof(int) * 8 - shift)); + return new Int32Value((int)((uint)a.Value >> shift), validMask); } - static Int32Value create(Bool3 b) { + static Int32Value Create(Bool3 b) { switch (b) { - case Bool3.False: return zero; - case Bool3.True: return one; + case Bool3.False: return Zero; + case Bool3.True: return One; default: return CreateUnknownBool(); } } public static Int32Value Ceq(Int32Value a, Int32Value b) { - return create(CompareEq(a, b)); + return Create(CompareEq(a, b)); } public static Int32Value Cgt(Int32Value a, Int32Value b) { - return create(CompareGt(a, b)); + return Create(CompareGt(a, b)); } public static Int32Value Cgt_Un(Int32Value a, Int32Value b) { - return create(CompareGt_Un(a, b)); + return Create(CompareGt_Un(a, b)); } public static Int32Value Clt(Int32Value a, Int32Value b) { - return create(CompareLt(a, b)); + return Create(CompareLt(a, b)); } public static Int32Value Clt_Un(Int32Value a, Int32Value b) { - return create(CompareLt_Un(a, b)); + return Create(CompareLt_Un(a, b)); } public static Bool3 CompareEq(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value == b.value ? Bool3.True : Bool3.False; + return a.Value == b.Value ? Bool3.True : Bool3.False; if (ReferenceEquals(a, b)) return Bool3.True; - if ((a.value & a.validMask & b.validMask) != (b.value & a.validMask & b.validMask)) + if (((uint)a.Value & a.ValidMask & b.ValidMask) != ((uint)b.Value & a.ValidMask & b.ValidMask)) return Bool3.False; return Bool3.Unknown; } public static Bool3 CompareNeq(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value != b.value ? Bool3.True : Bool3.False; + return a.Value != b.Value ? Bool3.True : Bool3.False; if (ReferenceEquals(a, b)) return Bool3.False; - if ((a.value & a.validMask & b.validMask) != (b.value & a.validMask & b.validMask)) + if (((uint)a.Value & a.ValidMask & b.ValidMask) != ((uint)b.Value & a.ValidMask & b.ValidMask)) return Bool3.True; return Bool3.Unknown; } public static Bool3 CompareGt(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value > b.value ? Bool3.True : Bool3.False; + return a.Value > b.Value ? Bool3.True : Bool3.False; if (a.HasValue(int.MinValue)) return Bool3.False; // min > x => false if (b.HasValue(int.MaxValue)) @@ -430,7 +616,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareGt_Un(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return (uint)a.value > (uint)b.value ? Bool3.True : Bool3.False; + return (uint)a.Value > (uint)b.Value ? Bool3.True : Bool3.False; if (a.HasValue(uint.MinValue)) return Bool3.False; // min > x => false if (b.HasValue(uint.MaxValue)) @@ -440,7 +626,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareGe(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value >= b.value ? Bool3.True : Bool3.False; + return a.Value >= b.Value ? Bool3.True : Bool3.False; if (a.HasValue(int.MaxValue)) return Bool3.True; // max >= x => true if (b.HasValue(int.MinValue)) @@ -450,7 +636,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareGe_Un(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return (uint)a.value >= (uint)b.value ? Bool3.True : Bool3.False; + return (uint)a.Value >= (uint)b.Value ? Bool3.True : Bool3.False; if (a.HasValue(uint.MaxValue)) return Bool3.True; // max >= x => true if (b.HasValue(uint.MinValue)) @@ -460,7 +646,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareLe(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value <= b.value ? Bool3.True : Bool3.False; + return a.Value <= b.Value ? Bool3.True : Bool3.False; if (a.HasValue(int.MinValue)) return Bool3.True; // min <= x => true if (b.HasValue(int.MaxValue)) @@ -470,7 +656,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareLe_Un(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return (uint)a.value <= (uint)b.value ? Bool3.True : Bool3.False; + return (uint)a.Value <= (uint)b.Value ? Bool3.True : Bool3.False; if (a.HasValue(uint.MinValue)) return Bool3.True; // min <= x => true if (b.HasValue(uint.MaxValue)) @@ -480,7 +666,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareLt(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value < b.value ? Bool3.True : Bool3.False; + return a.Value < b.Value ? Bool3.True : Bool3.False; if (a.HasValue(int.MaxValue)) return Bool3.False; // max < x => false if (b.HasValue(int.MinValue)) @@ -490,7 +676,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareLt_Un(Int32Value a, Int32Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return (uint)a.value < (uint)b.value ? Bool3.True : Bool3.False; + return (uint)a.Value < (uint)b.Value ? Bool3.True : Bool3.False; if (a.HasValue(uint.MaxValue)) return Bool3.False; // max < x => false if (b.HasValue(uint.MinValue)) @@ -500,24 +686,24 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareTrue(Int32Value a) { if (a.AllBitsValid()) - return a.value != 0 ? Bool3.True : Bool3.False; - if ((a.value & a.validMask) != 0) + return a.Value != 0 ? Bool3.True : Bool3.False; + if (((uint)a.Value & a.ValidMask) != 0) return Bool3.True; return Bool3.Unknown; } public static Bool3 CompareFalse(Int32Value a) { if (a.AllBitsValid()) - return a.value == 0 ? Bool3.True : Bool3.False; - if ((a.value & a.validMask) != 0) + return a.Value == 0 ? Bool3.True : Bool3.False; + if (((uint)a.Value & a.ValidMask) != 0) return Bool3.False; return Bool3.Unknown; } public override string ToString() { if (AllBitsValid()) - return value.ToString(); - return string.Format("0x{0:X8}({1:X8})", value, validMask); + return Value.ToString(); + return string.Format("0x{0:X8}({1:X8})", Value, ValidMask); } } } diff --git a/de4dot.blocks/cflow/Int64Value.cs b/de4dot.blocks/cflow/Int64Value.cs index 9ec2ff41..48a236e3 100644 --- a/de4dot.blocks/cflow/Int64Value.cs +++ b/de4dot.blocks/cflow/Int64Value.cs @@ -21,27 +21,27 @@ using System; namespace de4dot.blocks.cflow { public class Int64Value : Value { - public static readonly Int64Value zero = new Int64Value(0); - public static readonly Int64Value one = new Int64Value(1); + public static readonly Int64Value Zero = new Int64Value(0); + public static readonly Int64Value One = new Int64Value(1); - const ulong NO_UNKNOWN_BITS = ulong.MaxValue; - public readonly long value; - public readonly ulong validMask; + internal const ulong NO_UNKNOWN_BITS = ulong.MaxValue; + public readonly long Value; + public readonly ulong ValidMask; public Int64Value(long value) : base(ValueType.Int64) { - this.value = value; - this.validMask = NO_UNKNOWN_BITS; + this.Value = value; + this.ValidMask = NO_UNKNOWN_BITS; } public Int64Value(long value, ulong validMask) : base(ValueType.Int64) { - this.value = value; - this.validMask = validMask; + this.Value = value; + this.ValidMask = validMask; } bool HasUnknownBits() { - return validMask != NO_UNKNOWN_BITS; + return ValidMask != NO_UNKNOWN_BITS; } public bool AllBitsValid() { @@ -49,13 +49,17 @@ namespace de4dot.blocks.cflow { } bool IsBitValid(int n) { - return IsBitValid(validMask, n); + return IsBitValid(ValidMask, n); } static bool IsBitValid(ulong validMask, int n) { return (validMask & (1UL << n)) != 0; } + bool AreBitsValid(ulong bitsToTest) { + return (ValidMask & bitsToTest) == bitsToTest; + } + public static Int64Value CreateUnknown() { return new Int64Value(0, 0UL); } @@ -65,11 +69,11 @@ namespace de4dot.blocks.cflow { } public bool IsNonZero() { - return ((ulong)value & validMask) != 0; + return ((ulong)Value & ValidMask) != 0; } public bool HasValue(long value) { - return AllBitsValid() && this.value == value; + return AllBitsValid() && this.Value == value; } public bool HasValue(ulong value) { @@ -77,8 +81,8 @@ namespace de4dot.blocks.cflow { } public static Int64Value Conv_U8(Int32Value a) { - long value = (long)(ulong)(uint)a.value; - ulong validMask = a.validMask | (NO_UNKNOWN_BITS << 32); + long value = (long)(ulong)(uint)a.Value; + ulong validMask = a.ValidMask | (NO_UNKNOWN_BITS << 32); return new Int64Value(value, validMask); } @@ -87,12 +91,14 @@ namespace de4dot.blocks.cflow { } public static Int64Value Conv_U8(Real8Value a) { - return new Int64Value((long)(ulong)a.value); + if (!a.IsValid) + return CreateUnknown(); + return new Int64Value((long)(ulong)a.Value); } public static Int64Value Conv_I8(Int32Value a) { - long value = a.value; - ulong validMask = a.validMask; + long value = a.Value; + ulong validMask = a.ValidMask; if (IsBitValid(validMask, 31)) validMask |= NO_UNKNOWN_BITS << 32; else @@ -105,30 +111,140 @@ namespace de4dot.blocks.cflow { } public static Int64Value Conv_I8(Real8Value a) { - return new Int64Value((long)a.value); + if (!a.IsValid) + return CreateUnknown(); + return new Int64Value((long)a.Value); + } + + bool CheckSign(ulong mask) { + return ((ulong)Value & mask) == 0 || ((ulong)Value & mask) == mask; + } + + public static Int32Value Conv_Ovf_I1(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) || + !a.CheckSign(NO_UNKNOWN_BITS << 7)) + return Int32Value.CreateUnknown(); + return Int32Value.Conv_I1(a); + } + + public static Int32Value Conv_Ovf_I1_Un(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) || + (ulong)a.Value > (ulong)sbyte.MaxValue) + return Int32Value.CreateUnknown(); + return Int32Value.Conv_I1(a); + } + + public static Int32Value Conv_Ovf_I2(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) || + !a.CheckSign(NO_UNKNOWN_BITS << 15)) + return Int32Value.CreateUnknown(); + return Int32Value.Conv_I2(a); + } + + public static Int32Value Conv_Ovf_I2_Un(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) || + (ulong)a.Value > (ulong)short.MaxValue) + return Int32Value.CreateUnknown(); + return Int32Value.Conv_I2(a); + } + + public static Int32Value Conv_Ovf_I4(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 31) || + !a.CheckSign(NO_UNKNOWN_BITS << 31)) + return Int32Value.CreateUnknown(); + return Int32Value.Conv_I4(a); + } + + public static Int32Value Conv_Ovf_I4_Un(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 31) || + (ulong)a.Value > (ulong)int.MaxValue) + return Int32Value.CreateUnknown(); + return Int32Value.Conv_I4(a); + } + + public static Int64Value Conv_Ovf_I8(Int64Value a) { + return a; + } + + public static Int64Value Conv_Ovf_I8_Un(Int64Value a) { + if (!IsBitValid(a.ValidMask, 63) || a.Value < 0) + return CreateUnknown(); + return a; + } + + public static Int32Value Conv_Ovf_U1(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) || + a.Value < 0 || a.Value > byte.MaxValue) + return Int32Value.CreateUnknownUInt8(); + return Int32Value.Conv_U1(a); + } + + public static Int32Value Conv_Ovf_U1_Un(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 8) || + (ulong)a.Value > byte.MaxValue) + return Int32Value.CreateUnknownUInt8(); + return Int32Value.Conv_U1(a); + } + + public static Int32Value Conv_Ovf_U2(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) || + a.Value < 0 || a.Value > ushort.MaxValue) + return Int32Value.CreateUnknownUInt16(); + return Int32Value.Conv_U2(a); + } + + public static Int32Value Conv_Ovf_U2_Un(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 16) || + (ulong)a.Value > ushort.MaxValue) + return Int32Value.CreateUnknownUInt16(); + return Int32Value.Conv_U2(a); + } + + public static Int32Value Conv_Ovf_U4(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 31) || + a.Value < 0 || a.Value > uint.MaxValue) + return Int32Value.CreateUnknown(); + return Int32Value.Conv_U4(a); + } + + public static Int32Value Conv_Ovf_U4_Un(Int64Value a) { + if (!a.AreBitsValid(NO_UNKNOWN_BITS << 32) || + (ulong)a.Value > uint.MaxValue) + return Int32Value.CreateUnknown(); + return Int32Value.Conv_U4(a); + } + + public static Int64Value Conv_Ovf_U8(Int64Value a) { + if (!IsBitValid(a.ValidMask, 63) || a.Value < 0) + return CreateUnknown(); + return a; + } + + public static Int64Value Conv_Ovf_U8_Un(Int64Value a) { + return a; } public static Int64Value Add(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return new Int64Value(a.value + b.value); + return new Int64Value(a.Value + b.Value); if (ReferenceEquals(a, b)) - return new Int64Value(a.value << 1, (a.validMask << 1) | 1); + return new Int64Value(a.Value << 1, (a.ValidMask << 1) | 1); return CreateUnknown(); } public static Int64Value Sub(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return new Int64Value(a.value - b.value); + return new Int64Value(a.Value - b.Value); if (ReferenceEquals(a, b)) - return zero; + return Zero; return CreateUnknown(); } public static Int64Value Mul(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return new Int64Value(a.value * b.value); + return new Int64Value(a.Value * b.Value); if (a.IsZero() || b.IsZero()) - return zero; + return Zero; if (a.HasValue(1)) return b; if (b.HasValue(1)) @@ -139,14 +255,14 @@ namespace de4dot.blocks.cflow { public static Int64Value Div(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) { try { - return new Int64Value(a.value / b.value); + return new Int64Value(a.Value / b.Value); } catch (ArithmeticException) { return CreateUnknown(); } } if (ReferenceEquals(a, b) && a.IsNonZero()) - return one; + return One; if (b.HasValue(1)) return a; return CreateUnknown(); @@ -155,14 +271,14 @@ namespace de4dot.blocks.cflow { public static Int64Value Div_Un(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) { try { - return new Int64Value((long)((ulong)a.value / (ulong)b.value)); + return new Int64Value((long)((ulong)a.Value / (ulong)b.Value)); } catch (ArithmeticException) { return CreateUnknown(); } } if (ReferenceEquals(a, b) && a.IsNonZero()) - return one; + return One; if (b.HasValue(1)) return a; return CreateUnknown(); @@ -171,103 +287,172 @@ namespace de4dot.blocks.cflow { public static Int64Value Rem(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) { try { - return new Int64Value(a.value % b.value); + return new Int64Value(a.Value % b.Value); } catch (ArithmeticException) { return CreateUnknown(); } } if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1)) - return zero; + return Zero; return CreateUnknown(); } public static Int64Value Rem_Un(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) { try { - return new Int64Value((long)((ulong)a.value % (ulong)b.value)); + return new Int64Value((long)((ulong)a.Value % (ulong)b.Value)); } catch (ArithmeticException) { return CreateUnknown(); } } if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1)) - return zero; + return Zero; return CreateUnknown(); } public static Int64Value Neg(Int64Value a) { if (a.AllBitsValid()) - return new Int64Value(-a.value); + return new Int64Value(-a.Value); + return CreateUnknown(); + } + + public static Int64Value Add_Ovf(Int64Value a, Int64Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + try { + return new Int64Value(checked(a.Value + b.Value)); + } + catch (OverflowException) { + } + } + return CreateUnknown(); + } + + public static Int64Value Add_Ovf_Un(Int64Value a, Int64Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + ulong aa = (ulong)a.Value, bb = (ulong)b.Value; + try { + return new Int64Value((long)checked(aa + bb)); + } + catch (OverflowException) { + } + } + return CreateUnknown(); + } + + public static Int64Value Sub_Ovf(Int64Value a, Int64Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + try { + return new Int64Value(checked(a.Value - b.Value)); + } + catch (OverflowException) { + } + } + return CreateUnknown(); + } + + public static Int64Value Sub_Ovf_Un(Int64Value a, Int64Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + ulong aa = (ulong)a.Value, bb = (ulong)b.Value; + try { + return new Int64Value((long)checked(aa - bb)); + } + catch (OverflowException) { + } + } + return CreateUnknown(); + } + + public static Int64Value Mul_Ovf(Int64Value a, Int64Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + try { + return new Int64Value(checked(a.Value * b.Value)); + } + catch (OverflowException) { + } + } + return CreateUnknown(); + } + + public static Int64Value Mul_Ovf_Un(Int64Value a, Int64Value b) { + if (a.AllBitsValid() && b.AllBitsValid()) { + ulong aa = (ulong)a.Value, bb = (ulong)b.Value; + try { + return new Int64Value((long)checked(aa * bb)); + } + catch (OverflowException) { + } + } return CreateUnknown(); } public static Int64Value And(Int64Value a, Int64Value b) { - long av = a.value, bv = b.value; - ulong am = a.validMask, bm = b.validMask; + long av = a.Value, bv = b.Value; + ulong am = a.ValidMask, bm = b.ValidMask; return new Int64Value(av & bv, (am & bm) | (((ulong)av & am) ^ am) | (((ulong)bv & bm) ^ bm)); } public static Int64Value Or(Int64Value a, Int64Value b) { - long av = a.value, bv = b.value; - ulong am = a.validMask, bm = b.validMask; + long av = a.Value, bv = b.Value; + ulong am = a.ValidMask, bm = b.ValidMask; return new Int64Value(av | bv, (am & bm) | ((ulong)av & am) | ((ulong)bv & bm)); } public static Int64Value Xor(Int64Value a, Int64Value b) { if (ReferenceEquals(a, b)) - return zero; - long av = a.value, bv = b.value; - ulong am = a.validMask, bm = b.validMask; + return Zero; + long av = a.Value, bv = b.Value; + ulong am = a.ValidMask, bm = b.ValidMask; return new Int64Value(av ^ bv, am & bm); } public static Int64Value Not(Int64Value a) { - return new Int64Value(~a.value, a.validMask); + return new Int64Value(~a.Value, a.ValidMask); } public static Int64Value Shl(Int64Value a, Int32Value b) { if (b.HasUnknownBits()) return CreateUnknown(); - if (b.value == 0) + if (b.Value == 0) return a; - if (b.value < 0 || b.value >= sizeof(long) * 8) + if (b.Value < 0 || b.Value >= sizeof(long) * 8) return CreateUnknown(); - int shift = b.value; - ulong validMask = (a.validMask << shift) | (ulong.MaxValue >> (sizeof(long) * 8 - shift)); - return new Int64Value(a.value << shift, validMask); + int shift = b.Value; + ulong validMask = (a.ValidMask << shift) | (ulong.MaxValue >> (sizeof(long) * 8 - shift)); + return new Int64Value(a.Value << shift, validMask); } public static Int64Value Shr(Int64Value a, Int32Value b) { if (b.HasUnknownBits()) return CreateUnknown(); - if (b.value == 0) + if (b.Value == 0) return a; - if (b.value < 0 || b.value >= sizeof(long) * 8) + if (b.Value < 0 || b.Value >= sizeof(long) * 8) return CreateUnknown(); - int shift = b.value; - ulong validMask = a.validMask >> shift; + int shift = b.Value; + ulong validMask = a.ValidMask >> shift; if (a.IsBitValid(sizeof(long) * 8 - 1)) validMask |= (ulong.MaxValue << (sizeof(long) * 8 - shift)); - return new Int64Value(a.value >> shift, validMask); + return new Int64Value(a.Value >> shift, validMask); } public static Int64Value Shr_Un(Int64Value a, Int32Value b) { if (b.HasUnknownBits()) return CreateUnknown(); - if (b.value == 0) + if (b.Value == 0) return a; - if (b.value < 0 || b.value >= sizeof(long) * 8) + if (b.Value < 0 || b.Value >= sizeof(long) * 8) return CreateUnknown(); - int shift = b.value; - ulong validMask = (a.validMask >> shift) | (ulong.MaxValue << (sizeof(long) * 8 - shift)); - return new Int64Value((long)((ulong)a.value >> shift), validMask); + int shift = b.Value; + ulong validMask = (a.ValidMask >> shift) | (ulong.MaxValue << (sizeof(long) * 8 - shift)); + return new Int64Value((long)((ulong)a.Value >> shift), validMask); } static Int32Value Create(Bool3 b) { switch (b) { - case Bool3.False: return Int32Value.zero; - case Bool3.True: return Int32Value.one; + case Bool3.False: return Int32Value.Zero; + case Bool3.True: return Int32Value.One; default: return Int32Value.CreateUnknownBool(); } } @@ -294,27 +479,27 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareEq(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value == b.value ? Bool3.True : Bool3.False; + return a.Value == b.Value ? Bool3.True : Bool3.False; if (ReferenceEquals(a, b)) return Bool3.True; - if (((ulong)a.value & a.validMask & b.validMask) != ((ulong)b.value & a.validMask & b.validMask)) + if (((ulong)a.Value & a.ValidMask & b.ValidMask) != ((ulong)b.Value & a.ValidMask & b.ValidMask)) return Bool3.False; return Bool3.Unknown; } public static Bool3 CompareNeq(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value != b.value ? Bool3.True : Bool3.False; + return a.Value != b.Value ? Bool3.True : Bool3.False; if (ReferenceEquals(a, b)) return Bool3.False; - if (((ulong)a.value & a.validMask & b.validMask) != ((ulong)b.value & a.validMask & b.validMask)) + if (((ulong)a.Value & a.ValidMask & b.ValidMask) != ((ulong)b.Value & a.ValidMask & b.ValidMask)) return Bool3.True; return Bool3.Unknown; } public static Bool3 CompareGt(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value > b.value ? Bool3.True : Bool3.False; + return a.Value > b.Value ? Bool3.True : Bool3.False; if (a.HasValue(long.MinValue)) return Bool3.False; // min > x => false if (b.HasValue(long.MaxValue)) @@ -324,7 +509,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareGt_Un(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return (ulong)a.value > (ulong)b.value ? Bool3.True : Bool3.False; + return (ulong)a.Value > (ulong)b.Value ? Bool3.True : Bool3.False; if (a.HasValue(ulong.MinValue)) return Bool3.False; // min > x => false if (b.HasValue(ulong.MaxValue)) @@ -334,7 +519,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareGe(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value >= b.value ? Bool3.True : Bool3.False; + return a.Value >= b.Value ? Bool3.True : Bool3.False; if (a.HasValue(long.MaxValue)) return Bool3.True; // max >= x => true if (b.HasValue(long.MinValue)) @@ -344,7 +529,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareGe_Un(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return (ulong)a.value >= (ulong)b.value ? Bool3.True : Bool3.False; + return (ulong)a.Value >= (ulong)b.Value ? Bool3.True : Bool3.False; if (a.HasValue(ulong.MaxValue)) return Bool3.True; // max >= x => true if (b.HasValue(ulong.MinValue)) @@ -354,7 +539,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareLe(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value <= b.value ? Bool3.True : Bool3.False; + return a.Value <= b.Value ? Bool3.True : Bool3.False; if (a.HasValue(long.MinValue)) return Bool3.True; // min <= x => true if (b.HasValue(long.MaxValue)) @@ -364,7 +549,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareLe_Un(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return (ulong)a.value <= (ulong)b.value ? Bool3.True : Bool3.False; + return (ulong)a.Value <= (ulong)b.Value ? Bool3.True : Bool3.False; if (a.HasValue(ulong.MinValue)) return Bool3.True; // min <= x => true if (b.HasValue(ulong.MaxValue)) @@ -374,7 +559,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareLt(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return a.value < b.value ? Bool3.True : Bool3.False; + return a.Value < b.Value ? Bool3.True : Bool3.False; if (a.HasValue(long.MaxValue)) return Bool3.False; // max < x => false if (b.HasValue(long.MinValue)) @@ -384,7 +569,7 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareLt_Un(Int64Value a, Int64Value b) { if (a.AllBitsValid() && b.AllBitsValid()) - return (ulong)a.value < (ulong)b.value ? Bool3.True : Bool3.False; + return (ulong)a.Value < (ulong)b.Value ? Bool3.True : Bool3.False; if (a.HasValue(ulong.MaxValue)) return Bool3.False; // max < x => false if (b.HasValue(ulong.MinValue)) @@ -394,24 +579,24 @@ namespace de4dot.blocks.cflow { public static Bool3 CompareTrue(Int64Value a) { if (a.AllBitsValid()) - return a.value != 0 ? Bool3.True : Bool3.False; - if (((ulong)a.value & a.validMask) != 0) + return a.Value != 0 ? Bool3.True : Bool3.False; + if (((ulong)a.Value & a.ValidMask) != 0) return Bool3.True; return Bool3.Unknown; } public static Bool3 CompareFalse(Int64Value a) { if (a.AllBitsValid()) - return a.value == 0 ? Bool3.True : Bool3.False; - if (((ulong)a.value & a.validMask) != 0) + return a.Value == 0 ? Bool3.True : Bool3.False; + if (((ulong)a.Value & a.ValidMask) != 0) return Bool3.False; return Bool3.Unknown; } public override string ToString() { if (AllBitsValid()) - return value.ToString(); - return string.Format("0x{0:X8}L({1:X8})", value, validMask); + return Value.ToString(); + return string.Format("0x{0:X8}L({1:X8})", Value, ValidMask); } } } diff --git a/de4dot.blocks/cflow/Real8Value.cs b/de4dot.blocks/cflow/Real8Value.cs index 868f2339..5087046d 100644 --- a/de4dot.blocks/cflow/Real8Value.cs +++ b/de4dot.blocks/cflow/Real8Value.cs @@ -19,35 +19,159 @@ namespace de4dot.blocks.cflow { public class Real8Value : Value { - public readonly double value; + public readonly double Value; + public readonly bool IsValid; public Real8Value(double value) : base(ValueType.Real8) { - this.value = value; + this.Value = value; + this.IsValid = true; + } + + public Real8Value(double value, bool isValid) + : base(ValueType.Real8) { + this.Value = value; + this.IsValid = isValid; + } + + public static Real8Value CreateUnknown() { + return new Real8Value(0, false); + } + + public Real8Value ToSingle() { + if (!IsValid) + return CreateUnknown(); + return new Real8Value((float)Value); } public static Real8Value Add(Real8Value a, Real8Value b) { - return new Real8Value(a.value + b.value); + if (!a.IsValid || !b.IsValid) + return CreateUnknown(); + return new Real8Value(a.Value + b.Value); } public static Real8Value Sub(Real8Value a, Real8Value b) { - return new Real8Value(a.value - b.value); + if (!a.IsValid || !b.IsValid) + return CreateUnknown(); + return new Real8Value(a.Value - b.Value); } public static Real8Value Mul(Real8Value a, Real8Value b) { - return new Real8Value(a.value * b.value); + if (!a.IsValid || !b.IsValid) + return CreateUnknown(); + return new Real8Value(a.Value * b.Value); } public static Real8Value Div(Real8Value a, Real8Value b) { - return new Real8Value(a.value / b.value); + if (!a.IsValid || !b.IsValid) + return CreateUnknown(); + return new Real8Value(a.Value / b.Value); } public static Real8Value Rem(Real8Value a, Real8Value b) { - return new Real8Value(a.value % b.value); + if (!a.IsValid || !b.IsValid) + return CreateUnknown(); + return new Real8Value(a.Value % b.Value); } public static Real8Value Neg(Real8Value a) { - return new Real8Value(-a.value); + if (!a.IsValid) + return CreateUnknown(); + return new Real8Value(-a.Value); + } + + public static Real8Value Add_Ovf(Real8Value a, Real8Value b) { + return CreateUnknown(); + } + + public static Real8Value Add_Ovf_Un(Real8Value a, Real8Value b) { + return CreateUnknown(); + } + + public static Real8Value Sub_Ovf(Real8Value a, Real8Value b) { + return CreateUnknown(); + } + + public static Real8Value Sub_Ovf_Un(Real8Value a, Real8Value b) { + return CreateUnknown(); + } + + public static Real8Value Mul_Ovf(Real8Value a, Real8Value b) { + return CreateUnknown(); + } + + public static Real8Value Mul_Ovf_Un(Real8Value a, Real8Value b) { + return CreateUnknown(); + } + + public static Int32Value Conv_Ovf_I1(Real8Value a) { + return Int32Value.CreateUnknown(); + } + + public static Int32Value Conv_Ovf_I1_Un(Real8Value a) { + return Int32Value.CreateUnknown(); + } + + public static Int32Value Conv_Ovf_I2(Real8Value a) { + return Int32Value.CreateUnknown(); + } + + public static Int32Value Conv_Ovf_I2_Un(Real8Value a) { + return Int32Value.CreateUnknown(); + } + + public static Int32Value Conv_Ovf_I4(Real8Value a) { + return Int32Value.CreateUnknown(); + } + + public static Int32Value Conv_Ovf_I4_Un(Real8Value a) { + return Int32Value.CreateUnknown(); + } + + public static Int64Value Conv_Ovf_I8(Real8Value a) { + return Int64Value.CreateUnknown(); + } + + public static Int64Value Conv_Ovf_I8_Un(Real8Value a) { + return Int64Value.CreateUnknown(); + } + + public static Int32Value Conv_Ovf_U1(Real8Value a) { + return Int32Value.CreateUnknownUInt8(); + } + + public static Int32Value Conv_Ovf_U1_Un(Real8Value a) { + return Int32Value.CreateUnknownUInt8(); + } + + public static Int32Value Conv_Ovf_U2(Real8Value a) { + return Int32Value.CreateUnknownUInt16(); + } + + public static Int32Value Conv_Ovf_U2_Un(Real8Value a) { + return Int32Value.CreateUnknownUInt16(); + } + + public static Int32Value Conv_Ovf_U4(Real8Value a) { + return Int32Value.CreateUnknown(); + } + + public static Int32Value Conv_Ovf_U4_Un(Real8Value a) { + return Int32Value.CreateUnknown(); + } + + public static Int64Value Conv_Ovf_U8(Real8Value a) { + return Int64Value.CreateUnknown(); + } + + public static Int64Value Conv_Ovf_U8_Un(Real8Value a) { + return Int64Value.CreateUnknown(); + } + + public override string ToString() { + if (!IsValid) + return ""; + return Value.ToString(); } } } diff --git a/de4dot.code/deobfuscators/ArrayFinder.cs b/de4dot.code/deobfuscators/ArrayFinder.cs index 821405eb..af7ccc1b 100644 --- a/de4dot.code/deobfuscators/ArrayFinder.cs +++ b/de4dot.code/deobfuscators/ArrayFinder.cs @@ -86,7 +86,7 @@ namespace de4dot.code.deobfuscators { var intValue = resultValueArray[i] as Int32Value; if (intValue == null || !intValue.AllBitsValid()) return null; - resultArray[i] = (byte)intValue.value; + resultArray[i] = (byte)intValue.Value; } return resultArray; } @@ -99,7 +99,7 @@ namespace de4dot.code.deobfuscators { var intValue = resultValueArray[i] as Int32Value; if (intValue == null || !intValue.AllBitsValid()) return null; - resultArray[i] = (short)intValue.value; + resultArray[i] = (short)intValue.Value; } return resultArray; } @@ -112,7 +112,7 @@ namespace de4dot.code.deobfuscators { var intValue = resultValueArray[i] as Int32Value; if (intValue == null || !intValue.AllBitsValid()) return null; - resultArray[i] = (int)intValue.value; + resultArray[i] = (int)intValue.Value; } return resultArray; } @@ -168,8 +168,8 @@ namespace de4dot.code.deobfuscators { var index = emulator.Pop() as Int32Value; var array = emulator.Pop(); if (ReferenceEquals(array, theArray) && index != null && index.AllBitsValid()) { - if (0 <= index.value && index.value < resultValueArray.Length) - resultValueArray[index.value] = value; + if (0 <= index.Value && index.Value < resultValueArray.Length) + resultValueArray[index.Value] = value; } } else diff --git a/de4dot.code/deobfuscators/Babel_NET/BabelMethodCallInliner.cs b/de4dot.code/deobfuscators/Babel_NET/BabelMethodCallInliner.cs index eb514e26..88623545 100644 --- a/de4dot.code/deobfuscators/Babel_NET/BabelMethodCallInliner.cs +++ b/de4dot.code/deobfuscators/Babel_NET/BabelMethodCallInliner.cs @@ -64,8 +64,8 @@ namespace de4dot.code.deobfuscators.Babel_NET { return false; var instr = instructions[emulateIndex]; var targets = (Instruction[])instr.Operand; - if (switchIndex.value >= 0 && switchIndex.value < targets.Length) - emulateIndex = instructions.IndexOf(targets[switchIndex.value]); + if (switchIndex.Value >= 0 && switchIndex.Value < targets.Length) + emulateIndex = instructions.IndexOf(targets[switchIndex.Value]); else emulateIndex++; return true; @@ -221,7 +221,7 @@ namespace de4dot.code.deobfuscators.Babel_NET { var retValue2 = (Int32Value)retValue; if (!retValue2.AllBitsValid()) return false; - newValue = retValue2.value; + newValue = retValue2.Value; return true; default: diff --git a/de4dot.code/deobfuscators/Babel_NET/StringDecrypter.cs b/de4dot.code/deobfuscators/Babel_NET/StringDecrypter.cs index bda53b08..77b4f663 100644 --- a/de4dot.code/deobfuscators/Babel_NET/StringDecrypter.cs +++ b/de4dot.code/deobfuscators/Babel_NET/StringDecrypter.cs @@ -126,7 +126,7 @@ namespace de4dot.code.deobfuscators.Babel_NET { emulator.Push(new Int32Value(offset)); foreach (var instr in OffsetCalcInstructions) emulator.Emulate(instr); - return ((Int32Value)emulator.Pop()).value; + return ((Int32Value)emulator.Pop()).Value; } public string Decrypt(object[] args) { @@ -348,7 +348,7 @@ namespace de4dot.code.deobfuscators.Babel_NET { case Code.Newarr: var arrayType = (ITypeDefOrRef)instr.Operand; - int arrayCount = ((Int32Value)emulator.Pop()).value; + int arrayCount = ((Int32Value)emulator.Pop()).Value; if (arrayType.FullName == "System.Char") emulator.Push(new UserValue(new char[arrayCount])); else @@ -362,7 +362,7 @@ namespace de4dot.code.deobfuscators.Babel_NET { break; case Code.Ldelem_U1: - arrayIndex = ((Int32Value)emulator.Pop()).value; + arrayIndex = ((Int32Value)emulator.Pop()).Value; array = (Value)emulator.Pop(); if (array is UserValue) emulator.Push(new Int32Value(((byte[])((UserValue)array).obj)[arrayIndex])); @@ -372,22 +372,22 @@ namespace de4dot.code.deobfuscators.Babel_NET { case Code.Stelem_I1: value = emulator.Pop(); - arrayIndex = ((Int32Value)emulator.Pop()).value; + arrayIndex = ((Int32Value)emulator.Pop()).Value; array = (Value)emulator.Pop(); if (array is UserValue) - ((byte[])((UserValue)array).obj)[arrayIndex] = (byte)((Int32Value)value).value; + ((byte[])((UserValue)array).obj)[arrayIndex] = (byte)((Int32Value)value).Value; break; case Code.Stelem_I2: value = emulator.Pop(); - arrayIndex = ((Int32Value)emulator.Pop()).value; + arrayIndex = ((Int32Value)emulator.Pop()).Value; array = (Value)emulator.Pop(); if (array is UserValue) - ((char[])((UserValue)array).obj)[arrayIndex] = (char)((Int32Value)value).value; + ((char[])((UserValue)array).obj)[arrayIndex] = (char)((Int32Value)value).Value; break; case Code.Ldelem_Ref: - arrayIndex = ((Int32Value)emulator.Pop()).value; + arrayIndex = ((Int32Value)emulator.Pop()).Value; array = (Value)emulator.Pop(); var userValue = array as UserValue; if (userValue != null && userValue.obj is string[]) @@ -451,7 +451,7 @@ namespace de4dot.code.deobfuscators.Babel_NET { object CreateDNLibOperand(OpCode opcode, Value op) { if (op is Int32Value) - return ((Int32Value)op).value; + return ((Int32Value)op).Value; if (op is StringValue) return ((StringValue)op).value; return null; diff --git a/de4dot.code/deobfuscators/DeepSea/DsMethodCallInliner.cs b/de4dot.code/deobfuscators/DeepSea/DsMethodCallInliner.cs index 0a23829a..7da4cc1d 100644 --- a/de4dot.code/deobfuscators/DeepSea/DsMethodCallInliner.cs +++ b/de4dot.code/deobfuscators/DeepSea/DsMethodCallInliner.cs @@ -191,8 +191,8 @@ namespace de4dot.code.deobfuscators.DeepSea { if (value == null || !value.AllBitsValid()) return false; var targets = (Instruction[])instr.Operand; - if (value.value >= 0 && value.value < targets.Length) - index = instrs.IndexOf(targets[value.value]); + if (value.Value >= 0 && value.Value < targets.Length) + index = instrs.IndexOf(targets[value.Value]); else index++; break; diff --git a/de4dot.code/deobfuscators/Dotfuscator/StringDecrypter.cs b/de4dot.code/deobfuscators/Dotfuscator/StringDecrypter.cs index 71466c7b..5576b00f 100644 --- a/de4dot.code/deobfuscators/Dotfuscator/StringDecrypter.cs +++ b/de4dot.code/deobfuscators/Dotfuscator/StringDecrypter.cs @@ -73,15 +73,23 @@ namespace de4dot.code.deobfuscators.Dotfuscator { continue; simpleDeobfuscator.Deobfuscate(method); - var instructions = method.Body.Instructions; - for (int i = 0; i <= instructions.Count - 3; i++) { - var ldci4 = method.Body.Instructions[i]; + var instrs = method.Body.Instructions; + for (int i = 0; i < instrs.Count - 3; i++) { + var ldarg = instrs[i]; + if (!ldarg.IsLdarg() || ldarg.GetParameterIndex() != 0) + continue; + var callvirt = instrs[i + 1]; + if (callvirt.OpCode.Code != Code.Callvirt) + continue; + var calledMethod = callvirt.Operand as MemberRef; + if (calledMethod == null || calledMethod.FullName != "System.Char[] System.String::ToCharArray()") + continue; + var stloc = instrs[i + 2]; + if (!stloc.IsStloc()) + continue; + var ldci4 = instrs[i + 3]; if (!ldci4.IsLdcI4()) continue; - if (instructions[i + 1].OpCode.Code != Code.Ldarg_1) - continue; - if (instructions[i + 2].OpCode.Code != Code.Add) - continue; var info = new StringDecrypterInfo(method, ldci4.GetLdcI4Value()); stringDecrypterMethods.Add(info.method, info); diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs index 26b0d1cc..a03df11b 100644 --- a/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs +++ b/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs @@ -626,7 +626,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { if (val == null || !val.AllBitsValid()) fields[field] = null; else - fields[field] = val.value; + fields[field] = val.Value; break; case Code.Call: