Example #1
0
		public override bool GetDecryptedModule(int count, ref byte[] newFileData, ref DumpedMethods dumpedMethods) {
			if (count != 0 || version == Version.Unknown)
				return false;

			byte[] fileData = ModuleBytes ?? DeobUtils.ReadModule(module);
			byte[] decompressed;
			using (var peImage = new MyPEImage(fileData)) {
				var section = peImage.Sections[peImage.Sections.Count - 1];
				var offset = section.PointerToRawData;
				offset += 16;

				byte[] compressed;
				int compressedLen;
				switch (version) {
				case Version.V0x:
					compressedLen = fileData.Length - (int)offset;
					compressed = peImage.OffsetReadBytes(offset, compressedLen);
					decompressed = Lzmat.DecompressOld(compressed);
					if (decompressed == null)
						throw new ApplicationException("LZMAT decompression failed");
					break;

				case Version.V1x_217:
				case Version.V218:
					if (peImage.PEImage.ImageNTHeaders.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;
		}
		byte[] Unpack2(MyPEImage peImage) {
			shouldUnpack = false;
			uint headerOffset = (uint)peImage.Length - 12;
			uint offsetEncryptedAssembly = CheckOffset(peImage, peImage.OffsetReadUInt32(headerOffset));
			uint ezencryptionLibLength = peImage.OffsetReadUInt32(headerOffset + 4);
			uint iniFileLength = peImage.OffsetReadUInt32(headerOffset + 8);

			uint offsetClrVersionNumber = checked(offsetEncryptedAssembly - 12);
			uint iniFileOffset = checked(headerOffset - iniFileLength);
			uint ezencryptionLibOffset = checked(iniFileOffset - ezencryptionLibLength);

			uint clrVerMajor = peImage.OffsetReadUInt32(offsetClrVersionNumber);
			uint clrVerMinor = peImage.OffsetReadUInt32(offsetClrVersionNumber + 4);
			uint clrVerBuild = peImage.OffsetReadUInt32(offsetClrVersionNumber + 8);
			if (clrVerMajor <= 0 || clrVerMajor >= 20 || clrVerMinor >= 20 || clrVerBuild >= 1000000)
				return null;

			var settings = new IniFile(Decompress2(peImage.OffsetReadBytes(iniFileOffset, (int)iniFileLength)));
			sizes = GetSizes(settings["General_App_Satellite_Assemblies_Sizes"]);
			if (sizes == null || sizes.Length <= 1)
				return null;
			shouldUnpack = true;
			if (sizes[0] != offsetEncryptedAssembly)
				return null;
			filenames = settings["General_App_Satellite_Assemblies"].Split('|');
			if (sizes.Length - 1 != filenames.Length)
				return null;

			byte[] ezencryptionLibData = Decompress1(peImage.OffsetReadBytes(ezencryptionLibOffset, (int)ezencryptionLibLength));
			var ezencryptionLibModule = ModuleDefMD.Load(ezencryptionLibData);
			var decrypter = new ApplicationModeDecrypter(ezencryptionLibModule);
			if (!decrypter.Detected)
				return null;

			var mainAssembly = UnpackEmbeddedFile(peImage, 0, decrypter);
			decrypter.MemoryPatcher.Patch(mainAssembly.data);
			for (int i = 1; i < filenames.Length; i++)
				satelliteAssemblies.Add(UnpackEmbeddedFile(peImage, i, decrypter));

			ClearDllBit(mainAssembly.data);
			return mainAssembly.data;
		}
		DumpedMethods CreateDumpedMethods(MyPEImage peImage, byte[] fileData, byte[] methodsData) {
			var dumpedMethods = new DumpedMethods();

			var methodsDataReader = MemoryImageStream.Create(methodsData);
			var fileDataReader = MemoryImageStream.Create(fileData);

			var methodDef = peImage.MetaData.TablesStream.MethodTable;
			for (uint rid = 1; rid <= methodDef.Rows; rid++) {
				var dm = new DumpedMethod();

				peImage.ReadMethodTableRowTo(dm, rid);
				if (dm.mdRVA == 0)
					continue;
				uint bodyOffset = peImage.RvaToOffset(dm.mdRVA);

				byte b = peImage.OffsetReadByte(bodyOffset);
				uint codeOffset;
				if ((b & 3) == 2) {
					if (b != 2)
						continue;	// not zero byte code size

					dm.mhFlags = 2;
					dm.mhMaxStack = 8;
					dm.mhLocalVarSigTok = 0;
					codeOffset = bodyOffset + 1;
				}
				else {
					if (peImage.OffsetReadUInt32(bodyOffset + 4) != 0)
						continue;	// not zero byte code size

					dm.mhFlags = peImage.OffsetReadUInt16(bodyOffset);
					dm.mhMaxStack = peImage.OffsetReadUInt16(bodyOffset + 2);
					dm.mhLocalVarSigTok = peImage.OffsetReadUInt32(bodyOffset + 8);
					codeOffset = bodyOffset + (uint)(dm.mhFlags >> 12) * 4;
				}
				fileDataReader.Position = codeOffset;

				if (!decrypter.Decrypt(fileDataReader, dm))
					continue;

				dumpedMethods.Add(dm);
			}

			return dumpedMethods;
		}
		public bool Decrypt(MyPEImage peImage, ISimpleDeobfuscator simpleDeobfuscator, ref DumpedMethods dumpedMethods, Dictionary<uint, byte[]> tokenToNativeCode, bool unpackedNativeFile) {
			if (encryptedResource.Method == null)
				return false;

			encryptedResource.Initialize(simpleDeobfuscator);
			if (!encryptedResource.FoundResource)
				return false;
			var methodsData = encryptedResource.Decrypt();

			bool hooksJitter = FindDnrCompileMethod(encryptedResource.Method.DeclaringType) != null;

			xorKey = GetXorKey();
			XorEncrypt(methodsData);

			var methodsDataReader = MemoryImageStream.Create(methodsData);
			int patchCount = methodsDataReader.ReadInt32();
			int mode = methodsDataReader.ReadInt32();

			int tmp = methodsDataReader.ReadInt32();
			methodsDataReader.Position -= 4;
			if ((tmp & 0xFF000000) == 0x06000000) {
				// It's method token + rva. DNR 3.7.0.3 (and earlier?) - 3.9.0.1
				methodsDataReader.Position += 8L * patchCount;
				patchCount = methodsDataReader.ReadInt32();
				mode = methodsDataReader.ReadInt32();

				PatchDwords(peImage, methodsDataReader, patchCount);
				while (methodsDataReader.Position < methodsData.Length - 1) {
					uint token = methodsDataReader.ReadUInt32();
					int numDwords = methodsDataReader.ReadInt32();
					PatchDwords(peImage, methodsDataReader, numDwords / 2);
				}
			}
			else if (!hooksJitter || mode == 1) {
				// DNR 3.9.8.0, 4.0+

				PatchDwords(peImage, methodsDataReader, patchCount);
				bool oldCode = !IsNewer45Decryption(encryptedResource.Method);
				while (methodsDataReader.Position < methodsData.Length - 1) {
					uint rva = methodsDataReader.ReadUInt32();
					int size;
					if (oldCode) {
						methodsDataReader.ReadUInt32();	// token, unknown, or index
						size = methodsDataReader.ReadInt32();
					}
					else
						size = methodsDataReader.ReadInt32() * 4;

					var newData = methodsDataReader.ReadBytes(size);
					if (unpackedNativeFile)
						peImage.DotNetSafeWriteOffset(rva, newData);
					else
						peImage.DotNetSafeWrite(rva, newData);
				}
			}
			else {
				// DNR 4.0+ (jitter is hooked)

				var methodDef = peImage.MetaData.TablesStream.MethodTable;
				var rvaToIndex = new Dictionary<uint, int>((int)methodDef.Rows);
				uint offset = (uint)methodDef.StartOffset;
				for (int i = 0; i < methodDef.Rows; i++) {
					uint rva = peImage.OffsetReadUInt32(offset);
					offset += methodDef.RowSize;
					if (rva == 0)
						continue;

					if ((peImage.ReadByte(rva) & 3) == 2)
						rva++;
					else
						rva += (uint)(4 * (peImage.ReadByte(rva + 1) >> 4));
					rvaToIndex[rva] = i;
				}

				PatchDwords(peImage, methodsDataReader, patchCount);
				int count = methodsDataReader.ReadInt32();
				dumpedMethods = new DumpedMethods();
				while (methodsDataReader.Position < methodsData.Length - 1) {
					uint rva = methodsDataReader.ReadUInt32();
					uint index = methodsDataReader.ReadUInt32();
					bool isNativeCode = index >= 0x70000000;
					int size = methodsDataReader.ReadInt32();
					var methodData = methodsDataReader.ReadBytes(size);

					int methodIndex;
					if (!rvaToIndex.TryGetValue(rva, out methodIndex)) {
						Logger.w("Could not find method having code RVA {0:X8}", rva);
						continue;
					}

					uint methodToken = 0x06000001 + (uint)methodIndex;

					if (isNativeCode) {
						totalEncryptedNativeMethods++;
						if (tokenToNativeCode != null)
							tokenToNativeCode[methodToken] = methodData;

						// Convert return true / false methods. The others are converted to
						// throw 0xDEADCODE.
						if (DeobUtils.IsCode(nativeLdci4, methodData)) {
							uint val = BitConverter.ToUInt32(methodData, 4);
							// ldc.i4 XXXXXXXXh / ret
							methodData = new byte[] { 0x20, 0, 0, 0, 0, 0x2A };
							methodData[1] = (byte)val;
							methodData[2] = (byte)(val >> 8);
							methodData[3] = (byte)(val >> 16);
							methodData[4] = (byte)(val >> 24);
						}
						else if (DeobUtils.IsCode(nativeLdci4_0, methodData)) {
							// ldc.i4.0 / ret
							methodData = new byte[] { 0x16, 0x2A };
						}
						else {
							tokenToNativeMethod[methodToken] = methodData;

							// ldc.i4 0xDEADCODE / conv.u4 / throw
							methodData = new byte[] { 0x20, 0xDE, 0xC0, 0xAD, 0xDE, 0x6D, 0x7A };
						}
					}

					var dm = new DumpedMethod();
					peImage.ReadMethodTableRowTo(dm, MDToken.ToRID(methodToken));
					dm.code = methodData;

					var codeReader = peImage.Reader;
					codeReader.Position = peImage.RvaToOffset(dm.mdRVA);
					byte[] code;
					var mbHeader = MethodBodyParser.ParseMethodBody(codeReader, out code, out dm.extraSections);
					peImage.UpdateMethodHeaderInfo(dm, mbHeader);

					dumpedMethods.Add(dm);
				}
			}

			return true;
		}
Example #5
0
 uint ReadUInt32(uint offset) => peImage.OffsetReadUInt32(methodInfosOffset + offset);
Example #6
0
        List <CsHeaderVersion> GetCsHeaderVersions(uint codeHeaderOffset, MDTable methodDefTable)
        {
            if (sigType == SigType.Old)
            {
                return new List <CsHeaderVersion> {
                           CsHeaderVersion.V10
                }
            }
            ;
            if (!IsOldHeader(methodDefTable))
            {
                return new List <CsHeaderVersion> {
                           CsHeaderVersion.V52
                }
            }
            ;
            if (csRtType.IsAtLeastVersion50())
            {
                return new List <CsHeaderVersion> {
                           CsHeaderVersion.V50
                }
            }
            ;
            if (IsCsHeader40(codeHeaderOffset))
            {
                return(new List <CsHeaderVersion> {
                    CsHeaderVersion.V40,
                    CsHeaderVersion.V30,
                });
            }
            return(new List <CsHeaderVersion> {
                CsHeaderVersion.V45,
                CsHeaderVersion.V50,
            });
        }

        bool IsCsHeader40(uint codeHeaderOffset)
        {
            try {
                uint offset       = codeHeaderOffset + codeHeader.totalCodeSize + 0x28;
                uint prevCodeOffs = 0;
                for (int i = 0; i < (int)codeHeader.numMethods; i++, offset += 4)
                {
                    uint codeOffs = peImage.OffsetReadUInt32(offset);
                    if (prevCodeOffs != 0 && codeOffs != 0 && codeOffs < prevCodeOffs)
                    {
                        return(false);
                    }
                    if (codeOffs != 0)
                    {
                        prevCodeOffs = codeOffs;
                    }
                }

                return(true);
            }
            catch (IOException) {
                return(false);
            }
        }

        bool IsOldHeader(MDTable methodDefTable)
        {
            if (methodDefTable.RowSize != codeHeader.methodDefElemSize)
            {
                return(true);
            }
            if ((uint)methodDefTable.StartOffset - peImage.RvaToOffset((uint)peImage.Cor20Header.MetaData.VirtualAddress) != codeHeader.methodDefTableOffset)
            {
                return(true);
            }

            return(false);
        }

        ICsHeader CreateCsHeader(CsHeaderVersion version)
        {
            switch (version)
            {
            case CsHeaderVersion.V30: return(new CsHeader30(this));

            case CsHeaderVersion.V40: return(new CsHeader40(this));

            case CsHeaderVersion.V45: return(new CsHeader45(this));

            case CsHeaderVersion.V50: return(new CsHeader5(this, 0x28));

            case CsHeaderVersion.V52: return(new CsHeader5(this, 0x30));

            default: throw new ApplicationException("Unknown CS header");
            }
        }
Example #7
0
        public bool Decrypt(MyPEImage peImage, ISimpleDeobfuscator simpleDeobfuscator, ref DumpedMethods dumpedMethods, Dictionary <uint, byte[]> tokenToNativeCode, bool unpackedNativeFile)
        {
            if (encryptedResource.Method == null)
            {
                return(false);
            }

            encryptedResource.Initialize(simpleDeobfuscator);
            if (!encryptedResource.FoundResource)
            {
                return(false);
            }
            var methodsData = encryptedResource.Decrypt();

            bool hooksJitter = FindDnrCompileMethod(encryptedResource.Method.DeclaringType) != null;

            xorKey = GetXorKey();
            XorEncrypt(methodsData);

            var methodsDataReader = MemoryImageStream.Create(methodsData);
            int patchCount        = methodsDataReader.ReadInt32();
            int mode = methodsDataReader.ReadInt32();

            int tmp = methodsDataReader.ReadInt32();

            methodsDataReader.Position -= 4;
            if ((tmp & 0xFF000000) == 0x06000000)
            {
                // It's method token + rva. DNR 3.7.0.3 (and earlier?) - 3.9.0.1
                methodsDataReader.Position += 8L * patchCount;
                patchCount = methodsDataReader.ReadInt32();
                mode       = methodsDataReader.ReadInt32();

                PatchDwords(peImage, methodsDataReader, patchCount);
                while (methodsDataReader.Position < methodsData.Length - 1)
                {
                    uint token     = methodsDataReader.ReadUInt32();
                    int  numDwords = methodsDataReader.ReadInt32();
                    PatchDwords(peImage, methodsDataReader, numDwords / 2);
                }
            }
            else if (!hooksJitter || mode == 1)
            {
                // DNR 3.9.8.0, 4.0+

                PatchDwords(peImage, methodsDataReader, patchCount);
                bool oldCode = !IsNewer45Decryption(encryptedResource.Method);
                while (methodsDataReader.Position < methodsData.Length - 1)
                {
                    uint rva = methodsDataReader.ReadUInt32();
                    int  size;
                    if (oldCode)
                    {
                        methodsDataReader.ReadUInt32();                         // token, unknown, or index
                        size = methodsDataReader.ReadInt32();
                    }
                    else
                    {
                        size = methodsDataReader.ReadInt32() * 4;
                    }

                    var newData = methodsDataReader.ReadBytes(size);
                    if (unpackedNativeFile)
                    {
                        peImage.DotNetSafeWriteOffset(rva, newData);
                    }
                    else
                    {
                        peImage.DotNetSafeWrite(rva, newData);
                    }
                }
            }
            else
            {
                // DNR 4.0+ (jitter is hooked)

                var  methodDef  = peImage.MetaData.TablesStream.MethodTable;
                var  rvaToIndex = new Dictionary <uint, int>((int)methodDef.Rows);
                uint offset     = (uint)methodDef.StartOffset;
                for (int i = 0; i < methodDef.Rows; i++)
                {
                    uint rva = peImage.OffsetReadUInt32(offset);
                    offset += methodDef.RowSize;
                    if (rva == 0)
                    {
                        continue;
                    }

                    if ((peImage.ReadByte(rva) & 3) == 2)
                    {
                        rva++;
                    }
                    else
                    {
                        rva += (uint)(4 * (peImage.ReadByte(rva + 1) >> 4));
                    }
                    rvaToIndex[rva] = i;
                }

                PatchDwords(peImage, methodsDataReader, patchCount);
                int count = methodsDataReader.ReadInt32();
                dumpedMethods = new DumpedMethods();
                while (methodsDataReader.Position < methodsData.Length - 1)
                {
                    uint rva          = methodsDataReader.ReadUInt32();
                    uint index        = methodsDataReader.ReadUInt32();
                    bool isNativeCode = index >= 0x70000000;
                    int  size         = methodsDataReader.ReadInt32();
                    var  methodData   = methodsDataReader.ReadBytes(size);

                    int methodIndex;
                    if (!rvaToIndex.TryGetValue(rva, out methodIndex))
                    {
                        Logger.w("Could not find method having code RVA {0:X8}", rva);
                        continue;
                    }

                    uint methodToken = 0x06000001 + (uint)methodIndex;

                    if (isNativeCode)
                    {
                        totalEncryptedNativeMethods++;
                        if (tokenToNativeCode != null)
                        {
                            tokenToNativeCode[methodToken] = methodData;
                        }

                        // Convert return true / false methods. The others are converted to
                        // throw 0xDEADCODE.
                        if (DeobUtils.IsCode(nativeLdci4, methodData))
                        {
                            uint val = BitConverter.ToUInt32(methodData, 4);
                            // ldc.i4 XXXXXXXXh / ret
                            methodData    = new byte[] { 0x20, 0, 0, 0, 0, 0x2A };
                            methodData[1] = (byte)val;
                            methodData[2] = (byte)(val >> 8);
                            methodData[3] = (byte)(val >> 16);
                            methodData[4] = (byte)(val >> 24);
                        }
                        else if (DeobUtils.IsCode(nativeLdci4_0, methodData))
                        {
                            // ldc.i4.0 / ret
                            methodData = new byte[] { 0x16, 0x2A };
                        }
                        else
                        {
                            tokenToNativeMethod[methodToken] = methodData;

                            // ldc.i4 0xDEADCODE / conv.u4 / throw
                            methodData = new byte[] { 0x20, 0xDE, 0xC0, 0xAD, 0xDE, 0x6D, 0x7A };
                        }
                    }

                    var dm = new DumpedMethod();
                    peImage.ReadMethodTableRowTo(dm, MDToken.ToRID(methodToken));
                    dm.code = methodData;

                    var codeReader = peImage.Reader;
                    codeReader.Position = peImage.RvaToOffset(dm.mdRVA);
                    byte[] code;
                    var    mbHeader = MethodBodyParser.ParseMethodBody(codeReader, out code, out dm.extraSections);
                    peImage.UpdateMethodHeaderInfo(dm, mbHeader);

                    dumpedMethods.Add(dm);
                }
            }

            return(true);
        }
 uint ReadUInt32(uint offset)
 {
     return(peImage.OffsetReadUInt32(methodInfosOffset + offset));
 }
Example #9
0
		static EncryptionVersion GetVersion(MyPEImage peImage, uint headerOffset) {
			uint m1lo = peImage.OffsetReadUInt32(headerOffset + 0x900);
			uint m1hi = peImage.OffsetReadUInt32(headerOffset + 0x904);

			foreach (var info in EncryptionInfos.Rva900h) {
				if (info.MagicLo == m1lo && info.MagicHi == m1hi)
					return info.Version;
			}

			return EncryptionVersion.Unknown;
		}