
Driver Buddy Reloaded est un plugin Python pour IDA Pro qui aide à automatiser certaines tâches fastidieuses de rétro-ingénierie des pilotes noyau Windows.

La méthode d'installation dépend de votre version d'IDA, car le gestionnaire de plugins intégré (et donc l'outil et le manifeste ) n'existe que dans . IDA 7.6 et 8.x n'ont pas de gestionnaire de plugins et ne scannent que le niveau supérieur du dossier des plugins.
hcliida-plugin.jsonhcli)Le dépôt fournit un manifeste ida-plugin.json, donc IDA 9.0+ charge le plugin depuis son propre sous-répertoire. Installez-le avec :```
hcli plugin install DriverBuddyReloaded
This drops the plugin into a subdirectory of your user plugins folder (e.g.
`%APPDATA%\Hex-Rays\IDA Pro\plugins\DriverBuddyReloaded\` or `~/.idapro/plugins/DriverBuddyReloaded/`), keeping the
`DriverBuddyReloaded.py` entry point *inside* that subdirectory. This is the intended layout: IDA reads the manifest,
loads the declared entry point from the subdirectory, and puts the subdirectory on `sys.path` so the entry point can
import the sibling `DriverBuddyReloaded` package. You do **not** need to move `DriverBuddyReloaded.py` to the top level.
Verify the install with `hcli plugin status`, then launch IDA and confirm the plugin appears under
`Edit -> Plugins` (check the Output window for any Python errors at startup).
To install from a local checkout for testing (e.g. after your own changes), run `hcli plugin install .` from the
repository root; `hcli plugin lint .` validates the manifest/layout first.
### IDA 7.6 / 8.x (copie manuelle)
Ces versions n'ont pas de gestionnaire de plugins, donc un plugin installé via `hcli` dans un sous-répertoire ne sera
**pas** reconnu. Copiez le dossier `DriverBuddyReloaded` et le fichier script `DriverBuddyReloaded.py` directement dans
le **niveau supérieur** du dossier des plugins IDA, par exemple :
- `%APPDATA%\Hex-Rays\IDA Pro\plugins\`
- `C:\Program Files\IDA Pro 8.4\plugins\`
- `~/.idapro/plugins/`
La disposition obtenue est `plugins\DriverBuddyReloaded.py` à côté de `plugins\DriverBuddyReloaded\` (le dossier du package).
### Remarques
Si votre IDA est configuré pour Python 2, exécutez le binaire `idapyswitch` (situé dans le dossier d'IDA) pour passer à Python 3.
**NOTE :** Driver Buddy Reloaded fonctionne sur IDA 7.6+, 8.x (y compris 8.4) et 9.0+ avec Python 3. Toutes les différences
spécifiques à la version de l'API IDA (la suppression de `get_inf_structure`, le module `ida_struct` et les helpers
`idc.*struc*` dans IDA 9.0, etc.) sont gérées en interne par la couche de compatibilité `DriverBuddyReloaded/ida_compat.py`.
## Utilisation rapide
Pour utiliser la fonctionnalité d'analyse automatique :
1. Lancez IDA et chargez un pilote Windows en mode noyau.
2. Allez dans `Edit -> Plugins -> Driver Buddy Reloaded` ou appuyez sur `CTRL+ALT+A` pour démarrer l'analyse automatique.
3. Consultez la fenêtre "Output" pour les résultats de l'analyse, ainsi que la fenêtre **Driver Buddy Reloaded - Findings**
qui s'ouvre à la fin de l'exécution (double-cliquez sur une ligne pour accéder à son adresse).
4. Les fichiers suivants sont écrits dans le répertoire DB d'IDA (tous préfixés par `<NOM_PILOTE>-YYYY-MM-DD-TIMESTAMP-`) :
- `findings.json` – résultats exploitables par machine (IOCTLs, fonctions signalées, noms de périphérique, pooltags, chaînes d'appel, heuristiques, audit ACL de périphérique, liens symboliques, audit des exports, opcodes privilégiés)
- `report.html` – un rapport HTML autonome, groupé par sévérité
- `pooltags.txt` – Pooltags extraits au format `pooltags.txt` pour WinDbg
- `autoanalysis.txt` – le journal textuel complet de l'analyse (miroir de la fenêtre Output)
Pour décoder un IOCTL :
1. Placez le curseur de la souris sur la ligne contenant un code IOCTL suspect.
2. Cliquez-droit et sélectionnez `Driver Buddy Reloaded -> Decode IOCTL` ; vous pouvez aussi utiliser le raccourci `CTRL+ALT+D`.
Pour rouvrir la fenêtre des IOCTLs ou la fenêtre des résultats à tout moment (sans relancer l'analyse) :
- Appuyez sur `CTRL+ALT+I` pour ouvrir la fenêtre des IOCTLs.
- Appuyez sur `CTRL+ALT+F` pour ouvrir la fenêtre des résultats.
### Utilisation avancée
- Le répertoire [vulnerable_function_lists](https://github.com/voidsec/driverbuddyreloaded/blob/main/DriverBuddyReloaded/vulnerable_functions_lists) contient des listes de
fonctions potentiellement dangereuses/problématiques, d'API Windows et d'opcodes ; une brève description expliquant
pourquoi une fonction/API spécifique a été listée est fournie. Vous pouvez modifier la liste `custom` en y incluant
des fonctions spécifiques au pilote.
**Note :** `winapi_function_prefixes` effectue une correspondance partielle sur le début du nom de fonction (par
exemple `Zw` correspondra à `ZwClose`, `ZwCommitComplete`, etc.) tandis que `winapi_functions` effectue des
correspondances exactes uniquement.
- Dans [find_opcodes.py](https://github.com/voidsec/driverbuddyreloaded/blob/main/DriverBuddyReloaded/find_opcodes.py), l'option `find_opcode_data` (par défaut `False`)
supprime les correspondances d'opcodes qui se situent dans des sections de données
([issue #11](https://github.com/VoidSec/DriverBuddyReloaded/issues/11)). Passer à `True` fait également remonter
les correspondances brutes d'octets dans les données ; si un opcode réel a été manqué de cette façon, aller à
l'adresse rapportée et redéfinir les octets comme du code permet généralement de le récupérer. Les correspondances
sont rapportées comme pour toute autre étape (fenêtre des résultats, `findings.json`, `report.html`).
**Attention :** passer à `True` génère davantage de faux positifs !
## À propos de Driver Buddy Reloaded
**Driver Buddy Reloaded** est un plugin IDA Pro en Python qui aide à automatiser certaines tâches fastidieuses de
rétro-ingénierie des pilotes Windows en mode noyau. Il offre de nombreuses fonctionnalités pratiques, notamment :
* Identifier le type de pilote (WDM, KMDF, UMDF, WDF, Mini-Filter, Stream Minidriver, AVStream, PortCls)
* Localiser les fonctions `DispatchDeviceControl` / `DispatchInternalDeviceControl` pour **tous** les types de pilotes
(une recherche par stockage `MajorFunction[IRP_MJ_DEVICE_CONTROL]` trouve le gestionnaire même dans un pilote
minifilter/WDF qui expose également un périphérique de contrôle legacy, et même lorsque l'affectation se trouve
dans une fonction auxiliaire plutôt que dans `DriverEntry`)
* Remplir les structures communes pour les pilotes `WDF` et `WDM`
* Tente d'identifier et d'étiqueter des structures comme `IRP` et `IO_STACK_LOCATION`
* Étiquette les appels aux fonctions `WDF` qui ne seraient normalement pas étiquetés
* Crée une énumération IDA `IRP_MJ_FUNCTION` et l'applique aux emplacements du tableau `MajorFunction` dans
`DriverEntry` (WDM)
* Trouver et décoder les codes IOCTL
* Analyse multi-stratégie automatique des fonctions de répartition identifiées (aucun placement de curseur requis) :
arbre C du décompilateur (récupère les codes cachés par une table de saut ou un dispatch par recherche binaire
qui n'apparaissent jamais comme immédiats), récupération via la table de saut IDA, et une méthode de repli sur
les opérandes immédiates brutes (le repli s'exécute uniquement sur une fonction qui lit réellement
l'IoControlCode de l'IRP, de sorte qu'une fonction auxiliaire mal identifiée ne peut pas fuir ses constantes
internes comme de faux IOCTLs)
* Les valeurs NTSTATUS sont résolues dynamiquement à partir de la base de données de types IDA (avec un repli
étendu codé en dur), et les IOCTLs **sortants** que le pilote se contente d'envoyer vers l'aval
(`IoBuildDeviceIoControlRequest` / `ZwDeviceIoControlFile` / ...) sont exclus pour ne pas être confondus avec
la surface d'attaque du pilote lui-même
* Signaler les fonctions sujettes aux mauvais usages
* Trouver les `DeviceName` potentiels (scan mmap + repli par chaînes IDA, avec adresse source)
* Extraire les `Pooltags` (principal basé sur les imports + repli par propagation de registre pour les tags placés
dans un registre)
* **Vérifications heuristiques de vulnérabilités** sur chaque répartiteur et les fonctions qu'il appelle
transitivement : copie utilisateur non validée, TOCTOU/double fetch, use-after-free (intra-fonction et
inter-fonctions via un global libéré), absence de porte de privilège, déséquilibre IRQL, mappage MDL dangereux,
tampons alloués sur la pile (`_alloca`), allocation de pool sans validation de taille, instructions CPU privilégiées
(entrées/sorties port `in`/`out`, `mov cr*`), écriture arbitraire (write-what-where), et références à
`\Device\PhysicalMemory` (motif BYOVD) – voir
[Vérifications heuristiques de vulnérabilités](#vérifications-heuristiques-de-vulnérabilités)
* **Audit ACL de périphérique et suivi des liens symboliques** : signale les périphériques créés par `IoCreateDevice`
sans descripteur de sécurité (accessible mondialement) / SDDLs faibles de `IoCreateDeviceSecure`, et décode les
chemins cibles de `IoCreateSymbolicLink`
* **Audit des exports** : signale les exports du pilote sans aucune référence croisée interne (surface d'attaque potentielle)
* **Score de risque** pour chaque IOCTL décodé (priorisation de `METHOD_NEITHER` / `FILE_ANY_ACCESS`, et majoration
d'un IOCTL uniquement pour les sinks/opcodes dangereux atteignables depuis son **propre** gestionnaire de cas –
`MmMapIoSpace`, `memcpy`, `__writemsr`, entrées/sorties port, accès PCI-Config – de sorte qu'un code bénin dans un
répartiteur monolithique n'est plus entaché par les sinks d'un frère dangereux ; lorsque l'attribution est imprécise,
la majoration est plafonnée plutôt que forcée à CRITIQUE) et présentation de tous les résultats, par sévérité, dans
une fenêtre de résultats cliquable (double-clic pour accéder à l'adresse)
* **Traçage des chaînes d'appel** depuis les gestionnaires de dispatch / IOCTL jusqu'aux sinks dangereux (heuristique,
basé sur les noms)
* Export des résultats sous forme de fichier **JSON** exploitable par machine et d'un **rapport HTML** autonome

### Recherche de DispatchDeviceControl
L'outil peut localiser et identifier automatiquement la routine `DispatchDeviceControl`. Cette fonction est utilisée
pour router tous les codes `DeviceIoControl` entrants vers la fonction spécifique du pilote associée à ce code.
L'identifier automatiquement rend la recherche des codes `DeviceIoControl` valides pour chaque pilote beaucoup plus
rapide. De plus, lors de l'investigation de vulnérabilités possibles dans un pilote suite à un crash, connaître
l'emplacement de cette fonction aide à concentrer l'attention sur l'appel de fonction spécifique associé au code
`DeviceIoControl` à l'origine du crash.
Lorsque l'analyse réussit, certaines sous-routines sont renommées comme suit :
- `DriverEntry` : la première routine d'origine fournie par le pilote, appelée après le chargement du pilote. Elle est
responsable de l'initialisation du pilote.
- `Real_Driver_Entry` : généralement la fonction vers laquelle l'exécution a été transférée depuis `DriverEntry`. C'est
là que le `DeviceName` est généralement initialisé.
- `DispatchDeviceControl`/`DispatchInternalDeviceControl` : si l'outil a pu récupérer les fonctions à certains offsets
spécifiques, les fonctions sont alors renommées avec le nom approprié.
- `Possible_DispatchDeviceControl_#` : si l'outil n'a pas pu récupérer `DispatchDeviceControl`
ou `DispatchInternalDeviceControl`, il utilise une recherche expérimentale en suivant le flux d'exécution et en
vérifiant les cas où la fonction charge des adresses connues de `IO_STACK_LOCATION` & `IRP` ; cela indique que la
fonction pourrait être le DispatchDeviceControl. Comme cela repose sur une heuristique, cela peut renvoyer plusieurs
résultats et est sujet à des faux positifs.

### Étiquetage des structures WDM et WDF
Plusieurs structures de pilote sont partagées entre tous les pilotes `WDM`/`WDF`. L'outil est capable d'identifier
automatiquement ces structures, comme les structures `IO_STACK_LOCATION`, `IRP` et `DeviceObject`, ce qui peut faire
gagner du temps lors du processus de rétro-ingénierie et fournir du contexte dans les zones du pilote où ces fonctions
sont utilisées.

### Recherche et décodage des codes IOCTL
Lors de la rétro-ingénierie de pilotes, il est courant de rencontrer des codes IOCTL. Ces codes, une fois décodés,
révèlent des informations utiles et peuvent attirer l'attention sur des parties spécifiques du pilote où les
vulnérabilités sont plus susceptibles d'exister.
En cliquant-droit sur un code IOCTL potentiel, une option de menu contextuel est présentée (ou en utilisant le
raccourci `Ctrl+Alt+D` lorsque le curseur est sur la ligne contenant un code IOCTL suspect) et peut être utilisée pour
décoder la valeur. Cela affichera un tableau avec tous les codes IOCTL décodés. En cliquant-droit sur un code IOCTL
décodé, dans la vue désassemblage, il est possible de le marquer comme invalide ; cela conservera tout commentaire
non-IOCTL intact.
- Les IOCTLs décodés sont affichés dans la fenêtre Output et listés dans la fenêtre des IOCTLs colorée par sévérité ;
après l'analyse automatique, ils sont également enregistrés dans `findings.json` / `report.html`.
L'analyse automatique exécute également une analyse multi-stratégie sur les fonctions de répartition identifiées pour
découvrir les IOCTLs automatiquement, sans nécessiter de placement manuel du curseur. Pour chaque répartiteur, elle
utilise le décompilateur Hex-Rays (lorsqu'il est disponible) pour lire les étiquettes de switch-case et les constantes
de comparaison `==`/`!=` directement depuis le flux de contrôle reconstruit, en se repliant sur les métadonnées de
table de saut d'IDA puis sur une analyse brute des opérandes immédiates. Le chemin via le décompilateur récupère les
codes qui n'apparaissent jamais textuellement dans le désassemblage – par exemple, les pilotes dont le répartiteur a
été compilé sous forme de table de saut (seules la base et la limite de la table survivent comme immédiats) ou sous
forme d'arbre de comparaison binaire (les codes intermédiaires ne survivent que sous forme de deltas). Sur un corpus
représentatif, cela a augmenté le taux de récupération de 7/28 à 28/28 (HEVD) et de 4/17 à 17/17 (ALSysIO64) sans
faux positifs.


### Signalement des fonctions
Driver Buddy Reloaded dispose de listes de fonctions C/C++, d'opcodes et d'API Windows (définies dans
le répertoire [vulnerable_function_lists](https://github.com/voidsec/driverbuddyreloaded/blob/main/DriverBuddyReloaded/vulnerable_functions_lists)) qui sont couramment
vulnérables ou qui peuvent faciliter les conditions de dépassement de tampon. Toutes les instances trouvées sont
signalées lors de l'analyse automatique et peuvent aider à rechercher des chemins de code contrôlés par l'utilisateur
atteignant des fonctions sensibles.

### Recherche du DeviceName
L'outil tente automatiquement de trouver les chemins de périphériques enregistrés par le pilote (`DeviceName`) ; si
aucun chemin ne peut être trouvé en recherchant les chaînes Unicode dans le binaire, l'analyste peut tenter
manuellement d'utiliser [FLOSS](https://github.com/mandiant/flare-floss/) de Mandiant pour trouver des chemins
obfusqués.

### Extraction des Pooltags
Lors de l'analyse automatique, l'outil extrait également les `Pooltags` utilisés par le binaire dans un format qui
fonctionne avec `pooltags.txt`. La sortie peut ensuite être copiée-collée à la fin du fichier et reprise par WinDbg.
- Un fichier `DriverName.sys-DATE-TIME_STAMP-pooltags.txt`, contenant tous les Pooltags extraits, sera écrit dans
le répertoire DB d'IDA.

### Vérifications heuristiques de vulnérabilités
Le module `heuristics.py` s'exécute après le traçage des chaînes d'appel et examine chaque répartiteur **et les
fonctions qu'il appelle transitivement** – de sorte que les gestionnaires par IOCTL, et pas seulement le prologue du
répartiteur, soient analysés. La correspondance des appelés tient compte des imports (un appel importé
`call cs:__imp_<Nom>` correspond au même nom qu'un appel local). Il émet des résultats dans la catégorie
**heuristic** (les résultats d'instructions privilégiées utilisent la catégorie **opcode**) :
| Vérification | Ce qui est signalé | Sévérité |
|---|---|---|
| Copie utilisateur non validée | `memcpy`/`RtlCopyMemory`/etc. sans `ProbeForRead`/`ProbeForWrite`/garde de chaîne sûre à proximité | HAUTE (gestionnaire), MOYENNE (autre) |
| TOCTOU / double fetch | une relecture de pointeur en mode utilisateur sur un chemin de flux de contrôle sans `ProbeForRead` intermédiaire (uniquement sur les gestionnaires METHOD_NEITHER, donc les relectures de tampon noyau ne sont pas signalées) | MOYENNE |
| Use-after-free | un pointeur libéré réutilisé intra-fonction (parcours de graphe de registres), ou un global libéré sans être mis à null puis déréférencé depuis une autre fonction | HAUTE |
| Absence de porte de privilège | un op sensible (`ZwOpenProcess`/`MmMapIoSpace`/PCI-config/etc.) atteignable depuis un répartiteur sans `SeAccessCheck`/`SeSinglePrivilegeCheck`/vérification de jeton sur le chemin | HAUTE |
| Déséquilibre IRQL | Appel pageable / `Zw*` / `MmMap*` lorsqu'une fonction élévatrice d'IRQL est également présente | MOYENNE |
| Mappage MDL dangereux | `MmMapLockedPages`/`MmProbeAndLockPages`/etc. avec `UserMode` dans le désassemblage | HAUTE, sinon MOYENNE |
| Allocation sur la pile | Appel à `_alloca`/`_malloca`/`_chkstk` (allocation importante ou dynamique sur la pile) | BASSE |
| Allocation de pool sans validation de taille | Appel à `ExAllocatePool*` sans garde arithmétique de sécurité à proximité (motif de débordement d'entier avant allocation) | HAUTE |
| Instruction privilégiée | entrées/sorties port (`in`/`out`), déplacement de registre de contrôle/débogage (`mov cr*`/`mov dr*`), chargement de table de descripteurs, `cli`/`sti`/`hlt` atteignables depuis un gestionnaire (primitive d'accès matériel BYOVD) | CRITIQUE (`out`) / HAUTE (`in`) / MOYENNE |
| Écriture arbitraire (write-what-where) | un stockage via un pointeur utilisateur doublement déréférencé `*(*p) = c` ; une copie contrôlée `*p = *q` est signalée comme une piste plus faible | HAUTE / MOYENNE |
| Référence à `\Device\PhysicalMemory` | Référence croisée à la chaîne de l'objet de périphérique mémoire physique (motif BYOVD via `ZwOpenSection`/`ZwMapViewOfSection`) | HAUTE (gestionnaire), MOYENNE (autre) |
Ce sont des **générateurs de pistes**, pas des vulnérabilités confirmées. Considérez les résultats HAUTE/CRITIQUE comme
des points de départ pour une revue manuelle.
## Indicateurs de fonctionnalités
Toutes les étapes d'analyse optionnelles sont contrôlées par `DriverBuddyReloaded/config.py`. Modifiez la classe
`Feature` pour les activer ou les désactiver :
| Indicateur | Par défaut | Description |
|---|---|---|
| `IOCTL_SCAN` | `True` | Découvrir et décoder les IOCTLs (scan du répartiteur + repli `IoControlCode`) |
| `IOCTL_DECOMPILER` | `True` | Utiliser l'arbre C d'Hex-Rays dans le scan du répartiteur (récupère les codes de table de saut / recherche binaire) |
| `HEURISTICS` | `True` | Vérifications heuristiques de vulnérabilités (voir le tableau ci-dessus) |
| `TOCTOU_CHECK` | `True` | Heuristique double-fetch / TOCTOU |
| `UAF_DETECT` | `True` | Heuristiques use-after-free (parcours de registres intra-fonction + global inter-fonctions) |
| `ACL_AUDIT` | `True` | Signaler les `IoCreateDevice` accessibles mondialement / SDDLs faibles `IoCreateDeviceSecure` |
| `SYMLINK_TRACK` | `True` | Décoder les chemins cibles de `IoCreateSymbolicLink` |
| `CALLCHAIN` | `True` | Traçage BFS des chaînes d'appel des gestionnaires vers les sinks dangereux |
| `EXPORTS_AUDIT` | `True` | Signaler les exports du pilote sans aucune référence croisée interne |
| `POOLTAG_FALLBACK` | `True` | Scanneur de pooltag par propagation de registre (utilisé quand le scan basé sur les imports ne trouve rien) |
| `IRP_MJ_ENUM` | `True` | Créer l'énumération IDA `IRP_MJ_FUNCTION` et l'appliquer aux emplacements `MajorFunction` (WDM uniquement) |
| `RISK_SCORING` | `True` | Score de risque IOCTL (pondérations METHOD/ACCESS + majoration par sink du gestionnaire) |
| `RESULTS_WINDOW` | `True` | Afficher la fenêtre des résultats Driver Buddy Reloaded après l'analyse |
| `JSON_EXPORT` | `True` | Écrire `findings.json` |
| `HTML_REPORT` | `True` | Écrire `report.html` |
| `SEGMENT_OPCODE_SCAN` | `False` | Scan linéaire des opcodes sur l'ensemble du segment (bruyant, désactivé par défaut) |
## Tests
Trois niveaux, du rapide au complet :
- **Régression pure-Python** (aucun IDA requis) – couvre toute la logique qui ne touche pas à la base de données
dynamique : ```
python tests/test_dbr.py
DBR_SDK=900 python tests/test_dbr.py # simulate the IDA 9.0 import paths
.sys réels et affiche un tableau de réussite/échec : pwsh tests/run_cross_version.ps1.pwsh tests/run_golden.ps1 réexécute l'analyse complète sur une copie vierge de chaque pilote de référence dans tests/drivers/ et compare les résultats avec la base de référence tests/drivers/<driver>.golden.json (insensible à l'ordre sur la catégorie, le titre, la sévérité et le code/méthode/accès IOCTL). Tout résultat ajouté (faux positif), résultat manquant (faux négatif) ou changement de sévérité fait échouer l'exécution. Ne régénérez une sortie dorée que lorsqu'un changement modifie intentionnellement les résultats, et examinez la différence. Les sorties dorées sont liées à la version du décompilateur IDA avec laquelle elles ont été capturées (8.4), exécutez donc la régression avec cette version.CTL_CODE via _is_valid_ctl_code() : le champ DeviceType (bits 31-16) doit être non nul, et la valeur ne doit pas correspondre à un code NTSTATUS connu ni au sentinelle 0xFFFFFFFF (DWORD)-1 (une constante de comparaison vue dans de vrais répartiteurs, par exemple WinRing0). Cela exclut les compteurs de boucle, les petites immédiates et les codes d'erreur tout en préservant tous les IOCTL valides, y compris les types de périphériques définis par le fournisseur (0x8000+). Le même filtre est appliqué aux quatre chemins de découverte : l'analyse de référence croisée IoControlCode et les trois collecteurs de répartiteurs (ctree du décompilateur, récupération de table de commutateur IDA, et analyse brute des opérandes immédiates).DriverBuddyReloaded/config.py.DispatchDeviceControl ne fonctionne que pour les pilotes x64find_opcode_data (par défaut False) supprime les correspondances d'opcode qui tombent dans les sections de données. Passer à True expose également les correspondances brutes d'octets dans les données, ce qui est sujet aux faux positifs ; si un véritable opcode a été manqué, aller à l'adresse signalée et redéfinir les octets en code le récupère généralement. Les correspondances sont rapportées comme dans toute autre étape (fenêtre des résultats, findings.json, report.html).