[back]
No CD cracking - Elder Scrolls 3: Morrowind (from binary, using OllyDbg)
I consider Morrowind to be the best game in the Elder Scrolls series. However, it has frustrated me several times by asking me for its CD! Thus, I had to take my revenge on it...

OllyDbg version 2.00 is an excellent debugger. The features I appreciated most were: visual representation of branches, modify (by assembling) in-place, and most of all the ability to save modified executable.



Found this on the stack while the above error dialog is displayed:


Address Value ASCII Comments
0019FE40 007CB478 ; ASCII "Insert the Morrowind CD into any CD-ROM/DVD drive."

When 007CB478 is read when it contains "Insert the Morrowind CD into any CD-ROM/DVD drive.", it is read from the following:


7599596C 8A01 MOV AL,BYTE PTR DS:[ECX]

and also


77411EEC 0FB60439 MOVZX EAX,BYTE PTR DS:[EDI+ECX]

Stack is full of pointers to that "no CD message", but the following is the return point to the highest-level invocation of a function which takes the pointer to the message as an argument:


0019FE58 00416FAD ´┐ŻoA. ; RETURN from USER32.759F39A0 to Morrowind.00416FAD

This is generated by the call below, which creates the dialog:


00416FA7 |. FF15 9C637400 |CALL DWORD PTR DS:[<&USER32.MessageBoxA>]
; show "insert CD" dialog

This function starts at:


00416E10 /$ 83EC 5C SUB ESP,5C
; entered even when CD is present

The following checks whether any CD drives are present in the system


00416EC2 |> \8A4424 13 MOV AL,BYTE PTR SS:[ESP+13]
; ESP+13 is 0019FE7F

00416EC6 |. 84C0 TEST AL,AL
00416EC8 |. 75 71 JNE SHORT 00416F3B
; when branch is taken, program checks the CD inside the drive
; when branch is not taken, program reports "computer has no CD drive"

This loops for each drive, checking whether any have the Morrowind CD inserted:


00416E6D |> /A0 8C6D7C00 /MOV AL,BYTE PTR DS:[7C6D8C]
00416E72 |. |84C0 |TEST AL,AL
00416E74 |. |75 4C |JNE SHORT 00416EC2
; branch is not taken when currently-checked drive contains CD (AL=0)
; branch is taken when currently-checked drive doesn't contain CD

WHEN NOT FOUND
then continues here once after not finding CD in any drives


00416F3B |> \A0 8C6D7C00 MOV AL,BYTE PTR DS:[7C6D8C]
; let FOUND_CD_DRIVE_LETTER = 007C6D8C
00416F40 |. 84C0 TEST AL,AL
00416F42 |. /0F85 F9000000 JNE 00417041
; when branch is taken (AL != 0), program skips any CD check failed places
; when branch is not taken, program prepares for reporting "CD check failed"

WHEN FOUND
goes to the following upon finding it during loop


00416EA4 |. A2 8C6D7C00 |MOV BYTE PTR DS:[7C6D8C],AL
; AL here contains ASCII of drive containing CD (e.g. 'C' for C:)

Then checks whether AutoRunMorrowind.exe exists and is readonly in the root of currently-checked drive


00416E85 |. 57 |PUSH EDI
00416E86 |. 68 6C6D7700 |PUSH OFFSET 00776D6C ; ASCII "%sAutoRunMorrowind.exe"
00416E8B |. 53 |PUSH EBX
00416E8C |. FF15 74627400 |CALL DWORD PTR DS:[<&MSVCRT.sprintf>]
00416E92 |. 6A 00 |PUSH 0
00416E94 |. 53 |PUSH EBX
00416E95 |. FF15 5C627400 |CALL DWORD PTR DS:[<&MSVCRT._access>]
00416E9B |. 83C4 14 |ADD ESP,14
00416E9E |. 85C0 |TEST EAX,EAX


Final approach


Thus, the entirety of the crack is made up of:

1. Force CD drive check stage to believe C: is a CD-ROM drive:


00416EC2 |> \8A4424 13 MOV AL,BYTE PTR SS:[ESP+13]
; modified to
00416EC2 \B0 43 MOV AL,43
00416EC4 90 NOP
00416EC5 90 NOP


2. Force CD check stage to believe C: contains the Morrowind CD (in 2 spots)


00416E6D |> /A0 8C6D7C00 /MOV AL,BYTE PTR DS:[7C6D8C]

; modified to

00416E6D /B0 43 MOV AL,43
00416E6F |90 NOP
00416E70 |90 NOP
00416E71 |90 NOP


00416F3B \A0 8C6D7C00 MOV AL,BYTE PTR DS:[7C6D8C]

; modified to

00416F3B \B0 43 MOV AL,43
00416F3D 90 NOP
00416F3E 90 NOP
00416F3F 90 NOP



It must be noted that since the game will henceforth believe C: is the CD-ROM drive containing the Morrowind CD, it will fail to load cutscenes. These videos are not installed to hard disk because of their large size - they're read from the CD during gameplay.


Fortunately, the workaround is trivial: press Escape when the initial cinematic fails to load, which instructs the game to fail silently, skipping all videos that could not be loaded. This results in normal gameplay, sans cutscenes.