public CfgManipulator(IModule module, PeReader.DefaultHost host, Log.Log logger, MethodCfg methodCfg) { this.host = host; this.logger = logger; this.module = module; this.methodCfg = methodCfg; }
// adds a nop instruction after every instruction in the given method cfg public void addNopsToCfg(MethodCfg methodCfg) { foreach (BasicBlock tempBB in methodCfg.basicBlocks) { List<IOperation> newOperations = new List<IOperation>(); for (int idx = 0; idx < tempBB.operations.Count(); idx++) { IOperation currentOperation = tempBB.operations.ElementAt(idx); // copy current operation to new operations list newOperations.Add(currentOperation); if (idx == tempBB.operations.Count() - 1) { break; } // ignore all prefixes (because nop after prefix will crash the program) if (currentOperation.OperationCode == OperationCode.No_ || currentOperation.OperationCode == OperationCode.Constrained_ || currentOperation.OperationCode == OperationCode.Readonly_ || currentOperation.OperationCode == OperationCode.Tail_ || currentOperation.OperationCode == OperationCode.Unaligned_ || currentOperation.OperationCode == OperationCode.Volatile_) { continue; } InternalOperation newNopOperation = new InternalOperation(); newNopOperation.OperationCode = OperationCode.Nop; // add nop operation after current one newOperations.Add(newNopOperation); } // replace old operations with new ones tempBB.operations = newOperations; } }
public GraphRandomStateGenerator(IModule module, PeReader.DefaultHost host, Log.Log logger, CfgManipulator cfgManipulator, Helper helperClass, Graph.Graph graph, MethodCfg methodCfg, bool debugging) { this.module = module; this.host = host; this.logger = logger; this.cfgManipulator = cfgManipulator; this.helperClass = helperClass; this.graph = graph; this.methodCfg = methodCfg; this.debugging = debugging; // add local random generator variable this.tempRandomLocal = new LocalDefinition(); this.tempRandomLocal.IsReference = false; this.tempRandomLocal.IsPinned = false; this.tempRandomLocal.IsModified = false; this.tempRandomLocal.Type = this.helperClass.systemRandom; this.tempRandomLocal.MethodDefinition = methodCfg.method; cfgManipulator.addLocalVariable(this.tempRandomLocal); }
// build recursively the cfg of the given operations private void buildRecursivelyCfg(MethodCfg methodCfg, IEnumerable<IOperation> operations, int currentIdx, IBranchTarget entryBranch, ref BasicBlock currentBasicBlock) { // check if a new basic block has to be created for (int bbIdx = 0; bbIdx < methodCfg.basicBlocks.Count(); bbIdx++) { // check if the current index points into an existing basic block // => split basic block BasicBlock tempBB = methodCfg.basicBlocks.ElementAt(bbIdx); if (tempBB.startIdx < currentIdx && tempBB.endIdx >= currentIdx) { // create new basic block which will be the second half of the found one BasicBlock newBasicBlock = new BasicBlock(this.semanticId); this.semanticId++; newBasicBlock.startIdx = currentIdx; newBasicBlock.endIdx = tempBB.endIdx; tempBB.endIdx = currentIdx - 1; // move the exit basic blocks to the new created basic block // and make the new created basic block the exit of the splitted one newBasicBlock.exitBranch = tempBB.exitBranch; newBasicBlock.exitBranch.sourceBasicBlock = newBasicBlock; NoBranchTarget tempExitBranch = new NoBranchTarget(); tempExitBranch.takenTarget = newBasicBlock; tempExitBranch.sourceBasicBlock = tempBB; tempBB.exitBranch = tempExitBranch; // set the current basic block to the new created basic block currentBasicBlock = newBasicBlock; // add splitted basic block branch and basic block branch that leads to this split // to the entries of the new one newBasicBlock.entryBranches.Add(entryBranch); newBasicBlock.entryBranches.Add(tempExitBranch); // distribute the instructions to the basic blocks List<IOperation> previousOperations = new List<IOperation>(); List<IOperation> nextOperations = new List<IOperation>(); for (int operationIdx = 0; (operationIdx + tempBB.startIdx) <= newBasicBlock.endIdx; operationIdx++) { if ((operationIdx + tempBB.startIdx) < currentIdx) { previousOperations.Add(tempBB.operations.ElementAt(operationIdx)); } else { nextOperations.Add(tempBB.operations.ElementAt(operationIdx)); } } tempBB.operations = previousOperations; newBasicBlock.operations = nextOperations; // add new basic block to the cfg methodCfg.basicBlocks.Add(newBasicBlock); return; } // if the current index of the operation points to the start index of an existing basic block // => update entry branches else if (tempBB.startIdx == currentIdx && entryBranch != null && currentBasicBlock != null) { tempBB.entryBranches.Add(entryBranch); // set the found basic block as the current basic block currentBasicBlock = tempBB; return; } // if the current index of the operation points to the start index of an existing basic block, has no entry branch // and is not the first instruction // set the current basic block to the found one else if (currentIdx != 0 && tempBB.startIdx == currentIdx && currentBasicBlock != null) { // set the found basic block as the current basic block currentBasicBlock = tempBB; return; } } // set index of current basic block and add it to the cfg currentBasicBlock.startIdx = currentIdx; methodCfg.basicBlocks.Add(currentBasicBlock); // check if the basic block was jumped to from another basic block // => update entry branches if (entryBranch != null) { currentBasicBlock.entryBranches.Add(entryBranch); } // parse every instruction to find branches etc for (int idx = currentIdx; idx < operations.Count(); idx++) { // check if the current instruction is the start instruction of an already existing basic block (except the current basic block) // => add the current basic block to the list of entry basic blocks, the found basic block to the list of exit basic blocks and set the index for (int bbIdx = 0; bbIdx < methodCfg.basicBlocks.Count(); bbIdx++) { BasicBlock tempBB = methodCfg.basicBlocks.ElementAt(bbIdx); if (tempBB.startIdx == idx && tempBB != currentBasicBlock) { currentBasicBlock.endIdx = idx - 1; // create new exit branch and add it NoBranchTarget currentExitBranch = new NoBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.takenTarget = tempBB; currentBasicBlock.exitBranch = currentExitBranch; // add current exit branch as entry for the found one tempBB.entryBranches.Add(currentExitBranch); return; } } // add current instruction to the basic block var operation = operations.ElementAt(idx); currentBasicBlock.operations.Add(operation); // check for special instructions like branches switch (operation.OperationCode) { // conditional branch instructions case OperationCode.Beq: case OperationCode.Bge: case OperationCode.Bge_Un: case OperationCode.Bgt: case OperationCode.Bgt_Un: case OperationCode.Ble: case OperationCode.Ble_Un: case OperationCode.Blt: case OperationCode.Blt_Un: case OperationCode.Bne_Un: case OperationCode.Brfalse: case OperationCode.Brtrue: case OperationCode.Beq_S: case OperationCode.Bge_S: case OperationCode.Bge_Un_S: case OperationCode.Bgt_S: case OperationCode.Bgt_Un_S: case OperationCode.Ble_S: case OperationCode.Ble_Un_S: case OperationCode.Blt_S: case OperationCode.Blt_Un_S: case OperationCode.Bne_Un_S: case OperationCode.Brfalse_S: case OperationCode.Brtrue_S: { // the current basic block ends here currentBasicBlock.endIdx = idx; // calculate the target index of the branch int branchTargetIdx = 0; uint branchTargetOffset; // do operation value can be of type long which can not be casted in this way if (operation.Value is long) { branchTargetOffset = Convert.ToUInt32(operation.Value); } else { branchTargetOffset = (uint)operation.Value; } while (true) { if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) { break; } else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) { throw new ArgumentException("Could not find target off branch."); } branchTargetIdx++; } // create new exit branch object ConditionalBranchTarget currentExitBranch = new ConditionalBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.notTakenTarget = new BasicBlock(this.semanticId); this.semanticId++; currentExitBranch.takenTarget = new BasicBlock(this.semanticId); this.semanticId++; currentBasicBlock.exitBranch = currentExitBranch; // start two new basic blocks from this branch on and end current execution this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.notTakenTarget); this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.takenTarget); return; } // unconditional branch instructions case OperationCode.Br: case OperationCode.Br_S: { // the current basic block ends here currentBasicBlock.endIdx = idx; // calculate the target index of the branch int branchTargetIdx = 0; uint branchTargetOffset = (uint)operation.Value; while (true) { if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) { break; } else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) { throw new ArgumentException("Could not find target off branch."); } branchTargetIdx++; } // create new exit branch object UnconditionalBranchTarget currentExitBranch = new UnconditionalBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.takenTarget = new BasicBlock(this.semanticId); this.semanticId++; currentBasicBlock.exitBranch = currentExitBranch; // start one new basic block from this branch on and end current execution this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.takenTarget); return; } // exit operation case OperationCode.Ret: { // the current basic block ends here currentBasicBlock.endIdx = idx; // create new exit branch object ExitBranchTarget currentExitBranch = new ExitBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentBasicBlock.exitBranch = currentExitBranch; // end current execution return; } // operations that exit the current function/control flow case OperationCode.Throw: { // the current basic block ends here currentBasicBlock.endIdx = idx; // create new exit branch object ThrowBranchTarget currentExitBranch = new ThrowBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentBasicBlock.exitBranch = currentExitBranch; // start a new basic block if this was not the last instruction of the method // (needed because some control flows that are reached via throw are not found without it) if ((idx + 1) < operations.Count()) { BasicBlock newStartBasicBlock = new BasicBlock(this.semanticId); this.semanticId++; this.buildRecursivelyCfg(methodCfg, operations, idx + 1, null, ref newStartBasicBlock); } // end current execution return; } // switch instruction (has a variable set of jump targets) case OperationCode.Switch: { // the current basic block ends here currentBasicBlock.endIdx = idx; // create new exit branch object SwitchBranchTarget currentExitBranch = new SwitchBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.notTakenTarget = new BasicBlock(this.semanticId); this.semanticId++; currentBasicBlock.exitBranch = currentExitBranch; // calculate the target index of all switch branches int counter = 0; foreach (uint branchTargetOffset in (uint[])operation.Value) { int branchTargetIdx = 0; while (true) { if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) { break; } else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) { throw new ArgumentException("Could not find target off branch."); } branchTargetIdx++; } // start a new basic block from this branch on BasicBlock tempNextBasicBlock = new BasicBlock(this.semanticId); this.semanticId++; this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref tempNextBasicBlock); // add new basic block to branch targets currentExitBranch.takenTarget.Add(tempNextBasicBlock); counter++; } // start a new basic block directly after the switch instruction and end current execution this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.notTakenTarget); return; } // exception handler beginning or end (end of try block or catch block) case OperationCode.Leave: case OperationCode.Leave_S: { // the current basic block ends here currentBasicBlock.endIdx = idx; // calculate the target index of the branch int branchTargetIdx = 0; uint branchTargetOffset = (uint)operation.Value; while (true) { if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) { break; } else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) { throw new ArgumentException("Could not find target off branch."); } branchTargetIdx++; } // create new exit branch object ExceptionBranchTarget currentExitBranch = new ExceptionBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.exceptionTarget = new BasicBlock(this.semanticId); this.semanticId++; currentExitBranch.exitTarget = new BasicBlock(this.semanticId); this.semanticId++; currentBasicBlock.exitBranch = currentExitBranch; // start two new basic blocks from this branch on and end current execution this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.exceptionTarget); this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.exitTarget); return; } // create a virtual basic block at the end of a catch/finally handler case OperationCode.Rethrow: case OperationCode.Endfinally: { // the current basic block ends here currentBasicBlock.endIdx = idx; // create new exit branch object NoBranchTarget currentExitBranch = new NoBranchTarget(); currentExitBranch.sourceBasicBlock = currentBasicBlock; currentExitBranch.takenTarget = new BasicBlock(this.semanticId); this.semanticId++; currentBasicBlock.exitBranch = currentExitBranch; // start a new basic block from this branch on and end current execution this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.takenTarget); return; } default: break; } } }
// creates a method for a given method CFG (IMPORTANT: it updates the operations // and exception handlers of the existing method, does not create a new method) public void createMethodFromCfg(MethodCfg methodCfg) { // list of basic blocks that belong together logically (i.e. BB2 lies directly behind BB1 because it reaches it without a branch) IList<BasicBlockUnion> basicBlockUnions = new List<BasicBlockUnion>(); // first step: create basic block unions // create first basic block union starting from the start basic block BasicBlockUnion firstBasicBlockUnion = new BasicBlockUnion(); this.createRecursivelyBasicBlockUnion(basicBlockUnions, firstBasicBlockUnion, methodCfg.startBasicBlock); basicBlockUnions.Add(firstBasicBlockUnion); // create basic block unions for the rest of the basic blocks foreach (BasicBlock tempBB in methodCfg.basicBlocks) { // create a basic block union (if basic block is not contained by another existing basic block union) BasicBlockUnion basicBlockUnion = new BasicBlockUnion(); this.createRecursivelyBasicBlockUnion(basicBlockUnions, basicBlockUnion, tempBB); // if the newly created basic block union contains basic blocks // => add to list of basic block unions if (basicBlockUnion.basicBlocks.Count() != 0) { basicBlockUnions.Add(basicBlockUnion); } } // step two: merge basic block unions with respect to the exception handler foreach (OperationExceptionInformation exceptionHandler in methodCfg.method.Body.OperationExceptionInformation) { // create a temporary object to reorder the basic block unions with respect to the exception handler BasicBlockUnionExceptionHandlerOrder tempNewOrder = new BasicBlockUnionExceptionHandlerOrder(); tempNewOrder.exceptionHandler = exceptionHandler; // find all basic blocks that are connected to the current exception handler foreach (BasicBlockUnion basicBlockUnion in basicBlockUnions) { foreach (BasicBlock basicBlock in basicBlockUnion.basicBlocks) { // ignore all basic blocks that do not have any try/catch/finally handler in it if (basicBlock.tryBlocks.Count() == 0 && basicBlock.handlerBlocks.Count() == 0) { continue; } // find the try block that is connected to the current exception handler foreach (TryBlock tryBlock in basicBlock.tryBlocks) { // ignore try blocks that do not belong to the current exception handler if (tryBlock.exceptionHandler != exceptionHandler) { continue; } // check if basic block union already resides in try body // if not => add to try body if (!tempNewOrder.tryBody.Contains(basicBlockUnion)) { tempNewOrder.tryBody.Add(basicBlockUnion); } // check if the basic block starts the try block if (tryBlock.firstBasicBlockOfTryBlock) { tempNewOrder.tryStart = basicBlockUnion; } // check if the basic block ends the try block if (tryBlock.lastBasicBlockOfTryBlock) { tempNewOrder.tryEnd = basicBlockUnion; } } // find the handler block that is connected to the current exception handler foreach (HandlerBlock handlerBlock in basicBlock.handlerBlocks) { // ignore handler blocks that do not belong to the current exception handler if (handlerBlock.exceptionHandler != exceptionHandler) { continue; } // check if basic block union already resides in handler body // if not => add to handler body if (!tempNewOrder.handlerBody.Contains(basicBlockUnion)) { tempNewOrder.handlerBody.Add(basicBlockUnion); } // check if the basic block starts the handler block if (handlerBlock.firstBasicBlockOfHandlerBlock) { tempNewOrder.handlerStart = basicBlockUnion; } // check if the basic block ends the handler block if (handlerBlock.lastBasicBlockOfHandlerBlock) { tempNewOrder.handlerEnd = basicBlockUnion; } } } } if (tempNewOrder.tryStart == null || tempNewOrder.tryEnd == null || tempNewOrder.handlerStart == null || tempNewOrder.handlerEnd == null) { throw new ArgumentException("Could not find all try/catch beginnings/ends."); } // merge basic block unions with respect to the current exception handler // check if the complete exception handling is done in only one basic block union // => ignore it if (tempNewOrder.tryStart == tempNewOrder.tryEnd && tempNewOrder.handlerStart == tempNewOrder.handlerEnd && tempNewOrder.tryStart == tempNewOrder.handlerStart) { continue; } // if not everything lies in the same basic block union // extend the basic block union that starts the try block BasicBlockUnion extendedUnion = tempNewOrder.tryStart; // if try block start and end are the same => nothing to merge // else merge the basic block unions if (tempNewOrder.tryStart != tempNewOrder.tryEnd) { foreach (BasicBlockUnion tryBodyBasicBlockUnion in tempNewOrder.tryBody) { // ignore the basic block union that starts the try block (already in extended union) // and ignore the basic block union that ends the try block (is added last) if (tryBodyBasicBlockUnion == tempNewOrder.tryStart || tryBodyBasicBlockUnion == tempNewOrder.tryEnd) { continue; } // extend first basic block union with the basic block union of the // try block body and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(tryBodyBasicBlockUnion.basicBlocks); basicBlockUnions.Remove(tryBodyBasicBlockUnion); } // extend first basic block union with the basic block union of the // try block end and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(tempNewOrder.tryEnd.basicBlocks); basicBlockUnions.Remove(tempNewOrder.tryEnd); } // if the try block end and the handler block start are not the same basic block union // => merge the union of the handler block start to the current basic block union if (tempNewOrder.tryEnd != tempNewOrder.handlerStart) { extendedUnion.basicBlocks.AddRange(tempNewOrder.handlerStart.basicBlocks); basicBlockUnions.Remove(tempNewOrder.handlerStart); } // if handler block start and end are the same => nothing to merge // else merge the basic block unions if (tempNewOrder.handlerStart != tempNewOrder.handlerEnd) { foreach (BasicBlockUnion handlerBodyBasicBlockUnion in tempNewOrder.handlerBody) { // ignore the basic block union that starts the handler block (already in extended union) // and ignore the basic block union that ends the handler block (is added last) if (handlerBodyBasicBlockUnion == tempNewOrder.handlerStart || handlerBodyBasicBlockUnion == tempNewOrder.handlerEnd) { continue; } // add basic block union of the handler block body to the extended basic block union // and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(handlerBodyBasicBlockUnion.basicBlocks); basicBlockUnions.Remove(handlerBodyBasicBlockUnion); } // extend the extended basic block union with the basic block union of the // handler block end and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(tempNewOrder.handlerEnd.basicBlocks); basicBlockUnions.Remove(tempNewOrder.handlerEnd); } } // step three: create one list of operations and modify jump offsets // create a list of operations from the basic blocks, // update basic block start/end indices accordingly // and update the offsets of the operations (needed to update branch operations) IList<IOperation> methodOperations = new List<IOperation>(); int operationIdx = 0; uint currentOffset = 0; foreach (BasicBlockUnion basicBlockUnion in basicBlockUnions) { foreach (BasicBlock basicBlock in basicBlockUnion.basicBlocks) { basicBlock.startIdx = operationIdx; //foreach (IOperation operation in basicBlock.operations) { for (int opIdx = 0; opIdx < basicBlock.operations.Count(); opIdx++) { IOperation operation = basicBlock.operations.ElementAt(opIdx); // a new operation object is needed because the old operations // are read only due to cci InternalOperation newOperation = new InternalOperation(); // exchange every short instruction with its larger one switch (operation.OperationCode) { case OperationCode.Beq_S: newOperation.OperationCode = OperationCode.Beq; break; case OperationCode.Bge_S: newOperation.OperationCode = OperationCode.Bge; break; case OperationCode.Bge_Un_S: newOperation.OperationCode = OperationCode.Bge_Un; break; case OperationCode.Bgt_S: newOperation.OperationCode = OperationCode.Bgt; break; case OperationCode.Bgt_Un_S: newOperation.OperationCode = OperationCode.Bgt_Un; break; case OperationCode.Ble_S: newOperation.OperationCode = OperationCode.Ble; break; case OperationCode.Ble_Un_S: newOperation.OperationCode = OperationCode.Ble_Un; break; case OperationCode.Blt_S: newOperation.OperationCode = OperationCode.Blt; break; case OperationCode.Blt_Un_S: newOperation.OperationCode = OperationCode.Blt_Un; break; case OperationCode.Bne_Un_S: newOperation.OperationCode = OperationCode.Bne_Un; break; case OperationCode.Br_S: newOperation.OperationCode = OperationCode.Br; break; case OperationCode.Brfalse_S: newOperation.OperationCode = OperationCode.Brfalse; break; case OperationCode.Brtrue_S: newOperation.OperationCode = OperationCode.Brtrue; break; case OperationCode.Ldarg_S: newOperation.OperationCode = OperationCode.Ldarg; break; case OperationCode.Ldarga_S: newOperation.OperationCode = OperationCode.Ldarga; break; case OperationCode.Ldc_I4_S: newOperation.OperationCode = OperationCode.Ldc_I4; break; case OperationCode.Ldloc_S: newOperation.OperationCode = OperationCode.Ldloc; break; case OperationCode.Ldloca_S: newOperation.OperationCode = OperationCode.Ldloca; break; case OperationCode.Leave_S: newOperation.OperationCode = OperationCode.Leave; break; case OperationCode.Starg_S: newOperation.OperationCode = OperationCode.Starg; break; case OperationCode.Stloc_S: newOperation.OperationCode = OperationCode.Stloc; break; default: newOperation.OperationCode = operation.OperationCode; break; } newOperation.Value = operation.Value; newOperation.Location = operation.Location; newOperation.Offset = currentOffset; methodOperations.Add(newOperation); // replace old operation in basic block with newly created one basicBlock.operations[opIdx] = newOperation; operationIdx++; currentOffset += CfgBuilder.getSizeOfOperation(newOperation); } basicBlock.endIdx = operationIdx - 1; } } // step four: update branches with new target offsets foreach (BasicBlock tempBB in methodCfg.basicBlocks) { InternalOperation branchOperation = (InternalOperation)methodOperations.ElementAt(tempBB.endIdx); // check which kind of exit branch is used by this basic block and update its operation accordingly if (tempBB.exitBranch as NoBranchTarget != null) { continue; } else if (tempBB.exitBranch as TryBlockTarget != null) { continue; } else if (tempBB.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget tempExitBranch = (tempBB.exitBranch as ConditionalBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // get index of the branch target int targetBranchIdx = tempExitBranch.takenTarget.startIdx; // update offset of the taken branch branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset; } else if (tempBB.exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget tempExitBranch = (tempBB.exitBranch as SwitchBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // update all switch branches for (int switchIdx = 0; switchIdx < tempExitBranch.takenTarget.Count(); switchIdx++) { // get index of the branch target int targetBranchIdx = tempExitBranch.takenTarget.ElementAt(switchIdx).startIdx; // update offset of the taken branch ((uint[])branchOperation.Value)[switchIdx] = methodOperations.ElementAt(targetBranchIdx).Offset; } } else if (tempBB.exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget tempExitBranch = (tempBB.exitBranch as UnconditionalBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // get index of the branch target int targetBranchIdx = tempExitBranch.takenTarget.startIdx; // update offset of the taken branch branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset; } else if (tempBB.exitBranch as ExitBranchTarget != null) { continue; } else if (tempBB.exitBranch as ThrowBranchTarget != null) { continue; } else if (tempBB.exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget tempExitBranch = (tempBB.exitBranch as ExceptionBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // get index of the branch target int targetBranchIdx = tempExitBranch.exitTarget.startIdx; // update offset of the taken branch branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset; } else { throw new ArgumentException("Do not know how to handle exit branch."); } } // step five: create new exception handler with updated offsets and // create new method body of the cci method MethodDefinition method = methodCfg.method; var ilGenerator = new ILGenerator(this.host, method); // emit all operations to the new body foreach (IOperation operation in methodOperations) { ilGenerator.Emit(operation.OperationCode, operation.Value); } // list that is used to replace the pointer to the old exception handler in the basic blocks to the new exception handler List<OldExceptionHandlerMapping> oldExceptionHandlerMappings = new List<OldExceptionHandlerMapping>(); // create for each old exception handler a new one with updated data foreach (IOperationExceptionInformation exceptionHandler in method.Body.OperationExceptionInformation) { // create mapping object for old exception handler OldExceptionHandlerMapping oldExceptionHandlerMapping = new OldExceptionHandlerMapping(); oldExceptionHandlerMapping.oldExceptionHandler = exceptionHandler; oldExceptionHandlerMappings.Add(oldExceptionHandlerMapping); ILGeneratorLabel tryStart = new ILGeneratorLabel(); ILGeneratorLabel tryEnd = new ILGeneratorLabel(); ILGeneratorLabel handlerStart = new ILGeneratorLabel(); ILGeneratorLabel handlerEnd = new ILGeneratorLabel(); ILGeneratorLabel filterStart = new ILGeneratorLabel(); // search for the basic blocks that start/end the try block and handler block foreach (BasicBlock tempBB in methodCfg.basicBlocks) { foreach (TryBlock tempTryBlock in tempBB.tryBlocks) { // ignore try blocks that do not belong to the current exception handler if (tempTryBlock.exceptionHandler != exceptionHandler) { continue; } // get offset of the instruction that starts the try block if (tempTryBlock.firstBasicBlockOfTryBlock) { tryStart.Offset = tempBB.operations.ElementAt(0).Offset; oldExceptionHandlerMapping.tryStartOffset = tryStart.Offset; } // get offset of the instruction that ends the try block (always the last instruction of the basic block) if (tempTryBlock.lastBasicBlockOfTryBlock) { tryEnd.Offset = tempBB.operations.ElementAt(tempBB.operations.Count() - 1).Offset; // exception handler object needs offset of the end of the instruction (not the beginning) tryEnd.Offset += CfgBuilder.getSizeOfOperation(tempBB.operations.ElementAt(tempBB.operations.Count() - 1)); oldExceptionHandlerMapping.tryEndOffset = tryEnd.Offset; } } foreach (HandlerBlock tempHandlerBlock in tempBB.handlerBlocks) { // ignore handler blocks that do not belong to the current exception handler if (tempHandlerBlock.exceptionHandler != exceptionHandler) { continue; } // get offset ot the instruction that starts the handler block if (tempHandlerBlock.firstBasicBlockOfHandlerBlock) { handlerStart.Offset = tempBB.operations.ElementAt(0).Offset; oldExceptionHandlerMapping.handlerStartOffset = handlerStart.Offset; } // get offset of the instruction that ends the handler block if (tempHandlerBlock.lastBasicBlockOfHandlerBlock) { handlerEnd.Offset = tempBB.operations.ElementAt(tempBB.operations.Count() - 1).Offset; // exception handler object needs offset of the end of the instruction (not the beginning) handlerEnd.Offset += CfgBuilder.getSizeOfOperation(tempBB.operations.ElementAt(tempBB.operations.Count() - 1)); oldExceptionHandlerMapping.handlerEndOffset = handlerEnd.Offset; } } } // copy the exception handler filter filterStart.Offset = exceptionHandler.FilterDecisionStartOffset; oldExceptionHandlerMapping.filterStartOffset = filterStart.Offset; // add new exception handler oldExceptionHandlerMapping.exceptionType = exceptionHandler.ExceptionType; oldExceptionHandlerMapping.handlerKind = exceptionHandler.HandlerKind; ilGenerator.AddExceptionHandlerInformation(exceptionHandler.HandlerKind, exceptionHandler.ExceptionType, tryStart, tryEnd, handlerStart, handlerEnd, filterStart); } // create the body List<ILocalDefinition> variableListCopy = new List<ILocalDefinition>(method.Body.LocalVariables); List<ITypeDefinition> privateHelperTypesListCopy = new List<ITypeDefinition>(method.Body.PrivateHelperTypes); var newBody = new ILGeneratorMethodBody(ilGenerator, method.Body.LocalsAreZeroed, 8, method, variableListCopy, privateHelperTypesListCopy); // TODO dynamic max stack size? method.Body = newBody; // step six: replace pointer to the old exception handler with the new exception handler // map all old exception handler to the new objects foreach (IOperationExceptionInformation exceptionHandler in method.Body.OperationExceptionInformation) { // search for the new exception handler object to get the mapping to the old one bool found = false; foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) { if (oldExceptionHandlerMapping.exceptionType == exceptionHandler.ExceptionType && oldExceptionHandlerMapping.handlerKind == exceptionHandler.HandlerKind && oldExceptionHandlerMapping.filterStartOffset == exceptionHandler.FilterDecisionStartOffset && oldExceptionHandlerMapping.tryStartOffset == exceptionHandler.TryStartOffset && oldExceptionHandlerMapping.tryEndOffset == exceptionHandler.TryEndOffset && oldExceptionHandlerMapping.handlerStartOffset == exceptionHandler.HandlerStartOffset && oldExceptionHandlerMapping.handlerEndOffset == exceptionHandler.HandlerEndOffset) { oldExceptionHandlerMapping.newExceptionHandler = exceptionHandler; found = true; break; } } if (!found) { throw new ArgumentException("Not able to map old exception handler to new one."); } } // replace all old exception handler in the basic blocks with the new exception handler foreach (BasicBlock tempBB in methodCfg.basicBlocks) { // replace all exception handler in the try blocks foreach (TryBlock tryBlock in tempBB.tryBlocks) { foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) { if (tryBlock.exceptionHandler == oldExceptionHandlerMapping.oldExceptionHandler) { tryBlock.exceptionHandler = oldExceptionHandlerMapping.newExceptionHandler; break; } } } // replace all exception handler in the handler blocks foreach (HandlerBlock handlerBlock in tempBB.handlerBlocks) { foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) { if (handlerBlock.exceptionHandler == oldExceptionHandlerMapping.oldExceptionHandler) { handlerBlock.exceptionHandler = oldExceptionHandlerMapping.newExceptionHandler; break; } } } } // TODO // DEBUG /* // sanitize method name to store it as a file String invalidChars = System.Text.RegularExpressions.Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars())); String invalidRegStr = string.Format(@"([{0}]*\.+$)|([{0}]+)", invalidChars); String fileName = System.Text.RegularExpressions.Regex.Replace(methodCfg.method.ToString(), invalidRegStr, "_"); fileName = fileName.Length >= 230 ? fileName.Substring(0, 230) : fileName; // dump cfg created from the exit branches System.IO.StreamWriter dotFile = new System.IO.StreamWriter("e:\\" + "\\BBUnion_" + fileName + ".dot"); // start .dot file graph dotFile.WriteLine("digraph G {"); for (int bbuidx = 0; bbuidx < basicBlockUnions.Count(); bbuidx++) { BasicBlockUnion basicBlockUnion = basicBlockUnions.ElementAt(bbuidx); // write all basic blocks to .dot file for (int idx = 0; idx < basicBlockUnion.basicBlocks.Count(); idx++) { BasicBlock currentBasicBlock = basicBlockUnion.basicBlocks.ElementAt(idx); // write the current basic block to the file and all its instructions dotFile.WriteLine("BB" + bbuidx.ToString() + "_" + idx.ToString() + " [shape=record]"); bool first = true; for (int opIdx = 0; opIdx < currentBasicBlock.operations.Count(); opIdx++) { var operation = currentBasicBlock.operations.ElementAt(opIdx); if (first) { dotFile.Write("BB" + bbuidx.ToString() + "_" + idx.ToString() + " [label=\"{"); first = false; } else { dotFile.Write("|"); } // insert try block beginnings foreach (var tryBlock in currentBasicBlock.tryBlocks) { if (tryBlock.firstBasicBlockOfTryBlock && opIdx == 0) { dotFile.Write("TRY START (" + tryBlock.exceptionHandler.ExceptionType.ToString() + ")|"); } } // insert catch block beginnings foreach (var handlerBlock in currentBasicBlock.handlerBlocks) { if (handlerBlock.firstBasicBlockOfHandlerBlock && opIdx == 0) { if (handlerBlock.typeOfHandler == HandlerKind.Catch) { dotFile.Write("CATCH START (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")|"); } else if (handlerBlock.typeOfHandler == HandlerKind.Finally) { dotFile.Write("FINALLY START (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")|"); } else { throw new ArgumentException("Do not know how to handle handler."); } } } // check if instruction has an argument if (operation.Value != null) { dotFile.Write(operation.OperationCode.ToString() + " " + operation.Value.ToString()); } else { dotFile.Write(operation.OperationCode.ToString()); } // insert try block endings foreach (var tryBlock in currentBasicBlock.tryBlocks) { if (tryBlock.lastBasicBlockOfTryBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) { dotFile.Write("|TRY END (" + tryBlock.exceptionHandler.ExceptionType.ToString() + ")"); } } // insert catch block endings foreach (var handlerBlock in currentBasicBlock.handlerBlocks) { if (handlerBlock.lastBasicBlockOfHandlerBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) { if (handlerBlock.typeOfHandler == HandlerKind.Catch) { dotFile.Write("|CATCH END (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")"); } else if (handlerBlock.typeOfHandler == HandlerKind.Finally) { dotFile.Write("|FINALLY END (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")"); } else { throw new ArgumentException("Do not know how to handle handler."); } } } } dotFile.WriteLine("}\"]"); if ((idx + 1) < basicBlockUnion.basicBlocks.Count()) { dotFile.WriteLine("BB" + bbuidx.ToString() + "_" + idx.ToString() + " -> BB" + bbuidx.ToString() + "_" + (idx + 1).ToString() + "[ color=\"blue\" ]"); } } } // finish graph dotFile.WriteLine("}"); dotFile.Close(); */ }
// this constructor copies the given source method cfg and all its elements // NOTE: it ignores the transformation metadata public MethodCfg(MethodCfg sourceMethodCfg) { // copy link to the method this.method = sourceMethodCfg.method; // generate a list of already processed basic blocks List<BasicBlock> processedBasicBlocks = new List<BasicBlock>(); // set start basic block of the CFG as already processed processedBasicBlocks.Add(sourceMethodCfg.startBasicBlock); // create copy of start basic block BasicBlock copiedStartBasicBlock = new BasicBlock(); this.startBasicBlock = copiedStartBasicBlock; this.basicBlocks.Add(copiedStartBasicBlock); // copy simple values copiedStartBasicBlock.id = sourceMethodCfg.startBasicBlock.id; copiedStartBasicBlock.semanticId = sourceMethodCfg.startBasicBlock.semanticId; copiedStartBasicBlock.startIdx = sourceMethodCfg.startBasicBlock.startIdx; copiedStartBasicBlock.endIdx = sourceMethodCfg.startBasicBlock.endIdx; // copy all operations of the basic block foreach (IOperation operation in sourceMethodCfg.startBasicBlock.operations) { InternalOperation copiedOperation = new InternalOperation(); copiedOperation.OperationCode = operation.OperationCode; copiedOperation.Value = operation.Value; copiedOperation.Offset = operation.Offset; copiedOperation.Location = operation.Location; copiedStartBasicBlock.operations.Add(copiedOperation); } // process rest of the cfg and copy the exit branch if ((sourceMethodCfg.startBasicBlock.exitBranch as NoBranchTarget) != null) { NoBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as NoBranchTarget); // create a copied exit branch NoBranchTarget copiedExitBranch = new NoBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch); } else if (sourceMethodCfg.startBasicBlock.exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as UnconditionalBranchTarget); // create a copied exit branch UnconditionalBranchTarget copiedExitBranch = new UnconditionalBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch); } else if (sourceMethodCfg.startBasicBlock.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as ConditionalBranchTarget); // create a copied exit branch ConditionalBranchTarget copiedExitBranch = new ConditionalBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch, true); // process branch and next basic block nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, false); } else if (sourceMethodCfg.startBasicBlock.exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as SwitchBranchTarget); // create a copied exit branch SwitchBranchTarget copiedExitBranch = new SwitchBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // first process not taken branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, -1); // process all taken branches and next basic blocks for (int idx = 0; idx < exitBranch.takenTarget.Count(); idx++) { nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget.ElementAt(idx), ref nextCopiedBasicBlock, copiedExitBranch, idx); } } else if (sourceMethodCfg.startBasicBlock.exitBranch as ExitBranchTarget != null) { // create a copied exit branch ExitBranchTarget copiedExitBranch = new ExitBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; } else if (sourceMethodCfg.startBasicBlock.exitBranch as ThrowBranchTarget != null) { // create a copied exit branch ThrowBranchTarget copiedExitBranch = new ThrowBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; } else if (sourceMethodCfg.startBasicBlock.exitBranch as TryBlockTarget != null) { TryBlockTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as TryBlockTarget); // create a copied exit branch TryBlockTarget copiedExitBranch = new TryBlockTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch); } else if (sourceMethodCfg.startBasicBlock.exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as ExceptionBranchTarget); // create a copied exit branch ExceptionBranchTarget copiedExitBranch = new ExceptionBranchTarget(); copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock; copiedStartBasicBlock.exitBranch = copiedExitBranch; // process branch and next basic block BasicBlock nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exceptionTarget, ref nextCopiedBasicBlock, copiedExitBranch, true); // process branch and next basic block nextCopiedBasicBlock = null; this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exitTarget, ref nextCopiedBasicBlock, copiedExitBranch, false); } else { throw new ArgumentException("Do not know how to handle exit branch."); } // copy all try blocks foreach (TryBlock sourceTryBlock in sourceMethodCfg.startBasicBlock.tryBlocks) { TryBlock copiedTryBlock = new TryBlock(); copiedTryBlock.exceptionHandler = sourceTryBlock.exceptionHandler; copiedTryBlock.firstBasicBlockOfTryBlock = sourceTryBlock.firstBasicBlockOfTryBlock; copiedTryBlock.lastBasicBlockOfTryBlock = sourceTryBlock.lastBasicBlockOfTryBlock; copiedStartBasicBlock.tryBlocks.Add(copiedTryBlock); } // copy all handler blocks foreach (HandlerBlock sourceHandlerBlock in sourceMethodCfg.startBasicBlock.handlerBlocks) { HandlerBlock copiedHandlerBlock = new HandlerBlock(); copiedHandlerBlock.exceptionHandler = sourceHandlerBlock.exceptionHandler; copiedHandlerBlock.typeOfHandler = sourceHandlerBlock.typeOfHandler; copiedHandlerBlock.firstBasicBlockOfHandlerBlock = sourceHandlerBlock.firstBasicBlockOfHandlerBlock; copiedHandlerBlock.lastBasicBlockOfHandlerBlock = sourceHandlerBlock.lastBasicBlockOfHandlerBlock; copiedStartBasicBlock.handlerBlocks.Add(copiedHandlerBlock); } }
public CodeGenerator(IModule module, PeReader.DefaultHost host, Log.Log logger, Random prng, MethodCfg methodCfg, bool debugging=false, CfgManipulator manipulator=null) { this.host = host; this.logger = logger; this.module = module; this.prng = prng; this.methodCfg = methodCfg; this.debugging = debugging; this.manipulator = manipulator; callableMethods = retrieveCallableMethods(); }
public CodeMutator(IModule module, PeReader.DefaultHost host, Log.Log logger, Random prng, MethodCfg methodCfg, CfgManipulator manipulator, bool debugging=false) { this.host = host; this.logger = logger; this.module = module; this.prng = prng; this.methodCfg = methodCfg; this.debugging = debugging; this.manipulator = manipulator; returnBlock = new BasicBlock(); var exitBranch = new ExitBranchTarget(); returnBlock.exitBranch = exitBranch; returnBlock.operations.Add(createNewOperation(OperationCode.Ret)); methodCfg.basicBlocks.Add(returnBlock); }
// this function injects an opaque predicate to the target branch private void injectOpaquePredicateCode(CfgManipulator cfgManipulator, MethodCfg methodCfg, BasicBlock targetBasicBlock, IBranchTarget targetBranch, BasicBlockGraphNodeLink link, int opaquePredicate, LocalDefinition currentNodeLocal) { int currentValidPathId = link.validPathId; ConditionalBranchTarget opaqueExitBranch = null; // create "true" or "false" opaque predicate and add it to the code switch (opaquePredicate) { // "true" opaque predicate case 0: { BasicBlock opaqueStartBasicBlock = null; this.createCodeTruePredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal); // inject target branch with opaque predicate if ((targetBranch as SwitchBranchTarget) != null) { SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, true); } else if ((targetBranch as UnconditionalBranchTarget) != null) { UnconditionalBranchTarget tempTargetBranch = (targetBranch as UnconditionalBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, opaqueStartBasicBlock, opaqueExitBranch, true); } else { throw new ArgumentException("Not implemented yet."); } // set template semantic id of dead code basic block BasicBlock deadCodeBasicBlock = opaqueExitBranch.notTakenTarget; GraphTransformerDeadCodeBasicBlock deadCodeMetadata = (deadCodeBasicBlock.transformationMetadata.ElementAt(0) as GraphTransformerDeadCodeBasicBlock); deadCodeMetadata.semanticId = targetBasicBlock.semanticId; // create intermediate basic block and inject it between correct opaque predicate branch and target basic block BasicBlock intermediateBasicBlock = new BasicBlock(); intermediateBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Br, 0)); methodCfg.basicBlocks.Add(intermediateBasicBlock); // add metadata to intermediate basic block GraphTransformerIntermediateBasicBlock metadataIntermediate = new GraphTransformerIntermediateBasicBlock(); metadataIntermediate.correspondingGraphNodes.Add(link); intermediateBasicBlock.transformationMetadata.Add(metadataIntermediate); // create intermediate exit branch UnconditionalBranchTarget intermediateBasicBlockExitBranch = new UnconditionalBranchTarget(); intermediateBasicBlockExitBranch.sourceBasicBlock = intermediateBasicBlock; intermediateBasicBlock.exitBranch = intermediateBasicBlockExitBranch; cfgManipulator.insertBasicBlockBetweenBranch(opaqueExitBranch, true, intermediateBasicBlock, intermediateBasicBlockExitBranch); break; } // "false" opaque predicate case 1: { BasicBlock opaqueStartBasicBlock = null; this.createCodeFalsePredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal); // inject target branch with opaque predicate if ((targetBranch as SwitchBranchTarget) != null) { SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, false); } else if ((targetBranch as UnconditionalBranchTarget) != null) { UnconditionalBranchTarget tempTargetBranch = (targetBranch as UnconditionalBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, opaqueStartBasicBlock, opaqueExitBranch, false); } else { throw new ArgumentException("Not implemented yet."); } // set template semantic id of dead code basic block BasicBlock deadCodeBasicBlock = opaqueExitBranch.takenTarget; GraphTransformerDeadCodeBasicBlock deadCodeMetadata = (deadCodeBasicBlock.transformationMetadata.ElementAt(0) as GraphTransformerDeadCodeBasicBlock); deadCodeMetadata.semanticId = targetBasicBlock.semanticId; // create intermediate basic block and inject it between correct opaque predicate branch and target basic block BasicBlock intermediateBasicBlock = new BasicBlock(); intermediateBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Br, 0)); methodCfg.basicBlocks.Add(intermediateBasicBlock); // add metadata to intermediate basic block GraphTransformerIntermediateBasicBlock metadataIntermediate = new GraphTransformerIntermediateBasicBlock(); metadataIntermediate.correspondingGraphNodes.Add(link); intermediateBasicBlock.transformationMetadata.Add(metadataIntermediate); // create intermediate exit branch UnconditionalBranchTarget intermediateBasicBlockExitBranch = new UnconditionalBranchTarget(); intermediateBasicBlockExitBranch.sourceBasicBlock = intermediateBasicBlock; intermediateBasicBlock.exitBranch = intermediateBasicBlockExitBranch; cfgManipulator.insertBasicBlockBetweenBranch(opaqueExitBranch, false, intermediateBasicBlock, intermediateBasicBlockExitBranch); break; } // "Random" opaque predicate. case 2: { BasicBlock opaqueStartBasicBlock = null; if ((targetBranch as SwitchBranchTarget) != null) { SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget); var destinationBlock = tempTargetBranch.takenTarget[currentValidPathId]; this.createCodeRandomPredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal); bool chooseBranch = prng.Next(1) == 0; cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, chooseBranch); } else { throw new ArgumentException("Not implemented yet."); } break; } default: throw new ArgumentException("This case should never be reached."); } }
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; }
// Mutates all blocks in the given method CFG. private void mutateBlocks(MethodCfg methodCfg) { var manipulator = new CfgManipulator(this.module, this.host, this.logger, methodCfg); var codeMutator = new CodeMutator(this.module, this.host, this.logger, this.prng, methodCfg, manipulator, this.debugging); codeMutator.mutateBlocks(methodCfg.basicBlocks); }
// Searches semantically equivalent blocks in the given method CFG and obfuscates them. private void obfuscateSemanticallyEquivalentBlocks(MethodCfg methodCfg) { // Group all blocks with same semantic ID. var semanticGroups = new Dictionary<int, List<BasicBlock>>(); foreach(var block in methodCfg.basicBlocks) { List<BasicBlock> blockList = null; if(!semanticGroups.TryGetValue(block.semanticId, out blockList)) { blockList = new List<BasicBlock>(); semanticGroups[block.semanticId] = blockList; } if(block.semanticId != -1) { semanticGroups[block.semanticId].Add(block); } } // Mutate equivalent blocks. var manipulator = new CfgManipulator(this.module, this.host, this.logger, methodCfg); var codeMutator = new CodeMutator(this.module, this.host, this.logger, this.prng, methodCfg, manipulator, this.debugging); foreach(var blockList in semanticGroups.Values) { codeMutator.mutateSemanticallyEquivalentBlocks(blockList); } }
// this function is used to fill the created dead code basic blocks with actual dead code private void fillDeadCodeBasicBlocks(MethodCfg methodCfg) { var manipulator = new CfgManipulator(this.module, this.host, this.logger, methodCfg); CodeGenerator codeGenerator = new CodeGenerator(this.module, this.host, this.logger, this.prng, methodCfg, this.debugging, manipulator); //CodeGenerator codeGenerator = new CodeGenerator(this.module, this.host, this.logger, this.prng, methodCfg, true, manipulator); // search through all basic blocks if there are dead code basic blocks foreach (BasicBlock currentBasicBlock in methodCfg.basicBlocks) { // fill basic block with dead code if it is marked as a dead code basic block foreach (ITransformationMetadata metadata in currentBasicBlock.transformationMetadata) { if ((metadata as GraphTransformerDeadCodeBasicBlock) != null) { codeGenerator.generateDeadCode(currentBasicBlock, metadata); } } } }
// builds a CFG for the given method and returns it public MethodCfg buildCfgForMethod(MethodDefinition method) { MethodCfg methodCfg = new MethodCfg(); methodCfg.method = method; // start building the cfg BasicBlock firstBasicBlock = new BasicBlock(this.semanticId); this.semanticId++; methodCfg.startBasicBlock = firstBasicBlock; this.buildRecursivelyCfg(methodCfg, method.Body.Operations, 0, null, ref firstBasicBlock); // add exception handler to the cfg foreach (IOperationExceptionInformation exceptionHandler in method.Body.OperationExceptionInformation) { // debugging variables to throw an exception if start/end of try/handler block was not found bool tryStartFound = false; bool tryEndFound = false; bool handlerStartFound = false; bool handlerEndFound = false; // search each basic block if they reside in an exception handler List<BasicBlock> localCopy = new List<BasicBlock>(); localCopy.AddRange(methodCfg.basicBlocks); for (int bbIdx = 0; bbIdx < localCopy.Count(); bbIdx++) { BasicBlock basicBlock = localCopy.ElementAt(bbIdx); int lastOperationIdx = basicBlock.operations.Count() - 1; // ignore basic block if the start of the try block lies behind the current basic block // (catch or finally blocks can never lie before a try block) if (basicBlock.operations.ElementAt(lastOperationIdx).Offset < exceptionHandler.TryStartOffset) { continue; } // check if the current basic block resides in the try block of the exception handler else if ((exceptionHandler.TryStartOffset >= basicBlock.operations.ElementAt(0).Offset && exceptionHandler.TryStartOffset <= basicBlock.operations.ElementAt(lastOperationIdx).Offset) || (exceptionHandler.TryStartOffset <= basicBlock.operations.ElementAt(0).Offset && basicBlock.operations.ElementAt(lastOperationIdx).Offset < exceptionHandler.TryEndOffset)) { TryBlock tempTryBlock = new TryBlock(); tempTryBlock.exceptionHandler = exceptionHandler; // check if the try block starts inside this basic block if (exceptionHandler.TryStartOffset >= basicBlock.operations.ElementAt(0).Offset) { // find the index of the operation that starts the try block bool foundIdx = false; for (int idx = 0; idx < basicBlock.operations.Count(); idx++) { if (basicBlock.operations.ElementAt(idx).Offset == exceptionHandler.TryStartOffset) { // if the try block does not start at the beginning of the current basic block // => split basic block and let the try block begin at the second half of the basic block if (idx != 0) { // create new basic block which will be the second half of the found one BasicBlock newBasicBlock = new BasicBlock(this.semanticId); this.semanticId++; newBasicBlock.startIdx = basicBlock.startIdx + idx; newBasicBlock.endIdx = basicBlock.endIdx; basicBlock.endIdx = basicBlock.startIdx + idx - 1; // move the exit basic blocks to the new created basic block // and make the new created basic block the exit of the splitted one newBasicBlock.exitBranch = basicBlock.exitBranch; newBasicBlock.exitBranch.sourceBasicBlock = newBasicBlock; TryBlockTarget tempExitBranch = new TryBlockTarget(); tempExitBranch.takenTarget = newBasicBlock; tempExitBranch.sourceBasicBlock = basicBlock; basicBlock.exitBranch = tempExitBranch; // add splitted basic block branch to the entry of the new one newBasicBlock.entryBranches.Add(tempExitBranch); // distribute the instructions to the basic blocks List<IOperation> previousOperations = new List<IOperation>(); List<IOperation> nextOperations = new List<IOperation>(); for (int operationIdx = 0; (operationIdx + basicBlock.startIdx) <= newBasicBlock.endIdx; operationIdx++) { if ((operationIdx + basicBlock.startIdx) < newBasicBlock.startIdx) { previousOperations.Add(basicBlock.operations.ElementAt(operationIdx)); } else { nextOperations.Add(basicBlock.operations.ElementAt(operationIdx)); } } basicBlock.operations = previousOperations; newBasicBlock.operations = nextOperations; // add new basic block to the cfg methodCfg.basicBlocks.Add(newBasicBlock); // add try block to the new created basic block (it is the start of the try block) newBasicBlock.tryBlocks.Add(tempTryBlock); // try block can not end at the first part of the splitted basic block // (because it starts at the second one), but it can end at the // second part of the splitted basic block basicBlock = newBasicBlock; lastOperationIdx = newBasicBlock.operations.Count() - 1; } // the try block starts at the beginning of the current basic block => add the try block else { basicBlock.tryBlocks.Add(tempTryBlock); } // mark try block as the beginning of the try block tempTryBlock.firstBasicBlockOfTryBlock = true; foundIdx = true; tryStartFound = true; break; } } if (!foundIdx) { throw new ArgumentException("Did not find index of operation that starts Try block."); } } else { basicBlock.tryBlocks.Add(tempTryBlock); tempTryBlock.firstBasicBlockOfTryBlock = false; } // check if the try block ends at the end of this basic block (try blocks always end at the end of a basic block) if (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)) == exceptionHandler.TryEndOffset) { tempTryBlock.lastBasicBlockOfTryBlock = true; tryEndFound = true; } else { tempTryBlock.lastBasicBlockOfTryBlock = false; } continue; } // check if the current basic block resides in the handler block of the exception handler else if ((exceptionHandler.HandlerStartOffset >= basicBlock.operations.ElementAt(0).Offset && exceptionHandler.HandlerStartOffset <= basicBlock.operations.ElementAt(lastOperationIdx).Offset) || (exceptionHandler.HandlerStartOffset <= basicBlock.operations.ElementAt(0).Offset && basicBlock.operations.ElementAt(lastOperationIdx).Offset < exceptionHandler.HandlerEndOffset)) { // check if the handler block is a catch block if (exceptionHandler.HandlerKind == HandlerKind.Catch) { HandlerBlock tempCatchBock = new HandlerBlock(); tempCatchBock.typeOfHandler = HandlerKind.Catch; tempCatchBock.exceptionHandler = exceptionHandler; basicBlock.handlerBlocks.Add(tempCatchBock); // check if the catch block starts inside this basic block if (exceptionHandler.HandlerStartOffset >= basicBlock.operations.ElementAt(0).Offset) { // find the index of the operation that starts the catch block bool foundIdx = false; for (int idx = 0; idx < basicBlock.operations.Count(); idx++) { if (basicBlock.operations.ElementAt(idx).Offset == exceptionHandler.HandlerStartOffset) { tempCatchBock.firstBasicBlockOfHandlerBlock = true; foundIdx = true; handlerStartFound = true; break; } } if (!foundIdx) { throw new ArgumentException("Did not find index of operation that starts Catch block."); } } else { tempCatchBock.firstBasicBlockOfHandlerBlock = false; } // check if the catch block ends inside this basic block if (basicBlock.operations[0].Offset < exceptionHandler.HandlerEndOffset && exceptionHandler.HandlerEndOffset <= (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)))) { // check if the catch block ends at the last instruction of this basic block (this happens usually => optimization) if (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)) == exceptionHandler.HandlerEndOffset) { tempCatchBock.lastBasicBlockOfHandlerBlock = true; handlerEndFound = true; continue; } else { throw new ArgumentException("Did not find the operation that ends Catch block."); } } else { tempCatchBock.lastBasicBlockOfHandlerBlock = false; } continue; } // check if the handler block is a finally block else if (exceptionHandler.HandlerKind == HandlerKind.Finally) { HandlerBlock tempFinallyBock = new HandlerBlock(); tempFinallyBock.typeOfHandler = HandlerKind.Finally; tempFinallyBock.exceptionHandler = exceptionHandler; basicBlock.handlerBlocks.Add(tempFinallyBock); // check if the finally block starts inside this basic block if (exceptionHandler.HandlerStartOffset >= basicBlock.operations.ElementAt(0).Offset) { // find the index of the operation that starts the finally block bool foundIdx = false; for (int idx = 0; idx < basicBlock.operations.Count(); idx++) { if (basicBlock.operations.ElementAt(idx).Offset == exceptionHandler.HandlerStartOffset) { tempFinallyBock.firstBasicBlockOfHandlerBlock = true; foundIdx = true; handlerStartFound = true; break; } } if (!foundIdx) { throw new ArgumentException("Did not find index of operation that starts Finally block."); } } else { tempFinallyBock.firstBasicBlockOfHandlerBlock = false; } // check if the finally block ends inside this basic block if (basicBlock.operations[0].Offset < exceptionHandler.HandlerEndOffset && exceptionHandler.HandlerEndOffset <= (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)))) { // check if the finally block ends at the last instruction of this basic block if (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)) == exceptionHandler.HandlerEndOffset) { tempFinallyBock.lastBasicBlockOfHandlerBlock = true; handlerEndFound = true; continue; } else { throw new ArgumentException("Did not find the operation that ends Finally block."); } } continue; } else { throw new ArgumentException("Do not know how to handle exception handler."); } } } // check if start/end of try/handler block was found if(!tryStartFound || !tryEndFound || !handlerStartFound || !handlerEndFound) { throw new ArgumentException("Was not able to find start/end of try/handler block."); } } // TODO // DEBUG //this.logger.dumpMethodCfg(methodCfg, this.logger.sanitizeString(methodCfg.method.ToString())); return methodCfg; }
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 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; } } }
public void dumpMethodCfg(MethodCfg methodCfg, String fileName) { // shorten file name if it is too long fileName = fileName.Length >= 230 ? fileName.Substring(0, 230) : fileName; // dump cfg created from the exit branches System.IO.StreamWriter dotFile = new System.IO.StreamWriter(this.logPath + "\\exitBranches_" + fileName + ".dot"); // start .dot file graph dotFile.WriteLine("digraph G {"); // write all basic blocks to .dot file for (int idx = 0; idx < methodCfg.basicBlocks.Count(); idx++) { BasicBlock currentBasicBlock = methodCfg.basicBlocks.ElementAt(idx); // write the current basic block to the file and all its instructions dotFile.WriteLine("BB" + idx.ToString() + " [shape=record]"); bool first = true; for (int opIdx = 0; opIdx < currentBasicBlock.operations.Count(); opIdx++) { var operation = currentBasicBlock.operations.ElementAt(opIdx); if (first) { dotFile.Write("BB" + idx.ToString() + " [label=\"{"); dotFile.Write("NAME: BB" + idx.ToString() + "|"); dotFile.Write("ID: " + currentBasicBlock.id.ToString() + "|"); dotFile.Write("SEMANTIC ID: " + currentBasicBlock.semanticId.ToString() + "|"); first = false; // dump basic block transformation metadata foreach (ITransformationMetadata metadata in currentBasicBlock.transformationMetadata) { if ((metadata as GraphTransformerMetadataBasicBlock) != null) { GraphTransformerMetadataBasicBlock temp = (metadata as GraphTransformerMetadataBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } dotFile.Write("GRAPH_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } // dump the valid and invalid interfaces of the graph element (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { PathElement pathElement = null; foreach (PathElement tempElement in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.pathElements) { if (tempElement.validPathId == temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId) { pathElement = tempElement; break; } } if (pathElement == null) { throw new ArgumentNullException("No path element for valid graph id was found."); } String tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.validInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("valid Interfaces: " + tempOutput + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.invalidInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("invalid Interfaces: " + tempOutput + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if ((metadata as GraphTransformerPredicateBasicBlock) != null) { GraphTransformerPredicateBasicBlock temp = (metadata as GraphTransformerPredicateBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } if (temp.predicateType == GraphOpaquePredicate.True) { dotFile.Write("TRUE_PREDICATE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if (temp.predicateType == GraphOpaquePredicate.False) { dotFile.Write("FALSE_PREDICATE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if (temp.predicateType == GraphOpaquePredicate.Random) { dotFile.Write("RANDOM_PREDICATE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else { throw new ArgumentException("Do not know how to handle opaque predicate type."); } } else if ((metadata as GraphTransformerNextNodeBasicBlock) != null) { GraphTransformerNextNodeBasicBlock temp = (metadata as GraphTransformerNextNodeBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } if (temp.correctNextNode) { dotFile.Write("CORRECT_NEXT_NODE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else { dotFile.Write("WRONG_NEXT_NODE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } } else if ((metadata as GraphTransformerDeadCodeBasicBlock) != null) { GraphTransformerDeadCodeBasicBlock temp = (metadata as GraphTransformerDeadCodeBasicBlock); dotFile.Write("DEAD_CODE_BLOCK (template semantic ID: " + temp.semanticId.ToString() + ")|"); } else if ((metadata as GraphTransformerStateBasicBlock) != null) { GraphTransformerStateBasicBlock temp = (metadata as GraphTransformerStateBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } dotFile.Write("STATE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if ((metadata as GraphTransformerStateChangeBasicBlock) != null) { GraphTransformerStateChangeBasicBlock temp = (metadata as GraphTransformerStateChangeBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } dotFile.Write("STATE_CHANGE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if ((metadata as GraphTransformerIntermediateBasicBlock) != null) { GraphTransformerIntermediateBasicBlock temp = (metadata as GraphTransformerIntermediateBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } dotFile.Write("INTERMEDIATE_BASIC_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if ((metadata as DevBasicBlock) != null) { DevBasicBlock temp = (metadata as DevBasicBlock); dotFile.Write("DEV_NOTE: " + temp.note + "|"); } else { throw new ArgumentException("Do not know how to handle transformation metadata."); } } } else { dotFile.Write("|"); } // insert try block beginnings foreach (var tryBlock in currentBasicBlock.tryBlocks) { if (tryBlock.firstBasicBlockOfTryBlock && opIdx == 0) { dotFile.Write("TRY START (" + this.sanitizeString(tryBlock.exceptionHandler.ExceptionType.ToString()) + ")|"); } } // insert catch block beginnings foreach (var handlerBlock in currentBasicBlock.handlerBlocks) { if (handlerBlock.firstBasicBlockOfHandlerBlock && opIdx == 0) { if (handlerBlock.typeOfHandler == HandlerKind.Catch) { dotFile.Write("CATCH START (" + this.sanitizeString(handlerBlock.exceptionHandler.ExceptionType.ToString()) + ")|"); } else if (handlerBlock.typeOfHandler == HandlerKind.Finally) { dotFile.Write("FINALLY START (" + this.sanitizeString(handlerBlock.exceptionHandler.ExceptionType.ToString()) + ")|"); } else { throw new ArgumentException("Do not know how to handle handler."); } } } // check if instruction has an argument if (operation.Value != null) { dotFile.Write(operation.OperationCode.ToString() + " " + this.sanitizeString(operation.Value.ToString())); } else { dotFile.Write(operation.OperationCode.ToString()); } // insert try block endings foreach (var tryBlock in currentBasicBlock.tryBlocks) { if (tryBlock.lastBasicBlockOfTryBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) { dotFile.Write("|TRY END (" + this.sanitizeString(tryBlock.exceptionHandler.ExceptionType.ToString()) + ")"); } } // insert catch/finally block endings foreach (var handlerBlock in currentBasicBlock.handlerBlocks) { if (handlerBlock.lastBasicBlockOfHandlerBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) { if (handlerBlock.typeOfHandler == HandlerKind.Catch) { dotFile.Write("|CATCH END (" + this.sanitizeString(handlerBlock.exceptionHandler.ExceptionType.ToString()) + ")"); } else if (handlerBlock.typeOfHandler == HandlerKind.Finally) { dotFile.Write("|FINALLY END (" + this.sanitizeString(handlerBlock.exceptionHandler.ExceptionType.ToString()) + ")"); } else { throw new ArgumentException("Do not know how to handle handler."); } } } } dotFile.WriteLine("}\"]"); // write all the exits of the basic block to the file if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as NoBranchTarget != null) { NoBranchTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as NoBranchTarget); // search index of exit basic block in cfg for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.takenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"blue\" ]"); break; } } } else if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as TryBlockTarget != null) { TryBlockTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as TryBlockTarget); // search index of exit basic block in cfg for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.takenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"blue\" ]"); break; } } } else if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as UnconditionalBranchTarget); // search index of exit basic block in cfg for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.takenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"blue\" ]"); break; } } } else if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as ConditionalBranchTarget); // search index of exit basic block in cfg bool takenTargetFound = false; bool notTakenTargetFound = false; for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.takenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"green\" ]"); takenTargetFound = true; } else if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.notTakenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"red\" ]"); notTakenTargetFound = true; } else if (takenTargetFound && notTakenTargetFound) { break; } } } else if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as SwitchBranchTarget); // search index of exit basic block in cfg for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.notTakenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"red\" ]"); break; } } // search index for all exit basic blocks in cfg foreach (BasicBlock exitBasicBlock in tempBranch.takenTarget) { for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == exitBasicBlock) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"green\" ]"); break; } } } } else if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as ExceptionBranchTarget); // search index of exit basic block in cfg bool exitTargetFound = false; bool exceptionTargetFound = false; for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.exitTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"green\" ]"); exitTargetFound = true; } else if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.exceptionTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"red\" ]"); exceptionTargetFound = true; } else if (exitTargetFound && exceptionTargetFound) { break; } } } } // finish graph dotFile.WriteLine("}"); dotFile.Close(); // dump cfg created from the entry branches dotFile = new System.IO.StreamWriter(this.logPath + "\\entryBranches_" + fileName + ".dot"); // start .dot file graph dotFile.WriteLine("digraph G {"); // write all basic blocks to .dot file for (int idx = 0; idx < methodCfg.basicBlocks.Count(); idx++) { BasicBlock currentBasicBlock = methodCfg.basicBlocks.ElementAt(idx); // write the current basic block to the file and all its instructions dotFile.WriteLine("BB" + idx.ToString() + " [shape=record]"); bool first = true; for (int opIdx = 0; opIdx < currentBasicBlock.operations.Count(); opIdx++) { var operation = currentBasicBlock.operations.ElementAt(opIdx); if (first) { dotFile.Write("BB" + idx.ToString() + " [label=\"{"); dotFile.Write("NAME: BB" + idx.ToString() + "|"); dotFile.Write("ID: " + currentBasicBlock.id.ToString() + "|"); dotFile.Write("SEMANTIC ID: " + currentBasicBlock.semanticId.ToString() + "|"); first = false; // dump basic block transformation metadata foreach (ITransformationMetadata metadata in currentBasicBlock.transformationMetadata) { if ((metadata as GraphTransformerMetadataBasicBlock) != null) { GraphTransformerMetadataBasicBlock temp = (metadata as GraphTransformerMetadataBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } dotFile.Write("GRAPH_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } // dump the valid and invalid interfaces of the graph element (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { PathElement pathElement = null; foreach (PathElement tempElement in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.pathElements) { if (tempElement.validPathId == temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId) { pathElement = tempElement; break; } } if (pathElement == null) { throw new ArgumentNullException("No path element for valid graph id was found."); } String tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.validInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("valid Interfaces: " + tempOutput + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); tempOutput = ""; foreach (ITypeReference interfaceInList in pathElement.invalidInterfaces) { tempOutput += this.sanitizeString(interfaceInList.ToString()) + "; "; } dotFile.Write("invalid Interfaces: " + tempOutput + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if ((metadata as GraphTransformerPredicateBasicBlock) != null) { GraphTransformerPredicateBasicBlock temp = (metadata as GraphTransformerPredicateBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } if (temp.predicateType == GraphOpaquePredicate.True) { dotFile.Write("TRUE_PREDICATE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if (temp.predicateType == GraphOpaquePredicate.False) { dotFile.Write("FALSE_PREDICATE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if (temp.predicateType == GraphOpaquePredicate.Random) { dotFile.Write("RANDOM_PREDICATE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else { throw new ArgumentException("Do not know how to handle opaque predicate type."); } } else if ((metadata as GraphTransformerNextNodeBasicBlock) != null) { GraphTransformerNextNodeBasicBlock temp = (metadata as GraphTransformerNextNodeBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } if (temp.correctNextNode) { dotFile.Write("CORRECT_NEXT_NODE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else { dotFile.Write("WRONG_NEXT_NODE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } } else if ((metadata as GraphTransformerDeadCodeBasicBlock) != null) { GraphTransformerDeadCodeBasicBlock temp = (metadata as GraphTransformerDeadCodeBasicBlock); dotFile.Write("DEAD_CODE_BLOCK (template semantic ID: " + temp.semanticId.ToString() + ")|"); } else if ((metadata as GraphTransformerStateBasicBlock) != null) { GraphTransformerStateBasicBlock temp = (metadata as GraphTransformerStateBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } dotFile.Write("STATE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if ((metadata as GraphTransformerStateChangeBasicBlock) != null) { GraphTransformerStateChangeBasicBlock temp = (metadata as GraphTransformerStateChangeBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } dotFile.Write("STATE_CHANGE_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if ((metadata as GraphTransformerIntermediateBasicBlock) != null) { GraphTransformerIntermediateBasicBlock temp = (metadata as GraphTransformerIntermediateBasicBlock); String validPathIdString = ""; for (int linkIdx = 0; linkIdx < temp.correspondingGraphNodes.Count(); linkIdx++) { validPathIdString += temp.correspondingGraphNodes.ElementAt(linkIdx).validPathId.ToString() + ";"; } dotFile.Write("INTERMEDIATE_BASIC_BLOCK (valid ID: " + validPathIdString + ")|"); // dump position of the element in the graph (for each valid path) for (int nodeIdx = 0; nodeIdx < temp.correspondingGraphNodes.Count(); nodeIdx++) { String positionString = ""; foreach (int position in temp.correspondingGraphNodes.ElementAt(nodeIdx).graphNode.positionInGraph) { positionString += position.ToString() + ";"; } dotFile.Write("POSITION " + positionString + " (valid ID: " + temp.correspondingGraphNodes.ElementAt(nodeIdx).validPathId.ToString() + ")|"); } } else if ((metadata as DevBasicBlock) != null) { DevBasicBlock temp = (metadata as DevBasicBlock); dotFile.Write("DEV_NOTE: " + temp.note + "|"); } else { throw new ArgumentException("Do not know how to handle transformation metadata."); } } } else { dotFile.Write("|"); } // insert try block beginnings foreach (var tryBlock in currentBasicBlock.tryBlocks) { if (tryBlock.firstBasicBlockOfTryBlock && opIdx == 0) { dotFile.Write("TRY START (" + this.sanitizeString(tryBlock.exceptionHandler.ExceptionType.ToString()) + ")|"); } } // insert catch block beginnings foreach (var handlerBlock in currentBasicBlock.handlerBlocks) { if (handlerBlock.firstBasicBlockOfHandlerBlock && opIdx == 0) { if (handlerBlock.typeOfHandler == HandlerKind.Catch) { dotFile.Write("CATCH START (" + this.sanitizeString(handlerBlock.exceptionHandler.ExceptionType.ToString()) + ")|"); } else if (handlerBlock.typeOfHandler == HandlerKind.Finally) { dotFile.Write("FINALLY START (" + this.sanitizeString(handlerBlock.exceptionHandler.ExceptionType.ToString()) + ")|"); } else { throw new ArgumentException("Do not know how to handle handler."); } } } // check if instruction has an argument if (operation.Value != null) { dotFile.Write(operation.OperationCode.ToString() + " " + this.sanitizeString(operation.Value.ToString())); } else { dotFile.Write(operation.OperationCode.ToString()); } // insert try block endings foreach (var tryBlock in currentBasicBlock.tryBlocks) { if (tryBlock.lastBasicBlockOfTryBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) { dotFile.Write("|TRY END (" + this.sanitizeString(tryBlock.exceptionHandler.ExceptionType.ToString()) + ")"); } } // insert catch block endings foreach (var handlerBlock in currentBasicBlock.handlerBlocks) { if (handlerBlock.lastBasicBlockOfHandlerBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) { if (handlerBlock.typeOfHandler == HandlerKind.Catch) { dotFile.Write("|CATCH END (" + this.sanitizeString(handlerBlock.exceptionHandler.ExceptionType.ToString()) + ")"); } else if (handlerBlock.typeOfHandler == HandlerKind.Finally) { dotFile.Write("|FINALLY END (" + this.sanitizeString(handlerBlock.exceptionHandler.ExceptionType.ToString()) + ")"); } else { throw new ArgumentException("Do not know how to handle handler."); } } } } dotFile.WriteLine("}\"]"); foreach (IBranchTarget entry in methodCfg.basicBlocks.ElementAt(idx).entryBranches) { // search index of exit basic block in cfg for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == entry.sourceBasicBlock) { dotFile.WriteLine("BB" + tempIdx.ToString() + " -> BB" + idx.ToString() + "[ color=\"blue\" ]"); break; } } } } // finish graph dotFile.WriteLine("}"); dotFile.Close(); // dump a clean cfg created from the exit branches dotFile = new System.IO.StreamWriter(this.logPath + "\\clean_" + fileName + ".dot"); // start .dot file graph dotFile.WriteLine("digraph G {"); // write all basic blocks to .dot file for (int idx = 0; idx < methodCfg.basicBlocks.Count(); idx++) { BasicBlock currentBasicBlock = methodCfg.basicBlocks.ElementAt(idx); // write the current basic block to the file dotFile.WriteLine("BB" + idx.ToString() + " [shape=record]"); dotFile.WriteLine("BB" + idx.ToString() + " [label=\"\"]"); // write all the exits of the basic block to the file if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as NoBranchTarget != null) { NoBranchTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as NoBranchTarget); // search index of exit basic block in cfg for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.takenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"black\" ]"); break; } } } else if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as TryBlockTarget != null) { TryBlockTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as TryBlockTarget); // search index of exit basic block in cfg for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.takenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"black\" ]"); break; } } } else if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as UnconditionalBranchTarget); // search index of exit basic block in cfg for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.takenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"black\" ]"); break; } } } else if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as ConditionalBranchTarget); // search index of exit basic block in cfg bool takenTargetFound = false; bool notTakenTargetFound = false; for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.takenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"black\" ]"); takenTargetFound = true; } else if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.notTakenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"black\" ]"); notTakenTargetFound = true; } else if (takenTargetFound && notTakenTargetFound) { break; } } } else if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as SwitchBranchTarget); // search index of exit basic block in cfg for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.notTakenTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"black\" ]"); break; } } // search index for all exit basic blocks in cfg foreach (BasicBlock exitBasicBlock in tempBranch.takenTarget) { for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == exitBasicBlock) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"black\" ]"); break; } } } } else if (methodCfg.basicBlocks.ElementAt(idx).exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget tempBranch = (methodCfg.basicBlocks.ElementAt(idx).exitBranch as ExceptionBranchTarget); // search index of exit basic block in cfg bool exitTargetFound = false; bool exceptionTargetFound = false; for (int tempIdx = 0; tempIdx < methodCfg.basicBlocks.Count(); tempIdx++) { if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.exitTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"black\" ]"); exitTargetFound = true; } else if (methodCfg.basicBlocks.ElementAt(tempIdx) == tempBranch.exceptionTarget) { dotFile.WriteLine("BB" + idx.ToString() + " -> BB" + tempIdx.ToString() + "[ color=\"black\" ]"); exceptionTargetFound = true; } else if (exitTargetFound && exceptionTargetFound) { break; } } } } // finish graph dotFile.WriteLine("}"); dotFile.Close(); }
// creates a duplicate of the given source basic block with the branch targets to semantically equivalent basic blocks // (not necessary the target basic block of the given source basic block) private BasicBlock duplicateBasicBlock(MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock sourceBasicBlock) { // search for a semantically equal basic block in the unmodified method CFG int searchSementicId = sourceBasicBlock.semanticId; BasicBlock copiedOriginalTargetBasicBlock = null; if (searchSementicId == -1) { throw new ArgumentException("No distinct semantic id given to search for."); } foreach (BasicBlock searchBasicBlock in originalMethodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { copiedOriginalTargetBasicBlock = searchBasicBlock; break; } } if (copiedOriginalTargetBasicBlock == null) { throw new ArgumentException("Not able to find semantically equal basic block in copied CFG."); } // create a new basic block BasicBlock newBasicBlock = new BasicBlock(); // copy simple values newBasicBlock.semanticId = copiedOriginalTargetBasicBlock.semanticId; newBasicBlock.startIdx = copiedOriginalTargetBasicBlock.startIdx; newBasicBlock.endIdx = copiedOriginalTargetBasicBlock.endIdx; // copy all operations of the basic block foreach (IOperation operation in copiedOriginalTargetBasicBlock.operations) { newBasicBlock.operations.Add(this.helperClass.createNewOperation(operation.OperationCode, operation.Value, operation.Location, operation.Offset)); } if (copiedOriginalTargetBasicBlock.tryBlocks.Count() != 0 || copiedOriginalTargetBasicBlock.handlerBlocks.Count() != 0) { throw new ArgumentException("Not implemented yet."); } // create an exit branch for the new basic block if ((copiedOriginalTargetBasicBlock.exitBranch as NoBranchTarget) != null) { //throw new ArgumentException("Not implemented yet."); // TODO: problem here with having 2 no branches before a basic block (but not necessarily because all branches are processed and exchanged) NoBranchTarget exitBranch = (copiedOriginalTargetBasicBlock.exitBranch as NoBranchTarget); // create a copied exit branch NoBranchTarget copiedExitBranch = new NoBranchTarget(); copiedExitBranch.sourceBasicBlock = newBasicBlock; newBasicBlock.exitBranch = copiedExitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) searchSementicId = exitBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); 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."); } // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition); // set basic block as target for the branch targetBasicBlock.entryBranches.Add(copiedExitBranch); copiedExitBranch.takenTarget = targetBasicBlock; } else if (copiedOriginalTargetBasicBlock.exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget exitBranch = (copiedOriginalTargetBasicBlock.exitBranch as UnconditionalBranchTarget); // create a copied exit branch UnconditionalBranchTarget copiedExitBranch = new UnconditionalBranchTarget(); copiedExitBranch.sourceBasicBlock = newBasicBlock; newBasicBlock.exitBranch = copiedExitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) searchSementicId = exitBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); 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."); } // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition); // set basic block as target for the branch targetBasicBlock.entryBranches.Add(copiedExitBranch); copiedExitBranch.takenTarget = targetBasicBlock; } else if (copiedOriginalTargetBasicBlock.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget exitBranch = (copiedOriginalTargetBasicBlock.exitBranch as ConditionalBranchTarget); // create a copied exit branch ConditionalBranchTarget copiedExitBranch = new ConditionalBranchTarget(); copiedExitBranch.sourceBasicBlock = newBasicBlock; newBasicBlock.exitBranch = copiedExitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) (for "taken" branch) searchSementicId = exitBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); 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."); } // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition); // set basic block as target for the branch targetBasicBlock.entryBranches.Add(copiedExitBranch); copiedExitBranch.takenTarget = targetBasicBlock; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) (for "not taken" branch) searchSementicId = exitBranch.notTakenTarget.semanticId; possibleTargetBasicBlocks = new List<BasicBlock>(); 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."); } // use a random possible basic block as target randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition); // set basic block as target for the branch targetBasicBlock.entryBranches.Add(copiedExitBranch); copiedExitBranch.notTakenTarget = targetBasicBlock; } else if (copiedOriginalTargetBasicBlock.exitBranch as SwitchBranchTarget != null) { throw new ArgumentException("Not implemented yet."); } else if (copiedOriginalTargetBasicBlock.exitBranch as ExitBranchTarget != null) { // create a copied exit branch ExitBranchTarget copiedExitBranch = new ExitBranchTarget(); copiedExitBranch.sourceBasicBlock = newBasicBlock; newBasicBlock.exitBranch = copiedExitBranch; } else if (copiedOriginalTargetBasicBlock.exitBranch as ThrowBranchTarget != null) { throw new ArgumentException("Not implemented yet."); } else if (copiedOriginalTargetBasicBlock.exitBranch as TryBlockTarget != null) { throw new ArgumentException("Not implemented yet."); } else if (copiedOriginalTargetBasicBlock.exitBranch as ExceptionBranchTarget != null) { throw new ArgumentException("Not implemented yet."); } else { throw new ArgumentException("Do not know how to handle exit branch."); } return newBasicBlock; }