全局钩子的使用,相信看过<<VC++深入祥解>>的人,都有一定的了解,它是以DLL库的形式,通过SetWIndowsHookEx将钩子安装到要监控的进程中.
出于好奇,在网上找了一个密码获取的源码来研究了一番,进行了如下的总结:
1. 钩子注入函数
HHOOK SetWindowsHookEx( int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId );
对于第四个参数dwThreadID,如果不是在本进程注入DLL,则需要GetThreadProceessId来获取被注入进程的窗口创建线程ID,而此函数的输入参数必须提供一个HWND句柄,由此可见,在对其它进程完成钩子注入时,必须针对的是有窗口创建的线程(即使dwThread为0,则是对和桌面窗口创建线程一样的所有运行着的线程)。有了窗口,我们就可以通过FindWindow或FindWindowEx获取窗口对应的HWND句柄,进而获取对应的线程ID,接着就可以注入钩子。
2.全局钩子中的数据共享
对于动态库中全局变量,当为多个进程所共享时,则所有进程只共享一份数据;而当其中一个进程需要修改全局变量时,则会使用该全局变量的一个副本进行修改,且这个副本只为当前修改的进程所有。这就是“写时复制”.如果要在全局钩子里只共享一份数据,则可以使用#pragma data_seg("节名") ... #pragma data_seg(),并使用#pragma comment(linker, "/SECTION:节名,RWS")来设置该数据是可以共享和读写的(也可以在def文件里设置),这里要说的是RWS前面不能有空格,否则,会造成共享一份数据的失败。本人就是在这里被“坑”了。还是后来用dumpbin工具查看时发现没有共享属性的。
3. WM_GETTEXT命令不能获取另一个进程的TEdit类的窗口文本,可以通过全局信息原子表作为消息的参数,向指定窗口发送消息;
4. 关于按键的一些常识
a. 键盘钩子的回调函数中,检查键被按下的条件是:lParam&0x40000000 ,可参看下面第30位的说明;
-
0-15
- Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user's holding down the key. 16-23
- Specifies the scan code. The value depends on the OEM. 24
- Specifies whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is 1 if the key is an extended key; otherwise, it is 0. 25-28
- Reserved. 29
- Specifies the context code. The value is 1 if the ALT key is down; otherwise, it is 0. 30
- Specifies the previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up. 31
- Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released.
b. 虚拟键到字符的转换,可使用MapVirtualKey。其中uMapType设为2,返回的低字节即为字符码(没有shift按下)
UINT MapVirtualKey( UINT uCode, UINT uMapType );
c. GetKeyState检测键是否被按下,这里主要观察其返回值。对于返回值的高字节为1表示键被按下,为0表示弹起. 低字节表示键的锁定(诸如CAPS_LOCK),为1表示锁定,为0时表示解除锁定.
呵呵,就总结到这里吧。