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;
                }
            }
        }
Beispiel #2
0
        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;
                }
            }
        }