// this function fills the rest of the graph with random nodes private void fillNodesRecursively(NodeObject currentNode, List<int> currentPosition, int currentDepth, int maxDepth, List<PossibleNode> allPossibleNodes, ValidGraphPath[] validPaths) { // check if the maximal depth is reached if (currentDepth >= maxDepth) { return; } // fill all missing nodes of the current object with new random nodes for (int idx = 0; idx < currentNode.dimension; idx++) { // copy position list and add path index to the position List<int> tempCurrentPosition = new List<int>(currentPosition); tempCurrentPosition.Add(idx); if (currentNode.nodeObjects[idx] == null) { // get random possible node from list of all possible nodes int randElement = this.prng.Next(allPossibleNodes.Count); PossibleNode possibleNode = allPossibleNodes.ElementAt(randElement); NamespaceTypeDefinition classToUse = possibleNode.givenClass; MethodDefinition nodeConstructor = possibleNode.nodeConstructor; // generate path element from chosen interface PathElement pathElement = new PathElement(); // create new node object currentNode.nodeObjects[idx] = new NodeObject(this.graphDimension, this.graphValidPathCount, classToUse, nodeConstructor, pathElement, tempCurrentPosition); // search through every valid path if the new created filler node has the same attributes as the valid path node // => add it to the list of possible nodes that can be used for an exchange between valid node and filler node for (int validPathId = 0; validPathId < validPaths.Count(); validPathId++) { for (int depth = 0; depth < validPaths[validPathId].pathElements.Count(); depth++) { // check if the used class of the current filler node is in the list of possible classes of the valid path node if (validPaths[validPathId].pathElements.ElementAt(depth).linkGraphObject.possibleClasses.Contains(classToUse)) { // add current filler node to the list of possible exchange nodes if (!validPaths[validPathId].pathElements.ElementAt(depth).linkGraphObject.possibleExchangeObjects.Contains(currentNode.nodeObjects[idx])) { validPaths[validPathId].pathElements.ElementAt(depth).linkGraphObject.possibleExchangeObjects.Add(currentNode.nodeObjects[idx]); } } } } } this.fillNodesRecursively(currentNode.nodeObjects[idx], tempCurrentPosition, currentDepth + 1, maxDepth, allPossibleNodes, validPaths); } }
// dumps the rest of the graph recursively // IMPORTANT: will crash if a loop exists in the graph private void dumpGraphRecursively(System.IO.StreamWriter dotFile, NodeObject currentNode, String nodeName, bool dumpOnlyValidPath) { // write current node to file but only the valid path if (dumpOnlyValidPath) { if (currentNode.elementOfValidPath.Count() == 0) { return; } dotFile.WriteLine(nodeName + " [shape=record]"); dotFile.Write(nodeName + " [label=\"{"); dotFile.Write("Node: " + nodeName + "|"); dotFile.Write("Class: " + this.sanitizeString(currentNode.thisClass.ToString()) + "|"); String tempOutput = ""; foreach (PathElement pathElement in currentNode.pathElements) { tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.validInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("valid Interfaces (valid ID: " + pathElement.validPathId.ToString() + "): " + tempOutput + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.invalidInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("invalid Interfaces (valid ID: " + pathElement.validPathId.ToString() + "): " + tempOutput + "|"); } dotFile.Write("Constructor: " + this.makeFuncSigString(currentNode.constructorToUse) + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in currentNode.pathElements.ElementAt(0).mandatoryInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("mandatory Interfaces: " + tempOutput + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in currentNode.pathElements.ElementAt(0).forbiddenInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("forbidden Interfaces: " + tempOutput + "|"); tempOutput = ""; foreach (NamespaceTypeDefinition classInList in currentNode.possibleClasses) { tempOutput += this.sanitizeString(classInList.ToString()) + "; "; } dotFile.Write("possible Classes: " + tempOutput + "|"); String positionString = ""; foreach (int position in currentNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("Position: " + positionString + "|"); positionString = ""; foreach (NodeObject possibleNode in currentNode.possibleExchangeObjects) { positionString += "("; foreach (int position in possibleNode.positionInGraph) { positionString += position.ToString() + ";"; } positionString += ") "; } dotFile.Write("Possible exchange nodes: " + positionString + "|"); String validPathIdString = ""; foreach (int validPathId in currentNode.elementOfValidPath) { validPathIdString += validPathId.ToString() + ";"; } dotFile.Write("Valid Path Ids: " + validPathIdString); dotFile.WriteLine("}\"]"); for (int idx = 0; idx < currentNode.dimension; idx++) { // check if the tree is a complete tree if (currentNode.nodeObjects[idx] == null) { continue; } if (currentNode.nodeObjects[idx].elementOfValidPath.Count() != 0) { dotFile.WriteLine(nodeName + "-> " + nodeName + "_" + idx.ToString() + "[ color=\"green\" ]"); // dump rest of the graph recursively this.dumpGraphRecursively(dotFile, currentNode.nodeObjects[idx], nodeName + "_" + idx.ToString(), true); } } } // write current node to file with the whole graph else { dotFile.WriteLine(nodeName + " [shape=record]"); dotFile.Write(nodeName + " [label=\"{"); dotFile.Write("Node: " + nodeName + "|"); dotFile.Write("Class: " + this.sanitizeString(currentNode.thisClass.ToString()) + "|"); String tempOutput = ""; foreach (PathElement pathElement in currentNode.pathElements) { tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.validInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("valid Interfaces (valid ID: " + pathElement.validPathId.ToString() + "): " + tempOutput + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.invalidInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("invalid Interfaces (valid ID: " + pathElement.validPathId.ToString() + "): " + tempOutput + "|"); } dotFile.Write("Constructor: " + this.makeFuncSigString(currentNode.constructorToUse) + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in currentNode.pathElements.ElementAt(0).mandatoryInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("mandatory Interfaces: " + tempOutput + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in currentNode.pathElements.ElementAt(0).forbiddenInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("forbidden Interfaces: " + tempOutput + "|"); tempOutput = ""; foreach (NamespaceTypeDefinition classInList in currentNode.possibleClasses) { tempOutput += this.sanitizeString(classInList.ToString()) + "; "; } dotFile.Write("possible Classes: " + tempOutput + "|"); String positionString = ""; foreach (int position in currentNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("Position: " + positionString + "|"); positionString = ""; foreach (NodeObject possibleNode in currentNode.possibleExchangeObjects) { positionString += "("; foreach (int position in possibleNode.positionInGraph) { positionString += position.ToString() + ";"; } positionString += ") "; } dotFile.Write("Possible exchange nodes: " + positionString + "|"); String validPathIdString = ""; foreach (int validPathId in currentNode.elementOfValidPath) { validPathIdString += validPathId.ToString() + ";"; } dotFile.Write("Valid Path Ids: " + validPathIdString); dotFile.WriteLine("}\"]"); for (int idx = 0; idx < currentNode.dimension; idx++) { // check if the tree is a complete tree if (currentNode.nodeObjects[idx] == null) { continue; } if (currentNode.nodeObjects[idx].elementOfValidPath.Count() != 0) { dotFile.WriteLine(nodeName + "-> " + nodeName + "_" + idx.ToString() + "[ color=\"green\" ]"); } else { if (!dumpOnlyValidPath) { dotFile.WriteLine(nodeName + "-> " + nodeName + "_" + idx.ToString() + "[ color=\"red\" ]"); } } // dump rest of the graph recursively this.dumpGraphRecursively(dotFile, currentNode.nodeObjects[idx], nodeName + "_" + idx.ToString(), false); } } }
// dump graph to a .dot file // IMPORTANT: will crash if a loop exists in the graph public void dumpGraph(NodeObject startNode, String fileName, bool dumpOnlyValidPath) { // shorten file name if it is too long fileName = fileName.Length >= 230 ? fileName.Substring(0, 230) : fileName; // dump graph System.IO.StreamWriter dotFile = new System.IO.StreamWriter(this.logPath + "\\graph_" + fileName + ".dot"); // start .dot file graph dotFile.WriteLine("digraph G {"); // write start node to file but only the valid path String nodeName = "Node_0"; if (dumpOnlyValidPath) { if (startNode.elementOfValidPath.Count() != 0) { dotFile.WriteLine(nodeName + " [shape=record]"); dotFile.Write(nodeName + " [label=\"{"); dotFile.Write("Node: " + nodeName + "|"); dotFile.Write("Class: " + this.sanitizeString(startNode.thisClass.ToString()) + "|"); String tempOutput = ""; foreach(PathElement pathElement in startNode.pathElements) { tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.validInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("valid Interfaces (valid ID: " + pathElement.validPathId.ToString() + "): " + tempOutput + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.invalidInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("invalid Interfaces (valid ID: " + pathElement.validPathId.ToString() + "): " + tempOutput + "|"); } dotFile.Write("Constructor: " + this.makeFuncSigString(startNode.constructorToUse) + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in startNode.pathElements.ElementAt(0).mandatoryInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("mandatory Interfaces: " + tempOutput + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in startNode.pathElements.ElementAt(0).forbiddenInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("forbidden Interfaces: " + tempOutput + "|"); tempOutput = ""; foreach (NamespaceTypeDefinition classInList in startNode.possibleClasses) { tempOutput += this.sanitizeString(classInList.ToString()) + "; "; } dotFile.Write("possible Classes: " + tempOutput + "|"); String positionString = ""; foreach (int position in startNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("Position: " + positionString + "|"); positionString = ""; foreach (NodeObject possibleNode in startNode.possibleExchangeObjects) { positionString += "("; foreach (int position in possibleNode.positionInGraph) { positionString += position.ToString() + ";"; } positionString += ") "; } dotFile.Write("Possible exchange nodes: " + positionString + "|"); String validPathIdString = ""; foreach (int validPathId in startNode.elementOfValidPath) { validPathIdString += validPathId.ToString() + ";"; } dotFile.Write("Valid Path Ids: " + validPathIdString); dotFile.WriteLine("}\"]"); for (int idx = 0; idx < startNode.dimension; idx++) { // check if the tree is a complete tree if (startNode.nodeObjects[idx] == null) { continue; } if (startNode.nodeObjects[idx].elementOfValidPath.Count() != 0) { dotFile.WriteLine(nodeName + "-> " + nodeName + "_" + idx.ToString() + "[ color=\"green\" ]"); // dump rest of the graph recursively this.dumpGraphRecursively(dotFile, startNode.nodeObjects[idx], nodeName + "_" + idx.ToString(), true); } } } } // write start node to file with the whole graph else { dotFile.WriteLine(nodeName + " [shape=record]"); dotFile.Write(nodeName + " [label=\"{"); dotFile.Write("Node: " + nodeName + "|"); dotFile.Write("Class: " + this.sanitizeString(startNode.thisClass.ToString()) + "|"); String tempOutput = ""; foreach (PathElement pathElement in startNode.pathElements) { tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.validInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("valid Interfaces (valid ID: " + pathElement.validPathId.ToString() + "): " + tempOutput + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.invalidInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("invalid Interfaces (valid ID: " + pathElement.validPathId.ToString() + "): " + tempOutput + "|"); } dotFile.Write("Constructor: " + this.makeFuncSigString(startNode.constructorToUse) + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in startNode.pathElements.ElementAt(0).mandatoryInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("mandatory Interfaces: " + tempOutput + "|"); tempOutput = ""; foreach (ITypeReference interfaceInList in startNode.pathElements.ElementAt(0).forbiddenInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("forbidden Interfaces: " + tempOutput + "|"); tempOutput = ""; foreach (NamespaceTypeDefinition classInList in startNode.possibleClasses) { tempOutput += this.sanitizeString(classInList.ToString()) + "; "; } dotFile.Write("possible Classes: " + tempOutput + "|"); String positionString = ""; foreach (int position in startNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("Position: " + positionString + "|"); positionString = ""; foreach (NodeObject possibleNode in startNode.possibleExchangeObjects) { positionString += "("; foreach (int position in possibleNode.positionInGraph) { positionString += position.ToString() + ";"; } positionString += ") "; } dotFile.Write("Possible exchange nodes: " + positionString + "|"); String validPathIdString = ""; foreach (int validPathId in startNode.elementOfValidPath) { validPathIdString += validPathId.ToString() + ";"; } dotFile.Write("Valid Path Ids: " + validPathIdString); dotFile.WriteLine("}\"]"); for (int idx = 0; idx < startNode.dimension; idx++) { // check if the tree is a complete tree if (startNode.nodeObjects[idx] == null) { continue; } if (startNode.nodeObjects[idx].elementOfValidPath.Count() != 0) { dotFile.WriteLine(nodeName + "-> " + nodeName + "_" + idx.ToString() + "[ color=\"green\" ]"); } else { dotFile.WriteLine(nodeName + "-> " + nodeName + "_" + idx.ToString() + "[ color=\"red\" ]"); } // dump rest of the graph recursively this.dumpGraphRecursively(dotFile, startNode.nodeObjects[idx], nodeName + "_" + idx.ToString(), false); } } // finish graph dotFile.WriteLine("}"); dotFile.Close(); }
// builds a graph public void buildGraph(ValidGraphPath[] validPaths) { // check if at least one valid path is given int countValidPath = validPaths.Count(); if (countValidPath < 1) { throw new ArgumentException("At least 1 valid path have to be given."); } // check if the path has enough elements int maxDepth = this.graphDepth; if (maxDepth <= 1) { throw new ArgumentException("Path has to have at least 2 elements."); } // set needed attributes this.graphValidPathCount = countValidPath; // a list of all possible nodes for all graph elements List<PossibleNode> allPossibleNodes = new List<PossibleNode>(); // get a list of possible nodes that implement the first valid interface of the first node of the first valid path ITypeReference tempInterface = validPaths[0].pathElements[0].mandatoryInterfaces.ElementAt(0); List<PossibleNode> possibleNodes = new List<PossibleNode>((List<PossibleNode>)this.graphInterfaces[tempInterface]); List<PossibleNode> copiedList = new List<PossibleNode>(possibleNodes); foreach (PossibleNode possibleNode in copiedList) { // check if all needed interfaces (by all valid paths) are contained by the possible node // if not => remove if from the list of possible nodes bool validNode = true; foreach (ITypeReference neededInterface in validPaths[0].pathElements[0].mandatoryInterfaces) { if(!possibleNode.givenClass.Interfaces.Contains(neededInterface)) { validNode = false; break; } } if(!validNode) { possibleNodes.Remove(possibleNode); } // check if all forbidden interfaces (by all valid paths) are NOT contained by the possible node // if the possible node contains it => remove it from the list of possible nodes foreach (ITypeReference forbiddenInterface in validPaths[0].pathElements[0].forbiddenInterfaces) { if(possibleNode.givenClass.Interfaces.Contains(forbiddenInterface)) { validNode = false; break; } } if(!validNode) { possibleNodes.Remove(possibleNode); } } if (possibleNodes.Count() == 0) { throw new ArgumentException("No class was found which satisfies the given requirements."); } // add all possible nodes for this graph element to the list of all possible nodes allPossibleNodes.AddRange(possibleNodes); // get first random node of graph int randElement = this.prng.Next(possibleNodes.Count()); NamespaceTypeDefinition classToUse = possibleNodes.ElementAt(randElement).givenClass; MethodDefinition nodeConstructor = possibleNodes.ElementAt(randElement).nodeConstructor; // create start node of graph List<int> startPosition = new List<int>(); NodeObject startNode = new NodeObject(this.graphDimension, this.graphValidPathCount, classToUse, nodeConstructor, validPaths[0].pathElements[0], startPosition, 0); validPaths[0].pathElements[0].linkGraphObject = startNode; for (int validPathId = 1; validPathId < countValidPath; validPathId++) { startNode.elementOfValidPath.Add(validPathId); startNode.pathElements.Add(validPaths[validPathId].pathElements[0]); validPaths[validPathId].pathElements[0].linkGraphObject = startNode; } // add possible nodes to list of possible classes foreach (PossibleNode possibleNode in possibleNodes) { startNode.possibleClasses.Add(possibleNode.givenClass); } // build all valid paths for (int validPathId = 0; validPathId < countValidPath; validPathId++) { NodeObject currentNode = startNode; List<int> positionInGraph = new List<int>(); // build a random valid path for (int idx = 1; idx < maxDepth; idx++) { // get a list of possible nodes that implement the first valid interface of the first node of the first valid path tempInterface = validPaths[validPathId].pathElements[idx].mandatoryInterfaces.ElementAt(0); possibleNodes = new List<PossibleNode>((List<PossibleNode>)this.graphInterfaces[tempInterface]); // sort out nodes that do not satisfy all valid and invalid interface requirements of the node copiedList = new List<PossibleNode>(possibleNodes); foreach (PossibleNode possibleNode in copiedList) { // check if all needed interfaces (by all valid paths) are contained by the possible node // if not => remove if from the list of possible nodes bool validNode = true; foreach (ITypeReference neededInterface in validPaths[validPathId].pathElements[idx].mandatoryInterfaces) { if (!possibleNode.givenClass.Interfaces.Contains(neededInterface)) { validNode = false; break; } } if (!validNode) { possibleNodes.Remove(possibleNode); } // check if all forbidden interfaces (by all valid paths) are NOT contained by the possible node // if the possible node contains it => remove it from the list of possible nodes foreach (ITypeReference forbiddenInterface in validPaths[validPathId].pathElements[idx].forbiddenInterfaces) { if (possibleNode.givenClass.Interfaces.Contains(forbiddenInterface)) { validNode = false; break; } } if (!validNode) { possibleNodes.Remove(possibleNode); } } if (possibleNodes.Count() == 0) { throw new ArgumentException("No class was found which satisfies the given requirements."); } // add all distinct possible nodes for this graph element to the list of all possible nodes foreach (PossibleNode possibleNode in possibleNodes) { if (!allPossibleNodes.Contains(possibleNode)) { allPossibleNodes.Add(possibleNode); } } int pathIdx = validPaths[validPathId].pathIndices[idx]; if (currentNode.nodeObjects[pathIdx] != null) { // check if the used class of the node satisfy both paths NamespaceTypeDefinition usedClass = currentNode.nodeObjects[pathIdx].thisClass; bool validNode = false; foreach (PossibleNode possibleNode in possibleNodes) { if (usedClass == possibleNode.givenClass) { validNode = true; break; } } if (!validNode) { throw new ArgumentException("Node does not satisfy both valid paths."); } currentNode.nodeObjects[pathIdx].pathElements.Add(validPaths[validPathId].pathElements[idx]); currentNode.nodeObjects[pathIdx].elementOfValidPath.Add(validPathId); positionInGraph.Add(pathIdx); validPaths[validPathId].pathElements[idx].linkGraphObject = currentNode.nodeObjects[pathIdx]; } else { // add path index to the position and copy position list positionInGraph.Add(pathIdx); List<int> tempPositionInGraph = new List<int>(positionInGraph); // get random node for graph randElement = this.prng.Next(possibleNodes.Count()); classToUse = possibleNodes.ElementAt(randElement).givenClass; nodeConstructor = possibleNodes.ElementAt(randElement).nodeConstructor; currentNode.nodeObjects[pathIdx] = new NodeObject(this.graphDimension, this.graphValidPathCount, classToUse, nodeConstructor, validPaths[validPathId].pathElements[idx], tempPositionInGraph, validPathId); validPaths[validPathId].pathElements[idx].linkGraphObject = currentNode.nodeObjects[pathIdx]; // add possible nodes to list of possible classes foreach (PossibleNode possibleNode in possibleNodes) { currentNode.nodeObjects[pathIdx].possibleClasses.Add(possibleNode.givenClass); } } currentNode = currentNode.nodeObjects[pathIdx]; } } // fill the rest of the graph this.fillNodesRecursively(startNode, startPosition, 1, maxDepth, allPossibleNodes, validPaths); this.startingNode = startNode; }
// 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 searches for the next node of the given valid path id and the node idx for this node private void getNextNode(ref NodeObject nextNode, ref int nextNodeIdx, NodeObject[] currentNodes, int currentValidPathId) { // check if a child node exists // => if not set next node to starting node if (currentNodes[currentValidPathId].nodeObjects[0] == null) { nextNode = this.graph.startingNode; nextNodeIdx = this.prng.Next(this.graphDimension); } else { for (int i = 0; i < currentNodes[currentValidPathId].nodeObjects.Count(); i++) { // if the child node does not belong to a valid path // => skip it if (currentNodes[currentValidPathId].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 (currentNodes[currentValidPathId].nodeObjects[i].elementOfValidPath.Contains(currentValidPathId)) { nextNode = currentNodes[currentValidPathId].nodeObjects[i]; nextNodeIdx = i; break; } } } if (nextNode == null) { throw new ArgumentException("Not able to find correct child node."); } } }
// 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 injectMovePointerCode(CfgManipulator cfgManipulator, NodeObject sourceNode, BasicBlockGraphNodeLink targetLink, IBranchTarget entryBranch, LocalDefinition currentNodeLocal) { NodeObject targetNode = targetLink.graphNode; NodeObject currentNode = sourceNode; UnconditionalBranchTarget branchToManipulate = null; if ((entryBranch as UnconditionalBranchTarget) != null) { branchToManipulate = (entryBranch as UnconditionalBranchTarget); } else { throw new ArgumentException("Not yet implemented."); // TODO at the moment we assume unconditional branches as entry } // do nothing if the source node is already the same as the target node if (sourceNode == 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 (sourceNode.positionInGraph.Count() >= targetNode.positionInGraph.Count()) { goToStart = true; } else { for (int idx = 0; idx < sourceNode.positionInGraph.Count(); idx++) { if (sourceNode.positionInGraph.ElementAt(idx) != targetNode.positionInGraph.ElementAt(idx)) { goToStart = true; break; } } } // 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 (currentNode != 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, targetLink, currentNodeLocal, nextNodeIdx, true); cfgManipulator.insertBasicBlockBetweenBranch(branchToManipulate, injectedBasicBlock, injectedExitBranch); // 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 (currentNode.nodeObjects[nextNodeIdx] == null) { currentNode = this.graph.startingNode; } else { currentNode = currentNode.nodeObjects[nextNodeIdx]; } } // 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, targetLink, currentNodeLocal, nextNodeIdx, true); cfgManipulator.insertBasicBlockBetweenBranch(branchToManipulate, injectedBasicBlock, injectedExitBranch); // 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 (currentNode.nodeObjects[nextNodeIdx] == null) { currentNode = this.graph.startingNode; } else { currentNode = currentNode.nodeObjects[nextNodeIdx]; } } } // => 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 = sourceNode.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, targetLink, currentNodeLocal, targetNode.positionInGraph.ElementAt(idx), true); cfgManipulator.insertBasicBlockBetweenBranch(branchToManipulate, injectedBasicBlock, injectedExitBranch); // 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 (currentNode.nodeObjects[targetNode.positionInGraph.ElementAt(idx)] == null) { currentNode = this.graph.startingNode; } else { currentNode = currentNode.nodeObjects[targetNode.positionInGraph.ElementAt(idx)]; } } } // check if the final reached node is the same as the target node if (currentNode != targetNode) { throw new ArgumentException("Current node and target node are not the same."); } }
// this function adds recursively methods that adds the left and the right node to the current node in the graph // (and calls the next method that adds the left and right node) private MethodDefinition addNodeRecursively(NodeObject currentNode, int currentDepth, String newMethodName) { // create first parameter that is the current node in the graph List<IParameterDefinition> parameters = new List<IParameterDefinition>(); ParameterDefinition parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameters.Add(parameter); // create second parameter that is the current depth in the graph parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = host.PlatformType.SystemInt32; parameters.Add(parameter); // create method to add left and right node to the graph MethodDefinition newAddNodeMethod = this.helperClass.createNewMethod(newMethodName, this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO: method name // create body of method ILGenerator ilGenerator = new ILGenerator(this.host, newAddNodeMethod); // check if max depth of tree is reached ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldc_I4, this.graph.graphDepth); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Ceq); ILGeneratorLabel depthReachedBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Brfalse, depthReachedBranch); // set child nodes of this node MethodDefinition constructorToUse; for (int i = 0; i < this.graphDimension; i++) { // get constructor of the child node element constructorToUse = null; // check if the child node exists in the graph and the max depth is not yet reached if (currentNode.nodeObjects[i] == null && currentDepth != this.graph.graphDepth) { throw new ArgumentException("Given depth of graph is larger than the actual graph."); } else { // check if the child node does not exist // => use a random constructor node if (currentNode.nodeObjects[i] == null) { constructorToUse = currentNode.constructorToUse; // TODO: use random node constructor here } // else use constructor of given graph node else { constructorToUse = currentNode.nodeObjects[i].constructorToUse; } } // set child node ilGenerator.Emit(OperationCode.Ldarg_1); // current node from which the function is called ilGenerator.Emit(OperationCode.Ldarg_0); // needed as argument for the constructor ilGenerator.Emit(OperationCode.Newobj, constructorToUse); // iNode parameter ilGenerator.Emit(OperationCode.Ldc_I4, i); // index parameter ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); // get child node and set it recursively ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldarg_1); // current node from which the function is called ilGenerator.Emit(OperationCode.Ldc_I4, i); // index parameter ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldarg_2); // arg2 (current depth) + 1 ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Add); MethodDefinition newMethodToCall = null; if (currentDepth == this.graph.graphDepth) { newMethodToCall = newAddNodeMethod; // TODO: call random node generation method here } else { newMethodToCall = this.addNodeRecursively(currentNode.nodeObjects[i], currentDepth + 1, newMethodName + "_" + i.ToString()); // TODO: method name } ilGenerator.Emit(OperationCode.Callvirt, newMethodToCall); } ilGenerator.Emit(OperationCode.Ret); // set child nodes of this node to null ilGenerator.MarkLabel(depthReachedBranch); for (int i = 0; i < this.graphDimension; i++) { ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet); // iNode parameter ilGenerator.Emit(OperationCode.Ldc_I4, i); // index parameter ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); } ilGenerator.Emit(OperationCode.Ret); // generate body IMethodBody body = new ILGeneratorMethodBody(ilGenerator, true, 8, newAddNodeMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); newAddNodeMethod.Body = body; return newAddNodeMethod; }
public BasicBlockGraphNodeLink(NodeObject graphNode, int validPathId) { this.validPathId = validPathId; this.graphNode = graphNode; }