mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 04:15:26 +00:00
404 lines
11 KiB
NASM
404 lines
11 KiB
NASM
; 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
|
||
|