skip to content

In process hollowing, what must an operator do to a suspended host before the payload can run?

level: middleimportance: should knowfreq 55%

answer

  1. the host never really ran
  2. empty its original image first
  3. the payload landed somewhere new
  4. fix the addresses, repoint entry, resume
  5. 32-in-64 will not run

basics

~20 s

Hollowing starts a legitimate process suspended so it never actually runs, unmaps its original image from memory, writes the payload in its place, fixes the payload's relocations to wherever it landed, repoints the primary thread's entry at the payload, then resumes. The process ends up running code it was never loaded with.

solid answer

~50 s

The naive picture — 'just write shellcode into a running process' — misses most of what hollowing demands. The host is created in a suspended state so its original code never executes. The operator then unmaps the original image from the address it was loaded at, maps the payload in, and applies the payload's relocation fixups so its internal addresses match where it actually landed. The suspended thread's context is edited so the instruction pointer/entry targets the payload, and only then is the thread resumed. Two constraints bite: the payload's architecture must match the host's bitness — a 32-bit payload cannot simply live in a 64-bit host — and the process's own module list may still name the original image even though that image is gone, which is exactly the discrepancy the operator is trading on.

code

text · 7 lines
text
host: legitimate signed process, created SUSPENDED (never ran)
  original image      -> UNMAPPED from its load base
  payload image       -> written in, based/relocated to the new address
  primary thread ctx  -> entry point repointed at payload
  bitness             -> payload architecture MUST match the host
  state               -> RESUMED; module list may still name the original
...

go deeper

for a junior

Recall that hollowing replaces a legitimate process's contents with a payload while it looks like the original program, and that the process is started suspended.

for a middle

Walk the full sequence — suspend, unmap, map, relocate, repoint the thread, resume — and name why each step exists. Mention the bitness constraint.

for a senior

Contrast hollowing with reflective loading (no module-list entry) and thread hijacking (no new thread) in terms of what state each sets up and what residue it leaves.

for a principal

Reason about why these approaches proliferate: each is a different point on the cost curve of getting foreign code to run in a chosen process, and the choice follows what the operator can afford to set up and leave behind.

**What hollowing is trying to achieve.** The operator wants a process that, from the outside, is a known good program — a signed vendor binary launched normally — but that in fact executes the operator's code. 'Hollowing' names the trick: gut the legitimate process of its real contents and refill it, before it ever runs. **The sequence, and why each step is needed.** - **Create suspended.** The host is started in a suspended state so its primary thread never executes the original program. If it ran even briefly, you would not have a clean shell to fill. - **Unmap the original image.** The legitimate image is removed from the base address it was loaded at. This frees the region and is why the process is 'hollow' — its intended code is gone. - **Map the payload in.** The operator's image is written into the process's address space, often at a different base than it was compiled for. - **Apply relocations.** A compiled image contains absolute references that assume a particular load address. If the payload lands somewhere else, those references are wrong until the operator walks the relocation information and fixes each one. Skip this and the payload jumps to garbage. - **Repoint the thread.** The suspended primary thread's saved context is edited so its entry/instruction pointer targets the payload's entry rather than the original program's. - **Resume.** The thread is released and runs the payload. ```text host: legitimate signed browser, created SUSPENDED (never ran) original image -> UNMAPPED from its load base payload image -> written in, relocations fixed to new base primary thread ctx -> entry repointed at payload bitness -> payload MUST match host (no 32-in-64) state -> RESUMED; module list may still name the original ... ``` **Bitness.** A process's address space and loader are architecture-specific. A 32-bit payload cannot simply execute inside a 64-bit host, or vice versa. The operator must pick a host of the matching architecture, or carry both builds. Ignoring this is a classic reason an injection 'succeeds' yet the payload never runs. **How the cousins differ — without enumerating a catalogue.** Two related approaches change *what the operator has to leave behind*. **Reflective loading** maps and fixes up an image the same way but arranges for it to appear in no module list, so there is no loader bookkeeping tying the running code to a file. **Thread hijacking** avoids creating any new thread at all: it suspends an *existing* thread, points its context at code already written into the process, and resumes — nothing about the process's set of threads changes. Hollowing, reflective loading and thread hijacking are three answers to the same question — how does foreign code end up executing in a chosen process — priced differently in what state they must set up and what residue they create. **The wrong answer to avoid.** 'You write your code into the process and it runs' skips the unmap, the relocation fixups, the thread-context edit and the bitness match. Any one of those omitted and the payload crashes or never executes; describing them is how you show you understand the mechanism rather than the headline.

  • Why must the payload's architecture match the host process's bitness?
    The address space and loader are architecture-specific, so a 32-bit payload cannot execute inside a 64-bit host or vice versa. The operator has to choose a host of the matching bitness, or carry both builds; otherwise the injection appears to succeed but the code never runs correctly.
  • How does thread hijacking reach execution without the suspend-and-hollow dance?
    It suspends a thread that already exists in the target, edits that thread's saved context so the instruction pointer targets payload already written into the process, then resumes it. No new thread is created and no remote thread is spawned, so the process's set of threads is unchanged.
  • What is the point of applying relocations to the payload after mapping it in?
    A compiled image assumes it loads at a particular base and contains absolute references built on that assumption. When the payload lands at a different address, those references are wrong until the operator walks the relocation data and patches each one. Skipping it makes the payload jump to invalid addresses.

saying these in an interview costs you the question

  • Says hollowing just writes shellcode into a running process
  • Forgets the original image must be unmapped first
  • Omits relocation fixups after the payload is placed
  • Thinks a 32-bit payload runs in any host regardless of bitness

context