
;::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                Simple Morpher v.0.1                 :
;                                                     :
;                    x0man © 2008                     :
;                                                     :
;               http://www.virustech.org/             :
;::::::::::::::::::::::::::::::::::::::::::::::::::::::
;-----------------------------------------------------------------------------------------:
;                                                                                         :
;В Кратце расскажу алгоритм, который у меня реализован.                                   :
;                                                                                         :
;Есть массив в который заносятся данные о инструкциях                                     :
;Одним эллементом массива является:                                                       :
;                                                                                         :
;_OPCODE struct;                                                                          :
;	dwOldAddress	dd	?	; Старый адрес инструкции (до морфинга)               :
;	dwNewAddress	dd	?	; Новый адрес инструкции  (после морфинга)            :
;	dwJumpAddress	dd	?	; Адрес куда должен указывать прыжок(или вызов)       :
;                                   ; (если инструкция им является)                       :
;	dwLength		dd	?	; в данном примере эта переменная не используется     :
;	 					; Надеюсь вам она пригодиться больше чем мне :)       :
;_OPCODE ends                                                                             :
;                                                                                         :
;В "мой" Первый этап входит                                                               :
;  1. Парсинг кода, и выделение на каждую инструкцию одного                               :
;     эллемента массива, заполняя данные в структуре _OPCODE.                             :
;  2. Расширение кода для будущих изменений (замена коротких прыжков на длинные)          :
;  3. Если инструкция является прыжком или вызовом, нам нужно                             :
;     подсчитать скажем так EIP при выполнении оной.                                      :
;  4. И есстественно разбавление кода (инструкцией NOP)                                   :
;                                                                                         :
;Второй этап                                                                              :
;  1. Проходимся по массиву с описаниями инструкций                                       :
;  2. Если инструкция является вызовом, то вычисляем параметр у прыжка                    :
;    или вызова, и меняем его на корректный(уже в изменённом коде).                       :
;                                                                                         :
;                                                                                         :
;Вроде бы всё... для более точных описаний смотрим код!                                   :
;                                                                                         :
;Дизассемблер длинн инструкций я взял Catchy_32, который можно скачать с                  :
; http://www.wasm.ru, он также прилагается к исходникам в приложении.                     :
;                                                                                         :
;GreeTz:                                                                                  :
;        Osen                                                                             :
;        izee [ EOF-Project ] http://eof-project.net/                                     :
;                                                                                         :
;  tPORt  (http://www.tport.org/)                                                         :
;  REVENGE(http://www.revenge-crew.com/)                                                  :
;  TLG    (http://tlg.astalavista.ms/)                                                    :
;  TSRh   (http://tsrh.org.ua/)                                                           :
;  TPOC   (http://vx.netlux.org/tpoc/)                                                    :
;                                                                                         :
;                                                                                         :
;  Спасибо за внимание!                                                                   :
;                                                                                         :
;                                                                  10.05.2008             :
;                                                           x0man [VirusTech]             :
;                                                    http://www.virustech.org             :
;-----------------------------------------------------------------------------------------:

	.386
	.model flat, stdcall
	option casemap :none

	include \MASM32\INCLUDE\windows.inc
	include \MASM32\INCLUDE\kernel32.inc
	include \MASM32\INCLUDE\user32.inc
	
	includelib \MASM32\LIB\kernel32.lib
	includelib \MASM32\LIB\user32.lib
		
; #########################################################################

_OPCODE struct
	dwOldAddress	dd	?	; Старый адрес инструкции (до морфинга)
	dwNewAddress	dd	?	; Новый адрес инструкции  (после морфинга)
	dwJumpAddress	dd	?	; Адрес куда должен указывать прыжок(или вызов)
						; (если инструкция им является)
	dwLength		dd	?	; в данном примере эта переменная не используется
	 					; Надеюсь вам она пригодиться больше чем мне :)
_OPCODE ends
	
; #########################################################################

.code

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; Код для теста :)
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
test_code:
	@@:
	jmp @F
	mov eax, edx
	pop eax
	push eax
	call @F
	cmp eax, 0
	jne @B
	jmp @B
	add ecx, edx
	add eax, edx
	xchg edx, ecx
	call @B
	jne @F
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0,0,0,0
	jne @B
	ret
	@@:
	ret
	int 3
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::




;::::::::::::::::::::::::::::::::::
; Подключим дизасм длинн инструкций
include Catchy32\Catchy32.inc



;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::|
; Функция для подсчёта числа, куда должен указывать прыжок|
; Пример: dwCurrentAddress - указывает на код             |
;                                                         |
;                     00000000: 74 30  JE imm8            |
;  эта функция высчитывает "imm8"                         |
;  в нашем примере imm8 = 00000000 + 30 + 2 = 00000032    |
;   т.е.                                                  |
;   00000000 - Текущий адрес                              |
;         30 - Параметр                                   |
;          2 - Длинна инструкции JE imm8                  |
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::|
;                     00000000: 74 30  JE 00000032 --.    |
;                     00000002:                      |    |
;                                                    |    |
;                     00000032:                <-----°    |
; Это описание для "положительных" прыжков                |
; Для отрицательных, попробуйте разобрать сами            |
;                                там не сложно ;-)        |
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::|:::|
; IN  dwCurrentAddress : текущий адрес предпологаемого прыжка |
; OUT EAX              : Адрес куда прыжок указывает          |
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::|
get_jump_address proc dwCurrentAddress : DWORD

	push ecx
	push edi

	mov edi, dwCurrentAddress
	mov al, byte ptr [edi]
	
	;:::::::::::::::::::::::::::::::::::::
	; XX imm8
	cmp al, 070h
	jl @F
	cmp al, 07Fh
	jna @_jump_imm8_
	
@@:
	;:::::::::::::::::::::::::::::::::::::
	cmp al, 0EBh
	je @_jump_uncond_imm8_
	;:::::::::::::::::::::::::::::::::::::
	; 0F XX imm32
	cmp al, 00Fh
	jne @F
	mov ah, byte ptr [edi + 1]
	cmp ah, 080h
	jl @F
	cmp ah, 08Fh
	jna @_jump_imm32_
	;:::::::::::::::::::::::::::::::::::::

@@:	
	;:::::::::::::::::::::::::::::::::::::
	; JMP imm32
	cmp al, 0E9h
	je @_jump_uncond_imm32_
	

	;:::::::::::::::::::::::::::::::::::::
	; CALL
	cmp al, 0E8h
	je @_call_imm32_
	

	;:::::::::::::::::::::::::::::::::::::
	jmp @_exit_
	;:::::::::::::::::::::::::::::::::::::
	
@_jump_imm8_:
@_jump_uncond_imm8_:
	;:::::::::::::::::::::::::::::::::::::
	; Короткие прыжки
	movzx eax, byte ptr [edi + 1]
	mov cl, al
	test cl, 10000000b ; isNegative?
	
	jnz @_neg_1
		add edi, eax
		add edi, 2
		xchg eax, edi
		jmp @_exit_
	
	@_neg_1:
		neg al
		sub al, 2
		sub edi, eax
		xchg eax, edi
		jmp @_exit_	

	
@_jump_imm32_:
	;:::::::::::::::::::::::::::::::::::::
	; Длинные прыжки
	mov eax, dword ptr [edi + 2]
	mov ecx, eax
	shr ecx, 24d
	test ecx, 10000000b ; isNegative?
	
	jnz @_neg_2
		add eax, edi
		add eax, 6
		jmp @_exit_
		
	@_neg_2:
		neg eax
		sub eax, 6
		sub edi, eax
		xchg eax, edi
		jmp @_exit_
	;:::::::::::::::::::::::::::::::::::::
	

		
@_jump_uncond_imm32_:
@_call_imm32_:
	;:::::::::::::::::::::::::::::::::::::
	; JMP imm32 & CALL imm32
	mov eax, dword ptr [edi + 1]
	mov ecx, eax
	shr ecx, 24d
	test ecx, 10000000b ; isNegative?
	
	jnz @_neg_3
		add edi, eax
		add edi, 5
		xchg eax, edi
		jmp @_exit_
		
	@_neg_3:
		neg eax
		sub eax, 5
		sub edi, eax
		xchg eax, edi
	;///////////////////////////////////////
@_exit_:
	
	pop edi
	pop ecx

	ret
get_jump_address endp


;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::|
; Функция для поиска в массиве описаний инструкций             |
; Нового адреса для прыжка....                                 |
;                                                              |
; IN  dwAddress - Адрес прыжка                                 |
; IN  pOpcodes  - Указатель на массив с описаниями опкодов     |
; OUT EAX       - Новый адрес прыжка...                        |
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::|
get_new_jump_address proc dwAddress:DWORD, pOpcodes : DWORD
	push ecx
	
	assume ecx : ptr _OPCODE
	mov ecx, pOpcodes
	mov eax, dwAddress
	
	@@:
	cmp [ecx].dwOldAddress, eax
	je @F
	add ecx, sizeof _OPCODE
	cmp [ecx].dwOldAddress, 0
	jne @B
	xor eax, eax
	@@:
	mov eax, [ecx].dwNewAddress
	
	pop ecx
	ret
get_new_jump_address endp


;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::|
; Функция разбавляет определённый код, инструкцией NOP            |
; ВАЖНО! Код должен заканчиваться опкодом 0CCh                    |
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::|
; IN  dwCodeAddress  - Адрес кода для морфинга                    |
; IN  dwOutputBuffer - Адрес куда будет занесён проморфленный код |
; OUT EAX            - Размер проморфленного кода                 |
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::|
MorphCode proc dwCodeAddress	: DWORD, dwOutputBuffer : DWORD
local pOpcodes			: DWORD
local dwTotalCodeSize		: DWORD

	;::::::::::::::::::::::::::::::::::::::::::::::::::
	; pOpcodes       - Указатель на описания опкодов ::
	; dwOutputBuffer - Проморфленный код             ::
	;::::::::::::::::::::::::::::::::::::::::::::::::::
	
	;::::::::::::::::::::::::::::::::::::::::::::::::::::::::
	; Зарезервируем памяти для массива с описаниям инструкций
	invoke VirtualAlloc, NULL, 1024*1024, MEM_COMMIT + MEM_RESERVE, PAGE_READWRITE
	mov pOpcodes, eax
	
	;::::::::::::::::::::::::::::::::::::::::::::
	; Обнулим переменную в которую будем заносить
	; Общий размер кода
	push 0
	pop dwTotalCodeSize

	;:::::::::::::::::::::::::::::::::::::::::
	; Без комментариев
	assume ecx : ptr _OPCODE
	mov esi, dwCodeAddress	; Code Address
	mov edi, dwOutputBuffer	; New Code Address
	mov ecx, pOpcodes		; array of _OPCODES
	;::::::::::::::::::::::::::::::::::::::::	
	

	
;::::::::::::::::::::::::::::::::::::::::
; Первый этап :::::::::::::::::::::::::::
;::::::::::::::::::::::::::::::::::::::::

	;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
	; Укажем для первой инструкции её новый адрес что в EDI
	mov [ecx].dwNewAddress, edi

	;::::::::::::::::::::::::::::::::::::
	; Начинаем цикл
	; Loop 1
	@_loop_1:

	;::::::::::::::::::::::::::::::::::::
	; Узнаем длинну у инструкции
	; IN  ESI == Current Code Offset
	; OUT EAX == Instruction Length
	call c_Catchy

	;:::::::::::::::::::::::::::::::::::::
	; Занесём данные в массив с описаниями
	mov [ecx].dwOldAddress, esi
	mov [ecx].dwLength, eax

	;::::::::::::::::::::::::::::::::::::
	; Короткие условные прыжки меняем на длинные	
	; Они отличаются от длинных префиксом 00Fh
	; в начале и +10h к текущему опкоду прыжка
	; Пример:
	;    Было :00000000:     74 30
	;                    0F +10 30 00 00 00
	;    Стало:00000000: 0F  84 30 00 00 00
	cmp byte ptr [esi], 070h
	jl @F
	cmp byte ptr [esi], 07Fh
	ja @F
		push eax
		mov al, 00Fh
		stosb
		
		movzx eax, byte ptr [esi]
		add eax, 10h
		stosd	
		
		;:::::::::::::::::::::::::::::::::::::::
		; Подсчитаем адрес куда указывает прыжок
		push esi
		call get_jump_address
		
		;::::::::::::::::::::::::
		; Занесём данные в массив
		mov [ecx].dwJumpAddress, eax
		
		pop eax
		
		;::::::::::::::::::::::::::::::::::::
		; Прибавим к общему размеру кода
		; Длинну 00Fh XXh imm32, т.е. число 6
		; где XX » [80h..8Fh]
		add dwTotalCodeSize, 6
	;::::::::::::::::::::::::::::::::::::
	; Пропустим перенос маленького прыжка
	; Переходим к следующей инструкции
	jmp @_next_inst_	
	
	@@:
	;::::::::::::::::::::::::::::::::::::
	; Меняем...
	; JMP imm8 -> JMP imm32
	; Пример
	; Было : 00000000: EB 33
	; Стало: 00000000: E9 33 00 00 00
	cmp byte ptr [esi], 0EBh
	jne @F
		push eax
		
		mov al, 0E9h
		stosb
		xor eax, eax
		stosd

		;:::::::::::::::::::::::::::::::::::::::
		; Подсчитаем адрес куда указывает прыжок
		push esi
		call get_jump_address
		
		;::::::::::::::::::::::::
		; Занесём данные в массив
		mov [ecx].dwJumpAddress, eax

		pop eax		
		;:::::::::::::::::::::::::::::::
		; Прибавим к общему размеру кода
		; Длинну E9 imm32, т.е. число 5
		add dwTotalCodeSize, 5		
	jmp @_next_inst_
	;::::::::::::::::::::::::::::::::::::
	
	
	@@:
	;::::::::::::::::::::::::::::::::::::
	; Проверим на JMP imm32
	cmp byte ptr [esi], 0E9h
	jne @F

	push eax
	push esi
	call get_jump_address
	mov [ecx].dwJumpAddress, eax
	pop eax
	jmp @_replace_instr_
	;::::::::::::::::::::::::::::::::::::
	
	@@:	
	;::::::::::::::::::::::::::::::::::::
	; Проверим на CALL
	cmp byte ptr [esi], 0E8h
	jne @F
	
	push eax
	push esi
	call get_jump_address
	mov [ecx].dwJumpAddress, eax
	pop eax
	jmp @_replace_instr_
	;::::::::::::::::::::::::::::::::::::
	
	
	@@:
	;::::::::::::::::::::::::::::::::::::
	; 00Fh XX imm32
	cmp byte ptr [esi], 00Fh
	jne @F
	cmp byte ptr [esi + 1], 080h
	jl @F
	cmp byte ptr [esi + 1], 08Fh
	ja @F
		push eax
		push esi
		call get_jump_address
		mov [ecx].dwJumpAddress, eax
		pop eax		
	;::::::::::::::::::::::::::::::::::::

	@@:

@_replace_instr_:
	;::::::::::::::::::::::::::::::::::::::::::
	; Переносим инструкцию в новый буффер.
	; Этот код выполниться в том случае
	; Если мы не меняли оригинальные инструкции
	push esi
	push ecx
	
	mov ecx, eax
	rep movsb
	
	pop ecx
	pop e