static void ReplaceCFG(MethodDef method, List <Tuple <Instruction, uint, IMethod> > instrs, CEContext ctx) { InjectStateType(ctx); var graph = ControlFlowGraph.Construct(method.Body); var sequence = KeySequence.ComputeKeys(graph, null); var cfgCtx = new CFGContext { Ctx = ctx, Graph = graph, Keys = sequence, StatesMap = new Dictionary <uint, CFGState>(), Random = ctx.Random }; cfgCtx.StateVariable = new Local(ctx.CfgCtxType.ToTypeSig()); method.Body.Variables.Add(cfgCtx.StateVariable); method.Body.InitLocals = true; var blockReferences = new Dictionary <int, SortedList <int, Tuple <Instruction, uint, IMethod> > >(); foreach (var instr in instrs) { var index = graph.IndexOf(instr.Item1); var block = graph.GetContainingBlock(index); SortedList <int, Tuple <Instruction, uint, IMethod> > list; if (!blockReferences.TryGetValue(block.Id, out list)) { list = blockReferences[block.Id] = new SortedList <int, Tuple <Instruction, uint, IMethod> >(); } list.Add(index, instr); } // Update state for blocks not in use for (int i = 0; i < graph.Count; i++) { var block = graph[i]; if (blockReferences.ContainsKey(block.Id)) { continue; } InsertEmptyStateUpdate(cfgCtx, block); } // Update references foreach (var blockRef in blockReferences) { var key = sequence[blockRef.Key]; CFGState currentState; if (!cfgCtx.StatesMap.TryGetValue(key.EntryState, out currentState)) { Debug.Assert((graph[blockRef.Key].Type & ControlFlowBlockType.Entry) != 0); Debug.Assert(key.Type == BlockKeyType.Explicit); // Create new entry state uint blockSeed = ctx.Random.NextUInt32(); currentState = new CFGState(blockSeed); cfgCtx.StatesMap[key.EntryState] = currentState; var index = graph.Body.Instructions.IndexOf(graph[blockRef.Key].Header); Instruction newHeader; method.Body.Instructions.Insert(index++, newHeader = Instruction.Create(OpCodes.Ldloca, cfgCtx.StateVariable)); method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)blockSeed)); method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.CfgCtxCtor)); method.Body.ReplaceReference(graph[blockRef.Key].Header, newHeader); key.Type = BlockKeyType.Incremental; } var type = key.Type; for (int i = 0; i < blockRef.Value.Count; i++) { var refEntry = blockRef.Value.Values[i]; CFGState?targetState = null; if (i == blockRef.Value.Count - 1) { CFGState exitState; if (cfgCtx.StatesMap.TryGetValue(key.ExitState, out exitState)) { targetState = exitState; } } var index = graph.Body.Instructions.IndexOf(refEntry.Item1) + 1; var value = InsertStateGetAndUpdate(cfgCtx, ref index, type, ref currentState, targetState); refEntry.Item1.OpCode = OpCodes.Ldc_I4; refEntry.Item1.Operand = (int)(refEntry.Item2 ^ value); method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Xor)); method.Body.Instructions.Insert(index, Instruction.Create(OpCodes.Call, refEntry.Item3)); if (i == blockRef.Value.Count - 1 && targetState == null) { cfgCtx.StatesMap[key.ExitState] = currentState; } type = BlockKeyType.Incremental; } } }
static void ReplaceCFG(MethodDef method, List <Tuple <Instruction, uint, IMethod> > instrs, CEContext ctx) { var graph = ControlFlowGraph.Construct(method.Body); var sequence = KeySequence.ComputeKeys(graph, ctx.Random); var cfgCtx = new CFGContext { Graph = graph, Keys = sequence, Random = ctx.Random }; var blockReferences = new Dictionary <int, SortedList <int, Tuple <Instruction, uint, IMethod> > >(); foreach (var instr in instrs) { var index = graph.IndexOf(instr.Item1); var block = graph.GetContainingBlock(index); SortedList <int, Tuple <Instruction, uint, IMethod> > list; if (!blockReferences.TryGetValue(block.Id, out list)) { list = blockReferences[block.Id] = new SortedList <int, Tuple <Instruction, uint, IMethod> >(); } list.Add(index, instr); } cfgCtx.StateVariable = new Local(method.Module.CorLibTypes.UInt32); method.Body.Variables.Add(cfgCtx.StateVariable); method.Body.InitLocals = true; // Update state for blocks not in use for (int i = 0; i < graph.Count; i++) { if (blockReferences.ContainsKey(i)) { continue; } InsertEmptyStateUpdate(cfgCtx, graph[i]); } // Update references foreach (var blockRef in blockReferences) { var key = sequence[blockRef.Key]; var currentState = key.EntryState; var type = key.Type; for (int i = 0; i < blockRef.Value.Count; i++) { var entry = blockRef.Value.Values[i]; var targetState = i == blockRef.Value.Count - 1 ? key.ExitState : cfgCtx.Random.NextUInt32(); var index = graph.Body.Instructions.IndexOf(entry.Item1); var id = entry.Item2 ^ currentState; entry.Item1.OpCode = OpCodes.Ldc_I4; entry.Item1.Operand = (int)id; index = InsertStateGetAndUpdate(cfgCtx, index + 1, type, currentState, targetState); method.Body.Instructions.Insert(index + 0, Instruction.Create(OpCodes.Xor)); method.Body.Instructions.Insert(index + 1, Instruction.Create(OpCodes.Call, entry.Item3)); type = BlockKeyType.Incremental; currentState = targetState; } } }