public override void Mangle(ICFMangleContext context, Block.Regular block) { var fragments = context.SplitFragments(block); if (fragments.Count < 4) { return; } var current = fragments.First; while (current.Next != null) { var newFragment = new CilFragment(current.Value); context.AddJump(newFragment, current.Next.Value.First, true); current.Value = newFragment; current = current.Next; } var first = fragments.First.Value; fragments.RemoveFirst(); var last = fragments.Last.Value; fragments.RemoveLast(); var newFragments = fragments.ToList(); newFragments.Shuffle(Mangler.Rng); block.Fragment.Reset(first .Concat(newFragments.SelectMany(fragment => fragment)) .Concat(last)); }
public LinkedList <CilFragment> SplitFragments(Block.Regular block) { var statements = new LinkedList <CilFragment>(); var currentStatement = new CilFragment(); var requiredInstr = new HashSet <Instruction>(); var i = 0; var instr = block.Fragment.Instructions[i]; var fi = RootBlock.FlowInfo.Info; while (instr != null) { fi.TryGetValue(instr, out var info); i++; var next = i < block.Fragment.Instructions.Count ? block.Fragment.Instructions[i] : null; currentStatement.Add(instr); var shouldSpilt = next != null && fi.TryGetValue(next, out var ni) && ni.RefCount > 1; switch (instr.OpCode.FlowControl) { case FlowControl.Branch: case FlowControl.Cond_Branch: case FlowControl.Return: case FlowControl.Throw: shouldSpilt = true; if (info.DepthAfter != 0) { if (instr.Operand is Instruction) { requiredInstr.Add((Instruction)instr.Operand); } else if (instr.Operand is Instruction[]) { foreach (var target in (Instruction[])instr.Operand) { requiredInstr.Add(target); } } } break; } requiredInstr.Remove(instr); if ((instr.OpCode.OpCodeType != OpCodeType.Prefix && info.DepthAfter == 0 && requiredInstr.Count == 0) && (shouldSpilt || Mangler.Options.Intensity > Mangler.Rng.NextDouble())) { statements.AddLast(currentStatement); currentStatement = new CilFragment(); } instr = next; } if (!currentStatement.IsEmpty) { statements.AddLast(currentStatement); } return(statements); }
public abstract void Mangle(ICFMangleContext context, Block.Regular block);
internal Block.Root Parse() { var root = new Block.Root { FlowInfo = _flow = new FlowInfo() }; var ehScopes = new Dictionary <ExceptionHandler, (Block.Seh, Block.Seh, Block.Seh)>(); foreach (var eh in _exceptionHandlers) { var tryBlock = new Block.Seh(BlockType.Try, eh); var handlerType = BlockType.Handler; switch (eh.HandlerType) { case ExceptionHandlerType.Finally: handlerType = BlockType.Finally; break; case ExceptionHandlerType.Fault: handlerType = BlockType.Fault; break; } var handlerBlock = new Block.Seh(handlerType, eh); if (eh.FilterStart != null) { ehScopes[eh] = (tryBlock, handlerBlock, new Block.Seh(BlockType.Filter, eh)); } else { ehScopes[eh] = (tryBlock, handlerBlock, (Block.Seh)null); } Instruction instr; if ((instr = eh.TryStart) != null) { _flow[instr].DepthBefore = 0; } if ((instr = eh.FilterStart) != null) { _flow[instr].DepthBefore = 1; currentMaxStack = 1; } if ((instr = eh.HandlerStart) != null) { var pushed = eh.HandlerType == ExceptionHandlerType.Catch || eh.HandlerType == ExceptionHandlerType.Filter; if (pushed) { _flow[instr].DepthBefore = 1; currentMaxStack = 1; } else { _flow[instr].DepthBefore = 0; } } } var scopeStack = new Stack <Block>(); scopeStack.Push(root); stack = 0; resetStack = false; foreach (var instr in _instructions) { foreach (var eh in _exceptionHandlers) { 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 (var eh in _exceptionHandlers.Reverse()) { var(item1, item2, item3) = ehScopes[eh]; var parent = scopeStack.Count > 0 ? scopeStack.Peek() : null; if (instr == eh.TryStart) { parent?.Add(item1); scopeStack.Push(item1); } if (instr == eh.HandlerStart) { parent?.Add(item2); scopeStack.Push(item2); } if (instr == eh.FilterStart) { parent?.Add(item3); scopeStack.Push(item3); } } var scope = scopeStack.Peek(); if (!(scope.LastChild is Block.Regular block)) { scope.Add(block = new Block.Regular()); } block.Fragment.Add(instr); UpdateStack(instr); } foreach (var eh in _exceptionHandlers) { if (eh.TryEnd == null) { scopeStack.Pop(); } if (eh.HandlerEnd == null) { scopeStack.Pop(); } } _flow.MaxStack = currentMaxStack; Debug.Assert(scopeStack.Count == 1); return(root); }
public void Mangle(Block.Regular block) { var rng = _switch.Mangler.Rng; var fi = _context.RootBlock.FlowInfo.Info; var fragments = _context.SplitFragments(block); if (fragments.Count < 3) { return; } int i; var keyId = Enumerable.Range(0, fragments.Count).ToArray(); keyId.Shuffle(rng); var key = new int[keyId.Length]; for (i = 0; i < key.Length; i++) { var q = rng.NextInt32() & 0x7fffffff; key[i] = q - q % fragments.Count + keyId[i]; } var statementKeys = new Dictionary <Instruction, int>(); var current = fragments.First; i = 0; while (current != null) { if (i != 0) { statementKeys[current.Value.First] = key[i]; } i++; current = current.Next; } var lastInstructions = new HashSet <Instruction>(fragments.Select(f => f.Last())); var blockInstructions = new HashSet <Instruction>(block.Fragment); var firstFragmentInstructions = new HashSet <Instruction>(fragments.First()); bool HasUnknownSource(IEnumerable <Instruction> instrs) => instrs.Any(instr => { //return true; fi.TryGetValue(instr, out var info); if (info.RefCount > 1) { return(true); } Debug.Assert(info.RefCount == 1); var srcs = info.ReferencedBy; if (srcs.Count == 0) { return(false); } Debug.Assert(srcs.Count == 1); var src = srcs[0]; return // Target of switch => assume unknown (src.OpCode.Code == Code.Switch // Operand is Instruction[] // Not targeted by the last of statements || lastInstructions.Contains(src) // Not within current instruction block / targeted in first statement // || src.Offset <= fragments.First.Value.Last().Offset || src.Offset >= block.Fragment.Last().Offset || !blockInstructions.Contains(src) || firstFragmentInstructions.Contains(src)); }); var switchInstr = new Instruction(OpCodes.Switch); var switchHdr = new CilFragment(); if (_predicate != null) { 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, fragments.Count)); switchHdr.Add(Instruction.Create(OpCodes.Rem_Un)); switchHdr.Add(switchInstr); _context.AddJump(switchHdr, fragments.Last.Value.First, true); var switchHdrSecond = switchHdr.Instructions[1]; var operands = new Instruction[fragments.Count]; current = fragments.First; i = 0; while (current.Next != null) { var newFragment = new CilFragment(current.Value); if (i != 0) { var lastInstr = newFragment.Last(); // Convert to switch var converted = false; fi.TryGetValue(lastInstr, out var info); if (lastInstr.IsBr()) { // Unconditional var target = (Instruction)lastInstr.Operand; if (info.ReferencedBy.Count == 0 && statementKeys.TryGetValue(target, out var brKey)) { var targetKey = _predicate?.GetSwitchKey(brKey) ?? brKey; var unkSrc = HasUnknownSource(newFragment); newFragment.Instructions.RemoveAt(newFragment.Instructions.Count - 1); if (unkSrc) { newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey)); } else { var thisKey = key[i]; var r = rng.NextInt32(); newFragment.Add(Instruction.Create(OpCodes.Ldloc, _local)); newFragment.Add(Instruction.CreateLdcI4(r)); newFragment.Add(Instruction.Create(OpCodes.Mul)); newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey * r) ^ targetKey)); newFragment.Add(Instruction.Create(OpCodes.Xor)); } _context.AddJump(newFragment, switchHdrSecond, false); operands[keyId[i]] = newFragment.First; converted = true; } } else if (lastInstr.IsConditionalBranch()) { // Conditional var target = (Instruction)lastInstr.Operand; if (info.ReferencedBy.Count == 0 && statementKeys.TryGetValue(target, out var brKey)) { var unkSrc = HasUnknownSource(newFragment); var nextKey = key[i + 1]; var condBr = newFragment.Last().OpCode; newFragment.Instructions.RemoveAt(newFragment.Instructions.Count - 1); if (rng.NextBoolean()) { condBr = DnextFactory.InverseBranch(condBr); var tmp = brKey; brKey = nextKey; nextKey = tmp; } var thisKey = key[i]; int r = 0, xorKey = 0; if (!unkSrc) { r = rng.NextInt32(); xorKey = thisKey * r; } var brKeyInstr = Instruction.CreateLdcI4(xorKey ^ (_predicate?.GetSwitchKey(brKey) ?? brKey)); var nextKeyInstr = Instruction.CreateLdcI4(xorKey ^ (_predicate?.GetSwitchKey(nextKey) ?? nextKey)); var pop = Instruction.Create(OpCodes.Pop); newFragment.Add(Instruction.Create(condBr, brKeyInstr)); newFragment.Add(nextKeyInstr); newFragment.Add(Instruction.Create(OpCodes.Dup)); newFragment.Add(Instruction.Create(OpCodes.Br, pop)); newFragment.Add(brKeyInstr); newFragment.Add(Instruction.Create(OpCodes.Dup)); newFragment.Add(pop); if (!unkSrc) { newFragment.Add(Instruction.Create(OpCodes.Ldloc, _local)); newFragment.Add(Instruction.CreateLdcI4(r)); newFragment.Add(Instruction.Create(OpCodes.Mul)); newFragment.Add(Instruction.Create(OpCodes.Xor)); } _context.AddJump(newFragment, switchHdrSecond, false); operands[keyId[i]] = newFragment.First; converted = true; } } if (!converted) { // Normal var targetKey = _predicate?.GetSwitchKey(key[i + 1]) ?? key[i + 1]; if (!HasUnknownSource(newFragment)) { var thisKey = key[i]; var r = rng.NextInt32(); newFragment.Add(Instruction.Create(OpCodes.Ldloc, _local)); newFragment.Add(Instruction.CreateLdcI4(r)); newFragment.Add(Instruction.Create(OpCodes.Mul)); newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey * r) ^ targetKey)); newFragment.Add(Instruction.Create(OpCodes.Xor)); } else { newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey)); } _context.AddJump(newFragment, switchHdrSecond, false); operands[keyId[i]] = newFragment.First; } } else { operands[keyId[i]] = switchHdr.First; } current.Value = newFragment; current = current.Next; i++; } operands[keyId[i]] = current.Value.First; switchInstr.Operand = operands; var first = fragments.First.Value; fragments.RemoveFirst(); var last = fragments.Last.Value; fragments.RemoveLast(); var newStatements = fragments.ToList(); newStatements.Shuffle(rng); block.Fragment.Reset(first.Concat(switchHdr).Concat(newStatements.SelectMany(s => s)).Concat(last)); }
public override void Mangle(ICFMangleContext context, Block.Regular block) { PropImpl.GetOrAdd(context, () => new Impl(this, context)).Mangle(block); }