Yes, its actually pretty simple.
If you do e.g Foo* objPtr = new Foo();
your Foo object becomes allocated in a different place everytime you start the application. To find it though, you have to find the variable pointing to it, objPtr
in this case which is basically "static". However this can go through multiple levels. You can hardcode this value if you want, however this is not preferred.
Usually you search for e.g getters, which provide you with global objects or search for function in which these global objects are referenced directly. Through these global objects you now get the actual objects you want.
You find the them on runtime by searching for a sequence of bytes. Imagine a very simple function:
PUSH EBP
MOV EBP, ESP
MOV EAX, globalVar
POP EBP
You create a binary pattern which represents this code snippet (the opcodes etc.) and simply iterate over the whole programm trying to find this specific method. However, you pattern need to be unique, it should only match one location in the whole binary. This can sometimes be a bit tricky and requires you te be creative. In this case it probably wont be possible to find a unique pattern (the function is too generic). Once you found this function, you can call it to acquire the object or read the address directly from it (parsing MOV EAX, globalVar
). Although, calling is probably better because the code might change, its functionality/signature usually not.
Actually such pattern scanning isnt required if your searching for fucntions, which usually only move on recompilation but not on every start of the programm. However, the above example should give you an impression on how it is done. Also notice that if you dont search for methods but hardcode their addresses, your code will probably break on the next game patch.
The hard part is to find the fucntions, identify the structures and simply understand what your target programm does under the hood/ how it works. We call this process reverse engineering. Usually you always need some kind of "entry point" into the application (as you can imagine, a game is actually quite big). These can be multiple things, but the most common ones are certainly programms like cheat engine in conjunction with memory breakpoints, referenced strings from the target programm, library function calls (which expose public available names, e.g Win32, 3rd party libs) or already available knowledge (e.g: I know this object is an agent, so somewhere there must be a position member in it). But once you done that, actually finding the things you reversed in the programm is quite easy.