I've been trying to make modifications to Diablo II.exe for 1.09b in order for it not to use the CD. Onyx and other mods said in other posts that since Blizzard introduced the "no-cd patch" in 1.12+, that basically means that we can also make our own no-cd modifications for previous versions. So hopefully this post doesn't get locked or deleted.
Anyways, on to the content. I've been working and digging around the Diablo II.exe for 1.09b for about 10 hours now, also learning more about reverse engineering along the way. I'm not a beginner, but not pro either.
This is what I have so far:
Tools:
OllyDbg
PEiD
w32dasm
First I scanned the exe with PEiD to see if it was packed, and PEiD just said "Microsoft Visual C++ 6.0", which from some research means that it doesn't have any packing, it was just built with MSVC6.
When I opened the Diablo II.exe with File -> Open in OllyDbg, the base address is the usual 00400000, and Entry address is: 004014E3.
Initial searches for strings related to "Diablo II was unable to detect a Disc in your CD-ROM drive" and MessageBoxes with the title "CD-ROM drive error" with Olly and W32Dasm revealed that the address is around the following block:
Code: Select all
0040122D |. 51 |PUSH ECX ; |pStartupInfo
0040122E |. 6A 00 |PUSH 0 ; |CurrentDir = NULL
00401230 |. 6A 00 |PUSH 0 ; |pEnvironment = NULL
00401232 |. 6A 00 |PUSH 0 ; |CreationFlags = 0
00401234 |. 6A 01 |PUSH 1 ; |InheritHandles = TRUE
00401236 |. 6A 00 |PUSH 0 ; |pThreadSecurity = NULL
00401238 |. 6A 00 |PUSH 0 ; |pProcessSecurity = NULL
0040123A |. 52 |PUSH EDX ; |CommandLine
0040123B |. 6A 00 |PUSH 0 ; |ModuleFileName = NULL
0040123D |. FF15 0C504000 |CALL DWORD PTR DS:[<&KERNEL32.CreatePro>; \Process is ready to be created and request will be sent to kernel
00401243 |. 85C0 |TEST EAX,EAX ; tests something, the game should start here <<<<<< Notice this
00401245 |. 75 4E |JNZ SHORT Diablo_I.00401295 ; jump is taken <<<<<< Notice this
00401247 |. FF15 14504000 |CALL DWORD PTR DS:[<&KERNEL32.GetLastEr>; [GetLastError
0040124D |. 8BF0 |MOV ESI,EAX
0040124F |. 8D8424 8403000>|LEA EAX,DWORD PTR SS:[ESP+384]
00401256 |. 68 04010000 |PUSH 104
0040125B |. 50 |PUSH EAX
0040125C |. 6A 02 |PUSH 2
0040125E |. 53 |PUSH EBX
0040125F |. FFD5 |CALL EBP
00401261 |. 8D4C24 34 |LEA ECX,DWORD PTR SS:[ESP+34]
00401265 |. 68 04010000 |PUSH 104
Code: Select all
0040123D |. FF15 0C504000 |CALL DWORD PTR DS:[<&KERNEL32.CreatePro>; \Process is ready to be created and request will be sent to kernel
Inside kernel32
Code: Select all
750A1088 FF75 18 PUSH DWORD PTR SS:[EBP+18]
750A108B FF75 14 PUSH DWORD PTR SS:[EBP+14]
750A108E FF75 10 PUSH DWORD PTR SS:[EBP+10]
750A1091 FF75 0C PUSH DWORD PTR SS:[EBP+C]
750A1094 FF75 08 PUSH DWORD PTR SS:[EBP+8]
750A1097 6A 00 PUSH 0
750A1099 E8 01940100 CALL kernel32.CreateProcessInternalA ; This is where the kernel actually creates the process
750A109E 5D POP EBP
750A109F C2 2800 RETN 28
750A10A2 90 NOP
750A10A3 90 NOP
750A10A4 90 NOP
750A10A5 90 NOP
Code: Select all
00401557 |. FF15 10504000 CALL DWORD PTR DS:[<&KERNEL32.GetCommand>; [GetCommandLineA
0040155D |. A3 C8694000 MOV DWORD PTR DS:[4069C8],EAX
00401562 |. E8 FD0C0000 CALL Diablo_I.00402264
00401567 |. A3 B4644000 MOV DWORD PTR DS:[4064B4],EAX
0040156C |. E8 A60A0000 CALL Diablo_I.00402017
00401571 |. E8 E8090000 CALL Diablo_I.00401F5E
00401576 |. E8 05070000 CALL Diablo_I.00401C80
0040157B |. 8975 D0 MOV DWORD PTR SS:[EBP-30],ESI
0040157E |. 8D45 A4 LEA EAX,DWORD PTR SS:[EBP-5C]
00401581 |. 50 PUSH EAX ; /pStartupinfo
00401582 |. FF15 2C504000 CALL DWORD PTR DS:[<&KERNEL32.GetStartup>; \GetStartupInfoA
00401588 |. E8 79090000 CALL Diablo_I.00401F06
0040158D |. 8945 9C MOV DWORD PTR SS:[EBP-64],EAX
00401590 |. F645 D0 01 TEST BYTE PTR SS:[EBP-30],1
00401594 |. 74 06 JE SHORT Diablo_I.0040159C
00401596 |. 0FB745 D4 MOVZX EAX,WORD PTR SS:[EBP-2C]
0040159A |. EB 03 JMP SHORT Diablo_I.0040159F
0040159C |> 6A 0A PUSH 0A
0040159E |. 58 POP EAX
0040159F |> 50 PUSH EAX ; /Arg4
004015A0 |. FF75 9C PUSH DWORD PTR SS:[EBP-64] ; |Arg3
004015A3 |. 56 PUSH ESI ; |Arg2
004015A4 |. 56 PUSH ESI ; |/pModule
004015A5 |. FF15 28504000 CALL DWORD PTR DS:[<&KERNEL32.GetModuleH>; |\GetModuleHandleA
004015AB |. 50 PUSH EAX ; |Arg1
004015AC |. E8 4FFAFFFF CALL Diablo_I.00401000 ; \<- Diablo stuff really starts here
004015B1 |. 8945 A0 MOV DWORD PTR SS:[EBP-60],EAX
004015B4 |. 50 PUSH EAX
004015B5 |. E8 F3060000 CALL Diablo_I.00401CAD
I noticed that even if I put my CD inside and it loads D2, if I keep the game open and then continue stepping into the debugger, eventually it will go into code regarding cd-checks and it will end up saying to put in the disc (Even though the game is started and the CD is inside). Some code for that is the following:
Code: Select all
0040134C |. 8D8C24 8403000>|LEA ECX,DWORD PTR SS:[ESP+384]
00401353 |. 6A 05 |PUSH 5 ; /Style = MB_RETRYCANCEL|MB_APPLMODAL
00401355 |. 8D5424 38 |LEA EDX,DWORD PTR SS:[ESP+38] ; |
00401359 |. 51 |PUSH ECX ; |Title
0040135A |. 52 |PUSH EDX ; |Text
0040135B |. 6A 00 |PUSH 0 ; |hOwner = NULL
0040135D |. FF15 AC504000 |CALL DWORD PTR DS:[<&USER32.MessageBoxA>; \MessageBox: Do you want to retry? or cancel message..
00401363 |. 83F8 02 |CMP EAX,2
00401366 |.^0F85 DFFCFFFF \JNZ Diablo_I.0040104B ; If not = to 0, then go back to top to load game
0040136C |> 5D POP EBP ; Case 1 of switch 004012CC
0040136D |. 5B POP EBX
0040136E |> 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]
00401372 |. 50 PUSH EAX ; /hObject
00401373 |. FF15 58504000 CALL DWORD PTR DS:[<&KERNEL32.CloseHandl>; \CloseHandle
00401379 |. 8BC6 MOV EAX,ESI
0040137B |. 5F POP EDI
0040137C |. 5E POP ESI
0040137D |. 81C4 80060000 ADD ESP,680
00401383 \. C2 1000 RETN 10
I retrieved strings by either loading the .exe with w32dasm and looking for "String Data References", or using Olly's -> Executable Modules -> (Right click Diablo II.exe) and click "View Resource Strings".
Before starting this project I thought it would be pretty easy, just going into the code and just inverting some stuff, I probably was thinking to naively haha.
- fearedbliss