2016. 2. 3. 09:28

21. Windows Message Hooking

21.1. Hook

Hook(갈고리)는 원하는 것을 낚아채고 싶을 때 사용하는 도구이다. 컴퓨터 분야에서는 정보를 엿보거나 가로채는 경우에 사용되는 단어로 확장되어 사용된다. Hook을 하는 행위를 ‘후킹한다(Hooking)’라고 표현하는데 이는 중간에서 오고가는 정보를 엿보거나 가로채기 위한 일을 하거나 정보를 조작하는 행위를 의미한다. 실제로 ‘OS-Application-User’ 사이의 정보를 모두 조작 가능하다. 가장 기본적인 방식의 후킹은 Message Hook이다.


21.2. Message Hook

Windows 운영체제는 GUI를 제공하고, 이는 Event Driven1 방식으로 동작한다. 이벤트가 발생할 때 OS는 미리 정의된 메시지를 해당 응용프로그램으로 보낸다.

Created with Raphaël 2.1.2이벤트정의된 메시지응용프로그램

일반적인 경우의 Windows 메시지 흐름

Created with Raphaël 2.1.2키보드키보드OS message queueOS message queueApplication message queueApplication message queueWM_KEYDOWNmonitoringWM_KEYDOWNHook ChainEvent Handler 호출

Hook Chain의 키보드 메시지 훅들은 해당 메시지 열람 및 변조가 가능하다. Hook Chain은 동시에 여러개 설치가 가능하며, 설치 순서대로 호출된다. 이러한 특성때문에 Hook Chain이라고 불린다.


21.3. SetWindowsHookEx()

메시지 훅은 SetWindowsHookEx() 함수를 통해 간단히 구현할 수 있다.

//SetWindowsHookEx() API
HHOOK SetWindowsHookEx(
    int idHook,          // hook type
    HOOKPROC lpfn,       // hook procedure : 운영체제가 호출해주는 콜백함수
    HINSTANCE hMod ,     // 위 hook procedure가 속해있는 DLL 핸들
    DWORD dwThreadld     // Hook을 걸고 싶은 thread의 ID. 0을 주고 호출하면 글로벌 훅
);

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

enter image description here

  1. HookMain.exe는 KeyHook.dll을 최초로 로딩하여 키보드 훅을 설치하는 프로그램
  2. KeyHook.dll은 훅 프로시저가 존재하는 DLL 파일
  3. SetWindowssHookEx()를 이용하여 키보드 훅 설치
  4. 다른 프로세스에서 키 입력 이벤트가 발생하면 OS 에서 해당 프로세스의 메모리 공간에 KeyHook.dll을 강제로 로딩
  5. KeyboardProc() 함수가 호출됨

21.4.1. 실습 예제

21.4.2. 소스코드 분석

HookMain.cpp

#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 = LoadLibraryA(DEF_DLL_NAME);

    //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);
}

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 = key press, 1 = key release
        if( !(lParam & 0x80000000) )  // 키보드가 눌렀다 떨어질 때
        {  
            GetModuleFileNameA(NULL, szPath, MAX_PATH);
            p = strrchr(szPath, '\\');

            // 현재 프로세스 이름을 비교해서 만약 notepad.exe. 라면,
            // 메시지는 응용 프로그램(혹은 다음 훅)으로 전달되지 않음
            if( !_stricmp(p+1, DEP_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

21.5. Debugging

21.5.1. ‘HookMain.exe’ 디버깅

  • “press ‘q’ to quit!” 문자열을 참조한 코드를 찾음 으로써 main 함수 찾는다.
  • main 함수에 breakpoint를 걸어 HookStart()가 실행될 때 까지 디버깅
  • HookStart() 해당 주소의 CALL EAX 를 따라가서 KeyHook.dll의 함수임을 확인
  • HookStart에서 사용되는 SetWindowsHookExW() 함수 및 파라미터 확인

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

  • OllyDbg의 옵션(‘Break on new module(DLL)’을 Check 상태로 변경함으로써 새로운 DLL이 로딩될 때마다 자동으로 디버깅을 멈출 수 있다.
  • 이 상태에서 HookMain.exe를 실행하고 notepad.exe 에서 키보드를 입력하면 OllyDbg가 멈추면서 ‘Executable modules’ 창이 뜬다.
  • 여기서 KeyHook.dll이 로딩된 것을 확인할 수 있다.

22. 악의적인 목적으로 사용되는 키로거

관리 차원에서 (사용자 동의하에) 사용되는 키로거는 나쁘다고 할 수 없을 것이다. 하지만 악의적인 목적으로 사용자 몰래 실행되는 키로거는 문제가 된다.

22.1. 악성 키로거의 목표 및 사례

  • 목표 : 돈
  • 사례
    • 온라인 게임
    • 인터넷 뱅킹
    • 기업 정보 유출

22.2. 키로거의 종류와 향후 발전 방향

키보드 끝에 연결되어 키보드의 입력이 PC로 전달되는 과정에서 가로챈다. 내부에 flash memory를 내장하고 있어 키보드로부터 들어오는 전기 신호를 직접 입력받아 저장하는 장치이다.

22.3. 키로거에 대처하는 우리의 자세

  • 공공장소에서는 개인정보 입력 X
  • 보안 프로그램 업데이트
  • 개인정보 복붙으로 입력
  • 개인 방화벽 사용

22.4. 개인정보

비밀번호 어렵게 하자


  1. 이벤트에 반응하여 동작을 변경하는 방식

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

Reverse Engineering Chap 46  (0) 2016.02.03
Reverse Engineering Chap 50-51  (0) 2016.02.03
Reverse Engineering Chap 45  (0) 2016.01.30
Reverse Engineering Chap 34  (0) 2016.01.27
Reverse Engineering Chap 3-6  (0) 2016.01.27
Posted by 덜키