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

441 lines
12 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.

; 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