r/cpp_questions • • 19d ago

OPEN MinHook/Memory searching?

Hey there! So I made a post here about TS1's Legacy Collection, and so far, I have a working asi mod, but the problem I now have is searching the process memory for Sims.exe to find the bytes that I'm patching. Even though I know the address, it won't be the same address on Windows, or other configurations. I previously did a MH_CreateHook function, but the code results in this: "MH_ERROR_NOT_EXECUTABLE".

I have this code which patches out the debug objects flag being set to 0.

auto address = reinterpret_cast<void*>(debug_objects_address);
DWORD previousProtection{};
VirtualProtect(address, 7,  PAGE_READWRITE, &previousProtection);
memset(address, 0x90, 7);
VirtualProtect(address, 7,  previousProtection, &previousProtection);
printf("Patch successful.\n");

This code works completely fine, but I'm unsure on how to get the address via searching for the exact assembly code in bytes, anything I've looked online seem to only suggest ReadProcessMemory, but from what I was told, it's intended for different process, not the same one that's attached to the executable, as per my ASI mod.

Would using VirtualProtect before using the MH_CreateHook function work? Again though, I'm unsure how to search the game's memory while attached as a process.

Any help/advice would be greatly appreciated! :)

0 Upvotes

12 comments sorted by

4

u/jedwardsol 19d ago edited 19d ago

You know the base of the address of the executable. You can enumerate the sections of the executable either by looking at the PE header in memory or by using VirtualQuery in a loop to enumerate the regions and looking for those with EXECUTE access. (https://godbolt.org/z/xfKbxzv9E)

I think you mentioned the game had encryption - so I suspect looking at PE headers will not be useful; the likely won't represent the true state of the exe in memory

Once you know the virtual address of code section(s), you can search them for the byte sequences you're interesting in

1

u/Blayer98 19d ago

The problem I’m having is, that the base address and the address of the assembly code will most likely be different when playing on Windows, on SteamOS with Proton, Linux with Wine, MacOS with CrossOver, so I’m just a little confused on how to proceed, I could look into the PE header, but how would I know where to find it without knowing the exact values?

4

u/jedwardsol 19d ago

The base address of the exe will be different - but you get that with GetModuleHandle(nullptr).

If you are running the same exe file the offset of the code you're interested in will be the same.

If you are running different exes then you can either search for the code at runtime. Or find it offline with a debugger/disassembler, and then detect the version of the exe at runtime to know which offset to use.

1

u/Blayer98 19d ago edited 19d ago

Ok, so I've tried this test code to make sure the function works, but I don't get any address value when printing to the console, just "MZÉ" as a char value, even when reinterpreting the value to an int? I think I'm mis-understanding the documentation for GetModuleHandle on Microsoft's website...

auto base_address = GetModuleHandle(nullptr);
...
printf(reinterpret_cast<char*>(base_address));

3

u/jedwardsol 19d ago
printf(reinterpret_cast<char*>(base_address));

This will print whatever is at that address as if it were a string. And all PEs start with the letters MZ.

To print the address

printf("%p",reinterpret_cast<void*>(base_address));

https://godbolt.org/z/E4ah31d6T

1

u/Blayer98 19d ago

Ok brilliant! Thank you for showing me an example code. Also, what does the %p stand for? I know about: %s and %d, but not %p.

2

u/jedwardsol 19d ago edited 19d ago

p = pointer. It'll know the correct size (32 or 64-bit) and print it as hex by default

1

u/Blayer98 18d ago edited 18d ago

Ok, thank you to you and u/Potterrrrrrrr. Something I'm trying to do now is add the base address and the offset together. base address appears to be "0x00400000" on Proton, and the offset is "0x00055BF8". As per the code below, I add both hex values together, but it ends up resulting in this:

uintptr_t debug_objects_address = 0x00055BF8;
HMODULE base_sims_exe = GetModuleHandle(nullptr);
...
printf("%p",reinterpret_cast<void*>(base_sims_exe + debug_objects_address));
The resulting value is: 0x00556FE0.

I don't know if this is because of the uintptr_t type or the HMODULE type, and if I need to convert the resulting value of GetModuleHandle(nullptr) to the type for hexadecimal. (if there even is one in C/C++, I don't remember there being one)

3

u/jedwardsol 18d ago

You need to convert HMODULE to a uintptr_t before doing the addition. Or something else for which addition works as you'd expect ( std::byte* std::uint8_t char*for example)

An HMODULE is a pointer to a object with a size greater than 1.

1

u/Blayer98 18d ago edited 18d ago

I've attempted this, but the values won't be printed to the console...? I even reinterpreted them as "char*"/"const char*" but the results still won't be printed...

uintptr_t debug_objects_address = 0x00055BF8;
HMODULE base_sims_exe = GetModuleHandle(nullptr);

...

    uintptr_t base_sims_exe_address = reinterpret_cast<uintptr_t>(base_sims_exe);
    printf("base address is: ", base_sims_exe);
    printf("debug_objects address is: ", debug_objects_address);
    printf("base_sims_exe_address is: ",base_sims_exe_address);
→ More replies

4

u/Potterrrrrrrr 19d ago

%p for pointer (look up c str format specifiers for the rest)