앙 귬귬띠 

 

 

DLL 인젝션

- 훅(Hook) 이란 ?

중간에서 오고가는 정보를 엿보거나 가로채기 위해 초소를 설치함. (갈고리를 건다)

이중에서 메세지 훅에 대해서 알아봅시다.

 

- 메세지 훅 ?

Window는 GUI를 제공하고 Event Driven으로 동작한다고 핟나. 키보드/마우스 등 어떠한 행위를 할 때 이벤트가 발생하고 Window는 미리 정의된 메세지를 해당 응용 프로그램으로 통보합니다. 아래 그림을 살펴봅시다.

 

https://yokang90.tistory.com/58

만약에 키보드에 입력 이벤트가 발생하면 WM_KEYDOWN 메세지가 OS queue에 추가됩니다. OS는 어느 응용 프로그램에서 이벤트가 발생한지 확인 후에 큐에서 꺼내서 Application message queue에 추가합니다. 응용 프로그램(메모장)은 자신의 app 큐를 모니터링 하다가 WM_KEYDOWN 메세지를 확인한 다음에 해당 event handler를 호출하게 됩니다.

 

위 그림과 같이 훅이 설치되어있으면 OS와 APP 큐 사잉 ㅔ설치된 훅체인을 통해 키보드 메세지 훅들을 응용 프로그램보다 먼저볼 수 있습니다. 

-> 저부분에서 가로채는것 뿐만 아니라 메세지 자체의 변경도 가능하며, 아래로 안내려 보낼수도 있다!

 

메세지 훅같은 경우에는 SetWindowsHookEx() API를 사용하면 간단하게 구현할 수 있다고 합니다.

HHOOK SetWindowsHookExA(
  int       idHook,		// hook type
  HOOKPROC  lpfn,		// hook procedure
  HINSTANCE hmod,		// 프로시저가 속해있는 DLL 핸들
  DWORD     dwThreadId		// hook을 걸고 싶은 thread ID
);

msdn - api 정의

훅 프로시저는 OS가 호출해주는 콜백 함수이며 훅을 걸때 DLL 내부에 존재해야 한다.

4번째 변수 dwThreadID를 0으로 줄경우 전역(Global) 훅이 설치되며 실행중인 모든 프로세스에 영향이 간다.

 

키보드 메세지 후킹 실습

- chrome.exe 프로세스의 키보드 메세지를 가로채서 입력을 받지 못하도록 하는 실습

HookMain.exe
0.04MB
KeyHook.dll
0.03MB

HookMain.exe를 실행하면 다음과 같은 창이 뜬다.

후킹중

이 상태로 chrome.exe를 실행하여 키보드 입력을 해봅니다.

-> 되지 않음

 

Keyhook.dll 인젝션 되어있는 모습
PID 매칭됌

chrome.exe의 메모리에 keyhook.dll이 인젝션 된것이 보인다. 키보드 이벤트 발생시 chrome.exe는 아무것도 받지 못하기 때문에 검색창에 입력이 되지않는다.

 

Hookmain.exe 디버깅

EP에서 시작!

먼저 우리가 봤었던 press 'q'를 찾아봅시다. (문자열 검색기능 이용)

찾음

40104D에서 찾을 수 있습니다. 여기가 main()의 안이겠죠 ?

 

main()

 

401000에 BP를 설치한 후에 디버깅을 위부터 차례대로 시작합니다.

401006의 주소에서 Loadlibrary("keyhook.dll")을 호출합니다.

이후에 40104B의 call ebx에서 keyhook.hookstart() 함수가 호출됨을 알 수 있습니다.

call 안으로 들어가봅시다.

지금 보이는 그림은 HookMain.exe 프로세스에 로딩된 Keyhook.dll의 HookStart() 함수 입니다. 여기서 SetWindowsHookEx의 첫 번째와 두 번째 인자값들을 알 수 있습니다.

 

먼저 API의 첫 번째 파라미터 값은 WH_KEYBOARD(2)입니다. 두 번째 파라미터(lpfn)의 값은 10001020 이며, 이 값이 바로 훅 프로시저의 주소라고 합니다. main()의 나머지 부분들은 'q'를 입력시 종료받는 부분입니다. (디버깅해보기)

 

이제 notepad.exe를 실행 시킨다음에 HookMain.exe를 실행시키고 키보드 입력을 받습니다.

(디버그 dll 로드 on)

다음과 같이 10000000의 주소에 keyhook.dll이 로드되는 걸 볼 수 있습니다. 해당 EP로 가봅시다.

아까 봤던 훅 프로시저의 주소 (10001020)에 BP를 걸면 키보드 입력 이벤트가 발생할 때마다 이곳에서 멈춰집니다.

Hookmain.cpp과 keyhook.cpp 소스코드를 첨부합니다.

출처 - reversecore

HookMain.cpp
0.00MB
KeyHook.cpp
0.00MB

// HookMain.cpp	출처 - reversecore

/dll 로더
#include "stdio.h"
#include "conio.h"
#include "windows.h"
 
#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 = LoadLibrary("KeyHook.dll");
 
    // HookStrat, HookStop 함수의 주소를 얻어온다.
    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);
}
//keyhook.cpp

#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

'Reversing' 카테고리의 다른 글

DLL 인젝션  (2) 2019.04.12
리버싱 9  (0) 2019.04.10
리버싱 8  (0) 2019.04.09
리버싱 7  (0) 2019.04.05
리버싱 6  (2) 2019.04.04

+ Recent posts