准備寫一個進程管理的功能模塊,今天下午先寫了掃描獲取本機各個進程路徑,獲取各個進程映像名稱,進程完整路徑。
要獲取進程信息,第一步想到的就是提權,提權代碼用過多次了,今天也小結了一下(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); // 更推薦使用這個函數