diff --git a/blocks/blocks.csproj b/blocks/blocks.csproj
index f36efde1..13fb747f 100644
--- a/blocks/blocks.csproj
+++ b/blocks/blocks.csproj
@@ -37,6 +37,9 @@
+
+
+
diff --git a/blocks/cflow/BlockControlFlowDeobfuscator.cs b/blocks/cflow/BlockControlFlowDeobfuscator.cs
index 8223f435..acb457fd 100644
--- a/blocks/cflow/BlockControlFlowDeobfuscator.cs
+++ b/blocks/cflow/BlockControlFlowDeobfuscator.cs
@@ -71,6 +71,12 @@ namespace de4dot.blocks.cflow {
}
}
+ bool emulateBranch(int stackArgs, Bool3 cond) {
+ if (cond == Bool3.Unknown)
+ return false;
+ return emulateBranch(stackArgs, cond == Bool3.True);
+ }
+
bool emulateBranch(int stackArgs, bool isTaken) {
// Pop the arguments to the bcc instruction. The dead code remover will get rid of the
// pop and any pushed arguments. Insert the pops just before the bcc instr.
@@ -85,461 +91,133 @@ namespace de4dot.blocks.cflow {
var val2 = instructionEmulator.pop();
var val1 = instructionEmulator.pop();
- //TODO: If it's an unknown int32/64, push 1 if val1 is same ref as val2
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- return emulateBranch(2, int1.value == int2.value);
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- return emulateBranch(2, long1.value == long2.value);
- }
- else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
- var real1 = (Real8Value)val1;
- var real2 = (Real8Value)val2;
- return emulateBranch(2, real1.value == real2.value);
- }
- else if (val1.valueType == ValueType.Null && val2.valueType == ValueType.Null) {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ return emulateBranch(2, Int32Value.compareEq((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ return emulateBranch(2, Int64Value.compareEq((Int64Value)val1, (Int64Value)val2));
+ else if (val1.valueType == ValueType.Null && val2.valueType == ValueType.Null)
return emulateBranch(2, true);
- }
- else {
+ else
return false;
- }
}
bool emulate_Bne_Un() {
var val2 = instructionEmulator.pop();
var val1 = instructionEmulator.pop();
- //TODO: If it's an unknown int32/64, push 1 if val1 is same ref as val2
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- return emulateBranch(2, (uint)int1.value != (uint)int2.value);
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- return emulateBranch(2, (ulong)long1.value != (ulong)long2.value);
- }
- else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
- var real1 = (Real8Value)val1;
- var real2 = (Real8Value)val2;
- return emulateBranch(2, real1.value != real2.value);
- }
- else if (val1.valueType == ValueType.Null && val2.valueType == ValueType.Null) {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ return emulateBranch(2, Int32Value.compareNeq((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ return emulateBranch(2, Int64Value.compareNeq((Int64Value)val1, (Int64Value)val2));
+ else if (val1.valueType == ValueType.Null && val2.valueType == ValueType.Null)
return emulateBranch(2, false);
- }
- else {
+ else
return false;
- }
}
bool emulate_Bge() {
var val2 = instructionEmulator.pop();
var val1 = instructionEmulator.pop();
- //TODO: Support floats
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- return emulateBranch(2, int1.value >= int2.value);
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- return emulateBranch(2, long1.value >= long2.value);
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if (int1.value == int.MaxValue)
- return emulateBranch(2, true); // max >= x => true
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if (int2.value == int.MinValue)
- return emulateBranch(2, true); // x >= min => true
- else
- return false;
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if (long1.value == long.MaxValue)
- return emulateBranch(2, true); // max >= x => true
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if (long2.value == long.MinValue)
- return emulateBranch(2, true); // x >= min => true
- else
- return false;
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ return emulateBranch(2, Int32Value.compareGe((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ return emulateBranch(2, Int64Value.compareGe((Int64Value)val1, (Int64Value)val2));
+ else
return false;
- }
}
bool emulate_Bge_Un() {
var val2 = instructionEmulator.pop();
var val1 = instructionEmulator.pop();
- //TODO: Support floats
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- return emulateBranch(2, (uint)int1.value >= (uint)int2.value);
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- return emulateBranch(2, (ulong)long1.value >= (ulong)long2.value);
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if ((uint)int1.value == uint.MaxValue)
- return emulateBranch(2, true); // max >= x => true
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if ((uint)int2.value == uint.MinValue)
- return emulateBranch(2, true); // x >= min => true
- else
- return false;
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if ((ulong)long1.value == ulong.MaxValue)
- return emulateBranch(2, true); // max >= x => true
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if ((ulong)long2.value == ulong.MinValue)
- return emulateBranch(2, true); // x >= min => true
- else
- return false;
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ return emulateBranch(2, Int32Value.compareGe_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ return emulateBranch(2, Int64Value.compareGe_Un((Int64Value)val1, (Int64Value)val2));
+ else
return false;
- }
}
bool emulate_Bgt() {
var val2 = instructionEmulator.pop();
var val1 = instructionEmulator.pop();
- //TODO: Support floats
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- return emulateBranch(2, int1.value > int2.value);
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- return emulateBranch(2, long1.value > long2.value);
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if (int1.value == int.MinValue)
- return emulateBranch(2, false); // min > x => false
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if (int2.value == int.MaxValue)
- return emulateBranch(2, false); // x > max => false
- else
- return false;
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if (long1.value == long.MinValue)
- return emulateBranch(2, false); // min > x => false
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if (long2.value == long.MaxValue)
- return emulateBranch(2, false); // x > max => false
- else
- return false;
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ return emulateBranch(2, Int32Value.compareGt((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ return emulateBranch(2, Int64Value.compareGt((Int64Value)val1, (Int64Value)val2));
+ else
return false;
- }
}
bool emulate_Bgt_Un() {
var val2 = instructionEmulator.pop();
var val1 = instructionEmulator.pop();
- //TODO: Support floats
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- return emulateBranch(2, (uint)int1.value > (uint)int2.value);
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- return emulateBranch(2, (ulong)long1.value > (ulong)long2.value);
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if ((uint)int1.value == uint.MinValue)
- return emulateBranch(2, false); // min > x => false
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if ((uint)int2.value == uint.MaxValue)
- return emulateBranch(2, false); // x > max => false
- else
- return false;
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if ((ulong)long1.value == ulong.MinValue)
- return emulateBranch(2, false); // min > x => false
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if ((ulong)long2.value == ulong.MaxValue)
- return emulateBranch(2, false); // x > max => false
- else
- return false;
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ return emulateBranch(2, Int32Value.compareGt_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ return emulateBranch(2, Int64Value.compareGt_Un((Int64Value)val1, (Int64Value)val2));
+ else
return false;
- }
}
bool emulate_Ble() {
var val2 = instructionEmulator.pop();
var val1 = instructionEmulator.pop();
- //TODO: Support floats
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- return emulateBranch(2, int1.value <= int2.value);
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- return emulateBranch(2, long1.value <= long2.value);
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if (int1.value == int.MinValue)
- return emulateBranch(2, true); // min <= x => true
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if (int2.value == int.MaxValue)
- return emulateBranch(2, true); // x <= max => true
- else
- return false;
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if (long1.value == long.MinValue)
- return emulateBranch(2, true); // min <= x => true
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if (long2.value == long.MaxValue)
- return emulateBranch(2, true); // x <= max => true
- else
- return false;
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ return emulateBranch(2, Int32Value.compareLe((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ return emulateBranch(2, Int64Value.compareLe((Int64Value)val1, (Int64Value)val2));
+ else
return false;
- }
}
bool emulate_Ble_Un() {
var val2 = instructionEmulator.pop();
var val1 = instructionEmulator.pop();
- //TODO: Support floats
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- return emulateBranch(2, (uint)int1.value <= (uint)int2.value);
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- return emulateBranch(2, (ulong)long1.value <= (ulong)long2.value);
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if ((uint)int1.value == uint.MinValue)
- return emulateBranch(2, true); // min <= x => true
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if ((uint)int2.value == uint.MaxValue)
- return emulateBranch(2, true); // x <= max => true
- else
- return false;
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if ((ulong)long1.value == ulong.MinValue)
- return emulateBranch(2, true); // min <= x => true
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if ((ulong)long2.value == ulong.MaxValue)
- return emulateBranch(2, true); // x <= max => true
- else
- return false;
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ return emulateBranch(2, Int32Value.compareLe_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ return emulateBranch(2, Int64Value.compareLe_Un((Int64Value)val1, (Int64Value)val2));
+ else
return false;
- }
}
bool emulate_Blt() {
var val2 = instructionEmulator.pop();
var val1 = instructionEmulator.pop();
- //TODO: Support floats
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- return emulateBranch(2, int1.value < int2.value);
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- return emulateBranch(2, long1.value < long2.value);
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if (int1.value == int.MaxValue)
- return emulateBranch(2, false); // max < x => false
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if (int2.value == int.MinValue)
- return emulateBranch(2, false); // x < min => false
- else
- return false;
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if (long1.value == long.MaxValue)
- return emulateBranch(2, false); // max < x => false
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if (long2.value == long.MinValue)
- return emulateBranch(2, false); // x < min => false
- else
- return false;
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ return emulateBranch(2, Int32Value.compareLt((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ return emulateBranch(2, Int64Value.compareLt((Int64Value)val1, (Int64Value)val2));
+ else
return false;
- }
}
bool emulate_Blt_Un() {
var val2 = instructionEmulator.pop();
var val1 = instructionEmulator.pop();
- //TODO: Support floats
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- return emulateBranch(2, (uint)int1.value < (uint)int2.value);
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- return emulateBranch(2, (ulong)long1.value < (ulong)long2.value);
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if ((uint)int1.value == uint.MaxValue)
- return emulateBranch(2, false); // max < x => false
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if ((uint)int2.value == uint.MinValue)
- return emulateBranch(2, false); // x < min => false
- else
- return false;
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if ((ulong)long1.value == ulong.MaxValue)
- return emulateBranch(2, false); // max < x => false
- else
- return false;
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if ((ulong)long2.value == ulong.MinValue)
- return emulateBranch(2, false); // x < min => false
- else
- return false;
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ return emulateBranch(2, Int32Value.compareLt_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ return emulateBranch(2, Int64Value.compareLt_Un((Int64Value)val1, (Int64Value)val2));
+ else
return false;
- }
}
bool emulate_Brfalse() {
var val1 = instructionEmulator.pop();
- //TODO: Support floats
-
if (val1.valueType == ValueType.Int32)
- return emulateBranch(1, ((Int32Value)val1).value == 0);
+ return emulateBranch(1, Int32Value.compareFalse((Int32Value)val1));
else if (val1.valueType == ValueType.Int64)
- return emulateBranch(1, ((Int64Value)val1).value == 0);
+ return emulateBranch(1, Int64Value.compareFalse((Int64Value)val1));
else if (val1.valueType == ValueType.Null)
return emulateBranch(1, true);
else
@@ -549,12 +227,10 @@ namespace de4dot.blocks.cflow {
bool emulate_Brtrue() {
var val1 = instructionEmulator.pop();
- //TODO: Support floats
-
if (val1.valueType == ValueType.Int32)
- return emulateBranch(1, ((Int32Value)val1).value != 0);
+ return emulateBranch(1, Int32Value.compareTrue((Int32Value)val1));
else if (val1.valueType == ValueType.Int64)
- return emulateBranch(1, ((Int64Value)val1).value != 0);
+ return emulateBranch(1, Int64Value.compareTrue((Int64Value)val1));
else if (val1.valueType == ValueType.Null)
return emulateBranch(1, false);
else
diff --git a/blocks/cflow/InstructionEmulator.cs b/blocks/cflow/InstructionEmulator.cs
index 5a6298cc..ccfc45e6 100644
--- a/blocks/cflow/InstructionEmulator.cs
+++ b/blocks/cflow/InstructionEmulator.cs
@@ -35,50 +35,61 @@ namespace de4dot.blocks.cflow {
this.variableDefinitions = variableDefinitions;
valueStack.init();
- initValueList(args, parameterDefinitions.Count);
+ args.Clear();
+ foreach (var arg in parameterDefinitions)
+ args.Add(getUnknownValue(arg.ParameterType));
if (initLocals) {
locals.Clear();
- for (int i = 0; i < variableDefinitions.Count; i++) {
- var localType = variableDefinitions[i].VariableType;
- if (!localType.IsValueType)
- locals.Add(NullValue.Instance);
- else if (DotNetUtils.isAssembly(localType.Scope, "mscorlib")) {
- switch (localType.FullName) {
- case "System.Boolean":
- case "System.Byte":
- case "System.SByte":
- case "System.Int16":
- case "System.Int32":
- case "System.UInt16":
- case "System.UInt32":
- locals.Add(new Int32Value(0));
- break;
- case "System.Int64":
- case "System.UInt64":
- locals.Add(new Int64Value(0));
- break;
- case "System.Single":
- case "System.Double":
- locals.Add(new Real8Value(0));
- break;
- default:
- locals.Add(new UnknownValue());
- break;
- }
- }
- else
- locals.Add(new UnknownValue());
- }
+ foreach (var local in variableDefinitions)
+ locals.Add(getDefaultValue(local.VariableType));
+ }
+ else {
+ locals.Clear();
+ foreach (var local in variableDefinitions)
+ locals.Add(getUnknownValue(local.VariableType));
}
- else
- initValueList(locals, variableDefinitions.Count);
}
- void initValueList(List list, int size) {
- list.Clear();
- for (int i = 0; i < size; i++)
- list.Add(new UnknownValue());
+ static Value getDefaultValue(TypeReference typeReference) {
+ if (!typeReference.IsValueType)
+ return NullValue.Instance;
+ else if (DotNetUtils.isAssembly(typeReference.Scope, "mscorlib")) {
+ switch (typeReference.FullName) {
+ case "System.Boolean":
+ case "System.Byte":
+ case "System.SByte":
+ case "System.Int16":
+ case "System.Int32":
+ case "System.UInt16":
+ 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 (DotNetUtils.isAssembly(typeReference.Scope, "mscorlib")) {
+ switch (typeReference.FullName) {
+ case "System.Boolean": return Int32Value.createUnknownBool();
+ case "System.Byte": return Int32Value.createUnknownUInt8();
+ case "System.SByte": return Int32Value.createUnknown();
+ case "System.Int16": return Int32Value.createUnknown();
+ case "System.Int32": return Int32Value.createUnknown();
+ case "System.UInt16": return Int32Value.createUnknownUInt16();
+ case "System.UInt32": return Int32Value.createUnknown();
+ case "System.Int64": return Int64Value.createUnknown();
+ case "System.UInt64": return Int64Value.createUnknown();
+ }
+ }
+ return new UnknownValue();
}
static Value getValue(List list, int i) {
@@ -100,6 +111,12 @@ namespace de4dot.blocks.cflow {
args[index] = value;
}
+ Value getUnknownArg(int index) {
+ if (0 <= index && index < parameterDefinitions.Count)
+ return getUnknownValue(parameterDefinitions[index].ParameterType);
+ return new UnknownValue();
+ }
+
Value getLocal(int i) {
return getValue(locals, i);
}
@@ -113,6 +130,12 @@ namespace de4dot.blocks.cflow {
locals[index] = value;
}
+ Value getUnknownLocal(int index) {
+ if (0 <= index && index < variableDefinitions.Count)
+ return getUnknownValue(variableDefinitions[index].VariableType);
+ return new UnknownValue();
+ }
+
public Value pop() {
return valueStack.pop();
}
@@ -197,6 +220,9 @@ namespace de4dot.blocks.cflow {
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.Add_Ovf:
case Code.Add_Ovf_Un:
case Code.Sub_Ovf:
@@ -238,9 +264,7 @@ namespace de4dot.blocks.cflow {
case Code.Br:
case Code.Break:
case Code.Br_S:
- case Code.Call:
case Code.Calli:
- case Code.Callvirt:
case Code.Castclass:
case Code.Ckfinite:
case Code.Constrained:
@@ -364,204 +388,83 @@ namespace de4dot.blocks.cflow {
}
}
- void switchUnknownToSecondOperand(ref Value op1, ref Value op2) {
- if (op2.valueType == ValueType.Unknown)
- return;
- if (op1.valueType != ValueType.Unknown)
- return;
- Value tmp = op1;
- op1 = op2;
- op2 = tmp;
- }
-
void emulate_Conv_U1(Instruction instr) {
- //TODO: Doc says that result is sign-extended. You zero-extend it. Is that correct?
var val1 = valueStack.pop();
switch (val1.valueType) {
- case ValueType.Int32:
- var val32 = (Int32Value)val1;
- valueStack.push(new Int32Value((int)(byte)val32.value));
- break;
-
- case ValueType.Int64:
- var val64 = (Int64Value)val1;
- valueStack.push(new Int32Value((int)(byte)val64.value));
- break;
-
- case ValueType.Real8:
- var valr8 = (Real8Value)val1;
- valueStack.push(new Int32Value((int)(byte)valr8.value));
- break;
-
- default:
- valueStack.pushUnknown();
- break;
+ 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.pushUnknown(); break;
}
}
void emulate_Conv_I1(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
- case ValueType.Int32:
- var val32 = (Int32Value)val1;
- valueStack.push(new Int32Value((int)(sbyte)val32.value));
- break;
-
- case ValueType.Int64:
- var val64 = (Int64Value)val1;
- valueStack.push(new Int32Value((int)(sbyte)val64.value));
- break;
-
- case ValueType.Real8:
- var valr8 = (Real8Value)val1;
- valueStack.push(new Int32Value((int)(sbyte)valr8.value));
- break;
-
- default:
- valueStack.pushUnknown();
- break;
+ 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.pushUnknown(); break;
}
}
void emulate_Conv_U2(Instruction instr) {
- //TODO: Doc says that result is sign-extended. You zero-extend it. Is that correct?
var val1 = valueStack.pop();
switch (val1.valueType) {
- case ValueType.Int32:
- var val32 = (Int32Value)val1;
- valueStack.push(new Int32Value((int)(ushort)val32.value));
- break;
-
- case ValueType.Int64:
- var val64 = (Int64Value)val1;
- valueStack.push(new Int32Value((int)(ushort)val64.value));
- break;
-
- case ValueType.Real8:
- var valr8 = (Real8Value)val1;
- valueStack.push(new Int32Value((int)(ushort)valr8.value));
- break;
-
- default:
- valueStack.pushUnknown();
- break;
+ 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.pushUnknown(); break;
}
}
void emulate_Conv_I2(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
- case ValueType.Int32:
- var val32 = (Int32Value)val1;
- valueStack.push(new Int32Value((int)(short)val32.value));
- break;
-
- case ValueType.Int64:
- var val64 = (Int64Value)val1;
- valueStack.push(new Int32Value((int)(short)val64.value));
- break;
-
- case ValueType.Real8:
- var valr8 = (Real8Value)val1;
- valueStack.push(new Int32Value((int)(short)valr8.value));
- break;
-
- default:
- valueStack.pushUnknown();
- break;
+ 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.pushUnknown(); break;
}
}
void emulate_Conv_U4(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
- case ValueType.Int32:
- valueStack.push(val1);
- break;
-
- case ValueType.Int64:
- var val64 = (Int64Value)val1;
- valueStack.push(new Int32Value((int)(uint)val64.value));
- break;
-
- case ValueType.Real8:
- var valr8 = (Real8Value)val1;
- valueStack.push(new Int32Value((int)(uint)valr8.value));
- break;
-
- default:
- valueStack.pushUnknown();
- break;
+ 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.pushUnknown(); break;
}
}
void emulate_Conv_I4(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
- case ValueType.Int32:
- valueStack.push(val1);
- break;
-
- case ValueType.Int64:
- var val64 = (Int64Value)val1;
- valueStack.push(new Int32Value((int)val64.value));
- break;
-
- case ValueType.Real8:
- var valr8 = (Real8Value)val1;
- valueStack.push(new Int32Value((int)valr8.value));
- break;
-
- default:
- valueStack.pushUnknown();
- break;
+ 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.pushUnknown(); break;
}
}
void emulate_Conv_U8(Instruction instr) {
- //TODO: Doc says that result is sign-extended. You zero-extend it. Is that correct?
var val1 = valueStack.pop();
switch (val1.valueType) {
- case ValueType.Int32:
- var val32 = (Int32Value)val1;
- valueStack.push(new Int64Value((long)(ulong)(uint)val32.value));
- break;
-
- case ValueType.Int64:
- valueStack.push(val1);
- break;
-
- case ValueType.Real8:
- var valr8 = (Real8Value)val1;
- valueStack.push(new Int64Value((long)(ulong)valr8.value));
- break;
-
- default:
- valueStack.pushUnknown();
- break;
+ 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.pushUnknown(); break;
}
}
void emulate_Conv_I8(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
- case ValueType.Int32:
- var val32 = (Int32Value)val1;
- valueStack.push(new Int64Value((long)val32.value));
- break;
-
- case ValueType.Int64:
- valueStack.push(val1);
- break;
-
- case ValueType.Real8:
- var valr8 = (Real8Value)val1;
- valueStack.push(new Int64Value((long)valr8.value));
- break;
-
- default:
- valueStack.pushUnknown();
- break;
+ 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.pushUnknown(); break;
}
}
@@ -569,311 +472,105 @@ namespace de4dot.blocks.cflow {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- switchUnknownToSecondOperand(ref val1, ref val2);
-
- if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if (int1.value == 0)
- valueStack.push(val2);
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- valueStack.push(new Int32Value(int1.value + int2.value));
- }
- else
- valueStack.pushUnknown();
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if (long1.value == 0)
- valueStack.push(val2);
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- valueStack.push(new Int64Value(long1.value + long2.value));
- }
- else
- valueStack.pushUnknown();
- }
- else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
- var real1 = (Real8Value)val1;
- var real2 = (Real8Value)val2;
- valueStack.push(new Real8Value(real1.value + real2.value));
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Add((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Add((Int64Value)val1, (Int64Value)val2));
+ else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8)
+ 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.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- valueStack.push(new Int32Value(int1.value - int2.value));
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- valueStack.push(new Int64Value(long1.value - long2.value));
- }
- else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
- var real1 = (Real8Value)val1;
- var real2 = (Real8Value)val2;
- valueStack.push(new Real8Value(real1.value - real2.value));
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if (int2.value == 0)
- valueStack.push(val1);
- else
- valueStack.pushUnknown();
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if (long2.value == 0)
- valueStack.push(val1);
- else
- valueStack.pushUnknown();
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Sub((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Sub((Int64Value)val1, (Int64Value)val2));
+ else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8)
+ valueStack.push(Real8Value.Sub((Real8Value)val1, (Real8Value)val2));
+ else
valueStack.pushUnknown();
- }
}
void emulate_Mul(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- switchUnknownToSecondOperand(ref val1, ref val2);
-
- if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if (int1.value == 1)
- valueStack.push(val2);
- else if (int1.value == 0)
- valueStack.push(new Int32Value(0));
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- valueStack.push(new Int32Value(int1.value * int2.value));
- }
- else
- valueStack.pushUnknown();
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if (long1.value == 1)
- valueStack.push(val2);
- else if (long1.value == 0)
- valueStack.push(new Int64Value(0));
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- valueStack.push(new Int64Value(long1.value * long2.value));
- }
- else
- valueStack.pushUnknown();
- }
- else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
- var real1 = (Real8Value)val1;
- var real2 = (Real8Value)val2;
- valueStack.push(new Real8Value(real1.value * real2.value));
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Mul((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Mul((Int64Value)val1, (Int64Value)val2));
+ else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8)
+ 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.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- try {
- valueStack.push(new Int32Value(int1.value / int2.value));
- }
- catch (ArithmeticException) {
- valueStack.pushUnknown();
- }
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- try {
- valueStack.push(new Int64Value(long1.value / long2.value));
- }
- catch (ArithmeticException) {
- valueStack.pushUnknown();
- }
- }
- else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
- var real1 = (Real8Value)val1;
- var real2 = (Real8Value)val2;
- valueStack.push(new Real8Value(real1.value / real2.value));
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if (int2.value == 1)
- valueStack.push(val1);
- else
- valueStack.pushUnknown();
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if (long2.value == 1)
- valueStack.push(val1);
- else
- valueStack.pushUnknown();
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Div((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Div((Int64Value)val1, (Int64Value)val2));
+ else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8)
+ 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.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- try {
- valueStack.push(new Int32Value((int)((uint)int1.value / (uint)int2.value)));
- }
- catch (ArithmeticException) {
- valueStack.pushUnknown();
- }
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- try {
- valueStack.push(new Int64Value((long)((ulong)long1.value / (ulong)long2.value)));
- }
- catch (ArithmeticException) {
- valueStack.pushUnknown();
- }
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if (int2.value == 1)
- valueStack.push(val1);
- else
- valueStack.pushUnknown();
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if (long2.value == 1)
- valueStack.push(val1);
- else
- valueStack.pushUnknown();
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Div_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ 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.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- try {
- valueStack.push(new Int32Value(int1.value % int2.value));
- }
- catch (ArithmeticException) {
- valueStack.pushUnknown();
- }
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- try {
- valueStack.push(new Int64Value(long1.value % long2.value));
- }
- catch (ArithmeticException) {
- valueStack.pushUnknown();
- }
- }
- else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
- var real1 = (Real8Value)val1;
- var real2 = (Real8Value)val2;
- valueStack.push(new Real8Value(real1.value % real2.value));
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if (int2.value == 1)
- valueStack.push(new Int32Value(0));
- else
- valueStack.pushUnknown();
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if (long2.value == 1)
- valueStack.push(new Int64Value(0));
- else
- valueStack.pushUnknown();
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Rem((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Rem((Int64Value)val1, (Int64Value)val2));
+ else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8)
+ 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.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- try {
- valueStack.push(new Int32Value((int)((uint)int1.value % (uint)int2.value)));
- }
- catch (ArithmeticException) {
- valueStack.pushUnknown();
- }
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- try {
- valueStack.push(new Int64Value((long)((ulong)long1.value % (ulong)long2.value)));
- }
- catch (ArithmeticException) {
- valueStack.pushUnknown();
- }
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if (int2.value == 1)
- valueStack.push(new Int32Value(0));
- else
- valueStack.pushUnknown();
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if (long2.value == 1)
- valueStack.push(new Int64Value(0));
- else
- valueStack.pushUnknown();
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Rem_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Rem_Un((Int64Value)val1, (Int64Value)val2));
+ else
valueStack.pushUnknown();
- }
}
void emulate_Neg(Instruction instr) {
var val1 = valueStack.pop();
if (val1.valueType == ValueType.Int32)
- valueStack.push(new Int32Value(-((Int32Value)val1).value));
+ valueStack.push(Int32Value.Neg((Int32Value)val1));
else if (val1.valueType == ValueType.Int64)
- valueStack.push(new Int64Value(-((Int64Value)val1).value));
+ valueStack.push(Int64Value.Neg((Int64Value)val1));
else if (val1.valueType == ValueType.Real8)
- valueStack.push(new Real8Value(-((Real8Value)val1).value));
+ valueStack.push(Real8Value.Neg((Real8Value)val1));
else
valueStack.pushUnknown();
}
@@ -882,116 +579,45 @@ namespace de4dot.blocks.cflow {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- switchUnknownToSecondOperand(ref val1, ref val2);
-
- if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if (int1.value == 0)
- valueStack.push(new Int32Value(0));
- else if (int1.value == -1)
- valueStack.push(val2);
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- valueStack.push(new Int32Value(int1.value & int2.value));
- }
- else
- valueStack.pushUnknown();
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if (long1.value == 0)
- valueStack.push(new Int64Value(0));
- else if (long1.value == -1)
- valueStack.push(val2);
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- valueStack.push(new Int64Value(long1.value & long2.value));
- }
- else
- valueStack.pushUnknown();
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.And((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.And((Int64Value)val1, (Int64Value)val2));
+ else
valueStack.pushUnknown();
- }
}
void emulate_Or(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- switchUnknownToSecondOperand(ref val1, ref val2);
-
- if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if (int1.value == -1)
- valueStack.push(new Int32Value(-1));
- else if (int1.value == 0)
- valueStack.push(val2);
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- valueStack.push(new Int32Value(int1.value | int2.value));
- }
- else
- valueStack.pushUnknown();
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if (long1.value == -1)
- valueStack.push(new Int64Value(-1));
- else if (long1.value == 0)
- valueStack.push(val2);
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- valueStack.push(new Int64Value(long1.value | long2.value));
- }
- else
- valueStack.pushUnknown();
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Or((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Or((Int64Value)val1, (Int64Value)val2));
+ else
valueStack.pushUnknown();
- }
}
void emulate_Xor(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- switchUnknownToSecondOperand(ref val1, ref val2);
-
- if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if (int1.value == 0)
- valueStack.push(val2);
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- valueStack.push(new Int32Value(int1.value ^ int2.value));
- }
- else
- valueStack.pushUnknown();
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if (long1.value == 0)
- valueStack.push(val2);
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- valueStack.push(new Int64Value(long1.value ^ long2.value));
- }
- else
- valueStack.pushUnknown();
- }
- else {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Xor((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Xor((Int64Value)val1, (Int64Value)val2));
+ else
valueStack.pushUnknown();
- }
}
void emulate_Not(Instruction instr) {
var val1 = valueStack.pop();
if (val1.valueType == ValueType.Int32)
- valueStack.push(new Int32Value(~((Int32Value)val1).value));
+ valueStack.push(Int32Value.Not((Int32Value)val1));
else if (val1.valueType == ValueType.Int64)
- valueStack.push(new Int64Value(~((Int64Value)val1).value));
+ valueStack.push(Int64Value.Not((Int64Value)val1));
else
valueStack.pushUnknown();
}
@@ -1000,22 +626,10 @@ namespace de4dot.blocks.cflow {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- int bits;
- if (val2.valueType == ValueType.Int32)
- bits = ((Int32Value)val2).value;
- else if (val2.valueType == ValueType.Int64)
- bits = (int)((Int64Value)val2).value;
- else {
- valueStack.pushUnknown();
- return;
- }
-
- if (bits == 0)
- valueStack.push(val1);
- else if (val1.valueType == ValueType.Int32)
- valueStack.push(new Int32Value(((Int32Value)val1).value << bits));
- else if (val1.valueType == ValueType.Int64)
- valueStack.push(new Int64Value(((Int64Value)val1).value << bits));
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Shl((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int64Value.Shl((Int64Value)val1, (Int32Value)val2));
else
valueStack.pushUnknown();
}
@@ -1024,22 +638,10 @@ namespace de4dot.blocks.cflow {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- int bits;
- if (val2.valueType == ValueType.Int32)
- bits = ((Int32Value)val2).value;
- else if (val2.valueType == ValueType.Int64)
- bits = (int)((Int64Value)val2).value;
- else {
- valueStack.pushUnknown();
- return;
- }
-
- if (bits == 0)
- valueStack.push(val1);
- else if (val1.valueType == ValueType.Int32)
- valueStack.push(new Int32Value(((Int32Value)val1).value >> bits));
- else if (val1.valueType == ValueType.Int64)
- valueStack.push(new Int64Value(((Int64Value)val1).value >> bits));
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Shr((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int64Value.Shr((Int64Value)val1, (Int32Value)val2));
else
valueStack.pushUnknown();
}
@@ -1048,22 +650,10 @@ namespace de4dot.blocks.cflow {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- int bits;
- if (val2.valueType == ValueType.Int32)
- bits = ((Int32Value)val2).value;
- else if (val2.valueType == ValueType.Int64)
- bits = (int)((Int64Value)val2).value;
- else {
- valueStack.pushUnknown();
- return;
- }
-
- if (bits == 0)
- valueStack.push(val1);
- else if (val1.valueType == ValueType.Int32)
- valueStack.push(new Int32Value((int)((uint)((Int32Value)val1).value >> bits)));
- else if (val1.valueType == ValueType.Int64)
- valueStack.push(new Int64Value((long)((ulong)((Int64Value)val1).value >> bits)));
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Shr_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int64Value.Shr_Un((Int64Value)val1, (Int32Value)val2));
else
valueStack.pushUnknown();
}
@@ -1072,235 +662,62 @@ namespace de4dot.blocks.cflow {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- //TODO: If it's an unknown int32/64, push 1 if val1 is same ref as val2
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- valueStack.push(new Int32Value(int1.value == int2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- valueStack.push(new Int32Value(long1.value == long2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
- var real1 = (Real8Value)val1;
- var real2 = (Real8Value)val2;
- valueStack.push(new Int32Value(real1.value == real2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Null && val2.valueType == ValueType.Null) {
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Ceq((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Ceq((Int64Value)val1, (Int64Value)val2));
+ else if (val1.valueType == ValueType.Null && val2.valueType == ValueType.Null)
valueStack.push(new Int32Value(1));
- }
- else {
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
+ else
+ Int32Value.createUnknownBool();
}
void emulate_Cgt(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- //TODO: If it's an unknown int32/64, push 0 if val1 is same ref as val2
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- valueStack.push(new Int32Value(int1.value > int2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- valueStack.push(new Int32Value(long1.value > long2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
- var real1 = (Real8Value)val1;
- var real2 = (Real8Value)val2;
- valueStack.push(new Int32Value(real1.value > real2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if (int1.value == int.MinValue)
- valueStack.push(new Int32Value(0)); // min > x => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if (int2.value == int.MaxValue)
- valueStack.push(new Int32Value(0)); // x > max => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if (long1.value == long.MinValue)
- valueStack.push(new Int32Value(0)); // min > x => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if (long2.value == long.MaxValue)
- valueStack.push(new Int32Value(0)); // x > max => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else {
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Cgt((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Cgt((Int64Value)val1, (Int64Value)val2));
+ else
+ Int32Value.createUnknownBool();
}
void emulate_Cgt_Un(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- //TODO: If it's an unknown int32/64, push 0 if val1 is same ref as val2
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- valueStack.push(new Int32Value((uint)int1.value > (uint)int2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- valueStack.push(new Int32Value((ulong)long1.value > (ulong)long2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if ((uint)int1.value == uint.MinValue)
- valueStack.push(new Int32Value(0)); // min > x => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if ((uint)int2.value == uint.MaxValue)
- valueStack.push(new Int32Value(0)); // x > max => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if ((ulong)long1.value == ulong.MinValue)
- valueStack.push(new Int32Value(0)); // min > x => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if ((ulong)long2.value == ulong.MaxValue)
- valueStack.push(new Int32Value(0)); // x > max => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else {
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Cgt_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Cgt_Un((Int64Value)val1, (Int64Value)val2));
+ else
+ Int32Value.createUnknownBool();
}
void emulate_Clt(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- //TODO: If it's an unknown int32/64, push 0 if val1 is same ref as val2
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- valueStack.push(new Int32Value(int1.value < int2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- valueStack.push(new Int32Value(long1.value < long2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Real8 && val2.valueType == ValueType.Real8) {
- var real1 = (Real8Value)val1;
- var real2 = (Real8Value)val2;
- valueStack.push(new Int32Value(real1.value < real2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if (int1.value == int.MaxValue)
- valueStack.push(new Int32Value(0)); // max < x => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if (int2.value == int.MinValue)
- valueStack.push(new Int32Value(0)); // x < min => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if (long1.value == long.MaxValue)
- valueStack.push(new Int32Value(0)); // max < x => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if (long2.value == long.MinValue)
- valueStack.push(new Int32Value(0)); // x < min => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else {
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Clt((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Clt((Int64Value)val1, (Int64Value)val2));
+ else
+ Int32Value.createUnknownBool();
}
void emulate_Clt_Un(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
- //TODO: If it's an unknown int32/64, push 0 if val1 is same ref as val2
-
- if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- var int2 = (Int32Value)val2;
- valueStack.push(new Int32Value((uint)int1.value < (uint)int2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- var long2 = (Int64Value)val2;
- valueStack.push(new Int32Value((ulong)long1.value < (ulong)long2.value ? 1 : 0));
- }
- else if (val1.valueType == ValueType.Int32) {
- var int1 = (Int32Value)val1;
- if ((uint)int1.value == uint.MaxValue)
- valueStack.push(new Int32Value(0)); // max < x => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val2.valueType == ValueType.Int32) {
- var int2 = (Int32Value)val2;
- if ((uint)int2.value == uint.MinValue)
- valueStack.push(new Int32Value(0)); // x < min => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val1.valueType == ValueType.Int64) {
- var long1 = (Int64Value)val1;
- if ((ulong)long1.value == ulong.MaxValue)
- valueStack.push(new Int32Value(0)); // max < x => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else if (val2.valueType == ValueType.Int64) {
- var long2 = (Int64Value)val2;
- if ((ulong)long2.value == ulong.MinValue)
- valueStack.push(new Int32Value(0)); // x < min => false
- else
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
- else {
- valueStack.pushUnknown(); //TODO: Push int32 with bit 0 unknown
- }
+ if (val1.valueType == ValueType.Int32 && val2.valueType == ValueType.Int32)
+ valueStack.push(Int32Value.Clt_Un((Int32Value)val1, (Int32Value)val2));
+ else if (val1.valueType == ValueType.Int64 && val2.valueType == ValueType.Int64)
+ valueStack.push(Int64Value.Clt_Un((Int64Value)val1, (Int64Value)val2));
+ else
+ Int32Value.createUnknownBool();
}
void emulate_Unbox_Any(Instruction instr) {
@@ -1325,12 +742,30 @@ namespace de4dot.blocks.cflow {
void emulate_Ldarga(int index) {
valueStack.pushUnknown();
- setArg(index, new UnknownValue());
+ setArg(index, getUnknownArg(index));
}
void emulate_Ldloca(int index) {
valueStack.pushUnknown();
- setLocal(index, new UnknownValue());
+ 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);
}
}
}
diff --git a/blocks/cflow/Int32Value.cs b/blocks/cflow/Int32Value.cs
new file mode 100644
index 00000000..017b0c19
--- /dev/null
+++ b/blocks/cflow/Int32Value.cs
@@ -0,0 +1,488 @@
+/*
+ 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;
+
+namespace de4dot.blocks.cflow {
+ class Int32Value : Value {
+ 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;
+ }
+
+ public Int32Value(int value, uint validMask)
+ : base(ValueType.Int32) {
+ this.value = value;
+ this.validMask = validMask;
+ }
+
+ public bool hasUnknownBits() {
+ return validMask != NO_UNKNOWN_BITS;
+ }
+
+ bool allBitsValid() {
+ return !hasUnknownBits();
+ }
+
+ bool isBitValid(int n) {
+ return isBitValid(validMask, n);
+ }
+
+ static bool isBitValid(uint validMask, int n) {
+ return (validMask & (1U << n)) != 0;
+ }
+
+ public static Int32Value createUnknownBool() {
+ return new Int32Value(0, NO_UNKNOWN_BITS << 1);
+ }
+
+ public static Int32Value createUnknownUInt8() {
+ return new Int32Value(0, NO_UNKNOWN_BITS << 8);
+ }
+
+ public static Int32Value createUnknownUInt16() {
+ return new Int32Value(0, NO_UNKNOWN_BITS << 16);
+ }
+
+ public static Int32Value createUnknown() {
+ return new Int32Value(0, 0U);
+ }
+
+ public bool isZero() {
+ return hasValue(0);
+ }
+
+ public bool hasValue(int value) {
+ return allBitsValid() && this.value == value;
+ }
+
+ public bool hasValue(uint value) {
+ return hasValue((int)value);
+ }
+
+ public static Int32Value Conv_U1(Int32Value a) {
+ return Conv_U1(a.value, a.validMask);
+ }
+
+ public static Int32Value Conv_U1(Int64Value a) {
+ return Conv_U1((int)a.value, (uint)a.validMask);
+ }
+
+ public static Int32Value Conv_U1(int value, uint validMask) {
+ //TODO: Doc says that result is sign-extended. You zero-extend it. Is that correct?
+ value = (int)(byte)value;
+ validMask |= NO_UNKNOWN_BITS << 8;
+ return new Int32Value(value, validMask);
+ }
+
+ public static Int32Value Conv_U1(Real8Value a) {
+ //TODO: Doc says that result is sign-extended. You zero-extend it. Is that correct?
+ return new Int32Value((int)(byte)a.value);
+ }
+
+ public static Int32Value Conv_I1(Int32Value a) {
+ return Conv_I1(a.value, a.validMask);
+ }
+
+ public static Int32Value Conv_I1(Int64Value a) {
+ return Conv_I1((int)a.value, (uint)a.validMask);
+ }
+
+ public static Int32Value Conv_I1(int value, uint validMask) {
+ value = (int)(sbyte)value;
+ if (isBitValid(validMask, 7))
+ validMask |= NO_UNKNOWN_BITS << 8;
+ else
+ validMask &= ~(NO_UNKNOWN_BITS << 8);
+ return new Int32Value(value, validMask);
+ }
+
+ public static Int32Value Conv_I1(Real8Value a) {
+ return new Int32Value((int)(sbyte)a.value);
+ }
+
+ public static Int32Value Conv_U2(Int32Value a) {
+ return Conv_U2(a.value, a.validMask);
+ }
+
+ public static Int32Value Conv_U2(Int64Value a) {
+ return Conv_U2((int)a.value, (uint)a.validMask);
+ }
+
+ public static Int32Value Conv_U2(int value, uint validMask) {
+ //TODO: Doc says that result is sign-extended. You zero-extend it. Is that correct?
+ value = (int)(ushort)value;
+ validMask |= NO_UNKNOWN_BITS << 16;
+ return new Int32Value(value, validMask);
+ }
+
+ public static Int32Value Conv_U2(Real8Value a) {
+ //TODO: Doc says that result is sign-extended. You zero-extend it. Is that correct?
+ return new Int32Value((int)(ushort)a.value);
+ }
+
+ public static Int32Value Conv_I2(Int32Value a) {
+ return Conv_I2(a.value, a.validMask);
+ }
+
+ public static Int32Value Conv_I2(Int64Value a) {
+ return Conv_I2((int)a.value, (uint)a.validMask);
+ }
+
+ public static Int32Value Conv_I2(int value, uint validMask) {
+ value = (int)(short)value;
+ if (isBitValid(validMask, 15))
+ validMask |= NO_UNKNOWN_BITS << 16;
+ else
+ validMask &= ~(NO_UNKNOWN_BITS << 16);
+ return new Int32Value(value, validMask);
+ }
+
+ public static Int32Value Conv_I2(Real8Value a) {
+ return new Int32Value((int)(short)a.value);
+ }
+
+ public static Int32Value Conv_U4(Int32Value a) {
+ return a;
+ }
+
+ public static Int32Value Conv_U4(Int64Value a) {
+ return new Int32Value((int)(uint)a.value, (uint)a.validMask);
+ }
+
+ public static Int32Value Conv_U4(Real8Value a) {
+ return new Int32Value((int)(uint)a.value);
+ }
+
+ public static Int32Value Conv_I4(Int32Value a) {
+ return a;
+ }
+
+ public static Int32Value Conv_I4(Int64Value a) {
+ return new Int32Value((int)a.value, (uint)a.validMask);
+ }
+
+ public static Int32Value Conv_I4(Real8Value a) {
+ return new Int32Value((int)a.value);
+ }
+
+ public static Int32Value Add(Int32Value a, Int32Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return new Int32Value(a.value + b.value);
+ return createUnknown();
+ }
+
+ public static Int32Value Sub(Int32Value a, Int32Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return new Int32Value(a.value - b.value);
+ return createUnknown();
+ }
+
+ public static Int32Value Mul(Int32Value a, Int32Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return new Int32Value(a.value * b.value);
+ if (a.isZero() || b.isZero())
+ return new Int32Value(0);
+ if (a.hasValue(1))
+ return b;
+ if (b.hasValue(1))
+ return a;
+ return createUnknown();
+ }
+
+ public static Int32Value Div(Int32Value a, Int32Value b) {
+ if (a.allBitsValid() && b.allBitsValid()) {
+ try {
+ return new Int32Value(a.value / b.value);
+ }
+ catch (ArithmeticException) {
+ return createUnknown();
+ }
+ }
+ if (b.hasValue(1))
+ return a;
+ return createUnknown();
+ }
+
+ 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));
+ }
+ catch (ArithmeticException) {
+ return createUnknown();
+ }
+ }
+ if (b.hasValue(1))
+ return a;
+ return createUnknown();
+ }
+
+ public static Int32Value Rem(Int32Value a, Int32Value b) {
+ if (a.allBitsValid() && b.allBitsValid()) {
+ try {
+ return new Int32Value(a.value % b.value);
+ }
+ catch (ArithmeticException) {
+ return createUnknown();
+ }
+ }
+ if (b.hasValue(1))
+ return new Int32Value(0);
+ 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));
+ }
+ catch (ArithmeticException) {
+ return createUnknown();
+ }
+ }
+ if (b.hasValue(1))
+ return new Int32Value(0);
+ return createUnknown();
+ }
+
+ public static Int32Value Neg(Int32Value a) {
+ if (a.allBitsValid())
+ return new Int32Value(-a.value);
+ 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)));
+ }
+
+ 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)));
+ }
+
+ public static Int32Value Xor(Int32Value a, Int32Value b) {
+ if (ReferenceEquals(a, b))
+ return new Int32Value(0);
+ int av = a.value, bv = b.value;
+ uint am = a.validMask, bm = b.validMask;
+ return new Int32Value(av ^ bv, (uint)(am & bm));
+ }
+
+ public static Int32Value Not(Int32Value a) {
+ return new Int32Value(~a.value, a.validMask);
+ }
+
+ public static Int32Value Shl(Int32Value a, Int32Value b) {
+ if (b.hasUnknownBits())
+ return createUnknown();
+ if (b.value == 0)
+ return a;
+ 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);
+ }
+
+ public static Int32Value Shr(Int32Value a, Int32Value b) {
+ if (b.hasUnknownBits())
+ return createUnknown();
+ if (b.value == 0)
+ return a;
+ if (b.value < 0 || b.value >= sizeof(int) * 8)
+ return createUnknown();
+ 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);
+ }
+
+ public static Int32Value Shr_Un(Int32Value a, Int32Value b) {
+ if (b.hasUnknownBits())
+ return createUnknown();
+ if (b.value == 0)
+ return a;
+ 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);
+ }
+
+ static Int32Value create(Bool3 b) {
+ switch (b) {
+ case Bool3.False: return new Int32Value(0);
+ case Bool3.True: return new Int32Value(1);
+ default: return createUnknown();
+ }
+ }
+
+ public static Int32Value Ceq(Int32Value a, Int32Value b) {
+ return create(compareEq(a, b));
+ }
+
+ public static Int32Value Cgt(Int32Value a, Int32Value b) {
+ return create(compareGt(a, b));
+ }
+
+ public static Int32Value Cgt_Un(Int32Value a, Int32Value b) {
+ return create(compareGt_Un(a, b));
+ }
+
+ public static Int32Value Clt(Int32Value a, Int32Value b) {
+ return create(compareLt(a, b));
+ }
+
+ public static Int32Value Clt_Un(Int32Value a, Int32Value 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;
+ if (ReferenceEquals(a, b))
+ return Bool3.True;
+ if ((a.value & a.validMask & b.validMask) != (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;
+ if (ReferenceEquals(a, b))
+ return Bool3.False;
+ if ((a.value & a.validMask & b.validMask) != (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;
+ if (a.hasValue(int.MinValue))
+ return Bool3.False; // min > x => false
+ if (b.hasValue(int.MaxValue))
+ return Bool3.False; // x > max => false
+ return Bool3.Unknown;
+ }
+
+ 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;
+ if (a.hasValue(uint.MinValue))
+ return Bool3.False; // min > x => false
+ if (b.hasValue(uint.MaxValue))
+ return Bool3.False; // x > max => false
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 compareGe(Int32Value a, Int32Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return a.value >= b.value ? Bool3.True : Bool3.False;
+ if (a.hasValue(int.MaxValue))
+ return Bool3.False; // max >= x => true
+ if (b.hasValue(int.MinValue))
+ return Bool3.False; // x >= min => true
+ return Bool3.Unknown;
+ }
+
+ 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;
+ if (a.hasValue(uint.MaxValue))
+ return Bool3.False; // max >= x => true
+ if (b.hasValue(uint.MinValue))
+ return Bool3.False; // x >= min => true
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 compareLe(Int32Value a, Int32Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return a.value <= b.value ? Bool3.True : Bool3.False;
+ if (a.hasValue(int.MinValue))
+ return Bool3.False; // min <= x => true
+ if (b.hasValue(int.MaxValue))
+ return Bool3.False; // x <= max => true
+ return Bool3.Unknown;
+ }
+
+ 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;
+ if (a.hasValue(uint.MinValue))
+ return Bool3.False; // min <= x => true
+ if (b.hasValue(uint.MaxValue))
+ return Bool3.False; // x <= max => true
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 compareLt(Int32Value a, Int32Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ 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))
+ return Bool3.False; // x < min => false
+ return Bool3.Unknown;
+ }
+
+ 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;
+ if (a.hasValue(uint.MaxValue))
+ return Bool3.False; // max < x => false
+ if (b.hasValue(uint.MinValue))
+ return Bool3.False; // x < min => false
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 compareTrue(Int32Value a) {
+ if (a.allBitsValid())
+ return a.value != 0 ? Bool3.True : Bool3.False;
+ if ((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 Bool3.False;
+ return Bool3.Unknown;
+ }
+
+ public override string ToString() {
+ if (allBitsValid())
+ return value.ToString();
+ return string.Format("0x{0:X8}({1:X8})", value, validMask);
+ }
+ }
+}
diff --git a/blocks/cflow/Int64Value.cs b/blocks/cflow/Int64Value.cs
new file mode 100644
index 00000000..0aff87d4
--- /dev/null
+++ b/blocks/cflow/Int64Value.cs
@@ -0,0 +1,403 @@
+/*
+ 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;
+
+namespace de4dot.blocks.cflow {
+ class Int64Value : Value {
+ 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;
+ }
+
+ public Int64Value(long value, ulong validMask)
+ : base(ValueType.Int64) {
+ this.value = value;
+ this.validMask = validMask;
+ }
+
+ bool hasUnknownBits() {
+ return validMask != NO_UNKNOWN_BITS;
+ }
+
+ bool allBitsValid() {
+ return !hasUnknownBits();
+ }
+
+ bool isBitValid(int n) {
+ return isBitValid(validMask, n);
+ }
+
+ static bool isBitValid(ulong validMask, int n) {
+ return (validMask & (1UL << n)) != 0;
+ }
+
+ public static Int64Value createUnknown() {
+ return new Int64Value(0, 0UL);
+ }
+
+ public bool isZero() {
+ return hasValue(0);
+ }
+
+ public bool hasValue(long value) {
+ return allBitsValid() && this.value == value;
+ }
+
+ public bool hasValue(ulong value) {
+ return hasValue((long)value);
+ }
+
+ public static Int64Value Conv_U8(Int32Value a) {
+ //TODO: Doc says that result is sign-extended. You zero-extend it. Is that correct?
+ long value = (long)(ulong)(uint)a.value;
+ ulong validMask = a.validMask | (NO_UNKNOWN_BITS << 32);
+ return new Int64Value(value, validMask);
+ }
+
+ public static Int64Value Conv_U8(Int64Value a) {
+ return a;
+ }
+
+ public static Int64Value Conv_U8(Real8Value a) {
+ return new Int64Value((long)(ulong)a.value);
+ }
+
+ public static Int64Value Conv_I8(Int32Value a) {
+ long value = a.value;
+ ulong validMask = a.validMask;
+ if (isBitValid(validMask, 31))
+ validMask |= NO_UNKNOWN_BITS << 32;
+ else
+ validMask &= ~(NO_UNKNOWN_BITS << 32);
+ return new Int64Value(value, validMask);
+ }
+
+ public static Int64Value Conv_I8(Int64Value a) {
+ return a;
+ }
+
+ public static Int64Value Conv_I8(Real8Value a) {
+ return new Int64Value((long)a.value);
+ }
+
+ public static Int64Value Add(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return new Int64Value(a.value + b.value);
+ return createUnknown();
+ }
+
+ public static Int64Value Sub(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return new Int64Value(a.value - b.value);
+ return createUnknown();
+ }
+
+ public static Int64Value Mul(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return new Int64Value(a.value * b.value);
+ if (a.isZero() || b.isZero())
+ return new Int64Value(0);
+ if (a.hasValue(1))
+ return b;
+ if (b.hasValue(1))
+ return a;
+ return createUnknown();
+ }
+
+ public static Int64Value Div(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid()) {
+ try {
+ return new Int64Value(a.value / b.value);
+ }
+ catch (ArithmeticException) {
+ return createUnknown();
+ }
+ }
+ if (b.hasValue(1))
+ return a;
+ return createUnknown();
+ }
+
+ public static Int64Value Div_Un(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid()) {
+ try {
+ return new Int64Value((int)((uint)a.value / (uint)b.value));
+ }
+ catch (ArithmeticException) {
+ return createUnknown();
+ }
+ }
+ if (b.hasValue(1))
+ return a;
+ return createUnknown();
+ }
+
+ public static Int64Value Rem(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid()) {
+ try {
+ return new Int64Value(a.value % b.value);
+ }
+ catch (ArithmeticException) {
+ return createUnknown();
+ }
+ }
+ if (b.hasValue(1))
+ return new Int64Value(0);
+ return createUnknown();
+ }
+
+ public static Int64Value Rem_Un(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid()) {
+ try {
+ return new Int64Value((int)((uint)a.value % (uint)b.value));
+ }
+ catch (ArithmeticException) {
+ return createUnknown();
+ }
+ }
+ if (b.hasValue(1))
+ return new Int64Value(0);
+ return createUnknown();
+ }
+
+ public static Int64Value Neg(Int64Value a) {
+ if (a.allBitsValid())
+ return new Int64Value(-a.value);
+ return createUnknown();
+ }
+
+ public static Int64Value And(Int64Value a, Int64Value b) {
+ 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;
+ 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 new Int64Value(0);
+ 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);
+ }
+
+ public static Int64Value Shl(Int64Value a, Int32Value b) {
+ if (b.hasUnknownBits())
+ return createUnknown();
+ if (b.value == 0)
+ return a;
+ 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);
+ }
+
+ public static Int64Value Shr(Int64Value a, Int32Value b) {
+ if (b.hasUnknownBits())
+ return createUnknown();
+ if (b.value == 0)
+ return a;
+ if (b.value < 0 || b.value >= sizeof(long) * 8)
+ return createUnknown();
+ 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);
+ }
+
+ public static Int64Value Shr_Un(Int64Value a, Int32Value b) {
+ if (b.hasUnknownBits())
+ return createUnknown();
+ if (b.value == 0)
+ return a;
+ 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);
+ }
+
+ static Int32Value create(Bool3 b) {
+ switch (b) {
+ case Bool3.False: return new Int32Value(0);
+ case Bool3.True: return new Int32Value(1);
+ default: return Int32Value.createUnknown();
+ }
+ }
+
+ public static Int32Value Ceq(Int64Value a, Int64Value b) {
+ return create(compareEq(a, b));
+ }
+
+ public static Int32Value Cgt(Int64Value a, Int64Value b) {
+ return create(compareGt(a, b));
+ }
+
+ public static Int32Value Cgt_Un(Int64Value a, Int64Value b) {
+ return create(compareGt_Un(a, b));
+ }
+
+ public static Int32Value Clt(Int64Value a, Int64Value b) {
+ return create(compareLt(a, b));
+ }
+
+ public static Int32Value Clt_Un(Int64Value a, Int64Value b) {
+ return create(compareLt_Un(a, b));
+ }
+
+ public static Bool3 compareEq(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ 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))
+ 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;
+ if (ReferenceEquals(a, b))
+ return Bool3.False;
+ 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;
+ if (a.hasValue(int.MinValue))
+ return Bool3.False; // min > x => false
+ if (b.hasValue(int.MaxValue))
+ return Bool3.False; // x > max => false
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 compareGt_Un(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ 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))
+ return Bool3.False; // x > max => false
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 compareGe(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return a.value >= b.value ? Bool3.True : Bool3.False;
+ if (a.hasValue(int.MaxValue))
+ return Bool3.False; // max >= x => true
+ if (b.hasValue(int.MinValue))
+ return Bool3.False; // x >= min => true
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 compareGe_Un(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return (uint)a.value >= (uint)b.value ? Bool3.True : Bool3.False;
+ if (a.hasValue(uint.MaxValue))
+ return Bool3.False; // max >= x => true
+ if (b.hasValue(uint.MinValue))
+ return Bool3.False; // x >= min => true
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 compareLe(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return a.value <= b.value ? Bool3.True : Bool3.False;
+ if (a.hasValue(int.MinValue))
+ return Bool3.False; // min <= x => true
+ if (b.hasValue(int.MaxValue))
+ return Bool3.False; // x <= max => true
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 compareLe_Un(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ return (uint)a.value <= (uint)b.value ? Bool3.True : Bool3.False;
+ if (a.hasValue(uint.MinValue))
+ return Bool3.False; // min <= x => true
+ if (b.hasValue(uint.MaxValue))
+ return Bool3.False; // x <= max => true
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 compareLt(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ 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))
+ return Bool3.False; // x < min => false
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 compareLt_Un(Int64Value a, Int64Value b) {
+ if (a.allBitsValid() && b.allBitsValid())
+ 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))
+ return Bool3.False; // x < min => false
+ return Bool3.Unknown;
+ }
+
+ 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 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 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);
+ }
+ }
+}
diff --git a/blocks/cflow/Real8Value.cs b/blocks/cflow/Real8Value.cs
new file mode 100644
index 00000000..8b5f3e6f
--- /dev/null
+++ b/blocks/cflow/Real8Value.cs
@@ -0,0 +1,53 @@
+/*
+ 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 .
+*/
+
+namespace de4dot.blocks.cflow {
+ class Real8Value : Value {
+ public readonly double value;
+
+ public Real8Value(double value)
+ : base(ValueType.Real8) {
+ this.value = value;
+ }
+
+ public static Real8Value Add(Real8Value a, Real8Value b) {
+ return new Real8Value(a.value + b.value);
+ }
+
+ public static Real8Value Sub(Real8Value a, Real8Value b) {
+ return new Real8Value(a.value - b.value);
+ }
+
+ public static Real8Value Mul(Real8Value a, Real8Value b) {
+ return new Real8Value(a.value * b.value);
+ }
+
+ public static Real8Value Div(Real8Value a, Real8Value b) {
+ return new Real8Value(a.value / b.value);
+ }
+
+ public static Real8Value Rem(Real8Value a, Real8Value b) {
+ return new Real8Value(a.value % b.value);
+ }
+
+ public static Real8Value Neg(Real8Value a) {
+ return new Real8Value(-a.value);
+ }
+ }
+}
diff --git a/blocks/cflow/Value.cs b/blocks/cflow/Value.cs
index beaf0beb..8bc992d9 100644
--- a/blocks/cflow/Value.cs
+++ b/blocks/cflow/Value.cs
@@ -28,6 +28,12 @@ namespace de4dot.blocks.cflow {
String,
}
+ enum Bool3 {
+ Unknown = -1,
+ False,
+ True,
+ }
+
abstract class Value {
public readonly ValueType valueType;
@@ -72,45 +78,6 @@ namespace de4dot.blocks.cflow {
}
}
- class Int32Value : Value {
- public readonly int value;
-
- public Int32Value(int value)
- : base(ValueType.Int32) {
- this.value = value;
- }
-
- public override string ToString() {
- return value.ToString();
- }
- }
-
- class Int64Value : Value {
- public readonly long value;
-
- public Int64Value(long value)
- : base(ValueType.Int64) {
- this.value = value;
- }
-
- public override string ToString() {
- return value.ToString() + "L";
- }
- }
-
- class Real8Value : Value {
- public readonly double value;
-
- public Real8Value(double value)
- : base(ValueType.Real8) {
- this.value = value;
- }
-
- public override string ToString() {
- return value.ToString() + "D";
- }
- }
-
class StringValue : Value {
public readonly string value;