
Découverte, validation et confirmation automatisées du détournement de DLL. Transformer des erreurs de configuration locales en chemins d’attaque armés et confirmés.
<p align="center">
<img src="https://img.shields.io/badge/Platform-Windows-blue?style=for-the-badge&logo=windows" />
<img src="https://img.shields.io/badge/.NET-8.0_%7C_10.0-purple?style=for-the-badge&logo=dotnet" />
<img src="https://img.shields.io/badge/License-MIT-green?style=for-the-badge" />
<img src="https://img.shields.io/badge/Version-2.6.0-orange?style=for-the-badge" />
<img src="https://img.shields.io/badge/Black%20Hat%20Arsenal-Europe%202026-CC0000?style=for-the-badge" />
<img src="https://img.shields.io/badge/Black%20Hat%20Arsenal-SecTor%202026-CC0000?style=for-the-badge" />
</p>
<h1 align="center">DLLHijackHunter</h1>
<h4 align="center">Par <a href="https://projectmerai.com">ProjectMerai</a></h4>
<p align="center">
<strong>Découverte, validation et confirmation automatisées du détournement de DLL sous Windows</strong><br/>
<em>De « cette DLL est peut-être détournable » à « un utilisateur standard peut amener SYSTEM à charger ceci — voici la preuve. »</em>
</p>
---
## Sommaire
- [Vue d'ensemble](#overview)
- [Démarrage rapide](#quick-start)
- [Fonctionnement](#how-it-works)
- [Ce qu'il détecte](#what-it-detects)
- [Réduire les faux positifs](#reducing-false-positives)
- [Vérification : sonde de chargement et canary](#verification-load-probe-and-canary)
- [Notation, niveaux et chaînes d'attaque](#scoring-tiers-and-attack-chains)
- [Référence d'utilisation](#usage-reference)
- [Sécurité et impact opérationnel](#safety-and-operational-impact)
- [Compiler depuis les sources](#building-from-source)
- [Laboratoire de test (HijackRange)](#test-lab-hijackrange)
- [Limitations connues](#known-limitations)
- [Comparaison](#comparison)
---
## Vue d'ensemble
DLLHijackHunter trouve les opportunités de détournement de DLL sur un hôte Windows et s'efforce de les prouver, pas seulement de les lister. Il :
1. **Découvre** chaque emplacement où un binaire est lancé automatiquement — services, tâches planifiées, clés Run, dossiers Startup, serveurs COM, DLL AppInit/AppCert, entrées IFEO et binaires UAC à auto-élévation — et calcule où chaque DLL importée serait recherchée.
2. **Filtre** les emplacements qu'un attaquant ne peut pas réellement exploiter : API sets, KnownDLLs, répertoires dans lesquels un utilisateur standard ne peut pas écrire, processus protégés, et plus encore.
3. **Vérifie** (facultatif) avec le véritable chargeur Windows, en plaçant une DLL sonde bénigne et en vérifiant quelle copie remporte la recherche.
4. **Confirme** (facultatif) en déployant une DLL canary inoffensive, en déclenchant le service/la tâche/l'objet COM, et en enregistrant l'identité sous laquelle il s'est réellement exécuté.
5. **Note et rapporte** chaque constatation selon la confiance et l'impact, et corrèle les constatations en chaînes d'attaque (par exemple *utilisateur standard → SYSTEM*).
Chaque jugement est rendu **du point de vue de l'attaquant** — un utilisateur standard non privilégié — que le scanner lui-même s'exécute ou non avec élévation. S'exécuter en tant qu'Administrateur donne à l'outil plus de visibilité (ETW, canary, déclencheurs de service) ; cela ne rend jamais les répertoires protégés inscriptibles et ne gonfle jamais le privilège obtenu.
---
## Démarrage rapide
Téléchargez ou compilez `DLLHijackHunter.exe` (autonome ; aucune installation de .NET nécessaire), puis depuis une invite **élevée** :
```powershell
# Passive, read-only triage: no file drops, no service/task starts
.\DLLHijackHunter.exe --profile safe
# Full static analysis without touching the system, JSON report
.\DLLHijackHunter.exe --profile aggressive --no-canary --no-etw -o report.json
# Static analysis + real-loader verification (writes probe DLLs transiently)
.\DLLHijackHunter.exe --profile aggressive --no-canary --no-etw --verify-load -o report.html
# Everything, including ETW and canary confirmation — lab / authorised targets only
.\DLLHijackHunter.exe --profile aggressive -o report.html
# Focus on one application
.\DLLHijackHunter.exe --target "C:\Program Files\MyApp\app.exe" --no-canary
```
> **Antivirus :** les DLL canary et probe ne sont pas signées et se comportent comme des charges utiles de détournement, de sorte que Microsoft Defender peut les mettre en quarantaine. L'outil détecte cela et signale ces résultats comme **non concluants** plutôt que « non détournable ». Sur une machine de test, excluez les répertoires cibles et `%ProgramData%\DLLHijackHunter` pour obtenir des résultats définitifs.
---
## Fonctionnement
```mermaid
flowchart TB
subgraph S1["1 · Discovery"]
direction LR
EN["Launch points<br/>services · tasks · Run keys<br/>startup · COM · AutoElevate"] --> PE["PE analysis<br/>imports · delay loads<br/>manifest"] --> SO["Search order<br/>identity-aware PATH"]
ETW["ETW runtime trace<br/>optional, elevated"]
end
subgraph S2["2 · Filter pipeline"]
direction LR
HG["Hard gates<br/>API sets · KnownDLLs<br/>writability"] --> SG["Soft gates<br/>manifest · privilege<br/>PPL · LoadLibraryEx"] --> DD["Dedup and<br/>profile filters"]
end
subgraph S3["3 · Verification (optional)"]
direction LR
LP["Load probe<br/>real Windows loader"] --> CN["Canary<br/>deploy, trigger, confirm"]
end
subgraph S4["4 · Output"]
direction LR
SC["Scoring and tiers"] --> AC["Attack chains"] --> RP["Console · JSON · HTML"]
end
S1 --> S2 --> S3 --> S4
```
| Phase | Nécessite un administrateur | Modifie le système |
|---|:---:|---|
| Découverte statique + filtres | Non (l'admin voit davantage) | Non |
| Découverte d'exécution ETW | **Oui** | **Démarre** des services à démarrage automatique (jusqu'à 100) et exécute des tâches planifiées (jusqu'à 30) pour provoquer des chargements de DLL |
| Sonde de chargement (`--verify-load`) | Non | Écrit brièvement une DLL sonde bénigne à chaque position candidate, puis la supprime et restaure toute originale |
| Confirmation par canari | **Oui** | Écrit une DLL canari, arrête/démarre des services, exécute des tâches, active des objets COM, puis nettoie |
---
## Ce qu'il détecte
### Types de détournement
| Type | Signification | Remarques |
|---|---|---|
| **Fantôme** | La DLL n'existe nulle part dans le chemin de recherche | Placez-la n'importe où dans les chemins de recherche du binaire |
| **Ordre de recherche** | Un répertoire inscriptible est recherché avant la copie légitime | Inclut l'écrasement d'une DLL dans un répertoire inscriptible |
| **ENV PATH** | Un répertoire inscriptible dans `PATH` est recherché pour une DLL manquante | Les services sont évalués uniquement par rapport au PATH **machine** — les entrées PATH de l'utilisateur ne sont jamais recherchées par un service |
| **Redirection .local** | Redirection `<app>.exe.local\<dll>` | Signalée uniquement pour les exécutables **sans manifeste** (ou lorsque IFEO `DevOverrideEnable=1`) ; le chargeur ignore `.local` sinon, et il ne redirige jamais les KnownDLLs |
| **Side-load (UAC)** | Copier un EXE à auto-élévation à côté d'une DLL plantée | Uniquement pour les EXE avec `<autoElevate>true</autoElevate>` dans leur manifeste. L'auto-élévation exige un emplacement de confiance, donc la copie doit passer cette vérification (par ex. un dossier factice `C:\Windows \System32\`) |
| **AppInit DLLs** | `AppInit_DLLs` pointe vers une DLL inscriptible | Chargée dans chaque processus qui charge `user32.dll` |
| **AppCert DLLs** | `AppCertDLLs` pointe vers une DLL inscriptible | Chargée dans chaque appelant de `CreateProcess`/`WinExec` |
Les binaires IFEO `Debugger` et `SilentProcessExit\MonitorProcess` sont énumérés et analysés comme tout autre point de lancement. Les détournements basés sur le CWD ne sont pas produits actuellement.
### Sous quelle identité s'exécute la cible
Une identité correcte détermine à la fois le verdict d'élévation de privilèges et le score d'impact :
- **Services** — `ObjectName` (LocalSystem, Local Service, Network Service, ou un compte) ; les services svchost analysent aussi leur `ServiceDll`.
- **Tâches planifiées** — le principal de la tâche. Les formes SID telles que `S-1-5-18` sont mappées vers `NT AUTHORITY\SYSTEM` ; les principaux de groupe s'exécutent en tant que membre connecté (seul *Administrateurs + privilèges les plus élevés* compte comme élevé). Les charges utiles enveloppées dans `rundll32`, `cmd /c` ou `powershell -File` sont également analysées.
- **Clés Run / dossiers Démarrage** — énumérés pour **chaque profil utilisateur chargé** (`HKEY_USERS`) et le dossier Démarrage de chaque profil, attribués à cet utilisateur — pas seulement au compte exécutant le scanner.
- **COM** — les serveurs hors processus suivent `AppID` → `RunAs` / `LocalService` ; les serveurs in-process s'exécutent en tant que le client qui les charge.
### Base de connaissances et arme de PATH
- Un instantané intégré du jeu de données **[HijackLibs](https://hijacklibs.net/)** (≈590 DLL sur ≈700 exécutables, `Resources/hijacklibs.json`) est recoupé. Une correspondance augmente la confiance et lie la référence ; aucune correspondance ne signifie rien. Actualisez-le en remplaçant le fichier par `https://hijacklibs.net/api/hijacklibs.json`. Jeu de données © le projet HijackLibs et ses contributeurs.
- Pour chaque répertoire inscriptible du PATH **machine**, des candidats sont générés pour des services SYSTEM bien connus qui sondent le PATH pour des DLL manquantes (`IKEEXT → wlbsctrl.dll`, `Spooler → ualapi.dll`, `Schedule → WptsExtensions.dll`, `SessionEnv → tsmsisrv.dll`, `WlanSvc → wlanhlp.dll`).
---
## Réduire les faux positifs
**Barrières strictes** (le candidat est écarté) :
- **Ensembles d'API** — chaque nom de contrat `api-ms-*` / `ext-ms-*` est résolu via le schéma d'API set, jamais via l'ordre de recherche.
- **KnownDLLs** — lus depuis les répertoires d'objets actifs `\KnownDlls` et `\KnownDlls32` (pas seulement la liste d'amorçage du registre), plus `ntdll.dll`, qui est toujours mappé en premier.
- **Inscriptibilité relative à l'attaquant** — une position ne compte que si `Users`, `Authenticated Users`, `Everyone` ou `INTERACTIVE` (ainsi qu'un compte de service non privilégié tel que `LOCAL SERVICE`) détient le droit qui compte : **créer des fichiers** pour un dépôt de DLL, **créer des dossiers** pour un répertoire `.local`. Ceci est calculé à partir de l'ACL, indépendamment du jeton du scanner lui-même, de sorte qu'un scan élevé ne voit jamais `System32`, `Program Files` ou une racine de lecteur (`C:\`) comme inscriptible.
**Filtres souples** (la confiance est ajustée, avec la raison consignée dans les notes de la découverte) :
- Liaison **Manifest / WinSxS** de la DLL.
- **Delta de privilèges** — mesuré par rapport à un **attaquant utilisateur standard** : les cibles SYSTEM, LOCAL/NETWORK SERVICE et élevées par UAC constituent une élévation de privilèges ; les cibles de même privilège sont conservées comme découvertes de persistance / d'évasion de défense.
- **Mitigations LoadLibraryEx** — imports `SetDefaultDllDirectories`, `AddDllDirectory`, `SetDllDirectory`.
- **Processus protégés** — binaires PPL connus, services avec `LaunchProtected` défini dans la configuration du SCM (couvre les nouveaux Windows et les services AV/EDR tiers), et images `FORCE_INTEGRITY`.
- **Chargements optionnels gérés par erreur.**
Si un filtre ne parvient pas à s'évaluer, le candidat n'est pas pénalisé, mais l'échec est consigné dans ses notes et dans le journal plutôt que masqué.
---
## Vérification : sonde de chargement et canary
### Sonde de chargement (`--verify-load`)
Pour les candidats Phantom, Search-order et Side-load, une DLL sonde bénigne est copiée à la position inscriptible et un processus enfant de courte durée demande au **véritable chargeur Windows** de résoudre le nom :
| Résultat | Signification | Effet |
|---|---|---|
| **Wins** | Le chargeur a choisi la position inscriptible | Ordre de recherche prouvé ; la découverte peut atteindre **High** |
| **LosesToProtected** | Une copie KnownDLL, System32 ou SxS a gagné à la place | Probable faux positif ; −40 de confiance |
| **NotResolved** | Le nom n'a pas été résolu ; l'erreur du chargeur est consignée | Non concluant |
| **Error** | La sonde n'a pas pu s'exécuter — y compris lorsque la sonde est **mise en quarantaine par l'antivirus** | Non concluant, aucune pénalité |
| **Skipped** | `.local`, PATH, AppInit/AppCert utilisent des mécanismes différents | — |
La sonde modélise l'emplacement réel de la position : une DLL dans le **répertoire propre** du binaire est testée avant System32 (comme le fait le chargeur) ; les autres positions utilisent l'ordre de recherche classique ou moderne selon le cas. S'exécute en tant qu'utilisateur standard ; chaque sonde est supprimée et tout fichier d'origine restauré.
### Confirmation par canary
```mermaid
sequenceDiagram
autonumber
participant H as DLLHijackHunter
participant P as Hijack position
participant T as Service / task / COM
Note over H: Pick canary for target bitness,<br/>or build an export-forwarding proxy
H->>P: Back up original DLL, write canary
H->>T: sc start / schtasks /run / COM activation
T->>P: Load DLL by name (search order)
Note over P,T: Canary DllMain records user,<br/>integrity level and SeDebug
T-->>H: Confirmation file written
Note over H: Finding marked CONFIRMED
H->>P: Remove canary, restore original DLL
H->>T: Restore original service state
```
- **Aucun compilateur nécessaire.** Des canaries x64/x86 précompilés sont intégrés ; lorsque la DLL détournée possède des exports, un proxy de transfert d'exports est synthétisé à l'exécution par chirurgie PE afin que l'hôte continue de fonctionner.
- **Auto-localisation.** Le canary dérive son chemin de confirmation (`%ProgramData%\DLLHijackHunter\canary_<hash>.confirm`) depuis son propre chemin de chargement, de sorte qu'un seul binaire sert pour chaque candidat.
- **Aucune charge utile.** Il enregistre uniquement qui l'a chargé. Source : `src/DLLHijackHunter/Resources/canary_src.c` (recompiler avec `Resources/build_canary.bat`, MSVC requis uniquement pour cela).
- **Résultats :** `Fired`, `Timeout` (déclenché, jamais chargé), `Failed` (impossible de déclencher/déployer), `Blocked` (canary mis en quarantaine par l'antivirus — non concluant), `NotTested` (les clés Run, Startup, le contournement UAC et les cibles manuelles nécessitent une ouverture de session/redémarrage).
- **Réserve COM :** les objets COM in-process sont activés depuis un client lancé par le scanner, donc un canary déclenché prouve le chargement mais son identité est celle du scanner — il est enregistré comme *contexte d'appelant* et n'augmente pas l'impact.
Les canaries proxy peuvent encore être non concluants pour les exports uniquement ordinaux, les noms d'exports décorés, ou les hôtes qui nécessitent la vraie DLL résidente. Un canary non concluant ne signifie **pas** que le détournement est impossible.
---
## Notation, niveaux et chaînes d'attaque
Chaque constatation reçoit une **confiance** (issue des filtres, de la sonde, du canary et de la base de connaissances) et un score d'**impact** (privilège obtenu, fiabilité du déclenchement, furtivité, persistance au redémarrage), combinés en un score final de 0 à 10.
| Niveau | Exigence |
|---|---|
| **Confirmed** | Canary déclenché |
| **High** | ≥ 80 % **et** un signal de preuve : sonde gagnante, observation ETW ou correspondance HijackLibs |
| **Medium** | ≥ 50 % (les constatations statiques non vérifiées sont plafonnées ici et marquées `Static-only`) |
| **Low** | ≥ 20 % |
| **Informational** | En dessous de 20 % mais au-dessus du `--min-confidence` du profil |
Les **chaînes d'attaque** corrèlent les constatations en récits :
- **Chemin direct (Utilisateur → SYSTEM)** — toute constatation SYSTEM qu'un utilisateur standard peut implanter.
- **Échelle (Utilisateur → Admin → SYSTEM)** — un contournement UAC silencieux, affiché uniquement lorsqu'aucun chemin direct n'existe.
- **Longue manœuvre (Persistance)** — la meilleure constatation de démarrage automatique hors service (clé Run, Startup, tâche).
---
## Référence d'utilisation
```text
-p, --profile <name> aggressive | strict | safe | redteam | uac-bypass [default: aggressive]
-o, --output <path> Write a report; format from extension (.json / .html / .htm)
-f, --format <format> console | json | html [default: console]
-t, --target <target> Binary path, directory, or file name (partial match). Scopes discovery
and ETW to that target and skips system-wide PATH weaponisation.
--min-confidence <0-100> Override the profile's threshold (only when explicitly passed)
--no-canary Disable canary confirmation
--no-etw Disable ETW runtime discovery (no service/task starts)
--verify-load Real-loader verification of search order (transient probe DLLs)
--confirmed-only Report only canary-confirmed findings
--lpe-only Ignore System32 / Program Files / Windows positions
--canary-settle <sec> Seconds to wait for a canary to fire after triggering
--log-file <path> Write a diagnostic log (enumeration, filter, and probe failures)
-v, --verbose Verbose console output
```
### Profils
| Profil | Objectif | Canary | ETW | AutoElevate | COM | Constats de même privilège | Constats PPL | Confiance min |
|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| **aggressive** | Audit complet, labs | ✅ | ✅ | ✅ | ✅ | conservés | conservés | 15 % |
| **strict** | Escalade à haute confiance uniquement | ✅ | ✅ | — | — | écartés | écartés | 80 % |
| **safe** | Production, lecture seule | — | — | — | — | conservés | écartés | 50 % |
| **redteam** | Escalade confirmée uniquement (implique `--confirmed-only`) | ✅ | ✅ | — | ✅ | écartés | écartés | 50 % |
| **uac-bypass** | Vecteurs d'auto-élévation | — | — | ✅ | — | écartés | écartés | 20 % |
### Sortie
- **Console** (par défaut) : résumé, graphique des niveaux, constats, chaînes d'attaque. Rien n'est écrit sur le disque sauf si vous passez `--output` (un chemin qui n'est ni `.json` ni `.html` reçoit le rapport JSON lorsqu'il y a des constats).
- **JSON / HTML** : constats complets avec notes, résultats des filtres, résultats des sondes de chargement et du canary, références à la base de connaissances et chaînes d'attaque. Un rapport est écrit même lorsque rien n'est trouvé, afin qu'un fichier vide ne signifie jamais un échec d'exécution.
### Codes de sortie
| Code | Signification |
|---|---|
| `0` | Analyse terminée (avec ou sans constats) |
| `1` | Erreur non gérée |
| `3` | `--confirmed-only` (ou le profil `redteam`) demandé, mais le canary ne peut pas s'exécuter — non élevé, ou canary désactivé. Refusé au lieu de rapporter un faux « 0 constat ». |
---
## Sécurité et impact opérationnel
N'utilisez DLLHijackHunter que sur des systèmes que vous possédez ou que vous êtes explicitement autorisé à évaluer.
- `--profile safe` (ou `--no-canary --no-etw`) est **en lecture seule** — approprié pour le triage en production.
- **Le mode ETW démarre des services et exécute des tâches planifiées** pour provoquer des chargements de DLL, même sans le canary.
- **Le mode canary** remplace des DLL (avec sauvegarde/restauration), arrête et redémarre des services, exécute des tâches et active des objets COM. Les services fragiles peuvent mal se comporter pendant qu'un canary proxy est chargé.
- **`--verify-load`** écrit des DLL de sonde de manière transitoire dans des emplacements inscriptibles.
- Les DLL canary/sonde non signées peuvent être mises en quarantaine par l'antivirus ; ces résultats sont signalés comme non concluants (`Blocked` / sonde `Error`), jamais comme « non vulnérable ».
---
## Compilation depuis les sources
Prérequis : SDK .NET 8 (et le SDK .NET 10 si vous compilez également la cible `net10.0-windows`). La compilation sous Linux/macOS fonctionne avec `-p:EnableWindowsTargeting=true`.
```powershell
git clone https://github.com/projectmerai/DLLHijackHunter.git
cd DLLHijackHunter
# Self-contained single-file executable (no .NET runtime needed on the target)
dotnet publish src/DLLHijackHunter/DLLHijackHunter.csproj `
-c Release -f net8.0-windows -r win-x64 --self-contained `
-p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true `
-o ./publish
```
Le projet cible plusieurs frameworks (`net8.0-windows` et `net10.0-windows`), donc `dotnet publish` nécessite un `-f` explicite.
---
## Laboratoire de test (HijackRange)
`HijackRange/` contient un laboratoire délibérément vulnérable pour les démonstrations et les tests de régression :
- **Alpha** — un service SYSTEM dont le répertoire du binaire est accessible en écriture par `BUILTIN\Users`.
- **Beta** — une tâche planifiée SYSTEM présentant le même schéma.
- **Gamma** — un répertoire accessible en écriture ajouté au PATH système.
Compilez avec `HijackRange\build-all.bat`, déployez avec `HijackRange\setup.ps1` (en mode élevé), et supprimez avec `HijackRange\teardown.ps1`. Voir `HijackRange/demo-script.md`. Utilisez une VM jetable.
---
## Limitations connues
- **L'ordre de recherche statique est une approximation.** Le comportement à l'exécution (indicateurs `LoadLibraryEx`, `SetDefaultDllDirectories`, manifestes) est déduit des imports ; utilisez `--verify-load` ou le canary pour en avoir la preuve.
- **ETW** ne voit que les processus et les chargements qui se produisent pendant la fenêtre de trace (120 s par défaut).
- **La persistance** (« survit au redémarrage ») est déduite de la configuration de démarrage automatique, et non d'un test de redémarrage.
- **Les résultats de type Run keys / Startup / UAC side-load** ne peuvent pas être confirmés automatiquement par le canary.
- **Les DLL canary et probe ne sont pas signées** et peuvent être bloquées par un antivirus ou une politique de contrôle des applications.
---
## Comparaison
| Capacité | **DLLHijackHunter** | Robber | DLLSpy | WinPEAS | Procmon |
|---|:---:|:---:|:---:|:---:|:---:|
| Découverte automatisée | ✅ | ✅ | ✅ | ✅ | ❌ |
| Détection des DLL fantômes | ✅ | ❌ | ✅ | ❌ | ✅ |
| Analyse de l'ordre de recherche | ✅ | ❌ | ❌ | ❌ | ❌ |
| Vérification des ACL relatives à l'attaquant | ✅ | Partielle | ❌ | Basique | ❌ |
| Surveillance d'exécution ETW | ✅ | ❌ | ❌ | ❌ | ✅ |
| Vérification par le chargeur réel | ✅ | ❌ | ❌ | ❌ | ❌ |
| Preuve d'exécution par canary | ✅ | ❌ | ❌ | ❌ | ❌ |
| Analyse d'élévation de privilèges | ✅ | ❌ | ❌ | ❌ | ❌ |
| Découverte de contournement UAC | ✅ | ❌ | ❌ | ❌ | ❌ |
| Génération de DLL proxy à l'exécution | ✅ | ❌ | ❌ | ❌ | ❌ |
| Score de confiance et chaînes d'attaque | ✅ | ❌ | ❌ | ❌ | ❌ |
| Corrélation avec HijackLibs | ✅ | ❌ | ❌ | ❌ | ❌ |
| Rapports HTML / JSON | ✅ | ❌ | ❌ | TXT | ❌ |
| Binaire autonome | ✅ | ❌ | ❌ | ✅ | ❌ |
---
## Licence
MIT
## Crédits
Développé par **[ProjectMerai](https://projectmerai.com)**. Données de la base de connaissances issues du projet [HijackLibs](https://hijacklibs.net/).