【超詳細】遍歷Windows進程

摘要

遍歷系統進程經常使用的有三種方式windows

  • 頭文件<Tlhelp32.h>,先使用CreateToolhelp32Snapshot建立系統快照,即拷貝一份系統全部進程的信息到指定的結構體PROCESSENTRY32中,而後使用Process32FirstProcess32Next得到每個進程的詳細信息。須要注意的是編譯成32位程序只能獲取32位進程的詳細信息,編譯成64位則能獲取全部進程的詳細信息
  • 頭文件<psapi.h>,先使用EnumProcesses獲取系統全部的進程PID,而後用EnumProcessModules遍歷每一個進程中的模塊,最後用GetModuleFileNameEx獲取模塊的完整路徑或者用GetModuleBaseName獲取模塊的名稱。也須要注意程序編譯的位數與進程的位數
  • 無需頭文件,使用NativeAPI接口NtQuerySystemInformation,因爲是未公開函數因此須要自定義函數原型。留個坑之後填

CreateToolhelp32Snapshot

完整思路
(1).使用CreateToolhelp32Snapshot以及傳參TH32CS_SNAPPROCESS建立系統進程快照
(2).使用Process32First獲取第一個進程的信息存入到PROCESSENTRY32結構體中
(3).再用Process32Next遍歷全部進程
(4).最後用CloseHandle關閉句柄api

注意事項
程序很簡單,須要注意的是編碼問題,包括控制檯輸出的編碼以及程序自己的編碼,windows.h頭文件也定義許多保證編碼兼容性的變量,好比TEXT() _T TCHAR LPTSTR...函數

  • 注意控制檯中文輸出須要添加編譯指令-fexec-charset=gbk
  • 寬字符的使用通常是wchar_t *ws = L"你好"; wprintf(L"%s\n",ws)
  • TCHAR遇到寬字符就是Unicode編碼,不然就是char類型,TEXT() _T() _tprintf等函數同理
  • 使用這些保證兼容性的函數可能須要的頭文件有<locale.h><tchar.h>,可能須要添加代碼setlocale(LC_ALL,"chs");

完整Demoui

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <Tlhelp32.h>

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編碼

運行截圖spa

clipboard.png

EnumProcesses

完整思路
(1).使用EnumProcesses獲取全部進程PID
(2).獲取當前進程的Debug權限
(3).使用OpenProcess打開進程,依次獲取全部進程的進程句柄
(4).根據進程句柄以及EnumProcessModules遍歷進程的全部模塊
(5).使用GetModuleFileNameEx獲取進程的完整路徑
(6).使用CloseHandle關閉句柄以及取消Debug權限code

注意事項
使用EnumProcesses須要注意四個坑,先說明一下我是用的MinGW編譯器,用 VScode 寫完代碼本身調 gcc 編譯!orm

  • 注意導入頭文件的順序,<psapi.h>必定要在<windows.h>以後
  • 注意編譯指令順序,-lpsapi必定要在文件名proc3.c以後
  • 注意編譯成32位只能獲取32位進程的信息,編譯成64位都能獲取
  • 注意使用OpenProcess前必定要獲取Debug權限

完整Demotoken

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <psapi.h>

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接口

運行截圖

clipboard.png

END

相關文章
相關標籤/搜索