public override void Mangle(CilBody body, ScopeBlock root, CFContext ctx) { body.MaxStack++; foreach (InstrBlock block in GetAllBlocks(root)) { LinkedList <Instruction[]> fragments = SpiltFragments(block, ctx); if (fragments.Count < 4) { continue; } LinkedListNode <Instruction[]> current = fragments.First; while (current.Next != null) { var newFragment = new List <Instruction>(current.Value); ctx.AddJump(newFragment, current.Next.Value[0]); ctx.AddJunk(newFragment); current.Value = newFragment.ToArray(); current = current.Next; } Instruction[] first = fragments.First.Value; fragments.RemoveFirst(); Instruction[] last = fragments.Last.Value; fragments.RemoveLast(); List <Instruction[]> newFragments = fragments.ToList(); ctx.Random.Shuffle(newFragments); block.Instructions = first .Concat(newFragments.SelectMany(fragment => fragment)) .Concat(last).ToList(); } }
protected static IEnumerable <InstrBlock> GetAllBlocks(ScopeBlock scope) { foreach (BlockBase child in scope.Children) { if (child is InstrBlock) { yield return((InstrBlock)child); } else { foreach (InstrBlock block in GetAllBlocks((ScopeBlock)child)) { yield return(block); } } } }
public static ScopeBlock ParseBody(CilBody body) { var ehScopes = new Dictionary <ExceptionHandler, Tuple <ScopeBlock, ScopeBlock, ScopeBlock> >(); foreach (ExceptionHandler eh in body.ExceptionHandlers) { var tryBlock = new ScopeBlock(BlockType.Try, eh); var handlerType = BlockType.Handler; if (eh.HandlerType == ExceptionHandlerType.Finally) { handlerType = BlockType.Finally; } else if (eh.HandlerType == ExceptionHandlerType.Fault) { handlerType = BlockType.Fault; } var handlerBlock = new ScopeBlock(handlerType, eh); if (eh.FilterStart != null) { var filterBlock = new ScopeBlock(BlockType.Filter, eh); ehScopes[eh] = Tuple.Create(tryBlock, handlerBlock, filterBlock); } else { ehScopes[eh] = Tuple.Create(tryBlock, handlerBlock, (ScopeBlock)null); } } var root = new ScopeBlock(BlockType.Normal, null); var scopeStack = new Stack <ScopeBlock>(); scopeStack.Push(root); foreach (Instruction instr in body.Instructions) { foreach (ExceptionHandler eh in body.ExceptionHandlers) { Tuple <ScopeBlock, ScopeBlock, ScopeBlock> ehScope = ehScopes[eh]; if (instr == eh.TryEnd) { scopeStack.Pop(); } if (instr == eh.HandlerEnd) { scopeStack.Pop(); } if (eh.FilterStart != null && instr == eh.HandlerStart) { // Filter must precede handler immediately Debug.Assert(scopeStack.Peek().Type == BlockType.Filter); scopeStack.Pop(); } } foreach (ExceptionHandler eh in body.ExceptionHandlers.Reverse()) { Tuple <ScopeBlock, ScopeBlock, ScopeBlock> ehScope = ehScopes[eh]; ScopeBlock parent = scopeStack.Count > 0 ? scopeStack.Peek() : null; if (instr == eh.TryStart) { if (parent != null) { parent.Children.Add(ehScope.Item1); } scopeStack.Push(ehScope.Item1); } if (instr == eh.HandlerStart) { if (parent != null) { parent.Children.Add(ehScope.Item2); } scopeStack.Push(ehScope.Item2); } if (instr == eh.FilterStart) { if (parent != null) { parent.Children.Add(ehScope.Item3); } scopeStack.Push(ehScope.Item3); } } ScopeBlock scope = scopeStack.Peek(); var block = scope.Children.LastOrDefault() as InstrBlock; if (block == null) { scope.Children.Add(block = new InstrBlock()); } block.Instructions.Add(instr); } foreach (ExceptionHandler eh in body.ExceptionHandlers) { if (eh.TryEnd == null) { scopeStack.Pop(); } if (eh.HandlerEnd == null) { scopeStack.Pop(); } } Debug.Assert(scopeStack.Count == 1); return(root); }
public abstract void Mangle(CilBody body, ScopeBlock root, CFContext ctx);
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(); 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); 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(); 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); 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); } }