SOUS-CLASSEMENT DE FENÊTRE D'UN AUTRE PROCESS PAR INJECTION DLL

thenaoh Messages postés 111 Date d'inscription dimanche 28 septembre 2003 Statut Membre Dernière intervention 24 juin 2015 - 15 juin 2010 à 17:08
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 - 25 juin 2010 à 01:38
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/51913-sous-classement-de-fenetre-d-un-autre-process-par-injection-dll

racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
25 juin 2010 à 01:38
Franchement, je ne me suis jamais penché sur le sujet mais je pense que si on a vraiment besoin de contrer ces techniques, on a la possibilité de faire un hook API en kernel mode. On pourra intercepter et détourner pour notre processus LdrLoadDll() ou même CreateRemoteThread(). Ce n'est qu'une piste et il y en aura sûrement d'autres.
Pistol_Pete Messages postés 1053 Date d'inscription samedi 2 octobre 2004 Statut Membre Dernière intervention 9 juillet 2013 7
24 juin 2010 à 08:58
Merci pour ta réponse.
J'ai regardé le code et franchement, je ne vois absolument pas comment contrer cette technique.
Comment tu t'y prendrais?
Mettons qu'au moment de l'attache de la dll, on face une seg fault pour planter le programme cible.
A+
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
23 juin 2010 à 21:37
Microsoft a prévu toutes ces fonctions juste pour les besoins de débogage. C'est précisé par MSDN. La technique du CreateRemoteThread() est une idée de Jeffrey Richter qui l'a bien détaillée dans son livre "Programming Applications for Microsoft Windows" publié à la fin des années 90 par Microsoft. Il y a également parlé du sous-classement de fenêtre d'un autre processus mais sans fournir d'exemple de code.
Il est toujours très utile de comprendre comment les choses fonctionnent. Ainsi, si on a besoin de contrer ces techniques dans nos applications, on sait au moins ce qu'on doit faire.
Pistol_Pete Messages postés 1053 Date d'inscription samedi 2 octobre 2004 Statut Membre Dernière intervention 9 juillet 2013 7
22 juin 2010 à 09:07
Salut

C'est une très bonne source et très bien commenté comme toujours!
Bravo.
J'ai néanmoins une question plus haut niveau. A quoi peut servir cette technique mise à part l'espionnage et le hackage...
Windows ne devrait t'il pas justement luter contre les injections de code, de dll, au lieu de fournir des API fonctionnelles pour le faire.
Je prend juste l'exemple de la fonction CreateRemoteThread; a t'on vraiment besoin de créer un thread dans un process qui nous appartient pas...
Merci.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
19 juin 2010 à 20:54
Je viens de faire une petite investigation et, effectivement, la fenêtre du visualistaur appartient bien au process explorer.exe. C'est lui qui la crée. Elle n'a donc pas son propre process. Ceci explique pourquoi la dll ne s'injecte que la première fois. Les tentatives suivantes
échouent car la dll est déjà chargée dans le process explorer.exe. Puisque le sous-classement se fait dès le chargement dans DllMain(), cette dernière ne sera plus appelée et donc la fenêtre cible ne sera pas sous-classée. Il vaut donc mieux éviter ce genre de fenêtre et ne faire des tests qu'avec celles ayant leurs propres processus. Une fois fermées, leurs processus seront terminés et notre dll se trouvera libérée.
thenaoh Messages postés 111 Date d'inscription dimanche 28 septembre 2003 Statut Membre Dernière intervention 24 juin 2015
16 juin 2010 à 13:34
YEEESSSSSSSSSSSSSSSSSSSSSSSSS !!!!!!!!!!
ça y'est ça marche ! Merci infiniment !!!! J'avais mal compris où il fallait que je place ce code, mais maintenant, j'arrive sans problème à déplacer une fenêtre d'une autre application même si elle est sans focus :-)

Concernant le problème du visualisateur d'images, peut-être que ça peut intéresser d'autres personnes, mais ne te casse pas la tête pour moi, je n'en aurai pas l'utilité, et tu en as déjà fait beaucoup ! Cependant, si ça peut t'aider, lorsque j'avais fait le test avec le visualisateur d'images, j'ai pu finalement libérer la DLL en killant le processus explorer.exe . Je sais pas s'il y a un lien, m'enfin bon...

Encore une fois, merci beaucoup pour ton aide ! Me reste plus qu'à savoir comment faire pour connaître la forme du curseur de souris, notamment quand il prend la forme I-beam, mais ça fera l'objet d'un autre post ! (parce que oui, y'a aucun lien avec le sujet courant, évidemment ;-) !!)
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
16 juin 2010 à 13:07
Je n'avais pas faits de tests avec le visualisateur d'images de Windows car j'utilise un autre programme. Je viens de faire un test et c'est vrai ça ne marche que la première fois avec la visionneuse de Windows et la dll n'est effectivement pas libérée. Ca ne vient pas de mon code car normalement le système devrait forcer la libération de la dll une fois le processus de la visionneuse terminé. En essayant de supprimer la dll, le message d'erreur dit : "Cette action ne peut pas être réalisée car le fichier est ouvert dans COM surrogate". Je vais ce soir creuser un peu pour y voir un peu plus clair.
Pour ta fenêtre sans focus, dans le code de la dll, colle les lignes suivantes dans la procédure de sous-classement:
case WM_MOVING:
case WM_SIZING:
{
RECT *pRect=(RECT*)lParam;
SetWindowPos(hwnd, 0, pRect->left, pRect->top, pRect->right-pRect->left, pRect->bottom-pRect->top, 0);
return TRUE;
}
thenaoh Messages postés 111 Date d'inscription dimanche 28 septembre 2003 Statut Membre Dernière intervention 24 juin 2015
16 juin 2010 à 10:31
Merci pour ces précisions !

Alors j'ai refait de nouveaux tests, et il apparaît la chose suivante : si on teste ton code sur un Notepad, ça fonctionne sans problème, on peut refaire 15 fois la même manip, ça marchera les 15 fois (et la DLL est bien libérée comme il faut). Si je teste par contre avec le visualisateur d'images Windows, ça ne marchera qu'une fois, mais pas les suivantes (et la DLL n'est pas libérée), même quand je ferme le visualisateur d'images entre chaque test (et que je fais "Actualiser" dans ton appli entre chaque fois, bien sûr).

Mais pour en revenir à mon souci de fenêtre sans focus qui ne veut pas bouger avec ma souris, j'ai fait la chose suivante : dans le code de la DLL, sous le if(wParam==SC_CLOSE), j'ai ajouté le code suivant, pour forcer le déplacement de ma fenêtre :

else if(wParam == SC_MOVE)
{
RECT *pRect = (RECT *)lParam;
SetWindowPos(hwnd, 0, pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top, 0);
}

mais rien ne se passe. Aurais-tu une idée à ce sujet ?
Merci !!
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
15 juin 2010 à 21:54
Tu dois voir du coté de la dll. Comme précisé dans la présentation, le code de la dll est en pur C. Il ne suffit donc pas de le coller dans un nouveau projet C++. La seule modification à apporter est d'ajouter extern "C" devant la fonction DllMain:
extern "C" int APIENTRY DllMain(...
Le programme Injecteur n'utilise la dll que pour l'injecter dans le processus cible. Elle se trouve donc chargée par ce dernier et tant que ce processus n'est pas fermé la dll ne sera pas libérée donc impossible de la supprimer ou la modifier. C'est tout à fait normal. Tu n'as qu'à fermer toutes les fenêtres que tu as sous-classées pour libérer la dll. L'injecteur n'est pas responsable de sa libération. J'avais pensé ajouter un autre bouton qui appelle une autre fonction qui forcera le processus, ou tous les processus, cible à libérer la dll mais cela comporte le risque de les faire planter. Faute de temps, je ne l'ai finalement pas jugé nécessaire. Je vais revoir cette option plus tard.
Même après fermeture de l'injecteur, les fenêtres déjà choisies restent sous-classées et ont donc encore besoin de la dll. Quand tu relances l'injecteur puis tentes de re-sous-classer l'une de ces fenêtres, un message d'erreur te dira que cette fenêtre a déjà été sous-classée. C'est encore tout à fait normal. D'après les tests que j'ai faits je n'ai remarqué aucune anomalie.
J'espère que les choses sont plus claires maintenant.
thenaoh Messages postés 111 Date d'inscription dimanche 28 septembre 2003 Statut Membre Dernière intervention 24 juin 2015
15 juin 2010 à 17:49
Précisions concernant le problème rencontré : Ton code fonctionne lors de la 1ère utilisation ! Si je ferme et que je relance ton appli pour reproduire le test, là, plus rien ne se passe. N'y aurait-il pas un problème de ressource quelconque non libérée ? Car après avoir lancé puis quitté ton appli, je ne peux pas supprimer la DLL "wndprocdll.dll" (par contre je peux la renommer, ainsi que renommer le répertoire parent ... Comprenne qui pourra ...).

Merci !
thenaoh Messages postés 111 Date d'inscription dimanche 28 septembre 2003 Statut Membre Dernière intervention 24 juin 2015
15 juin 2010 à 17:08
Merci beaucoup pour ce code !

Sauf que j'ai un petit souci, car chez moi, ça ne marche pas ... J'ai créé 2 projets sous Dev C++ (un pour l'exécutable, un pour la DLL), et j'ai copié pour chacun des 2 projets le code que tu as mis en ligne. Mon premier souci a été que "PTHREAD_START_ROUTINE" me générait une erreur de compilation. Après investigation, il semblerait que ce soit un autre nom pour "LPTHREAD_START_ROUTINE", et j'ai donc fait le changement dans mon code. Maintenant, ça compile bien, mais lorsque je lance ton code et que clique sur "Injecter", rien ne semble injecté (je n'ai pas la popup "Ce message prouve que ..." quand je ferme la fenêtre cible), alors que l'exécutable que tu as fourni dans le zip marche.

Je cherche d'où ça peut venir, mais pour l'heure, je ne trouve pas. J'ai également essayé avec Visual Studio 2008 (et donc sans changer "PTHREAD_START_ROUTINE" cette fois), mais pareil, rien ne se passe.

Saurais-tu m'éclairer ?
Rejoignez-nous