Example #1
0
        void ProcessMethod(CilBody body, CFContext ctx)
        {
            uint maxStack;

            if (!MaxStackCalculator.GetMaxStack(body.Instructions, body.ExceptionHandlers, out maxStack))
            {
                ctx.Context.Logger.Error("Failed to calcuate maxstack.");
                throw new DotProtectception(null);
            }
            body.MaxStack = (ushort)maxStack;
            ScopeBlock root = BlockParser.ParseBody(body);

            GetMangler(ctx.Type).Mangle(body, root, ctx);

            body.Instructions.Clear();
            root.ToBody(body);
            foreach (ExceptionHandler eh in body.ExceptionHandlers)
            {
                var index = body.Instructions.IndexOf(eh.TryEnd) + 1;
                eh.TryEnd     = index < body.Instructions.Count ? body.Instructions[index] : null;
                index         = body.Instructions.IndexOf(eh.HandlerEnd) + 1;
                eh.HandlerEnd = index < body.Instructions.Count ? body.Instructions[index] : null;
            }
            body.KeepOldMaxStack = true;
        }
Example #2
0
        CFContext ParseParameters(MethodDef method, DotProtectContext context, ProtectionParameters parameters, RandomGenerator random, bool disableOpti)
        {
            var ret = new CFContext();

            ret.Type      = parameters.GetParameter(context, method, "type", CFType.Switch);
            ret.Predicate = parameters.GetParameter(context, method, "predicate", PredicateType.Normal);

            int rawIntensity = parameters.GetParameter(context, method, "intensity", 60);

            ret.Intensity = rawIntensity / 100.0;
            ret.Depth     = parameters.GetParameter(context, method, "depth", 4);

            ret.JunkCode = parameters.GetParameter(context, method, "junk", false) && !disableOpti;

            ret.Protection = (ControlFlowProtection)Parent;
            ret.Random     = random;
            ret.Method     = method;
            ret.Context    = context;
            ret.DynCipher  = context.Registry.GetService <IDynCipherService>();

            if (ret.Predicate == PredicateType.x86)
            {
                if ((context.CurrentModule.Cor20HeaderFlags & ComImageFlags.ILOnly) != 0)
                {
                    context.CurrentModuleWriterOptions.Cor20HeaderOptions.Flags &= ~ComImageFlags.ILOnly;
                }
            }

            return(ret);
        }
Example #3
0
        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();
            }
        }
Example #4
0
        LinkedList <Instruction[]> SpiltStatements(InstrBlock block, Trace trace, CFContext ctx)
        {
            var statements       = new LinkedList <Instruction[]>();
            var currentStatement = new List <Instruction>();

            // Instructions that must be included in the ccurrent statement to ensure all outgoing
            // branches have stack = 0
            var requiredInstr = new HashSet <Instruction>();

            for (int i = 0; i < block.Instructions.Count; i++)
            {
                Instruction instr = block.Instructions[i];
                currentStatement.Add(instr);

                bool shouldSpilt = i + 1 < block.Instructions.Count && trace.HasMultipleSources(block.Instructions[i + 1].Offset);
                switch (instr.OpCode.FlowControl)
                {
                case FlowControl.Branch:
                case FlowControl.Cond_Branch:
                case FlowControl.Return:
                case FlowControl.Throw:
                    shouldSpilt = true;
                    if (trace.AfterStack[instr.Offset] != 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 && trace.AfterStack[instr.Offset] == 0 &&
                     requiredInstr.Count == 0) &&
                    (shouldSpilt || ctx.Intensity > ctx.Random.NextDouble()))
                {
                    statements.AddLast(currentStatement.ToArray());
                    currentStatement.Clear();
                }
            }

            if (currentStatement.Count > 0)
            {
                statements.AddLast(currentStatement.ToArray());
            }

            return(statements);
        }
Example #5
0
            public void Compile(CFContext ctx)
            {
                var var    = new Variable("{VAR}");
                var result = new Variable("{RESULT}");

                CorLibTypeSig int32 = ctx.Method.Module.CorLibTypes.Int32;

                native = new MethodDefUser(ctx.Context.Registry.GetService <INameService>().RandomName(), MethodSig.CreateStatic(int32, int32), MethodAttributes.PinvokeImpl | MethodAttributes.PrivateScope | MethodAttributes.Static);
                native.ImplAttributes = MethodImplAttributes.Native | MethodImplAttributes.Unmanaged | MethodImplAttributes.PreserveSig;
                // Attempt to improve performance --- failed with StackOverflowException... :/
                //var suppressAttr = ctx.Method.Module.CorLibTypes.GetTypeRef("System.Security", "SuppressUnmanagedCodeSecurityAttribute").ResolveThrow();
                //native.CustomAttributes.Add(new CustomAttribute((MemberRef)ctx.Method.Module.Import(suppressAttr.FindDefaultConstructor())));
                //native.HasSecurity = true;
                ctx.Method.Module.GlobalType.Methods.Add(native);

                ctx.Context.Registry.GetService <IMarkerService>().Mark(native, ctx.Protection);
                ctx.Context.Registry.GetService <INameService>().SetCanRename(native, false);

                x86Register?reg;
                var         codeGen = new x86CodeGen();

                do
                {
                    ctx.DynCipher.GenerateExpressionPair(
                        ctx.Random,
                        new VariableExpression {
                        Variable = var
                    }, new VariableExpression {
                        Variable = result
                    },
                        ctx.Depth, out expression, out inverse);

                    reg = codeGen.GenerateX86(inverse, (v, r) => { return(new[] { x86Instruction.Create(x86OpCode.POP, new x86RegisterOperand(r)) }); });
                } while (reg == null);

                code = CodeGenUtils.AssembleCode(codeGen, reg.Value);

                expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) })
                              .GenerateCIL(expression)
                              .Compile <Func <int, int> >();


                ctx.Context.CurrentModuleWriterListener.OnWriterEvent += InjectNativeCode;
            }
Example #6
0
 public NormalPredicate(CFContext ctx)
 {
     this.ctx = ctx;
 }
Example #7
0
 public x86Predicate(CFContext ctx)
 {
     this.ctx = ctx;
 }
Example #8
0
 public CodeGen(Local state, CFContext ctx, IList <Instruction> instrs)
     : base(ctx.Method, instrs)
 {
     this.state = state;
 }
Example #9
0
 public ExpressionPredicate(CFContext ctx)
 {
     this.ctx = ctx;
 }
Example #10
0
        LinkedList <Instruction[]> SpiltFragments(InstrBlock block, CFContext ctx)
        {
            var fragments       = new LinkedList <Instruction[]>();
            var currentFragment = new List <Instruction>();

            int skipCount = -1;

            for (int i = 0; i < block.Instructions.Count; i++)
            {
                if (skipCount != -1)
                {
                    if (skipCount > 0)
                    {
                        currentFragment.Add(block.Instructions[i]);
                        skipCount--;
                        continue;
                    }
                    fragments.AddLast(currentFragment.ToArray());
                    currentFragment.Clear();

                    skipCount = -1;
                }

                if (block.Instructions[i].OpCode.OpCodeType == OpCodeType.Prefix)
                {
                    skipCount = 1;
                    currentFragment.Add(block.Instructions[i]);
                }
                if (i + 2 < block.Instructions.Count &&
                    block.Instructions[i + 0].OpCode.Code == Code.Dup &&
                    block.Instructions[i + 1].OpCode.Code == Code.Ldvirtftn &&
                    block.Instructions[i + 2].OpCode.Code == Code.Newobj)
                {
                    skipCount = 2;
                    currentFragment.Add(block.Instructions[i]);
                }
                if (i + 4 < block.Instructions.Count &&
                    block.Instructions[i + 0].OpCode.Code == Code.Ldc_I4 &&
                    block.Instructions[i + 1].OpCode.Code == Code.Newarr &&
                    block.Instructions[i + 2].OpCode.Code == Code.Dup &&
                    block.Instructions[i + 3].OpCode.Code == Code.Ldtoken &&
                    block.Instructions[i + 4].OpCode.Code == Code.Call)                 // Array initializer
                {
                    skipCount = 4;
                    currentFragment.Add(block.Instructions[i]);
                }
                if (i + 1 < block.Instructions.Count &&
                    block.Instructions[i + 0].OpCode.Code == Code.Ldftn &&
                    block.Instructions[i + 1].OpCode.Code == Code.Newobj)
                {
                    skipCount = 1;
                    currentFragment.Add(block.Instructions[i]);
                }
                currentFragment.Add(block.Instructions[i]);

                if (ctx.Intensity > ctx.Random.NextDouble())
                {
                    fragments.AddLast(currentFragment.ToArray());
                    currentFragment.Clear();
                }
            }

            if (currentFragment.Count > 0)
            {
                fragments.AddLast(currentFragment.ToArray());
            }

            return(fragments);
        }
Example #11
0
 public abstract void Mangle(CilBody body, ScopeBlock root, CFContext ctx);
Example #12
0
        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);
            }
        }