关于动态链接库以及钩子过程的概念这里不多说,请参考孙鑫的VC++ 深入详解!
我们知道Inner Hook只能屏蔽当前进程的主线程的鼠标消息和键盘消息,如果要想屏蔽当前运行的所有进程的鼠标消息和键盘消息,那么安装钩子过程的代码必须放入动态链接库中。
下面钩子过程的目的:屏蔽所有的鼠标消息以及除了F2以外的键盘消息,当按下F2,调用此钩子过程的应用程序退出,同时卸载钩子过程,你就可以趁别人不注意的时候在其电脑上安装这个应用程序^___^,恶作剧开始了,不知道后门的就只能重启电脑了!
Hook.h
#include<windows.h>
#include<stdio.h>
#define DLL_API extern "C" __declspec(dllimport) //extern "C"保证导出函数的函数名不发生改变
DLL_API void SetHook(HWND hwnd);
Hook.cpp
为Hook.dll创建一个共享的节,把全局变量g_hWnd放入此节中,让全局变量在多个进程中共享。
#include "Hook.h"
#pragma data_seg("MySec") //定义一个新节,将全局变量放入这个节中,用于共享
HWND g_hWnd = NULL;
#pragma data_seg()
#pragma comment(linker,"/section:MySec,RWS") //设置为共享的节
HHOOK g_hMouse = NULL;
//HHOOK g_hKeyBoard = NULL;
HHOOK g_hKeyBoardLL = NULL;
//鼠标钩子回调函数
LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam){
return 1; //return ture说明全部屏蔽
}
/*
//键盘钩子回调函数
LRESULT CALLBACK KeyBoardProc(int code, WPARAM wParam, LPARAM lParam){
if (VK_F2==wParam)
{
//当按下F2则退出调用这个dll的应用程序
::SendMessage(g_hWnd, WM_CLOSE, 0, 0);
UnhookWindowsHookEx(g_hMouse);
UnhookWindowsHookEx(g_hKeyBoard);
}
return 1; //return ture说明全部屏蔽
}
*/
//低级键盘钩子函数用来屏蔽功能键以及组合键
LRESULT CALLBACK KeyBoardLLProc(int code, WPARAM wParam, LPARAM lParam){
if (code == HC_ACTION)
{
KBDLLHOOKSTRUCT *kblp = (KBDLLHOOKSTRUCT*)lParam; //这个结构体暂时没怎么搞明白,官方msdn也写的不是很明白,有待琢磨
if (WM_KEYDOWN == wParam || WM_SYSKEYDOWN==wParam) //如果按键为按下状态
{
if (kblp->vkCode == VK_LWIN || kblp->vkCode == VK_RWIN) //屏敝 WIN (左右)
{
return TRUE;//表示已处理该消息
}
if (kblp->vkCode == 0x4D && ((GetKeyState(VK_LWIN) & 0x8000) ||
(GetKeyState(VK_RWIN) & 0x8000))) //屏敝 WIN+D 组合键(左右)
{
return TRUE;
}
if (kblp->vkCode == 0x44 && ((GetKeyState(VK_LWIN) & 0x8000) ||
(GetKeyState(VK_LWIN) & 0x8000))) //屏敝 WIN+M 组合键(左右)
{
return TRUE;
}
if (kblp->vkCode == VK_ESCAPE && GetKeyState(VK_CONTROL) & 0x8000) //屏敝 CTRL + ESC 组合键
{
return TRUE;
}
if (kblp->vkCode == VK_CONTROL) //屏敝 CTRL键
{
return TRUE;
}
if (kblp->vkCode == VK_TAB && kblp->flags & LLKHF_ALTDOWN) //屏敝 ATL + TAB 组合键
{
return TRUE;
}
if (kblp->vkCode == VK_ESCAPE && kblp->flags & LLKHF_ALTDOWN) //屏敝 ATL + ESC 组合键
{
return TRUE;
}
if (kblp->vkCode==VK_F2)
{
//当按下F2则退出调用这个dll的应用程序
::SendMessage(g_hWnd, WM_CLOSE, 0, 0);
UnhookWindowsHookEx(g_hMouse);
UnhookWindowsHookEx(g_hKeyBoardLL);
}
}
}
return TRUE;
//传给下一个钩子
//return CallNextHookEx(g_hKeyBoard, code, wParam, lParam);
}
void SetHook(HWND hwnd){
g_hWnd = hwnd;
g_hMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, GetModuleHandle("HookDll"), 0);
g_hKeyBoardLL = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardLLProc, GetModuleHandle("HookDll"), 0);
//g_hKeyBoard = SetWindowsHookEx(WH_KEYBOARD, KeyBoardProc, GetModuleHandle("HookDll"), 0);
}
Hook.def文件:保证导出函数的函数名称不发生改变
LIBRARY HookDll
EXPORTS
SetHook
核心代码如下所示:
BOOL CScreenProtectDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
int cxScreen, cyScreen;
cxScreen = GetSystemMetrics(SM_CXSCREEN);
cyScreen = GetSystemMetrics(SM_CYSCREEN);
SetWindowPos(&wndTopMost, 0, 0, cxScreen, cyScreen, SWP_NOMOVE | SWP_NOACTIVATE);
//HideTaskBar(FALSE);
typedef void (* HOOKPROC)(HWND hwnd);
HOOKPROC lpfnDllFuncHook; // Function pointer
hDLL = LoadLibrary(_T("HookDll.dll"));//加载动态链接库
if (hDLL != NULL)
{
lpfnDllFuncHook = (HOOKPROC)GetProcAddress(hDLL, "SetHook");
if (lpfnDllFuncHook != NULL)
{
// call the function
lpfnDllFuncHook(m_hWnd);
}
}
ShowCursor(FALSE);//隐藏鼠标
SetTimer(1, 1000, NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
void CScreenProtectDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
CDC*MemDC = new CDC();//定义一个显示设备对象
GetClientRect(m_rcClient);
dc.FillSolidRect(m_rcClient, RGB(192,192,192));
CFont*pOldFont,font;
COLORREF pOldColor;
CBitmap MemBitmap;
CBitmap *OldBitmap;
CString str="",str1="";
font.CreatePointFont(m_rcClient.Width()/2, _T("Arial Bold"));
CTime t = CTime::GetCurrentTime();
str1.Format(_T("%04d/%d/%d"), t.GetYear(), t.GetMonth(), t.GetDay());
str.Format(_T("TIME: %02d:%02d:%02d %s"),t.GetHour(), t.GetMinute(), t.GetSecond(),((t.GetHour() >= 12) ? _T("PM") : _T("AM")));
MemDC->CreateCompatibleDC(&dc);
MemBitmap.CreateCompatibleBitmap(&dc, m_rcClient.Width(), m_rcClient.Height());
OldBitmap = MemDC->SelectObject(&MemBitmap);
pOldColor = MemDC->SetTextColor(RGB(108, 108, 108)); //0 255 192
pOldFont = MemDC->SelectObject(&font);
//先用背景色将位图清除干净
MemDC->FillSolidRect(0, 0, m_rcClient.Width(), m_rcClient.Height(), RGB(192, 192, 192));
MemDC->TextOut(m_rcClient.Width()/3, m_rcClient.Height()/8, str1);
MemDC->TextOut(m_rcClient.Width()/6,m_rcClient.Height()/2.5,str);
MemDC->TextOut(m_rcClient.Width()/1.4, m_rcClient.Height()/1.3, "EasyLiu");
//将内存中的图拷贝到屏幕上进行显示
dc.BitBlt(0, 0, m_rcClient.Width(), m_rcClient.Height(), MemDC, 0, 0, SRCCOPY);
MemDC->SelectObject(OldBitmap);
MemDC->SelectObject(pOldFont);
MemDC->SelectObject(&pOldColor);
MemBitmap.DeleteObject();
OldBitmap->DeleteObject();
font.DeleteObject();
pOldFont->DeleteObject();
MemDC->DeleteDC();
delete MemDC;
}
void CScreenProtectDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
if (nIDEvent==1)
{
Invalidate();
}
CDialogEx::OnTimer(nIDEvent);
}
最后面讲一下动态链接库的加载方式
动态链接库有两种加载方式:隐式链接加载动态链接库和动态加载动态链接库。
1、隐式链接加载动态链接库
如果有XXX.h ,XXX.lib ,XXX.dll,这样就可以隐式链接加载了。
把这三个文件复制到工程目录下面,当发布应用程序的时候需要把XXX.dll文件放在Debug或者Release目录下面。
在所要引用的.cpp文件中加入#include"XXX.h", #pragma comment(lib,"XXX") ,这样就可以使用dll中封装的函数了。
其中其中语句“#pragma comment(lib,"XXX")”可以用工程设置对话框的设置来代替:就是右击工程,属性--》链接--》输入,加入lib文件所在的目录,比如我们在工程目录下面新建了一个文件夹:lib,然后把XXX.lib放在了这个目录下面,那么就应该在输入项里面输入:..\lib\XXX.lib。
2、动态加载动态链接库
如果只提供了XXX.dll,那么就需要用到动态加载了。
动态加载主要通过LoadLibrary,GetProcAddress,FreeLibrary这三个函数来实现,代码如下:
typedef void (* HOOKPROC)(HWND hwnd);
HOOKPROC lpfnDllFuncHook; // Function pointer
hDLL = LoadLibrary(_T("HookDll.dll"));
if (hDLL != NULL)
{
lpfnDllFuncHook = (HOOKPROC)GetProcAddress(hDLL, "SetHook");
if (lpfnDllFuncHook != NULL)
{
// call the function
lpfnDllFuncHook(m_hWnd);
}
}
在析构函数中:
if (hDLL!=NULL)
{
FreeLibrary(hDLL);
}