none
Impossible de récuperer le hwnd d'une fenetre d'ouverture de session! RRS feed

  • 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 ?

    samedi 18 juin 2011 20:12

Toutes les réponses

  • normal, il faut changer de Desktop
    dimanche 19 juin 2011 07:40
  • 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

    dimanche 19 juin 2011 09:26
  • 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++
    lundi 20 juin 2011 08:58
    Modérateur
  • 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.exe

    J'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!

    lundi 20 juin 2011 09:31
  • 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++
    lundi 20 juin 2011 11:31
    Modérateur
  • 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 !



    lundi 20 juin 2011 15:19
  • 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++

    vendredi 24 juin 2011 12:27
    Modérateur