mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-29 22:45:27 +00:00
759 lines
22 KiB
NASM
759 lines
22 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 esi
|
||
|
||
; Добавим к общему размеру кода
|
||
; длинну текущей инструкции
|
||
add dwTotalCodeSize, eax
|
||
|
||
;::::::::::::::::::::::::::::::::::::
|
||
; сюда прыгаем если мы заменили текущую инструкцию на свою
|
||
@_next_inst_:
|
||
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||
; Разбавляем код инструкцией NOP
|
||
; Тут можно разбавлять код
|
||
; любыми "пустыми" инструкциями
|
||
; вида:
|
||
;--------------
|
||
; push eax
|
||
; pop eax
|
||
;--------------
|
||
; mov eax, eax
|
||
;--------------
|
||
; и т.д.
|
||
push eax
|
||
mov al, 90h
|
||
stosb
|
||
pop eax
|
||
|
||
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||
; Увеличим общий размер кода на 1 (Длинна инструкции NOP)
|
||
; Так же если будете добавлять свой "пустой" код
|
||
; Нужно будет прибавить к dwTotalCodeSize его общую длинну(!)
|
||
add dwTotalCodeSize, 1
|
||
|
||
;::::::::::::::::::::::::::::::::::::
|
||
; Перейдём к следующей инструкции
|
||
add esi, eax
|
||
|
||
;::::::::::::::::::::::::::::::::::::
|
||
; перейдём к следующему элементу
|
||
; в нашей таблице с описаниями опкодов
|
||
add ecx, sizeof _OPCODE
|
||
|
||
;::::::::::::::::::::::::::::::::::::
|
||
; Заносим новый адрес у следующей инструкции
|
||
mov [ecx].dwNewAddress, edi
|
||
|
||
|
||
;::::::::::::::::::::::::::::::::::::
|
||
; Доходим до int 3
|
||
; Это значит что код закончился....
|
||
; и следовательно нам тут делать уже нечего.
|
||
cmp byte ptr [esi], 0CCh
|
||
jne @_loop_1
|
||
; End Loop 1
|
||
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||
|
||
;::::::::::::::::::::::::::::::::::::
|
||
; Укажем что массив с описаниями закончился
|
||
mov [ecx].dwOldAddress, 0
|
||
|
||
|
||
|
||
|
||
;::::::::::::::::::::::::::::::::::::::::
|
||
; Второй этап :::::::::::::::::::::::::::
|
||
;::::::::::::::::::::::::::::::::::::::::
|
||
mov ecx, pOpcodes
|
||
@_loop_2:
|
||
;::::::::::::::::::::::::::::::::::::::::
|
||
; Если инструкция является прыжком или вызовом
|
||
; то dwJumpAddress != 0 (!)
|
||
cmp [ecx].dwJumpAddress, 0
|
||
je @F
|
||
;::::::::::::::::::::::::::::::::::::::::
|
||
; Получим новый адрес адрес куда должен
|
||
; указывать прыжок или вызов
|
||
push pOpcodes
|
||
push [ecx].dwJumpAddress
|
||
call get_new_jump_address
|
||
|
||
;::::::::::::::::::::::::::::::::::::::::
|
||
; Проверим результат на нуль.
|
||
; По идее тут проверки быть не должно
|
||
; ибо EAX (если весь код по адресу dwCodeAddress был корректным)
|
||
; никогда не будет равняться нулю
|
||
; и эти 2 строчки лишние, но мне захотелось
|
||
; всётаки их написать :)))
|
||
cmp eax, 0
|
||
je @F
|
||
;::::::::::::::::::::::::::::::::::::::::
|
||
|
||
;::::::::::::::::::::::::::::::::
|
||
; Проверим адрес какой инструкции
|
||
; нужно поменять на новый
|
||
mov edx, [ecx].dwNewAddress
|
||
;:::::::::::::::::::::::::
|
||
; Длинные условные прыжки
|
||
; 00Fh XXh imm32
|
||
cmp byte ptr [edx], 00Fh
|
||
je @_0F_XX_imm32
|
||
;:::::::::::::::::::::::::::
|
||
; Длинный безусловный прыжок
|
||
; JMP imm32
|
||
cmp byte ptr [edx], 0E9h
|
||
je @_XXX_imm32_
|
||
;::::::::::::::::::::::
|
||
; Вызов (CALL imm32)
|
||
cmp byte ptr [edx], 0E8h
|
||
je @_XXX_imm32_
|
||
;::::::::::::::::::::::
|
||
jmp @F
|
||
|
||
;::::::::::::::::::::::::::::::::::::::
|
||
; 00Fh XXh imm32
|
||
; Нам нужно заменить есстественно imm32
|
||
; что находится по смещению [АДРЕС ПРЫЖКА + 2]
|
||
; Пример:
|
||
; 00Fh 84 imm32 ; JE imm32
|
||
; 00Fh 85 imm32 ; JNE imm32
|
||
@_0F_XX_imm32:
|
||
cmp eax, [ecx].dwNewAddress
|
||
jle @_less_or_equal_1
|
||
push eax
|
||
sub eax, [ecx].dwNewAddress
|
||
sub eax, 6
|
||
mov edx, [ecx].dwNewAddress
|
||
mov dword ptr [edx + 2], eax
|
||
pop eax
|
||
jmp @F
|
||
|
||
@_less_or_equal_1:
|
||
push eax
|
||
mov edx, [ecx].dwNewAddress
|
||
sub edx, eax
|
||
neg edx
|
||
sub edx, 6
|
||
mov eax, [ecx].dwNewAddress
|
||
mov dword ptr [eax + 2], edx
|
||
pop eax
|
||
jmp @F
|
||
|
||
;:::::::::::::::::::::::::::::::::::::::::::::
|
||
; Смещение imm32 в инструкциях JMP и CALL
|
||
; одно и тоже, следовательно код обработки
|
||
; нового адреса у них можно сделать одним
|
||
; imm32 находится по смещению [АДРЕС ПРЫЖКА + 1]
|
||
; Пример:
|
||
; E9 imm32
|
||
; E8 imm32
|
||
; :)
|
||
@_XXX_imm32_:
|
||
cmp eax, [ecx].dwNewAddress
|
||
jle @_less_or_equal_2
|
||
push eax
|
||
sub eax, [ecx].dwNewAddress
|
||
sub eax, 5
|
||
mov edx, [ecx].dwNewAddress
|
||
mov dword ptr [edx + 1], eax
|
||
pop eax
|
||
jmp @F
|
||
|
||
@_less_or_equal_2:
|
||
push eax
|
||
mov edx, [ecx].dwNewAddress
|
||
sub edx, eax
|
||
neg edx
|
||
sub edx, 5
|
||
mov eax, [ecx].dwNewAddress
|
||
mov dword ptr [eax + 1], edx
|
||
pop eax
|
||
jmp @F
|
||
;::::::::::::::::::::::::::::::::::::::::
|
||
|
||
|
||
@@:
|
||
;::::::::::::::::::::::::::::::
|
||
; Перейдём к следующем описанию
|
||
; Следующего опкода :)
|
||
add ecx, sizeof _OPCODE
|
||
|
||
;:::::::::::::::::::::::::::::::::::::
|
||
; Повторяем до тех пор пока
|
||
; не наткнёмся на конец массива
|
||
; На это указывает Нуль в dwOldAddress
|
||
cmp [ecx].dwOldAddress, 0
|
||
jne @_loop_2
|
||
|
||
;::::::::::::::::::::::::::::::::::::::::
|
||
; Освободим память что занимали
|
||
invoke VirtualFree, pOpcodes, NULL, MEM_RELEASE
|
||
|
||
@_exit_:
|
||
|
||
mov eax, dwTotalCodeSize
|
||
ret
|
||
MorphCode endp
|
||
|
||
.data
|
||
; Буфер куда занесём проморфленный код
|
||
dwOutputBuffer dd 0
|
||
|
||
; Размер буфера
|
||
dwOutputBufferSize dd 0
|
||
|
||
; Кол-во байт записанных в фаил
|
||
dwBytesWritten dd 0
|
||
|
||
; Имя файлика в который запишем проморфленный код
|
||
szFileName db 'morphed_code_dump_raw.bin',0
|
||
|
||
; Текст для MessageBoxA
|
||
szComplete db 'Complete! :)', 0
|
||
.code
|
||
|
||
start:
|
||
|
||
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||
; Зарезервируем память для проморфленного кода
|
||
; Размер можете выставить конечноже свой
|
||
; Всё зависит от кол-ва кода что собираетесь Морфить
|
||
invoke VirtualAlloc, NULL, 1024*1024, MEM_COMMIT + MEM_RESERVE, PAGE_READWRITE
|
||
mov dwOutputBuffer, eax
|
||
|
||
;::::::::::::::::
|
||
; Морфим код.....
|
||
invoke MorphCode, offset test_code, dwOutputBuffer
|
||
mov dwOutputBufferSize, eax
|
||
|
||
;::::::::::::::::::::::::::::::::
|
||
; Дампим проморфленный код в фаил
|
||
invoke CreateFile, offset szFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0
|
||
push eax
|
||
invoke WriteFile, eax, dwOutputBuffer, dwOutputBufferSize, addr dwBytesWritten, NULL
|
||
call CloseHandle
|
||
|
||
;:::::::::::::::::
|
||
; Освободим память
|
||
invoke VirtualFree, dwOutputBuffer, NULL, MEM_RELEASE
|
||
|
||
;:::::::::::::::::
|
||
; Мессадж :)
|
||
invoke MessageBoxA, 0, offset szComplete, 0, MB_ICONINFORMATION
|
||
|
||
;:::::::::::::::::
|
||
; Выход)
|
||
xor eax, eax
|
||
ret
|
||
end start
|
||
|
||
; #########################################################################
|