|
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
themandem Cheater Reputation: 0
Joined: 06 Dec 2019 Posts: 35
|
Posted: Sun Aug 20, 2023 12:37 pm Post subject: Why won't this function hook properly C++ |
|
|
i'm using MASM method to make my cheat. Since it's a x64 game, it won't let me use inline assembly in visual studio... so I have a separate .asm file with assembly code in it for a Godmode cheat.
just don't know why the function isn't hooking properly. i'll post my code.
Main.cpp contains this:
define everything here
Code: |
#include <cstdint>
#include "globals.h"
// Godmode
static float health{};
bool toggle0 = false;
uintptr_t JumpBack0{}; // Initialize JumpBack0
// Gets "ViceCity.exe" base module address
HMODULE hModule = GetModuleHandle(NULL);
uintptr_t moduleBase = reinterpret_cast<uintptr_t>(hModule);
|
body here
Code: |
// Function for access rights to a specific memory with specific length ... setting bytes / hook/inject
bool Hook(void* hookAddress, void* functionA, int length)
{
if (length < 5)
return false;
DWORD oldProtection;
VirtualProtect(hookAddress, length, PAGE_EXECUTE_READWRITE, &oldProtection);
memset(hookAddress, 0x90, length);
uintptr_t relativeAddress = ((uintptr_t)functionA - (uintptr_t)hookAddress) - 5;
*(BYTE*)hookAddress = 0xE9; // jmp instruction
*(uintptr_t*)((uintptr_t)hookAddress + 1) = relativeAddress;
DWORD temp;
VirtualProtect(hookAddress, length, oldProtection, &temp);
return true;
}
|
Code: |
// Godmode cheat hook
uintptr_t module_address0 = moduleBase + 0x108B2D0;
JumpBack0 = module_address0 + 5; // Address + length
Hook((void*)module_address0, (void*)Godmode, 5);
|
globals.h contains this:
Code: |
#pragma once
#include <cstdint>
extern "C"
{
extern bool toggle0;
extern uintptr_t moduleBase;
extern uintptr_t JumpBack0;
void Godmode(); // Declare the Godmode function
}
|
i have double checked my instruction that i'm hooking to. it requires a 5 byte jump. it's not doing a far jump or anything like that, just a regular 5 byte jump. when it gets hooked, i see the jmp being made, but there is some extra nonsense going on underneath this instruction. i see some additional bytes under it changing when i don't think it's supposed to do that.
it seems to be setting memory for 13 bytes instead of 5 bytes. the nonsense that gets added under goes on till just above ViceCity.exe+108B2DD: 41 55 - push r13. the extra stuff under it have opcodes like "add [rax],al"
Here is what it looks like before injection:
Code: |
{
// ORIGINAL CODE - INJECTION POINT: ViceCity.exe+108B2D0
ViceCity.exe+108B2C6: CC - int 3
ViceCity.exe+108B2C7: CC - int 3
ViceCity.exe+108B2C8: CC - int 3
ViceCity.exe+108B2C9: CC - int 3
ViceCity.exe+108B2CA: CC - int 3
ViceCity.exe+108B2CB: CC - int 3
ViceCity.exe+108B2CC: CC - int 3
ViceCity.exe+108B2CD: CC - int 3
ViceCity.exe+108B2CE: CC - int 3
ViceCity.exe+108B2CF: CC - int 3
// ---------- INJECTING HERE ----------
ViceCity.exe+108B2D0: 48 89 5C 24 18 - mov [rsp+18],rbx
// ---------- DONE INJECTING ----------
ViceCity.exe+108B2D5: 48 89 74 24 20 - mov [rsp+20],rsi
ViceCity.exe+108B2DA: 57 - push rdi
ViceCity.exe+108B2DB: 41 54 - push r12
ViceCity.exe+108B2DD: 41 55 - push r13
ViceCity.exe+108B2DF: 41 56 - push r14
ViceCity.exe+108B2E1: 41 57 - push r15
ViceCity.exe+108B2E3: 48 81 EC B0 00 00 00 - sub rsp,000000B0
ViceCity.exe+108B2EA: 0F B6 05 79 3D F3 03 - movzx eax,byte ptr [ViceCity.exe+4FBF06A]
ViceCity.exe+108B2F1: 4C 8D 35 08 4D F7 FE - lea r14,[ViceCity.exe]
ViceCity.exe+108B2F8: 44 0F 29 4C 24 70 - movaps [rsp+70],xmm9
}
|
and here is what it looks like after injection:
Code: |
ViceCity.exe+108B2CB - CC - int 3
ViceCity.exe+108B2CC - CC - int 3
ViceCity.exe+108B2CD - CC - int 3
ViceCity.exe+108B2CE - CC - int 3
ViceCity.exe+108B2CF - CC - int 3
ViceCity.exe+108B2D0 - E9 CBA0449A - jmp 7FF757A453A0
ViceCity.exe+108B2D5 - 03 00 - add eax,[rax]
ViceCity.exe+108B2D7 - 00 00 - add [rax],al
ViceCity.exe+108B2D9 - 20 57 41 - and [rdi+41],dl
ViceCity.exe+108B2DC - 54 - push rsp
ViceCity.exe+108B2DD - 41 55 - push r13
ViceCity.exe+108B2DF - 41 56 - push r14
ViceCity.exe+108B2E1 - 41 57 - push r15
ViceCity.exe+108B2E3 - 48 81 EC B0000000 - sub rsp,000000B0
ViceCity.exe+108B2EA - 0FB6 05 793DF303 - movzx eax,byte ptr [ViceCity.exe+4FBF06A]
ViceCity.exe+108B2F1 - 4C 8D 35 084DF7FE - lea r14,[ViceCity.exe]
ViceCity.exe+108B2F8 - 44 0F29 4C 24 70 - movaps [rsp+70],xmm9
|
|
|
Back to top |
|
|
atom0s Moderator Reputation: 199
Joined: 25 Jan 2006 Posts: 8519 Location: 127.0.0.1
|
Posted: Sun Aug 20, 2023 1:34 pm Post subject: |
|
|
Your issue is with type sizing. uintptr_t is not the same size when compiling in x86 as it is in x64.
On 32bit, it is treated as: 'unsigned int'
On 64bit, it is treated as: 'unsigned __int64'
This means when doing things like:
Code: |
(uintptr_t*)((uintptr_t)hookAddress + 1) = relativeAddress;
|
You are writing 8 bytes instead of 4.
_________________
- Retired. |
|
Back to top |
|
|
themandem Cheater Reputation: 0
Joined: 06 Dec 2019 Posts: 35
|
Posted: Sun Aug 20, 2023 1:41 pm Post subject: |
|
|
atom0s wrote: | Your issue is with type sizing. uintptr_t is not the same size when compiling in x86 as it is in x64.
On 32bit, it is treated as: 'unsigned int'
On 64bit, it is treated as: 'unsigned __int64'
This means when doing things like:
Code: |
(uintptr_t*)((uintptr_t)hookAddress + 1) = relativeAddress;
|
You are writing 8 bytes instead of 4. |
i also tried "uint64_t" and "unsigned long long int", but still the same problem persists .
oh wait, so you're saying i only need to type it once there? shouldn't 8 bytes be fine since it's a x64 process?
edit: omg you are right. thank you so much. changed that line to this and it fixed the hook:
Code: | *(uint32_t*)((uintptr_t)hookAddress + 1) = static_cast<uint32_t>(relativeAddress);
|
--------------------------------------------------------------------------------------
Now that the hook is working. another problem has come up. for some reason my .asm file is not being read? on the injected point, I press spacebar when viewing it in Cheat Engine disassembler, and it leads to a point in memory with '??' question marks. That is where the code to my Godmode cheat is supposed to be showing up! Weird thing is that in the globals.h header file it's giving a warning on my void Godmode(); declaration saying that the function definition cannot be found. this function is in my .asm file. i don't know why it can't find it.
I have never worked in visual studio MASM before so I apologize if things are messed up. but here's what my code looks like in the .asm file that contains the Godmode cheat:
Code: |
.data
.code
ALIGN 16
EXTERN moduleBase : QWORD
EXTERN toggle0 : BYTE
EXTERN JumpBack0 : QWORD
Godmode PROC
newmemA:
cmp byte ptr [toggle0], 0
je codeA
push rsi
mov rsi,qword ptr [moduleBase]
cmp rcx, [rsi + 4D6CC70h]
pop rsi
jne codeA
ret
codeA:
mov [rsp+18],rbx
jmp qword ptr [JumpBack0]
Godmode ENDP
END |
is there anything I forgot to do?
|
|
Back to top |
|
|
atom0s Moderator Reputation: 199
Joined: 25 Jan 2006 Posts: 8519 Location: 127.0.0.1
|
Posted: Sun Aug 20, 2023 8:59 pm Post subject: |
|
|
Quote: | Now that the hook is working. another problem has come up. for some reason my .asm file is not being read? on the injected point, I press spacebar when viewing it in Cheat Engine disassembler, and it leads to a point in memory with '??' question marks. |
This sounds like the jump you are writing is invalid then.
Something you need to keep in mind when writing a jump like that is that it is limited to a set range/distance. 0xE9 is a relative jump which treats the calculated offset as a signed integer to allow jumping in both directions, which limits the distance that can be jumped to +/- 2GB. If your module is getting loaded further than that from the place you are placing your patch, then the distance won't be valid and you'll have to patch in a different manner.
You can patch in a different method such as:
Code: |
push RAX
mov RAX, [addr_to_your_func]
jmp RAX
pop RAX
|
Doing this does take up a lot more data that you need to restore/recover in your cave, but allows for calling/jumping from [nearly] anywhere. You can save some extra space as well if you analyze the function you are patching to observe which registers are not being used and can be safely overwritten at the moment to avoid needing the push/pop calls as well.
You can then do similar math as before to calculate the return location properly based on the number of bytes you are using to create the 'mov/jmp' and so on.
_________________
- Retired. |
|
Back to top |
|
|
ParkourPenguin I post too much Reputation: 140
Joined: 06 Jul 2014 Posts: 4307
|
Posted: Sun Aug 20, 2023 9:36 pm Post subject: |
|
|
themandem wrote: | edit: omg you are right. thank you so much. changed that line to this and it fixed the hook:
Code: | *(uint32_t*)((uintptr_t)hookAddress + 1) = static_cast<uint32_t>(relativeAddress);
|
|
Minor note: you should make sure `relativeAddress` doesn't get truncated when cast down to a 32-bit displacement. If it does, your code will jump to garbage (probably `??`).
Something like this:
Code: | assert(relativeAddress == static_cast<uintptr_t>(static_cast<int32_t>(relativeAddress)); | Edit: changed `uint64_t` to `uintptr_t`
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
Back to top |
|
|
themandem Cheater Reputation: 0
Joined: 06 Dec 2019 Posts: 35
|
Posted: Sun Aug 27, 2023 4:55 am Post subject: |
|
|
fixed.
changed regular 5 byte hook to a far 14 byte hook to account for far jump since the allocated memory was too far.
Code: | // Function for access rights to a specific memory with specific length ... setting bytes / hook/inject
bool Far_Hook(void* hookAddress, void* functionA, size_t len)
{
if (len < 14)
{
return false;
}
DWORD protection;
VirtualProtect(hookAddress, len, PAGE_EXECUTE_READWRITE, &protection);
memset(hookAddress, 0x00, len);
*(WORD*)hookAddress = 0x25FF; //Far jump
*(uintptr_t*)((uintptr_t)hookAddress + 6) = (uintptr_t)(functionA);
if (len > 14)
{
uintptr_t nop_offset = (uintptr_t)hookAddress + 14;
memset((void*)nop_offset, 0x90, len - 14);
}
DWORD temp;
VirtualProtect(hookAddress, len, protection, &temp);
return true;
} |
|
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|