IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Discussion :

erreur 299 avec EnumProcessModulesEx en 64 bits


Sujet :

Windows

  1. #1
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut erreur 299 avec EnumProcessModulesEx en 64 bits
    Je souhaite énumérer les modules d'une application. Je suis sous Windows 64 bits, je compile les applications en 64 bits. Donc tout est en 64 bits. Dependency Walker me le confirme.

    Le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    #define PSAPI_VERSION 1
    #define _WIN32_WINNT 0x0601
    #include <stdio.h>
    
    #include <windows.h>
    #include <psapi.h>
    
    #define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
    
    int main(int argc, char *argv[])
    {
      STARTUPINFO         si;
      PROCESS_INFORMATION pi;
      char *file;
      HANDLE process;
      HMODULE modules[100];
      DWORD s;
      DWORD needed;
      BOOL res;
    
      if (argc < 2)
        return 1;
    
      file = argv[1];
      printf("%s\n", file);
    
      ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
      ZeroMemory(&si, sizeof(STARTUPINFO));
      si.cb = sizeof(STARTUPINFO);
    
      if (!CreateProcess(NULL, file, NULL, NULL, TRUE,
                         CREATE_SUSPENDED, NULL, NULL, &si, &pi))
        {
          printf("CreateProcess failed \n");
          return 1;
        }
    
      if (!WaitForInputIdle(pi.hProcess, INFINITE))
        {
          printf("WaitForInputIdle failed \n");
          return 1;
        }
    
      process = OpenProcess(QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pi.dwProcessId);
      if (!process)
        {
          printf("OpenProcess failed \n");
          return 1;
        }
    
      s = 100;
      res = EnumProcessModulesEx(process, modules, sizeof(modules), &needed, LIST_MODULES_ALL);
      if (!res)
        {
          printf("failed %ld\n", GetLastError());
        }
    
      printf("size : %lu, %Iu\n", needed, needed / sizeof(HMODULE));
    
      return 0;
    }
    EnumProcessModulesEx() retourne l'erreur 299 (ERROR_PARTIAL_COPY : "Only part of a ReadProcessMemory or WriteProcessMemory request was completed.")

    Cette erreur est renvoyée en général quand il y a un processus 32 bits, mais l'application que je passe en argument est une application 64 bits, ainsi que l'application dont le code est ci-dessus.

    Quelqu'un verrait-il le problème ?

    merci

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Je n'ai pas d'explication pour ton problème, mais juste pour être sûr, tu devrais peut-être commencer ton application par un printf("sizeof ptr=%Iu\n", sizeof(void*));Pour le reste, j'ai trois remarques:
    • j'ai du mal à voir comment tu peux WaitForInputIdle() un processus créé en CREATE_SUSPENDED...
    • le handle retourné par CreateProcess() est supposé avoir les droits PROCESS_ALL_ACCESS, j'ai donc du mal à voir pourquoi tu ouvres un second handle dessus.
    • Attention, needed est un DWORD et non pas un size_t, ton printf() final échouera donc.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Je n'ai pas d'explication pour ton problème, mais juste pour être sûr, tu devrais peut-être commencer ton application par un printf("sizeof ptr=%Iu\n", sizeof(void*));
    tu veux vérifier que je suis en 64 bits ? Donc oui, et ça renvoie 8.

    Pour le reste, j'ai trois remarques:
    • j'ai du mal à voir comment tu peux WaitForInputIdle() un processus créé en CREATE_SUSPENDED...
    • le handle retourné par CreateProcess() est supposé avoir les droits PROCESS_ALL_ACCESS, j'ai donc du mal à voir pourquoi tu ouvres un second handle dessus.
    honnêtement, je ne sais pas trop. Je fais un petit outil de détection de memory leak avec injection de DLL et d'API hook. J'ai repris une partie de code trouvé sur Codeproject pour cette partie. Le bout de code que j'ai posté est une adaptation très rapide de mon code pour faire un exemple de test d'EnumProcessModulesEx.

    Il me semble que j'avais enlevé WaitForInputIdle et OpenProcess et que j'avais constaté que ça ne marchait plus. Mais je regarderai, merci.

    Attention, needed est un DWORD et non pas un size_t, ton printf() final échouera donc.
    héhé, c'est un 'l' (lettre après 'k') et non un 'I' (i majuscule) pour needed. Ce n'est pas très visible

    J'ai enlevé WaitForInputIdle et OenProcess :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #define PSAPI_VERSION 1
    #define _WIN32_WINNT 0x0601
    #include <stdio.h>
    
    #include <windows.h>
    #include <psapi.h>
    
    int main(int argc, char *argv[])
    {
      STARTUPINFO         si;
      PROCESS_INFORMATION pi;
      char *file;
      HMODULE modules[100];
      DWORD s;
      DWORD needed;
      BOOL res;
    
      printf("sizeof ptr=%Iu\n", sizeof(void*));
    
      if (argc < 2)
        return 1;
    
      file = argv[1];
      printf("%s\n", file);
    
      ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
      ZeroMemory(&si, sizeof(STARTUPINFO));
      si.cb = sizeof(STARTUPINFO);
    
      if (!CreateProcess(NULL, file, NULL, NULL, TRUE,
                         CREATE_SUSPENDED, NULL, NULL, &si, &pi))
        {
          printf("CreateProcess failed \n");
          return 1;
        }
    
      s = 100;
      res = EnumProcessModulesEx(pi.hProcess, modules, sizeof(modules), &needed, LIST_MODULES_ALL);
      if (!res)
        {
          printf("failed %ld\n", GetLastError());
        }
    
      printf("size : %Iu %lu, %Iu\n", sizeof(modules), needed, needed / sizeof(HMODULE));
    
      return 0;
    }
    et même problème

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Mince, là je ne sais pas trop. Je n'ai jamais utilisé EnumProcessModules[Ex], lui préférant Module32First...
    Si tu remplaces LIST_MODULES_ALL par une des deux catégories, ça foire toujours? (je sais que ça n'aidera pas si tu veux tous les modules, mais ça devrait aider au moins à cerner le problème).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Mince, là je ne sais pas trop. Je n'ai jamais utilisé EnumProcessModules[Ex], lui préférant Module32First...
    tu pourrais me décrire un peu plus précisément cette méthode ?

    Si tu remplaces LIST_MODULES_ALL par une des deux catégories, ça foire toujours? (je sais que ça n'aidera pas si tu veux tous les modules, mais ça devrait aider au moins à cerner le problème).
    J'ai déjà essayé Pareil. Je ne comprends vraiment pas

  6. #6
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Citation Envoyé par d'Oursse Voir le message
    tu pourrais me décrire un peu plus précisément cette méthode ?
    Je fais un CreateToolHelp32Snapshot() avec les bons paramètres, puis j'utilise Module32First()/Module32Next().
    cela donne plein d'infos sur les modules en plus de leur HMODULE (qui sous Win32 est leur adresse de chargement dans le processus).

    Par contre, j'ignore comment ça réagit aux nouveaux trucs (64 bits, UAC, etc.), je n'ai pas vérifié depuis un moment.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Membre Expert
    Avatar de supersnail
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 719
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 719
    Par défaut
    Euh déjà, ça me paraît un peu délicat d'énumérer les modules d'un process en CREATE_SUSPENDED.

    En effet, un process créé dans ce mode n'a encore aucun module chargé (à part ntdll.dll), et son EIP pointe vers la fonction LdrInitializeThunk (qui se charge justement de parser l'IAT et de charger toutes les libs nécessaires au programme).

    Bref, EnumProcessModules* va parser directement le PEB (Process Environment Block), sauf que comme LdrInitializeThunk n'a pas encore commencé son boulot ben, la liste des modules chargés n'a pas encore été construite (et donc on peut pas la parcourir, ce qui expliquerait l'erreur ).

    Bref cette fonction est à utiliser sur un processus déjà lancé (sinon autant parser le PE et son IAT pour récupérer les modules utilisés par le programme :>)

  8. #8
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Je fais un CreateToolHelp32Snapshot() avec les bons paramètres, puis j'utilise Module32First()/Module32Next().
    cela donne plein d'infos sur les modules en plus de leur HMODULE (qui sous Win32 est leur adresse de chargement dans le processus).

    Par contre, j'ignore comment ça réagit aux nouveaux trucs (64 bits, UAC, etc.), je n'ai pas vérifié depuis un moment.
    c'est fou, le code ci-dessous donne aussi 299 comme valeur d'erreur. Je ne suis quand même pas le seul à vouloir énumérer les processus sous windows 64 bits. Il doit y avoir un truc faux évident que je ne vois pas

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    #define PSAPI_VERSION 1
    #define _WIN32_WINNT 0x0601
    #include <stdio.h>
    
    #include <windows.h>
    #include <TlHelp32.h>
    
    int main(int argc, char *argv[])
    {
      STARTUPINFO         si;
      PROCESS_INFORMATION pi;
      char *file;
      HANDLE handle;
    
      printf("sizeof ptr=%Iu\n", sizeof(void*));
    
      if (argc < 2)
        return 1;
    
      file = argv[1];
      printf("%s\n", file);
    
      ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
      ZeroMemory(&si, sizeof(STARTUPINFO));
      si.cb = sizeof(STARTUPINFO);
    
      if (!CreateProcess(NULL, file, NULL, NULL, TRUE,
                         CREATE_SUSPENDED, NULL, NULL, &si, &pi))
        {
          printf("CreateProcess failed \n");
          return 1;
        }
    
      handle = CreateToolhelp32Snapshot(TH32CS_SNAPALL, pi.dwProcessId);
      if (handle == INVALID_HANDLE_VALUE)
        {
          printf("failed %ld\n", GetLastError());
        }
    
      return 0;
    }

  9. #9
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Février 2013
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Février 2013
    Messages : 33
    Par défaut
    Bonsoir,
    Un petit point de la doc ( http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx )

    REMARKS
    ...
    To enumerate the heap or module states for all processes, specify TH32CS_SNAPALL and set th32ProcessID to zero. Then, for each additional process in the snapshot, call CreateToolhelp32Snapshot again, specifying its process identifier and the TH32CS_SNAPHEAPLIST or TH32_SNAPMODULE value.
    en mettant le th32ProcessID à zéro l'erreur disparait... (pas testé le reste par contre)

  10. #10
    Membre Expert
    Avatar de supersnail
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 719
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 719
    Par défaut
    Comme j'ai expliqué plus haut, lorsque un process est créé en suspended, sa liste de modules n'a pas encore été initialisée. Du coup les fonctions qui veulent essayer de parcourir une liste qui n'existe pas échouent lamentablement

  11. #11
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    Citation Envoyé par devbreizhbugs Voir le message
    Bonsoir,
    Un petit point de la doc ( http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx )


    en mettant le th32ProcessID à zéro l'erreur disparait... (pas testé le reste par contre)
    En effet, mais c'est un cas que j'aimerais éviter si possible.

    La doc dit clairement que c'est possible de prendre le snapshot d'un processus spécifique. Donc ça devrait marcher en passant la valeur de l'identifiant du processus. Est-ce que je passe la bonne valeur ? (i.e. pi.dwProcessId est ce que je devrais passer)

    Ensuite, la doc dit que 299 est retourné quand le processus (celui crée par CreateProcess et dont je passe l'identifiant) est 64 bits, tandis que l'appelant (mon programme) est 32 bits. Mais mon programme est bien 64 bits.

    Donc je suis perdu

  12. #12
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    Citation Envoyé par supersnail Voir le message
    Euh déjà, ça me paraît un peu délicat d'énumérer les modules d'un process en CREATE_SUSPENDED.

    En effet, un process créé dans ce mode n'a encore aucun module chargé (à part ntdll.dll), et son EIP pointe vers la fonction LdrInitializeThunk (qui se charge justement de parser l'IAT et de charger toutes les libs nécessaires au programme).

    Bref, EnumProcessModules* va parser directement le PEB (Process Environment Block), sauf que comme LdrInitializeThunk n'a pas encore commencé son boulot ben, la liste des modules chargés n'a pas encore été construite (et donc on peut pas la parcourir, ce qui expliquerait l'erreur ).

    Bref cette fonction est à utiliser sur un processus déjà lancé (sinon autant parser le PE et son IAT pour récupérer les modules utilisés par le programme :>)
    Je vais essayer de le faire après. Sinon, parser le PE est une option

    merci

  13. #13
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    Citation Envoyé par supersnail Voir le message
    Comme j'ai expliqué plus haut, lorsque un process est créé en suspended, sa liste de modules n'a pas encore été initialisée. Du coup les fonctions qui veulent essayer de parcourir une liste qui n'existe pas échouent lamentablement
    Ok, j'ai mis 0. Voici le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #define PSAPI_VERSION 1
    #define _WIN32_WINNT 0x0601
    #include <stdio.h>
    
    #include <windows.h>
    #include <psapi.h>
    
    int main(int argc, char *argv[])
    {
      STARTUPINFO         si;
      PROCESS_INFORMATION pi;
      char *file;
      HMODULE modules[100];
      DWORD s;
      DWORD needed;
      BOOL res;
    
      printf("sizeof ptr=%Iu\n", sizeof(void*));
    
      if (argc < 2)
        return 1;
    
      file = argv[1];
      printf("%s\n", file);
    
      ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
      ZeroMemory(&si, sizeof(STARTUPINFO));
      si.cb = sizeof(STARTUPINFO);
    
      if (!CreateProcess(NULL, file, NULL, NULL, TRUE,
                         0, NULL, NULL, &si, &pi))
        {
          printf("CreateProcess failed \n");
          return 1;
        }
    
      s = 100;
      res = EnumProcessModulesEx(pi.hProcess, modules, sizeof(modules), &needed, LIST_MODULES_ALL);
      if (!res)
        {
          printf("failed %ld\n", GetLastError());
        }
    
      printf("size : %Iu %lu, %Iu\n", sizeof(modules), needed, needed / sizeof(HMODULE));
    
      return 0;
    }
    même problème.

  14. #14
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Février 2013
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Février 2013
    Messages : 33
    Par défaut
    Citation Envoyé par d'Oursse Voir le message
    En effet, mais c'est un cas que j'aimerais éviter si possible.

    La doc dit clairement que c'est possible de prendre le snapshot d'un processus spécifique. Donc ça devrait marcher en passant la valeur de l'identifiant du processus. Est-ce que je passe la bonne valeur ? (i.e. pi.dwProcessId est ce que je devrais passer)
    En fait ce que je voulais souligner, c'est que la doc se contredit:
    la doc de TH32CS_SNAPALL dit qu'on peut prendre un snapshot de tout le system+d'un processus en particulier
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CreateToolhelp32Snapshot(TH32CS_SNAPALL, pi.dwProcessId);
    , alors que la section remarque dit qu'il faut faire un snapshot de tout le system et dans un deuxième appel, snapshooter un processus particulier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
    ...
    CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST|TH32CS_SNAPMODULE, pi.dwProcessId);
    //(et peut être un troisième appel avec CreateToolhelp32Snapshot(TH32CS_SNAPMODULE32, pi.dwProcessId); ?)
    edit:
    sinon, si tu mettais un sleep(10000) entre ton createprocess et ton CreateToolhelp32Snapshot/EnumProcessModulesEx laisser le temps au processus de se charger correctement? (surtout si le process en question mets du temps à se charger!)

  15. #15
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    Citation Envoyé par devbreizhbugs Voir le message
    En fait ce que je voulais souligner, c'est que la doc se contredit:
    la doc de TH32CS_SNAPALL dit qu'on peut prendre un snapshot de tout le system+d'un processus en particulier
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CreateToolhelp32Snapshot(TH32CS_SNAPALL, pi.dwProcessId);
    , alors que la section remarque dit qu'il faut faire un snapshot de tout le system et dans un deuxième appel, snapshooter un processus particulier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
    ...
    CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST|TH32CS_SNAPMODULE, pi.dwProcessId);
    //(et peut être un troisième appel avec CreateToolhelp32Snapshot(TH32CS_SNAPMODULE32, pi.dwProcessId); ?)
    je viens de tester, le 2ème appel foire...

    edit:
    sinon, si tu mettais un sleep(10000) entre ton createprocess et ton CreateToolhelp32Snapshot/EnumProcessModulesEx laisser le temps au processus de se charger correctement? (surtout si le process en question mets du temps à se charger!)
    ca ne marche toujours pas avec cette méthode

  16. #16
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    Bonjour

    après avoir abandonné un peu le projet, je le reprends.

    Mon but initial était de faire un détecteur de fuite mémoire, en injectant une DLL (inject.dll) dans un programme (par exemple toto.exe, qui peut dépendre d'autres DLL, par exemple tata.dll). Donc je crée un process en mode suspendu. Et il faut que j'injecte inject.dll dans toto.exe et tata.dll pour obtenir toutes les fuites de mémoire. J'y arrive pour toto.exe, ça marche très bien. Mais, comme je l'ai lu dans beaucoup de lien sur le net, et aussi dans un message de cette discussion, tata.dll n'est pas encore chargé quand toto.exe est en mode suspendu.

    J'ai trouvé un lien qui ne marche qu'en 32 bits, qui décrit une méthode permettant de faire ceci : dans l'entry point de toto.exe, on insère une boucle infinie, et j'attends que tout se charge correctement (ça utilise la structure CONTEXT (membre Eip) et GetThreadContext). Je n'ai pas encore testé cette méthode

    Je voulais savoir s'il y avait une méthode en 64 bits (ou une qui marche pour les 2 en même temps, ça serait mieux) pour attendre juste ce qu'il faut pour charger les DLL, pour que j'injecte inject.dll dans chacune des DLL dont dépend toto.exe ?

    merci

  17. #17
    Membre Expert
    Avatar de supersnail
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 719
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 719
    Par défaut
    Sinon, je suppose que tu détectes les fuites mémoire en plaçant des hooks sur les fonctions comme malloc/HeapAlloc et autres...

    Si c'est le cas, pourquoi pas tout simplement patcher l'EAT (Export Address Table) des fonctions t'intéressant dans kernel32 (qui lui est normalement chargé, au moins par ta DLL ), qui sera propagée par l'initialisation faite par ntdll

    Ou sinon une autre méthode (qui est elle aussi basée sur la création d'un processus en mode suspendu, et par certains points similaire à des techniques utilisées par certains packers mal conçus communément appelés "RunPE" ).
    Lorsqu'un processus est créé en mode suspended, EIP pointe vers l'adresse de LdrInitializeThunk dans ntdll.dll, mais le registre EAX contient l'adresse de l'entry point de l'exécutable (ntdll va donc faire un "call eax" ou un machin du genre lorsqu'il aura fini d'initialiser toutes les dll chargées par le programme). L'idée va donc de modifier EAX (via un SetThreadContext) pour qu'il pointe vers une zone mémoire allouée précédemment qui chargera la dll qui servira à tracer les fuites mémoire avant de repasser la main à l'entrypoint du programme.
    La procédure est normalement similaire en 64bits (n'ayant pas de windows 64bits sous la main je ne suis pas en mesure de tester hélas), il faudra juste veiller à utiliser RAX et RIP au lieu de leurs équivalent EAX et EIP.

  18. #18
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    Citation Envoyé par supersnail Voir le message
    Sinon, je suppose que tu détectes les fuites mémoire en plaçant des hooks sur les fonctions comme malloc/HeapAlloc et autres...
    oui, et je compte aussi detecter les appels GDI

    Si c'est le cas, pourquoi pas tout simplement patcher l'EAT (Export Address Table) des fonctions t'intéressant dans kernel32 (qui lui est normalement chargé, au moins par ta DLL ), qui sera propagée par l'initialisation faite par ntdll
    et bien, comme je veux aussi les objets GDI, il me semble que c'est insuffisant, vu qu'il faut aussi que gdi32.dll soit chargée. De plus, je veux aussi une trace des appels, donc il faut que toutes les dépendances de mon processus fils soient chargées.

    Ou sinon une autre méthode (qui est elle aussi basée sur la création d'un processus en mode suspendu, et par certains points similaire à des techniques utilisées par certains packers mal conçus communément appelés "RunPE" ).
    Lorsqu'un processus est créé en mode suspended, EIP pointe vers l'adresse de LdrInitializeThunk dans ntdll.dll, mais le registre EAX contient l'adresse de l'entry point de l'exécutable (ntdll va donc faire un "call eax" ou un machin du genre lorsqu'il aura fini d'initialiser toutes les dll chargées par le programme). L'idée va donc de modifier EAX (via un SetThreadContext) pour qu'il pointe vers une zone mémoire allouée précédemment qui chargera la dll qui servira à tracer les fuites mémoire avant de repasser la main à l'entrypoint du programme.
    La procédure est normalement similaire en 64bits (n'ayant pas de windows 64bits sous la main je ne suis pas en mesure de tester hélas), il faudra juste veiller à utiliser RAX et RIP au lieu de leurs équivalent EAX et EIP.
    je vais essayer de poster ce soir mon code pour la boucle infinie au niveau de l'entry point, qui semble marcher, mais il y a un nouveau problème :-)

  19. #19
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    voilà le code pour le patch, avec :

    exm->child.process2 : le processus fils crée avec CreateProcess
    exm->child.entry_point : l'entry point récupéré en parsant le fichier PE

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    static int
    exm_entry_point_patch(Exm *exm)
    {
        CONTEXT          context;
        unsigned char    nep[2];
    
        if (!VirtualProtectEx(exm->child.process2, exm->child.entry_point,
                              2, PAGE_EXECUTE_READWRITE, &exm->child.old_protect))
        {
            EXM_LOG_ERR("can not protect page 0x%p in process handle 0x%p failed",
                        exm->child.entry_point,
                        exm->child.process2);
            return 0;
        }
    
        if (!ReadProcessMemory(exm->child.process2, exm->child.entry_point,
                               exm->child.oep, 2, NULL))
        {
            EXM_LOG_ERR("read memory 0x%p of process handle 0x%p failed",
                        exm->child.entry_point,
                        exm->child.process2);
            return 0;
        }
    
        /* patch with an infinite loop : JMP -2 */
        nep[0] = 0xEB;
        nep[1] = 0xFE;
    
        EXM_LOG_DBG("patching process 0x%p at entry point 0x%p",
    		exm->child.process2,
    		exm->child.entry_point);
        if (!WriteProcessMemory(exm->child.process2, exm->child.entry_point,
                                nep, 2, NULL))
        {
            EXM_LOG_ERR("write memory 0x%p of process handle 0x%p failed",
                        exm->child.entry_point,
                        exm->child.process2);
            return 0;
        }
    
        ResumeThread(exm->child.thread);
    
        while (1)
        {
            Sleep(100);
            context.ContextFlags = CONTEXT_CONTROL;
            if (!GetThreadContext(exm->child.thread, &context))
            {
                EXM_LOG_ERR("can not retrieve the context of thread 0x%p, unpatch entry point",
                            exm->child.thread);
    
                SuspendThread(exm->child.thread);
    
                if (!exm_entry_point_unpatch(exm))
                {
                    EXM_LOG_ERR("can not unpatch entry point");
                }
    
                ResumeThread(exm->child.thread);
    
                return 0;
            }
    
    #if defined (_AMD64_)
            if ((uintptr_t)context.Rip == (uintptr_t)exm->child.entry_point)
                break;
    #elif defined (_X86_)
            if ((uintptr_t)context.Eip == (uintptr_t)exm->child.entry_point)
                break;
    #else
    # error "system not supported"
    #endif
        }
    
        /* SetThreadContext(exm->child.thread, &context); */
    
        return 1;
    }
    
    static int
    exm_entry_point_unpatch(Exm *exm)
    {
        DWORD new_protect;
    
        if (!WriteProcessMemory(exm->child.process2, exm->child.entry_point,
                                exm->child.oep, 2, NULL))
        {
            EXM_LOG_ERR("write memory 0x%p of process handle 0x%p failed",
                        exm->child.entry_point,
                        exm->child.process2);
            return 0;
        }
    
        if (!VirtualProtectEx(exm->child.process2, exm->child.entry_point,
                              2, exm->child.old_protect, &new_protect))
        {
            EXM_LOG_ERR("can not protect page 0x%p in process handle 0x%p failed",
                        exm->child.entry_point, exm->child.process2);
            return 0;
        }
    
        return 1;
    }
    Si je n'utilise pas ce code : j'injecte la DLL et je trace les appels à malloc(), etc..., mais je n'ai pas accès aux DLL dont dépend le processus car elles ne sont pas encore chargée

    Si j'utilise ce code, j'ai accès à ces DLL, mais l'injection échoue, ou plutôt, il n'y a pas de message d'erreur, mais les appels à malloc() ne sont plus tracés. Donc je suppose que l'injection n'est pas faite correctement

    je suis ouvert à toute solution faisant marcher ce code

    Code sans le patch : https://github.com/vtorri/examine (dans src/bin/examine_memcheck.c et voir src/lib/examine_pe.c pour le parsing du fichier PE, le code peut être amélioré, je le sais )

  20. #20
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    j'ai mis à jour le code sur github. Le code avec le patch est là.

    il est désactivé pour l'instant (ligne 46 de src/bin/examine_memcheck.c, la macro PATCH)
    pour l'activer, la mettre à 1

    là, je suis un peu désespéré. Je fait une quantité de recherche énorme sur google, mais aucune info précise ou code ne fait ce que je veux faire. C'est systématiquement des info sur une injection de DLL dans un process, mais jamais dans le process et ses process fils. Ou bien des info vagues sur ce qu'il faut faire, sans exemple concret.

    merci

Discussions similaires

  1. debutant: erreur LNK2001 avec la librairie GSL
    Par drill3 dans le forum MFC
    Réponses: 6
    Dernier message: 25/04/2005, 13h58
  2. Erreur EACCESSVIOLATION avec des compsts créés dynamiquement
    Par tsikpemoise dans le forum Bases de données
    Réponses: 4
    Dernier message: 28/02/2004, 19h05
  3. Erreur fréquente avec ASP et IIS
    Par Community Management dans le forum ASP
    Réponses: 2
    Dernier message: 11/02/2004, 22h20
  4. Erreurs IIS avec Multiples Frames avec xmlrad
    Par powerlog dans le forum XMLRAD
    Réponses: 4
    Dernier message: 01/07/2003, 13h15
  5. Comparaison d'un registre 8 bits avec une variable 32 bits
    Par tupperware dans le forum x86 32-bits / 64-bits
    Réponses: 3
    Dernier message: 15/10/2002, 10h25

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo