3种简单的键盘记录简单介绍
生活随笔
收集整理的這篇文章主要介紹了
3种简单的键盘记录简单介绍
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Ring3層鍵盤記錄的實現
????本文主要論述、對比了用戶層主要的三種實現鍵盤記錄的方法:利用鉤子函數、輪詢鍵盤消息和直接從輸入設備獲取數據。
在木馬程序中,鍵盤記錄是不可缺少的一部分,因為它是竊取別人電腦上數據的關鍵部分,記錄這些程序的賬號、密碼主要就是靠鍵盤記錄實現的。然后再將獲得的賬號、密碼發到某個指定的郵箱里或某個FTP或網站服務器上。?在用戶層實現鍵盤記錄遠比在系統層實現簡單,是比較常用的方法。
1、利用鉤子函數
最簡單的方法是使用SetWindowsHook函數。鉤子(Hook),是Windows消息處理機制中的監視點,應用程序可以在這里安裝一個監視函數以監視指定進程(本進程或其它進程都可以)發生的事件。當監視的事件消息到達后,鉤子函數可以在目標窗口處理函數之前處理它。
1.1?Hook的分類
總的來說,?Hook可以分為Local?Hook?(本地鉤子)?,和Remote?Hook?(遠程鉤子)?。Local?Hook對本進程中發生的事件進行監視,對系統的影響比較小;而Remote?Hook則可以對其他進程中發生的事件進行監視,針對整個系統的事件進行攔截。RemoteHook又可以分為Thread?Hook?(線程鉤子)和GlobalHook?(全局鉤子)?。線程鉤子能夠監視系統內其他進程中指定線程的事件(此時該Hook函數可以放置在DLL中,也可以放置在應用程序的模塊段)?;而全局鉤子能夠監視系統內所有進程空間地址中所有線程的事件(此時該Hook?函數必須放置在DLL中)?。
1.2?Hook的實現方法
1.2.1安裝和卸載Hook的方法
利用Ap?i函數HHOOK?SetWindowsHookEx?(?int?idHook,?HOOKPROC?lpfn,?H?INSTANCE?hMod,DWORD?dwThread?Id)?,進行鉤子的安裝。
其中:第一個參數為指定鉤子的類型(共15種);第二個參數為標識Hook函數的入口地址;第三個參數為鉤子函數所在模塊的句柄,如果是Local?Hook,此值為0;第四個參數為希望掛鉤線程的線程ID,為0時則攔截整個系統的消息。
SetWindowsHookEx總是將我們的Hook函數放置在掛接函數鏈的頂端,使得應用程序接收到相應消息時,我們的Hook函數能第一個被調用。Hook函數必須按照回調函數的格式聲明:LRESULT?W?INAP?I?HookProc?(?int?nCode,WPARAM?wParam,LPARAM?lParam)。其中nCode指定Hook類型,?wParam,?iParam的取值隨nCode?不同而不同,它代表了某種類型的Hook的某個特定動作。如果Hook函數需要將消息傳遞給下一個過濾函數,?則在該Hook?函數返回前還需要調用一次CallNextHookEx(?)函數。
利用Ap?i?函數BOOL?UnHookWindowsHookEx(HHOOK?hHook)卸載鉤子。
1.2.2?利用鍵盤鉤子監控系統鍵盤輸入實現過程
1)使用MFC?AppW?izard?(DLL)建立擴展動態鏈接庫KeyboardHook.?dll
2)在KeyboardHook.?h中添加導出函數InstallHook。
原型為__declspec?(?dllexport)?void?W?INAP?I??InstallHook?(?)?,以后在應用程序中調用此函數就能安裝一個全局鍵盤鉤子。
3)在Keyboard.?cpp中添加全局變量Hook和全局函數HookProc?(?)?、SaveKeyboardLog?(?)?分別實現處理與保存。
4)最后調用UninstallHook?(?)卸載鉤子
5)編寫應用程序調用KeyboardHook.dll。先調用動態鏈接庫的InstallHook函數安裝好鉤子,此時即可對系統下的鍵盤消息實施攔截處理。使用完畢后,通過動態鏈接庫中的UninstallHook函數卸載鍵盤鉤子。
這種鍵盤記錄十分簡單。隱蔽性較差。功能也不強,不能記錄虛擬鍵盤的輸入。
2.GetAsyncKeyState
利用GetAsyncKeyState實現鍵盤記錄也十分簡單,這個函數根據虛擬鍵表判斷按鍵類型。返回值為一個16位的二進制數,如果被按下則最高位為1,即返回-32767,但是如果需要對鍵盤進行全局性的記錄,則需要與另?一個API函數GetKeyState配合使用才能實現。原因在于GetAsyncKeyState函數只在按鍵的瞬間執行一次,如果按下的鍵是開關鍵?(如:caps?lock),那么過了那一瞬間GetAsyncKeyState函數則不起任何作用。而這個時候就需要用GetKeyState來判斷該開關鍵是否按下。因為每個鍵的虛擬碼是唯一,在這樣一種情況下,不管在大寫情況還是小寫情況下,按下的鍵記錄下來的信息都是一樣的。這個時候就需要一次判斷,需要判斷有兩個鍵是否按下,一個是caps?lock是否按下,一個是shift是否按下,因為shift不屬于開關鍵,那它自然就不需要GetKeyState函數,但是caps?lock是一個開關鍵它在這種情況下就需要用GetKeyState函數。所以在這種特例下我們就需要用GetKeyState函數了。另外insert?這個鍵也是一種特例它也需要用GetKeyState函數來判斷。
GetKeyState(int?nKey)用法
經過驗證,檢查非鎖定鍵(除去num?lock,caps?lock,scroll?lock外)按下狀態返回-127或-128,而且鍵值一定是鍵盤上刻的值(大寫字母或數字,%¥#之類的和小寫字母則不能識別),非按下狀態則為0或?1。檢查num?lock,caps?lock,scroll?lock三個鎖定鍵,鎖定狀態(鍵盤指示燈亮)返回1,否則返回0。
例如,不考慮其他因素,僅判斷“A”鍵是否按下,大寫鍵是否鎖定可以這樣實現:
if?(GetAsyncKeyState('A')?==?-32767)
{
???if?(GetKeyState(VK_CAPITAL)==1)??{log?<<?"A";}
???else???{log?<<?"a";}
?}
在輪詢過程中,往往需要使用死循環while(1),此時為防止CPU利用過高,可以加入windows.h下的sleep函數來使程序暫停若干毫秒。
與HOOK函數相比使用這兩個函數進行鍵盤記錄雖然在程序上顯的比較冗長,但是它卻更加的簡單,而且也不容易出現錯誤。而HOOK函數雖然使用起來,在代碼上看起來可能比較簡單,但是它卻很容易暴露在殺毒軟件的查殺之下。
3.?GetRawInput
微軟原來的鼠標鍵盤輸入模型:
鼠標和鍵盤產生輸入數據,系統中斷去處理這些與設備信息相關的數據,讓這些數據變得與設備無關。一個應用程序通過發送到他窗口的消息獲取與設備無關的消息,例如WM_CHAR,WM_MOUSEMOVE
原始輸入模型:
直接從設備獲取數據并且可以根據他們的需要來獲取。前提是一個應用程序想獲取原始數據就必須注冊他想要獲取原始輸入的那些設備,然后應用程序會收到WM_INPUT消息。
主要流程:?
1)向系統注冊一個或者多個原始輸入設備?
為了注冊這個設備,一個應用程序首先必須創建一個指明他所希望接受設備類別的(top?level?collection—TLC)RAWINPUTDEVICE結構。TLC被定義成為UsagePage(設備類)和Usage(設備類內的具體設備)。例如為了從鍵盤獲取原始輸入,設置UsagePage?=?1?and?Usage?=?6,應用程序調用RegisterRawInputDevice去注冊這個設備。
??BOOL?RegisitKeyBord(HWND?hwnd)
{
???if(NULL?==?hwnd)
??????return?false;
???PRegisterRawInputDevices?RegisterRawInputDevices?=?(PRegisterRawInputDevices)GetApiAdd("User32.dll",?"RegisterRawInputDevices");
???if(NULL?==?RegisterRawInputDevices)
??????return?false;
???RAWINPUTDEVICE?rid;
???rid.usUsagePage?=?0x01;
???rid.usUsage?=?0x06;
???rid.dwFlags?=?RIDEV_INPUTSINK;
???rid.hwndTarget?=?hwnd;
???return?RegisterRawInputDevices(&rid,?1,?sizeof(RAWINPUTDEVICE));
}
應用程序可以注冊系統當前沒有的設備。當設備可用之后,Windows管理器會自動將原始輸入數據發送到應用程序。應用程序可以調用GetRawInputDeviceList來獲取系統中原始輸入設備的列表。用GetRawInputDeviceList獲取的hDevice,應用程序調用GetRawInputDeviceInfo獲取設備信息。
2)在你注冊的原始輸入設備數據發生變化時,系統發送一個消息及新數據到你的進程?
3)調用GetRawInputData來獲取這些數據?
部分代碼:
case?WM_INPUT:
?????if(NULL?==?GetRawInputData)
?????{
????????DefWindowProc(hWnd,?message,?wParam,?lParam);
????????return?0;
?????}??????
?????GetRawInputData((HRAWINPUT)lParam,?RID_INPUT,?NULL,?&dwSize,?sizeof(RAWINPUTHEADER));
?????lpb?=?new?BYTE[dwSize];
?????if(lpb?==?NULL)?
?????{
????????DefWindowProc(hWnd,?message,?wParam,?lParam);
????????return?0;
?????}?
?????
?????if(GetRawInputData((HRAWINPUT)lParam,?RID_INPUT,?lpb,?&dwSize,?sizeof(RAWINPUTHEADER))?!=?dwSize)
????????MessageBox(NULL,?"GetRawInputData?doesn't?return?correct?size?!",?"Raw?Input?Test",?0);
?????raw?=?(RAWINPUT*)lpb;
?????if?(raw->header.dwType?==?RIM_TYPEKEYBOARD)?
?????{
??????wsprintf(vk,"[%s]\r\n%s",&ti,GetKeyName(raw->data.keyboard.VKey))
?????}
?????delete[]?lpb;?
?????這類鍵盤監控程序比前面兩種獲取信息的能力要強,可以獲取軟鍵盤的輸入。
4.漢字輸入記錄
1).先獲取當前正在輸入的窗口的輸入法句柄
????????????????????hIMC?=?ImmGetContext(hWnd);
2).將ImmGetCompositionString的獲取長度設為0來獲取字符串
???????dwSize=ImmGetCompositionString(hIMC,GCS_RESULTSTR,?NULL,?0);
?dwSize?+=?sizeof(WCHAR);?//?緩沖區大小要加上字符串的NULL結束符大小,
memset(lpstr,?0,?20);
3).?再調用一次.ImmGetCompositionString獲取字符串
???????ImmGetCompositionString(hIMC,?GCS_RESULTSTR,?lpstr,?dwSize);
現在lpstr里面即是輸入的漢字了。
5.記錄當前窗口
可以通過GetForegroundWindow函數來記錄當前窗口。
??if?(?prev?==?NULL)???
?????????????{???
?????????????????prev?=?GetForegroundWindow();???
?????????????????GetWindowText(prev,ti,256);???
?????????????????Writetitle();//寫窗口名
?????????????????Writefile();//寫按鍵
?????????????}???
?????else?if?(?prev?==?GetForegroundWindow()?)???
?????????????{?writefile();?}???
?????else???{???
????????????????prev?=?GetForegroundWindow();???
????????????????GetWindowText(prev,ti,256);??
?????????????????Writetitle();
?????????????????Writefile();
?????????????}???
6.防范
由上面的介紹可以看出,除了對記錄程序進行檢測處理之外,軟鍵盤可以在一定程度上提高安全性,但十分有限,比如對GetRawInput?類型的鍵盤記錄就無能為力。
????本文主要論述、對比了用戶層主要的三種實現鍵盤記錄的方法:利用鉤子函數、輪詢鍵盤消息和直接從輸入設備獲取數據。
在木馬程序中,鍵盤記錄是不可缺少的一部分,因為它是竊取別人電腦上數據的關鍵部分,記錄這些程序的賬號、密碼主要就是靠鍵盤記錄實現的。然后再將獲得的賬號、密碼發到某個指定的郵箱里或某個FTP或網站服務器上。?在用戶層實現鍵盤記錄遠比在系統層實現簡單,是比較常用的方法。
1、利用鉤子函數
最簡單的方法是使用SetWindowsHook函數。鉤子(Hook),是Windows消息處理機制中的監視點,應用程序可以在這里安裝一個監視函數以監視指定進程(本進程或其它進程都可以)發生的事件。當監視的事件消息到達后,鉤子函數可以在目標窗口處理函數之前處理它。
1.1?Hook的分類
總的來說,?Hook可以分為Local?Hook?(本地鉤子)?,和Remote?Hook?(遠程鉤子)?。Local?Hook對本進程中發生的事件進行監視,對系統的影響比較小;而Remote?Hook則可以對其他進程中發生的事件進行監視,針對整個系統的事件進行攔截。RemoteHook又可以分為Thread?Hook?(線程鉤子)和GlobalHook?(全局鉤子)?。線程鉤子能夠監視系統內其他進程中指定線程的事件(此時該Hook函數可以放置在DLL中,也可以放置在應用程序的模塊段)?;而全局鉤子能夠監視系統內所有進程空間地址中所有線程的事件(此時該Hook?函數必須放置在DLL中)?。
1.2?Hook的實現方法
1.2.1安裝和卸載Hook的方法
利用Ap?i函數HHOOK?SetWindowsHookEx?(?int?idHook,?HOOKPROC?lpfn,?H?INSTANCE?hMod,DWORD?dwThread?Id)?,進行鉤子的安裝。
其中:第一個參數為指定鉤子的類型(共15種);第二個參數為標識Hook函數的入口地址;第三個參數為鉤子函數所在模塊的句柄,如果是Local?Hook,此值為0;第四個參數為希望掛鉤線程的線程ID,為0時則攔截整個系統的消息。
SetWindowsHookEx總是將我們的Hook函數放置在掛接函數鏈的頂端,使得應用程序接收到相應消息時,我們的Hook函數能第一個被調用。Hook函數必須按照回調函數的格式聲明:LRESULT?W?INAP?I?HookProc?(?int?nCode,WPARAM?wParam,LPARAM?lParam)。其中nCode指定Hook類型,?wParam,?iParam的取值隨nCode?不同而不同,它代表了某種類型的Hook的某個特定動作。如果Hook函數需要將消息傳遞給下一個過濾函數,?則在該Hook?函數返回前還需要調用一次CallNextHookEx(?)函數。
利用Ap?i?函數BOOL?UnHookWindowsHookEx(HHOOK?hHook)卸載鉤子。
1.2.2?利用鍵盤鉤子監控系統鍵盤輸入實現過程
1)使用MFC?AppW?izard?(DLL)建立擴展動態鏈接庫KeyboardHook.?dll
2)在KeyboardHook.?h中添加導出函數InstallHook。
原型為__declspec?(?dllexport)?void?W?INAP?I??InstallHook?(?)?,以后在應用程序中調用此函數就能安裝一個全局鍵盤鉤子。
3)在Keyboard.?cpp中添加全局變量Hook和全局函數HookProc?(?)?、SaveKeyboardLog?(?)?分別實現處理與保存。
4)最后調用UninstallHook?(?)卸載鉤子
5)編寫應用程序調用KeyboardHook.dll。先調用動態鏈接庫的InstallHook函數安裝好鉤子,此時即可對系統下的鍵盤消息實施攔截處理。使用完畢后,通過動態鏈接庫中的UninstallHook函數卸載鍵盤鉤子。
這種鍵盤記錄十分簡單。隱蔽性較差。功能也不強,不能記錄虛擬鍵盤的輸入。
2.GetAsyncKeyState
利用GetAsyncKeyState實現鍵盤記錄也十分簡單,這個函數根據虛擬鍵表判斷按鍵類型。返回值為一個16位的二進制數,如果被按下則最高位為1,即返回-32767,但是如果需要對鍵盤進行全局性的記錄,則需要與另?一個API函數GetKeyState配合使用才能實現。原因在于GetAsyncKeyState函數只在按鍵的瞬間執行一次,如果按下的鍵是開關鍵?(如:caps?lock),那么過了那一瞬間GetAsyncKeyState函數則不起任何作用。而這個時候就需要用GetKeyState來判斷該開關鍵是否按下。因為每個鍵的虛擬碼是唯一,在這樣一種情況下,不管在大寫情況還是小寫情況下,按下的鍵記錄下來的信息都是一樣的。這個時候就需要一次判斷,需要判斷有兩個鍵是否按下,一個是caps?lock是否按下,一個是shift是否按下,因為shift不屬于開關鍵,那它自然就不需要GetKeyState函數,但是caps?lock是一個開關鍵它在這種情況下就需要用GetKeyState函數。所以在這種特例下我們就需要用GetKeyState函數了。另外insert?這個鍵也是一種特例它也需要用GetKeyState函數來判斷。
GetKeyState(int?nKey)用法
經過驗證,檢查非鎖定鍵(除去num?lock,caps?lock,scroll?lock外)按下狀態返回-127或-128,而且鍵值一定是鍵盤上刻的值(大寫字母或數字,%¥#之類的和小寫字母則不能識別),非按下狀態則為0或?1。檢查num?lock,caps?lock,scroll?lock三個鎖定鍵,鎖定狀態(鍵盤指示燈亮)返回1,否則返回0。
例如,不考慮其他因素,僅判斷“A”鍵是否按下,大寫鍵是否鎖定可以這樣實現:
if?(GetAsyncKeyState('A')?==?-32767)
{
???if?(GetKeyState(VK_CAPITAL)==1)??{log?<<?"A";}
???else???{log?<<?"a";}
?}
在輪詢過程中,往往需要使用死循環while(1),此時為防止CPU利用過高,可以加入windows.h下的sleep函數來使程序暫停若干毫秒。
與HOOK函數相比使用這兩個函數進行鍵盤記錄雖然在程序上顯的比較冗長,但是它卻更加的簡單,而且也不容易出現錯誤。而HOOK函數雖然使用起來,在代碼上看起來可能比較簡單,但是它卻很容易暴露在殺毒軟件的查殺之下。
3.?GetRawInput
微軟原來的鼠標鍵盤輸入模型:
鼠標和鍵盤產生輸入數據,系統中斷去處理這些與設備信息相關的數據,讓這些數據變得與設備無關。一個應用程序通過發送到他窗口的消息獲取與設備無關的消息,例如WM_CHAR,WM_MOUSEMOVE
原始輸入模型:
直接從設備獲取數據并且可以根據他們的需要來獲取。前提是一個應用程序想獲取原始數據就必須注冊他想要獲取原始輸入的那些設備,然后應用程序會收到WM_INPUT消息。
主要流程:?
1)向系統注冊一個或者多個原始輸入設備?
為了注冊這個設備,一個應用程序首先必須創建一個指明他所希望接受設備類別的(top?level?collection—TLC)RAWINPUTDEVICE結構。TLC被定義成為UsagePage(設備類)和Usage(設備類內的具體設備)。例如為了從鍵盤獲取原始輸入,設置UsagePage?=?1?and?Usage?=?6,應用程序調用RegisterRawInputDevice去注冊這個設備。
??BOOL?RegisitKeyBord(HWND?hwnd)
{
???if(NULL?==?hwnd)
??????return?false;
???PRegisterRawInputDevices?RegisterRawInputDevices?=?(PRegisterRawInputDevices)GetApiAdd("User32.dll",?"RegisterRawInputDevices");
???if(NULL?==?RegisterRawInputDevices)
??????return?false;
???RAWINPUTDEVICE?rid;
???rid.usUsagePage?=?0x01;
???rid.usUsage?=?0x06;
???rid.dwFlags?=?RIDEV_INPUTSINK;
???rid.hwndTarget?=?hwnd;
???return?RegisterRawInputDevices(&rid,?1,?sizeof(RAWINPUTDEVICE));
}
應用程序可以注冊系統當前沒有的設備。當設備可用之后,Windows管理器會自動將原始輸入數據發送到應用程序。應用程序可以調用GetRawInputDeviceList來獲取系統中原始輸入設備的列表。用GetRawInputDeviceList獲取的hDevice,應用程序調用GetRawInputDeviceInfo獲取設備信息。
2)在你注冊的原始輸入設備數據發生變化時,系統發送一個消息及新數據到你的進程?
3)調用GetRawInputData來獲取這些數據?
部分代碼:
case?WM_INPUT:
?????if(NULL?==?GetRawInputData)
?????{
????????DefWindowProc(hWnd,?message,?wParam,?lParam);
????????return?0;
?????}??????
?????GetRawInputData((HRAWINPUT)lParam,?RID_INPUT,?NULL,?&dwSize,?sizeof(RAWINPUTHEADER));
?????lpb?=?new?BYTE[dwSize];
?????if(lpb?==?NULL)?
?????{
????????DefWindowProc(hWnd,?message,?wParam,?lParam);
????????return?0;
?????}?
?????
?????if(GetRawInputData((HRAWINPUT)lParam,?RID_INPUT,?lpb,?&dwSize,?sizeof(RAWINPUTHEADER))?!=?dwSize)
????????MessageBox(NULL,?"GetRawInputData?doesn't?return?correct?size?!",?"Raw?Input?Test",?0);
?????raw?=?(RAWINPUT*)lpb;
?????if?(raw->header.dwType?==?RIM_TYPEKEYBOARD)?
?????{
??????wsprintf(vk,"[%s]\r\n%s",&ti,GetKeyName(raw->data.keyboard.VKey))
?????}
?????delete[]?lpb;?
?????這類鍵盤監控程序比前面兩種獲取信息的能力要強,可以獲取軟鍵盤的輸入。
4.漢字輸入記錄
1).先獲取當前正在輸入的窗口的輸入法句柄
????????????????????hIMC?=?ImmGetContext(hWnd);
2).將ImmGetCompositionString的獲取長度設為0來獲取字符串
???????dwSize=ImmGetCompositionString(hIMC,GCS_RESULTSTR,?NULL,?0);
?dwSize?+=?sizeof(WCHAR);?//?緩沖區大小要加上字符串的NULL結束符大小,
memset(lpstr,?0,?20);
3).?再調用一次.ImmGetCompositionString獲取字符串
???????ImmGetCompositionString(hIMC,?GCS_RESULTSTR,?lpstr,?dwSize);
現在lpstr里面即是輸入的漢字了。
5.記錄當前窗口
可以通過GetForegroundWindow函數來記錄當前窗口。
??if?(?prev?==?NULL)???
?????????????{???
?????????????????prev?=?GetForegroundWindow();???
?????????????????GetWindowText(prev,ti,256);???
?????????????????Writetitle();//寫窗口名
?????????????????Writefile();//寫按鍵
?????????????}???
?????else?if?(?prev?==?GetForegroundWindow()?)???
?????????????{?writefile();?}???
?????else???{???
????????????????prev?=?GetForegroundWindow();???
????????????????GetWindowText(prev,ti,256);??
?????????????????Writetitle();
?????????????????Writefile();
?????????????}???
6.防范
由上面的介紹可以看出,除了對記錄程序進行檢測處理之外,軟鍵盤可以在一定程度上提高安全性,但十分有限,比如對GetRawInput?類型的鍵盤記錄就無能為力。
實際上,更為簡單有效的方法是人為打亂輸入順序,例如,輸入密碼1234567,可以先輸入12567,再用鼠標切換焦點位置輸入34。此時鍵盤監控程序只會記錄錯誤的結果1256734
http://www.pediy.com/kssd/pediy11/123117.html
總結
以上是生活随笔為你收集整理的3种简单的键盘记录简单介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编程实现键盘记录功能
- 下一篇: 3.6 Meterpreter 键盘记录