MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.ddir.asm

441 lines
13 KiB
NASM
Raw Normal View History

2021-01-12 23:38:47 +00:00
; DDIR.ASM -- Double Column Sorted DIR Command
; ========
; (C) Copyright Charles Petzold, 1985
;
; COM file format
;
CSEG Segment
Assume CS:CSEG, DS:CSEG
Org 002Ch ; Offset of Environment
Environment Label Byte
Org 007Bh ; Parameter for COMMAND.COM
NewParameter Label Byte
Org 0080h ; Parameter passed to program
OldParameter Label Byte
Org 0100h ; Entry point
Entry: Jmp Begin
; All Data
; --------
db '(C) Copyright Charles Petzold, 1985'
DosVersMsg db "Needs DOS 2.0 +$" ; Error messages
MemAllocMsg db "Memory Problem$"
CommandMsg db "COMMAND Problem$"
Comspec db "COMSPEC=" ; Search string in environment
CommandAsciiz dd ? ; Eventual pointer to COMMAND
ParamBlock dw ? ; Parameter Block for EXEC
dw NewParameter,? ; First ? must be replaced
dw 5Ch,? ; with Environment segment;
dw 6Ch,? ; others with this segment
OldInterrupt21 dd ? ; For vector address storage
BufferPtr dw Offset FileBuffer ; For storing files listing
CharCounter dw 0 ; Keeps track of characters
NowDoingFile db 0 ; Flagged for file printed
WithinFileList db 0 ; Flagged for file list
FileCounter dw 0 ; Keeps track of files
LineCounter db 0 ; For pausing at screen end
PauseMessage db 6 dup (205)," Press any key to continue "
db 6 dup (205),181
PauseMsgEnd Label Byte
; Check DOS Version
; -----------------
Begin: Mov AH,30h ; DOS Version function call
Int 21h ; Call DOS
Cmp AL,2 ; Check if version 2
Jae DosVersOK ; If equal or over, all OK
Mov DX,Offset DosVersMsg ; Wrong DOS version message
ErrorExit: Mov AH,9 ; Set up for string write
Int 21h ; Call DOS for message
Int 20h ; Dishonorable discharge
; Adjust stack and un-allocate rest of memory
; -------------------------------------------
DosVersOK: Mov DI,Offset FileBuffer ; Place to save files
Mov CX,528 * 39 ; Allow room for 528 files
Mov AL,' ' ; Will clear with blanks
Cld ; Forward direction
Rep Stosb ; Clear the area
Mov BX,(Offset FileBuffer) + (528 * 39) + 100h
; New end of program
Mov SP,BX ; Set the stack pointer
Add BX,15 ; Add 15 for rounding
Mov CL,4 ; Number of shifts
Shr BX,CL ; Convert AX to segment
Mov AH,4Ah ; DOS call to shrink down
Int 21h ; allocated memory
Mov DX,Offset MemAllocMsg ; Possible error message
Jc ErrorExit ; Only print it if Carry set
; Search for Comspec in Environment
; ---------------------------------
Mov ES,[Environment] ; Environment Segment
Sub DI,DI ; Start search at beginning
Cld ; String increment to forward
TryThis: Cmp Byte Ptr ES:[DI],0 ; See if end of environment
Jz NoFindComSpec ; If so, we have failed
Push DI ; Save environment pointer
Mov SI,Offset ComSpec ; String to search for
Mov CX,8 ; Characters in search string
Repz Cmpsb ; Check if strings are same
Pop DI ; Get back the pointer
Jz FoundComspec ; Found string only zero flag
Sub AL,AL ; Zero out AL
Mov CX,8000h ; Set for big search
Repnz Scasb ; Find the next zero in string
Jmp TryThis ; And do the search from there
NoFindComSpec: Mov DX,Offset CommandMsg ; Message for COMSPEC error
Jmp ErrorExit ; Print it and exit
FoundComspec: Add DI,8 ; So points after 'COMSPEC='
Mov Word Ptr [CommandASCIIZ],DI ; Save the address of
Mov Word Ptr [CommandASCIIZ + 2],ES ; COMMAND ASCIIZ
; Set up parameter block for EXEC call
; ------------------------------------
Mov [ParamBlock],ES ; Segment of Environment string
Mov [ParamBlock + 4],CS ; Segment of this program
Mov [ParamBlock + 8],CS ; so points to FCB's
Mov [ParamBlock + 12],CS ; and NewParameter
; Save and set Interrupt 21h vector address
; -----------------------------------------
Mov AX,3521h ; DOS call to get Interrupt 21
Int 21h ; vector address
Mov Word Ptr [OldInterrupt21],BX ; Save offset
Mov Word Ptr [OldInterrupt21 + 2],ES ; And segment
Mov DX,Offset NewInterrupt21; Address of new Interrupt 21
Mov AX,2521h ; Do DOS call to
Int 21h ; set the new address
; Fix up new parameter for "/C DIR" String
; ------------------------------------
Mov AL,[OldParameter] ; Number of parameter chars
Add AL,5 ; We'll be adding five more
Mov [NewParameter],AL ; Save it
Mov Word Ptr [NewParameter + 1],'C/' ; i.e. "/C"
Mov Word Ptr [NewParameter + 3],'ID' ; Then "DI"
Mov Byte Ptr [NewParameter + 5],'R' ; And "R"
; Load COMMAND.COM
; -----------------
Push CS ; Push this segment so we can
Pop ES ; set ES to it
Mov BX,Offset ParamBlock ; ES:BX = address of block
Lds DX,[CommandAsciiz] ; DS:DX = address of ASCIIZ
Mov AX,4B00h ; EXEC call 4Bh, type 0
Int 21h ; Load command processor
; Return from COMMAND.COM
; -----------------------
Mov AX,CS ; Get this segment in AX
Mov DS,AX ; Set DS to it
Mov SS,AX ; And SS for stack segment
Mov SP,(Offset FileBuffer) + (528 * 39) + 100h
; Set Stack again
PushF ; Save Carry for error check
Push DS ; Save DS during next call
Mov DX,Word Ptr [OldInterrupt21] ; Old Int 21 offset
Mov DS,Word Ptr [OldInterrupt21 + 2]; and segment
Mov AX,2521h ; Call DOS to set vector
Int 21h ; address to original
Pop DS ; Restore DS to this segment
PopF ; Get back Carry flage
Jnc NormalEnd ; Continue if no error
Mov DX,Offset CommandMsg ; Otherwise we'll print error
Jmp ErrorExit ; message and exit
NormalEnd: Int 20h ; Terminate program
; New Interrupt 21h
; -----------------
NewInterrupt21 Proc Far
Sti ; Allow further interrupts
Cmp AH,40h ; Check if file / device write
Je CheckHandle ; If so, continue checks
SkipIntercept: Jmp CS:[OldInterrupt21] ; Just jump to old interrupt
CheckHandle: Cmp BX,1 ; Check if standard output
Jne SkipIntercept ; Not interested if not
PushF ; Push all registers that
Push AX ; we'll be messing with
Push CX
Push SI
Push DI
Push ES
Push CS ; Push the code segment
Pop ES ; So we can set ES to it
Cld ; Forward for string transfers
Mov SI,DX ; Now DS:SI = text source
Mov DI,CS:[BufferPtr] ; And ES:DI = text destination
Cmp CX,2 ; See if two chars to write
Jne RegularChars ; If not, can't be CR/LF
Cmp Word Ptr DS:[SI],0A0Dh ; See if CR/LF being written
Jne RegularChars ; Skip rest if not CR/LF
Mov CX,CS:[CharCounter] ; Get characters in line
Mov CS:[CharCounter],0 ; Start at new line
Cmp CS:[NowDoingFile],1 ; See if CR/LF terminates file
Jnz AllowTransfer ; If not, just write to screen
Mov AX,39 ; Max characters per line
Sub AX,CX ; Subtract those passed
Add CS:[BufferPtr],AX ; Kick up pointer by that
Mov CS:[NowDoingFile],0 ; Finished with file
Jmp PopAndReturn ; So just return to COMMAND
RegularChars: Add CS:[CharCounter],CX ; Kick up counter by number
Cmp CS:[CharCounter],CX ; See if beginning of line
Jne NotLineBegin ; If not, must be in middle
Cmp Byte Ptr DS:[SI],' ' ; See if first char is blank
Jne ItsAFile ; If not, it's a file line
Cmp CS:[WithinFileList],1 ; See if doing file listing
Jne AllowTransfer ; If not, just print stuff
Call SortAndList ; Files done -- sort and list
Mov CS:[WithinFileList],0 ; Not doing files now
Jmp Short AllowTransfer ; So just print the stuff
ItsAFile: Cmp CS:[FileCounter],528 ; See if 11 buffer filled up
Jb NotTooManyFiles ; If not just continue
Push CX ; Otherwise, save this register
Call SortAndList ; Print all up to now
Mov CS:[FileCounter],0 ; Reset the counter
Mov DI,Offset FileBuffer ; And the pointer
Mov CS:[BufferPtr],DI ; Save the pointer
Mov CX,528 * 39 ; Will clear for 528 files
Mov AL,' ' ; With a blank
Rep Stosb ; Clear it out
Pop CX ; And get back register
NotTooManyFiles:Mov CS:[WithinFileList],1 ; We're doing files now
Mov CS:[NowDoingFile],1 ; And a file in particular
Inc CS:[FileCounter] ; So kick up this counter
NotLineBegin: Cmp CS:[NowDoingFile],1 ; See if doing files
Je StoreCharacters ; If so, store the stuff
AllowTransfer: Pop ES ; Pop all the registers
Pop DI
Pop SI
Pop CX
Pop AX
PopF
Jmp SkipIntercept ; And go to DOS for print
StoreCharacters:Mov DI,CS:[BufferPtr] ; Set destination
Rep Movsb ; Move characters to buffer
Mov CS:[BufferPtr],DI ; And save new pointer
PopAndReturn: Pop ES ; Pop all the registers
Pop DI
Pop SI
Pop CX
Pop AX
PopF
Mov AX,CX ; Set for COMMAND.COM
Clc ; No error here
Ret 2 ; Return with CY flag cleared
NewInterrupt21 EndP
; Sort Files
; ----------
SortAndList: Push BX ; Push a bunch of registers
Push DX
Push SI
Push DS
Push CS ; Push CS
Pop DS ; so we can set DS to it
Assume DS:CSEG ; And inform the assembler
Mov DI,Offset FileBuffer ; This is the beginning
Mov CX,[FileCounter] ; Number of files to sort
Dec CX ; Loop needs one less than that
Jcxz AllSorted ; But zero means only one file
SortLoop1: Push CX ; Save the file counter
Mov SI,DI ; Set source to destination
SortLoop2: Add SI,39 ; Set source to next file
Push CX ; Save the counter,
Push SI ; compare source,
Push DI ; and compare destination
Mov CX,39 ; 39 characters to compare
Repz Cmpsb ; Do the compare
Jae NoSwitch ; Jump if already in order
Pop DI ; Get back these registers
Pop SI
Push SI ; And push them again for move
Push DI
Mov CX,39 ; 39 characters
SwitchLoop: Mov AL,ES:[DI] ; Character from destination
Movsb ; Source to destination
Mov DS:[SI - 1],AL ; Character to source
Loop SwitchLoop ; For the rest of the line
NoSwitch: Pop DI ; Get back the registers
Pop SI
Pop CX
Loop SortLoop2 ; And loop for next file
Pop CX ; Get back file counter
Add DI,39 ; Compare with next file
Loop SortLoop1 ; And loop again
; Now Display Sorted Files
; ------------------------
AllSorted: Mov SI,Offset FileBuffer ; This is the beginning
Mov CX,[FileCounter] ; Number of files to list
Inc CX ; In case CX is odd
Shr CX,1 ; CX now is number of lines
SetIncrement: Mov BX,24 * 39 ; Increment for double list
Cmp CX,24 ; But use it only if a full
Jae LineLoop ; screen is printed
Mov AX,39 ; Otherwise find increment
Mul CX ; by multiplying CX by 39
Mov BX,AX ; And make that the increment
LineLoop: Call PrintFile ; Print the first column file
Mov AL,' ' ; Skip one space
Call PrintChar ; by printing blank
Mov AL,179 ; Put a line down the middle
Call PrintChar
Mov AL,' ' ; Skip another space
Call PrintChar
Add SI,BX ; Bump up source by increment
Sub SI,39 ; But kick down by 39
Call PrintFile ; Print the second column file
Call CRLF ; And terminate line
Sub SI,BX ; Bring pointer back down
Inc [LineCounter] ; One more line completed
Cmp [LineCounter],24 ; Have we done whole screen?
Jz PauseAtEnd ; If so, gotta pause now
Loop LineLoop ; Otherwise just loop
Jmp Short AllFinished ; And jump out when done
PauseAtEnd: Mov [LineCounter],0 ; Reset the counter
Add SI,BX ; Go to next file
Push BX ; Save these registers
Push CX
Mov DX,Offset PauseMessage ; Test to print
Mov CX,Offset PauseMsgEnd - Offset PauseMessage
; Number of characters
Mov BX,2 ; Standard ERROR Output
Mov AH,40h ; Display to screen
Int 21h ; By calling DOS
Pop CX ; Retrieve pushed registers
Pop BX
Mov AH,8 ; Wait for character
Int 21h ; Through DOS call
Call CRLF ; Go to next line
Loop SetIncrement ; And recalculate increment
AllFinished: Pop DS ; Done with subroutine
Pop SI
Pop DX
Pop BX
Ret ; So return to caller
; Display Routines
; ----------------
PrintChar: Mov DL,AL ; Print character in AL
Mov AH,2 ; By simple DOS call
Int 21h
Ret ; And return
CRLF: Mov AL,13 ; Print a carriage return
Call PrintChar
Mov AL,10 ; And a line feed
Call PrintChar
Ret ; And return
PrintString: Lodsb ; Get character from SI
Call PrintChar ; Print it
Loop PrintString ; Do that CX times
Ret ; And return
PrintFile: Push CX ; Save the counter
Mov CX,32 ; Bytes for Name, Size, & Date
Call PrintString ; Print it
Inc SI ; Skip one space before time
Mov CX,6 ; Bytes for Time
Call PrintString ; It's a print!
Pop CX
Ret ; And return
FileBuffer Label Byte ; Points to end of code
CSEG EndS ; End of segment
End Entry ; Denotes entry point