Greetings everyone! It’s that time again: time to Omnify a new game. And we definitely have a doozy this time around.
Nioh 2, a game already regarded as very difficult, and one I’ve actually never played before. Omnifying something like is going to yield quite the potent brew of death-filled gameplay. No complaints here, however, as I’ll take on anything else after having to deal with the inane complexities of Cyberpunk 2077.
I expect a much more soberly designed binary to hack this time around. Sober design will hopefully lead to a quick Omnification, which means all the more time I get to spend working on brand new Omnified technology! Let’s get that Omnified ball rolling then by doing some reverse engineering and analysis of those oh-so-important player character data points.
Integers for Health? This Was Made in Japan, Yes?
I won’t lie: I love it when ye olde doubleword integers are used to store creature health values. Why? Well, no reason in particular, other than the fact that Cyberpunk 2077 used floats, and anything diametrically opposite from everything that game did can only be a good thing right!?
Well, luckily for us then, that Nioh 2 is a product of that lovely land of Japan; and, as I’ve stated time and time again: if it was made in Japan, then we’re very likely going to see health being stored as an integer as opposed to floating-point.
I actually don’t really have much of a preference on the matter, but it is good to know what to look for! So, for the health: where do we start? Well, I can see our health being displayed on the HUD in classic bar form…
Alrighty then. Can we get some numbers to help us out here? Never played this game before…and there are quite a few menus to look through. This Status menu looks promising, however!
We got some hard numbers! We can start then by doing a search for 4-byte integer values matching the health values shown above.
Two minutes pass…
I was actually quite surprised how quickly and easily I found the source-of-truth health values for the player! I simply rested at a shrine, searched for my health (which would’ve been at 920), and then made use of the free level you are given at the beginning of the game (with which I increased my total possible health).
Continuing my search using this new health value, I was left with only 5 results! That’s a very tight number. All we do from there is modify each one until we find the one that actually changes our health in the game.
Nice, we have it. Let’s find a place to hook into and create a pointer to our player’s health data structure.
There are a few instructions we can see here reading our health. We can expect that some of these are reading the health of other (non-player) creatures, as well as other vital stats belonging to the player.
We want to find one that is only reading health and only for the player, if such code exists. This is simple to do, we just load the disassembler for each one and go ahead with a Find out what addresses this instruction accesses operation!
The first instruction on the list seems to serve our purposes, as it appears to only be polling for our health:
So, we can hook in here, and we won’t have to worry about filtering out any other stats belonging to the player or any other entity, which is the best kind of hook (because “magical filters” can be fragile).
After finding the health and a good place to hook into it, I took a peek at the player’s health structure, and filled out a few of the fields whose purpose I could figure out.
So, as you can see above, not long after finding our current health value, I managed to find our maximum health value. This is very important for Vision, which, of course, needs to display both of these values to those oh-so-interested viewers of mine.
I did end up writing a simple hook upon discovery of a good place to put one, but I’m going to hold off on sharing it with you for a bit until we look over some of the other player’s stats, as I discovered a way to consolidate all relevant parts. More on that in a bit.
Ki! Ki! Or Stamina! Basically Stamina. But Not.
Now that we have the health squared away, let’s next look at the player’s stamina, or Ki as it is called in this game. Although it is called something other than stamina, it functions (from what I can gather) seemingly identical to how stamina functions. You take a short jog, or attack something, and it goes down. You wait a bit, and it goes up. Stamina.
Of course, the terminology becomes further confused given how there is actually a character stat in this game called “Stamina”:
The terminology for Ki is important to us because of the statistics module for Vision, which is responsible for displaying hacked Omnified game statistics. These statistics are composed of framework-defined and target-defined statistics; the former meant to be statistics universal to all games, and the latter for statistics specific to a particular Omnified target.
Well, stamina is framework-defined statistic, as most games have some kind of stamina involved with the gameplay. Being framework-defined, its name is kind of set in stone. So, on streams you will see Ki displayed as Stamina, and you’ll have to deal with it OK!
And that is the only reason (being to be able to display the Ki on Vision) why we’re going to figure out where the player’s Ki is stored and how to hook into it. It isn’t required for any of our Omnified systems to work, although we can definitely always change that!
In order to find the Ki source-of-truth, I basically went about it much the same way I did in order to find the health, although I didn’t have any more free levels to use. I just looked at the Status menu, did an Exact Value search for however much Ki I had, and then tried to do a mix of Decreased and Increased Value searches corresponding to the Ki getting drained through my actions followed by the Ki recovering via its natural regeneration.
Except…I ended up getting no results! That’s because, unlike health, Ki ended up not being stored as a 4-byte integer, but rather as a floating-point!
Which I suppose makes sense; more fine-grained calculations seem to be involved with Ki in this game, as it is a much more complicated stat in general in comparison to health (due to all the complicated mechanics such as Ki recovery, Ki Pulse, etc.). So, I have no issue with this.
Moving on, once the Ki’s source-of-truth is found, we can go about figuring out where to hook into in order to create our Ki (or stamina) pointer. Let’s see what’s accessing it…
Alright. We got a bunch of your standard floating-point type of operations going on here. We now want to do the very same thing that we did for the health: find an instruction, if one exists, that is accessing only our Ki, and only our player’s Ki.
As luck would have it, it would appear the instruction highlighted in the above image was polling exclusively for the player’s Ki:
Excellent. Once again, this is when I would share with all you lovely people the code for the hook written to create a pointer to the player’s Ki; however, I’m going to again hold off on that until later. And this is for reasons I shall get to later as well. Insert smiley face (you can’t actually do a smiley face in a serious article can you?).
Where Is My Mind? And Location Coordinates?
Let’s move on the last of the holy trifecta of important player statistics: the player’s location coordinates. I probably found the player’s coordinates faster in this game than any other! I’m getting good.
Let me share with you how.
I first did what I usually do: a new search with Cheat Engine, one whose scan type was Unknown initial value and value type was, of course, Float. I then began to vary my character’s position on the vertical axis (the easiest axis to isolate) by moving up a little hill, doing Increased value, going down the hill, and then doing Decreased value.
A bunch of times.
Eventually, I got the list of possible coordinate results down to the decent amount of around 40,000. This was pretty much the most I could reduce the list of results using the above method. Everything we had left more than likely had something to do with our player’s vertical coordinate value; however, most of these values were useless to us, as all we are ever interested in is the source-of-truth value.
One way I could cut the number of results down to an even smaller number was to figure out the possible range of values our player’s vertical coordinate might be. This would then leave me with values that I could sift through using a rough “binary search” until I found the value that actually determined where my character was (vertically) in the game.
So, to figure out the possible range of values the vertical coordinate might be, I had the idea to poke around our player’s health structure a bit. In the many games I’ve hacked at this point, I would encounter values close or identical to the player’s location coordinates in a wide variety of different places in memory. Nioh 2 was no different, as I found what looked very much to be like player coordinate values not too far away from the player’s current health value.
These of course were not the source-of-truth values for the player’s location, but they gave me a good range of values I could use to filter out some bad results from my previously described search. After doing that, I literally found the coordinates almost immediately after (using the commonly employed “binary search” technique of changing half of the results’ values at a time and seeing what makes me move)!
Definitely the fastest I’ve ever found them. Now, for the hook, let’s see what code is accessing our coordinates:
We got quite an assortment to choose from. This gets really tricky, really fast. It turns out that many of the well-functioning instructions shown above may not actually be running in all possible gameplay situations (for example, the code I first hooked into in the first level for the game would not execute when I was in tutorial areas).
So, instead of wasting any more time writing about all the various hooks I ended up trying in order to reliably find the player’s location coordinates in memory, let’s move on to the real solution to everything player data related.
A Unified Root Player Data Structure
Up through even the first few streams of Omnified Nioh 2, I had individual hooks for the player’s health, Ki, and location. That was all fine and dandy, but then I realized one day that the “health structure” was not actually a structure for just the player’s health, but more of a root for all the player’s data.
If you take a look back at the image I posted of the player’s health structure, you may notice several floating-point values starting at 0x48
. These are actually the source-of-truth Ki values for the player! It took me a bit to realize this, as the code accessing the player’s Ki was doing so using an offset of 0x8
.
Not only that, but I also eventually realized that the “health” (which we’ll now refer to as the root) structure also contained a pointer to the player’s location structure! Unbelievably convenient.
That means all we need to do is write a single hook to capture all (well, most) of the player-related data we’ll need in order to consume the major Omnified systems. I originally had the hook inserted into the same place where I was grabbing the player’s health, however it turned out this code was not executing reliably in all situations (for example, in the title screen where you can see the character, and also after killing a Yokai, which is odd).
Finding a Better Root Structure Hook
To find a better place to hook into, I kept a list of the instructions known to be reading our health open and then went through each one while I was in the title screen, until coming to a few that were still executing. So, now we had a few hooks to choose from that have been shown to be executing in both the title screen and the normal game.
Sadly, however, these ones actually required some filtering, as they were polling for more than just the player’s health. Fortunately, a filter was discovered on stream after some plodding around, and it is achieved by examining the structure containing the root structure, found by looking at rax
. If it is the player’s root structure we are looking at, then the base of the root containing structure will be set to 0x64
.
We will be inserting our hook at this new location, and we will be creating several pointers within it: one pointer for each type of data.
One more note, however, before we get into the code (although I do believe I have it documented in the code itself). The particular alignment of the root structure, which is a term I use to describe where the base address of a structure resides, when it is being read by the game, is not ideal.
Most of the operations in the game that read health from the player’s root structure have said structure aligned so that an offset of 0x20
yields the current health value. Interestingly enough, however, the operations in the game that write to the player’s health have the same structure aligned so that the current health value is instead found at an offset of 0x10
.
This means I’d have to shift the alignment of the root structure by 0x10
bytes every time I wanted to do an identity check of the entity whose data was being written to. This is kind of a pain, so I decided to do the realignment at a single place: our hook where we’ll be creating the pointer.
With that said, let’s take a look at the code that will grab all the player-related data we’ll need in order to make the game Omnified (more or less).
Player Root Structure Hook
// Creates pointers to multiple structures containing important player data. // Filtering is achieved by looking at the root containing structure pointed // at by rax. // If it is the player, the base of this structure will be set to 0x64. // We adjust the health structure's address by +0x10 bytes here as the game, // while accessing current health values using an 0x20 offset, will write to // it using a 0x10 offset. // [rcx+20] | {[player]+10}: Current health. // [rcx+18] | {[player]+8}: Maximum health. // [rcx+48] | {[player]+38}: Current stamina. // [rcx+4C] | {[player]+3C}: Maximum stamina. // [rcx+B8] | {[player]+A8}: Location structure. // [rcx+14C] | {[player]+13C}: Identifier for entity type. // UNIQUE AOB: 41 8B C6 48 3B 41 20 define(omniPlayerHook,"nioh2.exe"+807269) assert(omniPlayerHook,41 8B C6 48 3B 41 20) alloc(getPlayer,$1000,omniPlayerHook) alloc(player,8) alloc(playerLocation,8) registersymbol(playerLocation) registersymbol(player) registersymbol(omniPlayerHook) getPlayer: pushf cmp [rax],64 jne getPlayerOriginalCode push rax mov rax,rcx add rax,0x10 mov [player],rax mov rax,[rcx+B8] mov [playerLocation],rax pop rax getPlayerOriginalCode: popf mov eax,r14d cmp rax,[rcx+20] jmp getPlayerReturn omniPlayerHook: jmp getPlayer nop 2 getPlayerReturn:
Man, that’s nice and neat! I can tell already that hacking Nioh 2 will be extremely pleasant in comparison to Cyberpunk 2077.
Let the Omnification Begin…
Please remember that code posted in articles can very often end up outdated and no longer reflective of the current product. You can always find the latest version of the source code by checking out the Bad Echo technologies repository, with the Nioh 2 target files residing here.
For our next article, we’ll be discussing the implementation of the Apocalypse system into Nioh 2. Thanks for your interest, and please remember to follow the stream and say hello sometime if you think what I do has any value to you at all!