Systems Security & Exploitation

control-flow hijacking

A program is a script that the CPU follows line by line, and the program counter (rip on x86-64) is the bookmark saying which instruction comes next. Normally only the program's own logic moves that bookmark — through calls, returns, and branches. Control-flow hijacking is when an attacker, exploiting a memory bug, sets the bookmark themselves, so the CPU starts executing instructions the attacker chose instead of the program's intended path.

It is best understood as the GOAL that the memory-corruption bugs serve. Every code pointer the CPU obeys is a target: the saved return address on the stack (reached by a stack overflow), a function pointer in a struct (reached by a heap overflow, use-after-free, or type confusion), a C++ vtable pointer, or an entry in the Global Offset Table. Hijacking means overwriting one of these with an attacker-chosen address. The moment a ret, an indirect call (call rax), or an indirect jump uses the corrupted pointer, rip moves to the attacker's address and execution is theirs. What they point it AT has evolved: once at injected shellcode in a buffer, and — after DEP made data non-executable — at existing code via return-oriented programming or return-to-libc.

It matters because control-flow hijacking is the dividing line between a crash and a compromise: a bug that merely corrupts data may just make the program misbehave, but one that redirects execution can run arbitrary code with the program's privileges. The honest framing: the modern mitigations are organized precisely around this step — stack canaries protect return addresses, Control-Flow Integrity and shadow stacks check that indirect transfers go only to legitimate targets, and pointer authentication signs code pointers so a forged one is detected. None of these fix the underlying memory bug; they try to make a hijack fail even when the bug fires.

// any of these, once corrupted, redirects rip on use: ret // pops a (overwritten) return address into rip call qword [rax] // indirect call through a (overwritten) function pointer jmp qword [vtable] // C++ virtual dispatch through a (overwritten) vtable slot

Hijacking targets the few instructions where rip is taken from memory the attacker can corrupt.

A crash and a hijack come from the SAME class of bug; whether corruption stays a denial-of-service or becomes code execution depends on whether the attacker can steer a code pointer — which is exactly what CFI, shadow stacks, and PAC try to prevent.

Also called
control-flow redirectionPC hijackEIP/RIP control劫持控制流改寫程式計數器