示例#1
0
        public override void Mangle(CilBody body, ScopeBlock root, CFContext ctx)
        {
            Trace trace = new Trace(body, ctx.Method.ReturnType.RemoveModifiers().ElementType != ElementType.Void);
            var local = new Local(ctx.Method.Module.CorLibTypes.UInt32);
            body.Variables.Add(local);
            body.InitLocals = true;

            body.MaxStack += 2;
            IPredicate predicate = null;
            if (ctx.Predicate == PredicateType.Normal) {
                predicate = new NormalPredicate(ctx);
            }
            else if (ctx.Predicate == PredicateType.Expression) {
                predicate = new ExpressionPredicate(ctx);
            }
            else if (ctx.Predicate == PredicateType.x86) {
                predicate = new x86Predicate(ctx);
            }

            foreach (InstrBlock block in GetAllBlocks(root)) {
                LinkedList<Instruction[]> statements = SpiltStatements(block, trace, ctx);

                // Make sure .ctor is executed before switch
                if (ctx.Method.IsInstanceConstructor) {
                    var newStatement = new List<Instruction>();
                    while (statements.First != null) {
                        newStatement.AddRange(statements.First.Value);
                        Instruction lastInstr = statements.First.Value.Last();
                        statements.RemoveFirst();
                        if (lastInstr.OpCode == OpCodes.Call && ((IMethod)lastInstr.Operand).Name == ".ctor")
                            break;
                    }
                    statements.AddFirst(newStatement.ToArray());
                }

                if (statements.Count < 3) continue;

                int i;

                var keyId = Enumerable.Range(0, statements.Count).ToArray();
                ctx.Random.Shuffle(keyId);
                var key = new int[keyId.Length];
                for (i = 0; i < key.Length; i++) {
                    var q = ctx.Random.NextInt32() & 0x7fffffff;
                    key[i] = q - q % statements.Count + keyId[i];
                }

                var statementKeys = new Dictionary<Instruction, int>();
                LinkedListNode<Instruction[]> current = statements.First;
                i = 0;
                while (current != null) {
                    if (i != 0)
                        statementKeys[current.Value[0]] = key[i];
                    i++;
                    current = current.Next;
                }

                var statementLast = new HashSet<Instruction>(statements.Select(st => st.Last()));

                Func<IList<Instruction>, bool> hasUnknownSource;
                hasUnknownSource = instrs => instrs.Any(instr => {
                    if (trace.HasMultipleSources(instr.Offset))
                        return true;
                    List<Instruction> srcs;
                    if (trace.BrRefs.TryGetValue(instr.Offset, out srcs)) {
                        // Target of switch => assume unknown
                        if (srcs.Any(src => src.Operand is Instruction[]))
                            return true;

                        // Not within current instruction block / targeted in first statement
                        if (srcs.Any(src => src.Offset <= statements.First.Value.Last().Offset ||
                                            src.Offset >= block.Instructions.Last().Offset))
                            return true;

                        // Not targeted by the last of statements
                        if (srcs.Any(src => statementLast.Contains(src)))
                            return true;
                    }
                    return false;
                });

                var switchInstr = new Instruction(OpCodes.Switch);
                var switchHdr = new List<Instruction>();

                if (predicate != null) {
                    predicate.Init(body);
                    switchHdr.Add(Instruction.CreateLdcI4(predicate.GetSwitchKey(key[1])));
                    predicate.EmitSwitchLoad(switchHdr);
                }
                else {
                    switchHdr.Add(Instruction.CreateLdcI4(key[1]));
                }

                switchHdr.Add(Instruction.Create(OpCodes.Dup));
                switchHdr.Add(Instruction.Create(OpCodes.Stloc, local));
                switchHdr.Add(Instruction.Create(OpCodes.Ldc_I4, statements.Count));
                switchHdr.Add(Instruction.Create(OpCodes.Rem_Un));
                switchHdr.Add(switchInstr);

                if (trace.BeforeStack[statements.Last.Value[0].Offset] == 0)
                {
                    ctx.AddJump(switchHdr, statements.Last.Value[0]);
                }
                else
                {
                    ctx.AddJump(switchHdr, switchHdr[0]);
                }
                ctx.AddJunk(switchHdr);

                var operands = new Instruction[statements.Count];
                current = statements.First;
                i = 0;
                while (current.Next != null) {
                    var newStatement = new List<Instruction>(current.Value);

                    if (i != 0) {
                        // Convert to switch
                        bool converted = false;

                        if (newStatement.Last().IsBr()) {
                            // Unconditional

                            var target = (Instruction)newStatement.Last().Operand;
                            int brKey;
                            if (!trace.IsBranchTarget(newStatement.Last().Offset) &&
                                statementKeys.TryGetValue(target, out brKey)) {

                                if (trace.BeforeStack[target.Offset] == 0)
                                {
                                    var targetKey = predicate != null ? predicate.GetSwitchKey(brKey) : brKey;
                                    var unkSrc = hasUnknownSource(newStatement);

                                    var initialBeforeStack = trace.BeforeStack[newStatement[0].Offset];
                                    newStatement.RemoveAt(newStatement.Count - 1);

                                    if (unkSrc || initialBeforeStack != 0) {
                                        newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey));
                                    }
                                    else {
                                        var thisKey = key[i];
                                        var r = ctx.Random.NextInt32();
                                        newStatement.Add(Instruction.Create(OpCodes.Ldloc, local));
                                        newStatement.Add(Instruction.CreateLdcI4(r));
                                        newStatement.Add(Instruction.Create(OpCodes.Mul));
                                        newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey * r) ^ targetKey));
                                        newStatement.Add(Instruction.Create(OpCodes.Xor));
                                    }

                                    ctx.AddJump(newStatement, switchHdr[1]);
                                    ctx.AddJunk(newStatement);
                                }

                                if (trace.BeforeStack[newStatement[0].Offset] == 0)
                                {
                                    operands[keyId[i]] = newStatement[0];
                                }

                                converted = true;
                            }
                        }
                        else if (newStatement.Last().IsConditionalBranch()) {
                            // Conditional

                            var target = (Instruction)newStatement.Last().Operand;
                            int brKey;
                            if (!trace.IsBranchTarget(newStatement.Last().Offset) &&
                                statementKeys.TryGetValue(target, out brKey)) {

                                if (trace.BeforeStack[target.Offset] == 0)
                                {
                                    bool unkSrc = hasUnknownSource(newStatement);
                                    int nextKey = key[i + 1];
                                    OpCode condBr = newStatement.Last().OpCode;
                                    newStatement.RemoveAt(newStatement.Count - 1);

                                    if (ctx.Random.NextBoolean()) {
                                        condBr = InverseBranch(condBr);
                                        int tmp = brKey;
                                        brKey = nextKey;
                                        nextKey = tmp;
                                    }

                                    var thisKey = key[i];
                                    int r = 0, xorKey = 0;
                                    if (!unkSrc) {
                                        r = ctx.Random.NextInt32();
                                        xorKey = thisKey * r;
                                    }

                                    Instruction brKeyInstr = Instruction.CreateLdcI4(xorKey ^ (predicate != null ? predicate.GetSwitchKey(brKey) : brKey));
                                    Instruction nextKeyInstr = Instruction.CreateLdcI4(xorKey ^ (predicate != null ? predicate.GetSwitchKey(nextKey) : nextKey));
                                    Instruction pop = Instruction.Create(OpCodes.Pop);

                                    newStatement.Add(Instruction.Create(condBr, brKeyInstr));
                                    newStatement.Add(nextKeyInstr);
                                    newStatement.Add(Instruction.Create(OpCodes.Dup));
                                    newStatement.Add(Instruction.Create(OpCodes.Br, pop));
                                    newStatement.Add(brKeyInstr);
                                    newStatement.Add(Instruction.Create(OpCodes.Dup));
                                    newStatement.Add(pop);

                                    if (!unkSrc) {
                                        newStatement.Add(Instruction.Create(OpCodes.Ldloc, local));
                                        newStatement.Add(Instruction.CreateLdcI4(r));
                                        newStatement.Add(Instruction.Create(OpCodes.Mul));
                                        newStatement.Add(Instruction.Create(OpCodes.Xor));
                                    }

                                    ctx.AddJump(newStatement, switchHdr[1]);
                                    ctx.AddJunk(newStatement);

                                    converted = true;
                                }

                                if (trace.BeforeStack[newStatement[0].Offset] == 0)
                                {
                                    operands[keyId[i]] = newStatement[0];
                                }
                            }
                        }

                        if (!converted) {
                            // Normal

                            if (newStatement[newStatement.Count - 1].OpCode != OpCodes.Ret)
                            {
                                var nextStatement = current.Next;
                                if (trace.BeforeStack[nextStatement.Value[0].Offset] == 0)
                                {
                                    var targetKey = predicate != null ? predicate.GetSwitchKey(key[i + 1]) : key[i + 1];
                                    if (!hasUnknownSource(newStatement) && trace.BeforeStack[newStatement[0].Offset] == 0)
                                    {
                                        var thisKey = key[i];
                                        var r = ctx.Random.NextInt32();
                                        newStatement.Add(Instruction.Create(OpCodes.Ldloc, local));
                                        newStatement.Add(Instruction.CreateLdcI4(r));
                                        newStatement.Add(Instruction.Create(OpCodes.Mul));
                                        newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey*r) ^ targetKey));
                                        newStatement.Add(Instruction.Create(OpCodes.Xor));
                                    }
                                    else
                                    {
                                        newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey));
                                    }

                                    ctx.AddJump(newStatement, switchHdr[1]);
                                    ctx.AddJunk(newStatement);
                                }
                                else
                                {
                                    newStatement.Add(Instruction.Create(OpCodes.Br, nextStatement.Value[0]));
                                }
                            }

                            if (trace.BeforeStack[newStatement[0].Offset] == 0)
                            {
                                operands[keyId[i]] = newStatement[0];
                            }
                        }
                    }
                    else
                        operands[keyId[i]] = switchHdr[0];

                    current.Value = newStatement.ToArray();
                    current = current.Next;
                    i++;
                }

                if (trace.BeforeStack[current.Value[0].Offset] == 0)
                {
                    operands[keyId[i]] = current.Value[0];
                }

                for (i = 0; i < operands.Length; i++)
                {
                    if (operands[i] == null)
                    {
                        operands[i] = switchHdr[0];
                    }
                }

                switchInstr.Operand = operands;

                Instruction[] first = statements.First.Value;
                statements.RemoveFirst();
                Instruction[] last = statements.Last.Value;
                statements.RemoveLast();

                List<Instruction[]> newStatements = statements.Where(s => trace.BeforeStack[s[0].Offset] == 0).ToList();
                ctx.Random.Shuffle(newStatements);

                List<Instruction[]> newOrderedStatements = statements.Where(s => trace.BeforeStack[s[0].Offset] != 0).ToList();

                block.Instructions.Clear();
                block.Instructions.AddRange(first);
                block.Instructions.AddRange(switchHdr);
                foreach (var statement in newStatements)
                    block.Instructions.AddRange(statement);
                foreach (var statement in newOrderedStatements)
                    block.Instructions.AddRange(statement);
                block.Instructions.AddRange(last);
            }
        }
示例#2
0
        public override void Mangle(CilBody body, ScopeBlock root, CFContext ctx)
        {
            Trace trace = new Trace(body, ctx.Method.ReturnType.RemoveModifiers().ElementType != ElementType.Void);
            var   local = new Local(ctx.Method.Module.CorLibTypes.UInt32);

            body.Variables.Add(local);
            body.InitLocals = true;

            body.MaxStack += 2;
            IPredicate predicate = null;

            if (ctx.Predicate == PredicateType.Normal)
            {
                predicate = new NormalPredicate(ctx);
            }
            else if (ctx.Predicate == PredicateType.Expression)
            {
                predicate = new ExpressionPredicate(ctx);
            }
            else if (ctx.Predicate == PredicateType.x86)
            {
                predicate = new x86Predicate(ctx);
            }

            foreach (InstrBlock block in GetAllBlocks(root))
            {
                LinkedList <Instruction[]> statements = SpiltStatements(block, trace, ctx);

                // Make sure .ctor is executed before switch
                if (ctx.Method.IsInstanceConstructor)
                {
                    var newStatement = new List <Instruction>();
                    while (statements.First != null)
                    {
                        newStatement.AddRange(statements.First.Value);
                        Instruction lastInstr = statements.First.Value.Last();
                        statements.RemoveFirst();
                        if (lastInstr.OpCode == OpCodes.Call && ((IMethod)lastInstr.Operand).Name == ".ctor")
                        {
                            break;
                        }
                    }
                    statements.AddFirst(newStatement.ToArray());
                }

                if (statements.Count < 3)
                {
                    continue;
                }

                int i;

                var keyId = Enumerable.Range(0, statements.Count).ToArray();
                ctx.Random.Shuffle(keyId);
                var key = new int[keyId.Length];
                for (i = 0; i < key.Length; i++)
                {
                    var q = ctx.Random.NextInt32() & 0x7fffffff;
                    key[i] = q - q % statements.Count + keyId[i];
                }

                var statementKeys = new Dictionary <Instruction, int>();
                LinkedListNode <Instruction[]> current = statements.First;
                i = 0;
                while (current != null)
                {
                    if (i != 0)
                    {
                        statementKeys[current.Value[0]] = key[i];
                    }
                    i++;
                    current = current.Next;
                }

                var statementLast = new HashSet <Instruction>(statements.Select(st => st.Last()));

                Func <IList <Instruction>, bool> hasUnknownSource;
                hasUnknownSource = instrs => instrs.Any(instr => {
                    if (trace.HasMultipleSources(instr.Offset))
                    {
                        return(true);
                    }
                    List <Instruction> srcs;
                    if (trace.BrRefs.TryGetValue(instr.Offset, out srcs))
                    {
                        // Target of switch => assume unknown
                        if (srcs.Any(src => src.Operand is Instruction[]))
                        {
                            return(true);
                        }

                        // Not within current instruction block / targeted in first statement
                        if (srcs.Any(src => src.Offset <= statements.First.Value.Last().Offset ||
                                     src.Offset >= block.Instructions.Last().Offset))
                        {
                            return(true);
                        }

                        // Not targeted by the last of statements
                        if (srcs.Any(src => statementLast.Contains(src)))
                        {
                            return(true);
                        }
                    }
                    return(false);
                });

                var switchInstr = new Instruction(OpCodes.Switch);
                var switchHdr   = new List <Instruction>();

                if (predicate != null)
                {
                    predicate.Init(body);
                    switchHdr.Add(Instruction.CreateLdcI4(predicate.GetSwitchKey(key[1])));
                    predicate.EmitSwitchLoad(switchHdr);
                }
                else
                {
                    switchHdr.Add(Instruction.CreateLdcI4(key[1]));
                }

                switchHdr.Add(Instruction.Create(OpCodes.Dup));
                switchHdr.Add(Instruction.Create(OpCodes.Stloc, local));
                switchHdr.Add(Instruction.Create(OpCodes.Ldc_I4, statements.Count));
                switchHdr.Add(Instruction.Create(OpCodes.Rem_Un));
                switchHdr.Add(switchInstr);

                ctx.AddJump(switchHdr, statements.Last.Value[0]);
                ctx.AddJunk(switchHdr);

                var operands = new Instruction[statements.Count];
                current = statements.First;
                i       = 0;
                while (current.Next != null)
                {
                    var newStatement = new List <Instruction>(current.Value);

                    if (i != 0)
                    {
                        // Convert to switch
                        bool converted = false;

                        if (newStatement.Last().IsBr())
                        {
                            // Unconditional

                            var target = (Instruction)newStatement.Last().Operand;
                            int brKey;
                            if (!trace.IsBranchTarget(newStatement.Last().Offset) &&
                                statementKeys.TryGetValue(target, out brKey))
                            {
                                var targetKey = predicate != null?predicate.GetSwitchKey(brKey) : brKey;

                                var unkSrc = hasUnknownSource(newStatement);

                                newStatement.RemoveAt(newStatement.Count - 1);

                                if (unkSrc)
                                {
                                    newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey));
                                }
                                else
                                {
                                    var   thisKey = key[i];
                                    var   r       = ctx.Random.NextInt32(-1000000, -1000);
                                    Local newarr  = new Local(ctx.Method.Module.ImportAsTypeSig(typeof(UIntPtr)));
                                    ctx.Method.Body.Variables.Add(newarr);
                                    newStatement.Add(OpCodes.Ldc_I4.ToInstruction((thisKey * r) ^ targetKey));
                                    newStatement.Add(OpCodes.Stloc.ToInstruction(newarr));
                                    newStatement.Add(Instruction.Create(OpCodes.Ldloc, local));
                                    newStatement.Add(Instruction.CreateLdcI4(r));
                                    newStatement.Add(Instruction.Create(OpCodes.Mul));
                                    newStatement.Add(OpCodes.Ldloc.ToInstruction(newarr));
                                    newStatement.Add(Instruction.Create(OpCodes.Xor));
                                }
                                // thanks to habib for giving me this control flow crasher ages ago
                                ctx.AddJump(newStatement, switchHdr[1]);
                                ctx.AddJunk(newStatement);
                                operands[keyId[i]] = newStatement[0];
                                converted          = true;
                            }
                        }
                        else if (newStatement.Last().IsConditionalBranch())
                        {
                            // Conditional

                            var target = (Instruction)newStatement.Last().Operand;
                            int brKey;
                            if (!trace.IsBranchTarget(newStatement.Last().Offset) &&
                                statementKeys.TryGetValue(target, out brKey))
                            {
                                bool   unkSrc  = hasUnknownSource(newStatement);
                                int    nextKey = key[i + 1];
                                OpCode condBr  = newStatement.Last().OpCode;
                                newStatement.RemoveAt(newStatement.Count - 1);

                                if (ctx.Random.NextBoolean())
                                {
                                    condBr = InverseBranch(condBr);
                                    int tmp = brKey;
                                    brKey   = nextKey;
                                    nextKey = tmp;
                                }

                                var thisKey = key[i];
                                int r = 0, xorKey = 0;
                                if (!unkSrc)
                                {
                                    r      = ctx.Random.NextInt32();
                                    xorKey = thisKey * r;
                                }

                                Instruction brKeyInstr   = Instruction.CreateLdcI4(xorKey ^ (predicate != null ? predicate.GetSwitchKey(brKey) : brKey));
                                Instruction nextKeyInstr = Instruction.CreateLdcI4(xorKey ^ (predicate != null ? predicate.GetSwitchKey(nextKey) : nextKey));
                                Instruction pop          = Instruction.Create(OpCodes.Pop);

                                newStatement.Add(Instruction.Create(condBr, brKeyInstr));
                                newStatement.Add(nextKeyInstr);
                                newStatement.Add(Instruction.Create(OpCodes.Dup));
                                newStatement.Add(Instruction.Create(OpCodes.Br, pop));
                                newStatement.Add(brKeyInstr);
                                newStatement.Add(Instruction.Create(OpCodes.Dup));
                                newStatement.Add(pop);

                                if (!unkSrc)
                                {
                                    newStatement.Add(Instruction.Create(OpCodes.Ldloc, local));
                                    newStatement.Add(Instruction.CreateLdcI4(r));
                                    newStatement.Add(Instruction.Create(OpCodes.Mul));
                                    newStatement.Add(Instruction.Create(OpCodes.Xor));
                                }

                                ctx.AddJump(newStatement, switchHdr[1]);
                                ctx.AddJunk(newStatement);
                                operands[keyId[i]] = newStatement[0];
                                converted          = true;
                            }
                        }

                        if (!converted)
                        {
                            // Normal

                            var targetKey = predicate != null?predicate.GetSwitchKey(key[i + 1]) : key[i + 1];

                            if (!hasUnknownSource(newStatement))
                            {
                                var   thisKey = key[i];
                                var   r       = ctx.Random.NextInt32(-1000000, -1000);
                                Local newarr  = new Local(ctx.Method.Module.ImportAsTypeSig(typeof(UIntPtr)));
                                ctx.Method.Body.Variables.Add(newarr);
                                newStatement.Add(OpCodes.Ldc_I4.ToInstruction((thisKey * r) ^ targetKey));
                                newStatement.Add(OpCodes.Stloc.ToInstruction(newarr));
                                newStatement.Add(Instruction.Create(OpCodes.Ldloc, local));
                                newStatement.Add(Instruction.CreateLdcI4(r));
                                newStatement.Add(Instruction.Create(OpCodes.Mul));
                                newStatement.Add(OpCodes.Ldloc.ToInstruction(newarr));
                                newStatement.Add(Instruction.Create(OpCodes.Xor));
                            }
                            else
                            {
                                newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey));
                            }

                            ctx.AddJump(newStatement, switchHdr[1]);
                            ctx.AddJunk(newStatement);
                            operands[keyId[i]] = newStatement[0];
                        }
                    }
                    else
                    {
                        operands[keyId[i]] = switchHdr[0];
                    }

                    current.Value = newStatement.ToArray();
                    current       = current.Next;
                    i++;
                }
                operands[keyId[i]]  = current.Value[0];
                switchInstr.Operand = operands;

                Instruction[] first = statements.First.Value;
                statements.RemoveFirst();
                Instruction[] last = statements.Last.Value;
                statements.RemoveLast();

                List <Instruction[]> newStatements = statements.ToList();
                ctx.Random.Shuffle(newStatements);

                block.Instructions.Clear();
                block.Instructions.AddRange(first);
                block.Instructions.AddRange(switchHdr);
                foreach (var statement in newStatements)
                {
                    block.Instructions.AddRange(statement);
                }
                block.Instructions.AddRange(last);
            }
        }
示例#3
0
        public override void Mangle(CilBody body, ScopeBlock root, CFContext ctx)
        {
            MethodTrace trace = ctx.Context.Registry.GetService <ITraceService>().Trace(ctx.Method);

            body.MaxStack += 2;
            IPredicate predicate = null;

            if (ctx.Predicate == PredicateType.Normal)
            {
                predicate = new NormalPredicate(ctx);
            }
            else if (ctx.Predicate == PredicateType.Expression)
            {
                predicate = new ExpressionPredicate(ctx);
            }
            else if (ctx.Predicate == PredicateType.x86)
            {
                predicate = new x86Predicate(ctx);
            }

            foreach (InstrBlock block in GetAllBlocks(root))
            {
                LinkedList <Instruction[]> statements = SpiltStatements(block, trace, ctx);

                // Make sure .ctor is executed before switch
                if (ctx.Method.IsInstanceConstructor)
                {
                    var newStatement = new List <Instruction>();
                    while (statements.First != null)
                    {
                        newStatement.AddRange(statements.First.Value);
                        Instruction lastInstr = statements.First.Value.Last();
                        statements.RemoveFirst();
                        if (lastInstr.OpCode == OpCodes.Call && ((IMethod)lastInstr.Operand).Name == ".ctor")
                        {
                            break;
                        }
                    }
                    statements.AddFirst(newStatement.ToArray());
                }

                if (statements.Count < 3)
                {
                    continue;
                }

                int[] key = Enumerable.Range(0, statements.Count).ToArray();
                ctx.Random.Shuffle(key);

                var statementKeys = new Dictionary <Instruction, int>();
                LinkedListNode <Instruction[]> current = statements.First;
                int i = 0;
                while (current != null)
                {
                    if (i != 0)
                    {
                        statementKeys[current.Value[0]] = key[i];
                    }
                    i++;
                    current = current.Next;
                }

                var switchInstr = new Instruction(OpCodes.Switch);

                var switchHdr = new List <Instruction>();

                if (predicate != null)
                {
                    predicate.Init(body);
                    switchHdr.Add(Instruction.CreateLdcI4(predicate.GetSwitchKey(key[1])));
                    predicate.EmitSwitchLoad(switchHdr);
                }
                else
                {
                    switchHdr.Add(Instruction.CreateLdcI4(key[1]));
                }

                switchHdr.Add(switchInstr);

                ctx.AddJump(switchHdr, statements.Last.Value[0]);
                ctx.AddJunk(switchHdr);

                var operands = new Instruction[statements.Count];
                current = statements.First;
                i       = 0;
                while (current.Next != null)
                {
                    var newStatement = new List <Instruction>(current.Value);

                    if (i != 0)
                    {
                        // Convert to switch
                        bool converted = false;

                        if (newStatement.Last().IsBr())
                        {
                            // Unconditional

                            var target = (Instruction)newStatement.Last().Operand;
                            int brKey;
                            if (!trace.IsBranchTarget(trace.OffsetToIndexMap(newStatement.Last().Offset)) &&
                                statementKeys.TryGetValue(target, out brKey))
                            {
                                newStatement.RemoveAt(newStatement.Count - 1);
                                newStatement.Add(Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(brKey) : brKey));
                                ctx.AddJump(newStatement, switchHdr[1]);
                                ctx.AddJunk(newStatement);
                                operands[key[i]] = newStatement[0];
                                converted        = true;
                            }
                        }
                        else if (newStatement.Last().IsConditionalBranch())
                        {
                            // Conditional

                            var target = (Instruction)newStatement.Last().Operand;
                            int brKey;
                            if (!trace.IsBranchTarget(trace.OffsetToIndexMap(newStatement.Last().Offset)) &&
                                statementKeys.TryGetValue(target, out brKey))
                            {
                                int    nextKey = key[i + 1];
                                OpCode condBr  = newStatement.Last().OpCode;
                                newStatement.RemoveAt(newStatement.Count - 1);

                                if (ctx.Random.NextBoolean())
                                {
                                    condBr = InverseBranch(condBr);
                                    int tmp = brKey;
                                    brKey   = nextKey;
                                    nextKey = tmp;
                                }

                                Instruction brKeyInstr   = Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(brKey) : brKey);
                                Instruction nextKeyInstr = Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(nextKey) : nextKey);
                                Instruction pop          = Instruction.Create(OpCodes.Pop);
                                newStatement.Add(Instruction.Create(condBr, brKeyInstr));
                                newStatement.Add(nextKeyInstr);
                                newStatement.Add(Instruction.Create(OpCodes.Dup));
                                newStatement.Add(Instruction.Create(OpCodes.Br, pop));
                                newStatement.Add(brKeyInstr);
                                newStatement.Add(Instruction.Create(OpCodes.Dup));
                                newStatement.Add(pop);

                                ctx.AddJump(newStatement, switchHdr[1]);
                                ctx.AddJunk(newStatement);
                                operands[key[i]] = newStatement[0];
                                converted        = true;
                            }
                        }

                        if (!converted)
                        {
                            // Normal

                            newStatement.Add(Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(key[i + 1]) : key[i + 1]));
                            ctx.AddJump(newStatement, switchHdr[1]);
                            ctx.AddJunk(newStatement);
                            operands[key[i]] = newStatement[0];
                        }
                    }
                    else
                    {
                        operands[key[i]] = switchHdr[0];
                    }

                    current.Value = newStatement.ToArray();
                    current       = current.Next;
                    i++;
                }
                operands[key[i]]    = current.Value[0];
                switchInstr.Operand = operands;

                Instruction[] first = statements.First.Value;
                statements.RemoveFirst();
                Instruction[] last = statements.Last.Value;
                statements.RemoveLast();

                List <Instruction[]> newStatements = statements.ToList();
                ctx.Random.Shuffle(newStatements);

                block.Instructions.Clear();
                block.Instructions.AddRange(first);
                block.Instructions.AddRange(switchHdr);
                foreach (var statement in newStatements)
                {
                    block.Instructions.AddRange(statement);
                }
                block.Instructions.AddRange(last);
            }
        }
示例#4
0
        public override void Mangle(CilBody body, ScopeBlock root, CFContext ctx)
        {
            MethodTrace trace = ctx.Context.Registry.GetService<ITraceService>().Trace(ctx.Method);

            body.MaxStack += 2;
            IPredicate predicate = null;
            if (ctx.Predicate == PredicateType.Normal) {
                predicate = new NormalPredicate(ctx);
            }
            else if (ctx.Predicate == PredicateType.Expression) {
                predicate = new ExpressionPredicate(ctx);
            }
            else if (ctx.Predicate == PredicateType.x86) {
                predicate = new x86Predicate(ctx);
            }

            foreach (InstrBlock block in GetAllBlocks(root)) {
                LinkedList<Instruction[]> statements = SpiltStatements(block, trace, ctx);

                // Make sure .ctor is executed before switch
                if (ctx.Method.IsInstanceConstructor) {
                    var newStatement = new List<Instruction>();
                    while (statements.First != null) {
                        newStatement.AddRange(statements.First.Value);
                        Instruction lastInstr = statements.First.Value.Last();
                        statements.RemoveFirst();
                        if (lastInstr.OpCode == OpCodes.Call && ((IMethod)lastInstr.Operand).Name == ".ctor")
                            break;
                    }
                    statements.AddFirst(newStatement.ToArray());
                }

                if (statements.Count < 3) continue;

                int[] key = Enumerable.Range(0, statements.Count).ToArray();
                ctx.Random.Shuffle(key);

                var statementKeys = new Dictionary<Instruction, int>();
                LinkedListNode<Instruction[]> current = statements.First;
                int i = 0;
                while (current != null) {
                    if (i != 0)
                        statementKeys[current.Value[0]] = key[i];
                    i++;
                    current = current.Next;
                }

                var switchInstr = new Instruction(OpCodes.Switch);

                var switchHdr = new List<Instruction>();

                if (predicate != null) {
                    predicate.Init(body);
                    switchHdr.Add(Instruction.CreateLdcI4(predicate.GetSwitchKey(key[1])));
                    predicate.EmitSwitchLoad(switchHdr);
                }
                else {
                    switchHdr.Add(Instruction.CreateLdcI4(key[1]));
                }

                switchHdr.Add(switchInstr);

                ctx.AddJump(switchHdr, statements.Last.Value[0]);
                ctx.AddJunk(switchHdr);

                var operands = new Instruction[statements.Count];
                current = statements.First;
                i = 0;
                while (current.Next != null) {
                    var newStatement = new List<Instruction>(current.Value);

                    if (i != 0) {
                        // Convert to switch
                        bool converted = false;

                        if (newStatement.Last().IsBr()) {
                            // Unconditional

                            var target = (Instruction)newStatement.Last().Operand;
                            int brKey;
                            if (!trace.IsBranchTarget(trace.OffsetToIndexMap(newStatement.Last().Offset)) &&
                                statementKeys.TryGetValue(target, out brKey)) {
                                newStatement.RemoveAt(newStatement.Count - 1);
                                newStatement.Add(Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(brKey) : brKey));
                                ctx.AddJump(newStatement, switchHdr[1]);
                                ctx.AddJunk(newStatement);
                                operands[key[i]] = newStatement[0];
                                converted = true;
                            }
                        }
                        else if (newStatement.Last().IsConditionalBranch()) {
                            // Conditional

                            var target = (Instruction)newStatement.Last().Operand;
                            int brKey;
                            if (!trace.IsBranchTarget(trace.OffsetToIndexMap(newStatement.Last().Offset)) &&
                                statementKeys.TryGetValue(target, out brKey)) {
                                int nextKey = key[i + 1];
                                OpCode condBr = newStatement.Last().OpCode;
                                newStatement.RemoveAt(newStatement.Count - 1);

                                if (ctx.Random.NextBoolean()) {
                                    condBr = InverseBranch(condBr);
                                    int tmp = brKey;
                                    brKey = nextKey;
                                    nextKey = tmp;
                                }

                                Instruction brKeyInstr = Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(brKey) : brKey);
                                Instruction nextKeyInstr = Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(nextKey) : nextKey);
                                Instruction pop = Instruction.Create(OpCodes.Pop);
                                newStatement.Add(Instruction.Create(condBr, brKeyInstr));
                                newStatement.Add(nextKeyInstr);
                                newStatement.Add(Instruction.Create(OpCodes.Dup));
                                newStatement.Add(Instruction.Create(OpCodes.Br, pop));
                                newStatement.Add(brKeyInstr);
                                newStatement.Add(Instruction.Create(OpCodes.Dup));
                                newStatement.Add(pop);

                                ctx.AddJump(newStatement, switchHdr[1]);
                                ctx.AddJunk(newStatement);
                                operands[key[i]] = newStatement[0];
                                converted = true;
                            }
                        }

                        if (!converted) {
                            // Normal

                            newStatement.Add(Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(key[i + 1]) : key[i + 1]));
                            ctx.AddJump(newStatement, switchHdr[1]);
                            ctx.AddJunk(newStatement);
                            operands[key[i]] = newStatement[0];
                        }
                    }
                    else
                        operands[key[i]] = switchHdr[0];

                    current.Value = newStatement.ToArray();
                    current = current.Next;
                    i++;
                }
                operands[key[i]] = current.Value[0];
                switchInstr.Operand = operands;

                Instruction[] first = statements.First.Value;
                statements.RemoveFirst();
                Instruction[] last = statements.Last.Value;
                statements.RemoveLast();

                List<Instruction[]> newStatements = statements.ToList();
                ctx.Random.Shuffle(newStatements);

                block.Instructions.Clear();
                block.Instructions.AddRange(first);
                block.Instructions.AddRange(switchHdr);
                foreach (var statement in newStatements)
                    block.Instructions.AddRange(statement);
                block.Instructions.AddRange(last);
            }
        }