システムフック

投稿者: | 2012/11/15

ローカルフックは実行したプロセス内のみフックするのに対して、システムフックはプロセスを超えてフックができる。

基本的な処理フローはこんな感じ。

  1. フックプロシージャをDLL側で作る
    HHOOKやスタティック変数をDLL間で共有する(#pragma data_seg)
    共有領域を設定するため.defファイルを作る
    .defファイルはプロジェクトの「プロパティ」ー「リンカ」ー「入力」ー「モジュール定義ファイル」に名前を登録する
  2. SetWindowsHookExでフックプロシージャを登録
    第三引数はDLLのハンドルをセット(ここがローカルフックとは違う!)
  3. フックプロシージャでフック処理
    CallNextHookExで次のフックへ引き継ぎ
  4. UnhookWindowsHookExで解除

2,3,4はほとんどローカルフックと同じで、SetWindowsHookExにDLLのハンドルを渡す点だけが違う。1が主にシステムフックに必要な設定となる。書いてあるとおりDLLで作るのと最低限HHOOKを共有領域として設定して、.defファイルを設定する必要がある。キーボードフックなどでキーの値を取っておく場合は共有領域で宣言しておく必要がある。

DLL側のコード

#define DLL_API extern "C" __declspec( dllexport )

// 共有領域
#pragma data_seg(".shareddata")
HHOOK hMyHook=0;
#pragma data_seg()

HMODULE hInst;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                         )
{
     if(ul_reason_for_call==DLL_PROCESS_ATTACH){
          hInst = hModule;
     }

     return TRUE;
}

LRESULT CALLBACK MyHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
     //     nCodeがマイナスの場合は何もしないですぐに返す。そういう決まり。
     if(nCode < 0){ return CallNextHookEx(hMyHook, nCode, wParam, lParam); }

     // any hook

    return CallNextHookEx(hMyHook, nCode, wParam, lParam);
}

DLL_API bool BeginHook(){

     hMyHook = SetWindowsHookEx(
          WH_KEYBOARD,           // フックタイプ
          (HOOKPROC)MyHookProc,  // フックプロシージャのアドレス
          hInst,                 // ローカルフックではNULL。システムフックではDLLのハンドル。
          0);                    // フックされるスレッド

     if(hMyHook == NULL){
          return false;
     }

     return true;
}

DLL_API void EndHook(){

     if(UnhookWindowsHookEx(hMyHook) == 0){
          MessageBoxA(NULL, "Failed to delete hook!", "Error", MB_OK);
     }
}

.defファイル

SECTIONS
     .shareddata     READ WRITE SHARED

実行ファイル側

// dll関数を取得する関数ポインタタイプ
typedef bool (*BeginHookFunc)(void);
typedef void (*EndHookFunc)(void);

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
     // ウィンドウの生成など

     // dll load
     HMODULE     hModule = LoadLibrary(TEXT("HookDll.dll"));
     assert(hModule != NULL && "dll load error");
     {
          // dll関数ポインタ取得
          BeginHookFunc BeginHook     = (BeginHookFunc)GetProcAddress(hModule ,"BeginHook");
          assert(BeginHook != NULL && "dll func call error");
          EndHookFunc EndHook     = (EndHookFunc)GetProcAddress(hModule ,"EndHook");
          assert(EndHook != NULL && "dll func call error");

          BeginHook();
          // メイン メッセージ ループ:
          while (GetMessage(&msg, NULL, 0, 0))
          {
               if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
               {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
               }
          }
          EndHook();
     }
     // dll release
     FreeLibrary(hModule);

     return (int) msg.wParam;
}

以上のようにやっていることはローカルフックとほとんど同じだ。実行ファイル側でDLLを読み込んで関数ポインタを取得している部分が違うくらいで、他はローカルフックと同じでメインループの前後でBeginHook(),EndHook()してやればいい。
これでキーボードフックまでの下準備が整った。

システムフック参考
http://www.kab-studio.biz/Programing/Codian/DLL_Hook_SClass/08.html
http://www.kumei.ne.jp/c_lang/sdk2/sdk_161.htm


コメントを残す

メールアドレスが公開されることはありません。