When I call next hook inside my callback funtion in 64-bit native windows process (sc.exe, svchost.exe, ..),
the process crashed with C0000409 (Security check failure or Stack buffer overrun)
I verified it is Hardware-enforced Stack Protection.
https://techcommunity.microsoft.com/t5/ ... -p/2163340
If you hook a process with CET compatibility mode, the process will be terminated from kernel.
Is there any way to avoid this?
We are recently aware of this issue and we are seeing what can possibly be done about it but as of this moment we do not have a workaround unfortunately. Does this only seem to happen in critical processes then? I imagine only those processes built with the CET linker setting?
But some svchost are activated and others are disabled.
To enable shadow stack enforcement statically, you need to compile with linker setting(/CETCOMPAT).
Then IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT bit will be written to PE header (https://docs.microsoft.com/en-us/window ... cteristics)
Applications can also choose to dynamically enable shadow stack enforcement, by using the PROC_THREAD_ATTIBUTE_MITIGATION_POLICY attribute in CreateProcess. This allows programs with multiple executables with the same name to specify specific processes to enable enforcement.
Also there is SetProcessDynamicEnforcedCetCompatibleRanges API to set dynamic enforced CETCOMPAT ranges for the specified process from outside the target process.
I guess HSP checks on RET instruction.
As far as I remeber, x64 stack frame chain was broken inside callback function in older madCHook version.
Does current madCHook use RET to call next hook?
If then, is there any flag or method to hook without using RET (only JMP or something)?
The issue probably happens if the API you're hooking has a JMP or CALL instruction in the first 5 or 6 bytes of its API code. In that case madCodeHook currently uses a PUSH + RET logic in x64 in some situations in order to replace a relative JMP/CALL instruction (which can only go +/- 2GB far) with a true 64bit JMP/CALL.
I also don't think this will be a simple fix after reading more in-depth about CET. For example, I guess it's also watching context changes so (e.g: NtContinue) can't be adjusted, well then this would be a major issue when it came to setting a new EIP/RIP inside any exception handler. Also, CET checks not only for RET but also CALL, JMP and Indirect Branching, so it's going to be VERY difficult to make such adjustments to both MCH and madExceptIt's not an easy fix, though.
I'm not too worried about exception handling. I don't recall madCodeHook using that. For madExcept, it doesn't matter all too much, because CET will likely not be enabled for processes which don't have the "CET compatible" flag set.
it validates a lot of things to prevent quite a lot of binary instruction manipulations, included but not limited to IP validation.
I don't think just fixing up stubs to not look like ROP will make it compatible. I'm also aware that 99% of madExcept users control their own binary compilation and distribution but some certainly will not like the idea of not using the /CETCOMPAT linker flag, and those that are using portion of madExcept inside an injected DLL (I know a couple customers that do this personally) are also injected into processes that they have no control over come compilation time. MCH is the larger issue here, of course. With Delphi and madExcept it shouldn't matter though like you said.
I was reading that AMD's Zen 3 architecture will also have support for this, I have a Ryzen 3950x but it's based on Zen 2 so I still can't confirm what works vs. what is a violation, sadly.
P.S: I checked the MCH .pas unit (a lazy CTRL + F search for eip :=) and I do see EIP/RIP adjusted in small portions of an exception handler contained within, I think this will also be considered a violation, but guessing. Until we can personally test we won't know of course.
The link talks about "the call" failing, but they don't mean CALL but instead "the call to NtSetContext", where the "to NtSetContext" being implied.
Maybe it's me who is overthinking things, sure would like to be able to test directly instead of reading multiple documents. But, you may in fact be right and only need to address a couple things and not several. Check the Blackhat link for a lot more of the technical details, the first link doesn't have all of them.
We'll just have to test all areas where binary code is altered to see if they're a violation, in a nutshell.
Yes, very.it still needs carefully written assembler stubs
https://techcommunity.microsoft.com/t5/ ... -p/1247815madshi wrote: ↑Tue Mar 09, 2021 10:11 pm I don't see anything about CALL and JMP instructions being watched in the first link. Yes, CALL instructions get special handling, but only for the purpose of "filling" the shadow stack, so that the RET return address can be verified successfully. Other than that, I don't see any special handling for CALL and JMP mentioned. Or did I miss something?
Windows seems to support Shadow Stack, not Indirect Branch Tracking of CET.
Control-flow Enforcement Technology (CET) provides the following capabilities to defend against ROP/JOP
style control-flow subversion attacks:
Shadow Stack – return address protection to defend against Return Oriented Programming,
Indirect branch tracking – free branch protection to defend against Jump/Call Oriented Programming.
https://software.intel.com/sites/defaul ... review.pdf