天天看點

[Win32] 擷取程序完整路徑

本博文由CSDN部落客zuishikonghuan所作,版權歸zuishikonghuan所有,轉載請注明出處:http://blog.csdn.net/zuishikonghuan/article/details/47746621

上兩篇中,我們講到了ToolHelp API,Process API和提升Debug權限,這一篇中來說說如何擷取程序的程式路徑。

擷取程序路徑其實有很多方法。

方法1。使用ToolHelp API枚舉子產品,其中,Module32First得到一個MODULEENTRY32 結構,結構中有一個szExePath成員,這個成員代表這個程序第一個子產品的路徑,也就是程序的路徑

(32位程式隻能擷取32位程式路徑,64位程式可以擷取32位和64位程式路徑,但需要把TH32CS_SNAPMODULE換成TH32CS_SNAPMODULE32)

方法2。使用OpenProcess打開程序,需要具有PROCESS_QUERY_INFORMATION 和 PROCESS_VM_READ權限,然後用EnumProcessModules擷取第一個子產品的子產品句柄,之後用GetModuleFileNameEx擷取子產品路徑。

EnumProcessModules的子產品句柄無需釋放:Do not call CloseHandle on any of the handles returned by this function. The information comes from a snapshot, so there are no resources to be freed.

(32位程式隻能擷取32位程式路徑,64位程式隻能擷取64位程式路徑)

完整源碼:

#define PSAPI_VERSION 1
#include <psapi.h> 
#pragma comment(lib,"psapi.lib")
           
// 擷取程序路徑 參數1:程序ID 參數2:緩沖區指針,接收路徑
void GetProcessPath(DWORD dwProcessID, LPCTSTR buffer)
{	
	TCHAR Filename[MAX_PATH];
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID);
	if (hProcess == NULL)return;
	HMODULE hModule;
	DWORD cbNeeded;
	if (EnumProcessModules(hProcess, &hModule, sizeof(hModule), &cbNeeded))
	{
		if (GetModuleFileNameEx(hProcess, hModule, Filename, MAX_PATH)){
			RtlMoveMemory((void*)buffer, Filename, sizeof(TCHAR)*MAX_PATH);
		}
	}
	CloseHandle(hProcess);
}
           

方法3。使用GetProcessImageFileName,可以在32位程式中擷取32位和64位程序路徑,這個可以在xp和以後系統中用,但是取得的程序路徑是裝置名路徑,是以還需要周遊磁盤驅動器轉換成我們需要的路徑,比較麻煩。

方法4。使用QueryFullProcessImageName,可以在32位程式中擷取32位和64位程序路徑,同時這也是微軟提供的32位程式擷取64位程序路徑的正确方法,缺點是隻能在Vista以後的系統中用

BOOL WINAPI QueryFullProcessImageName(
  _In_    HANDLE hProcess,
  _In_    DWORD  dwFlags,
  _Out_   LPTSTR lpExeName,
  _Inout_ PDWORD lpdwSize
);
           

hProcess:程序句柄,需要具有PROCESS_QUERY_INFORMATION或者PROCESS_QUERY_LIMITED_INFORMATION權限

dwFlags:以下值

0:名稱應使用 Win32 路徑格式。

PROCESS_NAME_NATIVE:名稱應使用原生系統路徑格式

lpExeName:緩沖區指針,用于接收可執行映像的路徑

lpdwSize:以字元為機關指定緩沖區大小的 lpExeName,不包括空終止字元的數

傳回值:如果此函數成功,傳回值不為零。如果函數失敗,傳回值為零。

不過感覺這個函數忒難用,,那麼加上這個函數,GetModuleFileNameEx擷取不了的就用QueryFullProcessImageName,那麼GetProcessPath就成這樣的了:

// 擷取程序路徑 參數1:程序ID 參數2:緩沖區指針,接收路徑
void GetProcessPath(DWORD dwProcessID, LPCTSTR buffer)
{
	TCHAR Filename[MAX_PATH];
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID);
	if (hProcess == NULL)return;
	HMODULE hModule;
	DWORD cbNeeded;
	if (EnumProcessModules(hProcess, &hModule, sizeof(hModule), &cbNeeded))
	{
		if (GetModuleFileNameEx(hProcess, hModule, Filename, MAX_PATH)){
			RtlMoveMemory((void*)buffer, Filename, sizeof(TCHAR)*MAX_PATH);
		}
	}
	else{
		DWORD size = MAX_PATH;
		if (QueryFullProcessImageName(hProcess, 0, Filename, &size)){
			RtlMoveMemory((void*)buffer, Filename, sizeof(TCHAR)*MAX_PATH);
		}
	}
	CloseHandle(hProcess);
}
           

這樣絕大部分程序都可以擷取路徑了,有幾個系統程序(比如services.exe)程序即使以Debug也無法打開擷取句柄,是以無法擷取路徑



繼續閱讀