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

Compatibility with Microsoft's new "ProcessDynamicCodePolicy" #39

Closed
karliwson opened this issue Feb 3, 2017 · 9 comments
Closed

Compatibility with Microsoft's new "ProcessDynamicCodePolicy" #39

karliwson opened this issue Feb 3, 2017 · 9 comments

Comments

@karliwson
Copy link

karliwson commented Feb 3, 2017

In Windows 10 Windows 8, Microsoft introduced ProcessDynamicCodePolicy, a new security feature that forbids allocating or protecting dynamically allocated memory with PAGE_EXECUTE_READWRITE or any execution permission. It breaks MinHook, because it allocates virtual memory with that protection.

MH_CreateHook() returns MH_ERROR_MEMORY_ALLOC, and the exact error is:

#define STATUS_DYNAMIC_CODE_BLOCKED 0xC0000604

Steps to reproduce the error:

Inject something that uses MinHook into Microsoft Edge's content process ( MicrosoftEdgeCP.exe ) or any other process that uses "Dynamic code prohibited" policy.

Here's a screenshot of the process' information:

http://prntscr.com/e3wekq


I'm not familiar with the way MinHook handles memory, but I guess that it could simply allocate memory with PAGE_READWRITE protection and set it to PAGE_EXECUTE_READ when a hook is created using that memory piece.

@karliwson
Copy link
Author

Update:

I've tried that and it didn't work. Even protecting with PAGE_EXECUTE_READ returns STATUS_DYNAMIC_CODE_BLOCKED. Seems like you can't allocate or protect virtual memory with execution permission.

@m417z
Copy link
Collaborator

m417z commented Feb 3, 2017

From MSDN:

ProcessDynamicCodePolicy
When turned on, the process cannot generate dynamic code or modify existing executable code.

If existing executable code cannot be modified, then we cannot even set a trampoline. So allocating executable memory is a secondary issue here.
If only Edge's module has to be hooked, you can try IAT hooking, which can be implemented relatively easily without MinHook.

@karliwson
Copy link
Author

karliwson commented Feb 3, 2017

The executable code can be modified. In one of my tests, I changed minhook's allocation to PAGE_READWRITE just to pass the problem and see if it could set the JMP in the original code, and it did. Of course, it caused an exception when the function jumped to the trampoline, because the trampoline memory was not executable.

I trying to figure out how BlackBone can remotely map modules into processes protected by ProcessDynamicCodePolicy. It can create dynamic executable memory somehow. I use it to inject (manually map) my module, and the module runs without problems, proving that there's a way to execute dynamic code in the process.

@karliwson karliwson changed the title Compatibility with Microsoft's new "Dynamic code prohibited" policy Compatibility with Microsoft's new "ProcessDynamicCodePolicy" Feb 3, 2017
@m417z
Copy link
Collaborator

m417z commented Feb 3, 2017

In this case, I believe that reserving some space inside MinHook's code section and using it for the trampolines might work for supporting a fixed amount of hooked functions. For 64-bit, that's not a complete solution, as the code section might be located too far from the hooked function to be supported by a short jump.

That's some food for thought. I didn't think about it thoroughly, neither did I look at BlackBone - perhaps they have thought of a more elegant solution.

@karliwson
Copy link
Author

Seems to be a way. Regarding 64-bit, couldn't we use a MOV / CALL (maybe it's not a good option because it screws one register) or PUSH / RET instead of a JMP?

@m417z
Copy link
Collaborator

m417z commented Feb 7, 2017

We could, and it would work, but it would require to patch about 10 bytes instead of 5. The result is that short functions won't be supported. It might, or might not, work for you, depending on your needs.

@TsudaKageyu
Copy link
Owner

This just came to my mind, 6-byte absolute indirect JMP would work.
If we patch a function with FF 25 xx xx xx xx, the absolute destination address should be stored in the memory which is pointed by the 32-bit relative address xxxxxxxx and allocated with PAGE_READWRITE flag. If the destination address works without EXECUTE flag, we would be able to use PAGE_READ instead of PAGE_EXECUTE_READ.

@codypierce
Copy link

FYI this is also a potential security issue on Windows 7+ systems without this policy. Here is a BlackHat presentation covering the issues.

https://www.blackhat.com/docs/us-16/materials/us-16-Yavo-Captain-Hook-Pirating-AVs-To-Bypass-Exploit-Mitigations-wp.pdf

@karliwson
Copy link
Author

@codypierce That's true, allocating or changing executable memory in processes with that mitigation policy is now completely prohibited (I've tested in MS Edge on Windows 10 1703). It won't be possible to even patch the original function, because we can't change its memory from RX to RWX. Thus, it's not possible to use the indirect jump as @TsudaKageyu suggested.

As of now, I've only seen MS Edge (content child processes) and Google Chrome (renderer child processes) using that mitigation policy.

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