BIOS Rootkit实现分析与检测技术研究系列之--IVT Hook 1


本节目录
1. 引言
2. IVT和IVT Hook介绍
3. 使用Bochs调试BIOS
4. 小结


引言

    BIOS Rootkit为了达到控制系统流程的目的,一般会采用Hook IVT,即Hook中断向量表的方式来实现。IVT Hook的实现和检测,涉及许多具体的问题。因此,我把IVT Hook分几部分来进行讨论。在本节和下面几节中,我们将讨论如何借助Bochs的帮助来查看原始IVT、分析IVT Hook情况以及在此基础上写一个简单的IVT检测程序。闲话少说,这就开始我们的旅程吧。



IVT和IVT Hook介绍

    1. 什么是IVT
    IVT(Interrupt Vector Table)即中断向量表。对于IVT的详细解释,这里主要参考了Intel 公司的《Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide》、王爽先生的《汇编语言(第二版)》和张银奎先生的著作《软件调试》(书很厚,但物超所值)。具体描述可以参见上述著作。
   由于BIOS Rootkit存在于BIOS中,其初始运行环境为实模式。所以,我们讨论的IVT以及IVT Hook,都是针对实模式下的IVT来进行的。
    好,首先我们回忆一下:什么是中断?CPU在执行指令时因为检测到预先定义的某个(或多个)条件而产生的同步事件(如除法指令的除零错误),大部分书籍称之为内中断(《软件调试》一书详细阐述了中断和异常的区别)。
    CPU收到中断信息后,需要对中断信息进行处理,而用来处理中断信息的程序称为中断处理程序。所谓中断向量就是中断处理程序的入口地址,而中断向量表(IVT)就是中断处理程序入口地址的列表。可以看到,IVT就是一个入口地址表,如同Windows内核中的SSDT一样。对其进行Hook的方法与Hook SSDT类似。而Hook的目的,就是控制中断处理流程,进而控制系统的运行。
    IA-32架构规定,在实模式(Real Mode)下,IVT在内存中保存,起始地址为0。从内存0000:0000到0000:03FF的1024个内存单元中存放着中断向量表(IVT)。下图来自《Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide》:

    

     偷个懒,直接把《软件调试》上的相关描述进行引述,原文描述参见上面Intel的文献:
    中断调用采用int n的形式,n 代表中断向量号(n=1,2,3……)。这样通过n*4这样的计算,可以迅速定位到各个中断号对应的内存地址。n*4+2存放的是中断向量的段地址,n*4存放的是中断向量的偏移地址(实模式下的汇编程序设计请参考文献)。这样IVT的1024个内存单元总共可以存放256个中断向量。
    对于中断过程的执行步骤,描述如下:
    1)将代码段寄存器CS和指令指针寄存器(EIP)的低16位(IP)压入堆栈。
    2)将标志寄存器EFLAGS的低16位(FLAGS)压入堆栈。
    3)清除标志寄存器的IF标志,以禁止其他中断。
    4)清除标志寄存器的TF(Trap Flag)、RF(Resume Flag)、AC(Alignment Check)标志。
    5)使用向量号n作为索引,在IVT中找到对应的表项(n*4+IVT表基地址)。
    6)将表项中的段地址和偏移地址分别装入CS和IP寄存器中,并开始执行对应的代码。
    7)中断例程总是以IRET指令结束。IRET指令会从堆栈中弹出前面保存的CS、IP和标志寄存器值,然后返回执行被中断的程序。
    
    2. IVT Hook
    如果在第6个步骤,把我们自行设计的程序所在的段地址和偏移地址装入CS和IP寄存器中,CPU将会运行我们的程序。这就是IVT Hook的理论基础。这里的Hook技术和传统Hook的概念没有任何区别。


使用Bochs调试BIOS

    在进行IVT Hook实例分析之前,先说一下我使用Bochs进行BIOS调试的一些体会,这也是进行后续讨论的实践前提。
    这个系列的《简单ISA模块编写》一篇中,曾提醒大家进行BIOS刷写实验存在一定的风险。的确,一个程序编写上的小错误,或者刷新过程中电压的不稳定等等因素,都可能造成刷写的失败。而失败的结果往往都是不能正常引导计算机启动,即无法开机。在实验过程中,我把BIOS刷坏,开始都是抱去电脑维修店进行维修。对于刷写BIOS服务,我们那的当地价是30块钱刷一片,50块刷两儿。刷的时候还要求你连主板一起也拆了去。费钱、费力、费时间。于是,我在淘宝上邮购了一套硬件刷写BIOS的编程器,问题多多,一二百的编程器还是不能和维修店里的一二千的相比。刷写无数次失败后,我决定找到一种价廉物美的实验方法。第一个感觉就是:虚拟机。
    早就听说现在的虚拟机对BIOS能够进行仿真操作,先后从网上收集资料,然后自己实验比较。实验发现,对于主流的VMWare、VirtualPC,对于BIOS实验较为困难。如VMWare的BIOS定制很麻烦,而且缺少通用性。因为和本节内容关系不大,所以具体细节以后有时间补上。众里寻他千百度,终于,第一次感受到了Bochs的强大。
    Bochs是很出名,这里不多介绍。大家平时多用Bochs进行操作系统的调试,进行BIOS调试的时候可能相对较少。这里,我说说对BIOS调试的体会。这里我使用的Bochs版本为v2.3.7,在其帮助文档中,我们可以发现:optromimage 选项(It's amazing!)。这个选项允许我们对最多4个附加BIOS模块(如ISA模块)进行测试(当然包括调试),分别记为:optromimage1、optromimage2、optromimage3、optromimage4。下面是帮助原文:

  -------------------------------------------------------------------------------------------
    Example:    optromimage1: file=optionalrom.bin, address=0xd0000 

    This enables Bochs to load up to 4 optional ROM images.
    Be sure to use a read-only area, typically between C8000 and EFFFF. These optional ROM images should not overwrite the rombios (located at F0000-FFFFF) and the videobios (located at C0000-C7FFF).
    Those ROM images will be initialized by the BIOS if they contain the right signature (0x55AA).
    It can also be a convenient way to upload some arbitrary code/data in the simulation, that can be retrieved by the boot loader
  -------------------------------------------------------------------------------------------

    这个选项应写在.bxrc配置文件中。帮助中建议我们把附加模块的加载地址设定在C8000 和EFFFF之间,大家可以对照《简单ISA模块编写》一篇中的BIOS内存分布图来理解。其实,经过摸索发现,Bochs指对设定在0xd0000~0xe0000范围之间的附加模块能够提供很好的支持,而其他范围基本都以失败告终。另外,大家还要注意一点就是:我们设计的附加模块(如ISA模块),除了本身大小应为512字节的倍数外,还要注意optromimage的支持范围,即0xd0000~0xe0000。这个范围大小为64K,因此如果你的附加模块总量,即最多4个附加模块的总大小不能超过64K。否则,Bochs会出现错误提示,并只会顺序调用在范围内的一个或几个模块。这个问题曾困扰我很久,后来反复研究optromimage的帮助终于明白。希望能给大家在做类似工作时有所帮助。
    这样我们就可以把《简单ISA模块编写》一篇中提到的登录框程序,用Bochs来运行一下。配置文件相关选项就这样写:
  --------------------------------------------------------------------  
    # filename of ROM images
    romimage: file=../BIOS-bochs-latest
    optromimage1: file=ISAOEM_NASM.bin, address=0xd0000
    vgaromimage: file=../VGABIOS-lgpl-latest
  --------------------------------------------------------------------  
    这里除了我们刚刚介绍过的optromimage,还有romimage和vgaromimage。romimage允许你替换整个BIOS文件,这对特定BIOS Rootkit的编写有用,如Kris提到的直接修改BIOS入口的跳转指令:jmp xxxx,xxxx换成我们的程序入口。这个问题可以单独进行讨论。vgaromimage选项允许进行显卡BIOS的调试。下一步进行显卡BIOS Rootkit研究时,可能要借助它的帮忙。:)
    Bochs的调试命令和方法这里不多介绍,大家可以参阅Bochs的帮助文件。把我们的登录框程序和修改了的.bxrc配置文件放在同一目录下,运行后,我们会发现登录框程序运行。由于Bochs对于图形显示支持还不是很好,所以在Bochs中,你会发现提示输入密码的字符串没能很好显示,但这并不影响我们对功能的调试。效果图就不附上了。

    
小结

    这一节我们对实模式下的IVT和IVT Hook进行了理论的铺垫,并对用Bochs进行BIOS调试的一些细节进行了探讨。在下一节中,我们来实际分析一下IVT Hook的应用。


    
待续... 

  • 标 题:BIOS Rootkit实现分析与检测技术研究系列之--IVT Hook 2
  • 作 者:ppanger
  • 时 间:2008-10-29 16:50

BIOS Rootkit实现分析与检测技术研究系列之--IVT Hook 2


本节目录
1. 引言
2. 静态剖析leaving.bin
3. 动态调试leaving.bin
4. 小结
5. 附件


引言

    上节我们对IVT Hook技术进行了理论铺垫,这节我们通过对实际的BIOS Rootkit进行分析,来加深对IVT Hook技术的理解。对于已发表的BIOS Rootkit,目前只能找到的是:IceLord。IceLord在2007年发表了一篇《BIOS RootKit:Welcome Home,My Lord!》的文章。文中描述了BIOS Rootkit实现的相关技术,并给出了实现的二进制演示文件IceLord.exe(我拿到的是IcLord.exe,这并不影响本文的讨论,下面论述我们姑且叫做IceLord.exe)。而IceLord.exe用于嵌入BIOS的ISA模块文件为:leaving.bin。因此,在这个小节中我们主要对leaving.bin进行讨论。


静态剖析leaving.bin

    leaving.bin是ISA模块文件,也是整个IceLord.exe的核心。它作为资源类型附加于IceLord.exe文件中。直接用IDA Pro加载分析,如图:

    

    可以看到leaving.bin的标准ISA模块头。大小为16进制40h,即64*512=32K。

    在loc_66标号处,如图:

    

    我们看到橙色显示的1600h。用鼠标指向1600h后,IDA把我们引向该字段代表的区域,如图:
    

    我们可以清楚的看到“MZ”标志。我们知道“MZ”是Windows的PE可执行文件开头的特有标志,通过分析,这正是IceLord自带的Payload驱动文件protector.sys。为了不影响IDA对leaving.bin的分析,我们用WinHex把这个程序提取后组成一个新的leaving.bin程序,暂时取名为leaving_new.bin。然后再用IDA加载进行分析。
    在《BIOS RootKit:Welcome Home,My Lord!》中,作者提到,IceLord控制CPU流程的方法是通过hook IVT来实现的。即通过hook中断19h来实现。在《IVT Hook 1》小节我们对实模式下的中断向量表IVT(Interrupt Vector Table)进行过介绍。我们注意到,在调用具体中断的过程中,系统在第5、6步的操作是(请参阅《IVT Hook 1》小节):

  -------------------------------------------------------------------------------------------------
    5、使用向量号n作为索引,在IVT中找到对应的表项(n*4+IVT表基地址)。
    6、将表项中的段地址和偏移地址分别装入CS和IP寄存器中,并开始执行对应的代码。
  -------------------------------------------------------------------------------------------------

    对于int 19h中断,系统使用向量号19h(注意这里是16进制的19),然后在IVT中找到表项:19h*4+0(IVT默认加载到内存0000:0000处),即地址0000:0064h处。然后把19h对应的中断处理函数的段地址和偏移地址放入CS、IP寄存器里执行。如果我们把0000:0064h该为0000:xxxx,xxxx代表我们自定义的函数地址,系统就会先执行我们定义的函数,以达到控制系统流程的目的,这种方法就是典型的Hook法。Hook直译为钩子,通过钩子控制程序流程的方法是一种程序员普遍使用的方法,微软公司曾发行过detour函数库来帮助程序员简化这类开发。同时,Hook法被广泛使用在各类Rootkit开发当中,《ROOTKITS--Windows内核的安全防护》一书对此有详细描述。通过钩子来控制流程的方法同样也适用于BIOS Rootkit(关于如何hook中断的汇编实现,请参阅王爽.的《汇编语言(第二版)》)。
    我们来看一下leaving.bin是如何实现对int 19h中断的hook操作的,如图:

    

    leaving.bin程序首先对原始的int 19h调用地址进行保存,以待后面进行恢复调用。然后,hook掉原有地址,加入我们的自定义函数地址。图中New_int19h即为leaving.bin作者自定义的hook函数,当int 19h中断被系统调用时,会首先执行New_int19h,如图:

    

    在新的int 19h中断处理函数中,我们发现leaving.bin的作者又hook了int 13h中断,中断int 13h是标准的处理磁盘的BIOS中断类型。这种思路也符合IceLord在文献中的描述,即hook int 19h,再hook int 13h,以达到操作磁盘的目的。如何检测这种hook操作,我们在这个系列的后续小节进行讨论。
    静态剖析leaving.bin的讨论就在此告一段落。


动态调试leaving.bin

    在新的int 19h中断处理函数中,我们发现leaving.bin的作者又hook了int 13h中断,中断int 13h是标准的处理磁盘的BIOS中断类型。这种思路也符合IceLord在文献中的描述,即hook int 19h,再hook int 13h,以达到操作磁盘的目的。
    这种hook int 19h中断的操作是否真正执行,我们需要验证。验证的执行,我们需要借助Bochs的帮助。我们在上节介绍过Bochs强大的调试功能,它甚至能够调试BIOS和操作系统。在开始调试之前,我们首先来回忆一下Bochs调试器的几条常用调试命令(更详细命令使用请参阅Bochs使用帮助):

  -------------------------------------------------------------------------------------------------

    b addr  在某物理地址设置断点
    c  继续执行,直到遇上断点
    s  单步执行
    xp   查看内存内容
    u   对当前地址进行反汇编
  -------------------------------------------------------------------------------------------------

    首先要加载我们的目标文件leaving.bin。结合系列的上一篇介绍,Bochs对于文件的加载是通过改写配置文件来执行的。配置文件后缀名默认为.bxrc,文件由许多选项组成:如romimage:选项,代表需要加载的主BIOS文件的位置,默认为file=../BIOS-bochs-latest。又如boot:选项代表操作系统加载的位置,默认为c,即c盘。在这里我们需要一个特殊的选项:optromimage选项。
    optromimage选项允许Bochs加载用户自定义的BIOS附加模块,如ISA模块。这正符合我们的要求。我们的Bochs配置文件的关键选项如下:

  -------------------------------------------------------------------------------------------------
    # filename of ROM images
    romimage: file=../BIOS-bochs-latest
    optromimage1: file=leaving.bin, address=0xd0000
    vgaromimage: file=../VGABIOS-lgpl-latest
  -------------------------------------------------------------------------------------------------

    在Bochs安装目录下新建一个bios文件夹,然后把Bochs自带的Linux Demo文件夹下的所有文件拷贝一份到bios文件夹中,并把leaving.bin模块文件也拷贝一份到这里。然后改写.bxrc配置文件相应处为以上选项。特别需要加入optromimage选项,保存配置文件。在该配置文件上点击鼠标右键选择“调试”,Bochs将打开调试窗口开始进行调试,如图:

    

    选择默认选项6,程序跳入BIOS开始执行,我们看到前面分析过的BOOTBLOCK中的跳转语句,这里是jmp far f000:e05b,如图所示:

    

    我们调试的目的是需要查看leaving.bin模块是否真的hook了int 19h中断的调用。最好的方法就是跟踪int 19h中断调用,看其是否跳入leaving.bin自定义的函数地址来。跟踪需要断点的帮忙。在对BIOS设置断点的实际验证中,很多在物理地址设置的断点都未能被出发。由于Bochs没有对设置中断断点的命令,所以我们在这里使用一个笨办法,就是通过u反汇编命令直接在调试窗口查看调用int 19h中断的语句,然后直接在其所在地址下断。首先在调试窗口中输入s单步执行命令,使得程序进入BIOS主程序。然后我们输入命令:u /500,代表从当前位置开始反汇编500条语句,拖动调试窗口下拉条到顶部,我们发现了int 19h中断调用的语句地址为0x000fe2a7,如图:

    

    在地址0x000fe2a7处下断:b 0x000fe2a7。然后输入c执行程序命令,我们成功来到了断点处,如图:

    

    输入s,并进行反汇编:u /20,我们看到了真实的被leaving.bin hook过的中断处理函数入口:0x00097ca2,如图:

    

    对照我们在IDA静态反汇编的结果(对照上面的New_int19h反汇编结果),用Bochs动态调试的得到的与其完全吻合。这也真实了leaving.bin确实如期所说,对int 19h进行了hook操作,进而控制了CPU的执行流程。
    继续剖析leaving.bin文件,文献中提到其对于操作系统改写的实现,主要是基于对Ntldr这个Windows启动文件特征码的搜索上,我们在IDA的反汇编结果中也得到了证实,如图:

    

    可以看出程序对特征码0ABF3C033h的识别工作。联系leaving.bin对于hook int13h的一些程序片段,如图:

    

    我们不难发现,leaving.bin对NTLDR文件进行内存特征码搜索的思想,受到了著名Boot Rootkit项目eEye BootRoot的启发。eEye BootRoot项目由eEye公司安全研发人员Derek Soeder和Ryan Permeh创建,是一个旨在研究如何攻击MBR(Master Boot Record)从而实现Rootkit的研究项目。其目的是提供一种先于操作系统执行Rootkit的可能性,并研究对其的检测和防御技术。eEye BootRoot项目在2005年Black Hat USA大会上首次公布。可以访问eEye的网站进行进一步了解。
    在完成特征码的搜索操作后,leaving.bin会把保存过的原始int 13h中断向量值,重新写回原处,如图:

    

    这样的写回操作,会干扰我们将在系列后续小节中编写的,IVT Hook检测程序的检测结果,敬请期待。:)
    动态调试leaving.bin的讨论就在此告一段落。



小结

    在这篇文章中,我们详细讨论了BIOS Rootkit的ISA模块leaving.bin的执行情况。特别从静态和动态两个方面对IVT Hook技术进行了探讨。通过对BIOS Rootkit的实例分析,让我们对IVT Hook技术有了更深的理解。

附件

    附件里附上删除了protector.sys的leaving_new.bin和leaving_new.idb,供大家分析。

附件.rar


    
PS:为了给大家直观的印象,在这个小节特意多抓了些图片,影响网页速度了。


待续...