BIOS Rootkit实现分析与检测技术研究系列之--简单ISA模块编写
 
本节目录
1. ISA总线简介
2. BIOS文件分析
3. 编写简单ISA模块
4. 小结
5. 附录
6. 相关附件
 
引言
    
    作为目前BIOS Rootkit主要存在方式,在本小节中,我们一起来讨论一下简单ISA模块的编写。在这个小节里,我们主要讨论Award BIOS(资料相对多一些 :p)。
 
ISA总线简介
    
    20世纪80年代初期,IBM在推出自己的微机系统IBM PC/XT时,就定义了一种总线结构,称为XT总线。这是8位数据宽度的总线。随着IBM采用80286 CPU,推出IBM PC/AT微机系统,又定义了与XT总线兼容的16位的AT总线。ISA总线(Industrial Standard Architecture)即AT总线,它是在8位的XT总线基础上扩展而成的16位的总线体系结构。
    目前ISA总线标准基本被PCI(Periphearl Component Interconnect)总线标准替代。但在BIOS中还保留有对ISA调用的接口,主要是考虑到兼容老旧主板的需要。目前BIOS Rootkit多采用ISA模块编写方式,主要还是考虑到编写简单、向下兼容性好的优点。
    下面我们逐步来进行分析。
 
BIOS文件分析
    
     1. BIOS文件的静态分析
   1) BIOS文件一般结构分析
    固化在BIOS芯片中的BIOS文件保存着计算机最重要的基本输入输出的程序、系统设置信息、开机上电自检程序和系统启动自举程序。这些程序采用模块化方式组织在一起,Award、AMI或者Phoenix都采用这种组织方式。为了节约成本,这些模块一般都采用压缩的方式来进行存储。在需要调用模块时,在解压缩到内存执行。压缩算法主要采用LHA类似的压缩算法(对于LHA压缩算法还没深入了解 )。用16进制软件打开BIOS文件,我们可以发现“-lh5-”的字样,通过搜索这个字符串,也可以找出这个BIOS文件存在多少被压缩的模块。
    通常来说BIOS文件一般都包含着BOOTBLOCK和各种初始化微程序,自动检测硬盘和CD驱动器、输出PnP/PCI设备表等硬件设备程序,支持ACPI高级电源管理的启动程序。另外还有各个主板厂家自己开发的功能扩展程序模块,以及各个主板厂家的BIOS启动logo等。
    
    2) Award BIOS文件结构分析
    Award BIOS文件结构可以通过cbrom程序来查看。cbrom的查看功能可以正常运行于DOS模式或Windows的虚拟86模式。在Windows XP下运行虚拟86控制台程序cmd.exe(本文实验环境请参阅附录),把需要分析的BIOS文件(这里为awdbios.bin)和cbrom所在路径放在一起,然后在cbrom所在路径下输入:
    cbrom.exe awdbios.bin /D 
      
     

 
     结果如下:
 
    CBROM V2.20 (C)Phoenix Technologies, Ltd 2001 All Rights Reserved.
              ********  awdbios.bin BIOS component ********
 No. Item-Name         Original-Size     Compressed-Size       Original-File-Name 
====================================================================   
0. System BIOS        20000h(128.00K)   13E89h(79.63K)         9a69vpab.BIN
1. XGROUP CODE     0B540h(45.31K)    07E64h(31.60K)         awardext.rom
2. CPU micro code     04000h(16.00K)     03F9Fh(15.91K)        CPUCODE.BIN
3. ACPI table          04067h(16.10K)    01994h(6.39K)          ACPITBL.BIN
4. YGROUP ROM      05F00h(23.75K)    03DC5h(15.44K)        awardeyt.rom
5. GROUP ROM[ 0]     038A0h(14.16K)   01A4Dh(6.58K)         _EN_CODE.BIN
6. Flash ROM         0A016h(40.02K)    0577Bh(21.87K)        AWDFLASH.EXE
7. PCI ROM[A]        0A000h(40.00K)    05F74h(23.86K)         RTSpxe_m.lom
8. ISA ROM[1]        10000h(64.00K)     0F062h(60.10K)         romos.bin
 
  Total compress code space  = 5A000h(360.00K)
  Total compressed code size = 41583h(261.38K)
  Remain compress code space = 18A7Dh(98.62K)
 
                          ** Micro Code Information **
Update ID CPUID  |  Update ID CPUID  |  Update ID CPUID  |  Update ID CPUID
-------------------------+---------------------------+----------------------------+-------------------------
PGA478 14   0F0A|  PGA478 2E   0F12|  PGA478 01   0F21|  PGA478 08   0F23
PGA478 1E   0F24|  PGA478 05   0F13 |  PGA478 15   0F25|  PGA478 37   0F27
PGA478 17   0F29|  
 
    从显示结果可以看出,该BIOS中包含9个模块。BIOS通常以压缩的形式保存微程序(一般使用LHA压缩算法),这在显示结果中可以清楚的看到:每个模块类型、原始大小、压缩后的大小以及初始名字。
    第一个模块为9a69vpab.bin,cbrom识别为System BIOS。BIOS主要的代码都集中在这里。其中包括BOOTBLOCK和各种初始化微程序。BOOTBLOCK是BIOS的加载器,它负责在启动时初始化芯片组,把主要的BIOS代码解开,放入主内存。它也负责检查BIOS校验和,启动紧急恢复程序或切换到备用BIOS。BIOS加载入内存后,BOOTBLOCK被加载到0FE000h~0FFFFFh这段地址中。为了和以往的IBM PC XT/AT达成撤销性兼容,程序结构、流程、跳跃点和若干变量参考几乎已经固定。一般BIOS版本在做日后的追加和修改都基本不会改动这个部分。业界一般称这部分为“激活区段”,即“Boot Block”。
    第二个模块awardext.rom为BIOS的扩展部分,它在BIOS启动过程的最后阶段初始化设备。这个模块主要负责自动检测硬盘和CD驱动器、输出PnP/PCI设备表等工作。
    CPUCODE.BIN模块只是一组微程序。这组微代码用于修正开发中发生的错误。Intel公司在1996年推出的Pentium Pro处理器,具备一项称为“微码更新”(Microcode Update)的功能。在某一批集成电路存在设计中的Bug时,可以用微码的方式加以修正。这就是这个模块的功能。在AMD和Intel的网站有最新的用于插入BIOS中的微代码,提供微码更新的功能。
    ACPITBL.BIN包含ACPI表。ACPI(Advanced Configuration and Power Interface)不仅是简单的电源管理器,它还能控制所有设备的主总线,甚至控制BIOS。可以参考John Heasman的文章《Implementing and Detecting an ACPI BIOS Rootkit》。
    awardeyt.rom类似于awardext.rom,也是BIOS扩展部分。它是各个厂商自己定制的不同于标准AwardBIOS的功能,实际上几乎所有的厂商都会增加这一部分内容。
    _EN_CODE.BIN模块是BIOS使用的一组ASCII字符串。
    AWDFLASH.EXE是嵌入到BIOS中的BIOS刷新工具,即上篇文章介绍的AwardBIOS Flash Utility程序。它允许在开机时运行该程序,对BIOS进行刷新和备份操作。
    RTSpxe_m.lom为主板厂家在BIOS中内置的程序模块,包括一些集成设备的驱动程序集合。
    romos.bin为我们加入的BIOS代码。可以注意到该模块显示为ISA模块,这正是目前BIOS Rootkit广泛采用的模块嵌入方式。实际上这个模块来自于一个开源的BIOS ROM嵌入项目ROMOS(Martin. The ROMOS Project. http://rayer.ic.cz/romos/romos.htm)。我们后面的许多程序实例都借鉴于这个项目。
    cbrom并不能显示其他隐藏的模块,如decomp_blk.bin是独立的LHA解包器,负责对压缩模块的解压缩工作;又如boot_blk.bin模块,是真正的BOOTBLOCK模块,其包含在BIOS主模块9a69vpab.bin中等等。这些模块都可以通过Award BIOS Editor 1.0来查看和提取。
    
    上面对于模块的具体描述主要来自Kris Kaspersky的《Shellcoder 编程揭秘》一书,上面对于BIOS模块的叙述很详细,不乏许多真知灼见,大家可以参考一下。
    接下来,我们对BIOS文件中的模块进行详细剖析,以对其有一个直观的认识。
    主模块9a69vpab.bin中包含着BOOTBLOCK。而BOOTBLOCK加载到内存后位于000FE000h~000FFFFFh这个区段,而BIOS的入口点却在000FFFF0h。入口点为何不在区段开始?其实,在000FFFF0h~000FFFFF这16个字节中存放着一条跳转指令,用于调转到BIOS真正的执行入口。
    用Award BIOS Editor 1.0打开BIOS文件awdbios.bin,将上述模块分别提取出来(选择菜单“Actions->Extract All”)。然后交给WinHex和IDA Pro做进一步分析。用WinHex打开提取出的文件9a69vpab.bin,找到文件末尾,可以看到在文件尾部向前16个字节处的一段16进制数值:
    EA 5B E0 00 F0
    
     如图:
   

 
    用IDA Pro打开文件9a69vpab.bin,选择16位汇编模式,找到文件尾部的这段数值,在EA字符上按C键(进行反汇编操作),我们得到这样的汇编指令:
    jmp far ptr  0F000h : 0E05Bh
     如图:
   

    
     这句指令表示一个实模式下的跨段跳跃,跳到段地址为0F000h,偏移地址为0E05Bh的地方继续执行,即物理地址0FE05Bh处(BIOS内存分布请参看下面的分布图)。这基本是所有BIOS的BOOTBLOCK的执行方式。
 
    BIOS内存分布图(来源于互联网):
    

 
     对于其他的模块我们更关心ISA/PCI类型的模块,如ISA模块romos.bin。用IDA Pro可以顺利的进行反汇编。IDA Pro不能识别模块的进入点,需要对ISA模块格式有清楚了解后进行手动反汇编(ISA总线知识见上面描述)。ISA模块一般用于管理集成的ISA控制器(例如额外的COM端口,当然也可以是我们的BIOS Rootkit)。现在的主板上早就没有了ISA控制器,然而BIOS为了向后支持的需要,同样提供了对ISA模块的支持。ISA模块编写相对简单易行,因此成为目前BIOS Rootkit主要采用的方式。
    主BIOS模块9a69vpab.bin执行后,载入ISA模块,它将得到所有设备的完全控制权,包括PCI总线。也有一些BIOS Rootkit和PCI Rootkit对其增加了定制的PCI模块。定制的PCI模块伪造了PCI设备标志符,使它与真实设备的标志符相对应。PCI头伪造技术在后面的系列中有详细分析。ISA模块文件格式如下:
 
    ==============================================
      文件头部分  55h 0AAh            开头必须是这两个字节作为启动标志
                  01h                   紧接的一个字节代表ISA模块的大小为  
                                       N*512B 这里就是1*512=512B
                 jmp 程序进入点       一条跳转指令进入模块主体
    -----------------------------------------------------------------------------------
      文件运行主体  程序进入点:     ISA模块主体
                  …
                  …
                  …
    -----------------------------------------------------------------------------------
      文件结尾    一个字节         必须为整个模块的校验和
    ==============================================
 
    另外,整个ISA模块大小必须为512字节的倍数。
 
   Kris Kaspersky在《Shellcoder 编程揭秘》一书中,编写了一个简单的用于嵌入BIOS的ISA模块程序。程序采用FASM编写,作用是在BIOS启动的时候设置一个登录界面,只有输入正确的密码才能继续进行系统加载,否则会循环提示用户输入登录密码。
    由于FASM语法的特殊性,这个程序可能很多人编译通过后,在实际运行测试的时候都不能正常运行。经过摸索,发现问题出在开头的第一句:
    DB    55h, 0Ah
     上面我们刚说过ISA模块的开头必须为 55h AAh 这样的标志,否则系统将视为非法。但由于FASM语法的特殊性,如果程序写成:DB    55h, 0AAh 的话,将编译不通过,大家可以试试。这样,我们在后面进行ISA模块校验和计算的时候就会出错。所以在进行这个程序的校验和计算时,一定要先通过16进制编辑软件(如WinHex),手动将模块开头的0A字节变为AA字节,然后进行校验和的计算,并写入模块文件末尾。这样完成的模块才能够正常运行。
    对于模块校验的问题,Kris Kaspersky给出了一个IDA脚本来进行。校验方法很简单,按照《Shellcoder 编程揭秘》一书的叙述就是:“把所有的字节加起来(求和),除了100h,取余数:sum=(sum+next_byte) & 0xFF。整个块的校验和必须等于0:因此,最后的字节应该是(100h-sum) & 0xFF。”用程序实现起来也很简单,这里就不贴了,大家可以自己动手试试。把校验和写入模块文件的操作,在书中有详细描述,这里就不多说了,大家可以对照书进行参考。


我把文章中的程序改为NASM语法格式,程序如下:
;------------------------------------------------------------------------
;
;  ISAOEM_NASM.ASM 
;
;  改编自 Kris Kaspersky 《Shellcoder编程揭秘》
;  一书中例子程序的ISAOEM.ASM
;  用NASM编译
;  nasm o isaoem.bin isaoem_nasm.asm 
;  
;------------------------------------------------------------------------

org  0h        ; 运行于BIOS中

db  55h,0AAh    ; ISA模块头
db  01h        ; 大小为 1*512字节



jmp  x_code    ; 跳转到程序进入点

;------------------------------------------------------------------------
text  db  'Matrix has you!',0  ; 定义提示字符串
;------------------------------------------------------------------------

x_code:
    ; Preparing the registers
    ; ----------------------------------------
    mov  dx,101dh  ; Where to ouput (DH  Y, DL  X)
    mov  si,text    ; What to output
    xor    bx,bx    ; Initial color of characters -1
    mov  cx,1      ; Output one character at a time.

    ; Display color string.
    ; ----------------------------------------
  print_string:

    mov  ah,02h    ; Function for controlling the cursor
    int    10h      ; Position the cursor.
    inc    dl      ; Move to the next position.
    lodsb        ; Load the next character.
    test    al,al      ; Is this the end of the line?
    jz    input    ; Exit if yes.

    mov  ah,09h    ; Function for Printing a character
    inc    bl      ; Use all colors, one by one.
    int    10h      ; Print a character.
    jmp    print_string  ; Loop    

  input:  ; Wait for the password.
      ; ----------------------------
    xor    dx,dx    ; Checksum

  enters:
    xor    ax,ax    ; Function for reading a character from the keyboard
    int    16h      ; Read the character.

    cmp    al,0dh    ; Is this ENTER?
    jz    input    ; If yes, start the input again.

    xor    ah,ah    ; Clear the scan code.
    add    dx,ax    ; Compute the CRC.

    cmp    dx,'m'+'s'+'o'+']'+'['
    jnz    enters    ; If  the password is incorrect, continue.    

    retf    

times  512-($-$$)  db  0  ; 添加文件至512字节大小
;------------------------------------------------------------------------

    程序编译后,用校验工具求和写入,然后用AwardBIOS Flash Utility刷写进BIOS中。重启计算机后,运行效果如图:

    


     图片不是源程序中出现的字符,提示字符换作“Hello XPM!”。“XPM”是是女朋友的称呼,密码当然设为他的生日,其他没变(照片是用手机抓拍的,手机质量差,图像照下来不太好看 :P)。由于这个密码登录框程序位于BIOS中,所以通过给CMOS放电的方法是破解不了的。诚如Kris Kaspersky所说,只有对BIOS进行刷写操作,否则无法破解(当然换一个相同的BIOS芯片也行 ^_^)。

    2. BIOS的动态分析

    这个部分的内容主要参考陈文钦编著的《BIOS研发技术剖析》,目的是让大家对BIOS运行后的一些具体操作有个感性的认识。
    1).BIOS一般运行流程分析
    当计算机从开机的一瞬间开始,硬件特性就由CPU从主板的BIOS芯片内取得程序代码,用BIOS内部的程序代码获得控制权并且发挥作用。从CPU内外部的检测设置、激活DRAM以及针对芯片组与各种外围设备做初始化设置之后,最后驱动软盘或硬盘,直到把操作系统(如DOS,Win98/NT/2000/XP,Linux)加载成功,BIOS的开机引导工作就此告一段落,转向从事幕后的支持、协调工作,并帮助操作系统或应用程序,来处理外围设备沟通的细部操作。
    2).Award BIOS运行流程分析
    Intel 8086/8088处理器在CPU加电是所做的第一个动作就是设置:
    CS=DS=ES=SS=0FFFFh  IP=0000h
      即是将指令寄存器指向FFFF:0000h,转换成物理地址也就是000FFFF0h,随即开始获取指令码执行。BIOS加载进内存后分布图参见上面。
    从分布图中我们可以看出:BOOTBLOCK位于000FE000h~000FFFFFh这个区段,而BIOS的入口点却在000FFFF0h。确切的说,在000FFFF0h~000FFFFF这16个字节中存放着一个跳转指令,用于调转到BIOS的执行入口。这句跳转指令可以在BIOS文件的最尾部的16个字节看到)。

    就主板BIOS而言,其最重要的工作集中在以下几个方面:

    a. POST(Power On Self Test开机自检测)。
    开机系统将控制权交给BIOS时,它会针对CPU各项寄存器,先检查其是否运行正常,接下来会检查8254 timer(可编程外围计时芯片)、9259A(可编程中断器)、8237 DMA Controller(DMA控制器)的状态。

    b. Initial。
    BIOS会针对动态内存(DRAM)、主板芯片组、显卡以及相关外围的寄存器(register)做初始化(initialize)设置,并检测是否能够正常工作。

    c. 记录系统的设置值。
    BIOS会记录系统的设置值,并且会存贮在非挥发性内存(Non-Volatile RAM),如CMOS或Flash Memory(ESCD区域)等。

    d. 初始化常驻程序库。
    BIOS会将常驻程序库(Runtime Program)常驻于某一段内存中。并将其提供给操作系统或应用程序进行调用,如int 10h、int 13h、int 16h等中断调用函数。

    这些工作完成以后,BIOS会检查是否存在ISA/PCI附加模块,如果有则加载运行(如以ISA/PCI模块形式存在的BIOS Rootkit)。完成模块加载并成功运行后,BIOS将调用int 19h中断,把磁盘第0柱头0磁道1扇区的系统启动数据,即MBR(Master Boot Record)提取到内存0000:7c00处运行,从此完成BIOS向操作系统的CPU控制权移交工作。


小结

    在这个小节里,我们讨论了BIOS文件结构特性,以及对作为主要BIOS Rootkit存在方式的ISA模块,进行了详细描述。这为进一步深入探讨BIOS Rootkit的实现,先做一个热身,积累些感性的认识。


附录


    附录:我的实验平台
  ======================================================
    OS             Microsoft Windows XP (Service Pack 2)
    CPU             Intel Celeron Northwood Processor (0.13um) 2.02GH2
    BIOS          Phoenix Technologies Co.Ltd 6.00 PG  12/17/2003  512KB
    主板编号  I845PE-W83627-9A69VPABC-00
    主板芯片组  Intel 82845G/GL/GE Brookdale Host-Hub Interface Bridge 
                                  (B1-step) Epox Computer Co.Ltd
    Bochs          V 2.3.7
    NASM          V 2.03.01
    IDA Pro         V 4.7
    Cbrom         V 2.20
    Award BIOS Editor  V 1.0
    AwardBIOS Flash Utility   V 8.80
    WinFlash                  V 1.8
    ======================================================
    1. 硬件环境
       CPU:Intel Celeron Northwood Processor (0.13um) 2.02GH2
          内存:DDR2 512M
    2. 软件环境
      操作系统:Windows XP  Professional SP2;
      开发平台:NASM
         编程语言:NASM
    ======================================================

相关附件

    附件中提供了文中实验用的awdbios.bin这个BIOS文件、cbrom程序和ISAOEM_NASM.asm文件。供大家做实验用。

附件.rar


文中的程序在写入BIOS时存在一定风险,请谨慎使用!



      
    
待续...