zoukankan      html  css  js  c++  java
  • 获取进程ID,父进程ID,进程完整路径

      准备写一个进程管理的功能模块,今天下午先写了扫描获取本机各个进程路径,获取各个进程映像名称,进程完整路径。

      要获取进程信息,第一步想到的就是提权,提权代码用过多次了,今天也小结了一下(http://www.cnblogs.com/lsh123/p/8280575.html),不再复述。

    0x01  自定义结构体

    struct _PROCESS_INFORMATION_
    {
    	ULONG  ProcessID;
    	ULONG  ParentProcessID;
    	char   ImageNameData[MAX_PATH];
    	char   ProcessFullPathData[MAX_PATH];
    };
    

      首先定义好自己需要的各个成员变量为一个结构体,包括进程ID,父进程ID,映像名称,进程完整路径四个成员变量。

       

    0x02  进程ID,父进程ID,进程名  ProcessEntry32结构体

        要列出所有进程,需要调用CreateToolHelp32Snapshot函数先得到系统进程快照的句柄,函数包含在<tlhelp32.h>头中。函数的具体参数如下:

    HANDLE_WINAPI CreateToolHelp32Snapshot(  
                                           DWORD dwFlags,  
                                           DWORD th32ProcessID  
                                          );  
    

      参数含义:

      dwFlags:指定了获取系统进程快照的类型,获取进程相关信息应该填入参数 TH32CS_SNAPPROCESS 表示在快照中包含系统中所有的进程

      th32ProcessID:指向要获取进程快照的ID,获取系统内所有进程快照时是0

      函数调用:

      

    	HANDLE   SnapshotHandle = NULL;
    	PROCESSENTRY32  ProcessEntry32;
    	ProcessEntry32.dwSize = sizeof(PROCESSENTRY32);
    
    	SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    

      

      如果函数调用成功返回快照句柄,否则返回INVALID_HANDLE_VALUE。在得到系统进程快照句柄之后,需要调用Process32First函数查找系统进程快照中的第一个进程。函数参数如下:

    BOOL Process32First(  
                        HANDLE hSnapshot,  
                        LPROCESSENTRY32 lppe  
                       );  
    

      再调用Process32Next函数列出系统中下一个进程,利用do while循环遍历出所有进程,Process32Next参数如下:

    BOOL Process32Next(  
                        HANDLE hSnapshot,  
                        LPROCESSENTRY32 lppe  
                       );  
    

      两个函数的参数是一样的,其中hSnapshot是由CreateToolHelp32Snapshot函数返回的系统进程快照的句柄;而lppe是指向PROCESSENTRY32的结构体指针,进程的详细信息保存在结构体中。PROCESSENTRY32结构体定义:

    typedef struct tagPROCESSENTRY32 {  
                                      DWORD dwSize;//结构大小  
                                      DWORD cntUsage;//此进程的引用计数  
                                      DWORD th32ProcessID;//进程ID  
                                      DWORD th32DefaultHeapID;//进程默认堆ID  
                                      DWORD th32ModuleID;//进程模块ID  
                                      DWORD cntThreads;//此进程开启的线程计数  
                                      DWORD th32ParentProcessID;//父进程ID  
                                      LONG pcPriClassBase;//线程优先权  
                                      DWORD dwFlags;//保留  
                                      char szExeFile[MAX_PATH];//进程名  
                                    } PROCESSENTRY32;  
    

      可以看到PROCESSENTRY32结构体中我所需要的三个成员,进程ID,父进程ID,进程名。

      当上述两个函数列举到进程时返回TRUE,否则返回FALSE。当列举到一个进程时lppe参数就会返回进程的详细信息,所以用户就可以读取这些进程的信息,然后输出。

    列举完后,需要调用CloseHandle函数关闭系统进程句柄。

    		do
    		{
    			//打开进程并返回句柄
    			ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
    				FALSE, ProcessEntry32.th32ProcessID);   //打开目标进程  
    														//		(ProcessEntry32.th32ProcessID !=4))
    			if (ProcessHandle == NULL)// 权限太高 - 降低打开
    			{
    				ProcessHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
    					FALSE, ProcessEntry32.th32ProcessID);   //打开目标进程
    
    				if (ProcessHandle == NULL)
    				{
    					strcpy(ProcessFullPathData, "打开进程失败");
    
    					goto Label1;
    
    				}
    			}
    			//获得进程下的第一个模块
    			HMODULE ModuleHandle = NULL;
    
    			DWORD ReturnLength = GetModuleFileNameEx(ProcessHandle, ModuleHandle,
    				ProcessFullPathData,
    				sizeof(ProcessFullPathData));
    
    			if (ReturnLength == 0)
    			{
    				RtlZeroMemory(ProcessFullPathData, MAX_PATH);
    
    				QueryFullProcessImageName(ProcessHandle, 0, ProcessFullPathData, &ReturnLength);	// 更推荐使用这个函数
    				if (ReturnLength == 0)
    				{
    					strcpy(ProcessFullPathData, "枚举信息失败");
    				}
    			}
    			//BufferData[[20][calc.exe][              ][20][calc.exe][              ][20][calc.exe][              ]                          ]
    		Label1:
    			ZeroMemory(&v1, sizeof(v1));
    
    			v1.ProcessID = ProcessEntry32.th32ProcessID;
    			v1.ParentProcessID = ProcessEntry32.th32ParentProcessID;
    			//v1.ParentProcessID = GetParentProcessID(v1.ProcessID);
    			memcpy(v1.ImageNameData, ProcessEntry32.szExeFile, lstrlen(ProcessEntry32.szExeFile) + 1);
    			memcpy(v1.ProcessFullPathData, ProcessFullPathData, lstrlen(ProcessFullPathData) + 1);
    
    			ProcessInfo.push_back(v1);
    			if (ProcessHandle != NULL)
    			{
    				CloseHandle(ProcessHandle);
    				ProcessHandle = NULL;
    			}
    
    		} while (Process32Next(SnapshotHandle, &ProcessEntry32));
    

      

    0x03  进程完整路径

        获得进程完整路径的3个WINDOWS API:

        GetModuleFileNameEx

        GetProcessImageFileName

        QueryFullProcessImageName

        

      第一个函数:想获得进程可执行文件的路径最常用的方法是通过GetModuleFileNameEx函数获得可执行文件的模块路径这个函数从Windows NT 4.0开始到现在的Vista系统都能使用,向后兼容性比较好。

      第二个函数:GetProcessImageFileName函数,这个函数在Windows XP及其以后的系统中都能使用,使用此函数返回的路径不是通常的系统盘符,如"C:...",而是驱动层的表示方式"DeviceHarddiskVolume1...",所以使用起来不是很方便。

      第三个函数:Windows Vista新增的函数QueryFullProcessImageName。

      函数原型:

      

    DWORD GetModuleFileNameEx(
    HANDLEhProcess,
    HMODULE hModule,
    LPTSTR lpFilename,
    DWORD nSize)
    

       hProcess是目标进程的句柄、

      hModule是目标模块的句柄(当此参数为NULL时函数返回的是进程可执行文件的路径)、

      lpFilename是存放路径的字符串缓冲区、

      nSize表示缓冲区的大小。函数调用失败将返回0。需要注意的是进程的句柄须有PROCESS_QUERY_INFORMATION和PROCESS_VM_READ权限。

    DWORD
     GetProcessImageFileName(
    HANDLE hProcess,
    LPTSTR lpImageFileName,
    DWORD nSize)
    

       hProcess是目标进程的句柄、

      lpImageFileName是存放路径的字符串缓冲区、

      nSize表示缓冲区的大小。函数失败将返回0。需要注意的是进程句柄需要有PROCESS_QUERY_INFORMATION的权限。

    BOOL QueryFullProcessImageName(
    HANDLEhProcess,
    DWORD dwFlags,
    LPTSTR lpExeName,
    PDWORD lpdwSize)
    

      hProcess是目标进程的句柄、

      dwFlags一般设为0(表示返回的路径是Win32的路径格式,如"C:...",如将其设为PROCESS_NAME_NATIVE将返回"DeviceHarddiskVolume1..."这样的格式路径)、

      lpExeName是存放路径的字符串缓冲区、

      lpdwSize表示缓冲区的大小。

      函数失败将返回FALSE。需要注意的是调用此函数的句柄须有PROCESS_QUERY_INFORMATION或这是PROCESS_QUERY_LIMITED_INFORMATION的权限,并且只能在Vista或更高版本的系统中使用。

      调用GetModuleFileNameEx和GetProcessImageFileName需要包含Psapi.h头文件

      

    DWORD ReturnLength = GetModuleFileNameEx(ProcessHandle, ModuleHandle,
    				ProcessFullPathData,
    				sizeof(ProcessFullPathData));
    
    			if (ReturnLength == 0)
    			{
    				RtlZeroMemory(ProcessFullPathData, MAX_PATH);
    
    				QueryFullProcessImageName(ProcessHandle, 0, ProcessFullPathData, &ReturnLength);	// 更推荐使用这个函数
    				
    

      

  • 相关阅读:
    分布式事务的四种解决方案
    十大经典排序算法
    Vineyard 加入 CNCF Sandbox,将继续瞄准云原生大数据分析领域
    因你不同,2021 阿里云开发者大会重磅开启 @ 所有开发者!
    【深度】阿里巴巴万级规模 K8s 集群全局高可用体系之美
    业界率先支持 MCP-OVER-XDS 协议,Nacos 2.0.1 + 1.4.2 Release 正式发布
    被解救的代码
    KubeVela + KEDA:为应用带来“与生俱来”的弹性伸缩能力
    论好文章和烂文章
    Fluid 进入 CNCF Sandbox,加速大数据和 AI 应用拥抱云原生
  • 原文地址:https://www.cnblogs.com/lsh123/p/8280603.html
Copyright © 2011-2022 走看看