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

This tutorial is more focused towards using multiple tools to aid in reverse engineering our selected target (Diablo! Patch v1.09).

Today: We'll be using both x32dbg and CheatEngine 6.7 (http://www.cheatengine.org/downloads.php).

What is "CheatEngine?" You may be wondering. That's a fairly good question to ask. I'll answer it.
"CheatEngine" is a memory searching ('memory scanner'), debugger, reverse engineering tool all rolled into one!

Why would we want to use both x32dbg and CheatEngine when CheatEngine can do it all on it's own?
The only answer I can provide: Because although x32dbg does provide the ability of searching for (constant or static) string references:
It cannot actively scan the process memory for a particular string! Where-as CheatEngine can.

Would you only eat steak with a fork or with a fork and knife? There are times when multiple tools will simplify your work.

Our objective for the day: Finding out where Diablo stores the monster kill count tallies.
Our first step is as usual: Basic research! We know from playing Diablo, that all kills are universal.
Your kills on any given number of single player characters will carry over to your multiplayer characters (no matter what server/connection type).

To simplify what I'm saying: If you kill 50 Fallen on your Sorcerer, then go kill 50 Zombies on your Rogue, then go kill 50 Scavenger's on Single Player and then log on to Battle.net and search around: You'll see that those monster kills are all still there (the counter is never reset).

This leads me to believe initially that the data is stored locally (in the DS or .data segment or "heap" (these are all aliases and are synonymous)).
This is why I've trumped up the idea of using CheatEngine! It sounds like a perfect match for the task at hand.

To reiterate our objective:
OBJECTIVE: Find out where Diablo stores the monster's total kill counters!

TOOLS USED: CheatEngine 6.7 and x32dbg (to create a hack "patch" to reset counters; Left as a user exercise)

First: Let's load up Diablo and have some fun! Kill those monsters! Play until you feel you've gotten ready to reverse engineer.
Second: Open CheatEngine. Click on the computer with a magnifying glass ("Open Process list"), click on "DIABLO," then click on "Attach debugger to process." Then click, "Yes."

Let's choose Fallen as our target to identify. We'll assume we have 3 kills on the Fallen. Under "value" in CheatEngine: Enter "3."
Click on "First Scan." This will pull open a list of all values in Diablo's process memory that contain "3." There might be hundreds of addresses listed!

We need to narrow down that list, so we can find what we're searching for. You will need to change the value (which is the deaths of the particular monster or game unit). Kill another Fallen. Now it should be at "4."

Open CheatEngine again, enter "4" in the "value" and press on "Next scan." If you're lucky, like I was: You'll be going...
WOW! Only ONE address left! It may or may not be what you're looking for, but you can quickly test it out!

Double click on the address. It'll create a quick-copy on the bottom pane window in CheatEngine.
Double left-click on the "VALUE" (which should be listed as "4"). This will open a dialog to modify the value.

Enter any value you can think of. I'm going to go with... 35!
If we're right: This should make our Fallen's kill counter set to 35.

In my game: I immediately noticed that "Fallen One" is not just one unit type. There are actually TWO types!
Those that carry Spears and those that carry Swords. Diablo identifies them as two different types with two different counters.

The address I have listed is:
Code:
Diablo.exe + 0x24CD18 (Monster kill counter for: Fallen)
---> 0x0064CD18 (the actual address you can reference in: x32dbg)
Diablo.exe = 0x400000 (base of the module)

Now we can close CheatEngine (do not worry about it saying it'll have to deattach the debugger).
Open x32dbg up, attach the debugger to DIABLO.exe and click on the heap (bottom left pane).
Use the hotkey: CTRL + G and enter your address (I will enter: 0x0064CD18)!

You can set a hardware break-point on this memory address. Right click on the value (0x24 is what I see) -> Breakpoint -> Hardware, Write -> Byte
Then resume Diablo and slay another Fallen monster (or whatever one you have selected as a target).

My x32dbg debugger popped on this memory address in the memory map (.text):
Code:
00433C61 | E8 B2 38 FE FF           | call    <diablo_copy.sub_417518>                  |

This is the instruction following where our break-point actually popped at. You can look at the immediate preceding instruction:
Code:
00433C5F | FF 00                    | inc     dword ptr ds:[eax]                        |

We can read this instruction out loud:
Increment a double-word pointer to the data-segment at the address of list at EAX

This means we should turn our attention towards the EAX register (in the far upper right pane window).
Code:
EAX = 0x0064CD18

This is the memory address in the Diablo.exe process under the .data segment. This particular value is our Fallen monster's kill count!
We can right click on the EAX value and click on: "Follow in dump (data segment)."
I interchangeably use DS, .data, dump, data segment and heap to illustrate that they are all just aliases.

Now you can visually see your kill counter in x32dbg! Smile

To review the actual set of instructions that are (partially) involved in loading the kill counter:
Code:
00433C43 | 8B 86 0C D4 64 00        | mov     eax,dword ptr ds:[esi+0x64D40C]           | [esi+64D40C]:sub_657D21+FE7
00433C49 | 8B 8E E0 D3 64 00        | mov     ecx,dword ptr ds:[esi+0x64D3E0]           |
00433C4F | 0F B6 00                 | movzx   eax,byte ptr ds:[eax]                     |
00433C52 | 89 AE C4 D3 64 00        | mov     dword ptr ds:[esi+0x64D3C4],ebp           |
00433C58 | 8D 04 85 E8 CC 64 00     | lea     eax,dword ptr ds:[eax*4+0x64CCE8]         |
00433C5F | FF 00                    | inc     dword ptr ds:[eax]                        |
00433C61 | E8 B2 38 FE FF           | call    <diablo_copy.sub_417518>                  |

I've decided to remove my hardware break point on the .data kill count directly and attach a breakpoint to the .text segment (00433C43).
In case you're a little confused: Try clicking on the large window with all the instructions, then pressing CTRL + G and entering "00433C43."

You should land here:
Code:
00433C43 | 8B 86 0C D4 64 00        | mov     eax,dword ptr ds:[esi+0x64D40C]           | [esi+64D40C]:sub_657D21+FE7

Then press F2 to set a breakpoint. Then open Diablo and kill another monster (any monster in this instance).

I will leave it as a user exercise to map out exactly which memory addresses are attached to which monsters.

There are a few ways you could tackle this problem, but I presume as a person new to reverse engineering: You will create a notepad document and draft up something like this...

(NOTE: These are real addresses; but do not represent the actual monster kill counters)
Code:
0064CD18 = Fallen (Spear)
0064CD28 = Fallen (Sword)
0064CD48 = Skeleton Captain
0064CCE8 = Skeleton

Perhaps a better way would be to find out how the game is deciding which offset to write to...
HINT: Monster index table is a possibility.

On a secondary note: We can also use this address to learn more about how the game renders text! Or how the game knows when to display monster's text based on the mouse's position (think: collision detection with the mouse).

Last freebie to encourage a happy reverse engineering experience:
Code:
00433C72 | 8B 86 08 D4 64 00        | mov     eax,dword ptr ds:[esi+0x64D408]           | [esi+64D408]:"Fallen One"

Go to this expression in the memory map module for Diablo.exe in the .text segment.

Tune in next time, for another fun reverse engineering tutorial objective! Smile
Reply


Messages In This Thread
RE: [Tutorial] Reverse engineering Diablo (v1.09) - by TheKillerVortex - 01-31-2018, 04:31 AM

Forum Jump:


Users browsing this thread: 1 Guest(s)