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.
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
| Item | Path | Why you need it |
|---|---|---|
| Database | C:\Windows\System32\sru\SRUDB.dat | All provider tables |
| ESE logs and checkpoint | C:\Windows\System32\sru\SRU*.log, SRUtmp.log, SRUres*.jrs, SRU.chk | Replay uncommitted transactions |
| Provider registration | HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SRUM\Extensions | Lists the provider GUIDs present on this build |
| SOFTWARE hive | C:\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:
| Table | GUID | Key columns | Answers |
|---|---|---|---|
| Application Resource Usage | {D10CA2FE-6FCF-4F6D-848E-B2E99266FA89} | ForegroundCycleTime, BackgroundCycleTime, FaceTime, foreground and background bytes read and written | Did this app run, how hard, and did it touch the disk heavily? |
| Network Data Usage | {973F5D5C-1D90-4944-BE8E-24B94231A174} | BytesSent, BytesRecvd, InterfaceLuid, L2ProfileId | How much did this app send and receive, over which network? |
| Network Connectivity | {DD6636C4-8929-4683-974E-22C046A43763} | ConnectedTime, ConnectStartTime, InterfaceLuid, L2ProfileId | Which 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 count | Was the laptop running on battery, awake, charging? |
| Push Notifications | {D10CA2FE-6FCF-4F6D-848E-B2E99266FA86} | Notification counts and payload sizes per app | Which apps were receiving notifications |
SruDbIdMapTable | none | IdType, IdIndex, IdBlob | Translates 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.exespikes 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
TimeStampas 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.
HarddiskVolumeNmust 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
- Collect
C:\Windows\System32\sru\in full and the SOFTWARE hive with.LOG1and.LOG2, from a shadow copy or image. - Hash the originals, work on copies.
- Check the state with
esentutl /mh; replay logs withesentutl /r sru /iif dirty. - Parse with SrumECmd (
-fand-r) and note the oldest and newestTimeStampper table. - Resolve device paths to drive letters and SIDs to accounts.
- In NetworkUsages, rank apps by
BytesSentper hour and per network profile; flag transfer tools, archivers, browsers and remote access tools. - In AppResourceUseInfo, confirm execution of suspicious binaries and look for heavy disk writes before uploads.
- 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.