;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;      The ULTImate MUTation Engine .93á (c) 1993 Black Wolf Enterprises
;               pardon the title, had to think of something... }-)
;
;ULTIMUTE is a mutation engine written for security-type applications and 
;other areas where mutation of executable code is necessary.  For my personal
;use, I have implemented it in Black Wolf's File Protection Utilities 2.1s,
;using it to encrypt the code placed onto EXE's and COM's to protect them
;from simple modification and/or unauthorized use.  The encryption algorithms
;themselves are terribly simple - the main point being that they change
;each time and are difficult to trace through.  This engine is written mainly
;to keep a "hack one, hack 'em all" approach from working on protected code,
;rather than to keep the code secure by a cryptologist's point of view.
;
;Including: Better Anti-Tracing abilities, 1017 byte size, Anti-Disassembling
;           code, largely variable size for decoder.  Also includes variable
;           calling segmentation (i.e. CS<>ES<>DS, and can be called via
;           near call, far call, or interrupt, the last of which can be
;           useful as a memory-resident handler for multiple programs to
;           use).
;
;Note: Please - this program and it's source have been released as freeware,
;      but do NOT use the mutation engine in viruses!  For one thing, the
;      decryptor sequence has several repetitive sequences that can be scanned
;      for, and for another, that just isn't what it was designed for and
;      I would NOT appreciate it.  If you MUST use someone else's mutation
;      engine for such, use the TPE or MTE.  I do NOT condone such, however.
;
;Any modifications made to this program should be listed below the solid line,
;along with the name of the programmer and the date the file was changed.
;Also - they should be commented where changed.  If at all possible, report
;modifications to file to the address listed in the documentation.
;
;DISCLAIMER:  The author takes ABSOLUTELY NO RESPONSIBILITY for any damages
;resulting from the use/misuse of this program.  The user agrees to hold
;the author harmless for any consequences that may occur directly or 
;indirectly from the use of this program by utilizing this program/file
;in any manner.  Please use the engine with care.
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;Modifications:
;       None as of yet (original release version)

.model tiny
.radix 16
.code

        public  _ULTMUTE, _END_ULTMUTE, Get_Rand, Init_Rand

;Underscores are used so that these routines can be called from C and other
;upper level languages.  If you wish to use Get_Rand and Init_Rand in C, you
;need to add underscores in their names as well.  Also, the random number
;generations may not be sound for all purposes.  They do the job for this
;program, but they may/may not be mathematically correct.

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;ENTRY:
;       CX=Code Length          BX=New_Entry_Point
;       DS:SI=Code              AX=Calling Style
;       ES:DI=Destination               1=Near Call, 2=Far Call, 3=Int Call
;
;RETURN:
;       CX=New Size             ES:DI = Same, now contains encrypted code 
;                                       w/decryptor
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
_ULTMUTE:                               
        push    bp ax bx cx dx es ds si di
        call    Get_Our_Offset
  Offset_Mark:
        inc     cx
        inc     cx
        mov     word ptr cs:[bp+1+Set_Size],cx
        mov     word ptr cs:[Start_Pos+bp],bx
        call    Init_Rand
        call    Get_Base_Reg
        call    Setup_Choices
        call    Create_EncDec
        call    Copy_Decrypt_Code
        call    Encrypt_It
Ending_ULTMUTE:
        pop     di si ds es dx cx bx ax
        add     cx,cs:[Decryptor_Length+bp]
        inc     cx
        inc     cx
        pop     bp
        cmp     ax,3       ;Select Returning method, i.e. retn, retf, iret
        je      Int_Call
        cmp     ax,2
        je      Far_Call
Near_Call:
        retn
Far_Call:
        retf
Int_Call:        
        iret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Get_Our_Offset:
        mov     bp,sp
        mov     bp,ss:[bp]              ;This trick finds our current offset
        sub     bp,offset Offset_Mark   ;from the compiling point, as it
        ret                             ;is usually not constant....
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Init_Rand:
        push    ax ds
        xor     ax,ax
        mov     ds,ax
        mov     ax,ds:[46c]             ;Get seed from timer click at
        pop     ds                      ;0000:046c
        mov     cs:[rand_seed+bp],ax
        pop     ax
        ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Get_Rand:
        push    cx dx
        mov     ax,cs:[rand_seed+bp]
        mov     cx,0deadh
        mul     cx                      ;This probably isn't a good algorithm,
        xor     ax,0dada                ;(understatement) but it works for
        ror     ax,1                    ;our purposes in this application.
        mov     cs:[rand_seed+bp],ax
        pop     dx cx
        ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
rand_seed       dw      0
Base_Reg        db      0
Base_Pointer    db      0
Start_Pos       dw      0
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Get_Base_Reg:
        call    Get_Rand
        and     ax,11b
        cmp     al,1                    ;Eliminate CX for loop purposes
        je      Get_Base_Reg
        mov     byte ptr cs:[bp+Base_Reg],al
   Do_Pointer_Reg:
        call    Get_Rand
        shr     al,1
        jc      Done_Base_Reg
        mov     byte ptr cs:[bp+Base_Pointer],0
        ret
    Done_Base_Reg:
        mov     byte ptr cs:[bp+Base_Pointer],1
        ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Setup_Choices:
        push    ds si        
        push    cs
        pop     ds
        mov     si,bp

        call    Get_Rand
        mov     word ptr [si+Xor_It+2],ax        ;Randomize Xor
        call    Get_Rand
        mov     word ptr [si+Dummy3+2],ax       ;Randomize Add/Sub
        mov     word ptr [si+Dummy7+2],ax       
        
        call    Get_Rand                        ;Randomize Add/Sub
        mov     word ptr [si+Dummy4+2],ax
        mov     word ptr [si+Dummy8+2],ax

        call    Get_Rand
        mov     byte ptr [si+Rand_Byte1],al     ;Randomize Random bytes
        mov     byte ptr [si+Rand_Byte2],ah
        call    Get_Rand 
        mov     byte ptr [si+Rand_Byte3],al
        mov     byte ptr [si+Rand_Byte4],ah
        call    Get_Rand
        mov     byte ptr [si+Rand_Byte5],al
        mov     byte ptr [si+Rand_Byte6],ah
        call    Get_Rand
        mov     byte ptr [si+Rand_Byte7],al
        mov     byte ptr [si+Rand_Byte8],ah
        call    Get_Rand
        mov     byte ptr [si+Rand_Byte9],al
        mov     byte ptr [si+Rand_Byte10],ah

        mov     al,byte ptr [si+Base_Reg]
  Set_Switcher:
        and     byte ptr [si+Switcher+1],0e6       ;Delete Register
        mov     ah,al
        shl     ah,1
        shl     ah,1
        shl     ah,1
        or      byte ptr [Switcher+1+si],ah
    Set_Switcher_Pointer:    
        push    ax
        mov     al,byte ptr [si+Base_Pointer]
        or      byte ptr [si+Switcher+1],al
    Set_Set_Pointy:
        and     byte ptr [si+Set_Pointy],0fe
        or      byte ptr [si+Set_Pointy],al
        and     byte ptr [si+Inc_Pointy],0fe
        or      byte ptr [si+Inc_Pointy],al
        and     byte ptr [si+Inc_Pointy+1],0fe
        or      byte ptr [si+Inc_Pointy+1],al
        pop     ax
  Set_Xorit:
        and     byte ptr [si+Xor_It+1],0fc
        or      byte ptr [si+Xor_It+1],al
  Set_Flip_It:
        and     byte ptr [si+Flip_It+1],0e4
        or      byte ptr [si+Flip_It+1],al
        or      byte ptr [si+Flip_It+1],ah
  Set_Rotate_It:
        and     byte ptr [si+do_rotate+1],0fc
        or      byte ptr [si+do_rotate+1],al
        and     byte ptr [si+do_rot2+1],0fc
        or      byte ptr [si+do_rot2+1],al
  Set_IncDec:
        and     byte ptr [si+inc_bx_com],0fc
        or      byte ptr [si+inc_bx_com],al
        and     byte ptr [si+dec_bx_com],0fc
        or      byte ptr [si+dec_bx_com],al

        and     byte ptr [si+Dummy5],0fc
        or      byte ptr [si+Dummy5],al
        and     byte ptr [si+Dummy6],0fc
        or      byte ptr [si+Dummy6],al

  Set_AddSub:
        and     byte ptr [si+Dummy3+1],0fc
        and     byte ptr [si+Dummy4+1],0fc
        or      byte ptr [si+Dummy3+1],al
        or      byte ptr [si+Dummy4+1],al
        
        and     byte ptr [si+Dummy7+1],0fc
        and     byte ptr [si+Dummy8+1],0fc
        or      byte ptr [si+Dummy7+1],al
        or      byte ptr [si+Dummy8+1],al
        pop     si ds
        ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Create_EncDec:
        push    es di cx
        push    cs
        pop     es
        lea     di,[bp+Encrypt_Sequence]
        call    Get_Rand
        and     ax,1fh
        shr     ax,1            ;Insure odd number of encryptors to prevent
        shl     ax,1            ;things like "INC AX / DEC AX" to leave prog
        inc     ax              ;unencrypted.

        mov     byte ptr cs:[bp+Encrypt_Length],al
        xchg    cx,ax
Make_Pattern:
        call    Get_Rand   
        and     ax,7
        stosb
        loop    Make_Pattern
        pop     cx di es
        ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Copy_Decrypt_Code:
        push    si di bx cx ds
        push    bx di                      ;save for loop

        push    cs
        pop     ds

        lea     si,[bp+Set_Pointy]               
        movsw
        movsb
        lodsb                   ;Copy initial encryptor
        movsw
        movsb
        lodsb
        movsw

        mov     cl,byte ptr cs:[bp+Encrypt_Length]
        xor     ch,ch
        lea     si,[Encrypt_Sequence+bp]        ;didn't have bp earlier
   Dec_Set_Loop:
        push    cx
        lodsb        
        push    si                      ;Create the Decryptor from Sequence

        mov     bl,al
        xor     bh,bh
        shl     bx,1
        add     bx,bp
        add     bx,offset Command_Table
        mov     ax,cs:[bx]
        
        mov     cl,ah
        xor     ah,ah

        lea     si,[Xor_It+bp]
        add     si,ax
        repnz   movsb

        pop     si
        pop     cx
        loop    Dec_Set_Loop


        lea     si,[Switcher+bp]
        movsw
        lodsb                           ;Finish off Decryptor
        movsw
        lodsb
        
        movsw   ;Loop Setup
        movsw                

        pop     si bx
        mov     ax,di                   ;Set Loop
        sub     ax,si                   ;Do size of loop and offset from loop
        
        mov     cs:[Decryptor_Length+bp],ax
        
        push    ax                              ;Changed for Jump
        not     ax
        add     ax,5
        stosw
        pop     ax

        add     bx,ax                   ;Set initial Pointer
        mov     es:[si+1],bx
                                        
        mov     ax,di
        pop     ds cx bx di si
        push    si di bx cx
Copy_Prog:
        push    ax
        sub     ax,di
        add     ax,bx
        mov     word ptr es:[di+1],ax
        pop     ax        
        mov     di,ax
        repnz   movsb
        pop     cx bx di si
        ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Encrypt_It:
        push    bx cx di si
        
        call    set_seqp

        mov     ax,cs:[Decryptor_Length+bp]
        inc     ax
        inc     ax
        add     di,ax                    ;DI=start of code to be encrypted
                                         ;CX=Length of code to encrypt
        mov     si,di
        push    es
        pop     ds
Big_Enc_Loop:
        push    cx
        call    Switcher
        mov     cx,cs:[Encrypt_Length+bp]        

   Encrypt_Value:
        push    ax bx cx dx si di        
        mov     si,cs:[Save_SI+bp]
        dec     si
        mov     bl,cs:[si]              ;??
        mov     cs:[Save_SI+bp],si
        lea     si,cs:[Com_Table_2+bp]
        xor     bh,bh
        shl     bx,1
        add     si,bx
        mov     bx,cs:[si]
        add     bx,bp
        mov     word ptr cs:[Next_Command+bp],bx
        pop     di si dx cx bx ax
        call    cs:[Next_Command+bp]
        Loop    Encrypt_Value

        pop     cx
        call    Switcher
        call    Inc_Pointy
        call    set_seqp
        loop    Big_Enc_Loop
        pop     si di cx bx
        ret

Save_SI         dw      0
Next_Command    dw      0
set_seqp:        
        push    si
        lea     si,cs:[Encrypt_Sequence+bp] ;SI=Encrypt_Sequence
        add     si,cs:[Encrypt_Length+bp] ;SI=End of Encrypt Sequence
        mov     cs:[Save_SI+bp],SI
        pop     si
        ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Command_Table:                  ;8 commands -> 3 bits.
        db      [Xor_It-Xor_It],(Flip_It-Xor_It-1)
        db      [Flip_It-Xor_It],(Rotate_It_1-Flip_It-1)
        db      [Rotate_It_1-Xor_It],(Rotate_It_2-Rotate_It_1-1)
        db      [Rotate_It_2-Xor_It],(Dummy1-Rotate_It_2-1)
        db      [Dummy1-Xor_It],(Dummy2-Dummy1-1)
        db      [Dummy2-Xor_It],(Dummy3-Dummy2-1)
        db      [Dummy3-Xor_It],(Dummy4-Dummy3-1)
        db      [Dummy4-Xor_It],(Dummy5-Dummy4-1)
Com_Table_2:
        dw      [offset Xor_It]
        dw      [offset Flip_It]
        dw      [offset Rotate_It_2]
        dw      [offset Rotate_It_1]
        dw      [offset Dummy5]
        dw      [offset Dummy6]
        dw      [offset Dummy7]
        dw      [offset Dummy8]
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Set_Pointy:
        mov     di,1234 ;Pointer to Code
        ret
Set_Size:        
        mov     cx,1234 ;Size
        ret
Switcher:
        xchg    bx,[di]
        ret
Inc_Pointy:
        inc     di
        inc     di
        ret

Loop_Mut:       
        dec     cx
        jz      End_Loop_Mut
    loop_set:
        jmp     _ULTMUTE
    End_Loop_Mut:
        ret
Xor_It: 
        xor     bx,1234
        ret
Flip_It:
        xchg    bh,bl
        ret

Rotate_It_1:
        jmp     before_rot
do_rotate:
        ror     bx,1
        jmp     after_rot
before_rot:  
        push    ax
        call    Ports1
        pop     ax
        jmp     do_rotate
Ports1:
        in      al,21
        or      al,02
        out     21,al
        ret

Ports2:        
        in      al,21
        xor     al,02
        out     21,al
        ret
after_rot:        
        push    ax
        call    ports2
        pop     ax
        ret

Rotate_It_2:
        cli
        jmp     confuzzled1
do_rot2:        
        rol     bx,1
        call    Switch_Int_1_3
        jmp     donerot2
        
confuzzled1:
        call    Switch_Int_1_3
        jmp     do_rot2

Switch_Int_1_3:        
        push    ax ds
        xor     ax,ax
        mov     ds,ax
        jmp     short exch1
        db      0eah
exch1:
        xchg    ax,word ptr ds:[4]
        jmp     short exch2
        db      9ah
exch2:
        xchg    ax,word ptr ds:[0c]
        xchg    ax,word ptr ds:[4]
        pop     ds ax
        ret
donerot2:
        ret

Dummy1:
        jmp     short inc_bx_com              ;Kill Disassemblers
        db      0ea
   Rand_Byte1:        
        db      0ea
   inc_bx_com:
        inc     bx
        ret
Dummy2:
        jmp     short Kill_1
  Rand_Byte2:        
        db      0ea
  Cont_Kill1:
        cli
        xchg    ax,ds:[84]
        xchg    ax,ds:[84]
        sti
        pop     ds ax
   dec_bx_com:        
        dec     bx
        jmp     short quit_Kill1
     Kill_1:
        push    ax ds
        xor     ax,ax
        mov     ds,ax                   ;Anti-Debugger (Kills Int 21)
        jmp     short Cont_Kill1
     Rand_Byte3:
        db      0e8
   quit_Kill1:
        ret
Dummy3:
        add     bx,1234
        push    bx
        call    throw_debugger
   Rand_Byte4:
        db      0e8                             ;Prefetch Trick
   into_throw:
        sub     bx,offset Rand_Byte4
        add     byte ptr [bx+trick_em+1],0ba
   trick_em:        
        jmp     short done_trick
   Rand_Byte5:
        db      0ea
   throw_debugger:
        pop     bx
        jmp     short into_throw
   Rand_Byte6:
        db      0ea
   done_trick:
        sub     byte ptr [bx+trick_em+1],0ba
        pop     bx
        ret
Dummy4:
        sub     bx,1234
        jmp     short Get_IRQ
Rand_Byte7   db      0e8
Kill_IRQ:        
        out   21,al
        xor   al,2
        jmp   short Restore_IRQ
Rand_Byte8   db      0e8        
Rand_Byte9   db      0e8                ;This will kill the keyboard
   Get_IRQ:                             ;IRQ
        push    ax
        in    al,21
        xor   al,2
        jmp    short  Kill_IRQ
Rand_Byte10  db      0e8
Restore_IRQ:        
        out   21,al
        pop     ax
        ret

;The following are used for the encryption algorithm to reverse commands that
;include anti-tracing.
Dummy5: 
        dec     bx
        ret
Dummy6:
        inc     bx
        ret
Dummy7:
        sub     bx,1234
        ret
Dummy8:
        add     bx,1234
        ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Decryptor_Length        dw      0
Encrypt_Length          dw      0
Encrypt_Sequence        db      30 dup(0)
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
_END_ULTMUTE:
end _ULTMUTE
