Шрифт:
Интервал:
Закладка:
Чтобы избежать этой проблемы, мы, ученые-компьютерщики, изобрели так называемые языки ассемблера. Они созданы на основе железа и двоичного кода компьютеров и привязаны к ним, но сделаны понятнее, напоминая языки, на которых мы все разговариваем. На одном языке ассемблера сложение 10 и 20 может выглядеть примерно вот так:
MOV 10, REG 1
MOV 20, REG 2
ADD REG 1, REG 2, MEM 3
MOV MEM3, SCR
Сложение 10 и 20 на воображаемом, но наглядном языке ассемблера. Я придумал свой язык потому, что он понятнее, и потому, что, хоть у меня две научные степени в компьютерных науках, я до сих пор боюсь ошибиться, когда пишу на настоящем. Тут я точно не ошибся, поскольку сам официально заявляю, что это язык – «какой угодно, в котором код выше дает в сумме 30»
Как видите, тут есть очевидные недостатки. Ассемблер утомительный и скучный, нужно постоянно помнить кучу деталей (адрес в памяти, заполнены ваши регистры или нет и т. д.), и поэтому в них очень просто ошибиться. Надо хорошо знать аппаратную часть вашего компьютера, чтобы писать на ассемблере, а раз у разных процессоров немного разная архитектура, все знать невозможно. Но хотя бы в сравнении с двоичным кодом он намного яснее, чем если читать бесконечный поток нолей и единиц!
Следующий шаг – убрать из уравнения железо, чтобы не приходилось знать о расположении (и даже о существовании) таких деталей, как сумматоры и регистры. Такие языки уже называются высокоуровневыми языками программирования, и они куда более интуитивно понятны. С ними можно написать что-то вроде «сложить 10 и 20 и показать результат на экране» – и это просто сработает (см. врезку). А сработает потому, что вы по готовности запускаете другую программу, под названием «компилятор», чтобы перевести высокоуровневый код в максимально эффективный для вашего компьютера двоичный. Вывести сумму 10 и 20 на высокоуровневом языке можно вот так просто:
print 10+20
Результат сложения 10 и 20 на высокоуровневом языке программирования.
Результат – 30. Гарантирую
Сейчас существуют сотни языков программирования, каждый – с собственной философией, специализацией и сценариями использования. – Но все существуют с одной целью: упростить для людей чтение и написание кода, а это, в свою очередь, упрощает создание программ, их понимание и поддержку. Высокоуровневые языки раскрыли потенциал компьютеров и помогают создавать сложное, масштабное и прекрасное программное обеспечение. Они дали нам, людям, свободу действовать на уровне идей, а компиляторам остались запутанные, однообразные, пустяковые детали для их воплощения. За исключением тех, для кого двоичный код – хобби, и немногочисленных случаев специализированного ПО[77], сегодня все программы пишутся на высокоуровневых языках.
Радости компилирования высокоуровневых языков
Любой, кто писал код на любом высокоуровневом языке, наверняка уже мысленно сочиняет гневное письмо в мой адрес из-за фразы, что «это просто сработает». Эти люди знают, какими неуловимыми могут быть баги. Когда-то давно, занимаясь научной работой, я четыре часа разбирался, почему моя программа не хочет компилироваться, и наконец заметил, что в одном месте я случайно отпустил клавишу Shift и поставил вместо точки с запятой двоеточие, а на том языке все строчки должны были заканчиваться точкой с запятой.
Эта замена, случившаяся, скорее всего, из-за того, что я на микросекунду быстрее убрал палец с кнопки, и отличавшаяся всего на один пиксель, убила для меня полдня. Короче, компьютеры – это круто!
Поэтому программы и уязвимы перед злодейским планом, который вы провернете.
Низкоуровневые пакости для высокоуровневых языков
Уязвимость спрятана у всех на виду. Когда пишешь код на любом высокоуровневом языке, доверяешь компьютеру аккуратно преобразить написанное в двоичный код. Чтобы влезть в чей-то код, достаточно влезть в компилятор. Есть очевидный способ – плюс коварный, практически незаметный способ.
Давайте сначала рассмотрим очевидный.
Вот что происходит, когда вы компилируете приложение, написанное на высокоуровневом языке:
Допустим, вы проникли в компьютер жертвы через интернет и тайно изменили компилятор так, чтобы, компилируя с командой Print, он добавлял единицу к любому выведенному числу. И теперь, когда кто-нибудь использует компилятор, процесс выглядит вот так:
Внезапно, хоть кодировщики не наделали ошибок, все, что они создали с измененным компилятором, будет радостно извещать мир, что 10 + 20 = 31.
Приложения станут работать так, как не задумывалось, а бедные программисты-жертвы не смогут найти и исправить глюк «10 + 20 = 31» в своем коде, куда они посмотрят первым делом, поскольку изменения не там. Причина таится в исходном коде компилятора.
Конечно, они довольно быстро сообразят, что здесь что-то не то, ведь у их программ откровенная и заметная ошибка: каждое число больше на единицу. Но что, если действовать тоньше? Что, если вместо того, чтобы возиться с командой Print, сделать так: во всех ситуациях, когда компилятор обнаружит код с паролем, он проследит, чтобы заодно работал и пароль «райанкрутой». (Можно использовать свое имя, но скромно замечу, что мое на какое-то время собьет власти с вашего следа: мой вам подарок.)
Сделайте так – и получите то, что принято называть «бэкдор», или «черный ход», в любую компьютерную программу, которую создают с вашим компилятором: термин значит, что ваши жертвы могут как угодно запирать, ставить на сигнализацию и укреплять переднюю дверь – это не важно, ведь у вас есть секретная дверка, о которой никто не знает.
Не важно, насколько талантливы разработчики и как безопасен их пароль: все, что соберет ваш злодейский компилятор, примет пароль «райанкрутой» и разработчики никогда об этом не догадаются, если только случайно тоже его не попробуют.
Тут вы наверняка подумали: «Но ты же сказал, что компиляторы – такие же компьютерные программы, как и любые другие, а значит, любой может заглянуть в исходный код компилятора и найти мои изменения. Стоит им убрать ту часть, которая делает „райанкрутой“ паролем, и моему замыслу конец».
И вы правы: так может сделать кто угодно. Но вы сами сказали: компиляторы – такие же программы, как и любые другие.
И значит, они сами скомпилированы.
И вот тут – самый коварный момент.