[back]
No CD cracking - Elder Scrolls 4: Oblivion (from binary, using OllyDbg)
I greatly enjoyed Oblivion, which was groundbreaking when it released. Its nature was green and vibrant, cities beautiful, quests intriguing. Certain things, however, were questionable; examples include faces and requiring the game CD to be inserted to allow play.

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.



Begin by finding dialog string in program memory:


Text strings referenced in Oblivion, item 12170
Address = 00998F30
Command = PUSH OFFSET 009ED780
Comments = ASCII "Insert the Oblivion Disc."

Reference from:


00998F30 /. 68 80D79E00 PUSH OFFSET 009ED780
; Arg2 = ASCII "Insert the Oblivion Disc."
; function start at 00998F30

Stack:


0019FE4C [00960405 �. ; RETURN to Oblivion.00960405

00960403 |. FFD0 |CALL EAX
; calls "no CD" dialogue opener

Reaches following with arguments pointers to "no CD" strings:


0040D178 |. E8 A370FFFF CALL 00404220 ; \Oblivion.00404220

This is hit many times until one of the hits brings up the message dialog.
The condition is there to only catch that last hit:


INT3 breakpoints, item 0
Address = 0040D178
Module = Oblivion
Status = Cond
Disassembly = CALL 00404220
Comment =
Condition = EAX == 00A3086C


Revelation: the above code path was a red herring. It has nothing to do with displaying the error message; it does some sort of initialization of strings... maybe pre-loading localizations.

Reached only once, right before "no CD" dialog:
Update: also reached with CD inserted:


00960410 \. C3 RETN

Last known call before dialog, but reached when CD is in too:


0096433B |. E8 1099AAFF CALL 0040DC50 ; \Oblivion.0040DC50

With no CD reaches:


0040DE37 |. E8 64ED0700 CALL 0048CBA0 ; [Oblivion.0048CBA0
; ...
0040DF86 |. 8B3D 54B29E00 MOV EDI,DWORD PTR DS:[<&USER32.MessageBoxA>]
; Entry point of procedure
; ...
0040DFB6 |. FFD6 |CALL ESI

Call into USER32.MessageBoxA to show the dialog:


0040E018 |. FFD7 |CALL EDI

Likely branch before USER32.MessageBoxA:


0040DF73 |> \A0 7051AD00 MOV AL,BYTE PTR DS:[0AD5170]
0040DF7A |. /0F85 B5000000 JNE 0040E035
; AL = 0 when no CD
; AL = ASCII of drive letter of CD drive containing CD when CD

Find writes to 0AD5170 via memory breakpoint on write.


The following writes 0 - probably some initial value:


00404AEE |. 881D 7051AD00 MOV BYTE PTR DS:[0AD5170],BL

The following writes drive letter of CD drive containing CD:


00404B40 |. A2 7051AD00 |MOV BYTE PTR DS:[0AD5170],AL

Start of "check many CD drives for CD" loop:


00404B00 |> /A0 7051AD00 /MOV AL,BYTE PTR DS:[0AD5170]

Returns 0 when argument is the drive containing the CD:


00404B32 |. E8 D2C85500 |CALL 00961409 ; \Oblivion.00961409
; returns 0 when drive contains CD (checks for :\OblivionLauncher.exe)
; returns nonzero when drive doesn't contain CD

; change to

00404B32 31C0 XOR EAX,EAX
00404B34 90 NOP
00404B35 90 NOP
00404B36 90 NOP

This causes the game to no longer require a CD, as long as the computer has at least one CD drive.
I want to remove this requirement.

This calls KERNEL32.GetDriveTypeA to check whether currently-checked drive is a CD drive:


00404B0E |. FFD5 CALL EBP

From API documentation, KERNEL32.GetDriveTypeA return types:


DRIVE_UNKNOWN 0
DRIVE_NO_ROOT_DIR 1
DRIVE_REMOVABLE 2
DRIVE_FIXED 3
DRIVE_REMOTE 4
DRIVE_CDROM 5
DRIVE_RAMDISK 6

This skips over the "does drive contain CD" if currently-checked drive is not a CD drive:


00404B10 |. 83F8 05 CMP EAX,5
00404B13 |. 75 32 JNE SHORT 00404B47
; branch taken when drive is not a CD drive

; change to

00404B10 |. 83F8 05 CMP EAX,5
00404B13 90 NOP
00404B14 90 NOP


This treats the first enumerated drive as a CD drive, irrespective of type.


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:


00404B10 |. 83F8 05 CMP EAX,5
00404B13 |. 75 32 JNE SHORT 00404B47
; branch taken when drive is not a CD drive

; change to

00404B10 |. 83F8 05 CMP EAX,5
00404B13 90 NOP
00404B14 90 NOP


2. Force CD check stage to believe C: contains the Oblivion CD


00404B32 |. E8 D2C85500 |CALL 00961409 ; \Oblivion.00961409
; returns 0 when drive contains CD (checks for \OblivionLauncher.exe)
; returns nonzero when drive doesn't contain CD

; change to

00404B32 31C0 XOR EAX,EAX
00404B34 90 NOP
00404B35 90 NOP
00404B36 90 NOP