ZX-Ревю 1992 №11-12 1991 г.

Защита программ - заканчиваем печать третьего тома книги В.С. Михайленко, посвященной вопросам защиты программ для "Синклер"-совместимых компьютеров.


Темы статьи: Программирование  

ЗАЩИТА ПРОГРАММ

Сегодня мы заканчиваем печать третьего тома книги В.С. Михайленко, посвященной вопросам защиты программ для "Синклер"-совместимых компьютеров и переходим к четвертому тому, который написан в соавторстве с экспертом из Белорусского Государственного Университета (БГУ) А. К. Туровичем.

Полностью печать статей данного цикла будет завершена в 1993 году.

Продолжение.

(Начало: 9-16, 53-60, 97-104, 141-146, 185-192).

1.2 Смещение системной переменной PROG.

Многие из Вас, вероятно, не раз убеждались в справедливости принципа, "чем проще - тем надежнее". Этот принцип был известен издавна и не раз подтверждал себя на практике. Актуальным он является и для нас, потому что темой нашего разговора будет метод, основанный на смещении системной переменной PROG. Метод, на первый взгляд достаточно простой, но, тем не менее, достаточно эффективный. Рассмотрим более подробно принцип его применения для защиты компьютерных программ.

Как Вам уже, вероятно, известно, Бейсик, в стандартном "Спектруме (без подключенной периферии) начинается с адреса 23755. Об этой свидетельствует содержимое системной переменной PROG (23635). Таким образом, практически всегда Бейсик в компьютере начинается с одного и того же адреса памяти. Однако, такое положение вещей достаточно легко изменить, если осуществить изменение системной переменной PROG. Рассмотрим, что это нам дает.

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

Для начала вы создаете специальную программу в машинных кодах, которая осуществляет изменение системной переменной PROG. После этого Вам понадобится совместить ее с программой на Бейсике (о том, как это сделать, было подробно написано в т.1 гл.1). Конечно, можно достаточно просто изменить содержимое PROG и из Бейсика путем применения POKE, однако предпочтительней закамуфлировать выполненные операции, а еще лучше замаскировать адрес старта программы в кодах одним из методов, предложенных в т.1 гл. 4 (Напомню что основное предпочтение отдавалось там изменению содержимого числового значения, расположенного после управляющего кода 14). Заканчивает данную программу на Бейсике команда LOAD"".

Как Вы уже, вероятно, догадались, данная Бейсик-программа служит исключительно для подготовки к загрузке Вашей специальной программы-загрузчика. Причем Ваш загрузчик в машинных кодах ассемблирован таким образом, чтобы работать только в новой области (после изменения системной переменной PROG). Адрес старта загрузчика, вполне естественно, тоже будет замаскирован и будет указывать на точку расположения вашей исходной процедуры после изменения системной переменной. Теперь Вам осталось только совместить исходную программу в машинных кодах с новой Бейсик-программой и после выяснения адреса реального старта осуществить необходимые изменения чисел после функции RANDOMIZE USR.

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

просмотра.

После загрузки первой Бейсик-программы, она автоматически запускается и изменяет системную переменную PROG так, чтобы следующая Бейсик-программа загружалась уже в новую область. Такое изменение дает нам исключительную возможность правильно запустить Вашу программу-загрузчик в машинных кодах. Это объясняется тем, что ваша программа-загрузчик ассемблирована под новое значение системной переменной PROG и не будет работать, если не выполнить вышеописанных изменений.

Карта памяти компьютера до и после изменения системной переменной PROG показана на рис. 1.

Область экрана

Область системных переменных

(PROG)-

БЕЙСИК

Рис. 1 а

Область экрана

Область системных переменных

(PROG)-

БЕЙСИК

Рис. 1 б

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

Примечание: Разумеется, изменение системной переменной PROG само по себе уменьшает объем памяти, доступной для пользователя, однако это бывает оправдано, например, когда мы строим на этом методе защиту.

Любопытно, что системная переменная PROG изменяется принудительно, в случае подключения INTERFACE 1. в этом случае между областью системных переменных и Бейсиком размещаются системные переменные, необходиные для работы 8K ПЗУ INTERFACE 1.

На рисунке взятая в скобки надпись системной переменной PROG означает, что Бейсик начинается с ячейки памяти, адрес которой находится в системной переменной PROG.

Теперь вы видите, что если попробовать загрузить второй Бейсик-файл не изменяя PROG, то программа в кодах, размещенная там, не будет работать, аналогично, как не будет работать и обыкновенная программа в кодах, перемещенная из места, для которого она ассемблирована, в какое-либо иное место памяти. Для программистов, работающих в машинных кодах причина неработоспособности в подобном случае очевидна - не совладают адреса переходов при обычной адресации.

Небольшая историческая справка.

Когда взлом компьютерных программ только начинался, во многих программах Билла Гильберта, да и других "хаккеров" можно было встретить строку приблизительно следующего содержания:

0 LIST USR (PEEK 23635 + 256*PEEK 23636 +17)

которая собственно и должна была запускать встроенную программу в машинных

кодах. Очевидно, что LIST USR - это лишь одна из разновидностей команды RANDOMIZE USR (об этом уже было записано в главе "новейшие достижения защиты"). Как видно, программа в кодах запускалась с адреса на 17 байтов большего, чем тот, на который указывала системная переменная PROG. Четыре байта уходили на номер и длину строки, еще один - на код оператора REM. А остальное место до начала программы Гильберт любил заполнять своими инициалами. Удобство такой записи адреса старта процедуры в кодах заключалось в том, что она сама находила, где находится Бейсик-программа. Это было необходимо ввиду широкого распространения в то время ИНТЕРФЕЙСА 1 и микродрайвов, которые изменяли значение PROG. Кроме того, такая запись затрудняла пользователю прочтение реального адреса старта машинокодовой процедуры.

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

1.3 Кодирование и декодирование блоков машинных кодов.

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

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

Не вдаваясь в подробности, хочу напомнить читателям, что инструкция LDIR осуществляет перенос блоков кодов из одного места памяти в другое. Все необходимые значения для выполнения данной операции задаются заранее и заносятся в регистры микропроцессора. Для тех, кто интересуется работой данной команды процессора Z80 более подробно рекомендую книгу "ИНОФОРКОМа" "Первые шаги в машинных кодах".

Итак, каким же образом действует данная защита. Предположим, что исходная программа содержит два блока в машинных кодах. Один из них достаточно большой (порядка нескольких десятков килобайт), а второй небольших размеров (порядка нескольких килобайт или даже нескольких сот байтов).

B

A

A

Рис. 2

На рисунке изображены блоки кодов, из которых состоит исходная программа.

Стрелкой показано, что после загрузки второй блок занимает заранее отведенное ему место в памяти, после чего программа может нормально функционировать. Перемещение блоков кодов из одного места памяти в другое осуществляется с использованиеи инструкции LDIR.

На рис. 2 изображена технология осуществления защиты данного типа защиты. Сразу после запуска программы осуществляется перенос блоков кодов из одного места памяти в другое, после которого программа может нормально функционировать.

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

Одним из примеров программы, использующей данный принцип, защиты может служить программа GREEN BERET, загрузчик которой был достаточно подробно описан в четвертой главе второго тома.

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

Рассмотрим более подробно, как этого можно добиться.

Одним из наиболее широко используемых приемов является самая обыкновенная инверсия содержимого ячеек памяти.

Как Вы уже вероятно знаете, любое значение, содержащееся в определенной ячейке памяти можно представить десятиричным значением от 0 до 255, шестнадцатиричным значением от 0 до FF или двоичным значением 00000000 до 11111111. Для программиста все эти системы счисления альтернативны, хотя известно, что компьютер оперирует двоичными значениями числа, в то время как при программировании принято использовать шестнадцатиричную систему счисления (шестнадцатиричная система счисления - HEX система - является профессиональной системой счисления для программистов). Так вот, любое шестнадцатиричное число можно представить в двоичном виде, используя специальные таблицы. А процесс инверсии очень легко понять, используя двоичное представление. Инвертировать байт - это значит изменить содержимое каждого его бита на противоположное.

Например, байт 00 после инверсии превращается в байт FF:

0000 0000 - байт 00Н представленный в двоичном виде;

1111 1111 - после инверсии все значения данного байта заменяются на противоположные. Шестнадцатиричное значение данного двоичного числа FF.

Аналогично, байт 01010101 после инверсии преобразуется в 10101010 и т.д.

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

Однако кодирование инверсией, как Вы могли убедиться, является достаточно примитивным и поэтому настало время рассмотреть систему защиты, применяемую в большинстве фирменных программ (ART STUDIO, ATIC ATAC, NIGHT SHADE, THE WORD).

Рассмотрим эту систему зашифровки на примере программы "ART STUDIO".

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

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

Поскольку запуск программы начинается с адреса 26000, исследуем команды, расположенные начиная с этого адреса: 26000 JP 26024

Как видим, сразу осуществляется переход к процедуре декодирования. (В дальнейшем мы рассмотрим с Вами и процедуру кодирования, размещенную в данной программе в адресах 26003...26021).

26034 LD HL,26049

26027 PUSH HL

26028 LD HL,25049

26031 LD DE,26719

26034 LD A (HL)

26035 SUB 34

26037 RLCA

26038 XOR #CC

26040 LD (HL),A

26041 INC HL

26042 OR A

26043 SBC HL, DE

26045 ADD HL, DE

26046 JP NZ,26034

26048 RET

Данная процедура сначала помещает в стек значение адреса 26049 - сюда программа перейдет после выполнения команды RET.

После этого и начинается процесс декодирования; в регистр HL снова загружается адрес 26049 - как начало декодируемого блока. Затем в цикле декодируются последовательно байты загружаемого блока, причем инструкции: SUB 34 RLCA XOR #CC

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

Выполнение инструкции RET приводит не к возврату в Бейсик, а к переходу на адрес, который был последним занесен в стек - в нашем случае 26049. Следовательно, по этой инструкции происходит запуск на исполнение расшифрованного блока.

Следует отметить, что инструкции, осуществляющие дешифрацию, в ходе своей работы не теряют ни одного бита. Это необходимое условие для данного типа программ, поскольку кодированию и декодированию может подвергнуться практически любой байт от 00 до FF.

Теперь рассмотрим, каким образом можно осуществить декодирование данной программа, чтобы после возврата в Бейсик подробно изучить новообразующуюся часть программы. Для этого нам понадобится перестроить работу исходной программы так, чтобы на стек не попало значение 26049, а там оставалось последним значение возврата в бейсик-программу.

Для выполнения поставленной цели существуют два пути:

- либо уничтожить команду PUSH HL, заслав вместо нее код NOP, т.е. ноль.

- либо запустить программу после помещения на стек вышеуказанных значений, командой RANDOMIZE USR 26028. В этом случае мы возвратимся в Бейсик по выполнении инструкции RET.

Теоретически оба метода взаимозаменяемы и могут быть применены равноправно. Однако, на практике оказывается, что это не так. В частности, в программе ART STUDIO существует блок программы, проверяющий сохранность значений ячеек памяти в месте расположения декодирующей процедуры. Если он обнаружит изменение содержимого ячеек памяти, то программа зависнет.

Процедура проверки находится начиная с адреса 26283:

26263 LD Н,A

26284 LD L,A

26285 PUSH HL

26292 LD A,(26024)

26295 CP #21

26297 RET NZ 26298 LD HL,(26025)

26301 OR A

26302 LD DE, 26049

26305 SBC HL, DE

86307 RET NZ

26308 LD A,(26027)

26311 CP #E5

26313 RET NZ

26314 POP HL

26315 RET

Рассмотрим более подробно, как работает данная процедура.

Для начала мы помещаем 0 на стек, используя то, что содержимое аккумулятора равно 0. После этого осуществляется проверка байтов 26024-26027 (включительно) и, если обнаруживается несовпадение с тем, что там ожидал найти автор программы, то происходит возврат на 00, а это ничто иное, как перезапуск компьютера. Если же проверка прошла успешно, мы снимаем ноль со стека и возвращаемся в вызвавшую данную подпрограмму процедуру.

Теперь Вы видите, что менять содержимое ячейки POKE 26027,0 достаточно рискованно. Поэтому в данном случае лучше воспользоваться вторым предложенным вариантом, а на будущее запомнить, что возможность проверки работы защиты -достаточно частое явление в компьютерных программах.

Рассмотренные нами три примера, разумеется, не исчерпывают всех возможных вариантов кодирования. Каждый программист старается разработать свой собственный метод, как можно более изощренный. Однако, при подобной разработке Вам необходимо учитывать, что инструкции, осуществляющие шифрацию и дешифрацию, не должны терять в ходе своей работы ни одного бита. В программе ART STUDIO вычитание производится по модулю 256 и для двух разных входных данных результаты тоже различны. RLCA заменяет значение битов 7,6,3,2 на противоположные.

Другими операторами, имеющими аналогичные свойства, являются ADD, INC, DEC, RRCA, CPL и др.

Однако, в данном случае нельзя использовать функции OR или AND, поскольку Вам не удастся правильно восстановить содержимое исходной программы.

1.4 Новые POKES.

Многие программисты, длительное время работающие с компьютером, наверняка изучили большинство POKES, обычно применяемых для защиты компьютерных программ. Многие считают малоперспективным разрабатывать новые приемы защиты, основанные на этом направлении и пытаются создавать более изощренные приемы. Тем не менее, несмотря на свою давнюю историю, этот метод защиты компьютерных программ не следует предавать забвению.

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

Метод засылки в определенные ячейки памяти измененных значений (в большинстве случаев этими ячейками являются системные переменные) начал применяться с самого начала появления защиты компьютерных программ для "Спектрума". Он применялся как для защиты от нажатия клавиши "BREAK", так и от произвольного листинга. (См. т.1). Следует отметить, что в дальнейшем использование данной методики было сильно ограничено ввиду незначительного количества ячеек памяти, которые приводили к защитному эффекту. Это привело к тому, что практически вся информация о POKES быстро стала широким достоянием большого числа "хаккеров". По этой причине информация о новых POKES, имеющих "защитные" функции является тем козырем, который даст вам возможность охладить неумеренный пыл юных взломщиков. В этой статье я приведу информацию о двух ячейках памяти, изменяя содержимое которых, можно получить либо оригинальную защиту от листинга, либо защитить работающую программу от непредусмотренной остановки нажатием клавиши "BREAK". Несмотря на то, что эти методы различны по принципу действия, их объединяет то, что изменение содержимого ячеек памяти происходит в области системных переменных. Рассмотрим каждый из них более подробно.

1. POKE 23743,80 приводит к тому, что мы не можем получить на экране никакой информации, в том числе и листинга. Это объясняется тем, что мы изменили адрес программы вывода на основной экран компьютера. Тем не менее, адрес программы вывода с клавиатуры в нижнюю часть экрана остался прежним и поэтому мы можем вызвать в командную строку любую из строк исходной программы командой EDIT. Такая возможность несомненно является достаточно значительным дефектом эти защиты, однако это дело поправимое, поскольку для защиты от подобных ухищрений Вы можете аналогичным образом изменить и адрес программы вывода для этого канала.

В заключение лишь следует добавить, что для нормализации работы компьютера Вам необходимо набрать: POKE 23743,83

Эти изменения нормализуют работу канала и теперь Вы можете без труда ознакомиться с листингом.

Данный метод защиты был обнаружен мной в программе MASBLAST -1990.

2. РОКЕ 23613, РЕЕК (23700)-5 создает защиту от нажатия клавиши "BREAK" и приводит вначале к зависанию компьютера, а через несколько секунд к самосбросу.

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

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

Как видите, данные методы защиты основаны на использовании хорошо известных приемов РОКЕ и я уверен, что возможности данной методики еще далеко не исчерпаны и в будущем свое слово здесь скажете Вы, дорогие читатели.

1.5 Метод нулевых строк - новые возможности.

В данной статье разобран оригинальный метод защиты компьютерных программ к "Спектрум"-совместимым компьютерам. Подробные комментарии позволяют использовать этот материал не только как полезную процедуру, но и как пособие тем, кто самостоятельно изучает программирование на языке АССЕМБЛЕРА.

В первом томе (см. стр. 13) Вашему вниманию была предложена статья "Универсальная система защиты - метод нулевых строк". Несмотря на определенные достоинства, эта программа обладает целым рядом недостатков, которые в некоторых случаях могут нарушить работу Вашей исходной программы на Бейсике. Постараюсь объяснить причину возникающих в ходе работе программы "зануления" неточностей.

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

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

Я же, не вдаваясь в подробности, хочу отметить, что в этой пятибайтной последовательности чисел вполне может встретиться и число "13", однако в случае наличия его в пятибайтном числовом стринге, оно не должно анализироваться программой, как код "ENTER ", поскольку данный стринг является единым целым (компьютер определяет это по обнаружению управляющего кода "14"). Во всех остальных случаях число "13" должно восприниматься компьютером как код "ENTER".

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

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

С момента опубликования вышеуказанной статьи я продолжал работу над данной темой и пришел к ряду выводов, с некоторыми из которых хочу поделиться с читателями. Разработанная мной программа не "зануляет" первую строку Вашей программы, что несомненно осложняет ее использование. Кроме этого, стоит отметить, что решение, когда программа "зануления" располагается после исходной программы на Бейсике, не совсем удачно, так как:

- по-первых, выполнение программы "зануления" осуществляется на Бейсике, что существенно сказывается на ее быстродействии;

- во-вторых, почти всегда придется "занулять" все строки программы, а это не всегда необходимо;

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

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

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

- команда занимает в памяти меньше места на один байт;

- программа становится перемещаемой, то есть не зависит от своего места расположения в памяти.

Полученная программа приведена в Листинге 1. Рассмотрим принцип ее действия.

Листинг 1.

Programing by Michailenko Vadim.

All rights reserved. Mensk 1991.

Michailenko Vadim driver system

for "EDITAS-48" files special for "INFORCOM".

ORG 64130 LD BC,9990 LD HL,(23635) XOR A LD HL,(A) INC HL LD (HL), A

NEXT

CONT

XOR A LD (HL),0 INC HL LD (HL),0 JR NEXT

FINAL

INC HL LD A,(HL) CP C RET Z DEC HL JR CONT END

Сразу после начала работы в регистр BC заносится номер строки программы, до которой необходимо вести "зануление". Это значение можно изменять. Таким образом, Вы сможете осуществить "зануление" не всей исходной программы, а лишь определенной ее части. О том, как заменить число 9990 на другое, будет написан ниже.

После этого, по содержимому системной переменной PROG мы узнаем начало области Бейсика и осуществляем "зануление" первой программной строки.

Команда XOR A - простейший способ обнуления аккумулятора, ставший стандартным.

Это был подготовительный этап в работе программы - далее следует работа в циклическом режиме. По содержимому двух байтов, следующих за номером строки, программа определяет длину данной строки и, следовательно, сразу же может определить начало следующей. Теперь нобходимо проверить, не имеет ли данная строка программы номер 9990, который свидетельствовал бы об окончании работы, и, если номер совпадает, то процедура заканчивает свою работу и осуществляет возврат в Бейсик. В случае, если необходимый номер еще не достигнут, программа "зануляет" номер текущей строки и осуществляет возврат к началу цикла, после чего процесс повторяется.

Данная процедура имеет подстраховку для забывчивых пользователей. Если Вы обратили внимание, то возврат в Бейсик предусмотрен и после команды сравнения CP 13. Это может пригодиться, если Вы забыли создать строку с контрольным номером. В этом случае процедура "занулит" все строки программы и возвратится в Бейсик, когда обнаружит окончание исходной программы. При такой форме работы компьютер не "зависнет" и вам не придется перезагружать процедуру "зануления". Однако, свою исходную программу вам все же придется перезагрузить, так как процедура в машинных кодах внесет непоправимое изменение в номера строк Вашей исходной программы на Бейсике.

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

10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 160 190 200 210 220 230 240 250 260 270 280 290 300 310 320 330 340

INC HL LD E, (HL) INC HL LD D,(HL) ADD HL,DE LD A,(HL) CP 13 RET NZ INC HL LD A,(HL) CP B

JR Z,FINAL

Наиболее простым вариантом ввода такой строки было бы набрать: 9990 REM ENTER.

Однако, как уже упоминалось, Вы можете изменить номер контрольной строки и для этого вам необходимо ввести соответствующие изменения в исходную программу в машинных кодах, в случае, если нобходимый вам номер равен X, то достаточно подать команды:

LET a=INT(X/256): LET b=Х-256*а:POKE adr+1,b: POKE adr+2,a

В данном случае adr - это значение ячейки памяти, начиная с которой вы загрузили процедуру "зануления".

Естественно, что вводить новый номер конечной строки надо перед запуском процедуры.

Для читателей, которые не имеют ни малейшего желания разбираться в программах в машинных кодах, однако желающих использовать данную процедуру, я привожу здесь программу на Бейсике, которая позволит Вам загрузить в память компьютера описанную выше процедуру "зануления" (см. Листинг 2).

Листинг 2.

5 REM programming by Michailenko Vadim Mensk 1992

10 CLEAR 63129

20 FOR I=62130 TO 62168

30 READ A: POKE I,A

40 NEXT I

50 REM RANDOMIZE USR 68130

60 DATA 1,6,39,42,83,92,175,119,35,119,35,94,35,86,25,126,254,13,192,35,136,164,40,8,175, 54,0,35,5,0,24,234,35,126,185,200,43,24,241 Данная программа на Бейсике загружает блок машинных кодов, начиная с адреса 62130. Для того, чтобы записать этот блок машинных кодов отдельным файлом, необходимо подать прямую команду:

SAVE "имя файла" CODE 62130,39

Как уже упоминалось в статье, данная программа рассчитана для работы в произвольной области ОЗУ. Для того, чтобы загрузить ее в необходимую Вам область памяти, следует подать команду: LOAD "имя файла" CODE adr

где adr - адрес начала загрузки.

Том 4. Методы защиты программ от копирования.

Введение.

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

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

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

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

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

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

При использовании приводимого нами материала необходимо учитывать, что большинство программ, которые мы будем рассматривать, написаны в машинных кодах. Это еще раз говорит о том, что высокого уровня профессионализма можно добиться, только изучив программирование на языке Ассемблера. Несмотря на то, что большинство рассматриваемых процедур снабжены подробным комментарием, мы настоятельно рекомендуем Вам перед прочтением данного материала поближе познакомиться с программированием в машинных кодах. Одной из лучших книг, которые нам приходилось встречать по данной тематике, является разработка "ИНФОРКОМа" "Практикум по программированию в машинных кодах".

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

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

1. Временные диаграммы и основные характеристики файловой структуры записи на магнитную ленту.

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

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

Основа проста. К порту компьютера с адресом 254 подсоединяется посредством контроллера ULA микрофонное гнездо MIC и выходное EAR. Напряжение в микрофонном гнезде полностью зависит от третьего бита байта, вписываемого в этот порт. Если этот бит равен 0, то выходное напряжение составляет 0,75 Вольта, а если 1 - 1,3 В. Очередная смена установки этого бита на 0 или 1 в компьютерном порту 254 приводит к образованию прямоугольного сигнала, изображенного на диаграмме 1.

1.3 В

0.75 В

Диаграмма 1. Система кодирования информации на магнитофонной ленте в виде

прямоугольных импульсов.

Показанный на диаграмме прямоугольный сигнал можно записать на ленту как звук с определенной частотой, зависящей от времени, в течение которого установка третьего бита есть константа. Рассмотрим это на примере программы, взятой из книги Анджея Кадлофа "Спектрум и магнитофон".

Данная программа попеременно включает и выключает магнитофонный бит компьютерного порта 254:

1 OUT 254,0

2 OUT 254,8

3 GOTO 1

Подключив усилитель низкой частоты к выходу MIC, мы услышим звук низкого тона. Это объясняется тем, что интерпретатор БЕЙСИКа работает очень медленно. На таком уровне скорости он не позволяет генерировать высокие тона. Поэтому собственные процедуры для записи и считывания с кассеты должны быть написаны только в машинном коде.

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

В машинном коде Z-80 существует обширная группа команд, позволяющая процессору получать данные от внешняя устройств и выдавать данные на эти устройства. Это делается по аналогии с загрузкой данных в регистры микропроцессора из ячеек ОЗУ и выдачей их в ОЗУ на хранение.

Как Вам уже, вероятно, известно, принцип внутренних и внешних устройств оценивается по отношению к микропроцессору Z-80. Именно поэтому такие части компьютерной системы, как клавиатура, магнитофон и звуковой динамик являются внешними.

Мнемоники команд АССЕМБЛЕРа, отвечающих за ввод/вывод байтов через внешний порт аналогичны операторам БЕЙСИКа IN и OUT. Однако, на языке АССЕМБЛЕРа передаваемые в порт данные рассматриваются как восьмибитные числа, и поскольку порт 254 служит для связи процессора не только с магнитофоном но и с клавиатурой, со звуковым динамиком и с бордюром экрана, у нас могут возникать побочные эффекты, если мы используем порт 254 из БЕЙСИКа.

Рассмотрим раскладку данного порта при записи и чтении информации. При вводе информации в порт 254 шестой бит указывает на наличие сигнала на магнитофонном разъеме (вход в компьютер), причем единице соответствует отсутствие сигнала, в то время как ноль показывает его наличие. Младшие пять битов определяют, какая из пяти клавиш каждого полуряда клавиатуры была нажата. Бит равен нулю, если клавиша была нажата и единице, если нет. Все это наглядно демонстрирует приведенная ниже диаграмма.

7

6

5

4

3

2

1

0

| 1

Сигнал Сигналы с

EAR клавиатуры

Изучим выходную раскладку сигналов компьютерного порта 254. Информация, которая находится в четвертом бите, передает сигнал на звуковой динамик "Спектрума". По третьему биту выдается сигнал на разъем MIC (запись информации на магнитофон). А по младшим трем битам, как мы уже упоминали, выдается сигнал на установку цвета бордюра. Цвет устанавливается в соответствии с номером одного из восьми стандартных цветов "Спектрума". Вся приведенная выше информация наглядно демонстрируется на диаграмме.

7

6

5

4

3

2

1

0

Сигнал на динамик

Цвет бордюра

Сигнал на разъем MIC

Информация, которую мы получаем с магнитофона, не является набором прямоугольных импульсов, а характеризуется сигналом близким к синусоидальному. Однако, такой сигнал тоже поддается компьютерному анализу. На этом принципе основана программа цветомузыки, когда в такт мелодии, игравшей на магнитофоне, экран начинал изменять свой цвет, приведенная в одном из номеров "ZX-РЕВЮ".

Для кодирования данных в "Спектруме" каждый записанный блок состоит из комбинаций четырех различных видов импульсов. Первым генерируется пилотирующий сигнал, при котором смена напряжения наступает регулярно через 619.4 микросекунды, что соответствует 2168 тактам частоты синхронизации микропроцессора Z-80. Генерируемый сигнал имеет частоту 807 Гц. Его продолжительность составляет порядка пяти секунд для заголовка ("хэдера") и около двух секунд для блоков данных. Конец пилотирующего сигнала характеризуется тремя фронтами, образующими так называемый импульс синхронизации (синхроимпульс). Интервалы между ними составляют соответственно 667 и 735 тактов частоты синхронизации микропроцессора. Далее без перерыва во времени пересылаются отдельные биты данных, причем единица представляется двумя фронтами, появляющимися с интервалом 1710 тактов (488.6 микросекунды), в то время как логический ноль представлен 855 тактами (244,3 микросекунды). Интервалы между передаваемыми байтами отсутствуют. Наглядно характеристики сигналов показаны на диаграмме 2.

2168

2168

735

1710

855

2168

2168

667

1710

855

Пилотирующий сигнал

Синхроимпульс

Логич. "1"

Логич. "0

"

Диаграмма 2

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

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

Теоретически ознакомление с вышеописанными временными характеристиками сигналов уже достаточно Вам для написания программ записи и чтения с кассет в формате "Спектрума".

Однако, дело это достаточно сложное и требует очень хорошего знания языка АССЕМБЛЕРа. Еще для правильности интерпретации считываемых файлов необходимо подробно изучить, как производится контроль правильности блока данных. Ведь записывая каждый файл на ленту, "Спектрум" добавляет к нему два байта: один в начале и один в конце. Первый из них сигнализирует о том, является ли данный блок заголовком (значение байта в этом случае равно нулю) или же собственно блоком данных (в этом случае байт принимает значение 255).

Последний байт блока, так называемый байт четности, связан непосредственно с контролем правильности считывания. Его значение записывается в регистр и во время записи последовательного ряда байтов. Принцип контроля основан на применении команды "ИСКЛЮЧАЮЩЕЕ ИЛИ" (XOR). Здесь результат равен единице, если хотя бы один из операндов равен единице, но не оба вместе. В остальных случаях он равен нулю. Перед посылкой каждого восьмибитового байта из регистра L выполняются команды: LD A^ XOR L LD H,A

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

ТАРЕ LOADING ERROR

Эта система на практике оказывается не только очень простой, но и очень эффективной.

Для того, чтобы научиться защищать собственные программы от копирования, вам необходимо не только представлять, каким образом информация кодируется на магнитной ленте, но и разобраться с основными принципами работы встроенных программ чтения и записи с магнитофона. Эти программы построены так, что они очень просты и непритязательны, если в одной упряжке используются "SAVE'^ "LOAD", известна точная длина блока данных и вас не волнует возврат в БЕЙСИК вследствие ошибки или нажатия "BREAK".

Структурная схема заголовка.

Байты 0 1 2..11 12-13 14-15 16-17 -

Флаг тип имя длина старт бейсик-длина паритет

IX+ - 0 1..10 11-12 13-14 15-16 17

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

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

Чтобы согласовать разночтения в литературе относительно длины заголовков давайте считать, что первый и последний байты являются служебными и к пользователю не имеют никакого отношения, а остальные семнадцать - информационными.

Тогда:

Байт 0 - флаговый байт, для заголовков всегда равен нулю, а для блоков данных равен

255.

Байт 1 - содержит число, характеризующее тип записи:

0 -- это БЕЙСИК-программа,

1 -- числовой массив,

2 -- массив символов,

3 -- блок кодов.

Байты 2-11 - содержат имя программы (блока данных).

Байты 12-13 - длина блока. Длина программы кодируется двухбайтным шестнадцатиричным числом. (Для БЕЙСИК-программы это, соответственно, разность между содержимым системных переменных "ELINE - PROG").

Байты 14-15 - хранит в себе начальный адрес загрузки (если это блок машинных кодов) или номер строки автостарта для БЕЙСИК-программ. Если же блок является массивом данных, то для него байт 15 кодируется специальным образом: биты 0-4 - имя от A=1 до Z=26; бит 5 - сброшен, если массив - числовой. бит 6 - активен, если массив - строковый. бит 7 - активен всегда.

Байт 16-17 - это длина для БЕЙСИКа, то есть разность между содержимым системных переменные "VARS-PROG".

Последний байт - байт четности ("PARITY BYTE"). Он выдается при записи блока на ленту автоматически и при загрузке считывается и проверяется.

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

Каждый пользователь "Спектрума" обратил внимание на то, что блок информации (файл) на магнитной ленте начинается с синхронизирующего сигнала длительностью две или пять секунд. Частота этого сигнала составляет около восьмисот Герц (период 1.25 миллисекунды). После этого сигнала идет один период специального синхросигнала для которого длительность нуля составляет около 0.19 миллисекунды, а единицы - 0.21 миллисекунды. Затем следуют байты данных передаваемые последовательно, начиная со старшего бита.

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

На этом мы пока прервемся, а далее рассмотрим процедуры, которые отвечают за загрузку и выгрузку программ.

(Продолжение следует).




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Содержание
Объявления - обьявление к господам программистам.
Мнение - ARS/Fatality - минский проотец ZX-NET и в частности C-DOS modem'а.
TR-DOS для начинающих - 5-я глава книги "Общие сведения по дисковой системе ТР ДОС".
Юмор - В.Тихонов.

В этот день...   23 апреля