출처: http://blog.naver.com/egeroo?Redirect=Log&logNo=60002934064

-----------------------------------------------------------------
Hook.
-----------------------------------------------------------------
윈도우의 시스템 메세지 핸들링 메커니즘안에서 애플리케이션이
서브루틴을 설치함으로써 타겟 윈도우 프로시져에 도착하기 전에
메세지를 감시할수 있다.


-> 후킹은 시스템을 전반적으로 느리게 만드므로 필요시 사용후
곧바로 지워야 한다.

Hook Chanins

여러가지 후킹 타입을 지원하는데, 여러 메세지 핸들링 메카니즘에
대한것들로 예를 들어 애플리케이션이 WH_MOUSE 후킹을 쓰면
마우스 메세지 후킹을 할 수 있다.
시스템은 각 후킹 타입에 대해 따로 분리된 후크 체인을 갖고 있다.
후크체인은 특별히 애플리케이션에서 후크 프로시져로 불리는
콜백 함수들의 포인터들의 리스트이다.
만일 특별한 타입의 후크에 연관된 메세지가 발생하면 시스템은
그 메세지를 후크체인에 있는 각 후크 프로시져들에게 통보한다.
후크 프로시져의 호출은 수반한 후크의 타입에 의존된다. 몇 종류의 후크에
대한 후크 프로시져는 오직 메세지를 감시한다. 다른것들은 메세지를
수정할수 있고 체인에서의 진행을 멈추게 할수있으며 다음 후크프로시져나
목적 윈도우로가는것을 막을수도 있다.

Hook Procedures
각 후크종류의 이점을 얻기 위해서 개발자는 후크 프로시져를 제공받으며
SetWindowsHookEx 함수를 이용해 원하는 후크 체인에 설치할 수 있다.
후크 프로시져는 반드시 다음 문법을 따라야 한다.

LRESULT CALLBACK HookProc{ int nCode, WPARAM wParam, LPARAM lParam );

HookProc은 애플리케이션 마다 정의한 후크 이름으로 바꿀수 있다.

nCode파라미터는 후크 프로시져가 행해야 할 행동에 대한 코드이다.
후크 코드 값은 후크 타입에 의존하는데, 각 타입은 자신의 후크코드 집합을
갖게 된다. wParam과 lParam인자의 값은 후크 코드에 의존되지만 보통
send나 post를 통해 만들어진 메세지들에 대한 정보를 갖고 있다.

SetWindowsHookEx함수는 항상 후크 체인의 시작점에 후크 프로시져를 설치한다.
어떤 후크에 대해 감시하는 이벤트가 발생했을때 시스템은 그 후크에 관련된
후크 체인의 처음 프로시져를 호출하게 된다. 체인안의 각 후크 프로시져는
이 이벤트를 다음 프로시져를 넘겨줄것인가를 결정할 수 있다.
후크 프로시져는 다음 프로시져로 이 이벤트를 넘길수있는데 이때
CallNextHookEx함수를 호출함으로 할 수 있다.

어떤 후크 타입에서의 후크 프로시져는 오직 메세지를 감시할수 있음을 주의해라
시스템이 각 후크 프로시져에게 메세지를 넘길때,
각 후크 프로시져를 CallNextHookEx를 호출

후크프로시져는 시스템안 모든 스레드를 감시하는 전역적으로 쓰일수 있으며
특정 스레드를 감시할수 있으며 단지 하나의 스레드를 위한 메세지를 감시
할수 있다. 전역적인 후크( global hook )프로시져는 어떤 애플리케이션의
문맥(context)중에서 호출될수있다. 그래서 프로시져는 반드시 분리된 DLL
모듈안에 있어야 한다. 한 스레드 후크 프로시져는 오직 연관된 스레드의
문맥안에 호출된다. 만일 애플리케이션이 그 자신의 스레드들의 하나에
대해서 후크 프로시져를 설치한다면, 후크 프로시져는 애플리케이션의 여분 코드
로써 같은 모듈안에 있거나 DLL 안에 둘중 하나에 있을수 있다. 만일
애플리케이션이 다른 애플리케이션의 스레드를 위해서 후크프로시져를
설치하려면, 그 프로시져는 반드시 DLL안에 있어야 한다. 자세한 내용은
DLL 부분을 참조 하라.

전역적 후크는 오직 디버깅을 목적으로 써라. 아니라면 사용하지 말아라.
전역적 후크는 시스템의 성능을 저하시키며, 다른 애플리케이션이 같은
타입의 전역 후크를 사용한다면 충돌을 일으킬수 있다.

Hook Types
각 후크 타입들은 애플리케이션이 시스템 메세지 핸들링 메커니즘에서
감시할수 있는 것들이다.

WH_CALLWNDPROC and WH_CALLWNDPROCRET Hooks
WH_CALLWNDPROC과 WH_CALLWNDPRORET 후크는 SendMessage함수를 이용해
윈도우로 보낸 메세지를 감시할수 있게 한다. 시스템은 WH_CALLWNDPROC후크
프로시져를 목적지 윈도우 프로시져로 전달되기 전에 호출한다. 그리고
윈도우 프로시져가 메세지를 처리한 후 시스템은 WH_CALLWNDPROCRET 후크
프로시져를 호출한다.

WH_CALLWNDPROCRET 후크는 CWPRETSTRUCT구조체의 주소를 건내주는데
이는 메세지를 처리하려는 윈도우로 부터 반환된 값과 그 메세지와
연관된 메세지 인자들도 갖고 있다. 서브클래싱된 윈도우는 메세지 집합
처리안에서 작동하지 않는다.
CallWndProc과 CallWndRetProc함수를 참조

WH_CBT Hook
시스템은 WH_CBT후크 프로시져를 윈도우가 활성화,생성,파괴,최소화,
최대화,이동,크기변경을 하기 전에 호출한다. 즉 시스템명령이 완성되기
전, 시스템 메세지 큐에서 마우스나 키보드 이벤트를 지우기 전 ,
인풋포커스를 세팅하기 전, 시스템 메세지큐를 동기화하기 전.
후크 프로시져에서 반환하는 값은 시스템이 그들 명령들을 허락하거나
금지하는가를 결정하게 된다. WH_CBT후크는 컴퓨터 기반 트레이닝
(Computer-Based Traning) 애플리케이션에서 주요 쓰인다.
CBTProc 함수를 참조


WH_DEBUG Hook
시스템은 어떤 다른 후크와 연관되어 후크 프로시져가 호출되기 전에
WH_DEBUG 후크 프로시져를 호출한다. 개발자는 시스템이 다른 타입의
후크와 연관된 후크 프로시져를 호출할것 인지를 결정할 수 있다.
DebugProc 함수를 참조

WH_FOREGROUNDIDLE Hook
이 후크는 개발자가 백그라운드 스레드가 아이들 상태 시간에 있을때
낮은 수행권한으로 후크 프로시져가 수행되게 할 수 있다.
ForegroundIdleProc 함수를 참조

WH_GETMESSAGE Hook
이 후크는 애플리케이션이 GetMessage나 PeekMessage를 통해 돌려지는
메세지를 감시할 수 있게 해준다. 개발자는 WH_GETMESSAGE 후크를
씀으로써 마우스나 키보드 입력이나 메세지큐로 들어온 다른
메세지들을 감시할수 있다.
GetMsgProc 함수를 참조

WH_JOURNALPLAYBACK Hook
이 후크는 애플리케이션이 시스템 메세지 큐로 메세지를 추가시킬수
있게 한다. 개발자는 이 후크를 이용해 마우스나 키보드 이벤트같은것이
이전에 레코드된것(녹화한것)을 플레이시킬수 있다. 일반적인 마우스나
키보드 입력은 WH_JOURNALPLAYBACK 후크가 설치된 동안에서는 불가능하다.
WH_JOURNALPLAYBACK 후크는 전역적인 후크이다.  어떤 특정  스레드에
대한 후크를 쓸수 없다.
WH_JOURNALPLAYBACK 후크는 타임아웃 값을 반환한다. 이값은 시스템이
플레이백 후크로 부터 현재 메세지가 처리되기 전까지 얼마나 많은
밀리초를 기다렸는가를 나타내는다.
JournalPlaybackProc 함수를 참조

WH_JOURNALRECORD Hook
이 후크는 개발자가 입력된 이벤트들을 녹화(레코드)하거나 감시할수
있게 한다. 일반적으로 개발자는 이 후크를 이용해 일련의 마우스나
키보드 이벤트를 녹화한 후에 WH_JOURNALPLAYBACK 후크를 통해
플레이할수 있다.  이 후크는 전역 후크로 - 특정 스레드에
대한 후크로 사용할수 없다.
JournalRecordProc 함수를 참조

WH_KEYBOARD Hook
이 후크는 애플리케이션이 GetMessage나 PeekMeesage로 얻어진
WM_KEYDOWN과 WM_KEYUP메세지들을 감시할수 있게 한다. 개발자는
WH_KEYBOARD릴 이용해 메세지큐로 보내진(posted) 키보드
입력을 감시 할수 있다.
KeyboardProc 함수를 참조

WH_KEYBOARD_LL Hook [ 윈NT 4.0 서비스팩 3에 의해 갱신됨 ]
이 후크는 개발자가 스레드 입력 큐안으로 들어온(posted) 키보드
입력 이벤트를 감시할수 있다.
LowLevelKeyboardProc 함수를 참조

WH_MOUSE Hook
이 후크는 개발자가 GetMessage나 PeekMessage로 들어온 마우스
메세지를 감시할수 있다. 개발자는 WH_MOUSE를 이용해 메세지 큐로
전달된(Posted) 마우스 입력을 감시할수 있다.
MouseProc함수를 참조

WH_MOUSE_LL Hook [ 윈NT 4.0 서비스팩 3에 의해 갱신됨 ]
이 후크는 개발자가 스레드 입력 큐안으로 전달된(posted)것들중
마우스 입력 이벤트를
감시할수 있게 한다.
LowLevelMouseProc함수를 참조

WH_MSGFILTER and WH_SYSMSGFILTER Hooks

이 후크들은 개발자가 메뉴,스크롤바, 메세지 박스, 다이얼로그
박스에 의해 처리되는 메세지들을 감시할수 있고 언제 다른 윈도우가
사용자에 의해 Alt+Tab이나 Alt+Esc키조합을 누름으로써 활성화 되는지를
탐지 할수 있다. 이 후크는 오직 메뉴,스크롤바,메세지박스,대화상자로
넘겨지는 메세지를 감시할수 있다. 이런 것들은 후크 프로시져를 설치한
애플리케이션에 의해 생성된 것들이어야 한다. WH_SYSMSGFILTER 후크는
모든 애플리케이션에 대해 그런 메세지들을 감시한다.

WH_MSGFILTER와 WH_SYSMSGFILTER후크들은 개발자가 메인 메세지루프안의
필터링을 끝낸 모달루프의 메세지 필터링을 형성할수 있게 한다. 예를 들어
종종 큐로 부터 메세지를 받을때나 메세지를 특별한 처리를 위해 메세지를
발송할때, 애플리케이션은 메인 루프안에서 새로운 메세지가 도착했는지
검사하게 된다. 그러나 모달루프 안에서는 애플리케이션이 메인메세지 루프에서
그 메세지를 필터링(변환,Filter)하기 위한 기회를 주지 않고 시스템이 곧바로
메세지를 회수하고 발송하게 된다. 만일 애플리케이션이 WH_MSGFILTER또는
WH_SYSMSGFILTER 후크 프로시져를 설치한다면, 시스템은 모달 루프 동안 그
프로시져를 호출하게 된다.

애플리케이션은 WH_MSGFILTER 후크를 직접 호출할수 있는데 이는
CallMsgFilter 함수로 가능하다. 이 함수를 사용함으로써, 애플리케이션은
같은 코드로 모달루프안에서 메세지를 메인 루프에서 쓰듯이 같은 코드로
필터링할수 있게 된다. 이렇게 하기 위해서, WH_MSGFILTER 후크 프로시져안에서
필터링 명령들을 GetMessage와 DispathMessage 함수 호출로 캡슐화해야 한다.

while ( GetMessage(&msg, (HWND)NULL,0, 0))
{
      if( !CallMsgFilter(&qmsg, 0 ))
        DispatchMessage(&qmsg);
}

CallMsgFilter의 마지막 인자가 간단히 후크 프로시져를 통해 넘어오는데,
개발자는  어떤 값이든 들여 보낼수 있다. MSGF_MAINLOOP같은 정의된
상수를 씀으로써 이 값은 프로시져가 어디서 호출이 되었는가를
결정할수 있게 사용될수 있다.

자세한 정보는 MessageProc과 SysMsgProc 함수를 참조하라.


WH_SHELL Hook
쉘애플리케이션은 WH_SHELL 후크를 사용함으로써 중요한
통지(notification)을 얻을 수 있다.  쉘 애플리케이션이 활성화
되어있고 최상위 레벨 윈도우가 생성되고 파괴될때 시스템은
WH_SHELL 후크 프로시져를 호출한다.

자세한 정보는 ShellProc함수를 참조하라

 
Using Hooks

Installing and Releasing Hook Procedures
개발자는 SetWindowsHookEx함수를 호출해 특정 타입의 후크
프로시져를 설치할수 있다. 프로시져가 모든 스레드에 연관되었거나
특정 스레드에 연관될수 있으며 프로시져 엔트리 포인터를 포인터와
연관될수 있다.

개발자는 애플리케이션과 분리된 DLL안의 전역 후크 프로시져를
설치 할수 있다. 프로시져가 설치하려는 애플리케이션은 후크
프로시져가 설치되기전에 DLL 모듈을 핸들링 해야 한다. LoadLibrary
함수를 이용해 DLL의 이름을 주면 DLL 모듈의 핸들러를 반환받을수 있다.
개발자가 핸들을 얻게 되면 개발자는 GetProcAddress 함수를 이용해
후크 프로시져의 주소를 반환받을수 있다. 마지막으로 개발자는
SetWindowsHookEx 함수를 이용해 후크 프로시져를 후크 체인에 설치
할수 있다. SetWindowsHookEx는 모듈 핸들을 거쳐 후크 프로시져
엔트리 포인트를 가리키게 되며 스레드 지정자로 0을 쓰면
( thread identifier) 후크 프로시져가 시스템안의 모든 스레드와
연관되었다고 하는것이다.
이 절차는 아래와 같은 예로 보여진다.

HOOKPROC hkprcSysMsg;
static HINSTANCE hinstDLL;
static HHOOK hhookSysMsg;

hinstDLL = LoadLibrary((LPCSTR)"c:\\windows\\sysmsg.dll");
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");
hhookSysMsg = SetWindowsHookEx(WH_SYSMSGFILTER, hkprcSysMsg,hinstDLL, 0);

개발자는 후크 체인안의 후크 프로시져를 UnhookWindowsHookEx함수를 호출함으로써
해체시킬수 있다. 이때 해체할 특정 후크 프로시져가 필요하다. 애플리케이션이
더이상 후크 프로시져가 필요없다면 곧바로 후크 프로시져를 해체하라.


You can release a global hook procedure by using UnhookWindowsHookEx,
but this function does not free the DLL containing the hook procedure.
This is because global hook procedures are called in the process
context of every application in the system, causing an implicit call
to the LoadLibrary function for all of those processes. Because a
call to the FreeLibrary function cannot be made for another process,
there is then no way to free the DLL. The system eventually
frees the DLL after all processes explicitly linked to the DLL
have either terminated or called FreeLibrary and all processes
that called the hook procedure have resumed processing outside the DLL.

개발자는 UnhookWindowsHookEx를 통해 전역 후크 프로시져를
해체할수 있다. 그러나 이 함수는 후크 프로시져를 포함한 DLL을
해체하진 않는다.  그런 프로세스들의 모두는 명시적으로 LoadLibrary
함수를 호출하여 사용하여 전역 후크 프로시져가 시스템안에서 매
애플리케이션의 프로세스 문맥안에서 호출되기 때문이다.  
때문에 FreeLibrary 함수는 다른 프로세스에서 사용 불가능하다.
그렇다면 DLL을 해체하는 방법은 없다. 명시적으로 연결된 DLL이
파괴되었는지 또는 FreeLibrary가 호출되었는지 또는 모든 후크
프로시져로 불리는 프로세스가 DLL 밖에서 처리를
재개한 후에 시스템은 간간히(Eventually) DLL을 해체한다.

전역 후크 프로시져를 설치하는 대처적인 방법으로는 DLL안의 설치
함수같은것을 제공하는 것이다. 이 방법을 통해 설치된 애플리케이션은
DLL모듈을 핸들링 할 필요가 없다.
DLL과 함꼐 연결된 애플리케이션은 설치 함수들을 접근할수 있다.
설치 함수는 DLL 모듈 핸들과 다른 SetWindowsHookEx를 호출하에
상세한 정보를 제공할수 있다.
DLL은 또한 전역 후크 프로시져를 해체하는 특정 함수를 포함할수
있다. 애플리케이션은 파괴될때 이 후크 해체 함수를 호출할수 있다.

[출처] hook 설명|작성자 박호진

AND