/// <summary> /// Inserts two additional instructions for constant coverage /// </summary> /// <param name="const_inst">The instruction with a constant value</param> /// <param name="const_value">Numerical constant value to be covered</param> private static void ProcessConstant(Instruction const_inst, int const_value) { List <int> two_places = Randomizer.MultipleNumbers(2, 0, const_inst.parent.Instructions.BinarySearch(const_inst), true, true); Instruction nop1 = new Instruction(const_inst.parent); Instruction nop2 = new Instruction(const_inst.parent); // We assume that we need 4 bytes for each constant. Variable t1 = const_inst.parent.parent.NewLocalVariable(Variable.Purpose.ConstRecalculation, Objects.Common.MemoryRegionSize.Integer); Variable t2 = const_inst.parent.parent.NewLocalVariable(Variable.Purpose.ConstRecalculation, Objects.Common.MemoryRegionSize.Integer); int first_number = Randomizer.SingleNumber(Common.GlobalMinValue, Common.GlobalMaxValue); Instruction.ArithmeticOperationType op = first_number < const_value ? Instruction.ArithmeticOperationType.Addition : Instruction.ArithmeticOperationType.Subtraction; int second_number = Math.Abs(first_number - const_value); MakeInstruction.Copy(nop1, t2, null, first_number); MakeInstruction.FullAssignment(nop2, t1, t2, null, second_number, op); const_inst.parent.Instructions.Insert(two_places[1], nop2); const_inst.parent.Instructions.Insert(two_places[0], nop1); const_inst.ModifyConstInstruction(t1, const_value); }
/// <summary> /// Makes FullAssignment instruction type from NoOperation /// </summary> /// <param name="left_value">Left value (variable only)</param> /// <param name="right_value1">Right value before operator</param> /// <param name="right_value2">Right value after operator (for variable), null for number</param> /// <param name="right_value_int">Right value after operator (for number), null for variable</param> /// <param name="operation">Desired arithmetic operation</param> public static void FullAssignment(Instruction ins, Variable left_value, Variable right_value1, Variable right_value2, int?right_value_int, Instruction.ArithmeticOperationType operation) { if (ins.statementType != Objects.Common.StatementType.NoOperation) { throw new ObfuscatorException("Only NoOperation instruction can be modified to other type!"); } if (right_value2 == null && right_value_int == null) { throw new ObfuscatorException("Wrong parameter passing: one of the second right value and the constant must be null."); } if (right_value2 != null && right_value_int != null) { throw new ObfuscatorException("Wrong parameter passing: both second right value and constant is null."); } if (left_value == null) { throw new ObfuscatorException("Wrong parameter passing: left value missing."); } if (right_value1 == null) { throw new ObfuscatorException("Wrong parameter passing: first right value missing."); } string left1 = left_value.name; string right1 = right_value1.name; string right2 = right_value_int == null ? right_value2.name : right_value_int.ToString(); string op; switch (operation) { case Instruction.ArithmeticOperationType.Addition: op = "+"; break; case Instruction.ArithmeticOperationType.Subtraction: op = "-"; break; case Instruction.ArithmeticOperationType.Multiplication: op = "*"; break; case Instruction.ArithmeticOperationType.Division: op = @"/"; break; default: throw new ObfuscatorException("Unsupported arithmetic operation type."); } ins.RefVariables.Clear(); ins.RefVariables.Add(left_value); ins.RefVariables.Add(right_value1); if (right_value_int == null) { ins.RefVariables.Add(right_value2); } ins.statementType = Objects.Common.StatementType.FullAssignment; ins.TACtext = string.Join(" ", left1, ":=", right1, op, right2); }
/// <summary> /// Parses a full assignment instruction /// </summary> /// <param name="inst">Instruction to be parsed</param> /// <param name="left_value">Left value of the assignment (variable only)</param> /// <param name="right_value1">Right value before arithmetic operator</param> /// <param name="right_value2">Right value after arithmetic operator (for variable), null for number</param> /// <param name="right_value_int">Right value after arithmetic operator (for number), null for variable</param> /// <param name="operation">Arithmetic operator</param> public static void FullAssignment(Instruction inst, out Variable left_value, out Variable right_value1, out Variable right_value2, out int?right_value_int, out Instruction.ArithmeticOperationType operation) { Validate(inst, Objects.Common.StatementType.FullAssignment); System.Collections.Specialized.StringCollection refvarIDs = new System.Collections.Specialized.StringCollection(); Match matchResult = Regex.Match(inst.TACtext, "ID_[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}", RegexOptions.None); while (matchResult.Success) { refvarIDs.Add(matchResult.Value); matchResult = matchResult.NextMatch(); } left_value = inst.RefVariables.Find(x => x.ID == refvarIDs[0]); right_value1 = inst.RefVariables.Find(x => x.ID == refvarIDs[1]); if (refvarIDs.Count == 3) { right_value2 = inst.RefVariables.Find(x => x.ID == refvarIDs[2]); right_value_int = null; } else { right_value_int = Convert.ToInt32(inst.TACtext.Split(' ')[4]); right_value2 = null; } switch (inst.TACtext.Split(' ')[3]) { case "+": operation = Instruction.ArithmeticOperationType.Addition; break; case "-": operation = Instruction.ArithmeticOperationType.Subtraction; break; case "*": operation = Instruction.ArithmeticOperationType.Multiplication; break; case @"/": operation = Instruction.ArithmeticOperationType.Division; break; case "%": operation = Instruction.ArithmeticOperationType.Modulo; break; default: throw new ParserException("Cannot parse arithmetic operation type."); } }
/// <summary> /// Function to make an actual fake instruction out of a Nop. /// </summary> /// <param name="ins">The nop we want to work on.</param> private static void _GenerateFakeInstruction(Instruction ins) { /* First we get a left value. */ Variable leftvalue = GetLeftValueForInstruction(ins); /* Then we check how many variables can we use as right value. */ List <Variable> rightvalues = GetRandomRightValues(ins, 2); /* We random generate a statement type which we may not use according to the available right values. */ Objects.Common.StatementType statementType = (Objects.Common.StatementType)Randomizer.OneFromManyWithProbability( new int[3] { 25, 15, 60 }, Objects.Common.StatementType.Copy, Objects.Common.StatementType.UnaryAssignment, Objects.Common.StatementType.FullAssignment); /* * The number of the available right values determines which kind of instructions * can we generate. * * - If we don't have any, then we must make a Copy with a constant. * * - If we have one, and it's the same as the left value, then we have to make * a Unary Assignment. * * - If we have one, but it's different from the left value, then we can make * a Copy (1), a Unary Assignment (2) and a Full Assignment with a constant (3). * * - If we have two, we can make all these and a Full Assignment with two * variables. * * Another important thing is that we cannot fill the variables with a value * without using themselves (like t = t + 1) while inside a loop. */ switch (rightvalues.Count) { case 0: /* If we have no available right values, and we are in a loop, then we can't do anything. */ if (DataAnalysis.isLoopBody[ins.parent]) { return; } /* We don't have any right values, so we have to copy a constant value. */ else { MakeInstruction.Copy(ins, leftvalue, null, Randomizer.SingleNumber(Common.GlobalMinValue, Common.GlobalMaxValue)); } break; case 1: /* We choose Full Assignment, or rightvalue is the same as leftvalue, or we are in a loop body. */ if (DataAnalysis.isLoopBody[ins.parent] || leftvalue.Equals(rightvalues[0]) || statementType == Objects.Common.StatementType.FullAssignment || (ins.DeadVariables.Keys.Contains(leftvalue) && ins.DeadVariables[leftvalue] == Variable.State.Filled)) { /* Here we random generate an operator. */ Instruction.ArithmeticOperationType op = (Instruction.ArithmeticOperationType)Randomizer.OneFromMany(Instruction.ArithmeticOperationType.Addition, Instruction.ArithmeticOperationType.Division, Instruction.ArithmeticOperationType.Multiplication, Instruction.ArithmeticOperationType.Subtraction); int num; if (op == Instruction.ArithmeticOperationType.Addition || op == Instruction.ArithmeticOperationType.Subtraction) { num = Randomizer.SingleNumber(Common.GlobalMinValue, Common.GlobalMaxValue); } else { /* * Here we generate an integer number which is the power of 2, and is * within the boundaries of GlobalMinNumber and GlobalMaxNumber. */ int min = Convert.ToInt32(Math.Ceiling(Math.Log(Common.GlobalMinValue, 2))); int max = Convert.ToInt32(Math.Floor(Math.Log(Common.GlobalMaxValue, 2))); int pow = Randomizer.SingleNumber(min, max); num = Convert.ToInt32(Math.Pow(2, pow)); } MakeInstruction.FullAssignment(ins, leftvalue, rightvalues.First(), null, num, op); } /* If we choose Unary Assignment. */ else if (statementType == Objects.Common.StatementType.UnaryAssignment) { MakeInstruction.UnaryAssignment(ins, leftvalue, rightvalues.First(), Instruction.UnaryOperationType.ArithmeticNegation); } /* If we choose Copy. */ else { MakeInstruction.Copy(ins, leftvalue, rightvalues.First(), null); } break; case 2: /* We make sure that the first right value isn't the same as the left value. */ if (leftvalue.Equals(rightvalues.First())) { Variable tmp = rightvalues[0]; rightvalues[0] = rightvalues[1]; rightvalues[1] = tmp; } /* * If we are in a loop body, then we can only make a full assignment like that: * t1 = t2 op t1 */ if (DataAnalysis.isLoopBody[ins.parent] || statementType == Objects.Common.StatementType.FullAssignment || (ins.DeadVariables.Keys.Contains(leftvalue) && ins.DeadVariables[leftvalue] == Variable.State.Filled)) { /* Here we random generate an operator: + or - */ /* TODO: (efficient) * and / */ Instruction.ArithmeticOperationType op = (Instruction.ArithmeticOperationType)Randomizer.OneFromMany(Instruction.ArithmeticOperationType.Addition, Instruction.ArithmeticOperationType.Subtraction); if (DataAnalysis.isLoopBody[ins.parent] || (ins.DeadVariables.Keys.Contains(leftvalue) && ins.DeadVariables[leftvalue] == Variable.State.Filled)) { MakeInstruction.FullAssignment(ins, leftvalue, rightvalues[0], leftvalue, null, op); } else { MakeInstruction.FullAssignment(ins, leftvalue, rightvalues[0], rightvalues[1], null, op); } } /* If we choose Copy. */ else if (statementType == Objects.Common.StatementType.Copy) { MakeInstruction.Copy(ins, leftvalue, rightvalues.First(), null); } /* If we choose Unary Assignment. */ else { MakeInstruction.UnaryAssignment(ins, leftvalue, rightvalues.First(), Instruction.UnaryOperationType.ArithmeticNegation); } break; } }