使用mhook钩住ZwCreateSection()、CreateProcess()和CreateProcessEx()

Hook ZwCreateSection(), CreateProcess() and CreateProcessEx() using mhook to block certain application from launching

本文关键字:CreateProcess CreateProcessEx mhook ZwCreateSection 使用 钩住      更新时间:2023-10-16

我正试图使用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 Createdn";
}
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在评论中提到的那样,您应该首先在本地进程中测试这些东西。采纳他的建议,你的生活会更幸福。


一般注意事项

首先,不要在API挂钩方面触及Win32 API,除非你想要任何人都能理解的最有缺陷的设计实现。

  1. 您可以修补NtResumeThread(NTDLL),然后进行检查以确定它是否作为进程创建的一部分被调用。当您生成一个程序时,负责进程创建操作的进程将调用NtResumeThread来恢复新创建的进程的主线程
  2. 或者,您可以修补NtCreateUserProcess(NTDLL),只要您不打算支持Windows Vista之前的任何操作系统版本。但是,由于严重的安全原因,Windows 2000和Windows XP不应该再使用了,而且已经很久没有得到支持了,所以我希望你根本不要关注它们

以上两种想法都比依赖于挂钩Win32 API来完成您要做的事情要好,但它们仍然是非常糟糕的想法。我将解释一些原因。

  1. 修补其他进程内存的虚拟内存以拦截进程创建通常是个坏主意,应该尽可能避免,因为您可能会引入额外的漏洞(例如,在内存中留下某些标志或回调例程/助手例程中的错误,这些错误可能会被滥用),并导致程序不稳定
  2. 绕过API挂钩的用户模式补丁是非常简单的,并且对于执行内存补丁的人来说,要花很长的时间来防止这些绕过,您最终可能会造成比以前更大的伤害(例如性能下降、潜在漏洞等)。绕过以Win32 API为目标的API挂钩的一个例子是自己重新实现Win32 API例程,绕过NTAPI上的API挂钩的一种例子是自己执行系统调用
  3. 您的API进程创建挂钩对于以管理员身份启动的程序不起作用,即使您要修补NTAPI。原因是,当您以管理员身份生成程序时,consent.exe会起作用。我相信consent.exe无论如何都是一个受保护的进程(你可以仔细检查,如果我不记得了,我就不正确了——尽管如果它是受保护进程,这在逻辑上是有意义的),如果它是,那么你无论如何都无法将代码注入其中(更不用说对consent.exe这样的进程做这样的事情99.9%的时候是完全不负责任的)

对于Windows Vista和Windows 7,您可以将代码注入csrss.exe,然后修补CsrCreateProcess(由csrss.exe所依赖的模块导出)。它将比将代码注入多个进程更可靠(也将用于监控提升进程上的进程创建),但就稳定性和安全性而言,这仍然是个坏主意。您需要启用SeDebugPrivilege才能触摸csrss.exe获取记录。

对于csrss.exe是受保护进程的较新版本的Windows,您可以在类似lsass.exe的进程中修补NtOpenProcess(NTDLL)。然而,对于稳定性和安全性来说,这又是个坏主意,更不用说无法保证它始终100%可靠。这只是一个估计,你可以尝试教育实验。您还需要考虑lsass.exe是受保护进程的可能性(有一个选项可以通过修改注册表来启用它——出于安全原因,每个人都应该这样做)。

上述两种想法都有其自身的原因,也是不好的。


有Windows Management Instrumentation(WMI),它可以用来接收新进程创建的通知,但它不会表现为"拦截"。它的行为就像创建后的通知。然而,如果您所需要做的只是创建日志进程,那么从关注安全性、稳定性和效率的角度来看,这或多或少是在用户模式下可以做的最好的事情,而不会干扰未记录的行为。

上面的想法是一个好的例子,应该是安全、高效、稳定和有文件记录的。


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

内核模式的另一种方法是通过PsSetLoadImageNotifyRoute/Ex(然后对NTDLL.DLL进行过滤)或通过PsSetCreateThreadNotify例程(并使用线程ID保存您自己的进程监控日志,以确定线程创建是否是进程的第一个线程创建)。


现在,关于DLL注入,不要使用AppInit_DLL。这是实现你在最初帖子中试图做的事情的最有缺陷的机制之一。即使我不同意你的设计,我也不妨解释一下为什么这是一个有缺陷的设计。

AppInit_dll只会影响加载了User32.dll的程序,这意味着您的监控将受到严重限制/不可靠。您将被阻止在非GUI程序中监控进程创建(这些程序很少导入User32.dll,比如Windows服务,甚至是不依赖任何与User32相关的控制台进程,比如消息框等)。

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


总体而言,作为一般性评论,您确实不想继续尝试执行您请求的帮助(挂接Win32 API),并且我提到的用于完成流程创建监控的其他挂接方法仅用于理论目的,而非实际建议您采取这些路径。我再怎么强调也不为过,专注于文档和稳定性是很重要的,因为虽然你现在可能不相信,但试图用你目前正在尝试的设计来做一些事情,很容易让你陷入困境,造成严重破坏。我一点也不夸张。

重要的是要记住,执行远程代码执行通常是个坏主意,只有在没有其他方法的情况下才能执行。真正需要它的一个例子是,AV供应商试图开发Behavior Blocker/HIPS,但没有内核模式回调来过滤他们试图过滤的内容(他们可能没有通过Intel VT-x或AMD SVM的虚拟化支持来控制x64上的内核,而不会引起错误检查)。一个糟糕的理由是,它的目的是简单地"记录"进程创建,尤其是当有WMI这样的选项具有这方面的功能时。

请不要误解这一点,但我从经验中了解到,API挂钩并不是所有时候的答案,通常需要考虑更好的设计。有时你可能真的不得不依赖它,但根据我所看到的,大多数询问它的人真的不需要依赖它

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

祝你好运。