Three Different Ways of Doing the Same Thing

Submit Tutorials Related to Memory Hacking Software

Moderators: g3nuin3, SpeedWing, WhiteHat, mezzo

Three Different Ways of Doing the Same Thing

Postby Shynd » Thu Nov 22, 2007 12:50 am

Here I will give three different examples of how to slow down the timer in Minesweeper (Start -> Programs -> Games -> Minesweeper). When you start your game in Minesweeper, the timer is at zero. When you click your first square, the timer is set to 1 and then, every second, is incremented by 1. Here are three different ways of making the timer get incremented every TWO seconds instead of one.

Method One: The EIP Skip
I'll let L. Spiro go into a little more depth on how the EIP register works, but it basically contains a pointer to the current line of ASM to be executed. If you change EIP, you change what the process is doing. If you want to skip an instruction, set EIP to the address of the instruction AFTER the one you want to skip.
Code: Select all
01002FF5 | FF05 9C570001 | INC     DWORD PTR [100579C] | ;increase the value of the timer
As you can see, the instruction at address 01002FF5 increases the value of the timer. This is where we'll set our breakpoint.
Image
  • Address = 01002FF5
  • On execute, hardware breakpoint
  • Callback Function: Script Function, Parm 1 (means we'll have to write a On_BP_1 script function)
Now then, the function:
Code: Select all
//global variable used in the first breakpoint handler
bool winmine_skip_increment = false;

//this shows how one can use a breakpoint to skip over lines of
//ASM instructions to change the game's behavior
//this does not change any values in RAM and is, therefore, unable to
//be detected by a simple CRC check (which many games use for anti-hacking)
void On_BP_1(LPVOID lpvAddress, LPPROC_INFO_MHS lpProcInfo)
{
   //on each breakpoint, alternate winmine_skip_increment between true and false
   //that way, the incrementer is only skipped every other time, thus decreasing
   //the timer by two
   winmine_skip_increment = !winmine_skip_increment;
   
   //if winmine_skip_increment is true (which only happens every other time)
   if (winmine_skip_increment)
   {
      //tell the user that we're skipping the timer incrementer
      PrintF("Timer increment skipped!");
      
      //move the next operation to be executed to one line BEYOND the incrementer
      //remember, the incrementer is held at 0x01002FF5... 0x01002FFB is the next line
      lpProcInfo->pcContext->Eip = 0x1002FFB;
      //remember to always set bSetContext to true if you make any changes
      //to lpProcInfo->pcContext... if bSetContext isn't set to true, your changes
      //will not take
      lpProcInfo->bSetContext = true;
   }
}
As you can see, we have a global boolean variable called winmine_skip_increment. At the start of our breakpoint handler, we set winmine_skip_increment to !winmine_skip_increment, or NOTwinmine_skip_increment. This means that if, when the breakpoint is hit, winmine_skip_increment is true, it is now false; if false, it's now true. We only skip over the timer increment if it's true, meaning the timer will be skipped every other time, effectively cutting the speed of the timer in half.

Voila! Now you'll have twice as much time to get the same score in Minesweeper. Sure, that's not useful, but I'm sure you can think of other ways to use this method. Don't like how a program does something every time you take an action? Change EIP to skip over the part you don't like. It doesn't change the checksum of the process' RAM so it's less detectable than simply NOPing or JMPing to another instruction and, as you can see, it is quite powerful.



Method Two: The External Variable
Another way to cut the timer in half is to set a breakpoint after the timer has been incremented and, when the breakpoint is hit, write our own timer value to memory. L. Spiro Script external variables make this quite easy. First, the breakpoint, which we set at the instruction directly after the timer increment:
Code: Select all
01002FF5 | FF05 9C570001 | INC     DWORD PTR [100579C] | ;timer increment
01002FFB | E8 B5F8FFFF   | CALL    010028B5            | ;BREAKPOINT HERE (after timer has been incremented)
We breakpoint at line 01002FFB, like so:
Image
  • Address = 01002FFB
  • On execute, hardware
  • Callback Function: Script Function, Parm 2 (we'll write function On_BP_2)
Now, again, the function:
Code: Select all
//global variable used in the second breakpoint handler
int winmine_realtimer = 0;

//this shows how one can use a breakpoint to change the value of an
//address in memory BEFORE it changes to what it's supposed to be.
//this wouldn't get picked up by a simple CRC anti-hack routine either, but
//is still just slightly riskier because whatever function(s) L. Spiro uses to
//write to memory when using an external variable might get picked up
//(i have no idea whether they would or not)
void On_BP_2(LPVOID lpvAddress, LPPROC_INFO_MHS lpProcInfo)
{
   //define winmine_timer as the address that holds the value of the timer
   extern int winmine_timer = {"winmine.exe", 0x579C};
   
   //show the user the timer increments
   PrintF("Timer: %d", winmine_timer);
   
   //increment our variable that holds what the REAL time is (incremented
   //once each time this BP is hit, just like the timer WOULD be if we
   //weren't changing the value)
   winmine_realtimer++;
   
   //change the value of winmine's timer
   //dividing by 2 cuts time in half; dividing by 3 makes it 3x slower, etc.
   winmine_timer = winmine_realtimer / 2;
}

We have a global integer called winmine_realtimer that will keep track of the number of times the breakpoint is hit and, as a result, the number of seconds that have ACTUALLY passed. Inside the function, we define an external variable named winmine_timer as "winmine.exe" + 0x579C (which turns out to be 100579C, the address at which winmine's timer value is held). We incremement the realtimer with each bp hit, then set winmine_timer to realtimer / 2, or half of realtimer. This effectively writes to the address holding the game's timer HALF of the time that has actually passed. If realtimer is 4, we set winmine_timer to 2; if realtimer is 18, we set winmine_timer to 9.

This method is useful for changing the value of a game variable at exactly the right moment using breakpoints and external variables / memory writes. Find the operation that tells the game how much damage you just took and change the damage to whatever you want. Breakpoint on the instruction that limits how much time you have left to finish a quest and give yourself more time. Of course, those two examples are only useful in single-player games, but I'm sure you can put this method to use in your favorite multi-player game with just a little imagination ;)


Method Three: The Codecave
This one will not use any breakpoints at all. This one is my favorite way of doing it because it's cut and dried and you can set it and forget it. It doesn't chew up one of your four available hardware breakpoints (you only get four of those, by the way, if you didn't know) and it will never make your game take a performance hit (not that breakpoints usually do, either, but you never know).

The only reason I don't like this one is it's easily detectable by a CRC/checksum check. This does alter the game code. However, in many games there either a) won't be a checksum check or b) will be one but it can be disabled or bypassed easily. So, really, whichever of these three methods--or any others you can think of, for that matter--speaks to you, use that one. This one speaks to me.

Now then, we know that the instruction at 01002FF5 increments the timer. I chose that address to overwrite with a JMP to the codecave that I wrote, which looks like this:
Code: Select all
01004A60 | 8B35 985B0001    | MOV     ESI, DWORD PTR [1005B98] |
01004A66 | 85F6             | TEST    ESI, ESI                 |
01004A68 | 75 12            | JNZ     SHORT 01004A7C           |
01004A6A | FF05 9C570001    | INC     DWORD PTR [100579C]      |
01004A70 | C605 985B0001 01 | MOV     BYTE PTR [1005B98], 1    |
01004A77 | E9 7FE5FFFF      | JMP     01002FFB                 |
01004A7C | C605 985B0001 00 | MOV     BYTE PTR [1005B98], 0    |
01004A83 | E9 73E5FFFF      | JMP     01002FFB                 |
In the first line, I move the value held at 01005B98 into ESI. 1005B98 is an empty address in the game's .data section, so it will never be changed unless I change it. That effectively makes it a global variable available to the ASM codecave that we're writing. Let's name the variable should_skip.

So, we move should_skip into ESI and then test esi to see if it's zero. If it's not zero--if (should_skip == true)--then we skip down to address 01004A7C, write 0 (false) to should_skip, and jump back to the main game routine; the timer isn't incremented.

If, however, we test ESI and it IS zero--if (should_skip == false)--then we don't skip the incrementer, write 1 to should_skip (true), and then jump back to the main game routine.

This means that the timer will only be incremented every other time. If you're having trouble visualizing this in action, attach MHS to winmine, inject the code, then add a breakpoint to line 01002FF5 (it'll say JMP 01004A60). Put Single Step as the Callback Function for the breakpoint. Then, start up the timer by clicking on a square in Minesweeper. It'll break on the code and allow you to step through it, showing you the route through the codecave it takes (press F8 to move to the next instruction). Press F9 when it's jumped back to the main game and it will break again in about one second, allowing you to step through the OTHER possible route through the codecave.

The code injection is pretty straight forward and already covered in the other tutorial I wrote, which has a link at the bottom of this post. Here's the code for the injection:
Code: Select all
//byte array to hold the overwritten operation for injection
BYTE winmine_overwritten[6];
//handle to the process used for restoring the overwritten operation
//after winmine.exe has been closed
HANDLE winmine_pHandle;

//this shows how one can use code injection to achieve the same thing as the
//above two examples.
//however, since this uses code injection, it DOES alter the CRC/MD5/checksum
//of the RAM, so it's easily detectable
void On_Open_WINMINE_EXE(HANDLE hProcess, DWORD dwProcessId)
{
   //ask the user if they want to inject or not
   //if trying either of hte breakpoint examples, i suggest not injecting
   if (MessageBox(MBS_YES | MBS_NO, "Inject Code?", "Would you like to inject code to make the timer half as fast?") == MBS_NO)
      return;
   
   //store a handle to winmine.exe in winmine_pHandle (used for cleaning up in On_Close)
   winmine_pHandle = hProcess;
   
   //read the original opcodes into winmine_overwritten
   //these will be re-written to winmine if the user starts hacking another
   //process with MHS -- it's always important to clean up after yourself, even if
   //just to keep in good habit
   ReadProcessMemory(hProcess, (void *)0x01002FF5, &winmine_overwritten, sizeof(winmine_overwritten), NULL);
   
   /* OUR CODE CAVE
   01004A60 | 8B35 985B0001    | MOV     ESI, DWORD PTR [1005B98] | ;move our boolean variable into ESI
   01004A66 | 85F6             | TEST    ESI, ESI                 | ;test esi to see if it's zero
   01004A68 | 75 12            | JNZ     SHORT 01004A7C           | ;if it's not zero, jump ahead
   01004A6A | FF05 9C570001    | INC     DWORD PTR [100579C]      | ;if it's zero, increase the timer
   01004A70 | C605 985B0001 01 | MOV     BYTE PTR [1005B98], 1    | ;write 1 to our variable
   01004A77 | E9 7FE5FFFF      | JMP     01002FFB                 | ;jump back to main game routine
   01004A7C | C605 985B0001 00 | MOV     BYTE PTR [1005B98], 0    | ;if it's not zero, write zero to it
   01004A83 | E9 73E5FFFF      | JMP     01002FFB                 | ;jump back to main game routine*/
   BYTE winmine_codecave[40] = {0x8B, 0x35, 0x98, 0x5B, 0x00, 0x01, 0x85, 0xF6, 0x75, 0x12,
                        0xFF, 0x05, 0x9C, 0x57, 0x00, 0x01, 0xC6, 0x05, 0x98, 0x5B,
                        0x00, 0x01, 0x01, 0xE9, 0x7F, 0xE5, 0xFF, 0xFF, 0xC6, 0x05,
                        0x98, 0x5B, 0x00, 0x01, 0x00, 0xE9, 0x73, 0xE5, 0xFF, 0xFF};
   BYTE winmine_jmp[6] = {0xE9, 0x66, 0x1A, 0x00, 0x00, 0x90};
   
   //write codecave to memory first so that it will already be there when the
   //game code is overwritten to jump to the codecave
   WriteProcessMemory(hProcess, (void *)0x01004A60, winmine_codecave, sizeof(winmine_codecave), NULL);
   //write the jmp over the timer incrementer
   WriteProcessMemory(hProcess, (void *)0x01002FF5, winmine_jmp, sizeof(winmine_jmp), NULL);
}

//clean up just in case MHS gets detached from winmine.exe
void On_Close_WINMINE_EXE()
{
   //make sure winmine_pHandle isn't null
   if ((DWORD)winmine_pHandle != 0)
   {
      //write the overwritten opcodes back to the main game routine
      WriteProcessMemory(winmine_pHandle, (void *)0x01002FF5, winmine_overwritten, sizeof(winmine_overwritten), NULL);
      //close the handle to the process
      CloseHandle(winmine_pHandle);
   }
}

Whenever MHS starts hacking winmine.exe, it will pop up a message box asking you if you'd like to inject the code. Click No to use one of the other methods or Yes to inject. Once it's injected, Minesweeper's timer will be half as fast even if MHS crashes, because it's all handled in the codecave which we injected.



You can find the fully documented, syntax highlighted version of my script HERE.

Here are links to my other two MHS tutorials, as well:
InfernoRose Packet - Using Code Injection and Multithreading
InfernoRose Packet - Using Script Breakpoint Handling


-Shynd
User avatar
Shynd
Acker
 
Posts: 68
Joined: Fri Jan 05, 2007 2:11 am

Postby L. Spiro » Thu Nov 22, 2007 10:42 am

Keep it up.

This little package is for what you have been waiting:
http://www.memoryhacking.com/MemHack/MHS4.0.0.6.Preview.rar
This is not the official release so a few extras are not yet added but I am sure its is enough to help a lot with the tutorials.





For those interested, EIP is the extended instruction pointer which indicates the next instruction to be executed by a thread. Each thread has one.
Putting this at a new location causes the thread to start executing that code, which is effective as a JMP instruction that does not modify the game RAM, which gives you a method for JMP’ing that is hard to detect.


L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Postby noLimit » Wed Nov 28, 2007 5:23 pm

I never thought that this program has been so advance now!

I have a glimps of this a year back and I can't imagine with the features and functionality it have now.

Keep it up Spiro.
noLimit
I Have A Few Questions
 
Posts: 8
Joined: Wed Nov 28, 2007 5:16 pm

Postby L. Spiro » Fri Dec 28, 2007 9:06 am

I just noticed that there is a problem at the very bottom.
You keep a copy of the process HANDLE at the start, but that is just a copy of the one MHS is using, and MHS closes it itself. If you close it with scripts it gets closed twice.
After the script closes it, MHS can no longer use it to finish the rest of what it needs to do when the process is closed.

This was probably made when MHS did not give the HANDLE to the closing function, but now that it does you could update the tutorial to use that instead and remove the global completely.


L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan


Return to Tutorials

Who is online

Users browsing this forum: No registered users and 0 guests