From 010ae7df56f9be739e9da742a385f87877e16dc4 Mon Sep 17 00:00:00 2001 From: yck1509 Date: Mon, 23 Jun 2014 00:18:22 +0800 Subject: [PATCH] Add compression progress reporting --- Confuser.Core/Services/CompressionService.cs | 78 ++++++++++++------- Confuser.Protections/Compress/Compressor.cs | 40 ++++++---- .../Compress/CompressorContext.cs | 4 +- Confuser.Protections/Resources/MDPhase.cs | 8 +- 4 files changed, 80 insertions(+), 50 deletions(-) diff --git a/Confuser.Core/Services/CompressionService.cs b/Confuser.Core/Services/CompressionService.cs index be853b61a..8a9340f43 100644 --- a/Confuser.Core/Services/CompressionService.cs +++ b/Confuser.Core/Services/CompressionService.cs @@ -24,42 +24,41 @@ public CompressionService(ConfuserContext context) { /// public MethodDef GetRuntimeDecompressor(ModuleDef module, Action init) { Tuple> decompressor = context.Annotations.GetOrCreate(module, Decompressor, m => { - var rt = context.Registry.GetService(); + var rt = context.Registry.GetService(); - List members = InjectHelper.Inject(rt.GetRuntimeType("Confuser.Runtime.Lzma"), module.GlobalType, module).ToList(); - MethodDef decomp = null; - foreach (IDnlibDef member in members) { - if (member is MethodDef) { - var method = (MethodDef)member; - if (method.Access == MethodAttributes.Public) - method.Access = MethodAttributes.Assembly; - if (!method.IsConstructor) - method.IsSpecialName = false; + List members = InjectHelper.Inject(rt.GetRuntimeType("Confuser.Runtime.Lzma"), module.GlobalType, module).ToList(); + MethodDef decomp = null; + foreach (IDnlibDef member in members) { + if (member is MethodDef) { + var method = (MethodDef)member; + if (method.Access == MethodAttributes.Public) + method.Access = MethodAttributes.Assembly; + if (!method.IsConstructor) + method.IsSpecialName = false; - if (method.Name == "Decompress") - decomp = method; - } - else if (member is FieldDef) { - var field = (FieldDef)member; - if (field.Access == FieldAttributes.Public) - field.Access = FieldAttributes.Assembly; - if (field.IsLiteral) { - field.DeclaringType.Fields.Remove(field); - } - } - } - members.RemoveWhere(def => def is FieldDef && ((FieldDef)def).IsLiteral); + if (method.Name == "Decompress") + decomp = method; + } else if (member is FieldDef) { + var field = (FieldDef)member; + if (field.Access == FieldAttributes.Public) + field.Access = FieldAttributes.Assembly; + if (field.IsLiteral) { + field.DeclaringType.Fields.Remove(field); + } + } + } + members.RemoveWhere(def => def is FieldDef && ((FieldDef)def).IsLiteral); - Debug.Assert(decomp != null); - return Tuple.Create(decomp, members); - }); + Debug.Assert(decomp != null); + return Tuple.Create(decomp, members); + }); foreach (IDnlibDef member in decompressor.Item2) init(member); return decompressor.Item1; } /// - public byte[] Compress(byte[] data) { + public byte[] Compress(byte[] data, Action progressFunc = null) { CoderPropID[] propIDs = { CoderPropID.DictionarySize, CoderPropID.PosStateBits, @@ -89,9 +88,29 @@ public byte[] Compress(byte[] data) { fileSize = data.Length; for (int i = 0; i < 8; i++) x.WriteByte((Byte)(fileSize >> (8 * i))); - encoder.Code(new MemoryStream(data), x, -1, -1, null); + + ICodeProgress progress = null; + if (progressFunc != null) + progress = new CompressionLogger(progressFunc, data.Length); + encoder.Code(new MemoryStream(data), x, -1, -1, progress); + return x.ToArray(); } + + private class CompressionLogger : ICodeProgress { + private readonly Action progressFunc; + private readonly int size; + + public CompressionLogger(Action progressFunc, int size) { + this.progressFunc = progressFunc; + this.size = size; + } + + public void SetProgress(long inSize, long outSize) { + double precentage = (double)inSize / size; + progressFunc(precentage); + } + } } /// @@ -110,7 +129,8 @@ public interface ICompressionService { /// Compresses the specified data. /// /// The buffer storing the data. + /// The function that receive the progress of compression. /// The compressed data. - byte[] Compress(byte[] data); + byte[] Compress(byte[] data, Action progressFunc = null); } } \ No newline at end of file diff --git a/Confuser.Protections/Compress/Compressor.cs b/Confuser.Protections/Compress/Compressor.cs index b0bb29d76..18ee3e635 100644 --- a/Confuser.Protections/Compress/Compressor.cs +++ b/Confuser.Protections/Compress/Compressor.cs @@ -105,7 +105,8 @@ private void PackModules(ConfuserContext context, CompressorContext compCtx, Mod key[i] |= 1; compCtx.KeySig = key; - foreach (var entry in modules.WithProgress(context.Logger)) { + int moduleIndex = 0; + foreach (var entry in modules) { byte[] name = Encoding.UTF8.GetBytes(entry.Key); for (int i = 0; i < name.Length; i++) name[i] *= key[i + 4]; @@ -113,11 +114,16 @@ private void PackModules(ConfuserContext context, CompressorContext compCtx, Mod uint state = 0x6fff61; foreach (byte chr in name) state = state * 0x5e3f1f + chr; - byte[] encrypted = compCtx.Encrypt(comp, entry.Value, state); + byte[] encrypted = compCtx.Encrypt(comp, entry.Value, state, progress => { + progress = (progress + moduleIndex) / modules.Count; + context.Logger.Progress((int)(progress * 10000), 10000); + }); var resource = new EmbeddedResource(Convert.ToBase64String(name), encrypted, ManifestResourceAttributes.Private); stubModule.Resources.Add(resource); + moduleIndex++; } + context.Logger.EndProgress(); } private void InjectData(ModuleDef stubModule, MethodDef method, byte[] data) { @@ -137,14 +143,14 @@ private void InjectData(ModuleDef stubModule, MethodDef method, byte[] data) { stubModule.GlobalType.Fields.Add(dataField); MutationHelper.ReplacePlaceholder(method, arg => { - var repl = new List(); - repl.AddRange(arg); - repl.Add(Instruction.Create(OpCodes.Dup)); - repl.Add(Instruction.Create(OpCodes.Ldtoken, dataField)); - repl.Add(Instruction.Create(OpCodes.Call, stubModule.Import( - typeof (RuntimeHelpers).GetMethod("InitializeArray")))); - return repl.ToArray(); - }); + var repl = new List(); + repl.AddRange(arg); + repl.Add(Instruction.Create(OpCodes.Dup)); + repl.Add(Instruction.Create(OpCodes.Ldtoken, dataField)); + repl.Add(Instruction.Create(OpCodes.Call, stubModule.Import( + typeof (RuntimeHelpers).GetMethod("InitializeArray")))); + return repl.ToArray(); + }); } private void InjectStub(ConfuserContext context, CompressorContext compCtx, ProtectionParameters parameters, ModuleDef stubModule) { @@ -173,7 +179,11 @@ private void InjectStub(ConfuserContext context, CompressorContext compCtx, Prot uint seed = random.NextUInt32(); compCtx.OriginModule = context.OutputModules[compCtx.ModuleIndex]; - byte[] encryptedModule = compCtx.Encrypt(comp, compCtx.OriginModule, seed); + + byte[] encryptedModule = compCtx.Encrypt(comp, compCtx.OriginModule, seed, + progress => context.Logger.Progress((int)(progress * 10000), 10000)); + context.Logger.EndProgress(); + compCtx.EncryptedModule = encryptedModule; MutationHelper.InjectKeys(entryPoint, @@ -198,9 +208,8 @@ private void InjectStub(ConfuserContext context, CompressorContext compCtx, Prot instrs.RemoveAt(i - 1); instrs.RemoveAt(i - 2); instrs.InsertRange(i - 2, compCtx.Deriver.EmitDerivation(decrypter, context, (Local)ldDst.Operand, (Local)ldSrc.Operand)); - } - else if (method.DeclaringType.Name == "Lzma" && - method.Name == "Decompress") { + } else if (method.DeclaringType.Name == "Lzma" && + method.Name == "Decompress") { MethodDef decomp = comp.GetRuntimeDecompressor(stubModule, member => { }); instr.Operand = decomp; } @@ -230,8 +239,7 @@ public void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) { uint sigToken = 0x11000000 | sigRid; ctx.KeyToken = sigToken; MutationHelper.InjectKey(writer.Module.EntryPoint, 2, (int)sigToken); - } - else if (evt == ModuleWriterEvent.MDBeginAddResources) { + } else if (evt == ModuleWriterEvent.MDBeginAddResources) { // Compute hash byte[] hash = SHA1.Create().ComputeHash(ctx.OriginModule); uint hashBlob = writer.MetaData.BlobHeap.Add(hash); diff --git a/Confuser.Protections/Compress/CompressorContext.cs b/Confuser.Protections/Compress/CompressorContext.cs index ae435e61d..9d859bcfe 100644 --- a/Confuser.Protections/Compress/CompressorContext.cs +++ b/Confuser.Protections/Compress/CompressorContext.cs @@ -19,7 +19,7 @@ internal class CompressorContext { public string ModuleName; public byte[] OriginModule; - public byte[] Encrypt(ICompressionService compress, byte[] data, uint seed) { + public byte[] Encrypt(ICompressionService compress, byte[] data, uint seed, Action progressFunc) { data = (byte[])data.Clone(); var dst = new uint[0x10]; var src = new uint[0x10]; @@ -37,7 +37,7 @@ public byte[] Encrypt(ICompressionService compress, byte[] data, uint seed) { if ((i & 0xff) == 0) state = (state * state) % 0x8a5cb7; } - data = compress.Compress(data); + data = compress.Compress(data, progressFunc); Array.Resize(ref data, (data.Length + 3) & ~3); var encryptedData = new byte[data.Length]; diff --git a/Confuser.Protections/Resources/MDPhase.cs b/Confuser.Protections/Resources/MDPhase.cs index 2b717361d..9c8bb313a 100644 --- a/Confuser.Protections/Resources/MDPhase.cs +++ b/Confuser.Protections/Resources/MDPhase.cs @@ -53,7 +53,10 @@ private void OnWriterEvent(object sender, ModuleWriterListenerEventArgs e) { } // compress - moduleBuff = ctx.Context.Registry.GetService().Compress(moduleBuff); + moduleBuff = ctx.Context.Registry.GetService().Compress( + moduleBuff, + progress => ctx.Context.Logger.Progress((int)(progress * 10000), 10000)); + ctx.Context.Logger.EndProgress(); uint compressedLen = (uint)(moduleBuff.Length + 3) / 4; compressedLen = (compressedLen + 0xfu) & ~0xfu; @@ -93,8 +96,7 @@ private void OnWriterEvent(object sender, ModuleWriterListenerEventArgs e) { MutationHelper.InjectKeys(ctx.InitMethod, new[] { 0, 1 }, new[] { (int)(size / 4), (int)(keySeed) }); - } - else if (e.WriterEvent == ModuleWriterEvent.EndCalculateRvasAndFileOffsets) { + } else if (e.WriterEvent == ModuleWriterEvent.EndCalculateRvasAndFileOffsets) { TablesHeap tblHeap = writer.MetaData.TablesHeap; tblHeap.FieldRVATable[writer.MetaData.GetFieldRVARid(ctx.DataField)].RVA = (uint)encryptedResource.RVA; }