Skip to content

__EventFilterEventConsumer

WMI Parser

Find WMI event subscriptions — the filter, the consumer and the binding that ties them — in the CIM repository. Live objects through the index, deleted ones carved from free space. Parsed in your browser with WebAssembly; nothing is uploaded.

  • OBJECTS.DATA
  • INDEX.BTR
  • MAPPING1-3.MAP
  • CCM_RecentlyUsedApps

Drop the WMI Repository folder here

OBJECTS.DATA alone is enough to carve filters, consumers and bindings, deleted ones included. Add INDEX.BTR and MAPPING1-3.MAP for the structured view: namespaces, and live versus deleted. Folders and ZIP triage collections (KAPE, Velociraptor) work as-is.

A synthetic repository from a fictional intrusion — no real data, no working payloads. Tip: open the IntelPerfMonitor binding, then switch to Evidence of execution (SCCM) and center the time range on m64.exe (±1 h).

100% client-side: the repository is parsed by WebAssembly in your browser and never uploaded.

How to get your data

Full acquisition guide

Collect the whole C:\Windows\System32\wbem\Repository folder — OBJECTS.DATA, INDEX.BTR and MAPPING1-3.MAP from the same moment — then drop it here. On a live machine the files are locked by the WMI service, so read them from a shadow copy.

  1. Copy the Repository folder
  2. Drop the folder or ZIP here
  3. Parsed in your browser, never uploaded

Paste into Windows PowerShell run as administrator (system drive C:). It creates one shadow copy so all repository files come from the same instant, copies the Repository folder, then removes the snapshot.

PowerShell · Admin
New-Item -ItemType Directory -Force -Path C:\triage | Out-Null
$sc = Invoke-CimMethod -ClassName Win32_ShadowCopy -MethodName Create -Arguments @{ Volume = 'C:\' }
$vss = Get-CimInstance -ClassName Win32_ShadowCopy -Filter "ID='$($sc.ShadowID)'"
cmd /c mklink /d C:\triage\vss "$($vss.DeviceObject)\"
robocopy C:\triage\vss\Windows\System32\wbem\Repository C:\triage\Repository /E /B /R:0 /W:0 /NP /NDL
cmd /c rmdir C:\triage\vss
$vss | Remove-CimInstance

Result: C:\triage\Repository with OBJECTS.DATA, INDEX.BTR and the MAPPING files. Drop that folder here (drag it, or use Choose a folder).

Analysing on another machine? Pack it into one ZIP with the tar.exe built into Windows 10 1803 and later (a ZIP made with PowerShell's Compress-Archive works too):

PowerShell / cmd
tar -a -c -f C:\triage\wmi-repository.zip -C C:\triage Repository

Just want a quick look first? This lists the live bindings only (no deleted objects, and it asks WMI itself, so a tampered WMI can hide things):

PowerShell · Admin
'__EventFilter','__EventConsumer','__FilterToConsumerBinding' | ForEach-Object { Get-CimInstance -Namespace root/subscription -ClassName $_ } | Format-List *

ConfigMgr client? CCM_RecentlyUsedApps lives in the same repository, so the copy above already holds it. To check first whether the Configuration Manager client is installed (service CcmExec, namespace root\ccm) and peek at the live records:

PowerShell · Admin
Get-Service CcmExec -ErrorAction SilentlyContinue
Get-CimInstance -Namespace root/ccm/SoftwareMeteringAgent -ClassName CCM_RecentlyUsedApps |
  Sort-Object LastUsedTime -Descending |
  Select-Object LastUsedTime, LastUserName, FolderPath, ExplorerFileName, LaunchCount, CompanyName, ProductName |
  Format-Table -AutoSize

Gotchas

  • A plain copy fails while the WMI service runs. Don't stop the service to copy the files: it rewrites the repository and can drop deleted records. Use the shadow-copy command, KAPE or Velociraptor.
  • Take all files at the same instant. An INDEX.BTR or MAPPING file from another moment breaks the structured view (carving still works and the tool warns).
  • Deleted subscriptions survive only until WMI reuses their pages: collect early, before reboots and software installs.

What is a WMI event subscription?

WMI (Windows Management Instrumentation) can run an action when something happens. A permanent event subscription has three parts: an __EventFilter (a WQL query describing the event), an event consumer (what to do: run a command line, a VBScript/JScript, write a log line, an event log entry or an e-mail) and a __FilterToConsumerBinding that ties the two together.

Subscriptions are stored in the WMI (CIM) repository and survive reboots. Their actions run as SYSTEM — a command line started by the WMI provider host (WmiPrvSE.exe), or a script run by scrcons.exe — with nothing in a Run key or a scheduled task. That is why attackers use them for persistence (MITRE ATT&CK T1546.003), and why they are easy to miss.

Where it is stored

  • C:\Windows\System32\wbem\Repository\OBJECTS.DATA — every class definition and instance, in 8 KiB pages. Freed pages keep their old content until reused.
  • INDEX.BTR — a B-tree of keys such as NS_<hash>\CI_<hash>\IL_<hash>.<page>.<record>.<length>, where each hash is the SHA-256 (MD5 on XP) of an upper-cased name.
  • MAPPING1.MAP, MAPPING2.MAP, MAPPING3.MAP — logical-to-physical page maps for OBJECTS.DATA and INDEX.BTR; Windows keeps three generations and uses the newest.
  • Subscriptions normally live in the root\subscription namespace, but any namespace works.

What this tool shows

  • Every binding joined to its filter (the trigger query) and its consumer (the command line, script, log file or event log target).
  • Two ways of finding each object, always labelled: structured (through INDEX.BTR and the current MAPPING file, like python-cim) and carving (a scan of all of OBJECTS.DATA for record headers and binding text, like PyWMIPersistenceFinder).
  • Deleted and older versions of objects recovered from freed pages and page slack, told apart from live ones when the MAPPING files are present.
  • Findings with reasons: encoded PowerShell, user-writable paths, script consumers, persistence triggers (uptime, logon, timers), bindings outside root\subscription, unbound or broken pieces, and Windows' own defaults (SCM Event Log and BVT) recognised by name and content.
  • On machines with the Configuration Manager client: CCM_RecentlyUsedApps as evidence of execution — path, user, LastUsedTime, launch count and version information, including older copies carved from freed space, with a time range and findings.

Limitations

  • WMI subscription objects carry no documented timestamps. Each instance header holds two undocumented FILETIMEs, shown as leads; the subscription views have no time filter (the SCCM view does: LastUsedTime is a real time).
  • Carved records have no namespace, and a record split over non-adjacent freed pages may only be partly readable.
  • Without INDEX.BTR and a MAPPING file, class layouts come from a built-in copy of the standard Windows classes (validated on each record), and live and deleted records cannot be told apart.
  • MOF files, the AutoRecover list and other persistence places are out of scope; the Windows XP layout is supported with less testing.

How to get the files

  • Collect the whole Repository folder with KAPE (WBEM target), Velociraptor (Windows.Triage.Targets, WBEM) or from a disk image.
  • On a live system, read the files from a volume shadow copy so they all come from the same instant. Never stop the WMI service to copy them.
  • Keep older copies too (shadow copies, Windows.old): a deleted subscription may still be there.

Credits and method

  • flare-wmi / python-cim — Willi Ballenthin, FireEye (now Mandiant). The repository structures — MAPPING files, INDEX.BTR pages, OBJECTS.DATA table of contents, class definition and instance headers — are ported from python-cim, and the structured mode follows its object resolver. Apache-2.0.
  • PyWMIPersistenceFinder — David Pany, Mandiant. The string-carving pass follows its idea: find __FilterToConsumerBinding text and its EventConsumer.Name / __EventFilter.Name references anywhere in OBJECTS.DATA, and treat BVT and SCM Event Log bindings as common defaults. MIT.
  • WMI Attacks, Defense and Forensics (DEF CON 23) — William Ballenthin, Matt Graeber, Claudiu Teodorescu (FireEye, 2015). The talk (and companion white paper) that documented the repository format and WMI persistence; slides and demos are kept in the flare-wmi repository.
  • [MS-WMIO]: WMI Encoding Version 1.0 Protocol — Microsoft. The public specification of the object encoding inside each record: class parts, NdTable, value table, heap and encoded strings.

FAQ

Is my repository uploaded anywhere?

No. The parser is Rust compiled to WebAssembly and runs in a Web Worker in your browser. There is no upload endpoint.

Is OBJECTS.DATA enough?

Yes for finding subscriptions: carving mode scans every byte for filter, consumer and binding records, deleted ones included. With INDEX.BTR and the MAPPING files you also get namespaces and a reliable live/deleted verdict.

What do “Index”, “Carved record” and “String match” mean?

They say how an object was found. Index: through INDEX.BTR and the current MAPPING file, so it is live. Carved record: its record header was found by scanning OBJECTS.DATA; if it is not also indexed, it sits in freed space. String match: only the binding's text survived, the way PyWMIPersistenceFinder finds bindings.

Are SCM Event Log Consumer and BVTConsumer malicious?

No, when they match what Windows installs: the SCM Event Log binding ships with Windows Vista and later, and the BVT binding (cscript KernCap.vbs) is a harmless leftover on Windows 7-era images. The tool checks the content too and flags a default name with different content.

Can it tell when a subscription was created?

Not reliably. The repository stores no documented per-object timestamp. Each instance header has two FILETIMEs that often track when the instance was written; they are shown as leads. Correlate with event ID 5861 in Microsoft-Windows-WMI-Activity/Operational, which logs new permanent consumers.

What is the Evidence of execution (SCCM) view?

On machines with the Configuration Manager (SCCM / ConfigMgr) client, the repository also holds CCM_RecentlyUsedApps in root\ccm\SoftwareMeteringAgent: one record per executable and user with LastUsedTime (that user's last launch, a CIM DATETIME carrying its UTC offset), a launch count and the file's version information. The tool reads it from the same OBJECTS.DATA, carves older copies from freed space and adds a time range. Without the ConfigMgr client there is no such data.

Read CCM_RecentlyUsedApps from the WMI repository: which programs each user ran, when last and how often, including older copies carved from OBJECTS.DATA.
Step-by-step checklist for WMI persistence: live queries, the repository, event IDs 5860 and 5861, Sysmon 19-21, execution evidence and a safe clean-up.
The two WMI subscriptions Windows ships — SCM Event Log and BVTFilter/BVTConsumer — what they contain, why they are harmless, and how attackers can abuse the names.