Autor Beitrag
freaktonx
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Mo 19.07.10 13:33 
Hey,

Ich habe da ein Problem. Es geht um WriteProcessMemory und ReadProcessMemory.

1.Ich habe mich ein wenig schlau gemacht und habe folgenden Code gefunden.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
adresse:=ptr($106445A8);  // Adresse des Pointers
  hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  ProcessEntry.dwSize := Sizeof(ProcessEntry);
  Schleife := Process32First(hSnapshot, ProcessEntry);
  while Schleife do
  begin
    if (CompareText(ProcessEntry.szExeFile, ProcessName) = 0then
      pID := ProcessEntry.th32ProcessID;
    Schleife := Process32Next(hSnapshot, ProcessEntry);
  end;
  CloseHandle(hSnapshot);
  hProcess := OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);

ReadProcessMemory(hProcess, adresse, @wert, SizeOf(wert), BytesRead);
adresse := Ptr(wert + $10a2b8);
ReadProcessMemory(hProcess, adresse, @wert, SizeOf(wert), BytesRead);
CloseHandle(hProcess);

// ausgabe des wertes der gelesenen Adresse
  Label1.Caption :=inttostr(wert);


Der Code funktioniert auch super nur habe ich das Problem das die Value vom Typ Float und nicht Byte ist. Kann mir jemand sagen wie ich den Float Wert ermitteln kann? Ich habe auch schon versucht SizeOf(single) zu machen aber funzt auch nicht.

2.Ich habe ebenfalls einen Code zum Thema WriteProcessMemory gefunden.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
 var
  c : Cardinal;
  buf,buf1: pchar;
begin
  c:=FindWindow(nil,'Fenstername'); //Get WindowHandle
  buf := #01#00#00#00;
  if c=0 then
  begin
    MessageDlg('Fehlermeldung',mtwarning,[mbOK],0);
    Exit;
  end;
  GetWindowThreadProcessId(c,@c); //Get ProcessID and ignore ThreadID
  c:=OpenProcess(PROCESS_ALL_ACCESS,False,c);  //Get ProcessHandle
  WriteProcessMemory(c,Pointer($0018ECE4),buf,4,write);
  CloseHandle(c);
end;


Meine Frage dazu wie kann ich in der Prozedur mit Offsets arbeiten? Ich habe es so versucht:WriteProcessMemory(c,Pointer($0018ECE4+$DDC),buf,4,write);
und so:
WriteProcessMemory(c,Pointer($DDC+$0018ECE4),buf,4,write);
beides funktioniert nicht.

Bin für jede Antwort dankbar.

gruß freaktonx
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Di 20.07.10 09:27 
Hallo und :welcome: in der Entwickler Ecke.

Ich kann keine Variable namens Value finden, du meinst sicherlich Wert. Float sind, wenn ich mich nicht irre, 6 Bytes. Du deklarierst einfach "Wert" als Float und versuchst es mal damit. Bei deinem Aufruf musst du nichts ändern nur zur Anzeige geht dann natürlich nicht mehr IntToStr.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Di 20.07.10 10:53 
Du solltest dich mit folgendem Beschäftigen
1) Pointer und wie sie funktionieren.
2) Was Read/WriteProcessmemory machen --> Zusammenhang zu pointern
3) Was ein Offset bedeutet
4) GANZ WICHTIG: Was ist eine Addition?

Sry aber fällt dir hierran was auf:?
Zitat:
WriteProcessMemory(c,Pointer($0018ECE4+$DDC),buf,4,write);
und so:
WriteProcessMemory(c,Pointer($DDC+$0018ECE4),buf,4,write);
freaktonx Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Di 20.07.10 20:17 
@Sinspin
Ja genau mit Value meinte ich Wert. Wie hast du das gedacht Wert als Float zu deklarieren? Ich habe das mit:
 wert : Real;
da kommt aber ne Fehlermeldung.

@Flamefire
Also ich habe mich heute mal ein bisschen mehr die 4 Punkte von dir informiert aber zu einer Lösung bin ich nicht gekommen . Und ja daran ist mir was aufgefallen!! Man muss ja nicht den Pointer mit dem Offset addieren sondern die Adresse auf die der Pointer zeigt. Also kann das so nicht gehen:
ausblenden Delphi-Quelltext
1:
2:
WriteProcessMemory(c,Pointer($0018ECE4+$DDC),buf,4,write);
WriteProcessMemory(c,Pointer($DDC+$0018ECE4),buf,4,write);

oder sehe ich das falsch?

gruß freaktonx
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Di 20.07.10 20:35 
Verständnisfrage: Kann eine der 2 Lösungen funktionieren, wenn die andre nicht funktioniert? (Angenommen, das Offset usw ist richtig)

Wenn du dich mit Pointern beschäftigt hast dann hier eine Hilfe:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
var p1:PInteger;
    i,j:Integer;
begin
p1:=@i;
i:=55;
//p1^ = 55
p1^:=20;
//i = 20
j:=30;
Move(i,j,sizeOf(i));
//i=30
j:=25;
Move(p1^,j,sizeof(Integer));
i=25;
end;


Und wenn das Handle h = das des eigenen Prozesses ist, dann gilt: (buf ist datentyp (integer, cardinal, array...), ptr ein beliebiger pointer, count ein int)
ReadProcessMemory(h,ptr,buf,ct,ict) = Move(buf,ptr^,ct)
WriteProcessMemory(h,ptr,buf,ct,ict) = Move(ptr^,buf,ct)

Wenn du irgendwas nicht verstehst, dann hast du dich nicht mit Pointern beschäftigt ;-)
freaktonx Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Mi 21.07.10 02:09 
Ich steig da irgend wie nicht ganz durch. Was soll mir das Beispiel zeigen?

gruß freaktonx
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Mi 21.07.10 10:39 
das beispiel soll dir zeigen, was pointer machen, und wie der move befehl arbeitet in analogie zu pointern, damit du die analogien zu RMP und WPM (die ich drunter geschrieben hab) verstehst.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Mi 21.07.10 12:10 
user profile iconfreaktonx hat folgendes geschrieben Zum zitierten Posting springen:
@Sinspin
Ja genau mit Value meinte ich Wert. Wie hast du das gedacht Wert als Float zu deklarieren? Ich habe das mit:
 wert : Real;
da kommt aber ne Fehlermeldung.

Hach ja, Float gibt es bei Delphi ja nicht. In C ist Float ein 32 Bit (4 Byte) Gleitkommawert, jedenfalls laut der BDS 2010 Hilfe. Das entspricht in Delphi den Typ Single.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
freaktonx Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Mi 21.07.10 16:04 
Hey,
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
  
var
wert : single;
begin
adresse:=ptr($05583F2C); 
// Handle der fremden Anwendung besorgen
  hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  ProcessEntry.dwSize := Sizeof(ProcessEntry);
  Schleife := Process32First(hSnapshot, ProcessEntry);
  while Schleife do
  begin
    if (CompareText(ProcessEntry.szExeFile, ProcessName) = 0then
      pID := ProcessEntry.th32ProcessID;
    Schleife := Process32Next(hSnapshot, ProcessEntry);
  end;
  CloseHandle(hSnapshot);
  hProcess := OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);

ReadProcessMemory(hProcess, adresse, @wert, SizeOf(single), BytesRead);
Label1.Caption :=FloatToStr(wert);

Wenn der Code so ist funktioniert das ohne probleme. Thx schon mal dafür. Aber das Problem ist jetzt das addieren der Offsets.[/delphi]
Wenn ich das so lasse wie es vorher war also:
ausblenden Delphi-Quelltext
1:
2:
3:
ReadProcessMemory(hProcess, adresse, @wert, SizeOf(single), BytesRead);
adresse := Ptr(wert + $08);
ReadProcessMemory(hProcess, adresse, @wert, SizeOf(single), BytesRead);

dann kommt direkt ne Fehlermeldung. E2008 Incompatible types. Ist ja auch irgendwie logisch. Könnt ihr mir sagen was ich da jetzt machen soll/muss?

gruß freaktonx
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Mi 21.07.10 18:04 
Du kannst auch SizeOf(Wert) schreiben, das ist sogar besser falls du Wert mal änderst, da brauchst du nichts weiter anpassen.

Hm, ich denke mal der Fehler kommt in Zeile 2.
Ist ja auch logisch, Pointer sind Ganzzahlen, das was du da nimmst (Single) ist Gleitkomma. Also nicht für Adressoperationen gedacht.
ich vermute daher das an deinem programmaufbau was nicht passt.
Ich halte es für sehr Unwahrscheinlich das für den ersten Aufruf wirklich ein Floatwert genommen werden muss. Wahrscheinlich eher ein Unsigned-Int, was in Delphi einem LongWord gleich kommt.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
freaktonx Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Mi 21.07.10 18:49 
OMG ich hatte einen Denkfehler.^^ Ich habe es jetzt so gelöst:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
var
wert : Integer;
wert1 : single ;
begin  
adresse:=ptr($1069E02C);  // Adresse des Pointers
// Handle der fremden Anwendung besorgen
  hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  ProcessEntry.dwSize := Sizeof(ProcessEntry);
  Schleife := Process32First(hSnapshot, ProcessEntry);
  while Schleife do
  begin
    if (CompareText(ProcessEntry.szExeFile, ProcessName) = 0then
      pID := ProcessEntry.th32ProcessID;
    Schleife := Process32Next(hSnapshot, ProcessEntry);
  end;
  CloseHandle(hSnapshot);
  hProcess := OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);

ReadProcessMemory(hProcess, adresse, @wert, SizeOf(Wert), BytesRead);
adresse := Ptr(wert + $08);
ReadProcessMemory(hProcess, adresse, @wert, SizeOf(wert), BytesRead);
adresse := Ptr(wert + $F04);
ReadProcessMemory(hProcess, adresse, @wert1, SizeOf(wert), BytesRead);
Label1.Caption :=FloatToStrF(wert1,ffFixed,10,2);

Ich danke euch für die Hilfe. Zu dem Thema WriteProcessMemory ist mir auch gerade die Lösung eingefallen =):
ausblenden Delphi-Quelltext
1:
2:
3:
  ReadProcessMemory(hProcess, adresse, @wert, SizeOf(wert), BytesRead); //Adresse auslesen
  adresse := Ptr(wert + $DDC);                                          //Offset dazu addieren
  WriteProcessMemory(c,adresse,buf,4,write);                            //Wert schreiben


Eine Frage habe ich aber noch gibt es auch eine möglichkeit einen Gleitkommawert zu schreiben? Da ja buf:=#01#00#00#00 ist und ich keine Ahnung habe wie ich so ein Gleitkommawert ausdrücken soll.

gruß freaktonx
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Mi 21.07.10 18:59 
benenne deine variablen mal richtig...
dann kommen schonmal weniger fehler. bei dir heißt alles wert.
mach lieber basepointer. pointer1 o.ä.

und dann hatte ich gesagt:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
var x,y:Single;
    p:PSingle;
begin
p:=@x;
y:=20.3;
//1.
x:=y;
//2.
p^:=y;
//3.
Move(p^,y,sizeof(y));
//4.
WriteProcessMemory(h,p,y,sizeof(y));


1 bis 4 ist das gleiche (im eigenen prozess)
also jetzt nochmal ganz genau nachdenken, was du tust
freaktonx Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Mi 21.07.10 20:19 
Sry entweder ich habe gerade einen übelsten Blackout oder keine Ahnung. Ich verstehe nicht auf was du hinaus willst.
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Mi 21.07.10 21:35 
ok. dann mal langsam
ein pointer enthällt eine adresse. unter dieser adresse befinden sich Daten (meistens)
wenn du wie in meinem besipiel p nimmst, dann befindet sich an der adresse p der wert von x
p^ heißt demzufolge "greife auf den wert zu"
p^:=y; heißt schreibe y an die adresse p. sprich: kopiere den wert von adresse @y an adresse p
intern werden natürlich bytes verschoben. wieviele hängt vom typ ab.
bei PByte ist es 1 Byte, PWord 2 Byte, PInteger/PSingle usw. 4 Byte etc.

Move macht das ganze ebenfalls: es kopiert bytes von einer adresse an eine andere. nur dass man angibt wieviele.
RPM/WPM machen das gleiche nur auch für andere Prozesse als den eigenen

ABER: Es werden immer bytes kopiert. es ist egal was das mal war. also sind alle 4 varianten oben identisch.

was willst du also? Du willst einen Wert an eine bestimmte stelle schreiben. Also Bytes kopieren
sagen wir mal, wir sind im gleichen Prozess und wollen 20.3 an $1234 schreiben:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
p:PSingle;
x:Single;
begin
p:=Ptr($1234);
x:=20.3;
p^:=x;


fertig. schon haben wir an der adresse $1234 die 20.3 stehen. Da wir aber WPM brauchen, wäre das ganze mit nem Move besser zu verdeutlichen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
p:PSingle;
x:Single;
begin
p:=Ptr($1234);
x:=20.3;
Move(p^,x,sizeOf(x)); // Kopiere n Bytes von @x nach p; n ist die Größe des Datentyps von x. In dem Fall 4

Auch hier haben wir an der adresse $1234 die 20.3 stehen.

Alles klar soweit?
Der letzte Schritt WPM zu benutzen ist einfach, wenn du mir folgen konntest. Darum lasse ich den mal für dich ;-)

Für diesen Beitrag haben gedankt: freaktonx
freaktonx Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Mi 21.07.10 22:26 
Hey für die Erklärung gibts erstmal ein Thx.
Ich hoffe das ich das jetzt richtig verstanden habe.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
var
  c : Cardinal;
  p,p1:PSingle;
  x:Single;
begin
      c:=FindWindow(nil,'Fenstername)'); //Get WindowHandle
      if c=0 then
        begin
          MessageDlg('ErrorMessage',mtwarning,[mbOK],0);
          Exit;
        end;
      p:=ptr($0018ECE4);
      x:=40;
      GetWindowThreadProcessId(c,@c); //Get ProcessID and ignore ThreadID
      c:=OpenProcess(PROCESS_ALL_ACCESS,False,c);  //Get ProcessHandle
      ReadProcessMemory(hProcess, p, @wert, SizeOf(wert), BytesRead); 
      p1 := Ptr(wert + $DDC);                                          
      WriteProcessMemory(c,p1,x,sizeOf(4));                            
      CloseHandle(c);
    end;

Wenn das jetzt so richtig ist dann ist da trotzdem noch irgendwo ein Fehler da ich einen Error bekomme. E2010 Incompatible types: 'Pointer' and 'Single'. Demnach ist da ein Konflickt zwichen p und x.

gruß freaktonx
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Mi 21.07.10 22:43 
RPM/WPM kopiert bytes von adressen!
Also musst du auch adressen übergeben.
dein WPM aufruf muss also analog wie dein RPM aufruf aussehen.

noch hinweise:
1) wo ist wert definiert?
2) für adressen verwende ich meist Cardinal und mache die ptr typecasts im aufruf. lässt sich besser rechnen.
also:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var baseAdress,base,next:Cardinal;
begin
baseAdress:=$1234;
ReadProcessMemory(hProcess,Ptr(baseAdress),@base,..);
base:=base+$AFFE;
ReadProcessMemory(hProcess,Ptr(base),@next,..);
WriteProcessMemory(hProcess,Ptr(next+$DEAD),@...);


Alternativ mit Pointer. Nicht mit PSingle o.ä. Macht zwar im Prinzip keinen Unterschied, aber man könnte auf die idee kommen, es wäre ein gültiger Pointer im eigenen Prozess und man greift dann mit p1^ drauf zu -->AV
3) "sizeOf(4)" ??? Bitte nochmal nachdenken!
freaktonx Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Do 22.07.10 02:07 
Du verwirrst mich irgendwie! :D Ich habe gerade gedacht ich habe es kappiert ...
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var baseAdress,base,next:Cardinal;
begin
baseAdress:=$1234;
ReadProcessMemory(hProcess,Ptr(baseAdress),@base,..);
base:=base+$AFFE;
ReadProcessMemory(hProcess,Ptr(base),@next,..);

Bis hierher komm ich auch ohne Probleme mit aber hier:WriteProcessMemory(hProcess,Ptr(next+$DEAD),@...);hört es bei mir auf. :roll: Wo kommt jetzt das Offset $DEAD her? Wie geht se danach weiter? Ich habe mal ein bisschen probiert und so habe ich dann auch keine Fehlermeldung bekommen aber der Wert hat sich nicht geändert.WriteProcessMemory(hProcess,ptr(next),@x,SizeOf(x),write) Was habe ich dieses mal falsch gemacht? @x ist doch der Wert der dann an die Adresse geschrieben wird oder ?
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Do 22.07.10 11:11 
sämtliche offsets sind nur ausgedacht.
ich wollte lediglich zeigen, dass man die incrementierung auch im aufruf machen und nicht extra in ner variable.
wenn es der eigene Prozess wäre, würde die kette so aussehen:

ausblenden Delphi-Quelltext
1:
PSingle(PCardinal(PCardinal($1234)^+$AFFE)^+$DEAD)^:=...;					


es ist doch egal ob ich
ausblenden Delphi-Quelltext
1:
2:
base:=base+$AFFE;
ReadProcessMemory(hProcess,Ptr(base),@next,..);
oder
ausblenden Delphi-Quelltext
1:
ReadProcessMemory(hProcess,Ptr(base+$AFFE),@next,..);					

schreibe
freaktonx Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Do 22.07.10 15:50 
Ah okay verstehe. Aber warum ändert sich der Werte dann nicht?
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
var
  c,baseAdress,base,next:Cardinal;
  x:Single;
begin
      c:=FindWindow(nil,'Fenstername)'); //Get WindowHandle
      if c=0 then
        begin
          MessageDlg('ErrorMessage',mtwarning,[mbOK],0);
          Exit;
        end;
      baseAdress:=ptr($0018ECE4);
      x:=40;
      GetWindowThreadProcessId(c,@c); //Get ProcessID and ignore ThreadID
      c:=OpenProcess(PROCESS_ALL_ACCESS,False,c);  //Get ProcessHandle
      ReadProcessMemory(hProcess, ptr(baseAdress), @base, SizeOf(base), BytesRead); 
      base := ptr(base + $DDC);                                          
      WriteProcessMemory(hProcess,ptr(base),@x,SizeOf(x),write);                            
      CloseHandle(c);
    end;
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Do 22.07.10 16:55 
weil du nicht nachdenkst und vernünftige variablennamen vergibst.
BTW: RPM und WPM haben rückgabewerte. außerdem kannst du im letzten parameter prüfen, wieviel geschrieben/gelesen wurde

dann ein getlasterror und due weißt bescheid.

oder du liest dir deinen Code nochmal langsam durch und vergibst gute namen für die vars