MalwareSourceCode/MSDOS/D-Index/Virus.MSDOS.Unknown.dos-edit.asm
vxunderground 4b9382ddbc re-organize
push
2022-08-21 04:07:57 -05:00

404 lines
10 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; 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