scroll lock键貌似功能已经越来越弱了。因此我们可以通过编程把scroll lock键改装一下。我改装成了有类似于手机键盘锁的功能的按键。scroll键盘指示灯亮的时候,不能进行键盘操作。
用到的知识:动态连接库技术、Windows Hook。
编程环境:visual c++ ,MFC
开始......
Hook是跟windows操作系统有密切关系的技术,叫“钩子”。windows操作系统的运行是基于维护一个消息队列来实现的。事件产生的事件会进入消息队列等待操作系统响应。Hook类似于在消息队列之前的一层网,过滤不感兴趣的消息,对感兴趣的消息进行处理,处理完后可以继续进入队列由操作系统处理,也可不再进行操作系统的处理。因为Hook的特殊性,hook技术是防病毒软件的大爱,也是盗号木马神马的大爱...
我的程序实现是在基于对话框的MFC应用程序上完成的。先要重载CXXXDLG的PreTranslateMessage()函数,这个函数是对消息进行预处理的。要先用这个函数判断一下scroll locks键的状态。
1 BOOL CScrollLockExpandDlg::PreTranslateMessage(MSG* pMsg)
3 {
5 // TODO: 在此添加专用代码和/或调用基类
7 //判断ScrollLock键状态:
9 if(GetKeyState(VK_SCROLL) && 0x001)
11 {
13 SetDlgItemTextW(IDC_KEY_STATE,_T("键盘处于锁定状态。\r\n关闭Scroll Lock键解除键盘锁定"));
15 }
17 else
19 {
21 SetDlgItemTextW(IDC_KEY_STATE,_T("键盘处于解锁状态。\r\n打开Scroll Lock键开启键盘锁定"));
23 }
24
25 return CDialogEx::PreTranslateMessage(pMsg);
27 }
然后将程序最小化改成最小化到系统托盘,不在任务栏显示了,太土了...
1 void CScrollLockExpandDlg::OnBnClickedToTray()
3 {
5 // TODO: 在此添加控件通知处理程序代码
7 NOTIFYICONDATA nid;
9 nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA);
11 nid.hWnd=this->m_hWnd;
13 nid.uID=IDR_MAINFRAME;
15 nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP ;
17 nid.uCallbackMessage=WM_SHOWTOTRAY;
19 nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
21 _tcscpy(nid.szTip,_T("Scroll Lock Expand"));
23 Shell_NotifyIcon(NIM_ADD,&nid);//在托盘区添加图标
25 ShowWindow(SW_HIDE);//隐藏主窗口
27 }
28
29 LRESULT CScrollLockExpandDlg::onShowToTray(WPARAM wParam,LPARAM lParam)
31 //wParam接收的是图标的ID,而lParam接收的是鼠标的行为
33 {
35 if(wParam!=IDR_MAINFRAME)
37 return 1;
39 switch(lParam)
41 {
43 case WM_RBUTTONUP://右击托盘图标时,出来个“关闭”右键菜单
45 {
47 LPPOINT lpoint=new tagPOINT;
49 ::GetCursorPos(lpoint);
51 CMenu menu;
53 menu.CreatePopupMenu();
55 menu.AppendMenu(MF_STRING,WM_DESTROY,L"关闭");
57 menu.TrackPopupMenu(TPM_LEFTALIGN,lpoint->x,lpoint->y,this);
59 HMENU hmenu=menu.Detach();
61 menu.DestroyMenu();
63 delete lpoint;
65 }
67 break;
69 case WM_LBUTTONDBLCLK://双击左键显示窗口
71 {
73 this->ShowWindow(SW_SHOW);
75 }
77 break;
79 }
81 return 0;
83 }
WM_SHOWTOTRAY 是自定义的消息,ONShowToTray是这个消息的消息响应函数。
这个工程就大概这样的了...
再在解决方案里建一个新工程,建一个空白的win dll工程。这个dll里是写Hook,因为是全局hook,所以要写在dll里,写程序里是不行的..
1 #include <windows.h>
2 #pragma data_seg("HookData")
3 HHOOK g_hHook = NULL;
4 HINSTANCE g_hInstDLL = NULL;
5 #pragma data_seg()
6 #pragma comment(linker,"/SECTION:HookData,RWS")
7
8 BOOL APIENTRY DllMain(HINSTANCE hInstDLL,
9 DWORD fdwReason,
10 LPVOID lpvReserved)
11 {
12 g_hInstDLL = hInstDLL;
13 return TRUE;
14 }
15
16 LRESULT WINAPI HookProc(int nCode, WPARAM wParam, LPARAM lParam)
17 {
18 if(GetKeyState(VK_SCROLL) && 0x001)
19 {
20 return 1;
21 }
22 // 将事件传递到下一个钩子
23 return CallNextHookEx(g_hHook, nCode, wParam, lParam);
24 }
25
26 extern "C" __declspec(dllexport) VOID InstallHook()
27 {
28 g_hHook = SetWindowsHookEx(WH_KEYBOARD,HookProc, g_hInstDLL, 0);
29 }
30
31 extern "C" __declspec(dllexport) DWORD KillHook(void)
32 {
33 UnhookWindowsHookEx(g_hHook);
34 return 0;
35 }
把这个编译完,用刚才那个主工程调用这个dll,在OninitialDlg后面安装钩子,就是调用InstallHook(),程序退出时再调用个KillHook()就哦了~
主要部分昨天不到1个小时就写完了,然后墨迹了两个小时,因为把钩子的用法记错了,一直是按键时hook能捕获到消息,捕获完处理完,它老是又跑到操作系统消息队列里再处理,就是还能打出字来...结果查了好多资料,居然是把返回值给搞错了。HookProc这个函数,返回over 0 的值表示消息已经经过处理,不用再进入系统消息队列。NND,青春就这么给浪费了。其实HookProc这个函数,完全可以写成记录键盘记录。寒假在家写过一个,一运行杀毒软件就提示有风险注入,把杀毒软件关了,打QQ密码,记录不到...word的可以..。大牛们应该都把hook钩子进行操作系统签名了吧...
我也没具体探究过hook的深层原理,不过上面说的处理完后不进操作系统消息队列肯定是不严密的。我的个人理解Hook处理完后,是将消息标记为已处理神马的。
另外,还可以实现Scroll键把方向键给变掉的功能。原理基本都是一样的,我把上下键变成了音量键,左右键变成了浏览器的前进后退键。和键盘多媒体键进行对比,这种变换对于操作系统来说是等价的,都是产生了相同的虚拟按键消息,不过对于硬件来说是不一样的。多媒体键盘产生的按键消息,是加工到了键盘的芯片里,算得上是汪荣贵说的嵌入式吧。这个和洋仔参加的信安竞赛也不是一码事,他那怎么回事我也不知道,不过肯定比我这种高级,而且不是依靠操作系统的。操作系统作为一个平台有利也有弊,如果硬件的安全完全依托在操作系统上,最后做出来肯定是不安全的,因为你不知道哪天就把系统换了....我的理解是只有集成到硬件上的才是最无懈可击的。我这么个小程序,windows平台上可以,拿到ubuntu/openbsd神马系统上去根本就是不能跑的。
我是想有空就多写点技术的东西,加深一下自己的记忆。
等接下来有空的话,我会把scroll灯改成网卡接口上一闪一闪的那个灯,也让他一闪一闪的...这个做起来比较费时间了,因为要判断网络数据流,winsock是不够用的,要用NIDS,winInet神马的了。