C++ Zugriff auf externen Speicherbereich

Rossibaer

Lieutenant
Registriert
Apr. 2007
Beiträge
754
Hallo zusammen, sicher könnt ihr mir da bei einem Problem helfen:

Folgender Code:

Code:
// im globalen header:
typedef unsigned int u32;
u32 const volatile * const pHTest = ((u32 *)0x1234);

// in der Funktion:
u32 test = *pHTest;

Sinn des ganzen soll sein, das ich auf den Inhalt (4 Byte) an einer bestimmten Stelle des Arbeitsspeichers (nur lesend deswegen const) zugreifen kann. Der Inhalt wird durch eine externe Quelle geändert (deswegen volatile). Mein Problem ist das ich sobald das Auslesen in der Funktion erfolgt, immer wieder folgende Fehlermeldung auftaucht:

Unbehandelte Ausnahme bei 0x00431f05 in Rene.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x00001234.

Kann mir jemand sagen was jetzt das Problem lösen könnte? Vielen Dank im voraus.
 
Zuletzt bearbeitet:
Ich würde mal sagen das liegt an der Adresse 0x1234.
Ich habs bei mir mit 0x17FF20 versucht und da bringt er keinen Fehler.

Gruß
BlackMark
 
Danke Blackmark, aber ich habe jetzt mal die Adresse von dir genommen. Ich bekomme weiterhin die gleiche Fehlermeldung. Muss ich eine bestimmte Option für den Compiler setzen? Ich verwende VS 2005 C++ Express und bin auf einem WinXP SP2 Rechner (32Bit)
 
Erstell mal eine ganz normale int oder unsigned int Variable und lies dir die Adresse davon aus, dann siehst du wo in etwa im Arbeitsspeicher die Variablen stehen und verwendest dann einfach eine Adresse die in etwa in diesem Bereich liegt.

Bei mir auf Vista x64 ist das eben ca. 0x0017FF20

Edit:
Damit man das dann auch für jeden PC egal ob XP | Vista x86 | x64 machen kann würde ich einfach jedesmal eine normale int Variable erstellen und dann das ganze auf deren Adresse legen, so solltest du immer eine korrekte Adresse haben.

Gruß
BlackMark
 
Zuletzt bearbeitet:
Ist die "externe Quelle" ein anderes Programm?
In dem Fall würde sich das Prinzip eines "Shared Memory" gut eignen.
Jedes Betriebssystem bietet das an. Sehr viele Bibliotheken verpacken das in einfach zugreifbare Klassen (Qt: QSharedMemory).

Die Frage bleibt nämlich immer: Wo schreibt Programm 1 was rein, und woher zur Hölle soll Programm 2 das wissen?!?
 
Also es geht darum, das ich mir erhoffe auf eine 32 Bit Integer Hardware Uhr an der o.a. Adresse zu zugreifen. Ich denke es wird mir nicht viel nutzen, wenn ich auf einen integer im Programm referenziere. Wie gesagt der Speicherbereich liegt außerhalb vom Programm, wird durch eine externe Quelle gesetzt und soll von meinem Programm ausgelesen werden. Danke aber trotzdem. Vielleicht haben die anderen noch eine Lösung.

Nachtrag: Es geht mir um die Technik "Memory mapped I/O". Das mit der Uhr ist nur ein Beispiel, an dem ich aber seit 2 Tagen hängen bleibe.
 
Zuletzt bearbeitet:
Windows verbietet direkte Zugriffe auf solche Speicherbereiche.
Wäre ja auch echt übel und der Stabilität wenig zuträglich, wenn jedes daher gelaufene Programm auf Hardwareregister zugreifen könnte, vor allem schreibend :freak:!

Welche "Hardwareuhr" soll das sein?
Und warum gerade die Adrese 0x1234?

Um auf solche Sache zugreifen zu können brachst du irgendwelche üble Magie aus dem ganzen MS Library Kram.
Irgendwelche bösen Sachen die man vermutlich auch zur Treiberentwicklung einsetzt.

(Ich lobe mir meine NEC V850 µC mit OSEK als Betriebssystem. Da sind alle bösen Sachen direkt möglich. Wildes Gefummel im Speicher herrlich :D)
 
Zuletzt bearbeitet:
Also so üble Magie aus der MS Library braucht man auch wieder nicht.
Das Auslesen und Schreiben in den Memory bereich von anderen Programmen ist nicht wirklich so schwer.

Das Problem ist eher woher weiß man die Adresse.

Eine Möglichkeit wäre eine konstante Adresse, somit hast du immer die gleiche Adresse und musst sie nicht erst suchen.

Gruß
BlackMark
 
Also kurz und knapp: geht nicht.

Das Zauberwort heißt Protected Mode. Windows und üblicherweise auch jedes andere OS (ausgenommen OSse aus der Zeit von MS-DOS) läuft im Protected Mode.

Damit läuft jeder User-Prozess in einem virtuellen Adressraum.

D.h. jeder Prozess hat (zumindest unter Windows (x86)) einen virtuellen Adressraum von 4GB. Dabei hält Windows Übersetzungstabellen von virtuellen Adressen auf physikalische. Fordert dein Programm Speicher von Windows an, so bekommt es eine virtuelle Speicheradresse übergeben und Windows reserviert dafür physikalischen Speicher und merkt sich die Übersetzung von virtueller auf physikalische Adresse.

Greift dein Programm nun auf eine virtuelle Adresse zu, die Windows nicht in eine physikalische übersetzen kann, so bekommst du die Access Violation. Das heißt auch in Folge, dass du die physikalische Adresse niemals aus einem Userprozess sehen kannst.


Für den Zugriff auf physikalischen Speicher brauchst du Kernel Ring 0 Privilegien - den haben meines Wissens höchstens Device Driver.


Nachtrag:
Falls du Memory Mapped I/O (unter Windows Memory Mapped Files genannt bzw. eine Spezialform von "echten" Memory Mapped Files) möchtest, geht das sehr wohl. Damit wird ein "Shared" Speicherbereich virtuell in deinen Adressraum gemappt. Wie auf diesen geteilten Speicher zugegriffen wird, müssen die beiden Programme über eine gemeinsame Schnittstelle definieren (z.B. an Startadresse (des geteilten Bereiches) + x Bytes steht Information y, die z Bytes groß ist und eine konkret vereinbarte Bedeutung hat). Zusätzlich werden vermutlich Synchonisierungsmechanismen wie eine globale Semaphore von Nöten sein. Zugriff auf physikalische Speicheradressen ist damit aber auch nicht möglich.
 
Zuletzt bearbeitet:
Ich hab zwei kleine Test Programme geschrieben, wobei eines das Hauptprogramm ist und das andere greift auf einen Wert im Hauptprogramm zu.
Leider hab ich es nicht geschafft, dass das zugreifende Programm die Adresse selbst herausfindet.
Deswegen muss man die Adresse selber eingeben, aber villeicht weiß ja jemand wie man das Problem lösen könnte.

Die Programme sind im Anhang

Edit:
Hab noch nen Fehler behoben!

Edit2:
Ich hab das Programm grad auf einem anderen PC mit Windows XP laufen lassen und mir ist aufgefallen, dass die Adresse die gleiche war.
Also falls die Adresse immer 4331360 ist, wäre das Problem gelöst.
Jedenfalls ist auf meinen beiden PC's Vista und XP die Adresse immer gleich!

Gruß
BlackMark
 

Anhänge

Zuletzt bearbeitet:
Vielen Dank für die Infos von euch. Am Ende habe ich mich doch entschieden einen anderen Weg einzuschlagen und das Thema erstmal beiseite zu legen. Ich stimme schon damit überein, das es in einem modernen OS nicht möglich sein sollte willkürlich auf beliebige Bereiche im Speicher zugreifen zu können. Jedoch muss es einen Weg für das geben, sonst liese sich bestimmte Hardware nicht direkt ansprechen. Wie dem auch sei, das Beispiel habe ich aus "Goldene Regeln der Spieleprogrammierung" Seite 11. Das Buch bearbeite ich zur Zeit sehr intensiv. Werde am Ende PerformanceCounter einsetzen und mich weiter mit dem nächsten Kapitel "2. Berechnungskomplexität" befassen.

@BlackMark: Extra Dank nochmal für die Testprogramme. Habe sie mir angeschaut, schön einfach und klar strukturiert. Für mich sind sie gut zu lesen. Leider haben sie mir nicht weiter geholfen, aber das Wissen, was drin steckt, werde ich sicher noch mal brauchen und deswegen in meine Sammlung aufnehmen. :-) Schöne Grüße nach Mühlau ...
 
Wieso helfen sie dir nicht weiter?
Das wäre genau das was du eigentlich wolltest, von einem Programm aus auf eine Variable in einem anderen Programm zugreifen.

Falls die Adresse wirklich auf jedem PC 4331360 ist könnte man diese in das Programm einbauen und somit hättest du eine Lösung die Windows zulässt und auch auf jedem PC funktioniert, und zwar ohne dass der Benutzer die Adresse jedes mal manuell eingeben muss ;)

Naja, wie auch immer, ich wünsche dir auch schöne Grüße und noch viel Spaß beim bearbeiten deines Buches!

Gruß
BlackMark
 
@BlackMark: Es ist wahr und deswegen werde ich die Lösung auch nicht in den Bithimmel schießen, sondern auf meinen Alltar für nützliche Hacks und Tweaks platzieren. Was mich davon abhält, diese Variante einzusetzen, ist die Tatsache, das hier mehrere API Aufrufe nötig sind, deren Performance ich jetzt auf die schnelle nicht abschätzen kann. Da aber der Bereich in dem es eingesetzt werden soll, sehr kritisch ist, sprich sehr oft durchlaufen wird und ich möglichst mit dem "Hintern auf dem blanken Silizium" rutschen möchte, werde ich vorerst eine andere Technik, wie oben geschrieben, fürs erste ausprobieren. Sollte das nicht fruchten, dann komme ich noch mal auf deine Lösung zurück. Im übrigen werde ich auch deine Lösung verarbeiten, aber an einer weniger kritschen Stelle - das ist jetzt nicht böse gemeint und sollte auch nicht falsch verstanden werden. Die Lösung ist gut und ich werde sie einsetzen. Zwar nicht dafür wie ursprünglich von mir gedacht, aber dennoch... Vielen Dank.
 
@Rossibaer:
Ok, ich bin natürlich nicht davon ausgegangen, dass dir die Performance so wichtig ist, jedoch wird es zimlich schwer das ganze ohne WinAPI zu realisieren, da Windows ja eben keinen Zugriff auf den Speicher von andern Programmen zulässt.

Aber dennoch wünsche ich dir gutes gelingen bei deinem Vorhaben!

Gruß
BlackMark
 
@BlackMark: Wie gesagt, es ist gut, das in der Hinterhand zu haben... Also danke nochmal für deine Lösung.

Allgemein möchte ich auf die Windows API weitestgehend verzichten und rein in den Möglichkeiten von C++ bleiben. So nativ wie möglich. Es kommt auch DirectX zum Einsatz, das muss dann aber auch schon alles sein, was ich noch zusätzlich an Bord nehmen möchte. Später ist dann gedacht das ganze auf OpenGL um zu schiften. Wenn mein Vorhaben scheitert, dann auch nicht so schlimm, weil die Erfahrungen umso wertvoller sind.

Also insgesamt Danke an die Community für eure Antworten.
 
BlackMark schrieb:
Also falls die Adresse immer 4331360 ist
Dank ASLR wird dies ab z.B. Windows Vista aufwärts nicht mehr funktionieren, wenn die Programme und Libraries dies unterstützen.

Finden lassen sich Adressen über das Suchen nach bestimmten Patterns. Z.B. indem der Wert der Variable vorher bekannt ist, der Speicher nach möglichen Adressen gescannt wird, dann der Wert der Variable auf einen anderen bekannten Wert geändert wird (repeat), bis man die Adresse herausgefunden hat. Falls andere Programme keine Abwehrmechanismen gegen solche Techniken implementieren - beispielsweise dumm doof den Wert+1 speichern (oder eleganter: Prüfsummen, Kopien, etc). Könnten beispielsweise Spiele, speziell MMO-Games machen, um Cheat-Tools abzuwehren.
Beim Schreiben kann man übrigens noch eklatanter auf die Nase fallen, durch z.B. ein gesetztes NX-Bit beim Zugriff auf's Code-Segment. Synchronisierung ist im übrigen völlig hinfällig und nicht deterministische,kaum zu findende und quasi unmöglich zu debuggende Abstürze sind vorprogrammiert.

@Rossibaer:
Um an Hardware-Adressen zu kommen, musst du schon einen eigenen Gerätetreiber schreiben.

Falls du "nur" einen High-Precision-Timer willst, brauchst du eigentlich nur QueryPerformanceCounter und QueryPerformanceFrequency. Wenn ich mich nicht täusche, sollte sich der HPT, sofern hardwareseitig unterstützt, auch über Assembler abfragen lassen - darüber bin ich mir aber absolut nicht sicher.
 
Zuletzt bearbeitet:
@TheNacer: Das ist genau das, was ich auch einsetzen wollte, wenn ich das oben genannte Beispiel wegen der Zugriffsverletzung nicht verwenden kann. Sozusagen hast du meinen Plan B entdeckt. ;) Komisch nur das in dem Buch halt diese 1 Zeile stand. Hab sie abgetippt und peng schon stand ich vor dem Problem das der Integer Wert nicht in eine Zeigeradresse konvertiert werden konnte. Also mal fix nen Cast gemacht nach (int *). Dann wars in Ordnung. Compiler beschwerte sich nicht, Linker sowieso nicht. Also dacht ich mir: hey, bevor ich es in meinem Programm verwende, dann lieber erst testen. Die Überraschung kam als ich dann versuchte den Wert an dieser Adresse in eine Integer Variable zu schreiben. Immer kam diese Meldung und das Programm stürzte ab. Es wäre zu schön gewesen, einfach nur Wert auslesen und fertig, keine API, keine speziellen includes. Hätte das funktioniert, dann hätte ich sicher auch andere Adressen ausprobiert um zu sehen was noch so geht. :D Nun muss ich doch auf die Api zurück und Plan B einsetzen...

Danke trotzdem für die Infos und die rege Beteiligung.

Grüße Rossibaer

PS: Lasst uns das Thema begraben oder in den Bithimmel schießen...
 
Zuletzt bearbeitet:
die frage... versuchst du auf dem kernspeicher zuzugreifen? du hast ehe keine berechtigung dafür sogar als admin (zumindest in windows)
 
@Roker: Eins vorweg, ich habe mich damit abgefunden das Thema erst einmal bei Seite zu legen und weiter an meinem eigentlichen Plan bzw. Aufgaben zu arbeiten. Es wäre halt nur ein kleines Sahnestück um eine nette Technik zu erlernen mit der ich vielleicht das ein oder andere Problem "performant" lösen könnte. Aber nun zu deiner Frage: Wo jetzt genau diese Speicheradresse hinweist, kann ich dir leider nicht genau sagen, weil diese Adresse, wie oben bereits erwähnt aus einem Beispiel des Buches "Goldene Regeln der Spieleprogrammierung" stammt. Spontan fallen mir jetzt folgende Varianten ein:
1. Absolute Adresse: an der Position 0x1234 (Hex), das könnte durchaus Kernelspeicher sein
2. Relative Adresse: Offset des Prozesses + 0x1234 (Hex), das könnte geschützter Speicher des Prozesses sein
Je nachdem wie jetzt das interne "Mapping" des Compilers diese Adresse interpretiert, lande ich sicher auf einen Bereich, der in irgend einer Weise geschützt ist. Das wirft aber die Frage auf, wozu man dann den Modifizierer "volatile" benötigt, wenn es aus praktischer Sicht nicht möglich ist (Zugriffsverletzung), außer man geht den Umweg über einen Treiber mit Ring 0 Privilegien? Das einzige wofür ich den volatile Modifizierer dann noch gebrauchen kann, wäre, das der Compiler bei meinen Zugriffen auf die Variable merkt, stets den tatsächlichen Wert zu lesen und nichts "weg zu optimieren", z.B. einmal lesen und den Inhalt stets in der Schleife zu verwenden, statt innerhalb der Schleife den Inhalt neu auszulesen. Dann müsste ich aber den Speicherbereich einer Variable innerhalb meines eigenen Prozesses für andere Programme publizieren, sodaß diese darauf zugreifen (lesend, schreibend) könnten. Diese Programme ständen dann aber vor genau dem selben Problem. Ich würde lediglich nur die Infrastruktur schaffen, sodaß mein Programm auch externe Veränderungen mit bekommen würde.

Was meinen die Experten zu dieser Sichtweise?
 
also wegen volatile ist hier alles gut beschrieben! volatile

damit stellst du sicher dass auch andere Prozesse auf dem speicher zugreifen können. aber ich würde nie eine variable deklarieren die wichte werte beinhaltet. es ist nur dann notwendig wenn du mehrere programmen laufen lässt die auf dem selben speicherwert zugreifen. natürlich wäre dass nur sinnvoll wenn diese varibale nur gelesen wird, sonst ist diese variable inkonsisten, oder du musst die prozesse syncronisieren. natürlich ist es auch unter den threads möglich. nur musst du halt die sync beachten wenn die was drauf schreiben willst.

einerseits ist das spiel mit den speicheradressen gut, andererseits bitten diese viele angriefmöglichkeiten auf das programm
 
Zurück
Oben