分布式机器 Scala 做推广 wxRuby express sqlalchemy smtp tinymce sms 河南普通话报名 ajax的get请求 jquery获取最后一个子元素 div外边距 idea整理代码格式 excel被保护怎么解除 oracle查询数据库 idea中svn的使用 svn更新本地代码 git下载项目 图片生成链接 docker保存镜像 docker创建容器 python连接mysql python语言 python自学教材 javaapplet java接口文档 java字符串替换 java实例变量 java实现队列 java代码注释 java中map java中random java集合框架图 java网课 java获取url参数 liunx命令大全 bcdautofix 嵌入式linux驱动程序设计从入门到精通 swing布局
当前位置: 首页 > 学习教程  > 编程语言

键盘钩子

2020/10/8 20:23:02 文章标签:

一 、总述 0x1 消息钩子 windows向用户提供GUI,它以事件驱动的方式工作。操作系统中借助鼠标,键盘,选择菜单,按钮,以及移动鼠标,改变窗口大小与位置等都属于事件(对此我感受最深的是学QT编程的…

一 、总述

0x1 消息钩子

windows向用户提供GUI,它以事件驱动的方式工作。操作系统中借助鼠标,键盘,选择菜单,按钮,以及移动鼠标,改变窗口大小与位置等都属于事件(对此我感受最深的是学QT编程的时候,每个按钮或其他事件都会对应一个槽函数,通过槽函数的调用来实现相应的功能)。发生事件时,OS会把事先定义好的消息发送给相应的程序,应用程序收到消息后会执行相应的操作。所以,敲击键盘时,消息会从os移动到应用程序,所谓的消息钩子,就是在此间偷看这些信息。

0x2 windows消息流

  1. 产生消息输入,消息被加入到【OS Message queue】
  2. OS判断是哪个应用程序中发生了事件,并从【OS Message queue】,并加入到相应的应用程序的【application message queue】中
  3. 应用程序监视自己的【application message queue】,发现新添加的消息,调用相应的事件处理程序进行处理

0x3 消息钩取工作原理

应用程序和OS之间好似有一条运输通道,而钩子,就是埋伏在这条运输通道上的小偷,他会翻看OS与应用程序之间的消息队列,必要时,还会对有些消息进行改变或者丢弃。

再一点,如果同时加上多个钩子,钩子就会向一条链一样,链起来,形象的称为“钩链”。

二、键盘钩子

钩子的主程序是以dll的形式存在着,然后通过一个应用程序进行调用,应用程序作为一个启动程序,将钩子的dll注册到windows上,主体是dll文件。

0x1 KeyHook.dll

BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpvReserved)
{
	switch (dwReason)
	{
	case DLL_PROCESS_ATTACH:
		g_hInstance = hinstDll;
		break;
	case DLL_THREAD_DETACH:
		break;
	}
	return true;
}

Dll文件的主函数,当dll被注入进程时,会首先调用该函数,该函数还可对一些变量进行一些初始化和变量赋值。

#ifdef __cplusplus
extern "C" {
#endif
	__declspec(dllexport) void HookStart()
	{
		g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
	}
	__declspec (dllexport) void HookStop()
	{
		if (g_hHook)
		{
			UnhookWindowsHookEx(g_hHook);
			g_hHook = NULL;
		}
	}
#ifdef __cplusplus
}
#endif

导入导出函数,用于在启动程序中来启动或卸载钩子。此处还声明了钩子类型,回调函数…

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	char szPath[MAX_PATH] = { 0, };
	char* p = NULL;	
	if (nCode == 0)
	{
		if (!(lParam & 0x80000000))
		{
			GetModuleFileNameA(NULL, szPath, MAX_PATH);
			p = strrchr(szPath, '\\');
			g_hWnd = FindWindow(NULL, (LPCWSTR)DEF_PROCESS_NAME);
			if (!_stricmp(p + 1, DEF_PROCESS_NAME))
			{
				return 1;
			}		
		}
	}
	return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

钩子函数中最关键的回调函数,当发生键盘输入事件时,会调用该函数进行消息处理,MSDN对他的定义如下

LRESULT CALLBACK KeyboardProc(
  _In_ int    code,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);

code,用来表示钩子程序如何处理消息,如果code的值小于0,则钩子程序需要直接将消息传给CallNextHookEx函数。

wParam,传递的是虚拟键值,在这,’A‘和’a‘ 是相同的虚拟键值。

lParam,传递一些额外扩展信息,用32比特来传递一些信息,具体情况请参考微软官网.

0x2 HookMain.exe

int main()
{
	HMODULE hDll = NULL;
	PFN_HOOKSTART HookStart = NULL;
	PFN_HOOKSTOP HookStop = NULL;
	char ch = 0;
	hDll = LoadLibraryA(DEF_DLL_NAME);
	HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);
	HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);
	HookStart();
	printf("press to quit!\n");
	while (_getch() != 'q');
	HookStop();
	FreeLibrary(hDll);
}

相比之下简单多了,通过调用dll的导出函数,直接实现了钩子的注册及卸载,可以看到,在调用HookStart后,执行一个死循环,也就是说,这就是个启动程序,启动之后就没用了。

思维扩展一点,可以将启动程序换到某个有实际功能的程序里,当该程序运行时,多起一个线程运行钩子,悄无声息的截获你的消息。:)

三、遇到的问题

0x1 注入失败,进程会卡死

多方查找,这是个很傻*的错误,原因是32位程序无法注入64位程序,可能是一开始我就是用32位注入64位出错了,我的操作系统是win10,再后来,我编译了64位的程序,可还是有程序会崩溃,于是上网查资料,遇到了同样经历的一位大哥,https://bbs.pediy.com/thread-250189.htm,我试了又试,还是回到了这个傻逼的架构不匹配的问题上。

由于32位和64位架构不匹配,当你64位的钩子注入到32位的程序里时,会使用sendmessage来传递消息,而这个进程,也就卡在了这里。。。

0x2 文件读写问题

本来想着在钩子里加个文件记录功能,能记录敲击的键盘按键,谁知virtual studio竟然不让我用fopen,气死我了。无奈转战createFile,谁知也是一地鸡毛,死活就是写不进去了。

最后通过改宏定义用上了fopen,说来也怪,能用fopen之后,CreateFile也能行了,不知道是不是那个宏的原因。

右键工程名–>属性–>C/C++–>预处理器–>预处理器定义,编辑右边输入框加入:
奈转战createFile,谁知也是一地鸡毛,死活就是写不进去了。

参考文章:《逆向工程核心原理》
https://blog.csdn.net/weixin_39449570/article/details/78801573


本文链接: http://www.dtmao.cc/news_show_250281.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?