Example #1
0
        void InjectData(ModuleDef stubModule, MethodDef method, byte[] data)
        {
            var dataType = new TypeDefUser("", "DataType", stubModule.CorLibTypes.GetTypeRef("System", "ValueType"));

            dataType.Layout      = TypeAttributes.ExplicitLayout;
            dataType.Visibility  = TypeAttributes.NestedPrivate;
            dataType.IsSealed    = true;
            dataType.ClassLayout = new ClassLayoutUser(1, (uint)data.Length);
            stubModule.GlobalType.NestedTypes.Add(dataType);

            var dataField = new FieldDefUser("DataField", new FieldSig(dataType.ToTypeSig()))
            {
                IsStatic     = true,
                HasFieldRVA  = true,
                InitialValue = data,
                Access       = FieldAttributes.CompilerControlled
            };

            stubModule.GlobalType.Fields.Add(dataField);

            MutationHelper.ReplacePlaceholder(method, arg => {
                var repl = new List <Instruction>();
                repl.AddRange(arg);
                repl.Add(Instruction.Create(OpCodes.Dup));
                repl.Add(Instruction.Create(OpCodes.Ldtoken, dataField));
                repl.Add(Instruction.Create(OpCodes.Call, InjectHelper.Import(stubModule,
                                                                              typeof(RuntimeHelpers).GetMethod("InitializeArray"))));
                return(repl.ToArray());
            });
        }
Example #2
0
        void MutateInitializer(REContext moduleCtx, MethodDef decomp)
        {
            moduleCtx.InitMethod.Body.SimplifyMacros(moduleCtx.InitMethod.Parameters);
            List <Instruction> instrs = moduleCtx.InitMethod.Body.Instructions.ToList();

            for (int i = 0; i < instrs.Count; i++)
            {
                Instruction instr  = instrs[i];
                var         method = instr.Operand as IMethod;
                if (instr.OpCode == OpCodes.Call)
                {
                    if (method.DeclaringType.Name == "Mutation" &&
                        method.Name == "Crypt")
                    {
                        Instruction ldBlock = instrs[i - 2];
                        Instruction ldKey   = instrs[i - 1];
                        Debug.Assert(ldBlock.OpCode == OpCodes.Ldloc && ldKey.OpCode == OpCodes.Ldloc);
                        instrs.RemoveAt(i);
                        instrs.RemoveAt(i - 1);
                        instrs.RemoveAt(i - 2);
                        instrs.InsertRange(i - 2, moduleCtx.ModeHandler.EmitDecrypt(moduleCtx.InitMethod, moduleCtx, (Local)ldBlock.Operand, (Local)ldKey.Operand));
                    }
                    else if (method.DeclaringType.Name == "Lzma" &&
                             method.Name == "Decompress")
                    {
                        instr.Operand = decomp;
                    }
                }
            }
            moduleCtx.InitMethod.Body.Instructions.Clear();
            foreach (Instruction instr in instrs)
            {
                moduleCtx.InitMethod.Body.Instructions.Add(instr);
            }

            MutationHelper.ReplacePlaceholder(moduleCtx.InitMethod, arg => {
                var repl = new List <Instruction>();
                repl.AddRange(arg);
                repl.Add(Instruction.Create(OpCodes.Dup));
                repl.Add(Instruction.Create(OpCodes.Ldtoken, moduleCtx.DataField));
                repl.Add(Instruction.Create(OpCodes.Call, InjectHelper.Import(moduleCtx.Module,
                                                                              typeof(RuntimeHelpers).GetMethod("InitializeArray"))));
                return(repl.ToArray());
            });
            moduleCtx.Context.Registry.GetService <IConstantService>().ExcludeMethod(moduleCtx.Context, moduleCtx.InitMethod);
        }
Example #3
0
        protected override void Execute(ConfuserContext context, ProtectionParameters parameters)
        {
            var moduleCtx = context.Annotations.Get <CEContext>(context.CurrentModule, ConstantProtection.ContextKey);

            if (!parameters.Targets.Any() || moduleCtx == null)
            {
                return;
            }

            var ldc    = new Dictionary <object, List <Tuple <MethodDef, Instruction> > >();
            var ldInit = new Dictionary <byte[], List <Tuple <MethodDef, Instruction> > >(new ByteArrayComparer());

            // Extract constants
            ExtractConstants(context, parameters, moduleCtx, ldc, ldInit);

            // Encode constants
            moduleCtx.ReferenceRepl = new Dictionary <MethodDef, List <Tuple <Instruction, uint, IMethod> > >();
            moduleCtx.EncodedBuffer = new List <uint>();
            foreach (var entry in ldInit.WithProgress(context.Logger))             // Ensure the array length haven't been encoded yet
            {
                EncodeInitializer(moduleCtx, entry.Key, entry.Value);
                context.CheckCancellation();
            }
            foreach (var entry in ldc.WithProgress(context.Logger))
            {
                if (entry.Key is string)
                {
                    EncodeString(moduleCtx, (string)entry.Key, entry.Value);
                }
                else if (entry.Key is int)
                {
                    EncodeConstant32(moduleCtx, (uint)(int)entry.Key, context.CurrentModule.CorLibTypes.Int32, entry.Value);
                }
                else if (entry.Key is long)
                {
                    EncodeConstant64(moduleCtx, (uint)((long)entry.Key >> 32), (uint)(long)entry.Key, context.CurrentModule.CorLibTypes.Int64, entry.Value);
                }
                else if (entry.Key is float)
                {
                    var t = new RTransform();
                    t.R4 = (float)entry.Key;
                    EncodeConstant32(moduleCtx, t.Lo, context.CurrentModule.CorLibTypes.Single, entry.Value);
                }
                else if (entry.Key is double)
                {
                    var t = new RTransform();
                    t.R8 = (double)entry.Key;
                    EncodeConstant64(moduleCtx, t.Hi, t.Lo, context.CurrentModule.CorLibTypes.Double, entry.Value);
                }
                else
                {
                    throw new UnreachableException();
                }
                context.CheckCancellation();
            }
            ReferenceReplacer.ReplaceReference(moduleCtx, parameters);

            // compress
            var encodedBuff = new byte[moduleCtx.EncodedBuffer.Count * 4];
            int buffIndex   = 0;

            foreach (uint dat in moduleCtx.EncodedBuffer)
            {
                encodedBuff[buffIndex++] = (byte)((dat >> 0) & 0xff);
                encodedBuff[buffIndex++] = (byte)((dat >> 8) & 0xff);
                encodedBuff[buffIndex++] = (byte)((dat >> 16) & 0xff);
                encodedBuff[buffIndex++] = (byte)((dat >> 24) & 0xff);
            }
            Debug.Assert(buffIndex == encodedBuff.Length);
            encodedBuff = context.Registry.GetService <ICompressionService>().Compress(encodedBuff);
            context.CheckCancellation();

            uint compressedLen = (uint)(encodedBuff.Length + 3) / 4;

            compressedLen = (compressedLen + 0xfu) & ~0xfu;
            var compressedBuff = new uint[compressedLen];

            Buffer.BlockCopy(encodedBuff, 0, compressedBuff, 0, encodedBuff.Length);
            Debug.Assert(compressedLen % 0x10 == 0);

            // encrypt
            uint keySeed = moduleCtx.Random.NextUInt32();
            var  key     = new uint[0x10];
            uint state   = keySeed;

            for (int i = 0; i < 0x10; i++)
            {
                state ^= state >> 12;
                state ^= state << 25;
                state ^= state >> 27;
                key[i] = state;
            }

            var encryptedBuffer = new byte[compressedBuff.Length * 4];

            buffIndex = 0;
            while (buffIndex < compressedBuff.Length)
            {
                uint[] enc = moduleCtx.ModeHandler.Encrypt(compressedBuff, buffIndex, key);
                for (int j = 0; j < 0x10; j++)
                {
                    key[j] ^= compressedBuff[buffIndex + j];
                }
                Buffer.BlockCopy(enc, 0, encryptedBuffer, buffIndex * 4, 0x40);
                buffIndex += 0x10;
            }
            Debug.Assert(buffIndex == compressedBuff.Length);

            moduleCtx.DataField.InitialValue = encryptedBuffer;
            moduleCtx.DataField.HasFieldRVA  = true;
            moduleCtx.DataType.ClassLayout   = new ClassLayoutUser(0, (uint)encryptedBuffer.Length);
            MutationHelper.InjectKeys(moduleCtx.InitMethod,
                                      new[] { 0, 1 },
                                      new[] { encryptedBuffer.Length / 4, (int)keySeed });
            MutationHelper.ReplacePlaceholder(moduleCtx.InitMethod, arg => {
                var repl = new List <Instruction>();
                repl.AddRange(arg);
                repl.Add(Instruction.Create(OpCodes.Dup));
                repl.Add(Instruction.Create(OpCodes.Ldtoken, moduleCtx.DataField));
                repl.Add(Instruction.Create(OpCodes.Call, InjectHelper.Import(moduleCtx.Module,
                                                                              typeof(RuntimeHelpers).GetMethod("InitializeArray"))));
                return(repl.ToArray());
            });
        }