使用mhook钩住ZwCreateSection(),CreateProcess()和CreateProcessEx()来阻止某些应用程序启动 [英] Hook ZwCreateSection(), CreateProcess() and CreateProcessEx() using mhook to block certain application from launching

查看:144
本文介绍了使用mhook钩住ZwCreateSection(),CreateProcess()和CreateProcessEx()来阻止某些应用程序启动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用mhook在CreateProcess(),CreateProcessEx()或ZwCreateSection()上创建全局钩子,以便可以阻止某些应用程序启动.我遵循了 https://www.apriorit.com/dev-blog/160个apihooks .但这似乎不起作用.是否有可能,如果是,请提供任何建议. 我尝试使用以下代码记录使用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. 您确定您的DLL已注入到正在生成您要监视其创建的程序的进程中吗?
  2. 您是否已与调试器进行了检查,以确保所使用的库成功钩住了例程?

调试另一个进程(例如explorer.exe),并在回调上断点的同时注入您的DLL.然后运行任何非高架程序,并查看断点是否命中.由于以下两个原因之一,它不会命中:钩子例程未被调用;或挂钩从未设置.

您还应该首先在本地过程中测试这些内容,就像注释中提到的@RbMm一样.采纳他的建议,您的生活将会更加幸福.


一般说明

首先,请不要在Win32 API的API挂钩方面碰到它,除非您想要任何人都可以理解的最有缺陷的设计实现.

  1. 您可以修补NtResumeThread(NTDLL),然后进行检查以确定是否在进程创建过程中调用了它.当您生成程序时,负责进程创建操作的进程将调用NtResumeThread来恢复新创建的进程的主线程.
  2. 或者,只要您不打算在Windows Vista之前支持任何操作系统版本,就可以修补NtCreateUserProcess(NTDLL).但是,出于严重的安全原因,不应再使用Windows 2000和Windows XP,并且很长一段时间以来都不再支持Windows 2000和Windows XP,因此,我希望您不要完全专注于它们.

以上两种想法都比依靠Win32 API来完成您要执行的操作要好,但是它们仍然是非常糟糕的想法.我会解释一些原因.

  1. 在其他进程的内存中修补虚拟内存以拦截进程的创建通常是一个坏主意,应尽量避免,因为您可能会引入其他漏洞(例如,在回调例程/帮助例程中给内存留一些标志或错误)可能会被滥用)并导致程序不稳定.
  2. 绕过用于API挂钩的用户模式修补非常简单,对于执行内存修补以花费较长时间来防止这些绕过的情况,您可能会造成比以前更大的危害(例如,性能降低,故障,潜在漏洞等).绕过针对Win32 API的API挂钩的示例是自己重新实现Win32 API例程,而绕过NTAPI上的API钩子的示例则是自己执行系统调用.
  3. 即使您要修补NTAPI,对于以管理员身份启动的程序,您用于进程创建的API钩子也无法正常工作.这样做的原因是因为当您以管理员身份生成程序时,相反会起作用.我认为同意.exe仍然是一个受保护的进程(如果我不记得,您可以仔细检查,以防万一我不正确-尽管如果这是一个受保护的进程在逻辑上是合理的),那么您就不会仍然无法将您的代码注入其中(更不用说在99.9%的时间中,对诸如accept.exe这样的过程执行这样的事情是完全不负责任的.)


对于Windows Vista和Windows 7,您可以将代码注入csrss.exe,然后修补CsrCreateProcess(由csrss.exe所依赖的模块导出).这比将代码注入到多个流程中更为可靠(并且还将用于监视提升流程中的流程创建),但是就稳定性和安全性而言,这仍然不是一个好主意.您需要启用SeDebugPrivilege才能触摸crsss.exe进行记录.

对于csrss.exe是受保护进程的Windows的较新版本,您可以在lsass.exe之类的进程中修补NtOpenProcess(NTDLL).但是,对于稳定性和安全性又是一个坏主意-更不用说不能保证这将始终是100%可靠的事实.这仅是您可以尝试进行教育实验的估计值.您还需要考虑lsass.exe是受保护进程的可能性(可以通过修改注册表来启用它-并且出于安全原因,每个人都应该这样做).

以上两种想法由于其自身的原因也是不好的.


有Windows Management Instrumentation(WMI),可用于接收有关创建新进程的通知,但不会表现为拦截".它的行为类似于创建后的通知.但是,如果您需要做的只是日志流程创建,那么它大概是您可以在用户模式下做的最好的事情,而不会弄乱未记录的行为,并且从关注安全性,稳定性和效率的角度来看,这是最好的选择.

上述想法是一个好的例子,应该是安全,有效,稳定和有据可查的.


监视进程创建的最佳方法(需要确定允许/阻止操作的方法)是使用PsSetCreateProcessNotifyRoutine回调通过内核模式设备驱动程序.请记住,对于较新版本的Windows,还存在该回调例程的Ex *和Ex2 *版本.

内核模式下的另一种方法是通过PsSetLoadImageNotifyRoutine/Ex(然后过滤NTDLL.DLL)或通过PsSetCreateThreadNotifyRoutine(并保留自己的带有线程ID的进程监视日志,以确定线程创建是否是第一个针对线程的方法)处理).


现在,关于DLL注入,请勿使用AppInit_DLL.这是完成您在原始帖子中尝试执行的操作时最有缺陷的机制之一.即使我不同意您的设计,也最好解释一下为什么它是一个有缺陷的设计.

AppInit_DLLs仅会影响已加载User32.dll的程序,这意味着您的监视将受到严格限制/不可靠.您将无法跨非GUI程序监视进程的创建(这些程序很少导入User32.dll,例如Windows Service甚至是不依赖于User32相关内容的控制台进程,例如消息框等).

更好的RCE方法将具有特权进程(因此,获得进程句柄的限制更少)依赖于远程线程创建/异步过程调用来触发执行简单且格式正确的shell代码(它将在该阶段之前写入进程的虚拟内存)以调用LdrLoadDll(NTDLL).只要注入的DLL也是本机的,这还将允许注入到本机进程(不依赖任何Win32 API模块的进程)中.


总的来说,作为一般性评论,您真的不想继续尝试寻求您的帮助(挂钩Win32 API),并且提到了我提到的用于完成过程创建监视的其他挂钩方法.仅出于理论目的,并非旨在实际建议您采用这些方法.我不能太强调重点放在文档和稳定性上是很重要的,因为尽管您现在可能不相信它,但是尝试做一些像您当前正在尝试的设计那样的事情,却很容易使您陷入困境.彻底破坏.我一点也不夸张.

请记住,执行远程代码执行通常是一个坏主意,请仅在没有其他方法的情况下执行此操作.一个可能真正需要它的例子是AV供应商试图开发一个行为阻止程序/HIPS,但是没有内核模式回调来过滤他们试图过滤的内容(并且他们可能没有通过英特尔提供的虚拟化支持) VT-x或AMD SVM来控制x64上的内核,而不会引起错误检查).一个糟糕的理由是,目的只是简单地记录"流程创建,尤其是当有诸如WMI之类的可用选项具有此功能时.

请不要采取这种错误的方式,但是我从经验中了解到,API挂钩确实并不能一直解决问题,通常需要考虑一种更好的设计.有时您可能确实必须依赖它,但是根据我所看到的,大多数询问它的人甚至根本不需要依赖它.

如果这不仅是实验,而且是针对生产级别的,请采用WMI或内核模式设备驱动程序方法.如果您采用内核模式设备驱动程序方法,请在内核模式下尽可能少地做,并在用户模式服务进程中处理过滤.

祝你好运.

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;
}

解决方案

Carrying on from the notes in the original post comments:

  1. Are you sure that your DLL was injected into the process which is spawning the program you're trying to monitor creation of?
  2. 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.

  1. 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.
  2. 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.

  1. 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.
  2. 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.
  3. 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.

这篇关于使用mhook钩住ZwCreateSection(),CreateProcess()和CreateProcessEx()来阻止某些应用程序启动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆