Пример #1
0
        private static IList <Instruction> AsukiPatch_UniversalizeOsuURL(ModuleExplorer exp, string str, FieldDef baseUrlField, string baseUrl = OSU_BASE_URL)
        {
            var parts = str.Split(new[] { baseUrl }, StringSplitOptions.None);

            if (parts.Length == 2)
            {
                var sb = new IlStringBuilder(exp.Module);

                if (!String.IsNullOrEmpty(parts[0]))
                {
                    sb.Add(parts[0]);
                }

                sb.Add(Instruction.Create(OpCodes.Ldsfld, baseUrlField));

                if (!String.IsNullOrEmpty(parts[1]))
                {
                    sb.Add(parts[1]);
                }

                return(sb.Instructions);
            }

            return(new List <Instruction> {
                Instruction.Create(OpCodes.Ldstr, str)
            });
        }
Пример #2
0
        public PatchResult Execute(ModuleExplorer exp)
        {
            if (!Enabled)
            {
                return(Result(PatchStatus.Disabled));
            }

#if DEBUG
            return(_patchMethod(this, exp));
#else
            try
            {
                return(_patchMethod(this, exp));
            }
            catch (Exception ex)
            {
                return(Result(PatchStatus.Exception, ex: ex));
            }
#endif
        }
Пример #3
0
        private static IList <Instruction> AsukiPatch_CreateServersArrayInitializer(ModuleExplorer exp, IList <string> addrList)
        {
            var ret = new List <Instruction>();

            ret.AddRange(new[]
            {
                Instruction.CreateLdcI4(addrList.Count),
                Instruction.Create(OpCodes.Newarr, exp.Module.CorLibTypes.String)
            });

            for (int i = 0; i < addrList.Count; i++)
            {
                ret.AddRange(new[]
                {
                    Instruction.Create(OpCodes.Dup),
                    Instruction.CreateLdcI4(i),
                    Instruction.Create(OpCodes.Ldstr, addrList[i]),
                    Instruction.Create(OpCodes.Stelem_Ref)
                });
            }

            return(ret);
        }
Пример #4
0
        public static int Main(string[] args)
        {
            // Console.ReadKey(true);

            if (args.Length < 2)
            {
                return(Exit("osu!patch - osu! assembly patcher based on NameMapper\n" +
                            "by exys, 2019 - 2020\n" +
                            "modded by Aoba Suzukaze, 2020\n" +
                            "\n" +
                            "Usage:\n" +
                            "osu!patch [clean module] [obfuscated module]"));
            }

            if (!File.Exists(_cleanOsuPath = Path.GetFullPath(args[0])))
            {
                return(XConsole.PrintFatal("Specified clean module path does not exist!\n"));
            }

            if (!File.Exists(_obfOsuPath = Path.GetFullPath(args[1])))
            {
                return(XConsole.PrintFatal("Specified obfuscated module path does not exist!\n"));
            }

            try
            {
                _obfOsuModule   = ModuleDefMD.Load(_obfOsuPath);
                _cleanOsuModule = ModuleDefMD.Load(_cleanOsuPath);

                _obfOsuAssembly = Assembly.LoadFile(_obfOsuPath);
            }
            catch (Exception ex) { return(XConsole.PrintFatal("Unable to load one of the modules! Details:\n" + ex)); }

            ObfOsuHash = MD5Helper.Compute(_obfOsuPath);             // ORIGINAL!!!!!!! hash, PLEASE PASS UNMODIFIED PEPPY-SIGNED ASSEMBLY AS _obfOsuModule!@!!32R1234 (refer to "Patch on update" patch)

            XConsole.PrintInfo($"Loaded assemblies: {_cleanOsuModule.Assembly.FullName} (clean); {_obfOsuModule.Assembly.FullName} (obfuscated).");
            XConsole.PrintInfo("MD5 hash of obfuscated assembly: " + ObfOsuHash);

            try
            {
                LoadPlugins();                 // Loading plugins
            }
            catch (Exception ex) { return(XConsole.PrintFatal("Something really bad happened while trying to process plugins! Details:\n" + ex)); }

            try
            {
                XConsole.PrintInfo("Cleaning control flow of obfuscated assembly");
                CleanControlFlow();
            }
            catch (Exception ex) { return(XConsole.PrintFatal("Unable to deobfuscate control flow of obfuscated assembly! Details:\n" + ex)); }

            try
            {
                XConsole.PrintInfo("Fixing strings in obfuscated assembly.");
                StringFixer.Fix(_obfOsuModule, _obfOsuAssembly);                 // Fixing strings
            }
            catch (Exception ex) { return(XConsole.PrintFatal("Unable to fix strings of obfuscated assembly! Details:\n" + ex)); }

            if (!Directory.Exists(CacheFolderLocation))
            {
                XConsole.PrintInfo("Creating cache folder...");
                Directory.CreateDirectory(CacheFolderLocation);
            }

            try
            {
                var nameProvider = InitializeNameProvider();                 // Fixing names (SimpleNameProvider/MapperNameProvider)
                _obfOsuExplorer = new ModuleExplorer(_obfOsuModule, nameProvider);
            }
            catch (Exception ex) { return(XConsole.PrintFatal("Unable to get clean names for obfuscated assembly! Details:\n" + ex)); }

#if DEBUG
            _obfOsuModule.Write(Path.Combine(Path.GetDirectoryName(_obfOsuPath), "OsuObfModule-cflow-string-nmapped.exe"), new ModuleWriterOptions(_obfOsuModule)
            {
                MetadataOptions = { Flags = DEFAULT_METADATA_FLAGS }
            });
#endif

            XConsole.PrintInfo("Done! Now patching.");

            bool overallSuccess = true;

            var failedDetails = new List <PatchResult>();

            void ExecutePatchCli(Patch patch)
            {
                XConsole.PrintInfo($"{patch.Name}: ", false);

                if (File.Exists(ConfigFileLocation))                 // incase if config file not initialized
                {
                    patch.Enabled = GetConfigEnabled(patch.Name);
                }

                PatchResult res = patch.Execute(_obfOsuExplorer);

                switch (res.Result)
                {
                case PatchStatus.Disabled:
                    Console.ForegroundColor = ConsoleColor.Gray;
                    XConsole.WriteLine("DISABLED");
                    break;

                case PatchStatus.Exception:
                case PatchStatus.Failure:
                    Console.ForegroundColor = ConsoleColor.Red;
                    XConsole.WriteLine("FAIL");
                    failedDetails.Add(res);
                    overallSuccess = false;
                    break;

                case PatchStatus.Success:
                    Console.ForegroundColor = ConsoleColor.Green;
                    XConsole.WriteLine("DONE");
                    break;

                default:
                    Console.ForegroundColor = ConsoleColor.DarkGray;
                    XConsole.WriteLine("[???]");
                    break;
                }

                Console.ResetColor();
            }

            // Executing local patches.
            foreach (var patch in LocalPatches.PatchList)
            {
                ExecutePatchCli(patch);
            }

            XConsole.PrintInfo("Done processing all local patches! Now processing patches from loaded add-ons...");

#if !CORE_PATCHES_ONLY
            // Executing all patches from all loaded plugins from all loaded assemblies (what a hierarchy)
            foreach (var plugin in _loadedPlugins)
            {
                XConsole.PrintInfo($"{plugin.AssemblyName}: Processing plugin: {plugin.TypeName}.");

                foreach (var patch in plugin.Type.GetPatches())
                {
                    ExecutePatchCli(patch);
                }

                XConsole.PrintInfo($"{plugin.AssemblyName}: Done processing: {plugin.TypeName}.");
            }
#endif
            if (!File.Exists(ConfigFileLocation))
            {
                XConsole.PrintInfo("Creating config file...");
                var configLines = string.Empty;

                foreach (var patch in Patches)
                {
                    configLines += patch.Name + " = " + "Enabled\n";                     // probably bad implementation of config but simplest i can imagine
                }
                File.WriteAllText(ConfigFileLocation, configLines);
                XConsole.PrintInfo("Config file created!");
            }

            XConsole.PrintInfo("Done processing all plugins.");

            if (failedDetails.Any())
            {
                XConsole.PrintInfo("There's some details about failed patches.");

                foreach (var details in failedDetails)
                {
                    details.PrintDetails(Console.Out);
                    XConsole.WriteLine();
                }
            }

            if (!overallSuccess)
            {
                XConsole.PrintInfo("There are some failed patches. Do you want to continue?");
                XConsole.PrintWarn("In case of self-update pressing 'N' will leave stock version of osu! without patching it!");
                XConsole.Write(XConsole.PAD + "Continue? (y/n) ");

                var exit = false;

                while (true)
                {
                    var key = Console.ReadKey(true).Key;

                    if (key == ConsoleKey.Y)
                    {
                        break;
                    }

                    if (key == ConsoleKey.N)
                    {
                        exit = true;
                        break;
                    }
                }

                XConsole.WriteLine();

                if (exit)
                {
                    return(Exit(XConsole.Info("Aborted by user.")));
                }
            }

            //string filename = Path.GetFileNameWithoutExtension(_obfOsuPath) + "-osupatch" + Path.GetExtension(_obfOsuPath);
            string filename = "ainu.exe";

            XConsole.PrintInfo($"Saving assembly as {filename}");

            try
            {
                _obfOsuModule.Write(Path.Combine(Path.GetDirectoryName(_obfOsuPath), filename), new ModuleWriterOptions(_obfOsuModule)
                {
                    MetadataOptions = { Flags = DEFAULT_METADATA_FLAGS }
                });
            }
            catch (Exception ex) { return(Exit(XConsole.Fatal("Unable to save patched assembly! Details:\n" + ex))); }

            _cleanOsuModule.Dispose();
            _obfOsuModule.Dispose();

#if DEBUG
            Console.ReadKey(true);
#endif

#if LIVE_DEBUG
            Process.Start(new ProcessStartInfo
            {
                FileName         = "cmd",
                Arguments        = "/c timeout /T 1 /NOBREAK & move /Y \"osu!-osupatch.exe\" \"osu!.exe\"",
                WorkingDirectory = Environment.CurrentDirectory,
                WindowStyle      = ProcessWindowStyle.Hidden,
                CreateNoWindow   = true,
                UseShellExecute  = false
            });
#endif

            return(overallSuccess ? 0 : 1);
        }
Пример #5
0
 public BodyConverter(Delegate del, ModuleExplorer osuModule) : this(del, new MemberConverter(osuModule))
 {
 }
Пример #6
0
 public MemberConverter(ModuleExplorer moduleExplorer) =>
Пример #7
0
 public MethodConverter(Delegate del, ModuleExplorer osuModule, bool hasThis = false) : this(del, new MemberConverter(osuModule), hasThis)
 {
 }
Пример #8
0
        private static void Initialize()
        {
            var lines = File.ReadAllLines(_osuPath);

            OsuPath         = lines[0];
            _osuHash        = MD5Helper.ComputeFile(OsuPath);
            OsuAssembly     = Assembly.LoadFrom(OsuPath);
            _obfOsuModule   = ModuleDefMD.Load(OsuPath);
            _cleanOsuModule = ModuleDefMD.Load(Resource.clean);

            StringFixer.Fix(_obfOsuModule, OsuAssembly); // Fix troubles when NameMapper can't find name due to unsimilar opcodes.

            _nameStorage = InitializeNameMapper();

            _config = new RConfig();

            exp = new ModuleExplorer(_obfOsuModule, _nameStorage);

            if (_config.Profiles == string.Empty)
            {
                // hacky thing because cant read json array when we have only one object so we add two objects, maybe there's a way to do it in other way?
                var profiles = new List <Profile>();

                profiles.Add(new Profile()
                {
                    Name        = "Default",
                    UniqueId    = GetRandomUniqueString(),
                    UninstallID = Guid.NewGuid().ToString(),
                    Adapters    = GetRandomMacAddress()
                });
                profiles.Add(new Profile()
                {
                    Name        = "Default2",
                    UniqueId    = GetRandomUniqueString(),
                    UninstallID = Guid.NewGuid().ToString(),
                    Adapters    = GetRandomMacAddress()
                });

                _config.Profiles        = JsonConvert.SerializeObject(profiles);
                _config.SelectedProfile = "Default";
            }
            Console.WriteLine("       --- Select Profile or use current one ---       \n");
            Console.WriteLine("--- 1) Select");
            Console.WriteLine("--- 2) Use current one");
            var key = Console.ReadKey(false).Key;

            Console.Clear();
            switch (key)
            {
            case ConsoleKey.D1:
                var profiles = JsonConvert.DeserializeObject <List <Profile> >(_config.Profiles);
                for (var i = 0; i < profiles.Count; i++)
                {
                    Console.WriteLine($"{i + 1}) {profiles[i].Name}");
                }
                Console.WriteLine("Select one of them or press SPACE to generate new one.");
                var _key = Console.ReadKey(false).Key;

                // TODO: Add support for selecting profiles count more than 9
                if (!(_key == ConsoleKey.Spacebar) && _key >= ConsoleKey.D1 && _key <= ConsoleKey.D9)
                {
                    var number = Convert.ToInt32(_key.ToString().Replace("D", ""));
                    Console.Clear();
                    _config.SelectedProfile = profiles[number - 1].Name;
                    Console.WriteLine("Selected Profile: " + _config.SelectedProfile);
                    Thread.Sleep(2000);
                    Console.Clear();
                }
                else if (_key == ConsoleKey.Spacebar)
                {
                    Console.Clear();
                    Console.WriteLine("       --- Generation Process ---       ");
                    Console.Write("Please type name of profile: ");
                    var profileName = Console.ReadLine();
                    Console.WriteLine("Started generating profile.");
                    profiles.Add(new Profile()
                    {
                        Name        = profileName,
                        UniqueId    = GetRandomUniqueString(),
                        UninstallID = Guid.NewGuid().ToString(),
                        Adapters    = GetRandomMacAddress()
                    });
                    _config.Profiles        = JsonConvert.SerializeObject(profiles);
                    _config.SelectedProfile = profileName;
                    Console.Clear();
                    Console.WriteLine("Done!\n");
                    Console.WriteLine($"UniqueId: {_config.CurrentProfile.UniqueId}\nUninstallID: {_config.CurrentProfile.UninstallID}\nMAC Address: {_config.CurrentProfile.Adapters}\n");
                    Thread.Sleep(2000);
                    Console.Clear();
                }
                break;

            case ConsoleKey.D2:
                break;
            }
            Patch();
        }