diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 8a368666..fa1a753f 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -116,7 +116,6 @@ - @@ -142,10 +141,14 @@ + + + + diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/QuickLZ.cs b/de4dot.code/deobfuscators/QuickLZ.cs similarity index 77% rename from de4dot.code/deobfuscators/dotNET_Reactor/QuickLZ.cs rename to de4dot.code/deobfuscators/QuickLZ.cs index a54a12e3..4a594ad3 100644 --- a/de4dot.code/deobfuscators/dotNET_Reactor/QuickLZ.cs +++ b/de4dot.code/deobfuscators/QuickLZ.cs @@ -11,44 +11,21 @@ using System; -namespace de4dot.code.deobfuscators.dotNET_Reactor { - static class QuickLZ { - static int sig = 0x5A4C4351; // "QCLZ" - - public static bool isCompressed(byte[] data) { - if (data.Length < 4) - return false; - return BitConverter.ToInt32(data, 0) == sig; - } - - static uint read32(byte[] data, int index) { +namespace de4dot.code.deobfuscators { + 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 - static void copy(byte[] src, int srcIndex, byte[] dst, int dstIndex, int size) { + 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 byte[] decompress(byte[] inData) { - 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; - } - - int inIndex = headerLength; + public static void decompress(byte[] inData, int inIndex, byte[] outData) { + int decompressedLength = outData.Length; int outIndex = 0; uint val1 = 1; uint count; @@ -89,18 +66,30 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor { inIndex += 3; } else if ((val2 & 8) == 0) { - size = (int)((val2 >> 4) & 0x07FF) + 3; 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; - inIndex += 4; } 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; - inIndex += 3; } } else { @@ -121,7 +110,39 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor { outData[outIndex++] = inData[inIndex++]; val1 >>= 1; } + } + } + 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; } } diff --git a/de4dot.code/deobfuscators/Spices_Net/Deobfuscator.cs b/de4dot.code/deobfuscators/Spices_Net/Deobfuscator.cs new file mode 100644 index 00000000..96511b30 --- /dev/null +++ b/de4dot.code/deobfuscators/Spices_Net/Deobfuscator.cs @@ -0,0 +1,137 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System.Collections.Generic; +using Mono.Cecil; +using de4dot.blocks.cflow; + +namespace de4dot.code.deobfuscators.Spices_Net { + public class DeobfuscatorInfo : DeobfuscatorInfoBase { + public const string THE_NAME = "Spices.Net"; + public const string THE_TYPE = "sn"; + + public DeobfuscatorInfo() + : base() { + } + + public override string Name { + get { return THE_NAME; } + } + + public override string Type { + get { return THE_TYPE; } + } + + public override IDeobfuscator createDeobfuscator() { + return new Deobfuscator(new Deobfuscator.Options { + ValidNameRegex = validNameRegex.get(), + }); + } + + protected override IEnumerable