Skip to content

Instantly share code, notes, and snippets.

@CamelCaseName
Created March 5, 2024 19:02
Show Gist options
  • Save CamelCaseName/07d96897a7547b83a9d0d658437ef746 to your computer and use it in GitHub Desktop.
Save CamelCaseName/07d96897a7547b83a9d0d658437ef746 to your computer and use it in GitHub Desktop.
Example of self embedded assembly extraction
using System.Reflection;
using System.Runtime.Loader;
namespace AssemblyTest
{
internal class AssemblyTest
{
static AssemblyTest()
{
SetOurResolveHandlerAtFront();
}
private static Assembly AssemblyResolveEventListener(object sender, ResolveEventArgs args)
{
if (args is null) return null!;
string dllName = args.Name[..args.Name.IndexOf(',')];
foreach (var field in typeof(AssemblyTest.Properties.Resources).GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
{
if (field.Name == dllName.Replace('.', '_'))
{
return Assembly.Load((byte[])field.GetValue(null)!);
}
}
return null!;
}
private static void SetOurResolveHandlerAtFront()
{
BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic;
FieldInfo? field = null;
Type domainType = typeof(AssemblyLoadContext);
while (field is null)
{
if (domainType is not null)
{
field = domainType.GetField("AssemblyResolve", flags);
}
else
{
return;
}
if (field is null)
domainType = domainType.BaseType!;
}
MulticastDelegate resolveDelegate = (MulticastDelegate)field.GetValue(null)!;
Delegate[] subscribers = resolveDelegate.GetInvocationList();
Delegate currentDelegate = resolveDelegate;
for (int i = 0; i < subscribers.Length; i++)
currentDelegate = Delegate.RemoveAll(currentDelegate, subscribers[i])!;
Delegate[] newSubscriptions = new Delegate[subscribers.Length + 1];
newSubscriptions[0] = (ResolveEventHandler)AssemblyResolveEventListener!;
Array.Copy(subscribers, 0, newSubscriptions, 1, subscribers.Length);
currentDelegate = Delegate.Combine(newSubscriptions)!;
field.SetValue(null, currentDelegate);
}
}
}
@CamelCaseName
Copy link
Author

CamelCaseName commented Mar 5, 2024

Just add all DLLs you want to load internally into your normal Resource.resx file.

this method can also be used to use specific assembly versions dynamically as we run before all other assembly resolvers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment