- Joined
- Aug 6, 2011
- Messages
- 405
- Reaction score
- 3
- Points
- 18
So I've been working some more on catch-ctd...
Now I want to hook every module that Orbiter loads.
If the module uses the new module method (inheriting from oapi::Module and registering that), hooking is really easy. I just simply create a module proxy to forward the events to the real module.
The issue is when a module is using the deprecated method, overloading the opc callbacks.
The issue is, unlike vessels, where the vessel DLL is called through LoadLibrary just prior to vessel creation, that I don't have any context.
I need to, if they exist, hook the following methods:
in every DLL. However, if I only use one function (so redirect all the opcPreStep functions to MyOpcPreStep), I don't know which original function to call!
The replacement function has to have the same signature of the original, so I can't pass additional data to MyOpcPreStep, and Orbiter doesn't reload the module DLL, so I can't use the "hint" method I used for vessel hooking.
I thought of a possible solution, which would be to define a MyOpcPreStep with an additional argument, designating which original function to call. Then, I would create a bunch of stubs that would look like this:
Then, for each new module, hook the original functions for that module to an unused stub.
The downside to this is I potentially need to create a lot of stubs. Even if I created 1000 stubs, it's still possible for catch-ctd to stop working with an obnoxious amount of addons installed.
As I was thinking about the stubs, they are all basically the same. Is there a way to create them at runtime? I know I can allocate memory, write bytes in that represent those functions, and mark it executable, get a pointer to the memory, and cast it to a function pointer. This should be "technically" doable, I just don't know how to start.
As to the calling convention (my knowledge is very sketchy), would the following work?
1. Write a MyOpcPreStep, with an additional first argument as an index to some vector that stores the original functions.
2. Write a naked stub function that pushes an integer to the stack, then jumps to MyOpcPreStep
3. Somehow convert that to bytes and malloc memory for the stub function, set it executable, and set it as the hook destination.
Because the naked function doesn't screw the stack, and the opcPreStep should (I think) use the _cdecl calling convention, arguments are pushed in reverse order.
The stub's push/jump to MyOpcPreStep would then effectively insert the additional info needed for MyOpcPreStep!
If that sounds legit, how do I do number 3?
---------- Post added at 04:38 PM ---------- Previous post was at 04:33 PM ----------
Here's how I imagine that would work:
Now I want to hook every module that Orbiter loads.
If the module uses the new module method (inheriting from oapi::Module and registering that), hooking is really easy. I just simply create a module proxy to forward the events to the real module.
The issue is when a module is using the deprecated method, overloading the opc callbacks.
The issue is, unlike vessels, where the vessel DLL is called through LoadLibrary just prior to vessel creation, that I don't have any context.
I need to, if they exist, hook the following methods:
Code:
opcOpenRenderViewport
opcCloseRenderViewport
opcPreStep
opcPostStep
opcFocusChanged
opcTimeAccChanged
opcPause
opcDeleteVessel
The replacement function has to have the same signature of the original, so I can't pass additional data to MyOpcPreStep, and Orbiter doesn't reload the module DLL, so I can't use the "hint" method I used for vessel hooking.
I thought of a possible solution, which would be to define a MyOpcPreStep with an additional argument, designating which original function to call. Then, I would create a bunch of stubs that would look like this:
Code:
MyOpcPreStep_helper1(original_prestep_args)
{
MyOpcPreStep([b]1[/b], original_prestep_args);
}
MyOpcPreStep_helper2(original_prestep_args)
{
MyOpcPreStep([b]2[/b], original_prestep_args);
}
Then, for each new module, hook the original functions for that module to an unused stub.
The downside to this is I potentially need to create a lot of stubs. Even if I created 1000 stubs, it's still possible for catch-ctd to stop working with an obnoxious amount of addons installed.
As I was thinking about the stubs, they are all basically the same. Is there a way to create them at runtime? I know I can allocate memory, write bytes in that represent those functions, and mark it executable, get a pointer to the memory, and cast it to a function pointer. This should be "technically" doable, I just don't know how to start.
As to the calling convention (my knowledge is very sketchy), would the following work?
1. Write a MyOpcPreStep, with an additional first argument as an index to some vector that stores the original functions.
2. Write a naked stub function that pushes an integer to the stack, then jumps to MyOpcPreStep
3. Somehow convert that to bytes and malloc memory for the stub function, set it executable, and set it as the hook destination.
Because the naked function doesn't screw the stack, and the opcPreStep should (I think) use the _cdecl calling convention, arguments are pushed in reverse order.
The stub's push/jump to MyOpcPreStep would then effectively insert the additional info needed for MyOpcPreStep!
If that sounds legit, how do I do number 3?
---------- Post added at 04:38 PM ---------- Previous post was at 04:33 PM ----------
Here's how I imagine that would work:
- Detours inserts a hook to the generated stub
- Orbiter calls some module's opcPreStep
- The detoured stub, which is inserted before the original function could mess with the stack, does a straight JMP to the stub
- The stub is also a naked function, doesn't screw the stack. That function pushes an unsigned int to the stack, then JMPs to MyOpcPreStep
- Because the signature on MyOpcPreStep is (unsigned int, original_prestep_args), it calls correctly