25 июня 2012 в 03:28

Машина Тьюринга восстановлена из уплотнённого кода

День назад праздновали день рождения Тьюринга, и на сайте Гугла был дудл с джаваскриптовой машинкой Тьюринга. Уже не первый раз поисковик показывает нетривиальные и интересные скрипты, которые потом, после дня празднования, исчезают в небытие. Странно, что на странице всех дудлов о них есть немного слов, но нет работающих моделей, как, например, по рассматриваемому дудлу машины Тьюринга (UPD4 (26.06.2012, 5:20) — по этой ссылке появился живой скрипт, можно играть; но обфусцированный ещё сильнее, чем был на странице). Возможно, они где-то есть, но поиск в интернете не привёл к результату. Такое своевольное поведение стихии интернета начало надоедать, поэтому вчера я без особого напряжения и старания, но решил извлечь работающий код и попытаться им управлять.

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

Выкладываю всё вытащенное на Гитхаб, уже с деобфускацией. Если авторы выскажут недовольство и потребуют удаления — что-нибудь придумаем, как уйти от авторских материалов (очень много кода из самого дудла, анимации спрайтов — там выполнять необязательно), а пока что проект рассматривается как образовательный. Ведь задача реинжиниринга игрушки не несёт иной цели, как обучиться методам реинжиниринга и деобфускации, а также знакомства с кухней непомерно разросшихся скриптов такого простого поначалу сайта. Поэтому в репозиторий я положил не только сам скрипт машинки, но и все присутствующие на странице скрипты — бара, футера, и чего-то ещё. Это может быть полезно как для знакомства, так и для восстановления функций игрушки (машины Тьюринга), потому что в ней как-то различаются 2 состояния пользователя — пришедшего первый раз и прошедшего первые 6 уровней (по числу букв «Google»).

В конечном итоге, вся игра заключена в одном файле turing12.3.js и в 2 картинках спрайтов (turing12-hp-deferredsprite.png, turing12-hp-sprite.png). Всё остальное для основной задачи несущественно.

Далее, запуск самой игры сформирован (вручную) в файле gTuring01.htm (при этом начинает работать встроенный двоичный счётчик на машине), а запуск страницы поиска для ознакомления с оболочкой и всеми прочими файлами rs.js, ssl_gb.js — в googleTuring.htm, но сама игра в последнем файле не запущена, только на первом. extern_chrome_ca.js — файл из канадского Гугла, неизвестно, что делает, к игре не относится. Если понадобятся сжатые исходники — они есть, но быть нужными не должны, деобфусцировано нормально, этим сервисом.

Найденный симулятор машины Тьюринга (JS) с доработками 2012 года.
Open-Turing-Project / OpenTuring (язык C)



UPD: rrock в комментариях рассказал, как запустить игру дальше и начать проходить уровни. Хотя это ещё не полное решение, но продолжение есть!

UPD2 (26.06.2012, 1:30): перед коммитом в Гитхаб (пока не сделан) — копаем немного дальше.

Просмотр кода turing12.3.js показывает, что в var T = function (a) {… (строка примерно 3638) записаны задания и программы для машины к каждому из них. Первое задание ( U = [{… z: "", p: "",) — это, видимо, программа счётчика, запускаемого по умолчанию.

Далее, почему удалось запустить из страницы поиска и не удалось из искусственно созданной — потому что событие клика повешено на внешний по отношению к геймплею объект — блок с id=«hplogo». От него и стартует первое задание, видимо, через строку " if ((Y = document.getElementById(«hplogo»)) && "… — единственное место, где ид встречается.

Также, легко догадаться и предположить, что все U[...] — это выбор правил уровня задания, а U[0] и место "m.aa(U[0].a.Va, e);" — запуск счётчика по умолчанию, Ab() и «a.onload = Ab» — функция запуска по умолчанию. (Однако, подстановка U[1] к запуску 1-го уровня не приводит, хотя поведение меняет. Имеет значение контекст.)

Цель копаний сейчас — создать ссылку, по которой запустится 1-й уровень игры со страницы gTuring01.htm.

UPD3 (26.06.2012, 3:30): сделан коммит. Цель на %75 достигнута — оба HTM-файла запускаются и играют по нескольку уровней. Подробности поведения и запоминания состояний не исследованы. Главное пока — работают.
Вариант rrockgithub.com/rrockru/GoogleTuring.

UPD4 (26.06.2012, 5:20): и, однако, мы зря беспокоились, что этот скрипт они не оживят — ещё вечером там была картинка, а сейчас — работающий скрипт! www.google.com/doodles/alan-turings-100th-birthday. Но! Там он закопан ещё глубже в обфускацию (как вам это нравится? src="/doodles/js/doodle_javascript.js"), а здесь он читаемый и открытый.

UPD5 (26.06.2012, 6:00): рабочий пример здесь: spmbt.kodingen.com/gTuringMachine/index.htm

+66
2363
75
spmbt 76,8

Комментарии (30)

+9
powder96 #
Жалко что всякие интересные штуки с главной гула не выкладывают в опенсорс — им там самое место, ИМХО.
+2
powder96 #
Если кто помнит синтезатор, то пока еще есть возможность его расковырять: google.com/logos/2012/moog12-hp.html. Себе уже скачал, состоит из четырех файлов: moog12-hp.html, moog-hp-base2.png,
+1
powder96 #
… moog-hp-k-sprite.png, и moog-hp-sprite2.png.
0
pehat #
Извините, может, я чего-то не понимаю, но мне не хочется искать код синтезатора в трех картинках. А вообще аналоги синтезатора Муга есть в любом уважающем себя секвенсоре, в FL Studio, например.
0
hammerit #
В опенсорс не выкладывают, но все штуки с главной они сохраняют. www.google.com/doodles/robert-moogs-78th-birthday
0
spmbt #
Но для машины Тьюринга выложен только рисунок (ссылка в статье). Возможно, они не успели там инсталлировать скрипт и позже он появится, раз скрипт синтезатора на своей странице имеется. Заранее, как я понимаю, никто ничего не знает и не обещает.
–8
newpavlov #
+8
newpavlov #
Упс, там же только описания…
+11
DaleMartinWatson #
Поднимите эту тему в популярные. Тогда может кто-то из сотрудников google, читающий Хабр, сможет посодействовать в получении чистых исходников этого дудла. Для некоммерческого использования, так сказать. Им то он, как я понимаю, уже не нужен. Во второй раз его уже не повесят.
+1
rrock #
А скрипт то еще на месте: www.google.com/logos/2012/turing12.3.js
+1
rrock #
Вроде заработало: в файле googleTuring.htm нужно исправить строку 4431, прописав путь к локальному скрипту. То есть: a.src = «turing12.3.js»
0
spmbt #
Отлично, спасибо. Я пошёл по более длинному пути, пытаясь выцепить сразу скрипт игры, а этот путь получился короче, хотя требует подгрузки всех скриптов на странице.

И ещё мешает почему-то моё дополнение с console.log на строках 3038,3039 turing12.3.js. Если заменить на оригинал this.ja = j(this.qb, this); — уровни начинают проходиться.

Сейчас у меня игра виснет при переходе на 4-й уровень (Fx12) из-за ошибки «a is undefined» a is undefined — строка 2730, turing12.3.js.

(Чуть позже сегодня закину обновления на гитхаб.)
0
rrock #
С уровнями разобрался — проблема в том, что Ваш деобфускатор в коде уровней вместо пробелов понатыкал табуляции и в итоге код смущается, когда ему вместо «R» прилетает «R ».
0
spmbt #
Супер. Записал пробелы вместо табуляций для коммита.
Обратите внимание, что у меня был патч ещё в этом месте: window.google && window.google.x00 — в самом конце файла turing12.3.js, а было — window.google && window.google.x. Иначе не запускалось.
0
rrock #
Да вот в том то и прикол, что если есть функция window.google.x, то как раз таки она запускает игру.
0
spmbt #
Нет, запускает, Rb(), как видим, а window.google.x({id: «DOODLE»}, Rb); запускает тоже, но некоторым хитрым образом — наверное, она отвечает за включение — выключение функции по появлению определеённой даты или через неё передаются контекстные данные юзера — зашёл он первый раз или не первый (предположения).

А главное, нашёл, почему не запускалась стандалоновая игра в gTuring01.htm. Она почему-то (потому что стилей соответствующих нет) имела высоту стартового покрывающего дива с id=hplogo, равную нулю. Сделал патч — this.V.style.height = (a.offsetHeight || 229) + «px»; //строка 3126 — и старт заработал. Выкладываю полученное на гитхаб. Наверное, это %75 готовности. Останется разобраться, как попадать на 7-й уровень. И где (в куках?) запоминается уровень так, что он не сбрасывается.
0
rrock #
У меня полностью работает :)

(function () {
window.google || (window.google = {});
google.doodle || (google.doodle = {});
google.doodle.url = «www.google.com/search?q=%D0%90%D0%BB%D0%B0%D0%BD+%D0%A2%D1%8C%D1%8E%D1%80%D0%B8%D0%BD%D0%B3&oi=ddle&ct=turing-doodle-static»;
google.doodle.alt = «100 лет со дня рождения Алана Тьюринга»;
var a = document.createElement(«script»);
a.src = «turing12.3.js»;
a.async = !0;
document.body.appendChild(a);
})();

Код отвечающий за сохранение уровня в строках 3632-3637.

А на 7-ой уровень мы попадаем тут (строка 3999):
0
rrock #
Да уж… Парсер такой парсер…

(function () {
window.google || (window.google = {});
google.doodle || (google.doodle = {});
google.doodle.url = «www.google.com/search?q=%D0%90%D0%BB%D0%B0%D0%BD+%D0%A2%D1%8C%D1%8E%D1%80%D0%B8%D0%BD%D0%B3&oi=ddle&ct=turing-doodle-static»;
google.doodle.alt = «100 лет со дня рождения Алана Тьюринга»;
var a = document.createElement(«script»);
a.src = «turing12.3.js»;
a.async = !0;
document.body.appendChild(a);
})();

0
rrock #
В общем вот мой вариант: github.com/rrockru/GoogleTuring
0
rrock #
Для того, чтобы всегда игра запускалась с первого уровня, достаточно в строке 3999 заменить
b = U[S.i].A, V.create(0 == b? 6: b)
на это:
V.create(1)
Либо вообще убрать сохранение в localStorage, то есть комментируем строку 3633.
0
spmbt #
Отлично, полная победа! (Напишите победный отчёт :) )
Тут ещё в индекс-файле грузить через скрипт необязательно.
Свой вариант выкладываю на хостинг, и приведу стартовый файл тоже в порядок.
0
rrock #
Ну не полная. Я, перед тем как заснуть, вспомнил, что нужно еще убрать переход на поиск после 6-го уровня.
0
rrock #
Победил переход после 6-го уровня:
строка 3908
!N && 12 == b? C(Ib, 500): a? C(Z(function () {
Теперь он будет осуществляться после 12-го, последнего.
0
rrock #
Точнее осуществлялся бы, если бы не выпилили все скрипты гугла :)
После 12-го уровня ошибка в строке 3841
sb? google.nav.go(…
0
rrock #
За компанию убрал реплеи :)
0
spmbt #
И ещё можно тогда запускать уровни по цифрам, а затем сочинять свои схемы и делать свои уровни. Ну это уже для фанатов.
0
rrock #
Да, запуск нужного уровня можно делать через
window.localStorage.setItem(«doodle-turing-p», [номер уровня])
до запуска скрипта игры.
0
rrock #
Судя по коду, мы сможем получить доступ только к 1-7 уровням. Дальше нумирация уровней начинает повоторяться. Если не ошибаюсь, то нужно разбирать функцию Eb из строки 3902. Но я смогу этим заняться только вечером, а то с работы уволят :)
0
rrock #
Ан нет. Всё работает исправно до 12-го уровня.
0
sompylasar #
Этот код теперь выложили в open source: code.google.com/p/turing-doodle/ — может кому пригодится эта ссылка.

На www.google.com/doodles/alan-turings-100th-birthday написали:
The code for this doodle has been open sourced.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.