본문 바로가기
Reversing/리버싱 핵심 원리

[리버싱 핵심 원리] 21장, Windows 메시지 후킹

by Y06 2021. 11. 24.

훅이란, 우리말로는 갈고리, 낚시바늘 정도의 뜻을 가지고 있는데, 원하는 것을 낚아채고 싶을 때 사용하는 도구이다. 이 갈고리의 뜻이 확장되어서 정보를 엿보거나 가로채는 경우에도 훅이라는 말을 쓴다.

 

메시지 훅

Windows 운영체제는 GUI(Graphic User Interface)를 제공하고, 이는 Event Driven 방식으로 동작합니다. 키보드/마우스를 이용하여 메뉴 선택, 버튼 선택, 마우스 이동, 창 크기 변경, 창 위치 이동 등의 작업은 모두 이벤트(Event)입니다. 이런 이벤트가 발생할 때 OS는 미리 정의된 메시지를 해당 응용 프로그램으로 통보한다. 응용 프로그램은 해당 메시지를 분석하여 필요한 작업을 진행하는 것입니다. 즉, 키보드를 입력할 때에도 OS로부터 응용 프로그램으로 메시지가 이동합니다. 메시지 훅이란 바로 이런 메시지를 중간에서 엿보는 것이다.

메시지 후킹 동작 원리

[일반적인 경우의 Windows 메시지 흐름에 대한 설명]

- 키보드 입력 이벤트가 발생하면 WM_KEYDOWN 메시지가 [OS message queue]에 추가됩니다.

- OS는 어느 응용 프로그램에서 이벤트가 발생했는지 파악해서 [OS message queue]에서 메시지를 꺼내어 해당 응용 프로그램의 [application message queue]에 추가한다.

- 응용 프로그램(메모장)은 자신의 [application message queue]를 모니터링하고 있다가 WM_KEYDOWN 메시지가 추가된 걸 확인하고 해당 event handler를 호출한다.

 

그림에서와 같이 키보드 메시지 훅이 설치되었다면 OS 메시지 큐와 응용 프로그램 메시지 큐 사이에 설치된 훅 체인(Hook Chain)에 있는 키보드 메시지 훅들이 응용 프로그램보다 먼저 해당 메시지를 볼 수 있다. 키보드 메시지 훅 함수 내에서는 메시지를 단순히 엿보는 기능뿐만 아니라 메시지 자체의 변경도 가능하며 또한 메시지를 가로채서 아래로 내려보내지 않게 할 수도 있다.

 

이러한 메시지 훅 기능은 Windows 운영체제에서 제공하는 기본 기능이며, 대표적인 프로그램으로 MS Visual Studio에서 제공되는 SPY++가 있다. SPY++는 막강한 메시지 후킹 프로그램으로서 운영체제에서 오고가는 모든 메시지를 볼 수 있다.

 

SetWindowsHookEx()

[SetWindowsHookEx() API의 정의]

 

HHOOK SetWindowsHookEx {

int idHook,  hook 타입

HOOKPROC lfpfn,  hook 절차

HINSTANCE hMod,  hook 절차가 속해 있는 DLL 핸들

DWORD dwThreadId  hook 하고 싶은 thread ID

};

hook procedure는 운영체제가 호출해주는 콜백 함수이다. 메시지 훅을 걸 때 hook procedure는 DLL 내부에 존재해야 하며, 그 DLL의 인스턴스 핸들이 바로 hMod이다.

*dwThreadid 파라미터에 0을 주고 호출하면 글로벌 훅(Global Hook)이 설치되며, 실행 중인 모든 프로세스에 영향을 미친다.

실습

HookMain.exe는 윈도우 메시지 후깅을 위한 실행파일이다. HookMain.exe 프로그램을 실행하면 "press 'q' to quit!"라는 메시지가 나타난다. 키보드 후킹을 멈추고 싶으면 q를 입력하면 된다.

Notepad.exe 프로세스는 키보드의 입력을 무시한다. Process Explorer를 이용하여 notepad.exe 프로세스를 살펴보면, KeyHook.dll이 로딩되어 있는 것을 확인할 수 있다.

다른 프로그램을 실행하고 키보드 이벤트를 발생시키면 저절로 KeyHook.dll이 인젝션되는 것을 확인할 수 있습니다. 하지만, 실제로 키보드 이벤트를 무시하는 동작은 notepad.exe에서만 발생한다. 

소스코드

 

LoadLibraryA: DLL(KeyHook.dll)을 로딩하는 함수

- HookMain.exe 프로세스의 주소공간으로 지정된 모듈을 로딩함

- return : 모듈에 대한 handle

GetProcAddress(hDll, DEF_HOOKSTART):

hDll(KeyHook.dll)에서 export하는 함수인 DEF_HOOKSTART(HostStart)의 주소를 획득함

GetProcAddress(hDll, DEF_HOOKSTOP):
hDll(KeyHook.dll)
에서 export하는 함수인 DEF_HOOKSTOP(HostStop)의 주소를 획득함

 

소스코드는 매우 간단하다. KeyHook.dll 파일을 로딩해서 HookStart() 함수를 호출하면 후킹이 시작되고, HookStop() 함수를 호출하면 후킹이 종료된다.

 

KeyHook.dll에 정의된 모습