mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 20:35:25 +00:00
304 lines
10 KiB
NASM
304 lines
10 KiB
NASM
; 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
|
||
|