mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-20 18:36:10 +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
|
|||
|
|