samedi 12 janvier 2008

Close a remote handle file.

Bonjour à tous,
me revoilà après un petit peu d'absence ,tout cela par la faute des vacances scolaires et des fêtes bien sure.
Trêve de plaisanterie ,en cette nouvelle année je reprend mon petit régime hebdomadaire.
Aujourd'hui c'est un post de Ivanlef0u qui attire mon attention : Playing with windows handle.
Dans ce post il explique comment récupérer le type d'un handle ainsi que son nom.
Bien sure on utilise encore une fois la belle api windows ainsi que quelques fonctions ,venues tout droit de ntdll.
Ceci dis j'ai voulus moi même tenter l'expérience ,en codant exactement ce qu'il avait déjà réalisé.
Cela permet de mettre des petites choses au point ,être sois même confronté aux problèmes éventuels et j'en passe.
Cependant j'ai décidé d'utilisé ce petit code afin de m'amuser avec les handles de type file.
Notre but ,va donc être de fermer un handle file d'un processus !

Comme vous le savez peut être ,chaque processus possèdent des handles ouvert sur des objets qui peuvent être :

- des files
- des events
- des mutexs
- des pipes et j'en passe
Allez voir par ici ,notre fabuleuse msdn : http://msdn2.microsoft.com/en-us/library/ms724251.aspx.

Je vais donc vous expliquez comment on va opérer :

- Tous d'abord ,on doit récupérer des informations sur tous les handles ouvert sur le système ,on utilisera ntQuerySystemInformation avec l'argument SystemHandleInformation.
- Ensuite on doit trier les structures ,afin de garder seulement celles qui concernent notre processus ,on compare donc le membre de la struct spécifiant le PID avec le PID de notre processus.
- A présent on doit retrouver le type de handle auquel nous avons a faire ,on duplique notre handle afin de query des informations dessus ,duplicateHandle donc.
- Une fois dupliqué nous pouvons utiliser NtQueryObject afin d'obtenir son type.
- A présent ,si vous lisez le post Ivanlef0u il parle d'un bug au niveau des types files : et bien en effet on est obligé d'implanter une petite astuce permettant de savoir si oui ou non notre fonction est bloquante.
On lance donc des threads qui s'occupe de récupérer le nom du handle ,seulement si il dépasse le timeout on les close.
Le thread va donc s'occuper de remplir notre structure ,que nous traiterons dans la fonction qui l'appel.
- On compare le nom avec le fichier que nous voulons fermer ,et on lance notre fonction CloseHandle.

Cette fonction utilise un système que l'on a largement travaillé ,au fil de se blog : l'exécution de code bien sure.
On créer un thread dans notre processus cible sur la fonction CloseHandle ,on lui passe un pointeur sur notre handle et BIM closed.

Voilà en gros le petit code.
Celui-ci est peut être assez 'velus' à lire ,des structures en pagailles et tous cela dans un seul fichier.
Tous cela pour dire que n'hésiter pas à utiliser les headers et compagnie.
Pour tester ce petit programme ,j'ai codé un petit fopen ,qui se charge de garder le fichier ouvert ,on peut alors lancer le close de notre handle.

Place au concret ,voici un petit screenshot :



et un petit dernier :



Maintenant le principale ,les codes :

-CloseAFuckingFileHandle.c.
-HandleOpen.c.

Voici quelques liens intéréssants :

-Je vous conseille de telecharger le SDK ,elle contient de la doc concernant certaines apis natives.
-ZwQueryInformationFile -> http://www.osronline.com/DDKx/kmarch/k111_9pyq.htm.
-Playing with windows Handles -> http://www.ivanlef0u.tuxfamily.org/?p=13.

PS : un petit merci à wizardman pour sa générosité concernant le futur dns :) ainsi que Nam_K .
PS2 : merci à blackclowns pour son zine ,vraiment technique un grand merci.
PS3 : Le blog est actuellement disponible avec l'adresse suivant : www.0vercl0k.fr

7 commentaires:

Anonyme a dit…

Nice.
Mdr le petit nom de domaine qui va bien.
Bonne continuation,

Signé ton poil de zboub de colibri préferé.

Anonyme a dit…

Salut,

Merci pour cet article.

Petite question.

Le problème de cette manipulation, c'est que tu coupes l'action du process parent sur le handle.

Aurais tu une idée pour au lieu de fermer le handle, d'utiliser le duplicate pour pouvoir copier le fichier.

Pour être plus clair, si on suppose que le fichier est en cours d'utilisation exclusive, alors tu peux pas le copier.

Mais si tu voulais le copier sans couper l'application qui l'utilise, tu ferais comment ?

@+

0vercl0k a dit…

Bonjour à toi,
et merci de t'intéresser a mes travaux.

Cependant, si je comprends bien tu voudrais fermer 'proprement' le handle?

C'est à dire que tu voudrais qu'il soit inutilisé lors de sa fermeture ?
Pour éviter de le couper pendant une écriture par exemple?

Donc c'est à ce moment là que je me demande qu'elle est l'intérêt : autant attendre que l'application n'en n'est plus besoin?

Ceci dit je vais réfléchir un peu à cela :).

Bonne après midi.
Cordialement, 0vercl0k.

Anonyme a dit…

Salut,

Encore moi l'anonyme (Régis)

Dans ton code, pourquoi fais tu ca :
PROCESSENTRY32 structprocsnapshot = {0};

Il y a un exemple intéressant chez microsoft :
http://msdn2.microsoft.com/en-us/library/ms686701(VS.85).aspx

Et ils ne font pas d'initialisation.

@+
Régis

Anonyme a dit…

Bon encore moi l'anonyme,

Je continue a décortiquer ton code et à le commenter pour être sûr de bien le maitriser.

J'ai relevé une erreur, voir 2.

if(Process32First(snapshot,&structprocsnapshot) == FALSE)
return 0;

Tu oublies de fermer le handle.

Anonyme a dit…

Re moi,

Maintenant dans ta boucle do while

Tu as :
retour = ntQuerySystemInformation(SystemHandleInformation,ptrStructHandle,tailleStruct,&tailleTotal);
tailleStruct *= 2;
ptrStructHandle = (PSYSTEM_HANDLE_INFORMATION)realloc(ptrStructHandle,tailleStruct);

Et donc, tant que retour est pas bon tu réalloues 2 fois plus de taille pour ta structure.

Alors que si je comprends bien l'explication de MSDN :
http://msdn2.microsoft.com/en-us/library/ms724509.aspx

"ReturnLength

An optional pointer to a location where the function writes the actual size of the information requested. If that size is less than or equal to the SystemInformationLength parameter, the function copies the information into the SystemInformation buffer; otherwise, it returns an NTSTATUS error code and returns in ReturnLength the size of buffer required to receive the requested information."

Dès que tu as un échec, alors le pointeur de ton argument contient la taille nécessaire pour ta structure, donc plutôt que de tâtonner en multipliant par 2, tu pourrais utiliser directement la taille qu'il te renvoie.

Dis moi si je me trompe

Je continue l'étude

0vercl0k a dit…

Re bonjour à toi,
En effet tes remarques sont justes, seulement.
Cependant, oublier de fermer un handle n'est pas bien grave, je pense, étant donné que le code est un juste un simple PoC, il illustrait une technique permettant de lancer une fonction au sein d'un processus "distant" avec la fonction CreateRemoteThread().
En espérant avoir été clair et désolé des petites négligence d'optimisations :).

PS : En ce qui concerne l'initialisation de la structure à zéro, celle-ci est peut être superflus, elle est juste ici pour éviter quelques problèmes, les variables devraient d'après mes lectures être initialisées..chose à laquelle je ne pense presque jamais .

Cordialement 0vercl0k.