Access violation

03/27/2014 15:07 Doktor.#1
Hey, bin momentan daran ein Programm zu coden, darin muss ich in einem Spiel ein Mob anvisieren, sofern alles gut, er visiert die Mobs korrekt an etc.
Mein Problem liegt daran das wenn ich ein Mob anvisieren möchte und kurz davor jemand anderes den Mob killt das mein Programm und das Game abstürzen, habs mir schon im Debugger angekuckt, komme damit aber auch nicht viel weiter, hab nur herausfinden können das es mit dem anvisieren zu tun hat.
Hab auch schon versucht kurz vor dem anvisieren zu überprüfen ob die Mob Adresse noch gültig ist, das hat mir aber auch nur gering geholfen, ab und zu stürzt es immer noch deshalb ab.

Bin mir jetzt grad völlig unklar wie ich dies beheben könnte.

Falls wer ne Idee hat, wäre ich froh wenn derjenige sich bei mir melden könnte. :)


Code:
for (int i = 0; i < m->getObjectsNumber(2); i++)
{
	if(m->object(2,i).Address == address){
		_asm
		{
		     //....
		}
		break;
	}
}
Mfg.
Doktor.
03/27/2014 16:17 Mostey#2
Der Code enthält nichts verwertbares, was ist m? Warum lässt du den Assembler Part weg? Implementierung von m.object? GetObjectsNumber?

Es ist naheliegend das die Objektinstanz auf die du dich beziehst nach dem Tot der Instanz nicht mehr gültig ist und gelöscht wird. Da solltest du überprüfen, ob die Instanz überhaupt noch gültig ist, bevor du etwas damit machst.

Du sagtest, das du bereits überprüft hast ob dies der Fall ist. Wie? Warum stürzt es ab? Gleiche Exception? Hast du das ganze mal dynamisch nachgespielt? (über CE zum Beispiel)
03/27/2014 16:53 Doktor.#3
m ist einfach ein Zeiger auf eine Klasse, wobei getObjectsNumber die Anzahl der Mobs(2) auf der Map zurückgibt.
m->object(2,i) gibt dann ein Struct zurückt wo die einzelnen Daten dieses Mobs(i) drin stehen.

Der Assembler Code ist:

MOV EDX,address
MOV EAX,DWORD PTR DS:[sPointer]
MOV EAX,DWORD PTR DS:[EAX]
CALL sCall

Würde der Fehler innerhalb der Instanz im Programm liegen, müsste Olly dann nicht im Modul der DLL stoppen?

Das Spielt stürzt immer an 3 verschiedenen Stellen ab,wobei recht nah bei einander liegen.
Hab schon versucht dies nach zustellen, hab mir eine DLL gemacht, die in 100ms takt einen neuen Mob anvisiert, stürzt immer unterschiedlich an einem dieser 3 Stellen ab, wie im original Programm.
03/27/2014 18:37 Mostey#4
Quote:
Originally Posted by Doktor. View Post
m ist einfach ein Zeiger auf eine Klasse
Das sieht man, auf welche Klasse bezieht sich m? Die Mobklasse eines spezifischen Mobs oder eine Art Pool für alle, die du dann mit m::object selektierst? Bitte etwas präziser.

Quote:
Originally Posted by Doktor. View Post
getObjectsNumber die Anzahl der Mobs(2)
Ergibt mMn keinen Sinn, wieso sollte eine Funktion die Anzahl der Mobs anhand der bereits gegebenen Anzahl zurückgeben? Meinst du vielleicht die ID des Mobs? :confused:

Quote:
Originally Posted by Doktor. View Post
MOV EDX,address
MOV EAX,DWORD PTR DS:[sPointer]
MOV EAX,DWORD PTR DS:[EAX]
CALL sCall
Du dereferenzierst also und rufst danach eine Funktion auf, wo überprüfst du auf Inhalt bzw. Existenz bevor du dereferenzierst? Ich habe vor einiger Zeit dafür mal die Funktion IsBadReadPtr genutzt und hatte keine Probleme. Hat allerdings einen relativ schlechten Ruf und einen wirklichen Ersatz scheint es auch nicht zu geben. ( [Only registered and activated users can see links. Click Here To Register...] )

Quote:
Originally Posted by Doktor. View Post
Würde der Fehler innerhalb der Instanz im Programm liegen, müsste Olly dann nicht im Modul der DLL stoppen?
Verstehe ich jetzt nicht, warum sollte Olly stoppen? Es geht um fehlerhaften Speicherzugriff, da kann Olly nix für. ;O


Quote:
Originally Posted by Doktor. View Post
Das Spielt stürzt immer an 3 verschiedenen Stellen ab,wobei recht nah bei einander liegen.
Hab schon versucht dies nach zustellen, hab mir eine DLL gemacht, die in 100ms takt einen neuen Mob anvisiert, stürzt immer unterschiedlich an einem dieser 3 Stellen ab, wie im original Programm.
Wie iterierst du denn so durch die Objekte? Gibt's da sowas wie ne Entitylist wo du dir alle rausholst? Könnte evtl. sein das durch fehlende Objekte (durch den Kill werden sie wahrscheinlich gelöscht) der Speicher nicht gelesen werden kann weil diese Speicherstelle nicht mehr existiert. Genaueres dazu kann dir aber sicher jemand wie snow911 oder MrSmith sagen, da kenne ich mich nicht sonderlich gut aus.
03/27/2014 18:47 MrSm!th#5
Quote:
Würde der Fehler innerhalb der Instanz im Programm liegen, müsste Olly dann nicht im Modul der DLL stoppen?
Hast du Olly denn als JIT Debugger eingestellt?

Quote:
Verstehe ich jetzt nicht, warum sollte Olly stoppen? Es geht um fehlerhaften Speicherzugriff, da kann Olly nix für. ;O
Debugger können auf Exceptions breaken.
Muss man bei Olly aber, wenn ich mich recht erinnere, aktivieren.
03/27/2014 19:08 Doktor.#6
Hab es mir jetzt nochmal ganz genau angekuckt, ich erklär vorher nochmal wie genau ich die Mobs auslese.

Ich hab einen Pointer, wo zumal die Anzahl der Mobs drin steht, die ich dann auslese mit na Funktion, an dem Pointer befindet sich dann noch in alle Mobs auf der Map mit ihren Infos, die ich dann auslese, dann hab ich alle Adressen etc. von den einzelnen Mobs.
Soweit ich erkennen konnte und testen konnte, verschieben sich die Adressen wenn ein Mob gekillt wird, und das Mob was an letzter Stelle steht(wobei es egal ist an welcher Stelle es steht) und dann gekillt wird eine falsche Adresse hat, bzw. der Mob für die Adresse nicht mehr existiert und dann zum Absturz führt, wenn ich versuch mit der Adresse ein Mob an zu visieren.

Würde glatt sagen das ich es zu langsam kontrolliere ob die Adresse noch gültig ist.
Wobei ich wie oben schon steht vor dem aufrufen des _asm codes nochmal alle Mobs überprüfe ob die Adresse gültig ist, aber anscheint zu langsam(?!) ist.
03/27/2014 20:51 Mostey#7
Quote:
Originally Posted by Doktor. View Post
Würde glatt sagen das ich es zu langsam kontrolliere ob die Adresse noch gültig ist.
Das Problem sehe ich hier nicht in der Zeit sondern in deiner Umsetzung.

So wie ich das verstanden habe, sieht der Aufbau also wie folgt aus:

0x400000 Mob1
0x401000 Mob2
0x402000 Mob3

(ein Mob Objekt ist 0x1000 Bytes groß)

Wenn du jetzt irgendwo in deinem Programm alle Mobs einliest, hast du die oben vermerkten Instanzen in deinem Struct (oder Klasse, wie auch immer). Nun zielst du auf Mob2. Du rufst anschließend deine Funktion auf, in der die Instanzen abgefragt werden und alles läuft ohne Probleme. Jetzt komme ich und kille Mob1. Deiner Aussage nach zu urteilen verschieben sich die Instanzen jetzt und ordnen sich neu an.

Heißt also die Instanzen liegen nun so im Speicher:

0x400000 Mob2
0x401000 Mob3

Du merkst den Unterschied? Die Instanzen rücken alle um eins auf, du hast aber in deiner Klasse noch das vorherige Abbild. Wenn du jetzt mit deiner Funktion darüber iterierst, hast du an Adresse 0x402000 die Access Violation sofern sich dort nichts befindet weil du dein Struct nicht geupdated hast, ich habe ja schließlich einen Mob gekillt.

TL;DR: mit m->getObjectsNumber(2) holst du dir (wahrscheinlich, ich weiß nicht wie die Funktion aussieht) immer wieder das alte Speicherabbild und iterierst darüber, du musst das Struct idealerweise vorher aktualisieren.

Übrigens alles rein logisch gesehen, kann natürlich auch alles falsch sein was ich hier von mir gegeben habe. Allerdings scheint mir das am plausibelsten.
03/27/2014 21:22 MrSm!th#8
Quote:
Originally Posted by Mostey View Post
Das Problem sehe ich hier nicht in der Zeit sondern in deiner Umsetzung.

So wie ich das verstanden habe, sieht der Aufbau also wie folgt aus:

0x400000 Mob1
0x401000 Mob2
0x402000 Mob3

(ein Mob Objekt ist 0x1000 Bytes groß)

Wenn du jetzt irgendwo in deinem Programm alle Mobs einliest, hast du die oben vermerkten Instanzen in deinem Struct (oder Klasse, wie auch immer). Nun zielst du auf Mob2. Du rufst anschließend deine Funktion auf, in der die Instanzen abgefragt werden und alles läuft ohne Probleme. Jetzt komme ich und kille Mob1. Deiner Aussage nach zu urteilen verschieben sich die Instanzen jetzt und ordnen sich neu an.

Heißt also die Instanzen liegen nun so im Speicher:

0x400000 Mob2
0x401000 Mob3

[...]
du musst das Struct idealerweise vorher aktualisieren.
Es liegt definitiv an der Umsetzung. Ohne Synchronsierung kann dieses Konzept nur schiefgehen in einer multithreaded Umgebung.
Da werden Hooks notwendig sein, die eine eigene Struktur threadsicher füllen.
Direkt mit den Gamestrukturen zu arbeiten und zu hoffen, dass diese lange genug gültig bleiben, garantiert einem eigentlich schon unregelmäßige Abstürze. Vielleicht kann man sich auch in selbigen Strukturen nach bereits existierenden Locks umsehen und sich einfach ebenfalls diese zu nutze machen, wenn das Spiel bereits multithreaded gestaltet ist.
03/27/2014 22:30 Doktor.#9
Quote:
Originally Posted by Mostey View Post
Du merkst den Unterschied? Die Instanzen rücken alle um eins auf, du hast aber in deiner Klasse noch das vorherige Abbild.

TL;DR: mit m->getObjectsNumber(2) holst du dir (wahrscheinlich, ich weiß nicht wie die Funktion aussieht) immer wieder das alte Speicherabbild und iterierst darüber, du musst das Struct idealerweise vorher aktualisieren.
Das hab ich ja schon alles berücksichtigt, getObjectsNumber liest die Zahl direkt aus dem Speicher des Spiels und m->object(2,i) liest direkt die Adresse aus dem Speicher und vergleicht sie dann mit der selbst angegebenen Adresse, ob sie noch gültig ist.
Ich aktualisiere also vorher die Daten und überprüfe sie dann, dennoch kommt es ab und zu zur Acces violation.
Ich werd's mal mit Hooks probieren.
04/17/2014 01:34 TheTompa#10
use

Code:
DWORD ReadMemory(DWORD addr)
{
        if(!IsBadReadPtr(&addr,sizeof(DWORD))
        {
              return (*(DWORD*)(addr));
        }

      return 0;
}
04/17/2014 02:13 Nightblizard#11
Quote:
Originally Posted by TheTompa View Post
use

Code:
DWORD ReadMemory(DWORD addr)
{
        if(!IsBadReadPtr(&addr,sizeof(DWORD))
        {
              return (*(DWORD*)(addr));
        }

      return 0;
}
No.

Quote:
Important This function is obsolete and should not be used. Despite its name, it does not guarantee that the pointer is valid or that the memory pointed to is safe to use. For more information, see Remarks on this page.
[Only registered and activated users can see links. Click Here To Register...]
04/17/2014 03:15 ​Tension#12
You could use VirtualQuery/Ex and check the structure element called AllocationProtect:
Quote:
Originally Posted by msdn
AllocationProtect
The memory protection option when the region was initially allocated. This member can be one of the memory protection constants or 0 if the caller does not have access.
Tested it in MASM and it works quite well.
04/17/2014 17:52 MrSm!th#13
Quote:
Originally Posted by Nightblizard View Post
No.


[Only registered and activated users can see links. Click Here To Register...]
Yes.
That quote simply doesn't fit the situation.
It refers to the fact that a "valid" (i.e. no Access Violation Exception will be thrown) pointer does not guarantee that it points to what you expect. It does not prevent you from editing editable things you actually don't want to edit by mistake.
However, in such "exotic" cases as hacking other programs it is a good way to check whether you can even read from / write to that area. If the pointer is valid in terms of page protection, it surely is valid in general as well.
If it is not, the developer of your target probably made a mistake and you couldn't do much about it anyway.

Same goes for VirtualQuery.