Skip to content

04 · Evidence of Execution

SRUM Forensics: App Usage and Network Bytes per Hour

Use SRUM (SRUDB.dat) to prove which apps ran, under which user, and how many bytes they sent: tables, ID mapping, dirty database repair, SrumECmd, pitfalls.

Published on 9 min read

This guide shows you how to extract, repair and read the System Resource Usage Monitor database so you can say which applications ran on a Windows host, under which account, in which hour, and how much data each of them moved over the network. It is the artifact to reach for when the question is "was data exfiltrated, by what, and when?"

What SRUM is and why it matters

SRUM was introduced in Windows 8 to feed the battery and data usage pages of Settings. Every hour or so, a set of providers hosted by the Diagnostic Policy Service (DPS) writes aggregated counters into SRUDB.dat, an ESE database. Nobody configures it, most attackers do not think about it, and it survives the deletion of the tools it describes.

Three properties make it unique among evidence of execution sources:

  • Per-user attribution: every record carries a user SID.
  • Network volume per application: bytes sent and received for each process, per interface.
  • History: weeks of hourly data, where Prefetch or BAM often keep only the latest run.

The SRUM cheat sheet summarises the artifact; this guide walks through an investigation.

Where the data lives

ItemPathWhy you need it
DatabaseC:\Windows\System32\sru\SRUDB.datAll provider tables
ESE logs and checkpointC:\Windows\System32\sru\SRU*.log, SRUtmp.log, SRUres*.jrs, SRU.chkReplay uncommitted transactions
Provider registrationHKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SRUM\ExtensionsLists the provider GUIDs present on this build
SOFTWARE hiveC:\Windows\System32\config\SOFTWARE (+ .LOG1, .LOG2)Resolves network profile IDs to names; may hold pending SRUM data

Collect the whole sru folder and the SOFTWARE hive with its transaction logs. Without the hive, network profiles stay as bare numbers.

Tables that matter

SRUM tables are named after the provider GUID. The ones used in almost every case:

TableGUIDKey columnsAnswers
Application Resource Usage{D10CA2FE-6FCF-4F6D-848E-B2E99266FA89}ForegroundCycleTime, BackgroundCycleTime, FaceTime, foreground and background bytes read and writtenDid this app run, how hard, and did it touch the disk heavily?
Network Data Usage{973F5D5C-1D90-4944-BE8E-24B94231A174}BytesSent, BytesRecvd, InterfaceLuid, L2ProfileIdHow much did this app send and receive, over which network?
Network Connectivity{DD6636C4-8929-4683-974E-22C046A43763}ConnectedTime, ConnectStartTime, InterfaceLuid, L2ProfileIdWhich networks was the host on, and for how long?
Energy Usage{FEE4E14F-02A9-4550-B5CE-5FA2DA202E37} (and an LT long-term variant)Charge level, capacity, cycle countWas the laptop running on battery, awake, charging?
Push Notifications{D10CA2FE-6FCF-4F6D-848E-B2E99266FA86}Notification counts and payload sizes per appWhich apps were receiving notifications
SruDbIdMapTablenoneIdType, IdIndex, IdBlobTranslates the numeric AppId and UserId in every other table

The exact set of tables varies by Windows version and edition; check the Extensions key and the database itself rather than assuming. Every data table shares AutoIncId, TimeStamp, AppId and UserId.

SruDbIdMapTable

The data tables never store a path or a SID directly. AppId and UserId are indexes into SruDbIdMapTable, where IdBlob holds the actual value and IdType says what kind of value it is: an application path, a service or packaged app name, or a user SID stored in binary form. Parsers do this join for you, but when a value looks odd (an empty app name, an unresolved SID) go back to the raw map. Paths are usually stored as device paths, for example \Device\HarddiskVolume3\Users\jdoe\AppData\Local\Temp\rclone.exe, so you need the volume mapping to translate them to drive letters.

Network interfaces and profiles

InterfaceLuid encodes the interface type: decoded, it tells wired Ethernet from Wi-Fi or mobile broadband. L2ProfileId points to a WLAN or wired profile; with the SOFTWARE hive supplied, SrumECmd resolves it to a profile name such as the Wi-Fi SSID. That is how you show a laptop was on a personal hotspot, not the corporate network, while a large upload happened. See network profiles for the registry side.

Timing: hourly buckets, not events

Two facts shape every SRUM conclusion.

Write interval. Providers aggregate in memory and flush roughly every 60 minutes, with some reports of shorter intervals for certain providers, and also flush at shutdown. The TimeStamp of a record is when the bucket was written, in UTC. It marks the end of an aggregation window, not the moment of activity. A 3 GB upload shown at 14:02 happened during the preceding window, not at 14:02.

Retention. Detailed tables are commonly kept for around 30 days, and various sources report up to about 60 days depending on the table and build; long-term energy tables can go back further. Always read the oldest TimeStamp per table in your data and state that range in the report.

Treat all SRUM times as UTC (UTC and local time) and correlate by hour, not by second.

Collection

The database is locked by the running service. Copy it through a shadow copy with esentutl, which also handles the ESE page format correctly:

mkdir E:\case\sru
esentutl.exe /y C:\Windows\System32\sru\SRUDB.dat /vss /d E:\case\sru\SRUDB.dat
robocopy C:\Windows\System32\sru E:\case\sru SRU*.log SRU.chk /COPY:DAT
reg save HKLM\SOFTWARE E:\case\SOFTWARE.hiv

On a dead-box image, simply export the folder and the SOFTWARE hive with its logs. KAPE's SRUM target collects both (see acquisition and triage); Velociraptor offers the SRUM triage target and the Windows.Forensics.SRUM artifact for live parsing. During live response, grab SRUM early: it is cheap and it covers weeks.

Repairing a dirty database

A copy of a live ESE database is almost always in Dirty Shutdown state, and some parsers refuse it. Check the header first, on a working copy, never on your only copy:

cd /d E:\case\sru
esentutl.exe /mh SRUDB.dat | findstr /i "State"

If the state is Dirty Shutdown, replay the logs. The base name of SRUM log files is sru, and /i tells ESE to ignore missing or mismatched attached databases:

esentutl.exe /r sru /i
esentutl.exe /mh SRUDB.dat | findstr /i "State"

Run it from the folder that holds both the database and the logs, ideally on a system whose ESE version is at least as recent as the source. If recovery fails, esentutl /p SRUDB.dat performs a destructive repair that discards damaged pages: use it only on a second copy and document it. SrumECmd can also attempt the repair itself on a copy when it detects a dirty database.

Parsing

SrumECmd (Eric Zimmerman) is the usual choice. Point it at the database and the SOFTWARE hive:

SrumECmd.exe -f E:\case\sru\SRUDB.dat -r E:\case\SOFTWARE.hiv --csv E:\out\srum
:: Or let it find both in a KAPE-style folder tree
SrumECmd.exe -d E:\case\C --csv E:\out\srum

It writes one CSV per table (AppResourceUseInfo, NetworkUsages, NetworkConnections, EnergyUsage, PushNotifications and others) with AppId, UserId and SIDs already resolved.

srum-dump (Mark Baggett) produces an annotated spreadsheet from a configurable template, which is convenient for reviewers who live in Excel. Its command-line arguments have changed between versions, so check the help of the build you use. For a quick look without tooling, NirSoft's AppResourcesUsageView and NetworkUsageView read SRUM on a live system.

Investigation patterns

Exfiltration window

Load NetworkUsages, sum BytesSent per application per hour and sort descending. Legitimate heavy uploaders (OneDrive, Teams, backup agents, browsers during video calls) set the baseline for this user. What stands out:

  • Command-line transfer tools: rclone.exe, curl.exe, winscp.exe, pscp.exe, megacmd-style clients.
  • A browser with an outbound spike that matches a visit to a file-sharing site in browser history.
  • Archivers (7z.exe, rar.exe, WinRAR.exe) with high disk write in Application Resource Usage just before the upload hour.
  • Remote access tools such as AnyDesk or TeamViewer sending far more than they receive, which suggests file transfer out (remote access tool forensics).
  • svchost.exe spikes that line up with BITS jobs.

Then report the ratio of sent to received and the network profile. "rclone.exe, under jdoe's SID, sent about 4.1 GB between 01:00 and 03:00 UTC over the Wi-Fi profile Jay iPhone" is a precise, defensible statement.

Proving a deleted tool ran

When the binary, its Prefetch file and its Amcache entry are gone, a SRUM row for \Device\HarddiskVolume3\Users\Public\x.exe with CPU cycle time still shows it ran, under which user, and during which hours. That also narrows the window for volume shadow copies that might still contain the file. The evidence of execution guide covers how SRUM fits with the other sources.

Service accounts and SYSTEM

Records under S-1-5-18 (SYSTEM) or service SIDs for binaries in user-writable paths are a strong lead for persistence or a remote execution tool. Cross-check with service installation events and scheduled tasks.

Proving the host was active

Network Connectivity and Energy Usage together show whether a laptop was on, on battery, and connected to which network at a given hour. That can confirm or refute an alibi ("the laptop was closed all weekend") far better than logon events alone.

Reporting SRUM findings

SRUM numbers invite over-precision. Write them as what they are: aggregated counters for a window, attributed to an application path and a SID. Give the bucket boundaries in UTC, the table the value came from, and the parser and version used. When you sum several hours, say so, and keep the per-hour rows in an appendix so a reviewer can check the arithmetic. Byte counts include protocol overhead and retransmissions, so a 4.1 GB BytesSent total does not mean exactly 4.1 GB of files left the network. Finally, describe what SRUM cannot show (destination, file names, exact start time) and name the sources you used to fill those gaps. A report that states these limits up front is much harder to attack in review or in court.

Pitfalls

  • Treating TimeStamp as event time. It is the end of an aggregation bucket, usually an hour.
  • Expecting destinations. SRUM has byte counts, not IPs or domains.
  • Ignoring the dirty state. A parser that silently skips uncommitted data can make the last hours look empty.
  • Missing recent data. A live copy may lack the last, unflushed hour.
  • Parsing without the SOFTWARE hive. Network profile names stay unresolved.
  • Over-reading device paths. HarddiskVolumeN must be mapped to a drive letter, and removable volumes change numbers.
  • Assuming completeness. Some processes are attributed to hosting processes (svchost.exe, packaged app containers), and very short-lived activity can fall below what the provider records.
  • Reading a small database as "nothing happened". Deleting SRUDB.dat requires stopping DPS; a database that starts recently while the system is old is a finding for anti-forensics.

Workflow checklist

  1. Collect C:\Windows\System32\sru\ in full and the SOFTWARE hive with .LOG1 and .LOG2, from a shadow copy or image.
  2. Hash the originals, work on copies.
  3. Check the state with esentutl /mh; replay logs with esentutl /r sru /i if dirty.
  4. Parse with SrumECmd (-f and -r) and note the oldest and newest TimeStamp per table.
  5. Resolve device paths to drive letters and SIDs to accounts.
  6. In NetworkUsages, rank apps by BytesSent per hour and per network profile; flag transfer tools, archivers, browsers and remote access tools.
  7. In AppResourceUseInfo, confirm execution of suspicious binaries and look for heavy disk writes before uploads.
  8. Correlate each SRUM hour with Prefetch, Amcache, BAM, browser history, firewall and proxy logs, and build the timeline in UTC.

Area 04

Evidence of Execution

The artifact cheat sheets behind this guide: location by Windows version, what each one proves and the tools to parse it.

Related articles