2006/01/20

Sometimes I impress myself.

In the game I'm playing, most of the time I'm controlling a person or a car, and the point of view is from a camera that is behind and a little above the me. When I move the mouse, it moves the camera around, but it's focal point remains on the character.

When you move the mouse left and right, the camera moves left or right as you'd expect. However, when you push the mouse forward or backwards, people disagree if they think the camera should move up or down. For this reason, the game makes have an option that you can access call "Invert Mouse Vertical Axis", which you can change to suit your own preference.

My problem is, depending on if I'm in certain vehicles or not (namely in a plane or not), I sometimes like that setting on, and sometimes off. And I really can't handle it when it's set the wrong way. It's like trying to write while looking in a mirror... all flipped around. What I've been doing has been going into the Options menu in the game and flipping that setting when I get in and out of planes, but after doing that a few times, I figured there must be a better way.

I did some research, and found part of my answer. This game has a very active "modding" community, who reverse engineer the game and play around with the internals. Specifically, they found the specific point in memory where the "Invert Mouse" setting is held. If that point in memory is a 1, then it's on. If it's a 0, then it's off. They also have tons of other memory address, that hold your characters x/y/z position in the world, money, stats... everything.

So I did some programming last night. I was able to write a program that looked for the game process in active memory (so, the game had to be running first). I was able to read and write values anywhere in this process memory space, so I wrote some code to write a 1 to the "Invert Mouse" address. Then I went into the game, made sure the setting was off, and tried running my program. What should have happened was that the setting got turned on.

It totally should have worked, but didn't. Bogus.

What I eventually found was that the memory address for that one specific setting was incorrect. When I tried other address, like other settings and money and stuff, everything worked as advertised. But that one specific setting, the ONLY one that I cared about, was incorrect. I was extrememly frustrated to find that the hard part (tweaking memory) actually was pretty easy, and the easy part (finding the right spot to tweak, which I thought was well published) was unfounded.

I took a break and had dinner. Diana had gotten home, and we chatted about our days. It's good to take breaks from problems.

After dinner, I did some more websearching, and realized that most of the Options menu stuff was stored in a particular region of memory. Most started at something like 0xBA0000. So, I modified my code to read 100,000 bytes of memory from 0xBA0000 into one buffer, then pause, then do it again, and then compare the buffers byte-for-byte. I then loaded up GTA, and ran my program, reading in memory until it paused. Then I went back to the game, flipped the Invert Mouse setting, and then continued the program, reading in the same block of memory to a second buffer, hopefully with a flipped bit.

When I ran through the comparison, I found that the buffers differed at offset 26437 in my buffers! Could this be it?

I converted 26437 to hex (0x6745h) and added it to my base search address (0xBA0000) to get the specific location, 0xBA6745. This single byte should hold the value of 1 or 0, and modifing that byte will change the "invert mouse" setting.

I modified my program yet again to flip the bit at that memory address when I hit a certain key. I then tested by going into the game, setting the option, alt-tabbing out and pressing a key in my app, and going back into the game to see that the option flipped. It totally worked. Rockin'. I was as jubilant at that moment as I was frustrated an hour earlier.

The hard part, it turns out, was that I now want my app to be running in the background while I play the game. But even in the background, I want it to listen to key presses so that, in mid game, I can hit some magic key and that will flip the option on the fly. It turns out that writing a key-spy like that (called a "hook") isn't very straightforward in the programming language that I'm using. Apparently it's debateable if it's even possible just using the language I'm using. But, I've found sample code that does it using a combination of languages (managed C# calling a C++ dll for doing the hooking), and I should be able to use that for my purposes.

The coolest thing about all this, aside from my own satisfaction at solving a tricky puzzle, is now the world is my oyster. I know where the game holds my money, for instance, and if I wanted I could give myself a million, billion dollars. I could teleport all over the world (potentially). I could whatever car I wanted at the push of a button (potentially). And I'm not just talking about this game, but the potential for this kind of manipulation is generalized across not only games, but all applications.

I feel like I've taken a little step into a much bigger world. I almost want to start World of Warcraft againt, just to try writing hacks for it. (Maybe Grand Theft Auto *is* a bad influnce! :)

No comments: