public void addObfuscationToMethod(MethodCfg methodCfg) { MethodCfg copyMethodCfg = new MethodCfg(methodCfg); CfgManipulator cfgManipulator = new CfgManipulator(this.module, this.host, this.logger, methodCfg); GraphRandomStateGenerator randomStateGenerator = new GraphRandomStateGenerator(this.module, this.host, this.logger, cfgManipulator, this.helperClass, this.graph, methodCfg, this.debugging); // DEBUG if (this.debugging) { //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)); this.debuggingNumber++; } // add local state variable LocalDefinition intStateLocal = new LocalDefinition(); intStateLocal.IsReference = false; intStateLocal.IsPinned = false; intStateLocal.IsModified = false; intStateLocal.Type = this.host.PlatformType.SystemInt32; intStateLocal.MethodDefinition = methodCfg.method; cfgManipulator.addLocalVariable(intStateLocal); // add local current graph node variable LocalDefinition currentNodeLocal = new LocalDefinition(); currentNodeLocal.IsReference = false; currentNodeLocal.IsPinned = false; currentNodeLocal.IsModified = false; currentNodeLocal.Type = this.nodeInterface; currentNodeLocal.MethodDefinition = methodCfg.method; cfgManipulator.addLocalVariable(currentNodeLocal); // create new basic block that sets the current node to the start node and get the state // (will be the new starting basic block of the method) BasicBlock startBasicBlock = new BasicBlock(); startBasicBlock.startIdx = 0; startBasicBlock.endIdx = 0; // set the current node pointer to the start node startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Stloc, currentNodeLocal)); // initialize the random state generator List<IOperation> tempOperations = randomStateGenerator.generateCodeInitializeRandomState(); startBasicBlock.operations.AddRange(tempOperations); // set global state tempOperations = randomStateGenerator.generateCodeSetRandomState(intStateLocal); startBasicBlock.operations.AddRange(tempOperations); // create exit branch for the new start basic block NoBranchTarget startExitBranch = new NoBranchTarget(); startExitBranch.sourceBasicBlock = startBasicBlock; startBasicBlock.exitBranch = startExitBranch; // set the original start basic block as the target of the exit branch startExitBranch.takenTarget = methodCfg.startBasicBlock; methodCfg.startBasicBlock.entryBranches.Add(startExitBranch); // set new start basic block as start basic block of the method cfg methodCfg.startBasicBlock = startBasicBlock; methodCfg.basicBlocks.Add(startBasicBlock); // obfuscate the control flow this.addMetadataIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal); this.processExitBranchesIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal); this.addOpaquePredicatesIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal); this.removeReplaceUnconditionalBranchesIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal); // fill dead code basic blocks with actual dead code this.fillDeadCodeBasicBlocks(methodCfg); this.obfuscateSemanticallyEquivalentBlocks(methodCfg); // TODO QUICK FIX // mutateBlocks() does not work when debugging is deactivated // but since we only focus on probabilistic control flow, ignore it for now this.debugging = true; this.mutateBlocks(methodCfg); this.debugging = false; // if debugging is activated => add code that allows to trace the control flow through the method if (this.debugging || this.trace) { List<IOperation> traceWriterOperations = null; // add code to the beginning of each basic block that writes to the trace file for (int idx = 0; idx < methodCfg.basicBlocks.Count(); idx++) { traceWriterOperations = new List<IOperation>(); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldfld, this.debuggingTraceWriter)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, "BB" + idx.ToString() + ";ID" + methodCfg.basicBlocks.ElementAt(idx).id.ToString())); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.textWriterWriteLine)); methodCfg.basicBlocks.ElementAt(idx).operations.InsertRange(0, traceWriterOperations); // check if the basic block has an exit branch // => add code that closes the file handler of the trace file before the ret instruction if ((methodCfg.basicBlocks.ElementAt(idx).exitBranch as ExitBranchTarget) != null) { traceWriterOperations = new List<IOperation>(); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldfld, this.debuggingTraceWriter)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.textWriterClose)); methodCfg.basicBlocks.ElementAt(idx).operations.InsertRange(methodCfg.basicBlocks.ElementAt(idx).operations.Count() - 1, traceWriterOperations); } } // create local integer variable needed for the trace file code LocalDefinition intLocal = new LocalDefinition(); intLocal.IsReference = false; intLocal.IsPinned = false; intLocal.IsModified = false; intLocal.Type = this.host.PlatformType.SystemInt32; intLocal.MethodDefinition = methodCfg.method; cfgManipulator.addLocalVariable(intLocal); traceWriterOperations = new List<IOperation>(); // get the hash code of this instance as unique object id traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.objectGetHashCode)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Stloc, intLocal)); // initialize io stream writer for trace file (use object hash as id for this trace and only append) traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingDumpLocation + "\\" + this.debuggingTraceFilePrefix + "_")); // cast random integer to string and store in object id traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloca, intLocal)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Call, this.helperClass.int32ToString)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, ".txt")); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Call, this.helperClass.stringConcatThree)); // only append to file traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_1)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Newobj, this.helperClass.streamWriterCtorAppend)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Stfld, this.debuggingTraceWriter)); // write marker to trace file that marks the beginning of this trace traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldfld, this.debuggingTraceWriter)); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, "\n------NEWSTART------\n")); traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.textWriterWriteLine)); // add code to the beginning of the start basic block methodCfg.startBasicBlock.operations.InsertRange(0, traceWriterOperations); } logger.dumpMethodCfg(copyMethodCfg, "copy_final"); return; }
// this function generates code for the "state change" private void createCodeStateChange(ref BasicBlock outStateChangeBasicBlock, ref SwitchBranchTarget outStateChangeExitBranch, GraphRandomStateGenerator randomStateGenerator, BasicBlockGraphNodeLink link, LocalDefinition intStateLocal) { // create a basic block to change the current global state BasicBlock stateChangeBasicBlock = new BasicBlock(); stateChangeBasicBlock.startIdx = 0; stateChangeBasicBlock.endIdx = 0; // create graph transformer metadata for the basic block GraphTransformerStateChangeBasicBlock metadataChange = new GraphTransformerStateChangeBasicBlock(); metadataChange.correspondingGraphNodes.Add(link); stateChangeBasicBlock.transformationMetadata.Add(metadataChange); // generate code for setting the new global state List<IOperation> tempOperations = randomStateGenerator.generateCodeSetRandomState(intStateLocal); stateChangeBasicBlock.operations.AddRange(tempOperations); // create switch statement for the "state switch" stateChangeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, intStateLocal)); uint[] switchSize = new uint[this.graph.graphValidPathCount]; stateChangeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Switch, switchSize)); // create exit branch for the new state basic block SwitchBranchTarget stateChangeExitBranch = new SwitchBranchTarget(); stateChangeExitBranch.sourceBasicBlock = stateChangeBasicBlock; stateChangeBasicBlock.exitBranch = stateChangeExitBranch; // create the dead code for this "state switch" BasicBlock deadCodeBasicBlock = new BasicBlock(); deadCodeBasicBlock.startIdx = 0; deadCodeBasicBlock.endIdx = 0; // set the dead code basic block as "not taken" target for the conditional branch of the checking basic block deadCodeBasicBlock.entryBranches.Add(stateChangeExitBranch); stateChangeExitBranch.notTakenTarget = deadCodeBasicBlock; // TODO at the moment always the not taken branch of the switch statement is the dead code basic block // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); outStateChangeBasicBlock = stateChangeBasicBlock; outStateChangeExitBranch = stateChangeExitBranch; }