Pointer und Offsets
-
Hallo
Ich habe ein kleinen Memory Hack für Pinball geschrieben (um den score zu ändern).
Nur leider muss ich immer wenn ich Pinball neu starte die Adresse mit cheat engine neu suchen und in den Code einfügen. Ich weiß, dass ich das verhindern kann, indem ich die Offsets rausfinde und die mit der vorherigen Adresse addiere! Aber wie finde ich die Offsets raus? Muss ich die Adresse und die Offsets nicht in eine Datei abspeichern, dass wenn ich den Pc ausmache nicht nochmal alles neu suchen muss?
-
Du brauchst die DLL Base Adresse.
Die bekommst du mit:
Module32First und Module32NextDann rechnest du: Zieladresse - DLL Base Adresse = erg
Dann einfach immer:
Dll Base Adresse + erg = Zieladresse
Dann geht es.
-
Was ist den Module32First bzw.wie verwendet man die Funktion?
-
RTFM.
Um das auch mal gesagt zu haben
-
Bassmaster schrieb:
Du brauchst die DLL Base Adresse.
Die bekommst du mit:
Module32First und Module32NextDann rechnest du: Zieladresse - DLL Base Adresse = erg
Dann einfach immer:
Dll Base Adresse + erg = Zieladresse
Hat dann nicht Zieladresse denselben Wert wie zu Beginn? Wozu dann die Rechnerei?
-
Weil sich die Basisadressen beim Neustart des Programms ändern können. Deshalb base + offset, damit man immer an der richtigen Stelle landet.
-
Belli schrieb:
Bassmaster schrieb:
Du brauchst die DLL Base Adresse.
Die bekommst du mit:
Module32First und Module32NextDann rechnest du: Zieladresse - DLL Base Adresse = erg
Dann einfach immer:
Dll Base Adresse + erg = Zieladresse
Hat dann nicht Zieladresse denselben Wert wie zu Beginn? Wozu dann die Rechnerei?
Sichwort: ASLR
-
Hi schrieb:
Weil sich die Basisadressen beim Neustart des Programms ändern können.
Das ist mir schon klar.
Aber:Bassmaster schrieb:
Du brauchst die DLL Base Adresse.
Dann rechnest du: Zieladresse - DLL Base Adresse = ergDann einfach immer:
Dll Base Adresse + erg = Zieladresse
das verwirrt mich. Das klingt nicht wie:
1. Base Adresse ermitteln.
2. Base Adresse + Offset = Zieladressewie ich es erwarten würde ...
-
Doch, wieso nicht?
Zieladresse - DLL Base Adresse = erg
Zieladresse, also die aktuelle Adresse der Interesse, zB 0x8674C0.
Basisadresse des Moduls, das diese Adresse beinhaltet, zB. 0x740000.
0x8674C0 - 0x740000 = 0x1274C0 ist erg (offset)Dll Base Adresse + erg = Zieladresse
0x5B0000 (Basisadresse wechselt) + 0x1274C0 (erg/offset) = 0x6D74C0 (neue Zieladresse, selbe Position im Modul wie vorher 0x8674C0)
-
Okay, ich hatte nicht verstanden, dass zwei unterschiedliche Programmaufrufe gemeint waren ...
-
Dll Base Adresse + erg = Zieladresse
0x5B0000 (Basisadresse wechselt) + 0x1274C0 (erg/offset) = 0x6D74C0 (neue Zieladresse, selbe Position im Modul wie vorher 0x8674C0)Muss man dann nicht trotzdem immer wenn die Basisadresse wechselt sie neu raussuchen und in den Quellcode schreiben? Und wie kann man die Dll base adresse und die Offsets rausfinden?
Bin grad ein bischen Verwirrt
-
Bassmaster schrieb:
Du brauchst die DLL Base Adresse.
Die bekommst du mit:
Module32First und Module32NextOffset findest du selbst raus, indem du die gewünschte Adresse hernimmst und die aktuelle Base des Moduls, das sie beinhaltet, abziehst.
Das musst du natürlich nur 1x machen, der offset bleibt fix, wenn sich das Modul selbst nicht verändert.
-
lolipoplol schrieb:
Muss man dann nicht trotzdem immer wenn die Basisadresse wechselt sie neu
raussuchen und in den Quellcode schreiben?Die Basisadresse musst du immer wieder neu ermitteln, dafür kannst du ja die Funktion Module32First bzw. Module32Next verwenden, du musst die Basisadresse also nicht immer neu in deinen Quelltext schreiben und neu compilieren.
Hier ein Beispiel:
unsigned GetDllBaseAddress( unsigned ProcessId, string DllName ) { HANDLE snap; MODULEENTRY32 lppe; ZeroMemory(&lppe,sizeof(MODULEENTRY32)); lppe.dwSize = sizeof(MODULEENTRY32); snap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, ProcessId ); if ( snap == INVALID_HANDLE_VALUE ) { cout<< "CreateToolhelp32Snapshot error: " << GetLastError() << "\n"; return 0; } Module32First( snap, &lppe ); do { if ( !strcmp( lppe.szModule,DllName.c_str()) ) { cout<<lppe.szModule<< " "<<hex<<lppe.hModule<<"\n"; break; } } while ( Module32Next ( snap , &lppe ) == 1 ) ; return unsigned(lppe.hModule); }
-
Falls du den Code verwendest:
- Bitte Funktionsargumente überprüfen
- Bitte Rückgabewerte von Funktionen überprüfen
- Ein komplettes string Objekt zu übergeben ist zu viel, ein Sring-Pointer reicht, falls C dann sowieso ein C-String Pointer
- Der Aufruf von ZeroMemory ist unnötig.
- Bitte abstrakte Windows Datentypen bei Windowsfunktionen zur Rückgabewertabfrage benutzen (TRUE anstatt 1)
-
Tippsundso schrieb:
- Bitte Funktionsargumente überprüfen
Unnötig, wenn man den Code nur selbst verwendet und weiß was man tut.
Tippsundso schrieb:
- Ein komplettes string Objekt zu übergeben ist zu viel, ein Sring-Pointer reicht
Dann doch gleich ne const ref.
Tippsundso schrieb:
- Bitte abstrakte Windows Datentypen bei Windowsfunktionen zur Rückgabewertabfrage benutzen (TRUE anstatt 1)
Meist unnötig und hässlich!
:p
-
thx @ Hi das erspart mir Schreibarbeit.
-
Hi schrieb:
Tippsundso schrieb:
- Bitte Funktionsargumente überprüfen
Unnötig, wenn man den Code nur selbst verwendet und weiß was man tut.
Tippsundso schrieb:
- Ein komplettes string Objekt zu übergeben ist zu viel, ein Sring-Pointer reicht
Dann doch gleich ne const ref.
Tippsundso schrieb:
- Bitte abstrakte Windows Datentypen bei Windowsfunktionen zur Rückgabewertabfrage benutzen (TRUE anstatt 1)
Meist unnötig und hässlich!
:p
zu 1: So etwas ist nie unnötig und man sollte das automatisch immer machen! Wenn man da sogar nur ein bisschen nachlässig ist, dann ist die Wahrscheinlichkeit gegeben, dass man das auch mal in einem echten Projekt vergisst. Und dann krachst's unter Umständen.
zu 2: Kann man auch machen.
zu 3: Wenn man WinAPI programmiert, dann sollte man schon auch den Style verwenden. Und wenn eine Funktion abstrakt einen BOOL berechnet, dann überprüfe ich eben auf FALSE/TRUE. Das hat schon seinen Sinn, warum man dies machen soll. Verstehe auch nicht, was daran hässlich sein soll?!
Du würdest doch auch nichtvoid* hOwnProcess = GetCurrentProcess();
schreiben, oder?!
Gut, dieses Beispiel ist schon extremer, aber dennoch darf man niemals nachlässig sein!! Wenn ich WinAPI bezogen programmiere, dann verwende ich auch nur die abstrakten Datentypen, welche dafür vorgesehen sind.
-
Tippsundso schrieb:
Du würdest doch auch nicht
void* hOwnProcess = GetCurrentProcess();
schreiben, oder?!
Dochdoch, immer. Wenn es native Typen sind...
Aber ich arbeite ja auch nur für mich.:p
-
Tippsundso schrieb:
Du würdest doch auch nicht
void* hOwnProcess = GetCurrentProcess();
schreiben, oder?!
Gut, dieses Beispiel ist schon extremer, aber dennoch darf man niemals nachlässig sein!! Wenn ich WinAPI bezogen programmiere, dann verwende ich auch nur die abstrakten Datentypen, welche dafür vorgesehen sind.
Klar. Wenn bald irgendwann Windows 128Bit rauskommt, kannste einfach den Sourcecode nehmen und auf 128Bit compilieren und fertig ist der Lack. Schon kann das Programm mit mehr als 16Mio Terabyte Ram umgehen. Einfach so.
Also bei der Umstellung von 32 auf 64 war das schon sehr praktisch, daß ich mich vorher schon an die Typen gehalten hatte.Nee, eigentlich ist es für mich nur viel einfacher, mich an die MS-Typen und Konstanten zu halten. Dann muss ich weniger nachdenken, sondern kann einfach machen, was in der Doku steht.
-
Pointer und Offsets mit WinApi?
Bereits Windows 3.1 (16 bit) hatte da eigene Vorgehensweisen mit Handles und WinApi-Funktionen.
Es ist zweckmässig, sich daran zu halten. Offsets waren unter DOS-16 ein Graus zur Überwindung der 64-kB-Grenze, woran man sich nur ungern erinnern möchte!
-
Ähh, was?
Lies den ersten Post des Threads...