*******************************************************
*标题:【原创】SSDT Hook的妙用-对抗ring0 inline hook  *
*作者:堕落天才                                        *
*日期:2007年3月10号                                   *
*声明:本文章的目的仅为技术交流讨论                    *
*******************************************************

1,SSDT
     SSDT即系统服务描述符表,它的结构如下(参考《Undocument Windows 2000 Secretes》第二章):
     typedef struct _SYSTEM_SERVICE_TABLE
     {
       PVOID   ServiceTableBase;        //这个指向系统服务函数地址表
       PULONG  ServiceCounterTableBase;
       ULONG   NumberOfService;         //服务函数的个数,NumberOfService*4 就是整个地址表的大小
       ULONG   ParamTableBase;
     }SYSTEM_SERVICE_TABLE,*PSYSTEM_SERVICE_TABLE;   
     
     typedef struct _SERVICE_DESCRIPTOR_TABLE
     {
       SYSTEM_SERVICE_TABLE   ntoskrnel;  //ntoskrnl.exe的服务函数
       SYSTEM_SERVICE_TABLE   win32k;     //win32k.sys的服务函数,(gdi.dll/user.dll的内核支持)
       SYSTEM_SERVICE_TABLE   NotUsed1;
       SYSTEM_SERVICE_TABLE   NotUsed2;
     }SYSTEM_DESCRIPTOR_TABLE,*PSYSTEM_DESCRIPTOR_TABLE;
     
     内核中有两个系统服务描述符表,一个是KeServiceDescriptorTable(由ntoskrnl.exe导出),一个是 KeServieDescriptorTableShadow(没有导出)。两者的区别是,KeServiceDescriptorTable仅有 ntoskrnel一项,KeServieDescriptorTableShadow包含了ntoskrnel以及win32k。一般的 Native API的服务地址由KeServiceDescriptorTable分派,gdi.dll/user.dll的内核API调用服务地址由 KeServieDescriptorTableShadow分派。还有要清楚一点的是win32k.sys只有在GUI线程中才加载,一般情况下是不加 载的,所以要Hook KeServieDescriptorTableShadow的话,一般是用一个GUI程序通过IoControlCode来触发 (想当初不明白这点,蓝屏死机了N次都想不明白是怎么回事)。
 
 2,SSDT HOOK 
    SSDT HOOK 的原理其实非常简单,我们先实际看看KeServiceDescriptorTable是什么样的。    
    lkd> dd KeServiceDescriptorTable
    8055ab80  804e3d20 00000000 0000011c 804d9f48
    8055ab90  00000000 00000000 00000000 00000000
    8055aba0  00000000 00000000 00000000 00000000
    8055abb0  00000000 00000000 00000000 00000000   
    在windbg.exe中我们就看得比较清楚,KeServiceDescriptorTable中就只有第一项有数据,其他都是0。其中804e3d20就是
KeServiceDescriptorTable.ntoskrnel.ServiceTableBase,服务函数个数为0x11c个。我们再看看804e3d20地址里是什么东西:
    lkd> dd 804e3d20
    804e3d20  80587691 805716ef 8057ab71 80581b5c
    804e3d30  80599ff7 80637b80 80639d05 80639d4e
    804e3d40  8057741c 8064855b 80637347 80599539
    804e3d50  8062f4ec 8057a98c 8059155e 8062661f
    如上,80587691 805716ef 8057ab71 80581b5c 这些就是系统服务函数的地址了。比如当我们在ring3调用 OpenProcess时,进入sysenter的ID是0x7A(XP SP2),然后系统查KeServiceDescriptorTable,大概 是这样 KeServiceDescriptorTable.ntoskrnel.ServiceTableBase(804e3d20) + 0x7A * 4 = 804E3F08, 然后804E3F08 ->8057559e 这个就是OpenProcess系统服务函数所在,我们再跟踪看看:
    lkd> u 8057559e
    nt!NtOpenProcess:
    8057559e 68c4000000      push    0C4h
    805755a3 6860b54e80      push    offset nt!ObReferenceObjectByPointer+0x127 (804eb560)
    805755a8 e8e5e4f6ff      call    nt!InterlockedPushEntrySList+0x79 (804e3a92)
    805755ad 33f6            xor     esi,esi
    原来8057559e就是NtOpenProcess函数所在的起始地址。  
    嗯,如果我们把8057559e改为指向我们函数的地址呢?比如 MyNtOpenProcess,那么系统就会直接调用MyNtOpenProcess,而不是原来的NtOpenProcess了。这就是SSDT HOOK 原理所在。

3, ring0 inline hook
     ring0 inline hook 跟ring3的没什么区别了,如果硬说有的话,那么就是ring3发生什么差错的话程序会挂 掉,ring0发生什么差错的话系统就挂掉,所以一定要很小心。inline hook的基本思想就是在目标函数中JMP到自己的监视函数,做一些判断然 后再JMP回去。一般都是修改函数头,不过再其他地方JMP也是可以的。下面我们来点实际的吧:
     lkd> u nt!NtOpenProcess
     nt!NtOpenProcess:
     8057559e e95d6f4271      jmp     f199c500
     805755a3 e93f953978      jmp     f890eae7
     805755a8 e8e5e4f6ff      call    nt!InterlockedPushEntrySList+0x79 (804e3a92)
     ...
     同时打开“冰刃”跟“Rootkit Unhooker”我们就能在NtOpenProcess函数头看到这样的“奇观”,第一个jmp是“冰 刃”的,第二个jmp是“Rootkit Unhooker”的。他们这样是防止被恶意程序通过TerminateProcess关闭。当然“冰刃”还 Hook了NtTerminateProcess等函数。

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
    好了,道理就说完了,下面就进入本文正题。
    对付ring0 inline hook的基本思路是这样的,自己写一个替换的内核函数,以NtOpenProcess为例,就是 MyNtOpenProcess。然后修改SSDT表,让系统服务进入自己的函数MyNtOpenProcess。而MyNtOpenProcess要做 的事就是,实现NtOpenProcess前10字节指令,然后再JMP到原来的NtOpenProcess的十字节后。这样NtOpenProcess 函数头写的JMP都失效了,在ring3直接调用OpenProcess再也毫无影响。
***************************************************************************************************************************
#include

typedef struct _SERVICE_DESCRIPTOR_TABLE
{
  PVOID   ServiceTableBase;
  PULONG  ServiceCounterTableBase;
  ULONG   NumberOfService;
  ULONG   ParamTableBase;
}SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TABLE; //由于KeServiceDescriptorTable只有一项,这里就简单点了
extern PSERVICE_DESCRIPTOR_TABLE    KeServiceDescriptorTable;//KeServiceDescriptorTable为导出函数

/
VOID Hook();
VOID Unhook();
VOID OnUnload(IN PDRIVER_OBJECT DriverObject);
//
ULONG JmpAddress;//跳转到NtOpenProcess里的地址
ULONG OldServiceAddress;//原来NtOpenProcess的服务地址
//
__declspec(naked) NTSTATUS __stdcall MyNtOpenProcess(PHANDLE ProcessHandle,
               ACCESS_MASK DesiredAccess,
               POBJECT_ATTRIBUTES ObjectAttributes,
               PCLIENT_ID ClientId) 
{
  DbgPrint("NtOpenProcess() called");
  __asm{
    push    0C4h
    push    804eb560h  //共十个字节
    jmp     [JmpAddress]     
  }
}
///
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
  DriverObject->DriverUnload = OnUnload;
  DbgPrint("Unhooker load");
  Hook();
  return STATUS_SUCCESS;
}
/
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
  DbgPrint("Unhooker unload!");
  Unhook();
}
/
VOID Hook()
{
  ULONG  Address;
  Address = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;//0x7A为NtOpenProcess服务ID
  DbgPrint("Address:0xX",Address);

OldServiceAddress = *(ULONG*)Address;//保存原来NtOpenProcess的地址
  DbgPrint("OldServiceAddress:0xX",OldServiceAddress);

DbgPrint("MyNtOpenProcess:0xX",MyNtOpenProcess);

JmpAddress = (ULONG)NtOpenProcess + 10; //跳转到NtOpenProcess函数头+10的地方,这样在其前面写的JMP都失效了
  DbgPrint("JmpAddress:0xX",JmpAddress);
    
  __asm{//去掉内存保护
    cli
         mov  eax,cr0
    and  eax,not 10000h
    mov  cr0,eax
  }

*((ULONG*)Address) = (ULONG)MyNtOpenProcess;//HOOK SSDT

__asm{//恢复内存保护  
          mov  eax,cr0
    or   eax,10000h
    mov  cr0,eax
    sti
  }
}
//
VOID Unhook()
{
  ULONG  Address;
  Address = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;//查找SSDT

__asm{
    cli
          mov  eax,cr0
    and  eax,not 10000h
    mov  cr0,eax
  }

*((ULONG*)Address) = (ULONG)OldServiceAddress;//还原SSDT

__asm{  
         mov  eax,cr0
    or   eax,10000h
    mov  cr0,eax
    sti
  }

DbgPrint("Unhook");
}
××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
    就这么多了,或许有人说,没必要那么复杂,直接恢复NtOpenProcess不就行了吗?对于象“冰刃”“Rookit Unhooker”这 些“善良”之辈的话是没问题的,但是象NP这些“穷凶极恶”之流的话,它会不断检测NtOpenProcess是不是已经被写回去,是的话,嘿嘿,机器马 上重启。这也是这种方法的一点点妙用。

SSDT Hook的妙用-对抗ring0 inline hook相关推荐

  1. 对付ring0 inline hook

    对付ring0 inline hook的基本思路是这样的,自己写一个替换的内核函数,以NtOpenProcess为例,就是MyNtOpenProcess.然后修改SSDT表,让系统服务进入自己的函数M ...

  2. 关于Win7 x64 Shadow SSDT 的探索和 Inline HOOK

    http://bbs.pediy.com/thread-210481.htm 来看雪一年了,在这里面学到了很多知识,非常感谢各位前辈对知识的分享和不懈的研究,也非常感谢各位大神对我们这些小白的照顾,特 ...

  3. Windows驱动开发学习笔记(六)—— Inline HOOK

    Windows驱动开发学习笔记(六)-- Inline HOOK SSDT HOOK Inline Hook 挂钩 执行流程 脱钩 实验一:3环 Inline Hook 实验二:0环 Inline H ...

  4. Windows内核实验005 Inline Hook

    文章目录 准备工作 寻找Inline Hook的返回地址 编写代码 动态变化的返回地址 JmpTargetAddr Inline Hook基本框架 示例代码 实战HOOK KiTrap01 无需计算偏 ...

  5. PLT hook与Inline hook

    前言 在目前的安卓APP测试中对于Native Hook的需求越来越大,越来越多的APP开始逐渐使用NDK来开发核心或者敏感代码逻辑. 个人认为原因如下: 安全的考虑.各大APP越来越注重安全性,ND ...

  6. Inline Hook

    @author: dlive IAT Hook时如果要钩取的API不在IAT中(LoadLibrary后调用),则无法使用该技术.而Inline Hook不存在这个限制. 0x01 Inline Ho ...

  7. INLINE HOOK过驱动保护的理论知识和大概思路

    INLINE HOOK过驱动保护的理论知识和大概思路,简单驱动保护就是简单的HOOK掉内核API的现象 找到被HOOK的函数的当前地址在此地址处先修改页面保护属性然后写入5个字节.5个字节就是一个简单 ...

  8. Windows内核API HOOK 之 Inline Hook

    来源:CSDN   作者:daiwen 名字起得好,Inline hook,乍一听,似乎很高深.此处的Inline,我以为,意指将汇编代码直接写入内核API的内存区域.Inline Hook不像用户态 ...

  9. Android hook、检测及对抗相关

    frida--hook 内存访问断点 环境:app:arm64      python 3.10   frida 15.2.2 简单的内存访问断点代码,可能还有些bug,根据apk需要自己改,下文为在 ...

最新文章

  1. c中的指针和直接引用结构体的编译后的差异
  2. mysql查看防火墙状态命令_Linux设置允许指定端口通过防火墙centos7
  3. MATLAB | matlab运行、下载链接及21个matlab基本图像调试代码
  4. ITK:将网格转换为非结构化网格
  5. JavaMail可能是邪恶的(并迫使您重新启动应用程序服务器)
  6. FPGA状态机二段式
  7. SQL优化:化解表关联的多对多join
  8. python没基础能自学吗-python自学没有基础会不会不好学?
  9. javascript学习----window对象的学习与总结
  10. Android-蓝牙AVRCP功能实现【转】
  11. 尚学堂马士兵Oracle教程 笔记
  12. PHPStudy介绍、下载与安装
  13. Ubuntu获取最高权限(su)的方式
  14. 明解C语言中级篇练习代码------第八章
  15. 创业公司怎么搞大数据?
  16. linux dsdt屏蔽显卡,关于DSDT屏蔽独显的一点认识和方法
  17. vim和emac体验
  18. Python分别用单线程,多线程,异步协程爬取一部小说,最快仅需要5s
  19. 计算机怎样发现路由器上u盘,路由器USB插口的4个功能,你也许一个都不知道!...
  20. pyepics --Auto-saving: simple save/restore PVs

热门文章

  1. Linux下清理内存和Cache方法 /proc/sys/vm/drop_caches
  2. Spring Boot整合@CacheEvict注解使用
  3. 代理模式coding-静态代理
  4. 多线程——线程的生命周期
  5. java imap 标记已读,JavaMail通过IMAP和POP3接收未读以及设置已读邮件
  6. C# 类、对象、方法和属性详解(重新排版,页面整洁)
  7. chapter3.1封装和解构
  8. cxgrid实现分组统计和添加Footer
  9. RMAN删除归档日志不释放问题
  10. 3中查询数据库连接数