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 processExitBranchesIter(CfgManipulator cfgManipulator, GraphRandomStateGenerator randomStateGenerator, MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock startBasicBlock, LocalDefinition intStateLocal, LocalDefinition currentNodeLocal) { int currentValidPathId; // create a list of basic blocks that still have to be processed by the algorithm List<BasicBlock> basicBlocksToProcess = new List<BasicBlock>(methodCfg.basicBlocks); System.Console.WriteLine("Basic Blocks to process (Control Flow): " + basicBlocksToProcess.Count()); while (true) { List<BasicBlock> copiedList = new List<BasicBlock>(basicBlocksToProcess); foreach (BasicBlock currentBasicBlock in copiedList) { // get the metadata for the current basic block GraphTransformerMetadataBasicBlock metadata = null; for (int i = 0; i < currentBasicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((currentBasicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } metadata = (currentBasicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (metadata == null) { throw new ArgumentException("Not able to find metadata for current basic block."); } // remove currently processed basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); // check if the current exit branch is of type "no branch target" if (currentBasicBlock.exitBranch as NoBranchTarget != null) { NoBranchTarget introBranch = (NoBranchTarget)currentBasicBlock.exitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) int searchSementicId = introBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); if (searchSementicId != -1) { foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } } else { possibleTargetBasicBlocks.Add(introBranch.takenTarget); } // create a list of target basic blocks of this branch List<Target> listOfTargets = new List<Target>(); Target target = new Target(); target.basicBlock = introBranch.takenTarget; listOfTargets.Add(target); // generate code for the "state switch" BasicBlock stateBasicBlock = null; SwitchBranchTarget stateExitBranch = null; this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes); cfgManipulator.insertBasicBlockBetweenBranch(introBranch, stateBasicBlock, stateExitBranch, 0); // create for each valid path a branch in the switch statement of the "state switch" for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the current valid path id) if (currentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateExitBranch.takenTarget.Count() <= currentValidPathId) { stateExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); // set switch taken branch for current valid path id to the chosen branch target stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = currentValidPathId; // get the link from the current basic block to the obfuscation graph BasicBlockGraphNodeLink currentGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { currentGraphLink = tempLink; break; } } if (currentGraphLink == null) { throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id."); } // get the metadata for the target basic block GraphTransformerMetadataBasicBlock targetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (targetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the target basic block to the obfuscation graph BasicBlockGraphNodeLink targetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { targetGraphLink = tempLink; break; } } if (targetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // choose randomly to either just correct the pointer position or to inject a "state change" switch (this.prng.Next(this.stateChangeWeight)) { // case: "state change" case 0: case 1: case 2: case 3: case 4: case 5: { // generate code for the "state change" BasicBlock stateChangeBasicBlock = null; SwitchBranchTarget stateChangeExitBranch = null; this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal); cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0); // create for each valid path a branch in the switch statement of the "state change" for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the changed current valid path id) if (changedCurrentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) { stateChangeExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); // set switch taken branch for current valid path id to the chosen branch target stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateChangeExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = changedCurrentValidPathId; // get the metadata for the change target basic block GraphTransformerMetadataBasicBlock changeTargetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (changeTargetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the change target basic block to the obfuscation graph BasicBlockGraphNodeLink changeTargetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == changedCurrentValidPathId) { changeTargetGraphLink = tempLink; break; } } if (changeTargetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // correct the pointer position to the obfuscation graph this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } } break; } // case: correct pointer position default: { this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } break; } } } } // check if the current exit branch is of type "unconditional branch target" else if (currentBasicBlock.exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget introBranch = (UnconditionalBranchTarget)currentBasicBlock.exitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) int searchSementicId = introBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); if (searchSementicId != -1) { foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } } else { possibleTargetBasicBlocks.Add(introBranch.takenTarget); } // create a list of target basic blocks of this branch List<Target> listOfTargets = new List<Target>(); Target target = new Target(); target.basicBlock = introBranch.takenTarget; listOfTargets.Add(target); // generate code for the "state switch" BasicBlock stateBasicBlock = null; SwitchBranchTarget stateExitBranch = null; this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes); cfgManipulator.insertBasicBlockBetweenBranch(introBranch, stateBasicBlock, stateExitBranch, 0); // create for each valid path a branch in the switch statement of the "state switch" for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the current valid path id) if (currentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateExitBranch.takenTarget.Count() <= currentValidPathId) { stateExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); //set switch taken branch for current valid path id to the chosen branch target stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = currentValidPathId; // get the link from the current basic block to the obfuscation graph BasicBlockGraphNodeLink currentGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { currentGraphLink = tempLink; break; } } if (currentGraphLink == null) { throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id."); } // get the metadata for the target basic block GraphTransformerMetadataBasicBlock targetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (targetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the target basic block to the obfuscation graph BasicBlockGraphNodeLink targetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { targetGraphLink = tempLink; break; } } if (targetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // choose randomly to either just correct the pointer position or to inject a "state change" switch (this.prng.Next(this.stateChangeWeight)) { // case: "state change" case 0: case 1: case 2: case 3: case 4: case 5: { // generate code for the "state change" BasicBlock stateChangeBasicBlock = null; SwitchBranchTarget stateChangeExitBranch = null; this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal); cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0); // create for each valid path a branch in the switch statement of the "state change" for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the changed current valid path id) if (changedCurrentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) { stateChangeExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); // set switch taken branch for current valid path id to the chosen branch target stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateChangeExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = changedCurrentValidPathId; // get the metadata for the change target basic block GraphTransformerMetadataBasicBlock changeTargetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (changeTargetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the change target basic block to the obfuscation graph BasicBlockGraphNodeLink changeTargetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == changedCurrentValidPathId) { changeTargetGraphLink = tempLink; break; } } if (changeTargetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // correct the pointer position to the obfuscation graph this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } } break; } // case: correct pointer position default: { this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } break; } } } } // check if the current exit branch is of type "conditional branch target" else if (currentBasicBlock.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget introBranch = (ConditionalBranchTarget)currentBasicBlock.exitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) int searchSementicId = introBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); if (searchSementicId != -1) { foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } } else { possibleTargetBasicBlocks.Add(introBranch.takenTarget); } // create a list of target basic blocks of this branch List<Target> listOfTargets = new List<Target>(); Target target = new Target(); target.basicBlock = introBranch.takenTarget; listOfTargets.Add(target); // generate code for the "state switch" BasicBlock stateBasicBlock = null; SwitchBranchTarget stateExitBranch = null; this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes); cfgManipulator.insertBasicBlockBetweenBranch(introBranch, true, stateBasicBlock, stateExitBranch, 0); // create for each valid path a branch in the switch statement of the "state switch" for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the current valid path id) if (currentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateExitBranch.takenTarget.Count() <= currentValidPathId) { stateExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); //set switch taken branch for current valid path id to the chosen branch target stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = currentValidPathId; // get the link from the current basic block to the obfuscation graph BasicBlockGraphNodeLink currentGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { currentGraphLink = tempLink; break; } } if (currentGraphLink == null) { throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id."); } // get the metadata for the target basic block GraphTransformerMetadataBasicBlock targetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (targetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the target basic block to the obfuscation graph BasicBlockGraphNodeLink targetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { targetGraphLink = tempLink; break; } } if (targetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // choose randomly to either just correct the pointer position or to inject a "state change" switch (this.prng.Next(this.stateChangeWeight)) { // case: "state change" case 0: case 1: case 2: case 3: case 4: case 5: { // generate code for the "state change" BasicBlock stateChangeBasicBlock = null; SwitchBranchTarget stateChangeExitBranch = null; this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal); cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0); // create for each valid path a branch in the switch statement of the "state change" for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the changed current valid path id) if (changedCurrentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) { stateChangeExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); // set switch taken branch for current valid path id to the chosen branch target stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateChangeExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = changedCurrentValidPathId; // get the metadata for the change target basic block GraphTransformerMetadataBasicBlock changeTargetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (changeTargetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the change target basic block to the obfuscation graph BasicBlockGraphNodeLink changeTargetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == changedCurrentValidPathId) { changeTargetGraphLink = tempLink; break; } } if (changeTargetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // correct the pointer position to the obfuscation graph this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } } break; } // case: correct pointer position default: { this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } break; } } } // search for all semantically equal basic blocks in the modified method CFG (as possible targets) searchSementicId = introBranch.notTakenTarget.semanticId; possibleTargetBasicBlocks = new List<BasicBlock>(); if (searchSementicId != -1) { foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } } else { possibleTargetBasicBlocks.Add(introBranch.notTakenTarget); } // create a list of target basic blocks of this branch listOfTargets = new List<Target>(); target = new Target(); target.basicBlock = introBranch.notTakenTarget; listOfTargets.Add(target); // generate code for the "state switch" stateBasicBlock = null; stateExitBranch = null; this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes); cfgManipulator.insertBasicBlockBetweenBranch(introBranch, false, stateBasicBlock, stateExitBranch, 0); // create for each valid path a branch in the switch statement of the "state switch" for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the current valid path id) if (currentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateExitBranch.takenTarget.Count() <= currentValidPathId) { stateExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); //set switch taken branch for current valid path id to the chosen branch target stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = currentValidPathId; // get the link from the current basic block to the obfuscation graph BasicBlockGraphNodeLink currentGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { currentGraphLink = tempLink; break; } } if (currentGraphLink == null) { throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id."); } // get the metadata for the target basic block GraphTransformerMetadataBasicBlock targetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (targetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the target basic block to the obfuscation graph BasicBlockGraphNodeLink targetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == currentValidPathId) { targetGraphLink = tempLink; break; } } if (targetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // choose randomly to either just correct the pointer position or to inject a "state change" switch (this.prng.Next(this.stateChangeWeight)) { // case: "state change" case 0: case 1: case 2: case 3: case 4: case 5: { // generate code for the "state change" BasicBlock stateChangeBasicBlock = null; SwitchBranchTarget stateChangeExitBranch = null; this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal); cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0); // create for each valid path a branch in the switch statement of the "state change" for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) { // ignore first valid path (with id 0) // => add artificial branch to original branch target (for the changed current valid path id) if (changedCurrentValidPathId != 0) { // fill switch taken branch list with null when index is out of range while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) { stateChangeExitBranch.takenTarget.Add(null); } // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption) switch (this.prng.Next(this.duplicateBasicBlockWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // duplicate the target basic block BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock); methodCfg.basicBlocks.Add(duplicatedBasicBlock); basicBlocksToProcess.Add(duplicatedBasicBlock); // add new basic block as target of the switch case stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock; duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch); // add new basic block to the list of target basic blocks target = new Target(); target.basicBlock = duplicatedBasicBlock; listOfTargets.Add(target); // add duplicated basic block to the list of possible target basic blocks possibleTargetBasicBlocks.Add(duplicatedBasicBlock); // create metadata for the newly created basic block if (!createAndAddMetadata(duplicatedBasicBlock)) { throw new ArgumentException("Creating metadata for the duplicated basic block failed."); } break; } default: { // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition); target = new Target(); target.basicBlock = newTarget; listOfTargets.Add(target); // set switch taken branch for current valid path id to the chosen branch target stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock; target.basicBlock.entryBranches.Add(stateChangeExitBranch); break; } } } // set current valid path id of the target target.currentValidPathId = changedCurrentValidPathId; // get the metadata for the change target basic block GraphTransformerMetadataBasicBlock changeTargetMetadata = null; for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) { continue; } changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock); break; } if (changeTargetMetadata == null) { throw new ArgumentException("Not able to find metadata for target basic block."); } // get the link from the change target basic block to the obfuscation graph BasicBlockGraphNodeLink changeTargetGraphLink = null; foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) { if (tempLink.validPathId == changedCurrentValidPathId) { changeTargetGraphLink = tempLink; break; } } if (changeTargetGraphLink == null) { throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id."); } // correct the pointer position to the obfuscation graph this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } } break; } // case: correct pointer position default: { this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal); // if debugging is activated => dump method cfg and add code to dump current graph if (this.debugging) { List<IOperation> debugOperations = new List<IOperation>(); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method))); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); target.basicBlock.operations.InsertRange(0, debugOperations); //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } break; } } } } // check if the current exit branch is of type "try block target" else if (currentBasicBlock.exitBranch as TryBlockTarget != null) { throw new ArgumentException("Not yet implemented."); } // check if the current exit branch is of type "switch branch target" else if (currentBasicBlock.exitBranch as SwitchBranchTarget != null) { throw new ArgumentException("Not yet implemented."); } // check if the current exit branch is of type "exception branch target" else if (currentBasicBlock.exitBranch as ExceptionBranchTarget != null) { throw new ArgumentException("Not yet implemented."); } // check if the current exit branch is of type "exit branch target" else if (currentBasicBlock.exitBranch as ExitBranchTarget != null) { continue; } // check if the current exit branch is of type "throw branch target" else if (currentBasicBlock.exitBranch as ThrowBranchTarget != null) { continue; } // this case should never be reached else { throw new ArgumentException("Do not know how to handle branch."); } } System.Console.WriteLine("Basic Blocks to process (Control Flow): " + basicBlocksToProcess.Count()); // check if basic blocks exist to process => if not break loop if (basicBlocksToProcess.Count() == 0) { break; } // adjust probability to duplicate basic blocks (each processing round the probability drops to duplicate a basic block) this.duplicateBasicBlockWeight += this.duplicateBasicBlockCorrectionValue; // adjust probability to insert a state change (each processing round the probability drops to insert a state change) this.stateChangeWeight += this.stateChangeCorrectionValue; } }
private void addMetadataIter(CfgManipulator cfgManipulator, GraphRandomStateGenerator randomStateGenerator, MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock startBasicBlock, LocalDefinition intStateLocal, LocalDefinition currentNodeLocal) { int currentValidPathId; // create transformation metadata for the start basic block GraphTransformerMetadataBasicBlock metadata = new GraphTransformerMetadataBasicBlock(); for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) { BasicBlockGraphNodeLink link = new BasicBlockGraphNodeLink(this.graph.startingNode, currentValidPathId); metadata.correspondingGraphNodes.Add(link); } startBasicBlock.transformationMetadata.Add(metadata); // create a list of basic blocks that still have to be processed by the algorithm List<BasicBlock> basicBlocksToProcess = new List<BasicBlock>(methodCfg.basicBlocks); basicBlocksToProcess.Remove(startBasicBlock); System.Console.WriteLine("Basic Blocks to process (Metadata): " + basicBlocksToProcess.Count()); // add metadata to all basic blocks while (true) { List<BasicBlock> copiedList = new List<BasicBlock>(basicBlocksToProcess); foreach (BasicBlock currentBasicBlock in copiedList) { // check if the current basic block was already visited => it is already used for the graph obfuscation => skip it bool hasGraphMetadata = false; for (int i = 0; i < currentBasicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((currentBasicBlock.transformationMetadata.ElementAt(i) as IGraphTransformerMetadata) == null) { continue; } hasGraphMetadata = true; break; } if (hasGraphMetadata) { basicBlocksToProcess.Remove(currentBasicBlock); continue; } if (!this.createAndAddMetadata(currentBasicBlock)) { continue; } // remove current basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); } System.Console.WriteLine("Basic Blocks to process (Metadata): " + basicBlocksToProcess.Count()); // check if basic blocks exist to process => if not break loop if (basicBlocksToProcess.Count() == 0) { break; } } }
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; }
// 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; }