Autor Beitrag
Don Krawallo
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 45

Windows 10 x64
Delphi 10.4.1
BeitragVerfasst: So 25.07.10 23:12 
Schönen Guten Abend hier im Forum und ein herzliches Hallo an alle Mitglieder.

Wie das Topic schon vermuten lässt handelt es sich ums Thema Spiele Trainer programmieren.
Folgender Fall... Ich habe bereits 2 Trainer in Delphi programmiert die auch hervorragend funktionieren.

Folgendes Beispiel ist aus meinem Trainer zu Die Sims 3 - Reiseabenteuer:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
WindowName   :=  FindWindow(nil,Fenstertitel);
ThreadId     :=  GetWindowThreadProcessId(WindowName,@ProcessId);
HandleWindow :=  OpenProcess(PROCESS_ALL_ACCESS,True,ProcessId);
              VirtualProtectEx(HandleWindow,pointer($00400408), 40, PAGE_EXECUTE_READWRITE, old);
              WriteProcessMemory(HandleWindow,pointer($00C3441E), @Patched[0],6,write);
              WriteProcessMemory(HandleWindow,pointer($00400408), @CC1[0],32,write);
              WriteProcessMemory(HandleWindow,pointer($00400428), @CC2[0],32,write);
              WriteProcessMemory(HandleWindow,pointer($00400448), @CC3[0],33,write);

Wie ihr sehen könnt wird das Spiel, also der Process per Auslesen des Fenstertitels gesucht/gefunden.
Nun aber stehe ich vor einem neuen Problem. Ich versuche mich derzeit an einem neuen Projekt und zwar
an einem Trainer zu Command & Conquer 4. Das Spiel wird herkömmlich über eine EXE namens C&C4.exe gestartet.
Diese wiederrum startet einen Process namens C&C4.game. Würde ich den Trainer nach obigen Beispiel programmieren
hab ich im Endeffekt nur Zugriff auf die C&C4.exe.
Meine Überlegung ist nun folgende das ich den Process direkt suchen lasse. Hier im Forum habe ich dann folgendes
Codeschnipsel gefunden:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
const
  ProcessName = 'DeineDatei.exe'// Bitte entsprechend ändern
var
  hSnapshot: THandle;
  hProcess: THandle;
  ProcessEntry: TProcessEntry32;
  Schleife: BOOL;
  pID: Integer;
begin
  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; // <-- Das ist die ProzessID
    Schleife := Process32Next(hSnapshot, ProcessEntry);
  end;
  CloseHandle(hSnapshot);
  hProcess := OpenProcess(PROCESS_ALL_ACCESS, True, pID); // <-- Das ist dann das gesuchte Handle

Diesen Codeschnipsel hab ich erstmal auf meinen Sims 3 Trainer übertragen um die ganze Sache erstmal zu testen.
Das sieht momentan auch so aus:
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:
Uses
..., Tlhelp32, ...;
var
  hSnapshot: THandle;
  hProcess: THandle;
  ProcessEntry: TProcessEntry32;
  Schleife: BOOL;
  pID: Integer;
  Const ProcessName = 'TS3EP01.exe';

Procedure TForm1.Hotkeyused( Var msg: TWMHotkey ) ;
   Begin
    If msg.hotkey = 1 Then Begin
    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, True, pID);
      VirtualProtectEx(hProcess,pointer($00400408), 40, PAGE_EXECUTE_READWRITE, old);
      WriteProcessMemory(hProcess,pointer($00C3441E), @Patched[0],6,write);
      WriteProcessMemory(hProcess,pointer($00400408), @CC1[0],32,write);
      WriteProcessMemory(hProcess,pointer($00400428), @CC2[0],32,write);
      WriteProcessMemory(hProcess,pointer($00400448), @CC3[0],33,write);
  closehandle(hProcess);
  End;
end;

Aber und genau da liegt der Knackpunkt an der Geschichte, die Cheatcodes werden nicht geschrieben.
Wie gesagt, der Trainer funktioniert ohne Tadel mit dem Beispiel ganz oben, wo ich den Process
bzw. das Spielefenster per Fenstertitel auslesen suche.

Nur mal so am Rande... Wenn ich die Trainer so programmiere das diese den Fenstertitel des Spiels
suchen kann es ja ebenfalls zu Problemen kommen wenn beispielsweise der Fenstertitel des Spiels
und z.b. der Installationsordner denselben Namen haben.

Vielleicht hat ja jemand von euch noch eine Idee wo bei dem letzten Beispiel der Fehler steckt?

Ich bedanke mich schonmal im vorraus für eure Aufmerksamkeit und wünsche noch eine gute Nacht.

MFG Don Krawallo
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Mo 26.07.10 01:24 
Hallo und :welcome: im Forum!

Grundsätzlich ist (abgesehen von der etwas unübersichtlichen Einrückung) an dem Code nichts auszusetzen. Ich habe das mal schnell mit einer anderen Anwendung probiert: funktioniert.

Schonmal im Debugger durchgesteppt? ggf. Auch mit einer Anwendung probiert die nicht im Vollbild läuft und deswegen einfacher zum Testen ist?
Ansonsten bietet es sich auch an, möglichst detaillierte Logdateien zu schreiben, wenn das Problem nur mit dem Echt-Spiel auftritt aber dann schlecht zu debuggen ist.

Was mir spontan einfällt sind Probleme mit Unicode (Delphi 2007 +) oder 64bit; die hatte neulich jemand, der das Gleiche machen wollte. Sollte sich finden lassen: Suche in: Delphi-Forum CREATETOOLHELP32SNAPSHOT


OT: übrigens schön, jemanden neues zu sehen der der deutschen Sprache mitsamt Höflichkeitsfloskeln mächtig ist. Du bist doch wirklich neu hier, oder? Der Nick kommt mir irgendwie bekannt vor. Weiß nur nicht woher...

cu
Martok

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."

Für diesen Beitrag haben gedankt: Don Krawallo
Don Krawallo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 45

Windows 10 x64
Delphi 10.4.1
BeitragVerfasst: Mo 26.07.10 01:58 
user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
... OT: übrigens schön, jemanden neues zu sehen der der deutschen Sprache mitsamt Höflichkeitsfloskeln mächtig ist. Du bist doch wirklich neu hier, oder? Der Nick kommt mir irgendwie bekannt vor. Weiß nur nicht woher...

cu
Martok


Danke für die Blumen :-)
Yep, ich bin neu hier, aber auch in einem anderen Forum (Game Trainer-Forum) unter selbigen Namen angemeldet.

Im übrigen... Ja, ich nutze ein 64-Bit Betriebssystem (Win 7). Meine Delphi Entwicklungsumgebung ist die 2010er Version.
Wie ich schon schrieb hab ich bereits zwei Trainer programmiert welche auch funktionieren.
Da ich insofern erstmal glücklich drüber war/bin das diese auch funktionieren hab ich mich mit dem Programm selbst
auch bis dato weniger auseinandergesetzt.

OK, das ganze ist sehr ominös :-)
Aber wenn mir die Frage an dieser Stelle noch gestattet sei? In welcher Hinsicht gibt bzw. könnte es Probleme
mit der Unicode Darstellung geben? Fällt Dir dazu ein fundiertes Beispiel ein?

MFG Don Krawallo
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Mo 26.07.10 02:18 
Hi,

Bezüglich Unicode kann es beim CompareText geben, wenn Delphi aus dem szExeFile einen String machen will.
Hier wäre was dazu: IsProcess funktioniert unter Delphi 2010 nicht mehr!. Da dann auch die verlinkte Diskussion in der DP beachten, dort gibts etwas Hintergrund dazu.
Fazit: Statt CompareText AnsiSameText nehmen.

Deswegen frug ich, ob denn der Prozess nicht gefunden wird oder danach was schiefgeht.

HTH,
Martok

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 26.07.10 06:02 
Der Quelltext hat zwar noch Fehler, funktioniert aber auch mit Delphi 2010 sofern der Prozess läuft. Denn szExeFile liefert ein Array of WChar, sprich WideChar, das funktioniert also mit Unicode.

CompareText ist eine delphieigene Funktion während AnsiSameText auf die API-Funktion CompareStringW hinausläuft. In jedem Fall wird aber zuerst eine Umwandlung in einen UnicodeString durchgeführt. Bei AnsiSameText danach noch eine auf PChar sprich PWideChar.

Dass der Prozess gar nicht laufen könnte, wird da gar nicht beachtet. Deshalb sollte auch eine Compilerwarnung kommen, da pID evtl. nicht initialisiert ist... :roll:
Besser also:
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:
const
  ProcessName = 'DeineDatei.exe'// Bitte entsprechend ändern
var
  hSnapshot: THandle;
  hProcess: THandle;
  ProcessEntry: TProcessEntry32;
  Schleife: BOOL;
  pID: Integer;
begin
  hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  ProcessEntry.dwSize := Sizeof(ProcessEntry);
  Schleife := Process32First(hSnapshot, ProcessEntry);
  pid := -1;
  while Schleife do
  begin
    if (CompareText(ProcessEntry.szExeFile, ProcessName) = 0then
      pID := ProcessEntry.th32ProcessID; // <-- Das ist die ProzessID
    Schleife := Process32Next(hSnapshot, ProcessEntry);
  end;
  CloseHandle(hSnapshot);
  if pid >= 0 then
    hProcess := OpenProcess(PROCESS_ALL_ACCESS, True, pID); // <-- Das ist dann das gesuchte Handle

Für diesen Beitrag haben gedankt: Don Krawallo
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: Mo 26.07.10 11:07 
UND: Schon mal mti Adminrechten starten versucht? Das problem hatte ich mal.
Auf jeden Fall aber erst mal Fehler suchen: Findet er die PID? Schreibt er? Was gibt er als Fehler zurück usw.
Don Krawallo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 45

Windows 10 x64
Delphi 10.4.1
BeitragVerfasst: Mo 26.07.10 20:35 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Der Quelltext hat zwar noch Fehler, funktioniert aber auch mit Delphi 2010 sofern der Prozess läuft. Denn szExeFile liefert ein Array of WChar, sprich WideChar, das funktioniert also mit Unicode.


Naja, der Prozess bzw. das Spiel läuft ja, oder vielmehr... Der Prozess muss ja laufen damit die entsprechenden Bytes geschrieben werden
und letztenendes der Trainer funktioniert.
Oder hab ich jetzt in dieser Hinsicht Dich falsch verstanden? :?:

Ich hab mich heute nochmal mit der ganzen Materie befasst, den Quellcode nach meinem genannten Beispiel auch wieder so aufgesetzt.
Soll heißen das sich der Quellcode in keiner weiße zum vorhergehenden Sourcecode unterscheidet.
Nunja, was soll ich sagen??? Auf einmal funktionierts. :roll:
Ich kann eigentlich von mir behaupten das ich ein recht großes Verständnis von den Computerdingen habe, programmiertechnisch wollt ich
mich hier ganz einfach absichern ob denn nicht doch ein Fehler im Quellcode steckt.
Aber ganz im Ernst, warum das auf einmal funktioniert... Bin ich absolut überfragt. Ich bin den neuen Quellcode mehrmals durchgegangen
hab aber keine Unterschiede festgestellt. Sehr mysteriös das ganze.

@jaenicke
Wenn ich Dich da jetzt richtig verstanden habe dann dient Deine (optimierte/fehlerbereinigte) Variante des Codes gewissermaßen
einer Vorbeugung zur unnötigen Prozessorauslastung? Oder bin ich da jetzt auf dem Holzweg?

MFG Don Krawallo

PS: Ich danke euch natürlich für eure bisherigen konstruktiven Beiträge. :o
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 26.07.10 20:59 
user profile iconDon Krawallo hat folgendes geschrieben Zum zitierten Posting springen:
Wenn ich Dich da jetzt richtig verstanden habe dann dient Deine (optimierte/fehlerbereinigte) Variante des Codes gewissermaßen einer Vorbeugung zur unnötigen Prozessorauslastung?
Nein, es wird nicht einfach OpenProcess aufgerufen egal ob der Prozess überhaupt existiert oder nicht. Denn dein Code oben achtet da nicht drauf.

Klar, normalerweise läuft der, aber man sollte schon immer auch mögliche Fehlerquellen ausschließen.
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Di 27.07.10 00:59 
Man sollte laut MSDN PROCESS_ALL_ACCESS vermeiden. Das könnte evtl. voll in die Hose gehen.
Zitat: "Windows Server 2003 and Windows XP/2000: The size of the PROCESS_ALL_ACCESS flag increased on Windows Server 2008 and Windows Vista. If an application compiled for Windows Server 2008 and Windows Vista is run on Windows Server 2003 or Windows XP/2000, the PROCESS_ALL_ACCESS flag is too large and the function specifying this flag fails with ERROR_ACCESS_DENIED. To avoid this problem, specify the minimum set of access rights required for the operation."
msdn.microsoft.com/e...ms684880(VS.85).aspx
nsylvain.blogspot.co...n32winnt-mayhem.html
Don Krawallo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 45

Windows 10 x64
Delphi 10.4.1
BeitragVerfasst: Di 31.08.10 02:24 
Ein scheenen guten Morgen allerseits...

Also mittlerweile, wie ich bereits schrieb, funktioniert das ganze anhand von CREATETOOLHELP32SNAPSHOT.
Mit dieser Funktion spiele ich momentan soweit rum, das ich an die Basisaddresse einer DLL komme...
Wie wir ja alle wissen werden diese dynamisch geladen und haben nach jedem Programmneustart eine neue/andere Basisaddresse.

So weit so gut...
Der Sourcecode sieht folgendermasßen aus:
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:
var
  Form3: TForm3;
  ModuleEntry: TModuleEntry32;
  ProcessEntry: TProcessEntry32;
  hSnapshot, hProcess, SnapMod: THandle;
  DLLBaseAddy: PByte;
  Schleife, FindDLLBase : Boolean;
  pID: Integer;
  write:  cardinal;
  old: DWORD;
  CC: array [0..7of byte = ($90$FF$26$EA$C5$62$78$34);
  Reset: array [0..7of byte = ($00$00$00$00$00$00$00$00);

  Const Processname = 'Cheat Engine.exe';
        DLLName = 'DBGHelp.dll';

procedure TForm3.Button1Click(Sender: TObject);
begin
  hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  ProcessEntry.dwSize := Sizeof(ProcessEntry);
  Schleife := Process32First(hSnapshot, ProcessEntry);
  pID := -1;
    while Schleife do begin
      if (CompareText(ProcessEntry.szExeFile, ProcessName) = 0then
      pID := ProcessEntry.th32ProcessID;
      Schleife := Process32Next(hSnapshot, ProcessEntry);
    end;
    if pID >= 0 then begin
      hProcess := OpenProcess(PROCESS_ALL_ACCESS, True, pID);
      SnapMod:= CreateToolhelp32Snapshot(TH32CS_Snapmodule, pID);
      ModuleEntry.dwSize := Sizeof(ModuleEntry);
      FindDLLBase:= Module32First (SnapMod, ModuleEntry);
      while FindDLLBase do begin
        if (CompareText(Moduleentry.szModule, DLLName) =0then
        DLLBaseAddy := ModuleEntry.modBaseAddr;
        FindDLLBase := Module32Next(SnapMod, ModuleEntry);
      end;
     CloseHandle(hSnapshot);
      VirtualProtectEx(hProcess,pointer(DLLBaseAddy+$0163AB), 5, PAGE_EXECUTE_READWRITE, old);
      WriteProcessMemory(hProcess,pointer(DLLBaseAddy+$0163AB), @CC[0],8,write);
      CloseHandle(hprocess);
    end;
end;


Das Programm bzw. die DLL in die geschrieben wird ist nur erstmal um zu testen ob mein SourceCode funktioniert...
Dieser funktioniert auch tadellos...
Problem gibts hierbei keines, da ich aber grade erst mit Delphi anfange möcht ich an dieser Stelle die Frage an
euch erfahrenen Programmierer richten...

Und zwar - Gibts jetzt an dem Code selbst, speziell die Routine SNAPMODULE, etwas auszusetzen bzw. zu optimieren
um eventuelle Fehlerquellen schon von vornherein auszuschließen?

Aber nun wünsch ich erstmal ne gute Nacht :lol:
Viele Grüße, Don Krawallo