In-Memory Assembly Resolve

74 views Asked by At

I have an entry assembly that is ran entirely in-memory. The entry assembly creates a new domain and then tries to attach an assembly resolver. This results in a FileNotFoundException within the new AppDomain because the OnResolveAssembly method is located in the entry assembly (in-memory) and the CLR is probing the disk looking for it.

Entry Assembly:

using System;
using System.Reflection;

public class Program
{
    public static void Main()
    {
        var newDomain = AppDomain.CreateDomain("new-domain");
        
        try { newDomain.AssemblyResolve += OnResolveAssembly; }
        catch (Exception e) { Console.WriteLine(e); }
    }

    public static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
    {
        // load required dll from resource stream

        return null;
    }
}

Publish And Serve Entry Assembly:

dotnet publish
python -m http.server -d .\bin\Debug\net48\publish\

Run Entry Assembly In-Memory Via Powershell:

[System.Reflection.Assembly]::Load((Invoke-WebRequest "http://127.0.0.1:8000/test.exe").Content).EntryPoint.Invoke($null, $null)

Error:

System.IO.FileNotFoundException: Could not load file or assembly 'test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
File name: 'test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.Load(String assemblyString)
   at System.Runtime.Serialization.FormatterServices.LoadAssemblyFromString(String assemblyName)
   at System.Reflection.MemberInfoSerializationHolder..ctor(SerializationInfo info, StreamingContext context)
   at System.AppDomain.add_AssemblyResolve(ResolveEventHandler value)
   at Program.Main()

This would be the offending line:

at System.Reflection.Assembly.Load(String assemblyString)

The same error will occur if I try to create a shared proxy object as well since the same process is applied of loading the containing assembly into the new domain:

var proxy = (Proxy) Domain.CreateInstanceAndUnwrap(typeof(Proxy).Assembly.FullName, typeof(Proxy).FullName);

I have tried manually loading assemblies into the new domain and while it does show they've been loaded, I am unable to do anything with them due to not being able to have a shared proxy object between domains.

Surely there is a way to run a C# binary entirely in-memory while retaining the ability to use AppDomain's.

0

There are 0 answers