Копирование без границ или передовые методики защиты CD

Star-force своими руками


Спиральная дорожка лазерных дисков очень похожа на грампластинку, только начинается не снаружи, а изнутри, наматываясь от центра к краю. Оптическая головка, удерживаемая в магнитном поле "звуковой катушки", движется на "салазках" поперек спиральной дорожки. Сама дорожка состоит из секторов с данными и каналов подкода. Номера секторов находятся как в заголовках самих секторов, так и в каналах подкода, "размазанных" вдоль спиральной дорожки. Для грубой наводки не требуемый сектор используются салазки и каналы подкода, а для точной— отклонение в магнитном поле и секторные заголовки.

Просто взять и измерять структуру спиральной дорожки нельзя, но можно сделать вот что: допустим, головка считывает сектор X, а следом за ним сектор Y. Если угол XOY, образованный центром (O) диска, секторами X и Y составляет порядка ~15 град, а сами сектора расположены на соседних витках спирали, то приводу достаточно всего лишь немного отклонить головку и через мгновение сектор Y сам падает в руки, как перезревшее яблоко — диск ведь вращается! Если же угол XOY составляет менее ~15 град, тогда за время перемещения головки, сектор Y уже "уплывет" и приводу придется ждать целый оборот лазерного диска, пока он не достигает оптической головки!

Рисунок 4 когда угол между секторами X и Y составляет ~15 град. при переходе на соседний виток, сектор Y сразу же "подлетает" к оптической головке (рисунок слева), при меньшем значении угла сектор Y успевает уплыть и головка вынуждена ждать целый сезон, тьфу, виток

Замеряя время чтения различных пар секторов, мы можем приблизительно определить их взаимное расположение на спиральной дорожке. У каждой партии диска для заданных секторов X и Y оно будет своим (ведь степень "закрутки" спирали неодинакова и варьируется от одного производителя к другому). Чтобы побороть упреждающее считывание (которым "страдают" многие приводы), защита должна читать сектора в порядке убывания их LBA-адресов.
Так же она должна измерять скорость вращения привода, чтобы во-первых, определить постоянство временных замеров (пляшут ли они как пьяные человечки или нет), а во-вторых скорректировать формулу для вычисления угла, ведь как легко показать, чем быстрее вращается диск, тем скорее "уплывает" сектор.

Исходный текст "измеряющей" программы приведен ниже:

//-[чтение сектора с диска]---------------------------------------------------

// ARG:

//     CD     указатель на строку с именем провода (например, "TEAC"),

//            адрес на ASPI-шине (например, "1.1") или имя диска("\\.\G:");

//            первые два варианта работают через ASPI, последний через SPTI;



//

//     buf    указатель на буфер SECROR_SIZE*2

//

//     sector номер сектора в LBA-формате

//

// RETURN:

//     0     успешно

//     -1     ошибка

read_from_cd(char *CD, unsigned char *buf, long sector)

{

       int stat;

       stat=cd_raw_sector_read(CD, buf, SECTOR_SIZE, sector, ONE_SECTOR, W_USER_DATA);

       if (stat == SCSI_OK) return 0; return -1;

}

//-[чтение TSC-счетчика]------------------------------------------------------

unsigned int A()

{

       __asm{

       _emit  0xF    ; RDTSC

       _emit  0x31

       }

}

#define argCD        v[1]

// КОНФИГУРАЦИЯ

//----------------------------------------------------------------------------

// номер первой точки измерения (LBA-адрес)

// данная утилита измеряет топологию только по одной точке,

// что не есть хорошо, т.к. легко подобрать похожий диск

// для уверенности следует выбрать несколько точек:

// в начале, середине и конце диска

#define _CFG_BGN_SEC_      17699

// кол-во секторов для измерения

// должно быть не меньше утроенного кол-ва секторов на виток в данной

// точке измерения (см. _CFG_BGN_SEC_ )

// число витков спирали N с поперечной плотностью D витков/мм

// от радиуса R1 до радиуса R2 определяется формулой: N = (R2- R1) * D



#define _CFG_LEN_SEC_      0x669

// максимальный шаг приращения

// в принципе должен быть равен удвоенному кол-ву секторов

// на данном витке спирали, что увеличивает точность измерений

// но можно использовать и  значение _CFG_LEN_SEC_

#define _CFG_LEN_DEL_      _CFG_LEN_SEC_

// начальный шаг приращения (должен быть по возможности мал)

#define _CFG_BGN_DEL_      0x2

// приблизительное кол-во секторов на данном витке спирали

// (в данной версии программы это значение мало на что влияет)

#define _CFG_xWHELL_ 27

// конечный сектор для проверки

#define _END_SEC_ (_CFG_BGN_SEC_+_CFG_LEN_SEC_)

// конечный шаг

#define _END_DEL_ (_CFG_BGN_DEL_+_CFG_LEN_DEL_)

#define FB(b) (##b = (##b + 1) % _END_DEL_);           // приращение шага

// шапка цикла

#define FH(a,b) for (##a=_END_SEC_,##b=_CFG_BGN_DEL_; ##a > _CFG_BGN_SEC_; ##a-=##b)

main(int c, char** v)

{

       int a, b; int x=0; int i=0; int A1, A2;

       unsigned char buf[SECTOR_SIZE];

      

       // проверка аргументов командной строки

       if (c < 2) {

              fprintf(stderr,"USAGE:sf.exe CD\n\n");

              printf( "       SCSI_INQUITY via ASPI32\n"\

                     "-------------------------------------\n");

                     read_from_cd("?.?", buf,0); return 0;

       }

      

       // этап первый

       //-----------------------------------------------------------------------

       // читаем случайные сектора для разгона привода

       fprintf(stderr,"%s\n",_TEXT_SPINEUP_);

       for (a = 0; a < 0x69; a++)

       {

              read_from_cd(argCD, buf,rand()%_END_SEC_);

              fprintf(stderr,"\r%02d%%",a*100/0x69);

       }

      

       // этап второй

       //------------------------------------------------------------------------

       // определяем кол-во секторов на дорожке и стабильность вращения привода



       // алгоритм определения кол-ва секторов: читаем сектора задом наперед,

       // с циклически увеличивающимся шагом, наименьшее значение шага

       // при котором время чтения секторов будет минимальным - и будет равно

       // кол-ву секторов на данном витке спирали

       // (fixit: пока не реализовано, кол-во секторов взято на глазок)

       //

       // алгоритм определения стабильности: читаем сектора с шагом, равным

       // кол-ву секторов на данном витке спирали, и оцениваем разброс;

       // если разброс будет слишком большим (превышает 10%-15%), следует

       // уменьшить скорость привода (как это сделать показано в CD.snail.c)

       fprintf(stderr,"\r%s\n",_TEXT_TEST_);

       for (a = _END_SEC_; a > _CFG_BGN_SEC_; a-=_CFG_xWHELL_)

       {

              A1=A(&c);read_from_cd(argCD, buf,a);A2=A(&c);

              fprintf(stderr,"\r%02d%%",(_END_SEC_-a)*100/_CFG_LEN_SEC_);

       }

      

       // этап третий (важнейший!)

       //------------------------------------------------------------------------

       // производим, собственно, измерения

       // fix1: добавить "сглаживание" полученных данных

       fprintf(stderr,"\r%s\n",_TEXT_ANGLE_);

      

       //  выводим шапку таблицы

       printf("delta:"); FH(a,b) { printf("\t%d",a); FB(b); } printf("\ntime:");

      

       // измеряем и тут же выводим результаты

       FH(a,b)

       {

              A1=A(&c); read_from_cd("TEAC", buf,a); A2=A(&c);

              printf("\t%d",(A2-A1)/100);

              fprintf(stderr,"\r%02d%%",(_END_SEC_-a)*100/_CFG_LEN_SEC_);

              FB(b);

       } printf("\n");

      

       // всему конец

       fprintf(stderr,"\r%s\n",_TEXT_END_); return 0;

}

Листинг 2 макет программы sf.c для снятия топологий

Программа использует библиотечку SCSIlib, разработанную автором для низкоуровневого управления приводами с прикладного уровня.Ее можно бесплатно скачать с ftp-сайта автора.


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