获取进程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); // 更推荐使用这个函数 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗