diff --git a/de4dot.code/AssemblyModule.cs b/de4dot.code/AssemblyModule.cs index a719b9a6..a52bda58 100644 --- a/de4dot.code/AssemblyModule.cs +++ b/de4dot.code/AssemblyModule.cs @@ -33,8 +33,24 @@ namespace de4dot { this.filename = Utils.getFullPath(filename); } + ReaderParameters getReaderParameters() { + return new ReaderParameters(ReadingMode.Deferred) { + AssemblyResolver = AssemblyResolver.Instance + }; + } + public ModuleDefinition load() { - readFile(); + return setModule(ModuleDefinition.ReadModule(filename, getReaderParameters())); + } + + public ModuleDefinition load(byte[] fileData) { + return setModule(ModuleDefinition.ReadModule(new MemoryStream(fileData), getReaderParameters())); + } + + ModuleDefinition setModule(ModuleDefinition newModule) { + module = newModule; + AssemblyResolver.Instance.addModule(module); + module.FullyQualifiedName = filename; return module; } @@ -47,25 +63,9 @@ namespace de4dot { } public ModuleDefinition reload(byte[] newModuleData, Dictionary dumpedMethods) { - var oldModuleName = module.FullyQualifiedName; - var assemblyResolver = AssemblyResolver.Instance; - assemblyResolver.removeModule(module); + AssemblyResolver.Instance.removeModule(module); DotNetUtils.typeCaches.invalidate(module); - - var readerParameters = new ReaderParameters(ReadingMode.Deferred); - readerParameters.AssemblyResolver = assemblyResolver; - module = ModuleDefinition.ReadModule(new MemoryStream(newModuleData), readerParameters, dumpedMethods); - assemblyResolver.addModule(module); - module.FullyQualifiedName = oldModuleName; - return module; - } - - void readFile() { - var assemblyResolver = AssemblyResolver.Instance; - var readerParameters = new ReaderParameters(ReadingMode.Deferred); - readerParameters.AssemblyResolver = assemblyResolver; - module = ModuleDefinition.ReadModule(filename, readerParameters); - assemblyResolver.addModule(module); + return setModule(ModuleDefinition.ReadModule(new MemoryStream(newModuleData), getReaderParameters(), dumpedMethods)); } public override string ToString() { diff --git a/de4dot.code/ObfuscatedFile.cs b/de4dot.code/ObfuscatedFile.cs index 02cbd4e1..8cf86863 100644 --- a/de4dot.code/ObfuscatedFile.cs +++ b/de4dot.code/ObfuscatedFile.cs @@ -30,6 +30,7 @@ using de4dot.blocks; using de4dot.blocks.cflow; using de4dot.AssemblyClient; using de4dot.renamer; +using de4dot.PE; namespace de4dot { class ObfuscatedFile : IObfuscatedFile, IDeobfuscatedFile { @@ -151,7 +152,7 @@ namespace de4dot { } public void load(IEnumerable deobfuscators) { - module = assemblyModule.load(); + loadModule(deobfuscators); AssemblyResolver.Instance.addSearchDirectory(Utils.getDirName(Filename)); AssemblyResolver.Instance.addSearchDirectory(Utils.getDirName(NewFilename)); @@ -163,6 +164,36 @@ namespace de4dot { initializeDeobfuscator(); } + void loadModule(IEnumerable deobfuscators) { + try { + module = assemblyModule.load(); + } + catch (BadImageFormatException) { + if (!unpackNativeImage(deobfuscators)) + throw new BadImageFormatException(); + } + } + + bool unpackNativeImage(IEnumerable deobfuscators) { + var peImage = new PeImage(Utils.readFile(Filename)); + + foreach (var deob in deobfuscators) { + try { + var unpackedData = deob.unpackNativeFile(peImage); + if (unpackedData == null) + continue; + module = assemblyModule.load(unpackedData); + this.deob = deob; + return true; + } + catch { + continue; + } + } + + return false; + } + void initializeDeobfuscator() { if (options.StringDecrypterType == DecrypterType.Default) options.StringDecrypterType = deob.DefaultDecrypterType; @@ -199,6 +230,15 @@ namespace de4dot { if (!options.ControlFlowDeobfuscation || options.StringDecrypterType == DecrypterType.None) savedMethodBodies = new SavedMethodBodies(); + // It's not null if it unpacked a native file + if (this.deob != null) { + deob.init(module); + deob.DeobfuscatedFile = this; + deob.earlyDetect(); + deob.detect(); + return; + } + foreach (var deob in deobfuscators) { deob.init(module); deob.DeobfuscatedFile = this; diff --git a/de4dot.code/deobfuscators/DeobfuscatorBase.cs b/de4dot.code/deobfuscators/DeobfuscatorBase.cs index ecd59b68..38d40d6c 100644 --- a/de4dot.code/deobfuscators/DeobfuscatorBase.cs +++ b/de4dot.code/deobfuscators/DeobfuscatorBase.cs @@ -23,6 +23,7 @@ using Mono.Cecil; using Mono.Cecil.Cil; using Mono.MyStuff; using de4dot.blocks; +using de4dot.PE; namespace de4dot.deobfuscators { abstract class DeobfuscatorBase : IDeobfuscator, IWriterListener { @@ -83,6 +84,10 @@ namespace de4dot.deobfuscators { DefaultDecrypterType = DecrypterType.Static; } + public virtual byte[] unpackNativeFile(PeImage peImage) { + return null; + } + public virtual void init(ModuleDefinition module) { setModule(module); } diff --git a/de4dot.code/deobfuscators/IDeobfuscator.cs b/de4dot.code/deobfuscators/IDeobfuscator.cs index 72bb8e61..e7c6046d 100644 --- a/de4dot.code/deobfuscators/IDeobfuscator.cs +++ b/de4dot.code/deobfuscators/IDeobfuscator.cs @@ -23,6 +23,7 @@ using Mono.Cecil; using Mono.MyStuff; using de4dot.blocks; using de4dot.renamer; +using de4dot.PE; namespace de4dot.deobfuscators { interface IDeobfuscatorOptions { @@ -66,6 +67,9 @@ namespace de4dot.deobfuscators { // Return true if methods can be inlined bool CanInlineMethods { get; } + // Returns null or the unpacked .NET PE file + byte[] unpackNativeFile(PeImage peImage); + void init(ModuleDefinition module); // Same as detect() but may be used by deobfuscators to detect obfuscator that decrypt