• pyhook的简单使用


    实验内容:

    通过python编程调用windows的api,编写键盘和鼠标监控的hook,将相关信息保存记录到txt文档中。

    实验步骤:

    1.Hook技术,pyHook3和pywin32简介

    1.1 Hook简介

    windows应用程序是基于消息驱动的。各种应用程序对各种消息作出响应从而实现各种功能。

      hook(钩子)是一种特殊的消息处理机制,它可以监视系统或者进程中的各种事件消息,截获发往目标窗口的消息并进行处理。所以说,我们可以在系统中自定义钩子,用来监视系统中特定事件的发生,完成特定功能,如屏幕取词,监视日志,截获键盘、鼠标输入等等。

    钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。Windows消息带了一些程序有用的信息,比如Mouse类信息,就带有鼠标所在窗体句柄、鼠标位置等信息,拦截了这些消息,就可以利用这些信息做出一些功能

      每一个Hook都有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。这个列表的指针指向指定的,应用程序定义的,被Hook子程调用的回调函数,也就是该钩子的各个处理子程序。当与指定的Hook类型关联的消息发生时,系统就把这个消息传递到Hook子程。一些Hook子程可以只监视消息,或者修改消息,或者停止消息的前进,避免这些消息传递到下一个Hook子程或者目的窗口。最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。

    系统钩子与线程钩子:

    SetWindowsHookEx()函数的最后一个参数决定了此钩子是系统钩子还是线程钩子。

    线程钩子用于监视指定线程的事件消息。线程钩子一般在当前线程或者当前线程派生的线程内。

    系统钩子监视系统中的所有线程的事件消息。因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库(DLL) 中。系统自动将包含“钩子回调函数”的DLL映射到受钩子函数影响的所有进程的地址空间中,即将这个DLL注入了那些进程。

    对于 Hook 技术,可以分为两块,第一块是在 Ring3 层的 Hook,俗称应用层 Hook 技术,另外一块自然是在 Ring0 层得 Hook,俗称为内核层 Hook 技术。

    1.2 Hook的windows API

    操作系统支持多种类型的钩子,每种类型都提供了它特有的消息处理机制。

    对于每种类型的钩子,系统都维护一个各自独立的钩子链,钩子链是一个指向用户提供的回调函数钩子过程的链表指针。

    Hook的安装:

    HHOOK SetWindowsHookEx{

    int idHook,//要安装的钩子的类型

    HOOKPPROC lpfn,//钩子过程的指针,拦截到制定系统消息后的预处理过程

    HINSTANCE hMod,//应用程序实例的句柄,如果是全局钩子,hInstance是DLL句柄(DllMain中给的模块地址。就是包含HookProc的动态库加载地址。否则给0就可以了,即勾自己。 )

    DWORD dwThreadId //要安装钩子的线程id,指定被监视的线程,如果明确指定了某个线程的id就只监视该线程,此时的钩子为线程钩子;如果该参数被设置为0,则表示此钩子为监视系统所有线程的全局钩子

    }

    返回值:若此函数执行成功,则返回值就是该挂钩处理过程的句柄;若此函数执行失败,则返回值为NULL(0).

    Hook过程:

    LRESULT CALLBACK HookProc{  //

    int nCode, //该参数是一个钩子标识码,钩子过程会利用它决定下一步的进行的操作。这个标识嘛的值与安装的钩子类型相关

    WPARAM wParam,//后面两个参数的定义都依赖于nCode参数,一般用于存放于窗口消息相关的内容

    LPARAM lParam}

    LRESULT 就是long型,是Windows API的一种返回类型;CALLBACK表示这个函数是给系统调用的,实际上CALLBACK就是__stdcall(回调函数)。HookProc指代自定义的函数。

    Hook卸载:

    BOOL WINAPI UnhookWindowsHookEx( __in HHOOK hhk);

    HHOOK要删除的钩子的句柄。这个参数是函数SetWindowsHookEx的返回值。返回值类型: BOOL,如果函数成功,返回值为非零值。如果函数失败,返回值为零。 要获得更多的错误信息,调用GetLastError函数.

    Hook信息传递:

    CallNextHookEx是一种函数,可以将钩子信息传递到当前钩子链中的下一个子程,一个钩子程序可以调用这个函数之前或之后处理钩子信息。

    LRESULT WINAPI CallNextHookEx( _In_opt_ HHOOK hhk, _In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam);

    Hook类型:

    有很多,举两个例子:

    WH_KEYBOARD     //当敲击键盘时将触发此钩子 
    WH_MOUSE    //当有鼠标操作时将触发此钩子 

    1.3 pyHook3与pywin32简介

      Pywin32:一个开源的python项目,该模块包含了几乎所有的windows API,供调用。https://github.com/mhammond/pywin32。封装方式是从windows的DLL中按类提取了API函数放在不同位置,比如process进程类API放在win32process模块。

      PyHook3:依赖于Pywin32,用于捕捉特定的Windows事件,封装了所有底层调用(比如对SetWindowsHookEx(),UnhookWindowsHookEx(),等函数封装),我们只需要关注程序逻辑。提供键盘和鼠标的Hook。

    2.安装pyHook3和pywin32(pycom)

    需要注意pyHook和pywin32与python版本的对应。

    2.1 查看python版本

    Python 3.7,AMD64

     

     

     

    2.2 pyHook3安装

    pyHook官方只支持python2,所以安装pyhook3

        Conda install swig

        Pip install pyhook3

    2.3 Pycom安装:

    Pycom即pywin32

    https://github.com/mhammond/pywin32/releases

    2.4 查看是否安装成功

    Conda list

    安装成功

     

     3.利用Hook实现键盘监控与鼠标监控

    3.1 思路:

    没有Hook时:

    键盘输入--> 系统消息队列 --> 对应应用程序的消息队列 --> 将消息发送到对应的窗口中

    添加Hook后:

    键盘输入 --> 系统消息队列 --> 对应应用程序消息队列 --> 将消息发送到钩子链中 --> 消息一一调用完毕所有的钩子函数(需要调用CallNextHookEx函数才能将消息传递下去) --> 将消息发送到对应的窗口中

    添加两个Hook函数分别对应键盘和鼠标。在Hook函数接收到信息后保存到txt中,完成监控,然后把信息传给目标程序。

    3.2 代码实现

    思路:

    添加一个键盘hook,会获取到键盘信息。Hook函数功能为将信息转化为string后写入txt文档,然后将信息继续传递给目标窗口。

    有用的信息为Time 事件时间,MessageName事件名称,WindowName事件所在窗口名,Ascii事件ASCII码,KEY 事件KEY,Scancode扫描码,Alt控制信息。

    添加一个鼠标Hook,获取鼠标信息,功能类似于键盘Hook。

    有用的信息为Time 事件时间,MessageName事件名称,WindowName事件所在窗口名,Position鼠标所在坐标位置,Wheel鼠标滚轮的信息。

    在键盘Hook的函数中判断键盘输入是否为Q,为Q时quit。

    存入的文档设置为F://records.txt。

    实验结果记录:

    1.code:

    # -*- coding: utf-8 -*-
    """
    Created on Wed Dec 25 11:33:41 2019
    @author: erio
    """
    #USB 接口的键盘鼠标
    import pythoncom
    import PyHook3 as pyHook
    import win32api
    import time
    
    path = 'F://records.txt'
    
    def onMouseEvent(event):
        with open(path, 'a+') as f:
            f.write("-----Mouse Event Start-----
    ")
            # 监听鼠标事件
            print ("MessageName:", event.MessageName)
            print ("WindowName:", event.WindowName)
            print ("Position:", event.Position)
            print ("Wheel:", event.Wheel)
            print ("---")
            # 返回 True 以便将事件传给其它处理程序
            # 注意,这儿如果返回 False ,则鼠标事件将被全部拦截
            t = time.localtime()
            t = time.asctime(t)
            result = "Time : " + t + "
    " + "MessageName: "+ str(event.MessageName)+'
    '+"WindowName: " + str(event.WindowName) + 
                    "
    " +"Position: "+str(event.Position)+'
    '+"Wheel: " +str(event.Wheel)+'
    '
            f.write(result)
            f.write("-----Mouse Event End-----
    
    
    ")
        f.close()
        return True
    
    def onKeyboardEvent(event):
        with open(path, 'a+') as f:
            # 监听键盘事件
            f.write("-----KeyBoard Event Start-----
    ")
            print ("MessageName:", event.MessageName)
            print ("WindowName:", event.WindowName)
            print ("Ascii:", event.Ascii, chr(event.Ascii))
            print ("Key:", event.Key)
            print ("ScanCode:", event.ScanCode)
            print ("Alt", event.Alt)
            print ("---")
            t=time.localtime()
            t=time.asctime(t)
            result ="Time : " + t + "
    " +"MessageName: "+ str(event.MessageName)+'
    '+"WindowName: " + str(event.WindowName) + " 
    " +
                    "Ascii: "+str(event.Ascii)+ ' '+chr(event.Ascii)+'
    '+"Key: " + str( event.Key) + "
    " +"ScanCode: "+str(event.ScanCode)+"
    "+
                    "Alt: "+str(event.Alt)+'
    '
            f.write(result)
            f.write("-----KeyBoard Event End-----
    
    
    ")
            f.close()
            if event.Key== 'Q':  # 按下F12后终止adsw
                win32api.PostQuitMessage()
        return True
    
    def main():
        # 创建一个“钩子”管理对象aaavv  q
        hm = pyHook.HookManager()
        # 监听所有键盘事件
        hm.KeyDown = onKeyboardEvent
        # 设置键盘“钩子”
        hm.HookKeyboard()
        # 监听所有鼠标事件
        hm.MouseAll = onMouseEvent
        # 设置鼠标“钩子”
        hm.HookMouse()
        # 进入循环,如不手动关闭,程序将一直处于监听状态
        pythoncom.PumpMessages()
    
    
    if __name__ == "__main__":
        main()

    2.records.txt文档展示

    实际随机操作后记录在records.txt中。由于记录较长(13kb),截取部分展示。

    键盘信息记录:包含普通按键和Alt

    信息为Time 事件时间,MessageName事件名称,WindowName事件所在窗口名,Ascii事件ASCII码,KEY 事件KEY,Scancode扫描码,Alt控制信息。

    -----KeyBoard Event Start-----

    Time : Wed Dec 25 17:19:28 2019

    MessageName: key down

    WindowName: Pyhook [D:Pyhook] - ... ecords.py [Pyhook] - PyCharm

    Ascii: 13

     

    Key: Return

    ScanCode: 28

    Alt: 0

    -----KeyBoard Event End-----

     

    -----KeyBoard Event Start-----

    Time : Wed Dec 25 17:19:32 2019

    MessageName: key sys down

    WindowName: Pyhook [D:Pyhook] - ... ecords.py [Pyhook] - PyCharm

    Ascii: 0  

    Key: Lmenu

    ScanCode: 56

    Alt: 32

    -----KeyBoard Event End-----

     

    -----KeyBoard Event Start-----

    Time : Wed Dec 25 17:19:34 2019

    MessageName: key sys down

    WindowName: Pyhook [D:Pyhook] - ... ecords.py [Pyhook] - PyCharm

    Ascii: 0  

    Key: Lmenu

    ScanCode: 56

    Alt: 32

    -----KeyBoard Event End-----

     

    -----KeyBoard Event Start-----

    Time : Wed Dec 25 17:19:34 2019

    MessageName: key sys down

    WindowName: Pyhook [D:Pyhook] - ... ecords.py [Pyhook] - PyCharm

    Ascii: 0  

    Key: Numpad2

    ScanCode: 80

    Alt: 32

    -----KeyBoard Event End-----

     

    鼠标信息记录:包含移动和按下左键

    信息为Time 事件时间,MessageName事件名称,WindowName事件所在窗口名,Position鼠标所在坐标位置,Wheel鼠标滚轮的信息。

     

    -----Mouse Event Start-----

    Time : Wed Dec 25 17:19:42 2019

    MessageName: mouse move

    WindowName: None

    Position: (997, 458)

    Wheel: 0

    -----Mouse Event End-----

     

    -----Mouse Event Start-----

    Time : Wed Dec 25 17:19:42 2019

    MessageName: mouse move

    WindowName: None

    Position: (995, 458)

    Wheel: 0

    -----Mouse Event End-----

     

    -----Mouse Event Start-----

    Time : Wed Dec 25 17:19:42 2019

    MessageName: mouse left down

    WindowName: None

    Position: (995, 458)

    Wheel: 0

    -----Mouse Event End-----

     

    -----Mouse Event Start-----

    Time : Wed Dec 25 17:19:42 2019

    MessageName: mouse left up

    WindowName: Pyhook [D:Pyhook] - ... ecords.py [Pyhook] - PyCharm

    Position: (995, 458)

    Wheel: 0

    -----Mouse Event End-----

  • 相关阅读:
    Java消息队列
    SpringBoot使用Redis缓存
    SpringBoot缓存
    c++question 004 c++基本数据类型有哪些?
    谭浩强 c++程序设计第一章课后习题 第10题
    谭浩强 c++程序设计第一章课后习题 第7题
    servlet从服务器磁盘文件读出到浏览器显示,中文乱码问题,不要忘记在输入流和输出流都要设置编码格式,否则一个地方没设置不统一就会各种乱码
    response.setContentType("text/html;charset=utf-8")后依然乱码的解决方法
    换了台电脑tomcat自己运行没问题,eclipse中配置tomcat开启了浏览器却404错误解决
    Dynemic Web Project中使用servlet的 doGet()方法接收来自浏览器客户端发送的add学生信息形成json字符串输出到浏览器并保存到本地磁盘文件
  • 原文地址:https://www.cnblogs.com/lqerio/p/12106771.html
Copyright © 2020-2023  润新知