フックプログラミングがそのような致命的な力を持っている理由、私たちは愛と憎しみをしましょう

1.フックはフックの実装メカニズムを紹介します

フックの英語名はフックです。これは、Windowsシステム内の特定のアプリケーションまたはすべてのプロセスのメッセージを傍受するためのテクノロジです。次の図は、Windowsアプリケーションによるメッセージ配信のプロセスを示しています。

为ä½é©åç¼ç¨å・æå¦æ¤å¤§çæ伤åï¼è®©æ们åç±åæ¨

 

キーボードのキーを押すと、オペレーティングシステムはキーを押したメッセージを受信し、メッセージをメッセージキューに入れます。次に、メッセージキューはメッセージを対応するアプリケーションにディスパッチし、その後オペレーティングシステムに送信します。アプリケーションによって処理されています。次に、オペレーティングシステムは、対応するアプリケーションによって作成されたウィンドウプロシージャを呼び出します。

        これらのメッセージをフックを介して傍受して、メッセージが渡されないようにしたり、対象のメッセージを傍受した後に何かを実行したりする場合があります。

1.2フックの分類と実装

        フックは、インプロセスフックとグローバルフックに分けられます。インプロセスフックは、指定されたプロセスからのメッセージをインターセプトし、プロセス内のフックを直接作成および削除できます。グローバルフックは、すべてのプロセスのメッセージをインターセプトすることです。これは、ダイナミックライブラリに実装できます。

        フックを実装するには、通常3つの手順があります。まず、特別なAPIであるSetWindowsHookExを使用してフックを作成します。作成が成功すると、メッセージはSetWindowsHookExの仮パラメーターで指定された処理関数に渡されます。次に、メッセージ処理機能で受信したメッセージを分析し、対応する処理を行います。最後に、フックが使い果たされた後、API(UnhookWindowsHookEx)を使用してフックを破棄します。

次に、フックを作成します

2.1フックの作成

SetWindowsHookExは、アプリケーション定義のフックプロセスをインストールし、作成されたフックプロセスをフックチェーンに配置します。複数のフックをインストールでき、複数のフックがフックチェーンを形成します。最後にインストールされたフックは常に一番上にあります。フックを作成する機能は次のとおりです。

为ä½é©åç¼ç¨å・æå¦æ¤å¤§çæ伤åï¼è®©æ们åç±åæ¨

 

フックを作成し、フックハンドルを返します。それ以外の場合は、NULLを返します。仮パラメータは次のように定義されています。

idHook:マウスメッセージフック、キーボードメッセージフック、メッセージキュー監視フックなどのフックプロセスタイプ。具体的な値は次のとおりです:

为ä½é©åç¼ç¨å・æå¦æ¤å¤§çæ伤åï¼è®©æ们åç±åæ¨

 

lpfn:対応するフックプロセス、つまりメッセージを処理するコールバック関数の名前。パラメータdwThreadIdが0の場合、またはdwThreadIdが別のプロセスによって作成されたスレッド識別子を指している場合、lpfnはダイナミックにあるフックを指している必要があります。ライブラリプロセス。その他の場合、lpfnはこのプロセスのフックプロセスを指すことができます。

hMod:フックプロシージャが配置されているDLLのハンドルなど、フックプロシージャが配置されているアプリケーションのインスタンスハンドルを指します。dwThreadIdで指定されたスレッドが現在のプロセスによって作成され、フックプロセスが現在のプロセスにある場合は、hModをNULLに設定する必要があります。

dwThreadId:フックに関連付けられたスレッドフラグを指定します。0の場合、フックはデスクトップで実行されているすべてのスレッドに関連付けられます。

 フックプロセスは、dwThreadIdの値に応じて、特定のスレッドまたはすべてのスレッドに関連付けることができます。

2.2フックプロセス分析

        フックプロセスは、フックによってインターセプトされたメッセージ、つまりSetWindowsHookEx関数の2番目のパラメーターを処理するコールバック関数です。形式は次のとおりです。

LRESULT CALLBACK MouseProc(int nCode、WPARAM wParam、LPARAM lParam);仮パラメーターの意味はすべて同じではなく、異なるフックプロシージャの仮パラメーターの意味も異なります。例としてマウスフックを取り上げましょう。パラメータの意味は次のとおりです。

nCode:フックプロセスに現在のメッセージの処理方法を指示します。フックがマウスメッセージフックの場合、次の2つの意味があります。

为ä½é©åç¼ç¨å・æå¦æ¤å¤§çæ伤åï¼è®©æ们åç±åæ¨

 

 wParam:マウスメッセージフラグを示します。

lParam: MOUSEHOOKSTRUCT構造体へのポインター。以下は、マウスメッセージを含むMOUSEHOOKSTRUCT構造体です。

typedef struct {

   POINT pt; //カーソルには、画面座標であるx、yが含まれています。

   HWND hwnd; //ターゲットウィンドウハンドル

   UINT wHitTestCode;

   ULONG_PTR dwExtraInfo;

} MOUSEHOOKSTRUCT、* PMOUSEHOOKSTRUCT;

これらの3つのパラメーターを使用して、メッセージを分析および処理できます。

        他のフックプロセスパラメータの意味は、KeyboardProc、MessageProcなどのMSDNドキュメントで詳細に確認できます。

2.3フックを破壊する

        BOOL UnhookWindowsHookEx(HHOOK hhk);このAPIの機能は、SetWindowsHookExによって作成されたフックをフックチェーンから削除することです。仮パラメータは、SetWindowsHookExによって返されるフックハンドルです。

3つのインプロセスフック

        インプロセスフックは通常、現在のアプリケーションからのメッセージを傍受するために使用されます。通常、アプリケーションの初期化時に作成できます。もちろん、作成するときに作成することもできますが、作成前のメッセージを傍受することはできません。

3.1マウスフック手順機能

以下は、マウスフックプロセスコードです。

HWND            g_DestWndH = NULL;
HHOOK          g_hHookDm = NULL;
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{            //此区间内的消息都是鼠标消息
             if (WM_MOUSEMOVE <= wParam && wParam <= WM_MOUSEWHEEL) {
                           if(g_DestWndH != NULL) {
                                         ::SendMessage(g_DestWndH, wParam, wParam, lParam);
                                         //鼠标钩子,lParam是MOUSEHOOKSTRUCT结构指针
                                         PMOUSEHOOKSTRUCT lpMsg = (PMOUSEHOOKSTRUCT)lParam;
                                         lpMsg->hwnd = NULL;    //把目的窗口置NULL
                                         lpMsg->dwExtraInfo = 0L;
                                         lpMsg->pt = CPoint(0, 0);
                                         lpMsg->wHitTestCode = 0L;
                           }
                           return 1;//如果想让此消息不再往下传,返回非0
             }
             else//不感兴趣的消息往下传
                           return ::CallNextHookEx(g_hHookDm, nCode, wParam, lParam);
}

3.2フックプロセスの作成

        フックプロセスを作成するためのコードは次のとおりです。

if(g_hHookDm == NULL) {
             //如果dwThreadId指定的线程是由当前进程创建,并且钩子过程在当时进程中,那么hMod必须设置为NULL。
             g_hHookDm = ::SetWindowsHookEx(WH_MOUSE,MouseProc, NULL, GetCurrentThreadId());
             if (NULL != g_hHookDm)//创建成功
                           g_DestWndH = m_hWnd;//保存目的窗口句柄
}

3.3インプロセスフックを破棄する

        フックチェーンからフックプロセスを取得し、APIを呼び出します。

if (NULL != g_hHookDm) {
             UnhookWindowsHookEx(g_hHookDm);
             g_DestWndH = NULL;
}

この時点で、フックを作成して破棄するプロセスでフックを作成および実行するプロセス全体が完了しています。

4、グローバルフック

4.1キーボードフック手順機能

上記のインプロセスフックは、このプロセスからのメッセージをインターセプトするためのものです。デスクトップのすべてのスレッドからのメッセージをインターセプトする場合は、グローバルフックを渡す必要があります。グローバルフックはDLLに実装する必要があります。フックプロセスはこのプロセスのコードに実装できないため、最初にDLLを作成する必要があります。コードについては、「HookDll」を参照してください。例としてキーボードフックを取り上げます。

 

nCode:マウスフックと同じ意味で、HC_ACTIONとHC_NOREMOVEの2つの値があります。

Param:のような特定の仮想キー表し:。VK_TABとVK_RETURNは、Tabキーを表し、それぞれのキーを入力し、他の仮想キーメッセージの場合、あなたはMSDNの「仮想キーコード」を表示することができます。

lParam:次のような拡張情報を格納します。キーリピートデータ、29ビットはALTキーの押下を表します。

パラメータの具体的な意味は、MSDNにあります。キーの組み合わせについては、以下のキーボードフック機能のサンプルコードを参照してください。

HHOOK g_HookKeyBoard = NULL;
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
             //wParam表示虚拟键,lparam第29位表示ALT键按下状态(按下为1,否则为0),
             //GetKeyState可以获得对应键的状态,所以收下表示Control + ALT + Z组合键按下
             if ('Z' == wParam && GetKeyState(VK_CONTROL) < 0 && (lParam >> 29 & 1)) {
                           ::SendMessage(g_DestWnd, WM_KEYDOWN, wParam, lParam);
                           return 1;
             }
             else
                           return CallNextHookEx(g_HookKeyBoard, nCode, wParam, lParam);
}

注:システムの特定のバージョンでは、デバッグ状態で、デバッガーウィンドウがフォーカスを取得しない場合、ブレークポイントが設定されている場所に留まりません。フォーカスを取得した場合にのみ留まります。 、デバッグ状態では、プロセスに属するメッセージはブレークポイントに留まりません。

4.2グローバルフックインターフェイスを作成する

        グローバルフックを作成する方法はDLLにあるため、インターフェイスを派生させる必要があります。コードは次のとおりです。

BOOL SetHook(HWND hWnd){
             if (NULL == hWnd)
                           return FALSE;
             g_DestWnd = hWnd;
             //第三个参数可通过些方法获得:GetModuleHandle("MouseHook.dll")
             return (NULL != (g_HookKeyBoard = ::SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInst, 0)));
}

その正式なパラメーターはウィンドウハンドルであり、インターセプトされた対象のメッセージを送信する必要があるウィンドウのハンドルを示します。MetWindowsHookEの3番目のパラメーターは、DLLのインスタンスハンドルであり、DllMainの着信パラメーターを介して取得できます。またはGetModuleHandleメソッドを介して取得します。すべてのデスクトップスレッドメッセージを取得するには、4番目のパラメーターを0にする必要があります。成功するとTRUEが返され、それ以外の場合はFALSEが返されます。

4.3グローバルフックインターフェイスを破棄します

        DLLで、グローバルフックを破棄するためのインターフェイスを導入する必要があります。コードは次のとおりです。

void DestroyHook(){
             if (NULL != g_HookKeyBoard) {
                           UnhookWindowsHookEx(g_HookKeyBoard);
                           g_DestWnd = NULL;
             }
}

4.4DLLを使用してグローバルフックを作成する

        以下は、グローバルフックの作成と破棄の実装です。コードは次のとおりです。

HINSTANCE hIst = NULL;
void CHookTestDlg::OnCreateDllHook()
{
             hIst = ::LoadLibrary("..\\HookDll\\Debug\\HookDll.dll");
             if (NULL != hIst) {
                           typedef BOOL (*pFunSetHook)(HWND);
                           pFunSetHook pSetHook = (pFunSetHook)GetProcAddress(hIst, "SetHook");
                           if (NULL != pSetHook) {
                                         if(pSetHook(m_hWnd))
                                                       AfxMessageBox("创建全局钩子成功...");
                           }
             }
}
void CHookTestDlg::OnDestroyDllHook()
{
             if (NULL != hIst) {
                           typedef void (*pFunDestroyHook)();
                           pFunDestroyHook pDestryHook = (pFunDestroyHook)GetProcAddress(hIst, "DestroyHook");
                           if (NULL != pDestryHook) {
                                         pDestryHook();
                                         ::FreeLibrary(hIst);
                                         hIst = NULL;
                           }
             }
}

フックの種類

(1)キーボードフックと低レベルキーボードフックは、さまざまなキーボードメッセージを監視できます。

(2)マウスフックと低レベルマウスフックは、さまざまなマウスメッセージを監視できます。

(3)シェルフックは、さまざまなシェルイベントメッセージを監視できます。アプリケーションの開始と終了など。

(4)ログフックは、システムメッセージキューから取得したさまざまなイベントメッセージを記録できます。

(5)ウィンドウプロシージャフックは、システムメッセージキューからターゲットウィンドウに送信されるすべてのメッセージを監視します。

 

13の一般的に使用されるフックタイプ:

WH_CALLWNDPROCおよびWH_CALLWNDPROCRETフック:ウィンドウプロシージャに送信されるメッセージを監視します。

WH_CBTフック:次のイベントの前に、システムはWH_CBTフックサブルーチンを呼び出します。これらのイベントには次のものが含まれます。

1.アクティブ化、作成、破棄、最小化、最大化、移動、サイズの変更などのウィンドウイベント。

2.システムの説明を完了します。

3.マウスとキーボードのイベントをシステムメッセージキューから移動します。

4.入力フォーカスイベントを設定します。

5.システムメッセージキューイベントを同期します。

Hookサブルーチンの戻り値は、システムがこれらの操作の1つを許可するか禁止するかを決定します。

WH_DEBUGフック

システムがシステム内の他のフックに関連付けられたフックサブルーチンを呼び出す前に、システムはWH_DEBUGフックサブルーチンを呼び出します。このフックを使用して、システムが他のフックに関連付けられたフックサブルーチンを呼び出すことを許可するかどうかを決定できます。

WH_FOREGROUNDIDLEフック

アプリケーションのフォアグラウンドスレッドがアイドル状態の場合、WH_FOREGROUNDIDLEフックを使用して優先度の低いタスクを実行できます。アプリケーションのフォアグラウンドスレッドが大まかにアイドル状態になると、システムはWH_FOREGROUNDIDLEフックサブルーチンを呼び出します。

WH_GETMESSAGEフック

アプリケーションはWH_GETMESSAGEフックを使用して、GetMessageまたはPeekMessage関数から返されるメッセージを監視します。WH_GETMESSAGEフックを使用して、マウスとキーボードの入力、およびメッセージキューに送信されるその他のメッセージを監視できます。

WH_JOURNALPLAYBACKフック:アプリケーションがシステムメッセージキューにメッセージを挿入できるようにします。

WH_JOURNALRECORDフック:入力イベントを監視および記録し、マウスとキーボードの連続イベントと再生を記録します。

WH_KEYBOARDフック:アプリケーションのWM_KEYDOWNおよびWM_KEYUPメッセージを監視します。

WH_KEYBOARD_LLフック:スレッドメッセージキューに入力されたキーボードメッセージを監視します。

WH_MOUSEフック: GetMessageまたはPeekMessage関数から返されるマウスメッセージを監視します。

WH_MOUSE_LLフック:スレッドメッセージキューに入力されたマウスメッセージを監視します。

WH_MSGFILTERおよびWH_SYSMSGFILTERフック:メニュー、スクロールバー、メッセージボックス、ダイアログメッセージを監視し、ユーザーがALT + TABまたはALT + ESCキーの組み合わせを使用してウィンドウを切り替えていることを確認します。

WH_SHELLフック:シェルアプリケーションは、WH_SHELLフックを使用して重要な通知を受信できます。シェルアプリケーションがアクティブ化され、トップレベルウィンドウが作成または破棄されると、システムはWH_SHELLフックサブルーチンを呼び出します。

WH_SHELLには5つの状況があります。

トップレベルの所有されていないウィンドウが生成、アクティブ化、または破棄されている限り、

タスクバーがボタンを再描画する必要がある場合。

システムがタスクバーに関するプログラムの最小化された形式を表示する必要がある場合。

現在のキーボードレイアウトステータスが変更されたとき。

ユーザーがCtrl + Escを押してタスクマネージャー(または同じレベルのプログラム)を実行したとき。

慣例により、シェルアプリケーションはWH_SHELLメッセージを受信しません。

したがって、アプリケーションがWH_SHELLメッセージを受信する前に、アプリケーションはSystemParametersInfo関数を呼び出して登録する必要があります。

フックは非常に強力なので、使用には注意する必要があります〜フックの致死性を試す必要がある場合は、グループを追加できます:①①⑤①③⑨⑤⑨∥⑤入手

フックプログラミングの動画がホームページにアップされており、ご覧いただけます

おすすめ

転載: blog.csdn.net/Python6886/article/details/111708872