From 643e155cf8187cb69f40dc0af6cb2d70f86ef9a8 Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 1 Dec 2012 03:24:12 +0100 Subject: [PATCH] Add options to preserve rids, heaps --- de4dot.code/AssemblyModule.cs | 12 +----- de4dot.code/ObfuscatedFile.cs | 33 ++++++++++++---- de4dot.code/deobfuscators/DeobfuscatorBase.cs | 4 ++ de4dot.code/deobfuscators/IDeobfuscator.cs | 4 +- de4dot.code/deobfuscators/Operations.cs | 4 ++ de4dot.cui/CommandLineParser.cs | 39 +++++++++++++++++++ de4dot.cui/FilesDeobfuscator.cs | 5 +++ 7 files changed, 82 insertions(+), 19 deletions(-) diff --git a/de4dot.code/AssemblyModule.cs b/de4dot.code/AssemblyModule.cs index f42bb347..a4150619 100644 --- a/de4dot.code/AssemblyModule.cs +++ b/de4dot.code/AssemblyModule.cs @@ -51,17 +51,7 @@ namespace de4dot.code { return module; } - public void save(string newFilename, bool preserveTokens, bool updateMaxStack, IModuleWriterListener writerListener) { - MetaDataFlags mdFlags = 0; - if (!updateMaxStack) - mdFlags |= MetaDataFlags.KeepOldMaxStack; - if (preserveTokens) { - mdFlags |= MetaDataFlags.PreserveRids | - MetaDataFlags.PreserveUSOffsets | - MetaDataFlags.PreserveBlobOffsets | - MetaDataFlags.PreserveExtraSignatureData; - } - + public void save(string newFilename, MetaDataFlags mdFlags, IModuleWriterListener writerListener) { if (module.IsILOnly) { var writerOptions = new ModuleWriterOptions(module, writerListener); writerOptions.MetaDataOptions.Flags |= mdFlags; diff --git a/de4dot.code/ObfuscatedFile.cs b/de4dot.code/ObfuscatedFile.cs index f5aa11bd..26e3646f 100644 --- a/de4dot.code/ObfuscatedFile.cs +++ b/de4dot.code/ObfuscatedFile.cs @@ -88,6 +88,8 @@ namespace de4dot.code { public List StringDecrypterMethods { get; private set; } public bool ControlFlowDeobfuscation { get; set; } public bool KeepObfuscatorTypes { get; set; } + public bool PreserveTokens { get; set; } + public MetaDataFlags MetaDataFlags { get; set; } public Options() { StringDecrypterType = DecrypterType.Default; @@ -251,6 +253,7 @@ namespace de4dot.code { } op.KeepObfuscatorTypes = options.KeepObfuscatorTypes; + op.MetaDataFlags = options.MetaDataFlags; return op; } @@ -322,13 +325,26 @@ namespace de4dot.code { return detected; } - bool ShouldPreserveTokens() { - return options.KeepObfuscatorTypes || deob.Type == "un"; + MetaDataFlags getMetaDataFlags() { + var mdFlags = options.MetaDataFlags | deob.MetaDataFlags; + + // Always preserve tokens if it's an unknown obfuscator + if (deob.Type == "un") { + mdFlags |= MetaDataFlags.PreserveRids | + MetaDataFlags.PreserveUSOffsets | + MetaDataFlags.PreserveBlobOffsets | + MetaDataFlags.PreserveExtraSignatureData; + } + + return mdFlags; } public void save() { Logger.n("Saving {0}", options.NewFilename); - assemblyModule.save(options.NewFilename, ShouldPreserveTokens(), options.ControlFlowDeobfuscation, deob as IModuleWriterListener); + var mdFlags = getMetaDataFlags(); + if (!options.ControlFlowDeobfuscation) + mdFlags |= MetaDataFlags.KeepOldMaxStack; + assemblyModule.save(options.NewFilename, mdFlags, deob as IModuleWriterListener); } IList getAllMethods() { @@ -556,7 +572,7 @@ namespace de4dot.code { deob.DeobfuscatedFile = null; if (!options.ControlFlowDeobfuscation) { - if (ShouldPreserveTokens()) + if (options.KeepObfuscatorTypes || deob.Type == "un") return; } @@ -611,6 +627,11 @@ namespace de4dot.code { } } + bool CanOptimizeLocals() { + // Don't remove any locals if we must preserve StandAloneSig table + return (getMetaDataFlags() & MetaDataFlags.PreserveStandAloneSigRids) == 0; + } + void deobfuscate(MethodDef method, BlocksCflowDeobfuscator cflowDeobfuscator, MethodPrinter methodPrinter, bool isVerbose, bool isVV) { if (!hasNonEmptyBody(method)) return; @@ -629,9 +650,7 @@ namespace de4dot.code { cflowDeobfuscator.deobfuscate(); if (options.ControlFlowDeobfuscation) { - // Don't remove any locals if we should preserve tokens or we won't be able - // to always preserve StandAloneSig tokens. - if (!ShouldPreserveTokens()) + if (CanOptimizeLocals()) numRemovedLocals = blocks.optimizeLocals(); blocks.repartitionBlocks(); } diff --git a/de4dot.code/deobfuscators/DeobfuscatorBase.cs b/de4dot.code/deobfuscators/DeobfuscatorBase.cs index 66b59fff..f52ce371 100644 --- a/de4dot.code/deobfuscators/DeobfuscatorBase.cs +++ b/de4dot.code/deobfuscators/DeobfuscatorBase.cs @@ -77,6 +77,10 @@ namespace de4dot.code.deobfuscators { public virtual RenamingOptions RenamingOptions { get; set; } public DecrypterType DefaultDecrypterType { get; set; } + public virtual MetaDataFlags MetaDataFlags { + get { return Operations.MetaDataFlags; } + } + public abstract string Type { get; } public abstract string TypeLong { get; } public abstract string Name { get; } diff --git a/de4dot.code/deobfuscators/IDeobfuscator.cs b/de4dot.code/deobfuscators/IDeobfuscator.cs index 6920144e..a65b7aa1 100644 --- a/de4dot.code/deobfuscators/IDeobfuscator.cs +++ b/de4dot.code/deobfuscators/IDeobfuscator.cs @@ -19,8 +19,9 @@ using System; using System.Collections.Generic; -using dot10.DotNet; using dot10.PE; +using dot10.DotNet; +using dot10.DotNet.Writer; using de4dot.blocks; using de4dot.blocks.cflow; using de4dot.code.renamer; @@ -58,6 +59,7 @@ namespace de4dot.code.deobfuscators { string Name { get; } IDeobfuscatorOptions TheOptions { get; } IOperations Operations { get; set; } + MetaDataFlags MetaDataFlags { get; } StringFeatures StringFeatures { get; } RenamingOptions RenamingOptions { get; } DecrypterType DefaultDecrypterType { get; } diff --git a/de4dot.code/deobfuscators/Operations.cs b/de4dot.code/deobfuscators/Operations.cs index 961e1e3c..d374f37c 100644 --- a/de4dot.code/deobfuscators/Operations.cs +++ b/de4dot.code/deobfuscators/Operations.cs @@ -17,6 +17,8 @@ along with de4dot. If not, see . */ +using dot10.DotNet.Writer; + namespace de4dot.code.deobfuscators { public enum OpDecryptString { None, @@ -26,11 +28,13 @@ namespace de4dot.code.deobfuscators { public interface IOperations { bool KeepObfuscatorTypes { get; } + MetaDataFlags MetaDataFlags { get; } OpDecryptString DecryptStrings { get; } } class Operations : IOperations { public bool KeepObfuscatorTypes { get; set; } + public MetaDataFlags MetaDataFlags { get; set; } public OpDecryptString DecryptStrings { get; set; } } } diff --git a/de4dot.cui/CommandLineParser.cs b/de4dot.cui/CommandLineParser.cs index 493cf8eb..7f25bf44 100644 --- a/de4dot.cui/CommandLineParser.cs +++ b/de4dot.cui/CommandLineParser.cs @@ -21,6 +21,7 @@ using System; using System.IO; using System.Collections.Generic; using dot10.DotNet; +using dot10.DotNet.Writer; using de4dot.code; using de4dot.code.deobfuscators; using de4dot.code.AssemblyClient; @@ -159,6 +160,43 @@ namespace de4dot.cui { miscOptions.Add(new NoArgOption(null, "keep-types", "Keep obfuscator types, fields, methods", () => { filesOptions.KeepObfuscatorTypes = true; })); + miscOptions.Add(new NoArgOption(null, "preserve-tokens", "Preserve important tokens, #US, #Blob, extra sig data", () => { + filesOptions.MetaDataFlags |= MetaDataFlags.PreserveRids | + MetaDataFlags.PreserveUSOffsets | + MetaDataFlags.PreserveBlobOffsets | + MetaDataFlags.PreserveExtraSignatureData; + })); + miscOptions.Add(new OneArgOption(null, "preserve-table", "Preserve rids in table: tr (TypeRef), td (TypeDef), fd (Field), md (Method), pd (Param), mr (MemberRef), s (StandAloneSig), ed (Event), pr (Property), ts (TypeSpec), ms (MethodSpec). Can be combined: ed,fd,md", "flags", (val) => { + foreach (var s in val.Split(',')) { + switch (s.Trim()) { + case "": break; + case "tr": filesOptions.MetaDataFlags |= MetaDataFlags.PreserveTypeRefRids; break; + case "td": filesOptions.MetaDataFlags |= MetaDataFlags.PreserveTypeDefRids; break; + case "fd": filesOptions.MetaDataFlags |= MetaDataFlags.PreserveFieldRids; break; + case "md": filesOptions.MetaDataFlags |= MetaDataFlags.PreserveMethodRids; break; + case "pd": filesOptions.MetaDataFlags |= MetaDataFlags.PreserveParamRids; break; + case "mr": filesOptions.MetaDataFlags |= MetaDataFlags.PreserveMemberRefRids; break; + case "s": filesOptions.MetaDataFlags |= MetaDataFlags.PreserveStandAloneSigRids; break; + case "ed": filesOptions.MetaDataFlags |= MetaDataFlags.PreserveEventRids; break; + case "pr": filesOptions.MetaDataFlags |= MetaDataFlags.PreservePropertyRids; break; + case "ts": filesOptions.MetaDataFlags |= MetaDataFlags.PreserveTypeSpecRids; break; + case "ms": filesOptions.MetaDataFlags |= MetaDataFlags.PreserveMethodSpecRids; break; + default: throw new UserException(string.Format("Invalid --preserve-table option: {0}", s)); + } + } + })); + miscOptions.Add(new NoArgOption(null, "preserve-strings", "Preserve #Strings heap offsets", () => { + filesOptions.MetaDataFlags |= MetaDataFlags.PreserveStringsOffsets; + })); + miscOptions.Add(new NoArgOption(null, "preserve-us", "Preserve #US heap offsets", () => { + filesOptions.MetaDataFlags |= MetaDataFlags.PreserveUSOffsets; + })); + miscOptions.Add(new NoArgOption(null, "preserve-blob", "Preserve #Blob heap offsets", () => { + filesOptions.MetaDataFlags |= MetaDataFlags.PreserveBlobOffsets; + })); + miscOptions.Add(new NoArgOption(null, "preserve-sig-data", "Preserve extra data at the end of signatures", () => { + filesOptions.MetaDataFlags |= MetaDataFlags.PreserveExtraSignatureData; + })); miscOptions.Add(new NoArgOption(null, "one-file", "Deobfuscate one file at a time", () => { filesOptions.OneFileAtATime = true; })); @@ -183,6 +221,7 @@ namespace de4dot.cui { Filename = val, ControlFlowDeobfuscation = filesOptions.ControlFlowDeobfuscation, KeepObfuscatorTypes = filesOptions.KeepObfuscatorTypes, + MetaDataFlags = filesOptions.MetaDataFlags, }; if (defaultStringDecrypterType != null) newFileOptions.StringDecrypterType = defaultStringDecrypterType.Value; diff --git a/de4dot.cui/FilesDeobfuscator.cs b/de4dot.cui/FilesDeobfuscator.cs index 03a511c3..47c650ec 100644 --- a/de4dot.cui/FilesDeobfuscator.cs +++ b/de4dot.cui/FilesDeobfuscator.cs @@ -21,6 +21,7 @@ using System; using System.IO; using System.Collections.Generic; using dot10.DotNet; +using dot10.DotNet.Writer; using de4dot.blocks; using de4dot.code; using de4dot.code.renamer; @@ -37,6 +38,7 @@ namespace de4dot.cui { public IList DeobfuscatorInfos { get; set; } public IList Files { get; set; } public IList SearchDirs { get; set; } + public MetaDataFlags MetaDataFlags { get; set; } public bool DetectObfuscators { get; set; } public bool DontCreateNewParamDefs { get; set; } public bool RenameNamespaces { get; set; } @@ -163,6 +165,7 @@ namespace de4dot.cui { DeobfuscatorContext = deobfuscatorContext, ControlFlowDeobfuscation = options.ControlFlowDeobfuscation, KeepObfuscatorTypes = options.KeepObfuscatorTypes, + MetaDataFlags = options.MetaDataFlags, CreateDestinationDir = !onlyScan, }); @@ -186,6 +189,7 @@ namespace de4dot.cui { public IDeobfuscatorContext DeobfuscatorContext { get; set; } public bool ControlFlowDeobfuscation { get; set; } public bool KeepObfuscatorTypes { get; set; } + public MetaDataFlags MetaDataFlags { get; set; } public bool CreateDestinationDir { get; set; } } @@ -312,6 +316,7 @@ namespace de4dot.cui { Filename = Utils.getFullPath(filename), ControlFlowDeobfuscation = options.ControlFlowDeobfuscation, KeepObfuscatorTypes = options.KeepObfuscatorTypes, + MetaDataFlags = options.MetaDataFlags, }; if (options.DefaultStringDecrypterType != null) fileOptions.StringDecrypterType = options.DefaultStringDecrypterType.Value;