使用mhook挂钩ZwCreateSection(),CreateProcess()和CreateProcessEx(),以阻止某些应用程序启动

时间:2018-06-21 10:33:07

标签: c++ winapi hook

我正在尝试使用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 个答案:

答案 0 :(得分:1)

继续使用原始帖子评论中的注释:

  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供应商试图开发一个Behavior Blocker / HIPS,但是没有内核模式回调来过滤他们试图过滤的内容(并且他们可能没有通过Intel的虚拟化支持) VT-x或AMD SVM来控制x64上的内核而不会导致错误检查)。一个糟糕的理由是,目的只是简单地“记录”流程创建,尤其是当有诸如WMI之类的可用选项具有此功能时。

请不要采取这种错误的方式,但是我从经验中学到,API挂钩确实不是一直存在的答案,通常需要考虑一种更好的设计。有时您可能确实必须依赖它,但是基于我所看到的,大多数询问它的人甚至根本不需要依赖它。

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

祝你好运。