mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-22 11:26:11 +00:00
510 lines
16 KiB
NASM
510 lines
16 KiB
NASM
|
||
;::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||
; 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 |