So to gain more experience with reversing, I am currently trying to write an external hack for a video game called Borderlands 2. I've been using cheat engine to scan for addresses of instructions that modify values such as ammo and health. I found an instruction that seems to be used for loss of health, and total ammo for all entities in the game. (i.e filling it with NOPs doesn't help me, because it puts me, as well as all of the enemies in godmode and gives everything inf. ammo). My goal is to have one command put me in god mode and a different one to give me inf. ammo and not affect any of the other creatures. Does anyone know how I can NOP this shared instruction only for my health when I use a godmode command and only for my ammo when I use an inf. ammo command? I imagine I need to somehow figure out if the instruction is being used to update my player values (probably by comparing some other offset from the base address to the enemy values at that offset), but I also need to figure out how to determine if the instruction is trying to modify my health or ammo so that I can NOP it only when it is modifying the one corresponding to whichever command I currently have active. Any ideas are welcome!
The joy of shared instructions! Here are a couple of ideas for you to consider, both of which I'm going to be using Cheat Engine to demonstrate, because it's fast becoming the superior dynamic analysis tool for game-hacking.
1. Instead of looking for the instruction that writes to the address, right-click on it and look for instructions that access the address. There, you will find instructions that read the value from the address, as well as instructions that write to it. An example of an instruction that reads the value might be for the HUD representation of health. To know how far up to show your health bar being filled, it reads the value from your health address.
What that means is if you find an address that reads your health value, that may be the only thing that instruction does. You can then create a code injection just before that instruction and move a custom value into the address that's being referenced or pointed at.
For example, let's say this is an instruction that reads from your health address:
In that case, your health address is being pointed to by [ecx+0C]. The value there is being moved into the eax register. What you could do is create a code injection at that instruction with which to write a custom health value to [ecx+0C] before the mov instruction runs. That would change the actual value of health, and thus that custom value is then read from the address. This is easy to do with Cheat Engine (via its native code injection functionality), but otherwise requires you to look into code-caving.
2. To use a shared instruction like the one you've found, you have to find a way to differentiate what you want to influence, from the rest of the addresses being written to. This can look like a daunting task, especially when you find a shared instruction like in GameMaker games where HUNDREDS of addresses are all being written to through one instruction, but fear not!
Your options are to find differences in the following places:
A) Memory addresses (Including the stack) B) Registers (General purpose, FPU/XMM, special purpose, etc.)
Right-click on the shared instruction and choose "Find out what addresses this instruction accesses." A new window will pop up showing addresses that instruction is writing to. From that window, you can do a whole lot of neat things.
First, Cheat Engine provides a handy Data/Structure Dissect tool that you can use to compare values between multiple memory addresses. If you select all the addresses (Shift-click, or Ctrl-click the ones you're interested in), then right-click, you'll see an option to open the data dissect tool. There, you can compare values to find differences in the same offsets!
Something else you can do from that list of addresses is hit Ctrl + R to view the contents of registers. There, you can usually find a register containing a different value between all addresses (you'll want to look for a differing value that's NOT a dynamic memory address, because that value will change when restarting the game).
Finally, when viewing the contents of registers, there are two little buttons on that window: 'S' and 'F'.
'S' lets you view the stack. There, you can look for values to differentiate. 'F' lets you view the contents of the FPU, and XMM registers. Sometimes, the latter can be helpful because, say, the FPU might have been used ONLY for health and not for any other values that shared instruction is writing to.
Bringing it all together, you'll use whatever unique value(s) you find to write a custom code injection that will allow you to single out the value you're interested in. Let's say your instruction is this:
And let's say that, in register ebx, you found a unique value of 2B.
Your injected code might look something like this:
label(customCode) label(restoreFlags) label(originalCode) label(return) customCode: pushf //Preserve flags register by pushing onto the stack cmp ebx,2B //Does ebx contain the value you're interested in? jne restoreFlags //If not, restore flags register and resume normal execution mov eax,(float)100 //If so, move a custom health value into eax for originalCode //Execution flow from here moves to restoreFlags restoreFlags: popf //Restore flags register //Execution flow from here moves to originalCode originalCode: mov [edx+0C],eax //eax contains either value from normal execution, or custom health jmp return //Return to the point we injected and resume normal execution
I don't mean this as shameless self-promotion, but I've been running a YouTube channel for the better part of 3 years that teaches reversing via game-hacking. If games are your medium and you enjoy learning via videos, I think you'd really learn a lot from my CE tutorial series, specifically. I also teach game-specific hacks, like Cuphead, ELEX, etc.
Kind of a shot into the blue here, but here are some thoughts which may help you and that won't fit into the comments:
3D Engines often work with entity-Objects in flexible inheritance hierarchies. I assume something like the following:
class GameObject(x, y, z) ... class GameEntity(x, y, z, health) : GameObject void takeDamage(x) void decreaseAmmo(x) ... class Player() : GameEntity
In most common languages (like C++), each class will have a separate function table pointing at the implementations of all class methods. For example, when we call
takeDamage on a
Player-Object, we would expect the method implemented for all
GameEntities to be executed. Therefore NOP'ing out the function will have the effects you described before.
It seems you have two valid options: Find the right function pointer to manipulate or check the identity of the
this-pointer which is often passed as the first parameter to a member function.