ToB企服应用市场:ToB评测及商务社交产业平台

标题: 7.6 实现进程挂起与恢复 [打印本页]

作者: 悠扬随风    时间: 2023-10-2 05:54
标题: 7.6 实现进程挂起与恢复
挂起与恢复进程是指暂停或恢复进程的工作状态,以达到一定的控制和管理效果。在 Windows 操作系统中,可以使用系统提供的函数实现进程的挂起和恢复,以达到对进程的控制和调度。需要注意,过度使用进程挂起/恢复操作可能会造成系统性能的降低,导致死锁等问题,因此在使用时应该谨慎而慎重。同时,通过和其他进程之间协同工作,也可以通过更加灵活的方式,实现进程的协调、交互等相应的功能,从而实现更加高效和可靠的进程管理。
要实现挂起进程,首先我们需要实现挂起线程,因为挂起进程的实现原理是通过调用SuspendThread函数循环将进程内的所有线程全部挂起后实现的,而要实现挂起线程则我们需要先确定指定进程内的线程信息,要实现枚举进程内的线程信息则可以通过以下几个步骤实现。
首先通过CreateToolhelp32Snapshot得到当前系统下所有的进程快照,并通过遍历进程的方式寻找是否符合我们所需要枚举的进程名,如果是则调用CreateToolhelp32Snapshot并通过传入TH32CS_SNAPTHREAD代表枚举线程,通过循环的方式遍历进程内的线程,每次通过调用OpenThread打开线程,并调用ZwQueryInformationThread查询该线程的入口信息以及线程所在的模块信息,最后以此输出即可得到当前进程内的所有线程信息。
  1. #include <iostream>
  2. #include <Windows.h>  
  3. #include <TlHelp32.h>
  4. #include <Psapi.h>
  5. using namespace std;
  6. typedef enum _THREADINFOCLASS
  7. {
  8.   ThreadBasicInformation,
  9.   ThreadTimes,
  10.   ThreadPriority,
  11.   ThreadBasePriority,
  12.   ThreadAffinityMask,
  13.   ThreadImpersonationToken,
  14.   ThreadDescriptorTableEntry,
  15.   ThreadEnableAlignmentFaultFixup,
  16.   ThreadEventPair_Reusable,
  17.   ThreadQuerySetWin32StartAddress,
  18.   ThreadZeroTlsCell,
  19.   ThreadPerformanceCount,
  20.   ThreadAmILastThread,
  21.   ThreadIdealProcessor,
  22.   ThreadPriorityBoost,
  23.   ThreadSetTlsArrayAddress,
  24.   ThreadIsIoPending,
  25.   ThreadHideFromDebugger,
  26.   ThreadBreakOnTermination,
  27.   MaxThreadInfoClass
  28. }THREADINFOCLASS;
  29. typedef struct _CLIENT_ID
  30. {
  31.   HANDLE UniqueProcess;
  32.   HANDLE UniqueThread;
  33. }CLIENT_ID;
  34. typedef struct _THREAD_BASIC_INFORMATION
  35. {
  36.   LONG ExitStatus;
  37.   PVOID TebBaseAddress;
  38.   CLIENT_ID ClientId;
  39.   LONG AffinityMask;
  40.   LONG Priority;
  41.   LONG BasePriority;
  42. }THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
  43. extern "C" LONG(__stdcall * ZwQueryInformationThread)
  44. (
  45. IN HANDLE ThreadHandle,
  46. IN THREADINFOCLASS ThreadInformationClass,
  47. OUT PVOID ThreadInformation,
  48. IN ULONG ThreadInformationLength,
  49. OUT PULONG ReturnLength OPTIONAL
  50. ) = NULL;
  51. // 枚举进程内的线程
  52. BOOL EnumThread(char *ProcessName)
  53. {
  54.   // 进程快照句柄
  55.   HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  56.   PROCESSENTRY32 process = { sizeof(PROCESSENTRY32) };
  57.   // 遍历进程
  58.   while (Process32Next(hProcessSnap, &process))
  59.   {
  60.     // char* 转 string
  61.     string s_szExeFile = process.szExeFile;
  62.     if (s_szExeFile == ProcessName)
  63.     {
  64.       HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
  65.       THREADENTRY32 te32;
  66.       // 创建线程快照
  67.       hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
  68.       if (hThreadSnap == INVALID_HANDLE_VALUE)
  69.       {
  70.         return FALSE;
  71.       }
  72.       // 为快照分配内存空间
  73.       te32.dwSize = sizeof(THREADENTRY32);
  74.       // 获取第一个线程的信息
  75.       if (!Thread32First(hThreadSnap, &te32))
  76.       {
  77.         return FALSE;
  78.       }
  79.       // 遍历线程
  80.       while (Thread32Next(hThreadSnap, &te32))
  81.       {
  82.         // 判断线程是否属于本进程
  83.         if (te32.th32OwnerProcessID == process.th32ProcessID)
  84.         {
  85.           // 打开线程
  86.           HANDLE hThread = OpenThread(
  87.             THREAD_ALL_ACCESS,        // 访问权限
  88.             FALSE,                    // 由此线程创建的进程不继承线程的句柄
  89.             te32.th32ThreadID         // 线程 ID
  90.             );
  91.           if (hThread == NULL)
  92.           {
  93.             return FALSE;
  94.           }
  95.           // 将区域设置设置为从操作系统获取的ANSI代码页
  96.           setlocale(LC_ALL, ".ACP");
  97.           // 获取 ntdll.dll 的模块句柄
  98.           HINSTANCE hNTDLL = ::GetModuleHandle("ntdll");
  99.           // 从 ntdll.dll 中取出 ZwQueryInformationThread
  100.           (FARPROC&)ZwQueryInformationThread = GetProcAddress(hNTDLL, "ZwQueryInformationThread");
  101.           // 获取线程入口地址
  102.           PVOID startaddr;                          // 用来接收线程入口地址
  103.           ZwQueryInformationThread(
  104.             hThread,                              // 线程句柄
  105.             ThreadQuerySetWin32StartAddress,      // 线程信息类型 ThreadQuerySetWin32StartAddress 线程入口地址
  106.             &startaddr,                           // 指向缓冲区的指针
  107.             sizeof(startaddr),                    // 缓冲区的大小
  108.             NULL
  109.             );
  110.           // 获取线程所在模块
  111.           THREAD_BASIC_INFORMATION tbi;            // _THREAD_BASIC_INFORMATION 结构体对象
  112.           TCHAR modname[MAX_PATH];                 // 用来接收模块全路径
  113.           ZwQueryInformationThread(
  114.             hThread,                             // 线程句柄
  115.             ThreadBasicInformation,              // 线程信息类型,ThreadBasicInformation :线程基本信息
  116.             &tbi,                                // 指向缓冲区的指针
  117.             sizeof(tbi),                         // 缓冲区的大小
  118.             NULL
  119.             );
  120.           // 检查入口地址是否位于某模块中
  121.           GetMappedFileName(
  122.             OpenProcess(                                        // 进程句柄
  123.             PROCESS_ALL_ACCESS,                                 // 访问权限
  124.             FALSE,                                              // 由此线程创建的进程不继承线程的句柄
  125.             (DWORD)tbi.ClientId.UniqueProcess                   // 唯一进程 ID
  126.             ),
  127.             startaddr,                            // 要检查的地址
  128.             modname,                              // 用来接收模块名的指针
  129.             MAX_PATH                              // 缓冲区大小
  130.             );
  131.           std::cout << "线程ID: " << te32.th32ThreadID << " 线程入口: " << startaddr << " 所在模块: " << modname << std::endl;
  132.         }
  133.       }
  134.     }
  135.   }
  136. }
  137. int main(int argc, char* argv[])
  138. {
  139.   EnumThread("lyshark.exe");
  140.   system("pause");
  141.   return 0;
  142. }
复制代码
读者可自行编译并运行上述代码,通过调用SuspendProcess函数并以此传入需要挂起的进程PID以及一个状态,当该状态为TRUE时则代表挂起进程,而当状态值为FALSE时则代表为恢复一个进程,当一个进程被挂起后其会出现卡死的现象,当恢复后一切都会变得正常。
本文作者: 王瑞
本文链接: https://www.lyshark.com/post/5fbc3082.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4