Техника защиты компакт-дисков от копирования

Некорректный Run-out как средство защиты или X-?сектор


С хакерской точки зрения программа StompRecord NOW! интереса уже хотя бы тем, что это практически единственная сервисная программа, скрытно записывающая на каждый "прожигаемый" диск специальную метку, —– своеобразный "водяной знак", о существовании которого подавляющее большинство пользователей даже и не догадывается и который со всей очевидностью нарушает их privacy [Y184] [n2k185] (). Но все по порядку.

Поддержка произвольной записи (Randomly Writable) в CD-RW дисках реализована через посредствам механизма блоков вбега/выбега (run-in/run-out block), тесно связанных с режимом пакетной записи. Каждый пакет (packet) начинается с четырех вбегающих блоков (трех —– на носителях DDCD носителях) и завершается двумя блоками выбегам (тремя —– на носителях DDCD носителях) (рис. 6.24). Блоки вбега/выбега представляют собой обыкновенные сектора, но с необычным значением поля MODE в их заголовке (листинг 6.62см. таблицу xxx). В зависимости от режима адресации блокиа вбега/выбега либо адресуются точно так же как и все остальные сектора, либо же исключаются из адресного пространства. Вне режима пакетной записи блоки Run-in/Run-out блоки практически нигде не используются, однако…

Рис. 6.24. унок 19 0x113 Области вбега и выбега

Листинг 6.62. Расширенная интерпретация поля MODE

Bits 7, 6, 5 = 000 - User Data block

= 001 - Fourth Run-in block

= 010 - Third Run-in block

= 011 - Second Run-in block

= 100 - First Run-in block

= 101 - Link block. Physical linking of EFM data

= 110 - Second Run-out block

= 111 - First Run-out block



Bits 4, 3, 2 = 000 - Reserved

Bits 1, 0 = 00 Mode 0 Data

= 01 - Mode 1 Data

= 10 - Mode 2 Data

= 11 -– Reserved

Рисунок 20 Расширенная интерпретация поля MODE

…интересным свойством программы Stomp Record NOW! является ее неявная поддержка блоков Run-out блоков, скрыто внедряемых в конец каждого трека данных, точнее —– в предпоследний сектор его области пост-зазораной области (Post-gap area), заголовок которого подвергается незначительным искажениям.


Поскольку, выбегающий блок всего один (тогда так по " Оранжевой книге" их должно быть как минимум два), да и вбегающих блоков не наблюдается, речь идет именно об искажении. Случайным или непреднамеренном – неизвестно. Возможно, это своеобразный "фирменный знак" или "водяная метка" разработчиков, так же иногда называемая "пасхальным яйцом", затрудняющая копирование оригинального диска (в рамках данной главы под "оригинальным диском" мы будем понимать диск, созданный с помощью Stomp Record NOW!, а предпоследний сектор области пост-зазораной области всякого трека  —– "водяным" сектором или X-сектором).

Поле MODE X-сектора, специфицирующее тип данного трека, вместо действительного трека замещается "водяной" константой E1h (реже —– E2h), что соответствует квалификатору первого блока выбега (см. листинг 6.62таблицу ххх). Три старших бита определяют конкретный квалификатор блока, а два младших —– тип трека. Таким образом, "водяное" число в общем случае равно: Water Mark Value (WMV) == E0h | Track MODE, соответственно: Track MODE == MODE & 3, где Track MODE —– тип трека, а MODE —– значение соответствующего поля заголовка сектора.

Помимо этого, в область данных X-сектора заносится идентификационная строка и серийный номер привода, осуществляющего "прожиг" диска (если только данный рекордер "знаком" Stomp Record NOW!).

"Желтая книга", так же известная под именем ECMA-130 (базовый стандарт лазерных дисков с данными), допускала существование лишь трех типов треков: MODE 0, MODE 1 и MODE 2, а все остальные трактовала как ошибку. Приложения, спроектированные в полном соответствии со стандартом ECMA-130, не в состоянии определить действительны тип X-?сектора, поскольку не "знают", что шесть старших бит поля MODE должны быть обнулены.


Такой сектор и в корзину не выкинешь, и через декодер Рида- Соломона не пропустишь, поскольку заранее неизвестно: присутствуют ли в нем коды EDC/ECC коды или же их там нет.

По стандарту области пред-зазора и пост-зазора предназначены исключительно для позиционирования оптической головки[7]

и не содержат в себе пользовательских данных. При штатной работе привода к этим секторам вообще не происходит никаких обращений (стандарт позволяет закладываться лишь на данные субканалов), благодаря чему "водяные знаки" (равно как и блоки вбега/выбега) никак не сказываются на работе привода и последний их просто не замечает. В тоже самое время, содержимое областей пред- и пос-зазора активно используется различными защитными механизмами для хранения ключевых меток, работающих приблизительно по такому же принципу, что и ключевые метки, записанные в инженерные сектора жестких дисков (71 и/или 72 трек дискеты). Не исключено, что между "водяными знаками" и ключевыми метками возникнет непредвиденный конфликт, приводящий к полной или частичной неработоспособности одной из сторон, так что злоупотреблять данной техникой право же не стоит.

Чтобы узнать, присутствуют ли на исследуемом диске "водяные знаки" или нет, мы должны считать предпоследние сектора всех Post-gap'ов в "сыром" виде, для чего нам пригодится утилита CD_RAW_SECTOR_READ или любая другая, аналогичная ей (очень хорошо подходит для этой цели Clone CDCloneCD). Остается определить абсолютные адреса конца областей пост-зазора всех треков. Это легко. Абсолютный адрес последнего сектора области Post-gap области равен стартовому адресу следующего трека минус sizeof(pre-gap) (стартовому адресу выводной области, если этот трек —– последний) минус единица. Соответственно, чтобы выйти на след предпоследнего сектора, от полученное значение следует уменьшить на единицу. Другими словами: x-sector address = (next track != lead-out)?next  track  address  – 3:lead out address – 2.



Стартовые адреса всех треков хранятся в point'ах указателях с номерами от 01 до 99 включительно, а стартовый адрес выводной области диска —– в point'e указателе с номером A2h. Допустим, на исследуемом диске имеется всего один-единственный трек и стартовый адрес выводной области равен 00:29:33

(см. листинг 6.63 ниже), тогда X-сектор будет располагаться по адресу 00:29:31.

Листинг 6.63. Определение адреса выводной области

[Entry 2]

Session=1

Point=0xa2

ADR=0x01

Control=0x04

TrackNo=0

AMin=0

ASec=0

AFrame=0

ALBA=-150

Zero=0

PMin=0

PSec=29

PFrame=33

PLBA=2058

Листинг 54 определение адреса выводной области

Отметим, что абсолютному адресу 00:29:31 соответствует LBA-адрес равный 2056. Запомним это значение, так как оно не раз и не два встретится в наших дальнейших экспериментах. Передав полученный адрес программе CD_RAW_SECTOR_READ, мы через секунду-другую получим на выходе его содержимое. Найти "водяной" сектор" в образе диска, снятом с помощью Clone CDCloneCD (или любой другой аналогичной ей программы) несколько сложение, но все же возможно. Существует по меньшей мере два пути: зная размер одного "сырого" сектора (2352 байта) и LBA-адрес "водяного" сектора, мы можем вычислить смещение искомого сектора в файле простым перемножением обоих величин (2352 * 2056 == 49С980h). Другой путь: просто поискать контекстным поиском HEX-последовательность 00 FF FF FF FF FF FF FF FF FF FF 00 00 29 31, т. е. Sync + address.

Но каким бы путем мы ни шли, результат будет таким как показано в листинге 6.64 (некорректный номер трека в заголовке сектора — E1h вместо 01h — выделен полужирным шрифтом и взят в рамку — и идентификатор рекордера, на котором выполнялся "прожиг" диска также выделен полужирным шрифтом)ов:

Листинг 6.64. "Водяные знаки", внедренные в предпоследний сектор области Post-gap программой Stomp Record Now!



0049C980:  00 FF FF FF FF FF FF FF ¦ FF FF FF 00 00 29 31 E1                )1с

0049C990:  52 49 44 30 31 00 00 00 ¦ 4E 45 43 00 00 00 00 00   RID01   NEC

0049C9A0:  4E 52 31 31 00 00 00 00 ¦ 02 58 56 00 00 00 00 00   NR11    OXV

0049C9B0:  4E 45 43 20 20 20 20 20 ¦ 20 20 20 20 20 20 20 20   NEC

0049C9C0:  20 20 20 20 20 20 20 20 ¦ 20 20 20 20 20 20 20 20

0049C9D0:  4E 52 2D 39 31 30 30 41 ¦ 20 20 20 20 20 20 20 20   NR-9100A

0049C9E0:  32 58 56 32 32 38 31 53 ¦ 31 31 31 20 20 20 20 20   2XV2281S111

0049C9F0:  00 00 00 00 00 00 00 00 ¦ 00 00 00 00 00 00 00 00

0049CA00:  00 00 00 00 00 00 00 00 ¦ 00 00 00 00 00 00 00 00

Листинг 55 водяные знаки, внедренные в предпоследний сектор post-gap'a программой Stomp Record Now: некорректный номер трека в заголовке сектора (E1h вместо 01h – выделен жирным шрифтом и взят в рамку) и идентификатор рекордера, на котором выполнялся прожиг диска (выделен жирным шрифтом)

Штатные копировщики (и Ahead  Nero в частности) не копируют содержимое областей пред- и пост-зазора и потому "водяные знаки" на скопированных дисках просто отсутствуют! Чтобы отличить оригинальный диск от его копии защитный механизм должен: 1) а) используя команду READ TOC (format 0x2 —– full TOC), считать оглавление диска в "сыром" виде; 2б) считать адрес выводной области любой из сессий (например, первой из них);  3в) определить адрес "водяного" сектора и, используя команду READ CD, считать его в "сыром" виде; 4г) проанализировать значение поля MODE (пятнадцатый байт заголовка сектора, считая от нуля),; если это поле больше двух, то – мы имеем дело с оригиналом или его качественной копией; . 5д) параноикам можно порекомендовать считать содержимое пользовательской области данных и сличить его с эталоном. Это не добавит защите стойкости (если копировщик скопирует "водяной" маркер в поле MODE, то он скопирует и пользовательскую часть сектора), но, возможно, придаст его разработчику чувство самоуспокоения.



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

Листинг 6.65. [crackme. 68E8B0Abh] поиск "водяных знаков", оставленных программой Stomp Record NOW!

// ВАЖНЕЙШИЕ КОНСТАНТЫ

#define _WATERMARK                   0xE1            // код водяного знака

#define _A2                            3               // смещение point'a A2h в TOC'e

#define _MODE                        15        // смещение поля MODE    в заголовке сектора

#define _M                             8                // смещение поля PMin    в TOC'e

#define _S                             9                // смещение поля PSec    в TOC'e

#define _F                             10              // смещение поля PFrame  в TOC'e

#define argCD        argv[1]

main(int argc, char** argv)

{

             int                          a, b, x_sec, LBA_lead_out = 0;

             unsigned char           buf[RAW_SECTOR_SIZE*2];

            

             // TITLE

             fprintf(stderr,"crackme.68E8B0ABh Record NOW! watermark\n");

            

             // справка по ключам

             if (argc != 2)         {

                     printf("USAGE: crackme.68E8B0ABh.exe CD\n"); return -1;}

            

             // читаем TOC в сыром виде

             a = cd_raw_toc_read(argCD, buf, RAW_SECTOR_SIZE, W_FULL_TOC);

            

             if (a != SCSI_OK) {             // операция выполнена успешно?

                     fprintf(stderr, "-ERR: read TOC\x7\n"); return -1; }

            

             // поиск point'a A2h, хранящего стартовый адрес выводной сессии



             for (a = 4; a < buf[0]*0x100L+buf[1]; a+=11)

             {               

                     // это point A2?

                     if (buf[a + _A2] == 0xA2)      

                     {

                             // point A2 найден

                             // получаем адрес выводной области первой сессии и сваливаем

                             LBA_lead_out=((buf[a+_M]*60+buf[a+_S])*75+buf[a+_F])-150; break;

                     }

             }

            

             // поиск адреса выводной области прошел успешно?

             if (LBA_lead_out == 0) {

                     fprintf(stderr,"-ERR: find A2h point\x7\n"); return -1;}

            

             // вычисляем адрес x-сектора, хранящего водяной знак

             x_sec = LBA_lead_out - 2;

            

             // читаем сектор с водяным знаком в сыром виде

             a = cd_raw_sector_read(argCD, buf, RAW_SECTOR_SIZE*2, x_sec, 1, 0xF8);

            

             if (a != SCSI_OK) {             // чтение сектора прошло успешно?

                     fprintf(stderr, "-ERR: read x-sector\x7\n"); return -1;         }

            

             // проверка на наличие водяного знака

             if (buf[_MODE] != _WATERMARK)

             {

                     // это не оригинальный диск

                     fprintf(stderr, "hello, hacker!\x7\n");         return 0;

             }      

            

             // это оригинальный диск

             printf("hello, legal user!\n");

}

Листинг 56 [crackme. 68E8B0Abh] поиск водяных знаков, оставленных программой Stomp Record NOW!

Тестирование копировщиков защищенных лазерных дисков показывает, что "водяные знаки" не копируются Clone CDCloneCD, который наотрез отказывается обрабатывать такие "неправильные" (с его точки зрения!) сектора, молчаливо приводя их в более потребный вид —– автоматически корректирует значение поля MODE и уничтожает всю идентификационнуюю информацию, в результате чего скопированный сектор приобретает следующий вид (листинг 6.66).:



Листинг 6.66.  На копии диска, полученной CloneCD, "водяные знаки" бесследно исчезают и поле MODE нормализуется! Таким образом, защищаемая программа может легко отличить оригинальный диск от его пиратского дубликата

0049C980:  00 FF FF FF FF FF FF FF ¦ FF FF FF 00 00 29 31 01               ¦$ O

0049C990:  00 00 00 00 00 00 00 00 ¦ 00 00 00 00 00 00 00 00

0049C9A0:  00 00 00 00 00 00 00 00 ¦ 00 00 00 00 00 00 00 00

0049C9B0:  00 00 00 00 00 00 00 00 ¦ 00 00 00 00 00 00 00 00

0049C9C0:  00 00 00 00 00 00 00 00 ¦ 00 00 00 00 00 00 00 00

0049C9D0:  00 00 00 00 00 00 00 00 ¦ 00 00 00 00 00 00 00 00

0049C9E0:  00 00 00 00 00 00 00 00 ¦ 00 00 00 00 00 00 00 00

Листинг 57 на копии диска, полученной Clone CD, водяные знаки бесследно исчезают и поле MODE нормализуется! таким образом, защищаемая программа может легко отличить оригинальный диск от его пиратского дубликата.

В других случаях скопированный X-сектор вообще не читается и команда READ CD с завидным постоянством возвращает малоинформативную сообщение от ошибке типа "MEDIUM ERROR" (ошибка носителя). Причины этого до конца не ясны. Возможно, Clone CDCloneCD пытается таким образом эмулировать bad-сектор, ошибочно посчитав X-сектор плохим, возможно это следствие неправильного обращения с пишущим приводом"писцом" (если Track MODE  >  2 то скремблирование сектора, записываемого в "сыром" режиме по идее не выполняется и на диске образуются неблагоприятные регулярные последовательности, которые в силу определенных конструктивных ограничений привода оказывается не так-то просто прочитать).

Но так или иначе, все "водяные знаки" копировщик Clone CDCloneCD просто "съедает", и защищенный диск оказывается неработоспособным. Конечно, в следующих версиях Clone CDCloneCD ситуация может круто измениться (поддержка X-секторов не требует кардинальных переработок кода копировщика и может появиться в любое время) и тогда защита, основанная на "водяных" метках, неизбежно падаетстановится бесполезной, кроме того X-сектора успешно копируются Alcohol 120% Алкоголем и вроде бы CDRWin, так что в чистом виде "водяные знаки" недостаточно эффективны и для усиления защиты их следует комбинировать с защитами других типов (искаженный стартовый адрес первого трека, нулевой трек на диске, фиктивный трек в Post-gap ключевого трека и т. д.).Подобные аддитивные защиты чрезвычайно стойки к копированию и на сегодняшний день не копируются ничем.


Содержание раздела