aujourd’hui on va voir un composant vraiment central de Windows : le registre.
C’est un sujet incontournable en développement système, parce qu’une très grande partie de la configuration de Windows et des logiciels passe par lui. Services, pilotes, paramètres noyau, shell, associations de fichiers, politiques, configuration applicative, profils utilisateurs, COM, installation de logiciels… le registre est partout.
Le problème, c’est que beaucoup de développeurs s’en servent comme d’une simple “boite à paramètres” sans vraiment comprendre ce que c’est, comment il est structuré, comment les accès sont sécurisés, quelles sont les bonnes API, ou encore pourquoi certaines opérations échouent selon le compte, l’intégrité ou la vue 32/64 bits utilisée.
Pourquoi le registre est un sujet fondamental
Comprendre correctement le registre permet de mieux voir :
- comment Windows stocke une grande partie de sa configuration
- comment les logiciels enregistrent leurs paramètres
- pourquoi certaines clés sont accessibles et d’autres non
- comment lire, écrire, créer, supprimer et énumérer proprement des clés et valeurs
- comment fonctionnent les notifications de changement
- comment le registre interagit avec les tokens, l’UAC et la vue Wow64
- pourquoi un service, un pilote ou un composant COM dépend souvent directement du registre
Ce qu’est réellement le registre Windows
Le registre Windows est une base de données hiérarchique gérée par le système. Il stocke des paramètres structurés sous forme de clés et de valeurs. Historiquement, il a remplacé ou centralisé beaucoup d’informations qui étaient auparavant dispersées dans des fichiers INI ou autres mécanismes plus simples.
Il contient notamment :
- des paramètres système
- des paramètres utilisateur
- des informations sur les services
- des informations sur les pilotes
- des données d’installation logicielle
- des associations de fichiers
- des informations COM et shell
- des politiques et réglages de sécurité
Le registre :
- n’est pas un simple fichier texte
- n’est pas un XML
- n’est pas une base SQL exposée directement à l’utilisateur
- n’est pas fait pour etre “parcouru à la main” par du code sans API dédiée
Le registre n’est pas juste “un fichier caché”
Derrière le registre, il existe des fichiers de ruches sur disque, mais il ne faut pas raisonner comme si l’application lisait directement un fichier structuré. Le système charge, maintient, arbitre, sécurise et expose ces données via le Configuration Manager coté noyau et les API user-mode adaptées.
Cela a plusieurs conséquences :
- les accès sont contrôlés par sécurité
- les vues peuvent varier selon le contexte 32/64 bits
- certaines clés sont virtuelles ou redirigées
- les modifications peuvent etre observées par le système ou d’autres composants
Les racines principales que l’on rencontre en user-mode sont :
- HKEY_LOCAL_MACHINE, souvent abrégé HKLM
- HKEY_CURRENT_USER, souvent abrégé HKCU
- HKEY_CLASSES_ROOT, souvent abrégé HKCR
- HKEY_USERS, souvent abrégé HKU
- HKEY_CURRENT_CONFIG, souvent abrégé HKCC
Leur rôle général :
- HKLM contient surtout des paramètres machine
- HKCU contient surtout les paramètres du profil utilisateur courant
- HKCR concerne notamment les classes et associations
- HKU expose les ruches des utilisateurs chargés
- HKCC donne accès à une vue de la configuration matérielle courante
Trois racines reviennent particulièrement souvent.
HKCU :
- contient les paramètres de l’utilisateur courant
- renvoie en pratique vers la ruche de cet utilisateur sous HKU
- est souvent le bon endroit pour des réglages applicatifs par utilisateur
- contient des paramètres machine
- est souvent utilisé pour des réglages globaux
- demande fréquemment des droits élevés pour l’écriture
- est une vue combinée liée aux classes
- intervient dans les associations de fichiers, COM, ProgID, CLSID, etc.
- ne doit pas etre abordé naïvement comme une simple ruche indépendante
Le registre est composé de deux grandes notions :
- les clés
- les valeurs
- des sous-clés
- des valeurs
- un nom
- un type
- une donnée brute
Les types de valeurs importants
Le registre stocke les données avec un type. Parmi les types les plus courants :
- REG_SZ : chaine Unicode terminée par zéro
- REG_EXPAND_SZ : chaine contenant des variables d’environnement expansibles
- REG_MULTI_SZ : liste de chaines Unicode, doublement terminée par zéro
- REG_DWORD : entier 32 bits
- REG_QWORD : entier 64 bits
- REG_BINARY : données binaires brutes
- REG_NONE : données sans typage particulier exploitable
HKEY : ce que c’est vraiment
Le type HKEY représente une clé de registre ouverte ou une racine prédéfinie. Visuellement, il ressemble à un handle, et conceptuellement c’en est un pour le monde du registre, mais attention : un HKEY ne se ferme pas avec CloseHandle.
Il se ferme avec :
- RegCloseKey
Ouvrir une clé existante
Pour ouvrir une clé déjà existante, l’API de base est :
- RegOpenKeyExW
Code: Select all
HKEY hKey = NULL;
LONG status = RegOpenKeyExW(
HKEY_CURRENT_USER,
L"Software\\MyApp",
0,
KEY_READ,
&hKey
);
if (status != ERROR_SUCCESS)
return 1;
- la racine ou clé parente
- le chemin relatif de la sous-clé
- les options réservées
- le masque d’accès désiré
- l’adresse recevant le HKEY ouvert
Créer ou ouvrir une clé avec RegCreateKeyExW
Quand on veut créer une clé si elle n’existe pas, ou l’ouvrir si elle existe déjà, l’API classique est :
- RegCreateKeyExW
Code: Select all
HKEY hKey = NULL;
DWORD disposition = 0;
LONG status = RegCreateKeyExW(
HKEY_LOCAL_MACHINE,
L"Software\\MyApp",
0,
NULL,
0,
KEY_WRITE,
NULL,
&hKey,
&disposition
);
if (status != ERROR_SUCCESS)
return 1;
- REG_CREATED_NEW_KEY
- REG_OPENED_EXISTING_KEY
L’API classique de lecture est :
- RegQueryValueExW
Code: Select all
DWORD type = 0;
DWORD size = sizeof(DWORD);
DWORD data = 0;
LONG status = RegQueryValueExW(
hKey,
L"Enabled",
NULL,
&type,
(LPBYTE)&data,
&size
);
if (status != ERROR_SUCCESS)
return 1;
if (type != REG_DWORD)
return 1;
Exemple de schéma :
Code: Select all
DWORD type = 0;
DWORD size = 0;
LONG status = RegQueryValueExW(
hKey,
L"MyString",
NULL,
&type,
NULL,
&size
);
if (status != ERROR_SUCCESS)
return 1;
/* allocation du buffer puis second appel */
Il faut aussi connaitre une API souvent plus pratique :
- RegGetValueW
Par exemple, on peut demander explicitement une lecture de type REG_DWORD ou REG_SZ. C’est souvent plus propre que RegQueryValueExW quand on veut du code un peu mieux cadré.
Ecrire une valeur : RegSetValueExW
Pour écrire une valeur existante ou nouvelle :
- RegSetValueExW
Code: Select all
DWORD data = 1;
LONG status = RegSetValueExW(
hKey,
L"Enabled",
0,
REG_DWORD,
(const BYTE*)&data,
sizeof(data)
);
if (status != ERROR_SUCCESS)
return 1;
Code: Select all
const wchar_t* text = L"Bonjour";
LONG status = RegSetValueExW(
hKey,
L"Message",
0,
REG_SZ,
(const BYTE*)text,
(DWORD)((wcslen(text) + 1) * sizeof(wchar_t))
);
Supprimer une valeur ou une clé
Pour supprimer une valeur :
- RegDeleteValueW
Code: Select all
RegDeleteValueW(hKey, L"Enabled");
- RegDeleteKeyW
- RegDeleteKeyExW
- RegDeleteTreeW
Exemple :
Code: Select all
RegDeleteTreeW(HKEY_CURRENT_USER, L"Software\\MyApp");
Droits d’accès sur les clés du registre
Le registre est sécurisé comme beaucoup d’autres objets Windows. Les accès sont soumis à des droits.
Masques d’accès importants :
- KEY_QUERY_VALUE
- KEY_SET_VALUE
- KEY_CREATE_SUB_KEY
- KEY_ENUMERATE_SUB_KEYS
- KEY_NOTIFY
- KEY_CREATE_LINK
- KEY_READ
- KEY_WRITE
- KEY_EXECUTE
- KEY_ALL_ACCESS
Registre, tokens, ACL et UAC
Les accès au registre dépendent directement du contexte de sécurité.
Cela implique notamment :
- le token du processus ou du thread
- les ACL de la clé
- le niveau d’intégrité
- l’UAC
- la zone du registre visée
Autrement dit, un échec sur RegCreateKeyExW ou RegSetValueExW ne veut pas dire que l’API est “capricieuse”. Très souvent, la sécurité explique parfaitement l’erreur.
Enumérer les sous-clés et valeurs
Pour explorer le contenu du registre, il faut connaitre les API d’énumération.
Pour les sous-clés :
- RegEnumKeyExW
- RegEnumValueW
Code: Select all
DWORD index = 0;
wchar_t name[256];
DWORD nameLen = 256;
while (RegEnumKeyExW(
hKey,
index,
name,
&nameLen,
NULL,
NULL,
NULL,
NULL) == ERROR_SUCCESS)
{
/* traitement */
index++;
nameLen = 256;
}
Obtenir des informations générales sur une clé
Une API très utile à connaitre est :
- RegQueryInfoKeyW
- le nombre de sous-clés
- le nombre de valeurs
- la longueur maximale des noms
- la longueur maximale des données
- le timestamp de dernière écriture
Notifications de changement dans le registre
Le registre peut aussi etre surveillé. L’API centrale ici est :
- RegNotifyChangeKeyValue
- ajout ou suppression de sous-clé
- changement de valeur
- modification d’attributs de sécurité
Flusher le registre
Il existe aussi :
- RegFlushKey
API avancées utiles à connaitre
Au-delà des fonctions de base, plusieurs API valent la peine d’etre connues de nom au minimum :
- RegOpenCurrentUser
- RegOpenUserClassesRoot
- RegOpenKeyTransactedW
- RegCreateKeyTransactedW
- RegDeleteKeyTransactedW
- RegCopyTreeW
- RegRenameKey
- RegLoadKeyW
- RegUnLoadKeyW
- RegSaveKeyW
- RegRestoreKeyW
- RegReplaceKeyW
- RegConnectRegistryW
- RegDisableReflectionKey
- RegEnableReflectionKey
- RegQueryReflectionKey
Transactions registre : à connaitre de nom
Windows a aussi proposé des API transacted pour certaines opérations, par exemple :
- RegOpenKeyTransactedW
- RegCreateKeyTransactedW
Le registre distant
Windows permet aussi, dans certains contextes, d’ouvrir une vue du registre sur une machine distante avec :
- RegConnectRegistryW
Registre et services
Les services Windows dépendent fortement du registre. Une zone fondamentale à connaitre est :
Code: Select all
HKLM\\SYSTEM\\CurrentControlSet\\Services
- la configuration des services
- les chemins binaires
- les types de démarrage
- les dépendances
- les paramètres de pilotes et services
Registre et pilotes
Les pilotes Windows ont eux aussi une relation étroite avec le registre. Leur configuration, leur chargement et certains paramètres d’initialisation s’appuient souvent sur des clés du registre, notamment sous la zone Services. C’est important à garder en tete quand on fait du système plus bas niveau.
Vue 32 bits / 64 bits et Wow64
Un point très important, souvent mal compris, concerne la vue 32 bits / 64 bits du registre sur les systèmes 64 bits.
Selon le contexte du processus et les flags utilisés, un programme peut voir une vue différente du registre, notamment sous certaines branches comme Software.
Flags importants à connaitre :
- KEY_WOW64_32KEY
- KEY_WOW64_64KEY
Sans comprendre ce point, on peut croire que le registre “ment” ou “ne contient pas la bonne clé”, alors qu’en réalité on regarde simplement une vue différente.
Redirection et réflexion du registre
Historiquement, sur les systèmes Wow64, certaines parties du registre impliquent des mécanismes de redirection, voire de réflexion selon les versions et scénarios. Il faut au moins connaitre ces notions de nom, car elles expliquent beaucoup de comportements surprenants dans les applications 32 bits sur système 64 bits.
API liées :
- RegDisableReflectionKey
- RegEnableReflectionKey
- RegQueryReflectionKey
Le registre n’est pas seulement un objet que l’on consulte clé par clé. Certaines API permettent d’intervenir à un niveau plus “hive”.
Parmi les API importantes à connaitre de nom :
- RegSaveKeyW
- RegRestoreKeyW
- RegLoadKeyW
- RegUnLoadKeyW
- RegReplaceKeyW
Les structures et types utiles autour du registre
Le monde du registre utilise moins de grosses structures que d’autres domaines Win32, mais il faut quand meme connaitre plusieurs types et notions importantes :
- HKEY
- FILETIME
- SECURITY_ATTRIBUTES
- SECURITY_DESCRIPTOR
- ACL
- DWORD
- LPBYTE
SECURITY_ATTRIBUTES et SECURITY_DESCRIPTOR interviennent dans des scénarios de sécurité plus avancés sur les clés.
Bonnes pratiques de lecture et écriture
Quand on manipule le registre proprement, quelques règles simples évitent beaucoup d’erreurs :
- toujours utiliser les versions W des API
- toujours vérifier le code de retour LONG
- toujours valider le type retourné avant d’interpréter les données
- gérer correctement les tailles de buffers
- fermer chaque HKEY ouvert avec RegCloseKey
- éviter d’écrire sous HKLM si HKCU suffit
- ne pas demander KEY_ALL_ACCESS sans raison
- faire attention à la vue 32/64 bits
Pour ouvrir, créer et fermer :
- RegOpenKeyExW
- RegCreateKeyExW
- RegCloseKey
- RegQueryValueExW
- RegGetValueW
- RegSetValueExW
- RegDeleteValueW
- RegDeleteKeyW
- RegDeleteKeyExW
- RegDeleteTreeW
- RegEnumKeyExW
- RegEnumValueW
- RegQueryInfoKeyW
- RegNotifyChangeKeyValue
- RegFlushKey
- RegCopyTreeW
- RegRenameKey
- KEY_WOW64_32KEY
- KEY_WOW64_64KEY
- RegConnectRegistryW
- RegOpenCurrentUser
Comme souvent en Win32, les erreurs les plus gênantes viennent d’une mauvaise compréhension des bases.
Parmi les fautes fréquentes :
- oublier RegCloseKey
- utiliser CloseHandle au lieu de RegCloseKey
- écrire dans HKLM sans comprendre les droits nécessaires
- ignorer le type réel d’une valeur
- mal gérer la taille des buffers
- utiliser ANSI au lieu des API W
- croire qu’une clé “n’existe pas” alors qu’on regarde la mauvaise vue 32/64 bits
- modifier des zones système sans comprendre leurs effets
- supposer que HKCR est une ruche simple et autonome
Le registre Windows est une base de données hiérarchique de configuration gérée par le système. Il organise ses données en clés et valeurs, exposées via des API dédiées. Chaque clé ouverte est représentée par un HKEY, qui doit etre fermé proprement avec RegCloseKey.
Les idées essentielles à garder sont les suivantes :
- le registre n’est pas un fichier texte
- HKLM, HKCU, HKCR, HKU et HKCC sont les grandes racines à connaitre
- une clé contient des sous-clés et des valeurs
- chaque valeur possède un type et une donnée
- les accès sont protégés par sécurité, tokens et ACL
- les services, pilotes et beaucoup de composants Windows dépendent directement du registre
- la vue 32/64 bits peut changer ce qu’un processus voit
- les notifications de changement et l’énumération font partie du modèle réel
Comprendre le registre, c’est comprendre comment Windows stocke une très grande partie de sa configuration et de celle des logiciels. C’est aussi comprendre que ce n’est pas une simple arborescence de noms, mais un mécanisme système avec sécurité, vues, types de données, hiérarchie, notifications et rôle central dans l’architecture du système.
Si tu maitrises déjà correctement :
- RegOpenKeyExW
- RegCreateKeyExW
- RegQueryValueExW
- RegGetValueW
- RegSetValueExW
- RegDeleteValueW
- RegDeleteTreeW
- RegEnumKeyExW
- RegEnumValueW
- RegQueryInfoKeyW
- RegNotifyChangeKeyValue
- RegCloseKey
Et surtout, tu commences à voir que le registre n’est pas juste “l’endroit où l’on met une option”, mais un vrai pilier de configuration du système Windows.
A bientot pour le prochain cours
