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



BeitragVerfasst: Mi 30.05.07 23:54 
Aloha liebes Delphiforum,

ich wende mich hier mit einem Problem an euch das sicherlich in jedem Forum das sich mit einer Programmiersprache beschäftigt ungern gesehen ist. Es ist die Frage nach einem fertigen Code der auch noch erklärt wird. Ich bin selbst Moderator in einem thematisch ähnlichem Forum und kenne diese Anfragen zur Genüge. Ich mag sie eigentlich auch nicht.
In diesem Fall jedoch, bitte ich eine Ausnahme zu machen und zuzulassen das ich eine solche Anfrage stelle.

An sich ist die Problemstellung folgende:

Wir haben ein Windowsanwendung. Ein selbsterstelltes Spiel um genau zu sein. Dieses Spiel benutzt 4 Byte große Integervariablen die es arrayartig anordnet im Speicher.
Wenn also z.B. sich die erste angelegte Variable dieses Spiels bei 19FFF8C befindet, dann wäre die nächste bei 19FFF90.
Halt 4 Byte draufaddiert. Soweit ganz simpel.

Nur stellt sich jetzt das Problem das die Speicheradresse an dem diese erste Variable vom Spiel abgelegt wird ja immer unterschiedlich ist. Dynamische Speicherverwaltung sei dank *grummel*. Ich müsste nun jedoch eben an die Adresse dieser ersten Spielevariable herankommen und ihren Wert auslesen können. Ich bräuchte also genauer gesagt ein Programm welches die Adresse der ersten Spielvariablen "herausfindet", dann entsprechend 16 Bytes draufaddiert und dann den Wert DIESER Variable in eine Textdatei schreibt.

Nun ist jedoch das Problem das ich anfangs ansprach, allein bin ich nicht dazu in der Lage dieses Programm zu schreiben. Ich habe bereits im Forum herumgesucht und bin dabei auf entsprechende Funktionen wie READPROCESSMEMORY und ähnliches getroffen. Ebenfalls habe ich versucht mir anhand euer Codeschnippsel und den gewonnen Programmiererfahrungen aus Java was zusammenzureimen. Leider ist mir dies nicht geglückt.
Darum nun die Frage: Kann mir jemand ein entsprechendes Programm schreiben und dann hier als Quellcode posten? Was genau bräuchtet ihr noch dafür als Angaben? Den Window Title? Oder anderes?

Ich hoffe das sich in dieser Hinsicht jemand erbarmt und mir antwortet. Allerdings bitte nicht mit einem simplen "Nutz die Suchfunktion und lern Delphi."


MFG Makenshi


Moderiert von user profile iconChristian S.: Topic aus Sonstiges (Delphi) verschoben am Do 31.05.2007 um 00:02
Moderiert von user profile iconUGrohne: Topic aus Job Börse verschoben am Fr 01.06.2007 um 10:02
Jann1k
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 866
Erhaltene Danke: 43

Win 7
TurboDelphi, Visual Studio 2010
BeitragVerfasst: Do 31.05.07 00:03 
also quelltext kann ich dir nciht schreiben, aber haste dieses tutorial gefunden?

www.delphi-library.d...hlight=spieletrainer

sieht für mich ganz nach dem aus was du brauchst.
Gast
Gast
Erhaltene Danke: 1



BeitragVerfasst: Do 31.05.07 21:03 
user profile iconJann1k hat folgendes geschrieben:
also quelltext kann ich dir nciht schreiben, aber haste dieses tutorial gefunden?

www.delphi-library.d...hlight=spieletrainer

sieht für mich ganz nach dem aus was du brauchst.


Das sieht durchaus interessant aus.
Eventuell hilft mir das schon weiter. Danke für den Hinweis !
Ich werd mal schauen ob ich es damit hinbekomme.
Makenshi Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Do 31.05.07 22:53 
ausblenden volle Höhe 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:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
unit maker;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  WindowName  :  integer;
  ProcessId  :  integer;
  ThreadId  :  integer;
  buf  :  PChar;
  HandleWindow  :  Integer;
  write  :  cardinal;

Const  WindowTitle  =  'Untitled';  //hier einfach den namen von unserm fenster eingeben! einfach spiel starten,
          //dann alt+tab drücken und in der taskleiste einfach nachschaun welche caption
                                        //unser programm hat und diese einfach einfügen.

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);

const
v1 = $90;
begin
 WindowName  :=  FindWindow(nil,WindowTitle);
          If  WindowName  =  0  then MessageDlg('...erst spiel starten...dann trainer starten =)',  mtwarning,[mbOK],0);
    ThreadId  :=  GetWindowThreadProcessId(WindowName,@ProcessId);
    HandleWindow  :=  OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId);
    GetMem(buf,1);
    buf^  :=  Chr(v1);
//----------------------------------------
//Hier kommen die Speicheroperationen rein
//----------------------------------------

//----------------------------------------
    FreeMem(buf);
    closehandle(HandleWindow);
end;

end.



Soweit habe ich es nun geschafft mit dem Thread. Anscheinend wird auch schon das richtige Fenster gefunden. Der Button ist also wie vorgesehen nur verfügbar wenn das Programm auch läuft. Passt soweit.

Nun habe ich leider noch zwei Probleme:

Ich habe mit Tsearch eine entsprechende Adresse per Autohack rausgefunden. Wie genau muss ich diese jetzt in Verbindung mit der READPROCESSMEMORY Funktion nutzen? Der Befehl ist mir noch nicht ganz klar. Das Trainerbeispiel setzt sich ja mit dem Schreiben auseinander. Das bräuchte ich nicht einmal.

Zum zweiten soll die Anwendung am besten im Hintergrund starten, kurz durchlaufen und dann auch wieder beendet werden.
Sie soll nicht erst eine Usereingabe entgegennehmen. Dafür muss ich dann denke ich einfach das Buttonelement weglassen?

Moderiert von user profile iconUGrohne: Code- durch Delphi-Tags ersetzt
Makenshi Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Fr 01.06.07 17:10 
Man möge mir bitte den Push und den Doppelpost verzeihen, nur habe ich das ganze mittlerweile zu einer Konsolenanwendung umgemünzt. Und entsprechend versucht das ganze selbst weiterzuschreiben.
Dabei kommt folgendes heraus:

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:
25:
26:
27:
28:
program menuetausch;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
TimerID : Word;
WindowName : Integer;
ProcessId : Integer;
ThreadId : Integer;
HandleWindow : Integer;
Buffer : Integer;
BytesRead : DWORD;

const
WindowTitle = 'Untitled';
AddressHealth = $48639B;

procedure Health(wTimerID,wMsg : Word; dwUser,dw1,dw2 : DWord); pascal;
begin
  WindowName := FindWindow(nil,WindowTitle);
  ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId);
  HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId);
  ReadProcessMemory(HandleWindow,pointer(AddressHealth),@Buffer,SizeOf(Buffer),BytesRead);
  writeln(IntToStr(Buffer));
end;


Das gibt aber wiederum folgende Fehlermeldungen vom Compiler:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
  [Error] menuetausch.dpr(15): Undeclared identifier: 'DWORD'
  [Error] menuetausch.dpr(23): Undeclared identifier: 'FindWindow'
  [Error] menuetausch.dpr(24): Undeclared identifier: 'GetWindowThreadProcessId'
  [Error] menuetausch.dpr(25): Undeclared identifier: 'OpenProcess'
  [Error] menuetausch.dpr(25): Undeclared identifier: 'PROCESS_ALL_ACCESS'
  [Error] menuetausch.dpr(26): Undeclared identifier: 'ReadProcessMemory'
  [Error] menuetausch.dpr(31): Declaration expected but end of file found



Hoffe auf Hilfe in dieser Sache. :)
jakobwenzel
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1889
Erhaltene Danke: 1

XP home, ubuntu
BDS 2006 Prof
BeitragVerfasst: Fr 01.06.07 17:18 
Da fehlt einfach nur ne Unit, nämlich Windows.

_________________
I thought what I'd do was, I'd pretend I was one of those deaf-mutes.
Makenshi Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Fr 01.06.07 17:21 
Stimmt. Da fehlte wohl einiges an Biblotheken.
So hat der Compiler es zumindestens gefressen:

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:
25:
26:
27:
28:
29:
30:
program menuetausch;

{$APPTYPE CONSOLE}

uses
    Windows, SysUtils;

var
TimerID : Word;
WindowName : Integer;
ProcessId : Integer;
ThreadId : Integer;
HandleWindow : Integer;
Buffer : Integer;
BytesRead : DWORD;

const
WindowTitle = 'Untitled';
AddressHealth = $48639B;

procedure Health(wTimerID,wMsg : Word; dwUser,dw1,dw2 : DWord); pascal;
begin
  WindowName := FindWindow(nil,WindowTitle);
  ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId);
  HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId);
  ReadProcessMemory(HandleWindow,pointer(AddressHealth),@Buffer,SizeOf(Buffer),BytesRead);
  writeln(IntToStr(Buffer));
end;

end.


Nur ist die Frage ob das nun so funzt. Mal fix in der Konsole starten...hoffentlich liest dann jemand das editierte.

Edit:

Das "writeln" müsste mir doch nun entsprechend etwas ausgeben? Da passiert leider nichts. :/
jakobwenzel
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1889
Erhaltene Danke: 1

XP home, ubuntu
BDS 2006 Prof
BeitragVerfasst: Fr 01.06.07 17:38 
Es würde auch etwas ausgeben, wenn die Prozedur denn aufgerufen werden würde.

BTW: Wenn du am Schluss noch ReadLn reinschreibst, musste erst enter drücken, bevor das Fenster zugeht.

_________________
I thought what I'd do was, I'd pretend I was one of those deaf-mutes.
Makenshi Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Fr 01.06.07 17:50 
Öhm ja...eine Prozedur die nie aufgerufen wird funktioniert nicht. Logischerweise. X_x
Also nun:

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:
25:
26:
program menuetausch;
{$APPTYPE CONSOLE}
uses
    Windows, SysUtils,Classes,Variants;
var
TimerID : Word;
WindowName : Integer;
ProcessId : Integer;
ThreadId : Integer;
HandleWindow : Integer;
Buffer : Integer;
BytesRead : DWORD;
const
WindowTitle = 'Untitled';
AddressHealth = $48639B;
begin
  WindowName := FindWindow(nil,WindowTitle);
  ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId);
  HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId);
  ReadProcessMemory(HandleWindow,pointer(AddressHealth),@Buffer,SizeOf(Buffer),BytesRead);
  write('Ausgelesener Wert: ');
  writeln(IntToStr(Buffer));
  write('Bytes gelesen: ');
  writeln(IntToStr(BytesRead));
  readln;
end.


Das ist nun ok so. Nur gibt das Programm die Art und Weise den Wert "-55542647" aus. Nicht wirklich das womit ich gerechnet hatte? An sich dachte ich das $48639B die Hexadresse einer bestimmten Variable wäre. So hab ich es jedenfalls mit Tsearch verstanden. Anscheinend ist auch das falsch so?
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Fr 01.06.07 20:21 
Ohne die kleinsten Grundlagen in Pascal, solltest du sowas erst gar net versuchen.
Zumindest solltest du verstehen war da -34234 rauskommt, denn die zahl wird als Integer (inttostr) nicht als hex ausgegeben (inttohex).
Ohne Debuggerkenntnisse wirst du auch nicht an die statische Addresse kommen, ausserdem sag mal um welches Spiel es sich handelt.

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Chryzler
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1097
Erhaltene Danke: 2



BeitragVerfasst: Fr 01.06.07 20:34 
user profile iconuall@ogc hat folgendes geschrieben:
Ohne Debuggerkenntnisse wirst du auch nicht an die statische Addresse kommen, ausserdem sag mal um welches Spiel es sich handelt.

Seltsamerweise war bei mir bis auf eine Ausnahme die Adresse immer gleich geblieben.
Und hab ich das jetzt richtig verstanden, es gibt statische Adressen und dynamische Adressen, und damit das Programm selber weiß, wo die Variablen zu finden sind, legt es Pointer im statischen Bereich an, die auf die eigentlichen Variablen im dynamischen Bereich zeigen? Oder so irgendwie.. Und dann muss man praktisch den Pointer finden, der auf die gewünschte Variable zeigt. Dann kann man den auslesen, da er ja immer an der selben Stelle zu finden ist, und dann zeigt er genau auf die Stelle, wo der eigentliche Wert steht? Richtig oder komplett falsch?
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Fr 01.06.07 20:38 
jo eignetlich richtig, kommt halt noch drauf an wo der statsiche pointer ist (eventl in einer dll) dann muss man halt noch bisl umrechnen wenn die dll wo anders geladen ist.
aber ja es gibt immer einen statsichen pointer der da hinzeigt, oder eine berechnung um an die dynamische variable zu kommen, es sei denn die liegt auf dem stack, dann wirds noch komplizierter

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Makenshi Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Fr 01.06.07 21:00 
user profile iconuall@ogc hat folgendes geschrieben:
Ohne die kleinsten Grundlagen in Pascal, solltest du sowas erst gar net versuchen.
Zumindest solltest du verstehen war da -34234 rauskommt, denn die zahl wird als Integer (inttostr) nicht als hex ausgegeben (inttohex).
Ohne Debuggerkenntnisse wirst du auch nicht an die statische Addresse kommen, ausserdem sag mal um welches Spiel es sich handelt.


Da genau liegt an sich auch das Problem. Ich arbeite in der Regel nicht mit Delphi.
Mein Problem ist jedoch das ich nunmal eine Variable aus dem Speicher auslesen muss. Da führt im Moment kein Weg herum.
Das Spiel ist kein bekanntes komerzielles Spiel oder ähnliches, sondern ein Spiel das mit einem Editor erzeugt wird.
Dieser Editor besitzt für das Spiel lediglich Variablen vom Typ Boolean und Integer. Allerdings muss ich ein externes Programm mit einer Variable dieses Spieles füttern. Das ganze ist sozusagen als Parameter für das externe Programm gedacht.
Da dieses Editorspiel keinerlei Möglichkeiten besitzt Systemvariablen zu verändern oder sonst irgendwie vernünftig zu kommunizieren, bleibt mir nur der Weg an der Quelle direkt zu graben. Das wäre in dem Fall der Arbeitsspeicher.

Mit Tsearch habe ich ja sogar bereits die erste Int-Variable aufgespürt. Leider fehlt mir in diesem Fall einfach das nötige Wissen um das ganze zu Nutzen. Ärgerlicherweise benötigen ich dennoch den Effekt der ganzen Sache.
Der übergeben Parameter soll dazu dienen Dateien in einem Ordner des Editorspiels entsprechende Grafikdateien zu kopieren.
Damit das externe Programm weiß welche Dateien es zu verändert hat, benötigen ich unbedingt diesen Parameter.

Ich hoffe so wird näher verständlich warum ich hier etwas unbeholfen aussehe. :)
An sich mag ich es auch nicht mit Funktionen zu arbeiten bei denen ich nicht weiß wie sie arbeiten. Nur bleibt mir in diesem Fall nichts anderes übrig.
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Fr 01.06.07 22:03 
Dann hilft wohl nur:
1) selbst nachforschungen antreten, z.b. kann man Daten inden Prozess mit WriteProcessMemory schreiben
2) das Problem in die Job Börse verschieben lassen

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Makenshi Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Fr 01.06.07 22:59 
Dann bleibt mir wohl nichts anderes übrig als das ganze nochmals in die Jobbörse zu schieben.
Ich dachte mir lediglich ich versuche mir einmal selbst das ganze zusammenzubasteln. Was damit wohl gescheitert ist.
Wie du vielleicht bemerkt hast habe ich Nachforschungen angestellt. Nur leider reicht mein Wissensstand und die Informationen nicht um mir zu meinem Programm zu verhelfen. Dafür gibt es da für mich zuviele unklare Stellen.
Aufgrund der Nachforschung ist ja überhaupt erst der Quellcode in meinem Post entstanden.

Nunja, ich hoffe mal das die Wahrscheinlichkeit hier höher ist jemanden zu finden der so ein Programm erschaffen mag. In anderen Foren sieht das nach meiner bisherigen Erfahrung eher schlecht aus.
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 02.06.07 14:14 
Bis jetztsollte der code ja stimmen, du liest eben das aus was an besagter Stelle steht. Was willst du denn jetzt noch amchen? Mit WriteProcessMemory kannst du den Speicher ändern.

Willst du eine absolute Adresse finden, die genau auf die Adresse von dir zeigt, wirds schwierig da das wenig mit Delphi zu tun hat.
ABer es sieht so aus als wenn 0x48639B im Speicherbereich der Exe liegt, sollte also keine Probleme geben.

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Makenshi Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Sa 02.06.07 16:56 
Öhm nunja, an sich hätte ich ganz gerne den Wert der in der Variable ist die an der Adresse 48639B steht.
Darum dachte ich anfangs es sei ok wenn die Zahl dort als Integer ausgegeben wird?

Ich bin ehrlich gesagt verwirrt. ReadProcessMemory liest doch eine bestimmte Stelle des Speichers aus? Oder habe ich das völlig falsch verstanden? Nur habe ich ja nicht den Wert herausbekommen der an dieser Stelle im Speicher steht?
Chryzler
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1097
Erhaltene Danke: 2



BeitragVerfasst: Sa 02.06.07 17:11 
Doch, stimmt schon. ReadProcessMemory liest den Wert aus, der an der Stelle steht, und WriteProcessMemory schreibt einen Wert an eine bestimmte Stelle.
Ich verstehe nur nicht, warum bei dir ein falscher Wert herauskommen sollte. Erstmal musst du dir sicher sein, dass die Adresse richtig ist. Dann musst du herausfinden, in welchem Datenformat die Zahl gespeichert ist, vielleicht ist es ja gar kein 4-Byte Integer. Und dann solltest du dir mal anzeigen lassen, wieviele Bytes denn tatsächlich ausgelesen wurden, nicht dass es beim Auslesen einen Fehler gegeben hat.
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 02.06.07 17:29 
user profile iconuall@ogc hat folgendes geschrieben:
Ohne die kleinsten Grundlagen in Pascal, solltest du sowas erst gar net versuchen.
Zumindest solltest du verstehen war da -34234 rauskommt, denn die zahl wird als Integer (inttostr) nicht als hex ausgegeben (inttohex).
Ohne Debuggerkenntnisse wirst du auch nicht an die statische Addresse kommen, ausserdem sag mal um welches Spiel es sich handelt.


Das was da bei dir rausklommt, kann durchaus stimmen, sofnern die adresse richitg ist.

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Makenshi Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Sa 02.06.07 17:44 
Nunja, das Programm sagt das 4 Bytes ausgelesen werden. Soweit ich weiß müssten es auch eindeutig 4 Byte Integer sein.
Nur ist meine Adresse dort keine statische. An sich werden die Variablen dynamisch bei jedem Start des Programms im Speicher verteilt. Alles nichts neues.

Der ausgegebene Wert kann auch nicht negativ sein. Ich sehe ihn ja. Er müsste an sich 4 sein.

Soweit ich weiß ist $48639B eine Grundadresse. Zumindestens kam sie bei der Benutzung der Autohackfunktion von Tsearch heraus. Daneben standen auch Assemblerbefehl. Entsprechend denk ich mal das das Editorspiel von dieses Grundadresse ausgehend mit entsprechenden Assemblerbefehlen die Adressen für die eigenen Variablen ausrechnet. Keine Ahnung ob ich das nun richtig verstanden habe.
Muss ich dann im meinem Delphiprogramm nicht ebenfalls die entsprechenden Assemblerbefehle benutzen? Wenn ja, dann hört beim Assembler leider absolut das Gebiet auf bei dem ich behaupten kann das ich es verstehe. Mit Assembler hatte ich leider noch nicht allzuviel zutun.