윈도우 환경에서 Python을 사용하여 키보드 후킹을 하는 방법 관련하여 좀더 쓰기 편하게 코드 정리를 하였다. 특수키를 확인하는 방법도 추가되었다.
소스
# -*- coding: utf-8 -*- #!/usr/bin/python import sys from ctypes import * from ctypes.wintypes import MSG from ctypes.wintypes import DWORD class KeyRogue: user32 = windll.user32 kernel32 = windll.kernel32 WH_KEYBOARD_LL = 13 WM_KEYDOWN = 0x0100 WM_SYSKEYDOWN = 0x0104 VK_CONTROL = 0x11 VK_MENU = 0x12 VK_SHIFT = 0x10 hooked = None hookProc = None pointer = None @staticmethod def installHookProc(hookProc): if KeyRogue.hooked is not None: print("already installed. uninstalling..") KeyRogue.uninstallHookProc() KeyRogue.hookProc = hookProc KeyRogue.pointer = KeyRogue.getFPTR(KeyRogue.hookProcInternal) KeyRogue.hooked = KeyRogue.user32.SetWindowsHookExA( KeyRogue.WH_KEYBOARD_LL, KeyRogue.pointer, KeyRogue.kernel32.GetModuleHandleW(None), 0 ) if not KeyRogue.hooked: return False return True @staticmethod def uninstallHookProc(): if KeyRogue.hooked is None: return KeyRogue.user32.UnhookWindowsHookEx(KeyRogue.hooked) KeyRogue.hooked = None @staticmethod def bytes(integer): return divmod(integer, 0x10000) @staticmethod def getFPTR(fn): CMPFUNC = CFUNCTYPE(c_int, c_int, c_int, POINTER(c_void_p)) return CMPFUNC(fn) @staticmethod def startKeyLog(): msg = MSG() KeyRogue.user32.GetMessageA(byref(msg), 0, 0, 0) @staticmethod def getKeyCode(lParam): high, low = KeyRogue.bytes(lParam[0]) return low @staticmethod def getKeyInfo(lParam): keyCode = KeyRogue.getKeyCode(lParam) return (keyCode, chr(keyCode)) @staticmethod def checkModifier(lParam, vKey): if KeyRogue.user32.GetAsyncKeyState(vKey) & 0x8000: return True return False @staticmethod def hookProcInternal(nCode, wParam, lParam): if wParam != KeyRogue.WM_KEYDOWN and wParam != KeyRogue.WM_SYSKEYDOWN: return KeyRogue.user32.CallNextHookEx(KeyRogue.hooked, nCode, wParam, lParam) if KeyRogue.hookProc: KeyRogue.hookProc(nCode, wParam, lParam) return KeyRogue.user32.CallNextHookEx(KeyRogue.hooked, nCode, wParam, lParam) @staticmethod def start(hookProc): if KeyRogue.installHookProc(hookProc): KeyRogue.startKeyLog() else: print("install failed") @staticmethod def stop(): KeyRogue.uninstallHookProc()client.py
from KeyRogue import * def hookProc(nCode, wParam, lParam): key = KeyRogue.getKeyInfo(lParam) print("key code = %d" % key[0]) print("key char = %c" % key[1]) if KeyRogue.checkModifier(lParam, KeyRogue.VK_CONTROL): print("CTRL pressed") if (key[1] == 'Q'): print("exit key pressed, call stop()") KeyRogue.stop() sys.exit(-1) if KeyRogue.checkModifier(lParam, KeyRogue.VK_MENU): print("ALT pressed") if KeyRogue.checkModifier(lParam, KeyRogue.VK_SHIFT): print("SHIFT pressed") KeyRogue.start(hookProc)
- Hook 설치 성공시 .start() 함수는 리턴되지 않는다.(심지어 stop() 함수를 사용하여 언인스톨되었을 경우에도) 따라서 GUI가 있는 프로그램에 키보드 후킹 기능을 추가하려면 별도의 쓰레드에서 실행되도록 처리가 필요하다.
참고사항
<테스트 환경> - OS : Windows 10 - Python 버전 : 3.6.5(32/64bit), 3.7.5(32bit)
'1. 연구 모듈 > Python' 카테고리의 다른 글
[Python] wxPython에서 어플리케이션 아이콘 변경 방법 (1) | 2021.03.29 |
---|---|
[Python] 키보드 후킹 - 간편화 코드 시행 착오 (0) | 2020.12.23 |
[Python] 키보드 후킹 - 1. 예제 코드 (0) | 2020.12.21 |
[Python] .INI 파일에 설정 읽고 쓰기 - 2. 간편화 코드 (0) | 2020.12.18 |
[Python] .INI 파일에 설정 읽고 쓰기 - 1. 예제 코드 (0) | 2020.10.16 |