Most security tooling operates at a high abstraction layer: file hashes, process names, alert rules. Attackers who understand Windows internals (how tokens flow through handles, what syscalls expose, how the kernel resolves names) can stay below that visibility. The same knowledge in a defender's hands means hunting at the layer where evasion actually happens — not the abstracted view your SIEM shows.
| Level | Characteristic | Limitation |
|---|---|---|
| Downloads tools | Runs exploits from GitHub, uses Metasploit modules | Stops when the tool doesn't work |
| Builds tools | Writes custom implants, modifies existing code | Copies techniques without understanding why |
| Understands systems | Knows why exploits work at the OS level | Can find new vulnerabilities, adapt to any defense |
Most people get stuck between levels 1 and 2. They can Base64 encode payloads, chain tools together, and follow tutorials. But when something breaks - when the technique stops working - they're stuck.
It's tempting to think evasion is about obfuscation:
This works against static signatures. It fails against behavioral analysis. Modern EDR doesn't care what your code looks like - it watches what it does.
Living off the land beats obfuscation. Understanding the system beats both.
If you want to move beyond tool user:
Windows executables have structure: headers, sections, imports, exports. Understanding PE format means understanding:
Every process has its own virtual address space. Understanding memory means understanding:
SeDebugPrivilege isn't magic - it's a bit in a token structure. Understanding tokens means understanding:
Processes reference kernel objects through handles. Understanding handles means understanding:
PROCESS_ALL_ACCESS actually grantsWindows services communicate through these mechanisms. Understanding them means understanding:
Reading isn't enough. Build these:
DebugActiveProcess, breakpoints, memory reading.NtQuerySystemInformation to enumerate handles.Can you explain why your technique works? Not how - why.
When you understand why, you can:
Here's what "understanding" looks like in practice. EDR hooks GetModuleHandle and GetProcAddress to detect malware resolving APIs. But if you understand how Windows actually tracks loaded modules, you can walk the data structures yourself:
class LDR_DATA_TABLE_ENTRY(ctypes.Structure):
"""Describes a loaded module (DLL) in the process."""
_fields_ = [
("InLoadOrderLinks", LIST_ENTRY),
("InMemoryOrderLinks", LIST_ENTRY),
("InInitializationOrderLinks", LIST_ENTRY),
("DllBase", ctypes.c_void_p),
("EntryPoint", ctypes.c_void_p),
("SizeOfImage", wintypes.ULONG),
("FullDllName", UNICODE_STRING),
("BaseDllName", UNICODE_STRING),
]
def find_module(name):
"""Find module by walking PEB - no GetModuleHandle call."""
peb = get_peb()
ldr = peb.Ldr.contents
head = ctypes.addressof(ldr.InLoadOrderModuleList)
entry_ptr = ldr.InLoadOrderModuleList.Flink
while ctypes.addressof(entry_ptr.contents) != head:
entry = ctypes.cast(entry_ptr,
ctypes.POINTER(LDR_DATA_TABLE_ENTRY)).contents
if entry.BaseDllName.Buffer.lower() == name.lower():
return entry.DllBase
entry_ptr = entry.InLoadOrderLinks.Flink
return None
This finds any loaded DLL without calling monitored APIs. The technique extends to parsing export tables for function addresses - completely invisible to userland hooks.
The person who memorized "use PEB walking to evade hooks" knows what to do. The person who understands doubly-linked lists and Windows loader internals can implement it from scratch when their tool breaks.
Reference: Windows Internals by Mark Russinovich, David Solomon, Alex Ionescu