Registry Parser
All articles

Detecting T1543.003: malicious Windows service persistence

7 min read

MITRE ATT&CK T1543.003, Create or Modify System Process: Windows Service, is the persistence technique that buys an attacker the most for the least effort: a malicious Windows service survives reboots, starts before any user logs in, and runs as LocalSystem if it asks. Every detail of that arrangement is written into the SYSTEM hive, which is what makes service persistence detection a registry problem first and an EDR problem second. The Service Control Manager reads its entire configuration from SYSTEM\CurrentControlSet\Services at boot, so if something is configured to launch as a service, it is in that hive — and you can find it offline, on an acquired image, without ever booting the box. This post is the detection companion to our MITRE ATT&CK and the registry overview, focused on one question: how do you tell the one malicious Windows service apart from the thousand legitimate ones?

Where it lives in the registry

Service definitions sit under SYSTEM\CurrentControlSet\Services\<name>. The key name is the short service name — the one sc.exe and net start use — not the friendly display name. CurrentControlSet is a runtime symlink the kernel resolves at boot to one of the numbered ControlSet00N keys, so on an offline hive you resolve it yourself by reading Select\Current and pointing at the matching ControlSet001 or ControlSet002. (Diffing the two control sets is a cheap manual step that catches changes which landed in only one set; the services plugin deep-dive walks through that gotcha in full.)

Under each service key, T1543.003 is fully described by a handful of values:

  • Start (REG_DWORD) — the load-order control. 0 Boot, 1 System, 2 Auto, 3 Demand, 4 Disabled. Start=2 is the value an attacker wants: auto-start, every boot, no user interaction.
  • Type (REG_DWORD) — 0x1/0x2 for kernel and filesystem drivers, 0x10 for an own-process service (its own .exe), 0x20 for a shared-process service hosted inside svchost.exe.
  • ImagePath — the binary the SCM launches. An .exe for own-process, a .sys under System32\drivers for a driver, or the literal %SystemRoot%\System32\svchost.exe -k <group> line for a shared-process service.
  • Parameters\ServiceDll — for svchost-hosted services, the DLL that actually runs. ImagePath only names svchost.exe; the code is here.
  • ObjectName — the account the service runs under, usually LocalSystem, LocalService, or NetworkService.

Those five values are the whole attack surface. Read all of them; never trust a svchost ImagePath on its own, because for every shared-process service it says the same benign thing.

The malicious patterns

T1543.003 shows up in four shapes, all of them visible in the SYSTEM hive.

A brand-new service pointing at a dropped binary. The crudest and most common variant: sc create, New-Service, or the underlying CreateService API writes a fresh service key with ImagePath aimed at the attacker's binary, Start=2, ObjectName=LocalSystem. PsExec is the canonical example — it drops PSEXESVC to run its payload as SYSTEM. The tell is a service whose name you do not recognise, whose ImagePath is in a non-standard directory, with a recent key LastWrite.

Modifying an existing service's ImagePath. Instead of creating a new key, the attacker repoints a legitimate, disabled, or rarely-used service at their binary. The trustworthy service name stays; the binary behind it changes. This defeats any detection that only watches for unfamiliar service names. Pair it with a Start change and it becomes the next pattern.

Start type changes for boot persistence. Flipping Start from 4 (Disabled) or 3 (Demand) to 2 (Auto) converts a dormant or manually-triggered service into one that launches every boot. The inverse is just as interesting for detection: an attacker setting a security product's service to Start=4 is disabling your EDR or Windows Defender. Both directions are a single DWORD change, and both are invisible unless you baseline Start values.

ServiceDll swap for svchost-hosted services. The most evasive variant. The attacker leaves ImagePath as the normal svchost.exe -k <group> line, leaves the service name alone, and only rewrites Parameters\ServiceDll to point at a malicious DLL. From the outside the service looks completely normal and the code runs inside a legitimate, signed svchost.exe process. This is precisely why ServiceDll deserves its own column in any triage view and why you compare it against what that service's DLL is supposed to be.

What normal looks like

You cannot spot the anomaly without knowing the baseline. On a healthy Windows install:

  • Service ImagePath and ServiceDll values resolve into System32, System32\drivers, or a vendor directory under Program Files. Nothing legitimate launches a service binary out of a user-writable path.
  • svchost-hosted services name a group (-k netsvcs, -k LocalServiceNetworkRestricted, and so on) that actually appears in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost, and the service is a member of that group.
  • The vast majority of service keys carry a LastWrite timestamp clustered around OS install or patch dates. They do not change between Patch Tuesdays.
  • ObjectName is one of the three standard service accounts. A named local or domain user as the run-as account is unusual for a built-in service.
  • The two control sets agree: a service in ControlSet001 exists with the same Start, ImagePath, and ServiceDll in ControlSet002.

Capture a known-good SYSTEM hive from a golden image and treat it as your reference. Most of T1543.003 detection is a diff against that reference, and the rest is sorting by timestamp.

How to hunt it

Service persistence detection comes down to a few mechanical checks against the table of services:

  • Recently-created or recently-modified service keys. Every service key carries a LastWrite timestamp. Sort by it. A cluster of service keys written around your suspected intrusion window, against a backdrop of keys untouched since install, is a strong lead. Caveat: LastWrite updates on any value change, so a recent timestamp means the key was touched, not necessarily created — corroborate creation against the USN journal or the binary's MFT timestamps.
  • ImagePath or ServiceDll in user-writable or temp paths. Anything resolving into %APPDATA%, %LOCALAPPDATA%, \Users\<name>\, \Temp\, \ProgramData\ (a softer signal), or the bare C:\Windows\ root rather than System32 is anomalous. This alone catches most dropped-binary new services.
  • Unsigned or oddly-named binaries. The hive gives you the path, not the signature — but the path is the pivot. Pull the binary referenced by ImagePath/ServiceDll and verify its signature out of band. Random eight-character DLL names, or a binary impersonating a system file from the wrong directory, are classic.
  • svchost services whose ServiceDll is outside System32. A shared-process service with the normal svchost.exe -k line but a ServiceDll resolving anywhere other than System32 is the ServiceDll-swap pattern, full stop.
  • Fabricated svchost groups. Cross-reference each svchost service's -k <group> against the group membership defined in SOFTWARE\...\Svchost. A service claiming a group it is not a member of, or a custom group name absent from the standard svchost config, is a planted host group.
  • Start drift. Diff Start values against your baseline. A security service flipped to 4, or a previously-dormant service flipped to 2, is the boot-persistence pattern.

None of these is conclusive on its own; together they triangulate the malicious service fast.

Investigate it in your browser

You do not need a Perl environment or a live system to run these checks. The parser on this site decodes the same SYSTEM-hive fields the SCM reads — short name, display name, ImagePath, ServiceDll, run-as account, Start, and Type — and resolves CurrentControlSet for you, so you can analyze a SYSTEM hive in your browser and start sorting by LastWrite immediately. Drop the hive in, sort the service table by last-write, scan the ImagePath and ServiceDll columns for anything outside System32, and line the svchost rows up against the group config. The mechanics behind that view — every field, how Start and Type decode, and the control-set diff — are covered in the services plugin deep-dive.

Related techniques

A service is one persistence surface, and an attacker who fails to slip a service past you will fall back to another. Scheduled tasks are the close cousin: T1053.005, which hides in a crowd of legitimate Microsoft tasks and is parsed out of TaskCache — see the taskcache plugin deep-dive. Run keys and Image File Execution Options are the noisier, faster persistence the same actor often plants alongside or instead of a service; the Run keys and IFEO writeup covers those. Hunt them in the same pass. For the full map of which ATT&CK techniques leave registry artifacts and where, start with MITRE ATT&CK and the registry. T1543.003 is the most durable of them, and the SYSTEM hive records every detail offline — read all five values, distrust the svchost ImagePath, baseline Start, and sort by LastWrite. The malicious service is rarely subtle once you know which columns lie to you.