MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.delz.asm

328 lines
14 KiB
NASM
Raw Normal View History

2021-01-12 23:38:47 +00:00
INTERRUPTS SEGMENT AT 0H
ORG 9H*4 ;holds the address of its service routine
KEYBOARD_INT LABEL DWORD
ORG 21H*4 ;This is to use INT 21H
INT_21H LABEL DWORD ;which is the DOS function call interrupt
INTERRUPTS ENDS
ROM_BIOS_DATA SEGMENT AT 40H ;BIOS statuses held here, also keyboard buffer
ORG 1AH
HEAD DW ? ;Unread chars go from Head to Tail
TAIL DW ?
BUFFER DW 16 DUP (?) ;The buffer itself
BUFFER_END LABEL WORD
ROM_BIOS_DATA ENDS
CODE_SEG SEGMENT
ASSUME CS:CODE_SEG
ORG 100H ;ORG = 100H to make this into a
;".com" file
FIRST: JMP LOAD_INT_21H
COPY_RIGHT DB '(C)1985 S Holzner'
BYPASS_FLAG DB 0 ;Bypass our checking for #? 1=Yes
ZERO_FLAG DB 0 ;Was there a zero in filename? 1=Yes
CR_FLAG DB 0
DTA DD ? ;The old disk transfer area address
OLD_INT_21H DD ? ;Address INT 21H uses normally
OLD_KEYBOARD_INT DD ? ;Location of old kbd interrupt
COUNT DW ?
FCB_OFFSET DW ? ;Offset of given filename to be deleted
FCB_SEG DW 0 ;Segment address of the same.
COMMAND_INDEX DW 0
DEL_Z DB 'DEL/Z',0
CRLF DB 13,10,'$' ;Carriage return, linefeed for messages
MSG DB ' ZEROED AND DELETED.',13,10,'$' ;The message
ERR DB 'Error deleting $' ;Error message
DELZ PROC FAR ;The function call interrupt will now come here.
PUSHF ;Save flags first (will get changed by CMPs)
CMP AH,13H ;Are we deleting?
JNE JUMP ;No, jump to function call Int and do not return
CMP ZERO_FLAG,1 ;Are we supposed to zero?
JNE JUMP ;If not, don't
TEST BYPASS_FLAG,1 ;We are deleting. Is bypass on?
JZ DEL_CHECK ;No, check if we should delete file.
JUMP: POPF ;Restore flags
JMP OLD_INT_21H ;Jump to function call Int. (CALL won't work).
DEL_CHECK: ;DS:DX are pointing to filename to be deleted (from delete call)
PUSH BX ;Save all used registers to be polite
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH AX ;Save AX last since will pop first and return status in it
MOV FCB_OFFSET,DX ;Save address of the file-to-be-deleted's FCB
MOV FCB_SEG,DS ;Ditto for the segment address
MOV AH,2FH ;Now get Disk Transfer Area (DTA) address
INT 21H ;This will work since AH is not equal to 13H
MOV DTA,BX ;Store DTA address Low part
MOV DTA[2],ES ;Ditto High part
PUSH DS ;Save file-to-be-deleted's FCB's Segment address
MOV AH,1AH ;Put the new DTA in our Program Segment Prefix,
MOV DX,80H ; CS:0080H (CS came from INT 21H vector we set)
PUSH CS ;Now move DS into CS to set DTA
POP DS
INT 21H ;Set Disk Transfer Area (DTA)
POP DS ;Restore Segment address of given file's FCB
MOV DX,FCB_OFFSET ;Restore the given file's FCB's address low part
MOV AH,11H ;Ask for DOS service 11H, which asks for the
INT 21H ; first match to the given file's FCB
TEST AL,1 ;Was a match found?
JZ TOP ;Yes, start checking if we should delete.
POP AX ;No, return status 0FF (not found) in AL
MOV AL,0FFH
JMP NONE_FOUND ;Over and out.
TOP:
MOV SI,81H ;the matching file's FCB is in DTA from search
MOV DI,0C0H ;We will move the name to print and scan for #
MOV CX,0BH ;11 characters per file
PUSH DS ;Get ready for string move, set up DS and ES
PUSH CS ;Set them both to CS (use program segment
POP DS ; prefix area)
MOV DX,80H ;Point to match to open file
MOV AH,0FH ;Select the correct DOS call
INT 21H
CMP AL,0 ;If error opening file, exit
JNE ERROR
MOV BX,80H ;Set record size to 512
MOV WORD PTR [BX+14],512
MOV AX,[BX+16] ;Find the file's size in sectors
XOR DX,DX
TEST AX,511 ;Do we have to add an add'l sector?
JZ SHIF ;No, do the shift
INC DX ;Yes, add 1
SHIF: MOV CL,9 ;Divide by 512
SHR AX,CL
MOV COUNT,AX ;Store in Count
ADD COUNT,DX ;And add possible add'l sector
MOV AX,[BX+18] ;Now for the high part of size
MOV CL,7 ;Mult by 65536 div by 512
SHL AX,CL
ADD COUNT,AX ;And add to what we already have
MOV DX,80H ;Now prepare for sequential write
MOV CX,COUNT ;Do COUNT sectors
MOV AH,15H
FILL: INT 21H ;Fill with copies of this prog.
CMP AL,0 ;Error writing?
JNE ERROR ;Yes, jump to ERROR
LOOP FILL ;No, go back for next one
MOV AH,10H ;Close the file now.
INT 21H
CMP AL,0 ;Error closing?
JNE ERROR ;Yep, go to ERROR
MOV AH,13H ;No, delete the file at last (Whew)
MOV BYPASS_FLAG,1 ;Don't intercept this call
INT 21H
MOV BYPASS_FLAG,0
CMP AL,0 ;Everything OK?
JNE ERROR ;No, go to ERROR
CALL PRINT_NAME ;Yes, print the name
LEA DX,MSG ;And the zeroed message
MOV AH,9
INT 21H
JMP SAVE
ERROR: MOV AH,10H ;First make sure file is closed
INT 21H
LEA DX,ERR ;Then print error message and go on
MOV AH,9 ; to next file
INT 21H
CALL PRINT_NAME
SAVE: POP DS ;Get segment of original given file's FCB
MOV DX,FCB_OFFSET ;Search for next match -- point to original FCB
MOV AH,12H ;Search for next match
INT 21H
TEST AL,1 ;Was a match found?
JNZ OUT
JMP TOP
OUT: POP AX ;At least one file deleted, set AL acordingly,
MOV AL,0 ; which means set it to 0
NONE_FOUND:
PUSH DS ;Now we have to reset the Disk Transfer Area
PUSH AX ;Save AX since it contains success status
MOV AH,1AH ;Function call 1AH will do want we want
MOV DX,DTA[2] ;Get original DTA's segment into DS
MOV DS,DX
MOV DX,DTA ;Now get offset inside that segment of same
INT 21H ;And reset DTA
POP AX ;Restore AX with status
POP DS ;And DS with original DS
POP DI ;And restore the other registers
POP SI
POP DX
POP CX
POP BX
POPF ;We musn't forget our original PUSHF
IRET ;An interrupt deserves an IRET
DELZ ENDP ;And that's it
PRINT_NAME PROC NEAR ;This small subroutine just prints
MOV BX,80H+1 ; file's name from the FCB
MOV AH,2 ;Use DOS service 2
MOV CX,11 ;Print all 11 letters
PRINT: MOV DL,[BX] ;Printing loop
INT 21H
INC BX ;Get next letter
LOOP PRINT
RET ;And return
PRINT_NAME ENDP
READ_KEY PROC NEAR ;The keyboard interrupt will now come here.
ASSUME CS:CODE_SEG
PUSH AX ;Save the used registers for good form
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH SI
PUSH DS
PUSHF ;First, call old keyboard interrupt
CALL OLD_KEYBOARD_INT
ASSUME DS:ROM_BIOS_DATA ;Examine the char just put in
MOV BX,ROM_BIOS_DATA
MOV DS,BX
MOV BX,TAIL ;Point to current tail
CMP BX,HEAD ;If at head, kbd int has deleted char
JNE CR ;So leave
JMP NOCR
CR: SUB BX,2 ;Point to just read in character
CMP BX,OFFSET BUFFER ;Did we undershoot buffer?
JAE NO_WRAP ;Nope
MOV BX,OFFSET BUFFER_END ;Yes -- move to buffer top
SUB BX,2
NO_WRAP:MOV DX,[BX] ;Char in DX now
CMP DL,'Z' ;Make sure we are in upper case
JBE CHAROK
SUB DL,'a'-'A' ;Make REALLY sure.
CHAROK: PUSH CS
POP DS ;Point to Code Seg with DS
ASSUME DS:CODE_SEG
CMP CR_FLAG,1 ;CR_Flag resets Zero_Flag
JNE CHECK
MOV CR_FLAG,0 ;Reset CR_Flag
MOV ZERO_FLAG,0 ;And Zero_Flag
MOV COMMAND_INDEX,0 ;As well as Command_Index
CHECK: LEA SI,DEL_Z ;Check the typed character
ADD SI,COMMAND_INDEX ;Find place in test string
CMP DL,[SI] ;Match?
JNE NOSET ;If not, forget it
INC COMMAND_INDEX ;Match! Move to next char next time
CMP DL,'/' ;For DOS 3+, delete the /Z from buffer
JNE NOTSLSH
ASSUME DS:ROM_BIOS_DATA ;Examine the char just put in
MOV CX,ROM_BIOS_DATA
MOV DS,CX
MOV TAIL,BX ;Erase character from buffer
MOV AH,10 ;Get ready to print the character
MOV CX,1
MOV AL,DL
XOR BX,BX ;Display page 0
INT 10H ;Print the '/'
MOV AH,3 ;Now prepare to move cursor over 1
INT 10H ;Get present position
ADD DX,1 ;Add 1
MOV AH,2 ;And reset cursor
INT 10H
NOTSLSH:CMP DL,'Z' ;For DOS 3+, delete the /Z from buffer
JNE NOTZ
ASSUME DS:ROM_BIOS_DATA ;Examine the char just put in
MOV CX,ROM_BIOS_DATA
MOV DS,CX
MOV TAIL,BX ;Erase character from the buffer
MOV AH,10 ;Prepare to type the 'Z'
MOV CX,1
MOV AL,DL
XOR BX,BX
INT 10H
MOV AH,3 ;And now adjust the cursor
INT 10H ;Moving it to the left 1 space
ADD DX,1
MOV AH,2
INT 10H
NOTZ: ASSUME DS:CODE_SEG
PUSH CS
POP DS
CMP BYTE PTR [SI+1],0
JNE NOSET
MOV ZERO_FLAG,1
MOV COMMAND_INDEX,0
NOSET: MOV CR_FLAG,0
CMP DX,1C0DH
JNE NOCR
MOV CR_FLAG,1
NOCR: POP DS
POP SI
POP DI
POP DX
POP CX
POP BX
POP AX
IRET
READ_KEY ENDP
LOAD_INT_21H PROC NEAR ;This subroutine installs DELZ
ASSUME DS:INTERRUPTS ;Now set DS to point to INTERRUPTS seg.
MOV AX,INTERRUPTS
MOV DS,AX
MOV AX,KEYBOARD_INT ;Get the old interrupt service routine
MOV OLD_KEYBOARD_INT,AX ;address and put it into our location
MOV AX,KEYBOARD_INT[2] ;OLD_KEYBOARD_INT so we can call it.
MOV OLD_KEYBOARD_INT[2],AX
MOV KEYBOARD_INT,OFFSET READ_KEY
MOV KEYBOARD_INT[2],CS ;routine into the keyboard interrupt
MOV AX,INT_21H ;Get the original function call INT's
MOV OLD_INT_21H,AX ;address and put it into our location
MOV AX,INT_21H[2] ;OLD_INT_21H so we can still jump there
MOV OLD_INT_21H[2],AX
MOV INT_21H[2],CS ;Install our delete filter's address
MOV INT_21H,OFFSET DELZ ; as new function call INT
PUSH CS ;Now point to CS in preparation for
POP DS ; terminate and stay resident call
MOV DX,OFFSET LOAD_INT_21H ;Set up everything but LOAD_INT_21H to
INT 27H ;stay and attach itself to DOS
LOAD_INT_21H ENDP ;End of loading subroutine
CODE_SEG ENDS ;End of Code Segment
END FIRST ;END "FIRST" so 8088 will go to FIRST first.