Windows 8.1 DirectDraw und Kompatibilität mit älteren Spielen

4054
Caleb C

Ich versuche, ein altes Spiel (Nascar Heat 2002) auf meinem Windows 8.1-Laptop auszuführen. Mein Problem ist, dass das Spiel vor dem Start abstürzt und in den Protokollen gemeldet wird, dass kein Video-RAM verfügbar ist. Dies ist die Protokolldatei:

41.37.114: data directory: C:\Program Files (x86)\Hasbro Interactive\NASCAR Heat\Data\ 41.37.115: Config Dir: C:\Program Files (x86)\Hasbro Interactive\NASCAR Heat\ 41.37.274: ddraw: created directdraw with aticfx32.dll (AMD Radeon HD 8650G + HD 8600/8700M Dual Graphics) 41.37.274: ddraw: version 0.0.0.0 41.40.904: vid: 0 meg card (reported:0.523438) 41.40.904: vid: using AGP textures (1397), total: 0 41.40.905: unsupported: 0 megs of vram" 

Soweit ich das beurteilen kann, ist die Version von DirectDraw, die Windows 8.1 enthält, nicht mit älteren Spielen wie diesem kompatibel. Ich habe versucht, WineD3Ds Libs zu verwenden, unter anderem mit dem Ziehen von Wrappern / Hacks, aber ohne Erfolg. Meine Frage ist also: Gibt es eine Möglichkeit, eine emulierte Menge an vram (meine Karte hat einen Video-RAM) entweder in Windows oder in einem Draw-Wrapper zu erzwingen, um sicherzustellen, dass dieses Spiel dies erkennt? Ich habe auf die neuesten Katalysatortreiber aktualisiert und habe die Microsoft DirectX 9.0c-Endbenutzerlaufzeit

2
Keine Frage............? Xavierjazz vor 9 Jahren 0
Windows 8.1 ist vollständig kompatibel mit älteren DirectX-Spielen, sofern die verwendete DirectX-Version installiert ist. Ramhound vor 9 Jahren 0
Sehen Sie, das ist die Sache, ich habe die Endbenutzer-Laufzeit installiert, die die Kompatibilität korrigieren soll, aber das hat nicht funktioniert Caleb C vor 9 Jahren 0

1 Antwort auf die Frage

6
beatcracker

Ich habe einen schleichenden Verdacht ...

Ich kann eine Videokarten-Erkennungsroutine von hier aus riechen. Das hat nichts mit Windows und \ oder DirectDraw zu tun (teilweise auch, aber nicht so wie Sie denken). Es ist nur ein altes Spiel, das Annahmen macht, die nicht länger gültig sind. Es ist nicht ungewöhnlich. Zum Beispiel stürzt Oni-Spiel auf modernen Videokarten ab :

Dieses Problem wurde auf den Überlauf eines bestimmten Textpuffers zurückgeführt, der die OpenGL-Erweiterungen in der startup.txt Datei auflistet . Als Oni geschrieben wurde, war der Speicherauszug der OpenGL-Erweiterungsliste viel kürzer und die Entwickler erlaubten keinen größeren Speicherauszug. Moderne Grafikkarten verursachen fast immer diesen Überlauf.

Wir müssen tiefer gehen

Ich besitze zwar nicht Nascar Heat 2002, aber ich habe eine NASCAR Heat-Demo heruntergeladen, und es ist genau das gleiche Problem. Also habe ich meinen Debugger und den Disassembler entfernt und einen Abend damit verbracht, herauszufinden, was mit dem Spiel nicht stimmt.

Das Spiel besteht eigentlich aus zwei ausführbaren Dateien, die über Semaphore miteinander kommunizieren : die ausführbare Hauptdatei ( NASCAR Heat Demo.exein meinem Fall) und die eigentliche Spiel-Engine ( .\run\race.bin). Die Videokarten-Erkennungsroutine befindet sich im race.bin. Beim Start des Spiels wird die ausführbare Hauptdatei race.binin den Windows-TEMP-Ordner kopiert heat.binund von dort ausgeführt. Wenn Sie versuchen, umbenennen race.binzu race.exeund führen Sie es, sucht es nach Semaphore, die durch das Hauptprogramm erstellt werden soll, und wenn es nicht zeigt diese Meldung gefunden:

Hinterlistiger Benutzer!  Wo ist mein Kanarienvogel?

Nach einer Demontage und einem kurzen Blick auf die String-Referenzen habe ich einen Funktionsaufruf gefunden, der eine vid: 0 meg card (reported:0.523438)Nachricht ausgibt. Es ist eigentlich ein Teil des Verfahrens zur Erkennung der Speichergröße einer Videokarte, das im Pseudocode so aussieht (zu stark vereinfacht):

RawVidMemSize = GetVidMemSizeFromDirectDraw()  // Add 614400 bytes (600Kb - 640x480 mode?) to vidmem size (what for?!) RawVidMemSize = RawVidMemSize + 614400  if (RawVidMemSize < 2000000) { MemSize = 0 } else { if (RawVidMemSize < 4000000) { MemSize = 2 }  if (RawVidMemSize < 8000000) { MemSize = 4 }  if (RawVidMemSize < 12000000) { MemSize = 8 }  if (RawVidMemSize < 16000000) { MemSize = 12 }  if (RawVidMemSize < 32000000) { MemSize = 16 }  if (RawVidMemSize < 64000000) { MemSize = 32 }  if (RawVidMemSize > 64000000) { MemSize = 64 } } 

Für Interessierte ist hier der tatsächliche Kontrollfluss der Funktion von der IDA mit meinen Kommentaren. Vollbild auf Klick.

Erkennung der Speichergröße der Videokarte

Nun ist es an der Zeit, sich genau anzusehen, was in diesem Verfahren passiert. Ich habe einen klassischen Break & Enter-Trick benutzt (den ersten Befehl am race.binEinstiegspunkt mit gepatcht int3), gestartet NASCAR Heat Demo.exeund darauf gewartet, dass der Debugger auftaucht. Und dann wurden die Dinge klar.

Die von GetVidMemSizeFromDirectDraw()is 0xFFFF0000( 4294901760 bytes = 4095MB) zurückgegebene Videospeichergröße hat nichts mit der Realität zu tun (sollte auf meinem PC 1 GB betragen). Es stellt sich heraus, dass DirectDraw für die moderne Videocard- / PC-Architektur nicht gut geeignet ist

Mit dem Wachstum von physischen Speichern, sowohl RAM als auch VRAM, hat diese API auch Probleme beim Kopieren, da sie 32-Bit-DWORD-Zählungen der Größe in Byte zurückgibt.

und neigt dazu zu berichten, wie es sich anfühlt :

Sie haben ein System mit mindestens 1 GB Videospeicher und 4 GB oder mehr Systemspeicher (RAM).

Sie führen das Direct-X-Diagnosetool aus und meldet, dass auf der Registerkarte der Registerkarte "Ungefährer Gesamtspeicher" unerwartet wenig vorhanden ist.

Möglicherweise werden auch Probleme mit einigen Spielen oder Anwendungen angezeigt, bei denen Sie nicht die höchsten Detaileinstellungen auswählen können.

Die API, die DXDiag verwendet, um den Systemspeicher anzunähern, wurde nicht für Systeme in dieser Konfiguration entwickelt

Bei einem System mit 1 GB Videospeicher werden die folgenden Werte mit dem zugehörigen Systemspeicher zurückgegeben:

╔═══════════════╦═══════════════════════════════════╗ ║ System Memory ║ Reported Approximate Total Memory ║ ╠═══════════════╬═══════════════════════════════════╣ ║ 4GB ║ 3496MB ║ ║ 6GB ║ 454MB ║ ║ 8GB ║ 1259MB ║ ╚═══════════════╩═══════════════════════════════════╝ 

In meinem Fall wird also nur der Wert gemeldet, der fast in die 32-Bit-Ganzzahl passt. Und da laufen die Dinge schlecht. Erinnere dich an diese Zeile?

RawVidMemSize = RawVidMemSize + 614400 

Es wird so:

RawVidMemSize = 4294901760 + 614400 (= 4295516160) 

Und 4295516160ist 548865mehr als 32-Bit-Wert ( 0xFFFFFFFF = 4294967295). Also der Integer-Überlauf und das Endergebnis ist 548864. Das Spiel glaubt nun, dass meine Vidmem-Größe 536 KB groß ist und sich weigert zu laufen.

Sie können dies in diesem Online-Emulator für x86-Assemblys selbst überprüfen . Geben Sie den Code ein, klicken Sie in der rechten linken Ecke Windowsund aktivieren Sie das RegistersKontrollkästchen. Klicken Sie auf die StepSchaltfläche und beobachten, wie 0xFFFF0000in EAX - Register wird 0x00086000mit CarryFlagge. Wenn Sie auf den Registerwert klicken, wird zwischen der Hex- und Dezimaldarstellung einer Zahl gewechselt.

mov eax, 0xFFFF0000 add eax, 0x96000 

Wie kann ich das beheben?

DirectDraw wird wahrscheinlich niemals einen Wert zurückgeben, der größer als 32-Bit-Ganzzahl ist (der mit 1 begrenzt werden kann, unabhängig von der tatsächlichen Speichergröße). Die einfachste Möglichkeit, dieses Problem zu beheben, besteht darin, die RawVidMemSize = RawVidMemSize + 614400Operation aus dem Code zu entfernen. t löst den Überlauf aus, in der ausführbaren Datei sieht es so aus:

  • Montage-Mnemonic: add eax, 96000h
  • Aktuelle Opcodes (Hex): 0500600900

Um es zu entfernen, müssen wir es durch NOP- Anweisungen (hex :) ersetzen 90. Ich kenne den Datei-Offset bereits, aber in Ihrer ausführbaren Datei kann es anders sein. Glücklicherweise ist Hex-String 0500600900in meinem race.binund wahrscheinlich in Ihrem einzigartig . Holen Sie sich den Hex-Editor (ich empfehle HxD : es ist kostenlos, portabel und einfach zu verwenden) und öffnen Sie Ihre binDatei.

Führen Sie eine Hex-String-Suche aus:

Hex-String-Suche

Sobald ein Hex-String gefunden wurde

Hex-String gefunden

Ersetzen Sie es mit 90

Patch!

Speicher die Datei. HxD erstellt automatisch eine Sicherungskopie der Datei, die Sie wiederherstellen können, wenn etwas schief geht.

In meinem Fall war das genug und ich konnte das Spiel starten. So heat.logsieht es nach dem Patch aus:

21.33.564: Entwurf: Direktentnahme mit aticfx32.dll (AMD Radeon HD 5800 Series) erstellt.
21.33.564: Entwurf: Version
0.0.0.0 21.34.296: VID : 64- Meg-Karte (gemeldet: 4095.937500 )
21.34.296: VID: using AGP-Texturen (3231), gesamt: 64
21.34.305: vid: Dreifachpuffer eingeschaltet

Wenn Ihre Datei zufällig mehrere Vorkommen enthält 0500600900, ersetzen Sie die erste und versuchen Sie, das Spiel zu starten. Wenn dies nicht funktioniert, stellen Sie die Datei aus der Sicherung wieder her und versuchen Sie es als Nächstes. Ersetzen Sie nicht alles auf einmal, dies ist keine gute Idee.

Es wurde auch bestätigt, dass derselbe Fehler in Viper Racing existiert . Viper Racing verwendet eine etwas andere (ältere?) Version der Game Engine als Nascar, der Bug ist jedoch derselbe: Auch er versucht, 614400Bytes zur Videospeichergröße hinzuzufügen . Die zu durchsuchenden Werte unterscheiden sich, da der Compiler in diesem Fall entschieden hat, keine Register zu verwenden und nur auf die Variable vom Stapel zuzugreifen, dh:

  • Montage-Mnemonic: add [esp+18h+var_14], 96000h
  • Aktuelle Opcodes (Hex): 8144240400600900

Viel Spaß beim Fahren!

  1. Dies ist eine dieser Annahmen, über die ich gesprochen habe.