Skip to content

Gelöschte WMI-Persistenz aus OBJECTS.DATA wiederherstellen

Warum gelöschte WMI-Filter, Consumer und Bindings in OBJECTS.DATA überleben, Index vs. Carving und python-cim vs. PyWMIPersistenceFinder.

Veröffentlicht am 5 Min. Lesezeit

Kurz gesagt. Das Löschen einer WMI-Subscription löscht sie nicht wirklich. Ihre Bytes bleiben in OBJECTS.DATA, bis WMI den Speicher wiederverwendet. Die Auswertung des Index (der Ansatz von python-cim) liefert, was aktiv ist; ein Scan der gesamten Datei (wie ihn David Panys PyWMIPersistenceFinder mit Text durchführt) findet auch, was entfernt wurde. Nutzen Sie beides und halten Sie fest, welche Methode was gefunden hat.

Warum gelöschte Objekte überleben

Das Repository ist ein Seitenspeicher. Wird eine Instanz gelöscht oder neu geschrieben, aktualisiert WMI INDEX.BTR und schreibt eine neue Generation der MAPPING-Datei. Der alte Datensatz wird nicht genullt:

  • wird seine ganze Seite freigegeben, ist die Seite nicht zugeordnet — nicht mehr referenziert, Bytes unverändert;
  • bleiben andere Datensätze in der Seite, wird der Bereich des Datensatzes zu Slack innerhalb einer weiterhin genutzten Seite.

In beiden Fällen behält der Datensatz seinen Header — den SHA-256 seines Klassennamens in UTF-16 — und seinen Heap mit Strings: die Abfrage, die Befehlszeile, das Skript, die Binding-Referenzen. Bis dort etwas anderes geschrieben wird, ist er wiederherstellbar. Wie lange das dauert, hängt davon ab, wie aktiv WMI auf dem Host ist: Sichern Sie früh.

Zwei Wege, ein Repository zu lesen

Strukturiert: dem Index folgen

So arbeitet python-cim, und so arbeitet Windows. Schlüssel in INDEX.BTR wie NS_…/CI_<hash("__EVENTFILTER")>/IL_….page.record.length verweisen über die aktuelle MAPPING-Datei auf einen Datensatz. Die Klassendefinitionen geben jeder Eigenschaft Namen, Typ und Position, sodass jeder Wert exakt dekodiert wird — einschließlich Klassenstandards und des Namespace jedes Objekts.

Dieser Weg sieht nur, was der Index referenziert: aktive Objekte.

Carving: jedes Byte durchsuchen

Zwei Varianten:

  • Record Carving. OBJECTS.DATA nach den Hashes der Klassennamen von __EventFilter, __FilterToConsumerBinding und den Consumer-Klassen durchsuchen. Jeder Treffer ist der Anfang eines Instanzdatensatzes, aktiv oder nicht. Mit dem Klassenlayout dekodieren und die Konsistenz prüfen: Der Heap des Datensatzes muss genau dort enden, wo der Header es angibt, und mit dem Klassennamen beginnen.
  • String Carving. Die Idee von PyWMIPersistenceFinder: nach __FilterToConsumerBinding gefolgt von …EventConsumer.Name="…" und __EventFilter.Name="…" suchen, dann nach der Abfrage des Filters und dem Befehl des Consumers neben ihren Namen. Das braucht keinerlei Struktur und funktioniert daher auch, wenn der Header eines Datensatzes überschrieben wurde — um den Preis, raten zu müssen, welcher String welcher ist.

Carving sieht alles, kann aber allein nicht sagen, ob ein Treffer aktiv ist. Diese Einstufung liefert die MAPPING-Datei: Ein Treffer in einer zugeordneten Seite, innerhalb eines Eintrags im Inhaltsverzeichnis, ist belegt; ein Treffer in einer nicht zugeordneten Seite oder im Slack ist freigegeben.

Wie WMI Parser beides kombiniert

WMI Parser wertet den Index aus, wenn INDEX.BTR und eine MAPPING-Datei vorliegen, carvt anschließend immer die gesamte Datei und führt die Ergebnisse zusammen. Jedes Objekt zeigt, wie es gefunden wurde:

KennzeichnungBedeutung
IndexÜber INDEX.BTR und die aktuelle Zuordnung erreicht: aktiv
Gecarvter DatensatzDatensatz-Header beim Scan gefunden; mit dem Klassenlayout dekodiert
String-TrefferNur der Text des Bindings ist erhalten (wie bei PyWMIPersistenceFinder)

Eine gecarvte Kopie, die mit einem aktiven Objekt identisch ist, wird diesem als zusätzlicher Fundort zugeordnet. Eine abweichende gecarvte Kopie wird separat als Wiederhergestellt aufgeführt und, falls ein aktives Objekt denselben Schlüssel hat, als ältere Version markiert. Das Beispiel-Repository zeigt alle drei Fälle: einen gelöschten Anmelde-Filter und sein Binding, gefunden per Record Carving und erneut als Fragment ohne Header im Page Slack; sowie eine ältere Version eines Consumers, der einen kodierten PowerShell-Befehl ausführte, bevor er auf C:\ProgramData\Intel\m64.exe -svc geändert wurde.

Wiederhergestellte Objekte sorgfältig lesen

  • Kein Namespace. Datensätze speichern ihren Namespace nicht; nur der Index kennt ihn. Ein wiederhergestelltes Binding kann in root\subscription oder anderswo gelegen haben.
  • Geteilte Datensätze. Ein Datensatz, der länger als seine Seite ist, setzt sich auf der nächsten logischen Seite fort, die physisch überall liegen kann. Nach der Freigabe lassen sich die Teile schwer zusammensetzen; WMI Parser meldet dann einen unvollständigen Lesevorgang.
  • Layouts. Ohne die Klassendefinitionen des Repositorys (nur OBJECTS.DATA abgelegt) stützt sich die Dekodierung auf das integrierte Layout der Windows-Standardklassen und auf die oben genannten Selbstprüfungen. Eigene Consumer-Klassen werden dann nur über ihren Binding-Text gefunden.
  • Zeit. Instanz-Header enthalten zwei undokumentierte FILETIMEs. Sie folgen oft dem Schreibzeitpunkt der jeweiligen Kopie, was beim Ordnen von Versionen helfen kann, sind aber keine dokumentierten Erstellungsdaten.

Ein wiederhergestelltes Binding beweist, dass die Subscription irgendwann existierte, nicht, dass sie ausgeführt wurde. Suchen Sie nach Ausführungsspuren der Payload des Consumers (Prefetch, Amcache, Ereignisprotokolle) und nach den WMI-Activity-Ereignissen aus der Checkliste für die Untersuchung.

FAQ

Lässt sich eine gelöschte WMI-Subscription wiederherstellen?

Oft ja. Beim Löschen eines Objekts wird sein Seiten- oder Datensatzbereich in OBJECTS.DATA freigegeben, aber nicht überschrieben. Filter, Consumer oder Binding lassen sich daher carven, bis WMI diesen Bereich wiederverwendet.

Worin unterscheiden sich python-cim und PyWMIPersistenceFinder?

python-cim durchläuft INDEX.BTR und die MAPPING-Datei, um aktive Objekte mit ihren Klassenlayouts zu dekodieren. PyWMIPersistenceFinder durchsucht OBJECTS.DATA nach Binding-Text; das braucht nur diese eine Datei und kann gelöschte Datensätze treffen, dekodiert aber weniger.

Wie erkenne ich, ob ein wiederhergestelltes Objekt gelöscht oder nur älter ist?

Existiert ein aktives Objekt mit demselben Schlüssel und weicht dessen Inhalt ab, ist die wiederhergestellte Kopie sehr wahrscheinlich eine frühere Version. Hat kein aktives Objekt diesen Schlüssel, wurde es gelöscht.

Verwandte Artikel

Verwandte Artikel

CCM_RecentlyUsedApps aus dem WMI-Repository lesen: welche Programme jeder Benutzer wann zuletzt und wie oft startete, inklusive älterer Kopien aus OBJECTS.DATA.
Schritt-für-Schritt-Checkliste zu WMI-Persistenz: Live-Abfragen, Repository, Ereignis-IDs 5860 und 5861, Sysmon 19–21, Ausführungsspuren und Bereinigung.
Die zwei WMI-Subscriptions von Windows — SCM Event Log und BVTFilter/BVTConsumer: Inhalt, warum sie harmlos sind und wie Angreifer die Namen missbrauchen.