Global Hooking in Win32
 ====================================================

 후크에는 두가지가 있다.
   Local Hook   - 하나의 스레드나 프로세스 안에서의 후킹
   Global Hook  - 전역 모든 윈도우들에 대한 후킹

 후크를 하기 위해서는 기본적으로 두가지 자료형을 알아야 한다.
   HHOOK - 후크 핸들  윈도우 시스템에서 한번 이벤트가
           발생하면 후크 체인의 첫 후크핸들에게 이벤트를
           넘긴다. 각 후크들은 다음 후크를 호출하여 후크체인에
           있는 모든 후크 프로시져를 호출하게 된다.
   HOOKPROC - 후크 프로시져로 후크시 호출되는 프로시져이다.
    LRESULT CALLBACK fnHookProc(int nCode, WPARAM wParam, LPARAM lParam)
    라는 자료형을 갖는다.

 1. 로컬 후킹
   SetWindowHookEx를 이용하면 간단히 구현이 가능하다.
   각 후크는 후크 타입이 있는데 아래와 같다.
      WH_CALLWNDPROC - 윈도우 메세지가 목적지로 전달되기 전에
                       메세지를 후크할때 쓴다 (SendMessage)
                       CallWndProc라는 후크프로시져명의 도움말 참조한다.
      WH_CALLWNDPROCRET - 윈도우 메세지가 목적지에 전달되어 처리
                          된 후 후크가 일어난다
                          CallWndRetProc함수명 도움말 참조
      WH_CBT - computer-based training (CBT) application 에 유용한
               후크 타입 CBTProc 함수 참조
      WH_DEBUG - 디버깅에 유용한 후크 DebugProc 참조
      WH_FOREGROUNDIDLE - Foreground상태있는 윈도우가 idle상태로 들어갈
                          때 생기는 후크 이는 idle시 낮은 우선순위
                          (low priority)를 줄때 유용하다 ForegroundIdleProc
      WH_GETMESSAGE - 메세지가 Post된 후 후크됨 (PostMessage)
                      GetMsgProc 함수 참조
      WH_JOURNALPLAYBACK - WH_JOURNALRECORD에 의해서 Record되기 전에
                           일어나는 후크 JournalPlaybackProc
      WH_JOURNALRECORD - Input message가 시스템 메세지 큐로 들어가는것을
                         Record하는 후크 JournalRecordProc
      WH_KEYBOARD - 등등이 있다.... -_- 도움말 참조..

 
 --------------------- 로컬 후크 예제 ------------------------------
    HHOOK hHook;
    HOOKPROC hProc;
              :
    hProc = CallWndProc;            // CallWndProc 후크 프로시져로 연결
    hHook = ::SetWindowsHookEx(     // 후크를 설치한다. ( 후크체인에 끼워넣는다 )
                 WH_CALLWNDPROC,    // WH_CALLWNDPROC 후크 설치
                 hProc,             // 후크차례가 오면 분기되는 콜백후크 프로시져
                 (HINSTANCE) NULL,  // 전역 후크가 아닌 로컬 후크임을 말한다
                 dwTreadID);        // 특정 스레드를 정한다 0 이면 현재 스레드


    만일 여러 스레드중 한 HWND가 속한 스레드를 얻고 싶으면
    DWORD    dwProcessID = NULL;
    DWORD    dwTreadID = ::GetWindowThreadProcessId( hWnd, &dwProcessID );

    if( dwProcessID )
    {
                 :
         후크 설치코드 맨 마지막인자에 dwThreadID를 넣으면 된다.    
    }

// 자세한 프로시져 도움말을 보면 자세히 알수 있다.
LRESULT WINAPI CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    CWPSTRUCT* lpWp = (CWPSTRUCT*)lParam;
     //PMSG lpMsg = (PMSG)lParam;    
    if (nCode < 0 && hWnd == lpWp->hwnd )  // do not process message
        return CallNextHookEx(m_stHookCallProc.hHook, nCode, wParam, lParam);

    switch(  lpWp->message  )
    {
         case EM_REPLACESEL :
         TRACE("CallWndProc EM_REPLACESEL %s\r\n ", (char*)lpWp->lParam );
         break;

         default : 
         break;
    }   
    return CallNextHookEx(m_stHookCallProc.hHook, nCode,
        wParam, lParam);
}
 
2 전역 후킹
  전역 후킹을 하기 위해서는 후크 프로시져를 dll안에 넣어야 한다.
 


 --------------------- 전역 후크 예제 --------------------------

  testdll.dll 에서 ............

// dll에서 쓰는 자료는 dll공유를 했다.
// 이 후크 프로시져 dll은 내 프로그램에서 쓰이기도 하지만
// 시스템에 의해서 이 dll이 또 열리게 된다. ( dll의 참조카운트 증가
//  가 일어나지 않고 새로 dll이 생긴다. 따라서 두 dll은 자료가
//  분리되어 있는 셈이다. )
// 그러므로 부득이 하게 자료를 공유자료로 해야 한다.
#pragma data_seg(".shared")
    HHOOK             _hHook = NULL;
    HWND            _hTarget = NULL;
#pragma data_seg()
// 공유 자료로 했을 경우 아래처럼 링커 옵션도 주어야 한다.
#pragma comment(linker, "/SECTION:.shared,RWS")

// 자료 억세스 함수 마련...
extern "C" __declspec(dllexport) void fnSetHook( HHOOK hHook )
{
    _hHook = hHook;
}

extern "C" __declspec(dllexport) void fnSetHWND( HWND hWnd )
{
    _hTarget = hWnd;
    char szBuf[20];
    wsprintf( szBuf, "%lu", (ULONG)_hTarget );
    MessageBox( NULL, szBuf, "fnSetHWND당시의 _hTarget값", MB_OK);
}

extern "C" __declspec(dllexport) HHOOK fnGetHook()
{
    return _hHook;
}

// 콜백을 위한 CALLBACK 콜링컨벤션 키워드를 넣게 되면 나중에 GetAddressProc시
// NULL값을 리턴하므로 그냥 콜링컨벤션을 무시했다
//extern "C" __declspec(dllexport) LRESULT CALLBACK fnCallWndProc(int nCode, WPARAM wParam, LPARAM
lParam)
extern "C" __declspec(dllexport) LRESULT fnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    CWPSTRUCT* lpWp = (CWPSTRUCT*)lParam;
     
    if( nCode >= 0  ) //&& _hTarget == lpWp->hwnd ) // do not process message
    { 
        switch(  lpWp->message  )
        {
        case EM_REPLACESEL :
            if( _hTarget == lpWp->hwnd )
            {
                MessageBox( NULL, "EM_REPLACESEL 메세지 발쌩", "메세지 발쌩in
dll", MB_OK);
            }
            break;

        default : 
            break;
        }   
    }
    return CallNextHookEx( _hHook, nCode, wParam, lParam);
}


 내 프로그램에서 .........................
HINSTANCE    hInstDll = NULL
HHOOK        hHook = NULL;

// dll을 연다.
hInstDll = LoadLibrary("TestDll.dll");
if( hInstDll )
{
    // 후크 프로시져를 찾아낸다.
    LRESULT (*hHookDllProc)(int, WPARAM, LPARAM ) = (LRESULT (*)(int, WPARAM, LPARAM ))
GetProcAddress(hInstDll, "fnCallWndProc");
    if( hHookDllProc ) // 있으면 후크를 설치한다.
        hHook = SetWindowsHookEx( WH_CALLWNDPROC, (HOOKPROC)hHookDllProc, hInstDll, 0);
   
        // dll내의 자료를 세팅한다. HHOOK와 HWND 값 세팅
    void (*lpfnSetHook)(HHOOK) = (void (*)(HHOOK))GetProcAddress(hInstDll, "fnSetHook");
    if( lpfnSetHook )
        (*lpfnSetHook)( hHook );
        void (*lpfnSetHWND)(HWND) = (void (*)(HWND))GetProcAddress
(hInstDll, "fnSetHWND");
    if( lpfnSetHWND )
        (*lpfnSetHWND)( m_hTarget );
}



출처 : http://blog.naver.com/heroyik/14775896

+ Recent posts