Why can two process lists built from one memory image disagree about which processes existed?
answer
- one follows a list, one scans memory
- the list is a structure that can be edited
- freed pool memory is not wiped
- extra entries are usually ghosts
- injection creates no new process
basics
~20 sOne list walks the kernel's doubly-linked list of process structures; the other scans physical memory for those structures directly. Scanning also finds processes unlinked from the list and remnants of processes that already exited, so it usually returns more.
solid answer
~40 sWindows tracks running processes as a doubly-linked list of kernel process structures. Walking that list is fast and gives a clean answer, but it trusts a data structure the kernel - or anything with kernel write access - can edit. The alternative is to scan physical memory for the process structures themselves by their signature and pool allocation, ignoring the list entirely. The scan finds two extra classes: structures deliberately unlinked from the list to hide a process, and structures belonging to processes that have already exited but whose pool memory has not yet been reused. Extra entries are therefore *not* automatically evidence of hiding - exited processes are the common explanation, and a partly smeared image adds more. It is a cross-view check: a difference is a question to resolve, not a verdict.
go deeper
Know that a memory image can be enumerated two ways - following the kernel's process list, or scanning memory for the process structures - and that the scan often returns extra entries.
Explain both mechanisms and all three reasons the scan returns more: unlinked structures, structures of already-exited processes, and acquisition smear. Lead with the boring explanation.
Demonstrate triage on a discrepancy - exit time, thread and handle state, internal consistency - and volunteer the limitation that in-process injection leaves the list entirely correct.
Own where cross-view enumeration sits in a detection strategy: it answers one narrow technique, so decide what else the programme buys rather than presenting it as broad coverage.
## Two ways to answer the same question When a memory-analysis tool prints a process list, it can get there by two different routes, and they do not always agree. **List walking.** Windows maintains one kernel structure per process and threads them onto a doubly-linked list. Following that list from a known head gives you every process the kernel is prepared to admit exists, with clean parent-child ids, start times and paths. It is what the operating system's own APIs are ultimately doing, which is precisely the weakness: you are trusting a data structure to describe reality. **Pool scanning.** The alternative ignores the list and searches raw physical memory for the process structures themselves, recognising them by their allocation headers and by internal fields that must hold plausible values. Because it never follows a pointer that an adversary can edit, it finds structures the list does not reference. ## Why the scan finds more Three explanations, and they are not equally exciting. 1. **Exited processes.** By far the commonest. When a process ends, its kernel structure is freed, but freed pool memory is not wiped - it stays readable until something else allocates over it. On a busy server the scan routinely surfaces dozens of these ghosts, complete with names and start times, minutes or hours after the process died. 2. **Unlinked structures.** Code running with kernel privileges can unlink a process's structure from the list while leaving the process schedulable, because the scheduler does not use that list. The process runs and answers no enumeration. This is the case cross-view detection was invented for, and it is rare relative to the first. 3. **Acquisition smear.** The image was written over minutes from a running system, so a structure can be captured half-modified or a pointer captured before the object it referenced was freed. That produces entries that look partial or self-inconsistent. ## Reading the difference honestly The correct move on a discrepancy is triage, not escalation. Check whether the extra structure has an exit time recorded, whether its handle table and thread list are empty or unreadable, and whether its fields are internally consistent. A clean structure with live threads, an intact address space and no exit time deserves attention; a hollow one with a stale name is almost certainly a freed allocation. Then corroborate outside memory: was anything recorded about that image executing, and does the timeline support a process that ran and stopped? The direction of the inference also matters. A discrepancy is evidence that the list *may* have been manipulated. Agreement between the two views is much weaker evidence than people assume, because it only rules out one specific hiding technique. ## The far more important limitation Cross-view process enumeration is aimed at a *hidden process*. Most current tradecraft does not create one. If an operator injects a payload into a process that is already running - a signed, correctly installed application-server or service binary - then there is no new process at all. The process list is genuinely, completely correct: the same processes the administrators expect, with the same names, the same parents and the same signed images. Both views agree, and both are useless. That is the moment an analyst has to change instrument. Once the process list is exhausted, the questions move inside a process: what regions does its address space contain, which of them carry execute permission with no file backing them, do its threads start inside a loaded module, and does it own network endpoints its role does not explain. A purple-team exercise that injects into a running process on a production Windows server is specifically designed to make the process list a dead end - and the exercise value of the finding is partly that it demonstrates why enumeration alone was never going to see it. ## What to say in an interview Name both mechanisms, name the three explanations for a difference and lead with the boring one, and then volunteer the limitation: a clean process list rules out a hidden process, not an implant. Candidates who present the cross-view technique as a general implant detector have learned the technique without learning where it stops.
- Your scan shows six processes the linked list does not, none of them suspicious - how do you read that?Start from the likeliest cause: freed structures of processes that already exited and whose pool memory has not been reused. Check each for a recorded exit time, an empty or unreadable thread and handle list, and internally inconsistent fields. Anything hollow is residue. Only a structure that looks live - threads, an intact address space, no exit time - justifies treating it as a hidden process, and then you corroborate it elsewhere.
- Does a process list that matches across both views rule out an implant on the host?No. It only rules out a process hidden by unlinking its kernel structure. Code injected into an existing legitimate process produces a completely correct list, because no new process was ever created. At that point you stop enumerating processes and start examining what is inside them - region permissions, unbacked executable memory, thread start addresses and owned network endpoints.
- Why does unlinking a process's structure from the list not stop it running?That list exists for enumeration, not for scheduling. Threads are dispatched from separate structures, so removing the process from the enumeration list leaves it perfectly schedulable while the operating system's own listing APIs no longer report it. That asymmetry is exactly what makes a scan that ignores the list worth running.
saying these in an interview costs you the question
- Says any extra process from a scan means something is hidden
- Assumes a matching process list proves the host is clean
- Thinks freed kernel structures are zeroed immediately
- Believes unlinking a process would stop it executing