На главную

Библиотека Интернет Индустрии I2R.ru

Rambler's Top100

Малобюджетные сайты...

Продвижение веб-сайта...

Контент и авторское право...

Забобрить эту страницу! Забобрить! Блог Библиотека Сайтостроительства на toodoo
  Поиск:   
Рассылки для занятых...»
I2R » Хакеры и безопасность » Вирусы

Два глотка свежего воздуха

Когда-то человек слишком полагался на машины, но это лишь позволило
поработить его другим людям, имеющим более совершенные механизмы.
Ф. Херберт "Дюна"

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

Однако и при этом убытки от вирусов не превышают 5%-10% от общего ущерба (вызванного поломками аппаратуры, стихийными бедствиями и разумеется неадекватными действиями пользователя).

Фактически мы имеем дело с мифом, поддерживаемым заинтересованными в нем людьми (журналистами, специалистами по безопасности, разработчикам антивирусов и наконец, самими пользователями, которым гораздо выгоднее свались все на вируса, якобы появившегося в самый неожиданный момент, и уничтожившим всю якобы сделанную работу).

При этом далеко не каждый пользователь хоть раз в жизни сталкивался с "живым" вирусом. А если и сталкивался, то благодаря пренебрежительному отношению к собственной безопасности. Хочу заметить, распространенное заблуждение, что проверенная "свежим" антивирусом дискета или программа безопасна.

Действительно, до того момента пока вирус не будет кем-то обнаружен, отослан в антивирусный центр, проанализирован специалистами и включен в очередное дополнение он, разумеется,не будет детектироваться антивирусной программой. По моим наблюдения этот период занимает от недели до нескольких лет. Например, вирус GE2000 появился в базе "Диалог Науки" только спустя полтора года с момента его создания и выхода в свет. (под именем BreakPoint).

Как такое могло случиться? Очень просто - GE2000 заражал только главную загрузочную запись жесткого диска и дискет. Никаких деструктивных действий в нем не было предусмотрено - вот он и не был замечен пользователями. Но кто бы мог дать гарантию, что в некоторый час "Х" вирус не уничтожит диски на сотнях компьютерах?

Cуществует любопытный вирус "KENGA", которых в течении трех лет оккупировал компьютеры в Успенском районе. Но не был замечен только потому, что первая попытка деструктивного проявления пришлась на воскресенье, а вторая на праздники - когда все компьютеры были отключены. И только на третий год, получив широкое распространение, он записал в MBR-сектор сотен компьютеров компоненту, которая приводила к "зацикливанию" при загрузке MS-DOS даже с заведомо чистой дискеты. (Сейчас этот примем уже широко известен. Необходимо адрес расширенного раздела MS-DOS установить на 0\0\1 - т.е. на основной).

К счастью по избыточной информации на жестком диске ее удавалось восстановить без проблем во всех случаях, и проблема была решена. Но однако любопытно, что до сих пор ни один антивирус Кенгу не детектирует. Печально не правда ли? Зачем же пользователи покупают весьма дорогостоящие продукты, которые не в состоянии их защитить?

По большому счету от антивирусов все же больше вреда, чем пользы. Не буду упоминать случаи некорректного лечения зараженных файлов (оставляя это на совести разработчиков),а обращу внимание на "иллюзию безопасности" создаваемую антивирусами, утверждающими, что вирусов якобы не обнаружено. Человек расслабляется... чем это может кончиться всем хорошо известно. Уничтоженной информацией, последующим за ней выговором от начальства или в лучшем случае необходимостью приводить систему в исходное состояние, расходуя на это время, которое можно было бы с успехом употребить на нечто более полезное.

Прочитав это,автора возможно уже не раз упрекнули в замалчивании значимости, так называемых "Эвристических анализаторов". Действительно, цифры приводимые в руководствах к антивирусам очень внушительны. Обычно утверждается, что тот или иной эвристический алгоритм может обнаруживать до 80-90% новых, ранее неизвестных "насекомых".

И дело даже не в том, что эти цифры откровенная "липа"... Ведь если эвристический анализатор дает пусть даже 99.999% гарантию обнаружения, то он потенциально бессилен перед новыми вирусами! Почему? Да ведь вирусописатель, изучив код последнего найдет в нем слабые места и сможет написать вирус, который останется незамеченным!

И вновь мы возвращаемся к началу - что бы антивирус обнаруживал "заразу" ее сперва должны исследовать и включить - не важно куда в эвристический алгоритм или в базу сигнатур. Для пользователя это значит по меньшей мере то, что антивирусу все равно нельзя верить.

Обратим внимание еще на один факт. Не секрет, что большинство вирусов пишется школьниками и студентами, не обладающими ни знаниями, ни навыками. Их "продукция" может вызвать лишь снисходительную улыбку профессионалов. Вы говорите полиморфизм? Достижения автоматического проектирования и само-проектирования?

Увы, любой разработчик оптимизирующих компиляторов ежечасно сталкивается в своей работе с задачами на несколько порядков превосходящими сложность лучших представителей полиморфных генераторов. Фактически "полиморфики" создают лишь более или менее примитивные крипторы\декрипторы, оставляя нетронутым остальной "базовый" код. Таким образом, возможна автоматическая "распаковка" последних, которая выдает один и тот же код, независимо от "поколения" полиморфного вируса.

При этом "крутость" полиморфного генератора просто несущественна. В любом случае проверять будут не его, а расшифрованный код вируса. Выходит, по большому счету полиморфные вирусы не принесли ничего нового? И лишь чуть-чуть усложнили механизм антивируса для их выявления? Похоже что так.

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

Начнем с того, что получить произвольным образом само-изменяющийся код просто невозможно, по крайне мере на архитектуре микропроцессоров INTEL. В любом случае существуют жесткие рамки, которые позволяют одну и ту же операцию реализовать ограниченным числом способов. Которые, кстати, сказать детерминированы, т.е. известны заранее. И их достаточно немного, что бы можно было обойтись простым перечислением. Т.е. теоретически возможно перечислить все возможные ключевые фрагменты вирусов, что позволит их безошибочно детектировать. Невероятно сложно, создать такое, но все же возможно.

Вот если бы архитектура популярных микропроцессоров была иной... Но постойте! А почему был нет? Разве нам запретили писать свой эмулятор? Т.е. иначе говоря некоторую виртуальную машину, которая будет обрабатывать свой собственный код, построенный на произвольных принципах, из которого собственно и будет состоять вирус.

При этот реализация последней может быть какой угодно. Виртуальный процессор может иметь не только произвольный набор команд, но и самую необычную архитектуру. Например, представлять собой машину Тьюринга.

Между прочим, это неплохая идея. Во-первых специальным образом написанный эмулятор имеет несопоставимые затраты усилий на создание и анализ. Т.е. нетрудно написать эмулятор за вечер-другой, который специалисты будут "раскручивать" не одну неделю.

Кто сталкивался с защитами, построенными на основе "виртуальных машин" поймет без дальнейших объяснений. Сомневающихся я отправляю к булевскому эмулятору от Solar-a Desonger-a или к EM3R от KPNC (с динамически создаваемым набором команд). Последний кстати, мне еще неизвестно, что бы кто-то "сломал" уже в течении пяти лет, хотя на его создание ушло не более 100-150 человека часов.

Возможно этот момент требует пояснения. Что такое "эмулятор" в данном контексте? Фактически это интерпретатор кода, на котором написан вирус (ну или что-то еще). С первого взгляда может показаться, что последний ничем существенно от полиморфных расшифровщиков не отличается, но это, однако, не так.

Полиморфный статический расшифровщик (а других я пока не встречал) расшифровывает весь код вируса, после чего передает на него управление. Т. е. он является внешней (так называемой "конвертной") защитой. Избавиться от него не трудно - для это существует множество автоматических распаковщиков (UNP,CUP386,AUTOHACK). Они трассируют код расшифровщика и дождавшись завершения его работы "скидывают" полученный дамп на диск.

Точно так же и работают большинство антивирусных детекторов полиморфных вирусов. Как видно, при этом "крутость" полиморфик-алгоритма (как бы это ни было удивительно) вообще никакого значения не имеет. Все что может сделать автор вируса - это затруднить автоматическую распаковку разными хитрыми приемами программирования. Например, написать само трассирующийся код. Поэтому современные антивирусы должны эмулировать выполение подобных "анти-отладочные" инструкций, что с большим успехом (хотя и не без ляпов) они и делают вот уже несколько лет.

Гораздо более совершенная динамическая шифровка. При этом ни в один момент код не окажется расшифрованным целиком. По мере надобности дешифруются лишь небольшие порции кода, которые после отработки уничтожаются. Понятно, чем меньше длина декодируемого блока, тем лучше. Т. к. фрагмент в несколько десятков байт уже достаточен для надежного сигнатурного поиска.

В доведенной до абсурда идее можно сократить длину блока до одного бита. (вообще-то можно и меньше, но подобные алгоритмы выходят за рамки данной статьи). Но даже в этом случае один бит ну никак не может служить сигнатурой, тем более надежной.

Впрочем, таких вирусов сегодня нет и даже очень немногие защитные механизмы используют динамическую шифровку с подобной степенью дробления. Реализация ее достаточно сложна и доступна далеко не каждому. Однако, думается, что десяток сильнейших вирусописателей вполне могли бы написать нечто похожее, найдись у них достаточно свободного нечем не занятого времени.

При этом нет ни одного антивируса, который без серьезной переделки и доработки мог бы обнаруживать подобных "тварей", Однако, по крайней мере один алгоритм для этого есть. Исходя из того, что криптоскойкость используемых вирусописателями крипто-алгоритмов до смешного низка, то очевидно, что можно решиться "распаковать" код одним из криптоаналитических алгоритмов, используя атаку по прямому тексту.

Да, это не оговорка. Именно "по прямому тексту". И мы опять возвращаемся к детерминированности инструкций микропроцессоров Intel. Например, инструкция INT 21h кодируется как 0xCD 0x21, а это уже сильно облегчит криптоанализ. Могут возразить, что существует множество способа вызова прерывания... Это так, но только отчасти. На самом деле число вариантов будет достаточно немного и всех и можно перечислить.

Все дело в относительно простой логике преобразования кода шифровщиком. Ну и не в последнюю очередь "в открытом тексте". Всех этих недостатков лишен интерпретатор. Последний может обладать сколь угодно сложной логикой преобразования ("трансляции") своих инструкций в код процессора. Например у "булевских" интерпретаторов всего _одна_ инструкция, принимающая различные параметры. При этом даже простейшие команды, например сравнить две переменные "распадаются" на десятки команд булевского интерпретатора. Организация цикла уже потянет на сотню или около того. При этом инструкции явным образом не декодируются и не расшифровываются в опкод процессора. Просто для всего множества "виртуальных" команд есть своя реализация. Для булевского интерпретатора это знаменитая "Стрелка Пирса", реализуемая следующими инструкциями:

OR  A,B

NOT A

Этими двумя командами можно выразить все множество остальных, исходя из основ булевской алгебры и принципов эквивалентности. При этом "явной" трансляции не происходит. Т.е. множество команд реального и "виртуального" процессоров не пересекаются. "реальных" будет только две команды (ну еще десяток команд на выборку инструкций" - что-то наподобие:

Repeat:

MOV     SI,[0152]                         ;    Указатель команд

LODSW                                        ;    Читаем 1st операнд

XCHG    DI,AX                            ;    DI := [1st]

MOV     DI,[DI]                            ;    ^

LODSW                                        ;    Читаем 2st операнд

XCHG    BX,AX                           ;    BX := &2st

OR      DI,[BX]                              ;    t0 := [1st] | [2st]

LODSW                                        ;    Читаем 3st операнд

XCHG    DI,AX                            ;    AX := t0 ; DI = 3st

NOT     AX                                   ;    AX := NOT t0

MOV     [0152],SI                         ;    Update emIP

STOSW                                        ;    mov [3st],NOT(OR [1st],[2st])

JMP     Repeat                              ;    -- цикл выборки команд --^

Все остальное запрограммировано на "виртуальном" языке. При этом никакой автоматический распаковщик будет не в состоянии проанализировать код или преобразовать его в код "реального" процессора. Точнее последнее можно сделать можно без труда, но что нам даст малопонятная последовательность инструкций OR и NOT, беспорядочно усеивающих листинг? Их смысловую нагрузку может только человек, вооруженный математическим багажом знаний. Автоматический анализ не представляется на данном этапе развития информатики возможным.

Итак, вирус написанный на "виртуальной машине" имеет то достоинство (если это можно назвать достоинством), что требует уймы времени для анализа. Если появится тенденция в написании таких, то сомневаюсь, что бы антивирусная промышленность справилась с таким объемом работы - потребуются дополнительные высококвалифицированные сотрудники и вклады. А где их взять? Специалисты обычно не сидят без дела,в ожидании предложений, а уже имеют любимую работу, переманить с который их будет ой как не просто.

С другой стороны, без анализа работы виртуальной машины невозможно детектировать вирус, написанный не ней. Удивительно но, многие известные и уважаемые разработочки антивирусов просто ухмыльнулись и сказали, что включат "виртуальный код" без вникания в его суть, т.е. простой сигнатурный поиск по дампу кода интерпретатора.

А напрасно... привычка к идеологии INTEL не лучше средство в подобной борьбе. Пусть, обрабатываемый виртуальной машиной код выглядит так:

       |----------|
3 xx 7 xx 6 xx 2 xx 4 xx 0 xx 1 xx 5 xx 9 xx 11 x 16 x 20
          |-----------------|

т.е. каждая команда состоит из двух блоков кода, (обозначенного xx) и указателя на следующую команду. При этом сам код может зашифрован, например операцией XOR с номером текущей ячейки. (строго говоря это относится непосредственно не к коду, а скорее к организации виртаальной памяти интерпретатора. Архитектурно процедура выборки команда обращается к менеджеру памяти, который и осуществляет переход на заданную ячейку по указателю)

Что это дает? А то, что можно как произвольным образом перемешивать команды (корректируя лишь указатели). Учитывая, что они "ксорятся" в зависимости от своего место-положения, то поучается, что можно сохраняя работоспособность до неузнаваемости изменять код вируса. Конечно, зная этот механизм, нетрудно расшифровать его и антивирусу (и получить "исходный" код), но для этого необходимо проанализировать интерпретатор. Учитывая, что большая часть кода эмулятора может быть написана на его же собственном наборе команд, становится очевидно, что предстоит большая, кропотливая и утомительная работа по его изучению.

При этом вирусописатель и антивирусист находятся не в равноправных условиях. Действительно, интерпретаторы можно генерировать и автоматически, но вот до сих пор не создано (да и вряд ли когда нибудь будет создано) программы автоматической "декомпиляции" интерпретаторов. Более того,даже нет дизассемблера, легко настраиваемого на различные архитектуры. (IDA для этой цели окажется недостаточно гибка, хотя это пока единственный выбор) Выходит - что каждому вирусу (построенному на виртуальных машинах, разумеется) - по дизассемблеру!? Представляете какие это трудозатраты?

Впрочем, это проблема больше финансовая и организационная, чем техническая. Вирусы рано или поздно должны были усложниться до той степени, когда "ручным" анализом нескольких специалистов (а именно столько и работает в ОА "КАМИ") уже ничего нельзя будет сделать.

Однако, если вирусы научаться продуцировать не только свой наобум измененный код, но и генерировать усовершенствованные интерпретаторы своего кода, то теперь в игру включается "машинная эволюция" и потенциал вирусов многократно усиливается. Бытует мнение, что вышесказанное невозможное.

Однако, осмелюсь утверждать, что в подобном направлении ведутся интенсивные и небезуспешные исследования уже не один десяток лет. Ниже будут показаны простейшие и доступные для массового понимания машинной генерации виртуальных машин. Не будем пока трогать эволюционирующие механизмы, а сосредоточим свое внимание на "мутирующих". Т.е. случайным образом изменяя свое "тело" при этом сохраняя полную работоспособность. При этом выбранные алгоритмы должны обеспечивать по возможности максимальный уровень полиморфизма или по крайней мере затруднения в изучении кода.

Грубо говоря любой интерпретатор можно представить из двух функциональных частей - цикла выборки (и декодирования) инструкций и их реализации на уровне микрокода. Например, Интеловская инструкция LOOP на самом деле распадается на две DEC CX\JZ xxx.

Разумеется каждый микрокод имеет свою реализацию, которая уже работает на реальном микропроцессоре. Но, как было показано выше, возможно добиться (правда ценой снижения производительности - но к чему вирусам производительность?) Что бы на реальном процессоре выполнялась только одна команда - стрелка Пирса, а на ней уже строилось все остальные "богатство".

Теперь мы подходим к самому интересному - к интерпретатором с произвольно генерируемым набором инструкций. В самом деле, можно уничтожить инструкцию LOOP, заменив ее парой команд DEC\JZ. В совою очередь можно две соседние инструкции объединить в одну реализацию и заменить новой командой. Особенно это полезно проделывать с "устойчивыми комбинациями" типа CALL xxx\ OR AX,AX\JZ xx - это "сожмет" немного код. Если пойти дальше, то можно наугад взять несколько инструкций, даже не обязательно соседних и заменить их одной новой. И так продолжать пока "не надоест" или код окажется до неузнаваемости измененным.

Во "втором поколении" можно проделать то же самое. Теперь будет большой выбор инструкций для "дробления". Конечно, вероятнее всего, что полученные инструкции не совпадут с исходными, т.е. "второе" поколение еще больше будет отличаться от первого.

При этом может меняться до 99% кода, причем необратимо и недетерминированно. Т.е. никакой математический алгоритм не сможет определить тождественность двух разных поколений.

Однако, ~1% кода останется неизменным. Это, разумеется реальный код, исполняемый на реальном процессоре. И вот тут на помощь приходят существующие полиморфные алгоритмы. Написать процедуру автоматической генерации интерпретаторов по силам даже среднему виросописателю. В этом 100% кода меняется от поколения к поколению непредсказуемым образом, при этом у каждой копии своя "виртуальная" машина со своим набором команд и следовательно каждая требует отельного изучения и уникальных только для нее одной методов детектирования и лечения.

При этом отметим любопытный момент - проанализировать логику такой виртуальной машины невероятно трудно. Дело в том, что функции команд, сгенерированных произвольным образом, а затем таким же образом "рассыпанных" совершенно непостижимы. Это похоже на головоломку "pizzle". Число связей между отдельными командами стремиться к n!, где 'n' - число команд. Учитывая, что виртуальная машина может оперировать сотнями и даже тысячами команд, то становиться очевидным, что "вручную" проанализировать, а точнее декомпилировать код вируса будет невозможно.

Сегодня специалися экспериментируют с виртуальными машинами, манипулирующими с сотнями тысяч инструкций. При этом что бы понять логику их работы требуется проанализировать реализации все команд с особой тщательностью, поскольку результат выполнения одной инструкции зависит от множества остальных. Например, в микропроцессорах Intel многие инструкции взаимодействуют с регистром флагов. И если проигнорировать одну инструкцию, то мы не сможет предсказать результат выполнения другой. Например,

XOR AX,AX

JZ  xxxx

Что бы знать выполниться или нет условный переход, надо вспомнить, что XOR AX.AX устанавливает флаг нуля. А если у виртуальной машине будет несколько сотен или тысяч флагов? Вряд ли это можно не комментировать. Некоторые называют это "садизмом". Вероятно, "садизмом" по отношению к тому, кому придется это исследовать? Но ведь и в этом и заключается суть противостояния двух миров - антивирусов и вирусов. Нам нельзя полагаться на "добрых" вирусописателей. Такие конечно, не редки, но ведь в мире очень много разных людей, в том числе злых и агрессивных.

Давайте еще усилим реализацию. Пока мы говорили о случайном наборе команд. А почему бы еще случайным образом не изменять архитектуру? Например, путь будет случайное число стеков (включая нулевое)? Случайным образом организованная память, (т.е. функция преобразования логических адресов в физические генерируется случайным образом)? Данные и код могут быть перемешены, а могут быть разнесены в разные сегменты...

Кроме того, описываемая технология с легкостью стоить крос-платформенные вирусы. Действительно, ведь основная часть вируса написана на платформенно-независимом встроенном языке. И только маленький "кусочек" кода работает на реальном процессоре. Естественно, что нетрудно его переписать и для других систем. Это значительно увеличивает число потенциальных жертв при минимальных накладных расходах на разработку. Можно пойти дальше и выполнить интерпретатор на Си, а потом искать его компилятор на заражаемой машине и генерировать новый код. Ну или можно воспользоваться Бейсиком, встроенным в Браузеры Интерната и Текстовые и Электронные процессоры фирмы MicroSoft. Последнее кстати, особенно актуально на фоне сегодняшнего нашествия Макровирусов.

Правда захватывает дух? А ведь генерация каждого нового поколения необратима и непредсказуема. Т.е. невозможно создать детектор, который бы мог гарантировать тождественность разных поколений!

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

При этом даже два вируса, написанные совершенно независимыми людьми будут иметь меньше общего, чем один и тот же вирус, спустя несколько поколений. Поэтому-то и идентификация вирусов в этом случае теряет всякий смысл. Конечно, если только последний не содержит в себе текстовых строк или каких-то других характерных отличий.

Возможно, что эта статья уже вызвала чувство легкого беспокойства читателей за свою безопасность. В самом деле, что будет с миром компьютеров, если такой вирус кто нибудь не сегодня, завтра напишет? Не волнуйтесь, для компьютерщиков это не будет сильным потрясением. Ведь как бы не изощрялись авторы вирусов ведь существуют элементарные правила "гигиены" и кроме того такое понятие как "разграничение доступа".

Т.е. иначе говоря в грамотно сконфигурированной системе разрушения от любого стихийного бедствия (а не только вируса) должны быть близки к нулю. Конечно, это вряд ли относиться к "домашним" операционным системам типа win98, в которых вирусу не составить труда обойти примитивную систему разграничения доступа и уничтожить всю информацию.

Однако. win98 вообще не очень хорошая система для сегодняшних требований и если вы хотите более или менее обезопасить себя, используйте защищенные операционные системы. Не предлагаю инсталлировать UNIX, но NT вероятно оптимальна не только для офисного, но и "домашнего" использования.

В этом случае вирусу потребуется как минимум "пробить" систему безопасности NT. При этом не нужно путать неустойчивость NT перед сетевыми атаками и надежность подсистемы разграничения доступа. Последняя выполнена на редкость качественно и если пользователь не допустит грубых ошибок, то вирус не сможет нанести практически никакого ущерба.

Вроде бы все знают правило, что каждую программу следует запускать с минимальными правами доступа. С привилегиями супервизора следует запускать только ограниченный круг заведомо незараженных программ. Но просто удивительно, что для большинства пользователей режим супер-визова - основной режим работы, хотя он им реально и не требуется.

Грамотный системный администратор большую часть времени работает с минимально возможным уровнем привилегий, переключась в режим супер-визора только когда это действительно необходимо. При этом вирус не имеет никаких шансов разрушить такую систему. Напротив, не стоит удивляться, что вирус, запущенный с правами супер-пользователя быстро "расползется" по всей системе, заставляя администратора хвататься за голову и произносить нелестные слова в адрес виновника.

При этом антивирусы не являются и никогда не станут "панацеей" от всех бед. Пока последние не будут давать _реальных_ гарантий они останутся только бесполезной, но очень дорогой игрушкой (конечно, если их покупать, а не копировать варварски-пирацким способом). Вместо антивируса лучше купить реврайтер и периодически резервировать наработанные данные. Это все же надежнее, спокойнее, да и быстрее.

Все равно ведь эвристические анализаторы еще не научились лечить неизвестные им вирусы, поэтому как ни крути а требуется резервная копия. Но если есть резервная копия, то зачем нужен антивирус? Конечно,это несколько утрировано, но в этом все же больше истины, чем юмора.

Крис Касперски
Internet Security

Рассылки Subscribe.Ru
Все о защите данных на Идваре
Другие разделы
Прочие опасности
Вирусы
Хакеры
Киберпреступность
Уязвимость ПО
Новое в разделе
Защита данных
I2R-Журналы
I2R Business
I2R Web Creation
I2R Computer
рассылки библиотеки +
И2Р Программы
Всё о Windows
Программирование
Софт
Мир Linux
Галерея Попова
Каталог I2R
Партнеры
Amicus Studio
NunDesign
Горящие путевки, идеи путешествийMegaTIS.Ru

2000-2008 г.   
Все авторские права соблюдены.
Rambler's Top100