Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Dynamische Memory Adressen - Startpunkt herausfinden (https://www.delphipraxis.net/185926-dynamische-memory-adressen-startpunkt-herausfinden.html)

milos 19. Jul 2015 04:31

Dynamische Memory Adressen - Startpunkt herausfinden
 
Hey,

ich möchte einen Status in einem Spiel über ReadProcessMemory auslesen. Das würde auch soweit klappen, jedoch sind die Adressen nach jedem Neustart des Spiels anders.

Ich weiss, dass man nach einem "Eintrittspunkt" suchen muss, der dynamisch ist und ich dann einem festen wert addieren kann um zu meinem Ziel zu kommen, jedoch weiss ich nicht wie ich diesen "Eintrittspunkt" finden soll. Müsste halt bei jedem Start neu gesucht werden oder?

Hoffe einer kann mir hier helfen ^^

Freundliche Grüsse

Edit: Mir geht es primär um einen Weg wie man das in Delphi lösen kann. Wie das mit Memory Searchern geht weiss ich, bringt mir aber leider nicht viel :/

Neutral General 19. Jul 2015 09:45

AW: Dynamische Memory Adressen - Startpunkt herausfinden
 
Man sucht sich vorher die "Signatur" der Funktion heraus die man finden will. (Per Disassembler o.ä.)
Die Signatur ist eine eindeutige Bytefolge innerhalb der exe die am Anfang der gewünschten Funktion beginnt.

Wenn du die Funktion dann zur Laufzeit ermitteln willst musst du den Speicher des fremden Prozesses nach der Signatur durchsuchen. Die Startadresse der Signatur ist die Adresse der Funktion.

milos 19. Jul 2015 10:32

AW: Dynamische Memory Adressen - Startpunkt herausfinden
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Neutral General (Beitrag 1309150)
Man sucht sich vorher die "Signatur" der Funktion heraus die man finden will. (Per Disassembler o.ä.)
Die Signatur ist eine eindeutige Bytefolge innerhalb der exe die am Anfang der gewünschten Funktion beginnt.

Wenn du die Funktion dann zur Laufzeit ermitteln willst musst du den Speicher des fremden Prozesses nach der Signatur durchsuchen. Die Startadresse der Signatur ist die Adresse der Funktion.

Danke für die Antwort!
Ich bin mir gerade nicht sicher ob ich dich richtig verstanden habe, aber wenn doch, dann hab ich das alles bisher so gemacht, jedoch ändert sich die Adresse nach jedem Neustart des Spiels wieder, aber nur um den "Einstiegspunkt", siehe anhang. Den müsste ich irgendwie über Delphi rausbekommen also wenns geht ohne externes Programm wie Cheat Engine oä.

Falls ich dich komplett falsch verstanden haben sollte, und die Lösung eigentlich schon geschrieben wurde, tut es mir sehr leid. Bin ziemlich frisch in dem Bereich ^^

Freundliche Grüsse

Neutral General 19. Jul 2015 15:36

AW: Dynamische Memory Adressen - Startpunkt herausfinden
 
Liste der Anhänge anzeigen (Anzahl: 1)
Die Signatur ist ja gerade ist ja gerade dafür da die Funktion wiederzufinden OBWOHL die Adresse sich geändert hat.

Im Anhang ist ein Bild von einer Exe in einem Disassembler. Links siehst du rot Umrandet die ersten paar Befehle der Funktion die du finden willst (deren Signatur du willst). Auf der rechten Seite in der Hex-Ansicht siehst du die binäre Darstellung (als Hexwerte) dieser Befehle. Du kopierst dir die ersten x Bytes und schaust ob diese Bytereihenfolge mehr als einmal (also noch an anderen Stellen) vorkommt. Falls ja, musst du die Signatur solange vergrößern bis sie eindeutig ist.

In deinem Programm suchst du nun nach genau dieser Bytefolge (das ist jetzt die aus dem Beispiel, du musst natürlich deine Signatur benutzen):

Zitat:

56 33 F6 57 8B 3D 24 C2 5B 00 C7 05 48 86 5F 00 74 C6 5D 00 39 35 50 86 5F 00 76 1B
Da sich zumindest für far-jumps/calls/etc die Adressen ändern können musst du diese Bytes ignorieren.
Dadurch ergibt sich in meinem Fall folgendes Muster:

Zitat:

56 33 F6 57 8B 3D ** ** ** ** C7 05 ** ** ** ** ** ** ** ** 39 35 ** ** ** ** 76 1B
** bedeutet in dem Fall dass diese Bytes bei der Suche nach der Signatur ignoriert werden.
Du solltest jetzt nochmal sichergehen dass die Signatur trotz der "Don't care"-Bytes immernoch eindeutig ist!


Edit: Ich glaube ich hab dich ein bisschen falsch verstanden. Du suchst keine Funktion sondern einen einzelnen Variablenwert. Du kannst mit GetModuleHandle(nil) die Startadresse deines Prozesses herausfinden. Ggf. musst du dann die Basisadresse des Spiels per DLL-Injection herausfinden.

Aphton 19. Jul 2015 21:00

AW: Dynamische Memory Adressen - Startpunkt herausfinden
 
Mein Wissen über die Win-API ist etwas rostig, aber an sich sollte es nicht so schwer sein.

Ich verstehe dein Problem so:
Du hast beispielsweise die Speicheradresse 15 wo sich die Variable befindet und die Basisadresse bei des Spiels bei 9. Beim nächsten Start ist die Speicheradresse bei 33 und die Basisadresse des Spiels bei 27.
Dh. die Adresse der Variable ist relativ zur Basisadresse + 6.

Die Basisadresse ist meistens konstant, kann sich aber ändern oder wenn es eine Maßnahme gegen cheating ist, wird es sich ändern.
Um die Basisadresse rauszufinden, muss im Speicherbereich des Spiels laut GetModuleHandle
Zitat:

If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process (.exe file).
folgender Code ausgeführt werden:
Delphi-Quellcode:
  //
  GetModuleHandle(NIL)
"handle to the file" ist die Startadresse / Basisadresse / "Eintrittspunkt" so wie du das fälschlicherweise nennst.

Weiters bieten sich zwei Methoden an, um Code in einem fremden Speicherbereich / Prozess auszuführen:
- Dll Injection: du injizierst eine Dll die den Code oben ausführt
- Code Injection: du injizierst direkt Code in den fremden Process, führst in aus und liest das Result aus

Dll Injection ist einfach - vorallem weil es sehr viele Quellen gibt, wo das genau beschrieben wird.

Code Injection ist angenehmer, aber dafür etwas komplizierter.
Für die Codeinjection musst Speicher im fremden Process allozieren, den Speicherbereich per MSDN-Library durchsuchenVirtualProtect() auf PAGE_READWRITE_EXECUTE setzen (also ausführbar machen), deinen Code dort reinschreiben, dann einen weiteren Speicherbereich allozieren, wo du deine Daten festhältst (Variablen, Rückgabewerte usw - in diesem Fall genau 4 Bytes).
Weiters musst du in der Bytefolge deines Codes die Adresse des Speicherbereichs, denn du gerade alloziert hast, reinschreiben.
Anschließend kannst du dein Code ausführen, da er nun alle Daten enthält.
Nachdem dein Code fertig ist (WaitForSingleEvent() mit dem Handle von CreateRemoteThread oder so ähnlich - recherchieren!), kannst du den Rückgabewert anschließend wieder auslesen.

Warnung: VAC.
Sobald du im Spielprozess rumpfuscht, wird VAC sich ein Profil von dir machen. Bei nem offiziellen Server wirst du direkt geebannt, offline tricksen die auch rum - die merken sich, wer gerade an Blödsinn Interesse hat bzw. nen "cheat" entwickelt. Ich würd das einfach sein lassen. Sofern du es nicht gepirated hast, ist es nicht Wert, die ~15€, die du für das Spiel investiert hast, zu verlieren.

milos 21. Jul 2015 11:30

AW: Dynamische Memory Adressen - Startpunkt herausfinden
 
Liste der Anhänge anzeigen (Anzahl: 1)
Vielen dank für eure antworten :)

Aphton hat es erfasst. Ich würde gerne die Basisadresse (;)) eines Prozesses finden. Über den Weg mit dem Injecten und GetModuleHandle bin ich über Google schon gestossen, jedoch ist das Injecten genau das welches ich eigentlich vermeiden will, da das ganze Extern laufen soll ohne wirklich in den Prozess eingreifen zu müssen ausser das ich ein paar Daten auslesen will. Im Internet bin ich über eine Interessante Funktion gestossen:

Delphi-Quellcode:
function GetBasePointerOfModule(ProcessId: dword; Modulename: string): Integer;
var
  FSnapshotHandle: THandle;
  FModulEntry32: MODULEENTRY32;
  s: string;
begin
  Result := 0;
  FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId);
  try
    if FSnapshotHandle <> INVALID_HANDLE_VALUE then
    begin
      FModulEntry32.dwSize := SizeOf(FModulEntry32);
      if Module32First(FSnapshotHandle, FModulEntry32) then
      begin
        repeat
          s := FModulEntry32.szModule;
          if s = Modulename then
          begin
            Result := Integer(FModulEntry32.modBaseAddr);
            break;
          end;
        until (not Module32Next(FSnapshotHandle, FModulEntry32));
      end;
    end;
  finally
    closeHandle(FSnapshotHandle);
  end;
end;
Diese gibt mir immer eine Adresse zurück die immer gleich ist, bis man das Spiel neu startet. Jedoch scheint es nicht die gesuchte Basisadresse zu sein. Die Funktion benutze ich so:

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  GameHandle : Cardinal;
  BaseAddress : int64;

  Address : Int64;
  Bytesread: SIZE_T ;
  puffer : DWORD;

  Window : cardinal;
  PID : cardinal;
begin

  Window := FindWindow(nil,'Counter-Strike: Global Offensive');
  GetWindowThreadProcessId(Window,PID);
  GameHandle := OpenProcess(PROCESS_VM_READ,false,PID);

  if GameHandle > 0 then
  begin
    BaseAddress := GetBasePointerOfModule(PID, 'csgo.exe');

    showmessage('Base: ' + IntToHex(BaseAddress,8));

    Address :=BaseAddress + $0;

    ReadProcessMemory(GameHandle, ptr(Address), @puffer, sizeof(puffer), Bytesread);

    showmessage(puffer.ToString());
  end;
end;
Im Anhang gibts ein Bild, welches im Dialogfenster die zurückgegebene Adresse und unter dem Fenster die Baseadresse von Cheat Engine zeigt. Ist das ein Fehler der Funktion oder ist "csgo.exe" wahrscheinlich das falsche Modul?

Ich hoffe es gibt einen der weiter weiss ^^

Freundliche Grüsse

Wegen VAC: Danke für die Warnung :) Ich habe nicht vor einen "echten Hack" mit Aimbot, Wallhack usw. zu schreiben. Das ganze dient eher als kleine Übung und da es mich in den letzten Tagen sehr Interessiert hat würde ich da auch gerne weiter machen. Nun ist es nur noch die Basisadresse die mich daran hindert :/ Alles natürlich auf meinem Smurf, offline gegen Bots und ohne aktiviertem VAC :D

Und auch wenn man es mir nach dem Thread wahrscheinlich nicht glauben mag: Ich hacke nicht, dafür spiele ich schon zu lange Teambasierte Competetive Spiele mit Leidenschaft, als dass ich mein Spielerlebniss mit Hacken zerstöre ;)

Neutral General 21. Jul 2015 11:36

AW: Dynamische Memory Adressen - Startpunkt herausfinden
 
Warum denkst du, dass es nicht die richtige Basisadresse ist?
Vllt. sind deine Nachfolgenden Berechnungen einfach nicht ganz korrekt?

(PS: Ich denke "Eintrittspunkt" ist durchaus ein nutzbarer Begriff in dem Zusammenhang wenn man bedenkt, dass es im Englischen "entry point" genannt wird.)

milos 21. Jul 2015 12:40

AW: Dynamische Memory Adressen - Startpunkt herausfinden
 
Zitat:

Zitat von Neutral General (Beitrag 1309368)
Warum denkst du, dass es nicht die richtige Basisadresse ist?
Vllt. sind deine Nachfolgenden Berechnungen einfach nicht ganz korrekt?

(PS: Ich denke "Eintrittspunkt" ist durchaus ein nutzbarer Begriff in dem Zusammenhang wenn man bedenkt, dass es im Englischen "entry point" genannt wird.)

Weil ich es so probiert habe:
  1. Spiel gestartet.
  2. Basisadresse der Methode abgefragt und 008D0000 bekommen.
  3. Danach habe ich über Cheat Engine den Wert gesucht den ich haben wollte: 047AEC0C
  4. Wenn ich nicht falsch liege bekomme ich die Speicheradresse indem ich die Basisadresse von der in Cheat Engine gefundene Speicheradresse subtrahiere: 047AEC0C - 008D0000 = 3EDEC0C
  5. Nun lese ich in Delphi die Adresse (Basisadresse + Speicheradresse) aus und das klappt natürlich.
  6. Um ganz sicher zu sein teste ich dies natürlich indem ich das Spiel neustarte.
  7. Also versuche ich nochmal die errechnete Speicheradresse (03D1AE4C) mit der neuen Basisadresse (00FB0000) zu addieren und diese Adresse auszulesen, was nun nicht mehr klappt. (00FB0000 + 3EDEC0C = 4E8EC0C)
  8. Habe also Cheat Engine wieder angeschmissen, die Adresse manuel gesucht und siehe da: Die neue Adresse ist 0456E30C, also anders als ich es einen Schritt vorher versucht habe...
Habe ich hier was falsch gemacht?

Könnte es sein das csgo.exe nicht das richtige Modul ist?
Delphi-Quellcode:
BaseAddress := GetBasePointerOfModule(PID, 'csgo.exe');
Hab das ganze gerade 3 mal getestet um sicher sein zu können keinen Fehler gemacht zu haben.

Freundliche Grüsse :)

Neutral General 21. Jul 2015 13:05

AW: Dynamische Memory Adressen - Startpunkt herausfinden
 
Hast du in Cheatengine mal geschaut ob es einen Pointer auf deinen Wert gibt? Wahrscheinlich wird für deinen Wert dynamisch Speicher reserviert und der Speichermanager hat dann aufgrund von unterschiedlichen Speicherreservierungen/Freigaben zum letzten Start (man tut ja nicht jedes mal exakt das gleiche, d.h. für unterschiedliche (oder unterschiedlich viele) Daten wurden ggf. in unterschiedlicher Reihenfolge Speicher reserviert).

Die Speicheradresse zum Pointer auf diesen Wert könnte aber statisch sein (zumindest so statisch, dass er im Verhältnis zur Basisadresse immer am selben Ort im Speicher zu finden ist). Über den Pointer kriegst du dann natürlich dann auch den Wert an den du wirklich ranwillst (bzw. die Adresse des Werts).

Wenn du Pech hast musst du auf den Pointer auf den Pointer auf den Wert zurückgehen, falls der Pointer auf den Wert auch dynamisch ist.

(Okay das war z.T. etwas anstrengend zu lesen - ich hoffe man kann es trotzdem verstehen^^)

Aphton 24. Jul 2015 14:37

AW: Dynamische Memory Adressen - Startpunkt herausfinden
 
Zitat:

Zitat von Neutral General (Beitrag 1309368)
(PS: Ich denke "Eintrittspunkt" ist durchaus ein nutzbarer Begriff in dem Zusammenhang wenn man bedenkt, dass es im Englischen "entry point" genannt wird.)

Nein.
Mit der "Basisadresse" meint er "ImageBase", nicht EntryPoint.. Das sind zwei verschiedene Dinge.
Die ImageBase ist üblicherweise die Startadresse des Images (Exe / DLL) im Speicher (meist 0x00400000) und EntryPoint ist eine RVA (relative virtual address) zum ersten Code im ".code" oder ".text" Segment einer exe/dll.
Code:
ImageBase = 0x00400000
EntryPoint = 0x00000400

Address of First Asm Code (entry point) = ImageBase + EntryPoint = ... usw
Edit: Zum eigentlichen Thema - zum Beitraag #8
Wie Neutral General erwähnt hat, muss es nicht so sein, dass die Variable, die du auslesen willst, sich immer an derselben Adresse befindet. Das kann spieltechnisch realisiert sein, oder vlt funkt dir auch ASLR (oder ähnliches) rein. Ist jedoch alles umgehbar, man muss halt nur vorher rausfinde, was für ein Fall vorliegt.

Führ z.B. das hier 2x mal aus:
Delphi-Quellcode:
var
  myVar: ^Integer;
begin
  new(myVar);
  showMessage(IntToHex(myVar, 8));
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:41 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz