MalwareSourceCode/MSDOS/D-Index/Virus.MSDOS.Unknown.dos-edit.asm

404 lines
10 KiB
NASM
Raw Normal View History

2022-08-21 09:07:57 +00:00
; DOS-EDIT.ASM -- Resident DOS Command Line Editor
; ================================================
CSEG Segment
Assume CS:CSEG
Org 0080h
KeyboardBuffer Label Byte
Org 0100h
Entry: Jmp Initialize
; All Data
; --------
db "(C) Copyright 1985 Ziff-Davis Publishing Co."
OldInterrupt21 dd ? ; Original Interrupt 21 vector
OldInterrupt16 dd ? ; Original Interrupt 16 vector
DoingBuffKey db 0 ; Flag for doing Function Call 0Ah
BufferPointer dw KeyboardBuffer ; Pointer to Keyboard Buffer
BufferCounter db 0 ; Number of characters in buffer
MaxCharCol db ? ; Maximum Character Column on screen
OriginalCursor dw ? ; Place to save cursor on full-screen
InsertOn db 0 ; Insert mode flag
KeyRoutine dw Home,Up,PgUp,Dummy,Left,Dummy,Right
dw Dummy,End,Down,PgDn,Insert,Delete
; New Interrupt 21 (DOS Function Calls)
; -------------------------------------
NewInterrupt21 Proc Far
Mov CS:[DoingBuffKey],0 ; Turn flag off initially
Cmp AH,0Ah ; Check if doing buffered input
Jz BufferedInput
Jmp CS:[OldInterrupt21] ; If not, do regular interrupt
BufferedInput: Mov CS:[DoingBuffKey],-1 ; If so, turn on flag
PushF ; Simulate regular interrupt
Call CS:[OldInterrupt21]
Mov CS:[DoingBuffKey],0 ; Turn off flag
Mov CS:[BufferCounter],0 ; Re-set character counter
IRet ; Return to user program
NewInterrupt21 EndP
; New Interrupt 16 (BIOS Keyboard Routine)
; ----------------------------------------
NewInterrupt16 Proc Far
Sti ; Re-enable interrupts
Cmp CS:[DoingBuffKey],0 ; Check if doing call 0Ah
Jz DoNotIntercept ; If not, do old interrupt
Cmp CS:[BufferCounter],0 ; Check if chars in buffer
Jnz Substitute ; If so, get them out
Cmp AH,0 ; See if doing a get key
Jz CheckTheKey ; If so, get the key
DoNotIntercept: Jmp CS:[OldInterrupt16] ; Otherwise, do old interrupt
CheckTheKey: PushF ; Save flags
Call CS:[OldInterrupt16] ; Do regular interrupt
Cmp AX,4800h ; Check if up cursor
Jnz NotTriggerKey ; If not, don't bother
Call FullScreen ; Move around the screen
Cmp CS:[BufferCounter],0 ; Any chars to deliver?
Jz CheckTheKey ; If not, get another key
ReturnBuffer: Call GetBufferChar ; Otherwise, pull one out
Inc CS:[BufferPointer] ; Kick up the pointer
Dec CS:[BufferCounter] ; And knock down the counter
NotTriggerKey: IRet ; And go back to calling prog
; Substitute Key from Buffer
; --------------------------
Substitute: Cmp AH,2 ; See if shift status check
Jae DoNotIntercept ; If so, can't be bothered
Cmp AH,0 ; See if get a key
Jz ReturnBuffer ; If so, get the key above
Call GetBufferChar ; Otherwise get a key
Cmp CS:[BufferCounter],0 ; And clear zero flag
Ret 2 ; Return with existing flags
NewInterrupt16 EndP
; Get Buffer Character
; --------------------
GetBufferChar: Push BX
Mov BX,CS:[BufferPointer] ; Get pointer to key buffer
Mov AL,CS:[BX] ; Get the key
Sub AH,AH ; Blank out scan code
Pop BX
Ret
; Full Screen Routine
; -------------------
FullScreen: Push AX ; Save all these registers
Push BX
Push CX
Push DX
Push DI
Push DS
Push ES
Mov AX,CS ; Set AX to this segment
Mov DS,AX ; Do DS is this segment
Mov ES,AX ; And ES is also
Assume DS:CSEG, ES:CSEG ; Tell the assembler
Mov AH,0Fh ; Get Video State
Int 10h ; through BIOS
Dec AH ; Number of columns on screen
Mov [MaxCharCol],AH ; Save maximum column
; BH = Page Number throughout
Mov AH,03h ; Get cursor in DX
Int 10h ; through BIOS
Mov [OriginalCursor],DX ; And save the cursor position
Call Up ; Move cursor up
MainLoop: Cmp DH,Byte Ptr [OriginalCursor + 1] ; If at line
Jz TermFullScreen ; stated from, terminate
Mov AH,02h ; Set cursor from DX
Int 10h ; through BIOS
GetKeyboard: Mov AH,0 ; Get the next key
PushF ; By simulating Interrupt 16h
Call CS:[OldInterrupt16] ; which goes to BIOS
Cmp AL,1Bh ; See if Escape key
Jz TermFullScreen ; If so, terminate full screen
; Back Space
; ----------
Cmp AL,08h ; See if back space
Jnz NotBackSpace ; If not, continue test
Or DL,DL ; Check if cursor at left
Jz MainLoop ; If so, do nothing
Dec DL ; Otherwise, move cursor back
Call ShiftLeft ; And shift line to the left
Jmp MainLoop ; And continue for next key
; Carriage Return
; ---------------
NotBackSpace: Cmp AL,0Dh ; See if Carriage Return
Jnz NotCarrRet ; If not, continue test
Call End ; Move line into buffer
Mov AL,0Dh ; Tack on a Carriage Return
Stosb ; By writing to buffer
Inc [BufferCounter] ; One more character in buffer
Jmp MainLoop ; And continue
; Normal Character
; ----------------
NotCarrRet: Cmp AL,' ' ; See if normal character
Jb NotNormalChar ; If not, continue test
Cmp [InsertOn],0 ; Check for Insert mode
Jz OverWrite ; If not, overwrite
Call ShiftRight ; Shift line right for insert
Jmp Short NormalCharEnd ; And get ready to print
OverWrite: Mov CX,1 ; Write one character
Mov AH,0Ah ; By calling BIOS
Int 10h
NormalCharEnd: Call Right ; Cursor to right and print
Jmp MainLoop ; Back for another key
; Cursor Key, Insert, or Delete Subroutine
; ----------------------------------------
NotNormalChar: Xchg AL,AH ; Put extended code in AL
Sub AX,71 ; See if it's a cursor key
Jc GetKeyboard ; If not, no good
Cmp AX,12 ; Another check for cursor
Ja GetKeyboard ; If not, skip it
Add AX,AX ; Double for index
Mov DI,AX ; into vector table
Call [KeyRoutine + DI] ; Do the routine
Jmp MainLoop ; Back for another key
; Terminate Full Screen Movement
; ------------------------------
TermFullScreen: Mov DX,[OriginalCursor] ; Set cursor to original
Mov AH,2 ; And set it
Int 10h ; through BIOS
Pop ES ; Restore all registers
Pop DS
Pop DI
Pop DX
Pop CX
Pop BX
Pop AX
Ret ; And return to New Int. 16h
; Cursor Movement
; ---------------
Home: Mov DL,Byte Ptr [OriginalCursor] ; Move cursor to
Ret ; to original column
Up: Or DH,DH ; Check if at top row
Jz UpEnd ; If so, do nothing
Dec DH ; If not, decrement row
UpEnd: Ret
PgUp: Sub DL,DL ; Move cursor to far left
Ret
Left: Or DL,DL ; Check if cursor at far left
Jnz GoWest ; If not, move it left
Mov DL,[MaxCharCol] ; Move cursor to right
Jmp Up ; And go up one line
GoWest: Dec DL ; Otherwise, decrement column
Ret
Right: Cmp DL,[MaxCharCol] ; Check if cursor at far right
Jb GoEast ; If not, move it right
Sub DL,DL ; Set cursor to left of screen
Jmp Down ; And go down one line
GoEast: Inc DL ; Otherwise, increment column
Ret
End: Call TransferLine ; Move line to buffer
Mov DX,[OriginalCursor] ; Set cursor to original
Ret
Down: Inc DH ; Move cursor down one row
Ret
PgDn: Mov CL,[MaxCharCol] ; Get last column on screen
Inc CL ; Kick it up by one
Sub CL,DL ; Subtract current column
Sub CH,CH ; Set top byte to zero
Mov AL,' ' ; Character to write
Mov AH,0Ah ; Write blanks to screen
Int 10h ; through BIOS
Dummy: Ret
; Insert and Delete
; -----------------
Insert: Xor [InsertOn],-1 ; Toggle the InsertOn flag
Ret ; and return
Delete: Call ShiftLeft ; Shift cursor line left
Ret ; and return
; Transfer Line on Screen to Keyboard Buffer
; ------------------------------------------
TransferLine: Sub CX,CX ; Count characters in line
Mov DI,Offset KeyboardBuffer ; Place to store 'em
Mov [BufferPointer],DI ; Save that address
Cld ; String direction forward
GetCharLoop: Mov AH,02h ; Set Cursor at DX
Int 10h ; through BIOS
Mov AH,08h ; Read Character & Attribute
Int 10h ; through BIOS
Stosb ; Save the character
Inc CX ; Increment the counter
Inc DL ; Increment the cursor column
Cmp DL,[MaxCharCol] ; See if at end of line yet
Jbe GetCharLoop ; If not, continue
Dec DI ; Points to end of string
Mov AL,' ' ; Character to search through
Std ; Searching backwards
Repz Scasb ; Search for first non-blank
Cld ; Forward direction again
Jz SetBufferCount ; If all blanks, skip down
Inc CL ; Number of non-blanks
Inc DI ; At last character
SetBufferCount: Inc DI ; After last character
Mov [BufferCounter],CL ; Save the character count
Ret ; Return from routine
; Shift Line One Space Right (For Insert)
; ---------------------------------------
ShiftRight: Push DX ; Save original cursor
Mov DI,AX ; Character to insert
ShiftRightLoop: Call ReadAndWrite ; Read character and write
Inc DL ; Kick up cursor column
Cmp DL,[MaxCharCol] ; Check if it's rightmost
Jbe ShiftRightLoop ; If not, keep going
Pop DX ; Get back original cursor
Ret ; And return from routine
; Shift Line One Space Left (For Delete)
; --------------------------------------
ShiftLeft: Mov DI,0020h ; Blank at end
Mov BL,DL ; Save cursor column
Mov DL,[MaxCharCol] ; Set cursor to end of line
ShiftLeftLoop: Call ReadAndWrite ; Read character and write
Dec DL ; Kick down cursor column
Cmp DL,BL ; See if at original yet
Jge ShiftLeftLoop ; If still higher, keep going
Inc DL ; Put cursor back to original
Ret ; And return from routine
; Read and Write Character for Line Shifts
; ----------------------------------------
ReadAndWrite: Mov AH,2 ; Set Cursor from DX
Int 10h ; through BIOS
Mov AH,08h ; Read Character and Attribute
Int 10h ; through BIOS
Xchg AX,DI ; Switch with previous char
Mov CX,1 ; One character to write
Mov AH,0Ah ; Write character only
Int 10h ; through BIOS
Ret ; Return from Routine
; Initialization on Entry
; -----------------------
Initialize: Sub AX,AX ; Make AX equal zero
Mov DS,AX ; To point to vector segment
Les BX,dword ptr DS:[21h * 4]; Get and save Int. 21h
Mov Word Ptr CS:[OldInterrupt21],BX
Mov Word Ptr CS:[OldInterrupt21 + 2],ES
Les BX,dword ptr DS:[16h * 4]; Get and save Int. 16h
Mov Word Ptr CS:[OldInterrupt16],BX
Mov Word Ptr CS:[OldInterrupt16 + 2],ES
Push CS ; Restore DS register
Pop DS ; by setting to CS
Mov DX,Offset NewInterrupt21
Mov AX,2521h ; Set new Interrupt 21h
Int 21h ; through DOS
Mov DX,Offset NewInterrupt16
Mov AX,2516h ; Set new Interrupt 16h
Int 21h ; through DOS
Mov DX,Offset Initialize ; Number of bytes to stay
Int 27h ; Terminate & remain resident
CSEG EndS
End Entry
2021-01-12 23:41:47 +00:00