Accidental LOLBin: Controlling Media Keys with csc.exe

I was coding with music in the background when I needed to pause it. I reached for my mouse button that I’d configured for this, and… nothing. My usual utility had stopped working after a software update.

I decided to write a simple solution: a script that compiles C# code on-the-fly using only Windows built-in tools. It works well. But while documenting it, I realized something interesting: I’d accidentally implemented a technique listed in MITRE ATT&CK as T1027.004: Compile After Delivery.

The Goal

I needed a native way to send media keys (Play, Next, Prev) using only what’s included in Windows. No third-party binaries, no installations.

What’s a LOLBin?

LOLBin (Living Off the Land Binary) refers to legitimate system tools that can be used for purposes beyond their original intent.

Windows includes many of these: certutil.exe, mshta.exe, regsvr32.exe, and csc.exe (the C# compiler). They’re all signed by Microsoft and present in clean Windows installations.

Attackers sometimes prefer LOLBins because:

  • They don’t trigger antivirus alerts (they’re legitimate system files)
  • They don’t require downloading suspicious tools
  • They can bypass Application Whitelisting policies
  • They leave fewer obvious traces

The Code

I wrote a simple C# class that uses user32.dll to simulate media key presses.

MediaKey.cs
using System.Runtime.InteropServices;
using System.Threading;
class P
{
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, int f, int e);
static void Main(string[] a)
{
if (a.Length == 0)
return;
byte k = 0;
switch (a[0].ToLowerInvariant())
{
case "playpause":
k = 0xB3;
break;
case "next":
k = 0xB0;
break;
case "prev":
k = 0xB1;
break;
default:
return;
}
keybd_event(k, 0, 1, 0);
Thread.Sleep(10);
keybd_event(k, 0, 3, 0);
Thread.Sleep(50);
}
}

The code is deliberately minimal: short class names, no unnecessary namespaces, just what’s needed to work.

The “LOLBin” Mechanism

To run this without distributing an .exe, I used the C# compiler (csc.exe) that comes pre-installed with .NET Framework on Windows.

compile.bat
@echo off
setlocal EnableExtensions
set "SRC=%~dp0..\src\MediaKey.cs"
set "OUTDIR=%~dp0..\bin"
set "OUT=%OUTDIR%\MediaKey.exe"
set "CSC_FLAGS=/nologo /optimize+ /debug- /target:winexe /platform:anycpu"
echo Compiling %OUT%...
REM ---- 1) Validate source
if not exist "%SRC%" (
echo ERROR: "%SRC%" not found in: "%CD%"
pause
exit /b 1
)
REM ---- 2) Resolve csc.exe (x64 -> x86 -> PATH)
set "CSC=%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
if not exist "%CSC%" set "CSC=%WINDIR%\Microsoft.NET\Framework\v4.0.30319\csc.exe"
if not exist "%CSC%" (
for /f "delims=" %%I in ('where csc.exe 2^>nul') do ( set "CSC=%%I" & goto :got_csc )
echo ERROR: csc.exe not found. Install .NET Framework 4.x or add csc to PATH.
pause
exit /b 1
)
:got_csc
REM ---- 3) Prepare output
if not exist "%OUTDIR%" mkdir "%OUTDIR%" >nul 2>&1
REM ---- 4) Compile
"%CSC%" %CSC_FLAGS% /out:"%OUT%" "%SRC%"
if errorlevel 1 (
echo.
echo ERROR: Compilation failed.
pause
exit /b 1
)
echo.
echo OK: Compilation successful.
for %%F in ("%OUT%") do (
echo Generated: "%%~fF" (%%~zF bytes^)
echo.
echo Usage:
echo %%~fF playpause
echo %%~fF next
echo %%~fF prev
)
echo.
pause
exit /b 0

Why This Maps to T1027.004

This approach corresponds to MITRE ATT&CK T1027.004: Compile After Delivery.

Instead of sending a compiled executable (which antivirus software immediately scans), source code can be sent as text. Once on the target system, built-in tools like csc.exe compile it locally.

graph LR
  A[Source Code .cs] -->|csc.exe| B[Binary .exe]
  B -->|Execute| C[Runs]
  
  style A fill:#e3f2fd
  style B fill:#fff9c4
  style C fill:#c8e6c9

The basic flow:

  1. Delivery: Send code as text (bypasses binary scanning)
  2. Compilation: Use built-in compiler
  3. Execution: Run the fresh binary

In my case, I’m just controlling media playback. But it demonstrates how “Living Off the Land” works in practice.

Real-World Usage

This technique has been observed in actual threat campaigns:

  • MuddyWater (Iranian APT): Used csc.exe compilation in their operations targeting government and commercial networks in the Middle East and beyond.
  • DarkWatchman: A JavaScript-based RAT that dynamically compiles a C# keylogger using the Code DOM (Code Document Object Model) for fileless execution.
  • Imperial Kitten: Deployed IMAPLoader malware using this technique, writing C# source files to disk and compiling them after initial access.

These groups chose this method specifically to evade static analysis and antivirus detection during the delivery phase.

Detection

Security tools look for patterns like:

  • csc.exe running in unusual contexts (e.g., from temp directories)
  • Compilation followed by immediate execution
  • Source files from suspicious origins
  • Command-line arguments that include compilation flags with user-writable output directories

Detection rules for this technique are available in Sigma and other security platforms.

Legitimate vs Suspicious Use

Using csc.exe is normal in many contexts:

Legitimate:

  • Development automation scripts
  • Personal tools (like this one)
  • Documented build processes

Suspicious:

  • Compilation from temporary directories by non-developer users
  • Combined with other evasion techniques
  • Immediate execution after compilation from external sources

Takeaways

This small project showed me how the same tools used for everyday tasks can be leveraged differently. There’s nothing inherently malicious about csc.exe—context matters.

As someone starting in cybersecurity, I find this perspective useful. Every system utility, API, or programming pattern can be viewed from multiple angles: building something helpful vs finding attack vectors.

The complete code is available here: win-mediakey-lolbin