// this function adds recursively all basic blocks given to the method cfg private void addBasicBlockToCfgRecursively(BasicBlock currentBasicBlock) { // check if the current basic block is set if (currentBasicBlock == null) { return; } // add the given basic block to the method cfg basic blocks // if it is already added => rest is also done if (!methodCfg.basicBlocks.Contains(currentBasicBlock)) { this.methodCfg.basicBlocks.Add(currentBasicBlock); } else { return; } // recursively add all other basic blocks of the new target code to the method cfg if (currentBasicBlock.exitBranch as NoBranchTarget != null) { BasicBlock tempBB = ((NoBranchTarget)currentBasicBlock.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); } else if (currentBasicBlock.exitBranch as TryBlockTarget != null) { BasicBlock tempBB = ((TryBlockTarget)currentBasicBlock.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); } else if (currentBasicBlock.exitBranch as UnconditionalBranchTarget != null) { BasicBlock tempBB = ((UnconditionalBranchTarget)currentBasicBlock.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); } else if (currentBasicBlock.exitBranch as ConditionalBranchTarget != null) { BasicBlock tempBB = ((ConditionalBranchTarget)currentBasicBlock.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); tempBB = ((ConditionalBranchTarget)currentBasicBlock.exitBranch).notTakenTarget; this.addBasicBlockToCfgRecursively(tempBB); } else if (currentBasicBlock.exitBranch as SwitchBranchTarget != null) { BasicBlock tempBB = ((SwitchBranchTarget)currentBasicBlock.exitBranch).notTakenTarget; this.addBasicBlockToCfgRecursively(tempBB); foreach (BasicBlock takenTempBB in ((SwitchBranchTarget)currentBasicBlock.exitBranch).takenTarget) { this.addBasicBlockToCfgRecursively(takenTempBB); } } else if (currentBasicBlock.exitBranch as ExceptionBranchTarget != null) { BasicBlock tempBB = ((ExceptionBranchTarget)currentBasicBlock.exitBranch).exceptionTarget; this.addBasicBlockToCfgRecursively(tempBB); tempBB = ((ExceptionBranchTarget)currentBasicBlock.exitBranch).exitTarget; this.addBasicBlockToCfgRecursively(tempBB); } }
public void addObfuscationToMethod(MethodCfg methodCfg) { MethodCfg copyMethodCfg = new MethodCfg(methodCfg); CfgManipulator cfgManipulator = new CfgManipulator(this.module, this.host, this.logger, methodCfg); GraphRandomStateGenerator randomStateGenerator = new GraphRandomStateGenerator(this.module, this.host, this.logger, cfgManipulator, this.helperClass, this.graph, methodCfg, this.debugging); // DEBUG if (this.debugging) { //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } // add local state variable LocalDefinition intStateLocal = new LocalDefinition(); intStateLocal.IsReference = false; intStateLocal.IsPinned = false; intStateLocal.IsModified = false; intStateLocal.Type = this.host.PlatformType.SystemInt32; intStateLocal.MethodDefinition = methodCfg.method; cfgManipulator.addLocalVariable(intStateLocal); // add local current graph node variable LocalDefinition currentNodeLocal = new LocalDefinition(); currentNodeLocal.IsReference = false; currentNodeLocal.IsPinned = false; currentNodeLocal.IsModified = false; currentNodeLocal.Type = this.nodeInterface; currentNodeLocal.MethodDefinition = methodCfg.method; cfgManipulator.addLocalVariable(currentNodeLocal); // create new basic block that sets the current node to the start node and get the state // (will be the new starting basic block of the method) BasicBlock startBasicBlock = new BasicBlock(); startBasicBlock.startIdx = 0; startBasicBlock.endIdx = 0; // set the current node pointer to the start node startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Stloc, currentNodeLocal)); // initialize the random state generator List<IOperation> tempOperations = randomStateGenerator.generateCodeInitializeRandomState(); startBasicBlock.operations.AddRange(tempOperations); // set global state tempOperations = randomStateGenerator.generateCodeSetRandomState(intStateLocal); startBasicBlock.operations.AddRange(tempOperations); // create exit branch for the new start basic block NoBranchTarget startExitBranch = new NoBranchTarget(); startExitBranch.sourceBasicBlock = startBasicBlock; startBasicBlock.exitBranch = startExitBranch; // set the original start basic block as the target of the exit branch startExitBranch.takenTarget = methodCfg.startBasicBlock; methodCfg.startBasicBlock.entryBranches.Add(startExitBranch); // set new start basic block as start basic block of the method cfg methodCfg.startBasicBlock = startBasicBlock; methodCfg.basicBlocks.Add(startBasicBlock); // obfuscate the control flow this.addMetadataIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal); this.processExitBranchesIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal); this.addOpaquePredicatesIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal); this.removeReplaceUnconditionalBranchesIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal); // fill dead code basic blocks with actual dead code this.fillDeadCodeBasicBlocks(methodCfg); this.obfuscateSemanticallyEquivalentBlocks(methodCfg); // TODO QUICK FIX // mutateBlocks() does not work when debugging is deactivated // but since we only focus on probabilistic control flow, ignore it for now this.debugging = true; this.mutateBlocks(methodCfg); this.debugging = false; // if debugging is activated => add code that allows to trace the control flow through the method if (this.debugging || this.trace) { List<IOperation> traceWriterOperations = null; // add code to the beginning of each basic block that writes to the trace file for (int idx = 0; idx < methodCfg.basicBlocks.Count(); idx++) { traceWriterOperations = new List<IOperation>(); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldfld, this.debuggingTraceWriter)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, "BB" + idx.ToString() + ";ID" + methodCfg.basicBlocks.ElementAt(idx).id.ToString())); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.textWriterWriteLine)); methodCfg.basicBlocks.ElementAt(idx).operations.InsertRange(0, traceWriterOperations); // check if the basic block has an exit branch // => add code that closes the file handler of the trace file before the ret instruction if ((methodCfg.basicBlocks.ElementAt(idx).exitBranch as ExitBranchTarget) != null) { traceWriterOperations = new List<IOperation>(); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldfld, this.debuggingTraceWriter)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.textWriterClose)); methodCfg.basicBlocks.ElementAt(idx).operations.InsertRange(methodCfg.basicBlocks.ElementAt(idx).operations.Count() - 1, traceWriterOperations); } } // create local integer variable needed for the trace file code LocalDefinition intLocal = new LocalDefinition(); intLocal.IsReference = false; intLocal.IsPinned = false; intLocal.IsModified = false; intLocal.Type = this.host.PlatformType.SystemInt32; intLocal.MethodDefinition = methodCfg.method; cfgManipulator.addLocalVariable(intLocal); traceWriterOperations = new List<IOperation>(); // get the hash code of this instance as unique object id traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.objectGetHashCode)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Stloc, intLocal)); // initialize io stream writer for trace file (use object hash as id for this trace and only append) traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingDumpLocation + "\\" + this.debuggingTraceFilePrefix + "_")); // cast random integer to string and store in object id traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloca, intLocal)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Call, this.helperClass.int32ToString)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, ".txt")); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Call, this.helperClass.stringConcatThree)); // only append to file traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_1)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Newobj, this.helperClass.streamWriterCtorAppend)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Stfld, this.debuggingTraceWriter)); // write marker to trace file that marks the beginning of this trace traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldfld, this.debuggingTraceWriter)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, "\n------NEWSTART------\n")); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.textWriterWriteLine)); // add code to the beginning of the start basic block methodCfg.startBasicBlock.operations.InsertRange(0, traceWriterOperations); } logger.dumpMethodCfg(copyMethodCfg, "copy_final"); return; }
// ################################################### BRANCH MANIPULATION LOGIC ################################################### // insert the given new target basic block (given by start and end block) between the given branch to manipulate private void insertBasicBlockBetweenBranch(BasicBlock introBasicBlock, BasicBlock outroBasicBlock, IBranchTarget branchToManipulate, ref BasicBlock branchToManipulateTargetBasicBlock, BasicBlock newTargetStart, BasicBlock newTargetEnd, IBranchTarget exitBranch, ref BasicBlock exitBranchTargetBasicBlock) { // check if there exists try/handler blocks if (introBasicBlock.tryBlocks.Count() != 0) { throw new ArgumentException("Try blocks not yet implemented."); } if (introBasicBlock.handlerBlocks.Count() != 0) { throw new ArgumentException("Handler blocks not yet implemented."); } // add the new target given by basic blocks to the method cfg basic blocks if (!methodCfg.basicBlocks.Contains(newTargetStart)) { this.methodCfg.basicBlocks.Add(newTargetStart); } // recursively add all other basic blocks of the new target code to the method cfg if (newTargetStart.exitBranch as NoBranchTarget != null) { if (newTargetStart != newTargetEnd) { BasicBlock tempBB = ((NoBranchTarget)newTargetStart.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); } } else if (newTargetStart.exitBranch as TryBlockTarget != null) { if (newTargetStart != newTargetEnd) { BasicBlock tempBB = ((TryBlockTarget)newTargetStart.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); } } else if (newTargetStart.exitBranch as UnconditionalBranchTarget != null) { if (newTargetStart != newTargetEnd) { BasicBlock tempBB = ((UnconditionalBranchTarget)newTargetStart.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); } } else if (newTargetStart.exitBranch as ConditionalBranchTarget != null) { BasicBlock tempBB = ((ConditionalBranchTarget)newTargetStart.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); tempBB = ((ConditionalBranchTarget)newTargetStart.exitBranch).notTakenTarget; this.addBasicBlockToCfgRecursively(tempBB); } else if (newTargetStart.exitBranch as SwitchBranchTarget != null) { BasicBlock tempBB = ((SwitchBranchTarget)newTargetStart.exitBranch).notTakenTarget; this.addBasicBlockToCfgRecursively(tempBB); foreach (BasicBlock takenTempBB in ((SwitchBranchTarget)newTargetStart.exitBranch).takenTarget) { this.addBasicBlockToCfgRecursively(takenTempBB); } } else if (newTargetStart.exitBranch as ExceptionBranchTarget != null) { BasicBlock tempBB = ((ExceptionBranchTarget)newTargetStart.exitBranch).exceptionTarget; this.addBasicBlockToCfgRecursively(tempBB); tempBB = ((ExceptionBranchTarget)newTargetStart.exitBranch).exitTarget; this.addBasicBlockToCfgRecursively(tempBB); } else { throw new ArgumentException("Do not know how to handle branch target in order to add all basic blocks to the method CFG."); } // add the branch to manipulate as the entry branch of the new target basic block newTargetStart.entryBranches.Add(branchToManipulate); // remove branch entry from old target outroBasicBlock.entryBranches.Remove(branchToManipulate); // make the given target basic block the new branch target branchToManipulateTargetBasicBlock = newTargetStart; // set branch as exit branch of the new last basic block of the new target code newTargetEnd.exitBranch = exitBranch; // set the last basic block of the new target as source of the exit branch exitBranch.sourceBasicBlock = newTargetEnd; exitBranchTargetBasicBlock = outroBasicBlock; // add branch to the list of entry branches of the original outro basic block // (if the exit branch of the new code is a no branch target => check if it is the only one that entries the outro basic block) if ((exitBranch as NoBranchTarget) != null) { foreach (IBranchTarget temp in outroBasicBlock.entryBranches) { if ((temp as NoBranchTarget) != null) { throw new ArgumentException("Only one 'No Branch Target' can be entry of a basic block."); } } } outroBasicBlock.entryBranches.Add(exitBranch); }
// insert the given new target basic block between the given switch branch to manipulate public void insertBasicBlockBetweenBranch(SwitchBranchTarget branchToManipulate, int manipulateTakenBranchIdx, BasicBlock newTarget, ConditionalBranchTarget exitBranch, bool useTakenBranch) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = null; // check wether to use the taken or not taken part of the exit branch if (useTakenBranch) { outroBasicBlock = branchToManipulate.takenTarget.ElementAt(manipulateTakenBranchIdx); BasicBlock tempTakenTarget = null; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref tempTakenTarget, newTarget, newTarget, exitBranch, ref exitBranch.takenTarget); branchToManipulate.takenTarget[manipulateTakenBranchIdx] = tempTakenTarget; } else { outroBasicBlock = branchToManipulate.takenTarget.ElementAt(manipulateTakenBranchIdx); BasicBlock tempTakenTarget = null; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref tempTakenTarget, newTarget, newTarget, exitBranch, ref exitBranch.notTakenTarget); branchToManipulate.takenTarget[manipulateTakenBranchIdx] = tempTakenTarget; } }
// insert the given new target basic block (given by start and end block) between the given conditional branch to manipulate public void insertBasicBlockBetweenBranch(ConditionalBranchTarget branchToManipulate, bool manipulateTakenBranch, BasicBlock newTargetStart, BasicBlock newTargetEnd, UnconditionalBranchTarget exitBranch) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = null; // manipulate the correct branch if (manipulateTakenBranch) { outroBasicBlock = branchToManipulate.takenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTargetStart, newTargetEnd, exitBranch, ref exitBranch.takenTarget); } else { outroBasicBlock = branchToManipulate.notTakenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.notTakenTarget, newTargetStart, newTargetEnd, exitBranch, ref exitBranch.takenTarget); } }
// insert the given new target basic block between the given conditional branch to manipulate public void insertBasicBlockBetweenBranch(ConditionalBranchTarget branchToManipulate, bool manipulateTakenBranch, BasicBlock newTarget, ConditionalBranchTarget exitBranch, bool useTakenBranch) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = null; // check wether to use the taken or not taken part of the exit branch if (useTakenBranch) { // check wether to manipulate the taken or not taken branch of the branch to manipulate if (manipulateTakenBranch) { outroBasicBlock = branchToManipulate.takenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref exitBranch.takenTarget); } else { outroBasicBlock = branchToManipulate.notTakenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.notTakenTarget, newTarget, newTarget, exitBranch, ref exitBranch.takenTarget); } } else { // check wether to manipulate the taken or not taken branch of the branch to manipulate if (manipulateTakenBranch) { outroBasicBlock = branchToManipulate.takenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref exitBranch.notTakenTarget); } else { outroBasicBlock = branchToManipulate.notTakenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.notTakenTarget, newTarget, newTarget, exitBranch, ref exitBranch.notTakenTarget); } } }
// this function replaces a basic block inside the cfg (oldBasicBlock) with a new basic block (newBasicBlock) public void replaceBasicBlock(BasicBlock oldBasicBlock, BasicBlock newBasicBlock) { this.replaceBasicBlock(oldBasicBlock, newBasicBlock, newBasicBlock); }
public CodeMutator(IModule module, PeReader.DefaultHost host, Log.Log logger, Random prng, MethodCfg methodCfg, CfgManipulator manipulator, bool debugging=false) { this.host = host; this.logger = logger; this.module = module; this.prng = prng; this.methodCfg = methodCfg; this.debugging = debugging; this.manipulator = manipulator; returnBlock = new BasicBlock(); var exitBranch = new ExitBranchTarget(); returnBlock.exitBranch = exitBranch; returnBlock.operations.Add(createNewOperation(OperationCode.Ret)); methodCfg.basicBlocks.Add(returnBlock); }
private void mutateRet(BasicBlock block, int index) { if(prng.Next(3) == 0) { return; } var exitBranch = new UnconditionalBranchTarget(); exitBranch.takenTarget = returnBlock; exitBranch.sourceBasicBlock = block; block.exitBranch = exitBranch; returnBlock.entryBranches.Add(exitBranch); var branchToReturn = createNewOperation(OperationCode.Br, 0); block.operations[index] = branchToReturn; block.semanticId = -1; }
private void removeReplaceUnconditionalBranchesIter(CfgManipulator cfgManipulator, GraphRandomStateGenerator randomStateGenerator, MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock startBasicBlock, LocalDefinition intStateLocal, LocalDefinition currentNodeLocal) { // create a list of basic blocks that still have to be processed by the algorithm List<BasicBlock> basicBlocksToProcess = new List<BasicBlock>(methodCfg.basicBlocks); System.Console.WriteLine("Basic Blocks to process (Replace Unconditional Branches): " + basicBlocksToProcess.Count()); while (true) { List<BasicBlock> copiedList = new List<BasicBlock>(basicBlocksToProcess); foreach (BasicBlock currentBasicBlock in copiedList) { // check if basic block has entry branches that can be optimized bool hasUnconditionalBranchTarget = false; bool hasNoBranchTarget = false; foreach (IBranchTarget entryBranch in currentBasicBlock.entryBranches) { if ((entryBranch as NoBranchTarget) != null) { hasNoBranchTarget = true; continue; } else if ((entryBranch as UnconditionalBranchTarget) != null) { hasUnconditionalBranchTarget = true; continue; } } // skip if basic block already has no branch target if (hasNoBranchTarget) { // remove currently processed basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); continue; } // skip if basic block does not have an unconditional branch target if (!hasUnconditionalBranchTarget) { // remove currently processed basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); continue; } // replace one unconditional branch by a no branch List<IBranchTarget> copiedBranchList = new List<IBranchTarget>(currentBasicBlock.entryBranches); foreach (IBranchTarget entryBranch in copiedBranchList) { if ((entryBranch as UnconditionalBranchTarget) != null) { BasicBlock sourceBasicBlock = entryBranch.sourceBasicBlock; // create replacement branch NoBranchTarget replacementBranch = new NoBranchTarget(); replacementBranch.sourceBasicBlock = sourceBasicBlock; replacementBranch.takenTarget = currentBasicBlock; // replace old branch with new one sourceBasicBlock.exitBranch = replacementBranch; currentBasicBlock.entryBranches.Remove(entryBranch); currentBasicBlock.entryBranches.Add(replacementBranch); // replace unconditional branch instruction with nop IOperation lastOperation = sourceBasicBlock.operations.ElementAt(sourceBasicBlock.operations.Count() - 1); if (!CfgBuilder.isUnconditionalBranchOperation(lastOperation)) { throw new ArgumentException("Last instruction of basic block have to be an unconditional branch."); } IOperation replacementOperation = this.helperClass.createNewOperation(OperationCode.Nop); sourceBasicBlock.operations[sourceBasicBlock.operations.Count() - 1] = replacementOperation; break; } } // remove currently processed basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); } System.Console.WriteLine("Basic Blocks to process (Replace Unconditional Branches): " + basicBlocksToProcess.Count()); // check if basic blocks exist to process => if not break loop if (basicBlocksToProcess.Count() == 0) { break; } } }
// this function creates all methods that are needed for the generated graph public void createGraphMethods() { this.logger.writeLine("Adding graph methods to \"" + this.targetClass.ToString() + "\""); // check if the graph is already initialized (needed to create the methods) if (this.graph == null) { throw new ArgumentException("Graph is not initialized."); } // if debugging is activated // => add field for the basic block trace file if (this.debugging || this.trace) { this.logger.writeLine("Debugging activated: Adding field for a basic block tracer file"); // add trace writer field this.debuggingTraceWriter = new FieldDefinition(); this.debuggingTraceWriter.IsCompileTimeConstant = false; this.debuggingTraceWriter.IsNotSerialized = false; this.debuggingTraceWriter.IsReadOnly = false; this.debuggingTraceWriter.IsRuntimeSpecial = false; this.debuggingTraceWriter.IsSpecialName = false; this.debuggingTraceWriter.Type = this.helperClass.systemIOStreamWriter; this.debuggingTraceWriter.IsStatic = false; this.debuggingTraceWriter.Name = host.NameTable.GetNameFor("DEBUG_traceWriter"); this.debuggingTraceWriter.Visibility = TypeMemberVisibility.Public; this.debuggingTraceWriter.InternFactory = host.InternFactory; this.debuggingTraceWriter.ContainingTypeDefinition = this.targetClass; this.targetClass.Fields.Add(this.debuggingTraceWriter); } // create a method that can be called to generate the graph this.buildGraphMethod = this.helperClass.createNewMethod("buildGraph", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, null, CallingConvention.HasThis, false, false, true); // TODO RENAME ILGenerator ilGenerator = new ILGenerator(host, this.buildGraphMethod); // check if graph was already build // => if it was jump to exit ILGeneratorLabel buildGraphExitLabel = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brfalse, buildGraphExitLabel); // set initial node (root of the tree) ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldarg_0); // needed as argument for the constructor ilGenerator.Emit(OperationCode.Newobj, this.graph.startingNode.constructorToUse); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerSet); // build rest of graph in a "pseudo recursive" manner MethodDefinition newMethodToCall = this.addNodeRecursively(this.graph.startingNode, 1, "addNode_0"); // TODO: method name ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Callvirt, newMethodToCall); // exit ilGenerator.MarkLabel(buildGraphExitLabel); ilGenerator.Emit(OperationCode.Ret); // create body IMethodBody body = new ILGeneratorMethodBody(ilGenerator, true, 8, this.buildGraphMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); this.buildGraphMethod.Body = body; // create exchangeNodes method List<IParameterDefinition> parameters = new List<IParameterDefinition>(); // node type parameter ParameterDefinition parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameters.Add(parameter); // int array parameter for path to node one VectorTypeReference intArrayType = new VectorTypeReference(); intArrayType.ElementType = this.host.PlatformType.SystemInt32; intArrayType.Rank = 1; intArrayType.IsFrozen = true; intArrayType.IsValueType = false; intArrayType.InternFactory = host.InternFactory; parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = intArrayType; parameters.Add(parameter); // int array parameter for path to node two parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = intArrayType; parameters.Add(parameter); this.exchangeNodesMethod = this.helperClass.createNewMethod("exchangeNodes", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO RENAME ilGenerator = new ILGenerator(host, this.exchangeNodesMethod); List<ILocalDefinition> localVariables = new List<ILocalDefinition>(); // create local integer variable needed for the loops LocalDefinition loopIntLocal = new LocalDefinition(); loopIntLocal.IsReference = false; loopIntLocal.IsPinned = false; loopIntLocal.IsModified = false; loopIntLocal.Type = this.host.PlatformType.SystemInt32; loopIntLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(loopIntLocal); // create local iNode variable needed for nodeOne LocalDefinition nodeOneLocal = new LocalDefinition(); nodeOneLocal.IsReference = false; nodeOneLocal.IsPinned = false; nodeOneLocal.IsModified = false; nodeOneLocal.Type = this.nodeInterface; nodeOneLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(nodeOneLocal); // create local iNode variable needed for prevNodeOne LocalDefinition prevNodeOneLocal = new LocalDefinition(); prevNodeOneLocal.IsReference = false; prevNodeOneLocal.IsPinned = false; prevNodeOneLocal.IsModified = false; prevNodeOneLocal.Type = this.nodeInterface; prevNodeOneLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(prevNodeOneLocal); // create local integer variable needed for prevNodeOneIdx LocalDefinition prevNodeOneIdxLocal = new LocalDefinition(); prevNodeOneIdxLocal.IsReference = false; prevNodeOneIdxLocal.IsPinned = false; prevNodeOneIdxLocal.IsModified = false; prevNodeOneIdxLocal.Type = this.host.PlatformType.SystemInt32; prevNodeOneIdxLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(prevNodeOneIdxLocal); // create local iNode variable needed for nodeTwo LocalDefinition nodeTwoLocal = new LocalDefinition(); nodeTwoLocal.IsReference = false; nodeTwoLocal.IsPinned = false; nodeTwoLocal.IsModified = false; nodeTwoLocal.Type = this.nodeInterface; nodeTwoLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(nodeTwoLocal); // create local iNode variable needed for prevNodeOne LocalDefinition prevNodeTwoLocal = new LocalDefinition(); prevNodeTwoLocal.IsReference = false; prevNodeTwoLocal.IsPinned = false; prevNodeTwoLocal.IsModified = false; prevNodeTwoLocal.Type = this.nodeInterface; prevNodeTwoLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(prevNodeTwoLocal); // create local integer variable needed for prevNodeOneIdx LocalDefinition prevNodeTwoIdxLocal = new LocalDefinition(); prevNodeTwoIdxLocal.IsReference = false; prevNodeTwoIdxLocal.IsPinned = false; prevNodeTwoIdxLocal.IsModified = false; prevNodeTwoIdxLocal.Type = this.host.PlatformType.SystemInt32; prevNodeTwoIdxLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(prevNodeTwoIdxLocal); // create local iNode variable needed for temp LocalDefinition tempNodeLocal = new LocalDefinition(); tempNodeLocal.IsReference = false; tempNodeLocal.IsPinned = false; tempNodeLocal.IsModified = false; tempNodeLocal.Type = this.nodeInterface; tempNodeLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(tempNodeLocal); // initialize local variables /* iNode nodeOne = givenStartingNode; iNode prevNodeOne = null; int prevNodeOneIdx = 0; */ ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Stloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Stloc, prevNodeOneLocal); ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, prevNodeOneIdxLocal); // initialize loop ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); ILGeneratorLabel loopConditionAndIncBranch = new ILGeneratorLabel(); ILGeneratorLabel loopConditionBranch = new ILGeneratorLabel(); ILGeneratorLabel loopStartBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, loopConditionBranch); // start of the code in the loop /* if (nodeOne.getNode(pathToNodeOne[i]) != null) { */ ilGenerator.MarkLabel(loopStartBranch); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldelem_I4); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch); // get the node of the graph that should be exchanged (nodeOne) /* prevNodeOne = nodeOne; prevNodeOneIdx = pathToNodeOne[i]; nodeOne = nodeOne.getNode(pathToNodeOne[i]); */ ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Stloc, prevNodeOneLocal); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldelem_I4); ilGenerator.Emit(OperationCode.Stloc, prevNodeOneIdxLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneIdxLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Stloc, nodeOneLocal); // increment counter of loop ilGenerator.MarkLabel(loopConditionAndIncBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Add); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); // loop condition /* for (int i = 0; i < pathToNodeOne.Length; i++) { */ ilGenerator.MarkLabel(loopConditionBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldlen); ilGenerator.Emit(OperationCode.Conv_I4); ilGenerator.Emit(OperationCode.Clt); ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch); // initialize local variables /* iNode nodeTwo = givenStartingNode; iNode prevNodeTwo = null; int prevNodeTwoIdx = 0; */ ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Stloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoLocal); ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoIdxLocal); // initialize loop ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); loopConditionAndIncBranch = new ILGeneratorLabel(); loopConditionBranch = new ILGeneratorLabel(); loopStartBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, loopConditionBranch); // start of the code in the loop /* if (nodeTwo.getNode(pathToNodeTwo[i]) != null) { */ ilGenerator.MarkLabel(loopStartBranch); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldelem_I4); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch); // get the node of the graph that should be exchanged (nodeTwo) /* prevNodeTwo = nodeTwo; prevNodeTwoIdx = pathToNodeTwo[i]; nodeTwo = nodeTwo.getNode(pathToNodeTwo[i]); */ ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoLocal); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldelem_I4); ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoIdxLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoIdxLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Stloc, nodeTwoLocal); // increment counter of loop ilGenerator.MarkLabel(loopConditionAndIncBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Add); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); // loop condition /* for (int i = 0; i < pathToNodeTwo.Length; i++) { */ ilGenerator.MarkLabel(loopConditionBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ldlen); ilGenerator.Emit(OperationCode.Conv_I4); ilGenerator.Emit(OperationCode.Clt); ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch); // initialize loop ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); loopConditionAndIncBranch = new ILGeneratorLabel(); loopConditionBranch = new ILGeneratorLabel(); loopStartBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, loopConditionBranch); // start of the code in the loop ilGenerator.MarkLabel(loopStartBranch); /* if (nodeOne.getNode(i) == nodeTwo) { */ ILGeneratorLabel conditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brfalse, conditionBranch); /* nodeOne.setNode(nodeTwo.getNode(i), i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); /* nodeTwo.setNode(nodeOne, i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); ilGenerator.Emit(OperationCode.Br, loopConditionAndIncBranch); /* else if (nodeTwo.getNode(i) == nodeOne) { */ ilGenerator.MarkLabel(conditionBranch); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ceq); conditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Brfalse, conditionBranch); /* nodeTwo.setNode(nodeOne.getNode(i), i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); /* nodeOne.setNode(nodeTwo, i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); ilGenerator.Emit(OperationCode.Br, loopConditionAndIncBranch); /* else { */ ilGenerator.MarkLabel(conditionBranch); /* temp = nodeOne.getNode(i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Stloc, tempNodeLocal); /* nodeOne.setNode(nodeTwo.getNode(i), i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); /* nodeTwo.setNode(temp, i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, tempNodeLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); // increment counter of loop ilGenerator.MarkLabel(loopConditionAndIncBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Add); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); // loop condition /* for (int i = 0; i < GRAPH_DIMENSION; i++) { */ ilGenerator.MarkLabel(loopConditionBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldc_I4, this.graphDimension); ilGenerator.Emit(OperationCode.Clt); ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch); /* if (prevNodeOne != null) { */ conditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneLocal); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, conditionBranch); /* if (prevNodeOne != nodeTwo) { */ ILGeneratorLabel exitConditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, exitConditionBranch); /* prevNodeOne.setNode(nodeTwo, prevNodeOneIdx); */ ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneIdxLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); ilGenerator.Emit(OperationCode.Br, exitConditionBranch); /* else { */ ilGenerator.MarkLabel(conditionBranch); /* this.graphStartNode = nodeTwo; */ ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerSet); ilGenerator.MarkLabel(exitConditionBranch); /* if (prevNodeTwo != null) { */ conditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoLocal); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, conditionBranch); /* if (prevNodeTwo != nodeOne) { */ exitConditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, exitConditionBranch); /* prevNodeTwo.setNode(nodeOne, prevNodeTwoIdx); */ ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoIdxLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); ilGenerator.Emit(OperationCode.Br, exitConditionBranch); /* else { */ ilGenerator.MarkLabel(conditionBranch); /* this.graphStartNode = nodeOne; */ ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerSet); ilGenerator.MarkLabel(exitConditionBranch); ilGenerator.Emit(OperationCode.Ret); // create body body = new ILGeneratorMethodBody(ilGenerator, true, 8, this.exchangeNodesMethod, localVariables, Enumerable<ITypeDefinition>.Empty); this.exchangeNodesMethod.Body = body; // check if debugging is activated // => add function to dump graph as .dot file if (this.debugging) { this.logger.writeLine("Debugging activated: Adding code to dump graph as .dot file"); // create dumpGraph method parameters = new List<IParameterDefinition>(); // string parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.host.PlatformType.SystemString; parameter.Index = 0; parameters.Add(parameter); // node type parameter (current pointer of debug method) parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameter.Index = 1; parameters.Add(parameter); // node type parameter (current pointer of caller) parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameter.Index = 2; parameters.Add(parameter); this.debuggingDumpGraphMethod = this.helperClass.createNewMethod("DEBUG_dumpGraph", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // create dumpGraphRec method parameters = new List<IParameterDefinition>(); // stream writer parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.helperClass.systemIOStreamWriter; parameter.Index = 0; parameters.Add(parameter); // string parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.host.PlatformType.SystemString; parameter.Index = 1; parameters.Add(parameter); // node type parameter (current pointer of debug method) parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameter.Index = 2; parameters.Add(parameter); // node type parameter (current pointer of caller) ParameterDefinition currentNodeCallerParameter = new ParameterDefinition(); currentNodeCallerParameter.IsIn = false; currentNodeCallerParameter.IsOptional = false; currentNodeCallerParameter.IsOut = false; currentNodeCallerParameter.Type = this.nodeInterface; currentNodeCallerParameter.Index = 3; parameters.Add(currentNodeCallerParameter); MethodDefinition dumpGraphRecMethod = this.helperClass.createNewMethod("DEBUG_dumpGraphRec", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); currentNodeCallerParameter.ContainingSignature = dumpGraphRecMethod; // is needed when parameter is accessed via Ldarg // create body for dumpGraph method ilGenerator = new ILGenerator(host, this.debuggingDumpGraphMethod); localVariables = new List<ILocalDefinition>(); // create local string variable needed for debugging code LocalDefinition nodeNameLocal = new LocalDefinition(); nodeNameLocal.IsReference = false; nodeNameLocal.IsPinned = false; nodeNameLocal.IsModified = false; nodeNameLocal.Type = this.host.PlatformType.SystemString; nodeNameLocal.MethodDefinition = this.debuggingDumpGraphMethod; localVariables.Add(nodeNameLocal); // create local stream writer variable needed for debugging code LocalDefinition streamWriterLocal = new LocalDefinition(); streamWriterLocal.IsReference = false; streamWriterLocal.IsPinned = false; streamWriterLocal.IsModified = false; streamWriterLocal.Type = this.helperClass.systemIOStreamWriter; streamWriterLocal.MethodDefinition = this.debuggingDumpGraphMethod; localVariables.Add(streamWriterLocal); // create local integer variable for the for loop needed for debugging code LocalDefinition forIntegerLocal = new LocalDefinition(); forIntegerLocal.IsReference = false; forIntegerLocal.IsPinned = false; forIntegerLocal.IsModified = false; forIntegerLocal.Type = this.host.PlatformType.SystemInt32; forIntegerLocal.MethodDefinition = this.debuggingDumpGraphMethod; localVariables.Add(forIntegerLocal); // generate dump file location string ilGenerator.Emit(OperationCode.Ldstr, this.debuggingDumpLocation + this.debuggingDumpFilePrefix); ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldstr, ".dot"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // initialize io stream writer ilGenerator.Emit(OperationCode.Newobj, this.helperClass.streamWriterCtor); ilGenerator.Emit(OperationCode.Stloc, streamWriterLocal); // initialize .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldstr, "digraph G {"); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // check if the node to dump is the same as the current node of the class // if it is => color the current dumped node ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ceq); ILGeneratorLabel currentNodeEqualDumpedNodeBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Brtrue, currentNodeEqualDumpedNodeBranch); // case: current dumped node is not the current node of the class // create name for the nodes ilGenerator.Emit(OperationCode.Ldstr, "node_0"); ilGenerator.Emit(OperationCode.Stloc, nodeNameLocal); // write current node to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, " [shape=record]"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // jump to the end of this case ILGeneratorLabel currentNodeDumpedBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, currentNodeDumpedBranch); // case: current dumped node is the current node of the class ilGenerator.MarkLabel(currentNodeEqualDumpedNodeBranch); // create name for the nodes ilGenerator.Emit(OperationCode.Ldstr, "node_0"); ilGenerator.Emit(OperationCode.Stloc, nodeNameLocal); // write current node to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, " [shape=record, color=blue]"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // end of the case ilGenerator.MarkLabel(currentNodeDumpedBranch); // write start of label of the current node to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, " [label=\"{"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write current node name to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldstr, "Node: "); ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, "|"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write current node id to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldstr, "Id: "); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Callvirt, this.debuggingInterfaceIdGet); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write end of label of the current node to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldstr, "}\"]"); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // initialize counter of for loop ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal); // jump to loop condition loopConditionBranch = new ILGeneratorLabel(); loopStartBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, loopConditionBranch); // start of loop ilGenerator.MarkLabel(loopStartBranch); // check if childNodes[i] == startNode ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet); ilGenerator.Emit(OperationCode.Ceq); loopConditionAndIncBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch); // write connection of current node to next node to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); // generate first part of the string ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, " -> "); ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // generate second part of string and concat to first part ilGenerator.Emit(OperationCode.Ldstr, "_"); ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // write to .dot file ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // call method that dumps graph recursively ( this.dumpGraphRec(streamWriter, String name, nextNode) ) ilGenerator.Emit(OperationCode.Ldarg_0); // push stream writer parameter ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); // push string parameter ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, "_"); ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // push node parameter (current pointer of debug method) ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); // push node parameter (current pointer of the caller) ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Callvirt, dumpGraphRecMethod); // increment loop counter ilGenerator.MarkLabel(loopConditionAndIncBranch); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Add); ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal); // loop condition ilGenerator.MarkLabel(loopConditionBranch); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Ldc_I4, this.graphDimension); ilGenerator.Emit(OperationCode.Clt); ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch); // end .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldstr, "}"); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // close io stream writer ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterClose); ilGenerator.Emit(OperationCode.Ret); // create body body = new ILGeneratorMethodBody(ilGenerator, true, 8, this.debuggingDumpGraphMethod, localVariables, Enumerable<ITypeDefinition>.Empty); this.debuggingDumpGraphMethod.Body = body; // create body for dumpGraphRec method localVariables = new List<ILocalDefinition>(); ilGenerator = new ILGenerator(host, dumpGraphRecMethod); // create local integer variable for the for loop needed for debugging code forIntegerLocal = new LocalDefinition(); forIntegerLocal.IsReference = false; forIntegerLocal.IsPinned = false; forIntegerLocal.IsModified = false; forIntegerLocal.Type = this.host.PlatformType.SystemInt32; forIntegerLocal.MethodDefinition = dumpGraphRecMethod; localVariables.Add(forIntegerLocal); // check if the node to dump is the same as the current node of the class // if it is => color the current dumped node ilGenerator.Emit(OperationCode.Ldarg, currentNodeCallerParameter); ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ceq); currentNodeEqualDumpedNodeBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Brtrue, currentNodeEqualDumpedNodeBranch); // case: current dumped node is not the current node of the class // write current node to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, " [shape=record]"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // jump to the end of this case currentNodeDumpedBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, currentNodeDumpedBranch); // case: current dumped node is the current node of the class ilGenerator.MarkLabel(currentNodeEqualDumpedNodeBranch); // write current node to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, " [shape=record, color=blue]"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // end of the case ilGenerator.MarkLabel(currentNodeDumpedBranch); // write start of label of the current node to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, " [label=\"{"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write current node name to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldstr, "Node: "); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, "|"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write current node id to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldstr, "Id: "); ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Callvirt, this.debuggingInterfaceIdGet); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write end of label of the current node to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldstr, "}\"]"); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // initialize counter of for loop ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal); // jump to loop condition loopConditionBranch = new ILGeneratorLabel(); loopStartBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, loopConditionBranch); // start of loop ilGenerator.MarkLabel(loopStartBranch); // check if childNodes[i] == startNode ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet); ilGenerator.Emit(OperationCode.Ceq); loopConditionAndIncBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch); // write connection of current node to next node to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); // generate first part of the string ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, " -> "); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // generate second part of string and concat to first part ilGenerator.Emit(OperationCode.Ldstr, "_"); ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // write to .dot file ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // call method that dumps graph recursively ( this.dumpGraphRec(streamWriter, String name, nextNode) ) ilGenerator.Emit(OperationCode.Ldarg_0); // push stream writer parameter ilGenerator.Emit(OperationCode.Ldarg_1); // push string parameter ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, "_"); ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // push node parameter (current pointer of debug method) ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); // push node parameter (current pointer of the caller) ilGenerator.Emit(OperationCode.Ldarg, currentNodeCallerParameter); ilGenerator.Emit(OperationCode.Callvirt, dumpGraphRecMethod); // increment loop counter ilGenerator.MarkLabel(loopConditionAndIncBranch); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Add); ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal); // loop condition ilGenerator.MarkLabel(loopConditionBranch); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Ldc_I4, this.graphDimension); ilGenerator.Emit(OperationCode.Clt); ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch); ilGenerator.Emit(OperationCode.Ret); // create body body = new ILGeneratorMethodBody(ilGenerator, true, 8, dumpGraphRecMethod, localVariables, Enumerable<ITypeDefinition>.Empty); dumpGraphRecMethod.Body = body; } // inject code to build the graph to all constructors (except the artificial added ctor for a graph node) foreach (MethodDefinition ctorMethod in this.targetClass.Methods) { // only process constructors if (!ctorMethod.IsConstructor) { continue; } // skip the artificial added ctor with the node interface as parameter bool skip = false; if (ctorMethod.Parameters != null) { foreach (IParameterDefinition ctorParameter in ctorMethod.Parameters) { if (ctorParameter.Type == this.nodeInterface) { skip = true; break; } } } if (skip) { continue; } this.logger.writeLine("Injecting code to build graph to \"" + this.logger.makeFuncSigString(ctorMethod) + "\""); MethodCfg ctorMethodCfg = this.cfgBuilder.buildCfgForMethod(ctorMethod); // create new basic block that builds the graph // (will be the new starting basic block of the method) BasicBlock startBasicBlock = new BasicBlock(); startBasicBlock.startIdx = 0; startBasicBlock.endIdx = 0; startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.buildGraphMethod)); if (this.debugging) { // dump generated graph startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(ctorMethodCfg.method))); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); } // create exit branch for the new start basic block NoBranchTarget startExitBranch = new NoBranchTarget(); startExitBranch.sourceBasicBlock = startBasicBlock; startBasicBlock.exitBranch = startExitBranch; // set the original start basic block as the target of the exit branch startExitBranch.takenTarget = ctorMethodCfg.startBasicBlock; ctorMethodCfg.startBasicBlock.entryBranches.Add(startExitBranch); // set new start basic block as start basic block of the method cfg ctorMethodCfg.startBasicBlock = startBasicBlock; ctorMethodCfg.basicBlocks.Add(startBasicBlock); this.cfgBuilder.createMethodFromCfg(ctorMethodCfg); } }
private void addOpaquePredicatesIter(CfgManipulator cfgManipulator, GraphRandomStateGenerator randomStateGenerator, MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock startBasicBlock, LocalDefinition intStateLocal, LocalDefinition currentNodeLocal) { // create a list of basic blocks that still have to be processed by the algorithm List<BasicBlock> basicBlocksToProcess = new List<BasicBlock>(methodCfg.basicBlocks); System.Console.WriteLine("Basic Blocks to process (Opaque Predicates): " + basicBlocksToProcess.Count()); while (true) { List<BasicBlock> copiedList = new List<BasicBlock>(basicBlocksToProcess); foreach (BasicBlock currentBasicBlock in copiedList) { // process all entry branches of the current basic block List<IBranchTarget> copiedBranchList = new List<IBranchTarget>(currentBasicBlock.entryBranches); foreach (IBranchTarget entryBranch in copiedBranchList) { // get the metadata for the source basic block of the entry branch BasicBlock sourceBasicBlock = entryBranch.sourceBasicBlock; IGraphTransformerMetadata sourceMetadata = null; for (int i = 0; i < sourceBasicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((sourceBasicBlock.transformationMetadata.ElementAt(i) as IGraphTransformerMetadata) == null) { continue; } sourceMetadata = (sourceBasicBlock.transformationMetadata.ElementAt(i) as IGraphTransformerMetadata); break; } if (sourceMetadata == null) { throw new ArgumentException("Not able to find metadata for source basic block of the entry branch."); } // only process entry branches with only one link to the obfuscation graph if (sourceMetadata.correspondingGraphNodes.Count() != 1) { continue; } // check if the source basic block is a basic block that moves the pointer to the obfuscation graph // => use the link from the current basic block to the obfuscation graph BasicBlockGraphNodeLink link = null; if ((sourceMetadata as GraphTransformerNextNodeBasicBlock) != null) { // get the metadata for the current basic block (because the source basic block has moved the pointer to the obfuscation graph) IGraphTransformerMetadata currentMetadata = null; for (int i = 0; i < currentBasicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((currentBasicBlock.transformationMetadata.ElementAt(i) as IGraphTransformerMetadata) == null) { continue; } currentMetadata = (currentBasicBlock.transformationMetadata.ElementAt(i) as IGraphTransformerMetadata); break; } if (currentMetadata == null) { throw new ArgumentException("Not able to find metadata for source basic block of the entry branch."); } // when current basic block also moves the pointer to the obfuscation graph => skip opaque predicate insertion it (for the moment) // (problem with obfuscation graph nodes that do not reside on the vpath because of pointer correction code) if ((currentMetadata as GraphTransformerNextNodeBasicBlock) != null) { continue; } // get the link to the correct obfuscation graph node for the valid path that goes through the source basic block BasicBlockGraphNodeLink sourceLink = sourceMetadata.correspondingGraphNodes.ElementAt(0); foreach (BasicBlockGraphNodeLink tempLink in currentMetadata.correspondingGraphNodes) { if (tempLink.validPathId == sourceLink.validPathId) { link = tempLink; } } if (link == null) { throw new ArgumentException("Not able to find link from current basic block to the obfuscation graph."); } } // => just use the link from the source basic block to the obfuscation graph else { link = sourceMetadata.correspondingGraphNodes.ElementAt(0); } // decide randomly to add an opaque predicate switch (this.prng.Next(this.insertOpaquePredicateWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // choose randomly which opaque predicate should be added int opaquePredicate = this.prng.Next(2); this.injectOpaquePredicateCode(cfgManipulator, methodCfg, currentBasicBlock, entryBranch, link, opaquePredicate, currentNodeLocal); break; } default: { break; } } } // remove currently processed basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); } System.Console.WriteLine("Basic Blocks to process (Opaque Predicates): " + basicBlocksToProcess.Count()); // check if basic blocks exist to process => if not break loop if (basicBlocksToProcess.Count() == 0) { break; } } }
private void processExitBranchesIter(CfgManipulator cfgManipulator, GraphRandomStateGenerator randomStateGenerator, MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock startBasicBlock, LocalDefinition intStateLocal, LocalDefinition currentNodeLocal) { int currentValidPathId; // create a list of basic blocks that still have to be processed by the algorithm List<BasicBlock> basicBlocksToProcess = new List<BasicBlock>(methodCfg.basicBlocks); System.Console.WriteLine("Basic Blocks to process (Control Flow): " + basicBlocksToProcess.Count()); while (true) { List<BasicBlock> copiedList = new List<BasicBlock>(basicBlocksToProcess); foreach (BasicBlock currentBasicBlock in copiedList) { // get the metadata for the current basic block GraphTransformerMetadataBasicBlock metadata = null; for (int i = 0; i < currentBasicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((currentBasicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } metadata = (currentBasicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (metadata == null) { throw new ArgumentException("Not able to find metadata for current basic block."); } // remove currently processed basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); // check if the current exit branch is of type "no branch target" if (currentBasicBlock.exitBranch as NoBranchTarget != null) { NoBranchTarget introBranch = (NoBranchTarget)currentBasicBlock.exitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) int searchSementicId = introBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); if (searchSementicId != -1) { foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } } else { possibleTargetBasicBlocks.Add(introBranch.takenTarget); } // create a list of target basic blocks of this branch List<Target> listOfTargets = new List<Target>(); Target target = new Target(); target.basicBlock = introBranch.takenTarget; listOfTargets.Add(target); // generate code for the "state switch" BasicBlock stateBasicBlock = null; SwitchBranchTarget stateExitBranch = null; this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes); cfgManipulator.insertBasicBlockBetweenBranch(introBranch, stateBasicBlock, stateExitBranch, 0); // create for each valid path a branch in the switch statement of the "state switch" for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the current valid path id) if (currentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateExitBranch.takenTarget.Count() <= currentValidPathId) { stateExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); // set switch taken branch for current valid path id to the chosen branch target stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = currentValidPathId; // get the link from the current basic block to the obfuscation graph BasicBlockGraphNodeLink currentGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { currentGraphLink = tempLink; break; } } if (currentGraphLink == null) { throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id."); } // get the metadata for the target basic block GraphTransformerMetadataBasicBlock targetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (targetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the target basic block to the obfuscation graph BasicBlockGraphNodeLink targetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { targetGraphLink = tempLink; break; } } if (targetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // choose randomly to either just correct the pointer position or to inject a "state change" switch (this.prng.Next(this.stateChangeWeight)) { // case: "state change" case 0: case 1: case 2: case 3: case 4: case 5: { // generate code for the "state change" BasicBlock stateChangeBasicBlock = null; SwitchBranchTarget stateChangeExitBranch = null; this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal); cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0); // create for each valid path a branch in the switch statement of the "state change" for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the changed current valid path id) if (changedCurrentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) { stateChangeExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); // set switch taken branch for current valid path id to the chosen branch target stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateChangeExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = changedCurrentValidPathId; // get the metadata for the change target basic block GraphTransformerMetadataBasicBlock changeTargetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (changeTargetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the change target basic block to the obfuscation graph BasicBlockGraphNodeLink changeTargetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == changedCurrentValidPathId) { changeTargetGraphLink = tempLink; break; } } if (changeTargetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // correct the pointer position to the obfuscation graph this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } } break; } // case: correct pointer position default: { this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } break; } } } } // check if the current exit branch is of type "unconditional branch target" else if (currentBasicBlock.exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget introBranch = (UnconditionalBranchTarget)currentBasicBlock.exitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) int searchSementicId = introBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); if (searchSementicId != -1) { foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } } else { possibleTargetBasicBlocks.Add(introBranch.takenTarget); } // create a list of target basic blocks of this branch List<Target> listOfTargets = new List<Target>(); Target target = new Target(); target.basicBlock = introBranch.takenTarget; listOfTargets.Add(target); // generate code for the "state switch" BasicBlock stateBasicBlock = null; SwitchBranchTarget stateExitBranch = null; this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes); cfgManipulator.insertBasicBlockBetweenBranch(introBranch, stateBasicBlock, stateExitBranch, 0); // create for each valid path a branch in the switch statement of the "state switch" for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the current valid path id) if (currentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateExitBranch.takenTarget.Count() <= currentValidPathId) { stateExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); //set switch taken branch for current valid path id to the chosen branch target stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = currentValidPathId; // get the link from the current basic block to the obfuscation graph BasicBlockGraphNodeLink currentGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { currentGraphLink = tempLink; break; } } if (currentGraphLink == null) { throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id."); } // get the metadata for the target basic block GraphTransformerMetadataBasicBlock targetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (targetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the target basic block to the obfuscation graph BasicBlockGraphNodeLink targetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { targetGraphLink = tempLink; break; } } if (targetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // choose randomly to either just correct the pointer position or to inject a "state change" switch (this.prng.Next(this.stateChangeWeight)) { // case: "state change" case 0: case 1: case 2: case 3: case 4: case 5: { // generate code for the "state change" BasicBlock stateChangeBasicBlock = null; SwitchBranchTarget stateChangeExitBranch = null; this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal); cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0); // create for each valid path a branch in the switch statement of the "state change" for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the changed current valid path id) if (changedCurrentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) { stateChangeExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); // set switch taken branch for current valid path id to the chosen branch target stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateChangeExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = changedCurrentValidPathId; // get the metadata for the change target basic block GraphTransformerMetadataBasicBlock changeTargetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (changeTargetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the change target basic block to the obfuscation graph BasicBlockGraphNodeLink changeTargetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == changedCurrentValidPathId) { changeTargetGraphLink = tempLink; break; } } if (changeTargetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // correct the pointer position to the obfuscation graph this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } } break; } // case: correct pointer position default: { this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } break; } } } } // check if the current exit branch is of type "conditional branch target" else if (currentBasicBlock.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget introBranch = (ConditionalBranchTarget)currentBasicBlock.exitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) int searchSementicId = introBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); if (searchSementicId != -1) { foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } } else { possibleTargetBasicBlocks.Add(introBranch.takenTarget); } // create a list of target basic blocks of this branch List<Target> listOfTargets = new List<Target>(); Target target = new Target(); target.basicBlock = introBranch.takenTarget; listOfTargets.Add(target); // generate code for the "state switch" BasicBlock stateBasicBlock = null; SwitchBranchTarget stateExitBranch = null; this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes); cfgManipulator.insertBasicBlockBetweenBranch(introBranch, true, stateBasicBlock, stateExitBranch, 0); // create for each valid path a branch in the switch statement of the "state switch" for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the current valid path id) if (currentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateExitBranch.takenTarget.Count() <= currentValidPathId) { stateExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); //set switch taken branch for current valid path id to the chosen branch target stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = currentValidPathId; // get the link from the current basic block to the obfuscation graph BasicBlockGraphNodeLink currentGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { currentGraphLink = tempLink; break; } } if (currentGraphLink == null) { throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id."); } // get the metadata for the target basic block GraphTransformerMetadataBasicBlock targetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (targetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the target basic block to the obfuscation graph BasicBlockGraphNodeLink targetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { targetGraphLink = tempLink; break; } } if (targetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // choose randomly to either just correct the pointer position or to inject a "state change" switch (this.prng.Next(this.stateChangeWeight)) { // case: "state change" case 0: case 1: case 2: case 3: case 4: case 5: { // generate code for the "state change" BasicBlock stateChangeBasicBlock = null; SwitchBranchTarget stateChangeExitBranch = null; this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal); cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0); // create for each valid path a branch in the switch statement of the "state change" for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the changed current valid path id) if (changedCurrentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) { stateChangeExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); // set switch taken branch for current valid path id to the chosen branch target stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateChangeExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = changedCurrentValidPathId; // get the metadata for the change target basic block GraphTransformerMetadataBasicBlock changeTargetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (changeTargetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the change target basic block to the obfuscation graph BasicBlockGraphNodeLink changeTargetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == changedCurrentValidPathId) { changeTargetGraphLink = tempLink; break; } } if (changeTargetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // correct the pointer position to the obfuscation graph this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } } break; } // case: correct pointer position default: { this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } break; } } } // search for all semantically equal basic blocks in the modified method CFG (as possible targets) searchSementicId = introBranch.notTakenTarget.semanticId; possibleTargetBasicBlocks = new List<BasicBlock>(); if (searchSementicId != -1) { foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } } else { possibleTargetBasicBlocks.Add(introBranch.notTakenTarget); } // create a list of target basic blocks of this branch listOfTargets = new List<Target>(); target = new Target(); target.basicBlock = introBranch.notTakenTarget; listOfTargets.Add(target); // generate code for the "state switch" stateBasicBlock = null; stateExitBranch = null; this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes); cfgManipulator.insertBasicBlockBetweenBranch(introBranch, false, stateBasicBlock, stateExitBranch, 0); // create for each valid path a branch in the switch statement of the "state switch" for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the current valid path id) if (currentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateExitBranch.takenTarget.Count() <= currentValidPathId) { stateExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); //set switch taken branch for current valid path id to the chosen branch target stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = currentValidPathId; // get the link from the current basic block to the obfuscation graph BasicBlockGraphNodeLink currentGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { currentGraphLink = tempLink; break; } } if (currentGraphLink == null) { throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id."); } // get the metadata for the target basic block GraphTransformerMetadataBasicBlock targetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (targetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the target basic block to the obfuscation graph BasicBlockGraphNodeLink targetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { targetGraphLink = tempLink; break; } } if (targetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // choose randomly to either just correct the pointer position or to inject a "state change" switch (this.prng.Next(this.stateChangeWeight)) { // case: "state change" case 0: case 1: case 2: case 3: case 4: case 5: { // generate code for the "state change" BasicBlock stateChangeBasicBlock = null; SwitchBranchTarget stateChangeExitBranch = null; this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal); cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0); // create for each valid path a branch in the switch statement of the "state change" for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the changed current valid path id) if (changedCurrentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) { stateChangeExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); // set switch taken branch for current valid path id to the chosen branch target stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateChangeExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = changedCurrentValidPathId; // get the metadata for the change target basic block GraphTransformerMetadataBasicBlock changeTargetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (changeTargetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the change target basic block to the obfuscation graph BasicBlockGraphNodeLink changeTargetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == changedCurrentValidPathId) { changeTargetGraphLink = tempLink; break; } } if (changeTargetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // correct the pointer position to the obfuscation graph this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } } break; } // case: correct pointer position default: { this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } break; } } } } // check if the current exit branch is of type "try block target" else if (currentBasicBlock.exitBranch as TryBlockTarget != null) { throw new ArgumentException("Not yet implemented."); } // check if the current exit branch is of type "switch branch target" else if (currentBasicBlock.exitBranch as SwitchBranchTarget != null) { throw new ArgumentException("Not yet implemented."); } // check if the current exit branch is of type "exception branch target" else if (currentBasicBlock.exitBranch as ExceptionBranchTarget != null) { throw new ArgumentException("Not yet implemented."); } // check if the current exit branch is of type "exit branch target" else if (currentBasicBlock.exitBranch as ExitBranchTarget != null) { continue; } // check if the current exit branch is of type "throw branch target" else if (currentBasicBlock.exitBranch as ThrowBranchTarget != null) { continue; } // this case should never be reached else { throw new ArgumentException("Do not know how to handle branch."); } } System.Console.WriteLine("Basic Blocks to process (Control Flow): " + basicBlocksToProcess.Count()); // check if basic blocks exist to process => if not break loop if (basicBlocksToProcess.Count() == 0) { break; } // adjust probability to duplicate basic blocks (each processing round the probability drops to duplicate a basic block) this.duplicateBasicBlockWeight += this.duplicateBasicBlockCorrectionValue; // adjust probability to insert a state change (each processing round the probability drops to insert a state change) this.stateChangeWeight += this.stateChangeCorrectionValue; } }
private void addMetadataIter(CfgManipulator cfgManipulator, GraphRandomStateGenerator randomStateGenerator, MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock startBasicBlock, LocalDefinition intStateLocal, LocalDefinition currentNodeLocal) { int currentValidPathId; // create transformation metadata for the start basic block GraphTransformerMetadataBasicBlock metadata = new GraphTransformerMetadataBasicBlock(); for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { BasicBlockGraphNodeLink link = new BasicBlockGraphNodeLink(this.graph.startingNode, currentValidPathId); metadata.correspondingGraphNodes.Add(link); } startBasicBlock.transformationMetadata.Add(metadata); // create a list of basic blocks that still have to be processed by the algorithm List<BasicBlock> basicBlocksToProcess = new List<BasicBlock>(methodCfg.basicBlocks); basicBlocksToProcess.Remove(startBasicBlock); System.Console.WriteLine("Basic Blocks to process (Metadata): " + basicBlocksToProcess.Count()); // add metadata to all basic blocks while (true) { List<BasicBlock> copiedList = new List<BasicBlock>(basicBlocksToProcess); foreach (BasicBlock currentBasicBlock in copiedList) { // check if the current basic block was already visited => it is already used for the graph obfuscation => skip it bool hasGraphMetadata = false; for (int i = 0; i < currentBasicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((currentBasicBlock.transformationMetadata.ElementAt(i) as IGraphTransformerMetadata) == null) { continue; } hasGraphMetadata = true; break; } if (hasGraphMetadata) { basicBlocksToProcess.Remove(currentBasicBlock); continue; } if (!this.createAndAddMetadata(currentBasicBlock)) { continue; } // remove current basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); } System.Console.WriteLine("Basic Blocks to process (Metadata): " + basicBlocksToProcess.Count()); // check if basic blocks exist to process => if not break loop if (basicBlocksToProcess.Count() == 0) { break; } } }
// build recursively the cfg of the given operations private void buildRecursivelyCfg(MethodCfg methodCfg, IEnumerable<IOperation> operations, int currentIdx, IBranchTarget entryBranch, ref BasicBlock currentBasicBlock) { // check if a new basic block has to be created for (int bbIdx = 0; bbIdx < methodCfg.basicBlocks.Count(); bbIdx++) { // check if the current index points into an existing basic block // => split basic block BasicBlock tempBB = methodCfg.basicBlocks.ElementAt(bbIdx); if (tempBB.startIdx < currentIdx && tempBB.endIdx >= currentIdx) { // create new basic block which will be the second half of the found one BasicBlock newBasicBlock = new BasicBlock(this.semanticId); this.semanticId++; newBasicBlock.startIdx = currentIdx; newBasicBlock.endIdx = tempBB.endIdx; tempBB.endIdx = currentIdx - 1; // move the exit basic blocks to the new created basic block // and make the new created basic block the exit of the splitted one newBasicBlock.exitBranch = tempBB.exitBranch; newBasicBlock.exitBranch.sourceBasicBlock = newBasicBlock; NoBranchTarget tempExitBranch = new NoBranchTarget(); tempExitBranch.takenTarget = newBasicBlock; tempExitBranch.sourceBasicBlock = tempBB; tempBB.exitBranch = tempExitBranch; // set the current basic block to the new created basic block currentBasicBlock = newBasicBlock; // add splitted basic block branch and basic block branch that leads to this split // to the entries of the new one newBasicBlock.entryBranches.Add(entryBranch); newBasicBlock.entryBranches.Add(tempExitBranch); // distribute the instructions to the basic blocks List<IOperation> previousOperations = new List<IOperation>(); List<IOperation> nextOperations = new List<IOperation>(); for (int operationIdx = 0; (operationIdx + tempBB.startIdx) <= newBasicBlock.endIdx; operationIdx++) { if ((operationIdx + tempBB.startIdx) < currentIdx) { previousOperations.Add(tempBB.operations.ElementAt(operationIdx)); } else { nextOperations.Add(tempBB.operations.ElementAt(operationIdx)); } } tempBB.operations = previousOperations; newBasicBlock.operations = nextOperations; // add new basic block to the cfg methodCfg.basicBlocks.Add(newBasicBlock); return; } // if the current index of the operation points to the start index of an existing basic block // => update entry branches else if (tempBB.startIdx == currentIdx && entryBranch != null && currentBasicBlock != null) { tempBB.entryBranches.Add(entryBranch); // set the found basic block as the current basic block currentBasicBlock = tempBB; return; } // if the current index of the operation points to the start index of an existing basic block, has no entry branch // and is not the first instruction // set the current basic block to the found one else if (currentIdx != 0 && tempBB.startIdx == currentIdx && currentBasicBlock != null) { // set the found basic block as the current basic block currentBasicBlock = tempBB; return; } } // set index of current basic block and add it to the cfg currentBasicBlock.startIdx = currentIdx; methodCfg.basicBlocks.Add(currentBasicBlock); // check if the basic block was jumped to from another basic block // => update entry branches if (entryBranch != null) { currentBasicBlock.entryBranches.Add(entryBranch); } // parse every instruction to find branches etc for (int idx = currentIdx; idx < operations.Count(); idx++) { // check if the current instruction is the start instruction of an already existing basic block (except the current basic block) // => add the current basic block to the list of entry basic blocks, the found basic block to the list of exit basic blocks and set the index for (int bbIdx = 0; bbIdx < methodCfg.basicBlocks.Count(); bbIdx++) { BasicBlock tempBB = methodCfg.basicBlocks.ElementAt(bbIdx); if (tempBB.startIdx == idx && tempBB != currentBasicBlock) { currentBasicBlock.endIdx = idx - 1; // create new exit branch and add it NoBranchTarget currentExitBranch = new NoBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.takenTarget = tempBB; currentBasicBlock.exitBranch = currentExitBranch; // add current exit branch as entry for the found one tempBB.entryBranches.Add(currentExitBranch); return; } } // add current instruction to the basic block var operation = operations.ElementAt(idx); currentBasicBlock.operations.Add(operation); // check for special instructions like branches switch (operation.OperationCode) { // conditional branch instructions case OperationCode.Beq: case OperationCode.Bge: case OperationCode.Bge_Un: case OperationCode.Bgt: case OperationCode.Bgt_Un: case OperationCode.Ble: case OperationCode.Ble_Un: case OperationCode.Blt: case OperationCode.Blt_Un: case OperationCode.Bne_Un: case OperationCode.Brfalse: case OperationCode.Brtrue: case OperationCode.Beq_S: case OperationCode.Bge_S: case OperationCode.Bge_Un_S: case OperationCode.Bgt_S: case OperationCode.Bgt_Un_S: case OperationCode.Ble_S: case OperationCode.Ble_Un_S: case OperationCode.Blt_S: case OperationCode.Blt_Un_S: case OperationCode.Bne_Un_S: case OperationCode.Brfalse_S: case OperationCode.Brtrue_S: { // the current basic block ends here currentBasicBlock.endIdx = idx; // calculate the target index of the branch int branchTargetIdx = 0; uint branchTargetOffset; // do operation value can be of type long which can not be casted in this way if (operation.Value is long) { branchTargetOffset = Convert.ToUInt32(operation.Value); } else { branchTargetOffset = (uint)operation.Value; } while (true) { if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) { break; } else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) { throw new ArgumentException("Could not find target off branch."); } branchTargetIdx++; } // create new exit branch object ConditionalBranchTarget currentExitBranch = new ConditionalBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.notTakenTarget = new BasicBlock(this.semanticId); this.semanticId++; currentExitBranch.takenTarget = new BasicBlock(this.semanticId); this.semanticId++; currentBasicBlock.exitBranch = currentExitBranch; // start two new basic blocks from this branch on and end current execution this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.notTakenTarget); this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.takenTarget); return; } // unconditional branch instructions case OperationCode.Br: case OperationCode.Br_S: { // the current basic block ends here currentBasicBlock.endIdx = idx; // calculate the target index of the branch int branchTargetIdx = 0; uint branchTargetOffset = (uint)operation.Value; while (true) { if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) { break; } else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) { throw new ArgumentException("Could not find target off branch."); } branchTargetIdx++; } // create new exit branch object UnconditionalBranchTarget currentExitBranch = new UnconditionalBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.takenTarget = new BasicBlock(this.semanticId); this.semanticId++; currentBasicBlock.exitBranch = currentExitBranch; // start one new basic block from this branch on and end current execution this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.takenTarget); return; } // exit operation case OperationCode.Ret: { // the current basic block ends here currentBasicBlock.endIdx = idx; // create new exit branch object ExitBranchTarget currentExitBranch = new ExitBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentBasicBlock.exitBranch = currentExitBranch; // end current execution return; } // operations that exit the current function/control flow case OperationCode.Throw: { // the current basic block ends here currentBasicBlock.endIdx = idx; // create new exit branch object ThrowBranchTarget currentExitBranch = new ThrowBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentBasicBlock.exitBranch = currentExitBranch; // start a new basic block if this was not the last instruction of the method // (needed because some control flows that are reached via throw are not found without it) if ((idx + 1) < operations.Count()) { BasicBlock newStartBasicBlock = new BasicBlock(this.semanticId); this.semanticId++; this.buildRecursivelyCfg(methodCfg, operations, idx + 1, null, ref newStartBasicBlock); } // end current execution return; } // switch instruction (has a variable set of jump targets) case OperationCode.Switch: { // the current basic block ends here currentBasicBlock.endIdx = idx; // create new exit branch object SwitchBranchTarget currentExitBranch = new SwitchBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.notTakenTarget = new BasicBlock(this.semanticId); this.semanticId++; currentBasicBlock.exitBranch = currentExitBranch; // calculate the target index of all switch branches int counter = 0; foreach (uint branchTargetOffset in (uint[])operation.Value) { int branchTargetIdx = 0; while (true) { if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) { break; } else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) { throw new ArgumentException("Could not find target off branch."); } branchTargetIdx++; } // start a new basic block from this branch on BasicBlock tempNextBasicBlock = new BasicBlock(this.semanticId); this.semanticId++; this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref tempNextBasicBlock); // add new basic block to branch targets currentExitBranch.takenTarget.Add(tempNextBasicBlock); counter++; } // start a new basic block directly after the switch instruction and end current execution this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.notTakenTarget); return; } // exception handler beginning or end (end of try block or catch block) case OperationCode.Leave: case OperationCode.Leave_S: { // the current basic block ends here currentBasicBlock.endIdx = idx; // calculate the target index of the branch int branchTargetIdx = 0; uint branchTargetOffset = (uint)operation.Value; while (true) { if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) { break; } else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) { throw new ArgumentException("Could not find target off branch."); } branchTargetIdx++; } // create new exit branch object ExceptionBranchTarget currentExitBranch = new ExceptionBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.exceptionTarget = new BasicBlock(this.semanticId); this.semanticId++; currentExitBranch.exitTarget = new BasicBlock(this.semanticId); this.semanticId++; currentBasicBlock.exitBranch = currentExitBranch; // start two new basic blocks from this branch on and end current execution this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.exceptionTarget); this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.exitTarget); return; } // create a virtual basic block at the end of a catch/finally handler case OperationCode.Rethrow: case OperationCode.Endfinally: { // the current basic block ends here currentBasicBlock.endIdx = idx; // create new exit branch object NoBranchTarget currentExitBranch = new NoBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.takenTarget = new BasicBlock(this.semanticId); this.semanticId++; currentBasicBlock.exitBranch = currentExitBranch; // start a new basic block from this branch on and end current execution this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.takenTarget); return; } default: break; } } }
void createUnconditionalBranch(BasicBlock deadCodeBasicBlock, ITransformationMetadata basicBlockMetadata) { // Branch to some other basic block in our method (or to a newly created dead code block). var exitBranch = new UnconditionalBranchTarget(); exitBranch.sourceBasicBlock = deadCodeBasicBlock; deadCodeBasicBlock.exitBranch = exitBranch; deadCodeBasicBlock.operations.Add(createNewOperation(OperationCode.Br, 0)); // TODO: Decrease possibility for dead code to be added? if(prng.Next(2) == 0) { // Random BB as dead code block target. var targetBlock = randomTargetBlock(); targetBlock.entryBranches.Add(exitBranch); exitBranch.takenTarget = targetBlock; } else { // New dead code BB as dead code block target. var targetBlock = new BasicBlock(); targetBlock.startIdx = targetBlock.endIdx = 0; targetBlock.entryBranches.Add(exitBranch); exitBranch.takenTarget = targetBlock; generateDeadCode(targetBlock, basicBlockMetadata); } }
// builds a CFG for the given method and returns it public MethodCfg buildCfgForMethod(MethodDefinition method) { MethodCfg methodCfg = new MethodCfg(); methodCfg.method = method; // start building the cfg BasicBlock firstBasicBlock = new BasicBlock(this.semanticId); this.semanticId++; methodCfg.startBasicBlock = firstBasicBlock; this.buildRecursivelyCfg(methodCfg, method.Body.Operations, 0, null, ref firstBasicBlock); // add exception handler to the cfg foreach (IOperationExceptionInformation exceptionHandler in method.Body.OperationExceptionInformation) { // debugging variables to throw an exception if start/end of try/handler block was not found bool tryStartFound = false; bool tryEndFound = false; bool handlerStartFound = false; bool handlerEndFound = false; // search each basic block if they reside in an exception handler List<BasicBlock> localCopy = new List<BasicBlock>(); localCopy.AddRange(methodCfg.basicBlocks); for (int bbIdx = 0; bbIdx < localCopy.Count(); bbIdx++) { BasicBlock basicBlock = localCopy.ElementAt(bbIdx); int lastOperationIdx = basicBlock.operations.Count() - 1; // ignore basic block if the start of the try block lies behind the current basic block // (catch or finally blocks can never lie before a try block) if (basicBlock.operations.ElementAt(lastOperationIdx).Offset < exceptionHandler.TryStartOffset) { continue; } // check if the current basic block resides in the try block of the exception handler else if ((exceptionHandler.TryStartOffset >= basicBlock.operations.ElementAt(0).Offset && exceptionHandler.TryStartOffset <= basicBlock.operations.ElementAt(lastOperationIdx).Offset) || (exceptionHandler.TryStartOffset <= basicBlock.operations.ElementAt(0).Offset && basicBlock.operations.ElementAt(lastOperationIdx).Offset < exceptionHandler.TryEndOffset)) { TryBlock tempTryBlock = new TryBlock(); tempTryBlock.exceptionHandler = exceptionHandler; // check if the try block starts inside this basic block if (exceptionHandler.TryStartOffset >= basicBlock.operations.ElementAt(0).Offset) { // find the index of the operation that starts the try block bool foundIdx = false; for (int idx = 0; idx < basicBlock.operations.Count(); idx++) { if (basicBlock.operations.ElementAt(idx).Offset == exceptionHandler.TryStartOffset) { // if the try block does not start at the beginning of the current basic block // => split basic block and let the try block begin at the second half of the basic block if (idx != 0) { // create new basic block which will be the second half of the found one BasicBlock newBasicBlock = new BasicBlock(this.semanticId); this.semanticId++; newBasicBlock.startIdx = basicBlock.startIdx + idx; newBasicBlock.endIdx = basicBlock.endIdx; basicBlock.endIdx = basicBlock.startIdx + idx - 1; // move the exit basic blocks to the new created basic block // and make the new created basic block the exit of the splitted one newBasicBlock.exitBranch = basicBlock.exitBranch; newBasicBlock.exitBranch.sourceBasicBlock = newBasicBlock; TryBlockTarget tempExitBranch = new TryBlockTarget(); tempExitBranch.takenTarget = newBasicBlock; tempExitBranch.sourceBasicBlock = basicBlock; basicBlock.exitBranch = tempExitBranch; // add splitted basic block branch to the entry of the new one newBasicBlock.entryBranches.Add(tempExitBranch); // distribute the instructions to the basic blocks List<IOperation> previousOperations = new List<IOperation>(); List<IOperation> nextOperations = new List<IOperation>(); for (int operationIdx = 0; (operationIdx + basicBlock.startIdx) <= newBasicBlock.endIdx; operationIdx++) { if ((operationIdx + basicBlock.startIdx) < newBasicBlock.startIdx) { previousOperations.Add(basicBlock.operations.ElementAt(operationIdx)); } else { nextOperations.Add(basicBlock.operations.ElementAt(operationIdx)); } } basicBlock.operations = previousOperations; newBasicBlock.operations = nextOperations; // add new basic block to the cfg methodCfg.basicBlocks.Add(newBasicBlock); // add try block to the new created basic block (it is the start of the try block) newBasicBlock.tryBlocks.Add(tempTryBlock); // try block can not end at the first part of the splitted basic block // (because it starts at the second one), but it can end at the // second part of the splitted basic block basicBlock = newBasicBlock; lastOperationIdx = newBasicBlock.operations.Count() - 1; } // the try block starts at the beginning of the current basic block => add the try block else { basicBlock.tryBlocks.Add(tempTryBlock); } // mark try block as the beginning of the try block tempTryBlock.firstBasicBlockOfTryBlock = true; foundIdx = true; tryStartFound = true; break; } } if (!foundIdx) { throw new ArgumentException("Did not find index of operation that starts Try block."); } } else { basicBlock.tryBlocks.Add(tempTryBlock); tempTryBlock.firstBasicBlockOfTryBlock = false; } // check if the try block ends at the end of this basic block (try blocks always end at the end of a basic block) if (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)) == exceptionHandler.TryEndOffset) { tempTryBlock.lastBasicBlockOfTryBlock = true; tryEndFound = true; } else { tempTryBlock.lastBasicBlockOfTryBlock = false; } continue; } // check if the current basic block resides in the handler block of the exception handler else if ((exceptionHandler.HandlerStartOffset >= basicBlock.operations.ElementAt(0).Offset && exceptionHandler.HandlerStartOffset <= basicBlock.operations.ElementAt(lastOperationIdx).Offset) || (exceptionHandler.HandlerStartOffset <= basicBlock.operations.ElementAt(0).Offset && basicBlock.operations.ElementAt(lastOperationIdx).Offset < exceptionHandler.HandlerEndOffset)) { // check if the handler block is a catch block if (exceptionHandler.HandlerKind == HandlerKind.Catch) { HandlerBlock tempCatchBock = new HandlerBlock(); tempCatchBock.typeOfHandler = HandlerKind.Catch; tempCatchBock.exceptionHandler = exceptionHandler; basicBlock.handlerBlocks.Add(tempCatchBock); // check if the catch block starts inside this basic block if (exceptionHandler.HandlerStartOffset >= basicBlock.operations.ElementAt(0).Offset) { // find the index of the operation that starts the catch block bool foundIdx = false; for (int idx = 0; idx < basicBlock.operations.Count(); idx++) { if (basicBlock.operations.ElementAt(idx).Offset == exceptionHandler.HandlerStartOffset) { tempCatchBock.firstBasicBlockOfHandlerBlock = true; foundIdx = true; handlerStartFound = true; break; } } if (!foundIdx) { throw new ArgumentException("Did not find index of operation that starts Catch block."); } } else { tempCatchBock.firstBasicBlockOfHandlerBlock = false; } // check if the catch block ends inside this basic block if (basicBlock.operations[0].Offset < exceptionHandler.HandlerEndOffset && exceptionHandler.HandlerEndOffset <= (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)))) { // check if the catch block ends at the last instruction of this basic block (this happens usually => optimization) if (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)) == exceptionHandler.HandlerEndOffset) { tempCatchBock.lastBasicBlockOfHandlerBlock = true; handlerEndFound = true; continue; } else { throw new ArgumentException("Did not find the operation that ends Catch block."); } } else { tempCatchBock.lastBasicBlockOfHandlerBlock = false; } continue; } // check if the handler block is a finally block else if (exceptionHandler.HandlerKind == HandlerKind.Finally) { HandlerBlock tempFinallyBock = new HandlerBlock(); tempFinallyBock.typeOfHandler = HandlerKind.Finally; tempFinallyBock.exceptionHandler = exceptionHandler; basicBlock.handlerBlocks.Add(tempFinallyBock); // check if the finally block starts inside this basic block if (exceptionHandler.HandlerStartOffset >= basicBlock.operations.ElementAt(0).Offset) { // find the index of the operation that starts the finally block bool foundIdx = false; for (int idx = 0; idx < basicBlock.operations.Count(); idx++) { if (basicBlock.operations.ElementAt(idx).Offset == exceptionHandler.HandlerStartOffset) { tempFinallyBock.firstBasicBlockOfHandlerBlock = true; foundIdx = true; handlerStartFound = true; break; } } if (!foundIdx) { throw new ArgumentException("Did not find index of operation that starts Finally block."); } } else { tempFinallyBock.firstBasicBlockOfHandlerBlock = false; } // check if the finally block ends inside this basic block if (basicBlock.operations[0].Offset < exceptionHandler.HandlerEndOffset && exceptionHandler.HandlerEndOffset <= (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)))) { // check if the finally block ends at the last instruction of this basic block if (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)) == exceptionHandler.HandlerEndOffset) { tempFinallyBock.lastBasicBlockOfHandlerBlock = true; handlerEndFound = true; continue; } else { throw new ArgumentException("Did not find the operation that ends Finally block."); } } continue; } else { throw new ArgumentException("Do not know how to handle exception handler."); } } } // check if start/end of try/handler block was found if(!tryStartFound || !tryEndFound || !handlerStartFound || !handlerEndFound) { throw new ArgumentException("Was not able to find start/end of try/handler block."); } } // TODO // DEBUG //this.logger.dumpMethodCfg(methodCfg, this.logger.sanitizeString(methodCfg.method.ToString())); return methodCfg; }
void createExitBranch(BasicBlock deadCodeBasicBlock) { // Exit the function at this dead code block while also returning a sane local as return value. var exitBranch = new ExitBranchTarget(); exitBranch.sourceBasicBlock = deadCodeBasicBlock; deadCodeBasicBlock.exitBranch = exitBranch; if(methodCfg.method.Type.ToString() != "System.Void") { var locals = getSuitableLocals(methodCfg.method.Type.ToString()); if(locals.Count() == 0) { // TODO: Actually support the return here (e.g., by adding proper locals). throw new ArgumentException("Cannot yet handle creation of exit branches for non-void methods without" + " suitable locals."); } int index = prng.Next(locals.Count()); var local = methodCfg.method.Body.LocalVariables.ElementAt(index); deadCodeBasicBlock.operations.Add(createNewOperation(OperationCode.Ldloc, local)); } deadCodeBasicBlock.operations.Add(createNewOperation(OperationCode.Ret)); }
// this function replaces a basic block inside the cfg (oldBasicBlock) with a construction of new basic blocks (newBasicBlockStart and newBasicBlockEnd) public void replaceBasicBlock(BasicBlock oldBasicBlock, BasicBlock newBasicBlockStart, BasicBlock newBasicBlockEnd) { // add new basic blocks to cfg this.addBasicBlockToCfgRecursively(newBasicBlockStart); // add entry branches that enter the old basic block to the new basic block newBasicBlockStart.entryBranches.AddRange(oldBasicBlock.entryBranches); // exchange the target of the entry branches from the old basic block to the new one foreach (IBranchTarget entryBranch in new List<IBranchTarget>(oldBasicBlock.entryBranches)) { if ((entryBranch as NoBranchTarget) != null) { NoBranchTarget tempEntryBranch = (entryBranch as NoBranchTarget); // check sanity of entry branch if (tempEntryBranch.takenTarget != oldBasicBlock) { throw new ArgumentException("Entry branch must have old basic block as target."); } // set new basic block as target tempEntryBranch.takenTarget = newBasicBlockStart; } else if ((entryBranch as UnconditionalBranchTarget) != null) { UnconditionalBranchTarget tempEntryBranch = (entryBranch as UnconditionalBranchTarget); // check sanity of entry branch if (tempEntryBranch.takenTarget != oldBasicBlock) { throw new ArgumentException("Entry branch must have old basic block as target."); } // set new basic block as target tempEntryBranch.takenTarget = newBasicBlockStart; } else if ((entryBranch as ConditionalBranchTarget) != null) { ConditionalBranchTarget tempEntryBranch = (entryBranch as ConditionalBranchTarget); bool sanity = false; // change all branches to the old basic block to the new basic block if (tempEntryBranch.takenTarget == oldBasicBlock) { tempEntryBranch.takenTarget = newBasicBlockStart; sanity = true; } if (tempEntryBranch.notTakenTarget == oldBasicBlock) { tempEntryBranch.notTakenTarget = newBasicBlockStart; sanity = true; } // check sanity of entry branch if (!sanity) { throw new ArgumentException("Entry branch must have old basic block as target."); } } else if ((entryBranch as SwitchBranchTarget) != null) { SwitchBranchTarget tempEntryBranch = (entryBranch as SwitchBranchTarget); bool sanity = false; // change all branches to the old basic block to the new basic block if (tempEntryBranch.notTakenTarget == oldBasicBlock) { tempEntryBranch.notTakenTarget = newBasicBlockStart; sanity = true; } for (int idx = 0; idx < tempEntryBranch.takenTarget.Count(); idx++) { if (tempEntryBranch.takenTarget.ElementAt(idx) == oldBasicBlock) { tempEntryBranch.takenTarget[idx] = newBasicBlockStart; sanity = true; } } // check sanity of entry branch if (!sanity) { throw new ArgumentException("Entry branch must have old basic block as target."); } } else { throw new ArgumentException("Not yet implemented."); } // remove entry branch from the old basic block entry branches list oldBasicBlock.entryBranches.Remove(entryBranch); } IBranchTarget exitBranch = oldBasicBlock.exitBranch; // change the exit branch of the old basic block to be the exit branch of the new one exitBranch.sourceBasicBlock = newBasicBlockEnd; newBasicBlockEnd.exitBranch = exitBranch; // check if the old basic block was the start basic block of the cfg // => change it to the new basic block if (this.methodCfg.startBasicBlock == oldBasicBlock) { this.methodCfg.startBasicBlock = newBasicBlockStart; } // remove old basic block if it still belongs to the cfg if (this.methodCfg.basicBlocks.Contains(oldBasicBlock)) { this.methodCfg.basicBlocks.Remove(oldBasicBlock); } }
void createNoBranch(BasicBlock deadCodeBasicBlock) { // Set the dead code block above some other block. var exitBranch = new NoBranchTarget(); exitBranch.sourceBasicBlock = deadCodeBasicBlock; deadCodeBasicBlock.exitBranch = exitBranch; BasicBlock targetBlock = null; do { targetBlock = randomTargetBlock(); // Skip blocks that already have a "no branch" as entry. foreach(var entryBranch in targetBlock.entryBranches) { if(entryBranch is NoBranchTarget) { targetBlock = null; break; } } } while(targetBlock == null); targetBlock.entryBranches.Add(exitBranch); exitBranch.takenTarget = targetBlock; }
// insert the given new target basic block (given by start and end block) between the given unconditional branch to manipulate public void insertBasicBlockBetweenBranch(UnconditionalBranchTarget branchToManipulate, BasicBlock newTargetStart, BasicBlock newTargetEnd, UnconditionalBranchTarget exitBranch) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = branchToManipulate.takenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTargetStart, newTargetEnd, exitBranch, ref exitBranch.takenTarget); }
public void generateDeadCode(BasicBlock deadCodeBasicBlock, ITransformationMetadata basicBlockMetadata) { // Add the dead code to the basic block. var result = generateDeadCode(); foreach(var operation in result) { deadCodeBasicBlock.operations.Add(operation); } // Add metadata, if necessary (TODO: Use a set for metadata handling?) if(basicBlockMetadata != null && !deadCodeBasicBlock.transformationMetadata.Contains(basicBlockMetadata)) { deadCodeBasicBlock.transformationMetadata.Add(basicBlockMetadata); } // Choose epilogue of dead code block. int target = 1; if(!debugging) { target = prng.Next(3); if(prng.Next(1) == 0) { target = 0; } } switch(target) { case 0: createUnconditionalBranch(deadCodeBasicBlock, basicBlockMetadata); break; case 1: createExitBranch(deadCodeBasicBlock); break; case 2: createNoBranch(deadCodeBasicBlock); break; } }
// insert the given new target basic block between the given conditional branch to manipulate public void insertBasicBlockBetweenBranch(ConditionalBranchTarget branchToManipulate, bool manipulateTakenBranch, BasicBlock newTarget, SwitchBranchTarget exitBranch, int switchTakenBranchIdx) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = null; // check wether to manipulate the taken or not taken branch of the branch to manipulate if (manipulateTakenBranch) { outroBasicBlock = branchToManipulate.takenTarget; BasicBlock tempTakenTarget = null; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref tempTakenTarget); // fill switch taken branch list with null when index is out of range while (exitBranch.takenTarget.Count() <= switchTakenBranchIdx) { exitBranch.takenTarget.Add(null); } exitBranch.takenTarget[switchTakenBranchIdx] = tempTakenTarget; } else { BasicBlock tempTakenTarget = null; outroBasicBlock = branchToManipulate.notTakenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.notTakenTarget, newTarget, newTarget, exitBranch, ref tempTakenTarget); // fill switch taken branch list with null when index is out of range while (exitBranch.takenTarget.Count() <= switchTakenBranchIdx) { exitBranch.takenTarget.Add(null); } exitBranch.takenTarget[switchTakenBranchIdx] = tempTakenTarget; } }
// this constructor copies the given source method cfg and all its elements // NOTE: it ignores the transformation metadata public MethodCfg(MethodCfg sourceMethodCfg) { // copy link to the method this.method = sourceMethodCfg.method; // generate a list of already processed basic blocks List<BasicBlock> processedBasicBlocks = new List<BasicBlock>(); // set start basic block of the CFG as already processed processedBasicBlocks.Add(sourceMethodCfg.startBasicBlock); // create copy of start basic block BasicBlock copiedStartBasicBlock = new BasicBlock(); this.startBasicBlock = copiedStartBasicBlock; this.basicBlocks.Add(copiedStartBasicBlock); // copy simple values copiedStartBasicBlock.id = sourceMethodCfg.startBasicBlock.id; copiedStartBasicBlock.semanticId = sourceMethodCfg.startBasicBlock.semanticId; copiedStartBasicBlock.startIdx = sourceMethodCfg.startBasicBlock.startIdx; copiedStartBasicBlock.endIdx = sourceMethodCfg.startBasicBlock.endIdx; // copy all operations of the basic block foreach (IOperation operation in sourceMethodCfg.startBasicBlock.operations) { InternalOperation copiedOperation = new InternalOperation(); copiedOperation.OperationCode = operation.OperationCode; copiedOperation.Value = operation.Value; copiedOperation.Offset = operation.Offset; copiedOperation.Location = operation.Location; copiedStartBasicBlock.operations.Add(copiedOperation); } // process rest of the cfg and copy the exit branch if ((sourceMethodCfg.startBasicBlock.exitBranch as NoBranchTarget) != null) { NoBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as NoBranchTarget); // create a copied exit branch NoBranchTarget copiedExitBranch = new NoBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch); } else if (sourceMethodCfg.startBasicBlock.exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as UnconditionalBranchTarget); // create a copied exit branch UnconditionalBranchTarget copiedExitBranch = new UnconditionalBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch); } else if (sourceMethodCfg.startBasicBlock.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as ConditionalBranchTarget); // create a copied exit branch ConditionalBranchTarget copiedExitBranch = new ConditionalBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch, true); // process branch and next basic block nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, false); } else if (sourceMethodCfg.startBasicBlock.exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as SwitchBranchTarget); // create a copied exit branch SwitchBranchTarget copiedExitBranch = new SwitchBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // first process not taken branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, -1); // process all taken branches and next basic blocks for (int idx = 0; idx < exitBranch.takenTarget.Count(); idx++) { nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget.ElementAt(idx), ref nextCopiedBasicBlock, copiedExitBranch, idx); } } else if (sourceMethodCfg.startBasicBlock.exitBranch as ExitBranchTarget != null) { // create a copied exit branch ExitBranchTarget copiedExitBranch = new ExitBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; } else if (sourceMethodCfg.startBasicBlock.exitBranch as ThrowBranchTarget != null) { // create a copied exit branch ThrowBranchTarget copiedExitBranch = new ThrowBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; } else if (sourceMethodCfg.startBasicBlock.exitBranch as TryBlockTarget != null) { TryBlockTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as TryBlockTarget); // create a copied exit branch TryBlockTarget copiedExitBranch = new TryBlockTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch); } else if (sourceMethodCfg.startBasicBlock.exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as ExceptionBranchTarget); // create a copied exit branch ExceptionBranchTarget copiedExitBranch = new ExceptionBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exceptionTarget, ref nextCopiedBasicBlock, copiedExitBranch, true); // process branch and next basic block nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exitTarget, ref nextCopiedBasicBlock, copiedExitBranch, false); } else { throw new ArgumentException("Do not know how to handle exit branch."); } // copy all try blocks foreach (TryBlock sourceTryBlock in sourceMethodCfg.startBasicBlock.tryBlocks) { TryBlock copiedTryBlock = new TryBlock(); copiedTryBlock.exceptionHandler = sourceTryBlock.exceptionHandler; copiedTryBlock.firstBasicBlockOfTryBlock = sourceTryBlock.firstBasicBlockOfTryBlock; copiedTryBlock.lastBasicBlockOfTryBlock = sourceTryBlock.lastBasicBlockOfTryBlock; copiedStartBasicBlock.tryBlocks.Add(copiedTryBlock); } // copy all handler blocks foreach (HandlerBlock sourceHandlerBlock in sourceMethodCfg.startBasicBlock.handlerBlocks) { HandlerBlock copiedHandlerBlock = new HandlerBlock(); copiedHandlerBlock.exceptionHandler = sourceHandlerBlock.exceptionHandler; copiedHandlerBlock.typeOfHandler = sourceHandlerBlock.typeOfHandler; copiedHandlerBlock.firstBasicBlockOfHandlerBlock = sourceHandlerBlock.firstBasicBlockOfHandlerBlock; copiedHandlerBlock.lastBasicBlockOfHandlerBlock = sourceHandlerBlock.lastBasicBlockOfHandlerBlock; copiedStartBasicBlock.handlerBlocks.Add(copiedHandlerBlock); } }
// ################################################### SWITCH BRANCHES TO MANIPULATE ################################################### // insert the given new target basic block between the given switch branch to manipulate public void insertBasicBlockBetweenBranch(SwitchBranchTarget branchToManipulate, int manipulateTakenBranchIdx, BasicBlock newTarget, UnconditionalBranchTarget exitBranch) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = null; outroBasicBlock = branchToManipulate.takenTarget.ElementAt(manipulateTakenBranchIdx); BasicBlock tempTakenTarget = null; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref tempTakenTarget, newTarget, newTarget, exitBranch, ref exitBranch.takenTarget); branchToManipulate.takenTarget[manipulateTakenBranchIdx] = tempTakenTarget; }
// copies recursively the next basic block of the method CFG (with a switch branch as entry branch) private void copyMethodCfgRecursively(List<BasicBlock> processedBasicBlocks, BasicBlock sourceBasicBlock, ref BasicBlock targetBasicBlock, SwitchBranchTarget copiedEntryBranch, int takenEntryBranchIdx) { // check if source basic block was already processed if (processedBasicBlocks.Contains(sourceBasicBlock)) { bool found = false; foreach (BasicBlock searchBasicBlock in this.basicBlocks) { if (searchBasicBlock.id == sourceBasicBlock.id) { // set entry branch target if (takenEntryBranchIdx == -1) { copiedEntryBranch.notTakenTarget = searchBasicBlock; } else { // fill switch taken branch list with empty elements when index is out of range while (copiedEntryBranch.takenTarget.Count() <= takenEntryBranchIdx) { copiedEntryBranch.takenTarget.Add(null); } copiedEntryBranch.takenTarget[takenEntryBranchIdx] = searchBasicBlock; } searchBasicBlock.entryBranches.Add(copiedEntryBranch); found = true; break; } } if (!found) { throw new ArgumentException("Copied basic block was not found."); } return; } // add source basic block to the list of already processed basic blocks processedBasicBlocks.Add(sourceBasicBlock); // create copy of the source basic block targetBasicBlock = new BasicBlock(); this.basicBlocks.Add(targetBasicBlock); // set entry branch target if (takenEntryBranchIdx == -1) { copiedEntryBranch.notTakenTarget = targetBasicBlock; } else { // fill switch taken branch list with empty elements when index is out of range while (copiedEntryBranch.takenTarget.Count() <= takenEntryBranchIdx) { copiedEntryBranch.takenTarget.Add(null); } copiedEntryBranch.takenTarget[takenEntryBranchIdx] = targetBasicBlock; } targetBasicBlock.entryBranches.Add(copiedEntryBranch); // copy simple values targetBasicBlock.id = sourceBasicBlock.id; targetBasicBlock.semanticId = sourceBasicBlock.semanticId; targetBasicBlock.startIdx = sourceBasicBlock.startIdx; targetBasicBlock.endIdx = sourceBasicBlock.endIdx; // copy all operations of the basic block foreach (IOperation operation in sourceBasicBlock.operations) { InternalOperation copiedOperation = new InternalOperation(); copiedOperation.OperationCode = operation.OperationCode; copiedOperation.Value = operation.Value; copiedOperation.Offset = operation.Offset; copiedOperation.Location = operation.Location; targetBasicBlock.operations.Add(copiedOperation); } // process rest of the cfg and copy the exit branch if ((sourceBasicBlock.exitBranch as NoBranchTarget) != null) { NoBranchTarget exitBranch = (sourceBasicBlock.exitBranch as NoBranchTarget); // create a copied exit branch NoBranchTarget copiedExitBranch = new NoBranchTarget(); copiedExitBranch.sourceBasicBlock = targetBasicBlock; targetBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch); } else if (sourceBasicBlock.exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget exitBranch = (sourceBasicBlock.exitBranch as UnconditionalBranchTarget); // create a copied exit branch UnconditionalBranchTarget copiedExitBranch = new UnconditionalBranchTarget(); copiedExitBranch.sourceBasicBlock = targetBasicBlock; targetBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch); } else if (sourceBasicBlock.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget exitBranch = (sourceBasicBlock.exitBranch as ConditionalBranchTarget); // create a copied exit branch ConditionalBranchTarget copiedExitBranch = new ConditionalBranchTarget(); copiedExitBranch.sourceBasicBlock = targetBasicBlock; targetBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch, true); // process branch and next basic block nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, false); } else if (sourceBasicBlock.exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget exitBranch = (sourceBasicBlock.exitBranch as SwitchBranchTarget); // create a copied exit branch SwitchBranchTarget copiedExitBranch = new SwitchBranchTarget(); copiedExitBranch.sourceBasicBlock = targetBasicBlock; targetBasicBlock.exitBranch = copiedExitBranch; // first process not taken branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, -1); // process all taken branches and next basic blocks for (int idx = 0; idx < exitBranch.takenTarget.Count(); idx++) { nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget.ElementAt(idx), ref nextCopiedBasicBlock, copiedExitBranch, idx); } } else if (sourceBasicBlock.exitBranch as ExitBranchTarget != null) { // create a copied exit branch ExitBranchTarget copiedExitBranch = new ExitBranchTarget(); copiedExitBranch.sourceBasicBlock = targetBasicBlock; targetBasicBlock.exitBranch = copiedExitBranch; } else if (sourceBasicBlock.exitBranch as ThrowBranchTarget != null) { // create a copied exit branch ThrowBranchTarget copiedExitBranch = new ThrowBranchTarget(); copiedExitBranch.sourceBasicBlock = targetBasicBlock; targetBasicBlock.exitBranch = copiedExitBranch; } else if (sourceBasicBlock.exitBranch as TryBlockTarget != null) { TryBlockTarget exitBranch = (sourceBasicBlock.exitBranch as TryBlockTarget); // create a copied exit branch TryBlockTarget copiedExitBranch = new TryBlockTarget(); copiedExitBranch.sourceBasicBlock = targetBasicBlock; targetBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch); } else if (sourceBasicBlock.exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget exitBranch = (sourceBasicBlock.exitBranch as ExceptionBranchTarget); // create a copied exit branch ExceptionBranchTarget copiedExitBranch = new ExceptionBranchTarget(); copiedExitBranch.sourceBasicBlock = targetBasicBlock; targetBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exceptionTarget, ref nextCopiedBasicBlock, copiedExitBranch, true); // process branch and next basic block nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exitTarget, ref nextCopiedBasicBlock, copiedExitBranch, false); } else { throw new ArgumentException("Do not know how to handle exit branch."); } // copy all try blocks foreach (TryBlock sourceTryBlock in sourceBasicBlock.tryBlocks) { TryBlock copiedTryBlock = new TryBlock(); copiedTryBlock.exceptionHandler = sourceTryBlock.exceptionHandler; copiedTryBlock.firstBasicBlockOfTryBlock = sourceTryBlock.firstBasicBlockOfTryBlock; copiedTryBlock.lastBasicBlockOfTryBlock = sourceTryBlock.lastBasicBlockOfTryBlock; targetBasicBlock.tryBlocks.Add(copiedTryBlock); } // copy all handler blocks foreach (HandlerBlock sourceHandlerBlock in sourceBasicBlock.handlerBlocks) { HandlerBlock copiedHandlerBlock = new HandlerBlock(); copiedHandlerBlock.exceptionHandler = sourceHandlerBlock.exceptionHandler; copiedHandlerBlock.typeOfHandler = sourceHandlerBlock.typeOfHandler; copiedHandlerBlock.firstBasicBlockOfHandlerBlock = sourceHandlerBlock.firstBasicBlockOfHandlerBlock; copiedHandlerBlock.lastBasicBlockOfHandlerBlock = sourceHandlerBlock.lastBasicBlockOfHandlerBlock; targetBasicBlock.handlerBlocks.Add(copiedHandlerBlock); } }
// insert the given new target basic block between the given switch branch to manipulate public void insertBasicBlockBetweenBranch(SwitchBranchTarget branchToManipulate, int manipulateTakenBranchIdx, BasicBlock newTarget, SwitchBranchTarget exitBranch, int switchTakenBranchIdx) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = null; outroBasicBlock = branchToManipulate.takenTarget.ElementAt(manipulateTakenBranchIdx); BasicBlock branchToManipulateTakenTarget = null; BasicBlock exitBranchTakenTarget = null; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulateTakenTarget, newTarget, newTarget, exitBranch, ref exitBranchTakenTarget); // fill switch taken branch list with null when index is out of range while (exitBranch.takenTarget.Count() <= switchTakenBranchIdx) { exitBranch.takenTarget.Add(null); } exitBranch.takenTarget[switchTakenBranchIdx] = exitBranchTakenTarget; branchToManipulate.takenTarget[manipulateTakenBranchIdx] = branchToManipulateTakenTarget; }
// builds recursively a basic block union (a list of basic blocks that belong together in the control flow because // they are lying directly behind each other) private void createRecursivelyBasicBlockUnion(IList<BasicBlockUnion> basicBlockUnions, BasicBlockUnion currentUnion, BasicBlock currentBasicBlock) { // check if current basic block already belongs to a basic block union foreach (BasicBlockUnion basicBlockUnion in basicBlockUnions) { // ignore current basic block union if (basicBlockUnion == currentUnion) { continue; } foreach (BasicBlock tempBB in basicBlockUnion.basicBlocks) { if (tempBB == currentBasicBlock) { return; } } } // if there are no basic blocks inside the current basic block union // check if the entry to the current basic block could be a not taken branch // or no branch at all => start building the basic block union from the predecessor basic block if (currentUnion.basicBlocks.Count() == 0) { foreach (IBranchTarget entryBranch in currentBasicBlock.entryBranches) { BasicBlock predecessorBasicBlock = entryBranch.sourceBasicBlock; if (predecessorBasicBlock.exitBranch as NoBranchTarget != null) { NoBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as NoBranchTarget); // check if the basic block that comes directly after the predecessor basic block is the current one // => start building basic block union from the predecessor if (predecessorExitBranch.takenTarget == currentBasicBlock) { this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock); return; } continue; } else if (predecessorBasicBlock.exitBranch as TryBlockTarget != null) { TryBlockTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as TryBlockTarget); // check if the basic block that comes directly after the predecessor basic block is the current one // => start building basic block union from the predecessor if (predecessorExitBranch.takenTarget == currentBasicBlock) { this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock); return; } continue; } else if (predecessorBasicBlock.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as ConditionalBranchTarget); // check if the basic block that comes directly after the predecessor basic block is the current one // => start building basic block union from the predecessor if (predecessorExitBranch.notTakenTarget == currentBasicBlock) { this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock); return; } continue; } else if (predecessorBasicBlock.exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as SwitchBranchTarget); // check if the basic block that comes directly after the predecessor basic block is the current one // => start building basic block union from the predecessor if (predecessorExitBranch.notTakenTarget == currentBasicBlock) { this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock); return; } continue; } else if (predecessorBasicBlock.exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as ExceptionBranchTarget); // check if the basic block that comes directly after the predecessor basic block is the current one // => start building basic block union from the predecessor if (predecessorExitBranch.exceptionTarget == currentBasicBlock) { this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock); return; } continue; } } } // add current basic block to the union currentUnion.basicBlocks.Add(currentBasicBlock); // follow all not taken branches and add them to the current basic block union // (this means all basic blocks that follow directly the current one directly // because they lie directly behind the current one are added to the basic block union) if (currentBasicBlock.exitBranch as NoBranchTarget != null) { NoBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as NoBranchTarget); this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.takenTarget); return; } else if (currentBasicBlock.exitBranch as TryBlockTarget != null) { TryBlockTarget tempExitBranch = (currentBasicBlock.exitBranch as TryBlockTarget); this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.takenTarget); return; } else if (currentBasicBlock.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as ConditionalBranchTarget); this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.notTakenTarget); return; } else if (currentBasicBlock.exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as SwitchBranchTarget); this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.notTakenTarget); return; } else if (currentBasicBlock.exitBranch as UnconditionalBranchTarget != null) { return; } else if (currentBasicBlock.exitBranch as ExitBranchTarget != null) { return; } else if (currentBasicBlock.exitBranch as ThrowBranchTarget != null) { return; } else if (currentBasicBlock.exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as ExceptionBranchTarget); this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.exceptionTarget); return; } else { throw new ArgumentException("Do not know how to handle exit branch."); } }
// this function splits a basic block on the given index public void splitBasicBlock(BasicBlock firstPartBB, int splitIndex) { // check if the index is out of bounds if (splitIndex >= firstPartBB.operations.Count()) { throw new ArgumentException("Index is equal or greater than existing basic block operations."); } // check if there are at least 2 operations inside the basic block to split if (firstPartBB.operations.Count() < 2) { throw new ArgumentException("Too few operations in basic block for splitting."); } // create the new basic block that will become the second part of the basic block to split BasicBlock secondPartBB = new BasicBlock(); // move the exit basic blocks to the new created basic block // and make the new created basic block the exit of the splitted one secondPartBB.exitBranch = firstPartBB.exitBranch; secondPartBB.exitBranch.sourceBasicBlock = secondPartBB; NoBranchTarget tempExitBranch = new NoBranchTarget(); tempExitBranch.takenTarget = secondPartBB; tempExitBranch.sourceBasicBlock = firstPartBB; firstPartBB.exitBranch = tempExitBranch; // add splitted basic block branch // to the entries of the new basic block secondPartBB.entryBranches.Add(tempExitBranch); // distribute the instructions to the basic blocks List<IOperation> previousOperations = new List<IOperation>(); List<IOperation> nextOperations = new List<IOperation>(); for (int operationIdx = 0; operationIdx < firstPartBB.operations.Count(); operationIdx++) { if (operationIdx < splitIndex) { previousOperations.Add(firstPartBB.operations.ElementAt(operationIdx)); } else { nextOperations.Add(firstPartBB.operations.ElementAt(operationIdx)); } } firstPartBB.operations = previousOperations; secondPartBB.operations = nextOperations; // add a semantic id to the new basic block if (firstPartBB.semanticId == -1) { secondPartBB.semanticId = -1; } else { int highestSemanticId = 0; foreach (BasicBlock tempBB in methodCfg.basicBlocks) { if (tempBB.semanticId > highestSemanticId) { highestSemanticId = tempBB.semanticId; } } secondPartBB.semanticId = highestSemanticId + 1; } // add new basic block to the cfg methodCfg.basicBlocks.Add(secondPartBB); }
// this functions creates metadata for the given basic block and adds it private bool createAndAddMetadata(BasicBlock currentBasicBlock) { // get metadata of entry basic block (if exists) IGraphTransformerMetadata previousMetadata = null; BasicBlock previousBasicBlock = null; IBranchTarget previousExitBranch = null; for (int i = 0; i < currentBasicBlock.entryBranches.Count(); i++) { previousBasicBlock = currentBasicBlock.entryBranches.ElementAt(i).sourceBasicBlock; for (int j = 0; j < previousBasicBlock.transformationMetadata.Count(); j++) { // get graph transformer metadata for basic blocks if ((previousBasicBlock.transformationMetadata.ElementAt(j) as IGraphTransformerMetadata) == null) { continue; } previousMetadata = (previousBasicBlock.transformationMetadata.ElementAt(j) as IGraphTransformerMetadata); previousExitBranch = currentBasicBlock.entryBranches.ElementAt(i); break; } if (previousMetadata != null) { break; } } // skip basic block if there is no metadata in one of the entry basic blocks if (previousMetadata == null) { // TODO: here is room for optimization => do not skip it return false; } List<BasicBlockGraphNodeLink> previousLinks = previousMetadata.correspondingGraphNodes; // choose the next nodes of the obfuscation graph for the current basic block NodeObject[] currentNodes = new NodeObject[this.graph.graphValidPathCount]; // check if previous basic block has links to the obfuscation graph for all existing valid paths // (if previous basic block for example was a "state change" basic block it can only have one link to the obfuscation graph) // => just copy obfuscation graph nodes of previous basic block if it contains all valid paths if (previousLinks.Count() == this.graph.graphValidPathCount) { for (int currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { bool found = false; for (int i = 0; i < previousLinks.Count(); i++) { if (previousLinks.ElementAt(i).validPathId == currentValidPathId) { currentNodes[currentValidPathId] = previousLinks.ElementAt(i).graphNode; found = true; break; } } if (!found) { throw new ArgumentException("Was not able to find link to obfuscation graph in previous basic block for at least one valid path."); } } } // previous basic block does not contain all valid paths // => copy all existing valid paths links and choose random links for the missing ones else { for (int currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { bool found = false; for (int i = 0; i < previousLinks.Count(); i++) { if (previousLinks.ElementAt(i).validPathId == currentValidPathId) { currentNodes[currentValidPathId] = previousLinks.ElementAt(i).graphNode; found = true; break; } } // if a link for the current valid path does not exist // => choose randomly a node in the obfuscation graph on the current valid path if (!found) { int moveCount = this.prng.Next(this.graphDepth); NodeObject nextNode = this.graph.startingNode; for (int move = 0; move < moveCount; move++) { for (int i = 0; i < nextNode.nodeObjects.Count(); i++) { // if the child node does not belong to a valid path // => skip it if (nextNode.nodeObjects[i].elementOfValidPath.Count() == 0) { continue; } // the child node belongs to a valid path // => check if it is the correct valid path else { // if the child node belongs to the correct valid path // => set next node to it if (nextNode.nodeObjects[i].elementOfValidPath.Contains(currentValidPathId)) { nextNode = nextNode.nodeObjects[i]; break; } } } if (nextNode == null) { throw new ArgumentException("Not able to find correct child node."); } } currentNodes[currentValidPathId] = nextNode; } } } NodeObject[] nextNodes = new NodeObject[this.graph.graphValidPathCount]; for (int currentValidPathId = 0; currentValidPathId < currentNodes.Count(); currentValidPathId++) { // choose randomly if the pointer of the current valid path should be moved forward // => move the pointer of the current valid path forward if (this.prng.Next(2) == 0) { // get the next node of the valid path NodeObject nextNode = null; int nextNodeIdx = 0; this.getNextNode(ref nextNode, ref nextNodeIdx, currentNodes, currentValidPathId); nextNodes[currentValidPathId] = nextNode; } // => do not move the pointer of the current valid path forward else { // set next node in the graph to the current one (it was not changed) nextNodes[currentValidPathId] = currentNodes[currentValidPathId]; } } // create transformation metadata for the current basic block GraphTransformerMetadataBasicBlock metadata = new GraphTransformerMetadataBasicBlock(); for (int currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { BasicBlockGraphNodeLink link = new BasicBlockGraphNodeLink(nextNodes[currentValidPathId], currentValidPathId); metadata.correspondingGraphNodes.Add(link); } currentBasicBlock.transformationMetadata.Add(metadata); return true; }