YJX_Driver_017_需要具备的理论知识

1、

需要具备的理论知识

A、了解SSDT结构

B、由SSDT索引号获取当前函数地址

C、如何获取索引号

D、获取起源地址 -- 判断SSDT是否被HOOK

E、如何向内核地址写入自己的代码

 

【178】打开 工具KernelDetective

  对于内核NtOpenProcess函数,自己写 类似 sx.sys的话,需要哪些资料/思路:

    我们要取得 当前地址/起源地址,若 当前地址 != 起源地址 ==> 说明 NtOpenProcess函数 被HOOK了,就要转到当前的地址(KernelDetective中的选项卡"系统服务描述表"中选中"NtOpenProcess"那一行-->右击-->转到当前地址-->此时KernelDetective就跳转到选项卡"反汇编"中),然后改写 它里面的内容(ZC: 就是改写当前地址/函数中的汇编代码),让它跳转到原始的地址去(ZC: 不一定是修改 函数的第1条指令,∵hook的驱动可能会检测函数的首指令,∴ 我们可能修改的是 函数的中间的某条/某些指令)

【405】首先我们要 获取当前函数地址 的话,就要了解 SSDT结构,通过 SSDT结构 我们才能获取 获取当前函数的地址。而 获取当前函数地址 涉及到 SSDT的索引号,SSDT的索引号 等会 会通过WinDBG来了解一下。【510】获取了当前地址之后 还要 获取起源地址,然后两个地址(当前地址/起源地址)作比较,然后 要向内核的指定地址 写入我们自己的jmp代码

 

【610】了解SSDT结构

  SSDT 全称 System Services Descriptor Table --> 系统服务描述表 --> ntoskrnl.exe导出 KeServiceDescriptorTable这个表

    ZC: 之前只听说过 DLL导出,没听说过exe导出

  typedef struct ServiceDescriptorTable

  {
    PVOID ServiceTableBase;   // System Service Dispatch Table 的基地址 //【645】这个最重要
    PVOID ServiceCounterTable(0);

    //包含着 SSDT 中每个服务被调用次数的计数器。这个计数器一般由sysenter 更新。
    unsigned int NumberOfServices;  //由 ServiceTableBase 描述的服务的数目。
    PVOID ParamTableBase;  //包含每个系统服务参数字节数表的基地址-系统服务参数表
  } 

【680】ServiceDescriptorTable.ServiceTableBase 所指向的是 KernelDetective中 选项卡"系统服务描述表"中的 列"当前地址"

  【740】看一下,在OD里面如何才能得到 "当前地址"  【785】靠 打开的是 WinDBG

【785】打开 WinDBG(它自动连上虚拟机了...)

  【845】查看符号表 是否配置OK

  【895】看一下 WinDBG-->调试-->"模块(M)..." 里面,现在之加载了一个nt模块。如果需要加载别的模块的话,可以点击 按钮"重新加载"(ZC: 然而 貌似点击了之后 没啥效果嘛...)

    【980】应该在这里(WinDBG-->文件-->"符号文件路径(S)...") 勾选"重新加载"

【1025】WinDBG 符号路径设置:(ZC: 这是配置下载的,可以自己下 然后配置使用,这样速度快一点)

  srv*D:\WINDDK\symbols*http://msdl.microsoft.com/download/symbols

【1150】首次加载符号文件 较慢,此时 看一下 WinDBG-->调试-->"模块(M)..."(里面就有好多模块了) 就会显示下载的模块的名称

【1330】表KeServiceDescriptorTable 是一个导出的表,这个符号 在编程的时候可以直接引用它

  在WinDBG里面查看的话,输入命令"dd KeServiceDescriptorTable"(和OD里面调试命令类似)

    【1420】第1项 就是表的基地址(视频中为 0x804e58a0)

      【1525】要查看到0x804e58a0的话,OD里面的 加括号方式"dd [KeServiceDescriptorTable]" 没有用,[] 自动的被忽略掉了

        【1555】要这样"dd poi[KeServiceDescriptorTable]" 才表示 显示地址0x804e58a0处的DWORD信息

          【1633】KernelDetective里面的信息和WinDBG里面的信息做对比。ZC: 这里看出来,ServiceDescriptorTable.ServiceTableBase指向一个数组 里面存放所有的"当前地址"(x86/x64函数指针)

          【1750】得到 某个 "当前地址" 的计算公式:"dd poi[KeServiceDescriptorTable] + ?*4"(ZC: 注意,64位的话,就是?*8了)

          【1780】"dd poi[KeServiceDescriptorTable] + 0*4 l 1"(ZC: 最后第2个是小写字母l,最后一个是数字1),这样就只显示一个 long型数值

          【1800】"dd poi[KeServiceDescriptorTable] + 1*4 l 1"

          【1850】"dd poi[KeServiceDescriptorTable] + 0n17*4 l 1"(注意这里要"0n",∵ 17是一个十进制的数)

【2022】如何获取索引号

  【2070】方法一:通过 KernelDetective来看...

  【2160】方法二:

    回顾第11课

    ZC: 也就是通过 OD看到 调用SSDT的汇编代码 根据EAX的值 判断出来的

    【2315】ZC: 讲解到这里结束,还得在看看 第11课 的相关部分...

      ZC: 记得貌似 说过 相同版本的 Windows,这个索引应该是一样的

    【2405】之前用OD找到OpenProcess的SSDT索引的时候,∵OD中可以定位OpenProcess,然后搜索出相应的SSDT索引

  【2530】其实还有一种方法:

    在内核的情况下,【2565】WinDBG输入"dd ZwOpenProcess"  【2600】反汇编一下"u ZwOpenProcess"

      我们可以看到,它的首指令 也是专递的 索引号

      【2630】于是 我们在内核的时候可以通过定位 函数ZwOpenProcess的首指令的第2字节 就是索引号了

      【2680】获取内核函数的地址,用这个函数MmGetSystemRoutineAddress(起源地址)

    【2745】"u NtOpenProcess"

      【2758】当时在第11课,讲了 在应用层ZwOpenProcess和NtOpenProcess指向同一个地址,在内核中 指向的是2个不同的地址

【2900】如何向内核地址写入自己代码

  你可能这样想:"mov [xxx],xx" 实际上 也应该可以 没有做测试

  【3020】正常情况下 SSDT表 是被保护的,不能被写入。解决方式有三:

    (1)、更改注册表 -最简单的做法

    HKLM\SYSTEM\CurrentControlset\Control\SessionManger\MemoryManagement\  中
    EnforceWriteProtection=0(ZC: 将 EnforceWriteProtection 设置为 0,貌似 Win7x64下 默认没有该键值嘛...)
    DisablePagingExecutive=1(ZC: 将 EnforceWriteProtection 设置为 0)

    (2)、改变CR0寄存器的第1位wp位 置0-常用  【1362】该方法是网上流传的经常使用的【3255】置0: 表示去掉相应的写保护

    (3)、通过Memory Descriptor List(MDL)-正规做法  【3288】
      MmCreateMdl

      【3360】通过MmCreateMdl 来设置某一块内存 可读/可写 的属性

 

2、

 

posted @ 2016-04-01 13:37  DebugSkill  阅读(161)  评论(0编辑  收藏  举报