private LinkedList <Instruction[]> SpiltStatements(InstrBlock block, MethodTrace trace, CFContext ctx) { var statements = new LinkedList <Instruction[]>(); var currentStatement = new List <Instruction>(); for (int i = 0; i < block.Instructions.Count; i++) { Instruction instr = block.Instructions[i]; currentStatement.Add(instr); bool nextIsBrTarget = i + 1 < block.Instructions.Count && trace.IsBranchTarget(trace.OffsetToIndexMap(block.Instructions[i + 1].Offset)); if ((instr.OpCode.OpCodeType != OpCodeType.Prefix && trace.AfterStackDepths[trace.OffsetToIndexMap(instr.Offset)] == 0) && (nextIsBrTarget || ctx.Intensity > ctx.Random.NextDouble())) { statements.AddLast(currentStatement.ToArray()); currentStatement.Clear(); } } if (currentStatement.Count > 0) { statements.AddLast(currentStatement.ToArray()); } return(statements); }
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); } }