3. Расторгуев С.П., Дмитриевский Н.Н. Искусство защиты и «раздевания» программ. – М.: Совмаркет, 1991. – 94с.
4. Фролов А.В., Фролов Г.В. Аппаратное обеспечение IBM PC: В 2-х ч. Ч. 1. – М.: «ДИАЛОГ – МИФИ». 1992. – 208с.
5. Фролов А.В., Фролов Г.В. Аппаратное обеспечение IBM PC: В 2-х ч. Ч. 2. – М.: «ДИАЛОГ – МИФИ». 1992. – 208с.
ПРИЛОЖЕНИЕ
1 Текст модуля F_Disk
2 Текст модуля F_Prot
3 Текст программы Diskett
4 Текст программы Test.exe
1 ТЕКСТ МОДУЛЯ F_DISK
{===================} UNIT F_Disk; {=====================}
{
+-------------------------------------------------------------+
| Модуль содержит подпрограммы для гибкой работы с дисками. |
| Во всех подпрограммах параметр DISK относится к логическим |
| дискам: 0=А, 1=В, 2=С, 3=D и т. д. Параметр SEC - относи- |
| тельный номер сектора; 0 = загрузочный сектор, далее по |
| секторам до конца дорожки, по головкам, по цилиндрам. |
+-------------------------------------------------------------+
}
INTERFACE
type
{Информация из BPD загрузочного сектора:}
BPB_Type=record
SectSiz: Word; {Количество байт в секторе}
ClustSiz: Byte; {Количество секторов в кластере}
ResSecs: Word; {Количество секторов перед FAT}
FatCnt: Byte; {Количество FAT}
RootSiz:Word; {Количество элементов корневого каталога}
TotSecs:Word; {Количество секторов на диске}
Media:Byte; {Дескриптор носителя}
FatSize:Word {Количество секторов в FAT}
end; {BPB_Type}
{Доплнительная информация из загрузочного сектора:}
Add_BPB_Type=record
TrkSecs:Word; {Количество секторов на дорожке
для разделов меньше 32 Мбайт или 0}
HeadCnt:Word; {Количество головок}
HidnSecLo:Word; {Количество спрятанных секторов для
разделов меньше 32 Мбайт}
HidnSecHi:Word; {Вместе с HidnSecLo дает количество
спрятанных секторов для разделов больше 32 Мбайт}
LargSectors:LongInt; {Общее количество секторов для
разделов больше 32 Мбайт}
end; {Add_BPB_Type}
{Элементдисковогокаталога:}
Dir_Type=record case Byte of
1:(
Name:array[1..8] of Char; {Имяфайлаиликаталога}
Ext:array[1..3] of Char; {Расширение}
FAttr:Byte; {Атрибутыфайла}
Reserv:array[1..10] of Byte; {Резервноеполе}
Time:Word; {Время создания}
Date:Word; {Дата создания}
FirstC:Word; {Номер первого кластера}
Size:LongInt {Размер файла в байтах});
2:(NameExt:array[1..11] of Char)
end; {Dir_Type}
{Описатель логического раздела}
PartType=record
Act:Boolean; {Флаг активности раздела}
BegHead:Byte; {Головка начала раздела}
BegSC:Word; {Сектор/цилиндр начала}
SysCode:Byte; {Системный код}
EndHead:Byte; {Головка конца раздела}
EndSC:Word; {Сектор/цилиндр конца}
RelSect:LongInt; {Относительный сектор начала}
FoolSiz:LongInt {Объем в секторах}
end; {PartType}
{Загрузочный сектор диска}
PBoot=^TBoot;
TBoot=record
case Byte of
0:(
a:array[1..11] of Byte;
BPB:BPB_Type;
Add:Add_BPB_Type;
c:array[1..+$1BE-(SizeOf(BPB_Type)+SizeOf(Add_BPB_Type)+11)] of Byte;
Par:array[1..4] of PartType);
1:(b:array[1..512] of Byte)
end;
{Описатель диска по структуре IOCTL}
IOCTL_Type=record
BuildBPB:Boolean; {СтроитьВРВ}
TypeDrv:Byte; {Типдиска}
Attrib:Word; {Атрибутыдиска}
Cylindrs:Word; {Числоцилиндров}
Media:Byte; {Типносителя}
BPB:BPB_Type;
Add:Add_BPB_Type;
Reserv:array[1..10] of Byte;
end;
{Описательдиска}
TDisk=record
Number:Byte; {Номердиска 0=А, ...}
TypeD:Byte; {Типдиска}
AttrD:Word; {Атрибутыдиска}
Cyls:Word; {Число цилиндров на диске}
Media:Byte; {Дескриптор носителя}
SectSize:Word; {Количество байт в секторе}
TrackSiz:Word; {Количество секторов на дорожке}
TotSecs:LongInt; {Полная длина в секторах}
Heads:Byte; {Количество головок}
Tracks:Word; {Число цилиндров на носителе}
ClusSize:Byte; {Количество секторов в кластере}
MaxClus:Word; {Максимальный номер кластера}
FATLock:Word; {Номер 1-го сектора FAT}
FATCnt:Byte; {Количество FAT}
FATSize:Word; {Длина FAT в секторах}
FAT16:Boolean; {Признак 16-битового элемента FAT}
RootLock:Word; {Начало корневого каталога}
RootSize:Word; {Количество элементов каталога}
DataLock:Word; {Начальный сектор данных}
end;
{Список описателей диска}
PListDisk=^TListDisk;
TListDisk=record
DiskInfo:TDisk;
NextDisk:PListDisk
end;
var
Disk_Error:Boolean; {Флагошибки}
Disk_Status:Word; {Кодошибки}
const
Disks:PListDisk=NIL; {Начало списка описателей диска}
function ChangeDiskette(Disk:Byte):Boolean;
{Возвращает TRUE, если изменялось положение
запора на указанном проиводе гибкого диска}
procedure FreeListDisk(var List: PListDisk);
{Удаляетсписокописателейдисков}
procedure GetAbsSector(Disk,Head:Byte; CSec:Word; var Buf);
{Читает абсолютный дисковый сектор с помощью прерывания $13}
function GetCluster(Disk:Byte; Sector:Word):Word;
{Возвращает номер кластера по заданному номеру сектора}
function GetDefaultDrv:Byte;
{Возвращает номер диска по умолчанию}
procedure GetDirItem(FileName:String; var Item:Dir_Type);
{Возвращает элемент справочника для указанного файла}
procedure GetDirSector(Path:String; var Disk:Byte; var Dirs,DirSize:Word);
{Возвращает адрес сектора, в котором содержится
начало нужного каталога, или 0, если каталог не найден.
Вход:
PATH - полное имя каталога ('', если каталог текущий).
Выход:
DISK - номер диска;
DIRS - номер первого сектора каталога или 0;
DIRSIZE - размер каталога (в элементах DIR_TYPE).}
procedure GetDiskInfo(Disk:Byte; var DiskInfo:TDisk);
{Возвращает информацию о диске DISK}
function GetDiskNumber(c:Char):Byte;
{Преобразует имя диска A...Z в номер 0...26.
Если указано недействительное имя, возвращает 255}
function GetFATItem(Disk:Byte;Item:Word):Word;
{Возвращает содержимое указанного элемента FAT}
procedure GetIOCTLInfo(Disk:Byte; var IO:IOCTL_Type);
{Получить информацию об устройстве согласно общему выову IOCTL}
procedure GetListDisk(var List:PListDisk);
{Формируетсписокописателейдисков}
procedure GetMasterBoot(var Buf);
{Возвращает в переменную Buf главный загрузочный сектор}
function GetMaxDrv:Byte;
{Возвращает количество логических дисков}
function Getsector(Disk:Byte;Cluster:Word):Word;
{Преобразует номер кластера в номер сектора}
function PackCylSec(Cyl,Sec:Word):Word;
{Упаковывает цилиндр и сектор в одно слово для прерывания $13}
procedure ReadSector(Disk:Byte;Sec:LongInt;NSec:Word;var Buf);
{Читает сектор(секторы) на указанном диске}
procedure SetAbsSector(Disk,Head:Byte;CSec:Word;var Buf);
{Записывает абсолютный дисковый сектор с помощью прерывания $13}
procedure SetDefaultDrv(Disk:Byte);
{Устанавливает диск по умолчанию}
procedure SetFATItem(Disk:Byte;Cluster,Item:Word);
{Устанавливает содержимое ITEM в элемент CLUSTER таблицы FAT}
procedure SetMasterBoot(var Buf);
{Записывает в главный загрузочный сектор содержимое Buf}
procedure UnPackCylSec(CSec:Word;var Cyl,Sec:Word);
{Декодирует цилиндр и сектор для прерывания $13}
procedure WriteSector(Disk:Byte;Sec:LongInt;NSec:Word;var Buf);
{Записывает сектор(секторы) на указанный диск}
IMPLEMENTATION
uses DOS;
var
Reg:Registers;
procedure Output;
{Формируетзначения Disk_Status и Disk_Error}
begin
with Reg do
begin
Disk_Error:=Flags and FCarry=1;
Disk_Status:=ax
end
end; {Output}
{----------------------}
function ChangeDiskette(Disk:Byte):Boolean;
{Возвращает TRUE, если изменялось положение
запора на указанном приводе гибкого диска}
begin
with Reg do
begin
AH:=$16;
DL:=Disk;
Intr($13,Reg);
Output;
ChangeDiskette:=Disk_Error and (AH=6)
end
end; {ChangeDiskette}
{----------------------}
procedure FreeListDisk(var List:PListDisk);
{Удаляет список дисковых описателей}
var
P:PListDisk;
begin
while List<>NIL do
begin
P:=List^.NextDisk;
Dispose(List);
List:=P
end
end; {FreeListDisk}
{---------------------}
procedure GetAbsSector(Disk,Head:Byte;CSec:Word;var Buf);
{Читает абсолютный дисковый сектор с помощью прерывания $13}
begin
with Reg do
begin
ah:=2; {Операциячтения}
dl:=Disk; {Номер привода}
dh:=Head; {Номер головки}
cx:=CSec; {Цилиндр/сектор}
al:=1; {Читать один сектор}
es:=seg(Buf);
bx:=ofs(Buf);
Intr($13,Reg);
Output
end
end; {GetAbsSector}
{--------------------}
function GetCluster(Disk:Byte;Sector:Word):Word;
{Возвращает номер кластера по заданному номеру сектора}
var
DI:TDisk;
begin
GetDiskInfo(Disk,DI);
if not Disk_Error then with DI do
if(Sector-DataLock>=0) and (TotSecs-Sector>=0) then
GetCluster:= {Нормальноеобращение}
(Sector-DataLock) div ClusSize+2
else
GetCluster:=0 {Неверный номер сектора}
else GetCluster:=0 {Неверный номер диска}
end; {GetCluster}
{----------------------}
function GetDefaultDrv:Byte;
{Возвращает номер диска по умолчанию}
begin
with Reg do
begin
AH:=$19;
MSDOS(Reg);
GetDefaultDrv:=AL
end
end; {GetDefaultDrv}
{---------------------}
procedure GetDirItem(FileName:String;var Item:Dir_Type);
{Возвращает элемент справочника для указанного файла}
var
Dir:array[1..16] of Dir_Type; {Буферна 1 секторкаталога}
Path:DirStr; {Маршрутпоиска}
NameF:NameStr; {Имяфайла}
Ext:ExtStr; {Расширениефайла}
Disk:Byte; {Номердиска}
Dirs:Word; {Номерсектора}
DirSize:Word; {Размеркаталога}
Find:Boolean; {Флагпоиска}
j:Integer; {Номерэлементакаталога}
{-----------}
procedure FindItem;
{Ищет нужный элемент в секторах каталога}
var
k,i:Integer;
m:array[1..11] of char; {Массивимени}
Clus:word; {Номеркластера}
DI:TDisk;
begin
GetDiskInfo(Disk,DI); {Получаем длину кластера}
ReadSector(Disk,Dirs,1,Dir); {Читаемпервыйсектор}
k:=0; {Количество просмотренных элементов}
j:=1; {Текущий элемент каталога}
{Готовим имя и расширение для поиска}
FillChar(m,11,' ');
Move(NameF[1],m[1],Length(NameF));
if ext<>'' then
Move(Ext[2],m[9],Length(ext)-1);
Find:=False;
{Циклпоиска}
repeat
if Dir[j].Name[1]=#0 then
exit; {Обнаруженконецпоиска}
if (Dir[j].FAttr and $18)=0 then
begin {Проверяем очередное имя в каталоге}
Find:=True;
i:=1;
While Find and (i<=11) do
begin
Find:=m[i]=Dir[j].NameExt[i];
inc(i)
end;
end;
if not Find then inc(j);
if j=17 then
begin
inc(k,16);
if k>=DirSize then
exit; {Дошли до конца каталога}
j:=1; {Продолжаем с первого элемента следующего сектора}
if (k div 16) mod DI.ClusSize=0 then
if succ(Dirs)<DI.DataLock then
inc(Dirs) {Корневойкаталог}
else
begin {Конецкластера}
{Новыйкластер}
Clus:=GetFATItem(Disk,GetCluster(Disk,Dirs));
{Новыйсектор}
Dirs:=GetSector(Disk,Clus)
end
else {Очередной сектор - в кластере}
inc(Dirs);
ReadSector(Disk,Dirs,1,Dir)
end
until Find
end; {FindItem}
{---------}
begin {GetDirItem}
{Готовимимяфайла}
FileName:=FExpand(FileName);
FSplit(FileName,Path,NameF,Ext);
{Искатькаталог}
GetDirSector(Path,Disk,Dirs,DirSize);
Find:=Dirs<>0; {Dirs=0 - ошибкавмаршруте}
if Find then
FindItem; {Ищемнужныйэлемент}
if Find then
begin
{Переносимэлементкаталогав Item}
Move(Dir[j],Item,SizeOf(Dir_Type));
{Сброситьошибку}
Disk_Error:=False
end
else
begin {Файл не найден}
Disk_Error:=True;
Disk_Status:=$FFFF
end
end; {GetDirItem}
{------------------------}
Procedure GetDirSector(Path:String;var Disk:Byte;var Dirs,DirSize:Word);
{Возвращает адрес сектора, в котором содержится начало
нужного каталога, или 0, если каталог не найден.
Вход:
PATH - полное имя каталога ('', если каталог - текущий).
Выход:
DISK - номер диска;
DIRS - номер первого сектора каталога или 0;
DIRSIZE - размер каталога (в элементах DIR_TYPE).}
var
i,j,k:Integer; {Вспомогательные переменные}
Find:Boolean; {Признак поиска}
m:array[1..11] of Char; {Массив имени каталога}
s:string; {Вспомогательная переменная}