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