czwartek , 18 kwiecień 2024

Jak złamać zabezpieczenie kaset firmy Grubcio?

Złote czasy piratów komputerowych, działających prężnie w szczególności na platformie Commodore 64, mamy już dawno za sobą. Większość produkowanych kaset z grami i programami na początku lat 90 nie posiadała żadnych zabezpieczeń. Wyjątkiem od tej reguły stanowiło słynne Micrus Copy, pojawiające się nie tylko na kasetach produkowanych przez Waldemara Czajkowskiego. Któż z nas nie próbował przegrywać zabezpieczonych gier, które po ponownym wczytaniu wyświetlały komunikat „Illegal Copy”? Ale o tym może opowiem przy następnej okazji.

O ile autor wspomnianego przed chwilą zabezpieczenia pozostaje nadal nieznany (a może jednak ktoś go zna?), o tyle istniało jeszcze co najmniej jedno rozwiązanie, uniemożliwiające kopiowanie pirackich gier przez zwykłych użytkowników, bądź innych piratów. Wielu z nich bowiem było na tyle bezczelnych, że powielało w całości kasety przygotowane pieczołowicie przez konkurencyjnych handlarzy. Aby temu zapobiec, Jumbo z grupy Parados w 1991 roku opracował Tape Protectora v1.5 (zakładam, że były i wcześniejsze wersje, jednakże do dziś ten programik prawdopodobnie nie został wydany oficjalnie na scenie komputerowej), kto wie, być może czerpiąc inspirację z popularyzującego się wówczas Micrusa. Z jego dzieła korzystała przez długi czas tarnowska firma komputerowa Grubcio.

Tarnowska firma Grubcio początkowo nagrywała programy na różnorodnych kasetach, oznaczając je stosowną pieczątką.

 

Autor softu zabezpieczającego przed kopiowaniem wykorzystał w nim niepublikowane rozkazy procesora 65xx, które w połączeniu z dodatkowymi bajtami, powodują konkretną „sieczkę” na ekranie przy disassemblacji w monitorze języka maszynowego. Przyjrzyjmy się zatem, jak wygląda typowy plik zabezpieczony przez Jumbo.

Zanim jednak to uczynimy, warto uzbroić się w Action Replay’a, ostatecznie w inny kartridż, zawierający monitor. Do odbezpieczenia programu nie jest wymagany żaden moduł, jednakże kilkuminutowe oczekiwanie na zapisanie pliku na dyskietce bez turbo raczej nie należy do zadań komfortowych.

Po bezbłędnym wczytaniu gry wpisujemy komendę LIST i po naciśnięciu klawisza RETURN pojawia nam się następująca linia programu w Basicu:

19991 SYS2065

Kod zabezpieczenia jednak nie startuje od komórki #2065 ($0811), albowiem Jumbo zastosował tutaj prosty, ale skuteczny trick, polegający na maskowaniu ostatniej cyfry przy komendzie SYS. W rzeczywistości właściwą komórką startową jest #2064 ($0810), a czwórka zasłaniana jest przez piątkę z wykorzystaniem basicowego odpowiednika wciśnięcia klawisza INST/DEL (literka t w rewersie). Dla niedowiarków, polecam zajrzeć do monitora języka maszynowego, najlepiej w Actionie za pomocą komendy I*0800- (po chwili należy nacisnąć klawisz RUN/STOP, by przerwać wyświetlanie zawartości pamięci), aby przekonać się, że nie mijam się z prawdą.

Jak zatem przedstawia się kod zabezpieczający? Jest on złożony z dwóch części. Pierwsza z nich wygląda tak:

Disassemblacja pierwszej procedury Tape Protectora:  
0810 SKW (.byte $fc, $40, $60) 
0813 LDA #$00 0815 SKW (.byte $0c, $99, $00) 
0818 STA $0286 
081b SKW (.byte $14, $a9) 
081d STA $d020 
0820 SKB (.byte $64, $a1) 
0822 STA $d021 
0825 SKB (.byte $f4, $b0) 
0827 JSR $e544 
082a SKB (.byte $d4, $ee) 
082c SEI 
082d SKW (.byte $dc, $99, $23) 
0830 LDY #$00 
0832 SKW (.byte $3c, $61, $08) 
0835 LDA $0856,y 
0838 SKB (.byte $54, $a9) 
083a EOR $ff00,y 
083d SKB (.byte $34, $a5) 
083f STA $0400,y 
0842 SKW (.byte $0c, $99, $c9) 
0845 INY 
0846 SKW (.byte $fc, $c9, $33) 
0849 CPY #$8a 
084b SKW (.byte $5c, $44, $40) 
084e BNE $0835 
0850 SKW (.byte $fc, $ee, $00) 
0853 JMP $0428

Z powyższego wynika, że Jumbo wykorzystał dwa niepublikowane rozkazy procesora 6510 (i pochodnych): SKBSKW. Dla obu mnemonik kod operacji (tzw. opcode) może przybierać kilka różnych wartości. W naszym przypadku zostały wykorzystane: $0c, $5c, $fc, $dc dla SKW oraz $14, $34, $54, $64, $d4, $f4 dla SKB. Pierwszy mnemonik nakazuje procesorowi przeskoczyć dwa kolejne bajty w pamięci (SKip Word), a drugi tylko jeden bajt (SKip Byte). Dodanie tuż po nich odpowiednich bajtów ma na celu wprowadzenie w błąd potencjalnej osoby, która zechciałaby podejrzeć kod w monitorze.

Przykład kaset produkowanych przez Grubcia. Przez długi czas dominowały proste okładki z zielonym paskiem (ten sam schemat istniał w przypadku kaset firmy Joy Computer), a w późniejszym okresie pojawiły się kolorowe, różnorodne okładki.

 

Postarałem się powyżej dokładnie przepisać ten kod, by wyjaśnić wszystkim, jak on działa. W nawiasie wpisałem bajty, które wyświetlają się tam, gdzie została wykorzystana komenda SKW lub SKB. Dla nas najważniejszą informacją jest to, że na ekran od $0400 przepisywany jest fragment pamięci od $0856 o długości #$8a bajtów. Jest on dodatkowo EOR’owany, czyli każdy bajt jest można to określić, „obracany” o zawartość z komórki $ff00+rejestr Y. W tym miejscu zlokalizowana jest jedna z Kernal’owskich procedur, stąd też zawartość tej części pamięci jest niezmienna.

W praktyce oznacza to, że każdy kolejny bajt pobierany po kolei, począwszy od $0856, EOR’owany jest o inną liczbę, pobieraną po kolei od $ff00. W efekcie czego na początku pamięci ekranu pojawia się linijka tekstu:

THIS IS THE END OF PIRACY! JUMBO/PARADOS

Tuż pod nią od $0428 zlokalizowana została procedura sprawdzająca, czy odpowiednia część bufora magnetofonu nie została przypadkiem wyzerowana. Dokładnie chodzi o zawartość komórek $035c-$0384, w której powinien znajdować się napis:

TAPE PROTECTOR V1.5 DONE BY JUMBO/PRS’91

Z reguły znajdują się tam zera (nawet podczas operacji ze stacją dysków), tak więc jeżeli przegramy grę zabezpieczoną przez Jumbo, wówczas procedura testująca bufor magnetofonu wpadnie w niekończącą się pętlę, a na ekranie oprócz czerni, nic nie będzie się działo.

Kiedy jednak test bufora wypadnie pomyślnie, wówczas następuje zdekodowanie i przeniesienie pod $0801 pożądanego przez nas programu. Przy okazji według moich analiz, pamięć zajmowana przez grę jest EOR’owana wartościami pobieranymi po kolei od $035c! Co oznacza w praktyce, że wartości przepisane wcześniej pod $0400 (w tym napis Jumbo o końcu piractwa), również biorą udział w dekodowaniu gry!

Na koniec programik ustawia komórki $ae/$af (z których korzystają niektóre depackery), a także $2d/$2e, czyli młodszy i starszy bajt właściwego końca programu. Jest to o tyle istotne, albowiem ułatwia nam późniejsze zgranie odbezpieczonego programu.

W jaki zatem sposób doszedłem do powyższych spostrzeżeń? Rozpocząłem najpierw analizę kodu od $0810, korzystając ze spisu niepublikowanych instrukcji assemblera dla procesora 65xx (dostępnego chociażby tutaj), bazując na wcześniejszej wiedzy uzyskanej dzięki rozgryzaniu sławnego Micrusa. Kilka minut analizy kodu w monitorze pozwoliło mi ustalić, co się tak naprawdę dzieje z zakodowanym plikiem. Zablokowałem skok do $0428, a następnie przeniosłem zawartość pamięci $0400-$0500 do $c000. Tam przejrzałem na spokojnie kod (tym razem daruję sobie jego przepisywanie tutaj, albowiem nie jest zaszyfrowany „nielegalami”) i zauważyłem pętelkę sprawdzającą bufor magnetofonu oraz kolejną pętelkę EOR-ującą i przenoszącą zaszyfrowaną grę, tkwiącą w pamięci od $08e0. Po zakończonej operacji program wykonuje systemowy skok do BASIC-a w celu uruchomienia odkodowanego pliku.

Przy złamaniu Tape Protectora v1.5 wykorzystałem sprytny pomysł, którego autorem jest TSD. Dawno, dawno temu, w #3 wydaniu papermaga Fuzz z listopada 1998 roku, zaprezentował on 3 POKI odbezpieczające sławne MICRUS COPY. Postanowiłem pójść tą samą drogą, ponieważ jest ona najłatwiejsza (owszem, można samemu na szybkiego napisać procedurę EOR-ującą i przenoszącą zakodowaną grę z $08e0 do $0801, „alepoco”?) i w zasadzie najbardziej optymalna. Jej zaletą jest prawidłowe ustawienie wartości komórek $2d/$2e, co umożliwia natychmiastowe zgranie odbezpieczonego pliku na kasetę bądź dyskietkę.

Na podstawie przeniesionego kodu z $0428 do $c028 obliczyłem, w którym dokładnie miejscu znajduje się procedura uruchamiająca rozkodowaną grę. Wystarczyłoby umieścić tam wartość #$60 (odpowiednik RTS – wyjścia z programu w języku maszynowym) i sprawa byłaby załatwiona (jak to uczynił TSD w przypadku MICRUSa), jednakże tutaj wszystko zostało sprytnie zEOR-owane, i to jak już wcześniej wspominałem, różnymi wartościami, pobieranymi począwszy od $ff00. Na szczęście szybko obliczyłem, co i gdzie należy wstawić, aby gra po zdekodowaniu nie została uruchomiona.

POKE 2258,188

Po wczytaniu zabezpieczonej gry, wpisaniu powyższego POKE i zatwierdzeniu klawiszem RETURN, wykonujemy komendę RUN. Na ekranie pojawi się stosowny komunikat serwowany przez JUMBO z mrugającymi na różne kolory literami i wydającym szumiące dźwięki SID-em. Po kilku chwilach komputer milknie i pojawia nam się niewidzialny kursor (w przypadku Action Replaya, jest on automatycznie biały, co również stanowi ułatwienie). Wówczas warto wyczyścić ekran (SHIFT+CRL/HOME), zmienić kolor kursora (np. CONTROL+2), o ile to potrzebne, a następnie zwyczajnie wykonać komendę SAVE (odpowiednią dla używanego modułu, jak i docelowego urządzenia), pamiętając jednak, by samemu wpisać właściwy tytuł pliku (jeżeli go zapomniałeś, nadal możesz go podejrzeć w monitorze od $0341.

I na tym kończy się nasza przygoda z zabezpieczeniem plików kasetowych autorstwa Jumbo/Parados. Przy okazji chciałbym zaznaczyć, że sporadycznie można trafić na kasety z serii Grubcio (oraz Joy Computer), które nie posiadają omawianego tutaj zabezpieczenia.

Opracowany POKE do odbezpieczenia TAPE PROTECTORa v1.5 przetestowałem z powodzeniem nie tylko na Actionie, ale również i na Finalu II oraz Black Boxie v8.

Na koniec chciałbym przekazać wyrazy uznania dla Jumbo za ciekawy i jednocześnie sprytny sposób na ówczesnych piratów, który prawdopodobnie czekał 21 lat na złamanie. Życzę owocnych prac przy archiwizowaniu kaset Grubcia. 🙂

Podziękowania dla Rysława za udostępnienie zabezpieczonych kaset.

V-12/Tropyx
Szczecin, 7.02.2012 r.