public void patch(byte[] peImageData) { var peImage = new PeImage(peImageData); foreach (var info in patchInfos) { for (int i = 0; i < info.offsets.Length; i++) peImage.dotNetSafeWriteOffset((uint)info.offsets[i], BitConverter.GetBytes(info.values[i])); } }
public override bool getDecryptedModule(ref byte[] newFileData, ref DumpedMethods dumpedMethods) { if (!needsPatching()) return false; var fileData = ModuleBytes ?? DeobUtils.readModule(module); var peImage = new PeImage(fileData); if (!decrypterType.patch(peImage)) return false; newFileData = fileData; return true; }
DumpedMethods decryptMethods(PeImage peImage, PeHeader peHeader, McHeader mcHeader) { var dumpedMethods = new DumpedMethods(); var methodInfos = new MethodInfos(mainType, peImage, peHeader, mcHeader); methodInfos.initializeInfos(); var metadataTables = peImage.Cor20Header.createMetadataTables(); var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef); uint methodDefOffset = methodDef.fileOffset; for (int i = 0; i < methodDef.rows; i++, methodDefOffset += methodDef.totalSize) { uint bodyRva = peImage.offsetReadUInt32(methodDefOffset); if (bodyRva == 0) continue; var info = methodInfos.lookup(bodyRva); if (info == null) continue; uint bodyOffset = peImage.rvaToOffset(bodyRva); ushort magic = peImage.offsetReadUInt16(bodyOffset); if (magic != 0xFFF3) continue; var dm = new DumpedMethod(); dm.token = (uint)(0x06000001 + i); dm.mdImplFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[1].offset); dm.mdFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[2].offset); dm.mdName = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[3].offset, methodDef.fields[3].size); dm.mdSignature = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[4].offset, methodDef.fields[4].size); dm.mdParamList = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[5].offset, methodDef.fields[5].size); var reader = new BinaryReader(new MemoryStream(info.body)); byte b = reader.ReadByte(); if ((b & 3) == 2) { dm.mhFlags = 2; dm.mhMaxStack = 8; dm.mhCodeSize = (uint)(b >> 2); dm.mhLocalVarSigTok = 0; } else { reader.BaseStream.Position--; dm.mhFlags = reader.ReadUInt16(); dm.mhMaxStack = reader.ReadUInt16(); dm.mhCodeSize = reader.ReadUInt32(); dm.mhLocalVarSigTok = reader.ReadUInt32(); uint codeOffset = (uint)(dm.mhFlags >> 12) * 4; reader.BaseStream.Position += codeOffset - 12; } dm.code = reader.ReadBytes((int)dm.mhCodeSize); if ((dm.mhFlags & 8) != 0) { reader.BaseStream.Position = (reader.BaseStream.Position + 3) & ~3; dm.extraSections = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position)); } dumpedMethods.add(dm); } return dumpedMethods; }
public bool decrypt(PeImage peImage, ISimpleDeobfuscator simpleDeobfuscator, ref Dictionary<uint, DumpedMethod> dumpedMethods, Dictionary<uint,byte[]> tokenToNativeCode) { if (encryptedResource.Method == null) return false; encryptedResource.init(simpleDeobfuscator); if (!encryptedResource.FoundResource) return false; var methodsData = encryptedResource.decrypt(); bool hooksJitter = findDnrCompileMethod(encryptedResource.Method.DeclaringType) != null; xorKey = getXorKey(); xorEncrypt(methodsData); var methodsDataReader = new BinaryReader(new MemoryStream(methodsData)); int patchCount = methodsDataReader.ReadInt32(); int mode = methodsDataReader.ReadInt32(); int tmp = methodsDataReader.ReadInt32(); methodsDataReader.BaseStream.Position -= 4; if ((tmp & 0xFF000000) == 0x06000000) { // It's method token + rva. DNR 3.7.0.3 (and earlier?) - 3.9.0.1 methodsDataReader.BaseStream.Position += 8L * patchCount; patchCount = methodsDataReader.ReadInt32(); mode = methodsDataReader.ReadInt32(); patchDwords(peImage, methodsDataReader, patchCount); while (methodsDataReader.BaseStream.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, 4.1, 4.2, 4.3, 4.4 patchDwords(peImage, methodsDataReader, patchCount); while (methodsDataReader.BaseStream.Position < methodsData.Length - 1) { uint rva = methodsDataReader.ReadUInt32(); uint token = methodsDataReader.ReadUInt32(); // token, unknown, or index int size = methodsDataReader.ReadInt32(); if (size > 0) peImage.dotNetSafeWrite(rva, methodsDataReader.ReadBytes(size)); } } else { // DNR 4.0 - 4.4 (jitter is hooked) var metadataTables = peImage.Cor20Header.createMetadataTables(); var methodDef = metadataTables.getMetadataType(PE.MetadataIndex.iMethodDef); var rvaToIndex = new Dictionary<uint, int>((int)methodDef.rows); uint offset = methodDef.fileOffset; for (int i = 0; i < methodDef.rows; i++) { uint rva = peImage.offsetReadUInt32(offset); offset += methodDef.totalSize; 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 Dictionary<uint, DumpedMethod>(); while (methodsDataReader.BaseStream.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)) { Log.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(); dm.token = methodToken; dm.code = methodData; offset = methodDef.fileOffset + (uint)(methodIndex * methodDef.totalSize); rva = peImage.offsetReadUInt32(offset); dm.mdImplFlags = peImage.offsetReadUInt16(offset + (uint)methodDef.fields[1].offset); dm.mdFlags = peImage.offsetReadUInt16(offset + (uint)methodDef.fields[2].offset); dm.mdName = peImage.offsetRead(offset + (uint)methodDef.fields[3].offset, methodDef.fields[3].size); dm.mdSignature = peImage.offsetRead(offset + (uint)methodDef.fields[4].offset, methodDef.fields[4].size); dm.mdParamList = peImage.offsetRead(offset + (uint)methodDef.fields[5].offset, methodDef.fields[5].size); if ((peImage.readByte(rva) & 3) == 2) { dm.mhFlags = 2; dm.mhMaxStack = 8; dm.mhCodeSize = (uint)dm.code.Length; dm.mhLocalVarSigTok = 0; } else { dm.mhFlags = peImage.readUInt16(rva); dm.mhMaxStack = peImage.readUInt16(rva + 2); dm.mhCodeSize = (uint)dm.code.Length; dm.mhLocalVarSigTok = peImage.readUInt32(rva + 8); } dumpedMethods[dm.token] = dm; } } return true; }
public bool decrypt(byte[] fileData, ref DumpedMethods dumpedMethods) { if (decrypter == null) return false; var peImage = new PeImage(fileData); if (peImage.Sections.Length <= 0) return false; var methodsData = findMethodsData(peImage, fileData); if (methodsData == null) return false; decrypter.initialize(methodsData); dumpedMethods = createDumpedMethods(peImage, fileData, methodsData); if (dumpedMethods == null) return false; return true; }
byte[] findMethodsData(PeImage peImage, byte[] fileData) { var section = peImage.Sections[0]; var reader = new BinaryReader(new MemoryStream(fileData)); const int RVA_EXECUTIVE_OFFSET = 1 * 4; const int ENC_CODE_OFFSET = 6 * 4; int lastOffset = (int)(section.pointerToRawData + section.sizeOfRawData); for (int offset = getStartOffset(peImage); offset < lastOffset; ) { offset = findSig(fileData, offset, lastOffset, initializeMethodEnd); if (offset < 0) return null; offset += initializeMethodEnd.Length; short retImm16 = BitConverter.ToInt16(fileData, offset); if (retImm16 != 0x0C && retImm16 != 0x10) continue; offset += 2; if (offset + ENC_CODE_OFFSET + 4 > lastOffset) return null; // rva is 0 when the assembly has been embedded int rva = BitConverter.ToInt32(fileData, offset + RVA_EXECUTIVE_OFFSET); if (rva != 0 && mainType.Rvas.IndexOf(rva) < 0) continue; int relOffs = BitConverter.ToInt32(fileData, offset + ENC_CODE_OFFSET); if (relOffs <= 0 || relOffs >= section.sizeOfRawData) continue; reader.BaseStream.Position = section.pointerToRawData + relOffs; int size = DeobUtils.readVariableLengthInt32(reader); int endOffset = relOffs + size; if (endOffset < relOffs || endOffset > section.sizeOfRawData) continue; return reader.ReadBytes(size); } return null; }
public ProDecrypter(PeImage peImage, CodeHeader codeHeader) : base(peImage, codeHeader) { for (int i = 0; i < 4; i++) key[i] = be_readUint32(codeHeader.decryptionKey, i * 4); }
public DecrypterBase(PeImage peImage, CodeHeader codeHeader) { this.peImage = peImage; this.codeHeader = codeHeader; endOfMetadata = peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress + peImage.Cor20Header.metadataDirectory.size); }
public override bool getDecryptedModule(ref byte[] newFileData, ref Dictionary<uint, DumpedMethod> dumpedMethods) { if (!options.DecryptMethods) return false; byte[] fileData = DeobUtils.readModule(module); var peImage = new PeImage(fileData); if (!new MethodsDecrypter().decrypt(peImage, ref dumpedMethods)) { Log.v("Methods aren't encrypted or invalid signature"); return false; } newFileData = fileData; return true; }
static void readTo(PeImage peImage, byte[] data, int destOffset, uint imageOffset, uint maxLength) { if (destOffset > data.Length) return; int len = Math.Min(data.Length - destOffset, (int)maxLength); var newData = peImage.offsetReadBytes(imageOffset, len); Array.Copy(newData, 0, data, destOffset, newData.Length); }
static byte[] getPeHeaderData(PeImage peImage) { var data = new byte[0x1000]; var firstSection = peImage.Sections[0]; readTo(peImage, data, 0, 0, firstSection.pointerToRawData); foreach (var section in peImage.Sections) { if (section.virtualAddress >= data.Length) continue; int offset = (int)section.virtualAddress; readTo(peImage, data, offset, section.pointerToRawData, section.sizeOfRawData); } return data; }
public PeHeader(MainType mainType, PeImage peImage) { headerData = getPeHeaderData(peImage); if (!mainType.IsOld && peImage.readUInt32(0x2008) != 0x48) { rvaDispl1 = readUInt32(0x0FB0) ^ XOR_KEY; rvaDispl2 = readUInt32(0x0FB4) ^ XOR_KEY; } }
public MethodInfos(MainType mainType, PeImage peImage, PeHeader peHeader, McHeader mcHeader) { this.mainType = mainType; this.peImage = peImage; this.peHeader = peHeader; this.mcHeader = mcHeader; structSize = getStructSize(mcHeader); uint methodInfosRva = peHeader.getRva2(0x0FF8, mcHeader.readUInt32(0x005A)); uint encryptedDataRva = peHeader.getRva2(0x0FF0, mcHeader.readUInt32(0x0046)); methodInfosOffset = peImage.rvaToOffset(methodInfosRva); encryptedDataOffset = peImage.rvaToOffset(encryptedDataRva); }
public McHeader(PeImage peImage, PeHeader peHeader) { this.peHeader = peHeader; this.data = peImage.readBytes(peHeader.getMcHeaderRva(), 0x2000); }
void decryptResources(byte[] fileData, PeImage peImage, PeHeader peHeader, McHeader mcHeader) { uint resourceRva = peHeader.getRva1(0x0E10, mcHeader.readUInt32(0x00A0)); uint resourceSize = peHeader.readUInt32(0x0E14) ^ mcHeader.readUInt32(0x00AA); if (resourceRva == 0 || resourceSize == 0) return; if (resourceRva != peImage.Cor20Header.resources.virtualAddress || resourceSize != peImage.Cor20Header.resources.size) { Log.w("Invalid resource RVA and size found"); } Log.v("Decrypting resources @ RVA {0:X8}, {1} bytes", resourceRva, resourceSize); int resourceOffset = (int)peImage.rvaToOffset(resourceRva); for (int i = 0; i < resourceSize; i++) fileData[resourceOffset + i] ^= mcHeader[i % 0x2000]; }
public override byte[] unpackNativeFile(PeImage peImage) { var unpacker = new ApplicationModeUnpacker(peImage); var data = unpacker.unpack(); if (data == null) return null; unpackedFiles.AddRange(unpacker.EmbeddedAssemblies); unpackedNativeFile = true; ModuleBytes = data; return data; }
public bool decrypt(PeImage peImage, ref DumpedMethods dumpedMethods) { this.peImage = peImage; uint offset = peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress + peImage.Cor20Header.metadataDirectory.size); if (!readCodeHeader(offset)) return false; var metadataTables = peImage.Cor20Header.createMetadataTables(); var methodDefTable = metadataTables.getMetadataType(PE.MetadataIndex.iMethodDef); if (methodDefTable.totalSize != codeHeader.methodDefElemSize) return false; var methodInfos = getMethodInfos(offset + 0x30 + codeHeader.totalCodeSize); offset = methodDefTable.fileOffset - methodDefTable.totalSize; foreach (var methodInfo in methodInfos) { offset += methodDefTable.totalSize; if (methodInfo.flags == 0 || methodInfo.codeOffs == 0) continue; uint rva = peImage.offsetReadUInt32(offset); peImage.writeUint16(rva, (ushort)methodInfo.flags); peImage.writeUint32(rva + 8, methodInfo.localVarSigTok); } dumpedMethods = new DumpedMethods(); offset = methodDefTable.fileOffset; for (int i = 0; i < methodInfos.Count; i++, offset += methodDefTable.totalSize) { var methodInfo = methodInfos[i]; if (methodInfo.codeOffs == 0) continue; var dm = new DumpedMethod(); dm.token = 0x06000001 + (uint)i; uint rva = peImage.offsetReadUInt32(offset); dm.mdImplFlags = peImage.offsetReadUInt16(offset + (uint)methodDefTable.fields[1].offset); dm.mdFlags = peImage.offsetReadUInt16(offset + (uint)methodDefTable.fields[2].offset); dm.mdName = peImage.offsetRead(offset + (uint)methodDefTable.fields[3].offset, methodDefTable.fields[3].size); dm.mdSignature = peImage.offsetRead(offset + (uint)methodDefTable.fields[4].offset, methodDefTable.fields[4].size); dm.mdParamList = peImage.offsetRead(offset + (uint)methodDefTable.fields[5].offset, methodDefTable.fields[5].size); dm.code = decrypter.decrypt(methodInfo); if ((peImage.readByte(rva) & 3) == 2) { dm.mhFlags = 2; dm.mhMaxStack = 8; dm.mhCodeSize = (uint)dm.code.Length; dm.mhLocalVarSigTok = 0; } else { dm.mhFlags = peImage.readUInt16(rva); dm.mhMaxStack = peImage.readUInt16(rva + 2); dm.mhCodeSize = (uint)dm.code.Length; dm.mhLocalVarSigTok = peImage.readUInt32(rva + 8); } dumpedMethods.add(dm); } return true; }
static void clearDllBit(byte[] peImageData) { var mainPeImage = new PeImage(peImageData); uint characteristicsOffset = mainPeImage.FileHeaderOffset + 18; ushort characteristics = mainPeImage.offsetReadUInt16(characteristicsOffset); characteristics &= 0xDFFF; characteristics |= 2; mainPeImage.offsetWriteUInt16(characteristicsOffset, characteristics); }
public NormalDecrypter(PeImage peImage, CodeHeader codeHeader) : base(peImage, codeHeader) { }
public ApplicationModeUnpacker(PeImage peImage) { this.peImage = peImage; }
DumpedMethods createDumpedMethods(PeImage peImage, byte[] fileData, byte[] methodsData) { var dumpedMethods = new DumpedMethods(); var methodsDataReader = new BinaryReader(new MemoryStream(methodsData)); var fileDataReader = new BinaryReader(new MemoryStream(fileData)); var metadataTables = peImage.Cor20Header.createMetadataTables(); var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef); uint methodDefOffset = methodDef.fileOffset; for (int i = 0; i < methodDef.rows; i++, methodDefOffset += methodDef.totalSize) { uint bodyRva = peImage.offsetReadUInt32(methodDefOffset); if (bodyRva == 0) continue; uint bodyOffset = peImage.rvaToOffset(bodyRva); var dm = new DumpedMethod(); dm.token = (uint)(0x06000001 + i); dm.mdImplFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[1].offset); dm.mdFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[2].offset); dm.mdName = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[3].offset, methodDef.fields[3].size); dm.mdSignature = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[4].offset, methodDef.fields[4].size); dm.mdParamList = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[5].offset, methodDef.fields[5].size); 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.BaseStream.Position = codeOffset; if (!decrypter.decrypt(fileDataReader, dm)) continue; dumpedMethods.add(dm); } return dumpedMethods; }
public override bool getDecryptedModule(ref byte[] newFileData, ref Dictionary<uint, DumpedMethod> dumpedMethods) { fileData = ModuleBytes ?? DeobUtils.readModule(module); peImage = new PeImage(fileData); if (!options.DecryptMethods) return false; var tokenToNativeCode = new Dictionary<uint,byte[]>(); if (!methodsDecrypter.decrypt(peImage, DeobfuscatedFile, ref dumpedMethods, tokenToNativeCode)) return false; if (options.DumpNativeMethods) { using (var fileStream = new FileStream(module.FullyQualifiedName + ".native", FileMode.Create, FileAccess.Write, FileShare.Read)) { var sortedTokens = new List<uint>(tokenToNativeCode.Keys); sortedTokens.Sort(); var writer = new BinaryWriter(fileStream); var nops = new byte[] { 0x90, 0x90, 0x90, 0x90 }; foreach (var token in sortedTokens) { writer.Write((byte)0xB8); writer.Write(token); writer.Write(tokenToNativeCode[token]); writer.Write(nops); } } } newFileData = fileData; return true; }
int getStartOffset(PeImage peImage) { int minOffset = int.MaxValue; foreach (var rva in mainType.Rvas) { int rvaOffs = (int)peImage.rvaToOffset((uint)rva); if (rvaOffs < minOffset) minOffset = rvaOffs; } return minOffset == int.MaxValue ? 0 : minOffset; }
public override byte[] unpackNativeFile(PeImage peImage) { var data = new NativeImageUnpacker(peImage).unpack(); if (data == null) return null; unpackedNativeFile = true; ModuleBytes = data; return data; }
public NativeImageUnpacker(PeImage peImage) { this.peImage = peImage; }
bool unpackNativeImage(IEnumerable<IDeobfuscator> deobfuscators) { var peImage = new PeImage(Utils.readFile(Filename)); foreach (var deob in deobfuscators) { byte[] unpackedData = null; try { unpackedData = deob.unpackNativeFile(peImage); } catch { } if (unpackedData == null) continue; try { module = assemblyModule.load(unpackedData); } catch { Log.w("Could not load unpacked data. Deobfuscator: {0}", deob.TypeLong); continue; } this.deob = deob; return true; } return false; }
static void patchDwords(PeImage peImage, BinaryReader reader, int count) { for (int i = 0; i < count; i++) { uint rva = reader.ReadUInt32(); uint data = reader.ReadUInt32(); peImage.dotNetSafeWrite(rva, BitConverter.GetBytes(data)); } }
public bool decrypt(byte[] fileData, ref DumpedMethods dumpedMethods) { var peImage = new PeImage(fileData); var peHeader = new PeHeader(mainType, peImage); var mcHeader = new McHeader(peImage, peHeader); dumpedMethods = decryptMethods(peImage, peHeader, mcHeader); if (dumpedMethods == null) return false; decryptResources(fileData, peImage, peHeader, mcHeader); return true; }