键盘记录器编写笔记
键盘Hook
目的
- 利用Windows钩子监控键盘事件,记录键盘字符,编译成dll在后台运行
实现
- 工程位于
E:\Project\Cpp\Keyboard\KeyboardRecorder\Crack
头文件
- 包含windows.h
全局变量
- 定义模块句柄
HINSTANCE hin
DllMain函数
-
DLL的入口函数,按照固定格式必写
-
在DLLMain中初始化
hin=HModule
Install函数
extern "C" __declspec(dllexport)
定义为导出函数- 调用
SetWindowsHookEx
钩子监控键盘事件,并注册回调函数KeyboardProc
- Sleep,主要工作在回调函数中完成,不Sleep的话进程很快退出
Remove函数
UnhookWindowsHookEx
卸载钩子
KeyboardProc函数
- 键盘回调,参数分别保存消息代码,虚拟键代码和扫描代码
- CreateFile创建文件,GetFileSize和SetFilePointer移动指针追加字符
HANDLE pFile = CreateFile("C:\\key.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwHigh;
DWORD dwPos = GetFileSize(pFile, &dwHigh);
SetFilePointer(pFile, dwPos, 0, FILE_BEGIN);
- 通过GetKeyboardState获取256字节的虚拟键代码
- 通过GetKeyState判断shift键是否按下
- 调用ToAscii函数,传入上述值,获取键盘Ascii码
- 将键盘字符通过WriteFile写入文件
- 返回CallNextHookEx
DLL调试
- 转化为exe来逐步调试,但实际上我并没能够进入回调函数内的断点
- 生成DLL,rundll运行并通过MessageBox来打印调试信息,并通过GetLastError来获取内部报错
char ch[10];
snprintf(ch, 10, "[INFO]%d", GetLastError());
MessageBox(NULL,ch,NULL,0);
- rundll在后台运行,每次调试后可通过下列方式杀死进程
1.资源监视器
资源监视器->CPU->关联句柄,输入运行的文件夹,结束下面的进程
2.tasklist
tasklist | findstr rundll
taskkill /pid pid /F
遇到的问题
- 由于dll是由rundll启动的,所以通过
getModuleHandle
获取不到主模块,传入SetWindowsHookEx
错误,解决方法:在dllMain函数中获取模块值 - 通过
GetKeyNameTextA(lParam, szKey, 100)
能够直接获取键盘字符,但是不能识别大小写和shift - (此部分实现在Crack_scan.cpp中)通过wParam判断键盘按下/弹上,通过vkCode取扫描码,将扫描码逐个转化为目标字符,该方法更细粒度,但实际调试发现取不到vkCode,故放弃
- (此部分实现在Crack.cpp中)最后选用了ToAscii函数来转化字符,可处理大小写和shift
- 尝试通过
GetActiveWindow
获取窗口标题,但结果不准确 - 将文件写入C盘会有权限问题,解决办法:一是写入
Windows/Temp
目录,二是点击目标文件夹属性->安全->编辑->full control,增加写权限
Windows API例程
https://hub.おうか.tw/microsoft/Windows-classic-samples/tree/1d363ff4bd17d8e20415b92e2ee989d615cc0d91