Все PC оснащаются относительно хорошим чипом таймера, Intel 8253 или его функциональным эквивалентом. Работая с частотой 1 193 180 Гц, он позволяет измерять интервалы времени с разрешением 840 наносекунд (т.е. он может измерить время выполнения ОДНОЙ команды деления на 16 МГц-ном 386, которое может составлять до 2.4 мс). Такой таймер более чем соответствует требованиям измерения интервалов времени для гибкого дисковода (передача одного байта данных на самой быстрой из возможных скоростей (500 KBS) занимает 16 мс), так что точность подобных измерений ограничивается не разрешением таймера, а случайными колебаниями скорости вращения диска.
Форматирование отдельных дорожек с использованием фактора чередования секторов и с последующим анализом времени доступа к секторам для обычных стандартных дорожек и для нестандартных дорожек. Нарушение последовательности секторов. Этот подход заключается в нарушении стандартной последовательности секторов, т. е. сектора на дорожке в процессе форматирования нумеруются не последовательно, начиная с единицы, а в другом порядке (вообще номера секторов могут выбираться произвольно). Можно нарушать и другие значения в параметрах CHRN сектора. Нарушение последовательности секторов и другие нарушения в параметрах CHRN проверяются при выполнении команды «Чтение идентификатора».
Нарушение стандартного значения поля N позволяет читать/записывать данные за пределами реального сектора. Следует отметить, что программа COPYIIPC неверно копирует дорожку, на которой последний сектор имеет N, большее или равное 6. При копировании разрушаются первые сектора на дорожке.
Более интересный способ защиты дискет от копирования связан с использованием при форматировании нестандартного чередования секторов на дорожке. В приведенной ниже программе использовано "обратное" расположение секторов - вначале идет сектор с номером 15, затем 14 и т. д.
{ Программа форматирует 20 дорожку диска, создавая на ней
сектора c обратным расположением }
Program ReversFormat;
Uses crt,sysp;
Const
TRK = 21; { Номер форматируемой дорожки }
sec_size = 2; { Размер сектора 2 - 512 байт }
var
dpt_ptr:^DPT absolute $0000:$0078;
{ $0000:$0078 - Адpес таблицы параметров дискеты }
c : char;
kod : byte;
old_sec_size, old_fill_char, old_eot : byte;
i,j : byte;
diskbuf: array [1..512] of byte;
buf : string [80];
ol : byte;
BEGIN
clrscr;
writeln('Программа уничтожит содержимое 20-й дорожки диска А:.');
writeln('Хотите продолжить?(Y/N)');
{ Ожидаем ответ от оператора и анализируем его }
c := readkey;
if (c<>'y') and (c<>'Y') then halt (1);
{ Сохpаняем стаpые значения из таблицы паpаметpов дискеты }
old_sec_size := dpt_ptr^.sec_size;
old_fill_char := dpt_ptr^.fill_char;
old_eot := dpt_ptr^.eot;
{ Устанавливаем в таблице параметров дискеты
код размера сектора, символ заполнения при
форматировании, количество секторов на дорожке }
dpt_ptr^.sec_size := sec_size;
dpt_ptr^.fill_char:= $f6;
dpt_ptr^.eot := 15;
ol := dpt_ptr^.eot;
asm
{ Устанавливаем тип диска }
mov ah,017H
mov al,3
mov dl,0
int 13h
{ Устанавливаем среду для форматирования }
mov ah,18h
mov ch,trk
mov cl,ol
mov dl,0
int 13h
end;
{ Подготавливаем буфер форматирования для 15 секторов }
i := 1;
for j:=15 downto 1 do
begin
diskbuf[i]:=trk;
diskbuf[i+1]:=0;
diskbuf[i+2]:=j;
diskbuf[i+3]:=sec_size;
i:=i+4;
end;
{ Подготавливаем параметры для функции форматирования
Вызываем функцию форматирования дорожки }
asm
mov ax,seg diskbuf
mov es,ax
mov ah,05h
mov al,15
mov ch,trk
mov cl,1
mov dh,0
mov dl,0
lea bx,diskbuf
int 13h
mov kod,ah
end;
writeln ('Форматирование завершилось с кодом: ',kod);
{ Восстанавливаем старые значения в таблице паpаметpов дискеты}
dpt_ptr^.sec_size := old_sec_size;
dpt_ptr^.fill_char:= old_fill_char;
dpt_ptr^.eot := old_eot;
END.
Для анализа используемого чередования секторов можно использовать следующую программу, которая пытается прочитать подряд два расположенных рядом сектора с номерами 1 и 2. Если сектора на дорожке чередуются обычным образом, то сектора с номерами 1 и 2 находятся рядом. Если же дорожка отформатирована приведенной выше программой, то эти сектора находятся на максимальном удалении друг от друга.
Программа анализирует время, необходимое на то, чтобы 50 раз подряд прочитать эти два сектора на двадцатой дорожке. Вначале используется головка 0 -это нестандартная дорожка, затем - головка 1, для которой раньше было выполнено стандартное форматирование.
На экран выводятся не только времена, но и их отношение, которое и может служить критерием при определении того, с чем мы имеем дело - с оригинальной дискетой или с ее копией.
program ReversTest;
uses dos;
Var
diskbuf :array [1..1024] of byte;
i,j :word;
start_time,end_time:longint;
kod :byte;
t1,t2 :longint;
{ Функция возвращает количество секунд от начала суток }
Function colsec : Longint;
var
chas,min,sec,sotsec:word;
begin
gettime (chas,min,sec,sotsec);
colsec:=chas*60*60+min*60+sec;
end;
begin
{ Читаем первый сектор дорожки для синхронизации таймера }
i:=0;
kod:=0;
while (kod<>1) and (i<3) do
asm
mov ax,seg diskbuf
mov es,ax
mov dx,offset diskbuf
mov ah,02
mov al,1
mov ch,20
mov cl,1
mov dh,0
mov dl,0
int 13h
mov kod,al
inc i
end;
i:=0;
{ Отсчет времени начинаем сразу после чтения сектора, это позволит компенсировать время, необходимое на разгон мотора дисковода}
start_time:=colsec;
{ повторяем 50 pаз чтение секторов с номерами 1 и 2 }
while (i<50) do
begin
j:=1;
kod:=0;
while (kod<>2) and (j<3) do
asm
mov ax,seg diskbuf
mov es,ax
mov dx,offset diskbuf
mov ah,02
mov al,02
mov ch,20
mov cl,01
mov dh,00
mov dl,00
int 13h
mov kod,al
inc j
end;
inc(i);
end;
end_time:=colsec;
t1:=end_time-start_time;
writeln ('Время для головки 0:',t1,' сек');
i:=0;
kod:=0;
while (kod<>1) and (i<3) do
asm
mov ax,seg diskbuf
mov es,ax
mov dx,offset diskbuf
mov ah,02
mov al,01
mov ch,20
mov cl,01
mov dh,01
mov dl,00
int 13h
mov kod,al
inc i
end;
i:=0;
start_time:=colsec;
{ повторяем 50 раз чтение секторов с номерами 1 и 2 }
while (i<50) do
begin
j:=1;
kod:=0;
while (kod<>2) and (j<3) do
asm
mov ax,seg diskbuf
mov es,ax
mov dx,offset diskbuf
mov ah,02
mov al,02
mov ch,20
mov cl,01
mov dh,01
mov dl,00
int 13h
mov kod,al
inc j
end;
inc(i);
end;
end_time:=colsec;
t2:=end_time-start_time;
writeln ('Время для головки 1:',t2,' сек');
writeln ('Отношения времен чтения для головок 1 и 2:',t1/t2);
end.
Приведенный выше метод защиты дискет от копирования проверен на программе COPY2PC. Оказалось, что эта программа не копирует чередование секторов на дорожке.