Microsoft에서는 프로세스간의 주고 받는 메세지를 후킹할 수 있는 함수를 제공한다.
바 로 SetWindowsHookEx()함수이다. 이 함수를 통해 DLL을 특정 프로세스나 모든 프로세스에 Injection할 수 있다.그리고 User-mode(ring 3)에서 동작하는 Keylogger들 대부분이 이 함수를 사용하여 구현된다.(SetWindowsHookEx()함수를 통해 후킹(Hooking)을 할 경우 전역 후킹이 간단하므로 많이 사용한다.)
먼저 SetWindowsHookEx()함수의 원형부터 알아보자.
(MSDN에 있는 내용이다.)
HHOOK SetWindowsHookEx(
int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId
);
첫번째 파라메터인 idHook 변수는 후킹 하고자 하는 메세지의 ID라고 할 수 있다. WH_GETMESSAGE, WH_KEYBOARD 등 다양한 메세지가 있다.(MSDN 참조)
idHook 파라메터에 지정된 값의 이벤트(메세지)가 발생할 경우 훅 프로시저(lpfb 파라메터에 설정된)가 동작하게 된다. 훅 프로시저는 Injection할 DLL(앞으로 Injected.dll이라 부르겠다)에 지정되어 있어야한다.
/* Injected.dll */
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
/* 원하는 코드 삽입 */
return CallNextHookEx(0, nCode, wParam, lParam);
};
마 지막에 CallNextHookEx()함수를 호출한 이유는 훅 체인에 있는 다른 훅 프로시저가 해당 메세지를 사용할 수도 있기때문이다. 예를들면 키보드메세지를 후킹하여 Keylogger를 만들었다고 하면 해당 메세지를 후킹 후 로깅을 하고 CallNextHookEx()함수를 통해 처리를 하지 않고 그냥 끝내 버린다면 들통나버릴것이다.
두번째 파라메터는 lpfn이다. 이 파라메터에는 Injected.dll에 지정된 훅 프로시저의 주소값을 지정한다.만약 IdHook에 WH_KEYBOARD를 지정하여 후킹 할경우 해당 훅 프로시저는 KeyboardProc이다. 주소 값을 지정해줘야하는데 하드코딩하여 지정해 줄 수 있지만 LoadLibrary()함수와 GetProcAddress를 이용하여 Injected.dll의 훅 프로시저의 주소를 구할 수 있다.
/* Injector.c */
HMODULE hDll;
unsigned long KeyboardProcAddr;
hDll = LoadLibrary("injected.dll");
KeyboardProcAddr = GetProcAddress(hDll, "KeyboardProc");
다음으로 세번째 파라메터인 hMod를 보자. hMod는 DLL의 핸들(Handle)을 지정해야한다.여기에선 Injected.dll의 핸들을 지정해주면 된다.
이미 Injector.c에서 LoadLibrary("Injected.dll"); 통해 핸들을 얻었으므로 hDll변수를 사용하면 된다.
네 번째 파라메터 dwThreadId는 후킹할 프로세스 즉 Injected.dll을 삽입할 스레드(Thread)의 ID이다. PID라고 하며 해당 파라메터에 0을 지정하면 모든 스레드에 훅(Hook)을 한다는 의미로 전역 훅을 할 수 있다. 특정 스레드에 Injection을 하려고 한다면 "작업관리자"를 통해 PID를 얻어 하드코딩하거나 아래와 같은 방법으로 PID를 얻어 사용할 수 있다.
/* 전역 훅 */
SetWindowsHookEx(WH_KEYBOARD, KeyboardProcAddr, hDll, 0)
/* 지역 훅*/
SetWindowsHookEx(WH_KEYBOARD, KeyboardProcAddr, hDll, GetCurrentThreadID());
dwThreadId 값을 얻기 위한 함수는 많다.