Ejemplo n.º 1
0
        private static void CleanControlFlow()
        {
            Logger.Instance.MaxLoggerEvent = 0;

            var options = new ObfuscatedFile.Options
            {
                Filename = _obfOsuPath,
                ControlFlowDeobfuscation = true,
                KeepObfuscatorTypes      = true,
                RenamerFlags             = 0,
                StringDecrypterType      = DecrypterType.None,
                MetadataFlags            = DEFAULT_METADATA_FLAGS
            };

            var obfFile = new ObfuscatedFile(options, new ModuleContext(TheAssemblyResolver.Instance), new NewAppDomainAssemblyClientFactory())
            {
                DeobfuscatorContext = new DeobfuscatorContext()
            };

            obfFile.Load(new List <IDeobfuscator> {
                new de4dot.code.deobfuscators.Unknown.DeobfuscatorInfo().CreateDeobfuscator()
            });

            obfFile.DeobfuscateBegin();
            obfFile.Deobfuscate();
            obfFile.DeobfuscateEnd();

            _obfOsuModule = obfFile.ModuleDefMD;
        }
Ejemplo n.º 2
0
        public static IObfuscatedFile SearchDeobfuscator(string filename)
        {
            TheAssemblyResolver.Instance.ClearAll();

            var fileOptions = new ObfuscatedFile.Options {
                Filename = filename
            };
            var moduleContext = new ModuleContext(TheAssemblyResolver.Instance);

            var ofile = new ObfuscatedFile(fileOptions, moduleContext, new NewAppDomainAssemblyClientFactory())
            {
                DeobfuscatorContext = new DeobfuscatorContext(),
            };

            try
            {
                ofile.Load(CreateDeobfuscatorInfos().Select(di => di.CreateDeobfuscator()).ToList());
            }
            catch (Exception)
            {
                return(null);
            }

            return(ofile);
        }
Ejemplo n.º 3
0
 void AddFile()
 {
     if (newFileOptions == null)
     {
         return;
     }
     files.Add(new ObfuscatedFile(newFileOptions, filesOptions.ModuleContext, filesOptions.AssemblyClientFactory));
     newFileOptions = null;
 }
Ejemplo n.º 4
0
        public IObfuscatedFile SearchDeobfuscator(string filename)
        {
            ModuleContext context = new ModuleContext();

            ObfuscatedFile.Options fileOptions = new ObfuscatedFile.Options {
                Filename = filename
            };
            ObfuscatedFile ofile = CreateObfuscationFile(fileOptions, context);

            return(ofile);
        }
        private IObfuscatedFile UpdateObfuscationFileWithOptions(De4dotWrapper de4Dot, string location, string newFile)
        {
            ObfuscatedFile.Options options = new ObfuscatedFile.Options();
            options.ControlFlowDeobfuscation = this.EnableControlFlowDeobfuscation;
            options.NewFilename         = newFile;
            options.KeepObfuscatorTypes = this.KeepObfuscatorClasses;
            options.Filename            = location;
            var            context = new ModuleContext();
            ObfuscatedFile result  = de4Dot.CreateObfuscationFile(options, context);

            return(result);
        }
Ejemplo n.º 6
0
        public FileSystemPath Execute(IAssemblyFile existingAssemblyFile, string newFileName, IProgressIndicator progressIndicator)
        {
            var context     = new ModuleContext();
            var fileOptions = new ObfuscatedFile.Options
            {
                Filename    = existingAssemblyFile.Location.FullPath,
                NewFilename = newFileName,
            };

            IObfuscatedFile obfuscationFile = CreateObfuscationFile(fileOptions, context);

            return(Deobfuscate(obfuscationFile, progressIndicator));
        }
Ejemplo n.º 7
0
        public override void Process()
        {
            IList <IObfuscatedFile> files = new List <IObfuscatedFile>();
            var filesOptions = new FilesDeobfuscator.Options();

            filesOptions.DeobfuscatorInfos        = deobfuscatorInfos;
            filesOptions.AssemblyClientFactory    = new NewAppDomainAssemblyClientFactory();
            filesOptions.RenameSymbols            = true;
            filesOptions.ControlFlowDeobfuscation = true;
            filesOptions.KeepObfuscatorTypes      = false;
            filesOptions.MetaDataFlags            = MetaDataFlags.PreserveAll;
            filesOptions.Files = files;

            var newFileOptions = new ObfuscatedFile.Options
            {
                Filename    = DeobfuscatorContext.Filename,
                NewFilename = "XPADDING",
                ControlFlowDeobfuscation = filesOptions.ControlFlowDeobfuscation,
                RenamerFlags             = filesOptions.RenamerFlags,
                KeepObfuscatorTypes      = filesOptions.KeepObfuscatorTypes,
                MetaDataFlags            = filesOptions.MetaDataFlags,
                PreserveTokens           = true
            };

            using (var asm = new MemoryStream())
            {
                DeobfuscatorContext.Assembly.Write(asm, new ModuleWriterOptions()
                {
                    Logger = DummyLogger.NoThrowInstance
                });
                files.Add(new ObfuscatedFile(newFileOptions, filesOptions.ModuleContext,
                                             filesOptions.AssemblyClientFactory, asm));

                using (var ms = new MemoryStream())
                {
                    new FilesDeobfuscator(filesOptions).doIt(ms, Rename);

                    // Better way to preserve these options?
                    var cor20Ver = DeobfuscatorContext.Assembly.ManifestModule.Cor20HeaderRuntimeVersion;
                    var clrVer   = DeobfuscatorContext.Assembly.ManifestModule.RuntimeVersion;
                    var clrFlags = DeobfuscatorContext.Assembly.ManifestModule.Cor20HeaderFlags;

                    DeobfuscatorContext.Assembly = AssemblyDef.Load(ms);

                    DeobfuscatorContext.Assembly.ManifestModule.Cor20HeaderRuntimeVersion = cor20Ver;
                    DeobfuscatorContext.Assembly.ManifestModule.RuntimeVersion            = clrVer;
                    DeobfuscatorContext.Assembly.ManifestModule.Cor20HeaderFlags          = clrFlags;
                }
            }
        }
Ejemplo n.º 8
0
            IObfuscatedFile CreateObfuscatedFile(SearchDir searchDir, string filename)
            {
                var fileOptions = new ObfuscatedFile.Options
                {
                    Filename = Utils.GetFullPath(filename),
                    ControlFlowDeobfuscation = options.ControlFlowDeobfuscation,
                    KeepObfuscatorTypes      = options.KeepObfuscatorTypes,
                    MetaDataFlags            = options.MetaDataFlags,
                    RenamerFlags             = options.RenamerFlags,
                };

                if (options.DefaultStringDecrypterType != null)
                {
                    fileOptions.StringDecrypterType = options.DefaultStringDecrypterType.Value;
                }
                fileOptions.StringDecrypterMethods.AddRange(options.DefaultStringDecrypterMethods);

                if (!string.IsNullOrEmpty(searchDir.OutputDirectory))
                {
                    var inDir  = Utils.GetFullPath(searchDir.InputDirectory);
                    var outDir = Utils.GetFullPath(searchDir.OutputDirectory);

                    if (!Utils.StartsWith(fileOptions.Filename, inDir, StringComparison.OrdinalIgnoreCase))
                    {
                        throw new UserException(string.Format("Filename {0} does not start with inDir {1}", fileOptions.Filename, inDir));
                    }

                    var subDirs = fileOptions.Filename.Substring(inDir.Length);
                    if (subDirs.Length > 0 && subDirs[0] == Path.DirectorySeparatorChar)
                    {
                        subDirs = subDirs.Substring(1);
                    }
                    fileOptions.NewFilename = Utils.GetFullPath(Path.Combine(outDir, subDirs));

                    if (fileOptions.Filename.Equals(fileOptions.NewFilename, StringComparison.OrdinalIgnoreCase))
                    {
                        throw new UserException(string.Format("Input and output filename is the same: {0}", fileOptions.Filename));
                    }
                }

                var obfuscatedFile = new ObfuscatedFile(fileOptions, options.ModuleContext, options.AssemblyClientFactory);

                if (Add(obfuscatedFile, searchDir.SkipUnknownObfuscators, false))
                {
                    return(obfuscatedFile);
                }
                obfuscatedFile.Dispose();
                return(null);
            }
Ejemplo n.º 9
0
        public ObfuscatedFile CreateObfuscationFile(ObfuscatedFile.Options fileOptions, ModuleContext moduleContext)
        {
            ObfuscatedFile ofile = new ObfuscatedFile(fileOptions, moduleContext, new NewAppDomainAssemblyClientFactory());

            ofile.DeobfuscatorContext = new DeobfuscatorContext();

            try
            {
                ofile.Load(CreateDeobfuscatorInfos().Select(di => di.CreateDeobfuscator()).ToList());
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return(null);
            }
            return(ofile);
        }
Ejemplo n.º 10
0
        private IObfuscatedFile CreateObfuscationFile(ObfuscatedFile.Options fileOptions, ModuleContext moduleContext)
        {
            var obfuscatedFile = new ObfuscatedFile(fileOptions, moduleContext, new NewAppDomainAssemblyClientFactory())
            {
                DeobfuscatorContext = new DeobfuscatorContext()
            };

            try
            {
                obfuscatedFile.load(knownDeobfuscators.Select(info => info.createDeobfuscator()).ToList());
            }
            catch (Exception ex)
            {
                MessageBox.ShowError(ex.Message);
                return(null);
            }
            return(obfuscatedFile);
        }
Ejemplo n.º 11
0
        void AddAllOptions()
        {
            miscOptions.Add(new OneArgOption("r", null, "Scan for .NET files in all subdirs", "dir", (val) => {
                AddSearchDir();
                searchDir = new FilesDeobfuscator.SearchDir();
                if (!Utils.PathExists(val))
                {
                    ExitError($"Directory {val} does not exist");
                }
                searchDir.InputDirectory = val;
            }));
            miscOptions.Add(new OneArgOption("ro", null, "Output base dir for recursively found files", "dir", (val) => {
                if (searchDir == null)
                {
                    ExitError("Missing -r option");
                }
                searchDir.OutputDirectory = val;
            }));
            miscOptions.Add(new NoArgOption("ru", null, "Skip recursively found files with unsupported obfuscator", () => {
                if (searchDir == null)
                {
                    ExitError("Missing -r option");
                }
                searchDir.SkipUnknownObfuscators = true;
            }));
            miscOptions.Add(new NoArgOption("d", null, "Detect obfuscators and exit", () => {
                filesOptions.DetectObfuscators = true;
            }));
            miscOptions.Add(new OneArgOption(null, "asm-path", "Add an assembly search path", "path", (val) => {
                TheAssemblyResolver.Instance.AddSearchDirectory(val);
            }));
            miscOptions.Add(new NoArgOption(null, "dont-rename", "Don't rename classes, methods, etc.", () => {
                filesOptions.RenameSymbols = false;
                filesOptions.RenamerFlags  = 0;
            }));
            miscOptions.Add(new OneArgOption(null, "keep-names", "Don't rename n(amespaces), t(ypes), p(rops), e(vents), f(ields), m(ethods), a(rgs), g(enericparams), d(elegate fields). Can be combined, eg. efm", "flags", (val) => {
                foreach (var c in val)
                {
                    switch (c)
                    {
                    case 'n': filesOptions.RenamerFlags &= ~RenamerFlags.RenameNamespaces; break;

                    case 't': filesOptions.RenamerFlags &= ~RenamerFlags.RenameTypes; break;

                    case 'p': filesOptions.RenamerFlags &= ~RenamerFlags.RenameProperties; break;

                    case 'e': filesOptions.RenamerFlags &= ~RenamerFlags.RenameEvents; break;

                    case 'f': filesOptions.RenamerFlags &= ~RenamerFlags.RenameFields; break;

                    case 'm': filesOptions.RenamerFlags &= ~RenamerFlags.RenameMethods; break;

                    case 'a': filesOptions.RenamerFlags &= ~RenamerFlags.RenameMethodArgs; break;

                    case 'g': filesOptions.RenamerFlags &= ~RenamerFlags.RenameGenericParams; break;

                    case 'd': filesOptions.RenamerFlags |= RenamerFlags.DontRenameDelegateFields; break;

                    default: throw new UserException($"Unrecognized --keep-names char: '{c}'");
                    }
                }
            }));
            miscOptions.Add(new NoArgOption(null, "dont-create-params", "Don't create method params when renaming", () => {
                filesOptions.RenamerFlags |= RenamerFlags.DontCreateNewParamDefs;
            }));
            miscOptions.Add(new NoArgOption(null, "dont-restore-props", "Don't restore properties/events", () => {
                filesOptions.RenamerFlags &= ~(RenamerFlags.RestorePropertiesFromNames | RenamerFlags.RestoreEventsFromNames);
            }));
            miscOptions.Add(new OneArgOption(null, "default-strtyp", "Default string decrypter type", "type", (val) => {
                if (!stringDecrypterTypes.GetValue(val, out object decrypterType))
                {
                    ExitError($"Invalid string decrypter type '{val}'");
                }
                defaultStringDecrypterType = (DecrypterType)decrypterType;
            }));
            miscOptions.Add(new OneArgOption(null, "default-strtok", "Default string decrypter method token or [type::][name][(args,...)]", "method", (val) => {
                defaultStringDecrypterMethods.Add(val);
            }));
            miscOptions.Add(new NoArgOption(null, "no-cflow-deob", "No control flow deobfuscation (NOT recommended)", () => {
                filesOptions.ControlFlowDeobfuscation = false;
            }));
            miscOptions.Add(new NoArgOption(null, "only-cflow-deob", "Only control flow deobfuscation", () => {
                filesOptions.ControlFlowDeobfuscation = true;
                // --strtyp none
                defaultStringDecrypterType = DecrypterType.None;
                // --keep-types
                filesOptions.KeepObfuscatorTypes = true;
                // --preserve-tokens
                filesOptions.MetadataFlags |= MetadataFlags.PreserveRids |
                                              MetadataFlags.PreserveUSOffsets |
                                              MetadataFlags.PreserveBlobOffsets |
                                              MetadataFlags.PreserveExtraSignatureData;
                // --dont-rename
                filesOptions.RenameSymbols = false;
                filesOptions.RenamerFlags  = 0;
            }));
            miscOptions.Add(new NoArgOption(null, "load-new-process", "Load executed assemblies into a new process", () => {
                filesOptions.AssemblyClientFactory = new NewProcessAssemblyClientFactory();
            }));
            miscOptions.Add(new NoArgOption(null, "keep-types", "Keep obfuscator types, fields, methods", () => {
                newFileOptions.KeepObfuscatorTypes = true;
            }));
            miscOptions.Add(new NoArgOption(null, "preserve-tokens", "Preserve important tokens, #US, #Blob, extra sig data", () => {
                newFileOptions.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), all (all previous tables). Use - to disable (eg. all,-pd). Can be combined: ed,fd,md", "flags", (val) => {
                foreach (var t in val.Split(','))
                {
                    var s = t.Trim();
                    if (s.Length == 0)
                    {
                        continue;
                    }
                    bool clear = s[0] == '-';
                    if (clear)
                    {
                        s = s.Substring(1);
                    }
                    MetadataFlags flag;
                    switch (s.Trim())
                    {
                    case "": flag = 0; break;

                    case "all": flag = MetadataFlags.PreserveRids; break;

                    case "tr": flag = MetadataFlags.PreserveTypeRefRids; break;

                    case "td": flag = MetadataFlags.PreserveTypeDefRids; break;

                    case "fd": flag = MetadataFlags.PreserveFieldRids; break;

                    case "md": flag = MetadataFlags.PreserveMethodRids; break;

                    case "pd": flag = MetadataFlags.PreserveParamRids; break;

                    case "mr": flag = MetadataFlags.PreserveMemberRefRids; break;

                    case "s": flag = MetadataFlags.PreserveStandAloneSigRids; break;

                    case "ed": flag = MetadataFlags.PreserveEventRids; break;

                    case "pr": flag = MetadataFlags.PreservePropertyRids; break;

                    case "ts": flag = MetadataFlags.PreserveTypeSpecRids; break;

                    case "ms": flag = MetadataFlags.PreserveMethodSpecRids; break;

                    default: throw new UserException($"Invalid --preserve-table option: {s}");
                    }
                    if (clear)
                    {
                        filesOptions.MetadataFlags &= ~flag;
                    }
                    else
                    {
                        filesOptions.MetadataFlags |= flag;
                    }
                }
            }));
            miscOptions.Add(new NoArgOption(null, "preserve-all", "Preserve all tokens", () => {
                newFileOptions.MetadataFlags |= MetadataFlags.PreserveAll;
            }));
            miscOptions.Add(new NoArgOption(null, "preserve-strings", "Preserve #Strings heap offsets", () => {
                newFileOptions.MetadataFlags |= MetadataFlags.PreserveStringsOffsets;
            }));
            miscOptions.Add(new NoArgOption(null, "preserve-us", "Preserve #US heap offsets", () => {
                newFileOptions.MetadataFlags |= MetadataFlags.PreserveUSOffsets;
            }));
            miscOptions.Add(new NoArgOption(null, "preserve-blob", "Preserve #Blob heap offsets", () => {
                newFileOptions.MetadataFlags |= MetadataFlags.PreserveBlobOffsets;
            }));
            miscOptions.Add(new NoArgOption(null, "preserve-sig-data", "Preserve extra data at the end of signatures", () => {
                newFileOptions.MetadataFlags |= MetadataFlags.PreserveExtraSignatureData;
            }));
            miscOptions.Add(new NoArgOption(null, "one-file", "Deobfuscate one file at a time", () => {
                filesOptions.OneFileAtATime = true;
            }));
            miscOptions.Add(new NoArgOption("v", null, "Verbose", () => {
                Logger.Instance.MaxLoggerEvent    = LoggerEvent.Verbose;
                Logger.Instance.CanIgnoreMessages = false;
            }));
            miscOptions.Add(new NoArgOption("vv", null, "Very verbose", () => {
                Logger.Instance.MaxLoggerEvent    = LoggerEvent.VeryVerbose;
                Logger.Instance.CanIgnoreMessages = false;
            }));
            miscOptions.Add(new NoArgOption("h", "help", "Show this help message", () => {
                Usage();
                Exit(0);
            }));

            defaultOption = new OneArgOption("f", null, "Name of .NET file", "file", (val) => {
                AddFile();
                if (!Utils.FileExists(val))
                {
                    ExitError($"File \"{val}\" does not exist.");
                }
                newFileOptions = new ObfuscatedFile.Options {
                    Filename = val,
                    ControlFlowDeobfuscation = filesOptions.ControlFlowDeobfuscation,
                    KeepObfuscatorTypes      = filesOptions.KeepObfuscatorTypes,
                    MetadataFlags            = filesOptions.MetadataFlags,
                    RenamerFlags             = filesOptions.RenamerFlags,
                };
                if (defaultStringDecrypterType != null)
                {
                    newFileOptions.StringDecrypterType = defaultStringDecrypterType.Value;
                }
                newFileOptions.StringDecrypterMethods.AddRange(defaultStringDecrypterMethods);
            });
            fileOptions.Add(defaultOption);
            fileOptions.Add(new OneArgOption("o", null, "Name of output file", "file", (val) => {
                if (newFileOptions == null)
                {
                    ExitError("Missing input file");
                }
                var newFilename = Utils.GetFullPath(val);
                if (string.Equals(Utils.GetFullPath(newFileOptions.Filename), newFilename, StringComparison.OrdinalIgnoreCase))
                {
                    ExitError($"Output file can't be same as input file ({newFilename})");
                }
                newFileOptions.NewFilename = newFilename;
            }));
            fileOptions.Add(new OneArgOption("p", null, "Obfuscator type (see below)", "type", (val) => {
                if (newFileOptions == null)
                {
                    ExitError("Missing input file");
                }
                if (!IsValidObfuscatorType(val))
                {
                    ExitError($"Invalid obfuscator type '{val}'");
                }
                newFileOptions.ForcedObfuscatorType = val;
            }));
            fileOptions.Add(new OneArgOption(null, "strtyp", "String decrypter type", "type", (val) => {
                if (newFileOptions == null)
                {
                    ExitError("Missing input file");
                }
                if (!stringDecrypterTypes.GetValue(val, out object decrypterType))
                {
                    ExitError($"Invalid string decrypter type '{val}'");
                }
                newFileOptions.StringDecrypterType = (DecrypterType)decrypterType;
            }));
            fileOptions.Add(new OneArgOption(null, "strtok", "String decrypter method token or [type::][name][(args,...)]", "method", (val) => {
                if (newFileOptions == null)
                {
                    ExitError("Missing input file");
                }
                newFileOptions.StringDecrypterMethods.Add(val);
            }));

            AddOptions(miscOptions);
            AddOptions(fileOptions);
            foreach (var info in deobfuscatorInfos)
            {
                AddOptions(info.GetOptions());
            }
        }
Ejemplo n.º 12
0
        void addAllOptions()
        {
            miscOptions.Add(new OneArgOption("r", null, "Scan for .NET files in all subdirs", "dir", (val) => {
                addSearchDir();
                searchDir = new FilesDeobfuscator.SearchDir();
                if (!Utils.pathExists(val))
                {
                    exitError(string.Format("Directory {0} does not exist", val));
                }
                searchDir.InputDirectory = val;
            }));
            miscOptions.Add(new OneArgOption("ro", null, "Output base dir for recursively found files", "dir", (val) => {
                if (searchDir == null)
                {
                    exitError("Missing -r option");
                }
                searchDir.OutputDirectory = val;
            }));
            miscOptions.Add(new NoArgOption("ru", null, "Skip recursively found files with unsupported obfuscator", () => {
                if (searchDir == null)
                {
                    exitError("Missing -r option");
                }
                searchDir.SkipUnknownObfuscators = true;
            }));
            miscOptions.Add(new NoArgOption("d", null, "Detect obfuscators and exit", () => {
                filesOptions.DetectObfuscators = true;
            }));
            miscOptions.Add(new OneArgOption(null, "asm-path", "Add an assembly search path", "path", (val) => {
                AssemblyResolver.Instance.addSearchDirectory(val);
            }));
            miscOptions.Add(new NoArgOption(null, "dont-rename", "Don't rename classes, methods, etc.", () => {
                filesOptions.RenameSymbols = false;
            }));
            miscOptions.Add(new NoArgOption(null, "dont-restore-props", "Don't restore properties/events", () => {
                filesOptions.RestorePropsEvents = false;
            }));
            miscOptions.Add(new OneArgOption(null, "default-strtyp", "Default string decrypter type", "type", (val) => {
                object decrypterType;
                if (!stringDecrypterTypes.getValue(val, out decrypterType))
                {
                    exitError(string.Format("Invalid string decrypter type '{0}'", val));
                }
                defaultStringDecrypterType = (DecrypterType)decrypterType;
            }));
            miscOptions.Add(new OneArgOption(null, "default-strtok", "Default string decrypter method token or [type::][name][(args,...)]", "method", (val) => {
                defaultStringDecrypterMethods.Add(val);
            }));
            miscOptions.Add(new NoArgOption(null, "no-cflow-deob", "No control flow deobfuscation (NOT recommended)", () => {
                filesOptions.ControlFlowDeobfuscation = false;
            }));
            miscOptions.Add(new NoArgOption(null, "load-new-process", "Load executed assemblies into a new process", () => {
                filesOptions.AssemblyClientFactory = new NewProcessAssemblyClientFactory();
            }));
            miscOptions.Add(new NoArgOption(null, "keep-types", "Keep obfuscator types, fields, methods", () => {
                filesOptions.KeepObfuscatorTypes = true;
            }));
            miscOptions.Add(new NoArgOption(null, "one-file", "Deobfuscate one file at a time", () => {
                filesOptions.OneFileAtATime = true;
            }));
            miscOptions.Add(new NoArgOption("v", null, "Verbose", () => {
                Log.logLevel = Log.LogLevel.verbose;
            }));
            miscOptions.Add(new NoArgOption("vv", null, "Very verbose", () => {
                Log.logLevel = Log.LogLevel.veryverbose;
            }));
            miscOptions.Add(new NoArgOption("h", "help", "Show this help message", () => {
                usage();
                exit(0);
            }));

            defaultOption = new OneArgOption("f", null, "Name of .NET file", "file", (val) => {
                addFile();
                if (!Utils.fileExists(val))
                {
                    exitError(string.Format("File \"{0}\" does not exist.", val));
                }
                newFileOptions = new ObfuscatedFile.Options {
                    Filename = val,
                    ControlFlowDeobfuscation = filesOptions.ControlFlowDeobfuscation,
                    KeepObfuscatorTypes      = filesOptions.KeepObfuscatorTypes,
                };
                if (defaultStringDecrypterType != null)
                {
                    newFileOptions.StringDecrypterType = defaultStringDecrypterType.Value;
                }
                newFileOptions.StringDecrypterMethods.AddRange(defaultStringDecrypterMethods);
            });
            fileOptions.Add(defaultOption);
            fileOptions.Add(new OneArgOption("o", null, "Name of output file", "file", (val) => {
                if (newFileOptions == null)
                {
                    exitError("Missing input file");
                }
                if (string.Equals(Utils.getFullPath(newFileOptions.Filename), Utils.getFullPath(val), StringComparison.OrdinalIgnoreCase))
                {
                    exitError(string.Format("Output file can't be same as input file ({0})", val));
                }
                newFileOptions.NewFilename = val;
            }));
            fileOptions.Add(new OneArgOption("p", null, "Obfuscator type (see below)", "type", (val) => {
                if (newFileOptions == null)
                {
                    exitError("Missing input file");
                }
                if (!isValidObfuscatorType(val))
                {
                    exitError(string.Format("Invalid obfuscator type '{0}'", val));
                }
                newFileOptions.ForcedObfuscatorType = val;
            }));
            fileOptions.Add(new OneArgOption(null, "strtyp", "String decrypter type", "type", (val) => {
                if (newFileOptions == null)
                {
                    exitError("Missing input file");
                }
                object decrypterType;
                if (!stringDecrypterTypes.getValue(val, out decrypterType))
                {
                    exitError(string.Format("Invalid string decrypter type '{0}'", val));
                }
                newFileOptions.StringDecrypterType = (DecrypterType)decrypterType;
            }));
            fileOptions.Add(new OneArgOption(null, "strtok", "String decrypter method token or [type::][name][(args,...)]", "method", (val) => {
                if (newFileOptions == null)
                {
                    exitError("Missing input file");
                }
                newFileOptions.StringDecrypterMethods.Add(val);
            }));

            addOptions(miscOptions);
            addOptions(fileOptions);
            foreach (var info in deobfuscatorInfos)
            {
                addOptions(info.getOptions());
            }
        }