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; } } }
// 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 functions creates metadata for the given basic block and adds it private bool createAndAddMetadata(BasicBlock currentBasicBlock) { // get metadata of entry basic block (if exists) IGraphTransformerMetadata previousMetadata = null; BasicBlock previousBasicBlock = null; IBranchTarget previousExitBranch = null; for (int i = 0; i < currentBasicBlock.entryBranches.Count(); i++) { previousBasicBlock = currentBasicBlock.entryBranches.ElementAt(i).sourceBasicBlock; for (int j = 0; j < previousBasicBlock.transformationMetadata.Count(); j++) { // get graph transformer metadata for basic blocks if ((previousBasicBlock.transformationMetadata.ElementAt(j) as IGraphTransformerMetadata) == null) { continue; } previousMetadata = (previousBasicBlock.transformationMetadata.ElementAt(j) as IGraphTransformerMetadata); previousExitBranch = currentBasicBlock.entryBranches.ElementAt(i); break; } if (previousMetadata != null) { break; } } // skip basic block if there is no metadata in one of the entry basic blocks if (previousMetadata == null) { // TODO: here is room for optimization => do not skip it return false; } List<BasicBlockGraphNodeLink> previousLinks = previousMetadata.correspondingGraphNodes; // choose the next nodes of the obfuscation graph for the current basic block NodeObject[] currentNodes = new NodeObject[this.graph.graphValidPathCount]; // check if previous basic block has links to the obfuscation graph for all existing valid paths // (if previous basic block for example was a "state change" basic block it can only have one link to the obfuscation graph) // => just copy obfuscation graph nodes of previous basic block if it contains all valid paths if (previousLinks.Count() == this.graph.graphValidPathCount) { for (int currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { bool found = false; for (int i = 0; i < previousLinks.Count(); i++) { if (previousLinks.ElementAt(i).validPathId == currentValidPathId) { currentNodes[currentValidPathId] = previousLinks.ElementAt(i).graphNode; found = true; break; } } if (!found) { throw new ArgumentException("Was not able to find link to obfuscation graph in previous basic block for at least one valid path."); } } } // previous basic block does not contain all valid paths // => copy all existing valid paths links and choose random links for the missing ones else { for (int currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { bool found = false; for (int i = 0; i < previousLinks.Count(); i++) { if (previousLinks.ElementAt(i).validPathId == currentValidPathId) { currentNodes[currentValidPathId] = previousLinks.ElementAt(i).graphNode; found = true; break; } } // if a link for the current valid path does not exist // => choose randomly a node in the obfuscation graph on the current valid path if (!found) { int moveCount = this.prng.Next(this.graphDepth); NodeObject nextNode = this.graph.startingNode; for (int move = 0; move < moveCount; move++) { for (int i = 0; i < nextNode.nodeObjects.Count(); i++) { // if the child node does not belong to a valid path // => skip it if (nextNode.nodeObjects[i].elementOfValidPath.Count() == 0) { continue; } // the child node belongs to a valid path // => check if it is the correct valid path else { // if the child node belongs to the correct valid path // => set next node to it if (nextNode.nodeObjects[i].elementOfValidPath.Contains(currentValidPathId)) { nextNode = nextNode.nodeObjects[i]; break; } } } if (nextNode == null) { throw new ArgumentException("Not able to find correct child node."); } } currentNodes[currentValidPathId] = nextNode; } } } NodeObject[] nextNodes = new NodeObject[this.graph.graphValidPathCount]; for (int currentValidPathId = 0; currentValidPathId < currentNodes.Count(); currentValidPathId++) { // choose randomly if the pointer of the current valid path should be moved forward // => move the pointer of the current valid path forward if (this.prng.Next(2) == 0) { // get the next node of the valid path NodeObject nextNode = null; int nextNodeIdx = 0; this.getNextNode(ref nextNode, ref nextNodeIdx, currentNodes, currentValidPathId); nextNodes[currentValidPathId] = nextNode; } // => do not move the pointer of the current valid path forward else { // set next node in the graph to the current one (it was not changed) nextNodes[currentValidPathId] = currentNodes[currentValidPathId]; } } // create transformation metadata for the current basic block GraphTransformerMetadataBasicBlock metadata = new GraphTransformerMetadataBasicBlock(); for (int currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { BasicBlockGraphNodeLink link = new BasicBlockGraphNodeLink(nextNodes[currentValidPathId], currentValidPathId); metadata.correspondingGraphNodes.Add(link); } currentBasicBlock.transformationMetadata.Add(metadata); return true; }
// 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."); } }
// 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 generates code for the "state change" private void createCodeStateChange(ref BasicBlock outStateChangeBasicBlock, ref SwitchBranchTarget outStateChangeExitBranch, GraphRandomStateGenerator randomStateGenerator, BasicBlockGraphNodeLink link, LocalDefinition intStateLocal) { // create a basic block to change the current global state BasicBlock stateChangeBasicBlock = new BasicBlock(); stateChangeBasicBlock.startIdx = 0; stateChangeBasicBlock.endIdx = 0; // create graph transformer metadata for the basic block GraphTransformerStateChangeBasicBlock metadataChange = new GraphTransformerStateChangeBasicBlock(); metadataChange.correspondingGraphNodes.Add(link); stateChangeBasicBlock.transformationMetadata.Add(metadataChange); // generate code for setting the new global state List<IOperation> tempOperations = randomStateGenerator.generateCodeSetRandomState(intStateLocal); stateChangeBasicBlock.operations.AddRange(tempOperations); // create switch statement for the "state switch" stateChangeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, intStateLocal)); uint[] switchSize = new uint[this.graph.graphValidPathCount]; stateChangeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Switch, switchSize)); // create exit branch for the new state basic block SwitchBranchTarget stateChangeExitBranch = new SwitchBranchTarget(); stateChangeExitBranch.sourceBasicBlock = stateChangeBasicBlock; stateChangeBasicBlock.exitBranch = stateChangeExitBranch; // create the dead code for this "state switch" BasicBlock deadCodeBasicBlock = new BasicBlock(); deadCodeBasicBlock.startIdx = 0; deadCodeBasicBlock.endIdx = 0; // set the dead code basic block as "not taken" target for the conditional branch of the checking basic block deadCodeBasicBlock.entryBranches.Add(stateChangeExitBranch); stateChangeExitBranch.notTakenTarget = deadCodeBasicBlock; // TODO at the moment always the not taken branch of the switch statement is the dead code basic block // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); outStateChangeBasicBlock = stateChangeBasicBlock; outStateChangeExitBranch = stateChangeExitBranch; }
// this function generates code to move the current pointer to the next child node (or start node if there is no next child node) private BasicBlock createCodeNextNode(IBranchTarget usedExitBranch, BasicBlockGraphNodeLink graphLink, LocalDefinition currentNodeLocal, int index, bool correctNextNode) { // create graph transformer metadata for the basic blocks GraphTransformerNextNodeBasicBlock metadata = new GraphTransformerNextNodeBasicBlock(); metadata.correctNextNode = correctNextNode; metadata.correspondingGraphNodes.Add(graphLink); // create new basic block BasicBlock nextNodeBasicBlock = new BasicBlock(); nextNodeBasicBlock.startIdx = 0; nextNodeBasicBlock.endIdx = 0; nextNodeBasicBlock.transformationMetadata.Add(metadata); nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4, index)); // TODO perhaps a more dynamically calculated index? nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceChildNodesGet)); nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Stloc, currentNodeLocal)); // check which exit branch is used to inject the code to the cfg and generate code for it accordingly if ((usedExitBranch as NoBranchTarget) != null) { nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Nop)); } else if ((usedExitBranch as UnconditionalBranchTarget) != null) { nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Br)); } else { throw new ArgumentException("Do not know how to generate code for given exit branch."); } // add exit branch to newly created basic block nextNodeBasicBlock.exitBranch = usedExitBranch; usedExitBranch.sourceBasicBlock = nextNodeBasicBlock; return nextNodeBasicBlock; }
// this function generates code for an opaque predicate that evaluates to "true" // => the "taken" branch of the conditional branch have to be taken for the correct code path private void createCodeTruePredicate(ref BasicBlock outStartBasicBlock, ref ConditionalBranchTarget outConditionalBranch, BasicBlockGraphNodeLink link, LocalDefinition currentNodeLocal) { // create a basic block that checks the opaque predicate (this check evaluates to "true") BasicBlock startBasicBlock = new BasicBlock(); startBasicBlock.startIdx = 0; startBasicBlock.endIdx = 0; // add graph transformer metadata to the basic block GraphTransformerPredicateBasicBlock metadata = new GraphTransformerPredicateBasicBlock(); metadata.predicateType = GraphOpaquePredicate.True; metadata.correspondingGraphNodes.Add(link); startBasicBlock.transformationMetadata.Add(metadata); // search for the valid and invalid interfaces list of the current valid path id List<ITypeReference> validInterfaces = null; List<ITypeReference> invalidInterfaces = null; foreach (PathElement pathElement in link.graphNode.pathElements) { if (pathElement.validPathId == link.validPathId) { validInterfaces = pathElement.validInterfaces; invalidInterfaces = pathElement.invalidInterfaces; } } if (validInterfaces == null || invalidInterfaces == null) { throw new ArgumentException("No valid/invalid interface list was found."); } emitPredicateCode(startBasicBlock, currentNodeLocal, validInterfaces, invalidInterfaces); // create the conditional branch for the checking basic block (taken => correct code; not taken => dead code) ConditionalBranchTarget startBasicBlockExitBranch = new ConditionalBranchTarget(); startBasicBlockExitBranch.sourceBasicBlock = startBasicBlock; startBasicBlock.exitBranch = startBasicBlockExitBranch; // create the dead code for this opaque predicate BasicBlock deadCodeBasicBlock = new BasicBlock(); deadCodeBasicBlock.startIdx = 0; deadCodeBasicBlock.endIdx = 0; // set the dead code basic block as "not taken" target for the conditional branch of the checking basic block deadCodeBasicBlock.entryBranches.Add(startBasicBlockExitBranch); startBasicBlockExitBranch.notTakenTarget = deadCodeBasicBlock; // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); // set the created basic block and conditional jumps as output outStartBasicBlock = startBasicBlock; outConditionalBranch = startBasicBlockExitBranch; }
// Generates code for an opaque predicate evaluating to a random value. // => Both branches point to basic blocks with equal semantics. private void createCodeRandomPredicate(ref BasicBlock outStartBasicBlock, ref ConditionalBranchTarget outConditionalBranch, BasicBlockGraphNodeLink link, LocalDefinition currentNodeLocal) { throw new ArgumentException("Not implemented."); // TODO: will improve the probabilistic control flow }
// this function generates code for an opaque predicate that evaluates to "false" // => the "not taken" branch of the conditional branch have to be taken for the correct code path private void createCodeFalsePredicate(ref BasicBlock outStartBasicBlock, ref ConditionalBranchTarget outConditionalBranch, BasicBlockGraphNodeLink link, LocalDefinition currentNodeLocal) { // create a basic block that checks the opaque predicate (this check evaluates to "false") BasicBlock startBasicBlock = new BasicBlock(); startBasicBlock.startIdx = 0; startBasicBlock.endIdx = 0; // add graph transformer metadata to the basic block GraphTransformerPredicateBasicBlock metadata = new GraphTransformerPredicateBasicBlock(); metadata.predicateType = GraphOpaquePredicate.False; metadata.correspondingGraphNodes.Add(link); startBasicBlock.transformationMetadata.Add(metadata); // search for the valid and invalid interfaces list of the current valid path id List<ITypeReference> validInterfaces = null; List<ITypeReference> invalidInterfaces = null; foreach (PathElement pathElement in link.graphNode.pathElements) { if (pathElement.validPathId == link.validPathId) { validInterfaces = pathElement.validInterfaces; invalidInterfaces = pathElement.invalidInterfaces; } } if(validInterfaces == null || invalidInterfaces == null) { throw new ArgumentException("No valid/invalid interface list was found."); } // add a random check to the code // important: for this predicate the dead code is reached by the "taken" branch and the correct code is reached by the "not taken" branch int randPosition; ITypeReference interfaceToCheck = null; switch (this.prng.Next(8)) { case 0: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; case 1: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 2: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_1)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; case 3: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 4: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 5: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; case 6: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_1)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 7: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; default: throw new ArgumentException("This case should never be reached."); } // create the conditional branch for the checking basic block (not taken => correct code; taken => dead code) ConditionalBranchTarget startBasicBlockExitBranch = new ConditionalBranchTarget(); startBasicBlockExitBranch.sourceBasicBlock = startBasicBlock; startBasicBlock.exitBranch = startBasicBlockExitBranch; // create the dead code for this opaque predicate BasicBlock deadCodeBasicBlock = new BasicBlock(); deadCodeBasicBlock.startIdx = 0; deadCodeBasicBlock.endIdx = 0; // set the dead code basic block as "taken" target for the conditional branch of the checking basic block deadCodeBasicBlock.entryBranches.Add(startBasicBlockExitBranch); startBasicBlockExitBranch.takenTarget = deadCodeBasicBlock; // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); // set the created basic block and conditional jumps as output outStartBasicBlock = startBasicBlock; outConditionalBranch = startBasicBlockExitBranch; }