首页 > 系统相关 >Windows 应用暂停技术汇总

Windows 应用暂停技术汇总

时间:2024-05-29 12:29:38浏览次数:23  
标签:std 遍历 cout Windows 汇总 进程 线程 暂停 APC

背景

在特定场景下,一些进程运行单纯的浪费资源,但又不能杀掉进程,所以需要通过挂起的方式,暂停进程运行。以释放资源给关键进程运行。

方法对比

在这里插入图片描述

方法详解

1. NtSuspendProcess

通过直接调用 NtSuspendProcess 来对进程进行挂起,通过 NtResumeProcess 来恢复进程。

此 API 是 ntdll.dll 导出但未文档化的接口。也是最常用到的接口。其中 ProcessHackerSystemInfomationsSandboxie 等都使用的这种方式。

但也存在一定的缺陷,一些情况下还是会存在无法挂起的情况。

例如:

[Plus v1.11.4] Process Suspend/Resume issues · Issue #3375 · sandboxie-plus/Sandboxie

devenv, msedge, discord, skype and other processes cannot be suspended · Issue #856 · winsiderss/sys

下面我们来看看它是怎么做的:

1.1 原理

通过 https://github.com/reactos/reactos 进去(这里也可以通过 windbg 来看,是一样的),可以看到其调用链:

NtSuspendProcess -> PsSuspendProcess -> PsGetNextProcessThread + PsSuspendThread -> KeSuspendThread -> KiSuspendThread -> KiInsertQueueApc

那这个我们就突然熟悉了,这就很明显了,就是通过在内核模式下,通过遍历线程,然后依次塞入 APC 来进行挂起。具体可以看 线程挂起和恢复 里面有详细的分析。

1.2 问题

  • 不能暂停内核代码。由于是塞了个 APC 到线程中去,所以是需要等内核代码执行完成后才会执行到 APC 中,才有可能被暂停(加之 APC 队列中可能还存在其他 APC)
  • 中断的影响不可恢复。如果在遍历线程的过程中进程意外退出,可能导致部分线程被挂起的状态,可能导致进程部分功能异常。且无法恢复。

1.3 示例

void ByNtSuspendProcess(DWORD dwProcessId)
{
    HANDLE hProcess = OpenProcess(PROCESS_SUSPEND_RESUME, FALSE, dwProcessId);
    if (hProcess == NULL)
    {
        std::cout << "OpenProcess failed" << std::endl;
        return;
    }

    if (NtSuspendProcess(hProcess) != STATUS_SUCCESS)
    {
        std::cout << "NtSuspendProcess failed" << std::endl;
        CloseHandle(hProcess);
        return;
    }

    std::cout << "Process suspended" << std::endl;
    CloseHandle(hProcess);
}

void ByNtResumeProcess(DWORD dwProcessId) {
    HANDLE hProcess = OpenProcess(PROCESS_SUSPEND_RESUME, FALSE, dwProcessId);
    if (hProcess == NULL)
    {
        std::cout << "OpenProcess failed" << std::endl;
        return;
    }

    if (NtResumeProcess(hProcess) != STATUS_SUCCESS)
    {
        std::cout << "NtResumeProcess failed" << std::endl;
        CloseHandle(hProcess);
        return;
    }

    std::cout << "Process resumed" << std::endl;
    CloseHandle(hProcess);
}

2. SuspendThread

通过遍历当前进程的所有线程,然后依次在用户模式下调用 SuspendThread 来实现进程的挂起,通过 ResumeThread 来恢复进程。

特别地:对于 WOW64 线程,需要调用 Wow64SuspendThreadResumeThread 来进行挂起和恢复。

API 参考:

这里不同的遍历线程方式,可能会产生不同的效果。

主要分为两种不同的遍历方式:

  • CreateToolhelp32Snapshot function (tlhelp32.h) - Win32 apps:通过创建快照的方式,依次进行挂起
    • 只记录调用时刻的线程列表,调用后创建的进程没法获取
    • 进程快照会带来较大的开销
    • 快照中记录的是线程 ID,如果该线程退出后,快速被分配其他线程,则有可能挂起错误的线程(可能性很少,但存在可能)
  • NtGetNextThread(undocument):依次枚举线程,再挂起。由于其是挂起一个线程,获取下一个线程,所以不存在上述问题。

2.1 原理

此方式的原理在 线程挂起和恢复 有较详细的分析,这里不再赘述。与 NtSuspendProcess 几乎一致。

2.2 问题

  • 额外的开销。由于在用户模式下遍历线程,并调用 SuspendThread,这里需要每次在获取目标线程的句柄时,都有额外的检查。
  • 不能暂停内核代码。由于是塞了个 APC 到线程中去,所以是需要等内核代码执行完成后才会执行到 APC 中,才有可能被暂停(加之 APC 队列中可能还存在其他 APC)
  • 中断的影响不可恢复。如果在遍历线程的过程中进程意外退出,可能导致部分线程被挂起的状态,可能导致进程部分功能异常。且无法恢复。

2.3 示例

  1. Snapshot & SuspendThread
void BySnapshotAndSuspendThread(DWORD dwProcessId)
{
   
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (hProcess == NULL)
    {
   
        std::cout << "OpenProcess failed" << std::endl;
        return;
    }

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwProcessId);
    if (hSnapshot == INVALID_HANDLE_VALUE)
    {
   
        std::cout << "CreateToolhelp32Snapshot failed" << std::endl;
        CloseHandle(hProcess);
        return;
    }

    THREADENTRY32 te32;
    te32.dwSize = sizeof(THREADENTRY32);
    if (!Thread32First(hSnapshot, &te32))
    {
   
        std::cout << "Thread32First failed" << std::endl;
        CloseHandle(hSnapshot);
        CloseHandle(hProcess);
        return;
    }

    do
    {
   
        if (te32.th32OwnerProcessID == dwProcessId)
        {
   
            HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID);
            if (hThread == NULL)
            {
   
                std::cout << "OpenThread failed" << std::endl;
                CloseHandle(hSnapshot);
                CloseHandle(hProcess);
                return;
            }

            if (SuspendThread(hThread) == -1)
            {
   
                std::cout << "SuspendThread failed" << std::endl;
                CloseHandle(hThread);
                CloseHandle(hSnapshot);
                CloseHandle(hProcess);
                return;
            }

            std::cout << "Thread " << te32.th32ThreadID << " suspended" << std::endl;
            CloseHandle(hThread);
        }
    } while (Thread32Next(hSnapshot, &te32));

    CloseHandle(hSnapshot);
    CloseHandle(hProcess);
}

void

标签:std,遍历,cout,Windows,汇总,进程,线程,暂停,APC
From: https://blog.csdn.net/Frendguo/article/details/139292288

相关文章

  • windows下载安装ipopt求解器 可用于pyomo调用
    方案一:采用官方编译的应用程序官方对windows下有已经编译好的应用程序,只需要下载下来,并将ipopt的应用程序所在文件夹路径添加到系统全局环境变量就可以了。这样在利用pyomo或者其他建模工具建模求解的时候就可以正常使用ipopt了。(但要注意防火墙或者杀毒软件可能会拦截需要设定......
  • Windows 11系统设置显示桌面图标方法分享
        随着Windows11操作系统的正式发布,许多用户纷纷升级,以体验其新颖的界面和改进的功能。然而,面对全新的用户界面和设置选项,即使是经验丰富的Windows用户也可能会遇到一些挑战。其中一个常见的问题就是如何在Windows11中设置显示桌面图标,这对于习惯了在桌面上组织文......
  • 将sublime text 3加入到windows右键功能中
    1.reg文件内容,编辑好之后,双击1.reg文件即可WindowsRegistryEditorVersion5.00[HKEY_CLASSES_ROOT\*\shell\SublimeText3]@="EditwithSublimeText3""Icon"="D:\\software\\sublime_text_build_4169_x64\\sublime_text.exe,0"[HKEY_CLASS......
  • 数据通信基本概念汇总
    1.数据通信基础        网关:提供协议转换,路由选择,数据交换的网络设备        报文:网络中所传递的一个数据单元。        数据载荷:最终要传递的信息        封装:给数据载荷添加头部和尾部的过程(形成新的报文)        解......
  • 【WinSW】- 使用WinSW将程序变成Windows的服务
    1、WinSW下载地址:https://github.com/winsw/winsw/releases2、以nginx和jar为例,在目标文件下,添加WinSW程序和对应的xml文件,两者的名字需要一致,如图所示3、xml配置说明,可直接拷贝后面配好的xml 4、nginx对应的xml配置<service><id>nginxServer3</id><name>nginxServ......
  • 【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service
    在使用AppService服务部署业务应用,因为有些第三方的接口需要调用者携带TLS/SSL证书(X509Certificate),在官方文档中介绍了两种方式在代码中使用证书:1)直接使用证书文件路径加载证书2)从系统的证书库中通过指纹加载证书本文中,将分别通过代码来验证以上两种方式. 第一步:使用P......
  • WindowsCA证书服务(五)为nginx申请x509证书
    简介我们不止windows的IIS呀,还有nginx,apache等等服务器,这些服务器不止要证书,还要私钥呢。还有一些东东要p12格式的证书,包含证书链和私钥的单文件证书。比如说深信服的防火墙。openssl经过一番搜索,这次真得脱离windows了。即使我使用第三方软件,让你在windows下生成了密钥对,还......
  • 周报 | 24.5.20-24.5.26文章汇总
    为了更好地整理文章和发表接下来的文章,以后每周都汇总一份周报。OpenCV与AI深度学习|YOLOv8自定义数据集训练实现火焰和烟雾检测(代码+数据集!)-CSDN博客周报|24.5.13-24.5.19文章汇总-CSDN博客DeepDriving|目标检测中的非极大值抑制(NMS)算法_非极大值抑制nms的基本原理......
  • 在 windows 通过 vscode 查看 linux 上的代码
    原理使用vscode的 Remote-SSH插件,通过SSH连接linux,直接查看linux上的代码,免手动同步vscodessh配置文件Config 私钥IdentityFile默认是~/.ssh/id_rsa,所以可省略登录界面打开linux文件夹 ......
  • WindowsCA证书服务(四)windows申请x509证书
    简介前面我们做了iis自己申请证书,IIS自己申请证书,IE认可,chrome不认可。这是因为chrome必须要x509的证书,带有v3扩展才可以,老版本的都被视为危险了。那么我们本次就尝试使用windows来申请x509证书。工具介绍certutil|MicrosoftLearn不建议在任何生产代码中使用 Certutil,它......