通过Hook拦截Windows 睡眠及休眠操作

之前写过一篇通过Hook 拦截Windows 用户注销。

现在尝试通过Hook拦截Windows睡眠及休眠操作,测试在Windows虚拟机中进行,而虚拟机中没有休眠按钮,只有睡眠操作,但是不管是睡眠还是休眠都是调用的一个函数,只是参数不同。

通过搜索引擎可以查询到操作系统调用PowrProf动态库的SetSuspendState函数,MSDN对此函数的解释如下:

通过关闭电源来暂停系统。 根据 休眠 参数,系统输入暂停 (睡眠) 状态或休眠 (S4) 。

通过调试发现,系统确实会调用这个函数,不同的是不同系统中触发的位置不一样,下面分情况讨论:

1、Win7 32位系统(64位系统)

  通过双机调试,通过.process /i EPROCESS 命令(EPROCESS为Explorer进程在内核中进程对象)将入侵调试此进程,使用g命令后,再次中断后此时已经位于目标进程上下文。 通过.reload /user加载用户态符号,x PowrProf!SetSuspendState 查询对应函数是否被加载,通过bp命令可以对此函数下断点。

  成功后继续运行系统,当触发睡眠操作时,Explorer进程会调用SetSuspendState此函数,进而调用NtInitiatePowerAction函数,NtInitiatePowerAction是更加核心的函数,位于NtDLL中,并且在内核中的SSDT表中也存在此函数。但是我们不在内核中HOOK此函数。

  根据之前HOOK Winlogon用户注销的经验来看,此次我们可以HOOK Explorer进程,在用户登录后,HOOK Explorer进程的导入表、延迟导入表,使其调用SetSuspendState时先调用我们自己的SetSuspendState函数,此时可以在当前会话的,默认桌面上显示一个程序,提示一下用户。

  Win7 64位没有调试,但是应该是也是通过Explorer进程来触发SetSuspendState函数的,也可以通过此方法拦截此程序。

2、Win10 1809 x64版本

  通过上面一样的方法,可以入侵调试winlogon进程,对PowrProf!SetSuspendState函数或者NtDll!NtInitiatePowerAction函数下断点,双机调试时对某个系统用户态函数下断点,所有的进程如果触发到此断点都会断下来。

  通过调试发现发现,此函数的触发路径有如下两个:

  (1) 当没有用户登录时,在登录界面点击右下角睡眠或者休眠,那么会通过winlogon进程触发PowrProf!SetSuspendState函数。

  (2) 如果当前用户已经登录,在开始菜单中点击睡眠或者休眠,那么会有一个服务程序启动一个名为RuntimeBroker.exe的程序,这个服务程序如下:

 

 

  服务程序为svchost.exe ,是启动很早的一个系统服务程序,这个进程共负责四个服务,当在explorer程序中点击睡眠或者休眠时,svchost.exe程序会启动一个名为RuntimeBroker.exe的程序,这个也可以通过调试来确认。

  先看一下RuntimeBroker.exe程序在搜索引擎下找到的定义:

  RuntimeBroker.exe 是 Windows 8 和Windows 10中包含的一个安全 Microsoft 进程,用于协助应用程序权限。Microsoft 对 Runtimebroker.exe 的定义是“Windows 部分信任组件的进程”的一部分。

  要注意的是,当我们启动系统登录用户后,可能系统中此时已经存在多了RuntimeBroker.exe进程,但是当我们点击睡眠/休眠按钮时,svchost.exe会重新启动一个RuntimeBroker.exe进程。

  所以,在这种情况下,我们无法通过之前的方法,进程枚举找到对应的RuntimeBroker.exe进程,然后HOOK对PowrProf!SetSuspendState函数的调用。除非我们选择去HOOK svchost.exe进程,但是这是系统关键服务,暂时不去动它。

  还可以使用设置注册表劫持的方案,操作系统如果查询到在下面这个注册表中有值时,就会启动我们自己设置的程序,启动时命令行参数中包含XXX.exe的路径

  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\XXX.exe,其中XXX需要替换为对应的exe名称,如果没有此项,就新建一个。

  然后新建一个字符串值,名称为Debugger,值设置为我们自己的程序,这样系统启动我们自己的程序后,我们通过命令行参数就可以得知自己需要启动哪个被劫持的程序,可以通过挂起方式启动此程序,之后注入一个DLL,再HOOK关键函数PowrProf!SetSuspendState,然后恢复此进程运行。

  接下来调用PowrProf!SetSuspendState时我们可以先启动一个进程或者直接在桌面弹框即可。

  这个进程的导入表如果不存在函数PowrProf!SetSuspendState的话,那么可以在初期就hook PowrProf模块的导出表,修改SetSuspendState的函数,这样之后获取SetSuspendState函数地址,也是从导出表来获取的。

  这个实现起来还是很复杂,后续自己手动实现或者有其它方案再行补充。在此对知识进行记录。

  

 

posted @ 2022-12-11 11:24  psj00  阅读(339)  评论(0编辑  收藏  举报