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

API, COM et SDKs Delphi Discussion :

Comment surcharger (hook) n'importe quelle API windows ? [Sources]


Sujet :

API, COM et SDKs Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Juin 2004
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 18
    Par défaut Comment surcharger (hook) n'importe quelle API windows ?
    Pour faciliter la recherche des utilisateurs du forum je copie colle une partie d'un post en rennomant le sujet.

    Le poste original était : Surveiller la base de registre.

    De fils en aiguille j'ai découvert un principe très interessant voià un résumé de cette recherche


    Voila je vais donc essayer de vous faire une petit topo sur cette méthode. Ce topo ne sera pas complet je compte sur vos compétences pour me reprendre sur quelque points ou pour apporter des précisions à mon propos.

    1) Point de départ :
    Je cherchais donc comment faire un hook sur la base de registre.

    a - première solution imcomplète : RegNotifyChangeKeyValue.
    Cette solution est expliquée ici : http://delphi.about.com/od/kbwinshell/l/aa052003a.htm

    Le gros défaut de cette solution est qu'elle ne renvoie pas la clé qui a subit une modification. Elle notifie seulement un changement.

    b - deuxième solution envisagée : le principe qu'utilise regmon. Là j'ai été un peu perturbé car le procédé utilise des fonctions non documentées de xp et que tout cela me paraissait un peu trop pointu. Pour info je vous donne différent liens dont j'ai cru comprendre qu'ils traitaient plus ou moins du sujet.

    http://www.eviloctal.com/forum/htm_d...603/20388.html

    et le site de regmon

    http://www.sysinternals.com/Utilities/Regmon.html (voir l'explication : "How Regmon Works")

    Peut-être aussi un référence bibliogrpahique :

    http://www.amazon.com/gp/product/020...lance&n=283155

    c - La solution utilisant le principe de Mathias Rauen (je décrirai plus bas cette méthode)

    En gros cette méthode permet de hooker n'importe quelle fonction API de windows. Pour le moment j'ai juste fait un hook sur RegOpenKey cela reste donc incomplet, mais le principe est vraiment très prometteur.

    2) Description du principe de Mathias Rauen

    Alors là je vais tenter une explication, mais je me reserve le droit d'être approximatif

    Les API windows sont donc chargées par le système et les programmes à partir des dll natives de windows. Par exemple on sait que TerminateProcess se trouve dans kernel32.dll. Quand un programme ou un utilisateur demande au systeme de terminer un process celui ci fait appel a cette fonction. Imaginons maintenant qu'il soit possible de surcharger cette fonction. C'est à dire d'executer un bout de code personnel au moment de son appel. On pourrait donc par exemple refuser qu'un processus donné soit terminé sans autorisation.

    Ceci est possible grâce au procédé développé par Mathias Rauen. Ce principe permet donc d'injecter la fonction surchargée d'une fonction originale (API) en lieu et place de celle-ci dans le système (system wide). D'ailleurs si quelqu'un veut bien m'expliquer ce que recouvre exactement ce terme (system wide) utilisé pas Mathias je suis preneur.

    L'ecriture de la fonction surchargée doit se faire dans une dl qui elle sera injecté dans le système.

    Pour développé un projet permettant cette injection il faut télécharger la collection de composants ici : http://madshi.net/madCollection.exe. Le composant qui nous interesse plus particulièrement est nommé madCodeHook.

    L'install registre une dcu "madCodeHook.dcu" et fournit une dll madCHook.dll nécessaire à l'injection.

    Pour résumé :

    on crée un dll contenant la fonction API surchargée. Cette dll est injectée dans le system à l'aide des fonctions contenues dans "madCodeHook.dcu" et de la dll "madCHook.dll". A mon avis c'est la dcu qui fait appel à "madCodeHook.dcu" .

    3) Passons à la pratique

    a - D'abord l'exemple de de l'auteur : http://help.madshi.net/HowToUseMadCodeHook.htm
    Cet exemple nous montre comment hooker l'API TerminanteProcess en autorisant ou non l'arrêt d'un processus donné.

    b - Maintenant mon exemple :
    Je vais en suivant Mathias hooker la fonction RegOpenKey qui est dans advapi32.dll.

    Ecriture de la dll surchargeant RegOpenKey :


    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
    library HookRegOpenKey;
    uses dialogs,classes,Sysutils, Windows, madRemote, madCodeHook, madStrings;
     
    // variable représentant l'api originale "function RegOpenKey(hKey: HKEY; lpSubKey: PChar; var phkResult: HKEY): Longint; stdcall;"
     
    var RegOpenKeyNext : function (HandleKey: Dword; lpSubKey: PChar; var phkResult: Dword): Longint; stdcall;
     
    // Fonction surchargée
     
    function RegOpenKeyCallback(HandleKey: Dword; lpSubKey: PChar; var phkResult: Dword) : Longint; stdcall;
    Var
    Str : TStringList;
    RootKey : string;
    begin
        // On renvoie la fonction originale pour que la demande soit bien prise en compte
        result := RegOpenKeyNext(HandleKey, lpSubKey,phkResult);
        // surcharge par mon code perso j'ouvre un fichier log ou seront enregistrer les infos
        Str:=TStringList.Create;
        If fileExists('c:\regkey.txt') Then Str.LoadFromFile('c:\regkey.txt');
        Case HandleKey Of
          HKEY_CLASSES_ROOT : RootKey := 'HKEY_CLASSES_ROOT\';
          HKEY_CURRENT_USER : RootKey := 'HKEY_CURRENT_USER\';
          HKEY_LOCAL_MACHINE : RootKey := 'HKEY_LOCAL_MACHINE\';
          HKEY_USERS : RootKey := 'HKEY_USERS\';
          HKEY_CURRENT_CONFIG : RootKey := 'HKEY_CURRENT_CONFIG\';
        End;
        Str.Add('-----------------');
        Str.Add(DateTimeToStr(Now) + ' : RegOpenKey called');
        Str.Add(RootKey + lpSubKey);
        Str.Add('-----------------');
        Str.SaveToFile('c:\regkey.txt');
        Str.Free;
    end;
    begin
    // HookAPI provient de madCodeHook.dcu et permet de subsituer la fonction surchargée à l'API originale.  
    HookAPI('advapi32.dll', 'RegOpenKeyA', @RegOpenKeyCallback, @RegOpenKeyNext);
    end.
    Remarque importante : La fonction surchargée doit impérativement respecter les conventions d'écriture (paramètres et variables) de l'originale.

    Maintenant l'ecriture du projet permettant l'injection :

    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
    unit InjectUnit;
    interface
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, madCodeHook,
      StdCtrls;
    type
      TForm1 = class(TForm)
        ButtonHook: TButton;
        ButtonUnHook: TButton;
        procedure ButtonHookClick(Sender: TObject);
        procedure ButtonUnHookClick(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
    var
      Form1: TForm1;
    implementation
    {$R *.DFM}
    procedure TForm1.ButtonHookClick(Sender: TObject);
    begin
      InjectLibrary(ALL_SESSIONS or SYSTEM_PROCESSES, 'HookRegOpenKey.dll');
    end;
    procedure TForm1.ButtonUnHookClick(Sender: TObject);
    begin
    UninjectLibrary(ALL_SESSIONS or SYSTEM_PROCESSES, 'HookRegOpenKey.dll');
    end;
    end.
    Voila il suffit d'utiliser InjectLibrary pour Hooker et UninjectLibrary pour UnHooker.

    PS : scusez pour les fautes d'orthographe je fait des efforts mais c'est souvent en vain.

    Quand j'aurai monté le projet global je vous le ferai parvenir. Car il me reste un autre point a résoudre : connaitre le processus qui vient d'accéder à la base de registre. Il faut aussi que je surcharge les appels aux fonctions d'écriture dans la base.

    Raziel

  2. #2
    Membre éclairé

    Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2003
    Messages
    286
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2003
    Messages : 286
    Par défaut
    mhhhh ... intéressant
    sympa de partager tes recherches, les librairies de Mathias Rauen m'ont l'air assez impressionnantes ...

  3. #3
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 489
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 489
    Par défaut
    salut


    le principe est assez simple microsoft met a notre disposition une api permettant d'injecter du code

    -pour info les virus utilise souvent cettte posibilite
    faite une recherche su et et voila une utilisation possible
    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
    105
     
     
    uses tlhelp32;
     
    procedure GetMyProcessID(const AFilename: string; const PathMatch: Boolean; var ProcessID: DWORD);
    var
      lppe: TProcessEntry32;
      SsHandle: Thandle;
      FoundAProc, FoundOK: boolean;
    begin
      ProcessID :=0;
      SsHandle := CreateToolHelp32SnapShot(TH32CS_SnapProcess, 0);
     
      lppe.dwSize := sizeof(TProcessEntry32);
      FoundAProc := Process32First(Sshandle, lppe);
      while FoundAProc do
      begin
        if PathMatch then
          FoundOK := AnsiStricomp(lppe.szExefile, PChar(AFilename)) = 0
        else
          FoundOK := AnsiStricomp(PChar(ExtractFilename(lppe.szExefile)), PChar(ExtractFilename(AFilename))) = 0;
        if FoundOK then
        begin
          ProcessID := lppe.th32ProcessID;
          break;
        end;
        FoundAProc := Process32Next(SsHandle, lppe);
      end;
      CloseHandle(SsHandle);
    end;
     
     
    function EnabledDebugPrivilege(const Enabled : Boolean) : Boolean;
    var
      hTk : THandle;
      rtnTemp : Dword;
      TokenPri : TOKEN_PRIVILEGES;
    const
      SE_DEBUG = 'SeDebugPrivilege';
    begin
      Result := False;
      if (OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,hTk)) then
      begin
        TokenPri.PrivilegeCount := 1;
        LookupPrivilegeValue(nil,SE_DEBUG,TokenPri.Privileges[0].Luid);
     
        if Enabled then
          TokenPri.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
        else
          TokenPri.Privileges[0].Attributes := 0;
     
        rtnTemp := 0;
        AdjustTokenPrivileges(hTk,False,TokenPri,sizeof(TokenPri),nil,rtnTemp);
     
        Result := GetLastError = ERROR_SUCCESS;
        CloseHandle(hTk);
     
      end;
    end;
     
    function InjectTo(const Host, Guest: string; const PID: DWORD = 0): DWORD;
    var
      hRemoteProcess: THandle;
      dwRemoteProcessId: DWORD;
     
      memSize: DWORD;
     
      pszLibFileRemote: Pointer;
     
      iReturnCode: Boolean;
      TempVar: DWORD;
     
      pfnStartAddr: TFNThreadStartRoutine;
     
      pszLibAFilename: PwideChar;
    begin
      Result := 0;
      EnabledDebugPrivilege(True);
     
      Getmem(pszLibAFilename, Length(Guest) * 2 + 1);
      StringToWideChar(Guest, pszLibAFilename, Length(Guest) * 2 + 1);
     
      if PID > 0 then
         dwRemoteProcessID := PID
      else
         GetMyProcessID(Host, False, dwRemoteProcessID);
     
      hRemoteProcess := OpenProcess(PROCESS_CREATE_THREAD + 
          PROCESS_VM_OPERATION + 
          PROCESS_VM_WRITE, 
          FALSE, dwRemoteProcessId);
     
      memSize := (1 + lstrlenW(pszLibAFilename)) * sizeof(WCHAR);
      pszLibFileRemote := PWIDESTRING(VirtualAllocEx(hRemoteProcess, nil, memSize, MEM_COMMIT, PAGE_READWRITE));
      TempVar := 0;
      iReturnCode := WriteProcessMemory(hRemoteProcess, pszLibFileRemote, pszLibAFilename, memSize, TempVar);
     
      if iReturnCode then
      begin
        pfnStartAddr := GetProcAddress(GetModuleHandle('Kernel32'), 'LoadLibraryW');
        TempVar := 0;
        Result := CreateRemoteThread(hRemoteProcess, nil, 0, pfnStartAddr, pszLibFileRemote, 0, TempVar);
      end;
      Freemem(pszLibAFilename);
    end;
    @+ Phil

  4. #4
    Membre éclairé

    Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2003
    Messages
    286
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2003
    Messages : 286
    Par défaut
    Encore un plus gros merci pour ce code qui est bien sympathique (et assez technique ....)

  5. #5
    Membre Expert
    Avatar de NoisetteProd
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    1 905
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 1 905
    Par défaut
    N'hésitez pas à proposer vos sources : http://www.developpez.net/forums/showthread.php?t=11501 ou bien contactez moi par MP.


  6. #6
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 489
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 489
    Par défaut
    salut

    le code n'est malheureusement pas de moi je l'ai recupere sur un site chinois

    sinon plus explicite voila du code russe

    http://www.sources.ru/magazine/0505/st.html

    @+ Phil

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 12
    Dernier message: 03/12/2010, 15h13
  2. Réponses: 2
    Dernier message: 03/10/2009, 07h51
  3. Comment reconnaitre le type de clavier (API windows)
    Par moulydi dans le forum Débuter
    Réponses: 8
    Dernier message: 08/07/2009, 15h58
  4. Réponses: 10
    Dernier message: 26/03/2008, 17h23
  5. Réponses: 69
    Dernier message: 15/06/2006, 11h42

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