Floppyspielereien Teil 2

Eine Vielzahl von Themen erwartet Sie in der zweiten Folge unseres Floppy-Kurses. Neben Informationen zu Directory und Bootsektor gibt es zwei Listings sowie Hinweise für einen Kopierschutz.

Vorab noch einige Anmerkungen zu HYPERFORMAT, dem Formatierprogramm aus der letzten ST. Mir ist zu Ohren gekommen, daß es vereinzelt Schwierigkeiten mit dem Beschreiben HYPERFORMATierter Disketten gab. Diese Probleme gibt es offenbar dann, wenn zwei Bedingungen Zusammentreffen:

  1. Das Laufwerk dreht zu schnell, oder
  2. Laufwerk und/oder Controller stammen aus einer alten Bauserie des ST.

Mein Verdacht ist also, daß es mehrere Bauserien des Controllers gibt. Sollten Sie einer von den Pechvögeln sein, könnten Sie - wenn Sie sich das Zutrauen und keine Garantieansprüche mehr haben - Ihren ST öffnen und mal nachsehen, welche genaue Bezeichnung Ihr Floppy-Controller hat, das ist der Chip, der ’WD1772’ heißt. Schreiben Sie bitte mir oder dieser Zeitschrift und geben Sie diese Bezeichnung mit an. Ich arbeite daran, auch die ältesten Bauserien noch glücklich zu machen.

Häufig stellt sich offenbar auch die Frage, ob das HYPERFORMAT kompatibel zum AMIGA-Format sei. Zwar haben beide Formate die gleiche Anzahl von Sektoren pro Tracks, zudem verwenden beide das sogenannte MFM-Verfahren zur physikalischen Aufzeichnung. Doch leider leistet sich der AMIGA (wie bei Commodore üblich) einen eigenen Standard, was das Format der einzelnen Sektoren selbst angeht. Zum Glück ist der Floppy-Controller des AMIGA sehr flexibel, da er hauptsächlich softwaregetrieben ist. Und so arbeite ich bereits an einem Programm für den AMIGA, das ihm ST-Disketten verständlich macht.

Und für diejenigen, die meinem Formatierprogramm nicht so recht trauen, habe ich auch noch ein Schmankerl, nämlich Listing 1. Dort finden Sie CHKDISK, ein Programm, das Disketten auf Lesefehler untersucht. Es ist nicht nur für HYPERFORMATierte Disketten brauchbar. Beim Start meldet es sich mit einem Menü. Mit ’t’ können Sie die Anzahl der Spuren verändern, die geprüft werden sollen, mit ’s’ die Anzahl der Seiten und mit ’p’ die Zahl der Sektoren pro Spur. ’C’ bricht das Programm jederzeit ab, mit RETURN wird es gestartet. Während des Checkvorgangs gibt das Programm den aktuellen Track aus. Wenn ein Fehler auf der Diskette ist, meldet sich CHKDISK mit einem Piepsen und einer Fehlermeldung mit genauer Angabe, wo der Fehler aufgetreten ist. Bei CHKDISK zeigt sich der Vorteil von FTYPERFORMATierten Disketten am deutlichsten: Lassen Sie mal eine HYPERFORMATierte Diskette checken und dann eine normale, und messen Sie jeweils die Zeit, die dafür benötigt wird!

Am besten, Sie setzen sich gleich mal vor Ihren Rechner und laden Ihren besten Diskmonitor, von denen es ja mittlerweile genug public domain gibt (zum Beispiel auch auf PD-Disketten der ST). Ich gehe davon aus, daß Ihr Diskmon zumindest Sektoren lesen, schreiben und in ASCII und Hexadezimal anzeigen kann sowie eine wenigstens minimale Editierfunktion hat. Sollten Sie keinen solchen Monitor, aber zumindest GfA-Basic haben, können Sie auch das Listing 2 abtippen -dann haben Sie einen kleinen Diskmonitor mit den erwähnten Fähigkeiten.

Formatieren Sie zunächst eine freie Diskette auf einseitiges Normalformat. Dazu müssen Sie Laufwerk A einmal anklicken und dann 'formatiere’ im DATEI-Menü wählen. Geben Sie dabei als Diskettennamen ’GRUMMEL. TST’ an.

In der letzten Folge hatte ich bereits erwähnt, daß die Directory, das Inhaltsverzeichnis der Diskette, beim einseitigen Normalformat bei Track 1, Sektor 3 beginnt. Darin stehen der Diskettenname (wenn angegeben) und die Namen aller Dateien, die Sie darauf abspeichern, mitsamt einigen wichtigen Informationen. So, ist das Laufwerk fertig? Dann starten Sie jetzt Ihren Diskmonitor, legen Sie die formatierte Diskette ein und lesen Sie Track 1, Sektor 3 ein (siehe Anleitung Ihres Diskmons). Es sollte ähnlich Verwirrendes erscheinen wie das hier:

47 52 55 4D 4D 45 4C 20 54 53 54 08 00 00 00 00 GRUMMEL TST......
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................

In den ersten 32 Bytes der Directory steht jetzt der Eintrag für den Diskettennamen. Die ersten 11 Bytes sind für den Namen und die Extension reserviert. Filenamen unter 8 Bytes werden mit Zwischenräumen erweitert, der Punkt wird nicht dargestellt, danach folgt die dreistellige Extension. Was die Länge der Dateinamen angeht, ist TOS ja - wie MS-DOS - recht geizig. Wenn man da an die Filenamen des AMIGA denkt... Die amputierten Dateinamen haben immerhin den Vorteil, daß das Verzeichnis kompakter wird und damit schneller zu laden ist: und wer will schon eine so einschläfernde Directory-Leseroutine wie beim AMIGA?

Bitnr. Bit = 1 Bit = 0 Anmerkungen
0 nur Lesen möglich Lesen und Schreiben erlaubt per 'Disk Info' im Desktop zu erreichen
1 'Hidden file' kein 'hidden file' Listschutz für das Verzeichnis
2 Systemdatei normale Datei Systemdateien werden auch nicht gelistet
3 Name ist Diskettenname Name ist Dateiname siehe Text oben
4 Datei ist ein Ordner Datei ist kein Ordner siehe Text unten
5 Datei wurde ordnungsgemäß bearbeitet 'Archive-Bit', vor allem für den Backup bei der Festplatte

Abb. 1

(Bytenummer)    
0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  
52  4F  4E  4E  49  45  20  20  55  53  41  00  00  00  00  00 BONNIE   USA 
00  00  00  00  00  00  86  03  46  oc  02  00  98  13  00      
16  17  IS  19  20  21  22  23  24  25  26  27  28  29  30  31  

Abb. 2

Wenn Sie genau nachzählen, haben wir noch nicht alle Bytes besprochen, in denen etwas steht. Im zwölften Byte steht ’08’. Dies ist das Dateikennzeichen und gibt in diesem Fall an, daß ’GRUMMEL.TST’ der Name der Diskette ist. In das Dateikennzeichen sind folgende Informationen kodiert:

MS-DOS kennt genau das gleiche Dateikennzeichen, sogar die Bitnummern stimmen überein. Wieder sieht man, daß die TOS-Entwickler auf der Diskettenebene sehr bemüht waren, sich an den IBM-Standard zu halten.

BITGESTEUERTE TARNKAPPEN UND ANDERE MAGIE

Natürlich sind Kombinationen der Bits möglich. Sie könnten also einen sichtgeschützten Ordner anlegen, der nicht beschreibbar ist, indem Sie das Dateikennzeichen auf $13 ändern - in der Theorie. Praktisch scheinen hier noch ein paar Unsauberkeiten von TOS verborgen zu sein. Experimentieren Sie ruhig ein wenig mit Ihrem Diskmonitor herum.

Kopieren Sie nun irgendeine Datei auf die leere Diskette und schauen Sie mit dem Diskmon im Verzeichnis (Track 1, Sektor 3) nach. Nehmen wir einmal an, die Datei hieße ’RONNIE.USA’. Dann bekämen Sie etwa folgendes Bild:

Byte 11 zeigt uns, daß RONNIE.USA eine ganz normale Datei ist. Die restlichen Bytes in dieser Zeile bedeuten schlicht & einfach nichts. Ein Directoryeintrag ist nun aber 32 und nicht 16 Bytes lang. Was ATARI in den Bytes der zweiten Hälfte versteckt hat, ist schnell erklärt:

Byte Inhalt
22-23 Uhrzeit der letzten Änderung
24-25 Datum
26-27 Erster Datencluster der Datei
28-31 Größe der Datei (Langwort)

Alle diese Bytepaare sind im 8086-Format abgespeichert (niedrigstwertiges Byte zuerst). Man muß sie also erst einmal umdrehen. Sehen wir uns das Datum von RONNIE.USA in den Bytes 22-23 an: Wir drehen ’86 03’ um und erhalten ’03 86’. Aufgeschlüsselt in Bits:

0000 0 011 100 0 0110 (0 3 8 6) 
Stunden—Minuten—Sekunden/2

Also in diesem Fall: 0 Uhr (0000 0), 24 Minuten (011100), 12 Sekunden (00110). Für das Datum von RONNIE.USA gilt ähnliches:

0000 110 0 010 0 0110 (0 C 4 6)
Jahr seit—Monat—Tag—1980

Was bedeutet, daß ich RONNIE.USA am 6.2.1986 gespeichert habe - aber das heißt auch nur, daß in meinem ST keine Echtzeituhr eingebaut ist, denn TOS setzt als Standardwert genau diesen Tag ein.

Bytes 26-27 geben an, bei welchem Cluster (das sind zwei aufeinanderfolgende logische Sektoren) die Datei beginnt. Auch diese Bytes muß man erst kräftig aufmischen, ebenso wie die darauffolgenden Bytes für die Größenangabe der Datei - waschechtes 8086-Format.

VON PHANTOMEN, FRÖSCHEN UND PRINZEN

Sollten Sie auf der Reise durch diverse Verzeichnisse einmal einen Phantomeintrag entdecken, der im Directoryfenster des Desktops nicht zu finden ist, dann ist das wahrscheinlich ein Eintrag, der mit dem Byte ’E5’ beginnt. ’E5’ heißt: Dieses File ist gelöscht. Nun kommen Sie mir ja nicht mit der Idee, Sie bräuchten nur dieses Byte zu ändern, und schon hätten Sie eine bereits abgetakelte Datei ins Leben zurückgeküßt. Dieser Frosch wird dadurch nämlich nicht zum schönen Prinzen ( = intakte Datei), es sei denn, die Datei ist höchstens ein Cluster (1024 Bytes) lang. Denn im Directoryeintrag steht nur ein Zeiger auf den ersten Cluster der Datei in der FAT (siehe letzte Folge) - der Rest der Verkettung wird in der FAT gelöscht, wenn Sie einen Prinzen, Verzeihung: eine Datei in die Wüste schicken.

Tun Sie jetzt mal etwas ganz Verwegenes: Legen Sie die GRUMMEL-Diskette ein, löschen sie alle Dateien auf ihr und klicken Sie im Desktop 'Neuer Ordner’ an. Nennen Sie ihn, wie Sie gerade lustig sind, also zum Beispiel LUSTIG.FLD (FLD für englisch FOLDER = Ordner). Entern Sie ihren Diskmonitor und lesen Sie den Directorysektor. Sie erhalten folgendes:

< Bytenummer 1                                                  
0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  
4C  55  53  54  49  47  20  20  46  4C  44  10  00  00  00  00  LUSTIG FLD  
00  00  00  00  00  00  55  04  46  0C  02  00  00  00  00  00  
16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  

Abb. 3

Byte 11 (Dateikennzeichen) sagt uns: LUSTIG.FLD ist ein Ordner. Alle restlichen Informationen sind die gleichen wie bei normalen Dateien, nur zeigen Byte 26 und 27 nicht auf den ersten Datencluster der Datei, sondern auf den ersten Cluster des Unterverzeichnisses (Subdirectory). Folgen wir diesem Hinweis: 'Cluster 2’ ist der erste von TOS vergebene Cluster überhaupt und beginnt bei einseitigen Disketten auf Spur 2, Sektor 1. Lesen wir diesen Sektor ein...


2E 20 20 20 20 20 20 20 20 20 20 10 00 00 00 00 . 00 00 00 00 00 00 04 55 0C 46 02 00 00 00 00 00 . . 2E 2E 20 20 20 20 20 20 20 20 20 10 00 00 00 00 . 00 00 00 00 00 00 04 55 0C 46 00 00 00 00 00 00 . .

Abb.4

Es werden also in diesem Unterverzeichnis gleich zwei Einträge angelegt: Eine fiktive Datei mit Namen und eine mit Namen Diese beiden No-bodies sind nur dazu da, um TOS im Wirrwarr der Unterverzeichnisse die Orientierung zu erleichtern. (beziehungsweise das Clusterbyte dieses Eintrags) zeigt auf das Unterverzeichnis selbst, so daß TOS nicht immer den ganzen Baum von Verzeichnissen lesen muß, um herauszufinden, wo die aktuelle Directory beginnt. zeigt auf die „Vater“directory, die hier angeblich bei Cluster 0 beginnt - das Zeichen dafür, daß die Vaterdirectory das oberste, das Wurzelverzeichnis ist.

ICH TARZAN - DU JANE

Mit Hilfe dieser speziellen Einträge schwingt sich TOS (Tarzan Operating System) an Zeigerlianen durch den Dateidschungel:

Die ’..'-Einträge zeigen jeweils auf das übergeordnete Verzeichnis, die ’.'-Einträge praktisch auf sich selbst.

Innerhalb eines Unterverzeichnisses können beliebig viele weitere Unter-Verzeichnisse angelegt werden - das heißt, fast. Wenn mehr als 40 Unterverzeichnisse auf einer Diskette sind, stürzt Ihnen Ihr TOS ab: Wenn Sie eine Diskette einlegen und das Verzeichnis einiesen, merkt sich TOS alle Di-rectories in einer speziellen Liste.

Nur ist der Platz für diese Liste leider beschränkt - mehr als 40 Verzeichnisse passen nicht rein.

Bei Disketten ist das nicht weiter tragisch, aber Festplattenbesitzer haben daran schwer zu knabbern - auf 20 Megabyte sind schnell 40 Directories erzeugt. Zum Glück gibt es korrigierte ROMs zu kaufen, und gerüchteweise habe ich auch davon gehört, daß die ROMs in den Mega-STs diesen Fehler nicht mehr aufweisen werden.

Alle diese kleinen Details der Diskettenverwaltung gibt es so oder ganz ähnlich sowohl in MS-DOS wie in UNIX - und daher auch das viele Gerede über die Kompatibilität (ein fürchterliches Wort) von MS-DOS und TOS. Wahr ist: Auf Diskettenebene verstehen sich MS-DOS und TOS ganz gut. Aber sonst werden Sie sich schön umschauen, wenn Sie eine PC-Datei auf einem ST zu starten versuchen.

MÜNCHHAUSEN UND DER ST

Nun zu einem weiteren rätselhaften Bereich auf der Diskette, dem Bootsektor. Der Bootsektor ist der erste Sektor auf der Diskette und wird bei jedem Diskettenwechsel überprüft. Er enthält wichtige Daten über das Format einer Diskette, kann aber auch selbst ein kleines Programm enthalten, das automatisch ausgeführt wird und das System hochbootet - er ist also der Haarschopf, an dem sich der Rechner selbst aus dem Sumpf zieht. Deshalb reagiert Ihr ST auch ziemlich heftig, wenn er so einen Bootsektor nicht lesen kann - hüten Sie also Ihre Systemdisketten wie Ihr Glasauge, machen Sie am besten eine Kopie auf eine hochwertige Diskette, schließen Sie sie weg, geschützt vor Kinderhänden, Hundeschnauzen, Kaffeetassen, Erdbeben, Feuer, Wasserrohrbruch und größeren intergalaktischen Katastrophen.

Es gibt zwei Typen von Bootsektoren: ausführbare und nicht ausführbare. Erstere werden für Systemdisketten verwendet, von denen das TOS gebootet wird. Ausführbare Bootsektoren werden vom Betriebssystem so abgeändert, daß ihre Checksumme (das heißt, die auf 16 Bit reduzierte Summe ihrer Bytes) gleich $ 1234 ist. Trifft das zu, versucht TOS, ein Programm im Bootsektor auszuführen.

Gemeinsam ist allen Bootsektoren folgender Aufbau: (Byte - Erklärung)

0-1
Verzweigungsbefehl auf Bootprogramm (wenn ausführbar)

2-7
’Loader’

8-10
24Bit-Seriennummer

11-12
BPS: Bytes pro Sektor (normal 512)

13
SPC: Sektoren pro Datencluster (normal 2)

14-15
RES: reservierte Sektoren (normal 1)

16
FAT: Anzahl der FATs (normal 2) 17-18

DIR: Anzahl der Einträge in der Directory (normal 112)

19-20
SEC: Anzahl der Sektoren auf der Diskette

21
MEDIA: „Media-Descriptor-Byte“

22-23
SPF: Sektoren pro FAT

24-25
SPT: Sektoren pro Track

26-27
SIDE: Anzahl der Seiten (SF354:1 SF314:2)

28-29
HID: versteckte Sektoren 510-511

Ausgleichswerte für die Checksumme (Differenz der Checksumme über die voranstehenden Bytes und $1234)

Alle 16-Bit-Worte sind wieder im 8086/ INTEL-Format abgesichert (also niedrigstwertiges Byte zuerst). Bei ausführbaren Bootsektoren sind weitere Bytes interessant:

30
EXEC: Ist das Flag gesetzt, wird versucht, nach dem Betriebssystem gleich COMMAND.PRG zu finden und zu starten (ohne Umweg über das DeskTop)

32
MODE: Ist MODE Null, wird das File FNAME gesucht. Wenn nicht, ist man im „Sektormodus“: Es werden einzelne Sektoren geladen (siehe SCNT und START)

34
START: erster Sektor, der bei MODE= 1 geladen werden soll

36
SCNT: Anzahl der Sektoren, die bei MODE=l geladen werden sollen

38
ADDR: Speicheradresse, wohin das Bootfile oder die Sektoren geladen werden sollen

42
Speicheradresse, wohin FATs und Directory geladen werden sollen

46
FNAME: Filename bei MODE=0 (maximal 11 Zeichen)

58
Anfang des Bootprogramms

Alle diese Flags werde ich Ihnen ganz bestimmt nicht vorkauen, sonst paßt in dieses Heft höchstens noch das Vorwort hinein. Aber einige interessante Stellen werden wir uns schon ansehen.

Besorgen Sie sich zunächst einmal einen ausführbaren Bootsektor. Sie haben doch sicher noch eine bootfähige Systemdiskette? Wenn nicht, formatieren Sie eine Diskette mit HYPERFORMAT und geben Sie dabei an, daß sie ausführbar sein soll. HYPERFORMAT erzeugt dann einen ausführbaren Bootsektor auf Track 0, Sektor 1. Lesen Sie mit Ihrem Diskmonitor den Bootsektor ein und ändern Sie EXEC (Byte 30, hexadezimal $1E) von Null auf Eins. Jetzt müssen Sie noch in den Ausgleichsbytes eine Eins abziehen, damit die Checksumme wieder stimmt. Schreiben Sie diesen modifizierten Sektor auf Ihre Diskette zurück und kopieren Sie auf diese Diskette ein TOS. IMG, ein DESKTOP.INF und ein COMMAND.PRG. Drücken Sie den Reset-Knopf, und Sie werden sehen, daß COMMAND.PRG noch vor dem Desktop ausgeführt wird.

Das kann man dazu verwenden, komplizierte Bootvorgänge auszuführen. Denn wenn COMMAND.PRG startet, sucht es auf der Diskette eine Batchdatei namens AUTOEXEC.BAT und führt sie aus, falls vorhanden. Wenn Sie sich also so eine Diskette zurechtgezimmert haben, brauchen Sie wirklich nur noch den Netzschalter, um Ihr System hochzufahren, wie Sie es wollen - beispielsweise mit installierter, gefüllter RAM-Disk, sauber geführtem Logbuch und einer fertigen Anwendung. Allerdings macht TOS beim Ausstieg aus COMMAND.PRG per ’exit’ noch Arger. Ich nehme an, daß das an nicht initialisierten GEM-Vektoren liegt - vielleicht hat sich ja schon ein Leser damit herumgeschlagen und kann darüber berichten.

Sie ahnen bestimmt, welche Tricks mit dem Bootsektor möglich sind. Andern Sie doch mal FNAME von TOS. IMG nach UNIX.IMG, ebenso den Namen von TOS.IMG auf Ihrer Bootdiskette und verblüffen damit Ihre Freunde! Oder gaukeln Sie Ihrem Rechner vor, das Laufwerk hätte 3 Seiten, 150 Spuren oder 0 Sektoren pro Track. Kürzen Sie die Anzahl der FATs oder deren Größe (vielleicht auch die der Directory) und gewinnen so Speicher auf der Diskette. Allerdings müssen Sie bei allen Änderungen auf einem ausführbaren Bootsektor immer die Checksumme ausgleichen, indem Sie die letzten beiden Bytes des Bootsektor abändern!

Das sollte Ansporn genug sein, sich mit dem Bootsektor zu beschäftigen. Es sei noch angemerkt, daß Sie natürlich nicht gezwungen sind, vom Bootsektor immer nur TOS.IMG zu laden...

Sollten Sie im Verlauf des Artikels bisher nicht alle Details verstanden haben, machen Sie sich keine großen Sorgen: Daran erkennt man die besonders nachdenklichen Menschen. Probieren Sie ein bißchen mit Ihrem Diskmonitor herum, kopieren oder löschen Sie Dateien, formatieren Sie mal normal, mal mit HYPERFORMAT, schnippeln Sie am Bootsektor herum und schauen Sie sich die Ergebnisse an. Kurz: Spielen Sie (das kann man auch ohne Joystick)! Was Sie dabei lernen, ist die Zeit sicher wert.

Wenn Sie beim Spielen einmal TOS-Fehlernummern bekommen (solche, die per Alert-Box im Desktop angezeigt werden), dann sind das bestimmt die Fehlernummern 33 und 35. Andere Nummern werden nicht angezeigt, obwohl TOS mehr Fehler unterscheidet. Das liegt an einem Fehler gerade in jener Routine des TOS, die die Fehler erkennen soll - ist das nicht tragisch? Man kann nur hoffen, daß ATARI bei den Mega-ST-Roms auch an diesen Fehler denkt.

Überhaupt gibt es allerlei Fehler in den ROMs. Bei dieser Gelegenheit möchte ich die wichtigsten, die mir aufgefallen sind, erwähnen:

  1. Die Laderoutinen sind äußerst langsam. Das liegt daran, daß TOS vor jedem Lesevorgang lieber zweimal nachprüft, ob der Lesekopf auch wirklich über der richtigen Spur liegt - was aber ziemlich unnötig ist. FAST-ROMs beheben diesen Fehler beim ROM-TOS, FASTLOAD und HYPERFORMAT beim RAM-TOS.
  2. Zuweilen kommt es vor, daß man ein Dokument auf dem Desktop anklickt und es sich auf dem Schirm anzeigen lassen will. Unter bestimmten (ungeklärten) Umständen stürzt TOS selbst bei dieser primitiven Routine ab (2-10000 Bomben)!
  3. Dialoge, die Fehler haben, deren Eingabemaske (alpha) numerisch definiert wurde, stürzen ab, wenn man den Unterstrich (_) eingibt.
  4. Fehler bei mehr als 40 Unterverzeichnissen (siehe oben).
  5. Im Desktop lassen sich weder Ordner- noch Diskettennamen ändern. Das liegt hauptsächlich daran, daß die zugehörige GEMDOS-Funktion RENAME ($56) keine solchen speziellen Dateien umnennen kann. Zwar ist im Aufruf ein Dummywort vorgesehen, das wahrscheinlich gerade zur Unterscheidung der Dateitypen dienen sollte, doch bewirkt es nichts.
  6. Fehler in der Fehlerroutine (siehe oben).
  7. Wenn man sich das Desktop mal in Zeitlupe anschaut, erkennt man, daß Window-Elemente oft mehrere Male gezeichnet, gelöscht und wieder gezeichnet werden. Darunter leidet die Geschwindigkeit.
  8. Unsauberkeiten beim Dateikennzeichen (siehe oben).

Wenn Sie weitere Fehler entdeckt haben, melden Sie sich! Wenn erst genug Fehler bekannt werden, nimmt sich ATARI vielleicht ein Flerz und killt die Bugs im ROM der Mega-STs.

Im letzten Teil dieser Folge möchte ich ein bißchen theoretischen Untergrund aufbauen, damit wir demnächst selbst einen Kopierschutz auf Disketten erzeugen können. Grundsätzlich einmal: Kopierschutz basiert immer darauf, den Disketten Eigenschaften mitzugeben, die Kopierprogramme nicht erwarten und deswegen nicht richtig übertragen können. Das jeweilige Programm fragt dann nach dem Starten auf diese besondere Eigenschaft ab. Flat die Diskette diese herstellerbedingte Macke, ist alles in Ordnung, das Programm hat einen ehrlichen Anwender vor sich. Fehlt der gewisse Tick, verabschiedet sich das Programm je nach Temperament des Programmierers mit einem bloßen ’Un-authorized Copy - Byebye’ oder mit frisch-fröhlichem Formatieren der Diskette, wobei sich proportional zur Reaktion des Programms das Gesicht des üblen Kopierers verfinstert.

Zur Erinnerung noch einmal die Grobstruktur einer Diskette: 80 Spuren sind jeweils in mehrere Sektoren (normalerweise 9) eingeteilt. Daraus ergibt sich bereits die erste Idee für einen Kopierschutz: Im Bootsektor gibt man an, daß auf jeder Spur nur 9 Sektoren sind, in Wirklichkeit aber formatiert man die Spuren auf 10 Sektoren. Ein argloses Kopierprogramm kopiert friedlich 9 Sektoren und vergißt den jeweils zehnten, ohne den das Programm nicht lauffähig ist.

Allerdings gibt es kaum noch ein Kopierprogramm, das auf einen solch simplen Trick noch hereinfällt. Eine verfeinerte Version dieses Kopierschutzes arbeitet mit variabler Sektoranzahl, das heißt, mal 5, dann 8, schließlich 10 Sektoren, wild durcheinander. Da muß ein Kopierprogramm schon schlauer sein und erst einmal vor dem Lesen jede Spur genau analysieren. Aber auch das ist bereits Standard.

Eine andere Idee: Wie Sie aus der letzten Folge bereits wissen, kann man die Sektoren nicht nur einfach hintereinander auf die Spur formatieren, sondern auch versetzt (Interleave), zum Beispiel so:

S(ektor) 1 S3 S5 S7 S9 S2 S4 S6 S8

Nehmen wir an, wir wollen Sektor 1 bis 9 lesen. Das funktioniert auch ganz prächtig. Ein unachtsames Kopierprogramm schreibt aber die Sektoren anders auf die Zieldiskette:

S1 S2 S3 S4 S5 S6 S7 S8 S9

Diesen Unterschied kann ein Programm dadurch herausfinden, indem es die Zeit mißt, die beim Lesen zweier aufeinanderfolgender Sektoren verstreicht - die ändert sich nämlich, wenn man am Interleave manipuliert. Nachteil dieses Kopierschutzes: Er kann auch mal ansprechen, wenn ein Laufwerk benutzt wird, das die Drehzahl nicht richtig einhält - und so auch ehrlichen Anwendern schaden.

Am gewalttätigsten aber sind Kopierschutzmechanismen, die an der Struktur der Sektoren selbst drehen. Zur Erinnerung - ein Sektor sieht beim ST so aus:

Vorspann (Index, Trackheader; "PoST Index Mark”)

(*) Lückenbytes (Pre Adress Mark) Synchronisationsbytes Adressmarke + Sektorinfo Checksumme

Lückenbytes (PoST Adress Mark) Synchronisationsbytes Datenmarke + DATEN Checksumme

Lückenbytes (PoST Data Mark)

zurück zu (*), bis alle Sektoren geschrieben sind, danach: Lückenbytes bis zum Trackende.

Als Kopierschutz könnte man jetzt die Anzahl der Synchronisations- oder Lückenbytes ändern. Kopien erkennt man wieder z. B. durch Zeitunterschiede (das ist allerdings sehr knifflig). Mein Formatierprogramm HYPERFORMAT, das Sie aus der letzten ST kennen, ist - wenn Sie so wollen -auch ein Kopierschutz, weil es ähnliches tut, um 11 Sektoren auf einer Spur unterzubringen. Ich kenne nur wenige Kopierprogramme, die HY-PERFORMATierte Disketten korrekt lesen können (das normale Filecopy des Desktop funktioniert dagegen hervorragend!). Deswegen sei an dieser Stelle auch ein Kopierprogramm für dieses Format angekündigt.

Ganz hartnäckig ist ein Schutz, wenn er im Controller Fehler erzeugt: Sei es, indem man die Checksummen im Sektor manipuliert, sei es durch sogenannte halbe Sektoren, das heißt, man kündigt dem Controller zwar einen Sektor mit 512 Bytes an, liefert aber nur 200 oder 300. Normalerweise meldet sich der Controller dann mit einem Lesefehler und streikt - und nur sehr gute Kopierprogramme sind dann so schlau und lassen das Laufwerk solange rotieren, bis sie jedes Byte rekonstruiert haben. Hier findet man eigentlich die größte Vielfalt von Ideen: Man könnte auch Sektoren mit jeweils 1024 Bytes einführen, die zwar der Controller lesen kann, aber nur mit speziellen Leseroutinen. Oder man vergißt Datenmarken, das sind Stopschilder für den Controller, an denen er innehält und weiß: Hoppla, jetzt kommen Daten.

So, jetzt habe ich Ihnen aber den Mund lange genug wäßrig gemacht. Diese Folge hat Ihnen gezeigt, wie Sie mit Directory und Bootsektor umspringen können. Sie haben jetzt ein Diskcheck-Programm, einen kleinen Diskmonitor in GfA-Basic, den wir schrittweise erweitern werden, sind jetzt vielleicht etwas aufmerksamer, was TOS-Fehler angeht und wissen -zumindest vom Prinzip her - wie ein Kopierschutz funktioniert. In der nächsten St werden wir uns daran machen, selbst einen Kopierschutz zu entwerfen. Wenn Sie ganz tief einsteigen wollen, dann halten Sie bis dahin Assembler-Kenntnisse bereit. Aber keine Angst: Für die Nur-Basic-Programmierer gibt es eine Einbindung der benötigten Routinen in BASIC. Keep hacking!

In den Untergrund

Tiefer in das Reich des Lesekopf können Sie mit dem MINIMON tauchen. Er ist in GfA-Basic verfaßt und besteht aus zwei Teilen, dem Sektormonitor und dem Trackmonitor. Der Trackmonitor ist noch nicht implementiert. Wir werden ihn im Laufe der Zeit vervollständigen, wenn wir im Kurs neue Tricks besprechen. Nach dem Start hat man die Auswahl zwischen Sektormonitor (S), Trackmonitor (T) und Quit (Q). Der Sektormonitor bietet folgende Funktionen:

Track einstellen: (’T’)
Eingabe der Spurnummer (bei mehr als 80 wird’s gefährlich für den Lesekopf Ihrer Floppy).

Seite einstellen: (’S’)
Vorder- oder Rückseite (0/1). Jede andere Nummer ist sinnlos, die 1 ohnehin nur für Besitzer doppelseitiger Laufwerke brauchbar.

Sektor einstellen: (’K’)
Sektornummer eingeben. Sinnvoll sind bei normalen Format 1-9, bei FAT-DISK und ähnlichen Formaten 1 -10, bei HYPERFORMAT 1-11.

Read sector: (’R’)
Den vorher mit ’T’, ’S’, ’K’ eingestellten Sektor in einen Puffer im Speicher einiesen.

Write sector: (’W’)
Den Pufferinhalt an die mit ’T’, ’S’ und ’K’ eingestellte Stelle schreiben.

Dump sector: (’D’)
Den Pufferinhalt ausgeben. Eine Zeile sieht so aus: [Bytenr] [16 Bytes] [ASCII]. Mit SPACE kann man die Ausgabe anhalten, mit irgendeiner anderen Taste abbrechen.

Edit: (’E')
Ein Byte im Puffer ändern. MINI-MON fragt zunächst nach der Nummer des Bytes (mit DUMP zu erfahren), dann nach dem neuen Inhalt des Bytes. Sie können den neuen Wert als Zahl eingeben oder (in ’ - Zeichen eingeschlossen) als ASCII-Zeichen.

Printer: (’P’)
Schaltet Druckerausgabe ein/aus.

Execute: (’X’)
Anderes Programm ausführen. Zeigt das Verzeichnis an und erlaubt, ein anderes Programm zu starten, von dem aus man wieder zum Minimon zurückkehren kann. Diese Funktion können Sie auch benutzen, um nur ein Verzeichnis auf den Schirm zu bringen. Sollten Sie am Directorysektor etwas geändert haben, empfiehlt es sich, vor ’X’ die Diskette kurz herauszuziehen und wieder einzusetzen.

Quit: (’Q')
Raus aus dem Sektormonitor.

Bei Lese- und Schreibvorgängen ermittelt MINIMON den Status des Laufwerks und zeigt ihn in der Statuszeile an.

Zum Programm selbst:

Am interessantesten' ist wohl der Betriebssystemaufruf in der Prozedur Lesen:

Status% = Xbios(8,L:Buffer%,L:0, Drive%, Sector%, Track%,Seite%,l)

Hier wird das XBIOS des ST aufgerufen und ihm verschiedene Parameter übergeben. ’8’ ist die Nummer der Leseroutine im XBIOS. ’L:Buffer%’ gibt die Adresse eines Puffers im Speicher an, wohin XBIOS den Sektorinhalt einiesen soll. ’L:’ ist GfA-spezifisch und erzwingt die Parameterübergabe als Langwort. Fehlt ’L:’, nimmt GfA-BASIC an, daß der Parameter Wortgröße haben soll. Nach Buffer% folgt ein (noch) vom Betriebssystem unbenutztes Langwort, sodann die Angabe des Laufwerks (hier voreingestellt mit 0 für Laufwerk A; Laufwerk B ist dann 1, C entspricht 2 usw.). Es folgen Sektor, Track, Seite und eine ominöse 1: Es soll nur ein Sektor eingelesen werden. Der Systemaufruf in der Prozedur Schreiben ist bis auf die Funktionsnummer identisch.

Wichtig: In der ST lief ja bereits eine Serie über das Betriebssystem, wo alle Parameter bei den Aufrufen angegeben waren. Für GfA-Basic ist anzumerken, daß alle Parameter hier (wie in C) in umgekehrter Reihenfolge hinzuschreiben sind; in Assembler steht die Funktionsnummer als letztes, in Basic als erstes.

*****************
* CHKDISK
* Testet eine Diskette in Laufwerk A
* (auch HYPERFORMATiert)
* auf fehlerhafte Sektoren
*
* Written 1987 by Claus Brod
* Version 1.0, last update 23.5.1987
*
****************

start:
move.l a7,a5    * Speicherplatz reservieren
move.l 4(a5),a5
move.l $c(a5),d0
add.l $14(a5),d0
add.l Slc(a5),d0
add.l #$500,d0  * stack
move.l d0,d1 add.l a5,d1
and.l #-2,d1    * gerade machen
move.l d1,a7
move.l d0,-(sp)
move.l a5,-(sp)
clr.w -(sp)
move.w #$4a,-(sp)
trap #1
add.l #12,sp

******************
* Hauptschleife
******************

lea header(pc),a2   * Begrüssung
bsr printmsg    * ausgeben
bsr parameter   ■   Parametereingabe
bsr main    * Ab    ins Hauptprogramm

exitus: * Sense
clr.w -(sp)
trap #1

*******************
* Prüfschleife 
*******************


main:
move.w #0,a4    * Aktueller Track
move.w #1,a5    * Aktueller Sektor
move.w #0,d6    * Aktuelle Seite

*****************
* Sektor lesen 
*****************

readsec:
move.w #1,-(sp) * nur 1 Sektor lesen
move.w  d6,-(sp)    * Seite
move.w  a4,-(sp)    * Track
move.w  a5,-(sp)    * Sektor
move.w #0,-(sp) * Laufwerk A
clr.l -(sp)
move.l #buffer,-(sp)    * Pufferadresse
move.w  #8,-(sp)    * Sektor lesen
trap #14    * XBIOS
add.l #20,sp
tst.b d0    * Fehler passiert?
bne fehler  * ja, zur Fehlerroutine
next:
addq.w #1,a5    * Nächster Sektor
cmp.w spt(pc),a5    * letzter Sektor?
bls readsec
move.w #1,a5    * Sektor 1

lea sides(pc),a2
cmp.b #1,(a2)   * 1 oder 2 Seiten
beq nexttrack   * nur eine Seite
sor.w #1,d6 * Seite wechseln
bne readsec * schon auf 0 gewechselt? nein, lesen
nexttrack:
bsr printtrack  * Tracknummer ausgeben
addq.w #1,a4    * nächster Track
cmp.w end(pc),a4    * schon alle Tracks?
bne readsec * nein, lesen
rts

*****************
* Fehlerroutine 
*****************

fehler:
lea s_error(pc),a2  * Fehlernummer ausgeben
bsr mkhex
lea m_error(pc),a2  * Fehlerstring ausgeben
bsr printmsg

move.w a4,d0    * Track ausgeben
lea s_track(pc),a2  * String für Track
bsr mkhex   * Hexzahl schreiben
lea m_track(pc),a2 
bsr printmsg

move.w a5,d0    * Sektor ausgeben
lea s_sec(pc),a2
bsr mkhex
lea m_sec(pc),a2
bsr printmsg

move.w d6,d0    * Seite ausgeben
lea s_side(pc),a2
bsr mkhex
lea m_side(pc),a2
bsr printmsg

bra next    * nächster Sektor

******************
* String ausgeben
******************

printmsg:   * String ausgeben (in: A2)
move.l a2,-(sp) * Adresse des Strings
move.w #9,-(sp)
trap #1
addq.l #6,sp
rts

******************
* Track ausgeben
******************

printtrack:         * Tracknummer ausgeben
move.l a4,d0
lea s_akt(pc),a2
bsr mkhex
lea m_akt(pc),a2
bsr printmsg
rts

*****************
* D0 nach hexadezimal wandeln
*****************

mkhex:  * Hexzahl erzeugen (in:DO)
move.l #1,d1    * Nur ein Byte

nochnbyte:
clr.l d2 
move.l d0,d2
asr.l #4,d0     * Ein Nibble weiterschieben
and.l #$0f,d2   * ausmaskieren
cmp.b #9,d2     * Zahl oder Buchstabe?
bis zahl
add.b #7,d2     * 7 addieren (Buchstabe)
zahl:
add.b #48,d2    * 48 addieren
move.b d2,0(a2,d1)  * Ergebnis schreiben
dbf d1,nochnbyte    * weiteres Byte wandeln?
rts

*******************
* auf Taste warten
*******************

getkey: * auf Taste warten (con in
move.w #7,-(sp) * without echo)
trap #1
addq.l #2,sp
rts

*********************
* Parameter-Menü ausgeben und 
* auf Eingaben warten
*********************

parameter:  * auf Eingabe von neuen Parametern
lea m_end(pc),a2    * warten
bsr printmsg

bsr getkey  * auf Taste warten

cmp.b #3,d0     * C?
beq exitus      * ja, raus
cmp.b #13,d0    * RETURN?
beq fertig      * ja, mit Check anfangen
cmp.b #'s',d0   * Seitenanzahl
beq op_sides    * ändern
cmp.b #'S',d0
beq op_sides
cmp.b #'t',d0   * Trackanzahl
beq op_tracks   * ändern
cmp.b #'T',d0 
beq op_tracks
cmp.b #'p',d0   * Sektorenanzahl
beq op_spt      * ändern
cmp.b #'P',d0
beq op_spt
bra parameter
fertig:
rts

*******************
* Seitenzahl ändern
*******************

op_sides:   * Anzahl der Seiten ändern
lea sides(pc),a2
lea s_seiten(pc),a3
eor.b #3,(a2)
eor.b #3,1(a3)
bra parameter

*******************
* Trackzahl ändern
*******************

op_tracks:      * Anzahl der Tracks ändern
lea end(pc),a2 
lea s_end(pc),a3 
move.b 1(a2),d0 
move.b 1(a3),d1 
addq.b #1,d1 
addq.b #1,d0
cmp.b #85,d0    * mehr als 85 sind nicht
bis trackok * drin
move.b #80,d0   * Startwert
move.b #'0',d1
trackok:
move.b d0,1(a2) 
move.b d1,1(a3) 
bra parameter

********************
* Sektoren pro Track ändern
********************

op_spt: * Anzahl der Sektoren pro
lea spt(pc),a3  * Track ändern
lea s_spt(pc),a2
move.b 1(a3),d0
addq.b #1,d0
cmp.b #11,d0
bis sptok
move.b #1,d0
sptok:
move.b d0,1(a3) 
bsr mkhex 
bra parameter

.even

* Fehlermeldung

m_error:
.dc.b 7,'Fehler ' 
s_error:
.dc.b '00',13,10,0 
m_track:
.dc.b ' bei Track: '
s_track:
.dc.b '00',13,10,0 
m_sec:
.dc.b ' Sektor:'
s_sec:
.dc.b '00',13,10,0 
m_side:
.dc.b ' Seite: ’
s_side:
.dc.b '00',13,10,13,10,0 
.even

* Begrüßung 

header:
.dc.b 27,’E',27,'pDISKCHECK’,27,'q',13,10 
.dc.b 'Written 1987 by Claus Brod'
.dc.b 13,10,0

m_end:
.dc.b 27,'Y',32+5,32+0,27,'pT',27,'qracks: '
s_end:
.dc.b '83',13,10 
m_seiten:
.dc.b 27,'pS',27,'qeiten: ' 
s_selten: 
dc.b '02',13,10 
m_spt:
.dc.b 'Sektoren ',27,'pp',27,’qro Track: $' 
s_spt:
.dc.b '0B',13,10
.dc.b 13,10,'RETURN Check starten',13,10 
.dc.b 'CTRL-C Abbrechen',13,10,0

m_akt:
.dc.b 27,'j',27,’Y’,32+0,32+65,'Track: ' 
s_akt:
.dc.b '00',27,'k',0 

end:
.dc.w 83 
spt:
.dc.w 11 
sides:
.dc.b 2

.bss
buffer:         * Sektorpuffer
.ds.b 512

Listing 1: Source Code

' Minimon für den ST 
' Written 1987 by Claus Brod
' Am Felsenkeller 2 
' 8772 Marktheidenfeld
'
Cls
Do
    Print
    Print "Minimon ST - (C) 1987 by Claus Brod"
    Print
    Repeat
        Print "Sektormonitor oder Trackmonitor oder Quit (S/T/Q)?" 
        A$=Upper$(Input$(1))
    Until A$="S" Or A$="T" Or A$="Q"
    Exit If A$ = "Q"
    If A$ = "S"
        @Sektormon
    Else
        @Trackmon
    Endif
Loop
End
'
'
Procedure Gibmirzeit
    Alert 1,"Funktion noch nicht|implementiert.",l,"OK",A 
Return
'
' Das Modul Trackmon wird im Laufe des Kurses noch 
' vervollständigt
'
Procedure Trackmon 
    @Gibmirzeit 
Return
'
' Sektormon: Kleiner Diskmon mit Standardfähigkeiten
'
Procedure Sektormon 
    Cls
    Prn%=0
    Status%=0
    Seite%=0
    Track%=0
    Sector%=1
    Drive%=0
    Sec$=Space$(5i2)
    R$=Chr$(27) + "p"
    O$=Chr$(27) + "q"
    @Lesen
    Do
        Print
        Print "....... Minimon (C) 1987 Claus Brod Status: ";Status%;........"
        Print R$;"R";OS:"ead, ";R$;"W";OS;"rite, ";R$;"T";O$;"rk (";Track%;"), ";
        Print R$;"S";0$;"eite (";Seite%;"), Se";R$;"k";OS;"tor (";Sector%;"), ";
        Print R$;"E";0$;"dit, ";R$;"D";O$;"ump, ";R$:"P";0$;"rn (o";
        If Prn%
            Print "n), ";
        Else
            Print "ff), ";
        Endif
        Print "E";RS;"x";O$;"ec, ";R$;"Q";O$;"uit”
        M$ = Upper$(Input$(1))
        If M$ = "X"
            @Exe 
        Endif 
        If M$="P"
            Prn%=1-Prn%
        Endif 
        If M$ = "T"
            Input "Track";Track%
        Endif 
        If M$ = "S"
            Input "Seite";Seite%
        Endif 
        If M$ = "K"
            Input "Sektor";Sector%
        Endif 
        If M$ = "R"
            @Lesen 
        Endif 
        If M$ = "W"
            @Schreiben
        Endif
        If M$ = "E" 
            @Edit 
        Endif 
        If M$ = "D"
            @Dump
        Endif
        Exit If M$ = "Q"
    Loop
Return
'
' Sektor einlesen
'
Procedure Lesen
    Buffer%=Varptr(Sec$)
    Status%=Xbios(8,L:Buffer%,L:0,Drive%,Sector%,Track%,Seite%,1)
Return
'
'
' Sektor schreiben
'
Procedure Schreiben 
    Buffer%=Varptr(Sec$)
    Status%=Xbios(9,L:Buffer%,L:0,Drive%,Sector%,Track%.Seite%,1)
Return
'
' Sektorpuffer ausgeben
'
Procedure Dump 
    If Prn%=0
        Open "O",#1,"con:"
    Else
        Open "O",#1,"prn:"
    Endif
    Print #1,"Track: ";Track%;" Sektor: ";Sector%;" Seite: ";Seite%
    For T=1 To 512 Step 16
        A$=Str$(T-1)
        While Len(A$)<3 
            A$="0"+A$
        Wend 
        D$ = "   "
        Print #1,A$;D$;
        For I=0 To 15
            V$=Mid$(Sec$,T+1,1)
            A$ = Hex$(Asc(V$))
            If V$<" " Or V$>"z"
                V$="."
            Endif
            Print #1,Right$("0"+A$,2)'
            DS=D$+V$
        Next I 
        Print #1,D$
        A$=Inkey$
        If A$ = " "
            A=Inp(2)
        Endif
        Exit If A$>"" And A$<>" "
    Next T 
    Close #1 
Return
'
' Byte ändern
'
Procedure Edit
    Input "Byte Nr.";Byte%
    Print "Alter Wert ist: ";Asc(Mid$(Sec$,Byte%+1,1)) 
    Input "Neuer Wert in dezimal oder ASCII";Wert$ 
    Wert%=Val(Wert$)
    If Wert%=0 And Left$(Wert$,1)<>"0" 
        Wert%=Asc(Wert$)
    Endif
    Mid$(Sec$,Byte%+1,1)=Chr$(Wert%)
Return
'
'
' anderes Programm ausführen
'
Procedure Exe
    Fileselect "*.*","",Sel$
    If Exist(Sel$)<>0 
        S=Fre(0)
        Reserve 50000 
        Showm
        Exec 0,Sel$,"",""
        Reserve S-1000 
    Endif 
Return

Listing 2: Diskmonitor in GFA-Basic
Claus Brod


Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]