摘要
遍历系统进程常用的有三种方式
- 头文件
,先使用CreateToolhelp32Snapshot
创建系统快照,即拷贝一份系统所有进程的信息到指定的结构体PROCESSENTRY32
中,然后使用Process32First
和Process32Next
获得每一个进程的详细信息。需要注意的是编译成32位程序只能获取32位进程的详细信息,编译成64位则能获取所有进程的详细信息 - 头文件
,先使用EnumProcesses
获取系统所有的进程PID,然后用EnumProcessModules
遍历每个进程中的模块,最后用GetModuleFileNameEx
获取模块的完整路径或者用GetModuleBaseName
获取模块的名称。也需要注意程序编译的位数与进程的位数 - 无需头文件,使用NativeAPI接口
NtQuerySystemInformation
,由于是未公开函数所以需要自定义函数原型。留个坑以后填
CreateToolhelp32Snapshot
完整思路
(1).使用CreateToolhelp32Snapshot
以及传参TH32CS_SNAPPROCESS
创建系统进程快照
(2).使用Process32First
获取第一个进程的信息存入到PROCESSENTRY32
结构体中
(3).再用Process32Next
遍历所有进程
(4).最后用CloseHandle
关闭句柄
注意事项
程序很简单,需要注意的是编码问题,包括控制台输出的编码以及程序本身的编码,windows.h
头文件也定义许多保证编码兼容性的变量,比如TEXT()
_T
TCHAR
LPTSTR...
- 注意控制台中文输出需要添加编译指令
-fexec-charset=gbk
- 宽字符的使用一般是
wchar_t *ws = L"你好"; wprintf(L"%s\n",ws)
-
TCHAR
遇到宽字符就是Unicode
编码,否则就是char
类型,TEXT()
_T()
_tprintf
等函数同理 - 使用这些保证兼容性的函数可能需要的头文件有
和
,可能需要添加代码setlocale(LC_ALL,"chs");
完整Demo
#include
#include
#include
#include
int main(int argc, char *argv[])
{
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hSnapshot_proc = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot_proc != INVALID_HANDLE_VALUE)
{
BOOL check = Process32First(hSnapshot_proc, &pe32);
while (check)
{
printf("进程PID = %d 进程名 = %s\n", pe32.th32ProcessID, pe32.szExeFile);
check = Process32Next(hSnapshot_proc, &pe32);
}
}
CloseHandle(hSnapshot_proc);
system("pause");
return 0;
}
编译命令gcc -fexec-charset=gbk proc1.c -o proc1
运行截图
EnumProcesses
完整思路
(1).使用EnumProcesses
获取所有进程PID
(2).获取当前进程的Debug
权限
(3).使用OpenProcess
打开进程,依次获取所有进程的进程句柄
(4).根据进程句柄以及EnumProcessModules
遍历进程的所有模块
(5).使用GetModuleFileNameEx
获取进程的完整路径
(6).使用CloseHandle
关闭句柄以及取消Debug
权限
注意事项
使用EnumProcesses
需要注意四个坑,先说明一下我是用的MinGW
编译器,用 VScode 写完代码自己调 gcc 编译!
- 注意导入头文件的顺序,
一定要在
之后 - 注意编译指令顺序,
-lpsapi
一定要在文件名proc3.c
之后 - 注意编译成32位只能获取32位进程的信息,编译成64位都能获取
- 注意使用
OpenProcess
前一定要获取Debug
权限
完整Demo
#include
#include
#include
#include
BOOL SetProcessPrivilege(char *lpName, BOOL opt);
int main(int argc, char *argv[])
{
DWORD Proc_pid[1024], Retn_bytes, Proc_count, Retn_bytes2;
unsigned int i;
HMODULE hMod[1024];
HANDLE hProcess;
char szModName[MAX_PATH];
if (EnumProcesses(Proc_pid, sizeof(Proc_pid), &Retn_bytes))
{
Proc_count = Retn_bytes / sizeof(DWORD);
SetProcessPrivilege("SeDebugPrivilege", 1);
for (i = 0; i < Proc_count; i++)
{
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, Proc_pid[i]);
if (hProcess != NULL)
{
EnumProcessModules(hProcess, hMod, sizeof(hMod), &Retn_bytes2);
GetModuleFileNameEx(hProcess, hMod[0], szModName, sizeof(szModName));
printf("PID=%d Path=%s\n", Proc_pid[i], szModName);
}
CloseHandle(hProcess);
}
SetProcessPrivilege("SeDebugPrivilege", 0);
}
system("pause");
return 0;
}
BOOL SetProcessPrivilege(char *lpName, BOOL opt)
{
HANDLE tokenhandle;
TOKEN_PRIVILEGES NewState;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tokenhandle))
{
LookupPrivilegeValue(NULL, lpName, &NewState.Privileges[0].Luid);
NewState.PrivilegeCount = 1;
NewState.Privileges[0].Attributes = opt != 0 ? 2 : 0;
AdjustTokenPrivileges(tokenhandle, FALSE, &NewState, sizeof(NewState), NULL, NULL);
CloseHandle(tokenhandle);
return 1;
}
else
{
return 0;
}
}
编译命令gcc proc3.c -lpsapi -o proc3
运行截图