Skip to content
This repository has been archived by the owner on Jan 27, 2019. It is now read-only.

Commit

Permalink
Add compression progress reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
yck1509 committed Jun 22, 2014
1 parent 88b7b4a commit 010ae7d
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 50 deletions.
78 changes: 49 additions & 29 deletions Confuser.Core/Services/CompressionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,42 +24,41 @@ public CompressionService(ConfuserContext context) {
/// <inheritdoc />
public MethodDef GetRuntimeDecompressor(ModuleDef module, Action<IDnlibDef> init) {
Tuple<MethodDef, List<IDnlibDef>> decompressor = context.Annotations.GetOrCreate(module, Decompressor, m => {
var rt = context.Registry.GetService<IRuntimeService>();
var rt = context.Registry.GetService<IRuntimeService>();

List<IDnlibDef> 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<IDnlibDef> 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;
}

/// <inheritdoc />
public byte[] Compress(byte[] data) {
public byte[] Compress(byte[] data, Action<double> progressFunc = null) {
CoderPropID[] propIDs = {
CoderPropID.DictionarySize,
CoderPropID.PosStateBits,
Expand Down Expand Up @@ -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<double> progressFunc;
private readonly int size;

public CompressionLogger(Action<double> progressFunc, int size) {
this.progressFunc = progressFunc;
this.size = size;
}

public void SetProgress(long inSize, long outSize) {
double precentage = (double)inSize / size;
progressFunc(precentage);
}
}
}

/// <summary>
Expand All @@ -110,7 +129,8 @@ public interface ICompressionService {
/// Compresses the specified data.
/// </summary>
/// <param name="data">The buffer storing the data.</param>
/// <param name="progressFunc">The function that receive the progress of compression.</param>
/// <returns>The compressed data.</returns>
byte[] Compress(byte[] data);
byte[] Compress(byte[] data, Action<double> progressFunc = null);
}
}
40 changes: 24 additions & 16 deletions Confuser.Protections/Compress/Compressor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,25 @@ 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];

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) {
Expand All @@ -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<Instruction>();
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<Instruction>();
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) {
Expand Down Expand Up @@ -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,
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions Confuser.Protections/Compress/CompressorContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<double> progressFunc) {
data = (byte[])data.Clone();
var dst = new uint[0x10];
var src = new uint[0x10];
Expand All @@ -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];
Expand Down
8 changes: 5 additions & 3 deletions Confuser.Protections/Resources/MDPhase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ private void OnWriterEvent(object sender, ModuleWriterListenerEventArgs e) {
}

// compress
moduleBuff = ctx.Context.Registry.GetService<ICompressionService>().Compress(moduleBuff);
moduleBuff = ctx.Context.Registry.GetService<ICompressionService>().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;
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 010ae7d

Please sign in to comment.