Адаптация программ для ZX Spectrum к TR-DOS современными средствами. Часть 1

  • Tutorial

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


5.25" Floppy


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


В этой статье я расскажу, как выполнить такую адаптация на примере игры Pac-Man, а именно, оригинального образа Pac-Man.tzx.


Инструменты


Несмотря на то, что в былые времена вся такая работа делалась непосредственно на ZX Spectrum (за отсутствием других вариантов), я буду адаптировать игру с использованием эмулятора и утилит командной строки. Основная причина в том, что особенно поначалу процесс адаптации состоит из большого количества проб и ошибок, и он проходит гораздо менее болезненно, если его автоматизировать. Всё то же самое можно проделать и непосредственно на спектруме.


В первой части мы будем использовать следующие инструменты:


  1. Эмулятор Fuse для отладки и тестирования.
  2. SkoolKit для дизассемблирования.

Отключение автозапуска в загрузчике


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


Есть несколько способов посмотреть на код загрузчика:


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


  2. Следующий способ — загрузить программу с использованием MERGE "" вместо LOAD "". В отличие от LOAD, MERGE игнорирует автозапуск программы. В случае с Pac-Man загрузка через MERGE приводит к зависанию компьютера с характерным сдвигом экрана влево. Это связано с тем, что вместо того, чтобы выполнять программу построчно, MERGE пытается разобрать её целиком и слить с уже загруженной программой. Однако, если в программе есть блок с машинными кодами, который нарушает синтаксис программы, это приводит к сбою.


  3. Если не хочется ломать голову, можно преобразовать образ ленты из TZX в TAP и воспользоваться утилитой listbasic, которая поставляется вместе с Fuse:


    $ tzx2tap Pac-Man.tzx
    $ listbasic Pac-Man.tap
       1 RANDOMIZE USR (PEEK 23635+256*PEEK 23636+91)

    Адрес 23635 ($5C53) соответствует системной переменной PROG, которая содержит начальный адрес области бейсика. Таким образом, точка входа в загрузчик смещена на 91 байт относительно области бейсика.


  4. Ещё один способ посмотреть на загрузчик описан в статье Desativando a autoexecução de um programa BASIC. В отладчике Fuse нужно поставить точку останова br 2053, загрузить программу, а когда загрузка закончится и выполнение кода прервётся, выполнить записать set 23619 128. Это предотвратит автозапуск программы и позволит выйти в бейсика.



Дизассемблирование загрузчика


Зная смещение точки входа относительно области бейсика, можно рассчитать её абсолютный адрес. В случае с ZX Spectrum 48К без загруженной TR-DOS, область бейсика начинается с адреса 23755 ($5CCB). Следовательно, загрузчик будет начинаться с адреса 23755 + 91 = 23846 ($5D26).


Для начала достаточно поставить точку останова на начальном адресе и посмотреть на машинные коды. В Fuse можно сделать br 23846 и начать загружать программу. Как только загрузчик начнёт выполняться, эмулятор остановится:


Debugger


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


LD IX, $8000 ; начальный адрес загрузки
LD DE, $4000 ; длина загружаемого файла
LD A,  $FF   ; индикатор тела файла
CALL   $0556 ; вызов LD-BYTES
JP     $8000 ; переход в программу

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


Если кратко, нужно сделать следующее:


  1. Сделать снапшот Pac-Man.z80 памяти компьютера, используя tap2sna.py или возможности эмулятора.
  2. Создать контрольный файл Pac-Man.ctl с начальным набором инструкций для дизассемблирования:
    i 16384 Ignore for now
    c $5D26 Loader
  3. Запустить дизассемблирование: sna2skool.py -H -c Pac-Man.ctl Pac-Man.z80 > Pac-Man.skool.
  4. В ходе изучения кода добавлять новые инструкции и комментарии в контрольный файл.
  5. Повторять до полного просветления.

В результате, после первого прохода получаем следующее (комментарии мои, адреса опущены):


ORG $5D26      ; те самые 23846, определённые выше

; Запрет прерываний
DI
IM 1

; Расшифровка загрузчика
LD D, IYh      ;
LD E, IYl      ;
LD B, $25      ; Длина зашифрованного загрузчика
EX DE, HL      ;
LD DE, $0019   ;
ADD HL, DE     ; На этом этапе HL содержит $5C53 (адрес переменной PROG)
LD E, (HL)     ; Загружаем значение PROG в DE и IX
INC HL         ;
LD D, (HL)     ;
LD IXh, D      ;
LD IXl, E      ;
LD A, (IX+$7F) ; Загружаем ключ расшифровки в аккумулятор (находится в $7F-м байте
               ; относительно PROG)
LD HL, $0035   ; Начало зашифрованного загрузчика ($35 байт относительно PROG)
ADD HL, DE     ;
PUSH HL        ; Сохраняем адрес загрузчика на стеке
XOR (HL)       ; Цикл расшифровки загрузчика
LD (HL), A     ;
INC HL         ;
DJNZ $5D43     ; Конец цикла
AND (HL)       ; 
RET NZ         ; По окончании расшифровки переходим в загрузчик по адресу на стеке

; Ключ для расшифровки
DEFB $77

Расшифровка загрузчика


Всё, что из этого действительно важно, это то, что расшифрованный загрузчик находится по адресу PROG + $35. Это значит, что если мы поставим точку останова br 23808, то к этот момент расшифровка уже выполнится мы увидим расшифрованный загрузчик:


Loader


Эта программа уже гораздо более похожа на типичный случай, упомянутый выше. В регистры IX и DE загружается значение $4000 (16384), делается что-то ещё и передаётся управление подпрограмме ПЗУ по адресу $055A (это на несколько байт ниже чем стандартная точка входа в LD-BYTES). Похоже, такой подход реализует какую-то защиту от копирования, т.к. стандартной процедурой этот файл не загружается и некоторые копировщики его не понимают.


Точка входа в программу


Осталось разобраться, как же вызывается программа после загрузки. Вместо привычного CALL LD-BYTES и JP здесь используется LD SP, XXXX и JP LD-BYTES. Первый (обычныйы) вариант работает следующим образом:


  1. CALL кладёт на стек текущее значение программного счётчика (PC).
  2. Управление передаётся вызываемой подпрограмме.
  3. При возврате из подпрограммы (RET) значение со стека снимается и происходит переход в вызывающую программу.

Почему здесь сделано иначе? Дело в том, что Pac-Man совместим с ZX Spectrum 16K и занимает абсолютно всю оперативную память (см. размер файла выше). Таким образом, загружаясь, программа затирает собой и загрузчик, и стек, где бы они ни находились. Если бы мы хотели перейти из ПЗУ в загрузчик с использованием стека и далее вызывать загруженную программу через JP, на момент окончания загрузки ни адреса, по которому находится JP, ни самой инструкции в памяти уже не было бы.


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


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


Итого


В результате изучения загрузчика мы выяснили следующее:


  1. Беззаголовочный файл длиной 16384 байт загружается по адресу 16384 (в экранную область, что в общем-то очевидно в процессе загрузки).
  2. По окончании загрузки указатель стека находится по адресу $5D7C, куда и передаётся управление.

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


Ссылки по теме:


  1. Профлицей «ТРУЪ Спектрумист».
  2. Reverse engineering ZX Spectrum (Z80) games.
  3. Adaptação de jogos de fita para Beta 48.
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 51

    +6
    Эх, школьные годы ) Помню ломал эти загрузчики без всяких дампов памяти, прямо на спектруме, с отладчиком и дизассемблером
    Помню самый сложный был завернут как матрешка, сам в себя раз 10, и раскодировался по-этапно, причем кодирование было с применением шагового регистра (не помню уж, вроде меняется с каждой инструкцией), вот с ним пришлось повозиться )
      0
      Мне ассемблерами/дизассемблерами на спектруме пользоваться не доводилось. Переводил инструкции в машинные коды по таблице в тетрадку и потом побайтово вводил.
        +1
        Как-то ковырялся с игрушкой Batman, и впервые не мог найти где же отнимаются жизни и бонусы. Несколько раз откладывал взлом, думал что недостаточно шарю в ассемблере. А на самом деле от лени я не просматривал код загрузчика, который перед запуском игры просто выполнял декодирование всего кода (не помню уже, то ли отнимая 1 от каждого байта, то ли сдвигая на 1 влево). Но получается полгода я откладывал взлом просто потому, что было лень посмотреть 20 байт в загрузчике.
        Опять таки, потому что вместо дизассемблера была бумажная тетрадка со списком команд и цикл с «print peek x» на бейсике
          0
          Видимо, большинство защит и держались на том, что у многих из нас были только тетрадки.
            0
            Ну в данном случае я взламывал количество жизней, а не загрузчик.

            А защита загрузчика, при наличии magic button — бессмысленна, и присутствовала в основном на оригинальных зарубежных кассетах, которые к нам доходили редко. У нас чаще были уже перехаканые версии, от того же Билла Гилберта и других.

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

              У меня была одна единственная бабина, переписанная напрямую на довольно приличном оборудовании, так с неё хорошо если треть игр загружалась. Но её так записывали не потому что какие-то защиты, просто человеку было лень возиться.
          0
          Регистр I (7-битный аналог TSC). Тоже попадался подобный загрузчик.
            0
            То есть R, конечно же.
          +1
          Все новое, это хорошо забытое старое. Книга Николая Родионова «Адаптация программ к системе TR-DOS» 1992 года
            0
            Да, я в неё тоже поглядывал в процессе.
              0
              От него же были и самые сильные защиты на кассетах с использованием регистра R и прочего. Провозился с ней в свое время дня три, так зацепило, что даже в институт не ходил это время. Бил Гилберт любил упаковывать куски кода ксорками вложенными раз 20 друг в друга.
                0
                Я с кассетными версиями от Родионова не сталкивался вообще, а вот от Билла Гилберта было много всяких. Интересно, есть ли где-нибудь готовый разбор загрузчика от него. Слышал, что там всё закодировано и перезакодировано и боюсь, что просто не хватит времени самому разобраться.
                  0
                  Вот одна из тех, что удалось найти сходу от Родионова:
                  IK+ with loader by Nicolas Rodionov


                  Уже не помню деталей, но по сравнению с Родионовым, у Гилберта защита была просто цветочки.
                    0
                    У Гилберта была не защита, а «перепаковка».
                    Основную защиту он сам снимал, делал свой загрузчик, в котором просто оставлял свой копилефт. В то время было модно сделать что-нибудь стильненькое.

                    Опять же, то что вы показываете — не защита, а именно стильненький загрузчик, не самый сложный. Мне больше нравились реализации различных «счетчиков»
                      0
                      Всё правильно. Я имел ввиду не защиту программы от копирования, а защиту самого загрузчика от дизассемблирования и модификаций. Несмотря на то, что взломанную программу можно было копировать свободно, автор, видимо, не хотел, чтобы его стильный копилефт убрали или заменили имя на своё.

                      Счётчики (как в Эксолоне от Билла Гилберта) — это мой любимый стильный загрузчик в своё время.
                        +1
                        Вот тут с Вами позволю себе не согласиться. Если у Вас спек 16, то это реальная защита. Фишка в том, что у вас грузится ВСЯ память ДО БАЙТА и таким образом нет возможности установить точку остановки — она попросту затрется. ATOS SOFT из Кривого Рога именно на этом строил свои ранние версии защиты — грузилась вся память начиная с 16384 и до 65535. Даже имея тогда 128к с trdos и последнюю версию отладчика STS я был просто бессилен — просто не было куда разместить эти несчастные 3 байта break point. А остановить загрузку = сброс. Да — можно было клацнуть magic просмотреть код программы, но во первых это было не спортивно, а во вторых — из за захламления стека нужные программе данные могли «запороться».
                          0
                          Интересно, как ATOS SOFT создавали такие файлы? Ведь где-то должна быть процедура выгрузки файла или хотя бы её вызов, но вся память занята игрой. Даже в случае с 128К дополнительная память располагалась в дополнительных страницах, и её на ходу вряд ли переключишь. Может оно и сохранялось вместе кодом выгрузки? В случае с Pac-Man наверняка просто использовалась машина с 48К.
                            +1
                            Надо сделать небольшой отступ — ATOSSOFT не только гениальным программистом был, но к тому же и довольно рукастым в плане железа. Он доделывал различные виды клонов до практически полной программной совместимости с оригиналом спека. Делал он это тремя путями (что касается именно клонов с измененных ПЗУ) заменой ПЗУ на содержащую фирменное ПО, установкой ПЗУ вторым этажом с добавлением на корпус переключателя выборки ПЗУ. И третий, самый распространенный у него (как сделано не знаю — я увы не железячник, но подобное было на компьютере Робик) собиралась какая-то схема, позволяющая в окно ПЗУ ставить свои данные + ставился переключатель защиты от записи. Для использования её надо было загрузить небольшую программу содержащую код ПЗУ и переклацнуть блокировку записи — после этого можно было свободно сброс делать и не бояться что данные будут удалены из этого участка ОЗУ.
                            Сделан был этот последний способ для того, чтобы можно было без особых усилий и вообще не имея программатора и УФ-лампы «перешить» ПЗУ. А необходимость была — ATOSSOFT выпускал свою версию ПЗУ с турбозагрузчиком, автоопределяющим скорость подачи данных с магнитофона и загружающего именно на этой скорости.
                            Версий ПЗУ было несколько и можно было купить обновленную версию у автора прям на рынке на кассете и загружать и использовать её.
                            Я лично был знаком с Андреем (ATOSSOFT) и он мне показывал свой отладчик — внешне чем то напоминавший STS. Расположен он был именно в такой ОЗУ (загружался) и там же находился переделанный TF-COPY, позволяющий копировать его защищенные версии программ.
                            Т.е. У него по сути была своя прошивка записанная в микросхему и ОЗУ подставляемое в окно ПЗУ по щелчку тумблера (вот тут чутка могу ошибаться — возможно переход по NMI был, но это не суть). Каким-то макаром и стек для работы отладчика был тоже в области ОЗУ.
                            Извините если запутал и много написал, но вроде всё правильно.
                            Собственно выгружал он именно из отладчика.
                            Один раз загрузив отладчик с копиром в подПЗУ можно было легко запускать как одно так и второе. Получалось что то типа теневого отладчика что то.
                              +1
                              >и её на ходу вряд ли переключишь
                              Имея 128К или выше, можно, вполне. Это просто отправить новое значение в порт ввода-вывода.
                              Щелкнуть страничкой и переставить указатель между передачей байтов — это 4-5 команд. Значит, счётчики крутящиеся на экране, успевали делать одновременно с загрузкой, ну а страницы расширенной памяти переключить — это намного быстрее. Были даже ленточные копировщики, которые принимали поток, сжимая на ходу, а потом и выгружали… Всё успевали.
                                +1
                                Ну да, действительно. Тот же TF-COPY умел сжимать-разжимать на ходу. Наткнулся, кстати, недавно на статью с парой демок, где ленточный загрузчик разжимает изображение прямо по ходу загрузки.
                              0
                              Загрузчик с простейшим сжатием некоторые такие проблемы мог порешать.
                              Опять же, можно грузить начиная чуть раньше, наплевав на экранную заставку (-6912)

                              Опять же, конкретно Гилберт особо защиты не ставил.
                                0
                                У ATOSSOFT'а только первые версии программ так шли (во всю память) а потом — во всю память плюс с хитрой загрузкой — загрузка не прерываясь грузила данные в разные адреса (сначала картинку, потом как буд-то бы щелчок и далее в #5b00, но потом по 3-4 кодовых блока в одном файле делал, которые грузились не подряд в память) при этом была повреждена контрольная сумма файла. При обычном копировании ставилась правильная контрольная сумма и всё — программа не работала.
                                  0
                                  По мне так «во всю память» — это своего рода свинство. Разработчик решает свои проблемы за счёт более долгого времени загрузки у пользователя. Даже если и увеличивает скорость загрузки, т.к. это сказывается на стабильности.
                          +1
                          Была родионовская Elite, которая грузиласть с самого начала экрана и до упора, причём звук с кассеты был неадекватным белым шумом, не кореллировавшимся с наполняемой заставкой. Загрузчик расшифровывал поток на ходу (обычный XOR), но всё равно загадочно и полоски на бордюре там были чёрно-красные или сине-красные, тоже нестандартные.
                          Книга Ларченко и Родионова «ZX Spectrum «Для пользователей и программистов»» — это да, кладезь информации в доинтернетую и доэмуляторную эпоху.
                            0
                            Интересно не видел раньше такого. Если бы ни видимый процесс загрузки, я бы по звуку подумал, что это просто сжатая картинка. Ан нет. Вот, кстати, этот релиз.
                              0
                              Была родионовская Elite, которая грузиласть с самого начала экрана и до упора

                              Потому что стэк можно было просто overwrite загрузкой =)
                                0
                                Там после загрузчика грузилось 2 блока, а не вся память одним блоком.
                                А звуки загрузки — ДА! Это просто нечто было. Я этот звук загрузки ELITE от Родионова ни с чем не перепутал бы. Он ВООБЩЕ не похож на загрузку других программ.
                                И ещё — это именно та версия игры, в которой если после загрузки в ответ на Load New Commander (Y/N) ответить Y, нажать 2. Save commander и введя любое имя выгрузить состояние, то после этого попадал в 47 галактику с рейтингом ELITE, немеряным баблом и товарами.
                                Ясно что глюк был — не инициализировал данные о пилоте, а выгружал по сути мусор, но это было просто мегакруто тогда!
                          +2
                          Был в своё время загрузчик — Microprotector. С какого-то времени все диски в единственно доступном (и то за 80 км) магазине стали защищать им. Столкнуся с ним, когда восстановил плохо читаемый диск. Стандартная процедура чтение-формат-запись дорожки, но привела к тому, что один нестандартный сектор (512 байт) отформатировался в 256 байт и диск перестал читаться, поскольку 0 дорожка оказалась зашифрована, а в том секторе был загрузчик, который повредился. Благодаря наличию другого диска с подобной защитой за вечер провел реверсижиниринг с отладкрй и понял, что защита (несколько вложенных xor на втором байте инструкции перехода) в целом зависела от 6 байт и они были разные для каждого диска (или партии). В течении еще одного дня написал анти-микропротектор, который 1. отображал нужные 6 байт, 2. снимал защиту с рабочего диска, 3. расшифровывал «восстановленный диск» запрашивая 6 байт… и это все на 48к, вот было интересно… с появлением Scorpion с теневым монитором это стало какой-то… банальностью
                            0
                            Я, похоже, жил в каком-то другом мире. До меня всё доходило уже взломанным и со снятыми защитами. То же «Звёздное наследие», которое нельзя было переписать копированием файла, можно было переписать полным копированием диска. Хотя в оригинальной версии вроде в дискете были какие-то дырочки.

                            Несмотря на то, что многие защиты по современным меркам кажутся примитивными, всё равно нахлынул какой-то внутренний зуд, хочется разобраться, как оно раньше работало. А из моделей спектрумов, ничего более крутого чем относительно стандарный 128К c AY и дисководом я до сих пор в глаза не видел.
                              +1

                              До меня всё доходило на кассетах, а о дисководе можно было только мечтать.

                                0
                                Для меня дисковод тоже долгое время был пределом мечтаний. Только в определённый момент я эту мечту осуществил и мир перевернулся.
                                  0
                                  Я тоже сначала с магнитофоном мучился, года 2-3, потом дисководы появились и у нас…
                                0
                                А звездное наследие я так и не прошел- у нас багованная версия была…
                                  0
                                  Я сам когда-то расковырял загузчик, убрал проверку этих самых байт на 0й дороге и думал всё — ан нет! Во время подгрузки когда то ли с острова то ли на остров плыть тебе говорили что у тебя мол неправильная копия игрового мира.
                                  Гениально кстати придумано. Вывод — копирование с помощью McDonald (медленно) или SOFT-COPY (намного быстрее).
                                  А вообще маленький форматер написал, который эту самую дорожку форматировал и записывал злосчастные байты, а потом просто копирование без форматирования и всё норм.
                                  +1
                                  ЗН, как же… У меня была оригинальная купленная на н.Арбате копия ЗН. Не покопаться в ней мне было бы обидным.
                                  1. В ней использовался модифицированный Microprotector, отличающийся отключенной индикацией. Помимо шифрованных basic-загрузчиков, как и в оригинальных реализациях, его наличие проверялсь рандомно при обращении к диску, когда производилось внутриигровое сохранение/загрузка. Впрочем эта защита снималась так же легко, как и оригинальный microprotector. В нём ключи (константы) шифрования были размещены на межсекторном пространтстве в конце образа нулевого трека. Обработка констант проводилась через команду контроллера чтение образа трека. Уязвимость состояла в том, что последний сектор в треке не был использован, поэтому было достаточно бережно перенести кусочек образа с константами в этот сектор, после этого дискета свободно копировалась. Процедура поиска констант начинала поиск заранее, поэтому информация с последнего сектора тоже успешно принималась.
                                  2. Внутриигровые патчи в виде бесконечных жизней было реализовать сложнее — в игре было три образа кода, записанные на дискете, которые рандомно меняли друг друга, опять же при отгрузках состояний. Если патчить только первый образ, то он рано или поздно замещался оригинальной копией, со всеми вытекающими. В игре блокировался сюжет, и она становилась «кирпичом». Видимо, как раз такая багованная версия описана ниже kxl.
                                    +2
                                    В нём ключи (константы) шифрования были размещены на межсекторном пространтстве в конце образа нулевого трека.
                                    В том микропротекторе, что мне попадался, был именно один большой сектор. Это переполняло буфер TR-DOS и позволяло перетирать системные переменные, а точнее адрес возврата… Вот где были искомые байтики — я уже не помню…
                                    0
                                    Дырочки были в медноноговском Чёрном Вороне, в ЗН был мод microprotector, дополнительно интегрированный во внутрь игры.
                                  0
                                  Вот совсем неожиданный материал. Причём так и не смог понять, полезный или нет. Скорее нет, чем да.
                                    0
                                    Я уверен, что вреда от него ноль. Так что скорее всего полезный.
                                      0
                                      Я о полезности, а не о вреде. Тем, кто понимает и знает о чем речь, наелись этого всего до 96-97 года. Обратите внимание, одни воспоминания в комментариях.
                                        +2
                                        Именно. Но для истории все же полезно.
                                    +1
                                    «Однако, если в программе есть блок с машинными кодами, который нарушает синтаксис программы, это приводит к сбою.»
                                    Там дело не в том что код встроен в бейсик — кодовые блоки в подавляющем большинстве программ шли после оператора REM (данные после которого просто игнорировались интерпретатором Бейсика), а в неправильном указании длины бейсик-строки (первые два байта — номер, а вот вторые — именно длина) если поставить обчень большую длину — вот такой эффект со смещением и будет появляться при наборе MERGE "".
                                    Я обходил так — заголовок (17 байт) грузил от одной ОЧЕНЬ длинной программы, а само тело — от взламываемой программы.
                                      0
                                      […] кодовые блоки в подавляющем большинстве программ шли после оператора REM (данные после которого просто игнорировались интерпретатором Бейсика) […]
                                      Да. Именно так я и буду делать загрузчик для TR-DOS в следующих частях.

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

                                      Видимо, «синтаксис» — не самая удачная формулировка.
                                      Я обходил так — заголовок (17 байт) грузил от одной ОЧЕНЬ длинной программы, а само тело — от взламываемой программы.
                                      По идее, можно было загрузить заголовок от любого кодового файла, у которого длина больше длины бейсик-программы, и вменяемый адрес загрузки. А если с дисководом, то вроде бы можно было загрузить тело без заголовка в копировщик и сохранить его на диск как кодовый файл с тем же результатом.
                                        0
                                        По идее, можно было загрузить заголовок от любого кодового файла, у которого длина больше длины бейсик-программы, и вменяемый адрес загрузки.

                                        Но при этом получали куда-то-там загруженные данные, которые являлись по сути бесик-программой (как минимум один оператор там ДОЛЖЕН был быть — иначе бы не запустилась кодовая программа).
                                        А если заголовок именно от бейсик-программы, то и грузились данные именно в положенное место, после чего их можно было (хоть и не всегда) просмотреть в обычном бейсике, а не запускать какие то доппрограммы для просмотра листинга.
                                        В случае с Pac-Man мне показалось, что кодовые блоки идут сразу за окончанием строки безо всякого соблюдения формата хранения бейсик-программы в памяти

                                        Если честно — не смотрел сам загрузчик и как хранятся там данные, но про оператор REM я ж сказал что в подавляющем большинстве. Естественно были и другие варианты хранения кода — можно было, например переменной A$ присвоить значение в 50 пробелов, сохранить загрузчик, а потом в данные этой переменной всандалить код каким-нибудь отладчиком, походу подкорректировав адрес старта.
                                        Да. Именно так я и буду делать загрузчик для TR-DOS в следующих частях.

                                        В некоторых случаях, для ускорения делания дисковых версий, делался минимальный загрузчик со встроенным в REM кодом, который загружал данные размером в 1 сектор в, допустим, #5d3b (начало бейсика с инициализированным TR-DOS). Это очень упрощало написание загрузчика и встраивание его в REM (раньше не особо у многих был доступ к ПК для написания загрузчиков на языках более высокого уровня с последующей компиляцией и получения на выходе готового TRD образа).
                                        Получается так — готовишь данные (допустим картинка и код) и пишешь загрузчик, который будет эти данные грузить в указанные места и указанной длины, откомпилированный, допустим, в адрес #5d3b. Потом на дискете выстраиваем файлы в таком порядке — универсальный Бейсик-загрузчик, кодовый загрузчик, картинка (если есть), код игры/программы и всё это «склеиваем» в моноблок. другие игра/программа — заменил кодовый загрузчик и всё — выстроил, склеил. Особо актуально если грузишь блоки в страницы и текстовочку на экран хочется вывести, а «впиливая» всё после REM можно не попасть в длину сектора одного. А так хоть и теряем один сектор, но полчаем удобство в сборке.
                                          +1
                                          можно было просто вручную вызвать загрузчик с нужного адреса, через функцию «биоса»
                                          В регистр AX и DX скидываешь куда грузить и сколько.

                                          Например загрузка экрана (могу уже в цифрах запутаться, но как-то так):
                                          62
                                          255
                                          0
                                          64 (это вроде как в AX загружаем 16384)
                                          17
                                          0
                                          27 (в DX длину экрана с цветом)
                                          55 (обнуляем флаги)
                                          205 call (вызываем загрузку)
                                          86
                                          5
                                          201 return (возвращаемся в бейсик)

                                          вводишь через poke подпрограмму куда-нить в свободное место и randomize usr адрес
                                            0
                                            Вот это память!
                                              +1
                                              ну тогда уж так:
                                              62 255 ld a,ff
                                              221 33 00 64 ld ix, 16384
                                              17 00 27 ld de, 6912
                                              55 scf
                                              205 86 5 call 1366
                                              201 ret
                                                0
                                                К слову, с этой игрой такая загрузка не прокатит, т.к. байт типа файла тут нестандартный — не 00 (заголовок), не FF (тело), а A6. И заходят они в процедуру ПЗУ не по адресу 0556, а 055A. Кто-нибудь объяснит, в чём дело и как переписать пример выше, чтобы работало? Расшифрованный загрузчик работает (см. вторую картинку из отладчика), только не совсем понятно, что в нём по делу, а что для того, чтобы запутать взломщика.
                                                  0
                                                  kalantaj если это наизусть, то круто. Совсем забыл про 221,33 =)

                                                  DeadMoroz — Ну надо посмотреть что в загрузчике между 0556 и 055А, если я не ошибаюсь, там еще какой-то регистр или порт инициализировался, что влияло, например, на цвет border-а во время загрузки.
                                                    0
                                                    Вот есть удобный справочник.
                                                      0
                                                      Вот, оказывается я был прав, про бордер тут есть. Это я помнил, что можно было делать нестандартный цвет бордера, чуть изменив стандартный загрузчик:

                                                      055A LD A,$0F The border is made white.

                                        Only users with full accounts can post comments. Log in, please.