Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
HintInject — Un projet PoC pour l'intégration de shellcode dans la table Hint/Name | Kitploit
Outils/GitHubGitHub/frkngksl/hintinject
Génération de PayloadsExploitationShellcodeTests d'IntrusionAnalyse de BinairesDéveloppement de Charges Utiles
GitHubfrkngksl/hintinject

HintInject

Un projet PoC pour l'intégration de shellcode dans la table Hint/Name

Voir le dépôt
11422il y a 4 moisVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

HintInject

HintInject est un outil d'encapsulation et de chargement de shellcode que j'ai développé en jouant avec les structures du fichier PE et de la table d'annuaire des importations. Il prend un fichier shellcode brut et place le shellcode par morceaux dans les entrées de la table Hint/Name, accessibles via la table de recherche d'importations d'une entrée de DLL importée fictive dans l'exécutable du chargeur. Ce chargeur fusionne ensuite ces morceaux pour exécuter le shellcode. Je ne sais pas s'il s'agit d'une technique nouvelle ou non, mais j'ai voulu la partager pour le plaisir.

Processus de chargement des DLL

Avant d'expliquer le fonctionnement de HintInject, je souhaite mentionner brièvement le processus de chargement des DLL en m'appuyant sur un post de Stack Overflow.

Pour obtenir les informations sur les DLL requises et les fonctions/imports, il faut d'abord consulter la Table d'annuaire des importations. La table d'annuaire des importations est une table d'entrées, une entrée pour chaque DLL importée. Ces entrées contiennent un pointeur vers le nom de la DLL importée, un pointeur vers la Table de recherche d'importations, un pointeur vers la Table d'adresses d'importations, ainsi que d'autres champs pour diverses informations.

En résumé, la table de recherche d'importations mène aux informations sur les imports, et la table d'adresses d'importations mène aux adresses des imports. Cependant, lorsque l'exécutable est sur le disque, ou juste avant le processus de chargement des DLL, la table d'adresses d'importations est identique à celle de la table de recherche d'importations. Le contenu de la table d'adresses d'importations est écrasé avec les adresses des imports pendant le processus de chargement des DLL.

Sans entrer dans les détails, nous pouvons examiner le diagramme ci-dessous pour voir la relation entre ces trois tables.

Si l'on entre un peu plus dans les détails, la table de recherche d'importations ne contient pas directement les noms des imports. Pour les fonctions importées par nom, elle contient des RVA (Relative Virtual Address) d'entrées de la Table Hint/Name. Ces entrées stockent les noms des fonctions sous forme de chaînes ASCII terminées par un caractère nul. Par conséquent, la définition de structure d'une entrée de la table Hint/Name est la suivante :

root@kitploit:~
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    CHAR   Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; 

Le champ Hint ici est en fait un index dans la table des pointeurs de noms d'exportation de la DLL. Il est utilisé pour accélérer la recherche de la position de cet import. Ainsi, nous pouvons résumer la relation entre la table de recherche d'importations et la table Hint/Name à l'aide du diagramme ci-dessous.

Pour conclure, afin de trouver une DLL et ses imports, il faut suivre les étapes suivantes :

  1. Aller à la table d'annuaire des importations à partir du tableau DataDirectory de l'Optional Header.
  2. Parcourir les entrées de la table d'annuaire des importations pour trouver la DLL souhaitée en vérifiant son champ de nom.
  3. Après avoir trouvé la bonne entrée, accéder à sa table de recherche d'importations en utilisant le champ OriginalFirstThunk.
  4. Parcourir toutes les entrées de la table de recherche d'importations, qui sont des pointeurs vers des entrées de la table Hint/Name.
  5. Vérifier les noms des imports à partir du champ Name des entrées de la table Hint/Name.

Comment fonctionne HintInject ?

Récemment, en examinant la technique d'injection de DLL dans les imports (ImportDLLInjection) partagée par x86matthew, j'ai vu comment ajouter une entrée fictive à l'annuaire d'importations des DLL chargées en mémoire. Ensuite, j'ai voulu développer un petit projet qui ajoute une entrée fictive directement à la table d'importations d'un binaire sur le disque, à la fois pour le plaisir et pour rafraîchir mes connaissances. En passant en revue le processus de chargement des DLL pour développer ce projet, le champ Hint dans les entrées de la table Hint/Name utilisées dans ce processus a attiré mon attention.

D'après la documentation MSDN, j'ai appris que ce champ est utilisé par le chargeur Windows pour trouver l'adresse de cet import, importé par son nom, directement à partir de la table des noms d'exportation de la DLL dans laquelle il se trouve. Cependant, dans le même document, il était indiqué que si la fonction ne peut pas être trouvée en utilisant ce champ, cette fonction sera recherchée via une opération de recherche binaire dans la table des noms d'exportation de la DLL. Sur la base de cette phrase, j'ai pensé que mettre une valeur incorrecte pour ce champ ne perturberait pas le processus de chargement des DLL.

Comme je l'ai mentionné ci-dessus, il y a une entrée dans la table Hint/Name correspondant à chaque fonction à importer. En d'autres termes, nous avons 2 octets à utiliser pour chaque import. En combinant plusieurs imports, on peut obtenir suffisamment de champs Hint pour stocker des shellcodes malveillants. En conséquence, on peut utiliser un binaire chargeur pour intégrer le shellcode dans les entrées Hint/Name de l'entrée fictive de DLL importée. Ce binaire chargeur peut accéder à ces entrées pour fusionner le shellcode à exécuter pendant l'exécution.

HintInject peut être utilisé pour créer un tel chargeur qui contient le shellcode dans sa table Hint/Name. Il crée d'abord une nouvelle section nommée .rrdata et copie l'annuaire d'importations actuel dans cette section. Ensuite, il ajoute une nouvelle entrée fictive dont les imports serviront à contenir le shellcode d'entrée. Les octets restants de la section sont utilisés pour stocker la table de recherche d'importations, la table d'adresses d'importations, le nom de la DLL et la table Hint/Name de la nouvelle entrée fictive. En dernière étape, HintInject utilise les champs Hint des imports pour placer des morceaux du shellcode d'entrée.

Exemple d'imports d'un binaire chargeur :

Capture d'écran 2022-05-08 à 11 43 42

Utilisation

  1. Compilez le projet avec l'option Release.
  2. Exécutez HintInject.exe avec votre shellcode au format brut et un chemin de sortie pour créer un chargeur de shellcode : HintInject.exe <Fichier Shellcode> <Nom de sortie>
  3. Lancez le chargeur pour exécuter le shellcode directement, ou vous pouvez donner un PID pour injecter le shellcode : Loader.exe <PID>
  4. Si vous le souhaitez, vous pouvez modifier la méthode d'injection du shellcode en modifiant la fonction InjectShellcode dans le fichier HintInjectLoader/Main.cpp.

Testé sur Windows 10 19044 avec Visual Studio 2019 :

Limitations

  1. En ce qui concerne les entrées de DLL fictives sur le chargeur qui exécute le shellcode, le nom de la DLL et celui des fonctions importées doivent exister réellement. Sinon, une erreur de DLL manquante se produit lors du démarrage de l'exécutable du chargeur. J'ai donc utilisé quelques DLL légitimes de System32 dans le projet.
  2. Si la taille de votre shellcode est plus grande et qu'il n'est pas possible de créer un chargeur pour celui-ci, vous pouvez ajouter d'autres DLL au tableau dllNames dans le fichier DllNamesForFakeImports.h.
  3. Pour chaque chargeur créé, les fonctions importées sont sélectionnées aléatoirement. Cependant, si vous souhaitez modifier l'ordre des DLL utilisées pour créer les entrées fictives, vous devez également modifier le tableau dllNames dans le fichier DllNamesForFakeImports.h. Par défaut, HintInject choisira les fonctions des DLL dans l'ordre du tableau. En d'autres termes, l'outil sélectionne d'abord les fonctions exportées de user32.dll ; si la taille du shellcode est supérieure à 2 * le nombre d'exportations de user32.dll, il commence également à utiliser les exportations de advapi32.dll et des autres.
root@kitploit:~
static LPCSTR dllNames[] = {"user32.dll","advapi32.dll","gdi32.dll","wininet.dll","comctl32.dll","shell32.dll","wsock32.dll","oleaut32.dll","ws2_32.dll","urlmon.dll"};

Références

  • https://stackoverflow.com/questions/32841368/whats-the-difference-between-the-import-table-import-adress-table-and-import
  • https://0xrick.github.io/win-internals/pe6/
  • https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#hintname-table
  • https://www.x86matthew.com/view_post?id=import_dll_injection

Avertissement

Pour des tests de sécurité autorisés uniquement. Toute utilisation abusive de cet outil contre des systèmes sans autorisation explicite est illégale.

Télécharger l’outil