Example #1
0
        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));
        }
Example #2
0
        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);
        }
Example #3
0
 public abstract void Mangle(ICFMangleContext context, Block.Regular block);
Example #4
0
        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);
        }
Example #5
0
            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));
            }
Example #6
0
 public override void Mangle(ICFMangleContext context, Block.Regular block)
 {
     PropImpl.GetOrAdd(context, () => new Impl(this, context)).Mangle(block);
 }