Theories and methods of Code-caves
Intro:
Since many have read my tutorial on basic memory hacking and got stuck on the creation of code-caves, I’ve decided to make a short follow-up on some code-cave techniques where I’ll explain the WHYs and the HOWs.
Note: In order to fully understand this tutorial it is suggested that you read my previous tutorial on basic memory hacking.
Index:
1. In theory
1.1 RAM, the temporary buffer
1.2 Code-caves in general
2. The methods
2.1 Tools:
2.2 Changing values
2.2.1 Changing values theory
2.2.2 Changing values method
3. F.A.Q.
3.1 The hack crashes the game
3.2 The hack has no effect
3.3 PB detects my hack
1. In theory
1.1 RAM, the temporary buffer
Before you’ll be able to understand code-caves you’ll need to understand how your RAM (Random Access Memory) works.
Everything running on a computer (even the operative system) uses your RAM as a temporary buffer to store information. This information is then either forwarded to be stored on a drive unit (hard drive, CD/DVD-burner, floppy…), or it will remain in the RAM as long as the process is running.
Whenever a program runs, it either uses your hardware memory modules or a page-file created by windows (virtual memory). In any case, the program "injects" code into the memory to be processed (read from and written to) since the program itself is already compiled* and cannot change.
The manner of which the program reads and writes code in the memory is fairly simple. Think of it as a list where numbers (hexadecimal addresses) defines the location of the rows. When you start a program, it injects (writes) code into a certain number of rows and then executes one predefined row called “entry point”. Once the entry point is executed, the program reads the following addresses in chronicle order.
*Compiled: A process where sourcecode is gathered by a compiler program and produces an executable file (.exe in windows).
1.2 Code-caves in general
A code-cave is a name designated to a method where you assemble (write to) an unused portion of your memory in order to change the behavior of the original operations.
A code-cave normally consists of 2 parts:
- - The Cave, located at a free portion of your memory. The cave itself consists of a copy of the original code, the changes you wish to make to the original code and a jump back to the original code.
- The Jump-gate, located in the original code. You can compare a jump-gate with a crossroad. Instead of letting traffic (dataflow) use the highway, you put up a roadblock (the jump-gate), diverting traffic to a road you control (whatever changes you wish).
2. The methods
2.1 Tools
To be able to use and follow the methods of this tutorial you will need no knowledge of any programming language, however, if you know the basics of ASM you will probably understand it the first time you read it.
The only tool you will need is Ollydbg 1.10 (search for it on google).
2.2 Changing values
2.2.1 Changing values theory
There are many reasons why you might need a code-cave. In the method below I’ve chosen to explain how to change a value in your memory and why you need a code-cave to accomplish this.
The effects you could get by changing values are almost unlimited since most functions in a program rely on values. Examples: money, health, levels, gun damage etc.
I will use Need For Speed - Underground 2 as example in this tutorial and explain how to change the value of money.
Since this tutorial will only cover code-caves, you should already know how to gather the right addresses in T-search, but I will give you a little reminder:
First of all you need to use T-search to get the dynamic address holding the value of money. This is done in the same way it was explained in my tutorial on basic memory hacking when looking for the dynamic team address or tag address.
Then you need to monitor the dynamic money address using Autohack in T-search. You also need to activate the part of the code handling the money value. You could do this by running over a “bonus icon” or buying something from a shop.
After some monitoring, T-Search shows these static addresses:
Now we need to figure out where the value of money is kept so that we can change it.
The best way to find the offset (in between brackets) in which the value is stored, is to look for similarities within the code. In this case the common offset is easy to find. [0x861E74] is the offset storing the value of money.
If we take the first address as an example (537BB8), the operation tells the game to read the value at 0x861E74 and move (MOV) it into ECX.
Let me break that line down even more for you:
ECX is a GPR (General Purpose Register), a place where information (a hexadecimal value) can be stored temporary. In the beginning of a code section, the registers are set to a specific value and then that value gets changed throughout the rest of the code as other operations use the registers to change that value.
The offset [0x861E74] is also a kind of variable; it can be either a register or an address.
In order to tell the game to change the value in the offset to a value we have chosen, we need to add a line of code into the memory. This is where the code-cave comes in handy. If we were to add the line of code directly into the original code, we would have to overwrite some code lines and the game could easily crash.
Finally, you need to know WHERE to add this line of code. Since only the creator of the game knows exactly how the game works, our task is to figure it out, by trying.
You can use many of the addresses above to attach your line of code to. I found one in particular that is quite suitable since it gets read pretty often: 537C64.
2.2.2 Changing values method
The following steps will show how to add a line of code without destroying the original:
1. Start the program or game of your wish
2. Start Ollydbg and choose Attach from the Files menu.
From the list, select the program you want to make a code-cave in and click Attach.
WARNING: When you attach a program, Ollydbg will automatically pause the process once it is scanned (if you haven’t set Ollydbg not to). Therefore you need to unpause it quickly otherwise the game might crash:
3. Right-click anywhere in the CPU window and select Thread -> Main
4. Right-click anywhere in the CPU window and select Go to -> Expression
Let’s use the address 00537C64 as an example and call it the “Money address”. Enter it and click OK.
Ollydbg will go to the address you entered and select it.
5. What we need to do now, is create an operation telling the game to change the value.
This is the line of code accessing the offset [861E74] and MOVes the value into EAX
MOV EAX,DWORD PTR DS:[861E74]
To change the value of [861E74], the next line of code should look like this:
MOV DWORD PTR DS:[861E74], 1388
This MOVes the value of 1388 into [861E74], lets call this line the “value changer”.
1388 is a hexadecimal number of 5000. So when add this line to your code, your money will change to 5000.
All this is ASM codes; you don’t need to understand it completely, as long as you understand what it’s doing.
6. The result of this would look something like this:
As you can see, when adding this line, we destroyed 4 others and the game will most likely crash. To solve this, we need to create a code-cave.
7. So, first we restore original code by selecting the red code, right-clicking it and selecting Undo selection.
8. Now that the code has returned to normal, select a minimum of 6 address lines where our money address is inside the range, and copy them to clipboard.
NOTE: The money address should not be the first or the last address in the copied range.
9. Open a notepad document and paste the addresses you copied. Also remove everything else except the ASM codes. So that it looks like this:
10. Now we can edit these lines and add our value changer like this:
11. Copy the lines you now have in your notepad document to an empty space in the same process. Empty spaces are normally situated at the end of a process. This is how empty space looks like:
The copied lines will look like this:
12. What you are looking at now is your code-cave. But there is one thing missing. When the game reads our code-cave from top to bottom and reaches the address 00782F81 the code just ends and the game will crash.
So you will need to make a jump back to the original code so that the dataflow can continue.
If you take a look at step 8. above, you will see an address that reads:
00537C70 E8 FBFBFFFF CALL speed2.00537870
The code at this line is the same as the last line in our code-cave. So I can safely destroy the copied line and create a jump out of it, like this:
There we are… we’ve now finished our code-cave, only one little thing left to do: The Jump-gate.
13. The jump-gate is the link between the original code and the code-cave.
As you can see, the jump-gate destroys a few lines of code, but since that code is already recreated in the cave, the game won’t crash.
14. Now you need to create a trainer and the tutorial on basic memory hacking explains how to do.
3. F.A.Q.
This F.A.Q. of this tutorial is going to be an ongoing project where new questions and answers are entered as new problems occur.
3.1 The hack crashes the game
- Always be careful where you make the jumps. If you are having difficulties seeing the dataflow, use a notepad document to clear things up and to detect errors.
This is the chronological order in which the above code-cave is read:
Starting at address 00537C5A ending at address 00537C78:
00537C5A E8 A13F2200 CALL speed2.0075BC00
00537C5F 8B4E 38 MOV ECX,DWORD PTR DS:[ESI+38]
00537C62 E9 FDB22400 JMP speed2.00782F64
00782F64 8907 MOV DWORD PTR DS:[EDI],EAX
00782F66 A1 741E8600 MOV EAX,DWORD PTR DS:[861E74]
00782F6B C705 741E8600 88130000 MOV DWORD PTR DS:[861E74],1388
00782F75 50 PUSH EAX
00782F76 68 44F77800 PUSH speed2.0078F744
00782F7B 51 PUSH ECX
00782F7C E9 EF4CDBFF JMP speed2.00537C70
00537C70 E8 FBFBFFFF CALL speed2.00537870
00537C75 83C4 18 ADD ESP,18
00537C78 5F POP EDI
Looking at this will expose errors like repeated an ASM code or skipping of a line. The red text is the most important. - A crash can also be caused by your jump-gate. If the lines that your jump-gate destroys are targets of other jumps, you need to make your jump-gate further up in the address lines.
This error can also be fixed by following the method below, solving reference errors. - If your code-cave is too small, the jump-gate will most definitely crash the game. Make it at least 6 addresses wide to be sure, since a JMP operation uses 5 sets of OPcodes.
3.2 The hack has no effect
- The most common error is caused by a “reference error”.
Let’s say you made a code-cave from address 00537C62 to address 00537C70
That means your jump-gate is located at 00537C62. That also means that you led the dataflow in another direction at address 00537C62.
Now imagine that another address somewhere in the vicinity jumps to address 00537C64. If that is the case, that jump will “override” your jump to the code-cave, causing your code-cave never to be read. In other words, the original code is executed instead of your code-cave and the hack will never be active.
To check if there are any jumps targeting the portion of code you wish to copy, select the lines you want to copy, right-click and chose Find references to -> Selected block.
The result:
As you can see, there are 2 addresses containing jumps to the code we need to copy. Let’s call them “reference jumps”.
To solve this, you need to assemble the reference jumps and redirect them to your code-cave addresses corresponding to the original ones.
In this case, the two addresses containing jumps are targeting addresses right outside our code-cave, so no adjustments need to be done. - If you chose to hack a value that only gets activated when you access that specific function in the game, that’s also when the hack will be activated (example: when selling or buying something). To solve this you need to find an address where that value is accessed frequently.
3.3 PB detects my hack
Question: I know that the PB scan-range starts at 00440F48 and I put my jump-gate at 00440F47, but I still get detected, why?
Answer: To answer this question I need to explain how OPcodes work.
You need to keep in mind that every address contains 1 pair of opcodes.
Lets take an example:
00537C62 E9 FDB22400 JMP speed2.00782F64
E9 is the opcode used by the address 00537C62.
You might think that all the opcodes (E9 FDB22400) are stored in the address 00537C62, but that is not the case.
These are the locations of every pair of opcode:
00537C62 E9
00537C63 FD
00537C64 B2
00537C65 24
00537C66 00
So, now you might realize that if PB scans a few addresses after your jump-gate, you run a risk having the end of your jump-gate inside the scan-range, even though the first address of your jump-gate is outside.
Written by Faldo, last updated: 2004-11-14