// 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);
 }
Exemple #8
0
        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);
        }
Exemple #9
0
        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;
                }

            }

        }
Exemple #15
0
        // 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;
                }
            }
        }
Exemple #16
0
        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);
            }
        }
Exemple #17
0
        // 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;
        }
Exemple #18
0
        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);
            }

        }
Exemple #20
0
        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);
        }
Exemple #22
0
        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;

        }
Exemple #28
0
        // 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;

        }