AMSI & .NET
1. RECAP: AMSI Behaviour in powershell versus .NET Applications
Let's recap the difference of AMSI behaviour in powershell versus .net applications, specifically focusing on your C# RemoteLoader that uses DnsClient.NET embedded with Fody.Costura.
We have seen before that AMSI is loaded by default in powershell processes:

In .net applications, AMSI is not loaded by default. Instead, it is loaded on-demand based on certain triggers, such as dynamic assembly loads (Assembly.Load) or script execution. This makes patching AMSI in .net applications more challenging, as the timing of AMSI loading can vary depending on the application's behavior.
When your C# RemoteLoader app calls the GetKey() method, it triggers the loading of AMSI because it involves dynamic assembly loading through the Fody.Costura library. This is not a problem for benign libraries like DnsClient.NET, but it does mean that AMSI is now active in your process.
We see this when we start our remote loader and monitor the loaded modules (check the timestamps):

After continuing execution to the GetKey() call, we see that amsi.dll is now loaded (check the timestamps):

Patching AMSI in .net applications requires careful consideration of when and how AMSI is loaded. Since AMSI is not present at process start, any patches must be applied after the relevant triggers occur. This can be more complex than patching AMSI in powershell, where it is always loaded.
Therefore, our AMSI patch forces AMSI to be loaded early in the process, before any dynamic assembly loads occur. This ensures that our patch is applied before AMSI can scan any assemblies or scripts, effectively neutralizing its monitoring capabilities. Once AMSI is loaded, our patch modifies its behavior to prevent it from scanning or blocking any content, allowing your RemoteLoader app to operate without interference.
AMSI will not be reloaded or re-initialized after being patched, so applying the patch early ensures that all subsequent AMSI activity is neutralized.
2. Detailed AMSI Patch debugging in .NET
Overview of functions available in amsi.dll:

We can attack AMSI in .net applications by patching the AmsiScanBuffer function, which is responsible for scanning buffers for malicious content. By modifying this function to always return a success code, we can effectively disable AMSI's scanning capabilities.
We can also attack other Amsi functions, such as AmsiInitialize, but AmsiScanBuffer is the most direct way to neutralize AMSI's scanning functionality.
In the next lab we'll implement this patch in our AMSIETWLoader, ensuring that AMSI is loaded early and patched before any scanning can occur. Here's a preview of the AMSI patch code we'll use:

Visually this looks like this:

Le's have a look in a debugger at the AmsiScanBuffer function in our AMSIETWLoader before patching:

After applying our AMSI patch, we can see that the AmsiScanBuffer function has been modified to always return (0xC3) a success code (0), effectively disabling AMSI's scanning capabilities:

Advantages of Patching AMSI in .NET Applications in your loader
- Early Neutralization: By forcing AMSI to load early in the process, we ensure that our patch is applied before any scanning can occur. This is crucial for .net applications where AMSI is not loaded by default.
- Comprehensive Coverage: Patching AmsiScanBuffer ensures that all subsequent scanning attempts by AMSI are neutralized, allowing your RemoteLoader app to operate without interference.
- Dependency Agnostic: Many shellcode generators (Havoc C2, Donut etc...) allow adding an AMSI/ETW stubs to the generated shellcode. This means they are static patches that could be detected easily or even fixed by Microsoft in future updates. By patching AMSI in your loader, you avoid relying on potentially fragile shellcode modifications. It also allows you to use standard shellcode without modifications, and to swap out patching techniques as needed.
- Less Telemetry Noise: By patching AMSI/ETW early on, you reduce the chances of generating suspicious telemetry events that could arise from other evasion techniques. This helps keep your operations stealthy and less likely to be flagged by security monitoring tools.
- Signature Evasion: Static AMSI patches in shellcode can be detected by signature-based defenses. By implementing the patch in your loader, you can avoid using static signatures, making it harder for defenders to identify your evasion techniques. Remember signatures might get updated, and our previous tricks with simple byte changes to evade signatures might not work forever.