[WIN32]简单的办法获取父进程信息(PID|进程名)
硬核开场~~~~
下面是例子用到的相关的函数:
。NtQueryInformationProcess
。QueryFullProcessImageName
。GetProcessImageFileName
。OpenProcess
。GetCurrentProcessId
。PathStripPath
这些函数以及参数的解释在MSDN上都可以查到,虽然有一个“NtQueryInformationProcess”是“未公开函数”,但是在头文件"winternl.h"中提供了它的声明。
NtQueryInformationProcess 函数用到了一个重要的结构:
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PPEB PebBaseAddress;
PVOID Reserved2;
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
typedef PROCESS_BASIC_INFORMATION *PPROCESS_BASIC_INFORMATION;
经过前辈的探索,得知结构体中的"Reserved3"字段就是父进程的PID
得到父进程PID后我们再打开这个进程就可以获取到这个进程的相关信息了。
在使用QueryFullProcessImageName、NtQueryInformationProcess或者GetProcessImageFileName时,要求用PROCESS_QUERY_INFORMATION的方式打开
因为这只是获取信息,我们不希望去打扰人家。。。
但是“QueryFullProcessImageName”和“GetProcessImageFileName”这两个函数的要求时必须用PROCESS_QUERY_INFORMATION 或 PROCESS_QUERY_LIMITED_INFORMATION的方式打开的进程句柄。
#ifndef UNICODE
#define UNICODE
#endif // UNICODE
#ifndef _UNICODE
#define _UNICODE
#endif // _UNICODE
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <winternl.h>
#include <Shlwapi.h>
/*
/// GetProcessImageFileName 函数
//windows7: kernel32.dll|.lib
// windows r8+: psapi.dll|.lib
#include <psapi.h>
*/
#pragma comment(lib, "shlwapi.lib")
#define SETVALUEFROMPOINTER(p, v) (*p=v)
#if defined(UNICODE) || defined(_UNICODE)
#define OutPutStr(f, v) wprintf_s(L##f, v)
#else
#define OutPutStr(f, v) printf_s(f, v)
#endif
DWORD GetParentPIDAndName( DWORD ProcessID, LPTSTR lpszBuffer_Parent_Name, PDWORD ErrCodeForBuffer );
int main(int argc, const char* argv[]) {
DWORD pid;
TCHAR buf = {0};
DWORD err_code;
pid = GetParentPIDAndName(GetCurrentProcessId(), buf, &err_code);
if ( err_code ) {
fprintf(stderr, "GetProcessName--> err code: %lu\n", err_code);
}
OutPutStr("ParentProcessPID: %lu\n", pid);
OutPutStr("ParentProcessFullName: %s\n", buf);
PathStripPath(buf);
OutPutStr("ParentProcessName: %s\n", buf);
return 0;
}
typedef
__kernel_entry NTSTATUS
(NTAPI*NQIP)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
DWORD GetParentPIDAndName( DWORD ProcessID, LPTSTR lpszBuffer_Parent_Name, PDWORD ErrCodeForBuffer ) {
/// 打开给定进程PID
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessID);
if ( !ProcessID ) {
DWORD err_code = GetLastError();
fprintf_s(stderr, "err code: %lu\n", err_code);
return 0;
}
/// 下面是获取函数 NtQueryInformationProcess 的函数指针
HMODULE hNtdll = GetModuleHandle(_T("ntdll.dll"));
if ( !hNtdll ) {
DWORD err_code = GetLastError();
fprintf_s(stderr, "err code: %lu\n", err_code);
CloseHandle(hProcess);
return 0;
}
NQIP _NtQueryInformationProcess = (NQIP)GetProcAddress(hNtdll, "NtQueryInformationProcess");
if ( !_NtQueryInformationProcess ) {
DWORD err_code = GetLastError();
fprintf_s(stderr, "err code: %lu\n", err_code);
CloseHandle(hProcess);
return 0;
}
//***
/// 获取打开的进程的进程进程信息
PROCESS_BASIC_INFORMATION pbi;
NTSTATUS status = _NtQueryInformationProcess(
hProcess,
ProcessBasicInformation,
(LPVOID)&pbi, sizeof(PROCESS_BASIC_INFORMATION),
NULL);
DWORD dwParentID = 0;
if ( NT_SUCCESS(status) ) {
/// 结构体 PROCESS_BASIC_INFORMATION 的 "Reserved3"字段 是父进程的PID
dwParentID = (LONG_PTR)pbi.Reserved3;
if ( NULL != lpszBuffer_Parent_Name ) {
HANDLE hParentProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwParentID);
if ( hParentProcess ) {
/// 用来接收进程文件名和路径的长度(必须!)
DWORD bufs;
/// 获取进程路径
BOOL ret = QueryFullProcessImageName(hParentProcess, 0, lpszBuffer_Parent_Name, &bufs);
if ( TRUE == ret )
SETVALUEFROMPOINTER(ErrCodeForBuffer, 0);
else
SETVALUEFROMPOINTER(ErrCodeForBuffer, GetLastError());
/*
/// 结果是DOS路径+文件名
TCHAR buf;
GetProcessImageFileName(hParentProcess, buf, BUFSIZ);
cout << ": " << buf << endl;
*/
}
else {
SETVALUEFROMPOINTER(ErrCodeForBuffer, GetLastError());
}
if ( hParentProcess )
CloseHandle(hParentProcess);
}
}
else {
DWORD err_code = GetLastError();
fprintf_s(stderr, "err code: %lu\n", err_code);
}
CloseHandle(hProcess);
return dwParentID;
}
“QueryFullProcessImageName”和“GetProcessImageFileName”的区别是,前者反回的是我们平常常见且使用的win32路径,后者返回的是完整的设备路径。
“GetProcessImageFileName”的介绍点击这儿
我编译运行的工具是codebocks+vs2010附带的编译工具(msvc)(cl-16.00.30319.01和link-10.00.30319.01)
codeblocks 运行一个程序是使用“cb_console_runner.exe”来启动的,所以它就是父进程。
结果:
完结撒花❀❀❀❀❀❀❀❀❀
希望这篇文章能对有需要的朋友提供帮助。。。
大佬,请问这里怎么补救? 本帖最后由 lovingxiaobing 于 2019-2-9 14:00 编辑
450046181 发表于 2019-2-9 13:47
大佬,请问这里怎么补救?
WTF? 您的VS没有找到这个函数。。。。
函数的MSDN文档:
https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-queryfullprocessimagenamea
如果是提示“连接不到外部符号”等类似的提示的话自己
#pragma comment(lib, "kernel32.lib")
如果还是找不到就自己用GetProcAddress导出来吧:$qqq
这个函数再 “Kernel32.dll” 里
谢谢你,教的很细心,呵呵~!{:1_893:} 谢谢分享
页:
[1]