33

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

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

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

4

5 に答える 5

39

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

始めるにはこれで十分です。

于 2009-05-17T00:59:24.113 に答える
13

イージーフック 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'r がより速くそこに到達します。そして、それは非常に積極的に維持されています。

于 2009-05-17T01:21:15.810 に答える
8

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

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

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

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

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

于 2009-05-17T01:08:40.580 に答える
3

これは、対象とする Windows のバージョンによって多少異なります。それにもかかわらず、Pre-Vista でプレイしている場合は、SetWindowsHookEx を使用して、実行中のすべてのプロセスに DLL を挿入するだけです。次に、DLL は Detours などを使用して適切な関数をフックする必要があります。

于 2009-07-16T13:05:47.253 に答える
-2

アセンブリでフックを作成していて、(何らかの理由で) Detours を使用していない場合は、FALSE を返すことに関するいくつかの重要な情報が必要です。

  • Win32、EAX を 0 に設定
  • Win64、RAX を 0 に設定

フックしている関数が最後に行うこととして、EAX または RAX (プラットフォームによって異なります) をゼロに設定する必要があります。その結果、呼び出し元のコードは戻り値として 0 を受け取ります (int またはポインター型の値を返すと仮定します)。

于 2010-04-07T09:26:08.833 に答える