Адаптация программ к системе TR-DOS. 1992 г.

Глава 7 - ксорка. (обещанное мной продолжение, написанное специально для этого издания).


Глава 7

КСОРКА

 (обещанное мной продолжение, написанное специально для этого издания)

 

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

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

Рассмотрим простенькую программку, которая, будучи запущена, оставит от вполне связного текста загрузчика нечто совершенно неудобоваримое:

 

            LD     HL,START   ;адрес начала загрузчика

            LD     BC,LENGTH  ;длина загрузчика

     LOOP   LD     A,(HL)     ;загрузка в А из памяти 

            XOR    176        ;изменение  байта в А

            LD     (HL),А     ;запись его обратно     

            INC    HL         ;увеличение указателя

            DEC    BC         ;увеличение счетчика

            LD     А,В        ;счетчик

            OR     С          ; равен 0?

            JR     NZ,LOOP    ;если нет, то на LOOP

 

Предположим, что с адреса START у нас находится загрузчик длиной LENGTH байт. Если разобраться, как работает приведенный фрагмент,

* Для начала можно посоветовать книгу [1], где подробно описан пакет DEVPAC — программы GENS4 и MONS4.

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

Полагаю, что уже кое-что становится понятным. В частности, ясно, куда пропадают загрузчики — да никуда, просто их авторы вставляют в них куски вроде приведенного. Когда же программа стартует, она сначала «расксоривается», а потом запускается. Возможно, уже стало понятно происхождение слов «ксорка», «заксорен», «расксоривается» и т. п. Дело вот в чем: излюбленной командой для заксоривания является XOR, так как ее повторное выполнение (с тем же параметром) приводит к тому, что операнду, с которым она работает, возвращается прежнее значение (которое он имел до первого выполнения XOR). Без этой команды, похоже, не обходится ни одна более или менее приличная защита.

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

Итак, способ первый. Он наиболее прост, но часто оказывается самым эффективным. Для его применения Вам нужно, естественно, хорошо разобраться с каким-нибудь монитором-отладчиком. Из ранее упомянутых отладчиков наиболее удобным для хакерских дел я считаю Mon2, a MONS4 более пригоден для отладки программ. Оба они имеют режимы трассировки, и часто бывает достаточно найти входную точку загрузчика, точнее — ксорки, и протрассировать ксорку от начала до конца. В результате Вы получите вполне приличный листинг загрузчика и, полагаю, еще раз перечитаете предыдущие главы этой брошюры. Не стоит бояться двух, пяти, ста вложенных ксорок (это не шутка, защита типа Alcatraz protection, например, содержит их около трехсот!). Если в ксорках не используются какие-нибудь специальные «извраты», то они могут быть с легкостью раскручены.

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

 

1. Использование недокументированных команд. Как известно, в Z80 есть некоторое количество команд, не описанных ни в каких фирменных справочниках. Даже если Вы сами хорошо представляете, что эти команды означают, то отладчику от этого легче не становится, и он либо «затыкается», либо игнорирует их, либо еще что-нибудь придумывает, чтобы отмазаться.

 

2. Использование регистра R, специального регистра регенерации динамической памяти, содержимое которого увеличивается на единицу после выполнения каждой команды (точнее, очередного цикла) микропроцессора. Обычно этот регистр используется разве что для генерации случайных чисел, однако ловкие программисты придумали, как его применить. Например, так:

 

            LD    HL,START

            LD    BC,LENGTH

            XOR   А           ;обнуление

            LD    R,A         ;регистра R

     LOOP   LD    A,R         ;получение очередного значения R

            XOR   (HL)        ;заксоривание

            LD    (HL),А      ;запись заксоренного значения

            INC   HL

            DEC   BC

            LD    А,В

            OR    С

            JR    NZ,LOOP

 

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

 

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

 

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

 

            LD     HL,START

            LD     B,LENGTH

            XOR    А

            LD     R,A

     LOOP   LD     A,R

            XOR    (HL)

            LD     (HL),A

            INC    HL

            DJNZ   LOOP

            JP     OUTTHERE

 

Здесь можно применить одно простое средство: поставить точку останова после команды перехода к циклу (DJZN). В данном случае мы можем себе это позволить, так как после команды перехода к циклу стоит команда JP. В принципе, на этом месте может стоять любая осмысленная команда, которая сама не участвует в ксорке и не    заксорена.

Но посмотрите, что получится, если в нашем примере адреса будут расположены следующим образом:

 

            ...

            LD     HL,START

            LD     B,LENGTH

            XOR    А

            LD     R,A

     LOOP   LD     A,R

            XOR    (HL)

            LD     (HL),A

            INC    HL

            DJNZ   LOOP

     START  ...

 

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

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

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

В нем, среди прочего мусора, Вы сможете отыскать расксоренный загрузчик. Запустите программу Disk Doctor (или аналогичную) и потихоньку изучайте этот файл, которым кнопка Magic загадила Ваш диск...

Тут, ребята, я не могу сказать ничего более конкретного, кроме того, что Вы будете иметь сорок восемь килобайт «нечта», из которого малопонятным путем надо будет вытянуть загрузчик. По сути, нужно решить две задачи: первую — определить, где загрузчик Находится (это довольно просто) и вторую — найти его входную точку. Вот здесь могут возникнуть вопросы. Однако, если Вы тщательно проработали ксорку до того, как нажали кнопку Magic, то количество вопросов наверняка уменьшится.

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

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

 

                Защита типа Alcatraz protection

 

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

Снять эту защиту честным путем мне не удалось, помогла только кнопка Magic, чего и Вам желаю.

Да, забыл сказать, что заставка в этой защите загружалась настолько красиво...

 

                Защита типа Speedlock protection

 

Чрезвычайно распространенная защита (встречалась, например, в Freddy Hardest, Tanx и в десятках двух программ).

Полагаю, что примерно 70—80 процентов программ снабжались ею (речь, разумеется, идет об оригинальных фирменных программах, облаченных в красивые разноцветные упаковки и снабженных описанием, а не о BillGilbert-S.S.Captain-JackO'Lantern-NicolasRodionov'вских взломах).

Защита, как впрочем и все защиты, была предназначена для ограничения распространения программ, то есть программы, закрытые ею, не копировались.

Мне попадалось несколько модификаций Speedlock'a. Наиболее талантливым, на мой взгляд, был первый вариант (разработан в 1984 году, автор, кажется, David Aubrey Jones), о нем я расскажу подробнее. Остальные варианты были разработаны уже другими авторами и вряд ли заслуживают внимания с точки зрения ксорок, хотя внешне они работали довольно забавно.

Для 1984 года в Speedlock'е применялись просто гениальные штучки. Я весьма благодарен ее автору, так как для меня эта защита была школой, пройдя которую, я понял очень многое. К сожалению, вряд ли Вам удастся столкнуться со Speedlock'oM, но если Вы захотите пройти школу «молодого бойца», то могу порекомендовать повозиться с моей программкой Disk Control Utility. Начинать лучше с версий не позже 2.12, в них использована ксорка, написанная мною году в 87, если не раньше, а она лишь жалкая пародия на Speedlock. В версиях позже 2.12 ксорка написана в 1992 году, а это уже не для «молодых бойцов», лучше попрактиковаться на чем-нибудь попроще.

 

Итак, более подробно о Speedlock'e. Листинг бейсик-загрузчика выглядел весьма разумно и понятно, а именно, примерно так:

 

     О

 

                             Speedlock protection

 

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

Операторы РОКЕ выполняли следующее: переустанавливали системную переменную ERR_SP  (адрес возврата по ошибке) так, что как только интерпретатор выполнял всю разумную часть бейсик-программы и сталкивался с неразумной, то он тут же вылетал, но не в процедуру обработки ошибки с целью написать сообщение Nonsense in Basic, a на загрузчик в кодах, точнее, на раскрутку ксорки.

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

 

     LOOP   LD    A,R

            XOR   (HL)

            LD    (HL),A

            LDI

            DEC   SP

            DEC   SP

            RET   PE

            DEC   SP

            DEC   SP

            RET   PO

 

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

 

            DEC   SP

            DEC   SP

 

счетчик стека устанавливался на указатель на адрес LOOP, a

 

            RET   РЕ

 

выполнял возврат по этому адресу в случае, если после выполнения

 

            LDI

 

регистр ВС не равен нулю, то есть необходимо продолжить цикл. Затем, после расксоривания, указатель стека снова дважды уменьшается на единицу, устанавливаясь на LOOP, а команда RET РЕ снова «возвращает» на LOOP. На всякий случай напомню, что команда LDI делает следующее:

 

            LD    (DE),(HL)   ;такой мнемоники в Z80 нет, но

                              ;чтобы описать LDI

                              ;ее использовать можно, так

                              ;как делает она именно это

            INC   HL

            INС   DE

            DEC   BC

 

Причем, в зависимости от состояния ВС (равно или не равно нулю), соответствующим образом устанавливается флаг процессора Parity, этим и объясняется использование команд RET PO и RET РЕ.

Когда же цикл завершается, то программа переходит ко второй группе операторов DEC SP, выполняет их и оператором RET PO «возвращается» на следующую расксорку.

Следующая расксорка выглядит примерно также, затем следует еще парочка попроще.

Вот такие дела.

                    ___________________

 

Теперь попробую придумать ксорку с использованием стека. Ну, например, так:

 

            ...

            LD    SP,END    ; начало заксоренной области + 2

     LOOP   LD    BC,LENGTH

            LD    A,R

            POP   HL        ;фактически: LD H,(SP-1)

                            ;LD L,(SP-2)

                            ;DEC  SP

                            ;DEC  SP

            XOR   A,H,      ;последовательная ксорка Н и L

            LD    H,A

            LD    A,R

            XOR   L,A

            PUSH  HL         ;фактически: LD (SP),L

                             ;LD(SP+1),H

                             ;...INC SP

                             ;...INC SP

            POP   HL         ;фактически: INC SP

                             ;INC SP

            DEC   BC         ;дальше ясно

            DJNZ  LOOP

            ...

 

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

 

            ...

            LD    SP,END     ; начало заксоренной области + 2

     LOOP   LD    BC,LENGTH

            LD    A,R

            POP   HL         ; фактически: LD H,(SP-1)

                             ; LD L,(SP-2)

                             ; DEC SP

                             ; DEC SP

            XOR   A,H       ; ксорка Н

            LD    H,A

            PUSH  HL         ; фактически: LD (SP),L    

                             ; LD(SP+1),H

                            ; ...INC SP

                            ; ...INC SP

            INC   SP           увеличение счетчика стека на 1

            DEC   BC           дальше ясно

            DJNZ  LOOP

            ...

 

Этот вариант будет работать несколько медленнее (впрочем, это вряд ли имеет принципиальное значение) и менее извращен: за каждый цикл ксорится один байт, а в первом случае за каждый цикл ксорится два байта и используются разные смещения регистра R.

                      __________________

 

Теперь несколько слов об использовании недокументированных команд. Довольно полное их описание можно найти в книге [ 1 ]. Я же остановлюсь на описании  наиболее распространенных из них, а именно командах, работающих с частями индексных регистров IX и IY как с 8-разрядными регистрами общего назначения. На самом деле все не так страшно, и, столкнувшись впервые с такими командами в Speedlock'e, я понял, где собака зарыта, затратив совсем немного умственных усилий.

Как известно, доступ к регистрам IX и IY осуществляется теми же кодами операций, что и к регистру HL, за одним лишь исключением — команды работы с регистрами IX и IY префиксируются байтами 221(DDh) и 253(FDh) соответственно. И если в фирменных руководствах есть описания только таких команд как LD IY,0, то это еще не значит, что нет команды LD IYh,0*.

 

Документированную команду LD IY,0 можно представить следующим образом:

 

            DEFB  253        ; префикс регистра IY

            LD    HL,0

 

По аналогии с командой LD IY,0 недокументированную команду LD IYh,0 можно записать в таком виде:

 

            DEFB  253

            LD    Н,0

 

Ассемблеры (например, GENS4), как и отладчики, недокументированные команды не понимают, но используя в них приведенную запись команды LD IYh,0, можно внедрять недокументированные команды в программы.___________________________________________________________

* Так как запись команды LD I,0 неоднозначна, части индексных регистров обозначаются IXh и IX1 (старший и младший байты регистра IX) и IYh, IYl (старший и младший байты регистра IY).

                      ___________________

 


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




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

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



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

Похожие статьи:
Обзор ПО - Обзор новинок: Last Hero of the Light Forces
Игрушки - MIDNIGHT RESISTANCE.
Вступление - Ну вот, это вроде пятая (или шестая), виртуальная тусовка в нашей сети.
Обо всём - письма читателей: Сeргeй Москалёв.
Наш гость - мемуары спектрумиста из Дзержинска - Nuts.

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