Как захватить Вселенную. Подчини мир своим интересам. Практическое руководство для вдохновленных суперзлодеев — страница 25 из 51

4. Они должны быть прозрачными, поскольку жизненно важно, чтобы не только выборы были честными, но и люди верили в их честность. Единственный способ этого добиться – полная прозрачность в том, как голоса отдают, собирают и подсчитывают.

5. Ну и, конечно, они должны быть точными, поскольку шанс есть только один, на выборах переигровок не бывает. Любые попытки аннулировать результаты, чтобы попробовать еще раз, приведут к серьезному недовольству, ведь выигравшие будут с полным правом считать, что их обманули.


И мы сразу видим взаимопротиворечащие стандарты: мы хотим честности, чтобы люди голосовали только раз, но хотим и анонимности, чтобы никто не узнал, как проголосовал каждый. Суровые ограничения… Но бумажное голосование справляется с ними отлично! Работникам избирательного участка нужно всего лишь проверить документы, чтобы убедиться, что голосуют только граждане (открытость: есть!) и голосуют они только раз, на том участке, к которому приписаны (честность: есть!). Но как только проголосовавший внесен в списки посетивших участок, забрал свой бюллетень, неотличимый от других, и удалился в кабинку для голосования, уже нельзя связать результат его голосования с конкретной личностью, обеспечивая анонимность (есть!). И все прозрачно (есть!), поскольку, хотя отметки в бюллетене делаются втайне, после этого он кладется в ящик для голосования на глазах у наблюдателей. Когда выборы заканчиваются, голоса подсчитывают публично, в идеале – под пристальным надзором представителей всех участников выборов. Это позволяет результатам быть точными (есть!) и подтверждаемыми, поскольку любые споры решаются пересчетом: возьмите те же бюллетени, сосчитайте снов – и готово.

Но посмотрите на недостатки бумажного голосования! Вручную – буквально руками, как пещерные люди какие-то! – подсчитывать очень долго. У работников избирательных участков и наблюдателей начинаются споры из-за не до конца пробитых бюллетеней-перфокарт, несовпадения подписей, «эту галочку засчитываем, а ту – нет». Плюс топать на избирательный участок совсем неудобно, особенно когда в стране не проводят выборы в выходной! Остановка работы будет стоить стране времени и денег, а значит, можно сэкономить тонны того и другого, голосуя в Сети. Мы же не в XIX веке живем – почему голосовать надо, как тогда? Каждый день мы заходим в банк онлайн, шопимся онлайн, платим налоги онлайн, голосуем за любимых звезд в реалити-шоу онлайн и выкладываем пикантные нюдсы онлайн![76] Что трудного в том, чтобы добавить в этот список и голосование? Ну а если по каким-то волшебным причинам невозможно сделать простое приложение для голосования, можно поставить компьютеры хотя бы на избирательных участках? Тогда результаты поступят уже через секунды, а не часы, а пересчет займет мгновение!

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

Так приступим!

Чтобы это провернуть, первым делом надо поподробнее разобраться, как, собственно, работают компьютеры.

Вы наверняка знаете, что эти машины функционируют благодаря двоичному коду: 0 и 1. Еще вы наверняка знаете, что вручную писать в двоичном коде трудно (вообще-то, настолько, что практически никто не хочет этим заниматься). Даже если у вас получится, то на выходе будет просто много цифр и никто – включая вас через несколько дней, как только вы забудете, что написали, – не разберется, что делает этот код. А ну-ка, быстро, что делает эта программа?

11001100 11001101 10001010 10101010 10101100
11001100 11011000 10101010 10101010
Может, компьютерная программа в двоичном коде, а может, кто-то настучал двумя пальцами по клавишам 1 и 0 соло для саксофона из хита Джорджа Майкла Careless Whisper

Честный ответ: «Что угодно – смотря как интерпретировать, на каком компьютере она работает… И даже при этом – поди разберись».

Чтобы избежать этой проблемы, мы, ученые-компьютерщики, изобрели так называемые языки ассемблера. Они созданы на основе железа и двоичного кода компьютеров и привязаны к ним, но сделаны понятнее, напоминая языки, на которых мы все разговариваем. На одном языке ассемблера сложение 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, сделать так: во всех ситуациях, когда компилятор обнаружит код с паролем, он проследит, чтобы