From 0a8d772c2202a5196a751e96656a5a39622205bf Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 29 Oct 2011 02:27:34 +0200 Subject: [PATCH] Decrypt methods sent to the JITter --- .../dotNET_Reactor/Deobfuscator.cs | 12 +-- .../dotNET_Reactor/MethodsDecrypter.cs | 83 +++++++++++++++++-- 2 files changed, 84 insertions(+), 11 deletions(-) diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs b/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs index 3bb05f52..337d7dfa 100644 --- a/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs @@ -20,6 +20,7 @@ using System.IO; using System.Collections.Generic; using Mono.Cecil; +using Mono.MyStuff; using de4dot.blocks; namespace de4dot.deobfuscators.dotNET_Reactor { @@ -117,7 +118,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor { booleanDecrypter.find(); } - public override byte[] getDecryptedModule() { + public override bool getDecryptedModule(ref byte[] newFileData, ref Dictionary dumpedMethods) { using (var fileStream = new FileStream(module.FullyQualifiedName, FileMode.Open, FileAccess.Read, FileShare.Read)) { fileData = new byte[(int)fileStream.Length]; fileStream.Read(fileData, 0, fileData.Length); @@ -125,12 +126,13 @@ namespace de4dot.deobfuscators.dotNET_Reactor { peImage = new PE.PeImage(fileData); if (!options.DecryptMethods) - return null; + return false; - if (!methodsDecrypter.decrypt(peImage, DeobfuscatedFile)) - return null; + if (!methodsDecrypter.decrypt(peImage, DeobfuscatedFile, ref dumpedMethods)) + return false; - return fileData; + newFileData = fileData; + return true; } public override IDeobfuscator moduleReloaded(ModuleDefinition module) { diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/MethodsDecrypter.cs b/de4dot.code/deobfuscators/dotNET_Reactor/MethodsDecrypter.cs index a35943e8..b8ba654f 100644 --- a/de4dot.code/deobfuscators/dotNET_Reactor/MethodsDecrypter.cs +++ b/de4dot.code/deobfuscators/dotNET_Reactor/MethodsDecrypter.cs @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.IO; using Mono.Cecil; using Mono.Cecil.Cil; +using Mono.MyStuff; using de4dot.blocks; namespace de4dot.deobfuscators.dotNET_Reactor { @@ -91,7 +92,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor { encryptedResource.ResourceDecrypterMethod = (MethodDefinition)callCounter.most(); } - public bool decrypt(PE.PeImage peImage, ISimpleDeobfuscator simpleDeobfuscator) { + public bool decrypt(PE.PeImage peImage, ISimpleDeobfuscator simpleDeobfuscator, ref Dictionary dumpedMethods) { if (encryptedResource.ResourceDecrypterMethod == null) return false; @@ -119,8 +120,8 @@ namespace de4dot.deobfuscators.dotNET_Reactor { int tmp = methodsDataReader.ReadInt32(); methodsDataReader.BaseStream.Position -= 4; if ((tmp & 0xFF000000) == 0x06000000) { - // It's method token + rva. DNR 3.7.0.3 - 3.9.0.1 - methodsDataReader.BaseStream.Position += 8 * patchCount; + // 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(); @@ -131,17 +132,87 @@ namespace de4dot.deobfuscators.dotNET_Reactor { patchDwords(peImage, methodsDataReader, numDwords / 2); } } - else { - // DNR 3.9.8.0, 4.0, 4.1, 4.2 + else if (!useXorKey || 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(); + uint token = methodsDataReader.ReadUInt32(); // token, unknown, or index int size = methodsDataReader.ReadInt32(); if (size > 0) peImage.dotNetSafeWrite(rva, methodsDataReader.ReadBytes(size)); } } + else { + // DNR 4.4 (jitter is hooked) + + var metadataTables = peImage.Cor20Header.createMetadataTables(); + var methodDef = metadataTables.getMetadataType(PE.MetadataIndex.iMethodDef); + var rvaToIndex = new Dictionary((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(); + 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; + } + + if (isNativeCode) { + //TODO: Convert to CIL code + Log.w("Found native code. Ignoring it for now... Assembly won't run. token: {0:X8}", 0x06000001 + methodIndex); + } + else { + var dm = new DumpedMethod(); + dm.token = (uint)(0x06000001 + methodIndex); + 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; }