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

454 lines
14 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.

; BROWSE.ASM -- Full Screen File Pager
; ====================================
CSEG Segment
Assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
Org 0080h
Parameter Label Byte
Org 0100h
Entry: Jmp Begin
; All Data
; --------
db 'ATTR='
Attribute db 0 ; Current screen attribute
db 'SHIFT='
ShiftHoriz db 8 ; Horizontal shift screen default
DosVersionFail db 'Requires DOS 2.0 or above$'
NoSpaceFail db 'Not enough memory$'
FileFail db 'File Not Found$'
ScreenFail db 'Unsupported video mode$'
Delimiters db 9,' ,;=/' ; Delimiters in parameter
FileHandle dw ? ; Use for saving file handle
WSMode db 0FFh ; AND value for non-WordStar mode
LineLength db ? ; Length of line (from BIOS)
NumberLines db 25,0 ; Number of lines (check EGA BIOS)
ScreenSize dw ? ; Size of screen in bytes
CheckRetrace db 1 ; Flag zero if EGA or MONO used
Addr6845 dw ? ; Could use for retrace check
ScreenAddr Label DWord ; Address of screen
ScreenOff dw 0 ; Higher for non-page 0
ScreenSeg dw 0B800h ; Set to B000h for Mono Mode 7
ScreenStart dw ? ; Points within buffer
EndOfFile dw ? ; Points within buffer
FileOffset dw -1, -1 ; Address within file of buffer data
HorizOffset dw 0 ; Horizontal offset for display
RightMargin dw 0 ; Right margin for offset display
Dispatch dw Home, Up, PgUp, Dummy, Left
dw Dummy, Right, Dummy, End, Down, PgDn
; Check DOS Version for 2.0 or above
; ----------------------------------
Begin: Cld ; All string directions forward
Mov AH,30h
Int 21h ; Get DOS Version Number
Cmp AL,2 ; Check for 2.0 or later
Jae DOSVerOK
Mov DX,Offset DOSVersionFail
ErrorExit: Mov AH,9 ; Write error message
Int 21h
Int 20h
; Parse Command Line to get File Name and WordStar flag
; -----------------------------------------------------
DOSVerOK: Mov SI,1 + Offset Parameter ; Points to parameter
NameSearch: Lodsb ; Get byte
Cmp AL,13 ; Check if carriage return
Jz NoFileFound ; If so, no file name
Mov DI,Offset Delimiters ; String of delimiters
Mov CX,5 ; Number of delimiters (no /)
Repne Scasb ; See if a match
Je NameSearch ; If a delimiter, keep looking
Mov DX,SI ; Otherwise found file name
Dec DX ; Points to beginning of it
EndSearch: Lodsb ; Get next byte
Cmp AL,13 ; See if carriage return
Je GotFileEnd ; If so, we're all done
Mov DI,Offset Delimiters ; String of delimiters
Mov CX,6 ; Number (including /)
Repne Scasb ; See if a match
Jne EndSearch ; If not, still in file name
Mov Byte Ptr [SI - 1],0 ; If so, mark end of file name
Jcxz GotFlag ; If slash, check for W
Jmp EndSearch ; Or continue flag search
GotFlag: Lodsb ; Get byte after / flag
Or AL,20h ; Uncapitalize
Cmp AL,'w' ; See if w for WordStar mode
Jnz GotFileEnd ; If not, just ignore it
Mov [WSMode],7Fh ; AND value for WordStar
; Open the File
; -------------
GotFileEnd: Mov Byte Ptr [SI - 1],0 ; Mark end of file name
; DX still points to name
Mov AX,3D00h ; Open file for reading
Int 21h ; by calling DOS
Jnc GotTheFile ; If no error, continue
NoFileFound: Mov DX,Offset FileFail ; Otherwise print a message
Jmp ErrorExit
GotTheFile: Mov [FileHandle],AX ; Save the file handle
; Get Screen Mode Information from BIOS Data Area
; -----------------------------------------------
Push ES ; Save register
Sub AX,AX
Mov ES,AX ; Set ES to 0 (BIOS Data)
Mov AL,ES:[0449h] ; Current Video Mode
Cmp AL,3 ; Check if Color Alpha
Jbe DisplayOK ; Continue if so
Cmp AL,7 ; Check if monochrome display
Je Monochrome ; If so, branch
Mov DX,Offset ScreenFail ; We can't handle graphics
Jmp ErrorExit ; So print an error message
Monochrome: Mov [ScreenSeg],0B000h ; Use Monochrome Segment
Mov [CheckRetrace],0 ; Don't have to check retrace
DisplayOK: Mov AL,ES:[044Ah] ; Number of Columns
Mov [LineLength],AL ; Save it
Mov AX,ES:[044Eh] ; Offset into screen buffer
Mov [ScreenOff],AX ; Save it
Mov AX,ES:[0463h] ; Address of 6845 Regsiter
Mov [Addr6845],AX ; Save it
Push ES
Sub DL,DL ; Set Rows to zero first
Sub BH,BH
Mov AX,1130h ; EGA BIOS: Get Information
Int 10h
Pop ES
Or DL,DL ; Check if DL is still zero
Jz NoEGA ; If so, skip rest of stuff
Inc DL
Mov [NumberLines],DL ; Save Number of Lines
Test Byte Ptr ES:[0487h],4 ; Check if must check retrace
Jnz NoEGA
Mov [CheckRetrace],0 ; EGA says we don't have to
NoEGA: Mov BH,ES:[0462h] ; Get Current Page (use later)
Pop ES
Mov AL,[LineLength] ; Length of each line
Mul [NumberLines] ; Total chars on screen
Add AX,AX ; Double for attributes
Mov [ScreenSize],AX ; And Save it
; See if enough memory is left
; ----------------------------
Add AX,Offset ScreenHold ; Add ScreenSize to code end
Add AX,256 ; Add a little stack room
Cmp AX,SP ; Check against stack pointer
Jbe GotEnufMemory ; Continue if OK
Mov DX,Offset NoSpaceFail ; Otherwise end program
Jmp ErrorExit ; with error messae
; Get Current Screen Attribute
; ----------------------------
GotEnufMemory: Cmp [Attribute],0 ; Check if attribute pre-set
Jnz GotAttribute ; If so, move on
Mov DL,' ' ; Write out a byte
Mov AH,2 ; using DOS
Int 21h
Mov AL,8 ; Now backspace
Mov AH,14 ; using BIOS call
Int 10h
Mov AH,8 ; Read character & attribute
Int 10h ; using BIOS call (BH = pg)
Mov [Attribute],AH ; And save attribute
; Save Current Screen
; -------------------
GotAttribute: Mov DX,Offset Terminate ; Set Ctrl-Break exit
Mov AX,2523h ; to terminate that way
Int 21h
Mov DI,Offset ScreenHold ; Destination of screen
Mov CX,[ScreenSize] ; Size of screen
Push DS ; Save Source Segment
Lds SI,[ScreenAddr] ; Get screen address
Rep Movsb ; Move in the bytes
Pop DS ; Restore Source Segment
; Get Keyboard Key and Decide on Action
; -------------------------------------
Call Home ; Read file in
Mov [ScreenStart],SI ; Set buffer address
KeyLoop: Call UpDateScreen ; Write file to screen
GetKey: Mov AH,8 ; Get key
Int 21h ; by calling DOS
Cmp AL,27 ; Check if ESC
Je Terminate ; If so, terminate
Cmp AL,0 ; Check if extended
Jnz GetKey ; If not, try again
Mov AH,8 ; Get extended code
Int 21h ; by calling DOS
Sub AL,71 ; Subtract Home key value
Jb GetKey ; If below that, not valid
Cmp AL,(81 - 71) ; Check if above PgDn
Ja GetKey ; If so, ignore it
Sub AH,AH ; Zero out top byte
Add AX,AX ; Double for word access
Mov BX,AX ; Offset in dispatch table
Mov SI,[ScreenStart] ; Set current buffer pointer
Call [Dispatch + BX] ; Do the call
Mov [ScreenStart],SI ; Set new buffer pointer
Jmp KeyLoop ; And update the screen
; Terminate -- Restore screen and close file
; ------------------------------------------
Terminate: Mov SI,Offset ScreenHold ; Address of Saved Screen
Les DI,[ScreenAddr] ; Address of Display
Mov CX,[ScreenSize] ; Number of characters
Rep Movsb ; Move them back
Mov BX,[FileHandle] ; Get File Handle
Mov AH,3Eh ; Close File
Int 21h
Int 20h ; Terminate
; Cursor Key Routines -- Home Key
; -------------------------------
Home: Sub BX,BX ; For zeroing out values
Mov AX,[FileOffset] ; Check if read in file
Or AX,[FileOffset + 2]
Mov [FileOffset],BX ; Zero out file address
Mov [FileOffset + 2],BX
Mov [HorizOffset],BX ; Zero out horizontal offset
Mov SI,Offset Buffer ; Reset buffer pointer
Jz Dummy ; Skip file read if in already
Mov DX,Offset Buffer ; Area to read file in
Mov CX,32768 ; Number of bytes to read
Call FileRead ; Read in file
Dummy: Ret
; Up and PgUp Keys
; ----------------
Up: Call GetPrevChar ; Get previous char in buffer
Jc UpDone ; If none available, finish
UpLoop: Call GetPrevChar ; Get previous char again
Jc UpDone ; if none, we're done
Cmp AL,10 ; Check if line feed
Jnz UpLoop ; If not, try again
Call GetNextChar ; Get char after line feed
UpDone: Ret
PgUp: Mov CX,Word Ptr [NumberLines] ; Number of lines
PgUpLoop: Call Up ; Do UP that many times
Loop PgUpLoop
Ret
; Left and Right Keys
; -------------------
Left: Mov [HorizOffset],0 ; Reset Horizontal Offset
Ret
Right: Mov AL,[ShiftHoriz] ; Get places to shift
Sub AH,AH
Add [HorizOffset],AX ; Move that many right
Ret
; End, Down, and PgDn Keys
; ------------------------
End: Mov BX,SI ; Save buffer pointer
Call PgDn ; Go page down
Cmp BX,SI ; Check if we did so
Jnz End ; If so, do it again
Ret
Down: Call GetNextChar ; Get next character
Jc NoMoreDown ; If no more, we're done
DownLoop: Call GetNextChar ; Get one again
Jc UpLoop ; If no more, find prev LF
Cmp AL,10 ; See if line feed
Jnz DownLoop ; If not, continue
NoMoreDown: Ret
PgDn: Mov CX,Word Ptr [NumberLines] ; Number of lines
PgDnLoop: Call Down ; Do DOWN that many times
Loop PgDnLoop
Ret
; Update Screen
; -------------
UpdateScreen: Push ES
Mov SI,[ScreenStart] ; Address of data in buffer
Les DI,[ScreenAddr] ; Address of display
Mov CX,ScreenSize ; Number of bytes in screen
Shr CX,1 ; Half for number of chars
Mov AL,' ' ; Will blank screen
Mov AH,[Attribute] ; With screen attribute
Rep Stosw ; Blank it
Mov AL,[LineLength] ; Length of display line
Sub AH,AH
Add AX,[HorizOffset] ; Add Horizontal Offset
Mov [RightMargin],AX ; That's right display margin
Sub DL,DL ; Line Number
LineLoop: Sub BX,BX ; Column Number
Mov AL,[LineLength] ; Use Line Length
Mul DL ; and Line Number
Add AX,AX ; to recalculate
Mov DI,AX ; display destination
Add DI,[ScreenOff] ; Add beginning address
CharLoop: Call GetNextChar ; Get next character
Jc EndOfScreen ; If no more, we're done
And AL,[WSMode] ; Will be 7Fh for WordStar
Cmp AL,13 ; Check for carriage return
Je CharLoop ; Do nothing if so
Cmp AL,10 ; Check for line feed
Je LineFeed ; Do routine if so
Cmp AL,9 ; Check for tab
Je Tab ; Do routine if so
Mov CX,1 ; Just 1 char to display
PrintChar: Cmp BX,[HorizOffset] ; See if we can print it
Jb NoPrint
Cmp BX,[RightMargin] ; See if within margin
Jae NoPrint
Mov AH,[Attribute] ; Attribute for display
Cmp [CheckRetrace],0 ; See if must stop snow
Jz WriteIt ; If not, skip retrace wait
Push BX
Push DX
Mov BX,AX ; Save character and attribute
Mov DX,[Addr6845] ; Set up I/O address
Add DX,6
RetraceWait1: In AL,DX ; Check until
Shr AL,1 ; vertical retrace
Jc RetraceWait1 ; ends
Cli ; Clear interrupts
RetraceWait2: In AL,DX ; Check until
Shr AL,1 ; vertical retrace
Jnc RetraceWait2 ; begins
Mov AX,BX ; Get back character & attr
Stosw ; Write to display
Sti ; Enable interrupts again
Pop DX
Pop BX
Jmp Short NoPrint ; Skip around "no snow" write
WriteIt: Stosw ; Write without retrace wait
NoPrint: Inc BX ; Bump up line counter
Loop PrintChar ; Do it CX times
Jmp CharLoop ; Then go back to top
Tab: Mov AX,BX ; Current column number
And AX,07h ; Take lower three bits
Mov CX,8
Sub CX,AX ; Subtract from 8
Mov AL,' ' ; Will print CX blanks
Jmp PrintChar
LineFeed: Inc DL ; Next line
Cmp DL,[NumberLines] ; See if down at bottom
Jb LineLoop ; If not, continue
EndOfScreen: Pop ES ; All done -- leave
Ret
; Get Next Character from buffer
; ------------------------------
; (Input is SI pointing to buffer, Returns AL, CY if no more)
GetNextChar: Cmp SI,[EndOfFile] ; See if at end of file
Jae NoMoreNext ; If so, no more chars
Cmp SI,Offset BufferEnd ; See if at end of buffer
Jb CanGetNext ; If not, just get character
Push CX ; Otherwise save registers
Push DX
Push DI
Push ES
Push DS ; Set ES to DS
Pop ES ; (could be different)
Mov SI,Offset BufferMid ; Move 2nd buffer half
Mov DI,Offset Buffer ; to 1st buffer half
Mov CX,16384
Sub [ScreenStart],CX ; New buffer pointer
Rep Movsb ; Move them
Mov SI,DI ; SI also buffer pointer
Add [FileOffset],32768 ; Adjust file addr to read
Adc [FileOffset + 2],0
Mov DX,Offset BufferMid ; Place to read file
Mov CX,16384 ; Number of bytes
Call FileRead ; Read the file
Sub [FileOffset],16384 ; Now adjust so reflects
Sbb [FileOffset + 2],0 ; 1st half of buffer
Pop ES ; Get back registers
Pop DI
Pop DX
Pop CX
Jmp GetNextChar ; And try again to get char
CanGetNext: Lodsb ; Get the character
NoMoreNext: Cmc ; So CY set if no more
Ret
; Get Previous Character from buffer
; ----------------------------------
GetPrevChar: Cmp SI,Offset Buffer ; See if at top of buffer
Ja CanGetPrev ; If not, just get character
Mov AX,[FileOffset] ; See if at top of file
Or AX,[FileOffset + 2]
Jz AtTopAlready ; If so, can't get anymore
Push CX ; Save some registers
Push DX
Mov SI,Offset Buffer ; Move 1st half of buffer
Mov DI,Offset BufferMid ; to 2nd half of buffer
Mov CX,16384
Add [ScreenStart],CX ; New buffer pointer
Rep Movsb ; Do the move
Sub [FileOffset],16384 ; Adjust file addr for read
Sbb [FileOffset + 2],0
Mov DX,Offset Buffer ; Area to read file into
Mov CX,16384 ; Number of bytes
Call FileRead ; Read the file
Pop DX ; Get back registers
Pop CX
Jmp Short CanGetPrev ; Now get character
AtTopAlready: Stc ; CY flag set for no more
Ret
CanGetPrev: Dec SI ; Move pointer back
Mov AL,[SI] ; Get the character
Clc ; CY flag reset for success
Ret
; Read CX bytes from the file into DX buffer
; ------------------------------------------
FileRead: Push AX ; Save some registers
Push BX
Push CX
Push DX
Mov [EndOfFile],-1 ; Initialize this
Mov DX,[FileOffset] ; Get file address to read
Mov CX,[FileOffset + 2]
Mov BX,[FileHandle] ; Get file Handle
Sub AL,AL ; Do LSEEK from beginning
Mov AH,42h ; LSEEK call
Int 21h
Pop DX ; Get back destination
Pop CX ; Get back count
Mov AH,3Fh ; Read file function call
Int 21h
Jnc NoReadError ; If no error, continue
Sub AX,AX ; Otherwise read zero bytes
NoReadError: Cmp AX,CX ; See if 32K has been read
Je GotItAll ; If so, we're home free
Add AX,DX ; Otherwise add to buffer addr
Mov [EndOfFile],AX ; And save as end of file
GotItAll: Pop BX
Pop AX
Ret
; File Buffer and Screen Hold Areas
; ---------------------------------
Buffer Label Byte ; Area for file reads
BufferMid equ Buffer + 16384 ; Halfway through it
BufferEnd equ BufferMid + 16384 ; At end of it
ScreenHold equ BufferEnd ; Area for holding screen
CSEG EndS ; End of segment
End Entry ; Denotes entry point