public GraphRandomStateGenerator(IModule module, PeReader.DefaultHost host, Log.Log logger, CfgManipulator cfgManipulator, Helper helperClass, Graph.Graph graph, MethodCfg methodCfg, bool debugging) {

            this.module = module;
            this.host = host;
            this.logger = logger;
            this.cfgManipulator = cfgManipulator;            
            this.helperClass = helperClass;
            this.graph = graph;
            this.methodCfg = methodCfg;
            this.debugging = debugging;

            // add local random generator variable
            this.tempRandomLocal = new LocalDefinition();
            this.tempRandomLocal.IsReference = false;
            this.tempRandomLocal.IsPinned = false;
            this.tempRandomLocal.IsModified = false;
            this.tempRandomLocal.Type = this.helperClass.systemRandom;
            this.tempRandomLocal.MethodDefinition = methodCfg.method;
            cfgManipulator.addLocalVariable(this.tempRandomLocal);


        }
Example #2
0
        public CodeGenerator(IModule module, PeReader.DefaultHost host, Log.Log logger, Random prng, MethodCfg methodCfg,
            bool debugging=false, CfgManipulator manipulator=null)
        {
            this.host = host;
            this.logger = logger;
            this.module = module;
            this.prng = prng;
            this.methodCfg = methodCfg;
            this.debugging = debugging;
            this.manipulator = manipulator;

            callableMethods = retrieveCallableMethods();
        }
Example #3
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);
        }
        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;
                }

            }

        }
        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 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;
                }

            }

        }
        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;

            }

        }
        // Mutates all blocks in the given method CFG.
        private void mutateBlocks(MethodCfg methodCfg)
        {
            var manipulator = new CfgManipulator(this.module, this.host, this.logger, methodCfg);
            var codeMutator = new CodeMutator(this.module, this.host, this.logger, this.prng, methodCfg, manipulator, this.debugging);

            codeMutator.mutateBlocks(methodCfg.basicBlocks);
        }
        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;
        }
        // Searches semantically equivalent blocks in the given method CFG and obfuscates them.
        private void obfuscateSemanticallyEquivalentBlocks(MethodCfg methodCfg)
        {
            // Group all blocks with same semantic ID.
            var semanticGroups = new Dictionary<int, List<BasicBlock>>();

            foreach(var block in methodCfg.basicBlocks) {
                List<BasicBlock> blockList = null;
                if(!semanticGroups.TryGetValue(block.semanticId, out blockList)) {
                    blockList = new List<BasicBlock>();
                    semanticGroups[block.semanticId] = blockList;
                }

                if(block.semanticId != -1) {
                    semanticGroups[block.semanticId].Add(block);
                }
            }

            // Mutate equivalent blocks.
            var manipulator = new CfgManipulator(this.module, this.host, this.logger, methodCfg);
            var codeMutator = new CodeMutator(this.module, this.host, this.logger, this.prng, methodCfg, manipulator, this.debugging);

            foreach(var blockList in semanticGroups.Values) {
                codeMutator.mutateSemanticallyEquivalentBlocks(blockList); 
            }
        }
        // this function is used to fill the created dead code basic blocks with actual dead code
        private void fillDeadCodeBasicBlocks(MethodCfg methodCfg) {

            var manipulator = new CfgManipulator(this.module, this.host, this.logger, methodCfg);
            CodeGenerator codeGenerator = new CodeGenerator(this.module, this.host, this.logger, this.prng, methodCfg, this.debugging, manipulator);
            //CodeGenerator codeGenerator = new CodeGenerator(this.module, this.host, this.logger, this.prng, methodCfg, true, manipulator);

            // search through all basic blocks if there are dead code basic blocks
            foreach (BasicBlock currentBasicBlock in methodCfg.basicBlocks) {

                // fill basic block with dead code if it is marked as a dead code basic block
                foreach (ITransformationMetadata metadata in currentBasicBlock.transformationMetadata) {
                    if ((metadata as GraphTransformerDeadCodeBasicBlock) != null) {
                        codeGenerator.generateDeadCode(currentBasicBlock, metadata);
                    }
                }

            }

        }
        // this function generates and injects code into the given entry branch that moves the pointer from the source node to the target node
        private void injectLinkMoveCode(CfgManipulator cfgManipulator, BasicBlockGraphNodeLink startGraphLink, BasicBlockGraphNodeLink targetGraphLink, IBranchTarget entryBranch, int currentValidPathId, LocalDefinition currentNodeLocal) {

            NodeObject targetNode = targetGraphLink.graphNode;
            NodeObject startNode = startGraphLink.graphNode;
            IBranchTarget branchToManipulate = entryBranch;

            // do nothing if the source node is already the same as the target node
            if (startNode == targetNode) {
                return;
            }

            // check if the pointer have to be moved to the start pointer before it can be moved to the target element
            bool goToStart = false;
            if (startNode.positionInGraph.Count() >= targetNode.positionInGraph.Count()) {
                goToStart = true;
            }
            else {
                for (int idx = 0; idx < startNode.positionInGraph.Count(); idx++) {
                    if (startNode.positionInGraph.ElementAt(idx) != targetNode.positionInGraph.ElementAt(idx)) {
                        goToStart = true;
                        break;
                    }
                }
            }

            // set current graph link (is used for the metadata of the pointer correcting basic blocks
            BasicBlockGraphNodeLink currentGraphLink = new BasicBlockGraphNodeLink(startGraphLink.graphNode, currentValidPathId);

            // check how to move the pointer to the target element
            // => first go to the start pointer
            if (goToStart) {

                // generate and inject code that moves the pointer on a random path forward until the start node of the graph is reached
                while (startNode != this.graph.startingNode) {

                    // generate code to move the pointer to the next node in the graph and inject it
                    int nextNodeIdx = this.prng.Next(this.graphDimension);
                    UnconditionalBranchTarget injectedExitBranch = new UnconditionalBranchTarget();
                    BasicBlock injectedBasicBlock = this.createCodeNextNode(injectedExitBranch, currentGraphLink, currentNodeLocal, nextNodeIdx, true);
                    if ((branchToManipulate as UnconditionalBranchTarget) != null) {
                        UnconditionalBranchTarget tempBranchToManipulate = (branchToManipulate as UnconditionalBranchTarget);
                        cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, injectedBasicBlock, injectedExitBranch);
                    }
                    else if ((branchToManipulate as SwitchBranchTarget) != null) {
                        SwitchBranchTarget tempBranchToManipulate = (branchToManipulate as SwitchBranchTarget);
                        cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, currentValidPathId, injectedBasicBlock, injectedExitBranch);
                    }
                    else {
                        throw new ArgumentException("Not yet implemented."); // TODO
                    }

                    // set the next branch to manipulate as the newly created exit branch
                    branchToManipulate = injectedExitBranch;

                    // move pointer to the next node in the graph or to the start node if it does not exist
                    if (startNode.nodeObjects[nextNodeIdx] == null) {
                        startNode = this.graph.startingNode;
                    }
                    else {
                        startNode = startNode.nodeObjects[nextNodeIdx];
                    }

                    // create new graph link for the current node
                    currentGraphLink = new BasicBlockGraphNodeLink(startNode, currentValidPathId);
                }

                // generate and inject code that moves the pointer to the correct position of the given graph node
                foreach (int nextNodeIdx in targetNode.positionInGraph) {

                    // generate code to move the pointer to the next node in the graph and inject it
                    UnconditionalBranchTarget injectedExitBranch = new UnconditionalBranchTarget();
                    BasicBlock injectedBasicBlock = this.createCodeNextNode(injectedExitBranch, currentGraphLink, currentNodeLocal, nextNodeIdx, true);
                    if ((branchToManipulate as UnconditionalBranchTarget) != null) {
                        UnconditionalBranchTarget tempBranchToManipulate = (branchToManipulate as UnconditionalBranchTarget);
                        cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, injectedBasicBlock, injectedExitBranch);
                    }
                    else if ((branchToManipulate as SwitchBranchTarget) != null) {
                        SwitchBranchTarget tempBranchToManipulate = (branchToManipulate as SwitchBranchTarget);
                        cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, currentValidPathId, injectedBasicBlock, injectedExitBranch);
                    }
                    else {
                        throw new ArgumentException("Not yet implemented."); // TODO
                    }

                    // set the next branch to manipulate as the newly created exit branch
                    branchToManipulate = injectedExitBranch;

                    // move pointer to the next node in the graph or to the start node if it does not exist
                    if (startNode.nodeObjects[nextNodeIdx] == null) {
                        startNode = this.graph.startingNode;
                    }
                    else {
                        startNode = startNode.nodeObjects[nextNodeIdx];
                    }

                    // create new graph link for the current node
                    currentGraphLink = new BasicBlockGraphNodeLink(startNode, currentValidPathId);
                }
            }

            // => go on a direct path to the target element
            else {

                // generate and inject code that moves the pointer to the correct position of the given graph node
                for (int idx = startNode.positionInGraph.Count(); idx < targetNode.positionInGraph.Count(); idx++) {

                    // generate code to move the pointer to the next node in the graph and inject it
                    UnconditionalBranchTarget injectedExitBranch = new UnconditionalBranchTarget();
                    BasicBlock injectedBasicBlock = this.createCodeNextNode(injectedExitBranch, currentGraphLink, currentNodeLocal, targetNode.positionInGraph.ElementAt(idx), true);
                    if ((branchToManipulate as UnconditionalBranchTarget) != null) {
                        UnconditionalBranchTarget tempBranchToManipulate = (branchToManipulate as UnconditionalBranchTarget);
                        cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, injectedBasicBlock, injectedExitBranch);
                    }
                    else if ((branchToManipulate as SwitchBranchTarget) != null) {
                        SwitchBranchTarget tempBranchToManipulate = (branchToManipulate as SwitchBranchTarget);
                        cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, currentValidPathId, injectedBasicBlock, injectedExitBranch);
                    }
                    else {
                        throw new ArgumentException("Not yet implemented."); // TODO
                    }

                    // set the next branch to manipulate as the newly created exit branch
                    branchToManipulate = injectedExitBranch;

                    // move pointer to the next node in the graph or to the start node if it does not exist
                    if (startNode.nodeObjects[targetNode.positionInGraph.ElementAt(idx)] == null) {
                        startNode = this.graph.startingNode;
                    }
                    else {
                        startNode = startNode.nodeObjects[targetNode.positionInGraph.ElementAt(idx)];
                    }

                    // create new graph link for the current node
                    currentGraphLink = new BasicBlockGraphNodeLink(startNode, currentValidPathId);
                }

            }

            // check if the final reached node is the same as the target node
            if (startNode != targetNode) {
                throw new ArgumentException("Current node and target node are not the same.");
            }

        }
        // this function injects an opaque predicate to the target branch
        private void injectOpaquePredicateCode(CfgManipulator cfgManipulator, MethodCfg methodCfg, BasicBlock targetBasicBlock, IBranchTarget targetBranch, BasicBlockGraphNodeLink link, int opaquePredicate, LocalDefinition currentNodeLocal) {

            int currentValidPathId = link.validPathId;
            ConditionalBranchTarget opaqueExitBranch = null;

            // create "true" or "false" opaque predicate and add it to the code
            switch (opaquePredicate) {

                // "true" opaque predicate
                case 0: {
                        BasicBlock opaqueStartBasicBlock = null;

                        this.createCodeTruePredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal);

                        // inject target branch with opaque predicate
                        if ((targetBranch as SwitchBranchTarget) != null) {
                            SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget);
                            cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, true);
                        }
                        else if ((targetBranch as UnconditionalBranchTarget) != null) {
                            UnconditionalBranchTarget tempTargetBranch = (targetBranch as UnconditionalBranchTarget);
                            cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, opaqueStartBasicBlock, opaqueExitBranch, true);
                        }
                        else {
                            throw new ArgumentException("Not implemented yet.");
                        }

                        // set template semantic id of dead code basic block
                        BasicBlock deadCodeBasicBlock = opaqueExitBranch.notTakenTarget;
                        GraphTransformerDeadCodeBasicBlock deadCodeMetadata = (deadCodeBasicBlock.transformationMetadata.ElementAt(0) as GraphTransformerDeadCodeBasicBlock);
                        deadCodeMetadata.semanticId = targetBasicBlock.semanticId;

                        // create intermediate basic block and inject it between correct opaque predicate branch and target basic block
                        BasicBlock intermediateBasicBlock = new BasicBlock();
                        intermediateBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Br, 0));
                        methodCfg.basicBlocks.Add(intermediateBasicBlock);

                        // add metadata to intermediate basic block
                        GraphTransformerIntermediateBasicBlock metadataIntermediate = new GraphTransformerIntermediateBasicBlock();
                        metadataIntermediate.correspondingGraphNodes.Add(link);
                        intermediateBasicBlock.transformationMetadata.Add(metadataIntermediate);

                        // create intermediate exit branch
                        UnconditionalBranchTarget intermediateBasicBlockExitBranch = new UnconditionalBranchTarget();
                        intermediateBasicBlockExitBranch.sourceBasicBlock = intermediateBasicBlock;
                        intermediateBasicBlock.exitBranch = intermediateBasicBlockExitBranch;

                        cfgManipulator.insertBasicBlockBetweenBranch(opaqueExitBranch, true, intermediateBasicBlock, intermediateBasicBlockExitBranch);

                        break;
                    }

                // "false" opaque predicate
                case 1: {
                        BasicBlock opaqueStartBasicBlock = null;

                        this.createCodeFalsePredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal);

                        // inject target branch with opaque predicate
                        if ((targetBranch as SwitchBranchTarget) != null) {
                            SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget);
                            cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, false);
                        }
                        else if ((targetBranch as UnconditionalBranchTarget) != null) {
                            UnconditionalBranchTarget tempTargetBranch = (targetBranch as UnconditionalBranchTarget);
                            cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, opaqueStartBasicBlock, opaqueExitBranch, false);
                        }
                        else {
                            throw new ArgumentException("Not implemented yet.");
                        }

                        // set template semantic id of dead code basic block
                        BasicBlock deadCodeBasicBlock = opaqueExitBranch.takenTarget;
                        GraphTransformerDeadCodeBasicBlock deadCodeMetadata = (deadCodeBasicBlock.transformationMetadata.ElementAt(0) as GraphTransformerDeadCodeBasicBlock);
                        deadCodeMetadata.semanticId = targetBasicBlock.semanticId;

                        // create intermediate basic block and inject it between correct opaque predicate branch and target basic block
                        BasicBlock intermediateBasicBlock = new BasicBlock();
                        intermediateBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Br, 0));
                        methodCfg.basicBlocks.Add(intermediateBasicBlock);

                        // add metadata to intermediate basic block
                        GraphTransformerIntermediateBasicBlock metadataIntermediate = new GraphTransformerIntermediateBasicBlock();
                        metadataIntermediate.correspondingGraphNodes.Add(link);
                        intermediateBasicBlock.transformationMetadata.Add(metadataIntermediate);

                        // create intermediate exit branch
                        UnconditionalBranchTarget intermediateBasicBlockExitBranch = new UnconditionalBranchTarget();
                        intermediateBasicBlockExitBranch.sourceBasicBlock = intermediateBasicBlock;
                        intermediateBasicBlock.exitBranch = intermediateBasicBlockExitBranch;

                        cfgManipulator.insertBasicBlockBetweenBranch(opaqueExitBranch, false, intermediateBasicBlock, intermediateBasicBlockExitBranch);

                        break;
                    }

                // "Random" opaque predicate.
                case 2: {
                        BasicBlock opaqueStartBasicBlock = null;

                        if ((targetBranch as SwitchBranchTarget) != null) {
                            SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget);
                            var destinationBlock = tempTargetBranch.takenTarget[currentValidPathId];

                            this.createCodeRandomPredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal);

                            bool chooseBranch = prng.Next(1) == 0;
                            cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, chooseBranch);
                        }
                        else {
                            throw new ArgumentException("Not implemented yet.");
                        }
                        break;
                    }

                default:
                    throw new ArgumentException("This case should never be reached.");
            }

        }
        // this function injects an opaque predicate to the target branch
        private void injectOpaquePredicateCode(CfgManipulator cfgManipulator, Target target, ref ConditionalBranchTarget opaqueExitBranch, IBranchTarget targetBranch, BasicBlockGraphNodeLink link, int currentValidPathId, int opaquePredicate, LocalDefinition currentNodeLocal) {

            // create "true" or "false" opaque predicate and add it to the code
            switch (opaquePredicate) {

                // "true" opaque predicate
                case 0: {
                        BasicBlock opaqueStartBasicBlock = null;

                        this.createCodeTruePredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal);

                        // inject target branch with opaque predicate
                        if ((targetBranch as SwitchBranchTarget) != null) {
                            SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget);
                            cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, true);
                        }
                        else {
                            throw new ArgumentException("Not implemented yet.");
                        }

                        // set template semantic id of dead code basic block
                        BasicBlock deadCodeBasicBlock = opaqueExitBranch.notTakenTarget;
                        GraphTransformerDeadCodeBasicBlock deadCodeMetadata = (deadCodeBasicBlock.transformationMetadata.ElementAt(0) as GraphTransformerDeadCodeBasicBlock);
                        deadCodeMetadata.semanticId = target.basicBlock.semanticId;

                        break;
                    }

                // "false" opaque predicate
                case 1: {
                        BasicBlock opaqueStartBasicBlock = null;

                        this.createCodeFalsePredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal);

                        // inject target branch with opaque predicate
                        if ((targetBranch as SwitchBranchTarget) != null) {
                            SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget);
                            cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, false);
                        }
                        else {
                            throw new ArgumentException("Not implemented yet.");
                        }

                        // set template semantic id of dead code basic block
                        BasicBlock deadCodeBasicBlock = opaqueExitBranch.takenTarget;
                        GraphTransformerDeadCodeBasicBlock deadCodeMetadata = (deadCodeBasicBlock.transformationMetadata.ElementAt(0) as GraphTransformerDeadCodeBasicBlock);
                        deadCodeMetadata.semanticId = target.basicBlock.semanticId;

                        break;
                    }

                // "Random" opaque predicate.
                case 2: {
                        BasicBlock opaqueStartBasicBlock = null;

                        if((targetBranch as SwitchBranchTarget) != null) {
                            SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget);
                            var destinationBlock = tempTargetBranch.takenTarget[currentValidPathId];

                            this.createCodeRandomPredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal);

                            bool chooseBranch = prng.Next(1) == 0;
                            cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, chooseBranch);
                        }
                        else {
                            throw new ArgumentException("Not implemented yet.");
                        }
                        break;
                    }

                default:
                    throw new ArgumentException("This case should never be reached.");
            }

        }