0x14 内核编程

1. 保护模式


  • 分段模式
    • 保护模式下段寄存器变成段选择子(高速缓冲区),由 13位索引1位TI 2位RPL 构成
      • RPL 表示当前访问段的请求权限
        • MAX(CPL,RPL)<= DPL
        • jmp fword 0x4B:00000000;
          • cpl 是执行这条指令的线程 cs 低两位
          • rpl 是 4b 的低两位 11,使用 3 的权限访问 4b对应的段描述符
          • dpl: 通过 4b找到的段描述符的 dpl 位
      • TI描述了当前使用GDT还是LDT,通常为0
        • rgdt是一个48位寄存器,gdtr 是基址 gdtl是范围
      • 索引即位于GDT或LDT中的下标

image.png

  • 分页机制
    • 没有开启PAE[10-10-12]:CR3(页目录表地址) -> 页目录项 -> 页表项 -> 物理地址
    • 开启了PAE[2-9-9-12]:CR3(页目录表指针) -> 页目录表地址->页目录表 -> 页表项 -> 物理页地址

image.png

2. 内核编程


  • 相关术语

    • DriverEntry:驱动程序的入口函数,参数一是驱动对象,参数二是所在路径
      • 注意 DriverEntry 没有名称粉碎,C++编写需要加上 extern “C”
    • 驱动对象:DRIVER_OBJECT,类似于三环中应用程序的身份,不能进行直接通信
      • 使用其中的 DriverSection 可以遍历系统中的所有驱动对象
    • 设备对象:DEVICE_OBJECT,类似于三环中的窗口,是程序的一部分,可用作接收消息
      • 需要为设备指定符号链接名供三环访问,格式: \DosDevices\Name \??\Name
    • IRP:I/O请求数据包,类似于窗口程序中的消息
    • IRQL:中断请求级别,从低到高为 PASSIVE_LEVEL 、APC_LEVEL 、DISPATCH_LEVEL(DPC)
      • 如果到来的中断有更高优先级,那么当前中断被挂起,CPU处理高优先级的中断
    • SSDT:系统服务描述表,保存了一系列的内核层函数
      • 通常使用 SYSENTER 进入内核,调用号保存在 eax寄存器,除此之外msr寄存器中的0x174号负责保存CS段寄存器,0x175号负责保存SS段寄存器,0x176号负责保存eip,通常是 KiFastCall,eax保存的是调用号
    • 分页内存和非分页内存
      • 分页内存:保存在页交换文件中的数据,使用会产生缺页异常
      • 非分页内存:直接保存在物理内存中的数据
  • R0/R3通信的通信方式

    • 直接方式(DODIRECT_IO):通过irp->MdlAddress获取_
    • 缓冲区方式(DOBUFFERD_IO):通过irp->AssociatedIrp.SystemBuffer获取_
    • 其他方式(NULL): _通过irp->UserBuffer获取

_

  • DeviceIoControl

    • 使用 CTL_CODE 定义需要发送的控制码。
    • 四种数据的传输方式
      • METHOD_BUFFERED:缓冲区
      • METHOD_IN_DIRECT \ METHOD_OUT_DIRECT:直接方式
      • METHOD_NEITHER:两者都不的方式
  • 内核Hook

    • SSDT Hook -> 替换函数
    • SYSENTER Hook -> KiFastCallEntry
    • Object Hook -> OBJECT_TYPE -> _OBJECT_TYPE_INITIALIZER(保存了用于操作对象的函数)
  • 内核重载

    • 开辟一块新内存空间,模拟PE加载器将内核模块重新加载到这段内存,用于修复被Hook的SSDT表

3. 安全基础


  • 3环切换到0环
    • eax保存调用号
    • edx保存用户层栈顶地址
    • MSR[0x176]保存进入到0环地址(KiFastCallEntry )
  • HOOK KiFastCallEntry
  • HOOK SSDT