Skip to content

Récupérer une persistance WMI supprimée dans OBJECTS.DATA

Pourquoi filtres, consommateurs et liaisons WMI supprimés subsistent dans OBJECTS.DATA : parcours d'index, carving, python-cim et PyWMIPersistenceFinder.

Publié le 6 min de lecture

En bref. Supprimer un abonnement WMI ne l'efface pas. Ses octets restent dans OBJECTS.DATA jusqu'à ce que WMI réutilise l'espace. Parcourir l'index (l'approche de python-cim) donne ce qui est actif ; balayer l'intégralité du fichier (comme le fait PyWMIPersistenceFinder de David Pany, sur le texte) retrouve aussi ce qui a été supprimé. Utilisez les deux, et notez quelle méthode a trouvé quoi.

Pourquoi les objets supprimés subsistent

Le dépôt est un stockage organisé en pages. Lorsqu'une instance est supprimée ou réécrite, WMI met à jour INDEX.BTR et écrit une nouvelle génération du fichier MAPPING. L'ancien enregistrement n'est pas mis à zéro :

  • si sa page entière est libérée, la page devient non mappée : plus référencée, mais ses octets restent intacts ;
  • si d'autres enregistrements restent dans la page, l'espace de l'enregistrement devient du slack (espace résiduel) au sein d'une page toujours utilisée.

Dans les deux cas, l'enregistrement conserve son en-tête (le SHA-256 UTF-16 du nom de sa classe) et son tas de chaînes : la requête, la ligne de commande, le script, les références de la liaison. Tant qu'aucune autre écriture ne l'écrase, il reste récupérable. Cette durée dépend de l'activité de WMI sur l'hôte : procédez tôt à la collecte.

Deux façons de lire un dépôt

Lecture structurée : suivre l'index

C'est ainsi que fonctionne python-cim, et c'est ce que fait Windows. Les clés d'INDEX.BTR telles que NS_…/CI_<hash("__EVENTFILTER")>/IL_….page.record.length pointent, via le fichier MAPPING courant, vers un enregistrement. Les définitions de classe donnent à chaque propriété son nom, son type et son emplacement : chaque valeur est donc décodée exactement, y compris les valeurs par défaut de la classe et l'espace de noms de chaque objet.

Cette méthode ne voit que ce que l'index référence : les objets actifs.

Carving : balayer chaque octet

Deux variantes :

  • Carving d'enregistrements. Rechercher dans OBJECTS.DATA les hachages des noms de classe __EventFilter, __FilterToConsumerBinding et des classes de consommateurs. Chaque occurrence marque le début d'un enregistrement d'instance, actif ou non. On le décode avec la structure de la classe, puis on vérifie sa cohérence : le tas de l'enregistrement doit se terminer exactement là où l'indique son en-tête, et commencer par le nom de la classe.
  • Carving de chaînes. L'idée de PyWMIPersistenceFinder : chercher __FilterToConsumerBinding suivi de …EventConsumer.Name="…" et __EventFilter.Name="…", puis la requête du filtre et la commande du consommateur à proximité de leurs noms. Aucune structure n'est nécessaire, ce qui fonctionne encore lorsque l'en-tête d'un enregistrement a été écrasé, au prix d'une part de déduction sur le rôle de chaque chaîne.

Le carving voit tout, mais seul, il ne peut pas dire si une occurrence est active. Ce verdict vient du fichier MAPPING : une occurrence dans une page mappée, à l'intérieur d'une entrée de la table des matières, est utilisée ; une occurrence dans une page non mappée ou dans le slack est libérée.

Comment WMI Parser combine les deux

WMI Parser parcourt l'index lorsque INDEX.BTR et un fichier MAPPING sont présents, puis effectue toujours le carving de l'intégralité du fichier, et fusionne les résultats. Chaque objet indique comment il a été trouvé :

LibelléSignification
IndexAtteint via INDEX.BTR et le mappage courant : actif
Enregistrement extraitEn-tête d'enregistrement trouvé par balayage ; décodé avec la structure de la classe
Correspondance texteSeul le texte de la liaison a subsisté (à la manière de PyWMIPersistenceFinder)

Une copie carvée identique à un objet actif est fusionnée avec lui comme emplacement supplémentaire. Une copie carvée différente est listée séparément comme Récupéré, et si un objet actif possède la même clé, elle est marquée comme version antérieure. Le dépôt d'exemple illustre les trois cas : un filtre d'ouverture de session supprimé et sa liaison, trouvés par carving d'enregistrements puis à nouveau sous forme de fragment sans en-tête dans le slack d'une page ; et une version antérieure d'un consommateur qui exécutait une commande PowerShell encodée avant d'être modifié en C:\ProgramData\Intel\m64.exe -svc.

Lire les objets récupérés avec prudence

  • Pas d'espace de noms. Les enregistrements ne stockent pas leur espace de noms ; seul l'index le connaît. Une liaison récupérée peut avoir résidé dans root\subscription ou ailleurs.
  • Enregistrements fragmentés. Un enregistrement plus long que sa page se poursuit sur la page logique suivante, qui peut se trouver n'importe où physiquement. Une fois libérés, les morceaux sont difficiles à réassembler ; WMI Parser signale alors une lecture partielle.
  • Structures de classe. Sans les définitions de classe du dépôt (si seul OBJECTS.DATA est fourni), le décodage repose sur la structure intégrée des classes Windows standard et sur les vérifications de cohérence ci-dessus. Les classes de consommateurs personnalisées ne sont alors trouvées que par le texte de leur liaison.
  • Horodatage. Les en-têtes d'instance contiennent deux FILETIME non documentés. Ils suivent souvent l'heure d'écriture de cette copie, ce qui peut aider à ordonner les versions, mais ce ne sont pas des dates de création documentées.

Une liaison récupérée prouve que l'abonnement a existé à un moment donné, pas qu'il s'est exécuté. Recherchez des traces d'exécution de la charge utile du consommateur (Prefetch, Amcache, journaux d'événements) ainsi que les événements WMI-Activity décrits dans la checklist d'investigation.

FAQ

Peut-on récupérer un abonnement WMI supprimé ?

Souvent, oui. La suppression d'un objet libère sa page ou l'espace de son enregistrement dans OBJECTS.DATA sans l'effacer : le filtre, le consommateur ou la liaison peut donc être extrait par carving tant que WMI ne réutilise pas cet espace.

Quelle différence entre python-cim et PyWMIPersistenceFinder ?

python-cim parcourt INDEX.BTR et le fichier MAPPING pour décoder les objets actifs à l'aide de la structure de leur classe. PyWMIPersistenceFinder recherche le texte des liaisons dans OBJECTS.DATA : il n'a besoin que de ce seul fichier et peut atteindre des enregistrements supprimés, mais il décode moins d'informations.

Comment savoir si un objet récupéré a été supprimé ou s'il s'agit d'une version antérieure ?

Si un objet actif possède la même clé avec un contenu différent, la copie récupérée est très probablement une version antérieure. Si aucun objet actif ne possède cette clé, l'objet a été supprimé.

Articles liés

Articles liés

Lire CCM_RecentlyUsedApps dans le dépôt WMI : quels programmes chaque utilisateur a lancés, quand et combien de fois, y compris les anciennes copies d'OBJECTS.DATA.
Checklist pas à pas face à une persistance WMI : requêtes en direct, dépôt, événements 5860 et 5861, Sysmon 19-21, traces d'exécution et nettoyage sûr.
Les deux abonnements WMI livrés avec Windows, SCM Event Log et BVTFilter/BVTConsumer : contenu attendu, innocuité et détournement de leurs noms.