public LookupModule Process(TypeModel model, BeebyteDeobfuscatorPlugin plugin)
        {
            PluginServices services = PluginServices.For(plugin);

            services.StatusUpdate("Creating model for Mono dll");
            if (plugin.CompilerType.Value != CppCompilerType.MSVC)
            {
                throw new System.ArgumentException("Cross compiler deobfuscation has not been implemented yet");
            }

            MonoDecompiler.MonoDecompiler monoDecompiler = MonoDecompiler.MonoDecompiler.FromFile(plugin.MonoPath);
            if (monoDecompiler == null)
            {
                throw new System.ArgumentException("Could not load unobfuscated application");
            }

            services.StatusUpdate("Creating LookupModel for obfuscated application");

            LookupModule lookupModel = new LookupModule(plugin.NamingRegex);

            lookupModel.Init(model.ToLookupModel(statusCallback: services.StatusUpdate), LookupModel.FromModuleDef(monoDecompiler.Module, statusCallback: services.StatusUpdate), statusCallback: services.StatusUpdate);
            services.StatusUpdate("Deobfuscating binary");
            lookupModel.TranslateTypes(statusCallback: services.StatusUpdate);

            plugin.CompilerType = null;
            return(lookupModel);
        }
Example #2
0
        public static float CompareFieldTypes(LookupType t1, LookupType t2, LookupModule lookupModel)
        {
            float comparative_score = 1.0f;

            float score_penalty = comparative_score / t1.Fields.Count(f => !f.IsStatic && !f.IsLiteral);

            foreach (var f1 in t1.Fields.Select((Value, Index) => new { Value, Index }))
            {
                LookupField f2 = t2.Fields[f1.Index];
                if (f1.Value.Name == f2.Name)
                {
                    return(1.5f);
                }
                if (!Regex.Match(f1.Value.Name, lookupModel.NamingRegex).Success&& f1.Value.Name != f2.Name)
                {
                    return(0.0f);
                }

                if (f1.Value.IsStatic || f1.Value.IsLiteral)
                {
                    continue;
                }

                if (f1.Value.GetType().Namespace == "System" && f2.GetType().Namespace == "System" && f1.Value.Name == f2.Name)
                {
                    comparative_score -= score_penalty;
                }
            }

            return(comparative_score);
        }
Example #3
0
        public void Generate(BeebyteDeobfuscatorPlugin plugin, LookupModule module)
        {
            using var exportFile = new FileStream(plugin.ExportPath + Path.DirectorySeparatorChar + "translations.txt", FileMode.Create);
            StreamWriter output = new StreamWriter(exportFile);

            foreach (Translation translation in module.Translations.Where(t => t.CleanName != t.ObfName))
            {
                output.WriteLine($"{translation.ObfName}/{translation.CleanName}");
            }
            output.Close();
        }
        public void Generate(BeebyteDeobfuscatorPlugin plugin, LookupModule module)
        {
            List <Translation> translations = module.Translations.Where(t =>
                                                                        t.Type == TranslationType.TypeTranslation &&
                                                                        !Regex.IsMatch(t.CleanName, @"\+<.*(?:>).*__[1-9]{0,4}|[A-z]*=.{1,4}|<.*>") &&
                                                                        !Regex.IsMatch(t.CleanName, module.NamingRegex) &&
                                                                        (t._type?.DeclaringType.IsEmpty ?? false) &&
                                                                        !(t._type?.IsArray ?? false) &&
                                                                        !(t._type?.IsGenericType ?? false) &&
                                                                        !(t._type?.IsNested ?? false) &&
                                                                        !(t._type?.Namespace.Contains("System") ?? false) &&
                                                                        !(t._type?.Namespace.Contains("MS") ?? false)
                                                                        ).ToList();

            List <JsonTypeMapping> mappings = new List <JsonTypeMapping>();

            foreach (Translation translation in translations)
            {
                List <string> KnownTypeTranslations = new List <string>();
                if (translation.CleanName != translation.ObfName)
                {
                    KnownTypeTranslations.Add(translation.ObfName);
                }

                JsonTypeMapping typeMapping = new JsonTypeMapping {
                    Name = translation.CleanName, KnownTranslations = KnownTypeTranslations
                };
                List <JsonFieldMapping> fieldMappings = new List <JsonFieldMapping>();
                foreach (LookupField field in translation._type.Fields)
                {
                    List <string> KnownFieldTranslations = new List <string>();
                    if (field.Translation != null && field.Translation?.CleanName != field.Translation?.ObfName)
                    {
                        KnownFieldTranslations.Add(field.Translation.ObfName);
                    }
                    fieldMappings.Add(new JsonFieldMapping
                    {
                        Name              = field.CSharpName,
                        Type              = field.Type.IsEmpty ? "unknown" : Regex.IsMatch(field.Type.Name, module.NamingRegex) ? "unknown" : field.Type.CSharpName,
                        Offset            = string.Format("0x{0:X}", field.Offset),
                        KnownTranslations = KnownFieldTranslations
                    });
                }
                typeMapping.Fields = fieldMappings;
                mappings.Add(typeMapping);
            }

            using var exportFile = new FileStream(plugin.ExportPath + Path.DirectorySeparatorChar + "mappings.json", FileMode.Create);
            StreamWriter output     = new StreamWriter(exportFile);
            string       jsonString = JsonSerializer.Serialize(mappings);

            output.Write(jsonString);
        }
        public void Generate(BeebyteDeobfuscatorPlugin plugin, LookupModule module)
        {
            JsonTranslations translations = new JsonTranslations
            {
                Types  = module.Translations.Where(t => t.Type == TranslationType.TypeTranslation && t.ObfName != t.CleanName).ToDictionary(t => t.ObfName, t => t.CleanName),
                Fields = module.Translations.Where(t => t.Type == TranslationType.FieldTranslation && t.ObfName != t.CleanName).ToDictionary(t => t.ObfName, t => t.CleanName),
            };

            using var exportFile = new FileStream(plugin.ExportPath + Path.DirectorySeparatorChar + "translations.json", FileMode.Create);
            StreamWriter output     = new StreamWriter(exportFile);
            string       jsonString = JsonSerializer.Serialize(translations);

            output.Write(jsonString);
            output.Close();
        }
        public static void SetName(this LookupField field, string name, LookupModule module)
        {
            string obfName = field.CSharpName;

            if (!Regex.Match(field.Name, module.NamingRegex).Success)
            {
                return;
            }

            if (field.Il2CppField != null)
            {
                field.Il2CppField.Name = name;
            }
            var translation = new Translation(obfName, field);

            module.Translations.Add(translation);
            field.Translation = translation;
        }
Example #7
0
        public LookupModule Process(TypeModel model, BeebyteDeobfuscatorPlugin plugin)
        {
            if (!plugin.CompilerType.HasValue)
            {
                return(null);
            }

            PluginServices services = PluginServices.For(plugin);

            services.StatusUpdate("Loading unobfuscated application");
            var il2cppClean = Il2CppInspector.Il2CppInspector.LoadFromPackage(new[] { plugin.BinaryPath }, statusCallback: services.StatusUpdate);

            if (il2cppClean == null)
            {
                il2cppClean = Il2CppInspector.Il2CppInspector.LoadFromFile(plugin.BinaryPath, plugin.MetadataPath, statusCallback: services.StatusUpdate);
            }

            if (il2cppClean == null)
            {
                throw new System.ArgumentException("Could not load unobfuscated application");
            }

            if (plugin.CompilerType.Value != CppCompiler.GuessFromImage(il2cppClean[0].BinaryImage))
            {
                throw new System.ArgumentException("Cross compiler deobfuscation has not been implemented yet");
            }
            services.StatusUpdate("Creating type model for unobfuscated application");
            var modelClean = new TypeModel(il2cppClean[0]);

            if (modelClean == null)
            {
                throw new System.ArgumentException("Could not create type model for unobfuscated application");
            }

            services.StatusUpdate("Creating LookupModel for obfuscated application");
            LookupModule lookupModel = new LookupModule(plugin.NamingRegex);

            lookupModel.Init(model.ToLookupModel(statusCallback: services.StatusUpdate), modelClean.ToLookupModel(statusCallback: services.StatusUpdate));
            services.StatusUpdate("Deobfuscating binary");
            lookupModel.TranslateTypes(true, statusCallback: services.StatusUpdate);

            plugin.CompilerType = null;
            return(lookupModel);
        }
        public static void Export(BeebyteDeobfuscatorPlugin plugin, LookupModule lookupModule)
        {
            PluginServices services = PluginServices.For(plugin);

            services.StatusUpdate("Generating output..");
            if (!lookupModule.Translations.Any(t => t.CleanName != t.ObfName))
            {
                return;
            }
            List <Translation> filteredTranslations = lookupModule.Translations
                                                      .Where(t => !t.CleanName.EndsWith('&'))
                                                      .GroupBy(t => t.CleanName)
                                                      .Select(t => t.First())
                                                      .GroupBy(t => t.ObfName)
                                                      .Select(t => t.First())
                                                      .ToList();

            lookupModule.Translations.Clear();
            lookupModule.Translations.AddRange(filteredTranslations);

            IGenerator.GetGenerator(plugin).Generate(plugin, lookupModule);
        }
        public static void SetName(this LookupType type, string name, LookupModule module)
        {
            if (!Regex.Match(type.Name, module.NamingRegex).Success&& type.Fields.Any(f => Regex.Match(f.Name, module.NamingRegex).Success))
            {
                var t = new Translation(type.CSharpName, type);
                module.Translations.Add(t);
                type.Translation = t;
                return;
            }

            string obfName = type.CSharpName;

            if (!type.ShouldTranslate(module) || type.IsEnum)
            {
                return;
            }

            type.Il2CppType.Name = name;
            var translation = new Translation(obfName, type);

            module.Translations.Add(translation);
            type.Translation = translation;
        }
        public void Generate(BeebyteDeobfuscatorPlugin plugin, LookupModule module)
        {
            IEnumerable <Translation> translations = module.Translations.Where(t =>
                                                                               t.Type == TranslationType.TypeTranslation &&
                                                                               !Regex.IsMatch(t.CleanName, @"\+<.*(?:>).*__[1-9]{0,4}|[A-z]*=.{1,4}|<.*>") &&
                                                                               !Regex.IsMatch(t.CleanName, module.NamingRegex) &&
                                                                               (t._type?.DeclaringType.IsEmpty ?? false) &&
                                                                               !(t._type?.IsArray ?? false) &&
                                                                               !(t._type?.IsGenericType ?? false) &&
                                                                               !(t._type?.IsNested ?? false) &&
                                                                               !(t._type?.Namespace.Contains("System") ?? false) &&
                                                                               !(t._type?.Namespace.Contains("MS") ?? false)
                                                                               );
            int            current  = 0;
            int            total    = translations.Count();
            PluginServices services = PluginServices.For(plugin);

            foreach (Translation translation in translations)
            {
                services.StatusUpdate(translations, $"Exported {current}/{total} classes");

                FileStream exportFile = null;
                if (!translation.CleanName.Contains("+"))
                {
                    exportFile = new FileStream(plugin.ExportPath +
                                                Path.DirectorySeparatorChar +
                                                $"{Helpers.SanitizeFileName(translation.CleanName)}.cs",
                                                FileMode.Create);
                }
                else
                {
                    if (!File.Exists($"{Helpers.SanitizeFileName(translation.CleanName.Split("+")[0])}.cs"))
                    {
                        continue;
                    }
                    var lines = File.ReadAllLines($"{Helpers.SanitizeFileName(translation.CleanName.Split("+")[0])}.cs");
                    File.WriteAllLines($"{Helpers.SanitizeFileName(translation.CleanName.Split("+")[0])}.cs", lines.Take(lines.Length - 1).ToArray());
                    exportFile = new FileStream(plugin.ExportPath +
                                                Path.DirectorySeparatorChar +
                                                $"{Helpers.SanitizeFileName(translation.CleanName.Split("+")[0])}.cs",
                                                FileMode.Open);
                }

                StreamWriter output = new StreamWriter(exportFile);

                if (!translation.CleanName.Contains("+"))
                {
                    string start = Output.ClassOutputTop;
                    start = start.Replace("#PLUGINNAME#", plugin.PluginName);
                    output.Write(start);
                    output.Write($"    [Translator]\n    public struct {translation.CleanName}\n    {{\n");
                }
                else
                {
                    var names = translation.CleanName.Split("+").ToList();
                    names.RemoveAt(0);
                    output.Write($"    [Translator]\n    public struct {string.Join('.', names)}\n    {{\n");
                }
                foreach (LookupField f in translation._type.Fields)
                {
                    output.WriteLine(f.ToFieldExport());
                }
                output.Write("    }\n}");

                output.Close();
                current++;
            }
        }
Example #11
0
 public static bool ShouldTranslate(this LookupType type, LookupModule module) => Regex.Match(type.Name, module.NamingRegex).Success ||
 type.Fields.Any(f => Regex.Match(f.Name, module.NamingRegex).Success) || type.Fields.Any(f => f.Translated);