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