lundi 28 janvier 2008

OutputDebugString

Bonjour a tous, dans cet article je vais essayer de vous expliquer comment récupérer les OutputDebugString d'un process en particulier.

Je pense que bon nombre d'entre vous connaissent déjà la fonction OutputDebugString() qui permet d'envoyer des strings au debugger, elle est très utilisés pour debugger une application pour remplacer les printf() qui pollue un peu la console.

Un outil très pratique pour récupérer les OutputDebugStrings est DebugView qui permet non seulement de récupérer les OutputDebugStrings des applis mais aussi ceux du kernel et peut aussi se connecter à un autre PC pour recevoir ses OutputDebugStrings.


Donc c'est parti, on va les récupérer ces OutputDebugString.
Bon on va voir un peu du côté de la page de man de msdn sur les debugging fonctions : http://msdn2.microsoft.com/en-us/library/ms679303(VS.85).aspx

Bon c'est cool, on voit la fameuse OutputDebugString() mais on voit aussi une fonction qui peut être très intéressante WaitForDebugEvent()

BOOL WINAPI WaitForDebugEvent(
__out LPDEBUG_EVENT lpDebugEvent,
__in DWORD dwMilliseconds
);


Mouai bon jusque là ça va rien de bien compliquer donc on lit la page de description jusqu'à la fin ( on fait pas comme moi et on se fait pas chier parce qu'on avait loupé un truc pourri =p )

Bon aller on fait un petit test alors

#include <windows.h>
#include <stdio.h>

int main(void)
{
LPDEBUG_EVENT lpDebugEvent;

if(!WaitForDebugEvent(lpDebugEvent, INFINITE))
printf("GetLastError() : %lu\n", GetLastError());

return 0;
}


Le résultat : GetLastError() : 6
Hum what the fuck ?

Bon on va voir ce que ça veut dire http://msdn2.microsoft.com/en-us/library/ms681381(VS.85).aspx

ERROR_INVALID_HANDLE The handle is invalid.

Bon au moins c'est clair.

Bon on regarde un peu mieux les fonctions de debugging, tiens c'est quoi DebugActiveProcess() ?

Super ça nous permet de spécifier un process.

Sauf qu'avant il faut choper le PID du process ( bon je passe j'en parlerais surement dans un prochain article ).

Donc on a le PID du process et on reteste en modifiant un peu le code.

#include <windows.h>
#include <stdio.h>

int main(void)
{
STARTUPINFO StartupInfo = {0};
PROCESS_INFORMATION ProcessInfo = {0};
char path[] = "C:\\test.exe";

if(!CreateProcess(path, NULL, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &StartupInfo, &ProcessInfo))
{
printf("Error with CreateProcess() to open %s : %lu\n", path, GetLastError());
exit(1);
}

DebugActiveProcess(ProcessInfo.dwProcessId);

while(1)
{
DEBUG_EVENT DebugEvent;

if(!WaitForDebugEvent(&DebugEvent, INFINITE))
{
printf("GetLastError() : %lu\n", GetLastError());
exit(1);
}

printf("Debug event code : %lu\n", DebugEvent.dwDebugEventCode);

if(DebugEvent.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
{
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
break;
}

ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_CONTINUE);
}

return 0;
}


Il y a plus ou moins de DebugEvent selon le process, on n'oublie pas d'appeler ContinueDebugEvent() pour qu'on puisse recevoir les autres DebugEvent et on n'oublie pas non plus de fermer les handles lorsqu'on reçoit EXIT_PROCESS_DEBUG_EVENT comme le dis la doc msdn.


Maintenant suffit de ce concentrer sur le OUTPUT_DEBUG_STRING_EVENT pour recevoir les OutputDebugString() et d'utiliser la structure OUTPUT_DEBUG_STRING_INFO de DEBUG_EVENT.

Comme on le lis dans la doc, il faut utiliser ReadProcessMemory pour récupérer la string.

#include <windows.h>
#include <stdio.h>

int main(void)
{
STARTUPINFO StartupInfo = {0};
PROCESS_INFORMATION ProcessInfo = {0};
char path[] = "C:\\test.exe";

if(!CreateProcess(path, NULL, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &StartupInfo, &ProcessInfo))
{
printf("Error with CreateProcess() to open %s : %lu\n", path, GetLastError());
exit(1);
}

DebugActiveProcess(ProcessInfo.dwProcessId);

while(1)
{
DEBUG_EVENT DebugEvent;

if(!WaitForDebugEvent(&DebugEvent, INFINITE))
{
printf("GetLastError() : %lu\n", GetLastError());
exit(1);
}

if(DebugEvent.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
{
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
break;
}
else if(DebugEvent.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
{
char *str = malloc(sizeof(char) * DebugEvent.u.DebugString.nDebugStringLength);

ReadProcessMemory(ProcessInfo.hProcess, DebugEvent.u.DebugString.lpDebugStringData, str, DebugEvent.u.DebugString.nDebugStringLength, NULL);

printf("OutputDebugString sent %s\n", str);

free(str);
}
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_CONTINUE);
}

return 0;
}


Et hop c'est magique, on récupère les OutputDebugString du Process.

Maintenant je vais essayer de trouver un moyen d'intercepter tout les OuputDebugString des tous les Process ( si quelqu'un connait un moyen d'y arriver qu'il me fasse signe ).

En espérant que cet article vous aura appris quelque chose d'utile et en espérant aussi que l'article soit assez compréhensible.

Si vous avez des questions ou des commentaires n'hésitez surtout pas.

Akhenathon

lundi 14 janvier 2008

Création d'un kernel

Mon projet du moment est la création d'un kernel en partant de zéro.
Donc bien entendu, il faut recoder entièrement la libc, ce qui n'est pas une mauvaise chose en soit je me suis bien éclater à écrire quelque fonction comme vsnprintf que gère le formatage des chaines à la façon de toutes les fonctions *f().

Pour le moment le kernel démarre et affiche un message de bienvenue à l'écran, ce qui est déjà bien.
J'ai commencé à implémenter quelques fonctions comme vsnprintf, printk qui est l'équivalent de printf mais pour le kernel ainsi que quelques structures de base comme size_t que j'utilise beaucoup.

Ouverture du blog

Bonjour à tous cher blogger,
j'ai décidé de créer ce blog pour traiter tout ce qui concerne le Reverse Engineering, la programmation et pour être plus général toutes mes découvertes intéressantes en sécurité informatique; my geek life quoi.

Je tiens à remercier très particulièrement lilxam qui sans lui ce blog n'existerait pas.

Have fun :)