Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Concerns with increasing: MAX_MEMORY_RANGE? (FindPrevFreeRegion and FindNextFreeRegion return NULL) #107

Open
dmner opened this issue Jan 5, 2023 · 9 comments

Comments

@dmner
Copy link

dmner commented Jan 5, 2023

Hi,

I'm attempting to hook a function in mono (which I suspect is part of why this is hit or miss). Randomly I'll get MH_ERROR_MEMORY_ALLOC errors while trying to hook the function. I suspect this is because it depends entirely on where the function got JITted to. stdlib functions seem to have the best results, but that is likely just because they get JITted first. I locally increased the MAX_MEMORY_RANGE constant by a factor of 2 to see if that would improve things and it did. Are there any concerns with increasing this value, will it cause unintended consequences?

Thanks

@m417z
Copy link
Collaborator

m417z commented Jan 6, 2023

Hi,

I encountered this problem before, see #10. Back then, MAX_MEMORY_RANGE was much smaller and the error was much more likely. I increased the range to 0x40000000, assuming that it will be good enough for all practical usages. Looks like sometimes, even that's not enough.

You can increase the value, but increasing it by a factor of 2 (i.e. to 0x80000000) can be dangerous since the distance between the target function and the relay function must be less than 0x7FFFFFFF/0x80000000:

; x64 mode (assumed that the target function is at 0x140000000)

; 32bit relative JMPs of 5 bytes cover about -2GB ~ +2GB
0x140000000: E9 00000080      JMP 0xC0000005  (RIP-0x80000000)
0x140000000: E9 FFFFFF7F      JMP 0x1C0000004 (RIP+0x7FFFFFFF)

; Target function (Jump to the Relay Function)
0x140000000: E9 FBFF0700      JMP 0x140080000 (RIP+0x7FFFB)

; Relay function (Jump to the Detour Function)
0x140080000: FF25 FAFF0000    JMP [0x140090000 (RIP+0xFFFA)]
0x140090000: xxxxxxxxxxxxxxxx ; 64bit address of the Detour Function

(from https://www.codeproject.com/Articles/44326/MinHook-The-Minimalistic-x-x-API-Hooking-Libra)

With the 0x80000000 constant, there's a rare possibility to get a larger distance. Also, if 0x40000000 is sometimes not enough, can you be sure that 0x80000000 will be enough in all cases? Perhaps in your case it's better to patch the target function itself with an absolute jump, if there's enough space for it.

@ethanporcaro
Copy link

I have this same issue sometimes, and even increasing the MAX_MEMORY_RANGE to 0x70000000 still won't work sometimes. You mentioned using an absolute jump, I would need to make some changes to the source, right? I'm not afraid of making changes but assembly is really difficult for me. Do you have any ideas?

@m417z
Copy link
Collaborator

m417z commented Feb 11, 2023

I would need to make some changes to the source, right?

Yes, you'll need to do mainly 2 changes:

  • Get rid of the relay function. Luckily, 32-bit already works that way, so you can just remove the code that's defined for 64-bit (some of the #if defined(_M_X64) || defined(__x86_64__) blocks).
  • Change the code that patches the jump at the beginning of the function. You're less lucky here as here it's the other way around, both 32-bit and 64-bit share an implementation, and you'll need to change it for 64-bit. Here's where the jump is patched. You'll need to patch an absolute jump instead, which is 14 bytes in size instead of 5.

@ethanporcaro
Copy link

ethanporcaro commented Feb 11, 2023 via email

@ethanporcaro
Copy link

I've been working on the changes. I tested them and they seem to work. One question, with the absolute jump, that would mean MAX_MEMORY_RANGE is no longer a constraint, because an absolute jump is absolute? So I can set it to something ridiculously high as long as it is less than the maximum value of an unsigned 64 bit integer?

@m417z
Copy link
Collaborator

m417z commented Feb 13, 2023

Not only that, you no longer need the FindPrevFreeRegion/FindNextFreeRegion functions and the relevant logic. This comment now applies to your 64-bit implementation as well and the same simple VirtualAlloc call can be used:

// In x86 mode, a memory block can be placed anywhere.

@m417z m417z changed the title Concerns with increasing: MAX_MEMORY_RANGE? Concerns with increasing: MAX_MEMORY_RANGE? (FindPrevFreeRegion and FindNextFreeRegion return NULL) Feb 22, 2023
@m417z
Copy link
Collaborator

m417z commented Feb 22, 2023

@EthanZoneCoding, @g0dzcsgo what is the target program/environment that you're having this problem in?
@dmner mentioned Mono, I'm wondering what other targets have this problem and what do they have in common (JITted code?). If this problem is common, perhaps it's a good idea to implement a fallback as discussed here into MinHook. I don't like it that much, since that means that these cases will only support functions which are at least 14 bytes long, but that's better than the current state of just failing.

@ethanporcaro
Copy link

I've been adding VR support to a game via hooking things like DirectX and internal game functions. DirectX is fine, but the internal function is hit or miss when the levels are loaded (it's a large game). That is why I thought the problem could be not finding a place to put in within the range.

@CNLouisLiu
Copy link

Is there a new solution to this problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants