키보드 메시지 후킹 실습
그렇다면 간단한 키보드 후킹을 해보자. 아래 그림을 보자
KeyHook.dll 파일은 훅 프로시저(KeyboardProc)가 존재하는 DLL 파일이다. 그리고 HookMain.exe는 KeyHook.dll을 최초로 로딩하여 키보드 훅을 설치하는 프로그램이다. HookMain.exe에서 KeyHook.dll 파일을 로딩한 후 SetWindowsHooEX()를 이용하여 키보드 훅(KeyboardProc)을 설치한다. 만약 다른 프로세스(explorer.exe, iexplore.exe, notepad.exe등)에서 키 입력 이벤트가 발생하면 OS에서 해당 프로세스의 메모리 공간에 KeyHook.dll을 강제로 로딩하고 KeyboardProc 함수가 호출된다.
여기서 중요한 점은 키 입력 이벤트가 발생한 프로세스에서 OS가 KeyHook.dll을 강제로 로딩시켜 준다는 점이다. 즉 메시지 후킹 기법은 DLL 인젝션 기법의 하나로 사용된다.
실습예제 HookMain.exe
실습 예제 파일을 가지고 키보드 후킹 실습을 해보자. Notepad.exe 프로세스으 ㅣ키보드 메시지를 가로채서 입력을 받지 못하도록 하는 간단한 실습이다.
1.HookMain.exe 실행- 키보드 훅 설치
Notepad.exe 실행
현재 시스템에 키보드 훅이 설치된 상태이다. notepad.exe를 실행하여 키보드를 입력하면 키보드 입력을 무시한다.
Process Exploere에서 KeyHook.dll이 인젝션된 프로세스를 검색해보았다. 다른 프로그램을 실행하고 키보드 이벤트를 발생하면 저절로 KeyHook.dll이 인젝션 되는 것을 확인 할 수 있다. 다른 프로세스에서 키보드 이벤트가 정상적으로 동작한다.
참고로 HookMain.exe를 종료하면 정상적으로 키보드가 입력된다.
그리고 Process Explorer로 Keyhook.dll을 검색해보면 아무것도 로딩하지 않고 있다.
2.소스 코드 분석
먼저 HookMain.exe 파일의 소스코드(HookMain.cpp)이다.
} #define DEF_DLL_NAME "KeyHook.dll" typedef void (*PFN_HOOKSTART)(); void main() // KeyHook.dll 로딩 // export 함수 주소 얻기 // 후킹 시작 // 사용자가 'q' 를 입력할 때까지 대기 // 후킹 종료 |
소스코드는 매우 간단하다. KeyHook.dll 파일을 로딩해서 HookStart() 함수를 호출하면 후킹이 시작되고, HookStop() 함수를 호출하면 후킹이 종료된다. 주석을 참고하면 이해하는데 어려움이 없을 것으로 생각된다.
KeyHook.cpp
그럼 이번에 KeyHook.dll 파일의 소스코드를 살펴보자.
#include "stdio.h" #define DEF_PROCESS_NAME "notepad.exe" HINSTANCE g_hInstance = NULL; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved) case DLL_PROCESS_DETACH: return TRUE; LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) if( nCode >= 0 ) // 현재 프로세스 이름을 비교해서 만약 notepad.exe 라면 0 아닌 값을 리턴함 // 일반적인 경우에는 CallNextHookEx() 를 호출하여 #ifdef __cplusplus __declspec(dllexport) void HookStop() |
DLL 소스코드 역시 간단하다. 익스포트 함수인 HookStart() 함수가 호출되면 SetWindowsHookEx()에 의해서 키보드 훅 체인에 KeyboardProc()이 추가된다.
키보드 훅이 설치된 상황에서 어떤 프로세스에서 키 입력 이벤트가 발생하면 OS는 해당 프로세스에게 강제로 KeyHook.dll을 인젝션한다. 이제 KeyHook.dll을 로딩한 프로세스에서 키보드 이벤트가 발생하면 KeyHook.KeyboardProc()이 먼저 호출된다.
KeyboardProc() 함수의 내용을 보면 키보드 입력이 발생했을 떄 현재 프로세스 이름과 "notepad.exe" 문자열과 비교하여 만약 같다면 1을 리턴해서 KeyboardProc() 함수를 종료시킨다. 이것은 메시지를 가초래서 없애버린것이다. 결국 키보드 메시지는 notepad.exe 프로그램의 메시지 큐에 전달되지 않는다.
즉 notepad.exe는 아무런 키보드 메시지를 받지 못하므로 아무것도 출력되지 않는다.
그 외의 경우에는 return CallNextHookEX(g_hHook, bCode,wParam,Iparam); 명령을 실행하면 메시지는 다른 응용 프로그램 혹은 훅 체인의 또 다른 훅 함수로 전달된다.
참고로 사용자의 키보드 입력을 감시/기록하는 프로그램을 키 로거(Key Logger)라고 한다. PC 악성코드중에서 키보드 메시지를 후킹하여 PC 사용자 몰래 키보드 입력을 빼돌리기도 한다.