3. ЗАЩИТА ПРОГРАММ НА БЕЙСИКЕ.
Прочитанная программа как правило не должна выглядеть "нормаль-
ной". Например, в программе есть строка с номером 0 или строки, упо-
рядочеиные по убыванию номеров; нельзя вызвать EDIT ни для какой
строки; видно подозрительную инструкцию RANDOMIZE USR 0 или просто
ничего не видно, т.к. программа не позволяет листать себя. Если в
программе, куда Вы вламываетесь, видно что-то необычное, то лучше
просматривать ее другим, несколько отличающимся от обычного способом:
не с помощью LIST, а непосредственно используя инструкцию РЕЕК.
Однако, сначала мы должны узнать, каким образом размещен в памяти
текст программы на БЕЙСИКе. Программа складывается из последователь-
ных строк и так хранится в памяти. Отдельная строка выглядит таким
образом:
Она занимает не менее 5 (а точнее 6, так как текст пустым быть не
может) байтов. Два первых означают ее номер, но он записан наоборот -
в отличие от всех обычных двухбайтных чисел, хранящихся в памяти (№0
- старший байт, LSB - младший байт).
Следующие 2 байта - это длина строки* т.е. чисАо символов, содер-
жащихся в строке вместе с завершающим ее знаком ENTER (#00). За этими
байтами находится текст строки, заканчиваемый ENTER. Если мы введем»
к примеру, такую строку:
10 REM BASIC
и запишем ее нажатием клавиши ENTER, то она будет записана в память
как последовательность байтов:
Параметр "длина строки" касается только ее текста. Следовательно,
хотя строка занимает в памяти 11 байт, этот параметр указывает лишь
на 7 байт: 6 байт текста и 1 байт - ENTER, заканчивающий строку.
Вам, наверное, уже понятно, на чем основан часто применяемый трюк
со строкой, имеющей нулевой номер. Достаточно в первые два байта
строки занести число 0 (с помощью РОКЕ), чтобы эта строке стала нуле-
вой строкой. Если мы хотим изменить номер первой строки в программе,
~то достаточно написать:
РОКЕ 23755,X: РОКЕ 23756,Y
и строка получит номер 256*X+Y. Независимо от его значения строка ос-
танется в памяти там, где была. Если, к примеру, введем
10 REM НОМЕР СТРОКИ 10
20 REM НОМЕР СТРОКИ 20 .
РОКЕ 23755,0: РОКЕ 23756,30
то первой строкой в программе будет номер 30, но она останется в па-
мяти как первая, а на экране мы получим следующее:
30 RE« НОМЕР СТРОКИ 10
20 REM НОМЕР СТРОКИ 20
Следовательно, чтобы начать разблокировать программу, в которой
имеются нулевые строки или строки» упорядоченные по убыванию номеров,
следуёт найти начала всех строк и в их поле "номер строки" последова-
тельно размещать к примеру 10, 20, 30 ... В памяти строки располага-
ются одна за другой, следовательно, с обнаружением их начал Вы не бу-
дете иметь трудностей. Если X указывает адрес какой-нибудь
программной строки, то следующий адрес равен
Х+РЕЕК(Х+2)+256*РЕЕК(Х+3)+4
т.е. к адресу строки добавляется длина ее текста, увеличенная на 4
байта, т.к. именно столько занимают параметры "номер строки" и "длина
строки".
Такой способ нахождения начала строки не действует к сожалению,
когда применяется другой способ защиты - фальшивая длина строки. Он
основан на том, что в поле "длина строки" вместо настоящего значения
дается очень большое число - порядка 43-65 тысяч. Этот способ приме-
няется очень часто, т.к. обычно делает невозможным считывание прог-
раммы с помощью MERGE (т.е. так, чтобы не было самостарта). Делается
это потому, что MERGE загружает программу с ленты в область W0RKSP, а
затем интерпретатор анализирует всю считанную программу строка за
строкой: последовательно проверяет номер каждой из них, а затем раз-
мещает в соответствующем месте области, предназначенной для текста
программы на БЕЙСИКе. Для каждой строки необходимо подготовить там
соответствующее количество свободных байт, "раздвигая" ухе существую-
щий текст программы. Если в поле "длина строки" стоит очень большое
число, то интерпретатор будет стараться освободить столько байтов в
области текста программы, что это завершится сообщением "OUT OF
MEMORY" или просто зависанием системы. Чтобы прочесть такую програм-
му, не вызывая ее самозапуска, следует применить соответствующую от-
мычку. Например такую, как представленная в разделе 2 программа "ЮА0
/MERGE".
Дополнительным эффектом от применения фальшивой длины строки яв-
ляется невозможность ее корректировки путем занесения ее в поле ре-
дактора с помощью клавиши "EDIT". Ситуация выглядит аналогично: опе-
рационная система старается выделить место для этой строки в области
редактирования строк БЕЙСИКа (от EJLINE до W0RKSP), однако это требу-
ет слишком большого количества памяти и, следовательно, кончается
только предупредительным звонком.
Если программа защищена этим способом, то адреса очередных строк
приходится искать "вручную" или догадываться где они находятся, помня
о том, что каждая строка кончается знаком ENTER (но не каждое число
13 означает ENTER).
Чтобы просмотреть программу на БЕЙСИКе, введите такую команду:
FOR N«23755 ТО РЕЕК 23627+256*РЕЕК 23628:
PRINT N;" ";РЕЕК N,CHR$ РЕЕК N AND РЕЕК N>31:
NEXT N
Она последовательно высветит адрес, содержимое байта с этим адре-
сом, а также символ, имеющий этот код, если только это не управляющий
символ (т.е. с кодом 0..31).
После смены нумерации строк и изменения их длин следующим спосо-
бом защиты программ являются управляющие символы, не позволяющие пос-
ледовательно просматривать программу (хотя и не только это).
Вернемся к первому примеру (строка 10 REM BASIC). Текст строки
складывается из 1 символов - ключевого слова REM (все ключевые слова
- инструкции и функции, а также знаки <*, >« и <> имеют однобайтовые
коды из диапазона 165..255, Если хотите их посмотреть - введите
FOR N«165 ТО 255: PRINT Не CHR$ N: NEXT N
и ознакомьтесь), а также 5-ти литер и символа ENTER. Так бывает всег-
да, если в строке находится инструкция REM - все знаки, введенные с
клавиатуры после этой инструкции, будут размещены в тексте строки без
малейших изменений. Иначе выглядит ситуация, когда в строке находятся
другие инструкции, требующие числовых параметров (а обычно так и бы-
вает). Введем,, например, строку
10 PLOT 10,9
и посмотрим» каким образом она запишется в память (лучше - вводя при-
веденную выше строку FOR N=23755 ТО ..,), Выгляди^ она так, как пока-
зано:
Как видно, текст быа модифицирован - после последней цифры каждо-
го числа, выступающего в тексте строки параметр, интерпретатор сделал
6 байтов пространства и поместил там символ с кодом 14, а также 5
байтов, в которых записано значение этого числа, но способом, понят-
ным интерпретатору. Это убыстряет (в определенной мере) выполнение
программы на БЕЙСИКе, т.к. во время выполнения программы интерпрета-
тор не должен каждый раз переводить числа из алфавитно-цифрового
представления (последовательности цифр) в пятибайтное представление,
пригодное для вычислений, а выбирает готовое значение из памяти после
управляющего символа 14. Зта странная запись также дает большие воз-
можности в деле затруднений доступа к программам. Во многих програм-
мах-загрузчиках присутствует такая строка:
0 RANDOMIZE USR 0: REM .
На первый взгляд» после запуска зта программа должна затереть всю
память. Однако, этого не происходит. После более внимательного прос-
мотра (с помощью РЕЕК - строка FOR N«23755 ...) оказывается, что пос-
ле USR 0 и символа CHR$ 14 совсем нет пяти нулей (а именно так выгля-
дит число 0 в пятибайтовой записи. Если число - целое, то в
пятибайтовой записи оно выглядит так:
байт 1-0
байт 2 - 0 для ♦ или 255 для -
байт 3 и 4 - последовательно мл. и старш. байты
(или дополнение до 2 для числа <0)
байт 5* - 0 h
но стоит, к примеру, 0,Qr218r92,0, что равнозначно числу 23770. Функ-
ция USR в это^ случае осуществляет переход не по адресу 0, ». именно
по 23770. Это как раз адрес байта, находящегося в нашем примере сразу
после инструкции REM. Обычно там находится программа-загрузчик, напи-
санная на машинном языке..
Следующим управляющим символом, часто прмиеняезмым для нециты, я»-
ляется символ CHR$ 8 - "BACKSPACE" или "шаг назад". Высвечивание это-
го символа вызывает сдвиг позиции вывода на одну позицию влево. Сле-
довательно* с помощью этого символа можно закрывать некоторые места в
листинге, печатая там другой текст. Если, например, в памяти последо-
вательно находятся знаки
LET A«USR 0: REM ««««««««
LOAD ""
(«обозначает CHR$ 8), то инструкция LOAD "" и последующий текст зак-
роют предшествующую инструкцию LET. Хотя на листинге теперь видна
только инструкция LOAD, но дальнейшая часть программы загружается не
ею, а машинной программой, вызываемой функцией USR. Такая защита при-
меняется, например, в загрузчике программы BETA BASIC 1.0.