【超详细】遍历Windows进程

摘要

遍历系统进程常用的有三种方式

  • 头文件,先使用CreateToolhelp32Snapshot创建系统快照,即拷贝一份系统所有进程的信息到指定的结构体PROCESSENTRY32中,然后使用Process32FirstProcess32Next获得每一个进程的详细信息。需要注意的是编译成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

运行截图

END

你可能感兴趣的:(windows,进程,c,遍历)