鼠标钩子使用方法图解,鼠标钩子能不能检测出来
今天小编为大家分享Windows系统下载、Windows系统教程、windows相关应用程序的文章,希望能够帮助到大家!
钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。Hook API是指Windows开放给程序员的编程接口,使得在用户级别下可以对操作系统进行控制,也就是一般的应用程序都需要调用API来完成某些功能,Hook API的意思就是在这些应用程序调用真正的系统API前可以先被截获,从而进行一些处理再调用真正的API来完成功能。1)键盘钩子和低级键盘钩子可以监视各种键盘消息。(2)鼠标钩子和低级鼠标钩子可以监视各种鼠标消息。(3)外壳钩子可以监视各种Shell事件消息。比如启动和关闭应用程序。(4)日志钩子可以记录从系统消息队列中取出的各种事件消息。(5)窗口过程钩子监视所有从系统消息队列发往目标窗口的消息
简单的说来,可以把一个完整的取词过程归纳成以下几个步骤:
1.安装鼠标钩子,通过钩子函数获得鼠标消息。
使用到的api函数:setwindowshookex
2.得到鼠标的当前位置,向鼠标下的窗口发重画消息,让它调用系统函数重画窗口。
使用到的api函数:windowfrompoint,screentoclient,invalidaterect
3.截获对系统函数的调用,取得参数,也就是我们要取的词。
对于大多数的windows应用程序来说,如果要取词,我们需要截获的是"gdi32.dll"中的"textouta"函数。
我们先仿照textouta函数写一个自己的mytextouta函数,如:
bool winapi mytextouta(hdc hdc, int nxstart, int nystart, lpcstr lpszstring,int cbstring)
//这里进行输出lpszstring的处理
把这个函数放在安装了钩子的动态连接库中,然后调用我们最后给出的hookimportfunction函数来截获进程对textouta函数的调用,跳转到我们的mytextouta函数,完成对输出字符串的捕捉。hookimportfunction的用法:
hookimportfunction(afxgetinstancehandle(),"gdi32.dll",&hd,porigfuns);
下面给出了hookimportfunction的源代码,相信详尽的注释一定不会让您觉得理解截获到底是怎么实现的很难,ok,let s go:
///////////////////////////////////////////// begin///////////////////////////////////////////////////////////////
#define makeptr(cast, ptr, addvalue)(cast)((dword)(ptr)+(dword)(addvalue))
//定义了hookfuncdesc结构,我们用这个结构作为参数传给hookimportfunction函数
typedef struct tag_hookfuncdesc
lpcstr szfunc;// the name of the function to hook.
proc pproc;// the procedure to blast in.
} hookfuncdesc,* lphookfuncdesc;
//这个函数监测当前系统是否是windownt
//这个函数得到hmodule--即我们需要截获的函数所在的dll模块的引入描述符(import descriptor)
pimage_import_descriptor getnamedimportdescriptor(hmodule hmodule, lpcstr szimportmodule);
bool hookimportfunction(hmodule hmodule, lpcstr szimportmodule,
lphookfuncdesc pahookfunc, proc* paorigfuncs)
///////////////////////下面的代码检测参数的有效性////////////////////////////
_assert(!isbadreadptr(pahookfunc, sizeof(hookfuncdesc)));
if(paorigfuncs) _assert(!isbadwriteptr(paorigfuncs, sizeof(proc)));
_assert(*pahookfunc.szfunc!=\0);
_assert(!isbadcodeptr(pahookfunc.pproc));
if((szimportmodule== null)||(isbadreadptr(pahookfunc, sizeof(hookfuncdesc))))
setlasterrorex(error_invalid_parameter, sle_error);
//////////////////////////////////////////////////////////////////////////////
//监测当前模块是否是在2gb虚拟内存空间之上
//这部分的地址内存是属于win32进程共享的
if(!isnt()&&((dword)hmodule>= 0x80000000))
setlasterrorex(error_invalid_handle, sle_error);
if(paorigfuncs) memset(paorigfuncs, null, sizeof(proc));
//调用getnamedimportdescriptor()函数,来得到hmodule--即我们需要
//截获的函数所在的dll模块的引入描述符(import descriptor)
pimage_import_descriptor pimportdesc= getnamedimportdescriptor(hmodule, szimportmodule);
return false;//若为空,则模块未被当前进程所引入
//从dll模块中得到原始的thunk信息,因为pimportdesc->firstthunk数组中的原始信息已经
//在应用程序引入该dll时覆盖上了所有的引入信息,所以我们需要通过取得pimportdesc->originalfirstthunk
pimage_thunk_data porigthunk= makeptr(pimage_thunk_data, hmodule,
pimportdesc->originalfirstthunk);
//从pimportdesc->firstthunk得到image_thunk_data数组的指针,由于这里在dll被引入时已经填充了
//所有的引入信息,所以真正的截获实际上正是在这里进行的
pimage_thunk_data prealthunk= makeptr(pimage_thunk_data, hmodule, pimportdesc->firstthunk);
//穷举image_thunk_data数组,寻找我们需要截获的函数,这是最关键的部分!
while(porigthunk->u1.function)
//只寻找那些按函数名而不是序号引入的函数
if(image_ordinal_flag!=(porigthunk->u1.ordinal& image_ordinal_flag))
pimage_import_by_name pbyname= makeptr(pimage_import_by_name, hmodule,
porigthunk->u1.addressofdata);
//如果函数名以null开始,跳过,继续下一个函数
if(\0== pbyname->name[0])
// bdohook用来检查是否截获成功
//检查是否当前函数是我们需要截获的函数
if((pahookfunc.szfunc[0]== pbyname->name[0])&&
(strcmpi(pahookfunc.szfunc,(char*)pbyname->name)== 0))
//我们已经找到了所要截获的函数,那么就开始动手吧
//首先要做的是改变这一块虚拟内存的内存保护状态,让我们可以自由存取
memory_basic_information mbi_thunk;
virtualquery(prealthunk,&mbi_thunk, sizeof(memory_basic_information));
_assert(virtualprotect(mbi_thunk.baseaddress, mbi_thunk.regionsize,
page_readwrite,&mbi_thunk.protect));
//保存我们所要截获的函数的正确跳转地址
paorigfuncs=(proc)prealthunk->u1.function;
//将image_thunk_data数组中的函数跳转地址改写为我们自己的函数地址!
//以后所有进程对这个系统函数的所有调用都将成为对我们自己编写的函数的调用
prealthunk->u1.function=(pdword)pahookfunc.pproc;
//操作完毕!将这一块虚拟内存改回原来的保护状态
_assert(virtualprotect(mbi_thunk.baseaddress, mbi_thunk.regionsize,
mbi_thunk.protect,&dwoldprotect));
//访问image_thunk_data数组中的下一个元素
// getnamedimportdescriptor函数的实现
pimage_import_descriptor getnamedimportdescriptor(hmodule hmodule, lpcstr szimportmodule)
if((szimportmodule== null)||(hmodule== null))
setlasterrorex(error_invalid_parameter, sle_error);
pimage_dos_header pdosheader=(pimage_dos_header) hmodule;
if(isbadreadptr(pdosheader, sizeof(image_dos_header))||
(pdosheader->e_magic!= image_dos_signature))
setlasterrorex(error_invalid_parameter, sle_error);
pimage_nt_headers pntheader= makeptr(pimage_nt_headers, pdosheader, pdosheader->e_lfanew);
if(isbadreadptr(pntheader, sizeof(image_nt_headers))||
(pntheader->signature!= image_nt_signature))
setlasterrorex(error_invalid_parameter, sle_error);
//检查pe文件的引入段(即.idata section)
if(pntheader->optionalheader.datadirectory[image_directory_entry_import].virtualaddress== 0)
//得到引入段(即.idata section)的指针
pimage_import_descriptor pimportdesc= makeptr(pimage_import_descriptor, pdosheader,
pntheader->optionalheader.datadirectory[image_directory_entry_import].virtualaddress);
//穷举pimage_import_descriptor数组寻找我们需要截获的函数所在的模块
pstr szcurrmod= makeptr(pstr, pdosheader, pimportdesc->name);
if(stricmp(szcurrmod, szimportmodule)== 0)
//如果没有找到,说明我们寻找的模块没有被当前的进程所引入!
if(pimportdesc->name== null)
//返回函数所找到的模块描述符(import descriptor)
memset(&stosvi, null, sizeof(osversioninfo));
stosvi.dwosversioninfosize= sizeof(osversioninfo);
bool bret= getversionex(&stosvi);
if(false== bret) return false;
return(ver_platform_win32_nt== stosvi.dwplatformid);
wwW.Xtw.Com.cN系统网专业的PC、手机系统开发下载平台,HarmonyOS系统、安卓、OS、windows电脑重装系统在线下载安装,操作系统平台技术学习,攻略教程,技术交流。
免责声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。内容仅供参考使用,不准确地方联系删除处理!
联系邮箱:773537036@qq.com