On va tenter de comprendre comment getmodulehand fonctionne afin de la coder from scracth et de manière custom :
Le PEB walking est la technique parfait pour obtenir l'adresse des dll qu'ont souhaite car dans cette "interface" il existe un attribut du nom de Ldr qui permet de récupérer des informations sur les DLLs chargé par le système.
1. L'accès matériel : Le registre GS et le TEB
Tout commence au niveau du processeur. Sous Windows x64, chaque thread possède une structure appelée TEB (Thread Environment Block).
Le processeur utilise le registre de segment GS pour pointer en permanence sur ce bloc.
À l'intérieur de ce TEB, à l'offset 0x60, se trouve l'adresse du PEB.
C'est la seule porte d'entrée "statique" : peu importe où ton code est chargé, le registre GS te donnera toujours le point de départ vers les structures internes de Windows.
2. Le Maillage : Les listes chaînées circulaires
Une fois dans le PEB, on accède au LDR (Loader Data). Le défi ici est que Windows ne stocke pas les DLL dans un simple tableau, mais dans une liste doublement chaînée circulaire.
Théorie du chaînage :
Chaque élément (maillon) n'est pas la DLL elle-même, mais une structure de contrôle (LDR_DATA_TABLE_ENTRY).
Ces maillons sont reliés par des connecteurs LIST_ENTRY.
Le concept de circularité : Le dernier maillon pointe vers le premier. Pour un programmeur, cela signifie qu'il n'y a pas de fin "NULL". La fin, c'est quand on revient à l'adresse de départ. C'est pour cela qu'on définit une "ancre" (pListHead) dans ton code.
3. Le concept de "Structure Opaque" et Reverse Engineering
C'est ici que ta démarche devient technique. Microsoft publie des fichiers d'en-tête (headers) officiels, mais ils y masquent la réalité.
Documentation Officielle : Elle affiche des champs nommés Reserved1, Reserved2, etc. C'est une structure opaque.
Réalité Système : Ces champs Reserved contiennent en fait les données les plus sensibles, comme l'adresse de base de la DLL (DllBase) ou le nom complet sur le disque.
Pourquoi est-ce faux dans les docs ? Pour empêcher les logiciels de dépendre de ces emplacements, car Microsoft veut pouvoir les changer sans casser les logiciels "officiels". Coder un loader custom demande donc d'utiliser des structures issues du Reverse Engineering, où la communauté a identifié que la donnée que tu cherches est stockée précisément à l'emplacement de Reserved2[0].
4. La gestion des chaînes en mémoire (Unicode)
Théoriquement, Windows NT (le noyau) travaille exclusivement en Unicode (UTF-16).
Contrairement au C standard (ASCII) où "A" = 1 octet (0x41), en Unicode, "A" = 2 octets (0x41 0x00).
Cela signifie que pour comparer le nom d'une DLL dans le PEB, tu ne peux pas utiliser des fonctions de comparaison classiques. Tu dois utiliser des fonctions capables de sauter d'octet en octet de deux en deux (comme _wcsicmp).
Résumé de la chaîne de dépendance théorique :
Matériel : Registre GS → → → Adresse du TEB.
Structure : TEB + 0x60 → → → Adresse du PEB.
Loader : PEB → → → Pointeur LDR → → → Tête de liste des modules.
Navigation : Suivre les Flink jusqu'Ã trouver le bon nom en Unicode.
Extraction : Lire la valeur dans le champ opaque identifié par le reverse engineering (Reserved2).
Code fonction custom :
Last updated 2 months ago