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-----\n")
        # 監聽鼠標事件
        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 + "\n" + "MessageName: "+ str(event.MessageName)+'\n'+"WindowName: " + str(event.WindowName) + \
                "\n" +"Position: "+str(event.Position)+'\n'+"Wheel: " +str(event.Wheel)+'\n'
        f.write(result)
        f.write("-----Mouse Event End-----\n\n\n")
    f.close()
    return True

def onKeyboardEvent(event):
    with open(path, 'a+') as f:
        # 監聽鍵盤事件
        f.write("-----KeyBoard Event Start-----\n")
        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 + "\n" +"MessageName: "+ str(event.MessageName)+'\n'+"WindowName: " + str(event.WindowName) + " \n" +\
                "Ascii: "+str(event.Ascii)+ ' '+chr(event.Ascii)+'\n'+"Key: " + str( event.Key) + "\n" +"ScanCode: "+str(event.ScanCode)+"\n"+\
                "Alt: "+str(event.Alt)+'\n'
        f.write(result)
        f.write("-----KeyBoard Event End-----\n\n\n")
        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] - ...\records.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] - ...\records.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] - ...\records.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] - ...\records.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] - ...\records.py [Pyhook] - PyCharm

Position: (995, 458)

Wheel: 0

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM