Pull to refresh

Расшифровывая Siri

Reading time5 min
Views9K
Ребята из французской компании Applidium ровно через месяц после релиза iPhone 4S отреверсили протокол персонального помощника Siri. Ниже перевод статьи, в которой описан сам процесс реверс-инжинеринга и те интересные факты, которые открылись исследователям.

14 октября 2011 Apple представила новый iPhone 4S. Одной из новых возможностей была система Siri – персональный помощник. Siri обрабатывает запросы на естественном языке для взаимодействия с пользователем.

Apple повествовала о том, что Siri отправляет данные на удаленный сервер (вероятно, поэтому Siri только работает поверх 3G или WiFi). Как только наши руки получили новенький iPhone 4S, мы решили узнать, как эта штука работает.

Сегодня нам таки удалось сломать и открыть протокол Siri. Как результат, теперь мы можем использовать движок распознавания Siri на любом девайсе. Да, это значит, что теперь любой сможет написать приложение для Android, которое будет использовать тот самый Siri! Или использовать Siri на iPad. И мы хотим поделиться своими знаниями с вами.

Демонстрация


Наверное, это наиболее удачное демо функции преобразования речи в текст через Siri. Мы создали простую звукозапись, на которой произносится фраза “autonomous demo of Siri” (автономное демо Siri), и получили замечательный результат!

Sample_Siri_speech_to_text.zip (70.78K)

Этот сэмпл никогда не проходил через какой-либо iPhone, но, несмотря на это, у нас получилось заставить Siri проанализировать его для нас.

Копаемся в протоколе – краткое техническое введение


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

Самый простой способ перехвата HTTP-трафика – создать подконтрольный тебе прокси-сервер, настроить iPhone на его использование, и смотреть на то, что проходит через наш прокси. Таким образом, мы нацепили tcpdump на сетевой шлюз, и поняли, что трафик Siri отправлялся по TCP на порт 443, на сервере 17.174.4.4.

Перейдя по 17.174.4.4 на десктопе мы заметили, что этот сервер предоставляет сертификат guzzoni.apple.com. Так оказалось, что Siri обращался к серверу guzzoni.apple.com по протоколу HTTPS.

Как вы знаете, «S» в HTTPS означает «безопасный»: весь трафик между клиентом и сервером зашифрован HTTPS. Поэтому мы не могли просто так читать его с помощью сниффера. В таком случае, самое простое решение – подделать HTTPS, используя поддельный сервер DNS, и посмотреть на то, что приходит на наш сервер. Ребята, которые стоят за Siri, сделали все правильно: они проверяют, что сертификат guzzoni является действительным, так что можно и не притворяться. Ну… они сделали проверку на то, что он в силе, но вы же можете добавить и свой собственный «корневой сертификат», который позволит пометить любой сертификат, и сделать его валидным.

Поэтому все, что нам было нужно, так это установить пользовательский SSL центр сертификации, добавить его в наш iPhone 4S, и подписать с его помощью сугубо наш поддельный сертификат, как «guzzoni.apple.com». И это сработало: Siri оправлял команды на наш собственный HTTPS сервер! Похоже, кто-то в Apple все-же упустил эту деталь.

Именно тогда мы поняли, что протокол Siri является непрозрачным. Давайте посмотрим на Siri HTTP запрос. Тело запроса является двоичным (мы поговорим об этом позже), и вот заголовки:

ACE /ace HTTP/1.0
Host: guzzoni.apple.com
User-Agent: Assistant(iPhone/iPhone4,1; iPhone OS/5.0/9A334) Ace/1.0
Content-Length: 2000000000
X-Ace-Host: 4620a9aa-88f4-4ac1-a49d-e2012910921


Несколько интересных вещей, которые можно из этого извлечь:

  • Запрос использует пользовательский метод “ACE”, а не более привычный GET.
  • URL тоже запрашивается как “/ace”.
  • Content-Length почти 2 Гб. Что, очевидно, не соответствует стандарту HTTP.
  • X-Ace-host это что-то напоминающее GUID. После экспериментов с несколькими iPhone 4S, мы поняли, что это значение, скорее всего, связано с реальным устройством (очень похоже на UDID).


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

Вот тогда мы взяли некоторое время, чтобы подумать. Как люди, которые занимаются разработкой мобильных приложений, мы знаем; есть одна вещь, которая очень важна, когда речь идет о работе с сетью – это сжатие. Пропускная способность часто ограничена, поэтому, как правило, очень хорошая идея – сжимать все, что мы передаем. А какая самая распространенная библиотека для сжатия данных? zlib: «zlib.net». Эта библиотека действительно эффективная и мощная (и конечно, она наполовину француженка!). Поэтому мы попытались прокачать наши бинарные данные через zlib. Но ничего не вышло, нам не хватало zlib-заголовка. Вот тогда мы думали: «хммм, мы уже имеем этот AACCEE-заголовок в теле запроса. Может быть, есть что-то еще? ». Нам, разработчикам, нравится держать данные упакованными. Три байта это не очень хорошая длина для заголовка. Пусть будет четыре. Таким образом, мы попробовали распаковать данные после четвертого байта. И это сработало!

Теперь, когда мы распаковали данные, мы получили какие-то новые двоичные данные. Не очень понятно как, но некоторые части этих данных были текстом. Среди них наше внимание привлек bplist00. Ура! Это, наверное, какие-нибудь бинарные данные plist. После того, как мы наигрались с этим двоичным потоком, мы поняли, что он состоял из следующих частей:

  • Части, начинающиеся с 0x020000xxxx являются “plist”-пакетами, хххх – это размер двоичных данных plist, за которыми следует заголовок.
  • Части, начинающиеся с 0x030000xxxx это “ping”-пакеты, отсылаемые iPhone’ом на сервера Siri, чтобы поддерживать соединение. Здесь хх это номер ping-последовательности.
  • Части, начинающиеся с 0x040000xxxx являются “pong”-пакетами, отсылаемые сервером Siri в качестве ответов на ping-пакеты. Аналогично, хх это количество номер pong-последовательности.


Расшифровка содержания бинарных plist очень проста, вы можете сделать это на Mac OS X с помощью команды “plutil” (через командную строку). Или в Ruby с помощью gem’а CFPropertyList на любой другой платформе.

То, что мы узнали


Мы действительно узнали несколько интересных вещей о том, как iPhone 4S общается с серверами Apple:

Аудио данные

iPhone 4S действительно отсылает необработанное аудио на сервер. Оно сжато с помощью аудиокодека Speex, который имеет смысл, поскольку этот кодек специально предназначенный для VoIP.

Идентификация

IPhone 4S рассылает идентификаторы повсюду. Так что если вы хотите использовать Siri на другом устройстве, вам все равно придется иметь идентификатор, по крайней мере, одного iPhone 4S. Конечно, мы не будем публиковать наши, но его очень легко получить, используя инструменты, о которых мы уже писали. Конечно, Apple в теории может внести в черный список идентификатор, но пока вы используете его в личных целях, все должно быть в порядке.

Фактическое содержание

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

Что дальше?


Вот коллекция инструментов, которую мы написали, чтобы помочь нам понять протокол. Они написаны, в основном, на Ruby (потому что это удивительно простой язык), некоторые части – на C, а некоторые – на Objective-C. Их разработка на самом деле не закончена, но и этого должно быть достаточного для тех, кто технически может написать Siri-приложение.

Давайте посмотрим, какие забавные вещи вы сделаете с помощью Siri! И давайте понаблюдаем, сколько времени понадобится Apple, чтобы поменять их политику безопасности.
Tags:
Hubs:
+102
Comments34

Articles

Change theme settings