Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Why won't this function hook properly C++

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming
View previous topic :: View next topic  
Author Message
themandem
Cheater
Reputation: 0

Joined: 06 Dec 2019
Posts: 35

PostPosted: Sun Aug 20, 2023 12:37 pm    Post subject: Why won't this function hook properly C++ Reply with quote

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
View user's profile Send private message
atom0s
Moderator
Reputation: 199

Joined: 25 Jan 2006
Posts: 8519
Location: 127.0.0.1

PostPosted: Sun Aug 20, 2023 1:34 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
themandem
Cheater
Reputation: 0

Joined: 06 Dec 2019
Posts: 35

PostPosted: Sun Aug 20, 2023 1:41 pm    Post subject: Reply with quote

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 Sad.
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
View user's profile Send private message
atom0s
Moderator
Reputation: 199

Joined: 25 Jan 2006
Posts: 8519
Location: 127.0.0.1

PostPosted: Sun Aug 20, 2023 8:59 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
ParkourPenguin
I post too much
Reputation: 140

Joined: 06 Jul 2014
Posts: 4307

PostPosted: Sun Aug 20, 2023 9:36 pm    Post subject: Reply with quote

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
View user's profile Send private message
themandem
Cheater
Reputation: 0

Joined: 06 Dec 2019
Posts: 35

PostPosted: Sun Aug 27, 2023 4:55 am    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites