Need Help with Trainer

Posts 1–5 of 5 · Page 1 of 1
Need Help with Trainer
I am making a trainer for Super Meat Boy in C++ and it is crashing. It does however work if I fill the code I am patching with nop's. I am trying to set the time to 1 on the level, however that causes it to crash. I have the code jumping from the place I patch to memory I allocated in the process. And I have it execute the code to make the time go to 1 and I jump back.

Since it works when I write the nop's, I think that's the right place and my write function is working. I'm thinking that it maybe my jump function that isn't working. Can you guys see where I am going wrong?

So here's the line I am replacing:
D99E7C030000 OR fstp DWORD PTR [esi+0x37c] which is at SuperMeatBoy + DD78



Code:
void timeChanger(Process *stuff, procInfo info) {
	BYTE readBytes[16];
	BYTE nop[6] = {0};
	BYTE original[] = {0xD9, 0x9E, 0x7C, 0x03, 0x00, 0x00}; // D99E7C030000 OR fstp DWORD PTR [esi+0x37c]
	BYTE timeBuffer[] = {0xC7, 0x86, 0x7C, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; // C7867C03000001000000 OR mov    DWORD PTR [esi+0x37c],0x1

	ExAddress space = (DWORD)VirtualAllocEx(info.hProcess, NULL, 50, MEM_COMMIT, PAGE_EXECUTE_READ);

	/*if (GetAsyncKeyState(VK_F1))
		stuff->Write(info.baseAddr + 0xDD78, nop, 6); // this write works
	else if (GetAsyncKeyState(VK_F2))
		stuff->Write(info.baseAddr + 0xDD78, original, 6); 

	//DWORD key = stuff->exUnProtect(info.baseAddr + 0xDD78, 6);
	stuff->Write(space, timeBuffer, 6); // My code I run in new space
	stuff->writeJump(space + 6, info.baseAddr + 0xDD7E); // jump back 6 bytes ahead of first 
	stuff->writeJump(info.baseAddr + 0xDD78, space);*/ // jump to space.  0xDD78 is where fstp DWORD PTR [esi+0x37c] is.
	//stuff->exProtect(info.baseAddr + 0xDD78, 6, key);
}
Code:
void Process::writeJump(DWORD address, DWORD destination) {
	BYTE buffer[4];
	BYTE jump[2] = {0xFF, 0x25};

	addrToLittleEndian(destination, buffer);

	BYTE fullJump[6] = {jump[0], jump[1], buffer[0], buffer[1], buffer[2], buffer[3]};

	if (!WriteProcessMemory(info.hProcess, (LPVOID)address, fullJump, 6, NULL))
		cout << "Failed jmp write. Error: " << GetLastError << endl;
}
Code:
void Process::addrToLittleEndian(DWORD address, BYTE* buffer) {
	DWORD bitMask = {0x000000FF};

	for (int i = 0; i < 4; ++i) {
		buffer[i] = (BYTE)((address & bitMask) >> i*8);
		bitMask <<= 8;
	}
I think the problem is that
stuff->Write(space, timeBuffer, 6); // My code I run in new space
&
stuff->writeJump(space + 6, info.baseAddr + 0xDD7E); // jump back 6 bytes ahead of first
the first line causes a problem because...you only copy 6 bytes out of timeBuffer -- so not the whole cpu instruction..!
your codecave will be 6 bytes of timeBuffer + jump back
BYTE timeBuffer[] = {0xC7, 0x86, 0x7C, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00};

c7,86,7c,03,00,00, + ff,25, +{first 2 bytes of addr} == 10 byte mov instruction
not the cpu instruction you want to execute.
You're only copying part of the mov instruction: But since the first few bytes are set up like the move instruction, that's what it is, and the cpu expects it to be 10 bytes, so it reads 10 bytes. Because you only copied over 6, the next 4 bytes it will get are part of the jump-back instruction! 0xff,0x25, and the first 2 bytes of the address you pass in. It's still a move instruction, but not the one you want : p After this point, the cpu will continue decoding the next bytes in ram, and since it took a chunk off the "jump back" instruction (it took the ff,25,first 2 bytes of addr), the jump-back instruction is now incomplete! The cpu's next instruction will be...the last 2 bytes of the addr we passed in -- random, and probably junk. This would cause a crash.

"It does however work if I fill the code I am patching with nop's."
because copying 6 bytes of nop's results in 6 complete instructions. copying 6 bytes of mov [esi+0x37c],0x1 isn't a complete instruction
(^^edit: I assumed you were talking about writing nops to *your codecave* and having that work.. ie. if the nops work, and your code doesn't, there is a problem with your code. But looking at your code you nopped the game-code instruction -- maybe you tried both? Anyway, your codecave *could* consist of 6 nops + a jmp back)

solution: (line1) copy the whole 'timeBuffer' instruction into your codecave (change 6 to 10 ofc)
(line2) change where the jumpback gets written (change 6 to length of timeBuffer, again 10)
maybe?
I applied your solutions and that still crashed. I tried jumping to the code cave and then jumping back out ahead of the 6 byte instruction to jump to the code cave, however this crashed it. So I think the problem is with my jumping somehow. In my writeJump function I have FF25 which is jmp DWORD PTR and then I add the address which I convert to little endian (am I supposed to do that?). I converted it to little endian because when I used the disassemble to find the bytes for the same instruction to a made up address, it had it in little endian order, so that's what I did.
Quote Originally Posted by turdhunter View Post
I applied your solutions and that still crashed. I tried jumping to the code cave and then jumping back out ahead of the 6 byte instruction to jump to the code cave, however this crashed it. So I think the problem is with my jumping somehow. In my writeJump function I have FF25 which is jmp DWORD PTR and then I add the address which I convert to little endian (am I supposed to do that?). I converted it to little endian because when I used the disassemble to find the bytes for the same instruction to a made up address, it had it in little endian order, so that's what I did.
Well, let have a look at your code cave in ram...

1) write the code cave into ram
2) do NOT overwrite the game instruction with a jump to code cave

3) use ce to view your code cave
--is the jump correct or not

edit: just noticed...
BYTE original[] = ... // D99E7C030000 OR fstp DWORD PTR [esi+0x37c]
BYTE timeBuffer[] = ... // C7867C03000001000000 OR mov DWORD PTR [esi+0x37c],0x1

The first instruction, the original, is storing a floating-point number.
The 2nd is storing a integer number.
'1' in integer is different than '1' in single.

Also, the instruction you're replacing...if it modifies the stack in any way, you must duplicate that, or the stack will get screwed up. What does fstp do..? : )
Try running the original game instruction in your code cave, so it does it's stack manipulation -- it pops a float value off the "floating-point register stack" (?) and stores it in the memory location. This must be done or the stack will become corrupt.
After that you need some way to set the memory location to your desired value. Then jump back.
Post code and screenshots please.
Posts 1–5 of 5 · Page 1 of 1

Post a Reply

Similar Threads

Tags for this Thread

None

Need help?