web-dev-qa-db-fra.com

Comment accrocher des fonctions Windows en C / C ++?

Si j'ai une fonction foo() que Windows a implémentée dans kernel32.dll et qu'elle retourne toujours true, puis-je avoir mon programme: "bar.exe" crochet/détourne cette fonction Windows et la fait retourner false pour tous processus à la place?

Ainsi, si mon svchost, par exemple, appelle foo(), il retournera false au lieu de true. La même action doit être attendue pour tous les autres processus en cours d'exécution.

Si c'est le cas, comment? Je suppose que je cherche un crochet à l'échelle du système ou quelque chose.

30
Clark Gaebel

Jetez un oeil à Détours , c'est parfait pour ce genre de choses.


Pour le raccordement à l'échelle du système, lisez cet article à partir de MSDN.


Commencez par créer un DLL qui gère le raccordement des fonctions. Cet exemple ci-dessous raccorde les fonctions d'envoi et de réception du socket.

#include <windows.h>
#include <detours.h>

#pragma comment( lib, "Ws2_32.lib" )
#pragma comment( lib, "detours.lib" )
#pragma comment( lib, "detoured.lib" )

int ( WINAPI *Real_Send )( SOCKET s, const char *buf, int len, int flags ) = send;
int ( WINAPI *Real_Recv )( SOCKET s, char *buf, int len, int flags ) = recv;  
int WINAPI Mine_Send( SOCKET s, const char* buf, int len, int flags );
int WINAPI Mine_Recv( SOCKET s, char *buf, int len, int flags );

int WINAPI Mine_Send( SOCKET s, const char *buf, int len, int flags ) {
    // .. do stuff ..

    return Real_Send( s, buf, len, flags );
}

int WINAPI Mine_Recv( SOCKET s, char *buf, int len, int flags ) {
    // .. do stuff ..

    return Real_Recv( s, buf, len, flags );
}

BOOL WINAPI DllMain( HINSTANCE, DWORD dwReason, LPVOID ) {
    switch ( dwReason ) {
        case DLL_PROCESS_ATTACH:       
            DetourTransactionBegin();
            DetourUpdateThread( GetCurrentThread() );
            DetourAttach( &(PVOID &)Real_Send, Mine_Send );
            DetourAttach( &(PVOID &)Real_Recv, Mine_Recv );
            DetourTransactionCommit();
            break;

        case DLL_PROCESS_DETACH:
            DetourTransactionBegin();
            DetourUpdateThread( GetCurrentThread() );
            DetourDetach( &(PVOID &)Real_Send, Mine_Send );
            DetourDetach( &(PVOID &)Real_Recv, Mine_Recv );
            DetourTransactionCommit(); 
        break;
    }

    return TRUE;
}

Ensuite, créez un programme pour injecter le DLL dans l'application cible.

#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>

void EnableDebugPriv() {
    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tkp;

    OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken );

    LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &luid );

    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = luid;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges( hToken, false, &tkp, sizeof( tkp ), NULL, NULL );

    CloseHandle( hToken ); 
}

int main( int, char *[] ) {
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof( PROCESSENTRY32 );

    HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, NULL );

    if ( Process32First( snapshot, &entry ) == TRUE ) {
        while ( Process32Next( snapshot, &entry ) == TRUE ) {
            if ( stricmp( entry.szExeFile, "target.exe" ) == 0 ) {
                EnableDebugPriv();

                char dirPath[MAX_PATH];
                char fullPath[MAX_PATH];

                GetCurrentDirectory( MAX_PATH, dirPath );

                sprintf_s( fullPath, MAX_PATH, "%s\\DllToInject.dll", dirPath );

                HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, entry.th32ProcessID );
                LPVOID libAddr = (LPVOID)GetProcAddress( GetModuleHandle( "kernel32.dll" ), "LoadLibraryA" );
                LPVOID llParam = (LPVOID)VirtualAllocEx( hProcess, NULL, strlen( fullPath ), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );

                WriteProcessMemory( hProcess, llParam, fullPath, strlen( fullPath ), NULL );
                CreateRemoteThread( hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)libAddr, llParam, NULL, NULL );
                CloseHandle( hProcess );
            }
        }
    }

    CloseHandle( snapshot );

    return 0;
}

Cela devrait être plus que suffisant pour vous lancer!

35
xian

EASYHOOK http://www.codeplex.com/easyhook

Dominez toutes les techniques susmentionnées en termes de simplicité, de flexibilité et de fonctionnalité.

Cela n'a pas été discuté précédemment sur Processus de hook non plus. J'ai lu toutes les feuilles de ce fil et avec une certitude absolue, EASYHOOK est largement supérieur. Peu importe si vous utilisez C, C++, CLR, peu importe.

Je vais coller un peu de la page d'accueil du codeplex, pour garantir que suffisamment d'omage soit payé.

Voici une liste incomplète des fonctionnalités:

  1. Un soi-disant "Thread Deadlock Barrier" éliminera de nombreux problèmes de base lors du raccordement d'API inconnues; cette technologie est unique à EasyHook
  2. Vous pouvez écrire des gestionnaires de hooks gérés pour les API non managées
  3. Vous pouvez utiliser tout le code managé pratique fourni, comme NET Remoting, WPF et WCF par exemple
  4. Une API de hooking documentée et pure non managée
  5. Prise en charge du raccordement en mode noyau 32 et 64 bits (consultez également mon pilote de contournement PatchGuard 3 qui se trouve dans la liste des versions)
  6. Aucune fuite de ressources ou de mémoire n'est laissée dans la cible
  7. Mécanisme d'injection furtif expérimental qui n'attirera pas l'attention des logiciels AV actuels
  8. EasyHook32.dll et EasyHook64.dll sont de purs modules non gérés et peuvent être utilisés sans aucun framework NET installé!
  9. Tous les crochets sont installés et retirés automatiquement de manière stable
  10. Prise en charge de Windows Vista SP1 x64 et Windows Server 2008 SP1 x64 en utilisant des API totalement non documentées, pour permettre toujours la connexion à n'importe quelle session de terminal.
  11. Trace de pile de module gérée/non gérée dans un gestionnaire de hook
  12. Obtenir l'appel du module géré/non géré dans un gestionnaire de hook
  13. Créer des traces de pile personnalisées dans un gestionnaire de hook
  14. Vous pourrez écrire des bibliothèques d'injection et des processus hôtes compilés pour AnyCPU, ce qui vous permettra d'injecter votre code dans des processus 32 et 64 bits à partir de processus 64 et 32 ​​bits en utilisant le même assembly dans tous les cas.
  15. EasyHook prend en charge la relocalisation d'adressage relative au RIP pour les cibles 64 bits.
  16. Aucun déballage/installation nécessaire.
  17. Le Visual Studio Redistributable n'est pas requis.

Je suis heureux que mon talonneur connaisse encore quelques trucs en comparaison qui me font les garder. Mais pour être sûr, lorsque vous avez besoin d'un CROCHET, 99 fois sur 100, EASYHOOK'r vous y conduira plus rapidement. Et c'est assez activement maintenu.

11
RandomNickName42

Veuillez donner plus de détails sur la fonction que vous souhaitez accrocher! Il existe plusieurs façons d'obtenir votre propre code appelé dans un tel cas, par exemple:

  • Vous pouvez créer un faux DLL avec le même nom que le DLL qui contient la fonction que vous voulez accrocher (et la copier dans le dossier de foo.exe). Cette bibliothèque exposerait exactement les mêmes fonctions que la DLL d'origine. Chaque fonction exposée contourne simplement l'appel à la DLL d'origine, à l'exception de la fonction que vous souhaitez accrocher.

  • Vous pouvez modifier la table des pointeurs de fonctions pendant l'exécution, par exemple avec le package (commercial) Detour mentionné par "kitchen". Cependant, faire un tel accrochage peut être fait facilement par vous-même, voir cet article pour savoir comment.

  • Vous pouvez savoir où la fonction spécifique est appelée dans foo.exe et remplacez simplement le code Assembly qui appelle la fonction par un code qui "renvoie true". Fondamentalement, vous corrigez "foo.exe "..

  • Pour des fonctions spécifiques, Windows propose un raccordement automatique, par ex. pour les événements de touches et de souris. Vérifiez la fonction SetWindowsHook pour cela.

8
beef2k

Cela dépend quelque peu de la version de Windows que vous souhaitez cibler. Néanmoins, si vous jouez sur Pre-Vista, vous pouvez simplement utiliser SetWindowsHookEx pour injecter votre DLL dans chaque processus en cours d'exécution. Votre DLL devra alors accrocher la fonction appropriée à l'aide de Détours ou similaire.

3
mrduclaw