public static void RelinkModule(string from, string toName) { MonoModder self = Modder; from = from.Inject(MonoModExt.SharedData); toName = toName.Inject(MonoModExt.SharedData); bool retrying = false; ModuleDefinition to = null; RETRY: if (toName + ".dll" == self.Module.Name) { to = self.Module; } else if (self.DependencyCache.TryGetValue(toName, out to)) { } else if (!retrying) { self.MapDependency(self.Module, toName); retrying = true; goto RETRY; } if (to != null) { self.Log($"[MonoModRules] RelinkModule: {from} -> {toName}"); self.RelinkModuleMap[from] = to; } }
public HookGenerator(MonoModder modder, string name) { Modder = modder; OutputModule = ModuleDefinition.CreateModule(name, new ModuleParameters { Architecture = modder.Module.Architecture, AssemblyResolver = modder.Module.AssemblyResolver, Kind = ModuleKind.Dll, Runtime = modder.Module.Runtime }); Namespace = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_NAMESPACE"); if (string.IsNullOrEmpty(Namespace)) { Namespace = "On"; } HookOrig = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_ORIG") == "1"; HookPrivate = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_PRIVATE") == "1"; modder.MapDependency(modder.Module, "MonoMod.RuntimeDetour"); if (!modder.DependencyCache.TryGetValue("MonoMod.RuntimeDetour", out md_RuntimeDetour)) { throw new FileNotFoundException("MonoMod.RuntimeDetour not found!"); } t_MulticastDelegate = OutputModule.ImportReference(modder.FindType("System.MulticastDelegate")); t_IAsyncResult = OutputModule.ImportReference(modder.FindType("System.IAsyncResult")); t_AsyncCallback = OutputModule.ImportReference(modder.FindType("System.AsyncCallback")); t_MethodBase = OutputModule.ImportReference(modder.FindType("System.Reflection.MethodBase")); t_RuntimeMethodHandle = OutputModule.ImportReference(modder.FindType("System.RuntimeMethodHandle")); TypeDefinition td_HookManager = md_RuntimeDetour.GetType("MonoMod.RuntimeDetour.HookManager"); t_HookManager = OutputModule.ImportReference(td_HookManager); m_GetMethodFromHandle = OutputModule.ImportReference( new MethodReference("GetMethodFromHandle", t_MethodBase, t_MethodBase) { Parameters = { new ParameterDefinition(t_RuntimeMethodHandle) } } ); m_Add = OutputModule.ImportReference(td_HookManager.FindMethod("Add")); m_Remove = OutputModule.ImportReference(td_HookManager.FindMethod("Remove")); }
/// <summary> /// Relink a .dll to point towards Celeste.exe and FNA / XNA properly at runtime, then load it. /// </summary> /// <param name="meta">The mod metadata, used for caching, among other things.</param> /// <param name="stream">The stream to read the .dll from.</param> /// <param name="depResolver">An optional dependency resolver.</param> /// <param name="checksumsExtra">Any optional checksums. If you're running this at runtime, pass at least Everest.Relinker.GetChecksum(Metadata)</param> /// <param name="prePatch">An optional step executed before patching, but after MonoMod has loaded the input assembly.</param> /// <returns>The loaded, relinked assembly.</returns> public static Assembly GetRelinkedAssembly(EverestModuleMetadata meta, Stream stream, MissingDependencyResolver depResolver = null, string[] checksumsExtra = null, Action <MonoModder> prePatch = null) { if (!Flags.SupportRelinkingMods) { Logger.Log(LogLevel.Warn, "relinker", "Relinker disabled!"); return(null); } string cachedPath = GetCachedPath(meta); string cachedChecksumPath = cachedPath.Substring(0, cachedPath.Length - 4) + ".sum"; string[] checksums = new string[2 + (checksumsExtra?.Length ?? 0)]; if (GameChecksum == null) { GameChecksum = Everest.GetChecksum(Assembly.GetAssembly(typeof(Relinker)).Location).ToHexadecimalString(); } checksums[0] = GameChecksum; checksums[1] = Everest.GetChecksum(meta).ToHexadecimalString(); if (checksumsExtra != null) { for (int i = 0; i < checksumsExtra.Length; i++) { checksums[i + 2] = checksumsExtra[i]; } } if (File.Exists(cachedPath) && File.Exists(cachedChecksumPath) && ChecksumsEqual(checksums, File.ReadAllLines(cachedChecksumPath))) { Logger.Log(LogLevel.Verbose, "relinker", $"Loading cached assembly for {meta}"); try { return(Assembly.LoadFrom(cachedPath)); } catch (Exception e) { Logger.Log(LogLevel.Warn, "relinker", $"Failed loading {meta}"); e.LogDetailed(); return(null); } } if (depResolver == null) { depResolver = GenerateModDependencyResolver(meta); } try { MonoModder modder = Modder; modder.Input = stream; modder.OutputPath = cachedPath; modder.MissingDependencyResolver = depResolver; string symbolPath; modder.ReaderParameters.SymbolStream = OpenStream(meta, out symbolPath, meta.DLL.Substring(0, meta.DLL.Length - 4) + ".pdb", meta.DLL + ".mdb"); modder.ReaderParameters.ReadSymbols = modder.ReaderParameters.SymbolStream != null; if (modder.ReaderParameters.SymbolReaderProvider != null && modder.ReaderParameters.SymbolReaderProvider is RelinkerSymbolReaderProvider) { ((RelinkerSymbolReaderProvider)modder.ReaderParameters.SymbolReaderProvider).Format = string.IsNullOrEmpty(symbolPath) ? DebugSymbolFormat.Auto : symbolPath.EndsWith(".mdb") ? DebugSymbolFormat.MDB : symbolPath.EndsWith(".pdb") ? DebugSymbolFormat.PDB : DebugSymbolFormat.Auto; } modder.Read(); modder.ReaderParameters.ReadSymbols = false; if (modder.ReaderParameters.SymbolReaderProvider != null && modder.ReaderParameters.SymbolReaderProvider is RelinkerSymbolReaderProvider) { ((RelinkerSymbolReaderProvider)modder.ReaderParameters.SymbolReaderProvider).Format = DebugSymbolFormat.Auto; } modder.MapDependencies(); if (!RuntimeRulesParsed) { RuntimeRulesParsed = true; InitMMSharedData(); string rulesPath = Path.Combine( Path.GetDirectoryName(typeof(Celeste).Assembly.Location), Path.GetFileNameWithoutExtension(typeof(Celeste).Assembly.Location) + ".Mod.mm.dll" ); if (!File.Exists(rulesPath)) { // Fallback if someone renamed Celeste.exe rulesPath = Path.Combine( Path.GetDirectoryName(typeof(Celeste).Assembly.Location), "Celeste.Mod.mm.dll" ); } if (File.Exists(rulesPath)) { ModuleDefinition rules = ModuleDefinition.ReadModule(rulesPath, new ReaderParameters(ReadingMode.Immediate)); modder.ParseRules(rules); rules.Dispose(); // Is this safe? } // Fix old mods built against HookIL instead of ILContext. _Modder.RelinkMap["MonoMod.RuntimeDetour.HookGen.ILManipulator"] = "MonoMod.Cil.ILContext/Manipulator"; _Modder.RelinkMap["MonoMod.RuntimeDetour.HookGen.HookIL"] = "MonoMod.Cil.ILContext"; _Modder.RelinkMap["MonoMod.RuntimeDetour.HookGen.HookILCursor"] = "MonoMod.Cil.ILCursor"; _Modder.RelinkMap["MonoMod.RuntimeDetour.HookGen.HookILLabel"] = "MonoMod.Cil.ILLabel"; _Modder.RelinkMap["MonoMod.RuntimeDetour.HookGen.HookExtensions"] = "MonoMod.Cil.ILPatternMatchingExt"; _Shim("MonoMod.Utils.ReflectionHelper", typeof(MonoModUpdateShim._ReflectionHelper)); _Shim("MonoMod.Cil.ILCursor", typeof(MonoModUpdateShim._ILCursor)); // If no entry for MonoMod.Utils exists already, add one. modder.MapDependency(_Modder.Module, "MonoMod.Utils"); } prePatch?.Invoke(modder); modder.AutoPatch(); modder.Write(); } catch (Exception e) { Logger.Log(LogLevel.Warn, "relinker", $"Failed relinking {meta}"); e.LogDetailed(); return(null); } finally { Modder.ClearCaches(moduleSpecific: true); Modder.Module.Dispose(); Modder.Module = null; Modder.ReaderParameters.SymbolStream?.Dispose(); } if (File.Exists(cachedChecksumPath)) { File.Delete(cachedChecksumPath); } File.WriteAllLines(cachedChecksumPath, checksums); Logger.Log(LogLevel.Verbose, "relinker", $"Loading assembly for {meta}"); try { return(Assembly.LoadFrom(cachedPath)); } catch (Exception e) { Logger.Log(LogLevel.Warn, "relinker", $"Failed loading {meta}"); e.LogDetailed(); return(null); } }
public HookGenerator(MonoModder modder, string name) { Modder = modder; OutputModule = ModuleDefinition.CreateModule(name, new ModuleParameters { Architecture = modder.Module.Architecture, AssemblyResolver = modder.Module.AssemblyResolver, Kind = ModuleKind.Dll, Runtime = modder.Module.Runtime }); // Copy all assembly references from the input module. // Cecil + .NET Standard libraries + .NET 5.0 = weirdness. modder.MapDependencies(); OutputModule.AssemblyReferences.AddRange(modder.Module.AssemblyReferences); modder.DependencyMap[OutputModule] = new List <ModuleDefinition>(modder.DependencyMap[modder.Module]); Namespace = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_NAMESPACE"); if (string.IsNullOrEmpty(Namespace)) { Namespace = "On"; } NamespaceIL = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_NAMESPACE_IL"); if (string.IsNullOrEmpty(NamespaceIL)) { NamespaceIL = "IL"; } HookOrig = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_ORIG") == "1"; HookPrivate = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_PRIVATE") == "1"; modder.MapDependency(modder.Module, "MonoMod.RuntimeDetour"); if (!modder.DependencyCache.TryGetValue("MonoMod.RuntimeDetour", out module_RuntimeDetour)) { throw new FileNotFoundException("MonoMod.RuntimeDetour not found!"); } modder.MapDependency(modder.Module, "MonoMod.Utils"); if (!modder.DependencyCache.TryGetValue("MonoMod.Utils", out module_Utils)) { throw new FileNotFoundException("MonoMod.Utils not found!"); } t_MulticastDelegate = OutputModule.ImportReference(modder.FindType("System.MulticastDelegate")); t_IAsyncResult = OutputModule.ImportReference(modder.FindType("System.IAsyncResult")); t_AsyncCallback = OutputModule.ImportReference(modder.FindType("System.AsyncCallback")); t_MethodBase = OutputModule.ImportReference(modder.FindType("System.Reflection.MethodBase")); t_RuntimeMethodHandle = OutputModule.ImportReference(modder.FindType("System.RuntimeMethodHandle")); t_EditorBrowsableState = OutputModule.ImportReference(modder.FindType("System.ComponentModel.EditorBrowsableState")); TypeDefinition td_HookEndpointManager = module_RuntimeDetour.GetType("MonoMod.RuntimeDetour.HookGen.HookEndpointManager"); t_ILManipulator = OutputModule.ImportReference( module_Utils.GetType("MonoMod.Cil.ILContext/Manipulator") ); m_Object_ctor = OutputModule.ImportReference(modder.FindType("System.Object").Resolve().FindMethod("System.Void .ctor()")); m_ObsoleteAttribute_ctor = OutputModule.ImportReference(modder.FindType("System.ObsoleteAttribute").Resolve().FindMethod("System.Void .ctor(System.String,System.Boolean)")); m_EditorBrowsableAttribute_ctor = OutputModule.ImportReference(modder.FindType("System.ComponentModel.EditorBrowsableAttribute").Resolve().FindMethod("System.Void .ctor(System.ComponentModel.EditorBrowsableState)")); m_GetMethodFromHandle = OutputModule.ImportReference( new MethodReference("GetMethodFromHandle", t_MethodBase, t_MethodBase) { Parameters = { new ParameterDefinition(t_RuntimeMethodHandle) } } ); m_Add = OutputModule.ImportReference(td_HookEndpointManager.FindMethod("Add")); m_Remove = OutputModule.ImportReference(td_HookEndpointManager.FindMethod("Remove")); m_Modify = OutputModule.ImportReference(td_HookEndpointManager.FindMethod("Modify")); m_Unmodify = OutputModule.ImportReference(td_HookEndpointManager.FindMethod("Unmodify")); }
public HookGenerator(MonoModder modder, string name) { Modder = modder; OutputModule = ModuleDefinition.CreateModule(name, new ModuleParameters { Architecture = modder.Module.Architecture, AssemblyResolver = modder.Module.AssemblyResolver, Kind = ModuleKind.Dll, Runtime = modder.Module.Runtime }); RDRefHide = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_RDREF_HIDE") == "1"; Namespace = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_NAMESPACE"); if (string.IsNullOrEmpty(Namespace)) { Namespace = "On"; } NamespaceIL = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_NAMESPACE_IL"); if (string.IsNullOrEmpty(NamespaceIL)) { NamespaceIL = "IL"; } HookOrig = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_ORIG") == "1"; HookPrivate = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_PRIVATE") == "1"; HookExtName = Environment.GetEnvironmentVariable("MONOMOD_HOOKGEN_EXTENSIONS"); if (string.IsNullOrEmpty(HookExtName)) { HookExtName = $"ːHookExtensionsː{NameVerifyRegex.Replace(modder.Module.Assembly.Name.Name, "_")}"; } modder.MapDependency(modder.Module, "MonoMod.RuntimeDetour"); if (!modder.DependencyCache.TryGetValue("MonoMod.RuntimeDetour", out module_RuntimeDetour)) { throw new FileNotFoundException("MonoMod.RuntimeDetour not found!"); } t_MulticastDelegate = OutputModule.ImportReference(modder.FindType("System.MulticastDelegate")); t_IAsyncResult = OutputModule.ImportReference(modder.FindType("System.IAsyncResult")); t_AsyncCallback = OutputModule.ImportReference(modder.FindType("System.AsyncCallback")); t_MethodBase = OutputModule.ImportReference(modder.FindType("System.Reflection.MethodBase")); t_RuntimeMethodHandle = OutputModule.ImportReference(modder.FindType("System.RuntimeMethodHandle")); t_EditorBrowsableState = OutputModule.ImportReference(modder.FindType("System.ComponentModel.EditorBrowsableState")); TypeDefinition td_HookEndpointManager = module_RuntimeDetour.GetType("MonoMod.RuntimeDetour.HookGen.HookEndpointManager"); td_HookExtensions = module_RuntimeDetour.GetType("MonoMod.RuntimeDetour.HookGen.HookExtensions"); t_HookExtensions = OutputModule.ImportReference(td_HookExtensions); t_HookEndpointManager = OutputModule.ImportReference(td_HookEndpointManager); t_HookEndpointManager = OutputModule.ImportReference(module_RuntimeDetour.GetType("MonoMod.RuntimeDetour.HookGen.HookIL")); t_ILManipulator = OutputModule.ImportReference(module_RuntimeDetour.GetType("MonoMod.RuntimeDetour.HookGen.ILManipulator")); m_Object_ctor = OutputModule.ImportReference(modder.FindType("System.Object").Resolve().FindMethod("System.Void .ctor()")); m_ObsoleteAttribute_ctor = OutputModule.ImportReference(modder.FindType("System.ObsoleteAttribute").Resolve().FindMethod("System.Void .ctor(System.String,System.Boolean)")); m_EditorBrowsableAttribute_ctor = OutputModule.ImportReference(modder.FindType("System.ComponentModel.EditorBrowsableAttribute").Resolve().FindMethod("System.Void .ctor(System.ComponentModel.EditorBrowsableState)")); m_GetMethodFromHandle = OutputModule.ImportReference( new MethodReference("GetMethodFromHandle", t_MethodBase, t_MethodBase) { Parameters = { new ParameterDefinition(t_RuntimeMethodHandle) } } ); m_Add = OutputModule.ImportReference(td_HookEndpointManager.FindMethod("Add")); m_Remove = OutputModule.ImportReference(td_HookEndpointManager.FindMethod("Remove")); m_Modify = OutputModule.ImportReference(td_HookEndpointManager.FindMethod("Modify")); m_Unmodify = OutputModule.ImportReference(td_HookEndpointManager.FindMethod("Unmodify")); }