使用ERROR_NOT_ENOUGH_MEMORY失败的CreateRemoteThread

时间:2016-11-04 18:32:12

标签: c++ windows service

这是一个非常奇怪的问题,但是,我相信,这是SO的主题。

说明:

我有一个用C#编写的服务,它调用我的C ++库。 C ++库通过WinExec执行一些第三方软件。

3rdparty软件通过CreateRemoteThread注入DLL。我没有此软件的源文件。

主要内容

我有2台电脑 - Win2008和Win10。

对于Win10 - 这个frankenstein工作正常,Service运行DLL,DLL运行3rdparty DLL注入器,DLL注入器注入东西。

对于Win2008,情况有所不同。如果我从CMD运行3rdparty DLL注入器 - 它完美无缺。但是如果我运行服务--Injector返回,他从CreateRemoteThread获得了ERROR_NOT_ENOUGH_MEMORY。

服务正在使用LocalService帐户,在Windows 10上一切正常。我正在寻找可能的想法\线索,为什么SERVICE出现问题(请记住,CMD工作正常),仅适用于Windows 2008。

2 个答案:

答案 0 :(得分:2)

此问题可能与跨权限级别创建远程线程有关,如以下博客文章中所述:

Injecting Code Into Privileged Win32 Processes

  

对于XP SP2及更高版本(2003,Vista),一些新的安全措施会阻止传统的CreateRemoteThread()函数正常工作。您应该能够打开进程,在其堆上分配内存,并将数据写入分配的区域,但在尝试调用远程线程时,它将因ERROR_NOT_ENOUGH_MEMORY而失败。

     

...

     

对于XP SP2,我做了一些调试,发现在CreateRemoteThread()内部,调用了ZwCreateThread(),它是从ntdll.dll导出的。调用是在指定线程应该开始挂起时进行的,它正确地执行,但是在调用ZwResumeThread()之前仍然在CreateRemoteThread()内部,有一个对CsrClientCallServer()的调用失败并最终导致错误消息。

本文解释了在不同版本的Windows上注入远程线程以避免错误的一些不同方法,最后得出以下结论:

  

此时,我们可以在所有目标平台上成功执行远程线程到特权进程,但如前所述,它非常混乱。我们使用三种不同的,大部分未记录的功能,并根据操作系统版本自动检测哪一种功能。

     

更好的解决方案是创建一个辅助程序,将服务对象(您的注入程序)添加到目标系统上的服务控制管理器数据库。由于您是管理员,无论如何都需要,您可以添加这些条目并启动服务。这将使注入器程序能够以不同于普通代码的不同访问权限运行,并且传统的CreateRemoteThread()将在Windows 2000,XP和2003 / Vista上正常运行。用于添加和控制服务的API函数由MSDN记录,并在所有平台上保持一致。

     

因此,所学到的是我们可以使用许多不同的函数将代码注入特权远程进程,包括XP SP2上的RtlCreateUserThread()和Vista上的NtCreateThreadEx(),但最佳方法是安装临时service并允许CreateRemoteThread()成为完成所有平台任务的单个API。

当然,由于您没有注射器的源代码而无法改变其工作原理,因此这一切都不重要。

此外,您也无法跨会话边界创建远程线程。在服务中调用WinExec()将在与服务相同的会话中运行注入器进程,即会话0.如果它尝试注入到在用户会话中运行的进程,那将永远不会工作。这也解释了为什么CMD在与注入的进程相同的会话中运行时,从CMD运行注入器的原因。

答案 1 :(得分:1)

我今天遇到了同样的问题,这似乎是问题 -

  

在Windows 8之前,终端服务按设计隔离每个终端会话。因此,如果目标进程与调用进程位于不同的会话中,则CreateRemoteThread将失败。

这解释了为什么您的代码适用于Windows 10但不适用于Windows 7/2008。

来源:https://msdn.microsoft.com/en-us/library/windows/desktop/dd405484(v=vs.85).aspx