Банк рефератов содержит более 364 тысяч рефератов, курсовых и дипломных работ, шпаргалок и докладов по различным дисциплинам: истории, психологии, экономике, менеджменту, философии, праву, экологии. А также изложения, сочинения по литературе, отчеты по практике, топики по английскому.
Полнотекстовый поиск
Всего работ:
364139
Теги названий
Разделы
Авиация и космонавтика (304)
Административное право (123)
Арбитражный процесс (23)
Архитектура (113)
Астрология (4)
Астрономия (4814)
Банковское дело (5227)
Безопасность жизнедеятельности (2616)
Биографии (3423)
Биология (4214)
Биология и химия (1518)
Биржевое дело (68)
Ботаника и сельское хоз-во (2836)
Бухгалтерский учет и аудит (8269)
Валютные отношения (50)
Ветеринария (50)
Военная кафедра (762)
ГДЗ (2)
География (5275)
Геодезия (30)
Геология (1222)
Геополитика (43)
Государство и право (20403)
Гражданское право и процесс (465)
Делопроизводство (19)
Деньги и кредит (108)
ЕГЭ (173)
Естествознание (96)
Журналистика (899)
ЗНО (54)
Зоология (34)
Издательское дело и полиграфия (476)
Инвестиции (106)
Иностранный язык (62791)
Информатика (3562)
Информатика, программирование (6444)
Исторические личности (2165)
История (21319)
История техники (766)
Кибернетика (64)
Коммуникации и связь (3145)
Компьютерные науки (60)
Косметология (17)
Краеведение и этнография (588)
Краткое содержание произведений (1000)
Криминалистика (106)
Криминология (48)
Криптология (3)
Кулинария (1167)
Культура и искусство (8485)
Культурология (537)
Литература : зарубежная (2044)
Литература и русский язык (11657)
Логика (532)
Логистика (21)
Маркетинг (7985)
Математика (3721)
Медицина, здоровье (10549)
Медицинские науки (88)
Международное публичное право (58)
Международное частное право (36)
Международные отношения (2257)
Менеджмент (12491)
Металлургия (91)
Москвоведение (797)
Музыка (1338)
Муниципальное право (24)
Налоги, налогообложение (214)
Наука и техника (1141)
Начертательная геометрия (3)
Оккультизм и уфология (8)
Остальные рефераты (21692)
Педагогика (7850)
Политология (3801)
Право (682)
Право, юриспруденция (2881)
Предпринимательство (475)
Прикладные науки (1)
Промышленность, производство (7100)
Психология (8692)
психология, педагогика (4121)
Радиоэлектроника (443)
Реклама (952)
Религия и мифология (2967)
Риторика (23)
Сексология (748)
Социология (4876)
Статистика (95)
Страхование (107)
Строительные науки (7)
Строительство (2004)
Схемотехника (15)
Таможенная система (663)
Теория государства и права (240)
Теория организации (39)
Теплотехника (25)
Технология (624)
Товароведение (16)
Транспорт (2652)
Трудовое право (136)
Туризм (90)
Уголовное право и процесс (406)
Управление (95)
Управленческие науки (24)
Физика (3462)
Физкультура и спорт (4482)
Философия (7216)
Финансовые науки (4592)
Финансы (5386)
Фотография (3)
Химия (2244)
Хозяйственное право (23)
Цифровые устройства (29)
Экологическое право (35)
Экология (4517)
Экономика (20644)
Экономико-математическое моделирование (666)
Экономическая география (119)
Экономическая теория (2573)
Этика (889)
Юриспруденция (288)
Языковедение (148)
Языкознание, филология (1140)

Курсовая работа: Защита программы от нелегального копирования

Название: Защита программы от нелегального копирования
Раздел: Рефераты по информатике
Тип: курсовая работа Добавлен 00:20:27 21 июля 2010 Похожие работы
Просмотров: 240 Комментариев: 22 Оценило: 2 человек Средний балл: 5 Оценка: неизвестно     Скачать

Министерство образования и науки Украины

ПОЯСНИТЕЛЬНАЯ ЗАПИСКА

к курсовому проекту

на тему "Защита программы от нелегального копирования"

по курсу "Кодирование и защита информации"

2004


Содержание

Введение

1 Описание существующих методов

Проверка типа ПК и версии ДОС

Проверка даты изготовления и контрольной суммы ПЗУ

Проверка места расположения файла на диске

Проверка состава аппаратных средств

Использование скрытых частей программы и особенностей физических носителей информации

2 Обоснование выбора используемого метода

3 Описание программы

Заключение

Список ссылок

Приложение


Введение

В данном курсовом проекте рассматривается проблема создания программы, нелегальное (без ведома официального распространителя) копирование которой приводит к потере программы способности нормально работать.

Сегодня в нашей стране сложилась парадоксальная ситуация, когда в большинстве отечественных ПК в основном используется «ворованное» программное обеспечение. Редкое исключение составляют те профессионалы, которые работают в частных фирмах или на совместных предприятиях.

В соответствии с международным правом труд автора программы приравнен к труду других творцов интеллектуальной собственности, таких как писатели, музыканты, художники, и подлежит защите. Однако в отличие от книги или картины массовое копирование программы не вызывает каких-либо технических трудностей и не требует специального оборудования (если, разумеется, не считать ПК). В отношении программа намного беззащитнее, чем, скульптура или книга. Общий ущерб от нелегального копирования программ по оценкам западных экспертов составляет от 2 до 10 млрд. долларов в год [1].

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

Несколько иначе обстоит дело с программами, которые не рассчитаны на массового пользователя. К таким относятся различного рода системы автоматизированного проектирования, предыздательские системы, специализированные базы данных и т. п. Как правило, это весьма наукоемкие товары, т. е. в них особенно велик вклад высококлассных специалистов в конкретных прикладных областях. Труд таких специалистов обычно высоко ценится, поэтому общие затраты на создание подобного рода программ могут быть весьма велики, что в сочетании со сравнительно небольшим кругом потенциальных пользователей делает цену каждой копии очень большой. Такие программы обычно снабжаются защитой, так как ограниченный спрос на них формирует весьма специфичный рынок: покупателями этих программ являются специалисты в конкретной прикладной деятельности, которые не имеют нужных навыков и, главное, желания заниматься «вскрытием» программ.


1. Описание существующих методов

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

Любая копия защищенной программы должна содержать в себе или во внешнем файле «ключ» - одно или несколько кодовых чисел. В момент проверки программа сравнивает некоторые специфические признаки рабочей среды с заранее закодированными в ключе и по результатам сравнения формирует соответствующий признак. Таким образом, мало создать копию программы: для того чтобы эта копия стала работоспособной, ей необходимо передать ключ, настроенный на работу с вполне определенным компьютером [1].

Анализ индивидуальных признаков среды подразумевает, какими специфическими признаками может обладать та программно-аппаратная среда, в которой работает программа. Для IBM-совместимых ПК этими признаками могут быть:

- тип ПК и тип (версия) операционной системы;

- дата изготовления ПЗУ BIOS и/или его контрольная сумма;

- физическое положение файлов на дисковом носителе;

- состав аппаратных средств;

- наличие скрытых частей программы;

- физические особенности (в том числе дефекты) носителя.

Некоторые из этих признаков очень индивидуальны (например, физические особенности некачественного носителя), другие обладают меньшей индивидуальностью (тип ПК, версия ДОС). Программа может использовать один или несколько признаков для проверки легальности копии. При этом особое значение приобретает способ использования программы: если программа рассчитана на работу на конкретном ПК, выбираются одни признаки, если она может свободно перемещаться с одного компьютера на другой без потери работоспособности, - другие. Назовем программы первого типа стационарными, а второго – мобильными. Защита тех и других программ имеет свои особенности, которые мы будем обсуждать.

Во всех случаях проверка легальности не должна существенно сказаться на быстродействии программы или требовать от пользователя каких-то дополнительных действий. Например, вряд ли можно считать сколько-нибудь эффективной систему, использующую пароль (кодовое слово), который должен ввести пользователь: во-первых, пользователь может забыть это слово и тем самым лишиться законно приобретенной программы, а во-вторых, ничто не мешает ему сообщить это слово любому другому пользователю. Система защиты не должна проверять пользователя, она должна проверить копию [3].

1.1 Проверка типа ПК и версии ДОС

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

Тип ПК записан в ПЗУ по адресу $F000:$FFFE, т. е. в предпоследнем байте мегабайтного адресного пространства ПК [4].

Версию ДОС можно получить с помощью функции ДОС $30 [4]. При обращении к этой функции в регистре AL возвращается старший, а в AH – младший номера версии. Регистр AL может содержать 0, если используется более ранняя ДОС чем 2.0.

Ценность этих проверок заключается в их исключительной простоте, однако могут найтись тысячи однотипных компьютеров, на которых используется одинаковая версия ДОС, поэтому ограничиваться только этими проверками вряд ли имеет смысл.

1.2 Проверка даты изготовления и контрольной суммы ПЗУ

Постоянное запоминающее устройство (ПЗУ) является неотъемлемой составной частью любого IBM – совместимого ПК. Содержимое ПЗУ учитывает особенности реализации конкретного ПК и может отличаться в компьютерах разного типа. Более того, в конце ПЗУ (по адресу $F000:$FFF5) обычно записывается дата его изготовления, поэтому даже для ПК одного типа (и одной и той же фирмы-изготовителя) контрольная сумма ПЗУ отличается в разных экземплярах ПК. Дата изготовления ПЗУ занимает 8 смежных байт. Данные хранятся в символьном виде в формате ММ/ДД/ГГ [1],[4].

Как показывает практика, любая уважающая себя фирма-изготовитель ПЗУ для IBM – совместимых ПК тщательно следит за корректностью этой даты. Конечно, каждый день во всем мире изготавливаются тысячи микросхем ПЗУ с одинаковой датой, однако вероятность того, что где-то используется ПК того же типа и с такой же датой изготовления, как и у компьютера владельца программы крайне мала. Разумеется, при массовой закупке ПК, например для оснащения учебного класса, многие или даже все одновременно приобретенные компьютеры могут иметь одну и ту же дату изготовления ПЗУ. Однако в таких случаях способность защищенных программ свободно переноситься с одного родственного компьютера на другой можно рассматривать как вполне естественную. Эта проверка используется для защиты стационарных программ.

1.3 Проверка места расположения файла на диске

Хорошей индивидуальностью обладает физический номер кластера, начиная с которого на жестком диске располагается файл с защищенной программой. Действительно, вряд ли что-либо другое в аппаратно-программной среде ПК (кроме, разумеется, содержимого оперативной памяти) меняется столь же динамично, как файловая структура жесткого диска. При создании легальной копии номер начального кластера для файла программы на жестком диске в общем случае совершенно случаен. Если в момент запуска программа проверит этот номер, то в подавляющем большинстве случаев она легко обнаружит факт нелегального копирования. Тем не менее, такой способ защиты нельзя считать идеальным по многим причинам. Проверка номера кластера выполняется далеко не так просто, как проверка типа ПК или даты изготовления ПЗУ, поскольку в стандартном Турбо Паскале нет средств для работы с дисками на физическом уровне. Однако главный недостаток заключается в другом: любое изменение местоположения файла даже в пределах одного каталога приводит к тому, что ранее установленная копия становится нелегальной. Это крайне неудобно для пользователя, в особенности, если он часто прибегает к процедуре переупорядочения файловой структуры с помощью дефрагментации жесткого диска. Если пользователь считает, что номер единственного кластера не обладает необходимой степенью индивидуальности, то можно проверять цепочку кластеров по таблице FAT или начальные кластеры нескольких файлов. Разумеется, такая проверка может использоваться для защиты только стационарных программ [1],[3].

1.4 Проверка состава аппаратных средств

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

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

Получение сведений о конфигурации ПК может быть осуществлено посредством чтения данных по определенным адресам КМОП-памяти. Более подробно об этом написано в [1], [4], [5].

1.5 Использование скрытых частей программы и особенностей физических носителей информации

Достаточно эффективным способом защиты (главным образом для мобильных программ) может служить создание и использование скрытых частей программы и/или особенностей физических носителей информации [3].

Скрытые части программы – это участки дискового носителя, тем или иным способом связанные с программой, но не зафиксированные в качестве файлов ДОС. В подавляющем большинстве случаев программе нет необходимости искусственно создавать такие участки, поскольку они уже имеются в «хвосте» любого файла. Дело в том, что ДОС распределяет дисковое пространство кластерами, имеющими длину от 512 до 4096 и более байтов. Даже если полезная длина файлов составляет всего несколько байт, ДОС выделит такому файлу целый кластер, большая часть которого будет заполнена «мусором» - случайной информацией, сохранившейся от предыдущего использования кластера в составе другого файла. При копировании файлов стандартными средствами ДОС копируется только полезная часть кластера, так что на новом месте «хвост» файла в общем случае будет заполнен другой информацией [1].

Более изощренный, но ничуть не более эффективный способ защиты состоит в создании и использовании дополнительных скрытых кластеров. Такие кластеры могут помечаться в FAT как сбойные или «потерянные» (т. е. не относящиеся ни к какому зарегистрированному файлу). Во всех случаях, помещается ли ключ в хвост файла или в отдельный кластер, защита может быть легко нейтрализована, если используется копирование дискеты «блок в блок» с помощью утилиты DISKCOPY или аналогичных несистемных программ.

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

Как показывает практика, лишь очень небольшое число дискет (менее 1%) имеет заводские дефекты изготовления, поэтому при массовом тиражировании коммерческих программ приходится создавать такие дефекты искусственно. Для этого иногда используются лазеры, а чаще – обыкновенная булавка. Однако следует иметь в виду, что царапины и проколы на поверхности дискеты могут повредить считывающие головки накопителя [1].

Недостатком описанного способа защиты являются относительно большие затраты времени на контроль всей дискеты и потеря работоспособности некоторой ее части. От этих недостатков можно избавится, если на дискете создать программным способом нестандартные для ДОС особенности [1]. Этими способностями могут быть:

- нестандартная длина секторов на всей дискете или какой-либо одной ее дорожке;

- специальное расположение (фактор чередования) секторов на дорожке;

- нестандартное количество дорожек.

Разумеется, надежность защиты с помощью программно создаваемых особенностей структуры дискеты будет значительно меньше. Тем не менее, следует помнить, что в большинстве случаев «взломщик» программы стремится изменить ее код, а не имитировать особый способ копирования дискет, так что несложная защита, связанная с использованием дополнительной дорожки, может оказаться ничуть не хуже, чем защита с помощью «лазерной дырки».

Как известно, ДОС может оперировать только с секторами длиной по 512 байт (исключением является создание утилитой VDISK виртуальных электронных дисков, размер секторов которых может отличаться от 512 байт). В то же время контроллеры ГД способны создавать и использовать секторы другого размера – по 128, 256 или 1024 байт. При обнаружении сектора нестандартного размера ДОС считает этот сектор сбойным, что можно использовать для защиты программы [5].

Далее, дорожки на дискете располагаются так, что самой внешней является нулевая дорожка, а самой внутренней – дорожка с максимальным номером. Обычно ДОС использует одинаковое количество секторов на всех дорожках, поэтому угловой размер каждого сектора постоянен, а, следовательно, плотность записи информации растет с ростом номера дорожки. Количество секторов на дорожке и дорожек на дискете ДОС назначается так, чтобы даже для самой внутренней дорожки эта плотность не превысила некоторого значения, еще гарантирующего уверенную работу схем контроллера ГД. На практике оказывается, что подавляющее большинство современных контроллеров способно обслуживать большее количество дорожек, чем принято в ДОС. В целях защиты от копирования программа может создать и использовать одну или несколько дополнительных дорожек, но не вносить их в список «видимых для ДОС», т.е. не изменять поле в загрузочном секторе, указывающее общее количество секторов на диске. Разумеется, возможен и другой вариант: можно «украсть» у ДОС несколько дорожек, уменьшив стандартное значение этого поля, однако нестандартная емкость дискеты легко обнаруживается, что снижает эффективность защиты. Дополнительные дорожки могут отделяться от основной рабочей зоны дискеты неотформатированным интервалом, что может затруднить их обнаружение специальными программами копирования [1],[4].

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


2. Обоснование выбора используемого метода

В данном курсовом проекте реализовано два метода защиты программы от нелегального копирования. Это защита стационарной программы и мобильной. Для защиты стационарной программы был выбран метод проверки даты создания ПЗУ. Этот метод был выбран благодаря тому, что дата создания ПЗУ является достаточно индивидуальной для каждого ПК, если только они не были приобретены в партии, например для оснащения компьютерного класса, но в таком случае защита программы от нелегального копирования становится неактуальной. Для защиты мобильного варианта программы на дискете была создана дополнительная дорожка с секторами нестандартного размера. Этот вариант был выбран потому, что в данном случае на дискету не требуется наносить физических повреждений, что приводит к потере работоспособности некоторой ее части. И эта защита может оказаться не ничуть не хуже, чем защита с использованием дефектов дискет.


3. Описание программы

Защита программ от нелегального копирования реализована в виде модуля, написанного на языке Turbo Pascal. Выбор этого языка программирования объясняется тем, что этот язык относительно прост, и при этом позволяет делать ассемблерные вставки и напрямую обращаться к памяти. Этот модуль подключается к программам, которые требуется защитить, и в программах используются его функции.

Модуль рассчитан на защиту как мобильных, так и стационарных программ. Основной процедурой модуля является процедура ProtCheck, осуществляющая контроль копии. Легальность мобильного варианта программы устанавливается за счет контроля скрытого сектора на ключевой дискете, в случае стационарного варианта проверяется дата создания ПЗУ. Две другие процедуры модуля позволяют установить защиту файла на жестком диске (процедура SetOnHD) и удалить стационарный вариант программы (процедура RemoveFromHD).

Ниже описана разница в защите стационарной и мобильной копиях. Стационарная программа учитывает индивидуальные характеристики компьютера и может исполняться только на одном конкретном ПК. Защита таких программ обычно не вызывает серьезных проблем, для этого можно использовать очень большой набор индивидуальных признаков. Наоборот, мобильная программа не может связываться с конкретным ПК и должна учитывать какие-то привносимые признаки, т. е. признаки, которые относительно просто создать на любом ПК на время работы программы. Здесь выбор признаков намного беднее: чаще всего для этих целей используются дополнительные аппаратные устройства (ключевая дискета или аппаратный ключ), которые придаются каждой легальной копии и без которых программа не может работать нормальным образом. Вариант использования ключевой дискеты и реализован в модуле F_Prot.

Для создания легальной копии программы должна использоваться особая технология подготовки дискеты. Эта особенность в данном случае заключается в том, что на стандартной дискете диаметром 3,5 дюйма, рассчитанной на емкость 1,44 Мб, создается дополнительная дорожка из нестандартных 256-байтных секторов. Один из секторов этой дорожки используется для записи ключевой информации. В процессе проверки легальности копии программы процедура ProtCheck считывает этот сектор и контролирует его содержимое. Для создания ключа используется программа Diskette. Эта программа на дискете емкостью 1,44 Мб создает 81-ю дорожку с 18-ю секторами размером по 256 байт, причем для нее используется обратный фактор чередования, т. е. секторы на дорожке размещаются в последовательности 18,17,16,…,2,1. Для этого она корректирует таблицу параметров дискеты, которую берет или в ПЗУ или в ОЗУ по определенному адресу [4], [5]. Программа сохраняет копию старой таблицы параметров дискеты и после завершения работы восстанавливает ее. В первый сектор новой дорожки записывается произвольная информация и число установок на жесткий диск защищаемой программы, (это число установок вводится пользователем при создании ключевой дискеты). Затем сектор читается и проверяется правильность операции записи-чтения. В конце программы измеряется время доступа к новой дорожке и стандартной дорожке. Для чтения и записи сектора используется прерывание $13. В случае ошибки чтения или записи сектора, программа выводит сообщение об ошибке и восстанавливает старую таблицу параметров дискеты.

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

Процедура ProtCheck вызывается из защищаемой программы всякий раз, когда требуется установить легальность копии. Ее заголовок имеет следующий вид:

ProcedureProtCheck(varNorma,Alarm;varRes:Integer)

В теле процедуры параметры-переменные Norma и Alarm трактуются как параметры процедурного типа

type

ProcType = Procedure;

т. е. являются адресами двух процедур без параметров. Процедура Alarm вызывается в случае, если программа обнаружила признаки нелегального копирования, а Norma – если эти признаки отсутствуют. В переменной Res возвращается результат работы ProtCheck: 0 – если выполнялась процедура Norma (легальная копия), 1 - выполнялась Alarm (нелегальная копия), 2 – не выполнялась ни та, ни другая процедура, так как программа не обнаружила дискету в приводе ГД и не смогла проверить легальность копии.

Процедура ProtCheck начинает работу с проверки поля Hard в глобальной типизированной константе Key. Это поле используется для анализа стационарности программы: если поле имеет значение 0, реализуется контроль мобильного варианта, в противном случае – стационарного варианта (установка поля Hard и всей константы Key осуществляется с помощью функции SetOnHD, см. ниже).

При контроле мобильного варианта программа пытается прочитать сначала на диске А, а если это не удается – на диске В ключевой сектор (первый сектор на нулевой поверхности дорожки номер 81) размером 256 байт. Этот сектор должен содержать следующую информацию:

1-й байт – ключ для шифровки содержимого сектора с помощью операции XOR;

17-й байт – количество уже созданных стационарных копий;

200-й байт – максимальное количество стационарных копий (если 255 - количество копий не ограничено);

256-й байт – контрольная сумма со 2-го по 255-й байт.

Если поле Hard константы Key содержит нулевое значение, осуществляется контроль стационарного варианта. В этом случае поле Dat содержит эталон даты создания ПЗУ, а поле Hard используется как ключ для шифровки этого поля с помощью операции XOR.

Если контроль стационарного варианта дает отрицательный результат (нелегальная копия), автоматически осуществляется анализ мобильного варианта (контроль дискеты). Таким образом, любая копия программы гарантированно работает, если в распоряжении пользователя есть ключевая дискета. Однако после правильной установки программы на жесткий диск с помощью процедуры SetOnHD программа может работать и без этой дискеты до тех пор, пока она не будет перенесена на новый компьютер, дата создания ПЗУ которого отличается от эталонной.

Для правильного создания стационарной копии программы используется функция SetOnHD, имеющая следующий заголовок:

FunctionSetOnHD: Integer;

Перед использованием функции SetOnHD необходимо любыми стандартными для ДОС средствами скопировать программу в один из каталогов жесткого диска. Эта функция вызывается в такой «нелегальной» копии, перед этим в любой привод ГД необходимо вставить ключевую дискету со снятой защитой от записи. Результат, возвращаемый функцией, имеет следующий смысл:

1 – в привод ГД не вставлена дискета;

2 – в привод вставлена дискета не эталонного типа (не 1,44 Мб или нет скрытого сектора);

3 – дискета защищена от записи или при записи на нее возникла ошибка;

4 – данный вариант программы не скопирован предварительно на жесткий диск;

5 – ошибка доступа к жесткому диску (программа не может прочитать собственный файл или не может записать в него новое значение константы Key);

6 – исчерпан лимит стационарных копий;

7 – данная программа уже представляет собой стационарный вариант программы, т. е. константа Key в ней уже определена.

Любое неотрицательное значение результата свидетельствует об успешном создании стационарной копии и равно количеству еще не использованных установок программы на жесткий диск.

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

Функция RemoveFromHD осуществляет обратные действия: уничтожает текущую стационарную копию и соответствующим образом увеличивает запас неизрасходованных установок программы. Она возвращает одно из следующих значений:

1 – в привод ГД не вставлена дискета;

2 – в привод вставлена дискета неэталонного типа (емкостью не 1,44 Мб или нет скрытого сектора);

3 – дискета защищена от записи или при записи на нее возникла ошибка;

4 – данный вариант программы не скопирован предварительно на жесткий диск;

5 – ошибка доступа к жесткому диску (программа не может прочитать собственный файл или не может записать в него новое значение константы Key).

Любое неотрицательное значение свидетельствует об успешном удалении стационарной копии и равно количеству еще не использованных установок программы на жесткий диск.

Также прилагается программа TEST.EXE, которая иллюстрирует приемы работы с модулем F_Prot. Программа анализирует ключи запуска: если используется ключ /SET, осуществляется установка программы на жесткий диск, если ключ /REMOVE, уничтожается стационарная копия программы, если этих ключей нет в команде запуска, программа осуществляет контроль легальности копии. Ключевая дискета должна быть предварительно подготовлена с помощью программы Diskette.

Программа Diskette и модуль F_Prot используют модуль F_Disk, который предназначен для работы с диском на физическом уровне.


Заключение

В результате выполнения данного курсового проекта, был написан модуль для защиты программ от нелегального копирования. Данный модуль позволяет защищать как стационарные и мобильные варианты программ. Этот модуль подключается к программе, которую требуется защитить, и программа использует его функции. Если функция проверки легальности копии возвращает негативный результат, то, на свое усмотрение, программист может сделать так, чтобы программа или не запускалась или выводила предупреждающее сообщение и реализовывала не все свои возможности. Для защиты стационарного варианта программы используется проверка даты создания ПЗУ данного ПК, если она не равна эталонной, то копия считается нелегальной. Для защиты мобильного варианта программы на ключевой дискете была создана дорожка с секторами нестандартного размера. Первый сектор дорожки содержит информацию, о программе, защищаемой от нелегального копирования. Ключевая дискета была подготовлена с помощью программы Diskett. Для тестирования работы модуля была написана программа Test.exe. Она показала, что написанный модуль работает верно.


Список ссылок

1. Фаронов В.В. Турбо Паскаль (в 3-х книгах). Кн.3. Практика программирования. – М.: Учебно-инженерный центр «МВТУ – ФЕСТО ДИДАКТИК», 1993. – 304с.

2. Юров В., Хорошенко С. Ассемблер: учебный курс – СПб: Издательство «Питер», 2000. – 672с.

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; {Вспомогательная переменная}

DI:TDisk; {Информация о диске}

Dir:array[1..16] of Dir_Type; {Секторкаталога}

Clus:Word; {Текущий кластер каталога}

label

err;

begin

{Начальный этап: готовим путь к каталогу и диск}

if Path='' then {Если каталог текущий,}

GetDir(0,Path); {дополняем маршрутом поиска}

if Path[2]<>':' then {Если нет диска,}

Disk:=GetDefaultDrv {берем текущий}

else

begin {Иначе проверяем имя диска}

Disk:=GetDiskNumber(Path[1]);

if Disk=255 then

begin {Недействительное имя диска}

Err: {Точка входа при неудачном поиске}

Dirs:=0; {Нет сектора}

Disk_Error:=True; {Флаг ошибки}

Disk_Status:=$FFFF; {Статус $FFFF}

exit

end;

Delete(Path,1,2) {Удаляемимядискаизпути}

end;

{Готовимциклпоиска}

if Path[1]='\' then {Удаляемсимволы \}

Delete(Path,1,1); {вначале}

if Path[Length(Path)]='\' then

Delete(Path,Length(Path),1); {иконцемаршрута}

GetDiskInfo(Disk,DI);

with DI do

begin

Dirs:=RootLock; {Сектор с каталогом}

DirSize:=RootSize {Длинакаталога}

end;

ReadSector(Disk,Dirs,1,Dir); {Читаемкорневойкаталог}

Clus:=GetCluster(Disk,Dirs); {Кластерначалакаталога}

{Цикл поиска по каталогам}

Find:=Path=''; {Path='' - конец маршрута}

while not Find do

begin

{Получаемв S первоеимядосимвола \}

s:=Path;

if pos('\',Path)<>0 then

s[0]:=chr(pos('\',Path)-1);

{Удаляем выделенное имя из маршрута}

Delete(Path,1,Length(s));

if Path[1]='\' then

Delete(Path,1,1); {Удаляем разделитель \}

{Готовим массив имени}

FillChar(m,11,' ');

move(s[1],m,ord(s[0]));

{Просмотр очередного каталога}

k:=0; {Количество просмотренных элементов каталога}

j:=1; {Текущий элемент в Dir}

repeat {Цикл поиска в каталоге}

if Dir[j].Name[1]=#0 then {Еслиимя}

Goto Err; {Начинается с 0 - это конец каталога}

if Dir[j].FAttr=Directory 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 {Исчерпансекторкаталога}

j:=1; {Продолжаем с 1-го элемента следующего сектора}

inc(k,16); {k - сколько элементов просмотрели}

if k>=DirSize then

goto Err; {Дошлидоконцакаталога}

if (k div 16) mod DI.ClusSize=0 then

begin {Исчерпан кластер - ищем следующий}

{Получаем новый кластер}

Clus:=GetFATItem(Disk,Clus);

{Можно не проверять на конец цепочки,

т. к. каталог еще не исчерпан}

{Получаемновыйсектор}

Dirs:=GetSector(Disk,Clus)

end

else {Очередной сектор - в текущем кластере}

inc(Dirs);

ReadSector(Disk,Dirs,1,Dir);

end

until Find;

{Найден каталог для очередного имени в маршруте}

Clus:=Dir[j].FirstC; {Кластерначала}

Dirs:=GetSector(Disk,Clus); {Сектор}

ReadSector(Disk,Dirs,1,Dir);

Find:=Path='' {Продолжаемпоиск, еслинеисчерпанпуть}

end {while not Find}

end; {GetDirSector}

{---------------}

procedure ReadWriteSector(Disk:Byte;

Sec:LongInt;Nsec:Word;var Buf;Op:Byte);forward;

procedure GetDiskInfo(Disk:Byte;var DiskInfo:TDisk);

{Возвращает информацию о диске DISK}

var

Boot:TBoot;

IO:IOCTL_Type;

p:PListDisk;

label

Get;

begin

Disk_Error:=False;

if (Disk<2) or (Disks=NIL) then

goto Get; {Не искать в списке, если дискета или нет списка}

{Ищем в списке описателей}

p:=Disks;

while (p^.DiskInfo.Number<>Disk) and (p^.NextDisk<>NIL) do

p:=p^.NextDisk; {Если не тот номер диска}

if p^.DiskInfo.Number=Disk then

begin {Найден нужный элемент - выход}

DiskInfo:=p^.DiskInfo;

exit

end;

{Формируем описатель диска с птмощью вызова IOCTL}

Get:

IO.BuildBPB:=True; {Требуем построить ВРВ}

GetIOCTLInfo(Disk,IO); {Получаем информацию}

if Disk_Error then

exit;

with DiskInfo, IO do {Формируемописатель}

begin

Number:=Disk;

TypeD:=TypeDrv;

AttrD:=Attrib;

Cyls:=Cylindrs;

Media:=BPB.Media;

SectSize:=BPB.SectSiz;

TrackSiz:=Add.TrkSecs;

TotSecs:=BPB.TotSecs;

if TotSecs=0 then

begin

ReadWriteSector(Number,0,1,Boot,2); {Дискбольшойемкости}

TotSecs:=Boot.Add.LargSectors; {Читаемзагрузочныйсектор}

end;

Heads:=Add.HeadCnt;

Tracks:=(TotSecs+pred(TrackSiz)) div (TrackSiz*Heads);

ClusSize:=BPB.ClustSiz;

FATLock:=BPB.ResSecs;

FATCnt:=BPB.FatCnt;

FATSize:=BPB.FatSize;

RootLock:=FATLock+FATCnt*FATSize;

RootSize:=BPB.RootSiz;

DataLock:=RootLock+(RootSize*SizeOf(Dir_Type)) div SectSize;

MaxClus:=(TotSecs-DataLock) div ClusSize+2;

FAT16:=(MaxClus>4086) and (TotSecs>20790)

end

end; {GetDiskinfo}

{----------------}

function GetDiskNumber(c:Char):Byte;

{Преобразует имя диска A...Z в номер 0...26.

Если указано недействительное имя, возвращает 255}

var

DrvNumber:Byte;

begin

if UpCase(c) in ['A'..'Z'] then

DrvNumber:=ord(UpCase(c))-ord('A')

else

DrvNumber:=255;

if DrvNumber>GetMaxDrv then

DrvNumber:=255;

GetDiskNumber:=DrvNumber;

end; {GetDiskNumber}

{---------------------}

function GetFATItem(Disk:Byte;Item:Word):Word;

{Возвращает содержимое указанного элемента FAT}

var

DI:TDisk;

k,j,n:Integer;

Fat:record

case Byte of

0: (w:array[0..255] of Word);

1: (b:array[0..512*3-1] of Byte);

end;

begin

GetDiskInfo(Disk,DI);

if not Disk_Error then with DI do

begin

if (Item>MaxClus) or (Item<2) then

Item:=$FFFF {Задан ошибочный номер кластера}

else

begin

if FAT16 then

begin

k:=Item div 256; {Нужный сектор FAT}

j:=Item mod 256; {Смещение в секторе}

n:=1 {Количество читаемых секторов}

end

else

begin

k:=Item div 1024; {Нужная тройка секторов FAT}

j:=(3*Item) shr 1-k*1536; {Смещение в секторе}

n:=3 {Количество читаемых секторов}

end;

{Читаем 1 или 3 сектора FAT}

ReadSector(Disk,FATLock+k*n,n,Fat);

if not Disk_Error then

begin

if FAT16 then

Item:=Fat.w[j]

else

begin

n:=Item; {Старое значение Item для проверки четности}

Item:=Fat.b[j]+Fat.b[j+1] shl 8;

if odd(n) then

Item:=Item shr 4

else

Item:=Item and $FFF;

if Item>$FF6 then

Item:=$F000+Item

end;

GetFatItem:=Item

end

end

end

end; {GetFATItem}

{------------------}

procedure GetIOCTLInfo(Disk:Byte;var IO:IOCTL_Type);

{Получаем информацию об устройстве согласно общему вызову IOCTL}

begin

with Reg do

begin

ah:=$44; {Функция 44}

al:=$0D; {Общийвызов IOCTL}

cl:=$60; {Дать параметры устройства}

ch:=$8; {Устройство - диск}

bl:=Disk+1; {Диск 1=А,...}

bh:=0;

ds:=seg(IO);

dx:=ofs(IO);

Intr($21,Reg);

Output

end

end; {GetIOCTLInfo}

{-------------------}

procedure GetListDisk(var List:PListDisk);

{Формирует список дисковых описателей}

var

Disk:Byte;

DI:TDisk;

P,PP:PListDisk;

begin

Disk:=2; {Начать с диска С:}

List:=NIL;

repeat

GetDiskInfo(Disk,DI);

if not Disk_Error then

begin

New(P);

if List=NIL then

List:=P

else

PP^.NextDisk:=P;

with P^ do

begin

DiskInfo:=DI;

NextDisk:=NIL;

inc(Disk);

PP:=P

end

end

until Disk_Error;

Disk_Error:=False

end; {GetListDisk}

{---------------------}

procedure GetMasterBoot(var Buf);

{Возвращаетвпеременной Buf главныйзагрузочныйсектор}

begin

GetAbsSector($80,0,1,Buf)

end; {GetMasterBoot}

{--------------------}

function GetMaxDrv:Byte;

{Возвращает количество логических дисков}

const

Max:Byte=0;

begin

if Max=0 then with Reg do

begin

ah:=$19;

MSDOS(Reg);

ah:=$0E;

dl:=al;

MSDOS(Reg);

Max:=al

end;

GetMaxDrv:=Max

end; {GetMaxDrv}

{-------------------}

function GetSector(Disk:Byte;Cluster:Word):Word;

{Преобразуем номер кластера в номер сектора}

var

DI:TDisk;

begin

GetDiskInfo(Disk,DI);

if not Disk_Error then with DI do

begin

Disk_Error:=(Cluster>MaxClus) or (Cluster<2);

if not Disk_Error then

GetSector:=(Cluster-2)*ClusSize+DataLock

end;

if Disk_Error then

GetSector:=$FFFF

end; {GetSector}

{----------------------}

function PackCylSec(Cyl,Sec:Word):Word;

{Упаковывает цилиндр и сектор в одно слово для прерывания $13}

begin

PackCylSec:=Sec+(Cyl and $300) shr 2+(Cyl shl 8)

end; {PackCylSec}

procedure ReadWriteSector(Disk:Byte;

Sec:LongInt;NSec:Word; var Buf; Op:Byte);

{Читает или записывает сектор (секторы):

Ор = 0 - читать; 1 - записать (малый диск)

= 2 - читать; 3 - записать (большой диск)}

type

TBuf0=record

StartSec:LongInt;

Secs:Word;

AdrBuf:Pointer

end;

var

Buf0:TBuf0;

S:Word;

O:Word;

begin

if Op>1 then with Buf0 do

begin

{Готовим ссылочную структуру для большого диска}

AdrBuf:=Ptr(Seg(Buf),Ofs(Buf));

StartSec:=Sec;

Secs:=NSec;

S:=Seg(Buf0);

O:=Ofs(Buf0);

asm

mov CX,$FFFF

mov AL,Op

shr AX,1

mov AL,Disk

push DS

push BP

mov BX,O

mov DS,S

jc @1

int 25H

jmp @2

@1: int 26H

@2: pop DX

pop BP

pop DS

mov BX,1

jc @3

mov Bx,0

xor AX,AX

@3: mov Disk_Error,BL

mov Disk_Status,AX

end

end

else {Обращение к диску малой емкости}

asm

mov DX,Word Ptr Sec {DX:=Sec}

mov CX,NSec {CX:=NSec}

push DS {Сохраняем DS - он будет испорчен}

push BP {Сохраняем BP}

lds BX,Buf {DS:BX - адрес буфера}

mov AL,Op {AL:=Op}

shr AX,1 {Переносим младший бит Oр в CF}

mov AL,Disk {AL:=Disk}

jc @Write {Перейти, если младший бит Ор<>0}

int 25H {Читаем данные}

jmp @Go {Обойти запись}

@WRITE:

int 26H {Записываем данные}

@GO:

pop DX {Извлекаем флаги из стека}

pop BP {Восстанавливаем BP}

pop DS {Восстанавливаем DS}

mov BX,1 {BX:=True}

jc @Exit {Перейти, если была ошибка}

mov BX,0 {BX:=False}

xor AX,AX {Обнуляем код ошибки}

@EXIT:

mov Disk_Error,BL {Флаг ошибки взять из BX}

mov Disk_Status,AX {Код ошибки взять из AX}

end

end; {ReadWriteSector}

{------------------------}

procedure ReadSector(Disk:Byte;Sec:LongInt;NSec:Word;var Buf);

{Читает сектор(секторы) на указанном диске}

var

DI:TDisk;

begin

GetDiskInfo(Disk,DI);

if DI.TotSecs>$FFFF then {Дискбольшойемкости?}

ReadWriteSector(Disk,Sec,Nsec,Buf,2) {-Да: операция 2}

else

ReadWriteSector(Disk,Sec,Nsec,Buf,0) {-Нет: операция 0}

end; {ReadSector}

{------------------------}

procedure SetAbsSector(Disk,Head:Byte;CSec:Word;var Buf);

{Записывает абсолютный дисковый сектор с помощью прерывания $13}

begin

with Reg do

begin

ah:=3; {Операциязаписи}

dl:=Disk; {Номер привода}

dh:=Head; {Номер головки}

cx:=CSec; {Цилиндр/сектор}

al:=1; {Читаем один сектор}

es:=seg(Buf);

bx:=ofs(Buf);

Intr($13,Reg);

Output

end

end; {SetAbsSector}

{------------------}

procedure SetDefaultDrv(Disk:Byte);

{Устанавливаетдискпоумолчанию}

begin

if Disk<=GetMaxDrv then with Reg do

begin

AH:=$E;

DL:=Disk;

MSDOS(Reg)

end

end;

{---------------------}

procedure SetFATItem(Disk:Byte;Cluster,Item:Word);

{Устанавливаем содержимое ITEM в элемент CLUSTER таблицы FAT}

var

DI:TDisk;

k,j,n:Integer;

Fat:record

case Byte of

0:(w: array[0..255] of Word);

1:(b: array[0..512*3-1] of Byte);

end;

begin

GetDiskInfo(Disk,DI);

if not Disk_Error then with DI do

begin

if (Cluster<=MaxClus) and (Cluster>=2) then

begin

if FAT16 then

begin

k:=Cluster div 256; {Нужныйсектор FAT}

j:=Cluster mod 256; {Смещение в секторе}

n:=1

end

else

begin

k:=Cluster div 1024; {Нужнаятройкасекторов FAT}

j:=(3*Cluster) shr 1-k*1536;

n:=3

end;

ReadSector(Disk,FatLock+k*n,n,Fat);

if not Disk_Error then

begin

if FAT16 then

Fat.w[j]:=Item

else

begin

if odd(Cluster) then

Item:=Item shl 4+Fat.b[j] and $F

else

Item:=Item+(Fat.b[j+1] and $F0) shl 12;

Fat.b[j]:=Lo(Item);

Fat.b[j+1]:=Hi(Item)

end;

if not FAT16 then

begin {Проверяем "хвост" FAT}

k:=k*n; {к - смещение сектора}

while k+n>FatSize do dec(n)

end;

inc(FATLock,k); {FATLock - номерсекторав FAT}

{Записываем изменение в FatCnt копий FAT}

for k:=0 to pred(FatCnt) do

WriteSector(Disk,FATLock+k*FatSize,n,Fat)

end

end

end

end; {SetFATItem}

{----------------------}

procedure SetMasterBoot(var Buf);

{Записываемвглавныйзагрузочныйсекторсодержимое Buf}

begin

with Reg do

begin

ah:=3; {Операциязаписи}

al:=1; {Кол-во секторов}

dl:=$80; {1-й жесткий диск}

dh:=0; {Головка 0}

cx:=1; {1-й сектор 0-й дорожки}

es:=seg(Buf);

bx:=ofs(Buf);

Intr($13,Reg);

Disk_Error:=(Flags and FCarry<>0);

if Disk_Error then

Disk_Status:=ah

else

Disk_Status:=0

end

end; {SetMasterBoot}

{---------------------}

procedure UnpackCylSec(CSec:Word;var Cyl,Sec:Word);

{Декодируем цилиндр и сектор для прерывания $13}

begin

Cyl:=(CSec and 192) shl 2+CSec shr 8;

Sec:=CSec and 63

end; {RecodeCylSec}

{----------------------}

procedure WriteSector(Disk:Byte;Sec:LongInt;NSec:Word;var Buf);

{Записывает сектор (секторы) на указанный диск}

var

DI:TDisk;

begin

GetDiskInfo(Disk,DI);

if DI.TotSecs>$FFFF then

ReadWriteSector(Disk,Sec,Nsec,Buf,3)

else

ReadWriteSector(Disk,Sec,Nsec,Buf,1);

end; {ReadSector}

{=============} end. {Unit F_Disk} {==============}

2 ТЕКСТМОДУЛЯ F_PROT

{==================} Unit F_Prot; {=======================}

{

+----------------------------------------------+

| Модуль используется для защиты программ от |

| нелегального копирования. Мобильный вариант |

| программы защищается с помощью ключевой ди- |

| скеты, стационарный вариант - за счет кон- |

| тролядатысозданияПЗУ. |

+----------------------------------------------+}

INTERFACE

procedure ProtCheck(var P1,P2; var Res: Integer);

{Проверяет легальность копии:

Р1 - адрес процедуры NORMA; Р2 - адрес процедуры ALARM;

Res - результат работы:

0: был вызов NORMA;

1: был вызов ALARM;

2: не вставлена дискета.

Любое другое значение может быть только при трассировке программы}

function SetOnHD: Integer;

{Устанавливает копию на жесткий диск. Возвращает:

-1 - не вставлена дискета;

-2 - не мастер-дискета;

-3 - защита от записи или ошибка записи;

-4 - программа не скопирована на ЖД;

-5 - ошибка доступа к ЖД;

-6 - исчерпан лимит установок;

-7 - программа уже установлена;

>=0 - количество оставшихся установок}

function RemoveFromHD: Integer;

{Удаляет копию с жесткого диска. Возвращает:

-1 - не вставлена дискета;

-2 - не мастер-дискета;

-3 - защита от записи или ошибка записи ГД;

-4 - программа не скопирована на ЖД;

-5 - ошибка доступа к ЖД;

>=0 - количество оставшихся установок}

IMPLEMENTATION

Uses DOS, F_Disk;

type

TDate=array[1..4] of Word;

TKey=record case Byte of

0:(

Hard: Word; {Ключ для шифровки данных}

Dat: TDate); {Дата создания ПЗУ}

1:(KeyW: array[1..5] of Word);

end;

const

TRK=80; {Номердорожки}

HED=0; {Номерголовки}

SEC=1; {Номер сектора}

SIZ=1; {Код размера секторов}

ETracks=80; {Эталонное количество дорожек на дискете}

ETrackSiz=18; {Эталонное количество секторов на дорожке}

Key:TKey=(KeyW:(0,0,0,0,0)); {Ключ стационарной программы}

{----------------}

type

TBuf=array[1..256] of Byte;

var

P:Pointer; {Ссылка на прежнюю ТПД}

Bif:TBuf; {Буфер чтения/записи сектора}

R:registers; {Регистры}

{----------------}

function DiskettPrepare(var DSK: Byte):Boolean;

type

DBT_Type=record {Структура таблицы параметров дискеты}

Reserv1:array[0..2] of Byte;

SizeCode:Byte; {Код размера сектора}

LastSect:Byte; {Количество секторов на дорожке}

Reserv2:array[5..10] of Byte

end;

var

Info: TDisk;

DBT,OldDBT:^DBT_Type;

begin

{проверяем наличие дискеты}

DSK:=0; {начинаем с диска А:}

repeat

GetDiskInfo(DSK,Info);

if Disk_Error then

if DSK=0 then

DSK:=1 {Повторяем для диска В:}

else

DSK:=2 {Закончить с ошибкой}

until not Disk_Error or (DSK=2);

if Disk_Error then

begin {Нет доступа ни к А:, ни к В:}

DiskettPrepare:=False;

Exit

end;

{проверяемтипдискеты}

with Info do

begin

if(Tracks<>ETracks) or

(TrackSiz<>ETrackSiz) then

begin {Неэталонныйтип}

DiskettPrepare:=False;

DSK:=3;

Exit

end;

{ПереустанавливаемТПД}

GetIntVec($1E,P);

OldDBT:=P;

New(DBT);

DBT^:=OldDBT^;

with DBT^ do

begin

SizeCode:=SIZ;

LastSect:=ETrackSiz

end;

SetIntVec($1E,DBT)

end;

DiskettPrepare:=True

end; {DiskettPrepare}

{----------------}

function LegalDiskett(var DSK:Byte):Boolean;

{Проверяет легальность мобильной копии}

var

k,n:Word;

begin

{Подготавливаемдискету}

if DiskettPrepare(DSK) then

begin

{читаемключевойсектор}

for k:=1 to 256 do

bif[k]:=0;

With R do

begin

ah:=0;

dl:=DSK;

Intr($13,R);

ah:=2;

al:=1;

ch:=TRK;

cl:=SEC;

dh:=HED;

dl:=DSK;

es:=seg(Bif);

bx:=ofs(Bif);

Intr($13,R);

ah:=0;

dl:=DSK;

Intr($13,R);

SetIntVec($1E,P);

if (Flags and FCarry)<>0 then

begin

LegalDiskett:=False;

DSK:=4;

Exit

end

else

begin {проверяем содержимое сектора}

for k:=2 to 256 do

Bif[k]:=Bif[k] xor Bif[1];

N:=0;

{$R-}

for k:=2 to 255 do

N:=N+Bif[k];

if (N mod 256=Bif[256]) then

begin

if N=0 then

begin

DSK:=4;

LegalDiskett:=False;

Exit

end;

DSK:=0;

LegalDiskett:=True

end

else

begin

DSK:=4;

LegalDiskett:=False

end

end

end

end

else

LegalDiskett:=False

end; {LegalDiskett}

function LegalHD(var DSK: Byte): Boolean;

{проверяет легальность стационарной копии}

var

k:Word;

Date:^TDate;

Legal:Boolean;

label

ExitL;

begin

{Расшифровываемключ}

with Key do for k:=2 to 5 do

KeyW[k]:=KeyW[k] xor KeyW[1];

{Проверяем дату изготовления ПЗУ}

k:=1;

Date:=ptr($F000,$FFF5);

repeat

Legal:=Date^[k]=Key.Dat[k];

inc(k)

until not Legal or (k=5);

LegalHD:=Legal;

{проверяемдискету}

if Legal then

DSK:=0

else

Legal:=LegalDiskett(DSK);

LegalHD:=Legal

end;

{----------------}

procedure ProtCheck(var P1,P2;var Res:Integer);

{Проверяет легальность копии:

Р1 - адрес процедуры NORMA; Р2 - адрес процедуры ALARM;

Res - результат работы:

0: был вызов NORMA;

1: был вызов ALARM;

2: не вставлена дискета.

Любое другое значение может быть только при трассировке программы}

type

PType = Procedure;

var

Norma: PType absolute P1;

Alarm: PType absolute P2;

DSK: Byte;

label

L1,L2;

begin

Res:=-1;

if Key.Hard=0 then

if LegalDiskett(DSK) then

begin

L1:

Norma;

Res:=0

end

else

begin

L2:

if DSK=2 then

Res:=2

else

begin

Alarm;

Res:=1

end

end

else

if LegalHD(DSK) then

goto L1

else

goto L2

end; {ProtCheck}

{---------------}

Procedure HidnSec(var Buf:TBuf;Inst,Limit:Byte);

{Шифрует буфер ключевого сектора}

var

k,n:Word;

begin

Randomize;

for k:=2 to 254 do

Buf[k]:=Random(256);

Buf[1]:=Random(255)+1; {Ключдляшифровки}

{$R-}

Buf[17]:=Inst; {Счетчикустановок}

Buf[200]:=Limit; {Лимитустановок}

n:=0; {ПодсчетКС}

for k:=2 to 255 do

n:=n+Buf[k];

Buf[256]:=n mod 256; {Контрольная сумма}

{Шифруемвседанные}

for k:=2 to 256 do

Buf[k]:=Buf[k] xor Buf[1];

{$R+}

end; {HidnSec}

{-----------------}

Function SetOnHD: Integer;

{Устанавливает стационарную копию на жесткий диск. Возвращает:

-1 - не вставлена дискета;

-2 - не мастер-дискета;

-3 - защита от записи или ошибка записи ГД;

-4 - программа не скопирована на ЖД;

-5 - ошибка доступа к ЖД;

-6 - исчерпан лимит установок;

-7 - программа уже установлена.

>=0 - количество оставшихся установок}

var

DSK:Byte; {Диск}

F:file; {Файл с программой}

Date:^TDate; {Дата ПЗУ}

NameF:String; {Имя файла с программой}

W:array[1..5] of Word; {Заголовокфайла}

n:Word; {Счетчик}

L:LongInt; {Файловоесмещение}

Inst:Byte; {Количествоустановок}

label

ErrWrt;

begin

if Key.Hard<>0 then

begin

SetOnHD:=-7;

Exit

end;

{проверяем резидентность программы}

NameF:=FExpand(ParamStr(0));

if NameF[1] in ['A','B'] then

begin

SetOnHD:=-4;

Exit

end;

{проверяемдискету}

if not LegalDiskett(DSK) then

begin

case DSK of

2: SetOnHD:=-1;

else

SetOnHD:=-2;

end;

Exit

end;

if (Bif[200]<>255) and (Bif[17]>=Bif[200]) then

begin {Исчерпанлимитустановок}

SetOnHD:=-6;

Exit

end;

{Запоминаем дату изготовления ПЗУ}

Date:=ptr($F000,$FFF5);

Key.Dat:=Date^;

{Шифруемпараметры}

Randomize;

with Key do

while Hard=0 do Hard:=Random($FFFF);

for n:=2 to 5 do with Key do

KeyW[n]:=KeyW[n] xor Hard;

{Открываем файл с программой}

Assign(F,NameF);

Reset(F,1);

{Читаем заголовок файла}

BlockRead(F,W,SizeOf(W),n);

if n<>SizeOf(W) then

begin

SetOnHD:=-5;

Exit

end;

{Ищемвфайлеположение Hard}

R.ah:=$62;

MSDOS(R);

P:=@Key;

L:=round((DSeg-R.bx-16+W[5])*16.0)+ofs(P^);

Seek(F,L);

{Записываем в файл}

BlockWrite(F,Key,SizeOf(Key),n);

if n<>SizeOf(Key) then

begin

SetOnHD:=-5;

Close(F);

Exit

end;

{Шифруемключевойсектор}

Inst:=Bif[200]-Bif[17]-1;

HidnSec(Bif,Bif[17]+1,Bif[200]);

{записываем на дискету новый ключ}

ifnotDiskettPrepare(DSK) then

begin {Ошибка доступа к дискете: удаляем установку}

ErrWrt:

FillChar(Key,SizeOf(Key),0);

Seek(F,L);

BlockWrite(F,Key,SizeOf(Key),n);

SetOnHD:=-3;

Close(F);

Exit

end;

with R do

begin

ah:=0;

dl:=DSK;

Intr($13,R);

ah:=3;

al:=1;

ch:=TRK;

cl:=SEC;

dh:=HED;

dl:=DSK;

es:=seg(Bif);

bx:=ofs(Bif);

Intr($13,R);

if(Flags and FCarry)<>0 then

goto ErrWrt

end;

{Нормальное завершение}

SetOnHD:=Inst;

SetIntVec($1E,P);

Close(F)

end; {SetOnHD}

{----------------}

function RemoveFromHD: Integer;

{Удаляет стационарную копию. Возвращает:

-1 - не вставлена дискета;

-2 - не мастер-дискета;

-3 - защита от записи или ошибка записи ГД;

-4 - программа не скопирована на ЖД;

-5 - ошибка доступа к ЖД;

>=0 - количество оставшихся установок}

var

k,n:Integer;

NameF:String;

B:array[1..512] of Byte;

F:file;

DSK,Inst:Byte;

begin

if Key.Hard=0 then

begin

RemoveFromHD:=-4;

Exit

end;

if not LegalDiskett(DSK) then

begin

if DSK=2 then

RemoveFromHD:=-1

else

RemoveFromHD:=-2;

Exit

end;

{СтираемфайлспрограммойнаЖД}

NameF:=FExpand(ParamStr(0));

if NameF[1] in ['A'..'B'] then

begin

RemoveFromHD:=-4;

Exit

end;

Assign(F,NameF);

{$I-}

Reset(F,1);

{$I+}

if IOResult<>0 then

begin

RemoveFromHD:=-5;

Exit

end;

{Уничтожаемзаголовокфайла}

FillChar(B,512,0);

BlockWrite(F,B,512,n);

if n<>512 then

begin

RemoveFromHD:=-5;

Exit

end;

Close(F);

Erase(F); {Стеретьфайл}

{Шифруемключевойсектор}

Inst:=Bif[200]-Bif[17]+1;

HidnSec(Bif,Bif[17]-1,Bif[200]);

{Записываем на дискету новый ключ}

if not DiskettPrepare(DSK) then

begin

RemoveFromHD:=-1;

Exit

end;

with R do

begin

ah:=0;

dl:=DSK;

Intr($13,R);

ah:=3;

al:=1;

ch:=TRK;

cl:=SEC;

dh:=HED;

dl:=DSK;

es:=seg(Bif);

bx:=ofs(Bif);

Intr($13,R);

if (Flags and FCarry)<>0 then

RemoveFromHD:=-3

else

RemoveFromHD:=Inst

end;

end; {RemoveFormHD}

{==================} end. {F_Prot} {=======================}

3 ТЕКСТПРОГРАММЫ DISKETT

{

+--------------------------------------------------------+

| Форматирование дорожки нестандартными секторами с помо-|

| щью прерывания $13. Эта программа готовит дискету для |

| работы с модулем F_Prot. |

+--------------------------------------------------------+}

Program Diskett;

Uses DOS, F_disk;

const

TRK=80; {Номер нестандартной дорожки}

DSK=0; {Номер диска}

SIZ=1; {Код размера сектора}

type

PDBT_Type=^DBT_Type; {Указатель на ТПД}

{Таблица параметров дискеты}

DBT_Type=record

Reserv1 : array [0..2] of Byte;

SizeCode: Byte; {Кодразмерасектора}

LastSect: Byte; {Количество секторов на дорожке}

Reserv2 : array [5..7] of Byte;

FillChar: Char; {Символ-заполнитель форматирования}

Reserv3 : Word

end;

{Элемент буфера форматирования}

F_Buf=record

Track:Byte; {Номердорожки}

Head:Byte; {Номерголовки}

Sect:Byte; {Номерсектора}

Size:Byte {Кодразмера}

end;

var

Old: PDBT_Type; {Указатель на исходную ТПД}

{-------------------}

Procedure Intr13(var R: registers; S: String);

{Обращается к прерыванию 13 и анализирует ошибку (CF=1 - признак ошибки).

Если ошибка обнаружена, печатает строку S и завершает работу программы}

begin

Intr($13, R);

if R.Flags and FCarry<>0 then

if R.ah<>6 then {Игнорируем ошибку от смены типа дискеты}

begin

WriteLn(S);

SetIntVec($1E, Old); {ВосстанавливаемстаруюТПД}

Halt

end

end; {Intr13}

Function AccessTime(DSK,TRK: Byte):Real;

{Измеряет время доступа к дорожке и возвращает его своим результатом (в секундах)}

var

E: array [1..18*512] of Byte;

t,k: LongInt;

R: registers;

begin

t:=MemL[0:$046C];

while t=MemL[0:$046C] do;

for k:=1 to 10 do with R do

begin

ah:=2;

al:=9;

ch:=TRK;

cl:=1;

dh:=0;

dl:=DSK;

es:=seg(E);

bx:=ofs(E);

Intr13(R, 'Error')

end;

AccessTime:=(MemL[0:$046C]-t-1)*0.055

end;

{--------------}

var

B: array [1..18] of F_Buf; {Буфердляформатирования}

k,N:Integer; {Счетчикцикла}

R:registers; {Регистры}

DBT:PDBT_Type; {УказательнановуюТПД}

C, D: array[1..1024] of Byte; {Буферчтения/записи}

Size: Word; {Длинасектора}

Info: TDisk;

begin {Главная программа}

{Проверяем доступ к диску и настраиваем драйвер}

GetDiskInfo(DSK, Info);

if Disk_Error then

begin

WriteLn('Ошибка доступа к диску');

Halt

end;

{Получаем длину сектора в байтах}

case SIZ of

0: Size:=128;

1: Size:=256;

2: Size:=512;

3: Size:=1024

else

WriteLn('Недопустимыйкоддлинысектора')

end;

{Корректируем таблицу параметров дискеты. Поскольку исходная ТПД может быть

в ПЗУ, делаем ее копию в ОЗУ и изменяем нужные элементы}

Old:=ptr(MemW[0:$1E*4+2],MemW[0:$1E*4]);

New(DBT);

DBT^:=Old^; {ПолучаемкопиюТПДвОЗУ}

SetIntVec($1E,DBT); {ИзменяемссылкунаТПД}

with DBT^ do

begin

SizeCode:=SIZ;

LastSect:=18;

FillChar:='+'

end;

with R do

begin

{Сбрасываемдисковод}

ax:=0;

dl:=DSK;

Intr13(R,'Ошибка доступа к диску');

{Готовим буфер форматирования с обратным фактором чередования секторов}

for k:=1 to 18 do {Для каждого из 18 секторов:}

with B[k] do

begin

Track:=TRK; {указываемномердорожки}

Head:=0; {номер головки}

Sect:=19-k; {номер сектора в обратной последовательности}

Size:=SIZ {и код размера}

end;

{Форматируем дорожку}

ah:=$05; {Код операции форматирования}

al:=18; {Создаем 18 секторов}

ch:=TRK; {на дорожке TRK}

cl:=1; {начиная с сектора 1}

dh:=0; {на поверхности 0}

dl:=DSK; {диска DSK}

es:=seg(B); {ES:BX - адрес буфера}

bx:=ofs(B);

Intr13(R,'Ошибка форматирования');

{Заполняем сектор случайными числами}

Randomize;

for k:=2 to 255 do

C[k]:=Random(256);

{Запрашиваем количество инсталяций на ЖД}

Write('Кол-во установок на ЖД: ');

ReadLn(C[200]);

C[17]:=0;

{Cчитываем контрольную сумму}

N:=0;

for k:=2 to 255 do

N:=N+C[k];

C[256]:=N mod 256;

{Шифруем сектор}

C[1]:=Random(255)+1;

for k:=2 to 256 do

C[k]:=C[k] xor C[1];

{Записываем сектор}

ah:=$03; {Код операции записи}

al:=1; {Записать 1 сектор}

ch:=TRK; {На дорожке TRK}

cl:=1; {Начиная с сектора 1}

dh:=0; {На поверхности 0}

dl:=DSK; {Диск DSK}

es:=seg(C);{Адрес буфера С для записи}

bx:=ofs(C);

Intr13(R,'Ошибка записи');

{Читаем сектор}

ah:=$02;

al:=1;

ch:=TRK;

cl:=1;

dh:=0;

dl:=DSK;

es:=seg(D); {Адрес буфера D для чтения}

bx:=ofs(D);

Intr13(R,'Ошибка чтения')

end;

{Проверяемсовпадение}

for k:=1 to Size do

if c[k]<>d[k] then

begin

WriteLn('Несовпадениеданных');

SetIntVec($1E,Old);

Halt

end;

WriteLn('Создана и проверена ',TRK+1,

'-я дорожка с секторами по ',Size,' байт');

{измеряем время доступа к новой дорожке}

Write('Время доступа к скрытой дорожке: ');

WriteLn(AccessTime(DSK,TRK):6:2,' c');

{измеряем время доступа к стандартной дорожке}

DBT^.SizeCode:=2; {Указываем стандартную длину сектора в ТПД}

Write('Доступ к обычной дорожке: ');

WriteLn(AccessTime(DSK,20):6:2,' c');

{Восстанавливаем старую ТПД}

SetIntVec($1E,Old)

end.

2 ТЕКСТ ПРОГРАММЫ TEXT.EXE

uses F_Prot,F_Disk;

procedure Alarm;Far;

begin

writeln('Нелегальнаякопия')

end;

procedure Norma;Far;

begin

writeln('Легальнаякопия')

end;

function ParStr:String;

var

S:string;

k:Byte;

begin

S:=ParamStr(1);

for k:=1 to Length(S) do S[k]:=UpCase(S[k]);

ParStr:=S

end;

var

p1,p2:Pointer;

d:Integer;

dsk:Byte;

begin

p1:=@Norma;

p2:=@Alarm;

if ParStr='/SET' then

Writeln('Установка на ЖД: ',SetOnHD)

else

if ParStr='/REMOVE' then

writeln('Удаление с ЖД: ',RemoveFromHD)

else

begin

ProtCheck(p1,p2,d);

Writeln('Результат проверки ',d);

readln

end

end.

Оценить/Добавить комментарий
Имя
Оценка
Комментарии:
Хватит париться. На сайте FAST-REFERAT.RU вам сделают любой реферат, курсовую или дипломную. Сам пользуюсь, и вам советую!
Никита14:59:25 04 ноября 2021
.
.14:59:23 04 ноября 2021
.
.14:59:21 04 ноября 2021
.
.14:59:20 04 ноября 2021
.
.14:59:18 04 ноября 2021

Смотреть все комментарии (22)
Работы, похожие на Курсовая работа: Защита программы от нелегального копирования

Назад
Меню
Главная
Рефераты
Благодарности
Опрос
Станете ли вы заказывать работу за деньги, если не найдете ее в Интернете?

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



Результаты(290432)
Комментарии (4189)
Copyright © 2005-2021 HEKIMA.RU [email protected] реклама на сайте