UserAssist et l'historique de lancement de programmes en ROT13
8 min de lecture
UserAssist est l'artefact qui, dans un bon jour, vous dit exactement quel exécutable un utilisateur a lancé, combien de fois, quand pour la dernière fois, et combien de temps le focus a duré. Dans un mauvais jour, il ne vous dit rien parce que le lancement venait d'un service ou d'une tâche planifiée. Savoir quel jour vous avez est la différence entre citer UserAssist comme preuve et le citer comme indice.
La clé, les GUID, l'encodage
Les données vivent sous
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist\
dans le NTUSER.DAT de l'utilisateur. Sous ce chemin vous obtenez une
poignée de sous-clés GUID, chacune suivant une catégorie d'activité
différente. Sur Windows moderne, les deux qui comptent sont :
{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}: exécutables lancés.{F4E57C4B-2036-45F0-A9AB-443BCFE33D9F}: fichiers raccourcis (LNK) invoqués.
Chacun de ces GUID a une sous-clé Count dont les valeurs
enregistrent les lancements. Le nom de la valeur est le chemin
complet vers l'élément lancé, encodé en ROT13. Oui, ROT13. En 2026.
L'encodage n'est pas une mesure de sécurité ; c'est un vestige d'une
vieille politique destinée à rendre les lectures occasionnelles moins
bruyantes. Quiconque a déjà regardé les données brutes l'a maudit une
fois puis a écrit le décodeur de quatre lignes.
HRZR_PGYFRFFNVA décode en UEME_CTLSESSION. P:\Cebtenz Svyrf\Vagrearg Rkcybere\VRKCYBER.RKR décode en C:\Program Files\Internet Explorer\IEXPLORE.EXE. Le décodeur est littéralement
un décalage ±13 sur les alphabétiques, laissant les chiffres et la
ponctuation tels quels.
Deux noms de valeurs non-lancement vivent aussi dans les clés Count et confondent régulièrement les analystes :
UEME_CTLSESSION: un compteur incrémenté au démarrage de session.UEME_CTLCUACount:ctor: un compteur générique lié à l'activation de contrôle. Ignorez pour la plupart.
Tout le reste avec un chemin est un véritable enregistrement de lancement.
Ce qui est dans la donnée de la valeur
La donnée de valeur est une structure binaire de taille fixe. Sur Windows 7 et ultérieur, elle fait 72 octets :
- Décalage 0x00 (4 octets) : ID de session où l'entrée a été touchée pour la dernière fois.
- Décalage 0x04 (4 octets) : compte d'exécutions.
- Décalage 0x08 (4 octets) : compte de focus (nombre de fois que la fenêtre a gagné le focus).
- Décalage 0x0C (4 octets) : temps de focus total en millisecondes, sommé sur les exécutions.
- Décalage 0x10 à 0x3B : champs liés au timer, principalement à zéro en pratique.
- Décalage 0x3C (8 octets) : FILETIME de la dernière exécution.
- Décalage 0x44 (4 octets) : champ final, dépendant de la version.
Sur Windows XP la structure faisait 16 octets avec une disposition différente. Si vous tombez encore sur des ruches XP en 2026, vous avez un autre ensemble de problèmes, mais la logique d'encodage est la même.
Un enregistrement décodé pourrait ressembler à :
Chemin : C:\Users\jdoe\AppData\Local\Programs\PuTTY\putty.exe
Compte exécutions : 12
Compte focus : 27
Temps focus : 3621542 ms (environ 60 minutes)
Dernière exécution : 2026-05-21 14:22:11 UTC
Cet enregistrement seul vous dit : cet utilisateur a lancé PuTTY douze fois via Explorer, avec environ une heure de focus de fenêtre cumulé, avec l'invocation la plus récente à l'horodatage donné.
Pourquoi c'est l'un des meilleurs artefacts d'exécution par
utilisateur
UserAssist vit dans le NTUSER.DAT de l'utilisateur. Il n'y a aucune ambiguïté sur l'attribution. Quand vous trouvez un enregistrement là, la réponse à "qui a lancé cela" est l'utilisateur dont le profil détient la ruche.
Comparez à Shimcache, qui dit "ce binaire était sur le système" mais ne peut vous dire qui l'a lancé. Comparez à AmCache, qui enregistre l'exécution mais est à l'échelle système. Comparez à Prefetch, qui suit l'exécution mais n'attribue pas à un utilisateur. UserAssist est le seul artefact courant qui cloue l'attribution depuis une source unique.
Il suit aussi les comptes d'exécution et le temps de focus. Un binaire lancé 47 fois avec deux heures de focus n'est pas le genre de chose qu'un attaquant insère pour une session unique. Un binaire lancé une fois avec trois secondes de focus peut être exactement cela.
Ce qui n'est pas suivi
C'est la partie qui piège les enquêteurs qui s'appuient sur UserAssist comme s'il était un journal d'exécution complet.
UserAssist enregistre les lancements via :
- Explorer (double-clic, simple clic sur un raccourci épinglé).
- Le menu Démarrer.
- La boîte de dialogue Exécuter (Win+R).
- La barre des tâches.
- Une invocation de fichier LNK.
UserAssist n'enregistre pas les lancements via :
- La ligne de commande (
cmd.exe,powershell.exe). - Les tâches planifiées.
- Les services.
- La création de processus WMI.
- Toute invocation non-GUI par un autre processus.
- L'exécution distante (PsExec, WinRM, RDP-via-rundll).
C'est par conception. Le shell enregistre les lancements pilotés par GUI. Les lancements programmatiques ne passent pas par le shell. Les attaquants qui connaissent cette règle traitent UserAssist comme une fenêtre sur le comportement manuel de l'utilisateur, pas sur le comportement du malware. La même logique s'applique à vous.
Une charge utile malware que l'utilisateur a double-cliquée depuis un lien de phishing apparaîtra dans UserAssist. La même charge utile exécutée par une tâche planifiée créée par le malware n'apparaîtra pas.
Le LastRun qui clignote
Le FILETIME LastRun est mis à jour à chaque lancement. Utile et
volatil. Si vous prélevez une ruche à 14:00 et que l'utilisateur
ouvre le binaire à 14:05, le LastRun a bougé et le précédent a
disparu de la ruche vivante. Acquérez la ruche une fois, à une heure
connue. Traitez cela comme votre état de référence.
Les snapshots VSS sont le filet de sécurité. Si VSS est activé, prenez NTUSER.DAT de chaque snapshot et reconstruisez les changements de LastRun au fil du temps. C'est la différence entre "dernière exécution mardi" et "dernière exécution mardi mais utilisée quotidiennement pendant deux semaines avant cela".
Compte de focus versus compte d'exécution
Le compte d'exécution s'incrémente au lancement. Le compte de focus s'incrémente quand la fenêtre gagne le focus, ce qui peut arriver plusieurs fois par lancement (clics ailleurs, clics retour). Le temps de focus s'accumule pendant que la fenêtre est active.
Un binaire avec compte d'exécution élevé et temps de focus faible a été lancé et écarté : un wrapper de tâche planifiée qui ouvre une fenêtre de console pour une demi-seconde correspond à ce schéma. Compte d'exécution modéré avec temps de focus très élevé est quelque chose que l'utilisateur utilise activement : un tableur, un éditeur, une app de chat.
Cherchant des lancements malicieux, le schéma intéressant est
"compte d'exécution élevé, temps de focus faible" combiné à un chemin
dans %APPDATA% ou %LOCALAPPDATA%\Temp. C'est un binaire lancé à
répétition avec chaque invocation se terminant rapidement.
L'exemple de décodage, de bout en bout
Un nom de valeur UserAssist brut pourrait ressembler à :
P:\Hfref\wqbr\NccQngn\Ybpny\Grzc\flgrk.rkr
Décodage ROT13 : C:\Users\jdoe\AppData\Local\Temp\sytex.exe
Un binaire dans \AppData\Local\Temp\ est suspect par défaut. Un
binaire là qui a des entrées UserAssist en est un que l'utilisateur a
double-cliqué, ce qui signifie qu'il est arrivé via téléchargement,
pièce jointe d'email, ou dépôt USB, et a été ouvert délibérément.
Regardez la donnée de valeur. Supposons que le compte d'exécution
est 1, le compte de focus est 1, le temps de focus est 412 ms. Le
binaire a tourné une fois, brièvement. Cela correspond à un
dropper. Pivotez vers le fichier LNK
dans Recent\, l'entrée Prefetch
pour sytex.exe, l'enregistrement AmCache
pour le fichier. Récupérez le fichier lui-même depuis le
MFT.
Cette séquence reconstruit le moment où un utilisateur a été infecté, avec des horodatages à la seconde et l'attribution complète.
Outils
- Le plugin
userassistde RegRipper. Gère le ROT13, le FILETIME, le compte d'exécution, le temps de focus. Sortie : une ligne par entrée. Lisez la source du plugin si vous voulez voir exactement ce qui est extrait. - RECmd d'Eric Zimmerman avec le fichier de lot
UserAssist. Mêmes sorties en CSV. - L'analyseur de ce site décode UserAssist dans sa vue arbre standard.
La plupart des décodeurs ad-hoc sautent le compte de focus et le temps de focus. Assurez-vous que votre outil fait remonter les quatre nombres, pas seulement le chemin et le LastRun.
Cas limites à connaître
Les profils itinérants peuvent traîner UserAssist entre hôtes. Un utilisateur qui se connecte sur plusieurs hôtes avec un profil itinérant aura un ensemble unique d'entrées UserAssist reflétant l'activité sur l'hôte qui a écrit le profil en dernier. Recoupez avec Prefetch (qui est par hôte) pour déterminer où chaque lancement s'est réellement passé.
Effacer UserAssist est possible mais laisse des traces. Certains
outils de "confidentialité" et utilitaires de classe CCleaner
effacent les valeurs UserAssist. L'effacement lui-même laisse la
sous-clé GUID présente avec un LastWrite récent et un Count vide. Ce
schéma seul est révélateur. Les cellules non allouées récupérées dans
la ruche peuvent encore contenir les valeurs effacées ; le plugin
del de RegRipper et les modes de récupération de yarp les
trouveront.
Les pseudo-chemins Software Distribution et Backup. Certaines
entrées référencent des GUID de dossier shell plutôt que des chemins
réels. {1AC14E77-02E7-4E5D-B744-2EB1AE5198B7} est System32.
{F38BF404-1D43-42F2-9305-67DE0B28FC23} est Windows. Un décodeur
qui ne les résout pas montrera des GUID dans le chemin, déroutant
mais techniquement correct.
Pour aller plus loin
- Didier Stevens, UserAssist : l'ingénierie inverse publique originale du format, toujours utile.
- La source du plugin
userassistde RegRipper. - Le blog Windows Incident Response d'Harlan Carvey : cherchez UserAssist ; il y a des années de notes.
UserAssist ne résoudra pas votre dossier seul. Combiné à Prefetch,
AmCache et les fichiers LNK dans Recent\, il répond à "qui a lancé
quoi, quand, et pendant combien de temps" avec une confiance que
presque rien d'autre sur le système n'égale. Rappelez-vous juste ce
qu'il ne voit pas, et pivotez vers d'autres artefacts pour couvrir
le manque.