13
1
mirror of https://github.com/vxunderground/MalwareSourceCode synced 2024-06-30 19:02:32 +00:00
vxug-MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.diskscan.asm

304 lines
10 KiB
NASM
Raw Normal View History

2021-01-12 23:41:47 +00:00
; 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