Entwickler-Ecke

Windows API - ShortString -> PChar


_eddy - So 24.06.07 01:58
Titel: ShortString -> PChar
Hallo Jungs und Mädels :)

Ich habe hier ein Problem, und zwar wollte ich per WriteProcessMemory einen Wert (halt in die Memory) schreiben. Hat auch soweit geklappt. Aber nur, wenn die Werte hardcodet waren (also im Programmcode schon implementiert).
Ich wollte dann später den Benutzer die Eingabe wählen lassen.

Zur Vorgeschichte:
Ich mache einen Trainer für MineSweeper :)

Naja, ich kann bis jetzt die Zeit auslesen, schreiben, einfrieren usw. Was halt nicht funktionieren will ist, den User die Zeit auswählen zu lassen, welches bei Minesweeper gesetzt werden soll.
Ich habe mir hier eine Funktion geschrieben:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
function InjectMemory(title: string; wheretowrite: Pointer; whattowrite: PChar; size: integer): integer;
var
c: cardinal;
write: cardinal;
begin
c := FindWindow(nil,PChar(title));
  if (c = 0then begin
  result := 1;
  exit;
  end;
GetWindowThreadProcessId(c, @c);
c := OpenProcess(PROCESS_ALL_ACCESS, False, c);
WriteProcessMemory(c,wheretowrite, whattowrite, size, write);
CloseHandle(c);
result := 0;
end;

Es macht halt nichts weiteres, als den Wert in die Memory zu schreiben. Ich rufe es wie folgt auf:

Zitat:

InjectMemory('MineSweeper',Ptr($1002FF5),chr($90)+chr($90)+chr($90)+chr($90)+chr($90)+chr($90),6);


Ich wähle halt den Titel der Anwendung, den Pointer zur Adresse, den Wert der geschrieben werden soll (in diesem Beispiel wird geNOPed) und die Länge. Das funktioniert halt alles auch, nur was nicht funktionieren will, ist sowas hier:

Zitat:

InjectMemory('MineSweeper',Ptr($100579C),Edit1.text[1]+Chr(0)+Chr(0)+Chr(0),4);

Dann erscheint die Fehlermeldung:
Zitat:

[Error] Unit1.pas(297): Incompatible types: 'ShortString' and 'PAnsiChar'


Ich weiß nicht wieso der bei so etwas streikt, oder wie der überhaupt auf ShortString kommt ?! Edit1.text[1] wäre ja hier ein String (oder halt Char), und was meine Funktion will ist ein PChar. Ich weiß nur, das Delphi selbst entscheidet ob er nun für String AnsiString oder ShortString nehmen soll.
Ich habe schon viele viele Varianten Probiert (Edit1.text in int umwandeln, es in ein byte speichern, in PChar umwandeln, einen AnsiString verwenden usw.)

Naja, wie auch immer, ich habs dann später so gelöst, dass ich aus ShortString einen String gemacht habe, und diesen dann zu PChar umgewandelt habe :S War schlecht gelöst, hat aber geklappt. Der Nachteil ist nun, ich kann nur eine Zahl die bis 255 reicht auswählen (kein Wunder, ShortString geht ja auch nur bis 255).

Weiß irgendeiner Rat?! Ich habe echt keine Ahnung mehr was ich noch machen kann...


Moderiert von user profile iconGausi: Topic aus Dateizugriff verschoben am So 24.06.2007 um 10:22


Gausi - So 24.06.07 10:18

Hallo und :welcome: in der Entwickler-Ecke!

Reicht da nicht ein einfacher Typecast?
InjectMemory('MineSweeper',Ptr($100579C),PChar(Edit1.text[1]+Chr(0)+Chr(0)+Chr(0)),4); :gruebel:


_eddy - So 24.06.07 14:12

Hallo Gausi,
Nein das hatte ich auch schon öfters versucht. Dann erscheint auch ein anderer Error, nämlich:
Zitat:

[Error] Unit1.pas(297): Invalid typecast

:(

Und wenn ich nur den Edit1.text[1] zu PChar mache, erscheint folgendes:
Zitat:

[Error] Unit1.pas(297): Incompatible types: 'String' and 'PAnsiChar'

*verzweifelt*


jakobwenzel - So 24.06.07 15:01

Probier mal, das ganze in nem String zwischenzuspeicehrn:

Delphi-Quelltext
1:
2:
3:
4:
var s:String;
begin
  s:=Edit1.text[1]+Chr(0)+Chr(0)+Chr(0);
  InjectMemory('MineSweeper',Ptr($100579C),PChar(s),4);


_eddy - So 24.06.07 16:20

Hallo Jakob,
Ja, das funktioniert zwar, aber leider wieder nur bis 255. Also, wenn ich genauso mache wie in deinem Beispiel nimmt der natürlich, bei der Eingabe "123" die "1" und das ist in der ASCII Tabelle die Zahl 49 :( Habs dann so versucht:


Delphi-Quelltext
1:
s:=chr(strtoint(Edit1.text))+Chr(0)+Chr(0)+Chr(0);                    


Jetzt funktionierts zwar, aber halt nur bis 255 *kopfkratz* Langsam glaube ich, das liegt an Chr? Kann ich das auch irgendwie anders lösen?!
Oder vielleicht liegt das daran, dass ich versuche mehr als 255 in ein Byte zu speichern? o_O Aber in den nächsten "Chr(0)" kann ich leider keine weitere Zahl hinspeichern :(
Weiß einer Rat?

//edit:
Ich merke gerade, dass es an Chr liegen MUSS (oder halt an dem Typ Byte) da man es auch nicht im Programm selber höher als 255 setzen kann:

Delphi-Quelltext
1:
s:=Chr(700)+Chr(0)+Chr(0)+Chr(0);                    

Funktioniert z.B. auch nicht.


GTA-Place - So 24.06.07 16:37

Es gibt ja auch nur 256 ASCII-Zeichen (0 - 255).


uall@ogc - So 24.06.07 16:39

1) solltest du keinen PChar nehmen, da der kein #0 entahlten darf. Sollte zwar so wie du es hast kein Problem machen aber WhatToWrite soltle bm typ Pointer sein (ist Pchar eigentlich auch)
was du schreiben willst muss halt in einen String (der kann #0 enthalten)
und dann übergibst du das mit @s[1]

2) ein Byte kann nur Werte von 0 bis 255 annehmen, chhr oder char wandelt einen charachter (ASCII Wert) in ein Byte um, was eben nur 255 groß sein kann. willst du also einen wert wie 1000 in den speicher schreiben, so wird es sich um ein word oder dword handeln. den bekommst du mit

setlength(s,length(s)+4) // dword
PDWord(@s[length(s)-4])^ := StrToInt(edit1.text);

in einen string. Weiß jetzt auch keinen einfachereren Weg, aber hab auch was getrunken und keine Lust mir dadrüber nu den Kopf zu zerbrechen ^^


_eddy - So 24.06.07 17:37

Hallo,
Danke Leute, jetzt klappt alles wunderbar :)

Delphi-Quelltext
1:
2:
3:
setlength(s,length(s)+4);
PDWord(@s[1])^ := StrToInt(edit1.text);
InjectMemoryS('MineSweeper',Ptr($100579C),@s[1],4);

Muss jetzt nur noch herausfinden was ich dort GENAU gemacht habe :D

Wieso muss ich erst einen DWord-Pointer zu s[1] zeigen lassen, und dann erst den Wert verändern o_O Der String bleibt doch ein String, oder wie jetzt? *total verwirrt ist*


uall@ogc - So 24.06.07 19:31

Es soll ja genau die Werte annehmen. Mit PDword kannst du also 4 Chars in dem String ändern. Die sollen also genau den Integerwert annehmen. Wenn du dem String direkt nen Integer zuweist dann steht darin die Hexwerte der Zeichen, nicht aber der Integer wert selbst.
Bisl kompliziert, gib einfach den String aus dann siehst du es ;P


_eddy - So 24.06.07 20:38

Hm, habs immernoch nicht wirklich verstanden. :D
Aber, wo ist denn die Grenze von Dword ?! Dword = 4 Byte , also 1024 ?!

Also, versteh ich das Richtig, das PDWord als Parameter einen Pointer möchte, und wiederum einen Pointer zurück liefert, wessen inhalt aber nun ein DWord geworden ist?! Dann würde ich die Codezeile in etwa verstehen ^^


uall@ogc - So 24.06.07 21:51

Ne DWORD = 4byte = 2^32 = xx millonen oder mehr ;P
PDWORD ist ein Pointer auf ein DWord. Ich caste den String (@s) als DWord (@=Pointer) und setze den Wert mit ^
Sozusagen ist es ein Pointer als Parameter auch wenns einfach nen Typecast ist ;P


_eddy - Mo 25.06.07 01:20

OK, danke. Habs jetzt einigermaßen verstanden :)