Auteur de questions
Impossible de récuperer le hwnd d'une fenetre d'ouverture de session!

Discussion générale
-
Bonjour,
Je suis en train de developper une application d'authentification automatique par carte à puce.
J'ai besoin d'envoyer le login et le mot de passe de l'utilisateur dans les champs adéquat de la fenetre d'ouverture de session Windows.J'ai donc créé un code qui me permet :
- de trouver le hwnd d'une fenetre par son nom (FindWindow)
- de lister les controles enfants de cette fenetre et d'obtenir leur ID
- d'envoyer une chaine de caractere dans le controle grace a son ID.Cela fonctionne parfaitement sur n'importe quelle fenetre.
Seul problème, sur certaines fenetres comme l'ouverture de session ou celle qui apparait quand on appuye sur Ctrl+Alt+Suppr, et bien je n'arrive meme pas à récuperer le handle de la fenetre principale!!!!!J'ai donc décidé de faire une énumération totale des fenetres et des sous fenetres avec leur handle et leur nom.
Et bien croyez le ou non, dans toutes les fenetres que j'ai, je n'ai pas les fenetres concernées...Je ne sais vraiment pas comment faire je suis complètement bloqué, pouvez vous maider ?
Mon code pour inserer du texte dans des controles :
#include <stdio.h> #include <stdlib.h> #include <windows.h> int main(int argc, char *argv[]) { HWND handleFenetre, handleControle[20] = { 0 }; int idControle[20] = { 0 }, i; char textelu[20][100] = { 0 }; sleep(10000); handleFenetre = FindWindow(NULL,"Propriétés système"); // On recupere le handle de la fenetre Sleep(100); printf("Handle fenetre = %d\n\n",handleFenetre); for (i=0;i<15;i++) { if(i==0) { handleControle[i] = GetWindow(handleFenetre,GW_CHILD); // On recupere le handle du sous-controle } else { handleControle[i] = GetWindow(handleControle[i-1],GW_HWNDNEXT); // On recupere le handle du sous-controle } idControle[i] = GetDlgCtrlID(handleControle[i]); // On s'en sert alors pour recuperer son ID GetDlgItemText(handleFenetre, idControle[i], textelu[i], 100); // On lit le texte du controle grace à son ID printf("Handle controle %d = %d\n",i,handleControle[i]); printf("Id controle %d = %d\n",i,idControle[i]); printf("Texte ctl %d = %s\n\n",i,textelu[i]); // On affiche le texte } SendDlgItemMessage(handleFenetre, idControle[3], WM_SETTEXT, 0, (WPARAM)"MonLogin"); SendDlgItemMessage(handleFenetre, idControle[4], WM_SETTEXT, 0, (WPARAM)"MonPass"); system("PAUSE"); return 0; }
Mon code pour enumérer toutes les fenetres et le mettre dans un fichier texte :
#include <stdio.h> #include <stdlib.h> #include <windows.h> typedef struct Fenetres { HWND handle; char titre[300]; } InfoFenetres; FILE* fichier; BOOL CALLBACK fonctionEnumerationFenetre(HWND hwnd, LPARAM lParam); BOOL CALLBACK fonctionEnumerationSousFenetre(HWND hwnd, LPARAM lParam); int main(int argc, char *argv[]) { HWND handleFenetre, handleControle[20] = { 0 }; int idControle[20] = { 0 }, i; char textelu[20][100] = { 0 }; fichier = fopen("test.txt", "w"); sleep(10000); EnumWindows(fonctionEnumerationFenetre,0); system("PAUSE"); return 0; } BOOL CALLBACK fonctionEnumerationFenetre(HWND hwnd, LPARAM lParam) { int taille = GetWindowTextLength(hwnd); char texte[taille+1]; char *c; InfoFenetres Fenetres[200]; static int i=0; GetWindowText(hwnd,texte,taille+1); Fenetres[i].handle = hwnd; strcpy(Fenetres[i].titre,texte); i++; fprintf (fichier, "-------------------------------------------------------\n"); fprintf (fichier, "HandleWnd = %d\n",hwnd); fprintf (fichier, "NomWnd = %s\n\n",texte); EnumChildWindows(hwnd,fonctionEnumerationSousFenetre,0); return 1; } BOOL CALLBACK fonctionEnumerationSousFenetre(HWND hwnd, LPARAM lParam) { int taille = GetWindowTextLength(hwnd); char texte[taille+1]; char *c; InfoFenetres Fenetres[200]; static int i=0; GetWindowText(hwnd,texte,taille+1); Fenetres[i].handle = hwnd; strcpy(Fenetres[i].titre,texte); i++; fprintf (fichier, "HandleChildWnd = %d\n",hwnd); fprintf (fichier, "NomChlidWnd = %s\n\n",texte); return 1; }
Et le contenu du fichier txt (donc pas de fenetre concernée) :------------------------------------------------------- HandleWnd = 65890 NomWnd = TF_FloatingLangBar_WndTitle ------------------------------------------------------- HandleWnd = 65892 NomWnd = CiceroUIWndFrame ------------------------------------------------------- HandleWnd = 65674 NomWnd = ------------------------------------------------------- HandleWnd = 65660 NomWnd = ------------------------------------------------------- HandleWnd = 65676 NomWnd = ------------------------------------------------------- HandleWnd = 65658 NomWnd = ------------------------------------------------------- HandleWnd = 131258 NomWnd = ------------------------------------------------------- HandleWnd = 131216 NomWnd = Menu Démarrer HandleChildWnd = 131254 NomChlidWnd = HandleChildWnd = 131256 NomChlidWnd = Clement HandleChildWnd = 131246 NomChlidWnd = HandleChildWnd = 131248 NomChlidWnd = HandleChildWnd = 131242 NomChlidWnd = HandleChildWnd = 131244 NomChlidWnd = HandleChildWnd = 131230 NomChlidWnd = &Tous les programmes HandleChildWnd = 131236 NomChlidWnd = HandleChildWnd = 131240 NomChlidWnd = HandleChildWnd = 131228 NomChlidWnd = HandleChildWnd = 131250 NomChlidWnd = HandleChildWnd = 131238 NomChlidWnd = ------------------------------------------------------- HandleWnd = 196680 NomWnd = ------------------------------------------------------- HandleWnd = 1572968 NomWnd = ------------------------------------------------------- HandleWnd = 262198 NomWnd = HandleChildWnd = 196670 NomChlidWnd = démarrer HandleChildWnd = 196668 NomChlidWnd = HandleChildWnd = 196672 NomChlidWnd = 20:45 HandleChildWnd = 196674 NomChlidWnd = HandleChildWnd = 196676 NomChlidWnd = Zone de notification HandleChildWnd = 196678 NomChlidWnd = HandleChildWnd = 65662 NomChlidWnd = HandleChildWnd = 65668 NomChlidWnd = Applications en cours d'exécution HandleChildWnd = 65672 NomChlidWnd = Applications en cours d'exécution HandleChildWnd = 65666 NomChlidWnd = Quick Launch ------------------------------------------------------- HandleWnd = 65688 NomWnd = ------------------------------------------------------- HandleWnd = 131218 NomWnd = ------------------------------------------------------- HandleWnd = 131252 NomWnd = ------------------------------------------------------- HandleWnd = 328126 NomWnd = C:\Documents and Settings\Clement\Bureau\Copie de clavier\clavier.exe ------------------------------------------------------- HandleWnd = 65882 NomWnd = ------------------------------------------------------- HandleWnd = 65952 NomWnd = ------------------------------------------------------- HandleWnd = 65950 NomWnd = DAEMON Tools Agent window ------------------------------------------------------- HandleWnd = 65946 NomWnd = DDE Server Window ------------------------------------------------------- HandleWnd = 65932 NomWnd = DccMan ------------------------------------------------------- HandleWnd = 65928 NomWnd = RAPIMgr ------------------------------------------------------- HandleWnd = 65922 NomWnd = ------------------------------------------------------- HandleWnd = 65888 NomWnd = ------------------------------------------------------- HandleWnd = 131390 NomWnd = MS_WebcheckMonitor ------------------------------------------------------- HandleWnd = 65846 NomWnd = CAvastTrayIcon ------------------------------------------------------- HandleWnd = 65842 NomWnd = ------------------------------------------------------- HandleWnd = 131368 NomWnd = avast! UI Control Window ------------------------------------------------------- HandleWnd = 65812 NomWnd = ------------------------------------------------------- HandleWnd = 131316 NomWnd = Dialog HandleChildWnd = 65798 NomChlidWnd = OK HandleChildWnd = 65800 NomChlidWnd = Cancel ------------------------------------------------------- HandleWnd = 65896 NomWnd = Connections Tray ------------------------------------------------------- HandleWnd = 196800 NomWnd = ------------------------------------------------------- HandleWnd = 262426 NomWnd = Jauge d'énergie HandleChildWnd = 65874 NomChlidWnd = État de l'alimentation HandleChildWnd = 65876 NomChlidWnd = Toujours &afficher l'icône sur la barre des tâches. HandleChildWnd = 65878 NomChlidWnd = Afficher les détails pour chaque &batterie. HandleChildWnd = 65880 NomChlidWnd = ------------------------------------------------------- HandleWnd = 65736 NomWnd = Management - O&O Defrag HandleChildWnd = 65740 NomChlidWnd = HandleChildWnd = 65744 NomChlidWnd = xtpBarTop HandleChildWnd = 65752 NomChlidWnd = Typical HandleChildWnd = 65746 NomChlidWnd = xtpBarBottom HandleChildWnd = 65748 NomChlidWnd = xtpBarLeft HandleChildWnd = 65750 NomChlidWnd = xtpBarRight ------------------------------------------------------- HandleWnd = 65734 NomWnd = MediaCenter ------------------------------------------------------- HandleWnd = 65730 NomWnd = ------------------------------------------------------- HandleWnd = 65664 NomWnd = ------------------------------------------------------- HandleWnd = 327754 NomWnd = ------------------------------------------------------- HandleWnd = 131150 NomWnd = ------------------------------------------------------- HandleWnd = 131154 NomWnd = ------------------------------------------------------- HandleWnd = 65578 NomWnd = NVSVCPMMWindowClass ------------------------------------------------------- HandleWnd = 65690 NomWnd = ------------------------------------------------------- HandleWnd = 65678 NomWnd = Program Manager HandleChildWnd = 65684 NomChlidWnd = HandleChildWnd = 65686 NomChlidWnd = FolderView ------------------------------------------------------- HandleWnd = 196666 NomWnd = M ------------------------------------------------------- HandleWnd = 196664 NomWnd = Default IME ------------------------------------------------------- HandleWnd = 65884 NomWnd = Default IME ------------------------------------------------------- HandleWnd = 65948 NomWnd = Default IME ------------------------------------------------------- HandleWnd = 65934 NomWnd = Default IME ------------------------------------------------------- HandleWnd = 65930 NomWnd = Default IME ------------------------------------------------------- HandleWnd = 65924 NomWnd = Default IME ------------------------------------------------------- HandleWnd = 131366 NomWnd = Default IME ------------------------------------------------------- HandleWnd = 65804 NomWnd = M ------------------------------------------------------- HandleWnd = 65738 NomWnd = Default IME ------------------------------------------------------- HandleWnd = 65872 NomWnd = Default IME ------------------------------------------------------- HandleWnd = 65732 NomWnd = Default IME ------------------------------------------------------- HandleWnd = 65698 NomWnd = M ------------------------------------------------------- HandleWnd = 131152 NomWnd = Default IME
Merci de bien vouloir m'aider je suis dans l'impasse !
Est-ce que les fenetres "sensibles" sont cachées ou autre ?
Toutes les réponses
-
-
Bonjour,
Oui il semblerai qu'on soit en procédure sécurisée (ce que Microsoft appelle S.A.S) par le biais de la DLL gina qui gere l'authentification.
De fait, meme avec GetForegroundWindow(); cela me retourne NULL alors que j'ai la fenetre d'ouverture de session active, ou bien celle de sortie d'écran de veille (meme résultat)
Le fait de simuler l'appui de touche avec keybd_event(); ne fonctionne visiblement pas non plus.
Lancer mon application en tant qu'utilisateur SYSTEM ne change rien non plus.Après tout ces tests je suis un peu dans l'impasse!
Peux tu me dire comment changer de desktop ?
Ou bien est-il possible de trouver une autre gina.dll ne disposant pas de ces restrictions ?Voici ce que j'ai trouvé et qui explique qu'il est impossible d'utiliser GetForegroundWindow(); quand plusieurs desktop sont actifs, et visiblement l'ecran d'ouverture de session et celui d'ecran de veille en sont d'autres -> http://support.microsoft.com/kb/118624/en-us
-
La candeur des débutants (en sécurité Windows ;-) ), c'est touchant.
Votre raisonnement est correct sauf que si n'importe quel programme pourrait le faire, la sécurité du système Windows, déjà passablement malmené, ne serait qu'une vaste supercherie. ;-))
Les Desktop de login et de l'économiseur d'écran sont des desktop très particulier.
Pour implémenter un mode de login particulier vous devez implémenter une dll GINA pour XP (ou plus vieux) http://en.wikipedia.org/wiki/Graphical_identification_and_authentication ; Credential Provider API pour Vista et supérieur http://technet.microsoft.com/en-us/library/ff404303(WS.10).aspx
Paul Bacelar, Ex - MVP VC++ -
Bonjour,
Après toutes mes recherches j'ai pu remarquer que cela est visiblement extremement compliqué.
Ce que j'ai compris :
- La fenetre d'ouverture de session dépend de gina.dll
- Elle est situé sur le Desktop le + sécurisé, à savoir le desktop winlogon.
- Hors sur ce Desktop un seul programme a le droit de s'éxecuter : winlogon.exeJ'ai compilé et implémenté sur une machine virtuelle ma propre dll gina (ginafull) téléchargée sur msdn.
Cela fonctionne bien (meme si c'est moche)Le problème c'est que je n'ai absoulement aucune connaissance dans l'écriture et la compilation de DLL, en etudiant gina je ne trouve meme pas le main() (peut etre qu'il n'y en a pas justement).
Je cherche donc un moyen simple d'executer un code qui me permettrai d'écouter mon port RS232, et d'envoyer le login/pass dans la fenetre d'ouverture de session.Il me semble pas que ce soit la vocation de la DLL, est-il donc possible dans cette DLL gina d'appeller mon .exe qui contiendrai mon code et qui s'executerai donc sur le desktop winlogon ?
Il ne s'agit pas de réinventer la roue, car visiblement cela est très bien implémenté sur windows 7 (d'après les liens que tu m'a donné), je cherche juste à concevoir quelque chose de simple pour XP. La puce serait elle meme très simple (type puce téléphone, et non a microprocesseur). Lorsque mes connaissances seront suffisantes je pourrai concevoir ma grosse machine a gaz gina ultra-sécurisée, mais j'en suis pas la!
-
Une Dll c'est du code exécutable comme un autre.
Du code exécutable avec un point d'entré "main" est un cas très particulier.
Il faut que vous changiez votre manière de penser.
GINA est une Dll car ce n'est pas elle qui pilote le processus d'authentification, elle n'est là que pour fournir un certain nombre d'information à WinLogon.exe.
Elle doit implémenter un certain nombre de point d'entré (fonctions C/C++) dont la liste est indiqué dans ces deux articles : http://msdn.microsoft.com/en-us/magazine/cc163803.aspx et http://msdn.microsoft.com/en-us/magazine/cc163786.aspx.
Ces articles montrent aussi comment utiliser les fonctionnalités de Winlogon.exe pour que les dll GINA puissent interagir avec l'IHM.
Le "main" d'une dll, c'est, sous le compilateur VC++, "DllMain", mais vous ne devez qu'initialiser les dll utilisées par votre dll et rien de plus. C'est Winlogon qui fait appel aux fonctions exportés par votre Dll GINA.
Créer une Dll avec VS, c'est très simple, il suffit de créer un projet de type Dll.
Il faudra faire attention à bien mettre devant le nom de chaque fonction à exporter la MACRO correspondant à celui de votre Dll (c'est une MACRO dont le nom dérive du nom de votre projet).
Je ne dis pas que faire une Dll GINA est trivial, mais faire une simple Dll, c'est très simple.
Je vous conseil de commencer par faire un exécutable qui encapsule le code d'accès au port RS232 dans des fonctions.
Quand ce code est au point, transférez le code des fonctions dans le projet Dll. En utilisant les noms de fonctions attendus par Winlogon.exe, implémentez ces fonctions à partir des précédente fonctions.
Essayez de comprendre dans quel ordre Winlogon.exe appel les fonctions exportées par la Dll et transformez le code de l'exécutable pour qu'il appel les fonctions de la dll selon l'ordre de Winlogon.
Vous pourrez ainsi débugger votre Dll sans avoir à tripatouiller votre base de registre.
Une fois que tous semble OK, configurez la base de registre pour voir comment Winlogon.exe supporte cette nouvelle méthode d'authentification.
Paul Bacelar, Ex - MVP VC++ -
OK, je pense avoir compris la majorité de ce que vous avez écrit.
Le probleme c'est qu'il faut bien que j'ai un executable qui tourne en permanence dans tous les Desktop et qui me servirai a scruter ce qui se passe sur le port RS232 ?
Des que la boucle infinie de cet executable detecte une carte, il faudrait qu'il envoie le login/pass à GINA, et qu'il valide.
-> Donc si j'ai bien compris, mon exe appelle une fonction que j'aurai ecrite dans gina.dll qui recoit le login/pass et qui contiendrai des PostMessage(); etc..)Mais je ne vois pas trop par où commencer...
Par exemple commencer par un truc simple sans parler du RS232 :
Recompiler gina.dll avec un sleep(20000) qui au bout de ce temps la, m'insere un login et un pass bidon arbritrairement défini.Et juste ca, je ne vois pas où l'implémenter dans la dll !
-
Le probleme c'est qu'il faut bien que j'ai un executable qui tourne en permanence dans tous les Desktop et qui me servirai a scruter ce qui se passe sur le port RS232 ?
Il n'y a pas un port RS232 par Desktop, il y a qu'un port RS232 partagé par tous les Desktop. OK ?
Il ne vous faut pas un exécutable, et encore moins qui tourne en permanence (boucle active, beurk), mais du code qui réagit à un évènement.
Ce code peut être dans le thread principale d'un exécutable dédié, mais peut aussi être dans le thread principale d'un exécutable non dédié, par des mécanismes de fonction de callback "STA" like ou d'envoie de message, etc. ; dans un thread de travail créé par un exécutable ou une dll (thread dédié ou pas à cette tâche), et encore bien d'autre moyens.
Des que la boucle infinie de cet executable detecte une carte, il faudrait qu'il envoie le login/pass à GINA, et qu'il valide.
Les boucle infinies, cela n'existe pas dans du code correct.
Vous voulez que la session de l'utilisateur interactif se coupe quand l'utilisateur insert une carte ?
Très étrange comme comportement, c'est plutôt la fermeture de la session lors du retrait de la carte qu'il faudrait implémenter.
La méthode la plus naturelle, utilisez les API de notification sur le driver de la carte pendant le DllMain de la Dll GINA. Ainsi, le code de la fonction de callback enregistrée sera automatiquement appelé par les mécanismes de l'API de notification.
Votre dll est chargé par WinLogon.exe, elle sera donc toujours chargée, même quand il n'y a pas d'utilisateur connecté.
Elle pourra demander la fin de la session lors du retrait de la carte et demander à WinLogin.exe d'affiché la mire de login lors de l'insertion de la carte. Il n'y a donc aucune boucle active.
-> Donc si j'ai bien compris, mon exe appelle une fonction que j'aurai ecrite dans gina.dll qui recoit le login/pass et qui contiendrai des PostMessage(); etc..)
Quel PostMessage ?
Je crois que vous avez une vue un peu trop stéréotypée d'un exécutable Windows. L'envoie de message n'est pas le seul moyen de communication avec un processus. Et c'est, pour moi, le pire de tous.
Commencez par avoir un exécutable qui charge implicitement votre dll (qui sera votre Dll GINA à la fin) et faites en sorte que du code (fonctions) de votre dll soit appelé lors de l'insertion et du retrait de la carte dans le lecteur. Cela devrait être facilement possible avec les API de notification de votre couche d'accès à ce lecteur.
Mais je ne vois pas trop par où commencer...
Par exemple commencer par un truc simple sans parler du RS232 :
Recompiler gina.dll avec un sleep(20000) qui au bout de ce temps la, m'insere un login et un pass bidon arbritrairement défini.Et juste ca, je ne vois pas où l'implémenter dans la dll !
Trop compliqué pour un début.Faites un simple exécutable qui utilise l'API de notification pour enregistrer des fonctions qui seront appelées lors des évènements d'insertion et de suppression de la carte. Utilisez OutputDebugString pour les traces.
Cela permet d'avoir des traces qui ne dépendent pas d'une console, d'une pompe à message et autres cochonneries qui n'existent pas dans des dll.
N'utilisez pas de boucle active mais une pompe à message pour que du temps CPU reste disponible pour les notifications.
Utilisez donc une pompe à message dans le main de votre exécutable.
Une fois cela fait, créer une dll et mettez le code de ces fonctions de callback dans votre dll. Mettez tout le code d'initialisation de l'API de notification du lecteur de carte dans la fonction DllMain de votre Dll. Attention, pas de pompe à message ou de boucle active SVP.
Créez un exécutable qui charge implicitement cette dll. Cela déclenchera l'appel de la fonction DllMain de votre dll dès le chargement de votre exécutable.
Ajoutez au code de l'exécutable les fonctions que votre dll GINA est sensé appelé dans le programme WinLogon.exe.
Ce n'est pas si compliqué que cela en a l'air, mais il faut comprendre qu'un programme n'est pas linéaire (pompe à message et fonction de callback sur évènement), et que la majorité du code s'exécute dans des modules qui ne sont pas de simples exécutables.
Si vous restez dans le brouillard, donnez nous la forme d'API de notification publiée par le driver ou la couche logicielle d'accès au lecteur de carte.
On vous montrera en pseudo-code comment utiliser cette API dans le cadre d'une Dll.
Paul Bacelar, Ex - MVP VC++