刘收获

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

获取进程ID,父进程ID,进程完整路径

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

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

 

0x01  自定义结构体

1
2
3
4
5
6
7
struct _PROCESS_INFORMATION_
{
    ULONG  ProcessID;
    ULONG  ParentProcessID;
    char   ImageNameData[MAX_PATH];
    char   ProcessFullPathData[MAX_PATH];
};

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

   

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

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

1
2
3
4
HANDLE_WINAPI CreateToolHelp32Snapshot( 
                                       DWORD dwFlags, 
                                       DWORD th32ProcessID 
                                      ); 

  参数含义:

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

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

  函数调用:

  

1
2
3
4
5
HANDLE   SnapshotHandle = NULL;
PROCESSENTRY32  ProcessEntry32;
ProcessEntry32.dwSize = sizeof(PROCESSENTRY32);
 
SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

  

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

1
2
3
4
BOOL Process32First( 
                    HANDLE hSnapshot, 
                    LPROCESSENTRY32 lppe 
                   ); 

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

1
2
3
4
BOOL Process32Next( 
                    HANDLE hSnapshot, 
                    LPROCESSENTRY32 lppe 
                   ); 

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

1
2
3
4
5
6
7
8
9
10
11
12
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函数关闭系统进程句柄。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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\0][              \0][20][calc.exe\0][              \0][20][calc.exe\0][              \0]                          ]
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:\...",而是驱动层的表示方式"\Device\HarddiskVolume1\...",所以使用起来不是很方便。

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

  函数原型:

  

1
2
3
4
5
DWORD GetModuleFileNameEx(
HANDLEhProcess,
HMODULE hModule,
LPTSTR lpFilename,
DWORD nSize)

   hProcess是目标进程的句柄、

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

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

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

 

1
2
3
4
5
DWORD
 GetProcessImageFileName(
HANDLE hProcess,
LPTSTR lpImageFileName,
DWORD nSize)

   hProcess是目标进程的句柄、

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

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

 

1
2
3
4
5
BOOL QueryFullProcessImageName(
HANDLEhProcess,
DWORD dwFlags,
LPTSTR lpExeName,
PDWORD lpdwSize)

  hProcess是目标进程的句柄、

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

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

  lpdwSize表示缓冲区的大小。

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

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

 

  

1
2
3
4
5
6
7
8
9
10
DWORD ReturnLength = GetModuleFileNameEx(ProcessHandle, ModuleHandle,
                ProcessFullPathData,
                sizeof(ProcessFullPathData));
 
            if (ReturnLength == 0)
            {
                RtlZeroMemory(ProcessFullPathData, MAX_PATH);
 
                QueryFullProcessImageName(ProcessHandle, 0, ProcessFullPathData, &ReturnLength);    // 更推荐使用这个函数
                

  

posted on   沉疴  阅读(4335)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示