/// <summary> /// Checking for collisions of FILLED vs. NOT_INITIALIZED and residual NOPs /// </summary> /// <param name="routine">A routine to be checked</param> public static void CheckForProblems(Routine routine) { foreach (Function func in routine.Functions) { /* Now we check for forbidden state collisions at every basic blocks' beginning. */ foreach (BasicBlock bb in func.BasicBlocks) { if (DataAnalysis.ForbiddenStateCollision(bb.Instructions.First())) { throw new ObfuscatorException("Forbidden state collision: FILLED meets NOT_INITIALIZED."); } } //Checking whether we have "nops" left if (GetAllNops(func).Count > 0) { throw new ObfuscatorException("Lack of available dead variables."); } } }
private static void Obfuscation(Routine routine) { Logging.WriteComplexityMetrics(routine, "Original"); //Checking whether the functions have either "division" or "modulo" operations //If they do, fake instructions with original variables should be inserted only before the return //to avoid problems with the these operations foreach (Function func in routine.Functions) { func.CheckDivisionModulo(); } //Creating fake input parameters in all functions FakeParameters.CreateFakeParameters(routine); //Checking for Multiple Obfuscation for (int i = 0; i < Convert.ToInt32(ConfigurationManager.AppSettings["MultipleRuns"]); i++) { //Creating fake variables foreach (Function func in routine.Functions) { for (int j = 0; j < (Common.PercentageFakeVars * func.LocalVariables.FindAll(x => !x.fake).Count) / 100; j++) { func.LocalVariables.Add(new Variable(Variable.Kind.Local, Variable.Purpose.Fake, Objects.Common.MemoryRegionSize.Integer)); } } if (ConfigurationManager.AppSettings["ConstCoverAlgInMultipleRuns"].Split('-')[i].Equals("1")) { Console.Write("Step 1: Constants coverage"); ConstCoverage.CoverConstants(routine); routine.Validate(); PrintSuccess(); Logging.WriteReadableTAC(routine, "CONST"); Logging.DrawCFG(routine, "CONST"); } if (ConfigurationManager.AppSettings["UncMeshingAlgInMultipleRuns"].Split('-')[i].Equals("1")) { Console.Write("Step 2: Meshing unconditional jumps"); Meshing.MeshUnconditionals(routine); routine.Validate(); PrintSuccess(); Logging.WriteReadableTAC(routine, "MeshingUNC"); Logging.DrawCFG(routine, "MeshingUNC"); } if (ConfigurationManager.AppSettings["CondMeshingAlgInMultipleRuns"].Split('-')[i].Equals("1")) { Console.Write("Step 3: Meshing conditional jumps"); Meshing.MeshConditionals(routine); routine.Validate(); PrintSuccess(); Logging.WriteReadableTAC(routine, "MeshingCOND"); Logging.DrawCFG(routine, "MeshingCOND"); } Console.Write("Step 4: Generation of fake NOP instructions"); foreach (Function func in routine.Functions) { FakeCode.GenerateNoOperations(func); } routine.Validate(); PrintSuccess(); Logging.WriteRoutine(routine, "NoOpersGeneration"); Logging.WriteReadableTAC(routine, "FakeNOPs"); Console.Write("Step 5: Partial data analysis"); DataAnalysis.GatherBasicBlockInfo(routine); PrintSuccess(); if (ConfigurationManager.AppSettings["FakeJumpsAlgInMultipleRuns"].Split('-')[i].Equals("1")) { Console.Write("Step 6: Generation of fake conditional jumps from NOPs"); foreach (Function func in routine.Functions) { FakeCode.GenerateConditionalJumps(func); } Logging.WriteRoutine(routine, "CondJumps"); foreach (Function func in routine.Functions) { FakeCode.GenerateNoOperations(func); } routine.Validate(); PrintSuccess(); } Console.Write("Step 7: Complete data analysis"); foreach (Function func in routine.Functions) { DataAnalysis.DeadVarsAlgortihm(func); } DataAnalysis.GatherBasicBlockInfo(routine); PrintSuccess(); Console.Write("Step 8: Generation of fake instructions from NOPs"); foreach (Function func in routine.Functions) { FakeCode.GenerateFakeInstructions(func); } Logging.WriteRoutine(routine, "FakeIns"); Logging.DrawCFG(routine, "CondJumps"); Logging.WriteComplexityMetrics(routine, "Final"); FakeCode.CheckForProblems(routine); routine.Validate(); PrintSuccess(); Logging.WriteReadableTAC(routine, "FakeInstrFromNOPs"); } }
/* * This function is called when we encounter a change in a dead variable's state. * So we want to push this change through all the instructions, and deal with * this variable only. * * However we can't just overwrite the statement without any check... */ private static void RefreshNext(Instruction ins, Variable var, Variable.State state) { /* * If this instruction uses this variable as well, or this instruction * uses a pointer that points to this variable then its state must not * be changed, because it's perfect as it is right now. */ if (ins.RefVariables.Contains(var)) { /* This instruction uses this variable. */ return; } /* * We have to do anything only if the variable is in this instruction is * dead, and it's state differs from the new state. */ if (ins.DeadVariables.ContainsKey(var) && // This variable is dead. ins.DeadVariables[var] != state) // The state differs. { foreach (Variable v in ins.RefVariables) { if (ins.DeadPointers.ContainsKey(v) && ins.DeadPointers[v].PointsTo.Equals(var)) { /* The instruction uses a pointer that points to this variable. */ return; } } /* * Now we are at the point, that maybe we have to change the state. * Although it's not sure, because if the instruction has more than one predecessors, * then the actual state might not change anything. * For example: NOT_INITIALIZED meets FREE, or FREE meets FILLED. * * NOTE: we don't know right now what to do if NOT_INIT meets FILLED... */ state = DataAnalysis.CheckPrecedingStates(ins, var, state); ins.DeadVariables[var] = state; foreach (Instruction inst in ins.GetFollowingInstructions()) { RefreshNext(inst, var, state); } } /* * Another case for doing something when we pass a dead pointer with changed state. * In this case we do not have to look for variables pointing to that one. * * WARNING FOR FUTURE: (1) */ if (ins.DeadPointers.ContainsKey(var) && // This is a dead pointer. ins.DeadPointers[var].State != state) // The states differ. { /* Just like in the previous case, we have to check all the preceding states for collisions. */ state = DataAnalysis.CheckPrecedingStates(ins, var, state); ins.DeadPointers[var].State = state; foreach (Instruction inst in ins.GetFollowingInstructions()) { RefreshNext(inst, var, state); } } }
/// <summary> /// Expands the fake route into the CFG and creates the conditional jumps for both Loop and Fake code /// </summary> /// <param name="fake1">The first fake basic block to be used in the expansion</param> /// <param name="mainLaneBB">The basic block we should go in case of no-loop</param> /// <param name="atFakeCodeGeneration">Wheter we are or not at the fake code generation phase</param> public static void ExpandFakeRoute(BasicBlock fake1, BasicBlock originalSuccessor, bool atFakeJumpGeneration) { //Creating fake2 to hold the next Loop condition BasicBlock fake2 = new BasicBlock(fake1.parent); fake2.Meshable = false; if (fake2.parent.containsDivisionModulo == false || originalSuccessor.Instructions.FindAll(x => x.TACtext.Contains("return")).Count > 0) { fake2.Involve = BasicBlock.InvolveInFakeCodeGeneration.Both; } fake2.inFakeLane = true; //Creating fake3 to hold the extra fake code in case of No-Loop BasicBlock fake3 = new BasicBlock(fake1.parent); if (fake3.parent.containsDivisionModulo == false || originalSuccessor.Instructions.FindAll(x => x.TACtext.Contains("return")).Count > 0) { fake3.Involve = BasicBlock.InvolveInFakeCodeGeneration.Both; } fake3.inFakeLane = true; //Creating the fake3 unconditional jump back to the Main Lane MakeInstruction.UnconditionalJump(fake3.Instructions.Last(), originalSuccessor); //Linking fake3 to fake2 fake2.LinkToSuccessor(fake3); //Creating fake4 to hold the extra fake code in case of No-Loop BasicBlock fake4 = new BasicBlock(fake1.parent); if (fake4.parent.containsDivisionModulo == false || originalSuccessor.Instructions.FindAll(x => x.TACtext.Contains("return")).Count > 0) { fake4.Involve = BasicBlock.InvolveInFakeCodeGeneration.Both; } fake4.inFakeLane = true; //Creating the fake4 unconditional jump back to the Main Lane MakeInstruction.UnconditionalJump(fake4.Instructions.Last(), originalSuccessor); //Linking fake4 to fake1 fake1.LinkToSuccessor(fake4); //Fetching the Conditional Jump (AlwaysFalse) created in the previous basic block Instruction originalInstruction = fake1.getPredecessors.First().Instructions.Last(); //Defining the relational operator for the fake1 conditional jump Instruction.RelationalOperationType relationalOperationEF1 = (Instruction.RelationalOperationType) Randomizer.OneFromMany(Instruction.RelationalOperationType.Smaller, Instruction.RelationalOperationType.SmallerOrEquals, Instruction.RelationalOperationType.Greater, Instruction.RelationalOperationType.GreaterOrEquals); //Defining the constant for the fake1 conditional jump int rightValueEF1 = 0; if (originalInstruction.GetConstFromCondition() >= originalInstruction.GetVarFromCondition().fixedMax.Value) { //If the original instruction's contant is diferent from the global max minus the max loop range, we should try //to get a value different from the original instruction's constant in order to have a more belieavable code do { rightValueEF1 = Randomizer.SingleNumber((int)originalInstruction.GetConstFromCondition(), Common.GlobalMaxValue - Common.LoopConditionalJumpMaxRange); } while (rightValueEF1 == (int)originalInstruction.GetConstFromCondition() && (int)originalInstruction.GetConstFromCondition() != Common.GlobalMaxValue - Common.LoopConditionalJumpMaxRange); } else { //If the original instruction's contant is diferent from the global min plus the max loop range, we should try //to get a value different from the original instruction's constant in order to have a more belieavable code do { rightValueEF1 = Randomizer.SingleNumber(Common.GlobalMinValue + Common.LoopConditionalJumpMaxRange, (int)originalInstruction.GetConstFromCondition()); } while (rightValueEF1 == (int)originalInstruction.GetConstFromCondition() && (int)originalInstruction.GetConstFromCondition() != Common.GlobalMinValue + Common.LoopConditionalJumpMaxRange); } //Creating the fake1 conditional jump Variable var = originalInstruction.GetVarFromCondition(); MakeInstruction.ConditionalJump(fake1.Instructions.Last(), var, rightValueEF1, relationalOperationEF1, fake2); //Defining the range for the fake2 conditional jump constant int range = Randomizer.SingleNumber(0, Common.LoopConditionalJumpMaxRange); //Defining relational operation for the extraFake2 conditional jump based on the extraFake1 condtional jump relational operation and the range Instruction.RelationalOperationType relationalOperationEF2 = Instruction.RelationalOperationType.Equals; switch (relationalOperationEF1) { case Instruction.RelationalOperationType.Smaller: case Instruction.RelationalOperationType.SmallerOrEquals: if (range <= 1) { relationalOperationEF2 = Instruction.RelationalOperationType.Equals; } else if (range == 2) { relationalOperationEF2 = (Instruction.RelationalOperationType) Randomizer.OneFromMany(Instruction.RelationalOperationType.GreaterOrEquals, Instruction.RelationalOperationType.Equals); } else { relationalOperationEF2 = (Instruction.RelationalOperationType) Randomizer.OneFromMany(Instruction.RelationalOperationType.Greater, Instruction.RelationalOperationType.GreaterOrEquals, Instruction.RelationalOperationType.Equals); } break; case Instruction.RelationalOperationType.Greater: case Instruction.RelationalOperationType.GreaterOrEquals: if (range <= 1) { relationalOperationEF2 = Instruction.RelationalOperationType.Equals; } else if (range == 2) { relationalOperationEF2 = (Instruction.RelationalOperationType) Randomizer.OneFromMany(Instruction.RelationalOperationType.SmallerOrEquals, Instruction.RelationalOperationType.Equals); } else { relationalOperationEF2 = (Instruction.RelationalOperationType) Randomizer.OneFromMany(Instruction.RelationalOperationType.Smaller, Instruction.RelationalOperationType.SmallerOrEquals, Instruction.RelationalOperationType.Equals); } break; } //Defining the constant for the fake2 conditional jump int rightValueEF2 = 0; if (rightValueEF1 == Common.GlobalMinValue || rightValueEF1 == Common.GlobalMaxValue) { rightValueEF2 = rightValueEF1; } else { switch (relationalOperationEF2) { case Instruction.RelationalOperationType.Smaller: case Instruction.RelationalOperationType.SmallerOrEquals: if (rightValueEF1 + range > Common.GlobalMaxValue) { rightValueEF2 = Randomizer.SingleNumber(rightValueEF1, Common.GlobalMaxValue); } else if (rightValueEF1 + range > (int)originalInstruction.GetConstFromCondition() && (originalInstruction.GetRelopFromCondition() == Instruction.RelationalOperationType.Smaller || originalInstruction.GetRelopFromCondition() == Instruction.RelationalOperationType.SmallerOrEquals)) { rightValueEF2 = Randomizer.SingleNumber(rightValueEF1, (int)originalInstruction.GetConstFromCondition()); } else { rightValueEF2 = Randomizer.SingleNumber(rightValueEF1, rightValueEF1 + range); } break; case Instruction.RelationalOperationType.Greater: case Instruction.RelationalOperationType.GreaterOrEquals: if (rightValueEF1 - range < Common.GlobalMinValue) { rightValueEF2 = Randomizer.SingleNumber(Common.GlobalMinValue, rightValueEF1); } else if (rightValueEF1 - range < (int)originalInstruction.GetConstFromCondition() && (originalInstruction.GetRelopFromCondition() == Instruction.RelationalOperationType.Greater || originalInstruction.GetRelopFromCondition() == Instruction.RelationalOperationType.GreaterOrEquals)) { rightValueEF2 = Randomizer.SingleNumber((int)originalInstruction.GetConstFromCondition(), rightValueEF1); } else { rightValueEF2 = Randomizer.SingleNumber(rightValueEF1 - range, rightValueEF1); } break; case Instruction.RelationalOperationType.Equals: { switch (relationalOperationEF1) { case Instruction.RelationalOperationType.Smaller: case Instruction.RelationalOperationType.SmallerOrEquals: if (rightValueEF1 - range < Common.GlobalMinValue) { rightValueEF2 = Randomizer.SingleNumber(Common.GlobalMinValue, rightValueEF1); } else if (rightValueEF1 - range < (int)originalInstruction.GetConstFromCondition() && (originalInstruction.GetRelopFromCondition() == Instruction.RelationalOperationType.Greater || originalInstruction.GetRelopFromCondition() == Instruction.RelationalOperationType.GreaterOrEquals)) { rightValueEF2 = Randomizer.SingleNumber((int)originalInstruction.GetConstFromCondition(), rightValueEF1); } else { rightValueEF2 = Randomizer.SingleNumber(rightValueEF1 - range, rightValueEF1); } break; case Instruction.RelationalOperationType.Greater: case Instruction.RelationalOperationType.GreaterOrEquals: if (rightValueEF1 + range > Common.GlobalMaxValue) { rightValueEF2 = Randomizer.SingleNumber(rightValueEF1, Common.GlobalMaxValue); } else if (rightValueEF1 + range > (int)originalInstruction.GetConstFromCondition() && (originalInstruction.GetRelopFromCondition() == Instruction.RelationalOperationType.Smaller || originalInstruction.GetRelopFromCondition() == Instruction.RelationalOperationType.SmallerOrEquals)) { rightValueEF2 = Randomizer.SingleNumber(rightValueEF1, (int)originalInstruction.GetConstFromCondition()); } else { rightValueEF2 = Randomizer.SingleNumber(rightValueEF1, rightValueEF1 + range); } break; } break; } } } //Selecting the target for fake2 in order to create a loop List <BasicBlock> reacheableBasicBlocks = DataAnalysis.GetReachableBasicBlocks(fake2, Common.Direction.Up); //In case we are at fake jump generation, we should try to choose reachable basic blocks in a loop body //in order to make the CFG irreducible if (atFakeJumpGeneration) { List <BasicBlock> loopReachableBasicBlocks = reacheableBasicBlocks.FindAll(x => DataAnalysis.isLoopBody.Keys.Contains(x) && DataAnalysis.isLoopBody[x] == true); //If we have reachable basic blocks in a loop body, we can use them if (loopReachableBasicBlocks.Count > 0) { int i = Randomizer.SingleNumber(0, 100); if (!fake2.parent.irreducibleCFG || i <= Common.JumpLoopBodyProbability) { reacheableBasicBlocks = loopReachableBasicBlocks; fake2.parent.irreducibleCFG = true; } } } //Check whether the amount of reachable basic blocks we have is greater than MaxJumpForLoop. //This parameter is used to control the chance of problems ("nops" left in the end) during //fake instructions generation. if (reacheableBasicBlocks.Count > Common.MaxJumpBackForLoop) { reacheableBasicBlocks.RemoveRange(Common.MaxJumpBackForLoop, reacheableBasicBlocks.Count - Common.MaxJumpBackForLoop); } //Defining the target basic block for the conditional jump BasicBlock loopTarget = (BasicBlock)Randomizer.OneFromMany(reacheableBasicBlocks.ToArray()); //Creating the fake2 conditional jump to the loop target MakeInstruction.ConditionalJump(fake2.Instructions.Last(), var, rightValueEF2, relationalOperationEF2, loopTarget); }