diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index 95947e61..892af111 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -198,6 +198,8 @@
+
+
diff --git a/de4dot.code/deobfuscators/MPRESS/Deobfuscator.cs b/de4dot.code/deobfuscators/MPRESS/Deobfuscator.cs
new file mode 100644
index 00000000..5311149b
--- /dev/null
+++ b/de4dot.code/deobfuscators/MPRESS/Deobfuscator.cs
@@ -0,0 +1,239 @@
+/*
+ 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;
+using System.Collections.Generic;
+using Mono.Cecil;
+using Mono.MyStuff;
+using de4dot.PE;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.MPRESS {
+ public class DeobfuscatorInfo : DeobfuscatorInfoBase {
+ public const string THE_NAME = "MPRESS";
+ public const string THE_TYPE = "mp";
+ 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 getOptionsInternal() {
+ return new List () {
+ };
+ }
+ }
+
+ class Deobfuscator : DeobfuscatorBase {
+ Options options;
+ Version version;
+ string obfuscatorName = DeobfuscatorInfo.THE_NAME;
+
+ enum Version {
+ Unknown,
+ V0x, // 0.71 - 0.99
+ V1x_217, // 1.x - 2.17
+ V218, // 2.18+
+ }
+
+ internal class Options : OptionsBase {
+ }
+
+ public override string Type {
+ get { return DeobfuscatorInfo.THE_TYPE; }
+ }
+
+ public override string TypeLong {
+ get { return DeobfuscatorInfo.THE_NAME; }
+ }
+
+ public override string Name {
+ get { return obfuscatorName; }
+ }
+
+ public Deobfuscator(Options options)
+ : base(options) {
+ this.options = options;
+ }
+
+ protected override int detectInternal() {
+ int val = 0;
+
+ if (version != Version.Unknown)
+ val += 100;
+
+ return val;
+ }
+
+ protected override void scanForObfuscator() {
+ version = detectVersion();
+ switch (version) {
+ case Version.V0x: obfuscatorName += " v0.71 - v0.99"; break;
+ case Version.V1x_217: obfuscatorName += " v1.x - v2.17"; break;
+ case Version.V218: obfuscatorName += " v2.18+"; break;
+ case Version.Unknown: break;
+ default: throw new ApplicationException("Unknown version");
+ }
+ }
+
+ class MethodInfo {
+ public readonly string returnType;
+ public readonly string parameters;
+ public readonly string name;
+
+ public MethodInfo(string returnType, string parameters, string name = null) {
+ this.returnType = returnType;
+ this.parameters = parameters;
+ this.name = name;
+ }
+ }
+
+ static readonly string[] requiredFields = new string[] {
+ "System.Reflection.Assembly",
+ };
+ static readonly MethodInfo[] methods_v0x = new MethodInfo[] {
+ new MethodInfo("System.Void", "()", ".ctor"),
+ new MethodInfo("System.Boolean", "(System.String,System.Byte[]&)"),
+ new MethodInfo("System.Boolean", "(System.Byte[],System.Byte[]&)"),
+ new MethodInfo("System.Int32", "(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32,System.Int32)"),
+ new MethodInfo("System.Int32", "(System.String[])"),
+ };
+ static readonly MethodInfo[] methods_v1x = new MethodInfo[] {
+ new MethodInfo("System.Void", "()", ".ctor"),
+ new MethodInfo("System.Boolean", "(System.String,System.Byte[]&)"),
+ new MethodInfo("System.Boolean", "(System.Byte[],System.Byte[]&,System.Int32)"),
+ new MethodInfo("System.Int32", "(System.Byte[],System.Byte[],System.Int32)"),
+ new MethodInfo("System.Int32", "(System.String[])"),
+ };
+ Version detectVersion() {
+ var ep = module.EntryPoint;
+ if (ep == null || ep.Body == null)
+ return Version.Unknown;
+ var type = ep.DeclaringType;
+ if (type == null)
+ return Version.Unknown;
+ if (!new FieldTypes(type).exactly(requiredFields))
+ return Version.Unknown;
+ if (module.Types.Count != 2)
+ return Version.Unknown;
+ if (module.Types[1] != type)
+ return Version.Unknown;
+ if (module.Types[0].Methods.Count != 0)
+ return Version.Unknown;
+
+ if (checkMethods(type, methods_v0x))
+ return Version.V0x;
+ if (checkMethods(type, methods_v1x)) {
+ var lfMethod = DotNetUtils.getMethod(type, "System.Boolean", "(System.String,System.Byte[]&)");
+ if (lfMethod != null) {
+ if (DeobUtils.hasInteger(lfMethod, (int)Machine.amd64))
+ return Version.V218;
+ return Version.V1x_217;
+ }
+ }
+ return Version.Unknown;
+ }
+
+ static bool checkMethods(TypeDefinition type, MethodInfo[] requiredMethods) {
+ var methods = new List(type.Methods);
+ foreach (var info in requiredMethods) {
+ if (!checkMethod(methods, info))
+ return false;
+ }
+ return methods.Count == 0;
+ }
+
+ static bool checkMethod(List methods, MethodInfo info) {
+ foreach (var method in methods) {
+ if (info.name != null && info.name != method.Name)
+ continue;
+ if (!DotNetUtils.isMethod(method, info.returnType, info.parameters))
+ continue;
+
+ methods.Remove(method);
+ return true;
+ }
+ return false;
+ }
+
+ public override bool getDecryptedModule(ref byte[] newFileData, ref DumpedMethods dumpedMethods) {
+ if (version == Version.Unknown)
+ return false;
+
+ byte[] fileData = ModuleBytes ?? DeobUtils.readModule(module);
+ var peImage = new PeImage(fileData);
+ var section = peImage.Sections[peImage.Sections.Length - 1];
+ var offset = section.pointerToRawData;
+ offset += 16;
+
+ byte[] decompressed, compressed;
+ int compressedLen;
+ switch (version) {
+ case Version.V0x:
+ compressedLen = fileData.Length - (int)offset;
+ compressed = peImage.offsetReadBytes(offset, compressedLen);
+ decompressed = Lzmat.decompress_old(compressed);
+ if (decompressed == null)
+ throw new ApplicationException("LZMAT decompression failed");
+ break;
+
+ case Version.V1x_217:
+ case Version.V218:
+ if (peImage.FileHeader.machine == Machine.amd64 && version == Version.V218)
+ offset = section.pointerToRawData + section.virtualSize;
+ int decompressedLen = (int)peImage.offsetReadUInt32(offset);
+ compressedLen = fileData.Length - (int)offset - 4;
+ compressed = peImage.offsetReadBytes(offset + 4, compressedLen);
+ decompressed = new byte[decompressedLen];
+ uint decompressedLen2;
+ if (Lzmat.decompress(decompressed, out decompressedLen2, compressed) != LzmatStatus.OK)
+ throw new ApplicationException("LZMAT decompression failed");
+ break;
+
+ default:
+ throw new ApplicationException("Unknown MPRESS version");
+ }
+
+ newFileData = decompressed;
+ return true;
+ }
+
+ public override IDeobfuscator moduleReloaded(ModuleDefinition module) {
+ var newOne = new Deobfuscator(options);
+ newOne.setModule(module);
+ return newOne;
+ }
+
+ public override IEnumerable getStringDecrypterMethods() {
+ return new List();
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/MPRESS/Lzmat.cs b/de4dot.code/deobfuscators/MPRESS/Lzmat.cs
new file mode 100644
index 00000000..e0f9dedd
--- /dev/null
+++ b/de4dot.code/deobfuscators/MPRESS/Lzmat.cs
@@ -0,0 +1,267 @@
+/*
+***************************************************************************
+** LZMAT ANSI-C decoder 1.01
+** Copyright (C) 2007,2008 Vitaly Evseenko. All Rights Reserved.
+** lzmat_dec.c
+**
+** This file is part of the LZMAT real-time data compression library.
+**
+** The LZMAT library 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 2 of
+** the License, or (at your option) any later version.
+**
+** The LZMAT library is distributed 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 the LZMAT library; see the file GPL.TXT.
+** If not, write to the Free Software Foundation, Inc.,
+** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**
+** Vitaly Evseenko
+**
+** http://www.matcode.com/lzmat.htm
+***************************************************************************
+*/
+
+using System;
+
+namespace de4dot.code.deobfuscators.MPRESS {
+ enum LzmatStatus {
+ OK = 0,
+ ERROR = -1,
+ INTEGRITY_FAILURE = 0x100,
+ BUFFER_TOO_SMALL = 0x110,
+ }
+
+ static class Lzmat {
+ const int LZMAT_DEFAULT_CNT = 0x12;
+ const int LZMAT_1BYTE_CNT = (0xFF + LZMAT_DEFAULT_CNT);
+ const int LZMAT_2BYTE_CNT = (0xFFFF + LZMAT_1BYTE_CNT);
+ const int LZMAT_MAX_2BYTE_CNT = (LZMAT_2BYTE_CNT - 1);
+
+ const int MAX_LZMAT_SHORT_DIST0 = 0x80;
+ const int MAX_LZMAT_SHORT_DIST1 = (0x800 | MAX_LZMAT_SHORT_DIST0);
+ const int MAX_LZMAT_LONG_DIST0 = 0x40;
+ const int MAX_LZMAT_LONG_DIST1 = (0x400 | MAX_LZMAT_LONG_DIST0);
+ const int MAX_LZMAT_LONG_DIST2 = (0x4000 | MAX_LZMAT_LONG_DIST1);
+ const int MAX_LZMAT_LONG_DIST3 = (0x40000 | MAX_LZMAT_LONG_DIST2);
+ const int MAX_LZMAT_GAMMA_DIST = (MAX_LZMAT_LONG_DIST3 - 1);
+
+ const int LZMAT_DIST_MSK0 = 0x3F;
+ const int LZMAT_DIST_MSK1 = 0x3FF;
+
+ static uint LZMAT_GET_U4(byte[] _p_, ref uint _i_, ref byte _n_) {
+ return (_n_^=1)!=0?(uint)(_p_[_i_]&0xF):(uint)(_p_[_i_++]>>4);
+ }
+
+ static byte LZMAT_GET_U8(byte[] _p_, uint _i_, byte _n_) {
+ return (byte)(((_n_)!=0?((_p_[_i_]>>4)|(_p_[_i_+1]<<4)):_p_[_i_]));
+ }
+
+ static ushort LZMAT_GET_LE16(byte[] _p_, uint _i_, byte _n_) {
+ return (ushort)((_n_)!=0?((_p_[_i_]>>4)|((ushort)(GET_LE16(_p_,_i_+1))<<4)):GET_LE16(_p_,_i_));
+ }
+
+ static ushort GET_LE16(byte[] _p_, uint _i_) {
+ return BitConverter.ToUInt16(_p_, (int)_i_);
+ }
+
+ public static LzmatStatus decompress(byte[] pbOut, out uint pcbOut, byte[] pbIn) {
+ pcbOut = 0;
+ uint cbIn = (uint)pbIn.Length;
+
+ uint inPos, outPos;
+ uint cbOutBuf = (uint)pbOut.Length;
+ byte cur_nib;
+ pbOut[0] = pbIn[0];
+ for(inPos=1, outPos=1, cur_nib=0; inPos<(cbIn-cur_nib);)
+ {
+ int bc;
+ byte tag;
+ tag = LZMAT_GET_U8(pbIn,inPos,cur_nib);
+ inPos++;
+ for(bc=0; bc<8 && inPos<(cbIn-cur_nib) && outPosMAX_LZMAT_SHORT_DIST1)
+ {
+ dist = r_cnt>>2;
+ switch(r_cnt&3)
+ {
+ case 0:
+ dist=(dist&LZMAT_DIST_MSK0)+1;
+ break;
+ case 1:
+ inPos+=cur_nib;
+ dist = (dist&LZMAT_DIST_MSK1)+0x41;
+ cur_nib^=1;
+ break;
+ case 2:
+ inPos++;
+ dist += 0x441;
+ break;
+ case 3:
+ if((inPos+2+cur_nib)>cbIn)
+ return LzmatStatus.INTEGRITY_FAILURE+1;
+ inPos++;
+ dist = (dist +
+ ((uint)LZMAT_GET_U4(pbIn,ref inPos,ref cur_nib)<<14))
+ +0x4441;
+ break;
+ }
+ }
+ else
+ {
+ dist = r_cnt>>1;
+ if((r_cnt&1)!=0)
+ {
+ inPos+=cur_nib;
+ dist = (dist&0x7FF)+0x81;
+ cur_nib^=1;
+ }
+ else
+ dist = (dist&0x7F)+1;
+ }
+//#undef cflag
+ r_cnt = LZMAT_GET_U4(pbIn,ref inPos,ref cur_nib);
+ if(r_cnt!=0xF)
+ {
+ r_cnt += 3;
+ }
+ else
+ {
+ if((inPos+1+cur_nib)>cbIn)
+ return LzmatStatus.INTEGRITY_FAILURE+2;
+ r_cnt = LZMAT_GET_U8(pbIn,inPos,cur_nib);
+ inPos++;
+ if(r_cnt!=0xFF)
+ {
+ r_cnt += LZMAT_DEFAULT_CNT;
+ }
+ else
+ {
+ if((inPos+2+cur_nib)>cbIn)
+ return LzmatStatus.INTEGRITY_FAILURE+3;
+ r_cnt = (uint)(LZMAT_GET_LE16(pbIn,inPos,cur_nib)+LZMAT_1BYTE_CNT);
+ inPos+=2;
+ if(r_cnt==LZMAT_2BYTE_CNT)
+ {
+ // copy chunk
+ if(cur_nib!=0)
+ {
+ r_cnt = ((uint)pbIn[inPos-4]&0xFC)<<5;
+ inPos++;
+ cur_nib = 0;
+ }
+ else
+ {
+ r_cnt = (uint)((GET_LE16(pbIn,inPos-5)&0xFC0)<<1);
+ }
+ r_cnt+=(uint)((tag&0x7F)+4);
+ r_cnt<<=1;
+ if((outPos+(r_cnt<<2))>cbOutBuf)
+ return LzmatStatus.BUFFER_TOO_SMALL;
+ while(r_cnt--!=0 && outPoscbOutBuf)
+ return LzmatStatus.BUFFER_TOO_SMALL+1;
+ r_pos = outPos-dist;
+ while(r_cnt--!=0 && outPos> 4) + 3;
+ if (outPosDispl == 0)
+ outPosDispl = 0x1000;
+ if (outPosDispl > outPos)
+ return 0;
+ if (r_cnt == 18) {
+ if (inPos >= inLen)
+ return 0;
+ r_cnt = inBuf[inIndex + inPos++] + 18;
+ }
+ if (r_cnt == 0x111) {
+ if (inPos + 2 > inLen)
+ return 0;
+ r_cnt = (inBuf[inIndex + inPos + 1] << 8) + inBuf[inIndex + inPos] + 0x111;
+ inPos += 2;
+ }
+ int outPos2 = outPos - outPosDispl;
+ while (r_cnt-- > 0 && outPos < outLen)
+ outBuf[outIndex + outPos++] = outBuf[outIndex + outPos2++];
+ }
+ else
+ outBuf[outIndex + outPos++] = inBuf[inIndex + inPos++];
+ }
+ }
+ if (inPos < inLen)
+ return 0;
+ return outPos;
+ }
+ }
+}
diff --git a/de4dot.cui/Program.cs b/de4dot.cui/Program.cs
index 6fca2285..e869b01a 100644
--- a/de4dot.cui/Program.cs
+++ b/de4dot.cui/Program.cs
@@ -49,6 +49,7 @@ namespace de4dot.cui {
new de4dot.code.deobfuscators.Eazfuscator_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Goliath_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.MaxtoCode.DeobfuscatorInfo(),
+ new de4dot.code.deobfuscators.MPRESS.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Skater_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.SmartAssembly.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Spices_Net.DeobfuscatorInfo(),