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()); }); }
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); }
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()); }); }