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); }
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); }
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; }
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++; } }
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);