Блог → Снова о возможностях программ защиты от копирования

Я продолжаю серию статей о защите софта от нелегального копирования, начатую в прошлом посте, и сегодня мы с вами, уважаемые читатели, рассмотрим такие способы защиты, как установка некопируемых меток и специальной пометки дисков. Если вы не читали первую статью, у вас есть время это сделать, напомню, что в ней я рассмотрел общие принципы создания защиты от копирования для ваших программ, и если вам интересен этот вопрос, возможно, лучше начать читать с самого начала. Мы же продолжаем.

Способы получения некопируемых меток

Существуют различные методы получения некопируемых меток на гибких магнитных дисках. Уточним, что именно подразумевается под копированием дискет - будем говорить о процессе дублирования гибкого магнитного носителя при помощи стандартного дисковода (одного или двух). В случае одного дисковода содержание диска в один или несколько приемов считывается в оперативную память или в файл, а затем записывается на диск; в случае двух дисководов процесс может происходить напрямую.

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

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

Особенность первого случая состоит в том, что метка наносится оборудованием того же типа, которым и читается. Однако, чаще всего копирование происходит не на том компьютере, на котором метка была проставлена. Поэтому, процесс копирования может внести в параметры представления информации на дискете особенности дисковода или дисководов, на которых производилось копирование, а также особенности того или иного способа копирования.

С другой стороны, возможно так создать метку, чтобы она не могла быть корректно считана и/или записана. Например, форматировать большое число секторов малой длины, а записывать информацию в виде длинных секторов и т.д. Итак, при нанесении магнитной метки можно выделить следующие приемы:
- Вынос метки за пределы стандартного поля копирования;
- Нестандартная разметка дорожки (дорожек) дискеты;
- Привязка к временным параметрам чтения/записи;
- Комбинированные методы (сочетание первых трёх). Известные системы защиты от копирования используют, как правило, комбинированные методы простановки метки. Так, система SHIELD (разработка фирмы "Элиас") использует нестандартное форматирование нулевой дорожки с созданием длинного сектора (8196 байт), который при копировании не может быть корректно записан. Система CONVOY (фирма "Элиас") использует простановку метки на нулевой дорожке путем прямого программирования портов контроллера флоппи-дисковода (метка ставится в межсекторном интервале).

Система CERBERUS (кооператив "Информатик") использует нестандартное форматирование первых трех дорожек совместно с измерением временных параметров чтения. Системы PROTECT (малое предприятие "ПласТоп") и НОТА, совмещают нестандартную разметку дорожки с выносом метки за пределы стандартного поля копирования. Рассмотрим метод выноса метки за пределы поля копирования. Известно, что, например, дискеты формата 360 Кб содержат 40 дорожек по 9 секторов в каждом, нумерация дорожек от 0 до 39. Идея метода состоит в том, чтобы, используя функцию 05h прерывания int 13h, форматировать дорожки с номерами от 40 и более. Этот способ позволяет защититься от программных копировщиков, которые копируют только дорожки в фиксированном интервале номеров например от 0 до 39 (или 40) (для дискет 360 Кб) или от 0 до 79 (для дискет 1,2 Мб).

В предлагаемой ниже таблице указаны поля копирования ряда широко применяемых программных копировщиков.



#include <bios.h>
// установим номер дорожки 41 ntrk=41;
// заполним буфер

for(a=0;a<512;a++)
buffer[a]=0;

// заполнение идентификаторов формата for(k=0;k<9;k++) {
// номер дорожки
buf[4*k]= ntrk;

// номер головки (рабочей поверхности) buf[4*k+l]=0;
// номер сектора от 1 до 9
buf[4*k+2]=k+l;

// длина сектора 512 байт
buf[4*k+3]=2;

}

// форматирование 41-й дорожки
flag=biosdisk(5,0,0,ntrk,1,9,buf);
if(flag!=0) {

printf ("Ошибка форматирования на дисководе А:");
return(0);

}

// запись первого сектора на вновь сформатированную дорожку
flag=biosdisk(3,0,0,ntrkf1,1,buffer);
if(flag!=0) {

printf ("Ошибка записи на дисководе А:");
return(0);

}


Далее рассмотрим способ нестандартного форматирования дорожки дискеты. Для этого можно применить также прерывание int 13h, изменив соответствующим образом таблицу базы гибкого диска. Ссылка на таблицу базы диска находится по адресу:
сегмент 0000:0122 (0000:0080h)
смещение 0000:0120 (0000:0078h)

Содержание таблицы базы диска:



Стандартное содержание таблицы базы диска для дискет плотности 360 Кбайт:



Из параметров базы диска наиболее интересны следующие:
- размер сектора (0 — 128 байт, 1 — 256 байт, 2 — 512 байт, 3 — 1024 байта);
- номер последнего сектора на дорожке;
- межсекторный интервал для операций чтения и записи;
- межсекторный интервал для операции форматирования.

Изменяя данные параметры, возможно добиться неверного копирования, например, за счет того, что многие средства копирования (например, COPYWRIT), выравнивают длину межсекторных интервалов. Другими способами являются:
- использование больших длин секторов;
- нестандартная нумерация секторов.

Ниже приведён код примера, как можно форматировать 39-ую дорожку диска нестандартным образом. Сформатированную таким образом дорожку можно прочитать только при знании параметров таблицы базы диска.


// таблица базы диска
unsigned char tf[11] = {
OxDF,2,0x25,1,0x12,0x2A,OxFF,0x13,0xF6,25,4};
unsigned char buf[256];

// установка новой таблицы базы диска и сохранение адреса старой
seg=peek(0,122);
ofs=peek(0,120);
poke(0,122,_DS);
poke(0,120,(unsigned)tf);
_ES=_DS;
ntrk=39;
for(k=0;k<9;k++) {
buf[4*k]=39;
buf[4*k+l]=0;
buf[4*k+2]=k+1;
buf[4*k+3]=1;
}

flag=biosdisk(5,0,0,39,1,9,buf);
if (flag!=0) {
printf ("ERROR on a drive A:") ;

// установка старой базы диска
poke(0,122,seg);
poke(0,120,ofs);
return(0);
}

flag=biosdisk(3,0,0,39,1,1,buffer);
if (flag!=0) {
printf ("ERROR on a drive A:");

// установка старой базы диска
poke(0,122,seg);
poke(0,120,ofs);
return(0);
}

// установка старой базы диска
poke(0,122,seg);
poke(0,12 0,ofs);


И пример чтения нестандартной 39-ой дорожки:


; таблица базы диска
tf db
ODFh,2,025h,1,012h,02AhT OFFh,013h,OF6h,25,4
; буфер для чтения
bf db 256 dup (0)

; подготовка новой таблицы базы диска и сохранение
; старого значения ее сегмента и смещения
mov ах,offset tf
mov bx,0
mov es,bx
mov bx,120
mov cx,es:[bx]
mov s_tf_ofs,cx
mov es:[bx],ax
mov ax,seg tf
mov bx,0
mov es,bx
mov bx,122
mov cx,es:[bx]
mov s_tf_seg,cx
mov es:[bx],ax

; установление параметров чтения: ah — номер функции,
; al - сколько секторов считать
mov ах,00201h

; bx - смещение буфера для чтения
mov bx,offset bf

; ch — номер дорожки (39),cl — номер сектора
mov cx,02701h

; es — сегмент буфера для чтения
mov dx,seg bf
mov e s,dx

; dh - головка (поверхность чтения), dl — дисковод
mov dx,0 int 13h

; установка старых значений таблицы базы диска
mov bx,0
mov es,bx
mov bx,120
mov cx,s_tf_ofs
mov es:[bx],cx
mov bx,0
mov es,bx
mov bx,122
mov cx,s_tf_seg
mov es:[bx],cx

; обработка кода ошибки
cmp ah,0
je metO
mov ax,04C00h
int 21h

metO :
; продолжение при успешном чтении.


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

#include <dos.h>
#include <bios.h>
#include <stdio.h>

main()
{

// таблица базы диска 1 (19 секторов по 256 байт)
static unsigned char
tf1[11]={OxDF,2,0x25,1,0x13,0x2A,OxFF,OxA,0xF6,25,4);

// таблица базы диска 2 (1 сектор на 8192 байта) static unsigned char
tf2[11] = {OxDF, 2, 0x25, 6, 0x1, 0x2A, OxFF, 0x50, 0xF6,25, 4};
int seg_tf,ofs_tf,a,ntrk,flag,sum;

// таблица идентификаторов формата static char buf[4];
// буфер для записи длинного сектора
static char buffer[8192];

// сохранение старой таблицы базы диска
seg_tf = peek (0,122 );
ofs_tf = peek(0,120);

// установка таблицы 1
poke(0,122,_DS);
poke(0,120,(unsigned)tf1);

_ES=_DS;
ntrk=39;
for(a=0;a<8192;a++)
buffer[a]=1;

buf[0]=ntrk;
buf[1]=0;
buf[2]=1;
buf[3]=6;

// форматирование 19 секторов
flag=biosdisk(5,0,0,ntrk,1,19,buf);
if (flag!=0) {
printf ("Ошибка форматирования %x",flag);
poke(0,122,seg_tf);
poke(0,120,ofs_tf);
return(0);
}

// установка таблицы 2
poke(0,120,(unsigned)tf2);

// запись одного сектора
flag=biosdisk(3,0,0,ntrk,1,1,buffer);
if (flag!=0) {
printf ("Ошибка записи %x",flag);
poke(0,122,seg_tf);
poke(0,120,ofs_tf);
return(0);
}

poke(0,122,seg_tf); poke(0,120,ofs_tf);
printf ("Длинный сектор сформатирован успешно");
return(0);
}


Обратимся теперь к вопросу простановки физической меток. Идея метода состоит в том, что при нанесении на рабочие поверхности ГМД повреждений, попытки чтения или записи секторов, приходящихся на поврежденные зоны, приведет к ошибке. Очевидно, что при копировании дискеты с физической меткой поврежденные зоны не образуются на копии, поэтому, попытка считать или записать те сектора, которые на оригинале были повреждены, на копии закончится вполне успешно. Этот факт и является критерием для различения копии и оригинала.

Более аккуратная простановка метки, например, при помощи лазера приводит к образованию, как правило, не более одного поврежденного сектора. Алгоритм работы с лазерной меткой будет примерно таким:
- сформатировать дискету;
- прожечь метку;
- определить путем записи и чтения в каждый сектор конкретный вид и место метки;
- при проверке легальности копии в это место надо записать произвольную информацию и считать ее;
- легальная копия дает метку (т.е. ошибочное чтение или запись) в нужном месте.

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