孙鑫VC学习笔记:第二十讲 Hook编程

2024-03-25 15:48

本文主要是介绍孙鑫VC学习笔记:第二十讲 Hook编程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

通过安装Hook过程,可以用来屏蔽消息队列中某些消息

The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. You would install a hook procedure to monitor the system for certain types of events. These events are associated either with a specific thread or with all threads in the same desktop as the calling thread.

 

Syntax

 

HHOOK SetWindowsHookEx(

 

 

int idHook,

HOOKPROC lpfn,

HINSTANCE hMod,

DWORD dwThreadId   //为零表示和所有安装的线程相关

);

 

一、下面我们来创建一个屏蔽鼠标过程的hook:

1.创建基于MFC的一个InnerHook工程项目

2.BOOL CInnerHookerDlg::OnInitDialog()中添加hook

SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());

要获得当前线程句柄,使用函数DWORD GetCurrentThreadId(void);

3.实现鼠标过程MouseProc为:

LRESULT CALLBACK MouseProc(

 

 

int nCode,

WPARAM wParam,

LPARAM lParam

)

{

return 1;  //返回值为一表示屏蔽鼠标过程

}

 

二、如果要屏蔽键盘消息,可以添加如下代码

1.CPP文件中添加一个变量:HHOOK g_hKeyBoard;

2.CInnerHookerDlg::OnInitDialog()中添加hook

g_hKeyBoard=SetWindowsHookEx(WH_KEYBOARD,KeyBoardProc,NULL,GetCurrentThreadId());

 

3.实现键盘过程keybroadProc为(只屏蔽空格键):

4.下边添加代码使程序在F2键按下后退出。

要关闭窗口,首先要获得窗口的句柄,先声明一个全局变量Hwnd g_hWnd

OnInitDialog()中把窗口句柄传给它:

g_hWnd=m_hWnd;

接下来为键盘钩子过程添加代码:

这时我们只能屏蔽主线程的键盘消息,如果要屏蔽所有消息,就得把代码放到动态链接库中实现。

三、屏蔽所有线程的消息

首先要创建一个动态链接库

1.新建一个Win32 Dynamic-Link Library项目工程Hook

  得到动态链接库模块的句柄有两种方式:

     方法1DllMain函数方式:

HMODULEHINSTANCE可以通用

     方法2GetModuleHandle函数方式

SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("Hook"),0);

这样我们所安装的钩子过程就和运行在同一个桌面上的所有进程相关了

2.编写MouseProc()

3.之后新建一个模块文件Hook.def,添加代码:

LIBRARY Hook

EXPORTS

SetHook  @2   //@2用来指定序号。

4.编译生成dll文件

 

接下来新建一个工程,用来测试刚才的DLL

    首先安装一个鼠标Hook屏蔽所有的鼠标消息。

1.新建一个基于MFC对话框的项目工程HookTest

2.BOOL CHookTestDlg::OnInitDialog()前声明SetHook函数

_declspec(dllimport) void SetHook();

3.Setting对话框的Link选项卡的,添加库文件:../Hook/Debug/Hook.lib

4.OnInitDialog()中调用 SetHook();

5.将生成好的动态链接库拷贝到测试程序项目工程目录下面。

 

调试运行,你会发现你的鼠标坏了,所有的鼠标操作都被屏蔽了。

 

 

    然后安装一个键盘Hook,我们可以按照刚才所做键盘Hook的过程在动态链接库中也做一个Hook

    这是需要给SetHook带上参数HWND hwnd.

    在测试程序中要把函数也带上参数,并给SetHook传入窗口句柄 SetHook(m_hWnd)

 

 

    接着,让程序窗口始终在其他窗口之前,而且将它最大化,从而使用户不能切换到窗口。

可以使用SetWindowPos函数

BOOL SetWindowPos(

HWND hWndInsertAfter,

int X,

int Y,

int cx,

int cy,

UINT uFlags

);

A window can be moved to the top of the Z-order either by setting the pWndInsertAfter parameter to &wndTopMost and ensuring that the SWP_NOZORDER flag is not set or by setting a window’s Z-order so that it is above any existing topmost windows. When a nontopmost window is made topmost, its owned windows are also made topmost. Its owners are not changed.

 

得到窗口的大小,可以使用函数GetSystemMetrics

int GetSystemMetrics(int nIndex);

代码:

int cxScreen,cyScreen;

cxScreen=GetSystemMetrics(SM_CXSCREEN);

cyScreen=GetSystemMetrics(SM_CYSCREEN);

SetWindowPos(&wndTopMost,0,0,cxScreen,cyScreen,SWP_SHOWWINDOW);

 

SetHook(m_hWnd);

因为第一个参数设置为&wndTopMost这时程序始终处于顶层窗口,

不管怎样切换窗口,我们的窗口显示在最前面。

 

 

 

四、如何实现在切换到其他线程时,也能响应F2退出程序

在程序中,我们屏蔽了鼠标和键盘,但是我们留下了一个退出程序的后门(F2)。

前面讲过动态链接库共享性的原理,多个进程可以共享同一份代码与数据页,

按道理切换到其它线程之后,按下F2应该也可以退出程序才对,

但是发现当切换到其他程序后,再按F2 程序不会退出,

这是因为系统的页面拷贝机制,如果系统发现被某线程要修改某个数据页面,

它就会先拷贝一份页面数据,再对新的页面数据进行修改,

其它没有更新数据的线程继续使用旧的页面数据。

比如:SetHook(HWND hwnd)中将形参传递给了一个全局变量g_hWnd

,那么调用SetHook的线程将使用新的存放了hwnd的数据页面,

而其它的线程继续使用旧的数据页面,所以在其它线程成为活动窗口的时候,

按下F2时,因为没有g_hWnd没有传递到hwnd窗口,所以按下F2没有反应。

 

我们可以通过创建一个新的节,将全局变量放到这个节当中,然后将这个节设置为一个共享的节,

这样全局变量就可以在多个线程间共享,从而使切换到其他线程时也能按下F2退出程序。

要显示动态链接库的节,可以使用命令行:  dumpbin  -headers  Hook.dll

 

如何创建一个新的节?

如果确实想在其他程序窗口下关闭我们的程序窗口,可以把共享窗口句柄,使系统不再进行页面拷贝,方法是使用下面语句把窗口句柄设为共享:

 

#pragma data_seg("MySec")//MySec是新创建的节的名字(不能超过8个字节)

HWND g_hWnd=NULL;  //新变量必须初始化,否则没有新建节的信息

#pragma  data_seg()   //以上为新建节

 

新创建的节共享以后才有效,共享节有两种方法:

1.#pragma comment(linker,"/section:MySec,RWS")  //设置节的属性,读,写,共享

2.也可以把#pragma comment(linker,"/section:MySec,RWS")省略。

Hook.def中添加如下代码:

SEGMENTS

MySec read write shared

也能对节的属性进行设置

 

SetWindowsHookEx函数的第一个参数设为WH_GETMESSAGE,能够破解密码。

使用Hook时要小心。

 

这篇关于孙鑫VC学习笔记:第二十讲 Hook编程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/845480

相关文章

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

Python异步编程中asyncio.gather的并发控制详解

《Python异步编程中asyncio.gather的并发控制详解》在Python异步编程生态中,asyncio.gather是并发任务调度的核心工具,本文将通过实际场景和代码示例,展示如何结合信号量... 目录一、asyncio.gather的原始行为解析二、信号量控制法:给并发装上"节流阀"三、进阶控制

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

C#多线程编程中导致死锁的常见陷阱和避免方法

《C#多线程编程中导致死锁的常见陷阱和避免方法》在C#多线程编程中,死锁(Deadlock)是一种常见的、令人头疼的错误,死锁通常发生在多个线程试图获取多个资源的锁时,导致相互等待对方释放资源,最终形... 目录引言1. 什么是死锁?死锁的典型条件:2. 导致死锁的常见原因2.1 锁的顺序问题错误示例:不同

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

C#反射编程之GetConstructor()方法解读

《C#反射编程之GetConstructor()方法解读》C#中Type类的GetConstructor()方法用于获取指定类型的构造函数,该方法有多个重载版本,可以根据不同的参数获取不同特性的构造函... 目录C# GetConstructor()方法有4个重载以GetConstructor(Type[]

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用