de4dot-cex/de4dot.code/deobfuscators/QuickLZ.cs
2017-01-05 13:46:04 +01:00

150 lines
4.4 KiB
C#

// QuickLZ data compression library
// Copyright (C) 2006-2011 Lasse Mikkel Reinhold
// lar@quicklz.com
//
// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything
// released into public must be open source) or under a commercial license if such
// has been acquired (see http://www.quicklz.com/order.html). The commercial license
// does not cover derived or ported versions created by third parties under GPL.
// Port of QuickLZ to C# by de4dot@gmail.com. This code is most likely not working now.
using System;
namespace de4dot.code.deobfuscators {
public class QuickLZBase {
protected static uint Read32(byte[] data, int index) {
return BitConverter.ToUInt32(data, index);
}
// Can't use Array.Copy() when data overlaps so here's one that works
protected static void Copy(byte[] src, int srcIndex, byte[] dst, int dstIndex, int size) {
for (int i = 0; i < size; i++)
dst[dstIndex++] = src[srcIndex++];
}
static int[] indexInc = new int[] { 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };
public static void Decompress(byte[] inData, int inIndex, byte[] outData) {
int decompressedLength = outData.Length;
int outIndex = 0;
uint val1 = 1;
uint count;
int size;
while (true) {
if (val1 == 1) {
val1 = Read32(inData, inIndex);
inIndex += 4;
}
uint val2 = Read32(inData, inIndex);
if ((val1 & 1) == 1) {
val1 >>= 1;
if ((val2 & 3) == 0) {
count = (val2 & 0xFF) >> 2;
Copy(outData, (int)(outIndex - count), outData, outIndex, 3);
outIndex += 3;
inIndex++;
}
else if ((val2 & 2) == 0) {
count = (val2 & 0xFFFF) >> 2;
Copy(outData, (int)(outIndex - count), outData, outIndex, 3);
outIndex += 3;
inIndex += 2;
}
else if ((val2 & 1) == 0) {
size = (int)((val2 >> 2) & 0x0F) + 3;
count = (val2 & 0xFFFF) >> 6;
Copy(outData, (int)(outIndex - count), outData, outIndex, size);
outIndex += size;
inIndex += 2;
}
else if ((val2 & 4) == 0) {
size = (int)((val2 >> 3) & 0x1F) + 3;
count = (val2 & 0xFFFFFF) >> 8;
Copy(outData, (int)(outIndex - count), outData, outIndex, size);
outIndex += size;
inIndex += 3;
}
else if ((val2 & 8) == 0) {
count = val2 >> 15;
if (count != 0) {
size = (int)((val2 >> 4) & 0x07FF) + 3;
inIndex += 4;
}
else {
size = (int)Read32(inData, inIndex + 4);
count = Read32(inData, inIndex + 8);
inIndex += 12;
}
Copy(outData, (int)(outIndex - count), outData, outIndex, size);
outIndex += size;
}
else {
byte b = (byte)(val2 >> 16);
size = (int)(val2 >> 4) & 0x0FFF;
if (size == 0) {
size = (int)Read32(inData, inIndex + 3);
inIndex += 7;
}
else
inIndex += 3;
for (int i = 0; i < size; i++)
outData[outIndex++] = b;
}
}
else {
Copy(inData, inIndex, outData, outIndex, 4);
int index = (int)(val1 & 0x0F);
outIndex += indexInc[index];
inIndex += indexInc[index];
val1 >>= indexInc[index];
if (outIndex >= decompressedLength - 4)
break;
}
}
while (outIndex < decompressedLength) {
if (val1 == 1) {
inIndex += 4;
val1 = 0x80000000;
}
outData[outIndex++] = inData[inIndex++];
val1 >>= 1;
}
}
}
public class QuickLZ : QuickLZBase {
static int DEFAULT_QCLZ_SIG = 0x5A4C4351; // "QCLZ"
public static bool IsCompressed(byte[] data) {
if (data.Length < 4)
return false;
return BitConverter.ToInt32(data, 0) == DEFAULT_QCLZ_SIG;
}
public static byte[] Decompress(byte[] inData) {
return Decompress(inData, DEFAULT_QCLZ_SIG);
}
public static byte[] Decompress(byte[] inData, int sig) {
/*int mode =*/ BitConverter.ToInt32(inData, 4);
int compressedLength = BitConverter.ToInt32(inData, 8);
int decompressedLength = BitConverter.ToInt32(inData, 12);
bool isDataCompressed = BitConverter.ToInt32(inData, 16) == 1;
int headerLength = 32;
if (BitConverter.ToInt32(inData, 0) != sig || BitConverter.ToInt32(inData, compressedLength - 4) != sig)
throw new ApplicationException("No QCLZ sig");
byte[] outData = new byte[decompressedLength];
if (!isDataCompressed) {
Copy(inData, headerLength, outData, 0, decompressedLength);
return outData;
}
Decompress(inData, headerLength, outData);
return outData;
}
}
}