mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-25 04:45:27 +00:00
312 lines
11 KiB
NASM
312 lines
11 KiB
NASM
|
; NO.ASM -- Hides specified files from command that follows
|
|||
|
; ======
|
|||
|
|
|||
|
CSEG Segment
|
|||
|
Assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
|
|||
|
Org 002Ch
|
|||
|
Environment Label Word ; Segment of Environment is here
|
|||
|
Org 0080h
|
|||
|
Parameter Label Byte ; Parameter is here
|
|||
|
Org 0100h
|
|||
|
Entry: Jmp Begin ; Entry Point
|
|||
|
|
|||
|
; Most Data (some more at end of program)
|
|||
|
; ---------------------------------------
|
|||
|
|
|||
|
db "Copyright 1986 Ziff-Davis Publishing Co.",1Ah
|
|||
|
db " Programmed by Charles Petzold ",1Ah
|
|||
|
SyntaxMsg db "Syntax: NO filespec command [parameters]$"
|
|||
|
DosVersMsg db "NO: Needs DOS 2.0 +$"
|
|||
|
FileSpecMsg db "NO: Incorrect File Spec$"
|
|||
|
TooManyMsg db "NO: Too many files to hide$"
|
|||
|
MemAllocMsg db "NO: Allocation Problem$"
|
|||
|
CommandMsg db "NO: COMMAND Problem$"
|
|||
|
Delimiters db 9,' ,;='
|
|||
|
FileList dw ? ; Storage of found files
|
|||
|
FileCount dw 0 ; Count of found files
|
|||
|
FileListEnd dw ? ; End of storage of found files
|
|||
|
BreakState db ? ; Store original break state here
|
|||
|
Comspec db 'COMSPEC=' ; String for Environment search
|
|||
|
ParamBlock dw ? ; Parameter block for EXEC call
|
|||
|
dw ?, ?
|
|||
|
dw 5Ch, ?
|
|||
|
dw 6Ch, ?
|
|||
|
StackPointer dw ? ; Save SP during EXEC call
|
|||
|
|
|||
|
; Check DOS Version
|
|||
|
; -----------------
|
|||
|
|
|||
|
Begin: Mov AH, 30h ; Check for DOS Version
|
|||
|
Int 21h ; through DOS call
|
|||
|
Cmp AL, 2 ; See if it's 2.0 or above
|
|||
|
Jae DosVersOK ; If so, continue
|
|||
|
|
|||
|
Mov DX, Offset DosVersMsg ; Error message
|
|||
|
ErrorExit: Mov AH, 9 ; Print String function call
|
|||
|
Int 21h ; Do it
|
|||
|
Int 20h ; And exit prematurely
|
|||
|
|
|||
|
; Parse Command Line to get NO File specification
|
|||
|
; -----------------------------------------------
|
|||
|
|
|||
|
ScanParam: Lodsb ; SUBROUTINE: Get byte
|
|||
|
Cmp AL, 13 ; See if end of parameter
|
|||
|
Je ErrorExit ; If so, exit
|
|||
|
Mov DI, Offset Delimiters ; Check if delimiter
|
|||
|
Mov CX, 5 ; There are 5 of them
|
|||
|
Repne Scasb ; Scan the string
|
|||
|
Ret ; And return
|
|||
|
|
|||
|
DosVersOK: Mov DX, Offset SyntaxMsg ; Possible error msg
|
|||
|
Mov SI, 1+Offset Parameter ; NO Parameter string
|
|||
|
Cld ; Directions forward
|
|||
|
|
|||
|
BegSearch: Call ScanParam ; Check byte in subroutine
|
|||
|
Je BegSearch ; If delimiter, keep searching
|
|||
|
Mov BX, SI ; Save pointer in BX
|
|||
|
Dec BX ; BX points to NO file spec
|
|||
|
|
|||
|
EndSearch: Call ScanParam ; Check byte in subroutine
|
|||
|
Jne EndSearch ; If not delimiter, keep going
|
|||
|
|
|||
|
; Construct full FilePath and save down at end of program
|
|||
|
; -------------------------------------------------------
|
|||
|
|
|||
|
Dec SI ; Points after NO file spec
|
|||
|
Xchg SI, BX ; SI points to beg, BX to end
|
|||
|
Mov DI, Offset FullPath ; Points to destination
|
|||
|
Cmp Byte Ptr [SI + 1], ':' ; See if drive spec included
|
|||
|
Jnz GetDrive ; If not, must get the drive
|
|||
|
Lodsw ; Otherwise, grab drive spec
|
|||
|
And AL, 0DFh ; Capitalize drive letter
|
|||
|
Jmp Short SaveDrive ; And skip next section
|
|||
|
|
|||
|
GetDrive: Mov AH, 19h ; Get current drive
|
|||
|
Int 21h ; through DOS
|
|||
|
Add AL, 'A' ; Convert to letter
|
|||
|
Mov AH, ':' ; Colon after drive letter
|
|||
|
|
|||
|
SaveDrive: Stosw ; Save drive spec and colon
|
|||
|
Mov AL, '\' ; Directory divider byte
|
|||
|
Cmp [SI], AL ; See if spec starts at root
|
|||
|
Jz HaveFullPath ; If so, no need to get path
|
|||
|
Stosb ; Store that character
|
|||
|
Push SI ; Save pointer to parameter
|
|||
|
Mov SI, DI ; Destination of current path
|
|||
|
Mov DL, [SI - 3] ; Drive letter specification
|
|||
|
Sub DL, '@' ; Convert to number
|
|||
|
Mov AH, 47h ; Get current directory
|
|||
|
Int 21h ; through DOS
|
|||
|
Mov DX, Offset FileSpecMsg ; Possible error message
|
|||
|
Jc ErrorExit ; Exit if error
|
|||
|
Sub AL, AL ; Search for terminating zero
|
|||
|
Cmp [SI], AL ; Check if Root Directory
|
|||
|
Jz RootDir ; If so, don't use it
|
|||
|
Mov CX, 64 ; Number of bytes to search
|
|||
|
Repnz Scasb ; Do the search
|
|||
|
Dec DI ; DI points to last zero
|
|||
|
Mov AL, '\' ; Put a backslash in there
|
|||
|
Stosb ; So filespec can follow
|
|||
|
RootDir: Pop SI ; Get back SI
|
|||
|
|
|||
|
HaveFullPath: Mov CX, BX ; End of NO file spec
|
|||
|
Sub CX, SI ; Number of bytes to transfer
|
|||
|
Rep Movsb ; Transfer them
|
|||
|
Sub AL, AL ; Terminating zero
|
|||
|
Stosb ; Save it
|
|||
|
Mov [FileList], DI ; Repository for found files
|
|||
|
|
|||
|
; Fix up parameter and ParamBlock for eventual COMMAND load
|
|||
|
; ---------------------------------------------------------
|
|||
|
|
|||
|
Sub BX, 4 ; Points to new param begin
|
|||
|
Mov AL, [Parameter] ; Old byte count of parameter
|
|||
|
Add AL, 80h ; Add beginning of old param
|
|||
|
Sub AL, BL ; Subtract beginning of new
|
|||
|
Mov AH, ' ' ; Space separator
|
|||
|
Mov Word Ptr [BX], AX ; Store it
|
|||
|
Mov Word Ptr [BX + 2], 'C/' ; Add /C to beginning of rest
|
|||
|
Mov AX, [Environment] ; Get environment segment
|
|||
|
Mov [ParamBlock], AX ; Save it
|
|||
|
Mov [ParamBlock + 2], BX ; Save parameter pointer
|
|||
|
Mov [ParamBlock + 4], CS ; Save segment of ParamBlock
|
|||
|
Mov [ParamBlock + 8], CS
|
|||
|
Mov [ParamBlock + 10], CS
|
|||
|
|
|||
|
; Find Files from NO File Specification
|
|||
|
; -------------------------------------
|
|||
|
|
|||
|
Mov DX, Offset DTABuffer ; Set File Find buffer
|
|||
|
Mov AH, 1Ah ; by calling DOS
|
|||
|
Int 21h
|
|||
|
|
|||
|
Mov DI, [FileList] ; Address of destination
|
|||
|
Mov DX, Offset FullPath ; Search string
|
|||
|
Sub CX, CX ; Search Normal files only
|
|||
|
Mov AH, 4Eh ; Find first file
|
|||
|
|
|||
|
FindFile: Int 21h ; Call DOS to find file
|
|||
|
Jnc Continue ; If no error continue
|
|||
|
Cmp AX, 18 ; If no more files
|
|||
|
Jz NoMoreFiles ; get out of the loop
|
|||
|
Mov DX, Offset FileSpecMsg ; Error message otherwise
|
|||
|
Jmp ErrorExit ; Exit and print message
|
|||
|
|
|||
|
Continue: Mov AX, DI ; Address of destination
|
|||
|
Add AX, 512 ; See if near top of segment
|
|||
|
Jc TooManyFiles ; If so, too many files
|
|||
|
Cmp AX, SP ; See if getting too many
|
|||
|
Jb StillOK ; If not, continue
|
|||
|
|
|||
|
TooManyFiles: Mov DX, Offset TooManyMsg ; Otherwise error message
|
|||
|
Jmp ErrorExit ; And terminate
|
|||
|
|
|||
|
StillOK: Mov SI, 30+Offset DTABuffer ; Points to filename
|
|||
|
Call AsciizTransfer ; Transfer it to list
|
|||
|
Inc [FileCount] ; Kick up counter
|
|||
|
Mov AH, 4Fh ; Find next file
|
|||
|
Jmp FindFile ; By looping around
|
|||
|
|
|||
|
NoMoreFiles: Mov [FileListEnd], DI ; Points after last file
|
|||
|
Mov DI, [FileList] ; Points to end of find string
|
|||
|
Mov CX, 64 ; Search up to 64 bytes
|
|||
|
Mov AL, '\' ; For the backslash
|
|||
|
Std ; Search backwards
|
|||
|
Repnz Scasb ; Do the search
|
|||
|
Mov Byte Ptr [DI + 2], 0 ; Stick zero in there
|
|||
|
Cld ; Fix up direction flag
|
|||
|
|
|||
|
; Stop Ctrl-Break Exits and Hide the files
|
|||
|
; ----------------------------------------
|
|||
|
|
|||
|
Mov AX,3300h ; Get Break State
|
|||
|
Int 21h ; By calling DOS
|
|||
|
Mov [BreakState],DL ; Save it
|
|||
|
Sub DL,DL ; Set it to OFF
|
|||
|
Mov AX,3301h ; Set Break State
|
|||
|
Int 21h ; By calling DOS
|
|||
|
Mov BL, 0FFh ; Value to AND attribute
|
|||
|
Mov BH, 02h ; Value to OR attribute
|
|||
|
Call ChangeFileMode ; Hide all the files
|
|||
|
|
|||
|
; Un-allocate rest of memory
|
|||
|
; --------------------------
|
|||
|
|
|||
|
Mov BX, [FileListEnd] ; Beyond this we don't need
|
|||
|
Add BX, 512 ; Allow 512 bytes for stack
|
|||
|
Mov SP, BX ; Set new stack pointer
|
|||
|
Add BX, 15 ; Prepare for truncation
|
|||
|
Mov CL,4 ; Prepare for shift
|
|||
|
Shr BX,CL ; Convert to segment form
|
|||
|
Mov AH,4Ah ; Shrink allocated memory
|
|||
|
Int 21h ; By calling DOS
|
|||
|
Mov DX,Offset MemAllocMsg ; Possible Error Message
|
|||
|
Jc ErrorExit2 ; Print it and terminate
|
|||
|
|
|||
|
; Search for Comspec in Environment
|
|||
|
; ---------------------------------
|
|||
|
|
|||
|
Push ES ; We'll be changing this
|
|||
|
Mov ES, [Environment] ; Set ES to Environment
|
|||
|
Sub DI, DI ; Start at the beginning
|
|||
|
Mov SI, Offset ComSpec ; String to search for
|
|||
|
Mov DX, Offset CommandMsg ; Possible error message
|
|||
|
|
|||
|
TryThis: Cmp Byte Ptr ES:[DI], 0 ; See if points to zero
|
|||
|
Jz ErrorExit2 ; If so, we can't go on
|
|||
|
Push SI ; Temporarily save these
|
|||
|
Push DI
|
|||
|
Mov CX, 8 ; Search string has 8 chars
|
|||
|
Repz Cmpsb ; Do the string compare
|
|||
|
Pop DI ; Get back the registers
|
|||
|
Pop SI
|
|||
|
Jz LoadCommand ; If equals, we've found it
|
|||
|
Sub AL, AL ; Otherwise search for zero
|
|||
|
Mov CX, -1 ; For 'infinite' bytes
|
|||
|
Repnz Scasb ; Do the search
|
|||
|
Jmp TryThis ; And try the next string
|
|||
|
|
|||
|
; Load COMMAND.COM
|
|||
|
; -----------------
|
|||
|
|
|||
|
LoadCommand: Add DI, 8 ; so points after 'COMSPEC='
|
|||
|
Push DS ; Switch DS and ES registers
|
|||
|
Push ES
|
|||
|
Pop DS
|
|||
|
Pop ES
|
|||
|
Mov [StackPointer],SP ; Save Stack Pointer
|
|||
|
Mov DX, DI ; DS:DX = Asciiz of COMMAND
|
|||
|
Mov BX, Offset ParamBlock ; ES:BX = parameter block
|
|||
|
Mov AX, 4B00h ; EXEC function call
|
|||
|
Int 21h ; Load command processor
|
|||
|
|
|||
|
; Return from COMMAND.COM
|
|||
|
; -----------------------
|
|||
|
|
|||
|
Mov AX, CS ; Current code segment
|
|||
|
Mov DS, AX ; Reset DS to this segment
|
|||
|
Mov ES, AX ; Reset ES to this segment
|
|||
|
Mov SS, AX ; Reset stack segment to it
|
|||
|
Mov SP, [StackPointer] ; Reset SP
|
|||
|
Pushf ; Save error flag
|
|||
|
Sub DL,DL ; Set Ctrl Break to OFF
|
|||
|
Mov AX,3301h
|
|||
|
Int 21h ; By calling DOS
|
|||
|
Popf ; Get back error flag
|
|||
|
Mov DX,Offset CommandMsg ; Set up possible error msg
|
|||
|
Jnc Terminate ; And print if EXEC error
|
|||
|
|
|||
|
; Unhide the Files, restore Ctrl-Break state, and exit
|
|||
|
; ----------------------------------------------------
|
|||
|
|
|||
|
ErrorExit2: Mov AH,9 ; Will print the string
|
|||
|
Int 21h ; Print it
|
|||
|
Terminate: Mov BL, 0FDh ; AND value for change
|
|||
|
Mov BH, 00h ; OR value for change
|
|||
|
Call ChangeFileMode ; Change file attributes
|
|||
|
Mov DL,[BreakState] ; Original break-state
|
|||
|
Mov AX,3301h ; Change the break-state
|
|||
|
Int 21h ; by calling DOS
|
|||
|
Int 20h ; Terminate
|
|||
|
|
|||
|
; SUBROUTINE: Change File Mode (All files, BL = AND, BH = OR)
|
|||
|
; -----------------------------------------------------------
|
|||
|
|
|||
|
ChangeFileMode: Mov CX, [FileCount] ; Number of files
|
|||
|
Jcxz EndOfChange ; If no files, do nothing
|
|||
|
Mov SI, [FileList] ; Beginning of list
|
|||
|
Mov DX, [FileListEnd] ; End of List
|
|||
|
ChangeLoop: Push SI ; Save pointer
|
|||
|
Mov SI, Offset FullPath ; Preceeding path string
|
|||
|
Mov DI, DX ; Destination of full name
|
|||
|
Call AsciizTransfer ; Transfer it
|
|||
|
Dec DI ; Back up to end zero
|
|||
|
Pop SI ; Get back pointer to filename
|
|||
|
Call AsciizTransfer ; Transfer it
|
|||
|
Push CX ; Save the counter
|
|||
|
Mov AX, 4300h ; Get attribute
|
|||
|
Int 21h ; by calling DOS
|
|||
|
And CL, BL ; AND with BL
|
|||
|
Or CL, BH ; OR with BH
|
|||
|
Mov AX, 4301h ; Now set attribute
|
|||
|
Int 21h ; by calling DOS
|
|||
|
Pop CX ; Get back counter
|
|||
|
Loop ChangeLoop ; And do it again if necessary
|
|||
|
EndOfChange: Ret ; End of subroutine
|
|||
|
|
|||
|
; SUBROUTINE: Asciiz String Transfer (SI, DI in, returned incremented)
|
|||
|
; --------------------------------------------------------------------
|
|||
|
|
|||
|
AsciizTransfer: Movsb ; Transfer Byte
|
|||
|
Cmp Byte Ptr [DI - 1], 0 ; See if it was end
|
|||
|
Jnz AsciizTransfer ; If not, loop
|
|||
|
Ret ; Or leave subroutine
|
|||
|
|
|||
|
; Variable length data stored at end
|
|||
|
; ----------------------------------
|
|||
|
|
|||
|
DTABuffer Label Byte ; For file find calls
|
|||
|
FullPath equ DTABuffer + 43 ; For file path and names
|
|||
|
CSEG EndS ; End of the segment
|
|||
|
End Entry ; Denotes entry point
|
|||
|
|