[返回]
摘自计算机世界日报

CIH病毒的分析与预防

总参第六十一研究所  
樊海宁 刘 勇 柴丽雅

  作为首例WIN32病毒,CIH感染32-bit后缀为.EXE的PE格式可执行文件,当染毒文件在Windows 95(或Windows 98)下首次执行时,它将驻留内存、监视之后所有的打开文件操作并传染,由于其用到的技术Windows NT并不支持,因此染毒文件在NT下无法执行。下面我们以CIH V1.2(最常见的一种)为例进行分析,最后给出一个CIH免疫程序。

  首先给出CIH的伪代码:



vir_entry_point:

PUSH    结构化例外处理链

  PUSH    EAX

  SIDT    FWORD PTR[ESP-2]

  POP    EBX;获取中断描述符表(IDT)基址

  CLI        ;关中断

  保存int 3入口地址

  设置新int 3入口为new_int3_isr

  INT  3;调用int 3使CPU由特权级3转入特权级0

  将病毒拷贝至分配的系统内存页中

  INT    3    ;在特权级0下常驻内存

vir_exit:

  STI        ;开中断

  POP    结构化例外处理链

  PUSH    EXE染毒前的程序入口点

  RET        ;转至程序正常执行处



new_int3_isr:

  若已将病毒拷贝至分配的系统内存页中,

  JMP to install_hook

  MOV    ECX,DR0  ;读取系统染毒标志

  JECXZ  alloc_mem_and_prepare_to_infect


CIH认为系统已染毒,调整栈顶的int 3返回地址为vir_exit

  恢复原来int 3入口地址

  IRETD        ;转至vir_exit处


alloc_mem_and_prepare_to_infect:  

  调用_PageAllocate分配2页系统内存

  IRETD



install_hook:

  LEA    EAX,file_hook

  VXDCall  IFSMgr_InstallFileSystemApiHook

  MOV    DR0,EAX  ;

将下一hook的入口点保存在DR0中作为

          ;系统是否染毒的标志。

  恢复原来int 3入口地址

  JMP    vir_exit

  

file_hook:

  PUSHAD        ;保护现场


  判断是否打开文件操作(IFSFN_OPEN)、文件后缀是否为.EXE、该文件是否已经染毒(通过PE格式文件的PE标志头的前一字节为0否判别)若条件全部满足则试图感染该EXE文件判断是否为4月26日,若是则试图破坏硬盘及BIOS。



  POPAD        ;恢复现场

  MOV    EAX,DR0

  JMP    [EAX]    ;继续下一个hook


  CIH两次int 3调用的目的是使CPU由用户态的特权级3转入特权级0,从而能够在核心态进行操作系统级的调用,完成系统内存的分配和文件系统hook的安装。

  通过分析,我们知道CIHv1.2没有使用任何反跟踪或变形技术。它通过检查调试寄存器0(DR0)来决定系统是否已被感染;通过检查PE标志头的前一字节决定该文件是否已被感染。基于此,我们可以写一个简单的免疫程序段,它可嵌到C程序中:



#define    FLAG    0x12345678

DWORD  rDR0;

  _asm{

    pushad      

;保护现场

    push    ebx

    sidt    fwordptr[esp-2]

    pop    ebx    

          ;获取中断描述符表基址



    add    ebx,0x1c

    cli

    mov    edx,[ebx]

    mov    dx,[ebx-4]  

        ;保存int 3入口地址



    lea    ecx,int3_isr

    mov    [ebx-4],cx

    shr    ecx,0x10

    mov    [ebx+2],cx    

  ;设置新int 3入口为int3_isr

    int    3

    jmp    ok



int3_isr:  

    mov    eax,dr0    

  ;在特权级0读取系统染毒标志

    mov    ecx,FLAG

    mov    dr0,ecx

    iretd

ok:

    mov    rDR0,eax

    mov    [ebx-4],dx

    shr    edx,0x10

    mov    [ebx+2],dx  

    ;恢复原来int 3入口地址

    sti

    popad    

      ;恢复现场

    }

  if(0==rDR0) printf(“疫苗安装成功。”);

  else if(FLAG==rDR0) printf(“疫苗已经安装。”);

  else printf(“系统可能已被CIH感染!!DR0=%lx”,rDR0);


  此方法通过设置调试寄存器DR0为非0使CIH误以为系统已被感染。对于一个干净的Windows 95/98系统,执行上述程序段后系统就不会被CIH感染,并且可以安全执行被CIH感染的EXE文件。