[Tutorial] Reverse engineering Diablo (v1.09)
#1
Hello.

This is a tutorial regarding how to go about reverse engineering a game. In this instance I've chosen a classic: Diablo!

In order to reverse engineer something: We must have a clear-cut objective. Without a clear objective (goal): We'll wander aimlessly.
We need to stay focused on our objective. It's O.K. to put down mile-stone markers, so you can revert back to interesting ideas, but stay focused.

The tool we'll be using to reverse engineer Diablo with today, will be: x32dbg ( https://x64dbg.com/#start ). This is an excellent, free and powerful tool.
Diablo's a 32-bit program. If you try to load it with x64dbg: The program should load up with x32dbg for you. If not: Load it up with x32dbg manually.

We'll start by defining our objective for the day. We will start off by finding more information about how Diablo's items in the inventory work.
We can uncover all sorts of interesting and fun information! Perhaps we'll learn how to make all items indestructible or increase stats.

OBJECTIVE: Learn about Diablo items (in the inventory).

Where should we attack this daunting task, you ask? I suggest we play Diablo for a little bit and gather some items up. In fact: Fill your inventory!
After you've had your fun and have filled up your inventory with items and equipped what items you can (weapon, shield, armor, helm, etc): Pause.

Just return to town and leave the game running. We're only beginning! Smile

Open x32dbg and click on "File" then "Attach" (or press ALT + F2 as a hotkey). Find the "DIABLO" process and attach our debugger to it.
After it's finished loading: Find the "Memory Map" tab and click on it. Scroll down until you find "DIABLO.EXE" then double-click on ".text" (executable).

Right click anywhere in the memory map window pane (where all the assembly code is shown) -> Search For -> Current Module -> String References.
Find something of interest that may lead you to your items in your inventory.

The only thing I saw was a reference to Griswold (NPC), asking if you want to sell an item. This means that Diablo must look at your item.
This will hopefully give us something good to look at. If at first you fail: Try, try again!

You can double click on the string reference and it'll jump you to where it's at in the memory map. Then you can press F2 to set a break-point.
Alternatively: You can just select the string (click once) and press F2 to set a break-point.

A break-point means that when the program executes that instruction: The entire program (Diablo) will freeze. Allowing you to go instruction-by-instruction through the program.
This will expose all the registers, memory dump, stack and other fancy things. This will allow us to gather more sensitive information.

You should probably talk to Griswold and attempt to sell an item at this point (after your break-point is set).
For me (v1.09 patch of Diablo) it popped on this particular address (yours should be the same, but maybe you're on another patch):
Code:
004597F9 | 68 78 32 4A 00           | push    diablo.4A3278                        | 4A3278:"Are you sure you want to sell this item?"

You'll notice at Griswold: He has a few menus after talking to him initially. The tree reads:
Talk to Griswold -> Sell items (your unused items in your inventory were loaded here?) -> "Selected item" -> Yes/No option

Our break-point appears to have popped when the static text of "Are you sure you want to sell this item?" is pushed into the text-rendering function.
We will have to walk our way through and put notes all over the place and explore! This is the fun part.

To put a comment on an instruction: You can use the hotkey of a semi-colon ( ; ). You can also place break-points along the way so you don't get lost.
You could also use CTRL + C and a notepad (or x32dbg's internal "NOTES" tab which is associated with this process (DIABLO.EXE)).

You can use the hotkey F8 to step over (meaning: The debugger will execute all Nth deep calls until you "step over" the function call) instructions.
If you'd like to step into a function: Press F7 (you can also hover the mouse over a function call to see a "preview pane window" pop up).

When we press F8: We're placed on a JMP command. That leads us here:
Code:
0045982C | 68 B0 31 4A 00           | push    diablo.4A31B0

We also see that it pushes the contents of the ESI register (which is another memory address).
You can right click on the ESI register (far upper right pane) and click on "Follow in dump" if you'd like to see what is being pushed onto the stack (lower right pane).

If you press F7 on the next call: You will enter into that function call. It is more than likely just a text-rendering function of sorts (top level perhaps?).
Code:
00459832 | E8 49 05 01 00           | call    <diablo.renderText()>

Upon entering the function, we can immediately see that a string reference to our item is moved into the EDI register (copied from the stack-segment).
Code:
00469D81 | 8B 7C 24 08              | mov     edi,dword ptr ss:[esp+0x8]

If we press F8 to step over some instructions: We'll find ourselves in a loop! This loop appears to be going through the string(s) to be displayed.
We exit out of the function, only to see that we're back at where we started! Frustrating, almost. It feels like we've made no progress.

The next instruction we've landed on is here:
Code:
00459831 | 56                       | push    esi                                       |
Pressed F7 here -> 00459832 | E8 49 05 01 00           | call    <diablo_copy.renderText()>                |
Landed here -> 00459837 | 59                       | pop     ecx                                       | ecx:"Say goodbye"

It's okay though. Don't give up hope and believe that it is "too hard" or "too complex." This is actually quite exciting to me.
We're making progress. We're learning something different and new. All roads lead to Rome. This is just the one I've chosen to take.

If we press F8 and walk down some more: We can see the "Yes/No" question posed by Griswold!
Code:
0045984E | 68 AC 31 4A 00           | push    diablo.4A31AC                        | 4A31AC:"Yes"

This is loading the menu screen (which is NOT our objective, but is quite interesting; Maybe we could put a marker?).
This is also quite important. The game (DIABLO.EXE) must delete our game item and exchange it for gold (also in our inventory).

I would step into the function where he asks if you would like to sell the item. We can repeat the same procedure.
We will find where the text "Yes" is displayed and place a break-point on it (by pressing F2).

You could place the break-point outside of the function (where it is called at least once):
Code:
00459857 | E8 89 E7 FF FF           | call    <diablo.sub_457FE5>                  |

However: This doesn't sound like a good idea. This was called when we first talked to Griswold and asked to sell items.
I believe it would be better to enter the function first (press F7) and place a break-point on the entry (press F2).

This is where I ended up. If you ever get lost: You can click on the memory map pane then use the hotkey CTRL + G and enter "00457FE5" as the address.
Code:
00457FE5 | 56                       | push    esi                                       |

Now that we have our new break-point set on (what we hopefully assume is Griswold's "Yes" option): We return to our game and try to sell our item!

Success! The debugger has popped on our break-point for displaying text. We can press "F9" to tell the debugger to run, until it hits a break-point.
If you have more than one item for sale: It should pop again and again and again.

What I am seeing is my "Leather Armor" constantly showing. That is the text being rendered that you see in Griswold's menu screen.
It must've come from my inventory. 'But how do I find that out?' You ask. Have patience! This is an incredibly odd way of solving the issue.

If you glance up at the registers (upper right window pane): You will see the text being displayed under the EAX register.
The EAX register is holding a memory address (more than likely our culprit). You can right click on the EAX register -> "Follow in dump"
Then you can right click on the beginning address where the item is being loaded from (in the dump, on the lower left) -> Breakpoint -> Hardware, Write -> Byte

For me, the address I am setting a hardware break-point on in the data segment (DS) or "dump" is:
Code:
006A0A2D

What will this do, you wonder? That's okay. Questions are good to ask! Never be afraid to ask questions.
Setting a break-point in the .data or data-segment or DS or "dump" will do different things based on your break-point's conditions.

A "hardware, write -> byte" means: It will freeze the program when the program attempts to modify that variable (by writing to it).
Why would we want to put a break-point there of all places, you ask?!! Because: Diablo must've loaded my item from the inventory.
It either copied my item from it's location and placed it at this new address OR it directly modifies my item from Griswold's menu.

We'll find out soon! Press F9 to continue. Wink

Oh wait! Even after putting our clever hardware break-point in the dump: It keeps popping on our text-rendering function.
Press F2 to disable the text-rendering function OR navigate to the "Breakpoints" tab at the top and left click on your active break-point and press "SPACE-BAR" (toggles disabled/enabled).

To reiterate: We want to remove (disable preferably) the break-point set in the .text (executable code; "Memory map"). The text-rendering one for Griswold.
Code:
00457FE5 | 56                       | push    esi                                       |

Now press F9 in the debugger, return to the game and attempt to sell an item to Griswold in exchange for gold.

Our debugger appears to have popped (as our game has frozen) yet again! Success! That is our data-segment break-point!!!
This is VERY exciting and GREAT news! This means something has attempted to WRITE to the memory address of our item string.

If we're lucky: This will be our item in the game and it will be directly modified. If not: It should be near-by anyway.

My debugger popped on this particular instruction (which is quite Greek to me):
Code:
00458AD5 | F3 A5                    | repe movsd                                        |

After a quick Google search on the mnemonics (Assembly instructions): "repe movsd"
ECX holds the number of bytes to copy; It copies FROM the address listed in ESI TO the address listed at EDI.

Quantity to copy: ECX
(Copy from) ESI -> (copy to) EDI

You can right click on the ESI or EDI registers and follow in the .data dump. This should be your inventory!
I would look at the ESI register first (as it's likely our inventory; since it is being copied from that location).

Voila! After following the address located in the ESI register and scrolling up/down the data segment: I can see other items!!!

I have "gold" I have the item I'm about to sell and scrolls and potions. You should see yours too!

After you've completed this tutorial: Now you have quite a few options opened in front of you (without the anxiety and stress).
You have the ability of easily finding out how Diablo manipulates menu text from NPCs, displaying text in general and items!

You can modify values in your items (that are in your inventory) and see what changes happen in the game (trial and error).
You could try dropping an item and seeing what values are changed in the inventory. This will tell you how the game really operates on the data.

In case you're not too comfortable with this: I'll give one freebie out for you (to encourage you to play with it).
If an item is NOT currently in the inventory: The value will be read as: 0xFF 0xFF 0xFF 0xFF

For my game: My shield's address (in the data-segment) is listed at:
Code:
00686EFC

You can right click in the "Dump" -> Go To -> Expression (or press CTRL + G)
Enter the address: 00686EFC then press enter

If you have a shield equipped: You will not see the first 4 bytes listed as 0xFF 0xFF 0xFF 0xFF
Instead: You will see some numerical value that the game interprets and uses to modify the graphics displayed.

Hopefully this tutorial has inspired you to learn more and try more things in general. Smile
Reply


Messages In This Thread
[Tutorial] Reverse engineering Diablo (v1.09) - by TheKillerVortex - 01-30-2018, 11:29 AM

Forum Jump:


Users browsing this thread: 1 Guest(s)