Example #1
0
 public override void Patch(Logger logger, AssemblyDefinition asmCSharp, AssemblyDefinition __reserved)
 {
     module = asmCSharp.Modules[0];
     foreach (ModuleDefinition mdef in asmCSharp.Modules)
     {
         logger.KeyInfo("Patching " + mdef.Types.Count + " type[s] ...");
         foreach (TypeDefinition tdef in mdef.Types)
         {
             NameNormalizer.CheckNames(tdef);
         }
     }
     NameNormalizer.FinalizeNormalizing();
     NameNormalizer.clnamestomod.Clear();
     NameNormalizer.vclasses.Clear();
 }
Example #2
0
        public static void Main(string[] args)
        {
            Console.WriteLine ("Assembly-CSharp Deobfuscator for 7 Days to Die [by the 7 Days to Die Modding Community]");

            ownFolder = Path.GetDirectoryName(Path.GetFullPath(Assembly.GetEntryAssembly ().Location));
            if (ownFolder == null) {
                ErrorExit("Unable to retrieve the folder containing Deobfuscator!");
                return;
            }
            bool verbosity = false;//(args.Length > 1) ? (args[0].ToLower().Equals("-v")) : false;
            if (File.Exists (Path.Combine(ownFolder, "config.xml")))
            {
                XmlDocument configDoc = new XmlDocument ();
                try {
                    configDoc.Load(Path.Combine(ownFolder, "config.xml"));
                } catch (Exception e) {
                    Console.WriteLine(Logger.Level_ToString(Logger.Level.WARNING) + "Unable to load config.xml : " + e.ToString ());
                }
                XmlNodeList configElems = configDoc.DocumentElement.ChildNodes;
                foreach (XmlNode curElem in configElems) {
                    if (!curElem.Name.ToLower().Equals("verbosity"))
                        continue;
                    XmlNode verbosityElem = curElem;
                    XmlAttributeCollection verbosityAttrs = verbosityElem.Attributes;
                    foreach (XmlNode curAttr in verbosityAttrs) {
                        if (curAttr.Name.ToLower().Equals("enabled")) {
                            verbosity = curAttr.Value.ToLower().Equals("true");
                            break;
                        }
                    }
                }
            }
            else
                Console.WriteLine(Path.Combine(ownFolder, "config.xml"));
            mainLogger = new Logger (Path.Combine(ownFolder, "mainlog.txt"), null, (int)(verbosity ? Logger.Level.INFO : Logger.Level.KEYINFO));
            mainLogger.Info("Started logging to mainlog.txt.");

            if ( args.Length == 0 || !args[0].ToLower().EndsWith(".dll") )
            {
                mainLogger.Write("Usage : deobfuscate \"<path to file>\"");
                mainLogger.Write("Alternatively, you can drag and drop file into deobfuscate.");
                ErrorExit("", 2);
            }
            var acsharpSource = Path.GetFullPath(args [0]);
            if (!File.Exists (acsharpSource)) {
                ErrorExit("Unable to retrieve the folder containing " + args[0]);
                return;
            }
            sourceAssemblyPath = acsharpSource;

            string patchersPath = Path.Combine(ownFolder, "patchers");
            if (!Directory.Exists (patchersPath)) {
                Directory.CreateDirectory (patchersPath);
            }

            DefaultAssemblyResolver resolver = new DefaultAssemblyResolver ();
            resolver.AddSearchDirectory (Path.GetDirectoryName(acsharpSource));

            AssemblyDefinition csharpDef = null;
            AssemblyDefinition mscorlibDef = null;

            try {
                csharpDef = AssemblyDefinition.ReadAssembly (acsharpSource, new ReaderParameters{ AssemblyResolver = resolver });
            } catch (Exception e) {
                ErrorExit("Unable to load " + args[0] + " :" + e);
                return;
            }
            try {
                mscorlibDef = AssemblyDefinition.ReadAssembly(Path.Combine(Path.GetDirectoryName(acsharpSource), "mscorlib.dll"), new ReaderParameters{ AssemblyResolver = resolver });
            } catch (Exception e) {
                mainLogger.Warning("Unable to load mscorlib.dll :" + e);
            }
            int csharpFileLen = (int)new FileInfo(acsharpSource).Length;
            if (csharpDef.Modules.Count == 0)
            {
                ErrorExit(args[0] + " is invalid!");
            }
            ModuleDefinition csharpModule = csharpDef.Modules[0];
            if (csharpModule.GetType("Deobfuscated") != null)
            {
                ErrorExit(args[0] + " already is deobfuscated!");
            }

            mainLogger.KeyInfo("Deobfuscating " + args[0] + "...");
            mainLogger.Write("___");
            string[] files = Directory.GetFiles(patchersPath, "*.dll");
            var patchers = new List<Patcher>();
            foreach (var file in files)
            {
                Assembly patcherAssembly;
                try
                {
                    patcherAssembly = Assembly.LoadFrom(file);
                }
                catch (Exception e)
                {
                    mainLogger.Error("Unable to load the patcher " + file + " :");
                    mainLogger.Error(e.ToString());
                    continue;
                }
                Type exttype = typeof (Patcher);
                Type extensiontype = null;
                foreach (var type in patcherAssembly.GetExportedTypes())
                {
                    if (exttype.IsAssignableFrom(type))
                    {
                        extensiontype = type;
                        break;
                    }
                }
                if (extensiontype == null)
                {
                    mainLogger.Error("Failed to load patcher " + file + " (Specified assembly does not implement an Patcher class)");
                    continue;
                }

                // Create and register the extension
                try
                {
                    var patcher = Activator.CreateInstance(extensiontype, new object[0]) as Patcher;
                    if (patcher != null)
                        patchers.Add(patcher);
                }
                catch (Exception e)
                {
                    mainLogger.Error("Unable to instantiate the patcher class " + file + " :");
                    mainLogger.Error(e.ToString());
                }
            }
            if (patchers.Count == 0)
            {
                ErrorExit("There are no patches to apply! Exiting.", 3);
                return;
            }
            foreach (var patcher in patchers)
            {
                mainLogger.KeyInfo("Executing patcher \"" + patcher.Name + "\" (by " + string.Join(",", patcher.Authors) + ")...");
                Logger curLogger = new Logger(Path.Combine(ownFolder, "log_" + patcher.Name + ".txt"), null, (int) (verbosity ? Logger.Level.INFO : Logger.Level.KEYINFO));
                try
                {
                    patcher.Patch(curLogger, csharpDef, null);
                }
                catch (TargetInvocationException e)
                {
                    mainLogger.Error("ERROR : Invoking the Patch method for " + patcher.Name + " resulted in an exception :");
                    mainLogger.Error(e.StackTrace);
                    mainLogger.Error(e.InnerException.StackTrace);
                }
                catch (Exception e)
                {
                    mainLogger.Error("ERROR : An exception occured while trying to invoke the Patch method of " + patcher.Name + " :");
                    mainLogger.Error(e.Message + Environment.NewLine + e.StackTrace);
                }
                curLogger.Close();
                mainLogger.Info("Writing the current Assembly-CSharp.dll to a MemoryStream...");
                var asmCSharpStream = new MemoryStream(csharpFileLen);
                csharpDef.Write(asmCSharpStream);
                mainLogger.Info("Reading the current Assembly-CSharp.dll from the MemoryStream...");
                asmCSharpStream.Seek(0, SeekOrigin.Begin);
                csharpDef = AssemblyDefinition.ReadAssembly(asmCSharpStream, new ReaderParameters {AssemblyResolver = resolver});
                asmCSharpStream.Close();
                csharpModule = csharpDef.Modules[0];
            }
            mainLogger.Write(); mainLogger.Write("___");

            if ((mscorlibDef != null) && (mscorlibDef.Modules.Count > 0))
            {
                csharpModule.Types.Add(new TypeDefinition("", "Deobfuscated", Mono.Cecil. TypeAttributes.Public, csharpDef.MainModule.TypeSystem.Object));
            }
            else
                mainLogger.Error("Unable to create the Deobufscated class!");
            string outputPath = Path.Combine(Path.GetDirectoryName(acsharpSource), Path.GetFileNameWithoutExtension(acsharpSource) + ".deobf.dll");
            mainLogger.KeyInfo ("Saving the new assembly to " + outputPath + " ...");
            try
            {
                csharpDef.Write (outputPath);
            }
            catch (Exception e)
            {
                ErrorExit ("Unable to save the assembly : " + e.Message + Environment.NewLine + e.StackTrace);
            }

            ErrorExit ("Success.", 0);
        }
Example #3
0
        public static void Apply(ModuleDefinition module, Logger logger)
        {
            int stat_obfCall = 0, stat_nullField = 0, stat_duppop = 0, stat_obfSwitch = 0, stat_obfIf = 0, stat_obfClasses = 0;

            //not as fancy as it could be; the alternate way would be checking the field's names (always 1 uppercase letter) but that method could more easily get outdated
            Dictionary<FieldDefinition, FieldRemoveInfo> suspectFields = new Dictionary<FieldDefinition, FieldRemoveInfo>();

            List<MethodDefinition> decryptMethods = new List<MethodDefinition>();
            MethodDefinition[] mdefs = HelperClass.findMembers<MethodDefinition>(module, null, true);
            for (int methodIndex = 0; methodIndex < mdefs.Length; methodIndex++)
            {
                MethodDefinition mdef = mdefs[methodIndex];
                if (mdef.HasBody)
                {
                    MethodBody mdefBody = mdef.Body;
                    for (int i = 0; i < mdefBody.Instructions.Count; i++)
                    {
                        Instruction instr = mdefBody.Instructions[i];
                        if (instr.OpCode == OpCodes.Call)
                        {
                            MethodReference mref = (MethodReference)instr.Operand;
                            MethodDefinition targetMethod = mref.Resolve();
                            //indicates that this is a method by the obfuscator that replaces single operations from other methods
                            if (targetMethod != null &&
                                targetMethod.IsStatic && targetMethod.DeclaringType.Namespace.Equals("A") &&
                                targetMethod.Body.Instructions.Count < 10 &&
                                targetMethod.DeclaringType.Methods.Count == 1 && targetMethod.DeclaringType.Fields.Count == 0)
                            {
                                //logger.Info(targetMethod.DeclaringType.FullName + "::" + targetMethod.Name + " -> " + mdef.DeclaringType.FullName + "::" + mdef.Name + " (@" + i + ")");
                                MethodBody targetBody = targetMethod.Body;
                                targetBody.SimplifyMacros();
                                bool canPatch = (targetBody.Instructions.Count > targetMethod.Parameters.Count) && !targetBody.HasVariables;
                                if (canPatch)
                                {
                                    for (int k = 0; k < targetMethod.Parameters.Count; k++)
                                    {
                                        if (targetBody.Instructions[k].OpCode != OpCodes.Ldarg || ((ParameterDefinition)targetBody.Instructions[k].Operand).Index != k)
                                        {
                                            canPatch = false;
                                            break;
                                        }
                                    }
                                    if (canPatch)
                                    {
                                        for (int k = targetMethod.Parameters.Count; k < targetBody.Instructions.Count; k++)
                                        {
                                            if (targetBody.Instructions[k].Operand is ParameterDefinition)
                                            {
                                                canPatch = false;
                                                break;
                                            }
                                        }
                                    }
                                }
                                if (!canPatch)
                                {
                                    logger.Warning("Cannot reimport the instructions from " + targetMethod.FullName + " (not yet supported)!");
                                    continue;
                                }
                                ILProcessor proc = mdefBody.GetILProcessor();
                                List<Instruction> targetInstructions = new List<Instruction>(targetBody.Instructions.Count-targetMethod.Parameters.Count);
                                int _k = 0; Instruction before = instr;
                                //create nop instructions to simplify creating jumps (the instruction and the operand will be changed afterwards)
                                for (int k = targetMethod.Parameters.Count; k < targetBody.Instructions.Count; k++, _k++)
                                {
                                    Instruction nopInstr = proc.Create(OpCodes.Nop);
                                    targetInstructions.Add(nopInstr);
                                    HelperClass.SafeInsertAfter(proc, before, nopInstr);
                                    //proc.InsertAfter(before, nopInstr);
                                    before = nopInstr;
                                }
                                _k = 0;
                                for (int k = targetMethod.Parameters.Count; k < targetBody.Instructions.Count; k++, _k++)
                                {
                                    Instruction curInstr = targetBody.Instructions[k];
                                    switch (curInstr.OpCode.Code)
                                    {
                                        case Mono.Cecil.Cil.Code.Ret://OpCodes.Ret.Code:
                                            HelperClass.SafeRemove(proc, targetInstructions[_k]);
                                            //proc.Remove(targetInstructions[_k]);
                                            targetInstructions.RemoveAt(_k);
                                            break;
                                        default:
                                            targetInstructions[_k].OpCode = curInstr.OpCode;
                                            if (curInstr.Operand is Instruction)
                                            {
                                                Instruction targetedInstruction = (Instruction)curInstr.Operand;
                                                int instrIndex = -1; int targetInstrIndex = -1;
                                                for (int l = targetMethod.Parameters.Count; l < targetBody.Instructions.Count; l++)
                                                {
                                                    if (targetBody.Instructions[l].Equals(targetedInstruction))
                                                    {
                                                        instrIndex = l;
                                                        targetInstrIndex = l - targetMethod.Parameters.Count;
                                                        break;
                                                    }
                                                }
                                                if (instrIndex == -1)
                                                    throw new Exception("Unable to find the target of instruction #" + k + " in " + targetMethod.FullName + "!");
                                                if (targetBody.Instructions[instrIndex].OpCode == OpCodes.Ret)
                                                    targetInstructions[_k].Operand = targetInstructions[targetInstructions.Count-1].Next;
                                                else
                                                    targetInstructions[_k].Operand = targetInstructions[targetInstrIndex];
                                            }
                                            else if (curInstr.Operand is Instruction[])
                                            {
                                                Instruction[] oldTargetList = (Instruction[])curInstr.Operand;
                                                Instruction[] newInstructions = new Instruction[oldTargetList.Length];
                                                for (int l = 0; l < oldTargetList.Length; l++)
                                                {
                                                    Instruction targetedInstruction = oldTargetList[l];
                                                    int instrIndex = -1; int targetInstrIndex = -1;
                                                    for (int m = targetMethod.Parameters.Count; m < targetBody.Instructions.Count; m++)
                                                    {
                                                        if (targetBody.Instructions[l].Equals(targetedInstruction))
                                                        {
                                                            instrIndex = l;
                                                            targetInstrIndex = l - targetMethod.Parameters.Count;
                                                            break;
                                                        }
                                                    }
                                                    if (instrIndex == -1)
                                                        throw new Exception("Unable to find the target of instruction #" + k + " in " + targetMethod.FullName + "!");
                                                    if (targetBody.Instructions[instrIndex].OpCode == OpCodes.Ret)
                                                        newInstructions[l] = targetInstructions[targetInstructions.Count-1].Next;
                                                    else
                                                        newInstructions[l] = targetInstructions[targetInstrIndex];
                                                }
                                                targetInstructions[_k].Operand = newInstructions;
                                            }
                                            else if (curInstr.Operand is MethodReference)
                                            {
                                                targetInstructions[_k].Operand = curInstr.Operand;//module.Import(((MethodReference)curInstr.Operand).Resolve());
                                            }
                                            else if (curInstr.Operand is FieldReference)
                                            {
                                                targetInstructions[_k].Operand = curInstr.Operand;//module.Import(((FieldReference)curInstr.Operand).Resolve());
                                            }
                                            else if (curInstr.Operand is TypeReference)
                                            {
                                                targetInstructions[_k].Operand = curInstr.Operand;//module.Import(((TypeReference)curInstr.Operand).Resolve());
                                            }
                                            else if (curInstr.Operand is IMetadataTokenProvider)
                                            {
                                                throw new Exception("Unsupported operand type IMetadataTokenProvider in " + targetMethod.FullName + "!");
                                                //IMetadataTokenProvider provider = (IMetadataTokenProvider)curInstr.Operand;
                                                //string name = provider.MetadataToken.ToString();
                                                //targetInstructions[_k].Operand = null;//module.Import(((TypeReference)curInstr.Operand).Resolve());
                                            }
                                            else
                                            {
                                                targetInstructions[_k].Operand = curInstr.Operand;
                                            }
                                            break;
                                    }
                                }

                                HelperClass.PatchInstructionReferences(mdefBody, instr, (targetInstructions.Count > 0) ? targetInstructions[0] : instr.Next);
                                HelperClass.SafeRemove(proc, instr);
                                i--;

                                stat_obfCall++;
                            }
                        }
                        else if (instr.OpCode == OpCodes.Ldsfld)
                        {
                            //remove fields generated by the obfuscator that always are null
                            FieldReference fref = (FieldReference)instr.Operand;
                            FieldDefinition targetField = fref.Resolve();
                            if (targetField != null && targetField.DeclaringType.Namespace.Equals("A") && targetField.IsAssembly)
                            {
                                if (targetField.DeclaringType.Fields.Count == 1 && targetField.DeclaringType.Methods.Count == 0)
                                {
                                    if (!suspectFields.ContainsKey(targetField))
                                    {
                                        FieldRemoveInfo fieldInfo = new FieldRemoveInfo();
                                        suspectFields.Add(targetField, fieldInfo);
                                    }
                                    suspectFields[targetField].references.Add(new InstructionIdentifier(mdefBody, instr));
                                }
                            }
                        }
                        else if (instr.OpCode == OpCodes.Stsfld)
                        {
                            //make sure the fields to remove really are not written to (doesn't work for structs whose members are altered)
                            FieldReference fref = (FieldReference)instr.Operand;
                            FieldDefinition targetField = fref.Resolve();
                            if (targetField != null && targetField.DeclaringType.Namespace.Equals("A") && targetField.IsAssembly)
                            {
                                if (targetField.DeclaringType.Fields.Count == 1 && targetField.DeclaringType.Methods.Count == 0)
                                {
                                    if (!suspectFields.ContainsKey(targetField))
                                    {
                                        FieldRemoveInfo fieldInfo = new FieldRemoveInfo();
                                        suspectFields.Add(targetField, fieldInfo);
                                    }
                                    suspectFields[targetField].shouldRemove = false;
                                }
                            }
                        }
                        else if ((instr.OpCode == OpCodes.Dup) && ((i+1) < mdefBody.Instructions.Count) && (mdefBody.Instructions[i+1].OpCode == OpCodes.Pop))
                        {
                            ILProcessor proc = mdefBody.GetILProcessor();
                            HelperClass.PatchInstructionReferences(mdefBody, instr, mdefBody.Instructions[i+2]);
                            HelperClass.SafeRemove(proc, mdefBody.Instructions[i+1]);
                            HelperClass.SafeRemove(proc, instr);
                            i--;
                            stat_duppop++;
                        }
                        else if (i > 0 &&
                            (instr.OpCode == OpCodes.Switch) &&
                            ((Instruction[])instr.Operand).Length == 1 && ((Instruction[])instr.Operand)[0] == mdefBody.Instructions[i-1])
                        {
                            Instruction ldInstr = mdefBody.Instructions[i-1];
                            HelperClass.PatchInstructionReferences(mdefBody, ldInstr, mdefBody.Instructions[i+1]);
                            ILProcessor proc = mdefBody.GetILProcessor();
                            HelperClass.SafeRemove(proc, mdefBody.Instructions[i-1]);
                            HelperClass.SafeRemove(proc, instr);
                            i -= 2;
                            stat_obfSwitch++;
                        }
                        else if ((instr.OpCode == OpCodes.Ldc_I4_1) && ((i+4) < mdefBody.Instructions.Count) &&
                            (mdefBody.Instructions[i+1].OpCode.Code == Code.Brtrue_S) &&
                            (mdefBody.Instructions[i+2].OpCode.Code == Code.Ldtoken) &&
                            (mdefBody.Instructions[i+3].OpCode.Code == Code.Pop)
                        )
                        {
                            Instruction ldInstr = mdefBody.Instructions[i-1];
                            HelperClass.PatchInstructionReferences(mdefBody, instr, mdefBody.Instructions[i+4]);
                            ILProcessor proc = mdefBody.GetILProcessor();
                            for (int k = 0; k < 4; k++)
                                HelperClass.SafeRemove(proc, mdefBody.Instructions[i]);
                            i--;
                            stat_obfIf++;
                        }
                    }
                }
                if ((methodIndex % (mdefs.Length/10)) == 0 && methodIndex > 0)
                    logger.KeyInfo("Removed garbage from method #" + (methodIndex + 1) + ".");
            }
            foreach (FieldRemoveInfo info in suspectFields.Values)
            {
                if (info.shouldRemove)
                {
                    foreach (InstructionIdentifier ident in info.references)
                    {
                        ILProcessor proc = ident.body.GetILProcessor();
                        Instruction newInstr = proc.Create(OpCodes.Ldnull);
                        HelperClass.PatchInstructionReferences(ident.body, ident.instr, newInstr);
                        HelperClass.SafeInsertAfter(proc, ident.instr, newInstr);
                        HelperClass.SafeRemove(proc, ident.instr);
                        stat_nullField++;
                    }
                }
            }
            List<TypeDefinition> referencedTypes = new List<TypeDefinition>();

            for (int methodIndex = 0; methodIndex < mdefs.Length; methodIndex++)
            {
                MethodDefinition mdef = mdefs[methodIndex];
                if (mdef.HasBody)
                {
                    MethodBody mdefBody = mdef.Body;
                    for (int k = 0; k < mdefBody.Instructions.Count; k++)
                    {
                        Instruction instr = mdefBody.Instructions[k];
                        if (instr.Operand is MethodReference)
                        {
                            MethodDefinition targetMethod = ((MethodReference)instr.Operand).Resolve();
                            if (targetMethod != null)
                            {
                                referencedTypes.Add(targetMethod.DeclaringType);
                            }
                        }
                        else if (instr.Operand is FieldReference)
                        {
                            FieldDefinition targetField = ((FieldReference)instr.Operand).Resolve();
                            if (targetField != null)
                            {
                                referencedTypes.Add(targetField.DeclaringType);
                            }
                        }
                        else if (instr.Operand is TypeReference)
                        {
                            TypeDefinition targetType = ((TypeReference)instr.Operand).Resolve();
                            if (targetType != null)
                            {
                                referencedTypes.Add(targetType);
                            }
                        }
                    }
                }
            }
            for (int i = module.Types.Count-1; i >= 0; i--)
            {
                TypeDefinition tdef = module.Types[i];
                if (tdef.Namespace.Equals("A") && !tdef.IsEnum && !tdef.Name.Equals("AssemblyInfoAttribute"))
                {
                    if (!referencedTypes.Contains(tdef))
                    {
                        module.Types.RemoveAt(i);
                        stat_obfClasses++;
                    }
                }
            }
            logger.KeyInfo("Removed " +
                stat_obfCall + " extracted method calls, " +
                stat_nullField + " always null fields, " +
                stat_duppop + " senseless dup/pop, " +
                stat_obfSwitch + " senseless switches, " +
                stat_obfIf + " senseless conditions, " +
                stat_obfClasses + " obfuscator classes.");
        }
Example #4
0
        public static void Main(string[] args)
        {
            Console.WriteLine("Assembly-CSharp Deobfuscator for 7 Days to Die [by the 7 Days to Die Modding Community]");

            ownFolder = GetContainingFolder(Assembly.GetEntryAssembly().Location);
            if (ownFolder == null)
            {
                ErrorExit("Unable to retrieve the folder containing Deobfuscator!");
            }
            bool verbosity = false;            //(args.Length > 1) ? (args[0].ToLower().Equals("-v")) : false;

            if (File.Exists(ownFolder.path + Path.DirectorySeparatorChar + "config.xml"))
            {
                XmlDocument configDoc = new XmlDocument();
                try {
                    configDoc.Load(ownFolder.path + Path.DirectorySeparatorChar + "config.xml");
                } catch (Exception e) {
                    Console.WriteLine(Logger.Level_ToString(Logger.Level.WARNING) + "Unable to load config.xml : " + e.ToString());
                }
                XmlNodeList configElems = configDoc.DocumentElement.ChildNodes;
                foreach (XmlNode curElem in configElems)
                {
                    if (!curElem.Name.ToLower().Equals("verbosity"))
                    {
                        continue;
                    }
                    XmlNode verbosityElem = curElem;
                    XmlAttributeCollection verbosityAttrs = verbosityElem.Attributes;
                    foreach (XmlNode curAttr in verbosityAttrs)
                    {
                        if (curAttr.Name.ToLower().Equals("enabled"))
                        {
                            verbosity = curAttr.Value.ToLower().Equals("true");
                            break;
                        }
                    }
                }
            }
            else
            {
                Console.WriteLine(ownFolder.path + Path.DirectorySeparatorChar + "config.xml");
            }
            mainLogger = new Logger(ownFolder.path + Path.DirectorySeparatorChar + "mainlog.txt", null, (int)(verbosity ? Logger.Level.INFO : Logger.Level.KEYINFO));
            mainLogger.Info("Started logging to mainlog.txt.");

            if (args.Length == 0 || !args[0].ToLower().EndsWith(".dll"))
            {
                mainLogger.Write("Usage : deobfuscate \"<path to Assembly-CSharp.dll>\"");
                mainLogger.Write("Alternatively, you can drag and drop Assembly-CSharp.dll into deobfuscate.");
                ErrorExit("", 2);
            }
            AssemblyPath acsharpSource = GetContainingFolder(args [0]);

            if (!File.Exists(acsharpSource.path + Path.DirectorySeparatorChar + acsharpSource.filename))
            {
                ErrorExit("Unable to retrieve the folder containing Assembly-CSharp.dll!");
            }
            sourceAssemblyPath = acsharpSource;

            string patchersPath = ownFolder.path + Path.DirectorySeparatorChar + "patchers";

            if (!Directory.Exists(patchersPath))
            {
                Directory.CreateDirectory(patchersPath);
            }
            if (!File.Exists(patchersPath + Path.DirectorySeparatorChar + "patchers.xml"))
            {
                ErrorExit("There are no patches to apply (patchers.xml doesn't exist)! Exiting.", 3);
            }

            XmlDocument patchersDoc = new XmlDocument();

            try {
                patchersDoc.Load(patchersPath + Path.DirectorySeparatorChar + "patchers.xml");
            } catch (Exception e) {
                ErrorExit("Unable to load patchers.xml : " + e.ToString());
            }

            List <PatcherAssembly> assemblies = new List <PatcherAssembly> ();
            XmlNode curNode = patchersDoc.DocumentElement.FirstChild;

            if (curNode != null)
            {
                do
                {
                    assemblies.Add(new PatcherAssembly(curNode));
                } while ((curNode = curNode.NextSibling) != null);
            }
            if (assemblies.Count == 0)
            {
                ErrorExit("There are no patches to apply (none listed in patchers.xml)! Exiting.", 3);
            }

            DefaultAssemblyResolver resolver = new DefaultAssemblyResolver();

            resolver.AddSearchDirectory(acsharpSource.path);

            AssemblyDefinition csharpDef   = null;
            AssemblyDefinition mscorlibDef = null;

            try {
                csharpDef = AssemblyDefinition.ReadAssembly(args [0], new ReaderParameters {
                    AssemblyResolver = resolver
                });
            } catch (Exception e) {
                ErrorExit("Unable to load Assembly-CSharp.dll :" + e.ToString());
            }
            try {
                mscorlibDef = AssemblyDefinition.ReadAssembly(acsharpSource.path + Path.DirectorySeparatorChar + "mscorlib.dll", new ReaderParameters {
                    AssemblyResolver = resolver
                });
            } catch (Exception e) {
                mainLogger.Warning("Unable to load mscorlib.dll :" + e.ToString());
            }
            int csharpFileLen = (int)new FileInfo(args[0]).Length;

            if (csharpDef.Modules.Count == 0)
            {
                ErrorExit("Assembly-CSharp.dll is invalid!");
            }
            ModuleDefinition csharpModule = csharpDef.Modules[0];

            if (csharpModule.GetType("Deobfuscated") != null)
            {
                ErrorExit("Assembly-CSharp already is deobfuscated!");
            }

            mainLogger.KeyInfo("Deobfuscating Assembly-CSharp.dll...");
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(LoadPublicAssembly);
            mainLogger.Write("___");
            foreach (PatcherAssembly curPatcher in assemblies)
            {
                mainLogger.Write();
                mainLogger.Write();

                string patcherName =
                    (curPatcher.assemblyFileName.IndexOf(".") != 0) ? curPatcher.assemblyFileName.Substring(0, curPatcher.assemblyFileName.LastIndexOf(".")) : curPatcher.assemblyFileName;
                string[] authors = new string[] { "the 7 Days to Die Modding Community" };


                Assembly patcherAssembly;
                try {
                    patcherAssembly = Assembly.LoadFrom(patchersPath + Path.DirectorySeparatorChar + patcherName + ".dll");
                } catch (Exception e) {
                    mainLogger.Error("Unable to load the patcher " + patcherName + " :");
                    mainLogger.Error(e.ToString());
                    continue;
                }
                Type       patcherType   = patcherAssembly.GetType(curPatcher.patcherClass);
                MethodInfo getNameMethod = patcherType.GetMethod("getName", new Type[0]);
                if (getNameMethod != null)
                {
                    patcherName = (string)getNameMethod.Invoke(null, new object[0]);
                }
                MethodInfo getAuthorsMethod = patcherType.GetMethod("getAuthors", new Type[0]);
                if (getAuthorsMethod != null)
                {
                    authors = (string[])getAuthorsMethod.Invoke(null, new object[0]);
                }
                MethodInfo patchMethod = patcherType.GetMethod("Patch", new Type[] { typeof(Logger), typeof(AssemblyDefinition), typeof(AssemblyDefinition) });
                if (patchMethod == null)
                {
                    mainLogger.Error("Unable to find the " + curPatcher.patcherClass + ".Patch(Logger,AssemblyDefinition,AssemblyDefinition) method for the patcher " + curPatcher.assemblyFileName + "!");
                    continue;
                }
                string authorsString = "";
                foreach (string curAuthor in authors)
                {
                    if (authorsString.Length > 0)
                    {
                        authorsString += ",";
                    }
                    authorsString += curAuthor;
                }
                mainLogger.KeyInfo("Executing patcher \"" + patcherName + "\" (by " + authorsString + ")...");
                try {
                    Logger curLogger = new Logger(ownFolder.path + Path.DirectorySeparatorChar + "log_" + patcherName + ".txt", null, (int)(verbosity ? Logger.Level.INFO : Logger.Level.KEYINFO));
                    patchMethod.Invoke(null, new object[] { curLogger, csharpDef, null });
                    curLogger.Close();
                } catch (TargetInvocationException e) {
                    mainLogger.Error("ERROR : Invoking the Patch method for " + patcherName + " resulted in an exception :");
                    mainLogger.Error(e.InnerException.ToString());
                } catch (Exception e) {
                    mainLogger.Error("ERROR : An exception occured while trying to invoke the Patch method of " + patcherName + " :");
                    mainLogger.Error(e.ToString());
                }
                mainLogger.Info("Writing the current Assembly-CSharp.dll to a MemoryStream...");
                MemoryStream asmCSharpStream = new MemoryStream(csharpFileLen + 2048 + 1024 * assemblies.Count);
                csharpDef.Write(asmCSharpStream);
                mainLogger.Info("Reading the current Assembly-CSharp.dll from the MemoryStream...");
                asmCSharpStream.Seek(0, SeekOrigin.Begin);
                csharpDef = AssemblyDefinition.ReadAssembly(asmCSharpStream, new ReaderParameters {
                    AssemblyResolver = resolver
                });
                asmCSharpStream.Close();
                csharpModule = csharpDef.Modules[0];
            }
            mainLogger.Write(); mainLogger.Write("___");

            if ((mscorlibDef != null) && (mscorlibDef.Modules.Count > 0))
            {
                csharpModule.Types.Add(new TypeDefinition("", "Deobfuscated",
                                                          Mono.Cecil.TypeAttributes.AutoLayout | Mono.Cecil.TypeAttributes.Public |
                                                          Mono.Cecil.TypeAttributes.AnsiClass | Mono.Cecil.TypeAttributes.BeforeFieldInit, csharpModule.Import(mscorlibDef.Modules[0].GetType("System.Object"))));
            }
            else
            {
                mainLogger.Error("Unable to create the Deobufscated class!");
            }

            string outputPath = acsharpSource.path + Path.DirectorySeparatorChar + "Assembly-CSharp.deobf.dll";

            mainLogger.KeyInfo("Saving the new assembly to " + outputPath + " ...");
            try
            {
                csharpDef.Write(outputPath);
            }
            catch (Exception e)
            {
                ErrorExit("Unable to save the assembly : " + e.ToString());
            }

            ErrorExit("Success.", 0);
        }