I’m trying to recreate HarmonyLib type method interception with help from ChatGPT. Initially I had a sharing violation so it suggested putting the assembly into memory (maybe it’s separate from the main assembly then however). While I think this does inject something, I don’t get any output when the methods are invoked. Hoping some code wizard knows if this is possible and if it can be solved. HarmonyLib messes with Unity dependencies although does work.
using System;
using System.Linq;
using System.Reflection;
using Mono.Cecil;
using Mono.Cecil.Cil;
using UnityEditor;
using UnityEngine;
[InitializeOnLoad]
public static class ILInjector
{
static ILInjector()
{
Inject();
}
public static void Inject()
{
// Get the path to the current assembly (Assembly-CSharp.dll)
string assemblyPath = Assembly.GetExecutingAssembly().Location;
if (!assemblyPath.EndsWith("Assembly-CSharp.dll"))
{
Debug.LogError("ILInjector can only modify Assembly-CSharp.dll");
return;
}
Debug.Log($"ILInjector: Modifying {assemblyPath}");
// Load the assembly into memory
var assembly = AssemblyDefinition.ReadAssembly(assemblyPath);
var module = assembly.MainModule;
// Inject IL code into each method of each type in the assembly
foreach (var type in module.Types)
{
foreach (var method in type.Methods)
{
try
{
if (method.HasBody && !method.IsConstructor && !method.IsGetter && !method.IsSetter)
{
InjectLogMethodExecution(method, module);
}
}
catch (Exception ex)
{
Debug.LogError($"ILInjector: Error injecting into method {method.FullName}: {ex.Message}");
}
}
}
// Write the modified assembly to a memory stream
using (var memoryStream = new System.IO.MemoryStream())
{
assembly.Write(memoryStream);
memoryStream.Position = 0;
// Load the modified assembly into the current AppDomain
var modifiedAssembly = Assembly.Load(memoryStream.ToArray());
// Ensure the modified assembly is loaded
Debug.Log($"ILInjector: Injection completed and loaded {modifiedAssembly.FullName}");
}
}
private static void InjectLogMethodExecution(MethodDefinition method, ModuleDefinition module)
{
var processor = method.Body.GetILProcessor();
// Create the instructions to be inserted
var ldstrInstruction = processor.Create(OpCodes.Ldstr, method.FullName);
var callInstruction = processor.Create(OpCodes.Call, module.ImportReference(typeof(ILInjector).GetMethod("LogMethodExecution", BindingFlags.Static | BindingFlags.NonPublic)));
// Insert instructions at the beginning of the method
processor.InsertBefore(method.Body.Instructions[0], ldstrInstruction);
processor.InsertBefore(method.Body.Instructions[1], callInstruction);
Debug.Log($"ILInjector: Injected method execution logging into method: {method.FullName}");
}
// Injected method to log method execution
private static void LogMethodExecution(string methodName)
{
Debug.Log($"Method executed: {methodName}");
}
}