• 内核调试、rootkit分析
  • 监控windows系统交互

10.1 驱动与内核代码

  • 驱动程序分析的困难性
    • 常驻内存,负责响应用户态请求
    • 应用程序不直接与驱动程序通信,而是直接访问设备对象,向具体的物理设备发送请求
  • 驱动程序必须加载到内核空间
  • 驱动首次被加载:DriverEntry函数被调用
  • 驱动:通过注册回调函数提供功能
    • 区别于DLL:通过导出表
  • 驱动对象&设备对象:windows为每个驱动创建一个驱动对象,以参数的形式传递给DriverEntry函数,DriverEntry函数用会调函数填充这个驱动对象,再创建一个可以被用户态应用程序访问的设备对象,应用程序与驱动的交互请求都通过这个设备对象进行
  • ReadFile:用户态应用程序获得硬件设备的文件句柄——>调用ReadFile——>内核处理——>驱动程序回调函数响应对I/O设备的读请求
  • DeviceIoControl:请求内核恶意组件最常见函数
    • 作用:用户态应用程序传递一个任意长度的缓冲区数据作为输入,接收一个任意长度的缓冲区数据作为输出
  • 内核处理用户态请求
    10.1.jpg
  • 一些内核恶意代码没有明显的用户态组件,也没有创建内核对象,仅仅运行在驱动程序中
  • 恶意驱动与内核组件交互
    • ntoskrnl.exe:操作系统核心功能
    • hal.dll:与主要硬件设备交互

10.2 安装内核调试

  • 内核调试
    • 设置虚拟机操作系统,开启内核调试
      • C:\boot.ini (/debugport=COM1【使用哪个端口连接调试系统与被调试系统】 /baudrate=115200【指定串口数据传输速率】)
    • 配置vmware使虚拟机与宿主系统之间有一条虚拟化的串口
    • 宿主操作系统配置windbg

10.3 使用windbg

  • 从内存中读取(dx addressToRead)
    • da:以ASCII文本显示
    • du:以Unicode文本显示
    • dd:以32位双字节显示
  • 改变内存的值
    • ex addressToWrite dataToWrite
  • 算数操作符
    • +、-、*、/
    • dwo:解引用32位指针,查看该指针代表地址的值(dwo (esp+4))
    • du dwo (esp+4)
      • 以宽字节字符串显示函数的第一个参数
  • 设置断点
    • bp 设置基本断点
      • 当断点命中时,可以指定将被执行的操作
    • g 完成操作后继续执行
    • bp GetProcAddress “da dwo(esp+8); g”
      • 当GetProcAddress被调用时中断,打印函数第二个参数,然后继续执行
      • 函数的第二个参数是函数名
  • 列举模块
    • lm
      • 列举加载到进程的所有模块
        • 用户模式的EXE和DLL
        • 内核模式的内核驱动
      • 如同OllyDbg中的内存映射

10.4 微软符号表

  • 定义:包含某些函数和变量的名字
  • 作用:
    • 告诉我们某个函数创建了一个进程的地址空间
    • 可以使用函数名称查找内存中的函数和数据
  • 搜索符号
    • moduleName!symbolName
    • moduleName
      • 表示.EXE、.DLL或者.SYS 文件名(不含扩展名)
      • ntoskrnl.exe是个特例,它被命名为 nt
    • symbolName
      • 与这个地址相关联的函数名
    • 例如: u nt!NtCreateProcess
      • 反汇编该函数
    • x:允许使用通配符来搜索函数或符号
      • x nt!CreateProcess:显示导出函数和内部函数
    • ln address:列出最接近给定内存地址的符号
  • 延时断点
    • bu:用符号在没有加载的代码中设置一个延迟断点
    • $iment:确定一个给定模块的入口点
    • bu $iment(driverName):在驱动代码执行前,驱动入口点处中断
  • 查看结构信息
    • 包括未公开的(恶意代码常用)
    • dt moduleName!symbolN:现实结构
    • dt moduleName!symbolN address:从地址address显示结构中的数据
  • 初始化函数:DriverInit,唯一一个在驱动每次被加载时都调用的函数,有时恶意代码会将全部恶意载荷放到该函数中
  • 配置windows符号表

10.5 内核调试实践(在内核中读写文件的驱动)

  • 从内核空间写文件的好处:更加难以被察觉(CreateFile 和 WriteFile——>NtCreateFile 和 NtWriteFile,导入函数中看不到)
  • 用户空间的代码
    • CreateService:创建驱动,参数dwServiceType 是 0x01(内核驱动)
      10.2.jpg
    • CreateFileA:创建一个文件来获得内核设备句柄(.\FileWriter\Device,7.1.4特殊文件)
      10.3.jpg
    • DeviceIoControl:恶意代码调用该函数向内核驱动发送数据(不唯一,CreateFile、ReadFile、WriteFile都可)
      10.5.jpg
  • 内核模式代码
    • 运行windbg如果开启了详细信息输出功能,将会在每次内核模块载入时得到通知
    • 调试恶意代码时,如果有内核模块被加载,该模块值得怀疑(排除KMixer.sys)
    • !drvobj 驱动名字:找到对应名字的驱动对象,可以获得驱动对象的地址
    • !object \Driver:浏览驱动对象,列出\Driver(根命令空间)中的所有对象
    • dt 驱动名字 address:查看驱动对象数据结构
      • MajorFunction:指向主函数表首项的一个指针,主函数表包含从用户空间调用恶意驱动时执行了什么操作
    • windows内核使用UNICODE_STRING结构
    • RtlInitUnicodeString:用来创建内核态字符串
    • ZwCreateFile:在内核态创建文件,对象名用来表示所涉及的主设备(大多数前缀是\DosDevices)
  • 查找驱动对象
    • 查找加载到内核空间的驱动程序
    • 应用程序直接与设备进行交互,而不是驱动,用户态识别设备对象再去查找驱动对象
    • 使用 !devobj 找到更多关于驱动对象的信息,能得到设备对象句柄
    • 设备对象提供一个指向驱动对象的指针,通过这个对象指针可以获得驱动程序的分发函数表
    • 使用 !devhandles 获得拥有相应设备句柄的所有用户态应用程序列表(使用该驱动的程序)
    • 知道了具体是哪个应用程序被感染了

10.6 Rootkit

  • 定义:通过修改操作系统内部函数来隐藏自己存在的痕迹
  • 系统服务描述表(SSDT)挂钩技术
    • SSDT:微软使用它来查找进入内核的系统调用,通常不被第三方应用程序或驱动程序访问。
    • 内核态代码只能被用户态的SYSCALL、SYSENTER或INT 0x2E指令访问
    • 举例:
      10.6.jpg
      • EAX=0x25,是NtCreateFile函数的序号,代码进入内核后系统使用这个值作为SSDT的索引
    • 挂钩后,rootkit会改变ssdt中某项的值,内核态系统调用时就变成运行rootkit的代码(指针)
  • rootkit分析实战
    • 分析已感染系统是否安装有恶意驱动
    • 检查SSDT,观察其函数指针是否在NT模块的地址范围内,识别挂钩函数
      10.7.jpg
    • lm:列举打开模块,找出是哪个模块包含了挂钩函数地址,定位驱动程序
      10.8.jpg
    • 查找挂钩代码。开始分析驱动。
      • 安装挂钩的代码段
        10.9.jpg
        • 实现了挂钩NtCreateFile函数的功能,1、2处创建了两个字符串,Rootkit用它们调用MmGetSystemRoutineAddress查找NtCreateFile函数和KeServiceDescriptorTable的导出地址(ntoskrnl.exe模块导出)
          10.10.jpg
        • 有了SSDT和NtCreateFile的地址,接下来4~5之间遍历SSDT,直到找到匹配NtCreateFile地址的值,使用挂钩函数的地址覆盖即可(6)。
      • 执行挂钩的函数
  • 中断
    • 有时rootkit使用中断来干扰系统事件,执行代码
    • 中断允许硬件触发软件事件
    • IoConnectInterrupt: 驱动调用为中断注册处理程序,然后为这个中断指定中断服务例程 (ISR),当触发中断时,该例程会被调用
    • IDT:中断描述符表
      • 存储ISR信息
      • !idt:查看idt
      • 正常IDT:所有中断都在微软签名的驱动中

10.7 加载驱动

  • 假设要分析的恶意代码都有一个加载它的用户态应用程序。
  • OSR Driver Loader工具

10.8 Windows Vista、Windows 7和 x64 版本的内核问题

  • BCDEdit程序替换boot.ini决定引导哪个系统
  • PatchGuard:添加内核保护补丁机制,阻止第三方程序修改内核。能够感染调试过程,因为调试器在插入断点时 会修改代码
  • 从64位版的Vista开始强制执行驱动签名
    • 只加载有数字签名的驱动
    • 有效防护!
    • 可以通过在BCDEdit中指定nointegritychecks关闭驱动签名功能