.NET AssemblyResolve Reflective Plugin Loader
What it does
A .NET malware sample subscribes to AppDomain.CurrentDomain.AssemblyResolve, intercepts resolution failures for missing plugin DLLs, and returns the assembly from a byte array delivered over the C2 channel. No DLL ever touches disk.
Detection / Fingerprint
- String
CurrentDomain_AssemblyResolveorAssemblyResolvealongsideResolveEventHandlerandbyte[] - .NET metadata tokens for
System.AppDomain::add_AssemblyResolveandSystem.Reflection.Assembly::Load - Absence of the expected plugin DLLs on disk despite
Assembly.Loadreferences in IL
Implementation patterns observed
In XenoRAT the handler is named DllHandler.CurrentDomain_AssemblyResolve; it receives a ResolveEventArgs.Name, maps it to a cached byte buffer, and calls Assembly.Load(byte[]) ^[sample 6133cd0b/strings.txt]. Plugin nodes (DllNodeHandler) traffic actual binary payloads over the existing C2 socket.
Reproduce on your own VMs
- Create a .NET Framework console app targeting 4.8
- Add
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve; - In
OnAssemblyResolve, read a DLL from aMemoryStreamor base64 string and returnAssembly.Load(bytes) - Reference a non-existent assembly name from code; watch it resolve in the handler
- Verify with ProcMon: no DLL file creation, only
Assembly.Loadin .NET ETW traces
Defensive countermeasures
- .NET ETW / CLRv4 provider: monitor
AssemblyLoadevents with no corresponding file-path - EDR userland hooks on
Assembly.Load(byte[]) - Behavioural rule: process with
mscoreeIAT only + TCP C2 +ManagementObjectSearcher+AssemblyResolve
Pages where observed
- xenorat — entity page