deep-divewindows-internalsregistry

How Windows really tracks startup apps: the StartupApproved\Run blob

Task Manager's Disable button doesn't delete anything — it flips one byte in a 12-byte blob. Here's the layout, the timestamps inside it, and why deleting the Run entry is the amateur move.

ProofTune Project··7 min read
Deep dive illustration Deep dive

Open Task Manager, flip a startup app to Disabled, and sign in again: the app doesn't launch. Now look at HKCU\Software\Microsoft\Windows\CurrentVersion\Run — the entry is still there, command line intact. Something else remembered your choice. This post is about that something, byte by byte.

Two registry keys, one state

Windows splits "what would run" from "whether it's allowed to" across two locations:

HKCU\…\CurrentVersion\Run
the command — name → command line (what to launch at sign-in)
HKCU\…\Explorer\StartupApproved\Run
the approval — same value name → a 12-byte REG_BINARY stamp

The Run key alone doesn't start anything at sign-in unless StartupApproved either has no entry for that name (interpreted as enabled by default) or has one in the enabled state. Task Manager's Startup tab is a UI over exactly these two keys.

The 12-byte layout

Dump the value in PowerShell and look at it:

terminal / powershell
$b = (Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run').'OneDrive'
$b -join ' '
# 3 0 0 0  1F 4A 22 83  E1 77 DC 01

The twelve bytes break down like this:

byte 0
state02 = enabled, 03 = disabled. This single byte is the whole on/off switch.
bytes 1–3
00 padding/reserved
bytes 4–11
a little-endian FILETIME: 100-nanosecond ticks since 1601-01-01 UTC — the moment the approval state was last written

That's the entire format. No flags, no GUIDs, no machine binding. The rest of the "startup disable" feature is the shell reading byte 0 at logon.

Decoding the timestamp

The FILETIME in the blob is real evidence — it tells you when the entry was last approved or blocked:

terminal / powershell
$bytes = $b[4..11]
[DateTime]::FromFileTimeUtc([BitConverter]::ToInt64($bytes, 0)).ToLocalTime()
# e.g. 2026-06-21 18:42:11  — when someone (or something) last flipped this entry

Tools that dump startup items for forensics (Autoruns, built-in scripts, EDR agents) all read the same two keys; the timestamp is what lets you answer "who disabled Teams last Tuesday." Entry proliferation across users is why the value lives under HKCU: approval is per-account by design.

Why good tools never delete

Batch "optimizer" scripts love to Remove-ItemProperty the Run key. That is a destructive one-way door:

  • The command line is gone. Re-enabling means reinstalling or hand-re-typing the command.
  • If the entry was vendor-mangled (arguments, quoted paths), you have lost the original text forever.
  • Auditing disappears with it — you can't even prove the entry existed.

The approval-blob model is strictly better: the entry stays, the launch is blocked, and flipping byte 0 back to 02 re-enables with the original command intact.

How ProofTune does it

ProofTune's startup toggle writes exactly what Task Manager writes — state byte 02/03, fresh FILETIME — and before touching a blob it captures the full 12 bytes for its journal. "Undo last change" restores that captured blob verbatim, so even the original timestamp survives a round trip.

The Task Manager model is the contract

Anything that touches startup entries should behave as if the user will check Task Manager afterwards:

  1. Never delete Run values — only stamp StartupApproved.
  2. Set the FILETIME to "now" when the user (not a background job) makes the change.
  3. If the blob is missing, treat the entry as enabled — that's Explorer's own default.
  4. Read the command verbatim for display; never edit arguments silently.

Follow those four rules and your tool is instantly compatible with Task Manager, Autoruns, and thirty years of muscle memory.

Edge cases that bite

  • Short blobs are real. Some installers write 4-byte or 8-byte approval stubs. A robust reader treats anything without a full 12-byte layout as "unknown state," never crashes, and shows it as such.
  • Both scopes exist. There's a machine twin at HKLM\…\StartupApproved\Run that does need admin rights to change. Per-account tools have no business there during normal tuning.
  • Disabled-but-re-enabled race: if a vendor updater re-adds its Run entry, the approval blob may or may not survive depending on whether the updater reused the value name. Only an undo model that stores the previous blob (not just "was disabled") can return the system to the true prior state.

The 12 bytes are small. The discipline around them is the whole feature.

ProofTune ProjectEngineering notes — every claim here names the bytes a real tool touches. Verify first, install second.
ProofTune logo

See these exact settings inside the real tool

The browser replica runs the same strings and states as the installed app — click around before you ever install anything.