mirror of
https://github.com/BepInEx/BepInEx.git
synced 2026-10-19 15:51:45 +00:00
Use process name for preloader assembly dump path; fixes #303
This commit is contained in:
1 parent
c85ece09fe
commit
b219c162de
2 files changed
+78
-51
No files matched your search
@@ -20,12 +20,14 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
/// </summary>
|
||||
public class AssemblyPatcher : IDisposable
|
||||
{
|
||||
private static readonly string CurrentAssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
|
||||
|
||||
/// <summary>
|
||||
/// The context of this assembly patcher instance that is passed to all patcher plugins.
|
||||
/// </summary>
|
||||
public PatcherContext PatcherContext { get; } = new()
|
||||
{
|
||||
DumpedAssembliesPath = Path.Combine(Paths.BepInExRootPath, "DumpedAssemblies")
|
||||
DumpedAssembliesPath = Utility.CombinePaths(Paths.BepInExRootPath, "DumpedAssemblies", Paths.ProcessName)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -36,6 +38,8 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
|
||||
private ManualLogSource Logger { get; } = BepInEx.Logging.Logger.CreateLogSource("AssemblyPatcher");
|
||||
|
||||
private static Regex allowedGuidRegex { get; } = new(@"^[a-zA-Z0-9\._\-]+$");
|
||||
|
||||
/// <summary>
|
||||
/// Performs work to dispose collection objects.
|
||||
/// </summary>
|
||||
@@ -50,7 +54,6 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
PatcherContext.PatcherPlugins.Clear();
|
||||
}
|
||||
|
||||
private static Regex allowedGuidRegex { get; } = new(@"^[a-zA-Z0-9\._\-]+$");
|
||||
private PatcherPluginMetadata ToPatcherPlugin(TypeDefinition type, string assemblyPath)
|
||||
{
|
||||
if (type.IsInterface || type.IsAbstract && !type.IsSealed)
|
||||
@@ -100,10 +103,10 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
};
|
||||
}
|
||||
|
||||
private static readonly string CurrentAssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
|
||||
private bool HasPatcherPlugins(AssemblyDefinition ass)
|
||||
{
|
||||
if (ass.MainModule.AssemblyReferences.All(r => r.Name != CurrentAssemblyName) && ass.Name.Name != CurrentAssemblyName)
|
||||
if (ass.MainModule.AssemblyReferences.All(r => r.Name != CurrentAssemblyName) &&
|
||||
ass.Name.Name != CurrentAssemblyName)
|
||||
return false;
|
||||
if (ass.MainModule.GetTypeReferences().All(r => r.FullName != typeof(BasePatcher).FullName))
|
||||
return false;
|
||||
@@ -146,7 +149,8 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
|
||||
PatcherContext.PatcherPlugins.Add(instance);
|
||||
|
||||
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var methods =
|
||||
type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
@@ -155,24 +159,28 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
|
||||
if (targetAssemblies.Length == 0 && targetTypes.Length == 0)
|
||||
continue;
|
||||
|
||||
|
||||
var parameters = method.GetParameters();
|
||||
|
||||
if (parameters.Length < 1 || parameters.Length > 2
|
||||
// Next few lines ensure that the first parameter is AssemblyDefinition and does not have any
|
||||
// target type attributes, and vice versa
|
||||
|| !(
|
||||
(parameters[0].ParameterType == typeof(AssemblyDefinition)
|
||||
|| parameters[0].ParameterType == typeof(AssemblyDefinition).MakeByRefType()
|
||||
&& targetTypes.Length == 0)
|
||||
|| (parameters[0].ParameterType == typeof(TypeDefinition)
|
||||
&& targetAssemblies.Length == 0)
|
||||
)
|
||||
|| (parameters.Length == 2 && parameters[1].ParameterType != typeof(string))
|
||||
|| (method.ReturnType != typeof(void) && method.ReturnType != typeof(bool))
|
||||
// Next few lines ensure that the first parameter is AssemblyDefinition and does not have any
|
||||
// target type attributes, and vice versa
|
||||
|| !(
|
||||
(parameters[0].ParameterType == typeof(AssemblyDefinition)
|
||||
|| parameters[0].ParameterType ==
|
||||
typeof(AssemblyDefinition).MakeByRefType()
|
||||
&& targetTypes.Length == 0)
|
||||
|| (parameters[0].ParameterType == typeof(TypeDefinition)
|
||||
&& targetAssemblies.Length == 0)
|
||||
)
|
||||
|| (parameters.Length == 2 &&
|
||||
parameters[1].ParameterType != typeof(string))
|
||||
|| (method.ReturnType != typeof(void) &&
|
||||
method.ReturnType != typeof(bool))
|
||||
)
|
||||
{
|
||||
Logger.LogWarning($"Skipping method [{method.FullDescription()}] as it is not a valid patcher method");
|
||||
Logger
|
||||
.LogWarning($"Skipping method [{method.FullDescription()}] as it is not a valid patcher method");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -231,7 +239,8 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
// It's also generally dangerous to change system.dll since so many things rely on it,
|
||||
// and it's already loaded into the appdomain since this loader references it, so we might as well skip it
|
||||
if (assembly.Name.Name == "System"
|
||||
|| assembly.Name.Name == "mscorlib") //mscorlib is already loaded into the appdomain so it can't be patched
|
||||
|| assembly.Name.Name ==
|
||||
"mscorlib") //mscorlib is already loaded into the appdomain so it can't be patched
|
||||
{
|
||||
assembly.Dispose();
|
||||
continue;
|
||||
@@ -328,7 +337,7 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
|
||||
RunPatcher(assembly, targetDll);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool RunPatcher(AssemblyDefinition assembly, string targetDll)
|
||||
{
|
||||
@@ -338,11 +347,14 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
|
||||
if (!isAssemblyPatch)
|
||||
{
|
||||
var targetType = assembly.MainModule.Types.FirstOrDefault(x => x.FullName == patchDefinition.TargetType.TargetType);
|
||||
var targetType =
|
||||
assembly.MainModule.Types.FirstOrDefault(x => x.FullName ==
|
||||
patchDefinition.TargetType.TargetType);
|
||||
|
||||
if (targetType == null)
|
||||
{
|
||||
Logger.LogWarning($"Unable to find type [{patchDefinition.TargetType.TargetType}] defined in {patchDefinition.MethodInfo.Name}. Skipping patcher"); //TODO: Proper name
|
||||
Logger
|
||||
.LogWarning($"Unable to find type [{patchDefinition.TargetType.TargetType}] defined in {patchDefinition.MethodInfo.Name}. Skipping patcher"); //TODO: Proper name
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -380,7 +392,6 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
foreach (var resolvedAss in AppDomain.CurrentDomain.GetAssemblies())
|
||||
@@ -414,6 +425,7 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
.AppendLine("Expect unexpected behavior and issues with plugins and patchers not being loaded.")
|
||||
.ToString());
|
||||
|
||||
var dumpedAssemblyPaths = new Dictionary<string, string>();
|
||||
// Finally, load patched assemblies into memory
|
||||
if (ConfigDumpAssemblies.Value || ConfigLoadDumpedAssemblies.Value)
|
||||
{
|
||||
@@ -423,10 +435,23 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
foreach (var kv in assemblies)
|
||||
{
|
||||
var filename = kv.Key;
|
||||
var name = Path.GetFileNameWithoutExtension(filename);
|
||||
var ext = Path.GetExtension(filename);
|
||||
var assembly = kv.Value;
|
||||
|
||||
if (patchedAssemblies.Contains(filename))
|
||||
assembly.Write(Path.Combine(PatcherContext.DumpedAssembliesPath, filename));
|
||||
if (!patchedAssemblies.Contains(filename))
|
||||
continue;
|
||||
for (var i = 0;; i++)
|
||||
{
|
||||
var postfix = i > 0 ? $"_{i}" : "";
|
||||
var path = Path.Combine(PatcherContext.DumpedAssembliesPath, $"{name}{postfix}{ext}");
|
||||
if (!Utility.TryOpenFileStream(path, FileMode.Create, out var fs))
|
||||
continue;
|
||||
assembly.Write(fs);
|
||||
fs.Dispose();
|
||||
dumpedAssemblyPaths[filename] = path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,14 +475,15 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
{
|
||||
Assembly loadedAssembly;
|
||||
|
||||
if (ConfigLoadDumpedAssemblies.Value)
|
||||
loadedAssembly = Assembly.LoadFrom(Path.Combine(PatcherContext.DumpedAssembliesPath, filename));
|
||||
if (ConfigLoadDumpedAssemblies.Value &&
|
||||
dumpedAssemblyPaths.TryGetValue(filename, out var dumpedAssemblyPath))
|
||||
loadedAssembly = Assembly.LoadFrom(dumpedAssemblyPath);
|
||||
else
|
||||
using (var assemblyStream = new MemoryStream())
|
||||
{
|
||||
assembly.Write(assemblyStream);
|
||||
loadedAssembly = Assembly.Load(assemblyStream.ToArray());
|
||||
}
|
||||
{
|
||||
using var assemblyStream = new MemoryStream();
|
||||
assembly.Write(assemblyStream);
|
||||
loadedAssembly = Assembly.Load(assemblyStream.ToArray());
|
||||
}
|
||||
|
||||
PatcherContext.LoadedAssemblies.Add(filename, loadedAssembly);
|
||||
|
||||
|
||||
@@ -9,6 +9,25 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
/// </summary>
|
||||
public class PatchDefinition
|
||||
{
|
||||
public PatchDefinition(TargetAssemblyAttribute targetAssembly, BasePatcher instance, MethodInfo methodInfo)
|
||||
{
|
||||
TargetAssembly = targetAssembly;
|
||||
Instance = instance;
|
||||
MethodInfo = methodInfo;
|
||||
|
||||
FullName = $"{MethodInfo.DeclaringType.FullName}/{MethodInfo.Name} -> {TargetAssembly.TargetAssembly}";
|
||||
}
|
||||
|
||||
public PatchDefinition(TargetTypeAttribute targetType, BasePatcher instance, MethodInfo methodInfo)
|
||||
{
|
||||
TargetType = targetType;
|
||||
Instance = instance;
|
||||
MethodInfo = methodInfo;
|
||||
|
||||
FullName =
|
||||
$"{MethodInfo.DeclaringType.FullName}/{MethodInfo.Name} -> {TargetType.TargetAssembly}/{TargetType.TargetType}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The assembly / assemblies this patch will target, if there any.
|
||||
/// </summary>
|
||||
@@ -33,24 +52,6 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
/// A friendly name for this patch definition, for use in logging and error tracking.
|
||||
/// </summary>
|
||||
public string FullName { get; }
|
||||
|
||||
public PatchDefinition(TargetAssemblyAttribute targetAssembly, BasePatcher instance, MethodInfo methodInfo)
|
||||
{
|
||||
TargetAssembly = targetAssembly;
|
||||
Instance = instance;
|
||||
MethodInfo = methodInfo;
|
||||
|
||||
FullName = $"{MethodInfo.DeclaringType.FullName}/{MethodInfo.Name} -> {TargetAssembly.TargetAssembly}";
|
||||
}
|
||||
|
||||
public PatchDefinition(TargetTypeAttribute targetType, BasePatcher instance, MethodInfo methodInfo)
|
||||
{
|
||||
TargetType = targetType;
|
||||
Instance = instance;
|
||||
MethodInfo = methodInfo;
|
||||
|
||||
FullName = $"{MethodInfo.DeclaringType.FullName}/{MethodInfo.Name} -> {TargetType.TargetAssembly}/{TargetType.TargetType}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -90,7 +91,7 @@ namespace BepInEx.Preloader.Core.Patching
|
||||
|
||||
/// <summary>
|
||||
/// The directory location as to where patched assemblies will be saved to and loaded from disk, for debugging
|
||||
/// purposes. Defaults to BepInEx/DumpedAssemblies
|
||||
/// purposes. Defaults to BepInEx/DumpedAssemblies/<ProcessName>
|
||||
/// </summary>
|
||||
public string DumpedAssembliesPath { get; internal set; }
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user