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) }); }
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 }
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); }
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); }
public BodyConverter(Delegate del, ModuleExplorer osuModule) : this(del, new MemberConverter(osuModule)) { }
public MemberConverter(ModuleExplorer moduleExplorer) =>
public MethodConverter(Delegate del, ModuleExplorer osuModule, bool hasThis = false) : this(del, new MemberConverter(osuModule), hasThis) { }
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(); }