web-dev-qa-db-ja.com

C / C ++でWindows関数をフックするにはどうすればよいですか?

Windowsがkernel32.dllに実装している関数foo()があり、常にtrueを返す場合、自分のプログラム: "bar.exe"をWindows関数にフック/迂回させて、すべてに対してfalseを返すようにできますか?代わりにプロセス?

したがって、たとえば、私のsvchostがfoo()を呼び出すと、trueではなくfalseが返されます。現在実行中の他のすべてのプロセスに対して同じアクションが期待されます。

もしそうなら、どうですか?私はシステム全体のフックか何かを探していると思います。

30
Clark Gaebel

Detours を見てください。これは、この種のものに最適です。


システム全体のフックについては、MSDNの この記事 を参照してください。


まず、DLLを作成します。これは、関数のフックを処理します。以下の例は、ソケットの送信および受信関数をフックします。

#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;
}

次に、DLLをターゲットアプリケーションに挿入するプログラムを作成します。

#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;
}

これはあなたが始めるのに十分すぎるはずです!

35
xian

[〜#〜] easyhook [〜#〜]http://www.codeplex.com/easyhook

シンプルさ、柔軟性、機能性において、前述のすべての技術を支配します。

以前は フックプロセス については説明されていませんでした。私はこのスレッドのすべての葉っぱを読んだことがあり、絶対的な保証があります [〜#〜] easyhook [〜#〜] は非常に優れています。 C、C++、CLRを使用しているかどうかは関係ありません。

十分なオマージュが支払われるように、codeplexホームページから少し貼り付けます。

以下は、機能の不完全なリストです。

  1. いわゆる「スレッドデッドロックバリア」は、不明なAPIをフックするときに多くのコア問題を解消します。このテクノロジーはEasyHookに固有のものです
  2. アンマネージAPIのマネージフックハンドラーを作成できます。
  3. NET Remoting、WPF、WCFなど、マネージドコードが提供するすべての便利な機能を使用できます。
  4. 文書化された純粋なアンマネージフッキングAPI
  5. 32ビットおよび64ビットのカーネルモードフッキングのサポート(リリースリストにある私のPatchGuard 3バイパスドライバーも確認してください)
  6. ターゲットにリソースまたはメモリリークが残っていない
  7. 現在のAVソフトウェアの注目を集めない実験的なステルス注入メカニズム
  8. EasyHook32.dllとEasyHook64.dllは純粋なアンマネージモジュールであり、NETフレームワークがインストールされていなくても使用できます。
  9. すべてのフックがインストールされ、安定した方法で自動的に削除されます
  10. 完全に文書化されていないAPIを利用することによるWindows Vista SP1 x64およびWindows Server 2008 SP1 x64のサポート。これにより、任意のターミナルセッションへのフックが可能になります。
  11. フックハンドラー内のマネージ/アンマネージモジュールのスタックトレース
  12. フックハンドラー内でマネージ/アンマネージモジュールを呼び出す
  13. フックハンドラー内にカスタムスタックトレースを作成する
  14. AnyCPU用にコンパイルされたインジェクションライブラリとホストプロセスを記述できます。これにより、すべてのケースでまったく同じアセンブリを使用して、64ビットおよび32ビットプロセスから32ビットおよび64ビットプロセスにコードをインジェクトでき​​ます。
  15. EasyHookは、64ビットターゲットのRIP相対アドレッシング再配置をサポートしています。
  16. 開梱/設置は必要ありません。
  17. Visual Studio再頒布可能パッケージは必要ありません。

私の売春婦は、いくつかのトリックをまだ知っていることを嬉しく思います。しかし、確かに、100の99倍のフックが必要な場合は、EASYHOOKを使用すれば、すばやくアクセスできます。そして、それはかなり積極的に維持されています。

11

フックしたい機能の詳細を教えてください!このような場合に独自のコードを呼び出す方法はいくつかあります。たとえば、

  • フックしたい関数を含むDLLと同じ名前で偽のDLLを構築できます(そして、それをfoo.exe)このライブラリは、元のDLLとまったく同じ関数を公開します。公開する各関数は、フックする関数を除いて、元のDLLへの呼び出しをバイパスするだけです。

  • たとえば、「kitchen」で言及されている(商用の)Detourパッケージを使用して、実行時に関数ポインタテーブルを変更できます。ただし、このようなフッキングは自分で簡単に行うことができます。方法については この記事 を参照してください。

  • 特定の関数がfoo.exeで呼び出されている場所を確認し、関数を呼び出すアセンブリコードを「trueを返す」コードに置き換えるだけです。基本的には、「foo.exe」にパッチを適用しています。

  • 特定の機能について、Windowsは自動フッキングを提供しています。キーとマウスイベント用。これについては、関数 SetWindowsHook を確認してください。

8
beef2k

これは、ターゲットにするWindowsのバージョンによって多少異なります。それでも、Pre-Vistaでプレイしている場合は、SetWindowsHookExを使用して、DLLを実行中のすべてのプロセスに挿入できます。DLL Detoursなどを使用して適切な関数をフックします。

3
mrduclaw