MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.diskscan.asm
2021-01-12 17:41:47 -06:00

304 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.

; DISKSCAN.ASM -- Checks out disk by reading sectors
; --------------------------------------------------
CSEG Segment
Assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
Org 100h
Entry: Jmp Begin
; All Data
; --------
db ' Copyright 1986 Ziff-Davis Publishing Co.'
db ' Programmed by Charles Petzold '
DriveError db 'Invalid Drive$'
DosVersErr db 'Needs DOS 2.0+$'
MemoryError db 'Needs 64K$'
ReadSegment dw ?
DriveNum db ?
DiskBlock db 18 dup (?)
TotalSectors dw ?
SectorsIn64K dw ?
StartSector dw 0
SectorLabel2 db 9,'Sector $'
SectorLabel db 13,'Sectors $'
DashLabel db ' - $'
ErrorLabel db ': Error!'
CRLF db 13,10,'$'
ErrorAddr dw Err0,Err1,Err2,Err3,Err4,Err5,Err6,Err7
dw Err8,Err9,ErrA,ErrB,ErrC,ErrD,ErrD,ErrD
Err0 db 'Write Protect$'
Err1 db 'Unknown Unit$'
Err2 db 'Drive Not Ready$'
Err3 db 'Unknown Command$'
Err4 db 'CRC Error$'
Err5 db 'Request Length$'
Err6 db 'Seek Error$'
Err7 db 'Unknown Media$'
Err8 db 'Sector Not Found$'
Err9 db 'No Paper$'
ErrA db 'Write Fault$'
ErrB db 'Read Fault$'
ErrC db 'General Failure$'
ErrD db 'Undocumented Error$'
BootSectMsg db 'Boot Sector$'
RootDirMsg db 'Root Directory$'
BadFatMsg db 'File Alloc. Table$'
InUseMsg db 'Used by file$'
NotInUseMsg db 'Unallocated$'
BadFlagMsg db 'Flagged as bad$'
FatReadMsg db "Can't Read FAT$"
Divisors dw 10000, 1000, 100, 10, 1 ; For decimal conversion
; Check Drive Parameter, DOS Version, and Enough Memory
; -----------------------------------------------------
ErrorExit: Mov AH,9 ; Write error message
Int 21h ; through DOS
Int 20h ; And terminate
Begin: Mov DX, Offset DriveError ; Possible message
Or AL, AL ; Check Drive Validity Byte
Jnz ErrorExit ; If not zero, invalid drive
Mov DX, Offset DosVersErr ; Possible message
Mov AH, 30h
Int 21h ; Get DOS Version Number
Cmp AL, 2 ; Check for 2.0 or later
Jb ErrorExit ; If not, terminate with message
Mov DX, Offset MemoryError ; Possible error message
Mov BX, 256+Offset EndProg ; Set beyond program
Mov SP, BX ; Move stack closer to code
Add BX, 15 ; Add 15 to round up
Mov CL, 4 ; Divide BX by 16
Shr BX, CL
Mov AH, 4Ah ; Free allocated memory
Int 21h ; by calling DOS Set Block
Jc ErrorExit ; Terminate on error
Mov BX, 1000h ; Ask for 64K bytes
Mov AH, 48h ; by using DOS
Int 21h ; Allocate Memory call
Jc ErrorExit ; Terminate on error
Mov [ReadSegment], AX ; Save segment of memory block
; Get Disk Information From DOS
; -----------------------------
Mov DL, DS:[005Ch] ; Get Drive Parameter
Push DS ; Save DS
Mov AH, 32h ; Call DOS to
Int 21h ; get DOS Disk Block (DS:BX)
Mov SI, BX ; Now DS:SI points to Disk Block
Mov DI, Offset DiskBlock ; DI points to destination
Mov CX, 18 ; 18 bytes to copy'
Cld ; Forward direction
Rep Movsb ; Move 'em in
Pop DS ; Get back DS
Mov BX, Offset DiskBlock ; BX to address Disk Block
Mov DX, 1 ; Set DX:AX to 65,536
Sub AX, AX
Div Word Ptr [BX + 2] ; Divide by Bytes Per Sector
Mov [SectorsIn64K], AX ; Save that values
Mov AX, [BX + 13] ; Last Cluster Number
Dec AX ; AX = Number of Clusters
Mov CL, [BX + 5] ; Cluster to Sector Shift
Shl AX, CL ; AX = Number Data Sectors
Add AX, [BX + 11] ; Add First Data Sector
Mov [TotalSectors], AX ; AX = Number Total Sectors
Mov AL, DS:[005Ch] ; Drive Number (0=def, 1=A)
Dec AL ; Make it 0=A, 1=B
Jns GotDriveNumber ; If no sign, not default drive
Mov AH, 19h ; Get current disk
Int 21h ; by calling DOS
GotDriveNumber: Mov [DriveNum], AL ; Save Drive Number (0=A, 1=B)
; Start Reading
; -------------
MainLoop: Mov DX, Offset SectorLabel ; String to display on screen
Call StringWrite ; Display it
Mov AX, [StartSector] ; Starting sector number
Call WordWrite ; Display number on screen
Mov DX, Offset DashLabel ; String containing a dash
Call StringWrite ; Display it on the screen
Mov CX, [SectorsIn64K] ; Number of sectors to read
Add AX, CX ; Add it to starting sector
Jc NumRecalc
Cmp AX, [TotalSectors] ; See if bigger than total
Jbe NumSectorsOK ; If so, proceed
NumRecalc: Mov AX, [TotalSectors] ; Otherwise get total sectors
Mov CX, AX ; Move it to CX also
Sub CX, [StartSector] ; Now CX = sectors to read
NumSectorsOK: Dec AX ; AX = last sector to read
Call WordWrite ; Display it on screen
Call ReadSectors ; Read the sectors
Jnc NextSectors ; If no error, skip detail
Call ReadSectors ; Repeat read
Jnc NextSectors ; If still no error, skip
DiskError: Mov DX, Offset ErrorLabel ; String saying "Error!"
Call StringWrite ; Display it on screen
ErrorLoop: Push CX ; Now save previous number
Mov CX, 1 ; So we can read one at a time
Call ReadSectors ; Read one sector
Jnc NoError ; If no error, proceed
Mov BL, AL ; Save error code
Mov DX, Offset SectorLabel2 ; String with "Sector "
Call StringWrite ; Display it on screen
Mov AX, [StartSector] ; The sector we just read
Call WordWrite ; Display it on screen
Mov DX, Offset DashLabel ; String with a dash
Call StringWrite ; Display it on screen
And BL, 0Fh ; Blank out error top bits
Sub BH, BH ; Now BX is error code
Add BX, BX ; Double it for word access
Mov DX, [ErrorAddr + BX] ; Get address of message
Call StringWrite ; Display message on screen
Call FindSector ; See where sector is
Mov DX, Offset CRLF ; String for new line
Call StringWrite ; Do carriage ret & line feed
NoError: Inc [StartSector] ; Kick up the start sector
Pop CX ; Get back counter
Loop ErrorLoop ; And read next sector
Mov AX, [StartSector] ; Sector of next group
Jmp Short CheckFinish ; Check if at end yet
NextSectors: Mov AX, [StartSector] ; For no error, increment
Add AX, [SectorsIn64K] ; StartSector for next group
Jc Terminate ; (If overflow, terminate)
Mov [StartSector], AX ; And save it
CheckFinish: Cmp AX, [TotalSectors] ; See if at then end
Jae Terminate ; If so, just terminate
Jmp MainLoop ; If not, do it again
Terminate: Int 20h ; Terminate
; Find Sector in FAT to see if used by file, etc.
; -----------------------------------------------
FindSector: Mov DX, Offset DashLabel ; Print dash
Call StringWrite
Mov AX, [StartSector] ; Sector with error
Mov DX, Offset BootSectMsg ; Set up message
Cmp AX, Word Ptr [DiskBlock + 6] ; See if sector boot
Jb PrintMsg ; If so, print as such
Mov DX, Offset BadFatMsg ; Set up message
Cmp AX, Word Ptr [DiskBlock + 16] ; See if sector in FAT
Jb PrintMsg ; If so, print as such
Mov DX, Offset RootDirMsg ; Set up message
Cmp AX, Word Ptr [DiskBlock + 11] ; See if sector in dir
Jb PrintMsg ; If so, print as such
Push [StartSector] ; Save the sector
Mov AX, Word Ptr [DiskBlock + 6] ; Reserved sectors
Mov [StartSector], AX ; Start of first FAT
Mov CL, [DiskBlock + 15] ; Sectors for FAT
Sub CH, CH ; Zero out top byte
Call ReadSectors ; Read in FAT
Pop [StartSector] ; Get back bad sector
Mov DX, Offset FatReadMsg ; Set up possible msg
Jc PrintMsg ; If read error, print
Mov AX, [StartSector] ; Get bad sector
Sub AX, Word Ptr [DiskBlock + 11] ; Subtract data start
Mov CL, [DiskBlock + 5] ; Sector Shift
Shr AX, CL ; Shift the sector
Add AX, 2 ; AX is now cluster
Push ES ; Save ES for awhile
Mov ES, [ReadSegment] ; ES segment of FAT
Cmp Word Ptr [DiskBlock + 13], 0FF0h; 12 or 16-bit FAT?
Jge Fat16Bit ; And jump accordingly
Mov BX, AX ; This is cluster number
Mov SI, AX ; So is this
Shr BX, 1 ; This is one-half cluster
Mov AX, ES:[BX + SI] ; BX + SI = 1.5 CX
Jnc NoShift ; If no CY from shift, got it
Mov CL, 4 ; If CY from shift must
Shr AX, CL ; shift word 4 bits right
NoShift: Or AX, 0F000h ; Now put 1's in top bits
Cmp AX, 0F000h ; See if zero otherwise
Jmp Short CheckWord ; And continue checking
Fat16Bit: Mov BX, AX ; This is cluster number
Shl BX, 1 ; Double it
Mov AX, ES:[BX] ; Pull out word from sector
Or AX, AX ; See if zero (unallocated)
CheckWord: Pop ES ; Get back ES
Mov DX, Offset NotInUseMsg ; Set up possible message
Jz PrintMsg ; If so, print message
Mov DX, Offset BadFlagMsg ; Set up possible message
Cmp AX, 0FFF7h ; See if cluster flagged bad
Jz PrintMsg ; If so, print message
Mov DX, Offset InUseMsg ; If not, cluster is in use
PrintMsg: Call StringWrite ; Print cluster disposition
Ret ; And return
; Read Sectors (CX = Number of Sectors, Return CY and AL for error)
; -----------------------------------------------------------------
ReadSectors: Push BX ; Push all needed registers
Push CX
Push DX
Push DS
Mov AL, [DriveNum] ; Get the drive number code
Sub BX, BX ; Buffer address offset
Mov DX, [StartSector] ; Starting Sector
Mov DS, [ReadSegment] ; Buffer address segment
Int 25h ; Absolute Disk Read
Pop BX ; Fix up stack
Pop DS ; Get back registers
Pop DX
Pop CX
Pop BX
Ret ; Return to program
; Screen Display Routines
; -----------------------
WordWrite: Push AX ; Push some registers
Push BX ; AX contains word to display
Push CX
Push DX
Push SI
Mov SI, Offset Divisors ; SI points to divisors
Mov CX, 4 ; CL counter; CH zero blanker
WordWriteLoop: Mov BX, [SI] ; Get divisor
Add SI, 2 ; Increment SI for next one
Sub DX, DX ; Prepare for division
Div BX ; Divide DX:AX by BX
Push DX ; Save remainder
Or CH, AL ; See if zero
Jz LeadZero ; If so, do not display it
Add AL, '0' ; Convert number to ASCII
Mov DL, AL ; Print out character
Mov AH, 2 ; by calling DOS
Int 21h
LeadZero: Pop AX ; Get back remainder
Dec CL ; Decrement counter
Jg WordWriteLoop ; If CL still > 0, do it again
Mov CH, 1 ; No more zero blanking
Jz WordWriteLoop ; Convert last digit to ASCII
Pop SI ; Get back pushed registers
Pop DX
Pop CX
Pop BX
Pop AX
Ret
StringWrite: Push AX ; Displays string from DX
Mov AH, 9 ; to screen by calling DOS
Int 21h
Pop AX
Ret
EndProg Label Byte ; End of program
CSEG EndS
End Entry