Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Обучение от Mail.Ru Group.
Онлайн-университет
для программистов с
гарантией трудоустройства.
Набор открыт!
2003 г

Лазерный диск с нулевым треком как средство защиты от копирования

Крис Касперски, журнал CODE

Задумывались ли вы, почему нумерация треков лазерных дисков начинается с единицы, а не с нуля? Ведь говорят, чтобы отличить программиста от простого смертного достаточно дать ему команду "рассчитайсь!". Нормальный человек скажет "первый" (если он действительно первый) и будет по-своему прав. Программист же сначала уточнит в какой системе исчисления вести расчет (в двоичной, восьмеричной, шестнадцатеричной…) и затем, сделав шаг вперед, гордо скажет "нулевой". "Так ведь лазерные диски изначально разрабатывались для пользователей! – ответите вы. – А пользователи более привычны к натуральной, а не позиционной системе исчисления и потому первый трек должен быть именно первым, но никак не нулевым".

И все же, несмотря на всю убедительность своих доводов, вы будете не правы. Отсчет треков всякого диска начинается не с единицы, но с нуля. Да, нулевой номер зарезервирован за служебным треком (вводной областью диска) и его содержимое недоступно на интерфейсном уровне, но это ничего не меняет! Поле TNO (Track Number) Q-подканала Lead-In области диска равно нулю, следовательно, с точки зрения привода всякий диск начинается с трека номер ноль. Электронная начинка привода читает и адресует нулевой трек точно так же, как и любой другой трек диска, сохраняя тем самым прозрачность и упорядоченность принятой системы нумерации. С точки зрения системных программистов, разрабатывающих микропрограммные прошивки, отсчет треков всегда начинается с нуля. С точки же зрения пользователей привода – с единицы. Одним словом, и волки сыты и овцы целы!

Атрибуты нулевого трека отсутствуют в TOC, поскольку этот трек как раз и служит для хранения TOC. Давайте задумаемся, что произойдет, если одному из point'ов подлинного или фиктивного трека мы присвоим значение ноль, то есть, попросту говоря, создадим еще один нулевой трек в пользовательской области диска?

Если помимо внесения подложных данных в TOC мы еще и скорректируем содержимое Q-канала подкода, забив поле TNO нулями, то с точки зрения привода такой трек будет неотличим от вводной области диска и попытка его посекторного чтения будет обречена на провал (хотя некоторые приводы и не такое читают). Субканальные данные нулевого трека теоретически должны быть доступны для чтения командами SEEK/READ SUBCHANNELL, но никаких гарантий на счет этого у нас нет, поскольку наличие двух подряд идущих Lead-In областей сильно нервирует привод, и его реакция становится совершенно непредсказуемой. Отказ от восстановления субканальных данных мало что меняет. Одно лишь наличие нулевого point'a в TOC'е – событие вполне неординарное и взаимно противоречивое.

Большинство приводов просто свихнутся и откажутся обрабатывать такой диск, совершенно непредсказуемым образом осуществляя чтение его оглавления. В частности, NEC при выполнении команды READ TOC возвращает ошибку, ASUS воспринимает нулевой трек как индикатор завершения TOC'а, а TEAC, столкнувшись с нулевым треком, начинает очень сильно нервничать и вместо атрибутов всех последующих треков выплевывает содержимое своих внутренних буферов вместе с мусором, оставшимся от TOC'а предыдущего диска. Короче говоря, нулевой трек делает лазерный диск практически полностью нечитабельным.

На этом, собственно, можно было бы и остановиться (кому нужна жутко конфликтная защита, работающая исключительно в лабораторных условиях и крайне нежизнеспособная на практике?!) если бы не одно "НО". Стремительное падение цены на оптические носители позволяет использовать лазерный диск не только для хранения полезной информации, но и в качестве своеобразного ключа.

Весь фокус в том, что наличие нулевого трека на диске никак не препятствует чтению субканальных данных спиральной дорожки, но подавляющее большинство копировщиков (включая Алкоголь и Clone CD) скорее зависнут, чем скопируют такой диск! Таким образом, алгоритм работы защитного механизма сводится к "ручному" чтению TOC'а командами SEEK/READ SUBCHANNEL с последующей проверкой его содержимого на предмет наличия нулевого трека.

И хотя ключевой диск не может содержать никаких других данных, кроме собственно самого проверяемого TOC'а, – это ли беда? В каком-то смысле это даже достоинство. Пусть на одном лазерном диске, никак не защищенном от копирования, содержится демонстрационная версия программы, свободно доступная и для скачивания через Интернет. Чтобы она превратилась в полноценную полнофункциональную версию, пользователь должен вставить в привод ключевой диск, полученный от регионального дилера или переданный непосредственно самим разработчиком по почте (собственно, не обязательно постоянно держать ключевой диск в приводе, защита может запомнить флаг регистрации и в реестре, запрашивая ключевой диск лишь изредка – на тот случай если пользователь захочет одолжить его кому-нибудь). Согласитесь, это гораздо надежнее ключевого файла или регистрационного номера, которым ничего не стоит поделиться с другом или выложить в Интернет, а учитывая что cубканальные данные диска могут хранить не только ключ, но и исполняемый (интерпретируемый) код, обеспечивающий полнофункциональность зарегистрированной программы, становится ясно, что, если у хакера нет ни одной полностью работоспособной копии защищенного приложения, взломать его за разумное время будет просто нереально. Но довольно слов, перейдем к делу, попытавшись перво-наперво создать образ защищенного диска с нулевым треком внутри. Как мы сейчас и увидим, это оказывается не так-то просто сделать!

Если просто обнулить point первого трека, то Clone CD наотрез откажется открывать такой образ, ссылаясь на ошибку анализа. На самом деле этих ошибок по меньшей мере две. Первая – полная неосведомленность Clone CD о потенциальной возможности существования нулевых треков, коих он в упор не видит. Вторая – непростительный оптимизм, закладывающийся на тот факт, что каждая сессия должна содержать в себе по меньшей мере один трек (что в действительности вовсе не факт, а лишь допущение).

Алкоголик воспринимает сессию с единственным нулевым треком внутри более благодушно, корректно отображая его номер (см. листинг ниже), однако при попытке записи такого образа на диск, выпрыгивает "accessviolation" и копировщик наглухо повисает, даже не удосужившись аварийно завершить свою работу (см. рис. 1). Вызов "Диспетчера программ" с последующим умерщвлением разбушевавшегося процесса не решает проблемы, т.к. лоток диска остается заблокированным и приходится прибегать к помощи утилиты CD.lock.exe для уменьшения счетчика блокировок на единицу.


Тип: Файл-образ CloneCD
Путь: L:\CD-hack\
Имя: IMAGE.CCD
IMAGE.img
IMAGE.sub
Размер: 8.81 MB
Сессий: 2
Треков: 2


Сессия 01:
Трек 00: Mode 1, Длина: 000000(0 Byte), Адрес: 000000
Сессия 02:
Трек 01: Mode 1, Длина: 000000(0 Byte), Адрес: 013458

Листинг 1 Алкоголик открывает образ защищенного диска вполне успешно, честно отображая нулевой номер первого трека, правда некорректно определяет его длину.


Рисунок 1 реакция Алкоголика на попытку записи образа диска с единственным нулевым треком внутри первой сессии

Постойте, но ведь это же… Это же настоящая золотая жила! Диск с единственным нулевым треком внутри первой сессии не то, что не копируется, он даже и не прожигается! Даже если хакер каким-то неизвестным науке способом снимет с защищенного диска правильный дамп, ему будет нечем этот дамп записать!!! Правда и разработчику защищаемого приложения ключевой диск нечем записать тоже… ну, разве что он отважится на разработку собственной программы "прожига". Естественно, изготовить штампованные CD с нулевым треков вообще не проблема, но этот путь доступен далеко не всем (индивидуальным программистам он недоступен точно).

Компромиссным вариантов защиты становится добавление в искажаемую сессию хотя бы единственного ненулевого трека. Такой диск может быть изготовлен с помощью того же Clone CD и корпеть над написанием собственной "прожигалки" в этом случае не надо, что есть плюс. Однако коль скоро для создания оригинального диска используется утилита массового распространения, процесс создания несанкционированных дубликатов значительно упрощается. Хакеру достаточно снять с диска корректный дамп, а все остальное – это забота Clone CD. Необходимость разрабатывать специализированный софт для взлома при этом отпадает. Один словом: все, что легко защищается, легко и ломается. Впрочем, квалифицированных хакеров не так уж и много, и для предотвращения "утекания" своей продукции для нас с вами достаточно добиться некопируемости ключевого диска распространенными копировщиками в автоматическом режиме. И, как мы увидим в дальнейшем, защита данного типа полностью удовлетворяет этому требованию.

Процесс подготовки защищенного диска не лишен определенных тонкостей. Создание фиктивного трека с нулевым номером не вызывает особых трудностей, но вот вопрос: где его разместить? В первой, а, может быть, лучше во второй сессии? До подлинного трека или после? Поскольку вводная область первой сессии недоступна для чтения на субканальном уровне, то прочитать TOC первой сессии вручную нельзя. Нельзя и закладываться на команду READ TOC, поскольку, как уже было сказано выше, ее корректное выполнение не гарантируется. Вводные области второй и всех последующих сессий свободно доступны на субканальном уровне и ручное чтение хранимого ими TOC'а все-таки возможно. Конкретная позиция нулевого трека внутри сессии особой роли не играет, и нулевой трек может быть с одинаковым успехом размещен как до ненулевого трека, так и после него.

Только, пожалуйста, не забывайте о необходимости коррекции point'а A0h, хранящего номер "первого" трека всякой сессии. Если его значение оставить без изменений, то образ диска запишется без каких-либо препирательств со стороны Clone CD, но никаких упоминаний о нулевом треке в TOC'е прожженного диска не окажется! Точно так же ведет себя и Алкоголь. Чтобы этого избежать, значение point'а A0h той сессии, к которой вы добавляете нулевой трек, должно быть сброшено в Zero.

Фрагмент отредактированного CCD-файла приведен ниже:


TocEntries=13TocEntries=14;корректируем количество входов в TOC
[Entry 8][Entry 8]; это вход не обязательно должен быть восьмым…
Session=2Session=2; …главное, чтобы Session == 2, а Point == A0h
Point=0xa0Point=0xa0; этот Point отвечает на номер первого трека
ADR=0x01ADR=0x01; это служебные поля ADR/Control, описывающие
Control=0x04Control=0x04; режим обработки трека (это трек с данными)
TrackNo=0TrackNo=0; TNO = 0 – это Lead-In область
AMin=0AMin=0; \
ASec=0ASec=0; +- условный текущий абсолютный адрес
AFrame=0AFrame=0; /
ALBA=-150ALBA=-150; условный текущий LBA-адрес
Zero=0Zero=0; это поле всегда равно нулю
PMin=2àPMin=0;корректируем номер "первого" трека
PSec=0PSec=0; эти поля не имеют никакого смысла и должны
PFrame=0PFrame=0; быть равны нулю
PLBA=8850PLBA=8850; LBA-"адрес" номера "первого" трека
[Entry 11];добавляем еще одно Entry, описывающее нулевой трек
Session=2; нулевой трек должен быть не в первой сессии
Point=0x00; номер трека - ноль
ADR=0x01; Sub-channel Q encodes current position data
Control=0x04; трек с данными
TrackNo=0; это Lead-In
AMin=0;\
ASec=0;  + - условный абсолютный адрес Lead-In
AFrame=0;/
ALBA=-150; условный LBA-адрес Lead-In
Zero=0; это поле должно быть равно нулю
PMin=3; \
PSec=1;  + - абсолютный стартовый адрес нулевого трека
PFrame=66; /
PLBA=13458; LBA-адрес нулевого трека

Листинг 2 фрагмент CCD-файла с добавленным нулевым треком

При просмотре геометрии защищенного таким образом диска Ahead Nero выдает приблизительно следующую информацию (см. рис. 2)[1]. То, что он посчитал вторую сессию открытой ("Session is open") вполне объяснимо, так как созданный нами нулевой трек был ошибочно принят Нероном за вводную область, в результате чего шаткое равновесие между вводными и выводными областями оказалось нарушенным. Между тем, вторая сессия диска все-таки закрыта, и анализ TOC подтверждает это. А не знать, что упоминание о вводных областях никогда в явном виде не присутствует в TOC'е – глупо. Разобраться, почему нулевой трек оказался приобщен Нероном к первой сессии, несколько сложнее. По видимому, это грубая алгоритмическая ошибка, которая не делает чести ни самому Нерону, ни его разработчикам.


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

Clone CD ведет себя аналогичным образом и при попытке копирования защищенного диска на приводах ASUS и TEAC со всего маху врезается в выводную область первой сессии диска. Вторая сессия (с нулевым треком) по причине грубых алгоритмических ошибок полностью выпадает из его поля зрения и в TOC'е скопированного диска о ней даже и не упоминается. Стартовый адрес выводной области первой сессии так же определяется неправильно (Clone CD устанавливает его на стартовый адрес нулевого трека второй сессии). Point'ы B0h (стартовый адрес следующей позиции для дозаписи) и C0h (стартовый адрес первой вводной области диска) тоже оказываются потерянными. Короче говоря, TOC скопированного диска более чем существенно отличается от TOC'а оригинального, и обнаружить факт несанкционированного копирования не составит никакого труда,. Д вы их сами сравните:


01 14 00 A0 00 00 00 00 01 00 00    01 14 00 A0 00 00 00 00 01 00 00
01 14 00 A1 00 00 00 00 01 00 00    01 14 00 A1 00 00 00 00 01 00 00
01 14 00 A2 00 00 00 00 00 1D 21    01 14 00 A2 00 00 00 00 03 01 42
01 14 00 01 00 00 00 00 00 02 00    01 14 00 01 00 00 00 00 00 02 00
01 54 00 B0 02 3B 21 03 16 0E 22
01 54 00 C0 A2 C8 E0 00 61 1B 15
02 14 00 A0 00 00 00 00 02 00 00
02 14 00 A1 00 00 00 00 00 00 00
02 14 00 A2 00 00 00 00 03 18 17
02 14 00 00 00 00 00 00 03 01 42

Листинг 3 TOC оригинального ключевого диска с нулевым треком внутри второй сессии (слева; атрибуты нулевого трека выделены серой заливкой) и TOC его копии, полученной с помощью Clone CD (справа). Все несовпадения выделены жирным шрифтом.

При попытке копирования защищенного диска на приводе NEC (который, как уже отмечалось, отказывается читать TOC с нулевым треком), Clone CD удивленно спрашивает "диск пуст?" и вне зависимости от нашего ответа даже не пытается приступить к его копированию, вызывая страшный хакерский гнев и раздражение.

Алкоголь при попытке копирования защищенного диска просто виснет, едва лишь успев перед смертью выбросить исключение "accessviolation", но зато заблокировав лоток привода так, что без уменьшения счетчика блокировок извлечь диск помогает разве что тотальная перезагрузка системы.

В общем, дело – мрак! (С точки зрения "пиратов", конечно). И мы по праву можем считать, что процедура создания некопируемого ключевого диска завершилась успешно. Теперь недурно бы разобраться: как с полученным диском вообще работать и каким именно образом защитный механизм сможет отличить копию от оригинала.

Первое, что приходит нам в голову – прочитать "сырой" TOC командой READ TOC и проверить наличие трека номер ноль, а для пущей надежности – и его атрибуты. Если нулевой трек действительно присутствует в TOC'е и его атрибуты (т. е. поля Session, ADR, Control, PMin:PSec:PFarme) полностью соответствуют эталону – это оригинальный диск и, соответственно, наоборот. Достоинство такого алгоритма в том, что он очень просто реализуется, укладываясь буквально в десяток строк кода, а недостаток – в нестабильности опознавания ключевого диска на определенных моделях приводов. Привод может отказаться читать TOC ‑ к такому повороту событий защита должна быть заранее готова. Давайте сделаем так: если команда READ TOC возвращает ошибку, но диск присутствует в приводе и не препятствует выполнению SEEK – это оригинальный диск. Конечно, подобное эвристическое допущение значительно ослабляет защиту, однако для большинства применений ее стойкости будет вполне достаточно.

Однако безошибочное выполнение команды READ CD еще не является свидетельством того, что она выполнена успешно. Ни один известный мне привод, способный читать TOC с нулевым треком, не читает его правильно, а потому защита должна заранее учитывать характер возможных искажений TOC'а и адекватно ему противостоять.

Рассмотрим, например, какой результат возвращает привод TEAC:


Номер сессии
  |      ADR/Control
  |   |      TNO
  |   |   |      Point
  |   |   |   |   |      AM:AS:AF  PM:PS:PF
  |   |   |   |   |   |   |   |   |   |   |
01 14 00 A0 00 00 00 00 01 00 00 ; point A0 - номер первого трека сессии 1 в PM
01 14 00 A1 00 00 00 00 01 00 00 ; point A1 - номер последнего трека сессии 1 в PM
01 14 00 A2 00 00 00 00 00 1D 21 ; point A2 - адрес Lead-out сессии 1 в PM:PS:PF
01 14 00 01 00 00 00 00 00 02 00 ; point 01 - стартовый адрес трека 1 в PM:PS:PF
01 54 00 B0 02 3B 21 03 16 0E 22 ; point B0 - позиция дозаписи в AM:AS:AF
01 54 00 C0 A2 C8 E0 00 61 1B 15 ; point C0 - стартовый адрес Lead-In в PM:PS:PF /искж
02 14 00 A0 00 00 00 00 02 00 00 ; point A0 - номер первого трека сессии 1 в PM
02 14 00 A1 00 00 00 00 00 00 00 ; point A1 - номер последнего трека сессии 2 в PM
02 14 00 A2 00 00 00 00 03 18 17 ; point A2 - адрес Lead-out сессии 2 в PM:PS:PF
02 14 00 00 00 00 00 00 03 01 42 ; point 00 - стартовый адрес трека 0 в PM:PS:PF
FB FD 00 FB F4 FB 7A FF FD FD FF ; \ | как видно, встретив нулевой трек, TEAC
FB DF 00 FA FD F5 FF BF FB FE FF ; + - мусор | вместо осмысленных данных начал изры-
FE F7 00 FB FF FD FB FF FF F7 FF ; / | гать мусор

Листинг 4 содержимое TOC'а ключевого диска, возращенное приводом TEAC, нулевой трек выделен серой заливкой, а мусор, следующий за ним – жирным шрифтом

Что это за подозрительный мусор, расположенный вслед за нулевым треком? Это – содержимое внутренних буферов привода, попавшее сюда в результате грубой программистской ошибке в микропрограмме привода (между прочим, тестировалась самая свежая на момент написания этих строк прошивка – 1.09). Небольшое расследование убедительно доказывает, что мусор носит не случайный характер и представляет собой "хвост" TOC'а предыдущего диска.

Давайте, вставив в привод какой-нибудь диск (например, "Soul Ballet Hit Collection"), сменим его на ключевой и посмотрим что у нас из этого получится:


01 10 00 A0 00 00 00 00 01 00 00     01 14 00 A0 00 00 00 00 01 00 00
01 10 00 A1 00 00 00 00 10 00 00     01 14 00 A1 00 00 00 00 01 00 00
01 10 00 A2 00 00 00 00 48 1C 05     01 14 00 A2 00 00 00 00 00 1D 21
01 10 00 01 00 00 00 00 00 02 00     01 14 00 01 00 00 00 00 00 03 00
01 10 00 02 00 00 00 00 03 35 40     01 54 00 B0 02 3B 21 03 16 0E 22
01 10 00 03 00 00 00 00 08 14 33     01 54 00 C0 A2 C8 E0 00 61 1B 15
01 10 00 04 00 00 00 00 0C 21 0D     02 14 00 A0 00 00 00 00 02 00 00
01 10 00 05 00 00 00 00 10 3A 2D     02 14 00 A1 00 00 00 00 00 00 00
01 10 00 06 00 00 00 00 16 23 19     02 14 00 A2 00 00 00 00 03 18 17
01 10 00 07 00 00 00 00 1C 1B 0C     02 14 00 00 00 00 00 00 03 01 42
01 10 00 08 00 00 00 00 21 07 49     09 25 00 1F 00 00 00 00 19 01 10
01 10 00 09 00 00 00 00 25 1F 19     0A 2A 00 01 00 00 00 00 06 01 10
01 10 00 0A 00 00 00 00 2A 01 06     0B 2D 00 2D 00 00 00 00 00 01 10
01 10 00 0B 00 00 00 00 2D 2D 00     0C 33 00 29 00 00 00 00 02 01 10
01 10 00 0C 00 00 00 00 33 29 02     0D 39 00 08 00 00 00 00 45 01 10
01 10 00 0D 00 00 00 00 39 08 45     0E 3F 00 1E 00 00 00 00 27 01 10
01 10 00 0E 00 00 00 00 3F 1E 27     0F 43 00 1E 00 00 00 00 29 01 10
01 10 00 0F 00 00 00 00 43 1E 29     10 44 00 03 00 00 00 00 15 FF FF
01 10 00 10 00 00 00 00 44 03 15

Листинг 5 TOC диска SoulBallet (слева) и TOC ключевого диска (справа), возвращенные приводом TEAC

Смотрите! Сейчас содержимое TOC'а ключевого диска существенно изменилось. Пускай не все содержимое, но вот хвост изменился точно. Причем последовательность байт "хвоста" ключевого диска соответствует последовательности байт диска "Soul Ballet". Пускай "…09 00 00 00 00 25 1F 19…" и "…09 25 00 1F 00 00 19…" и не совсем тождественные последовательности, но, если убрать паразитные нули, мы получим: "…09 25 1F 19…" и "…09 25 1F 19…", которые побайтно равны друг другу. Так что мы действительно имеем дело с ошибкой в прошивке, что не делает чести ни самому приводу, ни его разработчикам.

ASUS ведет себя более корректно, просто "обрубая" TOCпо нулевому треку, даже в том случае когда нулевой трек – не последний трек диска, что тоже расценивается как микропрограммная ошибка, пускай и не такая грубая.


01 14 00 A0 00 00 00 00 01 00 00
01 14 00 A1 00 00 00 00 01 00 00
01 14 00 A2 00 00 00 00 00 1D 21
01 14 00 01 00 00 00 00 00 03 00
01 54 00 B0 02 3B 21 03 16 0E 22
01 54 00 C0 A2 C8 E0 00 61 1B 15
02 14 00 A0 00 00 00 00 02 00 00
02 14 00 A1 00 00 00 00 00 00 00
02 14 00 A2 00 00 00 00 03 18 17
02 14 00 00 00 00 00 00 03 01 42

Листинг 6 TOC ключевого диска, возращенный приводом ASUS

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

Тем не менее, преднамеренное ослабление стойкости защиты – не выход. Уж лучше попробовать прочитать TOC вручную. Это достаточно трудно реализуется на программном уровне, но еще труднее ломается! Если команду READ TOC легко и проэмулировать, то воссоздать особенности обработки субканальных данных практически нереально, благодаря чему усиленный вариант защиты с легкостью обойдет все копировщики, эмулирующие виртуальные диски.

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

Первое и главное: абсолютные адреса секторов ни коим образом не связаны с "соответствующими" им субканальными данными, хотя бы уже потому, что одна секция субканальных данных "размазана" по нескольким секторам, причем в силу определенных конструктивных особенностей обработка субканальных данных и данных основного потока осуществляется раздельно, благодаря чему при позиционировании головки на сектор X с последующим вызовом команды READ SUBCHANNEL мы получим субканальные данные не сектора X, а сектора Y, лежащего "поблизости" от сектора X. Понятие "поблизости" всякий производитель определяет самостоятельно, зачастую уползая не на одну сотню секторов вперед.

Второе: связка команд SEEK/READ SUBCHANNEL неустойчива и обладает хреновой воспроизводимостью результатов. Никто не гарантирует, что позиционирование на сектор X+k приведет к чтению субканальных данных сектора Y+k. Привод может возвратить как данные сектора Y, так и данные сектора Y+i. Также никто не гарантирует, что повторное позиционирование не сектор X приведет к чтению субканальных данных сектора Y. (кстати, не забывайте между двумя соседними вызовами командами SEEK выдерживать паузу хотя бы в 1 сек, иначе головка просто не успеет переместиться на новое место, и привод как ни в чем не бывало возвратит уже скэшированные субканальные данные с места предыдущего позиционирования). Остается опираться лишь на текущие адреса секторов, возвращаемые в самой субканальной информации (поле "Absolute CD Address"). Встретив в этом поле адрес "своего" сектора, мы можеь быть абсолютно уверенными в том, что эта субканальная информация принадлежит именно "нашему" сектору, а не какому-то сектору еще.


Листинг 7 правильная интерпретация субканальной информации

Третье: конкретный формат субканальной информации определяется не Стандартом, а самим приводом и значительно варьируется от одной модели к другой. Наиболее непостоянны в этом смысле вводные и выводные области диска. Стандарт вообще ничего не говорит о возможности их чтения на субканальном уровне, молчаливо полагая, что это никому на хрен не нужно. Вот производители и извращаются в меру своей распущенности и фантазий. Поля абсолютных и относительных адресов могут безо всяких предупреждений меняться местами, а сами адреса могут задаваться как в формате M:S:F, так и в LBA-форме. Значения point'ов A0h, A1h и A2h (номер первого трека, номер последнего трека и адрес Lead-Out области) могут замещаться значениями 64h, 65h и 66h соответственно. Наконец, нестандартные point'ы (в том числе и нулевые point'ы) в субканальных данных зачастую попросту отсутствуют – вместо этого возвращаются данные либо предыдущей, либо последующей секций!

Все это значительно усложняет интерпретацию субканальных данных и поиск в ней нулевых треков, поэтому приходится действовать так: последовательно читая субканальные данные различных секторов диска, дожидаемся того момента, когда номера треков сменяться сначала на AAh, а затем и на 00h, что будет соответствовать переходу головки с Lead-Out области первой сессии на Lead-In область второй сессий. Продолжая читать Lead-In, мы попытаемся определить в какой закономерности изменяются поля абсолютных и относительных адресов и форму их представления (LBA или M:S:F). Собственно, формат представления определить очень легко. Если младший байт адреса принимает значения больше, чем 75 (4Bh), – это, несомненно, LBA и наоборот. Далее – поскольку поля относительных адресов в вводной области диска используются для хранения атрибутов "своего" point'а, то они чрезвычайно сильно отличаются от текущих адресов секторов – тех, на которых и осуществлялось позиционирование. Напротив, поля абсолютных адресов к текущим адресам должны быть достаточно близки.

Остается решить последнюю проблему – что делать, если в субканальных данных Lead-In области нулевого трека попросту не окажется? Не спешите делать вывод о нелицензионности диска – ведь, как уже было сказано выше, некоторые приводы нестандартные point'ы просто не возвращают. При этом абсолютные адреса секторов, хранящих субканальные атрибуты нулевого трека, в считанном TOC'е не будут присутствовать! Копия диска, полученная любым из существующих на данный момент копировщиков, по данным абсолютным адресам будет содержать атрибуты совершенно других треков, которые привод вполне корректно прочитает и возвратит, либо же вовсе откажется позиционировать головку на эту область, выдавая ту или иную ошибку.

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


  +internal+  Format    
    |   | | | | ADR/Control
  |   | | | | | TNO
  |   | | | | | | Point
  |   | | | | | | | +- PLBA -+  +- ALBA -+
  |   | | | | | | | | | | | | | | |    
LBA - 10D4:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6D ; LBA 10D4 а 116D
LBA - 10D5:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6D ; LBA 10D5 а 116D
LBA - 10D6:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6E ; LBA 10D5 а 116E
LBA - 10D7:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6D ; LBA 10D7 а 116D (!)
LBA - 10D8:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6E ; ("биение" головки)
LBA - 10D9:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6E ; LBA 2292 = 02:00:00 M:S:F
LBA - 10DA:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 73 ; LBA FFh - 6Ah = 95h (149)
LBA - 10DB:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 73 ; LBA 149 == MSF 0:0:1
LBA - 10DC:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 74 ; что удивительно, т.к.
LBA - 10DD:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 75 ; последнего трека должен
LBA - 10DE:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 74 ; быть в PM, но не в PF
LBA - 10DF:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 74 ; учитывайте это!
LBA - 10E0:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 79 ; продолжается биение го-
LBA - 10E1:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 79 ; ловки: сектора идут не
LBA - 10E2:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 7B ; упорядочено: 1179, 1179,
LBA - 10E3:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 79 ; 117B, 1179, 117A, 117A и
LBA - 10E4:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 7A ; нету секторов 1176, 1177
LBA - 10E5:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 7A ; и 178
LBA - 10E6:00 15 00 0C 01 14 00 02 00 00 34 92 00 00 11 80 ;  
LBA - 10E7:00 15 00 0C 01 14 00 02 00 00 34 92 00 00 11 80 ;  
LBA - 10E8:00 15 00 0C 01 14 00 02 00 00 34 92 00 00 11 80 ; биение головки
LBA - 10E9:00 15 00 0C 01 14 00 02 00 00 34 92 00 00 11 7F ; продолжается
LBA - 10EA:00 15 00 0C 01 14 00 02 00 00 34 92 00 00 11 80 ;  
LBA - 10EB:00 15 00 0C 01 14 00 02 00 00 34 92 00 00 11 81 ;  
LBA - 10EC:00 15 00 0C 01 14 00 00 00 00 34 B3 00 00 11 85 ; а вот и нулевой трек, он
LBA - 10ED:00 15 00 0C 01 14 00 00 00 00 34 B3 00 00 11 85 ; располагается в секторах
LBA - 10EE:00 15 00 0C 01 14 00 00 00 00 34 B3 00 00 11 86 ; 1185 и 1186 - запомним
LBA - 10EF:00 15 00 0C 01 14 00 00 00 00 34 B3 00 00 11 85 ; это обстоятельство!
LBA - 10F0:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 8C ; point A0 повторяется…
LBA - 10F1:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 8C ; а вместе с ним и все
LBA - 10F2:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 8B ; остальные point'ы. Читая
LBA - 10F3:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 8B ; субканальные данные даль-
LBA - 10F4:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 8C ; ше мы вновь встретим ну-
LBA - 10F5:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 8B ; левой трек, но уже в дру-
LBA - 10F6:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 8B ; гих секторах. Запомним и
LBA - 10F7:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 8B ; из для надежности

Листинг 8 результат чтения субканальной информации из Lead-In на приводе TEAC; отчетливо просматривается нулевой трек

Здесь абсолютные адреса представлены в LBA-форме, причем расхождение между адресом, на который осуществляется позиционирование головки, и адресом, чьи субканальные данные при этом читаются (далее по тексту – дельта) составляет порядка 400 секторов. Правда, равномерность "часового хода" очень хороша, абсолютные идут кучным пучком строго социалистического характера, хотя TEAC все-таки не без греха, и оплошности типа 11:6D, 11:6E, 11:6D, 11:6E случаются сплошь и рядом. Атрибуты нулевого трека присутствуют в явном виде, что не может не радовать.

А вот привод ASUS ведет себя более разболтанно:


  +internal+  Format    
    |   | | | | ADR/Control
  |   | | | | | TNO
  |   | | | | | | Point
  |   | | | | | | | +- PLBA -+  +- ALBA -+
  |   | | | | | | | | | | | | | | |    
LBA - 10D3:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6F ; здесь субканальные данные
LBA - 10D4:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 73 ; возвращаются еще более
LBA - 10D5:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 73 ; беспорядочно, и потому
LBA - 10D6:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 73 ; отделить соседние point'ы
LBA - 10D7:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 73 ; друг от друга уже не
LBA - 10D8:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6F ; удается, между тем они
LBA - 10D9:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6F ; лежат по тем же самым
LBA - 10DA:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6F ; ALBA адресам, что и в
LBA - 10DB:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6F ; предыдущем случае, а
LBA - 10DC:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 73 ; потому, ALBA адреса могут
LBA - 10DD:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 6F ; служить надежной опорой
LBA - 10DE:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 73 ; в идентификации point'ов
LBA - 10DF:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 73 ; не зависящей от настро-
LBA - 10E0:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 79 ; ения, разболтанности
LBA - 10E1:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 79 ; и конструктивных особен-
LBA - 10E2:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 79 ; ностей конкретных моделей
LBA - 10E3:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 75 ; приводов, что значительно
LBA - 10E4:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 7A ; упрощает процедуру про-
LBA - 10E5:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 75 ; верки степени лицензион-
LBA - 10E6:00 15 00 0C 01 14 00 02 00 00 34 92 00 00 11 80 ; ной "чистоты" анализиру-
LBA - 10E7:00 15 00 0C 01 14 00 02 00 00 34 92 00 00 11 81 ; емого диска…
LBA - 10E8:00 15 00 0C 01 14 00 A1 00 FF FF 6A 00 00 11 75    
LBA - 10E9:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 7B    
LBA - 10EA:00 15 00 0C 01 14 00 00 00 00 34 B3 00 00 11 85 ; атрибуты трека 0, обрати-
LBA - 10EB:00 15 00 0C 01 14 00 02 00 00 34 92 00 00 11 81    
LBA - 10EC:00 15 00 0C 01 14 00 A2 00 00 3B 45 00 00 11 7B    
LBA - 10ED:00 15 00 0C 01 14 00 00 00 00 34 B3 00 00 11 85 ; те внимание, что они рас-
LBA - 10EE:00 15 00 0C 01 14 00 02 00 00 34 92 00 00 11 81    
LBA - 10EF:00 15 00 0C 01 14 00 00 00 00 34 B3 00 00 11 86 ; полгаются по тем же LBA
LBA - 10F0:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 8B    
LBA - 10F1:00 15 00 0C 01 14 00 00 00 00 34 B3 00 00 11 85 ; адресам: 1185h и 1186!
LBA - 10F2:00 15 00 0C 01 14 00 A0 00 00 22 92 00 00 11 8B    

Листинг 9 результат чтения субканальной информации из Lead-In на приводе ASUS

Здесь: абсолютные адреса так же представлены в формате LBA и дельта составляет все те же 400 секторов, однако степень неупорядоченности возвращаемой информации значительно выше и номера секторов начинают потихонечку "плясать" (см. поле ALBA).



  +internal+  Format    
    |   | | | | ADR/Control
  |   | | | | | TNO
  |   | | | | | | Point
  |   | | | | | | | +- PLBA -+  +- ALBA -+
  |   | | | | | | | | | | | | | | |    
LBA - 1171:00 15 00 0C 01 14 00 64 00 00 11 6E 00 02 00 00 ; point 64 - это на самом
LBA - 1172:00 15 00 0C 01 14 00 64 00 00 11 6E 00 02 00 00 ; деле point A0 (номер пер-
LBA - 1173:00 15 00 0C 01 14 00 64 00 00 11 6E 00 02 00 00 ; вого трека), просто глу-
LBA - 1174:00 15 00 0C 01 14 00 64 00 00 11 6E 00 02 00 00 ; пый привод так нелепо его
LBA - 1175:00 15 00 0C 01 14 00 64 00 00 11 6E 00 02 00 00 ; исказил, так же обратите
LBA - 1176:00 15 00 0C 01 14 00 64 00 00 11 6E 00 02 00 00 ; внимание, что все адреса
LBA - 1177:00 15 00 0C 01 14 00 64 00 00 11 6E 00 02 00 00 ; идут к сектору 116E!
LBA - 1178:00 15 00 0C 01 14 00 65 00 00 11 74 00 00 00 00 ; резкий переход адресов
LBA - 1179:00 15 00 0C 01 14 00 64 00 00 11 6E 00 02 00 00 ; с 116E на 1174 (+6)
LBA - 117A:00 15 00 0C 01 14 00 65 00 00 11 74 00 00 00 00 ; такова дискретность SEEKа
LBA - 117B:00 15 00 0C 01 14 00 65 00 00 11 74 00 00 00 00 ; привода NEC!
LBA - 117C:00 15 00 0C 01 14 00 65 00 00 11 74 00 00 00 00    
LBA - 117D:00 15 00 0C 01 14 00 65 00 00 11 74 00 00 00 00    
LBA - 117E:00 15 00 0C 01 14 00 65 00 00 11 74 00 00 00 00    
LBA - 117F:00 15 00 0C 01 14 00 65 00 00 11 74 00 00 00 00    
LBA - 1180:00 15 00 0C 01 14 00 65 00 00 11 74 00 00 00 00    
LBA - 1181:00 15 00 0C 01 14 00 66 00 00 11 7A 00 00 3B 45    
LBA - 1182:00 15 00 0C 01 14 00 66 00 00 11 7A 00 00 3B 45    
LBA - 1183:00 15 00 0C 01 14 00 02 00 00 11 7F 00 00 34 92 ; 117F - …
LBA - 1184:00 15 00 0C 01 14 00 66 00 00 11 7A 00 00 3B 45    
LBA - 1185:00 15 00 0C 01 14 00 66 00 00 11 7A 00 00 3B 45    
LBA - 1186:00 15 00 0C 01 14 00 66 00 00 11 7A 00 00 3B 45    
LBA - 1187:00 15 00 0C 01 14 00 02 00 00 11 81 00 00 34 92 ; 117F - 1181 диапазон
LBA - 1188:00 15 00 0C 01 14 00 02 00 00 11 7F 00 00 34 92 ; адресов, занятых субка-
LBA - 1189:00 15 00 0C 01 14 00 02 00 00 11 7F 00 00 34 92 ; нальной информацией
LBA - 118A:00 15 00 0C 01 14 00 02 00 00 11 81 00 00 34 92 ; point'a == 2
LBA - 118B:00 15 00 0C 01 14 00 02 00 00 11 80 00 00 34 92    
LBA - 118C:00 15 00 0C 01 14 00 02 00 00 11 81 00 00 34 92    
LBA - 118D:00 15 00 0C 01 14 00 66 00 00 11 7A 00 00 3B 45    
LBA - 118E:00 15 00 0C 01 14 00 64 00 00 11 8B 00 02 00 00 ; смотрите! резкий переход
LBA - 118F:00 15 00 0C 01 14 00 64 00 00 11 8B 00 02 00 00 ; с адреса 1181 на адрес
LBA - 1190:00 15 00 0C 01 14 00 64 00 00 11 8B 00 02 00 00 ; 118B - 10 секторов пропу-
LBA - 1191:00 15 00 0C 01 14 00 64 00 00 11 8B 00 02 00 00 ; щено, причем это не про-
LBA - 1192:00 15 00 0C 01 14 00 64 00 00 11 8B 00 02 00 00 ; сто биение головки - этих
LBA - 1193:00 15 00 0C 01 14 00 64 00 00 11 8D 00 02 00 00 ; секторов в субканальных
LBA - 1194:00 15 00 0C 01 14 00 64 00 00 11 8D 00 02 00 00 ; данных нет вообще! И как
LBA - 1195:00 15 00 0C 01 14 00 64 00 00 11 8B 00 02 00 00 ; раз в них и содержатся
LBA - 1196:00 15 00 0C 01 14 00 65 00 00 11 92 00 00 00 00 ; атрибуты трека ноль, а
LBA - 1197:00 15 00 0C 01 14 00 65 00 00 11 92 00 00 00 00 ; раз так, то трек ноль все
LBA - 1198:00 15 00 0C 01 14 00 65 00 00 11 92 00 00 00 00 ; таки есть на диске (иначе
LBA - 1199:00 15 00 0C 01 14 00 65 00 00 11 92 00 00 00 00 ; бы эти сектора возращ.)

Листинг 10 результат чтения субканальной информации из Lead-In приводом NEC

Здесь: дельта "уползания" составляет порядка 10 секторов, а зачастую даже менее того, однако сама упорядоченность секторов вообще никакая, а нулевых point'ов вообще нет. Сектора с адресами 1185h и 1186h (в которых, собственно, и хранятся атрибуты нулевых треков) внаглую отсутствуют – вместо этого привод спозиционировал головку на адреса 118Bh и 118Dh, в результате чего количество 64hpoint'ов (в "девичестве" – A0h) до неприличия возросло. Ко всему прочему абсолютные адреса секторов по непонятной причине перекочевали в поле относительных адресов, и если бы мы попытались проанализировать субканальную информацию согласно Стандарту, у нашей защиты точно бы съехала крыша.

Итак, несмотря громоздкость и трудности реализации защитного механизма, он все-таки может быть реализован так, чтобы уверенно отличать ключевой диск на любой из моделей приводов. Но стоит ли овчинка выделки или, говоря другими словами, каким образом защищенный диск можно взломать?

А вот со взломом у нас туго. Да, в принципе, такой диск можно скопировать, но только не Сlone CD или Алкоголем и не на всех моделях приводах. Для взлома пригодны лишь те приводы, что уверенно читают TOC и возвращают атрибуты нестандартных point'ов, поскольку ко всему этому может привязываться защита. "Постойте! – воскликните вы, – но ведь защита не должна закладываться на доступность TOC'а и атрибуты нулевого point'а, иначе программа окажется неработоспособна на некоторых моделях приводов! " Это верно, однако, если привод соглашается читать TOC, – отчего же его не проверить?

Если привод взломщика не позволяет читать содержимое TOC, взломщик не сможет восстановить оригинальный TOC (ну разве что отдизассемблирует весь защитный механизм целиком) и потому скопированный диск будет работать лишь на его приводе!

Правда, при наличии привода, читающего TOC и хорошо смазанных подшипников в котелке копирование защищенного диска осуществляется очень просто. Достаточно лишь, считав TOC (команда READ TOC), считать и само содержимое диска на субканальном уровне (команды SEEK/READ SUBCHANNEL), а также содержимое основного канала (команда READ CD), после чего остается лишь сформировать CCD-, -IMG- и SUB-файлы и с помощью того же Clone CD записать их на диск. Однако такой взлом по зубам далеко не всякому хакеру, а с натиском желторотых пользователей эта защита без труда справится.

Новости мира IT:

Архив новостей

Последние комментарии:

Вышло обновление Firefox 57.0.1 (1)
Среда 06.12, 09:14

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 985 1945361
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2015 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...