查看原文
其他

浅谈钩子技术在windows 操作系统上的安全应用

2017-12-06 zyRun 合天智汇

走过路过,不要错过这个公众号哦!

0x00  目的

了解钩子的实现原理,类型以及通过编码实现钩子的应用.文章中钩子代码实现了监听IE浏览器打开,获取键盘在IE上的输入内容的功能。通过代码的演示功能,让读者并知道如何在windows 操作系统上预防钩子。


0x01  需要的知识

1

 钩子技术简介

钩子(Hook)是Windows消息处理机制的一个平台,应用程序可以在上面设置子进程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理Windows消息或特定事件。


钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。


Windows 有两种钩子,一种是特定线程钩子(Thread specific hooks),一种是全局系统钩子 (Systemwide hooks)。特定线程钩子只是监视指定的线程,而全局系统钩子则可以监视系统中所有的线程。无论是特定线程钩子,还是全局系统 钩子,都是通过 SetWindowsHookEx ()来设置钩子的。对于特定线程钩子,钩子的函数既可以是包含在一个.exe也可以是一个.dll。 但是对于一个全局系统钩子,钩子函数必须包含在独立的 dll中,因此,当我们要捕捉键盘响应时,我们必须创建一个动态链接库。但是当钩子函数在得到了控 制权,并对相关的事件处理完后,如果想要该消息得以继续的传递,那么则必须调用另一个函数:CallN。xtHookEx。由于系统必须对每个消息处理, 钩子程序因此增加了处理的负担,因此也降低了系统的性能。鉴于这一点,在windows ce中对钩子程序并不支持。所以当程序完成并退出时,应当释放钩 子,调用函数:UnhookWindowsHookEx。


2

钩子技术实现

编写钩子程序的步骤分为3步:定义钩子函数、安装钩子和卸载钩子。


2.1 定义钩子函数

钩子函数是一种特殊的回调函数。钩子监视的特定事件发生后,系统会调用钩子函数进行处理。不同事件的钩子函数的形式是各不相同的。下面以鼠标钩子函数举例说明钩子函数的原型:

LRESULT CALLBACK HookProc(int nCode ,WPARAM wParam,LPARAM lParam)

参数wParam和 lParam包含所钩消息的信息,比如鼠标位置、状态,键盘按键等。nCode包含有关消息本身的信息,比如是否从消息队列中移出。我们先在钩子函数中实现自定义的功能,然后调用函数 CallNextHookEx.把钩子信息传递给钩子链的下一个钩子函数。CallNextHookEx.的原型如下:

LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam )

参数 hhk是钩子句柄。nCode、wParam和lParam 是钩子函数。当然也可以通过直接返回TRUE来丢弃该消息,就阻止了该消息的传递。


2.2 安装钩子

在程序初始化的时候,调用函数SetWindowsHookEx安装钩子。其函数原型为:

HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId )

参数idHook表示钩子类型,它是和钩子函数类型一一对应的。比如,WH_KEYBOARD表示安装的是键盘钩子,WH_MOUSE表示是鼠标钩子等等。

  

       Lpfn是钩子函数的地址。


  HMod是钩子函数所在的实例的句柄。对于线程钩子,该参数为NULL;对于系统钩子,该参数为钩子函数所在的DLL句柄。


   dwThreadId 指定钩子所监视的线程的线程号。对于全局钩子,该参数为NULL。


  SetWindowsHookEx返回所安装的钩子句柄。

 

2.3 卸载钩子

当不再使用钩子时,必须及时卸载。简单地调用函数:

BOOL UnhookWindowsHookEx( HHOOK hhk)即可。


通常是把“钩子”做成动态链接库DLL,这样的好处是可以在系统内的每个进程中访问。可以把DLL看成一种仓库,它提供一些可以直接拿来用的变量、函数和类。在DLL的发展史上经历了“无库-静态链接库-动态链接库”的时代。静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该DLL不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态或者静态链接库,而在动态链接库中还可以包含其他的动态或者静态链接库。


3

钩子类型

3.1.  按事件分类

有如下的几种常用类型

  (1) 键盘钩子和低级键盘钩子可以监视各种键盘消息。

  (2) 鼠标钩子和低级鼠标钩子可以监视各种鼠标消息。

  (3) 外壳钩子可以监视各种Shell事件消息。比如启动和关闭应用程序。

  (4) 日志钩子可以记录从系统消息队列中取出的各种事件消息。

  (5) 窗口过程钩子监视所有从系统消息队列发往目标窗口的消息。


此外,还有一些特定事件的钩子提供给我们使用,不一一列举。


下面描述常用的Hook类型:

1、WH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks 

WH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks使你可以监视发送到窗口过程的消息。系统在消息发送到接收窗口过程之前调用WH_CALLWNDPROC Hook子程,并且在窗口过程处理完消息之后调用WH_CALLWNDPROCRET Hook子程。WH_CALLWNDPROCRET Hook传递指针到CWPRETSTRUCT结构,再传递到Hook子程。CWPRETSTRUCT结构包含了来自处理消息的窗口过程的返回值,同样也包 括了与这个消息关联的消息参数。

 

2、WH_CBT Hook 

在以下事件之前,系统都会调用WH_CBT Hook子程,这些事件包括:

1. 激活,建立,销毁,最小化,最大化,移动,改变尺寸等窗口事件;

2. 完成系统指令;

3. 来自系统消息队列中的移动鼠标,键盘事件;

4. 设置输入焦点事件;

5. 同步系统消息队列事件。

Hook子程的返回值确定系统是否允许或者防止这些操作中的一个。

 

3、WH_DEBUG Hook 

在系统调用系统中与其他Hook关联的Hook子程之前,系统会调用WH_DEBUG Hook子程。你可以使用这个Hook来决定是否允许系统调用与其他Hook关联的Hook子程。

 

4、WH_FOREGROUNDIDLE Hook 

当应用程序的前台线程处于空闲状态时,可以使用WH_FOREGROUNDIDLE Hook执行低优先级的任务。当应用程序的前台线程大概要变成空闲状态时,系统就会调用WH_FOREGROUNDIDLE Hook子程。

 

5、WH_GETMESSAGE Hook 

应用程序使用WH_GETMESSAGE Hook来监视从GetMessage or PeekMessage函数返回的消息。你可以使用WH_GETMESSAGE Hook去监视鼠标和键盘输入,以及其他发送到消息队列中的消息。

 

6、WH_JOURNALPLAYBACK Hook 

WH_JOURNALPLAYBACK Hook使应用程序可以插入消息到系统消息队列。可以使用这个Hook回放通过使用WH_JOURNALRECORD Hook记录下来的连续的鼠标和键盘事件。只要WH_JOURNALPLAYBACK Hook已经安装,正常的鼠标和键盘事件就是无效的。WH_JOURNALPLAYBACK Hook是全局Hook,它不能象线程特定Hook一样使用。WH_JOURNALPLAYBACK Hook返回超时值,这个值告诉系统在处理来自回放Hook当前消息之前需要等待多长时间(毫秒)。这就使Hook可以控制实时事件的回放。 WH_JOURNALPLAYBACK是system-wide local hooks,它們不會被注射到任何行程位址空間。(估计按键精灵是用这个hook做的)

 

7、WH_JOURNALRECORD Hook 

WH_JOURNALRECORD Hook用来监视和记录输入事件。典型的,可以使用这个Hook记录连续的鼠标和键盘事件,然后通过使用WH_JOURNALPLAYBACK Hook来回放。WH_JOURNALRECORD Hook是全局Hook,它不能象线程特定Hook一样使用。WH_JOURNALRECORD是system-wide local hooks,它們不會被注射到任何行程位址空間。

 

8、WH_KEYBOARD Hook 

在应用程序中,WH_KEYBOARD Hook用来监视WM_KEYDOWN and WM_KEYUP消息,这些消息通过GetMessage or PeekMessage function返回。可以使用这个Hook来监视输入到消息队列中的键盘消息。

 

9、WH_KEYBOARD_LL Hook 

WH_KEYBOARD_LL Hook监视输入到线程消息队列中的键盘消息。

 

10、WH_MOUSE Hook 

WH_MOUSE Hook监视从GetMessage 或者 PeekMessage 函数返回的鼠标消息。使用这个Hook监视输入到消息队列中的鼠标消息。

 

11、WH_MOUSE_LL Hook 

WH_MOUSE_LL Hook监视输入到线程消息队列中的鼠标消息。

 

12、WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks 

WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以监视菜单,滚动条,消息框,对话框消息并且发现用户使用ALT+TAB or ALT+ESC 组合键切换窗口。WH_MSGFILTER Hook只能监视传递到菜单,滚动条,消息框的消息,以及传递到通过安装了Hook子程的应用程序建立的对话框的消息。WH_SYSMSGFILTER Hook监视所有应用程序消息。WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以在模式循环期间过滤消息,这等价于在主消息循环中过滤消息。通过调用CallMsgFilter function可以直接的调用WH_MSGFILTER Hook。通过使用这个函数,应用程序能够在模式循环期间使用相同的代码去过滤消息,如同在主消息循环里一样。

 

13、WH_SHELL Hook 

外壳应用程序可以使用WH_SHELL Hook去接收重要的通知。当外壳应用程序是激活的并且当顶层窗口建立或者销毁时,系统调用WH_SHELL Hook子程。

WH_SHELL 共有5钟情況:

•只要有个top-level、unowned 窗口被产生、起作用、或是被摧毁; 

•当Taskbar需要重画某个按钮; 

•当系统需要显示关于Taskbar的一个程序的最小化形式; 

•当目前的键盘布局状态改变; 

•当使用者按Ctrl+Esc去执行Task Manager(或相同级别的程序)。 

按照惯例,外壳应用程序都不接收WH_SHELL消息。所以,在应用程序能够接收WH_SHELL消息之前,应用程序必须调用SystemParametersInfo function注册它自己。

以上是13种常用的hook类型!


3.2  按使用范围分类

主要有线程钩子和系统钩子:

(1) 线程钩子监视指定线程的事件消息。

(2) 系统钩子监视系统中的所有线程的事件消息。因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库(DLL)

中。这是系统钩子和线程钩子很大的不同之处。

几点需要说明的地方:

(1) 如果对于同一事件(如鼠标消息)既安装了线程钩子又安装了系统钩子,那么系统会自动先调用线程钩子,然后调用系统钩子。

(2) 对同一事件消息可安装多个钩子处理过程,这些钩子处理过程形成了钩子链。当前钩子处理结束后应把钩子信息传递给下一个钩子函数。而且最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。

(3) 钩子特别是系统钩子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装钩子,在使用完毕后要及时卸载。


4

开发工具

使用VC++ 的开发工具均可,本次实验,我们使用VS2008 。Microsoft Visual Studio 是微软公司的一款集成开发环境(IDE),开发平台为Windows操作系统。VS是Visual Studio 的英文缩写,在计

算机领域享誉盛名。使用VS系列工具,可以开发C/C++,C#等多款语言,下面的图里是给出的,VS2008创建新工程的选项


5

procexp.exe

Process Explorer 是一款增强型的任务管理器,你可以使用它方便地管理你的程序进程,能强行关闭任何程序。除此之外,它还详尽地显示计算机信息:CPU、内存使用情况,DLL、句柄信息,很酷的曲线图。下面的实战中,我们在通过演示来展示其功能。


0x03  实战环境

实验环境分为实现DLL的钩子过程,以及测试钩子的目标程序,效果演示及防御说明


1

创建win32DLL,实现代码

创建创建一个win32 DLL工程,名称为Ktr,


点击OK,点击Next,然后如下选择:DLL,空项目


项目创建好之后,分别创建Ktr.h和Ktr.c文件(右键Header Files或者Source Files->Add->New Item里选择.h和.c文件)。加入代码

下面我们来讲解代码


上面的Ktr.h中代码,和之前的DLL中类似,主要是6和7行声明了两个外部函数。继续看ktr.c(从DLL入口函数开始)


在DLLmain中有一个初始化函数,我们来看下


上面的函数将二维数组初始化,为后面的键盘输入做准备。


安装键盘钩子函数和窗口消息的钩子函数。


卸载函数比较简单,卸载两个钩子函数。接下来是两个重要的函数实现,即键盘钩子处理函数和窗口消息处理函数,先看窗口消息处理函数


此函数的功能是判断窗口是不是IE浏览器,具体步骤为:代码中先判断窗口是不是系统要激活的窗口,如果是,获得窗口所属的类的类名,判断是不是IE浏览器。最后调用CallNextHookEx函数交给下一个钩子函数处理。


这个函数代码较多,不便于截图一一介绍,把上面重点的部分截取出来,给大家介绍一下这个函数的处理流程:当IE浏览器窗口被激活后,函数会将键盘按下的键保存到二组数据中,将键盘弹起时的键写到文本中。最后调用CallNextHookEx函数交给下一个钩子函数处理。中间有一些处理特殊按键的代码。


例子中的代码,是不支持中文输入法的,大家也可以考虑,如何加入中文等。编译之后没有错误,会生成Ktr.dll.


2

创建测试项目win32程序。

DLL生成之后,我们创建一个win32应用程序,来加载DLL


点击OK,接下来Next,选择空工程,Windows Application,如下


加入代码。下面我们来讲解代码,


函数比较简单,使用了DLL工程中的头文件,创建安装钩子函数指针,用来记录dll中安装钩子的地址,然后加载DLL。


在加载DLL之前,我们使用了提权函数,提权的介绍会在下面4中介绍


加载成功则安装钩子,失败则弹框提示下。最后的while循环是消息的获取,消息的字符转换,消息分发给窗口程序的流程。


编译我们的程序,会生成Exe文件(如果有警告,请修改项目的字符集设置)。


3

任务描述:钩子功能演示

我们将exe和dll放在同一目录下,打开辅助工具procexp.exe。双击执行exe,在procexp.exe可以看到进程出现,


点击GetIEData进程,可以看到加载了Ktr.dll


下面打开IE浏览器,点击百度账号登录,输入类似账号密码的内容,如下


去C盘根目录查看产生的文本里的信息,如下


可以看到,拿到了用户的输入。如果测试的时候输入过多,会在下次的时候写入文本的,主要是看代码中二维数组的定义。


此代码会监控IE浏览器打开时输入的内容,所以在没有网络的情况也,也是可以测试的,比如如下:


打开文本,可以看到


当然我们的代码比较简单,没有去对写入的数据进行操作,很难分辨出来。但少量的话,还是可以看到的。


4

 钩子防御

应该说,很难通过肉眼去查看每个进程加载的DLL是善意的还是恶意的。最便捷的方式就是第三方工具,比如实验中的procexp.exe,当然也有其他的工具可以选择。这里以procexp.exe为例。如下图,点击某一个进程,可以看到其加载的DLL情况,一般情况下,正规的DLL会有描述,版本号等,如果没有,可以提防下。


如果对某一个DLL不太放心,可以鼠标点击这个DLL,如下图,procexp.exe会给出DLL位置,我们也可以通过位置,或者上网搜索来综合判断某一个DLL是好是坏。


当可以使用杀毒软件,去定期扫描系统,保证系统的安全性。


0x04  面临的问题

在使用钩子技术的时候,会面临一些实际问题,比如想把某个钩子注入到第三方的进程中,结果发现是吧。或者钩子监听的事件没有成功,这其中主要的原因是执行的进程权限不够。在编码演示的时候,你会发现debug模式下面,成功率很高,但是Release版本的时候,会出现失败的情况,这个问题主要是debug模式是调试模式,允许用户有较高的权限,而Release模式是发布模式,没有debug模式下的高权限。


针对此问题,给出两种常见的处理办法,一种是执行程序,根据实际环境中的某种漏洞,提权。此方法通常是要针对某些CVE漏洞,根据漏洞获取system权限,进行操作。此处涉及某些CVE漏洞,不展开说明。


另外一种办法,出自《windows 核心编程》一书,此书给了代码提权的实例。代码如下:


提权函数中有三个重要的API,需要了解;OpenProcessToken 得到进程的令牌句柄;LookupPrivilegeValue 查询进程的权限;AdjustTokenPrivileges 判断令牌权限;在Windows下,每个进程不是说有管理员权限就可以为所欲为。因为每个进程还有个令牌,而令牌代表了一些权限使用,如果需要某些特殊权限,需要自己去使能或除能。


所以使用这组函数提升权限的前提是进程具备该权限,只是访问令牌中没有启用该权限。如果进程的访问令牌中本身就没有关联该权限,这AdjustTokenPrivileges函数调用将会返回ERROR_NOT_ALL_ASSIGNED(值为1300L)的错误码。


提权在实际中有很多解决的方法,此处给出一种 通用方法,大家可以去参考《windows 核心编程》里的介绍去学习。

 

0x05  总结

本次给大家讲解了钩子技术在windows 安全方面的应用,希望读者可以动手在自己的环境里演示,禁止使用这些技术做违法的事情。读者因此做出危害网络安全的行为后果自负,与合天智汇及本人无关,特此声明!


别忘了投稿哟!!!

合天公众号开启原创投稿啦!!!

大家有好的技术原创文章。

欢迎投稿至邮箱:edu@heetian.com

合天会根据文章的时效、新颖、文笔、实用等多方面评判给予100元-500元不等的稿费哟。

有才能的你快来投稿吧!

重金悬赏 | 合天原创投稿奖励来啦!

    合天智汇

网址 : www.heetian.com

电话:4006-123-731

长按图片,据说只有颜值高的人才能识别哦→

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存