MCH and SEH
MCH and SEH
Hi,
i'd like to solve an issue with MCH hooks breaking the SEH handling when the default setting.
Let's say we hook RPC function NdrClientCall2. RPC error reporting relies on exceptions. The problem is that MCH modifies return address to watch the hook counts. So once the exception is raised it does not propagate to the top of the stack and it ends as an unhandled exception.
Is there any way to enable SEH propagation in the MCH hooks? One way is to use NO_HOOK_COUNT flag, but that is only temporary solution, because app will then crash sometimes in manual unhooking.
One way would be to repair stack (that return address that MCH modifies) in the hook which i succesfully tried and it worked then. But the problem is the exception itself, because it does not call your "lower the hook count code" in the hook return so introducing a deadlock. It needs to be fixed by own exception handler that does calls your code "lower the hook count code" and then continues an exception.
It would nice to have some API for "fix ret address and handle SEH exception built-in MCH library". It would be also nice to have this feature available in all of the MCH hooks. Also debuggers stack trace will work better.
Any thoughts?
Sicerely
PP
i'd like to solve an issue with MCH hooks breaking the SEH handling when the default setting.
Let's say we hook RPC function NdrClientCall2. RPC error reporting relies on exceptions. The problem is that MCH modifies return address to watch the hook counts. So once the exception is raised it does not propagate to the top of the stack and it ends as an unhandled exception.
Is there any way to enable SEH propagation in the MCH hooks? One way is to use NO_HOOK_COUNT flag, but that is only temporary solution, because app will then crash sometimes in manual unhooking.
One way would be to repair stack (that return address that MCH modifies) in the hook which i succesfully tried and it worked then. But the problem is the exception itself, because it does not call your "lower the hook count code" in the hook return so introducing a deadlock. It needs to be fixed by own exception handler that does calls your code "lower the hook count code" and then continues an exception.
It would nice to have some API for "fix ret address and handle SEH exception built-in MCH library". It would be also nice to have this feature available in all of the MCH hooks. Also debuggers stack trace will work better.
Any thoughts?
Sicerely
PP
Re: MCH and SEH
Interesting problem. And a rather difficult one. Especially x64 will be tricky because the x64 exception handling is so much different. Basically each dll/exe has a list of except handlers. But the hook stubs installed by madExcept are dynamically created, so they don't have a registered except handler.
I'll add this as a possible feature to my madCodeHook 4.0 to do list, but I'm not sure yet if I'll be able to pull this off completely automatically in both x86 and x64.
I'll add this as a possible feature to my madCodeHook 4.0 to do list, but I'm not sure yet if I'll be able to pull this off completely automatically in both x86 and x64.
Re: MCH and SEH
Well,
as i think about that the best way would be not to modify ret address before the hook call, but at the end of that. So for the whole time of the hook and orig call the ret address will be original, but at the end of the hook we manually call function MchFixRetAddress. This function woud know the stack address of the last ret address of the caller of the hook and change it as your code does it now.
as i think about that the best way would be not to modify ret address before the hook call, but at the end of that. So for the whole time of the hook and orig call the ret address will be original, but at the end of the hook we manually call function MchFixRetAddress. This function woud know the stack address of the last ret address of the caller of the hook and change it as your code does it now.
Re: MCH and SEH
But that wouldn't help with "in use" counter. It would still not be decreased, making madCodeHook believe that the hook callback function is still in use.
Re: MCH and SEH
now:
caller calls Orig
jmp Hook, count++, modify ret address
Hook BC
call Orig
Hook AC
count--, jmp Orig Caller
new
caller calls Orig
jmp Hook, count++
Hook BC
call Orig
Hook AC, modify ret address
count--, jmp Orig Caller
caller calls Orig
jmp Hook, count++, modify ret address
Hook BC
call Orig
Hook AC
count--, jmp Orig Caller
new
caller calls Orig
jmp Hook, count++
Hook BC
call Orig
Hook AC, modify ret address
count--, jmp Orig Caller
Re: MCH and SEH
i see, in case of wxception it wont work
Re: MCH and SEH
An exception in the hooked API is really problematic. I think I do need to add an option to HookAPI() to enable "exception passthrough". But as I said, it will be *very* difficult to achieve, especially in x64.
Re: MCH and SEH
what if we add try-finally in our hook and call some MCH api to lower the count?
and use function if AbnormalTermination
and use function if AbnormalTermination
Re: MCH and SEH
Hmmmm... Good thinking, I think that should work! At least as a workaround, until I (maybe) manage to implement this properly in madCodeHook.EaSy wrote:what if we add try-finally in our hook and call some MCH api to lower the count?
Re: MCH and SEH
Great,
are you able to add some support to the MCH beta for this? It would help us to use RPC calls with MCH hook counting enabled!
Thx.
are you able to add some support to the MCH beta for this? It would help us to use RPC calls with MCH hook counting enabled!
Thx.
Re: MCH and SEH
One more problem comes in my mind is the EXCEPTION_CONTINUE_EXECUTION, does it mean that we will still need to have ret address fixed during the RaiseException? Because i think that finally is not called in this case during the exception.
Re: MCH and SEH
so we need something like this?
now:
caller calls Orig
count++, modify ret address, jmp Hook
Hook BC
call Orig
Hook AC
ret
count--, jmp Orig Caller
new
caller calls Orig
count++, jmp Hook
try {
Hook BC
call Orig
Hook AC
}
finally { count-- }
modify ret address
ret
count--, jmp Orig Caller
EDIT: i changed the code, because finally behaves differently in SEH
now:
caller calls Orig
count++, modify ret address, jmp Hook
Hook BC
call Orig
Hook AC
ret
count--, jmp Orig Caller
new
caller calls Orig
count++, jmp Hook
try {
Hook BC
call Orig
Hook AC
}
finally { count-- }
modify ret address
ret
count--, jmp Orig Caller
EDIT: i changed the code, because finally behaves differently in SEH
Re: MCH and SEH
Oh well, I think I misjudged it. For some reason I thought that your try..finally block would be "outside" of madCodeHook's hook stubs. But it would be inside, which makes things so much more complicated. I suppose you could use a try..except block instead of a try..finally block, and then in the except block decrease the "in use" counter *and* fix the return address, and then re-raise the exception. But that sounds really awful.
Re: MCH and SEH
I was able to implement SEH handling using __finally. It is very very ugly since I have to abuse your counting trampoline and fix ret address during the origcall processing both for 32b and 64b and call that trampoline manually in case of exception. But it works and SEH is propagated up the stack now.
This won't be crash free 100% since the __finally handler is in our DLL and it is not part of your hook trampoline, but I think we can live with 99% for now.
The best solution would be to support propagating SEH exceptions natively in all MCH hooks, but that is something you need to implement something like __try _finally in your trampoline and fix the stack accordingly. On 64b you said it is harder, but you could use this function RtlInstallFunctionTableCallbackmto register that callback.
PP
This won't be crash free 100% since the __finally handler is in our DLL and it is not part of your hook trampoline, but I think we can live with 99% for now.
The best solution would be to support propagating SEH exceptions natively in all MCH hooks, but that is something you need to implement something like __try _finally in your trampoline and fix the stack accordingly. On 64b you said it is harder, but you could use this function RtlInstallFunctionTableCallbackmto register that callback.
PP
Re: MCH and SEH
Yes, I'm aware of RtlInstallFunctionTableCallback, it's still not an easy thing to implement in a dynamically created assembler stub. Not something I want to introduce in a minor madCodeHook 3.x build, especially since I'm already working on v4. But it's on my to do list...