# 编程实现遍历进程遍历线程遍历进程加载模块
# 背景
在我们开发程序的时候,经常需要在程序中实现遍历进程、遍历线程和遍历进程加载模块等获取系统信息的操作。
本文是基于Win32 API函数实现这三个常用操作,当然,方法肯定不止有一种。比如,我写的《在VS2013中编程使用WMI》这篇文章中,使用的是WMI去遍历进程的。
现在,我把这个小程序实现的思路以及实现过程,写成文档分享给大家。
# 函数介绍
## CreateToolhelp32Snapshot 函数
> 可以通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照。
>
> 函数声明
>
> ```c++
> HANDLE WINAPI CreateToolhelp32Snapshot(
> DWORD dwFlags,
> DWORD th32ProcessID
> );
> ```
>
> 参数
>
> - dwFlags
> 指定快照中包含的系统内容,这个参数能够使用下列数值(常量)中的一个或多个:
>
>| VALUE | MEANING |
> | ------------------- | -------------------------------- |
> | TH32CS_INHERIT | 声明快照句柄是可继承的 |
> | TH32CS_SNAPALL | 在快照中包含系统中所有的进程和线程 |
> | TH32CS_SNAPHEAPLIST | 在快照中包含在th32ProcessID中指定的进程的所有的堆 |
> | TH32CS_SNAPMODULE | 在快照中包含在th32ProcessID中指定的进程的所有的模块 |
> | TH32CS_SNAPPROCESS | 在快照中包含系统中所有的进程 |
> | TH32CS_SNAPTHREAD | 在快照中包含系统中所有的线程 |
>
> - th32ProcessID
> 指定将要快照的进程ID。如果该参数为0表示快照当前进程。该参数只有在设置了TH32CS_SNAPHEAPLIST或者TH32CS_SNAPMODULE后才有效,在其他情况下该参数被忽略,所有的进程都会被快照。
>
> 返回值
>
> - 调用成功,返回快照的句柄;调用失败,返回INVALID_HANDLE_VALUE 。
## Process32First 和 Process32Next 函数
当我们利用函数CreateToolhelp32Snapshot()获得当前运行所有进程的快照后,我们可以利用Process32First函数来获得第一个进程的句柄,Process32Next函数来获得下一个进程的句柄。
## Thread32First 和 Thread32Next 函数
当我们利用函数CreateToolhelp32Snapshot()获得当前运行所有线程的快照后,我们可以利用Thread32First函数来获得第一个线程的句柄,Thread32Next函数来获得下一个线程的句柄。
## Module32First 和 Module32Next 函数
当我们利用函数CreateToolhelp32Snapshot()获得指定进程的快照后,我们可以利用Module32First函数来获得进程第一个模块的句柄,Module32Next函数来获得进程下一个模块的句柄。
# 实现原理
大家可以从上面的函数介绍可以看出,重点理解CreateToolhelp32Snapshot这个函数的操作。我们遍历进程、遍历线程以及遍历进程加载模块等3个操作,都是基于CreateToolhelp32Snapshot函数进行下一步实现的。
对于遍历进程的实现原理是:
- 首先,使用CreateToolhelp32Snapshot 函数获取所有进程的快照
- 然后,根据进程快照,使用Process32First 和 Process32Next 函数进行遍历快照,并获取快照信息
- 最后,关闭上面获取的快照的句柄
对于遍历线程的实现原理是:
- 首先,使用CreateToolhelp32Snapshot 函数获取所有线程的快照
- 然后,根据线程快照,使用Thread32First 和 Thread32Next 函数进行遍历快照,并获取快照信息
- 最后,关闭上面获取的快照的句柄
对于遍历进程模块的实现原理是:
- 首先,使用CreateToolhelp32Snapshot 函数获取指定进程的所有模块快照。
- 然后,根据模块快照,使用Module32First 和 Module32Next 函数进行遍历快照,并获取快照信息
- 最后,关闭上面获取的快照的句柄。
# 程序实现
## 遍历进程
```c++
BOOL EnumProcess()
{
PROCESSENTRY32 pe32 = { 0 };
pe32.dwSize = sizeof(PROCESSENTRY32);
// 获取全部进程快照
HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcessSnap)
{
ShowError("CreateToolhelp32Snapshot");
return FALSE;
}
// 获取快照中第一条信息
BOOL bRet = ::Process32First(hProcessSnap, &pe32);
while (bRet)
{
// 显示 Process ID
printf("[%d]\t", pe32.th32ProcessID);
// 显示 进程名称
printf("[%s]\n", pe32.szExeFile);
// 获取快照中下一条信息
bRet = ::Process32Next(hProcessSnap, &pe32);
}
// 关闭句柄
::CloseHandle(hProcessSnap);
return TRUE;
}
```
## 遍历线程
```c++
BOOL EnumThread()
{
THREADENTRY32 te32 = { 0 };
te32.dwSize = sizeof(THREADENTRY32);
// 获取全部线程快照
HANDLE hThreadSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (INVALID_HANDLE_VALUE == hThreadSnap)
{
ShowError("CreateToolhelp32Snapshot");
return FALSE;
}
// 获取快照中第一条信息
BOOL bRet = ::Thread32First(hThreadSnap, &te32);
while (bRet)
{
// 显示 Owner Process ID
printf("[%d]\t", te32.th32OwnerProcessID);
// 显示 Thread ID
printf("[%d]\n", te32.th32ThreadID);
// 获取快照中下一条信息
bRet = ::Thread32Next(hThreadSnap, &te32);
}
// 关闭句柄
::CloseHandle(hThreadSnap);
return TRUE;
}
```
## 遍历指定进程模块
```c++
BOOL EnumProcessModule(DWORD dwProcessId)
{
MODULEENTRY32 me32 = { 0 };
me32.dwSize = sizeof(MODULEENTRY32);
// 获取指定进程全部模块的快照
HANDLE hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
if (INVALID_HANDLE_VALUE == hModuleSnap)
{
ShowError("CreateToolhelp32Snapshot");
return FALSE;
}
// 获取快照中第一条信息
BOOL bRet = ::Module32First(hModuleSnap, &me32);
while (bRet)
{
// 显示 Process ID
printf("[%d]\t", me32.th32ProcessID);
// 显示 模块加载基址
printf("[0x%p]\t", me32.modBaseAddr);
// 显示 模块名称
printf("[%s]\n", me32.szModule);
// 获取快照中下一条信息
bRet = ::Module32Next(hModuleSnap, &me32);
}
// 关闭句柄
::CloseHandle(hModuleSnap);
return TRUE;
}
```
# 程序测试
在 main 函数中调用上述封装好的函数,进行测试。main 函数为:
```c++
int _tmain(int argc, _TCHAR* argv[])
{
// 遍历进程
if (FALSE == EnumProcess())
{
printf("Enum Process Error!\n");
}
system("pause");
system("cls");
// 遍历线程
if (FALSE == EnumThread())
{
printf("Enum Thread Error!\n");
}
system("pause");
system("cls");
// 遍历指定进程模块
if (FALSE == EnumProcessModule(6876))
{
printf("Enum Process Module Error!\n");
}
system("pause");
return 0;
}
```
测试结果:
运行程序,首先成功显示系统上所有进程的信息:
![](http://www.writebug.com/myres/static/uploads/2021/10/19/5496ee49a93bfc16bc5fee2aec87b294.writebug)
然后,成功显示系统上所有线程的信息:
![](http://www.writebug.com/myres/static/uploads/2021/10/19/964b5bd36f8ffe436c10a95b7c6ab4bf.writebug)
最后,成功显示指定进程“6876”的所有模块信息:
![](http://www.writebug.com/myres/static/uploads/2021/10/19/bb8f839dd1cdf27d0cd2985d08958a59.writebug)
# 总结
这个小程序看似功能比较多,感觉比较复杂,实际上,它们三者的实现方式和思路都是相同的。你只要会一个,那么这三个应该都会了,这便是举一反三啊。
其中,这个小程序重点理解CreateToolhelp32Snapshot 函数的参数就好,对于快照的遍历,根据你获取的快照信息不同,调用的快照遍历函数也不同。
# 参考
参考自《[Windows黑客编程技术详解](https://www.write-bug.com/article/1811.html "Windows黑客编程技术详解")》一书
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
05205968034511599.zip (14个子文件)
enum-process
src
EnumProcess_Test
stdafx.h 219B
EnumProcess_Test.vcxproj.filters 1KB
EnumInfo.h 180B
EnumProcess_Test.vcxproj 5KB
ReadMe.txt 2KB
EnumInfo.cpp 2KB
EnumProcess_Test.cpp 519B
stdafx.cpp 214B
targetver.h 228B
Debug
EnumProcess_Test.exe 525KB
EnumProcess_Test.v12.suo 24KB
EnumProcess_Test.sln 972B
LICENSE 1KB
README.md 8KB
共 14 条
- 1
资源评论
工具盒子
- 粉丝: 60
- 资源: 1313
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功