Let’s Start Hacking Dark Souls III
It’s that time again, my friends. Time to set our sights on yet another game to modify, pervert, ruin, improve, and make beautiful. We’ve successfully corrupted the first two entries in the Dark Souls series already. So it is only natural then, that we begin the hacking and Omnification of Dark Souls III…
At the time of writing, the game currently being streamed is my Omnified Horizon Zero Dawn. Once we’ve beaten that, I will be continuing my playthrough of Omnified Dark Souls II (which was put on pause so we could play Omnified Horizon Zero Dawn, newly released on PC). Once Omnified Dark Souls II is complete, we’re going to want to finish off the series with a run through Omnified Dark Souls III.
That means we’re going to need to Omnify it first! And the sooner we Omnify it, the better; I’d like to build up a phatty library of Omnified games, so it would be neat if I could get this done prior to finishing Omnified Horizon Zero Dawn on stream. Then we could get started on the next, next game to Omnify. As to what game we will be Omnifying next…well I actually already know, but I won’t be sharing that with all of you quite yet.
This will also be the very first game whose Omnification will be documented and shared with the world here on my hackpad, with the process being described in a long-form article format. The very first Omnified games were hacked live on stream; the ones after that were hacked offline, with YouTube videos created for each step along the way.
So let’s see how this works! Let’s Omnify Dark Souls III!
Initial Goals and Finding the Player’s Health
How to begin our hacking of Dark Souls III? Like the previous games we’ve Omnified of late, we’ll begin Omnification by first doing an analysis of the various important data structures found in the game. While we do that, we’ll also locate and write some assembly code to create persistent pointers to the player data required most by our Omnified common functions:
- The player’s root structure, from which it should be easy to get to the player’s health, and…
- The player’s coordinates structure.
Omnified code specifically requires the sources of truth for both the player’s health and location coordinates. However, we should be able to locate both of these relationally (i.e. by walking down known data structures) with only the player’s root structure in hand. Typically I’ll create a pointer that points to the root structure, and then another pointer that points to the coordinates structure for the sake of convenience.
What is this root structure for the player that I mention, however? I define the root structure as the data structure from which all other data related to the player or creature being represented can be found. Many times more specific data structures will link back to the root structure. It is the easiest way to confirm or check for player identity when looking at a particular type of data structure. While I cannot speak for all games, most games I’ve disassembled feature a type of root structure for both player and non-player characters.
And what are these sources of truth I mention? Well, using the player’s health as an example: the player’s health may exist thousands of times in memory; however, only a single instance of the player’s health value will actually determine what the player’s health actually is. All other instances of the player’s health are mere reflections, or calculated values, that are used in related functionalities.
Typically, the easiest way to go about finding the player’s root structure is to first find the structure that contains the player’s health, which means we need to find the source of truth for the player’s health. Sometimes the health is in its own structure, sometimes it is in the root structure — we’ll make that call as we come across it in this game. So how do we go about finding the health in Dark Souls III?
Well, the first thing we need to do is see if the game itself tells us the numeric value for the health. In many games there is no numeric value displayed to the player, however FromSoft games are typically very kind in this regard. I believe the numeric value for the health was displayed in Dark Souls, Dark Souls II, and Sekiro (games that I’ve previously Omnified). So, let’s see if it is shown to us in Dark Souls III…
Ahh, look at that! The exact HP amounts are shown to us through the Status window in-game. Well, that makes this all a much more simplified affair then. To start off our search, all we need to do is boot up our Cheat Engine, attach it to the Dark Souls III process, and then do a search for 4 byte values equal to 483.
Now we can’t be completely sure that the player’s health is stored in a 4 byte format; indeed it is entirely possible that the health is stored as a floating point number. I’ve seen floating point used many times even when health is only displayed as a whole number. But I am reasonably sure that health is stored as either 2 or 4 bytes, and that is because FromSoft (the makers of this game, duh) is a Japanese developer.
Yes, for whatever reason, I have seen time and time again the use of 2-4 byte values for health almost 100% of the time when the developer is Japanese, and floating point almost 100% of the time when the developer is Western. And when I say “almost 100%”, I quite frankly mean: actually 100% of the time (while at the same time shielding myself from accusations of Balderdash!). It is an interesting topic truly and one that maybe I’ll dedicate an exploratory article to one day.
Anyway, if we do the above search we will probably get back tens or even hundreds of thousands of results — this is no surprise. Computer programs are complicated beasts these days, and have oodles of their own memory to use and abuse with whatever garbage they feel like generating. In order to narrow down the results a bit, we need to create a change in our player’s health value, and we do that by getting smacked around a bit, and then checking what our updated health is in the game.
As you can see above, the Status window is very conveniently displaying to us our updated health value after a few smacks from a baddie. A lot of other games don’t make it this easy, forcing us to search for “unknown values” in memory, followed by “decreased” or “increased” value searches. Anyway, in the case of Dark Souls III, all we need to do is input that updated health value of 391 into our search field and hit the Next Scan button.
Two searches and we’re already down to 9 results! That was…uncannily fast. Usually we have to do a lot more value changes and searches before getting this low of a number. Hacking (and Omnifying) Dark Souls III is turning out to be a walk in the park so far (seriously knocking on wood while I say this).
With only 9 results, we can easily figure out which one is the source of truth via process of elimination. We simply add them all to our address list, and then one by one, change the value for a particular address and see if that value is reflected in our health in the game. We know we have the source of truth when, for example, setting it to 222 causes our health to become that very value in the game.
As you can see above, we have located the source of truth for the player’s health in memory. So that’s great — however, as you may know, programs like games these days will assign data such as the various player intrinsics we deal with to dynamically allocated memory. As soon as our character dies or we reload the map, our health may indeed be in a very different spot in memory. So we need to find some existing game code that accesses our player’s health, and piggy back off that in order to create a reusable pointer that will always point to the health.
On the same note, we need to do some data structure analysis! Which means we need to do some dissecting of the data structure this health value is a member of. We can’t find the address to this data structure simply by looking at our health value — we need to see what offset is being used by existing program code to access the health value. Once we have the offset, we know then the address for the base structure, and once we have that we can make sense of what that is using Cheat Engine’s Structure dissect tool.
To figure out what offset is used to access this data, we’ll just go ahead and right click on our health in the address list and choose “Find out what accesses this address”.
Doing this will pop up a window of all the instructions currently reading from the place in memory our health is stored. We can glean all sorts of interesting information from what we see here, but what we’re primarily interested in at the moment is the offset used to access the health — hopefully everything presented to us in the window consists of accesses made using the same offset. This is not always, the case, but let’s hope for sanity’s sake that at least for the health we have some nice uniform offset usage…
Looks like the majority of these instructions are using the offset 0xD8 to access the health value. The instruction that is highlighted is the most frequently executed instruction, therefore making it ideal if we were to use it for piggy backing off of in order to set our own created pointer to the player’s health. If we want to use that instruction or any of these other instructions for this purpose, we first would want to make sure that the only address being accessed by the instruction was the health belonging to our player.
We can do that quickly by clicking on the “Show disassembler” button and then right clicking on the instruction in the Memory Viewer and choosing “Find out what addresses this instruction accesses”. If only one instruction is shown (and it helps to move around in the game, get by other creatures, etc.), then we got a great insertion point for populating our player data pointers.
However in the case of hacking Dark Souls III, all of the above functions are general purpose health polling functions, and they access the health values for all the creatures in the area. If we had to, we could devise a filtering function for a particular function (by examining the values of the various CPU registers, etc. for a pattern we can detect when the player is specifically being read), but such filtering functions can be quite brittle, and should only be something we need to do as a last resort.
Instead, we should actually try to complete our first goal here, and that’s locating and creating a pointer to our player’s root structure. To do that, however, we need to actually find said structure, and we can start that by taking a look at the structure that is housing our player’s health.
Finding the Player’s Root Structure
To take a look at the structure housing our player’s health, we need to get that structure’s address. If we take a look at the window showing instructions accessing our health value, we know that the offset used is 0xD8. If we refer specifically to the highlighted, most frequently executing instruction, that offset is being applied to the RCX register, which had the address 7FF4AE70BF20 assigned to it.
This is the address of the data structure housing the health. So all we need to do is open up the Memory Viewer (you can click on the “Memory View” button on Cheat Engine’s main window), and then click on Tools -> Dissect data/structures (or do a CTRL+D). Once we have this lovely window open, we just paste the address into the sole textbox, and then click on Structures -> Define new structure (or just do a CTRL+N).
And we have before us the data structure containing the player’s health: SprjChrDataModule, a structure I would refer to colloquially as the “character data module”. If you’re wondering where these wonderful, almost totally readable structure names are coming from, they are coming from RTTI data that Cheat Engine very recently added support for extracting in version 7.1.
The SprjChrDataModule structure is one I’ve seen while hacking a number of FromSoft games, not just Dark Souls III, including the most recent (at the time of writing), namely Sekiro. Scrolling down a bit to where the health is stored, I found the following values being stored (note that the specific member name itself is not pre-populated, I had to tweak the values and fill that in myself):
- D8: Current Health
- E0: Maximum Health
- E4: Current Focus Points
- EC: Maximum Focus Points
- F0: Current Stamina
- F8: Maximum Stamina
So this ‘character data module’, like similarly appearing structures in other FromSoft games, appears to hold all the character’s vitals. But the most interesting bit of data being held (or pointed to rather, in this case) in this structure is near the top, at the offset 0x8: a pointer to a PlayerIns structure. This is indeed, our root structure. This is the name of the root structure type for the player in a number of FromSoft games, although in Dark Souls II it was PlayerCtrl instead, I believe. The root structure for non-players in many (but not all) of the FromSoft games I’ve hacked, was EnemyIns (though in some games, this was only used for non-humanoid non-player characters).
It is my thought that the “Ins” in “PlayerIns” stands for “Instance”, and that’s indeed what one should conclude this structure describes when examining its contents; it is description of everything that has to do with a particular player or creature instance. If a subordinate structure links back to a root structure, many times the pointer will appear near the beginning of the structure, and in this case it appears at offset 0x8.
Now that we have our player’s root structure, we should try to find some code accessing it to inject into so we can create a reusable and reliable pointer of our own that will point to it. Having a pointer that goes directly to the player’s root structure will make hacking Dark Souls III much easier. To do that we should expand the Pointer entry found at offset 0x8 and then right click on the very first entry in the PlayerIns structure at offset 0x0, which is the base address of the root structure. We then should add that base address to our address list so we can do some further operations with it.
Once we have the beginning of our player’s root structure in our address list, all we need to do is right click on it there and choose “Find out what accesses this address”, much like we did with our player’s health.
Trying to find code that is accessing the player’s root structure directly like this is a bit of a gamble, but that’s what reverse engineering is really: rolling the dice a bit and seeing what sticks. If we’re unlucky we won’t get any hits here; on the flip-side, we may get way too many hits…
Well that is a very large number of instructions that seem to be polling our player’s root structure. Let’s not be scared away by the sheer vastness of this opcode ocean, however. We want to see if any of these instructions are good; in other words, we want to see if any of these instructions access the player’s (and only the player’s) root structure. Let’s highlight the first instruction listed and hit the “Show disassembler” button.
This will pop open the Memory Viewer, showing the highlighted disassembled instruction as well as all the instructions surrounding it. We want to then right click on the instruction in question and see if it is polling anything else by clicking “Find out what addresses this instruction accesses”.
As you might have noticed, the instruction we’re looking at isn’t even accessing the root structure with an offset! I guess that makes sense, since it is a root structure after all, but it could also easily mean that this is some generic, all-purpose memory reading function, and we might get blasted with an ungodly amount of different addresses of differing types being read…
Oh my, it is just accessing our player’s root structure! Is it too good to be true!?!? Quick, we must move our character around a bit in the game, interact with other creatures, etc. Have more addresses been added? No! We found it! The Holy Insertion Point of Antioch! We have located the place where we will inject some code into, in order to create our own root structure pointer for the player.
Hacking Dark Souls III with Root Structure Pointer Creation via Injection
Now the fun part. Nothing will aid in the study of Dark Souls III’s data structures as well as the Omnification of Dark Souls III more than a reliable self-populating root structure pointer for the player. We will achieve the creation of this pointer via injection, specifically by injecting into the bit of code discovered in the previous section.
With the instruction highlighted, we can open the “Auto Assemble” window by doing a CTRL+A, and then we can get the starting basis of our injection by doing Template -> Full Injection. I’ve taken this starting template and produced the following injection code, which will create a player pointer pointing to our player’s root structure.
Player Root Structure Hook
// Gets the player's root struct. // rcx: Address of player's root struct. define(omniPlayerHook, "DarkSoulsIII.exe" + C1A78C) assert(omniPlayerHook, 48 8B 01 FF 90 C0 02 00 00) alloc(getPlayer,$1000,omniPlayerHook) alloc(player,8) registersymbol(omniPlayerHook) registersymbol(player) getPlayer: push rbx mov rbx,player mov [rbx],rcx pop rbx getPlayerOriginalCode: mov rax,[rcx] call qword ptr [rax+000002C0] jmp getPlayerReturn omniPlayerHook: jmp getPlayer nop 4 getPlayerReturn:
Fairly simple hook. The address to our root structure is stored on the RCX register, so we simply load a pointer we’ve allocated (and assigned to the symbol player) and have it point to value written to RCX. We load the address of player onto the RBX register before having it point to RCX in case jump distances between where player is allocated and the address found on RCX are greater than 2GB. The cleanup code is not provided, and will not be provided in examples on my hackpad as it is almost always of the boilerplate variety (unregister all registered symbols, deallocate all allocated memory, etc.).
After assigning this hook to our cheat table (File -> Assign to current cheat table), we can execute it by checking the script’s checkbox, and lo and behold: we have a usable pointer to our player’s root structure. Let’s make use of it now by opening a “Structure dissect” window and loading a PlayerIns structure with the address resolved by [player].
Now we can easily check out and explore what makes up the PlayerIns structure with our pointer “player“, which will always be pointing to a valid root structure for our player. As you can see, even right at the beginning, there are a number of interesting subordinate data structures which may yield promising results through their understanding of and manipulation.
But I’m not going to cover everything one might run into when hacking Dark Souls III! I’m going to focus on the most important points of focus that we may run into when implementing the Omnified systems. For all additional data structures that require disassembly prior to implementation of said systems, I will cover those data structures in the particular article for that specific system.
To see where the player’s various stats are stored, such as their Strength, Dexterity, and Souls, you need to scroll all the way down to offset 0x1FA0, where you will run into the player’s PlayerGameData structure.
The PlayerIns structure is really quite large. There is a large sea of practically nothing between the first few data structures and PlayerGameData in PlayerIns. But here I am to save you from getting sore fingers from excessive scrolling of your mouse wheel — just drag that scrollbar down until you get to 1FA0.
If you expand the PlayerGameData node you may quickly see it contains some of the most important stats for the player. I’ve played around with some of the values and have mapped a number of the more notable fields out (remember, the structure value members aren’t automatically filled out with a label, you need to do this yourself).
The next and by far most important part of the PlayerIns structure can be found starting at the very distant offset of 0x23C0. This is where we can find a glut of various “character modules”, each of which is responsible for controlling a distinct aspect of our player.
Almost every FromSoft game I’ve disassembled so far has featured a large glob various character modules typically buried very deep into a player or character instance structure. Sometimes they’re pointed to by a “module collection” pointer, and sometimes they’re directly on the instance structure itself, as is the case here.
Just looking at their names, there sure seems to be a lot of juicy goodies here, however, there is one module we care in particular about; one module we will need, at the outset, in order for the Omnification and hacking of Dark Souls III to be successful: the SprjChrPhysicsModule located at offset 0x2428.
The SprjChrPhsyicsModule is consumed by the various Havok physics functions that Dark Souls III makes use of, and it contains the source of truth for a number of things, but most importantly: the player’s coordinates. We have shown, therefore, that if we have the player’s root structure, we can locate the source coordinates addresses in memory. This allows us to avoid a separate code injection solely purposed for the retrieval of the player’s coordinates (something that experience has shown me can very easily break and cause false positives and mismatches).
For convenience’s sake, it’s quite handy to actually have a separate pointer that points directly to the coordinate structure. There are a number of Omnified system initiation points where we will be making use of both, and not having to deal with having to dereference n levels deep into PlayerIns saves us a lot of annoying assembly code. So let’s update our original hook so that we also create a pointer to our player’s coordinates.
Player Root and Coordinates Structures Hook
// Gets the player's root, coordinates, and health structs. // rcx: Address of player's root struct. define(omniPlayerHook, "DarkSoulsIII.exe" + C1A78C) assert(omniPlayerHook, 48 8B 01 FF 90 C0 02 00 00) alloc(getPlayer,$1000,omniPlayerHook) alloc(player,8) alloc(playerCoords,8) registersymbol(omniPlayerHook) registersymbol(player) registersymbol(playerCoords) getPlayer: push rbx push rdx mov rbx,player mov [rbx],rcx mov rdx,[rcx+0x2428] mov rbx,playerCoords mov [rbx],rdx pop rdx pop rbx getPlayerOriginalCode: mov rax,[rcx] call qword ptr [rax+000002C0] jmp getPlayerReturn omniPlayerHook: jmp getPlayer nop 4 getPlayerReturn:
This hook is much like the first one, except we also do a bit of crawling down the PlayerIns structure to the physics module, and then have another allocated symbol (playerCoords) point to that structure as well. If we save the changes and run this script, we can quickly see that we now have a reliable and persistent pointer to the player’s coordinates which allows for easy reading and manipulation.
And this gives us a solid foundation of some of the requisite data we’ll need to initiate the various Omnified systems we’ll be plugging into the game. But, how would you, the reader, know that I’m not just pulling all of this out of my ass! FINE! I’ll show you…let’s add a large number to our player’s Y coordinate value.
Well, unfortunately, your lack of faith led me to throw the character high up into the air, and they are now falling to their death, as pictured above. Don’t let this weigh too heavily on your conscience, however, as we now have everything we need to start implementing those horrifying Omnified systems and really make this game twisted.
Implementation of the first of my Omnified systems, the Apocalypse system, will be covered in the next article in my series of the Omnifying and hacking of Dark Souls III! So stay tuned for that! If you enjoyed reading this, or have any questions, feel free to leave a comment.
If you want to catch live gameplay of this stuff, the only place you can do this is by following and watching my official Twitch stream at https://twitch.tv/omni! Thank you for your interest, and always keep it real friends.
-Omni