
A DTrace on Windows Reimplementation
Le traceur de Steve. Une réimplémentation du hook d'appels système de DTrace sur Windows. Considérez cela comme un hook SSDT compatible PatchGuard, mais sans bidouilles. Cela ne prend pas en charge SSSDT (API win32k), car les API d'appel système DTrace elles-mêmes ne prennent pas en charge cette table supplémentaire. Les API noyau Zw* peuvent être tracées en plus de tous les appels système SSDT en mode utilisateur.
Veuillez lire ce readme jusqu'au bout si vous développez de nouveaux plugins pour STrace !
DTrace sur Windows prend en charge plusieurs types de sondes. Cela inclut syscall, fbt, etw, profile, et peut-être d'autres. Cette réimplémentation ne réimplémente que les types de sondes syscall et etw. Tous les autres types de sondes sont considérés comme totalement hors du cadre de ce projet et ne seront jamais pris en charge. N'hésitez pas à forker le projet si vous souhaitez ajouter des types de sondes supplémentaires. Le périmètre a été limité aux seules sondes syscall et etw en raison de la complexité des autres types de sondes et des systèmes qu'ils touchent.
Cette réimplémentation abandonne complètement le langage de script D (notez : PAS DLang, le langage moderne plus populaire). La complexité d'une VM dans le noyau, comme dans l'implémentation DTrace d'origine, ne convient pas à ce projet. Au lieu de cela, cette implémentation expose directement les callbacks C pertinents nécessaires pour se brancher sur les interfaces noyau Windows de DTrace. Pour permettre le 'hot-loading' de scripts, un système de plugins basé sur des DLL a été utilisé en remplacement de l'environnement VM + scripting du dtrace d'origine. Ce système de plugins accepte une DLL 'normale' en mode utilisateur, sans aucun contrôle de sécurité activé ni dépendances externes, et la mappe manuellement dans l'espace d'adressage du noyau. La plugin dll possède des exports qui sont invoqués lorsque des callbacks d'appels système noyau se produisent. Les API noyau sont résolues via la table d'importation (IAT) normale de la DLL ; les DLL plugins se lient à ntoskrnl.lib, puis le pilote résout ces API au moment du chargement, permettant ainsi d'appeler normalement n'importe quelle API système dans les DLL plugins. Les performances de ce système de plugins sont excellentes, car du code natif, plutôt qu'un interpréteur de scripts ou un JIT, s'exécute directement entre ENTRY et RETURN de l'appel système. Cette conception améliore les performances par rapport à l'implémentation dtrace fournie par Microsoft.
La définition de hooks est très simple : vous disposez d'une routine pour enregistrer/désenregistrer un hook par nom d'API, avec un callback avant et après l'appel système. Les callbacks disposent d'arguments et de valeurs de retour accessibles en lecture seule. Les valeurs de retour peuvent être usurpées dans les sondes de retour et les arguments peuvent être modifiés dans les sondes d'entrée, mais l'appel système d'origine ne peut normalement pas remplacer ou 'annuler' un appel système - cette API agit comme un observateur. Il existe cependant une faille similaire à celle documentée dans (https://github.com/everdox/InfinityHook et https://github.com/everdox/InfinityHook/raw/master/resources/perf.png), qui permet de remplacer le pointeur d'appel système sur la pile. Avec cette faille, il est possible de remplacer complètement un appel système par un pointeur vers une routine que vous contrôlez. Lorsque des événements se produisent et que votre callback de hook se déclenche, tout ce que vous souhaitez peut être fait. Les callbacks sont synchrones, ce qui signifie que si vous retardez l'exécution dans le callback d'entrée, par exemple en restant dans une boucle while, l'appel système sera retardé de cette durée. L'exécution de l'appel système se produit juste après le retour du callback d'entrée, et juste avant l'entrée du callback de retour. Ce système est entièrement compatible PatchGuard ; cependant, DSE doit être désactivé, car Microsoft considère malheureusement ce type d'extension de noyau comme faisant partie du noyau NT et valide donc que le signataire racine est Windows. Cela ne fonctionne pas avec des astuces comme l'activation de signataires de noyau personnalisés ; DSE doit vraiment être désactivé pendant le démarrage du noyau.
ValidationFlags=IMGP_LATEST_MS_ROOT_REQUIRED | IMGP_WINDOWS_ROOT_REQUIRED | IMGP_MS_SIGNATURE_REQUIRED
Scenario=ImgSigningScenarioWindows
Le pilote Rust abandonne le système de plugins basé sur des DLL utilisé par le pilote C++ et tente plutôt d'utiliser un interpréteur web assembly pour héberger des scripts wasm dans le noyau Windows. Ceci afin d'être plus similaire à l'implémentation dtrace d'origine, qui utilise une VM, mais avec un meilleur langage que DLang. Cela offre le sandboxing et d'autres avantages intéressants. La POC est complète et fonctionne, mais elle n'est malheureusement pas utilisable en raison de problèmes de performances liés à l'interprétation du WASM avec WASMI. Un moteur wasm basé sur JIT compatible avec le noyau NT serait nécessaire pour que cette conception alternative soit viable. Il est inclus comme une nouveauté amusante et pourrait être utilisable pour autre chose avec un peu de travail.
Ce projet est en grande partie divisé entre ses composants C++ et Rust. Le pilote C est complet sur le plan fonctionnel et doit être privilégié. Dans les grandes lignes, le projet comprend les composants suivants
Configurer Visual Studio avec le DDK
Compilez le pilote et la cli, déplacez les fichiers dans le même dossier que le script, puis exécutez le script powershell dans le dossier d'installation en tant qu'administrateur :
./install_as_admin.ps1
Redémarrez, puis sélectionnez l'entrée de démarrage STrace et appuyez sur F8 (pas Entrée !) sur cet écran :

Cela devrait afficher cet écran ; sélectionnez le démarrage avec DSE désactivé :

Après un démarrage réussi, la CLI peut être utilisée pour charger et décharger les DLL plugins afin de commencer le tracing. Deux exemples de plugins sont fournis. Lisez les détails ci-dessous si vous rencontrez des problèmes. Vous devrez peut-être redémarrer à nouveau la première fois et potentiellement définir manuellement le service STrace pour qu'il démarre automatiquement at boot à l'aide d'un outil tel que process hacker.
L'installation DTrace d'origine se trouve ici : https://techcommunity.microsoft.com/t5/windows-kernel-internals/dtrace-on-windows-20h1-updates/ba-p/1127929. Le DTrace d'origine nécessite la configuration de Secure Boot et de la sécurité basée sur la virtualisation ; ce n'est pas le cas avec STrace, car il n'implémente pas les types de sondes (FBT) qui exigent ces fonctionnalités.
Ce projet effectue les mêmes opérations que l'installateur, mais via un simple script powershell au lieu d'un MSI. Le processus est simple. Copiez d'abord une DLL apiset dans system32 afin que l'extension du noyau soit activée. Installez ensuite une entrée de pilote afin que la fonction main du pilote soit exécutée au démarrage du système pour les communications en mode utilisateur. Les DLL ApiSet sont signées numériquement, donc l'apiset Microsoft d'origine a été utilisé, comme requis. Ce fichier n'est fourni que sous forme binaire et ne contient aucune logique si ce n'est de pointer l'import d'extension vers le pilote d'implémentation : ext-ms-win-ntos-trace-l1-1-0 -> dtrace.sys. Voir https://www.geoffchappell.com/studies/windows/win32/apisetschema/index.htm (ApiSetSchemaExtensions) pour les détails de ce mécanisme.
STrace est chargé très tôt pendant l'initialisation du noyau ; activer Test Signing dans la base de données de configuration de démarrage (BCD) n'est pas suffisant. L'application de la signature des pilotes (DSE) doit être désactivée pour que STrace se charge correctement, et cela doit être fait manuellement à chaque démarrage. Pour faciliter cela, le script d'installation crée une entrée de menu de démarrage facile à sélectionner pour l'utilisateur. Il n'existe aucun indicateur BCD permettant de désactiver définitivement DSE entre les redémarrages ; le noyau l'interdit spécifiquement.
Oublier de désactiver DSE au démarrage vous vaudra un voyage vers le menu Réparation automatique au redémarrage. Vous pouvez réessayer sans risque ; si le démarrage continue d'échouer, le pilote STrace devra être supprimé manuellement du dossier des pilotes. Sachez que les échecs de démarrage peuvent entraîner la désactivation du drapeau d'exécution automatique du service STrace par Windows* ; vous devrez peut-être le redéfinir sur exécution automatique si un échec de démarrage se produit à tout moment.
Pour développer vos propres plugins, il est préférable d'utiliser l'un des plugins existants comme projet de base. Les projets Visual Studio sont configurés avec de nombreux paramètres très spécifiques pour générer des binaires autonomes sans dépendances. Les paramètres non par défaut sont trop nombreux pour être listés ; copiez donc simplement l'un des projets et modifiez le code pour y ajouter votre propre logique à la place (https://stackoverflow.com/questions/884255/visual-studio-copy-project). Si vous créez un plugin utile, veuillez soumettre une PR ! Plus il y aura de plugins créés, plus ce système sera utile pour tout le monde !