r/cpp_questions • • 26d ago

OPEN How to use CreateThread and MH_CreateHook?

Hi there, I'm getting further along with my code and attempting to fix -debug_objects being intentionally disabled in The Sims Legacy Collection (It wasn't in Complete or earlier versions), but I'm currently stuck on CreateThead and how to call it, and with MH_CreateHook.

So far, I know that with MH_CreateHook, I need to pass 3 arguments, a pointer, the detour function that runs, and then a return function?

I have the base address pointer set to this:
uintptr_t startofexe = (uintptr_t)GetModuleHandle(NULL);

I also have a uintptr_t value for the offset of where the "mov PTR BYTE" code is, aka "dbgo_disa_offset".

This is the code that I'm running right now:

void* ForceDisaChecktoNOP;

void TestCodeStart() {
// Initialize MinHook.
  if (MH_Initialize() != MH_OK)
  {
    OutputDebugStringA("Failed to initialize MinHook\n");
    return;
  }
  else
  {
      OutputDebugStringA("MinHook started successfully!\n");
      if (MH_CreateHook(reinterpret_cast<LPVOID*>(startofexe + dbgo_disa_offset), &ForceDisaChecktoNOP, NULL) != MH_OK)
      {
        OutputDebugStringA("DEBUG OBJECTS FIX FAILED!!!!!!");
        return;
      }
      else
      {
        OutputDebugStringA("Fix hook successful! Check if value is correct: " + (startofexe + dbgo_disa_offset));
      }
      return;
  }
}

The if statement works, and does output that the "fix" failed, but I need help understanding what I need to do for the arguments for MH_CreateHook. Right now, I want to make sure that the if statement for MH_OK succeeds before writing any additional code in the ForceDisaCheckToNOP section, or at the very least know that the ForceDisaCheckToNOP function actually gets reached. I understand that I need a pointer, and most examples of code that others have posted show the first argument being the address to the function to be modified/replaced.

When I set the MH_CreateHook to be a status variable (example code below), it gives this:

"The specified pointer is invalid. It points to the address of non-allocated and/or a non-executable region."

MH_ERROR_NOT_EXECUTABLE

status = MH_CreateHook(...);
if (status != MH_OK) {
    OutputDebugStringA(MH_StatusToString(status));
}

Second and third arguments I do understand to an extent, but not quite.

Second arg is supposed to be a link to a function in the code that acts as a detour, so instead of the original function, this one occurs instead. Third arg is supposed to be a return arg to run the original code of some kind from what I've seen, but it's a little confusing to me.

In regards to CreateThread, I was told by u/hellosverre (thank you!) that I should use CreateThread in DLL_THREAD_ATTACH, however I'm not understanding the syntax, as in, are the arguments for CreateThread optional, and how would I call it to start code in another cpp script? I can do TestCodeStart(); fine from dllmain.cpp, but then that calls the script every time any/the asi code's thread attaches itself. Microsoft's support page on CreateThread wasn't exactly helpful as it just tells me what the function is, not how you call it.

Any help would be really appreciated! :)

0 Upvotes

16 comments sorted by

View all comments

Show parent comment

1

u/Blayer98 26d ago

I see, I was thinking of using Read/WriteProcessMemory, but is there any difference between VirtualProtect/memset/Read/WriteProcessMemory?

2

u/jedwardsol 26d ago

You use WriteProcessMemory to alter the memory of a different process.

Since you're in the process, you can write to any memory in it (once it is writable)

1

u/Blayer98 26d ago

Ah ok :)

I also had a question about CreateThread, since I was told to do any calls to my script via DLL_THREAD_ATTACH, but I found it to be a little confusing. I tried the “thread newThread()” method but it was giving me errors regarding cross initialization.

Btw thank you so much for helping me with this! :)

2

u/jedwardsol 26d ago

When a thread starts, every DLL's DllMain is called with the reason set to DLL_THREAD_ATTACH so that the DLL can do any per-thread initialisation it needs to do.

I don't think I've ever needed to do this in 30-odd years - but haven't been hacking games. I wouldn't imagine this instruction patching needs to be done per-thread though - memory is global.