Работа с ZX-Spectrum 1993 г.

Тайники. Глава 3. - защита программ на BASIC'e.


ГЛАВА 3

ЗАЩИТА ПРОГРАММ НА BASIC'e

Прочитанная программа, как правило, не должна выглядеть "нормально*.
Например, в программе есть строка с номером 0 или строки упорядочены по
убыванию номеров, нельзя вызвать EDIT ни для какой строки, видно
подозрительную инструкцию RANDOMIZE USR 0 или просто ничего не
видно, так как программа не позволяет листать себя. Если в программе, куда
Вы вламываетесь, Вы увидели что-то необычное, то лучше просматривать её
другим, несколько отличающимся от обычного, способом - не с помощью
LIST, а непосредственно используя функцию РЕЕК.

Однако, сначала мы должны узнать, каким образом размещен в памяти
текст программы на BASIC'e. Программа складывается из последовательных
строк и так хранится в памяти.

Отдельная строка программы выглядит таким образом:

MSB LSB LSB MSB

I 2 байта I 2 байта I .... I # OD I

номер строки длина текст ENTER
текста + ENTER

Рис. 1.

Она занимает не менее 5 (а точнее 6, так как текст пустым быть не мо-
жет) байтов. Два первых обозначают её номер, но он записан наоборот, от
всех обычных двухбайтовых чисел, хранимых в памяти (MSB - старшии байт,
LSB - младший байт).

Следующие 2 байта - это длина строки, т.е. число символов, содер-
жащихся в строке вместе с завершающим её знаком ENTER (# 0D). За этими
байтами находится текст строки, заканчиваемый ENTER.

Если мы введем, к примеру, такую строку:
10 REM BASIC

и запишем её, нажимая клавишу ENTER, то она будет записана в память
как последовательность байтов:

I О I 10 I 7 I О I 234 I 66 I 65 I 83 I 73 I 67 I 13 I

I 10 I 7 I REM BASIC I ENTER I

номер длина текст
Рис. 2.

Параметр «длина строки» касается только её текста, следовательно, хотя
строка занимает в памяти 11 байт, этот параметр указывает лишь на 7 байт: 6
байт текста и 1 байт - «ENTER», заканчивающий строку.

Вам, наверное, уже понятно, на чем основан часто применяемый трюк
со строкой, имеющей нулевой номер. Достаточно в первые два байта строки

занести число 0 (с помощью РОКЕ), чтобы эта строка стала нулевой строкой.
Если мы хотим изменить номер первой строки в программе (а интерфейсы
никакой быстрой памяти не подключены, т.к. в этом случае изменяется адрес
начала Basic'a), то достаточно написать:

РОКЕ 23755, X: РОКЕ 23756, Y
и строка получит номер 256*Х+У. Независимо от его значения строка
останется в памяти там, где была. Если, к примеру, введем:
10 REM номер строки 10
20 REM номер строки 20

РОКЕ 23755, 0 : РОКЕ 23756, 30
то первой строке в программе будет присвоен номер 30, но она оста-
нется в памяти как первая, а на экране мы получим следующее:
30 REM номер строки 10
20 REM номер строки 20
следовательно, чтобы начать разблокировать программу, в которой име-
ются нулевые строки или строки, упорядоченные по убыванию номеров, сле-
дует найти адреса каждой строки и в их поле «номер строки»
последовательно размещать, к примеру. 10. 20. 30,... В памяти строки распо-
лагаются одна за другой, следова тельно, с обнаружением их начал Вы буде-
те иметь трудности. Если X указывает адрес какой-нибудь программной
строки, то следующий адрес равен:

X + РЕЕК( Х+2 )+ 2Д6*РЕЕК( Х+3 )+4
т.е. к адресу строки добавляется длина её текста, увеличенная на 4 бай-
та. т.к. именно столько занимают параметры «номер строки» и «длина
строки». Такой способ нахождения начала строки не действует к сожалению,
когда применяется другой способ защиты - фальшивая длина строки. Он
основан на том, что в поле «длина строки» вместо настоящего значения дает-
ся очень большое число - порядка 43-65 тысяч. Этот способ применяется
очень часто, так как обычно делает возможным считывание программы с
помощью MERGE (т.е. так, чтобы не было самозапуска). Делается это потому,
что MERGE загружает программу с ленты в область WORKSPACE, а затем
интерпретатор анализирует всю считанную программу строка за строкой:
последовательно проверяет номер каждой из них. а затем размещает в соот-
ветствующем месте области, предназначенной для текста программы на
Basic'e. Для этой строки необходимо там подготовить соответствующее
количество свободных байт, «раздвигая» уже существующий текст програм-
мы. Если в поле «длина строки« стоит очень большое число, то интерпрета-
тор будет стараться сделать именно столько байтов пространства в области
текстов программы, что это завершится сообщением «OUT OF MEMORY»
или просто зависанием системы. Чтобы прочесть такую программу, не вызы-
вая ее самозапуск, следует применить соответствующую отмычку, например,
такую как представленная в главе 2 программа «LOAD/MERGE».

Дополнительным эффектом от применения фальшивой длины является
невозможность корректировки такой строки путём занесения её в поле
редактора с помощью клавиши «EDIT». Ситуация выглядит аналогично: опе-
рационная система старается освободить место для этих строк в области
редактирования строк BASIC'a (от переменной E_LINE до WORKSP), однако
это требует слишком большого количества свободной памяти, следователь-
но, кончается только предупредительным сигналом. Если программа
защищена этим способом, то адреса очередных строк приходится искать
«вручную» или догадываться, где они находятся, помня о том, что каждая
строка кончается знаком «ENTER» (но не каждое число 13 означает
«ENTER»). Чтобы просмотреть программу на BASIC'e введи такую строку:
FOR N=23755 ТО РЕЕК 23627+256*РЕЕК 23628:

PRI 1 N;" ";PEEK N,CHR$ PEEK N AND PEEK N 31:
NEXT N

Она последовательно высветит: адрес, содержимое байта с этим адре-
сом. а также символ, имеющий этот код. если только это не управляющий
символ (т.е. с кодом 0 ...31).

После смены нумерации строк и изменения их длин, следующим спосо-
бом защиты программ являются управляющие символы, не позволяющие пос-
ледовательно просматривать nporpaMMv «отя и не только это Вернемся к
первому примеру (строка «10 REM BASIC»). Текст строки складывается из 7
символов - ключевого слова REM (все ключевые слова - инструкции и
функции, а также знаки <=. >в и • > имеют однобайтовые коды из диапазона
1о5 ... 255. Если Вы не знаете какие, то введите:

FOR N-165 ТО 255: PRINT N, CHR$ N: NEXT N

и ознакомьтесь), а также пяти литер и символа «ENTER». Так бывает
всегда, если в строке находится инструкция REM - все знаки, введенные с
клавиатуры после этой инструкции, будут размещены в тексте строки без ма-
лейших изменений. Иначе выглядит ситуация, когда в строке находятся
другие инструкции, требующие числовых параметров (а обычно так и бывает)
Введем, например, строку
10 PLOT 10, 9

и посмотрим, каким образом она запишется в память (лучше - вводя
приведенную выше строку FOR N=23755 ТО ...). Выглядит она так. как показа-
но на рис.3:

I 0 j10 j 18} 0 1 246 |49|48ll4| 0 1 0 110 1 0 1 0 144! 57 14 0 ^ 0 9 [ 0 ' О ^j3
; 10 [ 18 [plot! i j 0 [ 10 гтт; 9

номер длина номер номер ENTER

Рис. 3

Как видно, текст был модифицирован - после последней цифры каждого
числа, выступающего в тексте строки как параметр, интерпретатор сделал 6
байтов пространства и поместил там символ с кодом 14. а также 5 байтов, в
которых записано значение этого числа, но способом, понятным интерпрета-
тору. Это убыстряет, в определенной мере, выполнение программы на
BASIC'e. т.к. во время выполнения программы интерпретатор не должен каж-
дый раз переводить числа из алфавитно-цифрового представления (последо-
вательности цифр) на пятибайтовое представление, пригодное для
вычислений, но готовое значение выбирается из памяти из-за управляющего
символа CHRS14. Эта странная запись также дает большие возможности в
деле затруднения доступа к программам Во многих программах-загрузчиках
(LOADEk) присутствует такая строка'

О RANDOMIZE USR О: REM ...
На первый взгляд, после запуска эта программа должна затереть всю
память, но так. однако, не происходит. После более внимательного осмотра
(с помощью РЕЕК - строка FOR N==23755...) оказывается, что после USR 0 и
символа CHRS 14 совсем нет пяти нулей (именно так в пятибайтовой записи
выглядит число нуль. Если это целое число то в пятибайтовой записи оно вы-
глядит:

байт 1 - О

байт 2 - О (для +) и 255 ил я -)

байт 3 и 4 - последовательно младший и старший (или

допочненис до 2 для -)
байт 5 - 0 )

но, к примеру, 0, 0, 218, 92, 0 - это равнозначно числу 23770. Функция
USR не осуществляет тогда переход по адресу 0, а именно по 23770, а это
как раз адрес байта, находящегося сразу после инструкции REM в нашем
примере. Там, обычно, находится программа-загрузчик, написанная на
машинном языке.

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

LET A=USR 0: REM «««

LOAD ...

(< обозначает CHRS 8), то инструкция LOAD "" и последующий текст за-
кроют предшествующую инструкцию LET AeUSR 0:. Хотя на листинге теперь
видна только инструкция LOAD но дальнейшая часть программы загружа-
ется не ею, а машинной программой, запускаемой функцией USR 0. (что.
очевидно, не должно обозначать переход к адресу 0). Такая защита,
например, применяется в загрузчике программы BETA BASIC 1.0.




СОДЕРЖАНИЕ:


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

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



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

Похожие статьи:
Упаковщики - распковка ZIP архивов.
Обо всём - шедевры цифровой графомании: история первого в мире Персонального Компьютера "Альтаир".
Капля припоя - Резервы ZX-Spectrum.
Посмеёмся - Байки ex-киндера.
От авторов - вступление.

В этот день...   23 ноября