본문 바로가기

공부/리버싱 핵심원리

Windows 메시지 후킹

1. 훅

Hook, 갈고리

 

(군사적으로 사용되는) 훅의 개념

"훅(hook)을 건다/설치한다 " or "후킹(hooking)한다"

→ 중간에 오고가는 정보를 엿보거나 가로채기 위해 검문/검색을 하는 "초소"를 설치한다.


2. 메시지 훅

Windows 운영 체제 (GUI 기반): Event Driven 방식

      ① 이벤트 발생 (ex. 키 보드 입력 이벤트)

           → WM_KEYDOWN 메시지가 OS message queue에 추가된다.

      ② OS는 이벤트가 발생한 응용 프로그램을 파악하고,

         OS message queue에서 메시지를 읽어와서

         해당 응용 프로그램의 message queue에 추가한다.

      ③ 응용 프로그램은 message queue에서 메시지를 읽어와서

          해당 이벤트에 대응되는 event handler를 호출하여 이벤트를 처리한다. 


3. SetWindowsHookEx()

an application-defined hook procedure 을 훅 체인에 추가

 

parameters:

       ① idHook: 추가하려는 hook procedure (Ipfn)의 hook type

              ✓ 예: WH_KEYBOARD

       ② Ipfn: hook procedur의 함수 포인터

       ③ hMod: hook procedur가 정의된 DLL의 handler

       ④ dwThreadld: hook procedur에 연결 시키려는 thread (응용프로그램).

           이 값이 0이면, 실행되고 있는 모든 thread (용용프로그램)에 연결된다.

 

HHOOK WINAPI SetWindowsHookEx( _In_ int _In_ HOOKPROC Ipfn, _In_ HINSTANCE hMod, _In_ DWORD dwThreadld idHook, ·

 

사용 예: SetWindowsHookEx(WH_ KEYBOARD, keyHook, pDLLhandler, 0)

→ pDLLHandler가 가르키는 DLL에 정의된 keyHook을 통하여 동작하고 있는 모든 어플리케이션의 키보드 메시지를 후킹하도록 설정한다 (즉, 훅 체인에 등록한다)


4. 키보드 메시지 후킹 실습

실습 시나리오

① 키 보드 메시지 후킹을 위하여 KeyHook.dll과 HookMain.cpp를 작성한다.

KeyHook.dll

#include "stdio.h"
#include "windows.h"

#define DEF_PROCESS_NAME		"notepad.exe"

HINSTANCE g_hInstance = NULL;
HHOOK g_hHook = NULL;
HWND g_hWnd = NULL;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
	switch( dwReason )
	{
        case DLL_PROCESS_ATTACH:
			g_hInstance = hinstDLL;
			break;

        case DLL_PROCESS_DETACH:
			break;	
	}

	return TRUE;
}

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	char szPath[MAX_PATH] = {0,};
	char *p = NULL;

	if( nCode >= 0 )
	{
		// bit 31 : 0 => press, 1 => release
		if( !(lParam & 0x80000000) )
		{
			GetModuleFileNameA(NULL, szPath, MAX_PATH);
			p = strrchr(szPath, '\\');

            // 현재 프로세스 이름을 비교해서 만약 notepad.exe 라면 0 아닌 값을 리턴함
            // => 0 아닌 값을 리턴하면 메시지는 다음으로 전달되지 않음
			if( !_stricmp(p + 1, DEF_PROCESS_NAME) )
				return 1;
		}
	}

    // 일반적인 경우에는 CallNextHookEx() 를 호출하여
    //   응용프로그램 (혹은 다음 훅) 으로 메시지를 전달함
	return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

#ifdef __cplusplus
extern "C" {
#endif
	__declspec(dllexport) void HookStart()
	{
		g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
	}

	__declspec(dllexport) void HookStop()
	{
		if( g_hHook )
		{
			UnhookWindowsHookEx(g_hHook);
			g_hHook = NULL;
		}
	}
#ifdef __cplusplus
}
#endif

 

HookMain.cpp

#define	DEF_DLL_NAME		"KeyHook.dll"
#define	DEF_HOOKSTART		"HookStart"
#define	DEF_HOOKSTOP		"HookStop"

typedef void (*PFN_HOOKSTART)();
typedef void (*PFN_HOOKSTOP)();

void main()
{
	HMODULE			hDll = NULL;
	PFN_HOOKSTART	HookStart = NULL;
	PFN_HOOKSTOP	HookStop = NULL;
	char			ch = 0;

    // KeyHook.dll 로딩
	hDll = LoadLibraryA(DEF_DLL_NAME);
    if( hDll == NULL )
    {
        printf("LoadLibrary(%s) failed!!! [%d]", DEF_DLL_NAME, GetLastError());
        return;
    }

    // export 함수 주소 얻기
	HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);
	HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);

    // 후킹 시작
	HookStart();

    // 사용자가 'q' 를 입력할 때까지 대기
	printf("press 'q' to quit!\n");
	while( _getch() != 'q' )	;

    // 후킹 종료
	HookStop();
	
    // KeyHook.dll 언로딩
	FreeLibrary(hDll);
}

 

② HookMain.exe를 실행한다.

        a. KeyHook.dll을 로딩한다.

        b. SetWindowsHookEx()함수를 이용하여 KeyboardProc()를 훅체인에 등록한다.

        c. OS는 실행 중인 응용 프로그램들에 KeyHook.dll을 인젝션한다.

③ 응용프로그램에서 키 보드 입력 이벤트가 발생한다.

KeyboardProc()가 해당 이벤트 메시지를 먼저 받아 처리한다


4.1 실습 예제: HookMain.exe

① HookMain.exe 실행

② notepad.exe 실행

→ 키 보드 입력

→ 노트패드의 프로세스 확인

keyhook.dll이 있다

HookMain.exe를 실행하면 키보드 입력 받는 프로그램들이 먹통이 된다.

App.이 notepad.exe 이면 프로시져(KeyboardProc)가 바로 리턴하여 App에게 이벤트를 전달하나, 그 외의 App이면 훅체인의 다음 프로시져를 콜하기 때문이다.


4.2 소스코드 분석: KeyHook.cpp (KeyHook.dll) 

다음과 같은 함수들로 구성된다.

DllMain

KeyboardProc

HookStart

HookStop


5.1 HookMain.exe 디버깅 - 문자열 검색

 

메인함수 분석

찾은 문자열 => HookStart()

 

HookStart() 함수 분석


5.2 Notepad.exe 프로세스 내의 KeyHook.dll 디버깅

1) OllyDbg 실행 -> 옵션 설정

2) HookMain.exe를 실행

3) notepad.exe에 키보드 입력

 

OllyDbg가 멈추면서 'Executable Modules' 창이 뜬다

KeyHook.dll

 

'공부 > 리버싱 핵심원리' 카테고리의 다른 글

DLL Injection&코드 인젝션  (0) 2024.05.22
DLL 인젝션  (0) 2024.05.21
인라인 패치 실습  (0) 2024.05.14
UPX 언패킹  (0) 2024.05.12
IAT 따라가기  (0) 2024.05.12