问题
I am trying to use mhook to create a global hook on CreateProcess(), CreateProcessEx() or ZwCreateSection() so that i can block certain application from launching. I followed the steps provided at https://www.apriorit.com/dev-blog/160-apihooks. But it doesn't seems to work. Is it even possible and if yes please provide any suggestion. I tried the following code to log every process creation using CreateProcess().
#include "stdafx.h"
#include<fstream>
#include "mhook/mhook-lib/mhook.h"
typedef BOOL (WINAPI *_CreateProcess)(
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);
_CreateProcess TrueCreateProcess =
(_CreateProcess)::GetProcAddress(::GetModuleHandle(L"kernel32"),"CreateProcess");
BOOL WINAPI HookCreateProcess(
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
)
{
std::wofstream out;
out.open("D:\\Log.txt",std::ios_base::app);
if(out!=NULL)
{
out<<"Process Created\n";
}
return TrueCreateProcess(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
}
BOOL WINAPI DllMain(
__in HINSTANCE hInstance,
__in DWORD Reason,
__in LPVOID Reserved
)
{
switch (Reason)
{
case DLL_PROCESS_ATTACH:
Mhook_SetHook((PVOID*)&TrueCreateProcess, HookCreateProcess);
break;
case DLL_PROCESS_DETACH:
Mhook_Unhook((PVOID*)&TrueCreateProcess);
break;
}
return TRUE;
}
回答1:
Carrying on from the notes in the original post comments:
- Are you sure that your DLL was injected into the process which is spawning the program you're trying to monitor creation of?
- Have you checked with a debugger to make sure that the library you're using was successful in hooking the routine?
Debug another process like explorer.exe and inject your DLL whilst break-pointing on the callback. Then run any non-elevated program and see if the break-point hits. It won't hit for one of two reasons: the hooked routine is not being invoked; or the hook was never set.
You should test these things in a local process first as @RbMm mentioned in the comments as well. Take his advice with that on-board and your life will be happier.
General notes
Firstly, do not touch the Win32 API for this in terms of API hooking unless you want the most flawed design implementation anyone could ever fathom.
- You can patch NtResumeThread (NTDLL) and then do checks to determine whether it is being invoked as part of process creation or not. When you spawn a program, the process responsible for the process creation operation will invoke NtResumeThread to resume the main thread of the newly created process.
- Alternatively, you can patch NtCreateUserProcess (NTDLL) as long as you do not plan on supporting any OS versions before Windows Vista. However, Windows 2000 and Windows XP should not be used anymore for serious security reasons and have not been supported for a long time now, therefore I hope you are not focused on them at all.
Both of the above ideas are better than relying on hooking the Win32 API for what you're trying to do, but they are still pretty bad ideas. I'll explain a few reasons as to why.
- Patching the virtual memory of other process's memory to intercept process creation is a bad idea in general and should be avoided as much as possible because you can introduce additional vulnerabilities (e.g. leaving memory with certain flags or mistakes in callback routines/helper routines which can be abused) and cause instability for the program.
- Bypassing user-mode patching for API hooking is extremely simple to do, and for one performing the memory patching to take great lengths to prevent those bypasses, you can end up causing even more harm than you previously were (e.g. performance slow-downs, potential vulnerabilities, etc.). An example of bypassing an API hook targeting the Win32 API would be to re-implement the Win32 API routine yourself, and an example of bypassing an API hook on the NTAPI would be to perform the system call yourself.
- Your API hooking for process creation is not going to work for programs being started up as administrator, even if you were to patch the NTAPI instead. The reason for this is because when you spawn a program as administrator, consent.exe comes into play instead. I believe that consent.exe is a Protected Process anyway (you can double check say on-case I am incorrect since I cannot remember - although it'd make logical sense if it was a Protected Process) and if it is, then you wouldn't be able to inject your code into it anyway (not to mention that doing such a thing for a process like consent.exe would be totally irresponsible 99.9% of the time).
For Windows Vista and Windows 7, you could go as far as injecting code into csrss.exe and then patching CsrCreateProcess (exported by a module which csrss.exe relies on). It would be more reliable than injecting code into multiple processes (and will also work for monitoring process creation on elevated processes) but it is still a bad idea in terms of stability and safety. You'll need to enable SeDebugPrivilege to touch csrss.exe for the record.
For newer versions of Windows where csrss.exe is a protected process, you could patch NtOpenProcess (NTDLL) in a process like lsass.exe. However, once again, bad idea for stability and safety - not to mention the fact that there is no guarantee this will be 100% reliable all of the time. This is merely just an estimate you could try for educational experiments. You'd also need to take into account of the possibility that lsass.exe is a Protected Process (there's an option to enable it via modifying the Registry - and everyone should be doing this for security reasons anyway).
Both of the above ideas are also bad for their own reasons.
There is Windows Management Instrumentation (WMI) which can be used to receive notifications for new process creation, but it won't behave as an "interception". It'll behave like a post-creation notification. However, if all you need to do is log process creation, it is more-or-less the best thing you can do from user-mode without messing with undocumented behavior and from a point-of-view focusing on security, stability and efficiency.
The above idea is an example of a good one which should be safe, efficient, stable and documented.
The best approach for monitoring process creation (where you would need to decide on allowing/blocking the operation) would be via a Kernel-Mode device driver, using the PsSetCreateProcessNotifyRoutine callback. Bear in mind, there's also an Ex* and Ex2* version of that callback routine for newer versions of Windows.
An alternative approach from Kernel-Mode would be via PsSetLoadImageNotifyRoutine/Ex (and then filtering for NTDLL.DLL) or via PsSetCreateThreadNotifyRoutine (and keeping your own process monitoring logs with thread IDs to determine if the thread creation is the first for the process it is for).
Now, in regards to DLL injection, do not use AppInit_DLLs. That is one of the most flawed mechanisms for accomplishing what you were trying to do in the original post. Even if I disagree with your design, I may as well explain why it is a flawed design.
AppInit_DLLs will only affect programs which have User32.dll loaded, which means your monitoring would be heavily limited/unreliable. You would be blocked off from monitoring process creation across non-GUI programs (which rarely import User32.dll - like a Windows Service or even a console process which doesn't rely on anything User32-related like Message Boxes, etc).
A better RCE method would be having a privileged process (so you are less-restricted in regards to obtaining process handles) which relies on Remote Thread Creation/Asynchronous Procedure Calls to trigger execution of simple and well-formed shell-code (which would be written to the process's virtual memory prior to that stage) to call LdrLoadDll (NTDLL). This would also allow injection into a Native process (a process not relying on any Win32 API modules), as long as the injected DLL was also native.
Overall though, and as a general comment, you really do not want to continue trying to do what you're asking for help with (hooking the Win32 API) and the other hooking methods I mentioned for accomplishing process creation monitoring is mentioned for theoretical purposes only, not with the intention of actually suggesting you take those paths. I cannot stress enough that it is important to focus on documentation and stability, because while you may not believe it now, trying to do things like you're currently trying to do with the design you've come up with, can easily mess you over and wreck havoc. I'm not exaggerating at all.
It is important to remember that performing Remote Code Execution is generally a bad idea, please only do it if there is no other way. An example of when it may be genuinely required would be an AV vendor trying to develop a Behavior Blocker/HIPS, but there not being a kernel-mode callback to filter what they are trying to filter (and they may not have virtualization support via Intel VT-x or AMD SVM to control the kernel on x64 without causing bug-checks). A lousy justification for it would be where the purpose is to simply "log" process creation, especially when there are options like WMI available which have functionality for just that.
Please don't take this the wrong way, but I've learnt from experience that API hooking really is not the answer all the time, and there is usually a better design to be considered. Sometimes you may really have to rely on it, but based on what I've seen, most asking about it really do not need to even rely on it.
If this isn't just an experiment, and if this is for production-level, take the WMI or Kernel-Mode device driver approach. If you take the Kernel-Mode device driver approach, do as little as possible from Kernel-Mode and handle filtering from within a User-Mode service process.
Good luck.
来源:https://stackoverflow.com/questions/50966351/hook-zwcreatesection-createprocess-and-createprocessex-using-mhook-to-blo