The Hacking of Dragon’s Dogma Begins
Time to make yet another game Omnified. This time we’ll be hacking my Omnified systems into that little gem of a game known as Dragon’s Dogma. This, rather strange, little game has always occupied a warm place in my heart. Like many other games, one issue I’ve had with the game is that it isn’t brutal enough! We’re going to get to work on fixing that particular issue right now.
In comparison to the last few games I’ve Omnified (basically the entire FromSoftware collection), I suspect we’ll have an easier time Omnifying some parts of this game, and maybe a bit of a harder time Omnifying other parts. The engine used by Dragon’s Dogma is the MT Framework, which is used by a number of CAPCOM games, most importantly Monster Hunter World. That game had built-in scaling support for characters (something I’ve not had in a game for a while now), which will greatly simplify Abomnification implementation.
We won’t be implementing that lovely character-morphing system until near the end of the Omnification of Dragon’s Dogma. Right now we need to get busy with the basics! That means we need to take a cursory look at important data structures and grab the necessities required by everything Omnified related.
Getting Busy With the Basics: Finding the Player’s Health
The data structure containing the player’s health is required by a number of Omnified systems, in particular the Apocalypse system. It’s also a nice way to find the root structure for the player. As always, the health address in memory we find must be the source of truth for the player’s health; that is, the health address we end up using needs to be the sole instance in memory that actually determines what the health for the player actually is (there can exist many, many temporary working values for the health in memory in addition to this).
How we find the health depends on whether the game displays the numeric value for the health to the player. Looking at the game, we can easily see that, thankfully, this value is indeed provided to us:
Sweet. We know that our health, at its maximum, is 450. This allows us to avoid having to search for unknown values; we can go ahead and just start off a search with Cheat Engine for a specific value. What about the data type though? Well, it’s been my experience that Japanese developers use integer (4 byte) values to store health. Every Japanese game I’ve Omnified has done this.
Not in this game though. Big surprise there (I’m serious, every Japanese made game I’ve hacked has stored health values as integers). I did a search for the health assuming it was 4 bytes and ended up with squat. So let’s assume I did the smart thing right from the get go and did the search the way you really should, by using a Value Type of All.
Be advised, the default settings that define what All encompasses needs to be tweaked! Check out Edit -> Scan Settings -> The all type includes, and make sure we include Float and Double. Now, let’s start the search for our health:
This gave us 29,701 results. Not bad! Let’s go get whacked a bit by enemies and then do another Exact Value search using the updated health value. Hopefully we can tank a few hits.
After I got hit by some goblins, or whatever those things are, we do the next search:
Well that was quick. Already narrowed it down to two results! And yes, as you can see, these are floating point types. We now figure out which health value is the real one by adding them to our address list and then seeing which one, when changed, causes the health to update in the game to the new value.
Except that when we try the above…we find that neither of the returned results update the health in the game. Whoops. That means something strange is going on here. Perhaps there is a rounding issue at hand. We hit the Undo Scan button to revert to the previous set of results, and then do a search across a range of values instead:
Here we see much more values that are approximately equal to our updated health value of 319. When searching for floats, Cheat Engine doesn’t require the results to exactly match the queried value — it will also include results that are close to that value. I’m not aware of the exact rules Cheat Engine follows, but I assume that it rounds the results to the nearest number before checking for equivalency with the specified value.
As we can see in the image, we see the number 319.5651855 pop up many times in the results. Normally we would round this number to 320, however the game must round down the internal health value before displaying it to the user. This is odd behavior for sure.
Let’s now figure out again which one is the source of truth by changing the value of each one and seeing which one updates the health in the game. This time, we are successful in finding the source of truth. Yay! Let’s now take a look at the data structure the health value resides in by first looking at some of the code accessing it. We right click on the health value and choose Find out what accesses this address, and the following window appears:
Looking at the instructions accessing the health, we can see the offset used to access it is 0x8. Looking at the first instruction, we can also see that the address of the struct containing the health value is in the eax register, with the address being 0x10C666AF0. Let’s take that address and plug it into a “Structure dissect” window so we can get an idea of what the health data structure looks like.
We load the address into the “Structure dissect” window. Then, when we attempt to define the structure, we see that the initial, suggested name, for the structure is “unnamed structure”. This indicates that there is no RTTI provided with this game. This shouldn’t be unexpected I suppose, and it will make some things a bit more difficult in figuring out, but I believe we’ll survive.
Shown above you can see what the struct containing our health looks like. I defined a few of the fields, namely the Current Health (at offset 0x8) and Maximum Health (at offset 0xC) fields. This maximum health value, however, is not the source of truth for the maximum health! It is read-only and has no effect on your character’s maximum health. This is strange.
As of now it is unknown to me what any of the other values are in the structure. Perhaps one of them leads to a root structure.
Due to the lack of RTTI information, it is going to be rather difficult to identify any sort of root structure from what we have. We are going to have to first find some other bits of important player data and then see if there are any common structures being pointed to from both of them. Given the difficulty of the exercise I’ll probably only really try to chart it out if I really need to.
Since I’m going to, at least for now, operate under the assumption that I’m not going to be finding the root structure, we will need to create a separate code injection for every player data structure type we’re interested in. So this means we can and should write up a player health hook right now! We were just looking at the instructions that accessed our health value, so we’ll just need to choose the right one for hooking into.
Going through that list of instructions, starting at the one with the most calls to it, we open up the code in the disassembler, right click the code in question, and select Find out what addresses this instruction accesses. We want to find something that ideally only accesses the player’s health, and nothing else.
A few of the methods access the health of everything on the map, and the majority of the rest seemed to access both the player’s and the health of the “pawn”. Eventually, we come across the instruction at DDDA.exe+332605, and it seems to only access the player’s health. So let’s hook into there baby!
Player Health Structure Pointer Creation via Injection
Having a root structure is great, but it isn’t required to make this thing Omnified. Given the lack of RTTI, the cost vs reward just isn’t worth it. That’s fine! It gives us some variety in how we go about Omnifying these things. We’ll be making separate hooks per data structure for now, and we’ll start with the grabbing the player’s health struct.
Since we spent some time finding a good place to inject into (somewhere where no filtering, etc. is required), this will be a very easy hook to write; in fact, here it is:
Player Health Structure Hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // Gets the player's health struct. // eax: Address of player's health struct. define (omniPlayerHealthHook, "DDDA.exe" + 332605) assert (omniPlayerHealthHook, F3 0F 10 40 08) alloc (getPlayerHealth,$1000, omniPlayerHealthHook) alloc (playerHealth,8) registersymbol (omniPlayerHealthHook) registersymbol (playerHealth) getPlayerHealth: pushf mov [playerHealth], eax getPlayerHealthOriginalCode: popf movss xmm0 ,[ eax +08] jmp getPlayerHealthReturn omniPlayerHealthHook: jmp getPlayerHealth getPlayerHealthReturn: |
Very simple, we’re just taking that health struct address stored in the eax register and throwing it in our playerHealth struct. This game is actually 32-bit so we don’t have to follow the typical precautions we have to when hacking 64-bit games, such as when we might deal with memory spaced apart more than 2 gigabytes.
The health structure is one of the big requirements for some Omnified systems, so we can mark that requirement as done. The next piece of data we’re going to be interested in is the location structure for the player, which will be a bit of a painful affair given the complete lack of relationships established between data types…but we’ll be OK!
Time to Find the Player Coordinates
Now that health has been taken care of, time to move to the real deal: the location structure for our player, which will contain our player’s coordinates. It is my hope that it will also contain our scaling parameters. I’m really hoping that this game will be the first game in awhile that has built in easy scaling support. This will make Abomnification implementation so much easier.
We don’t have a root structure to work from, so we need to find the coordinates the old fashioned way. We do this by manipulating the Y-coordinate of the character, which is (I’m guessing! It actually depends on the game…) the vertical axis for the character. It’s the easiest of the coordinates to isolate from the other ones.
So, to start off our quest to find the player’s coordinates we first must find…a rock!
We have found what we need! We will use this holy rock to effectuate changes to our Y-coordinate. We do this like so:
We will create changes to our Y-coordinate by repeatedly jumping on and off the rock and searching for increasing/decreasing changes for unknown initial valued floats as appropriate. So we start the search by selecting Float for the Value Type and Unknown initial value for the Scan Type, and then we will choose Increased Value after jumping up on the rock, and then Decreased Value after jumping off.
We will repeat the above many times, until we get down to a reasonable number. After quite a bit of jumping, I got the following:
I did some additional filtering, such as restricting the results to a range of reasonable values. That said, we’re still left with 854 possible results. We will narrow this list down by adding them all to the address list, highlighting half of them, pressing spacebar to freeze the value, and then jumping in the game.
If the player is unable to jump up correctly, that means that the source of truth for the Y-coordinate was frozen. We delete the entries in the address list that weren’t frozen, and then repeat with half of the remaining ones. If the player is able to jump up while we have some values frozen, that means that these values are bunk and we toss those away instead.
We repeat this, reducing the results by one half each time, until we get to our source of truth. For me, the address for the Y-coordinate was at 10DF50C4. Excellent. Let’s now repeat what we did for the health and check out the coordinate’s data structure using the same process to get struct info into the “Dissect structure” window.
After doing that, I played around with some values and named a few of the fields, giving us this:
There’s our location struct. Got our coordinates. Know what else we got? Scale parameters. Indeed, finally a game with built-in easy scaling support. This will make the Omnification process just loads easier. The custom scaling code required by the Abomnification system is by far the most complicated piece of hooking we need to do typically. I’m sure we’ll run into an equally awful gotcha in its place however (just kidding, knock on wood…).
Player Location Structure Pointer Creation via Injection
Let’s write a hook for the coordinates then. We first are going to see what instructions are reading the X-coordinate, and try to find one just accessing the player’s coordinates.
Taking the most frequently executed instruction that accesses our coordinates located at DDDA.exe+4D316A, I observed that it was only accessing our own player’s coordinates. Great! Your standard player coordinates polling function. Because there is no filtering required, this too will be a very simple hook, but still a very important one! Let’s write it.
Player Location Structure Hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // Gets the player's location structure. // eax: Address of the player's location struct. define (omniPlayerLocationHook, "DDDA.exe" + 4D316A) assert (omniPlayerLocationHook, F3 0F 10 40 40) alloc (getPlayerLocation,$1000, omniPlayerLocationHook) alloc (playerLocation,8) registersymbol (omniPlayerLocationHook) registersymbol (playerLocation) getPlayerLocation: mov [playerLocation], eax getPlayerLocationOriginalCode: movss xmm0 ,[ eax +40] jmp getPlayerLocationReturn omniPlayerLocationHook: jmp getPlayerLocation getPlayerLocationReturn: |
Another very simple hook. After adding that code, we apply the hack, hope that the game doesn’t crash, and add some entries in the table to display our coordinates. Luckily there was no crash, and we now have a table looking like this:
At the time of writing, I’ve also found another solution that is just as viable, if not a bit more. After exploring the data structures we’ve mapped already, I found that the location structure for the player can be found at [playerHealth+1B4]. If we want to instead remove the hook we just wrote and tie the creation of the player location pointer in with the player health, we can update our player health hook to look like the following:
Player Health and Location Structure Hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | // Gets requisite player information. // eax: Address of player's health struct. define (omniPlayerHook, "DDDA.exe" + 332605) assert (omniPlayerHook, F3 0F 10 40 08) alloc (getPlayer,$1000, omniPlayerHook) alloc (playerHealth,8) alloc (playerLocation,8) registersymbol (omniPlayerHook) registersymbol (playerHealth) registersymbol (playerLocation) getPlayer: pushf push ebx mov [playerHealth], eax // The health structure itself points to the the location structure // at 0x1B4. mov ebx ,[ eax +1B4] mov [playerLocation], ebx pop ebx getPlayerOriginalCode: popf movss xmm0 ,[ eax +08] jmp getPlayerReturn omniPlayerHook: jmp getPlayer getPlayerReturn: |
This is actually everything we need at this stage for the main Omnified systems to be implemented. Despite this, I’d like to get to know the game a little more, and see if we can figure out any of the common data structures that unify all these disparate bits of data. The health structure did not appear to have anything related to the character’s stamina in it, so let’s find that next!
Let’s Go Get That Stamina
The numeric value for the player’s stamina is not displayed on the main game screen, unlike the health, but we can see the numeric value of our stamina at its max if we pause the game and go into Status.
So we’ll be able to start off our search by doing an Exact Value type search using 540 as the value (with the player’s stamina bar filled up of course), but we’ll need to do successive Decreased Value and Increased Value type searches in order to track changes. Regardless of this, this should be a very easy value to find.
After doing this basic type of search described above, I got the results down to this cast of suspects:
Just a tiny list of 9 results that we need to weed down, using the same old tactic of changing their value and seeing what causes an update in the game. We could also just freeze the value by checking its box and seeing if stamina no longer changes value in the game.
After doing that I located the stamina at address 0x0E388198. Let’s see what the struct it belongs to looks like by right clicking and clicking Find out what accesses this address. We then look at the base address in the register used when loading the stamina by an instruction in the resulting window from the previous action.
The stamina value itself is pretty deep inside this structure at the offset 0x2A8. There really seems to be nothing of substance at the beginning of the struct either. Most interestingly, we see the current and maximum health values for the player in this struct as well. This time, the current health value is read-only (as it should be, there is only one source of truth), but the maximum health here in this struct is the source of truth. Very odd.
Player Stamina Structure Pointer Creation via Injection
We might as well write a hook that’ll inject a pointer for our stamina into the code as well. Looking at some of the instructions reading the stamina, it does appear (surprisingly I suppose) that not only the player has stamina, but other creatures do as well! So we’ll have to go through each one until we hopefully find an instruction that just returns the player’s stamina.
Luckily for us, the very last of the instructions returned, located at DDDA.exe+332654, only accesses the player’s stamina. So let’s write up a quick, very simple hook for it.
Player Stamina Structure Hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // Gets the player's stamina struct. // edi: Contains the player's stamina struct. define (omniPlayerStaminaHook, "DDDA.exe" + 332654) assert (omniPlayerStaminaHook, F3 0F 10 8F A8 02 00 00) alloc (getPlayerStamina,$1000, omniPlayerStaminaHook) alloc (playerStamina,8) registersymbol (omniPlayerStaminaHook) registersymbol (playerStamina) getPlayerStamina: mov [playerStamina], edi getPlayerStaminaOriginalCode: movss xmm1 ,[ edi +000002A8] jmp getPlayerStaminaReturn omniPlayerStaminaHook: jmp getPlayerStamina nop 3 getPlayerStaminaReturn: |
Once again, a very simple hook indeed. Well, now we have the player’s health, location, and stamina all being tracked and accessible from the other bits of code we’ll be writing in the future. This is really all we need for now, so we can wrap up this cursory look into Dragon Dogma’s data structures and player data.
Dragon’s Dogma Has Strange Data Organization
There’s a lot of strange things going on internally with Dragon’s Dogma. I’ve never personally been involved with the act of console porting, but I have to wonder if this strangeness is not an artifact of that process. Not incredibly familiar with the PS3 console either, but I do believe it is running on something that is pretty different than your typical x86 architecture.
So what kind of strange “things” have we ran into during this initial look into Dragon’s Dogma? Here are a few of them:
- If there’s a unifying root structure for each entity in the game, I didn’t stumble on it. I was able to find links to location data structures from the health data structure, but that’s it. A much deeper look would be required, but it really shouldn’t be that difficult.
- The health for creatures is stored as a float, which is not normal for Japanese developers. On top of that, it appears that the float is always rounded down prior to displaying it to the user, which is also not normal. We’ll have to see if it is rounded down when it is evaluating game mechanics such as “is creature dead”.
- The health and stamina values are not in the same data structure. This is not entirely unorthodox, but more often than not they will be in the same one. What is truly strange is that the maximum health in the health structure is read-only; the true maximum health is in the stamina structure (which has a read-only health value). That just comes off as…random sloppy data organization.
Anyways, nothing is crazy enough here that it will prevent us in Omnifying the game. There’s a bunch of good things going for us, in particular the availability of easy scaling parameters! Abomnification will be a breeze.
We’ll be implementing the Apocalypse system next and getting the damage crazy in this game. This will really make the game hard since the ability to dodge isn’t always available.
Thanks for your interest! Make sure to catch my live streams of my Omnified content at https://twitch.tv/omni, and say hello on my Discord at https://discord.gg/omni. Take care everybody.
~Omni