獲取進程ID,父進程ID,進程完整路徑


  准備寫一個進程管理的功能模塊,今天下午先寫了掃描獲取本機各個進程路徑,獲取各個進程映像名稱,進程完整路徑。

  要獲取進程信息,第一步想到的就是提權,提權代碼用過多次了,今天也小結了一下(http://www.cnblogs.com/lsh123/p/8280575.html),不再復述。

 

0x01  自定義結構體

struct _PROCESS_INFORMATION_
{
	ULONG  ProcessID;
	ULONG  ParentProcessID;
	char   ImageNameData[MAX_PATH];
	char   ProcessFullPathData[MAX_PATH];
};

  首先定義好自己需要的各個成員變量為一個結構體,包括進程ID,父進程ID,映像名稱,進程完整路徑四個成員變量。

   

0x02  進程ID,父進程ID,進程名  ProcessEntry32結構體

    要列出所有進程,需要調用CreateToolHelp32Snapshot函數先得到系統進程快照的句柄,函數包含在<tlhelp32.h>頭中。函數的具體參數如下:

HANDLE_WINAPI CreateToolHelp32Snapshot(  
                                       DWORD dwFlags,  
                                       DWORD th32ProcessID  
                                      );  

  參數含義:

  dwFlags:指定了獲取系統進程快照的類型,獲取進程相關信息應該填入參數 TH32CS_SNAPPROCESS 表示在快照中包含系統中所有的進程

  th32ProcessID:指向要獲取進程快照的ID,獲取系統內所有進程快照時是0

  函數調用:

  

	HANDLE   SnapshotHandle = NULL;
	PROCESSENTRY32  ProcessEntry32;
	ProcessEntry32.dwSize = sizeof(PROCESSENTRY32);

	SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

  

  如果函數調用成功返回快照句柄,否則返回INVALID_HANDLE_VALUE。在得到系統進程快照句柄之后,需要調用Process32First函數查找系統進程快照中的第一個進程。函數參數如下:

BOOL Process32First(  
                    HANDLE hSnapshot,  
                    LPROCESSENTRY32 lppe  
                   );  

  再調用Process32Next函數列出系統中下一個進程,利用do while循環遍歷出所有進程,Process32Next參數如下:

BOOL Process32Next(  
                    HANDLE hSnapshot,  
                    LPROCESSENTRY32 lppe  
                   );  

  兩個函數的參數是一樣的,其中hSnapshot是由CreateToolHelp32Snapshot函數返回的系統進程快照的句柄;而lppe是指向PROCESSENTRY32的結構體指針,進程的詳細信息保存在結構體中。PROCESSENTRY32結構體定義:

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函數關閉系統進程句柄。

		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。

  函數原型:

  

DWORD GetModuleFileNameEx(
HANDLEhProcess,
HMODULE hModule,
LPTSTR lpFilename,
DWORD nSize)

   hProcess是目標進程的句柄、

  hModule是目標模塊的句柄(當此參數為NULL時函數返回的是進程可執行文件的路徑)、

  lpFilename是存放路徑的字符串緩沖區、

  nSize表示緩沖區的大小。函數調用失敗將返回0。需要注意的是進程的句柄須有PROCESS_QUERY_INFORMATION和PROCESS_VM_READ權限。

 

DWORD
 GetProcessImageFileName(
HANDLE hProcess,
LPTSTR lpImageFileName,
DWORD nSize)

   hProcess是目標進程的句柄、

  lpImageFileName是存放路徑的字符串緩沖區、

  nSize表示緩沖區的大小。函數失敗將返回0。需要注意的是進程句柄需要有PROCESS_QUERY_INFORMATION的權限。

 

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頭文件

 

  

DWORD ReturnLength = GetModuleFileNameEx(ProcessHandle, ModuleHandle,
				ProcessFullPathData,
				sizeof(ProcessFullPathData));

			if (ReturnLength == 0)
			{
				RtlZeroMemory(ProcessFullPathData, MAX_PATH);

				QueryFullProcessImageName(ProcessHandle, 0, ProcessFullPathData, &ReturnLength);	// 更推薦使用這個函數
				

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM