SSDT的hook浅析

 ***********关于hook**********************************

 

  首先我们说下hook,什么是hook?hook的英文已经说明了,hook在英文中是钩的意思,计算机取其意叫钩子,而我的理解叫

  大家应该写过r3下程序,估计也写过一些r3的hook,例如有一个API是OpenProcess,功能是打开进程得到进程句柄,比如我们要结束一个进程,如果调用TerminateProcess这个API来结束进程,就必须知道进程句柄。

  那么结束一个进程的伪代码就是这样

  push PID       

  push 0

  push 2035711 //权限

  call OpenProcess

  push 0

  push eax

  call TerminateProcess

 

  这段代码执行,如果正常的话,这个PID的进程应该就会被结束了,这里我们来设想一下,假设我们这里call openprocess做一下修改,变成这样,

   push PID       

  push 0

  push 2035711 //权限

  call myopen 

  push 0

  push eax

  call TerminateProcess

 

  myopen这里是我自己写的一个函数,这个函数跟OpenProcess一样,也有三个参数,也有相同的返回值类型。在这个函数里,我把三个参数,传递给真正的OpenProcess,而把OpenProcess的返回值,做为myopen的返回值,那么,这套流程下来,肯定也是可以执行的,myopen函数类似这样:

  有童鞋要问了,这样做执行是可以执行,但是何必费力做一个包装函数,再调用原函数,这样的意义是什么?

   现在这套流程下来非常正常,我们做的这个包装函数没有意义,现在我们假设,如果有一个恶意进程PID=9527,你写这个结束程序来结束这个PID=9527的进程,这个恶意进程却给你安装了这个包装函数。但是,他稍微的修改了下,变成这样:

 

 嘿嘿,这样下来,会怎么样?你还能结束恶意进程吗?

 当然不能

 因为你如果打开PID为9527的进程时候,得不到正确的句柄返回值,返回值为0。

 这个方法,叫hook,我们也可以在OpenProcess的函数头进行hook。

 而我把这种方法,叫截,截获后,可阻止,可改变,可放行!hook,无非是截获流程,根据自己的需要替换,阻止,放行而已!

 r3层的r0层的hook原理一样,大道至简,现在很多驱动hook一上来就说内核,ssdt,弄的大家一头雾水,其实假传万卷书,真传一句话,驱动hook就是截获api在内核的执行流程,然后根据自己的需要替换,阻止,放行。 理论上你会r3的hook,你一定会r0的hook!

 

 

*********关于SSDT**********************************

 

  明白了HOOK原理后,那么内核hook就很简单了,只要我们在API函数执行流程走到内核后在内核流程中进行截断,处理,就是内核hook了

 我们在内核流程的位置选择了SSDT表,那么,SSDT表是什么?

 SSDT(System Services Descriptor Table),系统服务描述符表。这个表就是一个把ring3的Win32 API和ring0的内核API联系起来。SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等。

 

现在我们以OpenProcess来说明,看下SSDT表在函数执行流程中起的作用!

 

函数的执行流程以OpenProcess是这样.先说明,下面再解释

 

*r3 OpenProcess进入ntdll.dll的NtOpenProcess或ZwOpenProcess函数(反正是同一个地址)

 

*进入内核

 

*进入Ntoskrnl.exe的ZwOpenProcess

 

*根据ZwOpenProcess的索引,找到SSDT表对应的地址,再根据SSDT表对应地址的数据(Ntoskrnl.exe的NtOpenProcess),执行函数。

 

*也就是Ntoskrnl.exe的NtOpenProcess才是真正的执行主体

 

  

 根据上面OpenProcess的流程说明,进入内核后,OpenProcess是进入了Ntoskrnl.exe的ZwOpenProcess这个函数,根据这个函数的索引,在SSDT表查找到真正的内核执行体Ntoskrnl.exe的NtOpenProcess函数,然后执行。

 首先,我们先找到SSDT表,下面我们来看一个被内核导出的结构KeServiceDescriptorTable.

struct KeServiceDescriptorTable       
          SSDT表的指针 //这个指向系统服务函数地址表
          ServiceCounterTableBase;
          NumberOfService; //服务函数的个数
          TableBase
 end KeServiceDescriptorTable

 

这里第一个字段就是SSDT表的指针,我们用windbg看一下,先dd KeServiceDescriptorTable

第一个字段是80502b8c,这个就是SSDT表的地址了

 我们dd 80502b8c看看SSDT表

里面存放的都是一些NT函数地址。

之前说了Ntoskrnl.exe的ZwOpenProcess函数有个索引,根据索引在SSDT表里查找真正的内核执行体函数Ntoskrnl.exe的NtOpenProcess函数

我们看看ZwOpenProcess,用windbg查看,u nt!ZwOpenProcess

索引号是7Ah

那么Ntoskrnl.exe的NtOpenProcess函数应该存放的位置就是=80502b8ch(SSDT表的开始地址)+7Ah(索引)*4(每个函数的间隔),得到80502D74h

80502D74h处存放的地址是805C2296,这个应该是Ntoskrnl.exe的NtOpenProcess函数的地址,我们看下是不是

 

果然是的.

 

所以函数在由R3进R0后,要通过SSDT表的来选择最终执行的内核函数,假设我们想在内核中HOOKOpenProcess这个函数,只需要修改80502d74处存放的地址,放入我们自己写的newNtOpenProcess函数地址,在我们newNtOpenProcess函数中,进行了修改或替换或阻止或放行后执行真正的NtOpenProcess,这就是所谓的SSDThook

那么,我简单说下ssdt表中 hook OpenProcess这个函数步骤

1.先得到Ntoskrnl.exe的NtOpenProcess函数的地址(用MmGetSystemRoutineAddress函数得到内核导出函数地址)

2.再得到SSDT表中Ntoskrnl.exe的NtOpenProcess函数应该存放的位置

   (SSDT表的开始地址)+(索引)*4(每个函数的间隔)

     SSDT表的开始地址=[KeServiceDescriptorTable->SSDT表的指针]  

     索引=[Ntoskrnl.exe的zwOpenProcess地址+1]

3.自己建立一个新函数,参数和返回值要和Ntoskrnl.exe的NtOpenProcess函数一模一样

4.把自己的新函数地址写到SSDT表中我们算出来的存放位置处,(mov [(SSDT表的开始地址)+(索引)*4(每个函数的间隔)],新函数地址)

 

下面是部分重要代码:

 

执行效果如图:

 

 

posted on 2014-01-13 21:42  shellcode  阅读(6140)  评论(2编辑  收藏  举报

导航