Pull to refresh

Как запустили неподписанный код на Xbox 360

Reading time5 min
Views14K
Каждую игровую консоль стараются поломать. Стараются поломать энтузиасты, которые хотят запустить на ней собственноручно написанный код во всех самых защищенных режимах. Стараются поломать энтузиасты, которые хотят «запускать на ней бэкапы игр» (или если по-русски — заниматься пиратством). Стараются поломать энтузиасты, которые хотят поставить Линукс и, кроме самоцели, использовать более широко, чем хотел бы этого производитель консоли (так как деньги зарабатываются прежде всего на играх, сама консоль продается с минимальной наценкой, а то и в минус производителю).
В подавляющем большинстве случаев энтузиастам это удается.

Вот как была сделана самая интересная часть взлома Xbox 360 — запуск кода, не подписанного MS.


Взлом для пиратства


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

С тех пор изменилось одновременно многое и немногое — было отличное инженерное решение MS заливать микросхему с прошивкой черной эпоксидкой (надо таки узнать, чье было решение, уж очень по-русски), но оказалось, что можно перешивать прошивку, подцепляя DVD-ROM из xbox к PC. В каждом обновлении прошивка переписывалась, но достаточно было перезалить заново. И оно продолжает работать с Live.

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

Тем не менее, уязвимость очень серьезная, как такую могли оставить — я не понимаю. Моя единственная версия — очень торопились вывести консоль на рынок.
Тем не менее, от релиза до запуска пиратской игры — 4 месяца.

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

Давайте вкратце посмотрим, как на xbox360 устроена security-модель, чтобы примерно описать, почему это сложно.


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

Код, который расшифровывает и проверяет бинарник, сидит глубоко в ROM консоли и шифруется/проверяется и перепроверяется железом. Каждое обновление умеет туда прописывать новый код, потому что изначально приготовлено в той же суперсекретной лаборатории. Подменить этот код — нереально.

Сама игра всегда запускается в unprivileged mode, с read-only access на страницах памяти с кодом и отсутствием execute-flag на data и stack, то есть невозможно ни записать код в данных и передать туда управление (классический случай buffer overflow), ни подменить уже загруженный код своим (потому что read-only). Более того, весь executable код еще и постоянно висит в памяти зашифрованный ключем, который случайно генерится каждый запуск (хардверная фича процессора), чтобы защититься от расковыривания памяти физическими методами (грубо говоря — паяльником).

Все, связанное с encryption и decryption выполняется в hypervisor mode, в котором никогда нет кода игры, а только код прошивки. Как я понимаю, он как раз занимается расшифровкой бинарника и прочим секьюрити стаффом. У него нет таких ограничений, но разумеется коду игры в этот режим никогда не прорваться и ничего там не записать.

Казалось бы, все подперли. Код игры не подделать, даже если что-то круто закорраптить в данных, не поможет ни buffer overrun, ни модифицирование кода. Даже от физической атаки — и той убереглись.

Как же в этой ситуации можно было все профакапить?


Основной документ, описывающий уязвимость — здесь.
Вкратце, в одной из версий прошивок была некорректная проверка в самой главной команде syscall — вызове системной функции из игрового кода. Этой команде дается номер функции и ее аргументы, и она достает ее адрес из защищенной таблички, и передает ей управление во всех полномочиях. Проблема была в том, что при проверке номера функции на валидность использовалась 32-битная команда, а в вычислении оффсета — 64-битная. И тогда можно передать номер функции, который имеет какие-то ненулевые верхние биты, номер пройдет в вычисление оффсета, и таким образом будет указывать на память, которая трактуется как данные и не шифруется хардверной защитой. Из этой памяти возьмется адрес функции, и позовется в hypervisor mode, даже если этот адрес в данных. Если в нужном месте памяти будет указатель на твой собственный код — вуаля.

Это еще не уязвимость, надо разобраться как туда эти данные положить. Это не так тривиально — код модифицировать нельзя, а изменить данные игры на диске так, чтобы она своим кодом записала по нужным адресам нужные байты и позвала syscall — очень долгий и сложный анализ наудачу.

Знаете как сделали? Меня это больше всего восхищает в этой всей истории.
Сделали шейдерами.

Все шейдеры — разумеется ресурсы на диске и, как и все ресурсы, не зашифрованы, но при этом остаются шейдерами, то есть микрокодом видеокарты. А на xbox360 же умный GPU, он умеет и читать, и писать в память из шейдера. Больше того, и память-то у CPU и GPU общая, значит из шейдера можно и CPU-память прописать по нужному адресу. Зная, где часто бывает код — можно и покорраптить стек так, чтобы он ret сделал уже на syscall с правильными аргументами, взятыми с того же стека.
Такое получилось сделать на практике с King Kong Demo (http://www.xbox-scene.com/xbox1data/sep/EEZklEuAkAzUotmeVt.php)
Отмечу, что для этого требуется знать очень глубокие детали о коде игры, т.е. знать какое место стека покорраптить — это вряд ли возможно без доступа к коду игры и девкиту.

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

В результате, эксплойт работает подменой шейдера в King Kong, который пишет в память исполняемый код, и корраптит стек в строго определенном месте, чтобы выполнить вызов системной функции, которая из-за бага в прошивке передаст управление в тот самый код с полномочиями системы. Охренеть. Дожили, хак из шейдера. Довоевались за GPU.

Итого


Так и получилось сделать первый hello world своим кодом, а после этого уже и до работающего Убунту было недалеко, и собрать коммьюнити дело техники (http://www.free60.org).

Собственно, все. Для ровного счета — пусть продержался полтора года до запуска стороннего кода. И ведь, блин, все правильно и вменяемо задизайнили, и везде подперлись. Одна самая важная команда на всю систему — и в ней критический баг.
Вот что за херня, а?..
Tags:
Hubs:
Total votes 136: ↑135 and ↓1+134
Comments77

Articles