HOOK - 进程隐藏与进程保护(SSDT Hook 实现)(一)

进程隐藏与进程保护(SSDT Hook 实现)(一)

 

文章目录:html

                 

1. 引子 – Hook 技术:前端

2. SSDT 简介:数组

3. 应用层调用 Win32 API 的完整执行流程:安全

4. 详解 SSDT:函数

5. SSDT  Hook 原理:工具

6. 小结:post

          

1. 引子 – Hook 技术:学习

     

前面一篇博文呢介绍了代码的注入技术(远程线程实现),博文地址以下:ui

http://www.cnblogs.com/BoyXiao/archive/2011/08/11/2134367.htmlurl

虽然代码注入是很老的技术了,可是这种技术也仍是比较常见,

固然也比较好用的,好比在 Spy++ 中就使用了远程线程注入技术,

同时,若是有兴趣的阅读过 Spy++ 的源码的朋友,固然也能够在其源码中阅读到关于远程线程注入技术了。

            

(这篇博文虽然我会截断分为两篇博文撰写,可是博文仍然会比较长,内容实际上是比较多的,覆盖面也比较广,

须要有必定耐心和基础方可阅读完,有兴趣者请自备茶水以及零食,而后慢慢阅读全文,

PS:这话引用自园子里某位园友)

            

而后的话就是漫漫长夜,心情不佳,因而写了篇博文,恰好又喝了点,因此估计会有些许疏漏之处,还请见谅 ~

           

在这一篇博文中呢,介绍的是一种 Hook 技术,对于 Hook 技术,能够分为两块,

第一块是在 Ring3 层的 Hook,俗称应用层 Hook 技术,

而另一块天然是在 Ring0 层得 Hook,俗称为内核层 Hook 技术,

而在 Ring3 层的 Hook 基本上能够分为两种大的类型,

第一类便是 Windows 消息的 Hook,第二类则是 Windows API 的 Hook。

           

关于 Hook 的几种类型呢,下面给出几个简洁的图示:

image

            

image

          

image

         

关于 Windows 消息的 Hook,相信不少朋友都有接触过的,由于一个 SetWindowsHookEx 便可以完成消息 Hook,

在这里简要介绍一下消息 Hook,消息 Hook 是经过 SetWindowsHookEx 能够实现将本身的钩子插入到钩子链的最前端,

而对于发送给被 Hook 的窗口(也有多是全部的窗口,即全局 Hook)的消息都会被咱们的钩子处理函数所捕获到,

也就是咱们能够优先于窗体先捕获到这些消息,Windows 消息 Hook 能够实现为进程内消息 Hook 和全局消息 Hook,

对于进程内消息 Hook,则能够简单的将 Hook 处理函数直接写在这个进程内,便是本身 Hook 本身,

而对于用途更为普遍的全局消息 Hook,则须要将 Hook 处理函数写在一个 DLL 中,

这样才可让你的处理函数被全部的进程所加载(进程自动加载包含 Hook 消息处理函数的 DLL)。

对于 Windows 消息 Hook 呢,能够有个简单的邪恶应用,就是记录键盘按键消息,

从而达到监视用户输入的键值信息的目的,这样,对于一些简单的用户经过键盘输入的密码就能够被 Hook 获取到,

由于没当用户按下一个键时,Windows 都会产生一个按键消息(固然有按下,弹起等消息的区分),

而后咱们能够 Hook 到这个按键消息,这样就能够在 Hook 的消息处理函数中获取到用户按下的是什么键了。

                  

固然关于消息 Hook 的话,其不是这篇博文的重点,

这篇博文主要介绍的是 SSDT Hook 技术,即内核 Hook 技术的一种,

这种技术呢,也是比较老的技术了,貌似是当年 Rootkit 起火的时候出来的,

可是 SSDT Hook 如今也还比较流行,好比在不少的杀毒软件或者安全软件里面也都会使用到 SSDT Hook 技术。

关于内核 Hook 也有几种类型,下面也给出一副图示:

image

上面的几种内核级 Hook 技术,在看雪啊,debugman,xfocus 上都有不少的介绍,

而我只不过是落后这些技术不少年的小辈后生,在这里也只是将本身的学习以及一些总结的经验给列出来而已,

若是有兴趣想深刻了解这些内容的话,彻底能够在看雪上找到资料 ~

           

           

2. SSDT 简介:

         

如下介绍来自百度(PS:被百度文库弄去了不少博文,这里也抄它一下):

SSDT 的全称是 System Services Descriptor Table,系统服务描述符表。

这个表就是一个把 Ring3 的 Win32 API 和 Ring0 的内核 API 联系起来。

SSDT 并不只仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等。

经过修改此表的函数地址能够对经常使用 Windows 函数及 API 进行 Hook,从而实现对一些关心的系统动做进行过滤、监控的目的。

一些 HIPS、防毒软件、系统监控、注册表监控软件每每会采用此接口来实现本身的监控模块。

          

在 NT 4.0 以上的 Windows 操做系统中,默认就存在两个系统服务描述表,这两个调度表对应了两类不一样的系统服务,

这两个调度表为:KeServiceDescriptorTable 和 KeServiceDescriptorTableShadow,

其中 KeServiceDescriptorTable 主要是处理来自 Ring3 层得 Kernel32.dll 中的系统调用,

而 KeServiceDescriptorTableShadow 则主要处理来自 User32.dll 和 GDI32.dll 中的系统调用,

而且 KeServiceDescriptorTable 在 ntoskrnl.exe(Windows 操做系统内核文件,包括内核和执行体层)是导出的,

而 KeServiceDescriptorTableShadow 则是没有被 Windows 操做系统所导出,

而关于 SSDT 的所有内容则都是经过 KeServiceDescriptorTable 来完成的 ~

           

从下面的截图能够看出 KeServiceDescriptorTable 在 ntoskrnl.exe 中被导出:

image

             

而后咱们再来看看在 Windows 操做系统的源码 WRK 中,KeServiceDescriptorTable 是怎么被定义的 ~

首先来看 KeServiceDescriptorTable 是如何被 Windows 操做系统源码给导出的:

从下面的截图能够看出,这个系统服务描述表是在 WRK 源码中的某一个模块划分文件(.def)中所导出的。

关于 WRK 是什么东西 ? 则能够参阅个人另外一篇博文《Windows 内核(WRK)简介》,博文地址以下:

http://www.cnblogs.com/BoyXiao/archive/2011/01/08/1930904.html

            

image

     

而在 Windows 源码 WRK 中对于系统服务描述符表的代码定义以下(KeServiceDecriptorTable 即由该结构定义):

image

             

上面的这个结构定义在成员变量的名称上还看不出什么名堂,下面给出咱们将在本身代码中所使用的结构体:

   1:  typedef struct _KSYSTEM_SERVICE_TABLE
   2:  {
   3:      PULONG  ServiceTableBase;          // SSDT (System Service Dispatch Table)的基地址
   4:      PULONG  ServiceCounterTableBase;   // 用于 checked builds, 包含 SSDT 中每一个服务被调用的次数
   5:      ULONG   NumberOfService;           // 服务函数的个数, NumberOfService * 4 就是整个地址表的大小
   6:      ULONG   ParamTableBase;            // SSPT(System Service Parameter Table)的基地址
   7:   
   8:  } KSYSTEM_SERVICE_TABLE, *PKSYSTEM_SERVICE_TABLE;
   9:   
  10:  typedef struct _KSERVICE_TABLE_DESCRIPTOR
  11:  {
  12:      KSYSTEM_SERVICE_TABLE   ntoskrnl;  // ntoskrnl.exe 的服务函数
  13:      KSYSTEM_SERVICE_TABLE   win32k;    // win32k.sys 的服务函数(GDI32.dll/User32.dll 的内核支持)
  14:      KSYSTEM_SERVICE_TABLE   notUsed1;
  15:      KSYSTEM_SERVICE_TABLE   notUsed2;
  16:   
  17:  } KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
  18:   
  19:  //导出由 ntoskrnl.exe 所导出的 SSDT
  20:  extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;

              

有了上面的介绍后,咱们能够简单的将 KeServiceDescriptor 看作是一个数组了(其实质也就是个数组),

在应用层 ntdll.dll 中的 API 在这个系统服务描述表(SSDT)中都存在一个与之相对应的服务,

当咱们的应用程序调用 ntdll.dll 中的 API 时,最终会调用内核中与之相对应的系统服务,

因为有了 SSDT,因此咱们只须要告诉内核须要调用的服务所在 SSDT 中的索引就 OK 了,

而后内核根据这个索引值就能够在 SSDT 中找到相对应的服务了,而后再由内核调用服务完成应用程序 API 的调用请求便可。

基本结构能够参考下图:

image

          

             

3. 应用层调用 Win32 API 的完整执行流程:

       

有了上面的 SSDT 基础后,咱们再来看一下在应用层调用 Win32 API(这里主要指的是 ntdll.dll 中的 API)的完整流程,

这里咱们主要是分析 ntdll.dll 中的 NtQuerySystemInformation 这个 API 的调用流程,

(PS:Windows 任务管理器便是经过这个 API 来获取到系统的进程等等信息的)。

先给出一副图示(先记住这里有四个相似的 API,可是必须得注意区分开来,弄混淆了就麻烦大了):

image

             

再给出这些个 API 的基本的调用流程(让大伙有个印象,至少不会迷失):

image

                   

首先,使用 PE 工具来打开 ntdll.dll 文件,能够看到 NtQuerySystemInformation,

image

          

除了 NtQuerySystemInformation 外,同时还能够看到 ZwQuerySystemInformation,

image

                   

而实质上,在 Windows 操做系统中,

Ntdll.dll 中的ZwQuerySystemInformation 和 NtQuerySystemInformation 是同一函数,

能够经过下面的截图看出,这两个函数的入口地址指向同一区域,他们的函数入口地址都是同样的 ~

很奇怪吧 ~ 其实我也以为奇怪 ~ 何须画蛇添足呢 ~

image

           

众所周知 Ntdll.dll 中的 API 都只不过是一个简单的包装函数而已,

当 Kernel32.dll 中的 API 经过 Ntdll.dll 时,会完成参数的检查,

再调用一个中断(int 2Eh 或者 SysEnter 指令),从而实现从 Ring3 进入 Ring0 层,

而且将所要调用的服务号(也就是在 SSDT 数组中的索引值)存放到寄存器 EAX 中,

而且将参数地址放到指定的寄存器(EDX)中,再将参数复制到内核地址空间中,

再根据存放在 EAX 中的索引值来在 SSDT 数组中调用指定的服务 ~

       

通过上面的步骤后,便由 Ring3 层进入了 Ring0 层,

咱们再经过 PE 工具来查看 ntoskrnl.exe 中的 ZwQuerySystemInformation 和 NtQuerySystemInformation

           

image

            

image

    

先来看 ntoskrnl.exe 中的 ZwQuerySystemInformation:

             

image

        

在上面的这幅截图中,能够看到在 Ring0 下的 ZwQuerySystemInformation 将 0ADh 放入了寄存器 eax 中,

而后调用了系统服务分发函数 KiSystemService,而这个 KiSystemService 函数则是根据 eax 寄存器中的索引值,

而后再 SSDT 数组中找到索引值为 eax 寄存器中存放的值得那个 SSDT 项,

最后就是根据这个 SSDT 项中所存放的系统服务的地址来调用这个系统服务了 ~

好比在这里就是调用 KeServiceDescriptorTable[0ADh] 处所保存的地址所对应的系统服务了 ~

也就是调用 Ring0 下的 NtQuerySystemInformation 了 ~

至此,在应用层中调用 NtQuerySystemInformation 的所有流程也就结束了 ~

最后,贴出一点在 Ring0 下的 NtQuerySystemInformation 的反汇编代码:

image

              

     

4. 详解 SSDT:

          

在这一节里面,咱们未来看看 SSDT 究竟是个什么东西 ~ 这里使用 WinDbg 来调试 XP SP2 系统 ~

       

首先来看看 KeServiceDescriptorTable 是何物 ?

从下面的截图中能够看到 KeServiceDesciptorTable 的首地址为 804e58a0,

而后查看分析这个地址,能够查看到第一个系统服务的入口地址为 80591bfb !

2011-08-18_012703

       

咱们再来看看 80591bfb 这个地址对应的到底是何系统服务 ?

从下面的截图中,能够看到 SSDT 中第一个系统服务就是 NtAcceptConnectPort !!!

2011-08-18_013027

           

因为咱们知道了 SSDT 的首地址,又知道了 Ring0 下 NtQuerySystemInformation 服务的索引号,

因此能够根据 “SSDT 中系统服务地址所在的 Address = SSDT 首地址 + 4 * 索引号”,

推算出 NtQuerySystemInformation 服务的地址,

所以有 Address = 804e58a0 + 4 * 0adh = 804E5B54;

而后咱们再来看 804E5B54 这个地址的信息,信息以下截图:

从截图中,咱们能够看到 NtQuerySystemInformation 的起始地址为 80586ff1,

2011-08-18_020103

         

下面就来验证一下地址 80586ff1 究竟是不是 NtQuerySystemInformation 的首地址 ~

从下面的截图中能够确定 80586ff1 确实就是 NtQuerySystemInformation 的首地址,

这和咱们上面对 SSDT 中指定索引号的服务的地址的计算公式计算出来的结果是统一的 !!!

2011-08-18_020231

                   

从上面的介绍,能够看出,其实 SSDT 就是一个用来保存 Windows 系统服务地址的数组而已 !!!

           

                    

5. SSDT  Hook 原理:

        

有了上面的这部分基础后,就能够来看 SSDT HOOK 的原理了,

其实 SSDT Hook 的原理是很简单的,从上面的分析中,

咱们能够知道在 SSDT 这个数组中呢,保存了系统服务的地址,

好比对于 Ring0 下的 NtQuerySystemInformation 这个系统服务的地址,

就保存在 KeServiceDescriptorTable[0ADh] 中,

既然是 Hook 的话,咱们就能够将这个 KeServiceDescriptorTable[0ADh] 下保存的服务地址替换掉,

将咱们本身的 Hook 处理函数的地址来替换掉原来的地址,

这样当每次调用 KeServiceDescriptorTable[0ADh]时就会调用咱们本身的这个 Hook 处理函数了。

               

下面用几幅截图来表示:

image

        

下面的截图则是 SSDT Hook 以后了,能够看到将 SSDT 中的服务地址修改成 MyHookNtQuerySystemInformation 了,

这样的话,每次系统调用 NtQuerySystemInformation 这个系统服务时,

实质上调用的就是 MyHookNtQuerySystemInformation 了,而咱们为了保证系统的稳定性(至少不让其崩溃),

通常会在 MyHookNtQuerySystemInformation 中调用系统中原来的服务,也就是 NtQuerySystemInformation。

image

               

         

6. 小结:

          

本篇博文呢尚还只是介绍了 SSDT 究竟是个什么东西,而尚未给出具体的 SSDT Hook 的实现,

对于 SSDT Hook 的实现以及 Demo 我都放到(二)中完成,也就是本篇博文未完 , 待续 ……

关于 SSDT 的话,在看雪上有不少的文章,因为我也是前阵子对这东西忽然感兴趣了,

因此我也算是初次了解,天然也看过了不少的文章,SSDT 在 Google 一搜索能够出来一大堆,

可是要说介绍 SSDT 最详细的话,我想仍是个人这篇文章介绍的比较详细,

由于网上不少介绍 SSDT 的都只是将 SSDT 原理作了简单的介绍,而后在网上 down 一个 Demo,

把代码贴出来就完事了,甚至是代码都还没法完整编译经过的,

因此若是读者想对 SSDT 有所了解的话,能够好好看一看这篇文章的 ~

          

顺便这里还带出一个问题,是我这阵子脑子里忽然冒出来的一个疑问,

可是因为时间或者说是我的状态问题,一直没有去研究 ~ 不晓得园子里有木有对这个有研究的 ~

众所周知,在 Windows 操做系统中,System 进程的进程 PID 为 4,

我想问的就是:System 进程的 PID 为什么是 4 ?

欢迎你们对这个问题讨论啊 ~ 在这里先给点思路,

那就是能够经过 Windows 操做系统的启动过程,而后结合 WRK 源码进行研究 ~

 

转载自  Zachary.XiaoZhen - 梦想的天空

相关文章
相关标签/搜索