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

Delphi Discussion :

Remplacer une API par son propre code dans un processus (injection de code)


Sujet :

Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 59
    Par défaut Remplacer une API par son propre code dans un processus (injection de code)
    Bonjour,
    Voila mon problème, j'ai un exe (dont j'ai pas le source) qui effectue une conversion entre 2 formats de fichiers. Cet exe demande obligatoirement par le biais d'une boite de dialogue le nom et l'endroit ou doit se situer le fichier de destination.
    Mon but est de remplacer l'appel a GetSaveFileNameW par mon propre code qui retournerait le chemin du fichier de destination autrement que par une boite de dialgoue.

    Apres pas mal de recherche, j'ai bien la technique d'injection de dll par le biais de "CreateRemoteThread" mais arrivé la je trouve pas d'exemple me permettant de comprendre comment le code de ma dll se substitue au code de l'exe.

    J'ai regardé par le biais de "SetWindowsHookEx" mais d'apres ce que j'en ai vu ca permet uniquement d'intercepter les appels pas de substituer les paramètres de retour.

    Si quelqu'un a un exemple ou une idée suis preneur.

    Merci

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 081
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 081
    Par défaut
    Injection de Code ? oh ? c'est possible ça via les API Windows ? j'aurais cru que par ASM ...

    Tu peux aussi capturer le handle de la fenêtre, et via un SendMessage + WM_SETTEXT, envoyé le chemin, puis simuler le click sur le bouton

    tient ça donne globalement ceci

    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
    procedure TFrmTestStructureMemoire.TimerAutoSetPrintFileName(Sender: TObject);
    var
      HwndEdit, HwndButton: HWND;
      lpClassName: PChar;	// pointer to class name
      lpWindowName: PChar; 	// pointer to window name
      lpString: PChar;       // address of string
      HwndParent: HWND;
      HwndChildAfter: HWND;	// handle to a child window
      lpszClass: PChar;	    // pointer to class name
      lpszWindow: PChar;	    // pointer to window name
      lpRes : array[0..256] of Char;
      TmpStr : String;
    begin
          lpClassName:= nil; //'#32770';	                // pointer to class name
          lpWindowName:= 'Imprimer dans un Fichier'; 	// pointer to window name
          {Récupère le handle de la boite de dialogue Ouvrir}
          HwndParent := FindWindow(lpClassName, lpWindowName);
     
          if HwndParent <> 0 then begin
             if GetWindowText( HwndParent, lpRes, 256) > 0 then begin
                FichierLog('ShowMessage','Parent GetWindowText',lpRes);
             end;
     
             { Mettre la fenêtre au premier plan en connaissant son handle }
             BringWindowToTop(HwndParent);
     
             HwndChildAfter := GetWindow(HwndParent, GW_CHILD);
             if HwndChildAfter <> 0 then begin
     
                lpszClass := 'Edit';
                lpszWindow := nil;
                HwndEdit  := FindWindowEx(HwndParent, HwndChildAfter, lpszClass, lpszWindow);
                if HwndEdit <> 0 then begin
                   if GetWindowText( HwndEdit, lpRes, 256) > 0 then begin
                      FichierLog('ShowMessage','Old Edit GetWindowText', lpRes);
                   end;
                   TmpStr := '.\PrintFile' + IntToStr(Timer1.Tag) + '.txt';
                   if DeleteFile(TmpStr) then begin
                      FichierLog('ShowMessage','DeleteFile', TmpStr);
                   end;
                   lpString := PChar(TmpStr);
                   // lpString := nil;
                   // if not SetWindowText(HwndEdit, lpString) then begin
                   //    FichierLog('ShowMessage','SetWindowText', IntToStr(GetLastError()));
                   // end else begin
                       SendMessage(HwndEdit, WM_SETTEXT, 0, Longint(lpString));
                       SendMessage(HwndEdit, CM_TEXTCHANGED, 0, 0);
                       if GetWindowText( HwndEdit, lpRes, 256) > 0 then begin
                          FichierLog('ShowMessage','New Edit GetWindowText', lpRes);
                       end;
                   //end;
                end else begin
                    FichierLog('ShowMessage','FindWindowEx', IntToStr(GetLastError()));
                end;
     
                lpszClass := 'Button';
                lpszWindow := 'OK';
                HwndButton  := FindWindowEx(HwndParent, HwndChildAfter, lpszClass, lpszWindow);
                if HwndButton <> 0 then begin
                   // SendMessage(HwndButton, BM_CLICK, 0, 0);
                   SendMessage(HwndButton, WM_LBUTTONDOWN, 0, 0);
                   SendMessage(HwndButton, WM_LBUTTONUP, 0, 0);
                end else begin
                    FichierLog('ShowMessage','FindWindowEx', IntToStr(GetLastError()));
                end;
     
     
             end else begin
                 FichierLog('ShowMessage','GetWindow', IntToStr(GetLastError()));
             end;
          end else begin
              FichierLog('ShowMessage','FindWindow', IntToStr(GetLastError()));
          end;
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    160
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 160
    Par défaut
    Ben en fait si j'ai bien comprit ta question, l'injection de code ou le hook ne sont pas ce que tu cherches a faire, tu veux remplacer un GetSaveFileNameW dans un .exe par ta propre implementation de la fonction.

    Ca s'appelle du patching a l'execution et c'est une technique assez avancée de hacking.

    Et puis c'est un peu faire violence au fonctionnement normal de ton systeme.

    Je trouve que ce forum prend une drole d'alure

    Bon je n'ai pas le temps maintenant mais je ferais un petit topo là dessus dans la soiree.

    Cela dit je ne suis pas le meilleur specialiste du domaine.

    Edit vite fait en passant, faire ca sous delphi, je ne vois pas comment faire, la technique a laquelle je pense tourne en ring0.

    Prevoir C et assembleur et telechargement du DDK...

  4. #4
    Expert confirmé Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Par défaut
    Eventuellement, en faisant comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    keybd_event(VK_CONTROL,0,0,0); //touche ctrl enfoncée
    keybd_event(86,0,0,0); //touche v enfoncée
    keybd_event(86,0,KEYEVENTF_KEYUP,0); //touche v enfoncée
    keybd_event(VK_CONTROL,0,KEYEVENTF_KEYUP,0); //touche ctrl relevée
    voici la liste des touches Virtual Key:
    8 ou VK_BACK : Retour
    9 ou VK_TAB :TAB
    13 ou VK_RETURN : Entrer
    16 ou VK_SHIFT : Shifts
    17 ou VK_CONTROL : Controles
    18 ou VK_MENU : touches menu
    19 ou VK_PAUSE : Pause
    20 ou VK_CAPITAL : Majuscule
    27 ou VK_ESCAPE : Echape
    32 ou VK_SPACE : Espace
    33 ou VK_PRIOR : Page haut
    34 ou VK_NEXT : Page bas
    35 ou VK_END : Fin
    36 ou VK_HOME : touche début
    37 ou VK_LEFT : Flêche gauche
    38 ou VK_UP : Flêche haut
    39 ou VK_RIGHT : Flêche droite
    40 ou VK_DOWN : Flêche bas
    41 ou VK_SELECT : Arret defil
    42 ou VK_PRINT : Impr écran
    45 ou VK_INSERT : Insert
    46 ou VK_DELETE : Suppr
    48 : 0
    ...
    57 : 9
    65 : A
    ...
    90 : Z
    91 ou VK_LWIN : touche windows gauche
    92 ou VK_RWIN : touche windows droite
    96 ou VK_NUMPAD0 : 0 (clavier numérique)
    ...
    105 ou VK_NUMPAD9 : 9 (clavier numérique)
    106 ou VK_MULTIPLY : Multiplier
    107 ou VK_ADD : Ajouter
    108 ou VK_SEPARATOR : séparateur???
    109 ou VK_SUBTRACT : Soustraire
    110 ou VK_DECIMAL : point
    111 ou VK_DIVIDE : diviser
    112 ou VK_F1 : F1
    ...
    123 ou VK_F1 : F12
    144 ou VK_NUMLOCK : Verr Num
    145 ou VK_SCROLL : Arret défil
    160 ou VK_LSHIFT : Shift gauche
    161 ou VK_RSHIFT : Shift droit
    162 ou VK_LCONTROL : Controle gauche
    163 ou VK_RCONTROL : Controle droit
    162 ou VK_LMENU : Touche menu gauche
    165 ou VK_RMENU : Touche menu droit

    précision : y'a pas toutes les touche dans cette liste

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    160
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 160
    Par défaut
    je ne suis pas sur que ce soit "rellement" ce que cherche a faire monmien. Si tel est le cas, parfait c'est une bonne piste qui devrait marcher.

    Si son intention est autre, la solution est beaucoup plus compliquée.

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    160
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 160
    Par défaut patching de detour un defi pas si evident.
    La technique a laquelle je faisais référence, s'appelle patching de detour, et ce n'est pas un tutorial sur comment faire, car je ne maitrise pas suffisement le sujet.

    Plutot une explication général et un inventaire des difficultés a surmonter.
    Bien sur, le hook d'appel fonction en userland est plus simple a mettre en oeuvre pour peu que le contexte l'autorise.

    Le patching de détour sert exactement a faire ce qui est proposé par "monmien" c'est a dire a contourner et a remplacer une fonctionnalité,donc une fonction

    Je vais essayer de faire un petit schema vite fait
    Nom : patch.JPG
Affichages : 246
Taille : 15,0 Ko

    Tres grossierement ca donne ca sur un programme comprtant trois fonctions (qui peuvent etre aussi complexes qu'on veut)

    sur la deuxieme moitié on du schema on voit ce qu'on veut realise.

    Comme ca ca a l'air simple non?

    Seulement voilà, probleme numero 1: comment localiser la fonction dans un .exe qui tourne?

    et bien en fait, il faut connaitre a quoi ressemble la fonction une fois assemblée (c'est a dire en hexadecimal), reperer une sequence d'octet (une sorte de magic number) et chercher en memoire ou elle se trouve.

    Rien que ca... Bon courrage...

    Bon ensuite on obtient donc un pointeur sur la fonction. On fait quoi? On change quelques instructions ou toute la fonction?

    Bref determiner l'action a faire maintenant est le probleme numero 2)

    Ce qui nous menne directement au probleme numero 3)
    Comment techniquement detourner le flux, ce qui vient tout de suite en memoire c'est un JMP FAR vers notre "verrue" seulement voilà, notre JMP FAR tient en 7 octets!

    Et on risque de mechament flinguer la logique du programme... Et oui , ce serait si beau si chaque instruction était de la meme taille et tenait sur un octet. Mais non... C'est pas comme ca.

    probleme numero 4) Coder notre verrue et faire un nouveau JMP FAR pour revenir exactement au bon endroit, et bien sur rester coherente avec ce qu'attend la logique qui va suivre pour ne pas tout planter...

    Sans compter que là on parle d'aller trifouiller et patcher un executable qui tourne (donc pas en debug) et qui donc est sous la haute bienveillance de l'OS et du proco qui protegent son espace memoire.

    Seul un driver à l'autorisation de ce genre de chose.

    Donc probleme numero 5)
    Maitriser parfaitement l'assembleur, et l'ecriture de drivers, et le ring0 c'est pas de la tarte... Le plantage c'est l'ecran bleu assuré.

    Je tiens a preciser que les exemples fournis avec le DDK de chez microsoft ne traitent pas de cela, et qu'il serait etonnant de trouver du support.

    Ce n'est pas un jeu d'enfant.

    Mais ca, ca fonctionne dans tous les cas et ca permet de faire ce qu'on veut, sans ce soucier de la moindre protection.

    Pour en revenir au petit croquis, on peut aussi patcher a l'interieur de F2 , c'est a dire garder intacte une partie de la fonction...

    Voila je ne saurais pas etre plus technique, vu que je n'aborde ce sujet que depuis quelques jours.

  7. #7
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    j'ai bien une idée, qui devrait être réalisable (à vu de nez) mais je ne l'ai jamais vue en pratique.

    l'executation possède une table de liaison qui indiquer pour une série de DLL, les fonctions dont il a besoin...il devrait être possible de réécrire cette table de liaison en faisant pointer la fonction sur une autre DLL...que tu pourrais écrire ... ou plus simple encore, modifier dans l'entête EXE le nom de la DLL

    ceci dit, ça nécessite donc de modifier l'executable ce qui n'est souvent pas possible aux yeux de la loi.

    reste une technique qui fonctionne bien, c'est de placer dans le répertoire de l'application une DLL qui vient remplacer la version standard Windows. COMDLG32.DLL dans le cas qui nous intéresse.

    Avec Dependency Walker, il est facile de voir toutes les fonctions utilisées dans la DLL...seules celle-ci doivent être reprisent.

    Le plus fun c'est que la DLL de remplacement peut très bien faire appel à l'originale
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    function _GetSaveFileNameW(...):BOOL; stdcall external 'C:\WINNT\SYSTEM32\COMDLG32.DLL' name 'GetSaveFileNameW';
     
    function GetSaveFileNameW(...):BOOL; stdcall;
    begin
     Result:=_GetSaveFileNameW(...);
    end;
     
    exports
     GetSaveFileNameW;
    attention tout de même au chemin qui change d'une version de Windows à l'autre, un chargement dynamique peut s'avérer nécessaire.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

Discussions similaires

  1. Réponses: 3
    Dernier message: 11/12/2010, 14h18
  2. Réponses: 8
    Dernier message: 19/07/2010, 15h50
  3. Réponses: 2
    Dernier message: 21/09/2008, 17h21
  4. Remplacer une colonne par ses numéros correspondants dans une liste
    Par freestyler dans le forum Shell et commandes GNU
    Réponses: 27
    Dernier message: 12/06/2008, 15h42
  5. Application d'une matrice OPENGL par son propre code
    Par fanoplusplus64k dans le forum OpenGL
    Réponses: 4
    Dernier message: 03/10/2006, 23h36

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