Esempio n. 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));
        }
Esempio n. 2
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));
            }