VC++ Zugriffsverweigerung(Dereferenzierung)
-
Hallo Community,
ich bin neu hier im Forum und würde mich über hilfreiche Antworten sehr freuen.
Ich arbeite mit Visual Studio 2010 Ultimate, allerdings ist mir diese Umgebung neu, da ich meine Anfänge mit Dev C++ getan habe.
Der Quelltext:
#include <Windows.h> #include <iostream> using namespace std; int main() { DWORD Adresse = *(DWORD*)(0x010AFFD4 + 0x26B4); DWORD Outcome = *(DWORD*)(Adresse + 0x28); cout << hex << Outcome << endl; getchar(); }
Die Fehlermeldung
Unbehandelte Ausnahme bei 0x00f43733 in Test.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x010b2688.
Was mache ich falsch?
Mit freundlichen Grüßen
Infemo
-
Was soll denn deiner Meinung nach ausgegeben werden?
-
Darf ich mal raten: er will nen Cheat für WoW basteln.
-
Wenn man nach 0x010AFFD4 googled, findet man tatsächlich was über WoW. :xmas1:
-
Eigentlich ist es für Inkball ^^
Ihr könnt euch das ja mal runterladen und nach der Score Adresse suchen
0x00B21870 sollte als endgültige Adresse rauskommen der ich dann wie folgt
einen neuen Wert zuweisen möchte. Allerdings muss irgendetwas an der fett gedruckten Rechnung falsch sein...void SetValue() { int *Pointer; [b] DWORD Adress1 = *(DWORD*)(Adress_Base + Offset); DWORD Adress_Outcome = *(DWORD*)(Adress1 + Offset2); [/b] //Adressübergabe *Pointer = *(DWORD*)Adress_Outcome; //Dereferenzieren *Pointer=5000; }
Danke für eure Hilfe!
Grüße
-
So wie du das machen willst geht es nicht.
Such mal nach WriteProcessMemory().
-
Die Funktion befindet sich in einer Dll.
D.h. ich bin im Adressraum des Programmes. In diesem Fall Inkball. Dann sollte es doch mit Dereferenzieren funktionieren oder nicht?
-
Diese Zeile dürfte ja schon den Fehler liefern:
DWORD Adresse = (DWORD)(0x010AFFD4 + 0x26B4);
d.h. die sich ergebende Adresse ist 0x010b2688, was auch deiner Fehlermeldung entspricht:
Zugriffsverletzung beim Lesen an Position 0x010b2688.
An der Rechnung ist erstmal nichts falsch, sofern Du wirklich an dieser Position lesen willst, was aber nicht geklappt hat, weil dies eine ungültige Adresse ist. Lass mich raten, Du setzt Windows 7 ein?
-
Vielen Dank für Ihre hilfreiche Antwort.
Falls Sie mit "Lass mich raten, Du setzt Windows 7 ein?" meinen, dass mein Betriebssystem Windows 7 ist, dann ist die Antwort "Ja".
Wie kann die Adresse ungültig sein? Ich habe diese doch vorher genau definiert.
Wie kann ich die Zugriffsverweigerung umgehen und somit ein fehlerfreies oder überhaupt ein Ergebnis erzielen?
Liebe Grüße
Infemo
-
Windows 7 randomisiert die Ladeadressen bei jedem Programmstart. d.h. wenn Du im Debugger oder sonstwie feststellst, deine Highscore Adresse ist XY, dann ist sie beim nächsten Start des Programms eine andere.
-
Allerdings ist dies dcoh ein Pointer. Dieser bleibt immer gleich und zeigt auf die richtige Adresse.
Der Pointer sollte sich keineswegs ändern.
Wenn ja, wie kann ich dies verhindern?
-
Zunächst möchte ich feststellen, dass diese Frage nichts mit der MFC oder MSVS zu tun hat, sondern im Code.
Folgendes: in deiner EXE, die von Windows ausgeführt wird, befindet sich Binärcode. Dieser Binärcode kann wiederum unterteilt werden in Daten und Maschinencode. Der Maschinencode greift auf die Daten zu, und die Daten bieten dem Code eine Möglichkeit, sich auszutoben, und das nennt man dann Ausführung.
Wenn ein Prozess gestartet wird, bekommt dieser erst einmal 4 GB an RAM zugewiesen (auf 32-Bit-Systemen). Diese sind allerdings rein virtuell und müssen erst über Einträge in den Pagefiles mit reelem, physikalisch existieren Speicher verknüpft werden (über
malloc
/calloc
, demnew
-Operator oder einerHeapXXXX
-Funktion), sonst haut der Kernel/Betriebssystem eine Fehlermeldung raus. Diese 4 GB werden dann der Reihe nach mit dem Binärcode gefüllt. Maschinencode befindet sich für gewöhnlich im Codesegment (oder mehreren), Daten im Datensegment. Früher hatte das einen wichtigen Grund, aber ich glaube, heute macht man das nur der Abwärtskompatibilität wegen.Weiter im Text: in der EXE steht ziemlich genau, wo das Programm eingeladen sein will. Im virtuellen Speicher (übrigens hast du immer nur auf diesen Zugriff, außer bei der Treiberprogrammierung, habe ich gehört, aber nimmer damit beschäftigt) wird der Rotz dann eingeladen und angelegt, und der Code verlässt sich darauf, dass die Adressen des Speichers für die Daten im Datensegment richtig sind (auch hier gibt es Ausnahmen, wenn ein DLL-Modul oder eine Bibliothek meint, ausgerechnet in den von deiner Anwendung ausgewählten Lieblingsbereich geladen zu werden, dann muss das Programm an eine andere Stelle geladen und die Adressen hochgerechnet werden. Das sollte allerdings kaum passieren, da die Windows-DLL standardmäßig am Arsch des virtuellen Speichers geladen werden und daher mit deinem Programm fast nie in Berührung kommen sollten). Auf diese wird tatsächlich statisch zugegriffen:
1. Funktion muss aufgerufen werden, übernimmt einen Parameter. Die Adresse des zu übergebenden Wertes ist 0x12345678.
2. An Stelle 0x12345678 wird der Wert abgefragt und dann auf den Stack als Parameterübergabe gelegt (wobei es hier Unterschiede in der Reihenfolge und in dem Objekt, welches die Daten auf den Stack legt, gibt, aber das braucht dich nicht zu kümmern).
3. Fertig.Diese Art der Referenzierung ist ziemlich einfach. Man ruft einfach den Wert an einer Adresse ab und verwendet ihn.
Allerdings hat das auch einen Nachteil, welche einem umso bewusster wird, wenn man C oder C++ als LowLevel-Sprache definiert, weil Sie nativ keine Strings unterstützt. Es gibt zwar gute Klassen, die diese emulieren, aber nativ sind diese nicht in der Sprache vorhanden - und zwar aus dem Grund, weil zur Kompilierzeit nicht ersichtlich ist, wie groß das Objekt später ist. Ähnlich in den Segmenten und im Stack, hier muss auch bekannt sein, wie groß das Objekt ist, welches man verwenden will.
Deshalb hat ein weiser und liebender Gott Zeiger erfunden. Zeiger sind nichts anderes als ganz normale Variablen, in denen Werte stehen. Der Unterschied zu normalen Variablen ist jedoch, dass man bei Zeigern den Wert als Adresse interpretiert. In dieser Adresse können dann Daten stehen, und zwar sehr viel dynamischere, als es uns die Datensegmente oder der Stack erlauben. Der Zeiger an sich ist immer noch auf dem Stack oder im Segment, aber wenn man den Wert in ihm als Adresse interpretiert, kommt man zu freiem Speicher - wenn man ihn dem Betriebssystem so verkauft hat, dafür gibt es die bereits oben genannten Wege a'la
new
. Denn das OS bestimmt, was frei ist und was nicht.1. Funktion muss aufgerufen werden, übernimmt einen Parameter. Dieser ist unbekannt, aber im Code steht, dass, wenn man den Wert an Adresse 0x12345678 wiederum als Adresse interpretiert, dieser Wert erscheint.
2. An Stelle 0x12345678 wird der Wert abgefragt und als Adresse interpretiert.
3. An der interpretierten Adresse findet sich der gesuchte Wert.
4. Der gefundene Wert wird auf den Stack gelegt.
5. Fertig.Langer Rede kurzer Sinn: ich habe keine Ahnung, was du genau versuchst, aber eventuell solltest du nicht nach der Adresse, sondern nach dem Zeiger suchen.
EDIT: Es kann auch sein, dass ein Zeiger nicht im Stack oder in den Segmenten liegt. In diesem Fall braucht es einen Zeiger auf einen Zeiger, um auf diese Adresse weisen zu können.
int main() { char A; //Wert auf dem Stack char*B=&A; //Zeiger, welcher auf den zuvor angelegten Wert auf dem Stack zeigt. char*C=new char[10]; //Vom OS einen Speicherbereich von sizeof(char)*10, also 10 Bytes fordern. delete[] C; //Diesen aber auch flugs wieder löschen. char**D=new char*[10]; //Sophisticated - man erstellt einen Zeiger auf dem Stack und fordert Speicherplatz für //10 Zeiger auf einen character ein. Diese brauchen dann auch ihren Speicher. for(int i=0;i<10;i++) D[i]=new char[10]; //Jedem dieser Zeiger, auf den D zeigt, ebenfalls Platz für 10 characters einräumen. //Nun darf man D nicht einfach löschen. Der Speicher, auf den D zeigt, geht dadurch verloren, und damit auch die //Adressen, auf die die Unterzeiger von D gezeigt haben. Hier also 100 Bytes, die man bei OS wieder als //Arbeitslos melden muss. :) for(int i=;i<10;i++) delete[] D[i]; //Nun kann man D löschen. delete[] D; return 0; }
Ich hoffe, du hast das verstanden.
-
Infemo schrieb:
Allerdings ist dies dcoh ein Pointer. Dieser bleibt immer gleich und zeigt auf die richtige Adresse.
Der Pointer sollte sich keineswegs ändern.
Wenn ja, wie kann ich dies verhindern?
Der Pointer selbst hat ja auch eine Adresse. Der Zugriff darauf schlägt ja schon fehl und zwar wie gesagt aus dem Grund, dass Windows dein Programm bei jedem Start an eine andere Speicheradresse läd (die Startadresse/Ladeadresse/etc dies Moduls). Übrigens genau um das zu verhindern bzw zu erschweren was du vorhast (Malwareautoren können sich nicht mehr auf feste, immer gleiche Adressen in ihren Exploits verlassen).
Intern im Programmcode sind Zugriffe meistens relativ zur Startadresse kodiert (also nicht "Zugriff auf absolut 0xABCD" sondern als "Zugriff auf $aktPos+0x1234"). Wenn sie absolut sind, dann trägt Windows beim Laden des Programms dafür Sorge, dass die entsprechenden Offsets aufaddiert werden.
Du musst also nicht die absolute Adresse deines Pointers nehmen sondern die Pointeradresse relativ zur Startadresse deines Programms ermitteln. Jedesmal beim Laden von deiner DLL wiederrum die aktuelle Ladeadresse ermitteln und dir damit die richtige Adresse ausrechnen.
Wenn Dir das alles zu hoch ist, nimm für den Anfang bzw zum Testen Windows XP, da bleiben die Adressen gleich und es funktioniert mit deiner aktuellen Methode (sofern Du sonst keine Fehler drin hast, natürlich).
-
@Der aus dem Westen...
Vielen Dank für diese umfangreiche Antwort. Viele Dinge waren mir unklar bzw. ich habe noch nie von dem was Sie geschrieben haben gehört, allerdings war es sehr interessant und belehrend!
Soweit ich das mitbekommen habe, haben wir den Wert des Zeigers auf dem Stack, warum genau ein Stack weis ich nicht, aber ich bin mir sicher, man kann auch andere Datenstruckturen verwenden
Allerdings möchte ich den Wert verändern und dies funktioniert nur durch Dereferenzierung, indem ich den Wert eines, auf ein Objekt zeigenden, Zeiges verändere.
Das Objekt in diesem Fall wäre die Adresse.
Hier missling jedoch die Berechnung, weswegen das Verwenden auch nicht funktioniertIch habe verstanden was Sie erklärt haben, leider bringt mich das momentan noch nicht weiter
Der Witz mit den Arbeitslosen war aber gutNochmal zur Erklärung:
Ich möchte durch Dll Injection einen Wert in einem Programm (in diesem Fall Inkball) verändern. Da sich die Adresse jedoch bei jedem Programmstart änder brauche ich einen Pointer.
Diesen habe ich mit Hilfe von Cheat Engine herausgefunen:DWORD Address_Base = 0x010AFFD4;// Baseadresse DWORD Offset = 0x26B4; DWORD Offset2 = 0x28;
Diese drei Adressen sollten durch folgenden Berechnung die Adresse ergeben, von welche ich den Wert verändern möchte.
DWORD Address1 = *(DWORD*)(Address_Base + Offset); DWORD Address_Outcome = *(DWORD*)(Address1 + Offset2);
Um den Wert der Adresse verändern zu können, kommt die Dereferenzierung ins Spiel:
//Zeiger int *Pointer; //Adresse übergeben *Pointer = *(DWORD*)Address_Outcome; //Dereferenzieren *Pointer=5000;
Allerdings funktioniert dies ja nicht, da Windows 7 die Ladeadressen randomisiert bei jedem Programmstart und diese sich so ändern.
Allerdings sollte dies durch die Benutzung des Pointers egal sein.
Es funktioniert trotzdem nicht^^Problem verstanden?
@Morle
Meinst du ich sollte die Moduladresse von dem Prozess in den die Dll injeziert wurde nehmen und die zu der Adresse addieren?
Wie komme ich denn von der Absoluten auf die Adresse, welche relativ zur Programmstartadresse ist?Das Problem liegt darin, dass ich kein Windows XP zum testen zur Verfügung habe
Also bleibt mir nur die Hoffnung auf weitere hilfestellung von Ihnen!Mit freundlichen Grüßen
Infemo
-
Infemo schrieb:
@Der aus dem Westen...
Vielen Dank für diese umfangreiche Antwort. Viele Dinge waren mir unklar bzw. ich habe noch nie von dem was Sie geschrieben haben gehört, allerdings war es sehr interessant und belehrend!
Kannst mich übrigens ruhig duzen, habe die 21 nicht mal überschritten und will mich nicht so alt fühlen.
Infemo schrieb:
Soweit ich das mitbekommen habe, haben wir den Wert des Zeigers auf dem Stack, warum genau ein Stack weis ich nicht, aber ich bin mir sicher, man kann auch andere Datenstruckturen verwenden
Jetzt sprichst du was an. Als ich mich in die Materie einlaß, habe ich folgende Arten von Speicher kennengelernt:
- Datenspeicher (wo globale Variablen und statische Elemente definiert werden)
- Codespeicher (nona, wo der Code nun mal geladen wird)
- Register (Speicher direkt auf der CPU, sehr klein, sehr beschränkt - seit x64 nicht mehr so stark, aber für den kompiliert ja kaum einer für Windows - aber sehr schnell)
- Stack (C++ ist wie C sehr LowLevel-basiert, weshalb einige Konzepte 1:1 in Maschinencode übertragen werden können. So das Prozedurenkonzept - wenn eine Funktion aufgerufen wird, die ihre eigenen Werte definiert und speichert, werden diese auf den Stack gelegt und bei Rückkehr wieder weggenommen. Last in, first out - dieser Speicher ist, verglichen mit den vorherigen drei Speichern dynamischer, aber nicht dynamisch genug)
- Heap (der restliche Speicher, nicht vom Betriebssystem reserviert. Der freieste Speicher, aber auch der, für den man die größte Verantwortung übernimmt, denn diesen muss man auch wieder explizit freigeben)Mit diesem Modell kann man sich gut vorstellen, warum der Zeiger an sich im Datensegment oder auf dem Stack liegen sollte - man kennt die Adresse. Zugriff ist sehr wichtig, vor allem auf dem Heap. Wenn ich mit
new
Speicher reserviere, dessen Adresse aber in keinem Zeiger reserviere, den ich irgendwie ansprechen kann, dann kann ich diesen auch nicht wieder freigeben. Und der Basiszugriff läuft nur über diese Speicher ab - am Ende kommst du nur auf konstante Adressen, in denen Werte als dynamische Adressen gesichert werden.Infemo schrieb:
Allerdings möchte ich den Wert verändern und dies funktioniert nur durch Dereferenzierung, indem ich den Wert eines, auf ein Objekt zeigenden, Zeiges verändere.
Das Objekt in diesem Fall wäre die Adresse.
Hier missling jedoch die Berechnung, weswegen das Verwenden auch nicht funktioniertDer sagt denn, dass an dieser Stelle ein Zeiger auf dem Stack oder im Datensegment liegt? Es kann ja sehr gut sein, dass am Ende ein Zeiger auf dem Stack auf einen Zeiger im Heap zeigt, und dieser zeigt dann auf den von dir gewünschten Wert. Wenn du also die Kette verstehen willst, reicht es nicht, davon auszugehen, dass Zeiger immer eine konstante Adresse aufweisen, denn nicht du oder der Compiler bestimmen bei dynamischer Speicherverwaltung, wo der Zeiger am Ende hinzeigt, sondern das OS.
Such also erst einmal die Adresse auf dem Stack, interpretiere dann den Wert als Adresse, hohl dir dann den Wert an dieser Adresse und interpretiere diese noch einmal (interpretieren==dereferenzieren).
Infemo schrieb:
DWORD Address_Base = 0x010AFFD4;// Baseadresse DWORD Offset = 0x26B4; DWORD Offset2 = 0x28;
Diese drei Adressen sollten durch folgenden Berechnung die Adresse ergeben, von welche ich den Wert verändern möchte.
DWORD Address1 = *(DWORD*)(Address_Base + Offset); DWORD Address_Outcome = *(DWORD*)(Address1 + Offset2);
Ich kenne mich mit dem genannten Programm nicht aus, nur mit IDA.
Eventuell ist dessen Analyse aufschlussreicher, Schaden kann es nicht.
Infemo schrieb:
Allerdings funktioniert dies ja nicht, da Windows 7 die Ladeadressen randomisiert bei jedem Programmstart und diese sich so ändern.
Allerdings sollte dies durch die Benutzung des Pointers egal sein.
Es funktioniert trotzdem nicht^^Das Windows 7 die Ladeadressen randomisiert ist mir relativ neu. Ich erinnere mich an eigene Experimente, wo ich aus einer einfachen Scriptsprache heraus Werte aus konstanten Adressen auslesen konnte. Ja, diese waren KONSTANT im Code definiert, im Datensegment der Anwendung - und diese Experimente fanden unter Windows 7 statt.
Die Randomisierung würde auch eigentlich dem Sinn von PE-Modulen widersprechen. Weshalb sonst sollte man die DLL-Module in die hinteren Reihe des virtuellen Speichers schmeißen, wenn am Ende Anwendungen nicht an Basisadresse 0x04001000 (glaube zumindest, so oder so ähnlich war die Standardadresse für Anwendungen) geladen werden sollen? Das ganze würde mehr an das ELF-Format von Linux erinneren, in dem Anwendungen tatsächlich dynamisch in den Speicher geladen werden. Dies führt (wenn man Wikipedia vertrauen darf) dazu, dass die Adressen hochgerechnet werden müssen, bei jedem Adresszugriff, was zu langsameren Ausführungszeiten kann.
Wenn du mir erklären kannst, wie das gehen soll, würde ich mich furchtbar gerne belehren lassen.
-
Zunächst:
http://en.wikipedia.org/wiki/Address_space_layout_randomizationWie dem auch sei, eigentlich hätte ich gedacht ich hätte genug geschrieben. Die richtige Adresse (bzw das richtige Offset) findet man, indem man:
a) Sich die Moduladresse "m" notiert
b) Sich dann die Adresse des Pointers "p" raussucht (ohne das man zwischendurch das Programm beeendet natürlich)c) sich den Offset "o" berechnet als "o=p-m"
Im Folgenden kann man sich dann die richtige Adresse jedesmal ermitteln, indem man zunächst die aktuelle Moduladresse ermittelt und dann jeweils "o" draufaddiert.
Und jetzt mache ich Fondue
-
Ein Nachtrag noch:
Das was ich schrieb gilt für Pointer die im Datensegment liegen.
-
Der aus dem Westen... schrieb:
Kannst mich übrigens ruhig duzen, habe die 21 nicht mal überschritten und will mich nicht so alt fühlen.
Okay, konnte ich nicht wissen, nur eine Frage des Respektes
Der aus dem Westen... schrieb:
- Datenspeicher (wo globale Variablen und statische Elemente definiert werden)
- Codespeicher (nona, wo der Code nun mal geladen wird)
- Register (Speicher direkt auf der CPU, sehr klein, sehr beschränkt - seit x64 nicht mehr so stark, aber für den kompiliert ja kaum einer für Windows - aber sehr schnell)
- Stack (C++ ist wie C sehr LowLevel-basiert, weshalb einige Konzepte 1:1 in Maschinencode übertragen werden können. So das Prozedurenkonzept - wenn eine Funktion aufgerufen wird, die ihre eigenen Werte definiert und speichert, werden diese auf den Stack gelegt und bei Rückkehr wieder weggenommen. Last in, first out - dieser Speicher ist, verglichen mit den vorherigen drei Speichern dynamischer, aber nicht dynamisch genug)
- Heap (der restliche Speicher, nicht vom Betriebssystem reserviert. Der freieste Speicher, aber auch der, für den man die größte Verantwortung übernimmt, denn diesen muss man auch wieder explizit freigeben)Und ich dachte ich hätte Ahnung
Mit DAtenstruckturen kenn ich mich relativ gut aus, aber das zwei als "Hauptspeicher" dienen war mir nie bewusst
Der aus dem Westen... schrieb:
Das Windows 7 die Ladeadressen randomisiert ist mir relativ neu. Ich erinnere mich an eigene Experimente, wo ich aus einer einfachen Scriptsprache heraus Werte aus konstanten Adressen auslesen konnte. Ja, diese waren KONSTANT im Code definiert, im Datensegment der Anwendung - und diese Experimente fanden unter Windows 7 statt.
Die Randomisierung würde auch eigentlich dem Sinn von PE-Modulen widersprechen. Weshalb sonst sollte man die DLL-Module in die hinteren Reihe des virtuellen Speichers schmeißen, wenn am Ende Anwendungen nicht an Basisadresse 0x04001000 (glaube zumindest, so oder so ähnlich war die Standardadresse für Anwendungen) geladen werden sollen? Das ganze würde mehr an das ELF-Format von Linux erinneren, in dem Anwendungen tatsächlich dynamisch in den Speicher geladen werden. Dies führt (wenn man Wikipedia vertrauen darf) dazu, dass die Adressen hochgerechnet werden müssen, bei jedem Adresszugriff, was zu langsameren Ausführungszeiten kann.
Wenn du mir erklären kannst, wie das gehen soll, würde ich mich furchtbar gerne belehren lassen.
Die Basisadresse sollte im Normalfall 0x400000, jedoch hat sich das Problem bereits gelößt
Ich brauche keine Moduleadressen^^ Und eigentlich wiederspricht die dann auch dem randomisieren, da es so einwanfrei funktioniert. Habe das Programm bestimmt 20Mal neugestartet und es hat jedes Mal geklapptvoid RewriteValues() { DWORD Address1 = *(DWORD*)(Address_Base) + Offset; DWORD Address_Outcome = *(DWORD*)(Address1) + Offset2; *(DWORD*)Address_Outcome = 5000; }
Falsche Klammern und den neuen Zeiger brauche ich auch nicht
Und ich glaube ich wäre nicht in der Lage Dich zu belehren!
Aber ich wünsche Dir einen guten Rutsch(gehabt zu haben)ins neue Jahr und alle Gute für 2012Morle schrieb:
Wie dem auch sei, eigentlich hätte ich gedacht ich hätte genug geschrieben. Die richtige Adresse (bzw das richtige Offset) findet man, indem man:
a) Sich die Moduladresse "m" notiert
b) Sich dann die Adresse des Pointers "p" raussucht (ohne das man zwischendurch das Programm beeendet natürlich)c) sich den Offset "o" berechnet als "o=p-m"
Im Folgenden kann man sich dann die richtige Adresse jedesmal ermitteln, indem man zunächst die aktuelle Moduladresse ermittelt und dann jeweils "o" draufaddiert.
So würde es auch funktionieren, allerdings wäre das nur ein normaler Pointer. In diesem Fall haben wir einen Level 2Pointer. Bei komplexeren Programmen geht es auch bis auf 5 hoch. Da würde das dann etwas komplizierter werden, glaube ich.
Aber das Problem hat sich ja schon gelößt. Die Adresse ist somit auch eine AbsoluteMorle schrieb:
Und jetzt mache ich Fondue
Hoffe Du hast es Dir schmecken lassen
Dir auch noch ein frohes neues JahrUnd alles Gute!
Vielen Dank für Eure Hilfe! Auch wenn wir nicht direkt zur Lösunge gelant sind, hat denke ich jeder etwas neues dazu gelernt^^
Also wenn Ihr Fragen zu Cheat Engine oder Dereferenzierung bezüglich einer absoluten Adresse eines Level 2 Pointers habt, dann fragt michWüsche allen ALLES GUTE für das Jahr 2012!
Mit freundlichen Grüßen
InfemoEdit (Martin Richter): Quotes gefixed
-
"Maximal sind 10 Smielys erlaubt."
Entschuldigt meine Ernsthaftigekeit in dem schreiben aber WTF?!Und mein mniese Zitieren ^^
Ich habe die Codes nicht draufBis dann
-
Infemo schrieb:
Okay, konnte ich nicht wissen, nur eine Frage des Respektes
Rüschpeckt. Du bist gut.
Infemo schrieb:
Und ich dachte ich hätte Ahnung
Mit DAtenstruckturen kenn ich mich relativ gut aus, aber das zwei als "Hauptspeicher" dienen war mir nie bewusst
Eigentlich ist der Heap ja auch der Hauptspeicher. Ah, das geht sehr weit in die Windowsprogrammierung rein.
Wenn du deine Anwendung startest, wird erst einmal ein Prozess gestartet. Dieser Prozess bekommt seine 4 GB an vir. Speicher und einen eigenen Heap. Muss ich so nennen, obwohl es eigentlich nur einen Heap gibt, aber in Windows kann man nun mal mehrere Heaps verwalten. Heap ist englisch, bedeutet "Halde" oder "Haufen", und das Konzept dahinter ist auch recht logisch. Es gibt einen globalen Heap für den Prozess, auf den jeder Thread zugreifen kann (mit der Win-API-Funktion
[url)http://msdn.microsoft.com/en-us/library/windows/desktop/aa366569%28v=vs.85%29.aspx]GetProcessHeap[/url]
), und du kannst auch noch weitere Heaps erstellen, in denen du dann deine Sachen speicherst. Allerdings geschleunigt dies die Fragmentierung im virtuellen Adressraum, sodass der Kernel irgendwann meldet, dass für dein Prozess kein Speicher mehr übrig ist, selbst wenn im physikalisch vorhanden Speicher noch Platz für mindestens fünf chinesische Großstädte ist.Der Stack ist da anders. Mit deinem Prozess bekommst du automatisch auch einen Thread (
main
,WinMain
,_tmain
und wie sie nicht alle heißen - ich persönlich verwende nurmain
oderWinMain
), den dein Prozess abarbeitet. Du kannst weitere Thread erstellen lassen (vom OS, C++ definiert nativ keine Threads, oder zumindest noch nicht - ich meine, gehört zu haben, dass sich dies mit dem Standard C++11 ändert, aber sicher bin ich mir nicht), welche dann Code ausführen. Jeder Thread verfügt über einen eigenen Stack, und auf den Stack anderer Threads sollte man möglichst nicht zugreifen. Wenn man es schafft, das Programm so zu schreiben, dass die Threads weitestgehend unabhängig voneinander arbeiten können, ohne dass Thread A Thread B in irgendwelche Variablen reinfuscht (wie gesagt, da kein Teil des Standards, muss man sich hier auf die Funktionen des OS verlassen), ist die Anwendung Threadsicher. Bei jedem Prozess bekommst du also einen Heap und bei jedem Thread einen eigenen Stack zur Verfügung gestellt.Infemo schrieb:
Die Basisadresse sollte im Normalfall 0x400000, jedoch hat sich das Problem bereits gelößt
Ich brauche keine Moduleadressen^^ Und eigentlich wiederspricht die dann auch dem randomisieren, da es so einwanfrei funktioniert. Habe das Programm bestimmt 20Mal neugestartet und es hat jedes Mal geklapptIch habe etliche PE-Exen mit Hex-Editoren, die dafür ausgelegt waren, Maschinencode zu interpretieren (HIEW) und Disassemblern (IDA) geöffnet. Ich meine, mich zu erinnern, dass die ersten 0x1000 Bytes Headerdaten beinhalten (ist allerdings nicht fix - das PE-Format ist recht dynamisch, je nachdem, was du später alles im Speicher haben willst), dann kommt ein Adresssprung, und plötzlich bin ich bei 0x00401000 oder um den Dreh. Aber gut ... ich habe ja gesagt, dass die Sachen statisch im Stack oder in den Datensegmenten stehen.
Infemo schrieb:
Und ich glaube ich wäre nicht in der Lage Dich zu belehren!
Aber ich wünsche Dir einen guten Rutsch(gehabt zu haben)ins neue Jahr und alle Gute für 2012Ach, quatsch. Man lernt nicht aus.
Infemo schrieb:
So würde es auch funktionieren, allerdings wäre das nur ein normaler Pointer. In diesem Fall haben wir einen Level 2Pointer. Bei komplexeren Programmen geht es auch bis auf 5 hoch. Da würde das dann etwas komplizierter werden, glaube ich.
Aber das Problem hat sich ja schon gelößt. Die Adresse ist somit auch eine AbsoluteEs war ein Adressbereich, der dynamisch erstellt wurde, richtig?
Dir auch ein interessantes Jahr 2012.