Skip to content

Null-Byte Registry Key Hiding

Embedding a null byte in a key name via the native API makes a registry entry invisible to regedit while it still runs at boot.

The Windows registry is built on the kernel's object manager, which addresses keys and values with counted Unicode strings (UNICODE_STRING: an explicit length plus a buffer). The high-level Win32 registry API (RegOpenKeyEx, RegEnumValue) and regedit.exe instead treat names as null-terminated C strings. That mismatch is the whole trick: a key or value whose name contains an embedded null byte can be created through the native API (NtSetValueKey / ZwCreateKey), where the length is explicit, but the Win32 layer stops reading at the first null and either fails to open it or refuses to display it. Poweliks and Kovter pioneered this to make their fileless autorun entries invisible to a hand inspection with regedit.

The hidden value still functions: the loader entry stored under a Run key or a CLSID is read by the kernel-aware consumer that placed it, so the malware persists and executes at logon while an analyst browsing the hive sees nothing — or sees a key that errors when clicked.

How it works

Creation goes through the native API so the embedded null survives as part of the counted name:

text
:: Conceptual: native call sets a value whose name begins with a null byte
NtSetValueKey(hRunKey, "\0malware", REG_SZ, "rundll32 ...javascript:...")

The leading-null value sorts oddly and cannot be opened by regedit (which builds an ANSI/null-terminated request), so the entry appears empty or throws "Cannot open value." Kovter pairs this with a CLSID-based autorun and a script-engine payload, keeping the actual code in another hidden value to maximize the gap between what runs and what an analyst can see.

Detection & analysis

Static analysis:

  • Parse the raw registry hive at the cell level rather than through the Win32 API. Offline hive parsers read the nk/vk cell structures directly and surface names containing embedded or leading nulls. Tools: RegRipper, yarp/regipy, Registry Explorer (Eric Zimmerman), Velociraptor raw-hive plugins.
  • Diff the API view against the cell-level view of Run, RunOnce, and CLSID keys: a value present in the raw hive but absent or unopenable via reg query/regedit is the signature of null-byte hiding.
  • Recover prior states from registry transaction logs (.LOG1/.LOG2) and from hive copies inside Volume Shadow Copies; these often capture the moment the hidden value was written, including its full counted name.

Dynamic analysis:

  • Sysmon Event IDs 12/13/14 (registry object create/set/rename) log writes by their real native name, so an autorun value the analyst cannot see in regedit still appears in telemetry with its embedded null rendered. Correlate the writing process and command line.
  • Boot/logon execution of the payload (Event ID 4688 / Sysmon 1) reveals the consumer reading the hidden value — typically rundll32, mshta, or a script host launched from a Run/CLSID entry.

Detection rule hint: Alert when a cell-level hive parse finds a key or value name under Run/RunOnce/CLSID containing a null (0x00) byte, or when Sysmon 13 records a Run-key value set whose target is a script-engine/LOLBin command line. Recovery path: parse the raw hive (and its .LOG/shadow-copy versions) to dump the full counted name and the payload command, independent of the Win32 API.

Votes

Comments(0)