Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Tl;DW: There were versions of the game released that still had debug symbols.


To be more particular:

- The Japanese Playstation port contained debug symbols

- A Windows debug binary with all assertions in tact was found

It is my understanding that this combination allowed for a better understanding than just symbols alone.

(Could be a little fuzzy on the details; I watched this video last night, not just now.)


Debug assertions in game binaries for blizzard and blizzard-branched studios are more common than you might expect. At least at ArenaNet, it was studio philosophy to ship with most debug assertions enabled so we could gather crash reports in the field to fix bugs. We only exempted assertions where the checks would cause performance issues (i.e. in a renderer or audio mixer). Most of our engineering culture was inherited from Blizzard and I think that particular rule was too.


Cool insight to hear. Apparently for the original Diablo, the usual release builds actually didn't contain debug assertions. I guess it must've become a part of their culture sometime after the release of the original Diablo?

I definitely believe you, though. I am pretty much positive that I've seen Warcraft III's engine crashing on debug assertions before when playing with the scenario editing tools.


I wouldn't be surprised if Diablo development is why the policy was in place. One of ANet's founders did a lot of work trying to help ship Diablo and it sounded like it had some serious engineering and quality culture issues (iirc Diablo was originally being developed by another studio that Blizzard acquired, but I might be misremembering)


I also remember Diablo II throwing up assertions when I was playing with the parameters in the txt files. Fun times.


To give further background, the Devilution team has primarily relied on these resources:

1. The Japanese Playstation port with debug symbols contained in `DIABPSX.SYM`. (see [1]).

Example debug info of the Cathedral dungeon generation algorithm:

  // address: 0x801259D0
  // line start: 612
  // line end:   624
  void DRLG_L1Floor__Fv() {
   // register: 19
   register int i;
   // register: 20
   register int j;
   // register: 3
   register long rv;
  }
2. The debug release of the PE executable, which contained assert strings (see [2]).

Example assert string:

  "plr[myplr].InvGrid[i] <= plr[myplr]._pNumInv"
3. The Rich header of the PE executable, which details the exact version of the original compilers and linkers used to build `Diablo.exe` (see [3,4]).

Example information recovered from the Rich header of `Diablo.exe`:

  Id  Build  Count  Name       Description
   0      0    155  Unknown    [---] Number of imported functions (old)
   1      0    229  Import0    [---] Number of imported functions
   6   1668      1  Cvtres500  [RES] VS97 (5.0) SP3 cvtres 5.00.1668
   2   7303     29  Linker510  [IMP] VS97 (5.0) SP3 link 5.10.7303
   3   7303      1  Cvtomf510        VS97 (5.0) SP3 cvtomf 5.10.7303
   4   8447      2  Linker600  [LNK] VC++ 6.0 SP3,SP4,SP5,SP6 link 6.00.8447
  48   9044     72  Utc12_2_C  [---] VC++ 6.0 SP5 Processor Pack
  19   9049     12  Linker512        Microsoft LINK 5.12.9049
4. Discovery of the original set of compiler flags used to build `Diablo.exe` (see [5]).

Primarily "/O1" was used, but there are also peculiarities such as the use of both Microsoft Visual Studio 6 and Microsoft Visual Code 5 for linking the game.

5. The heartfelt dedication of a team of people. GalaXyHaXz did the initial heavy lifting and succeeded in the tremendous task of getting the decompiled source code of Diablo 1 compiling with the original toolchain. Later on she released the project open source and a community of open source collaborators formed. Most of us have never met in real life prior to joining the project, which stands to show that there is strength in online collaboration that transcend both culture and borders.

6. The Beta release and the Alpha4 release of Diablo 1 has also proved invaluable resources for cross-validation as the compiler optimization level was not set to release mode for these binaries.

Interestingly, in the process a number of bugs in the original implementation of Diablo 1 were discovered. These have been documented in the source code of Devilution with `// BUGFIX: foo` comments, and have also been detailed in [6].

To track the progress of the project, the "Binary identical functions" milestone has been used in tandem with an assembly diffing tool developed in Rust (see [7,8]).

Anecdotally, it was an incredible moment when we first managed to run the cross-platform port of Diablo 1 (DevilutionX, see [9]) natively on Linux and succeeded in playing a multiplayer game connecting our computers in Korea and Denmark. It is equally thrilling to see the modding and porting community picking up the torch and already succeeding in porting Diablo 1 to Nintendo Switch!

The main reason for conducting this bit of software archeology is to preserve the classic title that is Diablo 1, for generations to come. And to revive it for modern hardware platforms and make it more mod-friendly in the age of open source software.

Happy coding! - The Devilution Team

P.S. the project README explicitly states that to play the game, you still need to have access to the original game assets released on the Diablo 1 CD. To acquire a legal copy, please refer to https://www.gog.com/game/diablo

P.P.S. for the verification process, there have been proposals that are both ambitious at a level of PhD research (see [10]) and that made us feel warm and fuzzy <3 In the end, many of the techniques outlined were discussed mostly on a design level, some were included as Proof of Concepts, but most of the work in reverse engineering Diablo 1 was from tender labour of a team that care for Diablo 1 the way you would your firstborn child.

[1]: https://github.com/diasurgical/scalpel/blob/master/psx/_dump...

[2]: http://diablo1.se/notes/debug.html

[3]: https://github.com/diasurgical/devilution/issues/111#issueco...

[4]: http://bytepointer.com/articles/the_microsoft_rich_header.ht...

[5]: https://github.com/diasurgical/devilution/issues/111

[6]: https://github.com/diasurgical/devilution/issues/64

[7]: https://github.com/diasurgical/devilution/milestone/3

[8]: https://github.com/diasurgical/devilution-comparer

[9]: https://github.com/diasurgical/devilutionX

[10]: https://github.com/diasurgical/devilution/issues/171


Super noob question but i'm trying to wrap my head around how one could figure out the source code just based on things like debug info and assert strings? I watched the video and am staring at your examples and I just don't understand how you go from those to actual source code.


In the disassembly we can see a bunch of fine grained operations but the meaning behind them is opaque. For example, we see two array access operations but its not clear what they do. They might look like this:

mov al, [array + ebx]

Considering the assert statement from point 2: "plr[myplr].InvGrid[i] <= plr[myplr]._pNumInv"

From this we can see what the variables were named in the source code. Assuming "plr" = player and "InvGrid" = Inventory grid, we can deduce one the array access operations is to get the current player and another is for getting an item from the inventory grid.


Wow! Thanks for this information, this is very cool. Software preservation is a big deal and it's very hard work, so huge kudos to everyone involved.


Is there a version that runs on Windows 10? Its the game I used to initially addict my wife to gaming, and we'd like to play it again.

EDIT: Found it:

https://github.com/diasurgical/devilutionX/releases


And DevolutionX even works on Haiku too.


This is such a huge thing. If you are trying to reverse engineer something, spend time looking for other versions or test releases that might be out there. I've had a lot of success with this method.


The same thing happened for Oni. The debug symbols from a Mac version of the game were crossreferenced with dissassembly.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: