Skip to content

KernelCallbackTable Injection

Hijacking a GUI process by patching an entry in its PEB KernelCallbackTable to point at injected shellcode, then triggering execution with a window message such as WM_COPYDATA.

KernelCallbackTable injection targets GUI processes (classically explorer.exe) by abusing a dispatch table that user32.dll uses to call back into user mode when the kernel delivers window messages. Each GUI process's PEB holds a KernelCallbackTable pointer; the kernel indexes into it (via KeUserModeCallback) for callbacks like fnCOPYDATA. By patching one entry to point at injected shellcode and then sending the right window message, the attacker gets the OS itself to invoke the payload.

How it works

The injector writes shellcode into the target, reads the original KernelCallbackTable from the target PEB, makes a copy with one entry (e.g. fnCOPYDATA) repointed at the shellcode, writes the modified table back, and updates PEB->KernelCallbackTable to reference it. Sending a WM_COPYDATA message to the target's window then causes user32 to dispatch through the patched entry and execute the shellcode in the target's context.

text
WriteProcessMemory(hProc, shellAddr, shellcode, len)
ReadProcessMemory(hProc, &peb->KernelCallbackTable, &origTable, ...)
ReadProcessMemory(hProc, origTable, &localCopy, sizeof(localCopy))
localCopy.__fnCOPYDATA = shellAddr                  // patch one callback entry
newTable = VirtualAllocEx(hProc, ...); WriteProcessMemory(hProc, newTable, &localCopy, ...)
WriteProcessMemory(hProc, &peb->KernelCallbackTable, &newTable, sizeof(PVOID))
SendMessage(hWnd, WM_COPYDATA, ...)                  // kernel dispatches the patched entry

Detection & bypass

  • Static — The injector imports WriteProcessMemory/ReadProcessMemory plus window/message APIs (FindWindow, SendMessage/SendNotifyMessage with WM_COPYDATA). References to the PEB (NtQueryInformationProcess to find it) combined with messaging APIs and a GUI target name are a distinctive pairing.
  • Dynamic — The high-fidelity trigger is a cross-process write to the remote PEB->KernelCallbackTable field (or to the table it references), followed by a WM_COPYDATA/window message that drives execution. Watch for WriteProcessMemory whose destination is the PEB offset of KernelCallbackTable in a GUI process. ETW thread/stack traces will show a callback (fnCOPYDATA) returning into non-user32 memory.
  • Memory forensics — Inspect the target's KernelCallbackTable: a healthy table's entries all resolve inside user32.dll; a stomped entry points into private/unbacked memory or another module. The shellcode region itself is typically private executable memory that pe-sieve/Moneta flag, and the patched table pointer can be compared against a clean user32 baseline.
  • Tools — Process Hacker / WinDbg (dt nt!_PEB KernelCallbackTable, dump and validate entries), pe-sieve and Moneta (private executable shellcode region), API Monitor / Sysmon ETW (remote PEB writes, window messages), and Volatility (peb/VAD inspection plus callback-table validation).
Votes

Comments(0)