Windows重启管理器:工作原理和被劫持原理,第1部分

恶意软件利用多种技术来避免检测,威胁行为体不断发现和利用新的攻击方法。一种不太常见的技术包括利用Windows重新启动管理器。要领先于恶意作者,重要的是要了解他们并了解他们是如何工作的

重新启动管理器是一个库,用于减少软件更新期间所需的重新启动。更新过程中可能受影响的文件可能会被各种应用程序锁定,从而阻止更新过程对其进行修改。这可能会导致重新启动,迫使应用程序释放对更新程序目标文件的锁定。另一种方法是,重新启动管理器允许进程通过终止正在使用目标文件的进程(如果满足所需条件)来释放对目标文件的锁定。然而,此机制可能被劫持以达到恶意目的。

在这个由两部分组成的系列中,我们:

  • 使用软件安装程序的示例检查Restart Manager的机制。
  • 展示如何恶意使用重启管理器,解释恶意软件作者为什么以及如何使用此特定技术。
  • 讨论如何保护进程免受恶意使用Restart Manager的影响。

体系结构和功能

原产地

每个操作系统(OS)都有一种独特的方式来处理对文件的同时访问。在Windows的情况下,根据文件的打开方式,一个进程可以独占访问该文件,如已映射的文件或未使用file_SHARE_READ | file_SCHARE_WRITE模式打开的文件。在这种情况下,该文件可能被进程“锁定”,从而导致拒绝其他请求对该文件进行读写访问的进程。

图1。当一个进程试图打开另一个进程已映射的文件时,Windows显示的错误消息(单击放大)

如果其他进程需要访问“锁定的文件”,则可以请求重新启动整个系统,以解除文件的锁定。除了操作系统重启对用户操作造成的中断外,重启还可能是资源密集型的。为了解决这些痛点,从Windows Vista开始,微软推出了重新启动管理器,允许应用程序关闭锁定资源的进程,而无需重新启动。

使用重新启动管理器

重新启动管理器在Windows中通过存储在%Windows%\System32中的“RstrtMgr.dll”库实现

流程通过所谓的“会议,“其中他们注册了一组资源并接收与之相关的结果信息。资源表示流程需要访问的目标。如图2所示,资源可以是文件、进程或服务,会话可以由其中的一个或多个组成。重启管理器的作用是确定哪些进程当前正在阻塞给定的资源,称为受影响的应用程序,并将有关应用程序的信息存储到列表.

用户可以编写软件来创建Restart Manager会话,注册他们需要使用的一组文件、进程或服务,并确定当前是否有其他进程阻止他们这样做。如果有,重启管理器将提供受影响应用程序的列表,软件可以请求关闭这些应用程序。这使软件能够在执行操作之前检查是否没有任何东西会妨碍其执行,这对于不应中断的过程(例如更新)很重要。

图2。重启管理器的体系结构(单击放大)

要与Restart Manager交互,一个进程通常会执行以下操作:

  1. 创建重新启动管理器会话
  2. 注册可以是文件、服务或进程的资源
  3. 通过重新启动管理器返回的列表检索阻止注册资源的受影响应用程序

图3。应用程序对重新启动管理器的典型使用(单击放大)

让我们看看流程如何在技术上与Restart Manager接口,并解释如何使用Restart Manager API中的函数。 

使用库的第一步是创建阶段使用 Rm开始会话()1:

DWORD Rm开始会话(

[out]DWORD*pSessionHandle,

DWORD dwSession标志,

[out]WCHAR[]strSessionKey);

此函数用于创建使用Restart Manager的其他功能所需的会话密钥和会话句柄。如果需要,一个进程可以创建不同的会话,但Restart Manager可以同时处理整个系统最多64个会话。创建会话后,流程可以通过函数为每个会话注册一个或多个资源RmRegisterResource()2:

DWORD Rm寄存器资源(

[in]DWORD dwSessionHandle,

[in]UINT文件,

[in,可选]LPCWSTR[]rgsFileNames,

[in]UINT应用程序,

[in,可选]RM_UNIQUE_PROCESS[]rgApplications,

UINT服务,

[in,可选]LPCWSTR[]rgsServiceNames);

根据要注册的资源的性质,需要不同类型的信息。例如,注册进程需要初始化RM_UNIQUE_process结构,该结构收集进程id和进程创建时间:

typedef结构_RM_UNIQUE_PROCESS{

达沃德 dwProcessId;

文件时间进程开始时间;

}RM_UNIQUE_PROCESS,*PRM_UNIKE_PROCESS;

注册一个或多个资源后,进程可以使用函数通过Restart Manager获取受影响的应用程序(当前阻止资源的应用程序)的列表RmGetList():

DWORD房间列表(

[in]DWORD dwSessionHandle,

[out]需要UINT*pnProcInfo,

[输入,输出]UINT*pnProcInfo,

[输入、输出、可选]RM_PROCESS_INFO[]rgAffectedApps,

[out]LPDWORD lpdwRebootReasons);

RmGetList()返回RM_PROCESS_INFO结构的列表,这些结构为每个受影响的应用程序收集以下信息:

typedef结构_RM_PROCESS_INFO{

RM_UNIQUE_PROCESS过程;

WCHAR strAppName[CCH_RM_MAX_APP_NAME+1];

WCHAR strServiceShortName[CCH_RM_MAX_SVC_NAME+1];

RM_APP_TYPE应用程序类型;

ULONG应用状态;

DWORD TSSessionId;

BOOL b可重启;

}RM_PROCESS_INFO,*PRM_PROCESS_INFO;

RM_PROCESS_INFO结构包含重启管理器的关键信息,用于确定进程是否请求关闭目标应用程序:

  • 应用程序类型定义应用程序的性质:
    • 有或没有顶级窗口的独立进程
    • 控制台应用程序
    • Windows服务
    • 重新启动管理器已确定的关键应用程序无法关闭。
    • 注意:不要将此术语与系统关键过程,这一过程如果终止,则强制重新启动系统.”4Restart Manager可能会将受影响的应用程序归类为“关键应用程序”,因为它是:
      • 无法终止的系统关键进程
      • 没有关闭应用程序权限的进程
      • 受影响的应用程序之一是与Restart Manager的活动会话的所有者
    • RmUnknownApp,专门用于不属于任何其他类别的应用程序
  • 应用程序状态指示应用程序的当前执行上下文是:
    • 正在运行
    • 正在由重新启动管理器重新启动
    • 被重新启动管理器或外部操作停止
    • 停止/重新启动时遇到错误

通过AppStatus返回的值可以由这些值与OR运算符组合而成。

  • b可重启确定是否可以重新启动受影响的应用程序。

RmGetList()与受影响的应用程序列表一起在lpdwRebootReasons变量中指定是否需要重新启动系统。如果是,原因可能是以下之一:

typedef枚举_RM_REBOOT_REASON{

RmRebootReasonNone=0x0,

RmRebootReasonPermissionDenied=0x1,

RmRebootReasonSessionMismatch=0x2,

RmRebootReasonCriticalProcess=0x4,

RmRebootReasonCriticalService=0x8,

房间重新启动原因检测到自己

}RM_REBOOT_REASON;

此时,进程可以使用以下命令请求关闭受影响的应用程序房间关闭()5:

DWORD Rm关闭(

[in]DWORD dwSessionHandle,

[in]ULONG lAction标志,

[in,可选]RM_WRITE_STATUS_CALLBACK fnStatus

);

如果进程具有适当的权限,则重新启动管理器将管理终止受影响应用程序的请求。如果是这样的话,请求关闭的进程随后可以使用以下命令请求重新启动受影响的应用程序Rm重启()6:

DWORD Rm重新启动(

[in]DWORD dwSessionHandle,

DWORD数据重启动标志,

[in,可选]RM_WRITE_STATUS_CALLBACK fnStatus

);

RmShutdown()的机制

由于重启管理器能够合法终止进程,它还为恶意软件作者提供了劫持其终止机制的机会。当一个进程请求时,RmShutdown()函数将首先在内部检索与参数中给定的会话句柄关联的Restart Manager会话,然后执行内部检查以确保数据是最新的。除了内部检查之外,重新启动管理器还查询注册表项下当前会话的注册表配置单元HKCU\\软件\\Microsoft\\RestartManager(图4)同步内部数据和注册表信息。每个会话的配置单元在执行RmStartSession()时创建,并在执行Restart Manager的每个步骤中使用会话的内部数据进行更新。

图4。Restart Manager会话密钥之一的示例(单击以放大)

然后,重启管理器将执行一组检查,以确定关闭过程之前要考虑的潜在更改,例如:

  • 如果需要重新启动操作系统
  • 如果会话所有者通过请求进行修改Rm添加过滤器()7
  • 如果从Restart Manager的角度来看,受影响的应用程序不是关键应用程序

如果满足所有要求,则根据目标应用程序的性质选择不同的程序来关闭受影响的应用程序。

场景1:GUI应用程序

如果受影响的应用程序是一个GUI应用程序,如notepad.exe,则关闭过程分为三个步骤,在名为“ActionStrategy”的Restart Manager内部C++类的三个不同的未记录函数中实现:

  1. 操作策略::ShutdownPrepAction()
  2. 操作策略::ShutdownProcAction()
  3. 操作策略::WaitForProcsStop()

它们主要依赖于Windows API函数的使用发送消息超时W()。8

SendMessageTimeoutW()用于发送消息 表示要由GUI窗口处理的信息。系统和应用程序使用消息作为通信通道,通知应用程序有关用户输入、窗口大小调整或其他请求(如关闭过程)的信息。每条消息都使用以下参数进行传输:

  • 收件人窗口的窗口句柄
  • 表示要传输的信息类型的消息标识符
  • 可选参数(如果需要)

在ShutdownPrepAction()中,首先使用消息标识符调用SendMessageTimeoutW()WM_QUERYENDSESION(0x11)。9此消息请求目标应用程序询问应用程序是否准备结束会话。如果应用程序返回FALSE,意味着它还没有准备好,那么会发生什么取决于请求关闭的方式。RmShutdown()的第二个参数lActionFlags可以是值“RmForceShutdow”,用于设置强制关机。如果没有强制关闭,如果应用程序还没有准备好结束,则会取消关闭。但是,如果强制关闭,则无论应用程序是否准备结束,重启管理器都会移至过程的下一部分,类似于应用程序准备结束并对第一条消息返回TRUE的情况。

此过程的第二部分发生在函数中ShutdownProcAction(),使用值执行对SendMessageTimeoutW()的另一个调用WM_ENDSESSION(0x16)。10此消息通知应用程序会话需要结束,这意味着如果应用程序自身不退出,系统可以在短时间内关闭应用程序。它给应用程序一个超时时间,使应用程序可以在结束之前进行最后一次清理,这可能很有用,例如,可以保存用户数据。 

最后,如果应用程序仍未结束,则发送第三条消息WM_关闭(0x10)11要求应用程序销毁其GUI窗口以终止。

场景2:控制台应用程序

由于消息被设计为发送到GUI窗口句柄,因此当受影响的应用程序是控制台应用程序时,Restart Manager需要进行调整,而不是发送一个通知。为了表示终止请求,重新启动管理器将CTRL_C_EVENT发送到受影响的应用程序。此通知将由控制台的控制处理程序处理,该处理程序默认调用ExitProcess()。

场景3:与服务关联的应用程序

如果受影响的应用程序是服务,则应用的方法会有所不同,因为服务没有GUI窗口,因此无法应用SendMessageTimeoutW()。要关闭目标服务,需要使用ActionStrategy的两个核心功能:

  1. 操作策略::关闭服务
  2. 行动策略::TerminateProc

ShutdownService()首先使用Windows API函数QueryServiceStatus()检查服务是否处于service_STOPPED(0x1)状态。如果不是,该函数将调用控制服务()12通知服务应该停止:

图5。从ActionStrategy::StopService()、RstrtMgr.dll实现服务停止(单击放大)

然后,无论服务停止是否成功,ActionStrategy::TerminateProc()都会尝试使用终止进程()13:

图6。从ActionStrategy::TerminatePro()、RstrtMgr.dll(单击放大)实现进程终止

场景4:explorer.exe

最后,如果受影响的应用程序是Windows资源管理器,则调用名为ActionStrategy::ExplorerShutdownProcAction()的专用函数。该功能部分依赖于与场景1应用程序,首先使用消息WM_QUERYENDSESSION(0x11)调用SendMessageTimeoutW()以请求终止进程,然后执行第二个调用以发送WM_ENDSESSION(0x16)消息。但是,如果第二次调用检测到应用程序没有结束,则不会对SendMessageTimeoutW()进行第三次调用,并显示消息WM_CLOSE(0x10)。

实际上,在当前没有打开图形窗口的情况下,将带有WM_CLOSE(0x10)的SendMessageTimeoutW()发送到explorer.exe进程时,操作系统将生成一个弹出窗口来关闭系统。

图7。在带有WM_CLOSE的SendMessageTimeOutW()之后出现弹出窗口(单击放大)

当在系统上找不到图形窗口时,explorer.exe将该消息解释为“关闭”系统的请求,这与Restart Manager努力实现的目标相反。在这种情况下,当受影响的应用程序为explorer.exe时,Restart Manager会强制执行另一个过程,将RmShutdown限制为发送WM_QUERYENDSESION和WM_ENDSESSION。

合法使用案例

在内部Microsoft应用程序之外,一些安装程序利用重新启动管理器来确保当前没有其他应用程序正在使用安装所需的文件。为了识别其中一些,我们使用了一个名为镍钛矿,14它允许用户从常用下载的软件中选择一组应用程序,并生成一个二进制文件,一次安装所有应用程序。 

使用这个二进制,我们使用API监视器15为了监视父安装程序进程及其子进程,将对Restart Manager的调用挂接起来,以捕获使用它的安装程序。为此,我们首先在API monitor(下面图8的左上角)中设置挂接函数,然后启动ninite安装程序。 

图8。API Monitor捕获的安装程序调用的与Restart Manager相关的函数(单击放大)

在右上角,我们可以看到安装程序及其子进程,每个进程都从一个重命名为“target.exe”的可执行文件安装软件,该可执行文件启动一个“target.tmp”进程。如果安装的软件的名称被“target.exe”和“target.tmp”格式隐藏,我们可以使用二进制文件的图标查看通过它们安装的软件。在中间窗口中,在Visual Studio代码安装程序完成的挂钩调用中,我们可以看到安装程序对重新启动管理器执行了四次调用:

  • Rm开始会话()
  • RmRegister资源()
  • RmGetList()
  • RmEnd会话()

让我们仔细看看底部窗口中显示的RmRegisterResources()调用的参数,以观察安装程序要确保哪些文件未被其他进程使用。安装程序未注册任何进程或服务,但在重新启动管理器会话中注册了14个二进制文件,包括通常用于安装或更新的.exe和.dll二进制文件,如“inno_updater.exe”(索引为12的文件名). 

此示例显示了一个安装程序的重新启动管理器的典型用法,在安装或更新之前验证即将升级的二进制文件当前未被其他应用程序阻止。 

总结 

在这个博客中,我们回顾了重启管理器是什么以及它是如何工作的。该库使程序能够在执行某些操作之前,特别是在不应中断操作的情况下,验证没有应用程序会阻止其所需的资源。我们还详细介绍了进程如何使用Restart Manager请求关闭受影响的应用程序,以释放当前阻塞其所需资源的锁。在本系列的第二部分中,我们将探讨恶意作者如何劫持此功能,并研究实际示例。我们还将解释如何保护应用程序免受这些恶意技术的攻击,以及CrowdStrike Falcon平台如何让用户看到利用Restart Manager终止机制的攻击。

其他资源

  1. https://learn.microsoft.com/en-us/windows/win32/api/restartmanager/nf-restartmmanager-rmstartsession
  2. https://learn.microsoft.com/en-us/windows/win32/api/restartmanager/nf-restartmanger-rmregisterresources
  3. https://learn.microsoft.com/en-us/windows/win32/api/restartmanager/nf-restartmmanager-rmgetlist
  4. https://devblogs.microsoft.com/oldnewthing/20180216-00/?p=98035
  5. https://learn.microsoft.com/en-us/windows/win32/api/restartmanager/nf-restartmanager-rmshutdown
  6. https://learn.microsoft.com/en-us/windows/win32/api/restartmanager/nf-restartmanger-rmrrestart
  7. https://learn.microsoft.com/en-us/windows/win32/api/restartmanager/nf-restartmmanager-rmaddfilter
  8. https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winser-sensidmessagetimeoutw(https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winser-sensidmessagetimeoutw)
  9. https://learn.microsoft.com/en-us/windows/win32/shutdown/wm-queryendsession
  10. https://learn.microsoft.com/en-us/windows/win32/shutdown/wm-endsession
  11. https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-close
  12. https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-controlservice(英语)
  13. https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadasapi-terminateprocess
  14. https://ninite.com网站/
  15. http://www.rohitab.com/apimonitor

 

相关内容