mardi 19 février 2008

Reverse Msnmsgr.exe

Bon aujourd'hui on va s'attaquer à ce cher petit msnmsgr.exe, ce petit outil utilisé par le monde entier et qui connait un succès grandissant.

On va voir comment arriver à lancer plusieurs fois MSN alors qu'à vu d'œil il refuse de se lancer plusieurs fois, à la place il donne le focus à la fenêtre déjà lancé.

Bien pour tout vous dire je me suis longtemps demander comment faisait beaucoup de programme pour détecter si ils sont déjà lancés ou pas.

Ils auraient pût lister la liste des processus et vérifier si le nom du prog ni figurait pas mais non ce n'est pas assez flexible, il suffit de renommer l'exe pour pouvoir le lancer plusieurs fois et la solution n'est donc pas très bonne au final.
Et puis je me suis demander si ce n'était pas une sorte de variable globale qui était déclaré lors du lancement de l'exe et qui été détruit en même tant que l'exe, comme ça lorsque l'exe été relancé il lui suffisait de vérifier si la variable existait et si tel était le cas bim on lui balance un MessageBox comme c'est le cas pour CodeBlocks ou alors on donne le focus au premier exe.

Et puis la ça fait bingo parce que justement Windows a une API qui nous permet de déclarer des variables globales enfin c'est pas tout à fait des variables globales c'est plutôt des events grâce à CreateEvent.

Reverse de MsnMsgr

Bon alors c'est parti pour le Reverse de MsnMsgr, maintenant qu'on sait ( on suppose en fait ) quelle fonction MsnMsgr va utilisé pour y parvenir ça va être très simple.

Alors on lance notre cher olly ( moi j'utilise olly parce que c'est le seul que j'utilise mais vous pouvez bien entendu utiliser votre debogueur préférer ) et on ouvre MsnMsgr ( chez moi il se trouve dans C:\Program Files\MSN Messenger\ ).

Et on laisse olly analyser le code parce que MsnMsgr c'est un sacré morceau ... 5 min plus tard olly à fini ^^

Donc comme on suppose que MsnMsgr va utiliser l'API CreateEvent() on va faire un clic droit -> Search For -> Name (label) in current module et on va rechercher CreateEvent(), il n'y a pas de symbole CreateEvent() mais il y a CreateEventA() et CreateEventW() d'après la msdn la seule différence entre ces deux fonctions est que CreateEventA() utilise un encodage ANSI alors que CreateEventW() utilise un encodage Unicode ( http://msdn2.microsoft.com/en-us/library/ms682396(VS.85).aspx Section Requirements -> Unicode).
On va donc poser des breakpoints sur les deux API à coup de clic droit -> Set breakpoint on every reference.

Maintenant un petit coup de F9 pour lancer le prog, on reconnait bien la lenteur de microsoft ... 5 min après boum break sur CreateEventW()

On regarde l'argument EventName, il est à NULL donc ça ne nous intéresse pas aller re F9, encore un appel qui ne nous concerne pas re F9 et puis la un CreateEventW qui pourrait nous servir sauf qu'après analyse aucune vérification n'est faite et donc ça ne nous intéresse pas non plus.
Après avoir relancer encore une fois à coup de F9, on tombe sur un CreateEventA avec comme EventName "MSNMSGR".
On va analyser un peu ce code pour voir de quoi il retourne.

...

00543CCB > 68 78D75500 PUSH msnmsgr.0055D778 ; /EventName = "MSNMSGR"
00543CD0 . 57 PUSH EDI ; |InitiallySignaled
00543CD1 . 6A 01 PUSH 1 ; |ManualReset = TRUE
00543CD3 . 57 PUSH EDI ; |pSecurity
00543CD4 . FF15 3C144000 CALL DWORD PTR DS:[<&KERNEL32.CreateEventA>] ; \CreateEventA
00543CDA . 3BC7 CMP EAX,EDI
00543CDC . 8B5D E8 MOV EBX,DWORD PTR SS:[EBP-18]
00543CDF . 8943 24 MOV DWORD PTR DS:[EBX+24],EAX
00543CE2 . 0F84 EA4B0000 JE msnmsgr.005488D2
00543CE8 . FF15 8C154000 CALL DWORD PTR DS:[<&KERNEL32.GetLastError>] ; [GetLastError
00543CEE . 3D B7000000 CMP EAX,0B7
00543CF3 . 0F84 2F4B0000 JE msnmsgr.00548828

...

Donc il appelle CreateEventA avec comme EventName MSNMSGR puis il compare EAX avec EDI or on peut remarquer que EDI est à 0 comme le témoigne le InitiallySignaled et pSecurity à FALSE donc il va tester si la fonction renvoie 0 donc hop un coup de msdn sur CreateEvent et on nous dis que CreateEvent renvoie un handle si la fonction est un succès sinon elle renvoie NULL donc il ne fait que tester si la fonction à bien marcher.
Si la fonction échoue on sort sinon on continue avec un appel à GetLastError().
Comme nous le dis la msdn GetLastError retourne ERROR_ALREADY_EXISTS si jamais l'event existe déjà, on peut donc supposer que le CMP EAX, 0B7 va vérifier si GetLAstError() renvoie ERROR_ALREADY_EXISTS.
Donc on fait un petit coup de msdn sur GetLastError pour trouver à quoi correspond ERROR_ALREADY_EXISTS, elle nous indique une page avec tout les codes d'erreur ( http://msdn2.microsoft.com/en-us/library/ms681381(VS.85).aspx )

On va donc chercher à quoi correspond 0B7h soit 183 et on tombe sur
ERROR_ALREADY_EXISTS         Cannot create a file when that file already exists.
183
0xB7
Tiens on ne s'en serait jamais douté ^^

Donc il vérifie si l'event existe déjà et si il existe il jmp en 00548828

On regarde ce qu'il fait en 00548828 et on s'aperçoit qu'il va chercher la fenêtre de MsnMsgr grâce à FindWindowA() et va lui envoyer un message pour qu'il prenne le focus avec PostMessageW().

Patch MsnMsgr

Donc pour finir cet article, il vous suffit de changer le 0B7 ( ERROR_ALREADY_EXISTS ) de "CMP EAX, 0B7" en 00543CEE par autre chose comme 0B6 ( ERROR_INVALID_ORDINAL ), ça fera très bien l'affaire.

Et bien j'espère que vous avez appris quelque chose aujourd'hui ( en tout cas moi oui ) d'intéressant et puis au moins ça m'aura permis de patcher mon msn pour ouvrir plusieurs compte en même temps ( plus besoin de aMsn )

Have fun :)

vendredi 15 février 2008

La fin du monde de Unix ?

J'imagine que beaucoup d'entre vous connaissent le timestamp, pour ceux qui ne savent pas ce que c'est, c'est un nombre qui représente le nombre de secondes écoulées depuis le 1er Janvier 1970.
Le timestamp est utilisé un peu partout dans les codes Unix notamment dans Linux et malheureusement il subsiste une petite imperfection dans ce mode de fonctionnement.
Certes de prendre une référence commune pour une meilleure synchronisation des informations est une très bonne chose mais le timestamp est un nombre codée sur 32 bits dont seuls les 31 premiers sont utilisables vu que le dernier est réservé le signe ( hum je ne comprend pas trop pourquoi d'ailleurs mais bon ... ).

On peut donc penser qu'il arrivera un moment où on aura attend ces 31 bits et qu'il n'y auras plus de place pour des nombres plus grand.

Voici un petit calcul d'estimation de la fin du monde de Unix :
Fin du monde de Unix le 19/01/2038 a 04:14:07

Donc voila si rien ne change d'ici 2038 Unix a du soucis à se faire pour son futur.
Il se produira comme ce qu'il c'est produit pour le bug de l'an 2000, les programmeurs du monde entier se demander ce qu'il se passerait quand on passerait à l'an 2000 car beaucoup de programme représentaient la date avec seulement 2 chiffres et ils allaient passer de 99 à 00 ce qui aurait pu dérégler les ordinateurs du monde entier mais en fait rien de cela ne c'est produit avec quelque petit bug mineur mais rien de grave.


Référence :

Code de l'estimation de la fin du monde de Unix :
http://akhenathon2.free.fr/coding/FinUnix.c

C'est dommage quand même ^^

lundi 11 février 2008

L'Export Table et GetProcAddress()

J'imagines que tout le monde connait le format PE, le format des executables Windows. Si ce n'est pas le cas je vous conseille d'aller lire ceci avant de commencer cet article : http://en.wikibooks.org/wiki/Reverse_Engineering/PE

Bon alors je vais aujourd'hui parlais d'un point peu soulever dans le format PE car tout le monde parle de l'Import Table dans les introductions au format PE mais j'ai trouvé très peu d'articles sur l'Export Table donc c'est parti pour l'avanture.


Donc on va d'abord voir comment accéder à l'export table et nous verrons ensuite comment récupérer les informations utiles de l'export table et enfin une petite implémentation de GetProcAddress() avec ce que nous viendrons de voir.


Je vous laisse regarder une petite représentation du format PE pour voir ce qui nous interessent : http://ivanlef0u.free.fr/repo/windoz/pe/_pe-tuts/GlobalPE.htm


Donc le format PE commence par une strutcture IMAGE_DOS_HEADER qui contient entre autre un champ e_magic qui représente la signature et le champ e_lflanew qui nous permet de savoir où se trouve la strucuture IMAGE_NT_HEADER.
Donc dans cette structure il y a toujours une signature et si on descend un peu dans l'OptionalHeader, on se retrouve avec des structures IMAGE_DATA_DIRECTORY dont la première est ... l'Export Table.

Bon alors voila je vais finir cette première partie en vous donnant toutes les structures du format PE pour que vous compreniez un peu mieux de quoi on parle.
http://ivanlef0u.free.fr/repo/windoz/pe/pe.txt


Bon après cette très courte introduction au format PE, on va approfondir un petit l'export table pour voir comment elle est composée.
Donc voici un petit résumer de l'organisation de l'export table en mémoire :

Flags ( Characteristics )TimestampMajor VersionMinor VersionNameBaseNombre de FonctionsNombre de NomAdresses des fonctionsAdresses des noms de fonctionsAdresses des noms ordinaux


Donc ici la seule chose que va nous interesser ce sont les 5 derniers champs, normalement Nombre de fonctions == Nombre de Noms donc on peut prendre soit l'un soit l'autre.

Ensuite il faut savoir que les champs d'adresses sont des pointeurs sur un tableau de pointeurs et que ce sont des tableaux en parallèles ce qui veut dire que le premier pointeur du tableau des adresses des fonctions et le premier pointeur du tableau des adresses des noms de fonctions correspondent aux même objet et donc à la même fonction.

En clair soit TabAdressFunc le tableau des adresses des fonctions et TabNameFunc le tableau des adresses des noms de fonctions, TabAdressFunc[0] et TabNameFunc[0] sont deux pointeurs qui font référence à la même fonction.
Et bien entendu la même chose pour le dernier tableau qui sert à déterminer l'adresse de l'adresse de l'API.

Pour récupérer le PE file d'une dll, il suffit juste d'appeler GetModuleHandle() avec comme param le nom de la dll.
Et donc voici un code qui dump l'export table d'une dll en d'occurrence kernel32 et puis vous verez qu'il y a vraiment beaucoup de fonctions exportés.
http://akhenathon2.free.fr/coding/DumpExportTable.c

Et donc voici ce que tout le monde attend, une implémentation de GetProcAddress() :
http://akhenathon2.free.fr/coding/MyGetProcAddress.c

Bon je vous accordes que les codes sont très moches mais en ce moment je n'ai pas trop le temps ( oué c'est les cours mais bon ça en vaut la peine 19.25 en math c'est la classe surtout en 1S ), je les retoucherais si j'ai un peu de temps.

En espérant que cet article vous auras permit d'en apprendre un peu plus sur l'Export Table et éventuellement découvert une alternative à GetProcAddress().

Doc : http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
Have fun :)

vendredi 1 février 2008

Récupérer le PID d'un process

Bon alors aujourd'hui on va voir une alternative aux fameux Process32First()/Process32Next() que je vois très souvent dans les codes pour faire une liste des process ou alors pour rechercher un process dans les process en execution et que je commenterais pas ici car il y a des articles très bien partout sur le net.

Pour un exemple de code regarder ici : http://akhenathon2.free.fr/coding/ProcessNameToPid.c

Bon je vois toujours cette méthode qui consiste à faire une boucle sur Process32Next() pour avoir une liste des process et ensuite vérifier si le szExeFile du process correspond au nom du process qu'on cherche.

Bon les code se ressembleront un peu cependant on va utiliser une fonction qui nous renvoie une liste de PID ( les PID des process en execution ).

Allez c'est parti pour la chasse au PID. On va donc utiliser la fonction EnumProcesses() qui nous renvoie comme promis une liste de PID ainsi que le nombre de process en execution ( il faudra faire une petit opération pour l'avoir ).

Bon comme d'hab on va voir la doc msdn : http://msdn2.microsoft.com/en-us/library/ms682629(VS.85).aspx

Voici le prototype de la fonction EnumProcesses() :
BOOL WINAPI EnumProcesses(
__out DWORD* pProcessIds,
__in DWORD cb,
__out DWORD* pBytesReturned
);

Il nous faut donc un tableau de DWORD qui recevra la liste des PID ainsi qu'un DWORD qui recevra le nombre de bytes retournés, il suffira de le divisé par la taille d'un DWORD pour obtenir le nombre de process en execution.
Alors attention, le tableau doit être assez grand pour recevoir tout les PID j'ai choisi de faire un tableau à 128 entrée mais après a vous de juger le nombre de PID qu'il est sensé y avoir ( avec 128 on a quand même une bonne marge ).
#include <windows.h>
#include <psapi.h>

int main(void)
{
DWORD ListProcess[128], nProcess;

EnumProcesses(ListProcess, sizeof(ListProcess),
&nProcess);
nProcess /= sizeof(DWORD);

/* ... */

return 0;
}


Bon alors maintenant qu'on a la liste des process, il faut récupérer le nom des process pour pouvoir les comparer avec le process qu'on recherche.

Pour ce faire on va utiliser une combinaison des fonctions OpenProcess() ( pour récupérer un handle sur le process ) puis EnumProcessModules() qui nous renverra la liste des module du process et on a des la chance parce que le premier module est le process lui même ensuite suffira de faire un GetModuleBaseName() pour récupérer son nom.

Ici je vais juste faire une liste des process ( je mettrais à la fin quelques codes ).
#include <windows.h>
#include <psapi.h>
#include <stdlib.h>
#include <stdio.h>

int main(void)
{
DWORD ListProcess[128], nProcess;
size_t i;

EnumProcesses(ListProcess, sizeof(ListProcess),
&nProcess);
nProcess /= sizeof(DWORD);

for(i=0;i<nProcess;i++)
{
char szProcessName[MAX_PATH];
HANDLE hProcess=OpenProcess(PROCESS_VM_READ
|PROCESS_QUERY_INFORMATION,
FALSE, ListProcess[i]);

if(hProcess)
{
HMODULE hMod;
DWORD unused;

if(EnumProcessModules(hProcess, &hMod,
sizeof(hMod), &unused))
{
GetModuleBaseName(hProcess, hMod,
szProcessName,
sizeof(szProcessName)/sizeof(char));
printf("[+]ProcessName: %s\tPID: %lu\n",
szProcessName,
ListProcess[i]);
}
}
CloseHandle(hProcess);
}

return 0;
}


Ensuite en modifiant juste le HMODULE en un tableau assez grand vous pourrez récupérer tous les modules du process.

Et donc voici comme promis quelques petits code :
-> ProcessNameToPidWithEnumProcesses.c
-> ListModuleInProcess.c

Have fun :)

PS : N'oubliez pas de linker la lib psapi

Références :

EnumProcesses --> http://msdn2.microsoft.com/en-us/library/ms682629(VS.85).aspx
OpenProcess --> http://msdn2.microsoft.com/en-us/library/ms684320(VS.85).aspx
EnumProcessModules --> http://msdn2.microsoft.com/en-us/library/ms682631(VS.85).aspx
GetModuleBaseName --> http://msdn2.microsoft.com/en-us/library/ms683196(VS.85).aspx