Diablo 1 – Let’s CrackIt

Da ja bald Diablo III herauskommt, da dachte ich mir: „Ach, spielst du doch einmal wieder den ersten Teil von Diablo!“. Schnell die CD aus dem Regal geholt, dass Spiel installiert und dann musste ich mit bedauern feststellen: Diablo 1 braucht die CD ständig im Laufwerk. Ich hasse es, wenn Spiele irgendeinen Kopierschutz haben, die meine Freiheit einschränken. In diesem Fall eine einfache CD Protection. Also habe ich mich einmal herangesetzt und wollte schauen, wie denn dieser Kopierschutz genau funktioniert. Als erstes habe ich mir alle Dateien von Diablo 1 angeschaut und stellte fest, dass das installierte Spiel gerade mal 5 MB groß war. „Hmm… da scheint wohl irgendetwas zu fehlen“, dachte ich mir. Nun noch schaue welcher Inhalt auf der CD ist und tatsächlich, auf der CD befindet sich eine Datei, welche über 500 MB groß ist. Diese habe ich dann erst einmal in mein Diablo Verzeichnis kopiert, auf der Hoffnung der Kopierschutz sei umgangen, was natürlich nicht der Fall war. Immer wenn keine CD eingelegt war, kam eine Fehlermeldung,welche aussagte dass die „diabdat.mpq“ nicht geladen werden konnte.

Die „diabdat.mpq“ scheinen wohl alle Spielinhalte zu sein, deswegen liest er auch ständig von der CD, wenn man ohne Crack spielt. Also habe ich mir nun die Diablo.exe vorgenommen und die Fehlermeldung gesucht. Dafür habe ich erst einmal alle referenzierten Strings durchsucht und speziell nach „mpq“ gesucht. So habe ich dann die folgende Stelle ausfindig machen können:

 ;CPU Disasm
 ;Address   Hex dump          Command                                  Comments
 ;...
 0041ACF0  |> /6A 01         /PUSH 1                                  ; /Arg3 = 1
 0041ACF2  |. |68 E8030000   |PUSH 3E8                                ; |Arg2 = 3E8
 0041ACF7  |. |68 B4E74800   |PUSH OFFSET 0048E7B4                    ; |Arg1 = ASCII "DiabloCD"
 0041ACFC  |. |BA A4E74800   |MOV EDX,OFFSET 0048E7A4                 ; |ASCII "\diabdat.mpq"
 0041AD01  |. |8BCE          |MOV ECX,ESI                             ; |
 0041AD03  |. |E8 6A000000   |CALL 0041AD72                           ; \Diablo.0041AD72
 0041AD08  |. |85C0          |TEST EAX,EAX
 0041AD0A  |. |A3 944B6300   |MOV DWORD PTR DS:[634B94],EAX
 0041AD0F  |. |75 1B         |JNE SHORT 0041AD2C
 0041AD11  |. |8D45 FC       |LEA EAX,[LOCAL.1]
 0041AD14  |. |50            |PUSH EAX
 0041AD15  |. |E8 12EA0400   |CALL <JMP.&DiabloUI.UiCopyProtError>    ; Jump to DiabloUI.UiCopyProtError
 0041AD1A  |. |837D FC 02    |CMP DWORD PTR SS:[LOCAL.1],2
 0041AD1E  |.^\75 D0         |JNE SHORT 0041ACF0
 0041AD20  |. |B9 98E74800   |MOV ECX,OFFSET 0048E798                 ; ASCII "diabdat.mpq"
 0041AD25  |. |E8 726FFEFF   |CALL 00401C9C                           ; [Diablo.00401C9C
 0041AD2A  |.^\EB C4         \JMP SHORT 0041ACF0
 ;...
 

Die in den Kommentaren gekennzeichnete erste Funktion wird wohl versuchen die „diabdat.mpq“ von CD zu laden. Diese weißt im ersten Argument den String „DiabloCD“ auf. Diese Funktion sollte ich mir also einmal genauer anschauen. Ein Breakpoint auf die Funktion setzen und das Programm starten. Nach dem Klick auf den Play Button, passierte eine ganze Weile nichts, bis Schlussendlich Diablo startete und mir wieder die Fehlermeldung zeigte. „Wie kann das sein? Ich hab den Breakpoint doch an der richtigen Stelle gesetzt und er sollte genau dort anhalten!“. Also noch einmal das Programm zurücksetzen und manuell zu dem Punkt hinsteuern, wo Diablo gestartet wird. Ich bin jeden verdächtigen CALL Aufruf nachgegangen um so den Übeltäter zu finden. Ohne die CALLs zurückzuverfolgen wird man bei folgender Funktion merken, das hier Diablo gestartet wird.

 ;CPU Disasm
 ;Address   Hex dump          Command                                  Comments
 ;...
0046BD70  |> \50            PUSH EAX                                 ; /Arg4
0046BD71  |.  56            PUSH ESI                                 ; |Arg3
0046BD72  |.  6A 00         PUSH 0                                   ; |Arg2 = 0
0046BD74  |.  6A 00         PUSH 0                                   ; |/ModuleName = NULL
0046BD76  |.  FF15 BC914700 CALL DWORD PTR DS:[<&KERNEL32.GetModuleH ; |\KERNEL32.GetModuleHandleA
0046BD7C  |.  50            PUSH EAX                                 ; |Arg1
0046BD7D  |.  E8 C8CDF9FF   CALL 00408B4A                            ; \Diablo.00408B4A
 ;...
&#91;/x86&#93;

Nach dieser Funktion wird wieder Diablo gestartet und ich sollte mir diese einmal genauer anschauen. In dieser Funktion sieht es folgendermaßen aus.

&#91;x86&#93;
 ;CPU Disasm
 ;Address   Hex dump          Command                         Comments
 00408B4A  /$  55            PUSH EBP                         ; Diablo.00408B4A(guessed Arg1,Arg2,Arg3,Arg4)
 00408B4B  |.  8BEC          MOV EBP,ESP
 00408B4D  |.  81EC 0C010000 SUB ESP,10C
 00408B53  |.  53            PUSH EBX
 00408B54  |.  56            PUSH ESI
 00408B55  |.  8B75 08       MOV ESI,DWORD PTR SS:&#91;ARG.1&#93;
 00408B58  |.  8BCE          MOV ECX,ESI
 00408B5A  |.  E8 95020000   CALL 00408DF4                    ; Diablo wird gestartet
 00408B5F  |.  8935 EC565200 MOV DWORD PTR DS:&#91;5256EC&#93;,ESI
 00408B65  |.  E8 1B9D0400   CALL 00452885                    ; &#91;Diablo.00452885
 00408B6A  |.  85C0          TEST EAX,EAX
 ;...
&#91;/x86&#93;

In dem Kommentar hab ich wieder eine CALL-Funktion markiert, welche das Spiel startet. Diese sollte man also wieder zurückverfolgen und schauen was sie macht. Folgendes habe ich dann in dieser Funktion gefunden.

&#91;x86&#93;
 ;CPU Disasm
 ;Address   Hex dump          Command                                  Comments
 ;...
00408E2A  |.  FF15 70914700 CALL DWORD PTR DS:&#91;<&KERNEL32.GetModuleF ; \KERNEL32.GetModuleFileNameA
00408E30  |.  8D85 78FEFFFF LEA EAX,&#91;LOCAL.98&#93;
00408E36  |.  50            PUSH EAX                                 ; /<%s> = "D:\Spiele\Diablo\Diablo.exe" // hier ist gerade mein Pointer
00408E37  |.  8D85 64FDFFFF LEA EAX,[LOCAL.167]                      ; |
00408E3D  |.  68 48444800   PUSH OFFSET 00484448                     ; |Format = "Reload-%s"
00408E42  |.  50            PUSH EAX                                 ; |Buf => OFFSET LOCAL.167
00408E43  |.  FF15 E8934700 CALL DWORD PTR DS:[<&USER32.wsprintfA>]  ; \USER32.wsprintfA
00408E49  |.  33DB          XOR EBX,EBX
 ;...

Das hört sich ja gar nicht gut an: „Reload-D:\Spiele\Diablo\Diablo.exe“. Will er etwa das Spiel neustarten? Schauen wir doch mal weiter.

 ;CPU Disasm
 ;Address   Hex dump          Command                                          Comments
 ;...
00408F19  |.  50            PUSH EAX
00408F1A  |.  FF15 80914700 CALL DWORD PTR DS:[<&KERNEL32.CreateProcessA>]
00408F20  |.  6A FF         PUSH -1                                            ; /Timeout = WAIT_FOREVER
00408F22  |.  FF75 E4       PUSH DWORD PTR SS:[LOCAL.7]                        ; |hProcess => [LOCAL.7]
00408F25  |.  FF15 68934700 CALL DWORD PTR DS:[<&USER32.WaitForInputIdle>]     ; \USER32.WaitForInputIdle
00408F2B  |.  FF75 E8       PUSH DWORD PTR SS:[LOCAL.6]
 ;...

OK. Die folgende Stelle zeigt, dass ein neuer Prozess gestartet wird und dieser Prozess auf ewig auf den anderen wartet. Sprich Diablo wird noch einmal in einem neuen Prozess gestartet. Dadurch kann dieser nicht durch den Debugger zurückverfolgt werden und erst wenn das Spiel beendet wird, greift der Debugger wieder ein.
Da er Diablo einfach als neuen Prozess startet, dies in der nächsten Instanz aber so erkennt, dass das Spiel nicht noch eine neue Instanz startet, kann man auch einfach diese Funktion per NOP überschreiben und so unschädlich machen. So kann man dann im selben Prozess weiter debuggen.

 ;CPU Disasm
 ;Address   Hex dump          Command                       Comments
 ;...
 00408B58  |.  8BCE          MOV ECX,ESI
 00408B5A  |.  E8 95020000   CALL 00408DF4                  ; Diablo wird gestartet // diese Funktion per NOP überschreiben
 00408B5F  |.  8935 EC565200 MOV DWORD PTR DS:[5256EC],ESI
 00408B65  |.  E8 1B9D0400   CALL 00452885                  ; [Diablo.00452885
 00408B6A  |.  85C0          TEST EAX,EAX
 ;...

Nach dem ich die Funktion per NOP überschrieben habe, kommt noch weiterer Code der das Fenster aufbaut, das Blizzard-Logo-Intro initialisiert und endlich zu der Stelle kommt, wo die „diabdat.mpq“ geladen werden soll.

;CPU Disasm
;Address   Hex dump          Command                                    Comments
0041ACF0  |> /6A 01         /PUSH 1                                                        ; /Arg3 = 1
0041ACF2  |. |68 E8030000   |PUSH 3E8                                                      ; |Arg2 = 3E8
0041ACF7  |. |68 B4E74800   |PUSH OFFSET 0048E7B4                                          ; |Arg1 = ASCII "DiabloCD"
0041ACFC  |. |BA A4E74800   |MOV EDX,OFFSET 0048E7A4                                       ; |ASCII "\diabdat.mpq"
0041AD01  |. |8BCE          |MOV ECX,ESI                                                   ; |
0041AD03  |. |E8 6A000000   |CALL 0041AD72                                                 ; \Diablo.0041AD72 // unsere Ladefunktion
0041AD08  |. |85C0          |TEST EAX,EAX
0041AD0A  |. |A3 944B6300   |MOV DWORD PTR DS:[634B94],EAX
0041AD0F  |. |75 1B         |JNE SHORT 0041AD2C                                            ; //Die Überprüfung ob die CD vorhanden ist/war, wenn ja springe zu 0041AD2C
0041AD11  |. |8D45 FC       |LEA EAX,[LOCAL.1]
0041AD14  |. |50            |PUSH EAX
0041AD15  |. |E8 12EA0400   |CALL <JMP.&DiabloUI.UiCopyProtError>                          ; Jump to DiabloUI.UiCopyProtError
0041AD1A  |. |837D FC 02    |CMP DWORD PTR SS:[LOCAL.1],2
0041AD1E  |.^\75 D0         |JNE SHORT 0041ACF0
0041AD20  |. |B9 98E74800   |MOV ECX,OFFSET 0048E798                                       ; ASCII "diabdat.mpq"
0041AD25  |. |E8 726FFEFF   |CALL 00401C9C                                                 ; [Diablo.00401C9C
0041AD2A  |.^\EB C4         \JMP SHORT 0041ACF0                                            ; //Hier wird das Fehlermeldungsfenster erzeugt
0041AD2C  |>  6A 01         PUSH 1                                                         ; /Arg1 = 1                  //also CD drin, hier her springen
0041AD2E  |.  8D55 F8       LEA EDX,[LOCAL.2]                                              ; |
0041AD31  |.  B9 84E74800   MOV ECX,OFFSET 0048E784                                        ; |ASCII "ui_art\title.pcx"
0041AD36  |.  E8 CB7F0400   CALL 00462D06                                                  ; \Diablo.00462D06
0041AD3B  |.  85C0          TEST EAX,EAX
0041AD3D  |.  75 0A         JNE SHORT 0041AD49                                             ; wenn die diabdat.mpq korrekt geladen wurde überspringen, ansonsten Fehlermeldung
0041AD3F  |.  B9 60E74800   MOV ECX,OFFSET 0048E760                                        ; ASCII "Main program archive: diabdat.mpq"
0041AD44  |.  E8 536FFEFF   CALL 00401C9C                                                  ; [Diablo.00401C9C
0041AD49  |>  8B4D F8       MOV ECX,DWORD PTR SS:[LOCAL.2]
0041AD4C  |.  E8 2C7F0400   CALL 00462C7D                                                  ; [Diablo.00462C7D
0041AD51  |.  BA 50E74800   MOV EDX,OFFSET 0048E750                                        ; ASCII "\patch_rt.mpq"
0041AD56  |.  8BCF          MOV ECX,EDI
0041AD58  |.  6A 00         PUSH 0                                                         ; /Arg3 = 0
0041AD5A  |.  68 D0070000   PUSH 7D0                                                       ; |Arg2 = 7D0
0041AD5F  |.  68 40E74800   PUSH OFFSET 0048E740                                           ; |Arg1 = ASCII "DiabloInstall"
0041AD64  |.  E8 09000000   CALL 0041AD72                                                  ; \Diablo.0041AD72 //Oha selbe Ladefunktion wie bei Diabdat.mpq

Also bei 0041AD0F sollte man am besten einen JMP einfügen, damit man nicht mehr aufgefordert wird die CD einzulegen, jedoch ist unsere Ladefunktion so eingestellt das sie die „diabdat.mpq“ immer noch von CD laden will. Da sich die CD nicht mehr im Laufwerk befindet, wird die Funktion die Datei nie finden. Um das zu umgehen sollte ich wohl irgendetwas an der Funktion ändern. Die Lösung befindet sich weiter unten am Ende des Codes. Die „patch_rt.mpq“ befindet sich in dem lokalen Diablo Verzeichnis und diese wird immer korrekt geladen. Also schreiben wir die Ladefunktion so um, dass sie das Selbe macht, wie bei der „patch_rt.mpq“. Also passen wir alle Argumente so an, das die Funktion wie die, von der „patch_rt.mpq“ aussieht:

 ;CPU Disasm
 ;Address   Hex dump          Command                                  Comments
0041ACF0  |> /6A 00         PUSH 0                                   ; /Arg3 = 0
0041ACF2  |. |68 D0070000   PUSH 7D0                                 ; |Arg2 = 7D0
0041ACF7  |. |68 40E74800   PUSH OFFSET 0048E740                     ; |Arg1 = ASCII "DiabloInstall"
0041ACFC  |. |BA A4E74800   MOV EDX,OFFSET 0048E7A4                  ; |ASCII "\diabdat.mpq"
0041AD01  |. |8BCE          MOV ECX,ESI                              ; |
0041AD03  |. |E8 6A000000   CALL 0041AD72                            ; \Diablo.0041AD72
0041AD08  |. |85C0          TEST EAX,EAX
0041AD0A  |. |A3 944B6300   MOV DWORD PTR DS:[634B94],EAX
0041AD0F  |. |EB 1B         JMP SHORT 0041AD2C                       ; nun wird immer ein JMP ausgeführt. UiCopyProt(ect)Error wird umgangen :D
0041AD11  |. |8D45 FC       LEA EAX,[EBP-4]
0041AD14  |. |50            PUSH EAX
0041AD15  |. |E8 12EA0400   CALL <JMP.&DiabloUI.UiCopyProtError>     ; Jump to DiabloUI.UiCopyProtError
0041AD1A  |. |837D FC 02    CMP DWORD PTR SS:[EBP-4],2
0041AD1E  |.^\75 D0         JNE SHORT 0041ACF0
0041AD20  |. |B9 98E74800   MOV ECX,OFFSET 0048E798                  ; ASCII "diabdat.mpq"
0041AD25  |. |E8 726FFEFF   CALL 00401C9C                            ; [Diablo.00401C9C
0041AD2A  |.^\EB C4         JMP SHORT 0041ACF0
0041AD2C  |>  6A 01         PUSH 1                                   ; /Arg1 = 1
0041AD2E  |.  8D55 F8       LEA EDX,[EBP-8]                          ; |
0041AD31  |.  B9 84E74800   MOV ECX,OFFSET 0048E784                  ; |ASCII "ui_art\title.pcx"
0041AD36  |.  E8 CB7F0400   CALL 00462D06                            ; \Diablo.00462D06
0041AD3B  |.  85C0          TEST EAX,EAX
0041AD3D  |.  75 0A         JNE SHORT 0041AD49
0041AD3F  |.  B9 60E74800   MOV ECX,OFFSET 0048E760                  ; ASCII "Main program archive: diabdat.mpq"
0041AD44  |.  E8 536FFEFF   CALL 00401C9C                            ; [Diablo.00401C9C
0041AD49  |>  8B4D F8       MOV ECX,DWORD PTR SS:[EBP-8]
0041AD4C  |.  E8 2C7F0400   CALL 00462C7D                            ; [Diablo.00462C7D
0041AD51  |.  BA 50E74800   MOV EDX,OFFSET 0048E750                  ; ASCII "\patch_rt.mpq"
0041AD56  |.  8BCF          MOV ECX,EDI
0041AD58  |.  6A 00         PUSH 0                                   ; /Arg3 = 0
0041AD5A  |.  68 D0070000   PUSH 7D0                                 ; |Arg2 = 7D0
0041AD5F  |.  68 40E74800   PUSH OFFSET 0048E740                     ; |Arg1 = ASCII "DiabloInstall"
0041AD64  |.  E8 09000000   CALL 0041AD72                            ; \Diablo.0041AD72

Somit wird nun die „diabdat.mpq“ genauso wie die „patch_rt.mpq“ geladen und man kann das Spiel nun ohne CD spielen. Nun kann ich endlich das Spiel das erste Mal ohne CD starten und konnte nun mit einem Krieger in den Kampf ziehen. Doch was passierte nun, überall sind bunte Pixel und das Spiel sieht dadurch total doof aus.

Doch das liegt am Spiel und nicht am Crack. Unter Windows Vista/Windows 7 wird durch den Explorer irgendein Grafik-Glitch verursacht. Ich tippe einmal das es etwas mit der Aero-Oberfläche zu tun hat. Dieser Grafik-Bug gilt für die meisten Spiele die DirectX unter der Version 9 benutzen. Dafür musste dann noch ein kleines Batch-Skript her:

 taskkill /IM explorer.exe /F
 cd "D:\Spiele\Diablo\"
 start diablo.exe
 pause
 start explorer.exe

Nun kann man das Spiel in seiner vollen Pracht genießen. Mal schauen, welches Programm als nächstes dran glauben muss ;)! Ich hoffe es hat euch gefallen. Bis zum nächsten Mal.
Greetz TheVamp

Diablo.nz (5890 Downloads)

2 thoughts on “Diablo 1 – Let’s CrackIt”

  1. Leider ist es unter Win7 durchaus so, das Diablo sein eigenes „Installationslaufwerk“ wiederfindet.
    Deamontools ist zwar ne schöne Sache, muss aber nicht sein, solche Geschütze aufzufahren ;)
    Die Methode mit der Batch-Datei ist bei älteren Spielen unter Win7 durchaus vertretbar.

    P.S. Kannst du mir die .exe vererben ;)

  2. Du machst dir das vieleicht kompliziert:

    Zum Kopierschutz: CD in ein ISO konvertieren und dies dann über ein entsprechendes Programm (z.B. Deamon Tools) bereit stellen

    Zum Grafikproblem: In den Eigenschaften der EXE den Karteikartenreiter „Kompatibilität“ auswählen und Haken bei 256 Farben und 640×480 setzen. ggf. noch den Kompatibilitätsmodus auf win XP stellen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.