CProcessUtils.h
#pragma once
#include <wtypesbase.h>
#include <tchar.h>
#include <vector>
#include <map>
#include <string>
#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
namespace CProcessUtils
{
// https://learn.microsoft.com/zh-cn/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
// 版本号结构
typedef union _VERSON_NUMBER {
DWORD Data;
struct {
WORD wLow; // 版本号低16位
WORD wHigh; // 版本号高16位
}Version;
_VERSON_NUMBER() : Data(0) {}
}VERSON_NUMBER;
typedef struct _VS_VER_FIXEDFILEINFO {
DWORD dwSignature; // 0xFEEF04BD
VERSON_NUMBER dwStrucVersion; // 此结构的二进制版本号。 此成员的高序字包含主版本号,低序字包含次要版本号。
VERSON_NUMBER dwFileVersionMS; // 文件二进制版本号中最重要的 32 位。 此成员与 dwFileVersionLS 一起使用,形成用于数字比较的 64 位值。
VERSON_NUMBER dwFileVersionLS; // 文件二进制版本号中最低有效 32 位。 此成员与 dwFileVersionMS 一起使用,形成用于数字比较的 64 位值。
VERSON_NUMBER dwProductVersionMS; // 分发此文件的产品的二进制版本号中最重要的 32 位。 此成员与 dwProductVersionLS 一起使用,形成用于数字比较的 64 位值。
VERSON_NUMBER dwProductVersionLS; // 分发此文件的产品的二进制版本号中最低有效 32 位。 此成员与 dwProductVersionMS 一起使用,形成用于数字比较的 64 位值。
DWORD dwFileFlagsMask; // 包含指定 dwFileFlags 中的有效位的位掩码。 仅当在创建文件时定义位时,位才有效。
struct {
DWORD fVS_FF_DEBUG : 1; // 该文件包含调试信息,或者在启用调试功能的情况下进行编译。
DWORD fVS_FF_PRERELEASE : 1; // 该文件是开发版本,而不是商业发布的产品。
DWORD fVS_FF_PRIVATEBUILD : 1; // 文件不是使用标准发布过程生成的。 如果设置了此标志, StringFileInfo 结构应包含 PrivateBuild 条目。
DWORD fVS_FF_PATCHED : 1; // 该文件已修改,与同一版本号的原始发货文件不同。
DWORD fVS_FF_INFOINFERRED : 1; // 文件的版本结构是动态创建的;因此,此结构中的某些成员可能为空或不正确。 切勿在文件的 VS_VERSIONINFO 数据中设置此标志。
DWORD fVS_FF_SPECIALBUILD : 1; // 该文件由原始公司使用标准发布过程生成,但是相同版本号的正常文件的变体。 如果设置了此标志, StringFileInfo 结构应包含 SpecialBuild 条目。
DWORD fVS_FF_Reserved : 26; // 保留未使用
}dwFileFlags; // 包含指定文件的布尔属性的位掩码。
union _FILE_OS {
DWORD dwData;
struct {
enum eFileOSLo : WORD {
eVOS_LO_UNKNOWN = 0x0000L, // 系统不知道设计该文件的操作系统
eVOS_LO_WINDOWS16 = 0x0001L, // 该文件是为 16 位 Windows 设计的
eVOS_LO_PM16 = 0x0002L, // 该文件是为 16 位 Presentation Manager 设计的
eVOS_LO_PM32 = 0x0003L, // 该文件是为 32 位 Presentation Manager 设计的
eVOS_LO_WINDOWS32 = 0x0004L, // 该文件专为 32 位 Windows 设计
}Low;
enum eFileOSHi : WORD {
eVOS_HI_UNKNOWN = 0x0000L, // 系统不知道设计该文件的操作系统
eVOS_HI_DOS = 0x0001L, // 该文件是针对 MS-DOS 设计的
eVOS_HI_OS216 = 0x0002L, // 该文件是为 16 位 OS/2 设计的
eVOS_HI_OS232 = 0x0003L, // 该文件是为 32 位 OS/2 设计的
eVOS_HI_NT = 0x0004L, // 该文件是为 Windows NT 设计的
}High;
};
}dwFileOS; // 为其设计此文件的操作系统
enum eFileType : DWORD {
eVFT_UNKNOWN = 0x00000000L, // 系统不知道文件类型
eVFT_APP = 0x00000001L, // 该文件包含一个应用程序
eVFT_DLL = 0x00000002L, // 该文件包含一个 DLL
eVFT_DRV = 0x00000003L, // 该文件包含设备驱动程序
eVFT_FONT = 0x00000004L, // 该文件包含字体
eVFT_VXD = 0x00000005L, // 该文件包含一个虚拟设备
eVFT_STATIC_LIB = 0x00000007L // 该文件包含一个静态链接库
}dwFileType; // 文件的常规类型
union {
// 如果 dwFileTypeVFT_FONT, 则 dwFileSubtype 可以是以下值之一。
enum eFileSubtypeDrv : DWORD {
eVFT2_DRV_UNKNOWN = 0x00000000L, //系统未知驱动程序类型。
eVFT2_DRV_PRINTER = 0x00000001L, //文件包含打印机驱动程序。
eVFT2_DRV_KEYBOARD = 0x00000002L, //文件包含键盘驱动程序。
eVFT2_DRV_LANGUAGE = 0x00000003L, //文件包含语言驱动程序。
eVFT2_DRV_DISPLAY = 0x00000004L, //文件包含显示驱动程序。
eVFT2_DRV_MOUSE = 0x00000005L, //文件包含鼠标驱动程序。
eVFT2_DRV_NETWORK = 0x00000006L, //文件包含网络驱动程序。
eVFT2_DRV_SYSTEM = 0x00000007L, //文件包含系统驱动程序。
eVFT2_DRV_INSTALLABLE = 0x00000008L, //文件包含可安装的驱动程序。
eVFT2_DRV_SOUND = 0x00000009L, //该文件包含声音驱动程序。
eVFT2_DRV_COMM = 0x0000000AL, //文件包含通信驱动程序。
eVFT2_DRV_VERSIONED_PRINTER = 0x0000000CL, //文件包含版本控制打印机驱动程序。
}dwFileTypeVFT_DRV; // 驱动文件类型
// 如果 dwFileTypeVFT_VXD, 则 dwFileSubtype 包含虚拟设备控制块中包含的虚拟设备标识符。
enum eFileSubtypeFont : DWORD {
eVFT2_FONT_UNKNOWN = 0x00000000L, //系统未知字体类型。
eVFT2_FONT_RASTER = 0x00000001L, //文件包含光栅字体。
eVFT2_FONT_TRUETYPE = 0x00000003L, //文件包含 TrueType 字体。
eVFT2_FONT_VECTOR = 0x00000002L, //文件包含矢量字体。
}dwFileTypeVFT_FONT; // 字体文件类型
}dwFileSubtype; // 文件的子类型
DWORD dwFileDateMS; // 文件的 64 位二进制创建日期和时间戳中最高有效 32 位。
DWORD dwFileDateLS; // 文件的 64 位二进制创建日期和时间戳的最低有效 32 位。
} VS_VER_FIXEDFILEINFO, * PVS_VER_FIXEDFILEINFO;
// 语言与代码页
typedef struct _LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage; // https://learn.microsoft.com/zh-cn/windows/win32/menurc/varfileinfo-block
_LANGANDCODEPAGE() : wLanguage(0), wCodePage(0) {}
bool operator < (const _LANGANDCODEPAGE& r) const
{
MAKELANGID(this->wLanguage, this->wCodePage);
if (this->wLanguage < r.wLanguage)
{
return true;
}
if (this->wCodePage < r.wCodePage)
{
return true;
}
return false;
}
bool operator == (const _LANGANDCODEPAGE& r) const
{
return this->wLanguage == r.wLanguage && this->wCodePage == r.wCodePage;
}
}LANGANDCODEPAGE, * PLANGANDCODEPAGE;
// 版本号辅助类
class CVersionNumber
{
public:
CVersionNumber();
CVersionNumber(const _tstring& strVer);
CVersionNumber(WORD v1, WORD v2, WORD v3, WORD v4);
CVersionNumber& operator = (const _tstring& strVer);
_tstring GetString() const;
bool IsEmpty() const;
void Clear();
bool operator == (const CVersionNumber& ref);
bool operator != (const CVersionNumber& ref);
bool operator < (const CVersionNumber& ref);
bool operator <= (const CVersionNumber& ref);
bool operator > (const CVersionNumber& ref);
bool operator >= (const CVersionNumber& ref);
private:
int _Compare(const CVersionNumber& ref) const;
private:
WORD m_nVer[4]; //版本号
};
// PE文件信息
typedef struct _VERSION_INFO
{
LANGANDCODEPAGE langAndCodePage; // 语言代码页
_tstring strLanguageName; // 语言名
_tstring strComments; // 文件注释
_tstring strInternalName; // 内部名称
_tstring strProductName; // 产品名称
_tstring strCompanyName; // 公司名称
_tstring strLegalCopyright; // 法律版权
_tstring strProductVersion; // 产品版本
_tstring strFileDescription; // 文件描述
_tstring strLegalTrademarks; // 合法商标
_tstring strPrivateBuild; // 私有构建
_tstring strFileVersion; // 文件版本
_tstring strOriginalFilename; // 原始文件名
_tstring strSpecialBuild; // 特殊构建
_tstring strFileVersionEx; // 文件版本(从 VS_FIXEDFILEINFO 中获取)
_tstring strProductVersionEx; // 产品版本(从 VS_FIXEDFILEINFO 中获取)
VS_VER_FIXEDFILEINFO vsFixedInfo; // 固定文件信息
CVersionNumber FileVerNumber; // 文件版本号
CVersionNumber ProductVerNumber; // 产品版本号
}VERSION_INFO;
using VERSION_LIST = std::map<LANGANDCODEPAGE, VERSION_INFO>;
// 进程信息
typedef struct _PROC_INFO
{
_tstring strFilePath; // 可执行文件的名称
_tstring strExeFile; // 可执行文件的名称
_tstring strDomainName; // 域名
_tstring strUserName; // 用户名
LONG nPriClassBase; // 此进程创建的任何线程的基本优先级
DWORD dwPID; // 进程ID
DWORD dwParentPID; // 父进程ID
DWORD cntThreads; // 进程启动的执行线程
DWORD dwGdiCount; // GDI对象计数
DWORD dwUserCount; // 用户对象计数
DWORD dwHandleCount; // 句柄计数
DWORD dwSessionId; // 会话ID
BOOL fWow64; // 32位应用程序
VERSION_LIST fileVersion; // 文件版本信息
_PROC_INFO()
:
dwPID(0),
dwParentPID(0),
nPriClassBase(0),
cntThreads(0),
dwGdiCount(0),
dwUserCount(0),
dwHandleCount(0),
dwSessionId(0),
fWow64(0)
{
}
}PROC_INFO;
// 模块信息
typedef struct _MODULE_INFO
{
_tstring strModule; // 模块名
_tstring strExePath; // 模块路径
DWORD th32ProcessID; // 要检查其模块的进程标识符
DWORD GlblcntUsage; // 模块的负载计数,通常没有意义,通常等于0xFFFF
BYTE* modBaseAddr; // 拥有进程上下文中模块的基址
DWORD modBaseSize; // 模块的大小(以字节为单位)
HMODULE hModule; // 拥有进程上下文中模块的句柄
_MODULE_INFO()
:
th32ProcessID(0),
GlblcntUsage(0),
modBaseAddr(0),
modBaseSize(0),
hModule(NULL)
{
}
}MODULE_INFO;
// 进程节点信息
typedef struct _PROC_NODE
{
PROC_INFO ProcInfo; // 进程信息
std::vector<_PROC_NODE> NodeList; // 子进程列表
}PROC_NODE;
// PE文件头信息
typedef struct _PE_HEADER_INFO
{
IMAGE_DOS_HEADER m_DosHeader; // Dos头
union {
IMAGE_NT_HEADERS64 m_NtHeaders64; // NT头(64位)
IMAGE_NT_HEADERS32 m_NtHeaders32; // NT头(32位)
};
WORD m_NtHeadersMagic; // NT头魔数
}PE_HEADER_INFO;
// 进程名信息
typedef struct _PROCESS_NAME_INFO
{
DWORD SessionId;
DWORD ProcessId;
_tstring ProcessName;
_tstring UserName;
_tstring DomainName;
} PROCESS_NAME_INFO, * PPROCESS_NAME_INFO;
// 进程组信息
typedef struct _PROCESS_GROUPS_INFO
{
_tstring DomainName;
_tstring UserName;
_tstring SID;
DWORD Attributes;
} PROCESS_GROUPS_INFO, * PPROCESS_GROUPS_INFO;
// 窗口信息
typedef struct _WND_INFO
{
HWND hWnd;
DWORD dwPid;
DWORD dwTid;
_tstring strClass;
_tstring strText;
}WND_INFO;
// 窗口节点信息
typedef struct _WND_NODE
{
HWND hWnd; // 窗口句柄
DWORD dwPid; // 窗口进程ID
DWORD dwTid; // 窗口线程ID
_tstring strClass; // 窗口类名
_tstring strText; // 窗口名
_tstring strModule; // 窗口关联的模块名
std::vector<_WND_NODE> NodeList; // 子窗口列表
}WND_NODE;
using PROC_NAME_LIST = std::map<DWORD, PROCESS_NAME_INFO>;
using PROC_INFO_LIST = std::map<DWORD, PROC_INFO>;
using PROC_NODE_LIST = std::map<DWORD, PROC_NODE>;
using MODULE_INFO_LIST = std::vector<MODULE_INFO>;
//
// 进程提权
// @param: hProcess 进程句柄
// @param: lpPrivilegesName 特权名
// @ret: bool 操作是否成功
bool EnablePrivileges(HANDLE hProcess, LPCTSTR lpPrivilegesName);
//
// @brief: 创建进程
// @param: strExePath 可执行文件路径
// @param: strCommand 命令参数
// @param: strCurDir 程序的当前目录
// @param: bShow 是否显示程序
// @param: bWait 是否等待程序直到其退出
// @ret: bool 操作是否成功
bool CreateProcessNormal(
const _tstring& strExePath = _T(""),
const _tstring& strCommand = _T(""),
const _tstring& strCurDir = _T(""),
bool bShow = true,
bool bWait = true
);
//
// @brief: 创建 带有UI 权限的进程
// @param: strExePath 可执行文件路径
// @param: strCommand 命令参数
// @param: strCurDir 程序的当前目录
DWORD CreateProcessWithUIAccess(
const _tstring& strExePath,
const _tstring& strCommand,
const _tstring& strCurDir = _T("")
);
//
// @brief: 创建不带UI权限的进程
// @param: strExePath 可执行文件路径
// @param: strCommand 命令参数
// @param: strCurDir 程序的当前目录
DWORD CreateProcessNoUIAccess(
const _tstring& strExePath,
const _tstring& strCommand,
const _tstring& strCurDir = _T("")
);
//
// @brief: 创建 SYSTEM 权限的进程
// @param: strExePath 可执行文件路径
// @param: strCommand 命令参数
// @param: strCurDir 程序的当前目录
bool CreateProcessWithSystem(
const _tstring& strExePath,
const _tstring& strCommand,
const _tstring& strCurDir = _T("")
);
//
// @brief: 检查指定进程是否有UI权限
// @param: dwPid 进程ID
// @param: pdwErr 输出错误码
// @param: pfUIAccess 输出权限
// @param: 操作是否成功
BOOL CheckProcessUIAccess(
DWORD dwPid,
DWORD* pdwErr,
DWORD* pfUIAccess
);
//
// @brief: 获取文件版本列表
// @param: strFile 文件路径
// @param: fLocalised 本地化
// @ret: VERSION_LIST 文件版本信息列表
VERSION_LIST GetFileVersionList(const _tstring& strFile, bool fLocalised = true);
//
// @brief: 获取文件版本
// @param: strFile 文件路径
// @param: fLocalised 本地化
// @ret: VERSION_INFO 文件版本信息
VERSION_INFO GetFileVersion(const _tstring& strFile, bool fLocalised = true);
//
// @brief: 获取进程可执行文件路径
// @param: dwPID 进程ID
// @param: bNtPath 是否为Win32 样式的 NT 路径
// @ret: _tstring 进程可执行文件路径
_tstring GetPath(DWORD dwPID, bool bNtPath = true);
//
// @brief: 获取进程可执行文件路径
// @param: dwPID 进程ID
// @param: bNtPath 是否为Win32 样式的 NT 路径
// @ret: _tstring 进程可执行文件路径
_tstring GetPathEx(DWORD dwPID, bool bNtPath = true);
//
// @brief: 获取父进程可执行文件路径
// @param: dwPID 进程ID
// @param: bNtPath 是否为Win32 样式的 NT 路径
// @ret: _tstring 进程可执行文件路径
_tstring GetParentPath(DWORD dwPID, bool bNtPath = true);
//
// @brief: 获取进程名列表
// @ret: PROC_NAME_LIST 进程名列表
PROC_NAME_LIST GetProcessNames();
//
// @brief: 获取进程信息列表
// @param: strName 进程名
// @param: dwPID 进程ID
// @ret: std::map<DWORD, PROC_INFO> 进程信息列表
PROC_INFO_LIST GetProcessInfos(const _tstring& strName = _T(""), DWORD dwPID = 0);
//
// @brief: 获取进程信息
// @param: dwPID 进程ID
// @ret: PROC_INFO 进程信息
PROC_INFO GetProcessInfo(DWORD dwPID);
//
// @brief: 获取所有进程节点
// @ret: PROC_NODE_LIST 进程节点信息
PROC_NODE_LIST GetProcessNodes();
//
// @brief: 获取指定进程的模块信息(注意: 32位进程不能获取64位进程的模块信息)
// @param: dwPID 进程ID
// @ret: MODULE_INFO_LIST 模块信息
MODULE_INFO_LIST GetModuleInfos(DWORD dwPID);
//
// @brief: 获取进程加载的模块列表(注意: 32位进程不能获取64位进程的模块信息)
// @param: dwPID 进程ID
// @ret: _tstring 模块列表
std::vector<_tstring> GetModules(DWORD dwPID);
//
// @brief: 获取指定进程的进程节点
// @ret: std::map<DWORD, PROC_INFO> 进程信息
PROC_NODE GetProcessNode(DWORD dwPID);
//
// @brief: 获取父进程的进程ID
// @param: dwPID 进程ID
// @ret: DWORD 父进程的进程ID
DWORD GetParentID(DWORD dwPID);
//
// @brief: 等待进程结束
// @param: dwPID 进程ID
// @param: dwMilliseconds 超时时间
// @ret: bool 操作是否成功
bool WaitForProcess(DWORD dwPID, DWORD dwMilliseconds = INFINITE);
//
// @brief: 杀死指定进程
// @param: strName 进程名
// @ret: bool 操作是否成功
bool KillProcess(const _tstring& strName = _T(""));
//
// @brief: 杀死指定进程
// @param: dwPID 进程ID
// @ret: bool 操作是否成功
bool KillProcess(DWORD dwPID);
//
// @brief: 杀死指定进程ID的进程节点
// @param: dwPID 进程ID
// @ret: bool 操作是否成功
bool KillProcessNode(DWORD dwPID);
//
// @brief: DOS路径转Nt路径
// @param: strPath 路径
// @ret: _tstring Win32 样式的 NT 路径
_tstring DosPathToNtPath(const _tstring& strPath);
//
// @brief: Nt路径转DOS路径
// @param: strPath 路径
// @ret: _tstring DOS路径
_tstring NtPathToDosPath(const _tstring& strPath);
//
// @brief: 获取指定进程的PE头信息
// @param: dwPID 进程ID
// @param: pPEHeader PE头信息缓冲
// @ret: bool 操作是否成功
bool GetPEHeader(DWORD dwPID, PE_HEADER_INFO* pPEHeader);
//
// @brief: 获取进程的子系统类型
// @param: dwPID 进程ID
// @param: dwMilliseconds 超时时间
// @ret: DWORD 子系统类型
// 2: IMAGE_SUBSYSTEM_WINDOWS_GUI (windows 图形用户界面 (GUI) 子系统)
// 3: IMAGE_SUBSYSTEM_WINDOWS_CUI (Windows 字符模式用户界面 (CUI) 子系统)
DWORD GetSubsystemType(DWORD dwPID);
//
// @brief: 指定进程是否为 64 位处理器上运行的 32 位应用程序
// @param: dwPID 进程ID
// @param: dwMilliseconds 超时时间
// @ret: bool 进程是否为 64 位处理器上运行的 32 位应用程序
bool IsWow64Process(DWORD dwPID);
//
// @brief: 指定进程是否 32 位应用程序
// @param: dwPID 进程ID
// @param: dwMilliseconds 超时时间
// @ret: bool 进程是否 32 位应用程序
bool IsProcessX86(DWORD dwPID);
//
// @brief: 指定进程是否 64 位应用程序
// @param: dwPID 进程ID
// @param: dwMilliseconds 超时时间
// @ret: bool 进程是否 64 位应用程序
bool IsProcessX64(DWORD dwPID);
//
// @brief: 获取进程所运行的计算机的体系结构类型
// @param: dwPID 进程ID
// @ret: DWORD 计算机的体系结构类型
// 0x014C: IMAGE_FILE_MACHINE_I386 (X86 平台)
// 0x8664: IMAGE_FILE_MACHINE_AMD64 (X64 平台)
WORD GetMachine(DWORD dwPID);
//
// @brief: 进程是否为x86平台
// @param: dwPID 进程ID
// @ret: bool 检查结果
bool IsX86(DWORD dwPID);
//
// @brief: 进程是否为 X64 平台
// @param: dwPID 进程ID
// @ret: bool 检查结果
bool IsX64(DWORD dwPID);
//
// @brief: 进程是否为 ARM32 平台
// @param: dwPID 进程ID
// @ret: bool 检查结果
bool IsARM32(DWORD dwPID);
//
// @brief: 进程是否为 ARM64 平台
// @param: dwPID 进程ID
// @ret: bool 检查结果
bool IsARM64(DWORD dwPID);
//
// @brief: 进程是否运行于 windows 图形用户界面 (GUI) 子系统
// @param: dwPID 进程ID
// @ret: bool 检查结果
bool IsWindowsGUI(DWORD dwPID);
//
// @brief: 进程是否运行于Windows 字符模式用户界面 (CUI) 子系统
// @param: dwPID 进程ID
// @ret: bool 检查结果
bool IsWindowsCUI(DWORD dwPID);
//
// @brief: 挂起进程
// @param: dwPID 进程ID
// @ret: bool 检查结果
bool SuspendProcess(DWORD dwPID);
//
// @brief: 挂起进程节点
// @param: dwPID 进程ID
// @ret: bool 检查结果
bool SuspendProcessNode(DWORD dwPID);
//
// @brief: 恢复进程
// @param: dwPID 进程ID
// @ret: bool 检查结果
bool ResumeProcess(DWORD dwPID);
//
// @brief: 恢复进程节点
// @param: dwPID 进程ID
// @ret: bool 检查结果
bool ResumeProcessNode(DWORD dwPID);
//
// @brief: 获取进程组信息
// @param: dwPID 进程ID
// @ret: std::vector<PROCESS_GROUPS_INFO> 进程组信息
std::vector<PROCESS_GROUPS_INFO> GetProcessGroupsInfo(DWORD dwPID);
//
// @brief: 获取进程中句柄计数
// @param: dwPID 进程ID
// @ret: DWORD 句柄计数
DWORD GetProcessHandleCount(DWORD dwPID);
//
// @brief: 获取进程窗口列表
// @param: dwPID 进程ID
// @ret: std::map<HWND, WND_INFO> 窗口列表
std::map<HWND, WND_INFO> GetProcessWindows(DWORD dwPid);
//
// @brief: 获取进程窗口节点列表
// @param: dwPID 进程ID
// @ret: std::map<HWND, WND_NODE> 窗口节点列表
std::map<HWND, WND_NODE> GetProcessWindowNodes(DWORD dwPid);
//
// 创建UI权限令牌
// @param: phToken 输出令牌缓冲
// @ret: DWORD 错误码
DWORD _CreateUIAccessToken(PHANDLE phToken);
//
// 创建指定进程的令牌
// @param: pid 进程ID
// @param: strExePath 可执行文件路径
// @param: strCommand 命令参数
// @param: strCurDir 程序的当前目录
// @ret: bool 是否操作成功
bool CreateProcessWithPidToken(
DWORD pid,
const _tstring& strExePath,
const _tstring& strCommand,
const _tstring& strCurDir
);
}
CProcessUtils.cpp
#include "CProcessUtils.h"
#include <tlhelp32.h>
#include <psapi.h>
#include <strsafe.h>
#include <stdint.h>
#include <WtsApi32.h>
#include <sddl.h>
#pragma comment(lib, "Wtsapi32.lib" )
#pragma comment(lib, "Advapi32.lib" )
#pragma comment(lib, "Version.lib")
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define DPSAPI_VERSION = 1
#pragma comment(lib, "Psapi.lib")
namespace CProcessUtils
{
CVersionNumber::CVersionNumber()
:m_nVer{ 0 }
{
};
CVersionNumber::CVersionNumber(const _tstring& strVer)
:
m_nVer{ 0 }
{
_stscanf_s(strVer.c_str(), _T("%hd.%hd.%hd.%hd"), &m_nVer[0], &m_nVer[1], &m_nVer[2], &m_nVer[3]);
}
CVersionNumber::CVersionNumber(WORD v1, WORD v2, WORD v3, WORD v4)
:m_nVer{ v1, v2, v3, v4 }
{
}
CVersionNumber& CVersionNumber::operator = (const _tstring& strVer)
{
_stscanf_s(strVer.c_str(), _T("%hd.%hd.%hd.%hd"), &m_nVer[0], &m_nVer[1], &m_nVer[2], &m_nVer[3]);
return *this;
}
int CVersionNumber::_Compare(const CVersionNumber& ref) const
{
for (int i = 0; i < _countof(m_nVer); i++)
{
if (m_nVer[i] != ref.m_nVer[i])
{
return (m_nVer[i] > ref.m_nVer[i] ? 1 : -1);
}
}
return 0;
}
_tstring CVersionNumber::GetString() const
{
TCHAR szBuf[MAX_PATH] = { 0 };
(void)::StringCchPrintf(szBuf, _countof(szBuf), _T("%hd.%hd.%hd.%hd"),
m_nVer[0],
m_nVer[1],
m_nVer[2],
m_nVer[3]
);
return szBuf;
}
bool CVersionNumber::IsEmpty() const
{
for (const auto& item : m_nVer)
{
if (0 != item)
{
return false;
}
}
return true;
}
void CVersionNumber::Clear()
{
for (auto& item : m_nVer)
{
item = 0;
}
}
bool CVersionNumber::operator == (const CVersionNumber& ref)
{
return _Compare(ref) == 0;
}
bool CVersionNumber::operator != (const CVersionNumber& ref)
{
return _Compare(ref) != 0;
}
bool CVersionNumber::operator < (const CVersionNumber& ref)
{
return _Compare(ref) < 0;
}
bool CVersionNumber::operator <= (const CVersionNumber& ref)
{
return _Compare(ref) <= 0;
}
bool CVersionNumber::operator > (const CVersionNumber& ref)
{
return _Compare(ref) > 0;
}
bool CVersionNumber::operator >= (const CVersionNumber& ref)
{
return _Compare(ref) >= 0;
}
//
// @brief: 杀死进程节点
// @param: procNode 进程节点
// @ret: bool 操作是否成功
bool _KillProcessNode(const PROC_NODE& procNode);
//
// @brief: 挂起进程节点
// @param: procNode 进程节点
// @ret: bool 检查结果
bool _SuspendProcessNode(const PROC_NODE& procNode);
//
// @brief: 恢复进程节点
// @param: procNode 进程节点
// @ret: bool 检查结果
bool _ResumeProcessNode(const PROC_NODE& procNode);
//
// @brief: 获取指定进程的进程节点
// @param: procInfos 进程信息
// @param: dwPID 进程ID
// @ret: PROC_LIST 进程信息
PROC_NODE _GetProcessNode(
const PROC_INFO_LIST& procInfos,
DWORD dwPID
);
//
// @brief: 复制指定进程名的令牌
// @param: strName 进程名
// @param: dwSessionId 会话ID
// @param: dwDesiredAccess 权限
// @param: phToken 输出令牌缓冲
// @ret: DWORD 操作结果错误码
DWORD _DuplicateProcessToken(
const _tstring& strName,
DWORD dwSessionId,
DWORD dwDesiredAccess,
PHANDLE phToken
);
// @brief: 创建带有UI权限的进程
// @param: strExePath 可执行文件路径
// @param: strCommand 命令参数
// @param: strCurDir 程序的当前目录
// @param: fUIAccess 是否带有UI权限
// @ret: DWORD 操作结果错误码
DWORD _CreateProcessWithUIAccess(
const _tstring& strExePath,
const _tstring& strCommand,
const _tstring& strCurDir = _T(""),
bool fUIAccess = true
);
// 多字节字符串转宽字节字符串
std::wstring _MultiStrToWStr(UINT CodePage, const std::string& str);
// 字符串转宽字节字符串
std::wstring _TStrToWStr(const _tstring& str);
// 枚举进程窗口
void _EnumProcessWindows(std::map<HWND, WND_INFO>& infos, HWND hWnd, DWORD dwPid);
// 获取子窗口节点
WND_NODE _GetWindowNode(HWND hWnd, std::vector<MODULE_INFO>& modules);
std::wstring _MultiStrToWStr(
UINT CodePage,
const std::string& str
)
{
//计算缓冲区所需的字符长度
int cchWideChar = ::MultiByteToWideChar(CodePage, 0, str.c_str(), -1, NULL, NULL);
std::wstring strResult(cchWideChar, 0);
//成功则返回写入到指示的缓冲区的字符数
size_t nConverted = ::MultiByteToWideChar(CodePage, 0, str.c_str(), (int)str.size(), &strResult[0], (int)strResult.size());
//调整内容长度
strResult.resize(nConverted);
return strResult;
}
std::wstring _TStrToWStr(
const _tstring& str
)
{
#ifdef _UNICODE
return str;
#else
return _MultiStrToWStr(CP_ACP, str);
#endif
}
bool EnablePrivileges(
HANDLE hProcess,
LPCTSTR lpPrivilegesName
)
{
HANDLE hToken = NULL;
LUID luidValue = { 0 };
TOKEN_PRIVILEGES tokenPrivileges = { 0 };
BOOL isSuccess = FALSE;
do
{
if (!::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken))
{
break;
}
if (!::LookupPrivilegeValue(NULL, lpPrivilegesName, &luidValue))
{
break;
}
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Privileges[0].Luid = luidValue;
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!::AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, 0, NULL, NULL))
{
break;
}
isSuccess = true;
} while (false);
if (hToken)
{
::CloseHandle(hToken);
}
return isSuccess;
}
// 操作系统 版本号
// Windows 11 10.0*
// Windows 10 10.0*
// Windows Server 2022 10.0*
// Windows Server 2019 10.0*
// Windows Server 2016 10.0*
// Windows 8.1 6.3*
// Windows Server 2012 R2 6.3*
// Windows 8 6.2
// Windows Server 2012 6.2
// Windows 7 6.1
// Windows Server 2008 R2 6.1
// Windows Server 2008 6.0
// Windows Vista 6.0
// Windows Server 2003 R2 5.2
// Windows Server 2003 5.2
// Windows XP 64 位版本 5.2
// Windows XP 5.1
// Windows 2000 5.0
static bool _GetNtVersionNumbers(DWORD* pMajor, DWORD* pMinor, DWORD* pBuild)
{
typedef VOID(NTAPI* NTPROC)(DWORD* dwMajor, DWORD* dwMinor, DWORD* dwBuild);
HMODULE hModule = NULL;
static NTPROC ProcAddress = NULL;
bool fResult = false;
if (NULL == ProcAddress)
{
hModule = ::LoadLibrary(_T("ntdll.dll"));
if (NULL != hModule)
{
ProcAddress = (NTPROC)::GetProcAddress(hModule, "RtlGetNtVersionNumbers");
}
}
if (NULL != ProcAddress)
{
fResult = true;
ProcAddress(pMajor, pMinor, pBuild);
*pBuild &= 0xffff;
}
if (NULL != hModule)
{
::FreeLibrary(hModule);
}
return fResult;
}
static bool IsWindowsXPOrServer2003()
{
DWORD dwMajor = 0;
DWORD dwMinor = 0;
DWORD dwBuild = 0;
if (!_GetNtVersionNumbers(&dwMajor, &dwMinor, &dwBuild))
{
return false;
}
if (dwMajor == 5 && dwMinor >= 1)
{
return true;
}
return false;
}
static DWORD GetQueryAccess()
{
static DWORD dwDesiredAccess = PROCESS_QUERY_LIMITED_INFORMATION;
if (0 != dwDesiredAccess)
{
return dwDesiredAccess;
}
if (IsWindowsXPOrServer2003())
{
dwDesiredAccess = PROCESS_QUERY_INFORMATION;
}
return dwDesiredAccess;
}
bool CreateProcessNormal(
const _tstring& strExePath/* = _T("")*/,
const _tstring& strCommand/* = _T("")*/,
const _tstring& strCurDir/* = _T("")*/,
bool bShow,
bool bWait
)
{
SECURITY_ATTRIBUTES sa = { 0 };
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(sa);
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = bShow ? SW_SHOW : SW_HIDE;
si.hStdInput = NULL;
si.hStdOutput = NULL;
si.hStdError = NULL;
_tstring exePath = strExePath;
_tstring exeCommand = strCommand;
_tstring exeCurDir = strCurDir;
LPCTSTR lpApplicationName = NULL;
LPTSTR lpCommandLine = NULL;
LPCTSTR lpCurrentDir = NULL;
if (!exePath.empty())
{
lpApplicationName = exePath.c_str();
}
if (!exeCommand.empty())
{
lpCommandLine = (LPTSTR)exeCommand.c_str();
}
if (!exeCurDir.empty())
{
lpCurrentDir = exeCurDir.c_str();
}
if (!::CreateProcess(lpApplicationName, lpCommandLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, lpCurrentDir, &si, &pi))
{
return false;
}
if (bWait)
{
::WaitForSingleObject(pi.hProcess, INFINITE);
}
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
return true;
}
_tstring GetPath(DWORD dwPID, bool bNtPath)
{
_tstring strPath;
HANDLE hProcess = NULL;
TCHAR szBuffer[MAX_PATH] = { 0 };
DWORD dwSize = _countof(szBuffer);
do
{
hProcess = ::OpenProcess(GetQueryAccess(), FALSE, dwPID);
if (NULL == hProcess)
{
break;
}
// 句柄必须具有 PROCESS_QUERY_INFORMATION 或 PROCESS_QUERY_LIMITED_INFORMATION 访问权限。
// Windows Server 2003 和 Windows XP: 句柄必须具有 PROCESS_QUERY_INFORMATION 访问权限。
if (0 == ::GetProcessImageFileName(hProcess, szBuffer, dwSize))
{
break;
}
if (bNtPath)
{
strPath = DosPathToNtPath(szBuffer);
}
else
{
strPath = szBuffer;
}
} while (false);
if (NULL != hProcess)
{
::CloseHandle(hProcess);
}
return strPath;
}
_tstring GetPathEx(DWORD dwPID, bool bNtPath)
{
_tstring strPath;
HANDLE hProcess = NULL;
TCHAR szBuffer[MAX_PATH] = { 0 };
DWORD dwSize = _countof(szBuffer);
do
{
hProcess = ::OpenProcess(GetQueryAccess(), FALSE, dwPID);
if (NULL == hProcess)
{
break;
}
// 最低受支持的客户端: Windows Vista [仅限桌面应用]
// 最低受支持的服务器: Windows Server 2008 [仅限桌面应用]
// 进程句柄权限: PROCESS_QUERY_INFORMATION或PROCESS_QUERY_LIMITED_INFORMATION
if (!::QueryFullProcessImageName(hProcess, bNtPath ? 0 : PROCESS_NAME_NATIVE, szBuffer, &dwSize))
{
break;
}
strPath = szBuffer;
} while (false);
if (NULL != hProcess)
{
::CloseHandle(hProcess);
}
return strPath;
}
_tstring GetParentPath(DWORD dwPID, bool bNtPath)
{
_tstring strPath;
HANDLE hProcessSnap = NULL;
PROCESSENTRY32 pe32 = { 0 };
pe32.dwSize = sizeof(pe32);
do
{
hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcessSnap)
{
break;
}
if (!::Process32First(hProcessSnap, &pe32))
{
break;
}
do
{
if (pe32.th32ProcessID == dwPID)
{
strPath = GetPath(pe32.th32ParentProcessID, bNtPath);
break;
}
} while (::Process32Next(hProcessSnap, &pe32));
} while (false);
if (INVALID_HANDLE_VALUE != hProcessSnap)
{
::CloseHandle(hProcessSnap);
}
return strPath;
}
DWORD GetParentID(DWORD dwPID)
{
HANDLE hProcessSnap = NULL;
PROCESSENTRY32 pe32 = { 0 };
pe32.dwSize = sizeof(pe32);
DWORD dwParentProcessId = 0;
do
{
hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcessSnap)
{
break;
}
if (!::Process32First(hProcessSnap, &pe32))
{
break;
}
do
{
if (pe32.th32ProcessID == dwPID)
{
dwParentProcessId = pe32.th32ParentProcessID;
break;
}
} while (::Process32Next(hProcessSnap, &pe32));
} while (false);
if (INVALID_HANDLE_VALUE != hProcessSnap)
{
::CloseHandle(hProcessSnap);
}
return dwParentProcessId;
}
std::vector<_tstring> GetModules(DWORD dwPID)
{
std::vector<_tstring> modulesList;
TCHAR szModName[MAX_PATH] = { 0 };
HMODULE* phMods = NULL;
HANDLE hProcess = NULL;
DWORD cbNeeded = 0;
DWORD dwModSize = 0;
do
{
hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPID);
if (NULL == hProcess)
{
break;
}
if (!::EnumProcessModulesEx(hProcess, NULL, NULL, &cbNeeded, LIST_MODULES_ALL))
{
break;
}
dwModSize = cbNeeded;
phMods = (HMODULE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dwModSize);
if (NULL == phMods)
{
break;
}
if (!::EnumProcessModulesEx(hProcess, phMods, dwModSize, &cbNeeded, LIST_MODULES_ALL))
{
break;
}
size_t nModuleCnt = (cbNeeded / sizeof(HMODULE));
for (size_t i = 0; i < nModuleCnt; i++)
{
if (::GetModuleFileNameEx(hProcess, phMods[i], szModName, _countof(szModName)))
{
modulesList.push_back(szModName);
}
}
} while (false);
if (NULL != hProcess)
{
::CloseHandle(hProcess);
}
if (phMods)
{
::HeapFree(::GetProcessHeap(), 0, phMods);
}
return modulesList;
}
bool GetPEHeader(DWORD dwPID, PE_HEADER_INFO* pPEHeader)
{
HMODULE hModule = NULL;
LPVOID OldValue = NULL;
BOOL isDisableWow64Fs = ::Wow64DisableWow64FsRedirection(&OldValue);
bool fSuccess = false;
if (nullptr == pPEHeader)
{
return false;
}
do
{
DWORD dwFlags = LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE;
hModule = ::LoadLibraryEx(
GetPath(dwPID).c_str(),
0,
dwFlags
);
if (NULL == hModule)
{
break;
}
LPBYTE pHeader = (BYTE*)hModule;
BYTE* pImageData = (BYTE*)((ULONG_PTR)pHeader & ~((ULONG_PTR)0x03));
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageData;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
break;
}
PIMAGE_NT_HEADERS pNtHeader = (IMAGE_NT_HEADERS*)((BYTE*)(pDosHeader)+(DWORD)(pDosHeader->e_lfanew));
if (IMAGE_NT_SIGNATURE != pNtHeader->Signature)
{
break;
}
// 检查 是否为 32位程序可选头
if (IMAGE_NT_OPTIONAL_HDR32_MAGIC == pNtHeader->OptionalHeader.Magic)
{
pPEHeader->m_NtHeadersMagic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
pPEHeader->m_NtHeaders32 = *(PIMAGE_NT_HEADERS32)pNtHeader;
}
// 检查 是否为 64位程序可选头
else if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == pNtHeader->OptionalHeader.Magic)
{
pPEHeader->m_NtHeadersMagic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
pPEHeader->m_NtHeaders64 = *(PIMAGE_NT_HEADERS64)pNtHeader;
}
else
{
break;
}
pPEHeader->m_DosHeader = *(PIMAGE_DOS_HEADER)pImageData;
fSuccess = true;
} while (false);
if (isDisableWow64Fs)
{
::Wow64RevertWow64FsRedirection(OldValue);
}
if (NULL != hModule)
{
::FreeLibrary(hModule);
}
return fSuccess;
}
bool WaitForProcess(
DWORD dwPID,
DWORD dwMilliseconds/* = INFINITE*/
)
{
HANDLE hProcess = NULL;
bool fResult = false;
hProcess = ::OpenProcess(SYNCHRONIZE, FALSE, dwPID);
if (NULL == hProcess)
{
return false;
}
fResult = (WAIT_OBJECT_0 == ::WaitForSingleObject(hProcess, dwMilliseconds));
::CloseHandle(hProcess);
return fResult;
}
PROC_NAME_LIST GetProcessNames()
{
PROC_NAME_LIST mapResult;
PWTS_PROCESS_INFO pPi = NULL;
DWORD dwCount = 0;
do
{
if (!::WTSEnumerateProcesses(NULL, 0, 1, &pPi, &dwCount))
{
break;
}
for (DWORD i = 0; i < dwCount; i++)
{
PSID pUserSid = pPi[i].pUserSid;
TCHAR szName[MAX_PATH] = { 0 };
DWORD cchName = _countof(szName);
TCHAR szDomainName[MAX_PATH] = { 0 };
DWORD cchDomainName = _countof(szDomainName);
SID_NAME_USE sidNameUse = SidTypeUser;
if (::LookupAccountSid(NULL, pUserSid, szName, &cchName, szDomainName, &cchDomainName, &sidNameUse))
{
}
PROCESS_NAME_INFO info;
info.SessionId = pPi[i].SessionId;
info.ProcessName = pPi[i].pProcessName;
info.ProcessId = pPi[i].ProcessId;
info.UserName = szName;
info.DomainName = szDomainName;
mapResult.insert(std::make_pair(pPi[i].ProcessId, info));
}
} while (false);
if (pPi)
{
::WTSFreeMemory(pPi);
}
return mapResult;
}
PROC_INFO_LIST GetProcessInfos(const _tstring& strName/* = _T("")*/, DWORD dwPID/* = 0*/)
{
PROC_INFO_LIST infos;
HANDLE hProcessSnap = NULL;
PROCESSENTRY32 pe32 = { 0 };
pe32.dwSize = sizeof(pe32);
DWORD dwQueryAccess = GetQueryAccess();
do
{
hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcessSnap)
{
break;
}
if (!::Process32First(hProcessSnap, &pe32))
{
break;
}
do
{
PROC_INFO info;
info.dwParentPID = pe32.th32ParentProcessID;
info.dwPID = pe32.th32ProcessID;
info.strExeFile = pe32.szExeFile;
info.cntThreads = pe32.cntThreads;
info.nPriClassBase = pe32.pcPriClassBase;
HANDLE hProcess = NULL;
DWORD dwHandleCount = 0;
DWORD dwGdiCount = 0;
DWORD dwUserCount = 0;
// 获取句柄数量, GUI对象数量, 用户对象数量
do
{
// 打开进程
hProcess = ::OpenProcess(dwQueryAccess, FALSE, info.dwPID);
if (NULL == hProcess)
{
break;
}
::GetProcessHandleCount(hProcess, &dwHandleCount);
dwGdiCount = GetGuiResources(hProcess, GR_GDIOBJECTS);
dwUserCount = GetGuiResources(hProcess, GR_USEROBJECTS);
BOOL Wow64Process = FALSE;
if (::IsWow64Process(hProcess, &Wow64Process))
{
info.fWow64 = Wow64Process;
}
} while (false);
if (NULL != hProcess)
{
::CloseHandle(hProcess);
}
// 进程 ID 筛选
if (0 == dwPID || dwPID == info.dwPID)
{
if (strName.empty() || 0 == _tcsicmp(strName.c_str(), pe32.szExeFile))
{
info.dwHandleCount = dwHandleCount;
info.dwGdiCount = dwGdiCount;
info.dwUserCount = dwUserCount;
info.strFilePath = GetPath(info.dwPID);
info.fileVersion = GetFileVersionList(info.strFilePath);
infos.insert(std::make_pair(info.dwPID, info));
}
}
} while (::Process32Next(hProcessSnap, &pe32));
} while (false);
if (INVALID_HANDLE_VALUE != hProcessSnap)
{
::CloseHandle(hProcessSnap);
}
// 获取进程用户名信息
PROC_NAME_LIST mapResult = GetProcessNames();
for (auto& item : infos)
{
auto itFind = mapResult.find(item.first);
if (mapResult.end() != itFind)
{
item.second.strDomainName = itFind->second.DomainName;
item.second.strUserName = itFind->second.UserName;
item.second.dwSessionId = itFind->second.SessionId;
}
}
return infos;
}
PROC_INFO GetProcessInfo(DWORD dwPID)
{
PROC_INFO info;
PROC_INFO_LIST infos = GetProcessInfos(_T(""), dwPID);
auto itFind = infos.find(dwPID);
if (itFind != infos.end())
{
info = itFind->second;
}
return info;
}
PROC_NODE_LIST GetProcessNodes()
{
PROC_NODE_LIST mapResult;
PROC_INFO_LIST infos = GetProcessInfos();
for (const auto& item : infos)
{
if (mapResult.end() != mapResult.find(item.first))
{
continue;
}
if (0 == item.second.dwParentPID ||
infos.end() == infos.find(item.second.dwParentPID)
)
{
PROC_NODE node = _GetProcessNode(infos, item.first);
mapResult.insert(std::make_pair(item.first, node));
}
}
return mapResult;
}
MODULE_INFO_LIST GetModuleInfos(DWORD dwPID)
{
MODULE_INFO_LIST vModules;
HANDLE hModuleSnap = NULL;
MODULEENTRY32 me32 = { 0 };
me32.dwSize = sizeof(me32);
do
{
hModuleSnap = ::CreateToolhelp32Snapshot(
TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
dwPID
);
if (INVALID_HANDLE_VALUE == hModuleSnap)
{
break;
}
if (!::Module32First(hModuleSnap, &me32))
{
break;
}
do
{
MODULE_INFO info;
info.th32ProcessID = me32.th32ProcessID;
info.GlblcntUsage = me32.GlblcntUsage;
info.modBaseAddr = me32.modBaseAddr;
info.modBaseSize = me32.modBaseSize;
info.hModule = me32.hModule;
info.strExePath = me32.szExePath;
info.strModule = me32.szModule;
vModules.push_back(info);
} while (::Module32Next(hModuleSnap, &me32));
} while (false);
if (INVALID_HANDLE_VALUE != hModuleSnap)
{
::CloseHandle(hModuleSnap);
}
return vModules;
}
PROC_NODE GetProcessNode(DWORD dwPID)
{
PROC_INFO_LIST procInfos = GetProcessInfos();
return _GetProcessNode(procInfos, dwPID);
}
PROC_NODE _GetProcessNode(
const PROC_INFO_LIST& procInfos,
DWORD dwPID
)
{
PROC_NODE procNode;
for (auto& item : procInfos)
{
const PROC_INFO& info = item.second;
if (item.first == dwPID)
{
procNode.ProcInfo = info;
}
else if (info.dwParentPID == dwPID)
{
PROC_NODE subNode = _GetProcessNode(procInfos, info.dwPID);
procNode.NodeList.push_back(subNode);
}
}
return procNode;
}
bool KillProcess(const _tstring& strName/* = _T("")*/)
{
bool fResult = true;
PROC_INFO_LIST infos = GetProcessInfos(strName, 0);
for (const auto& item : infos)
{
if (!KillProcess(item.first))
{
fResult = false;
}
}
return fResult;
}
bool KillProcess(DWORD dwPID)
{
HANDLE hProcess = NULL;
BOOL fSuccess = false;
// 杀死进程
hProcess = ::OpenProcess(PROCESS_TERMINATE, FALSE, dwPID);
if (NULL == hProcess)
{
return false;
}
fSuccess = ::TerminateProcess(hProcess, 0);
::CloseHandle(hProcess);
return fSuccess;
}
bool _KillProcessNode(const PROC_NODE& procNode)
{
HANDLE hProcess = NULL;
BOOL fSuccess = false;
// 杀死子进程
for (auto item : procNode.NodeList)
{
_KillProcessNode(item);
}
// 杀死进程
hProcess = ::OpenProcess(PROCESS_TERMINATE, FALSE, procNode.ProcInfo.dwPID);
if (NULL == hProcess)
{
return false;
}
fSuccess = ::TerminateProcess(hProcess, 0);
::CloseHandle(hProcess);
return fSuccess;
}
bool KillProcessNode(DWORD dwPID)
{
return _KillProcessNode(GetProcessNode(dwPID));
}
_tstring DosPathToNtPath(const _tstring& strPath)
{
_tstring strResultPath;
TCHAR szDriveStrings[MAX_PATH] = { 0 };
TCHAR szDosBuf[MAX_PATH] = { 0 };
TCHAR szResultBuf[MAX_PATH] = { 0 };
LPTSTR pDriveStr = NULL;
// 获取盘符名到缓冲
if (::GetLogicalDriveStrings(_countof(szDriveStrings), szDriveStrings))
{
// 遍历盘符名
for (int i = 0; i < _countof(szDriveStrings); i += 4)
{
pDriveStr = &szDriveStrings[i];
pDriveStr[2] = _T('\0');
// 查询盘符对应的DOS设备名称
if (!::QueryDosDevice(pDriveStr, szDosBuf, _countof(szDosBuf)))
{
break;
}
// 对比路径前缀
size_t nLen = _tcslen(szDosBuf);
if (0 == _tcsnicmp(strPath.c_str(), szDosBuf, nLen))
{
lstrcpy(szResultBuf, pDriveStr);
lstrcat(szResultBuf, strPath.c_str() + nLen);
strResultPath = szResultBuf;
break;
}
}
}
return strResultPath;
}
_tstring NtPathToDosPath(const _tstring& strPath)
{
_tstring strResultPath;
TCHAR szDriveStrings[MAX_PATH] = { 0 };
TCHAR szDosBuf[MAX_PATH] = { 0 };
TCHAR szResultBuf[MAX_PATH] = { 0 };
LPTSTR pDriveStr = NULL;
// 获取盘符名到缓冲
if (::GetLogicalDriveStrings(_countof(szDriveStrings), szDriveStrings))
{
// 遍历盘符名
for (int i = 0; i < _countof(szDriveStrings); i += 4)
{
pDriveStr = &szDriveStrings[i];
pDriveStr[2] = _T('\0');
// 查询盘符对应的DOS设备名称
if (!::QueryDosDevice(pDriveStr, szDosBuf, _countof(szDosBuf)))
{
break;
}
// 对比路径前缀
size_t nLen = _tcslen(pDriveStr);
if (0 == _tcsnicmp(strPath.c_str(), pDriveStr, nLen))
{
lstrcpy(szResultBuf, szDosBuf);
lstrcat(szResultBuf, strPath.c_str() + nLen);
strResultPath = szResultBuf;
break;
}
}
}
return strResultPath;
}
DWORD GetSubsystemType(DWORD dwPID)
{
PE_HEADER_INFO peHeader = { 0 };
if (!GetPEHeader(dwPID, &peHeader))
{
return 0;
}
if (IMAGE_NT_OPTIONAL_HDR32_MAGIC == peHeader.m_NtHeadersMagic)
{
return peHeader.m_NtHeaders32.OptionalHeader.Subsystem;
}
if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == peHeader.m_NtHeadersMagic)
{
return peHeader.m_NtHeaders64.OptionalHeader.Subsystem;
}
return 0;
}
bool IsWow64Process(DWORD dwPID)
{
HANDLE hProcess = NULL;
bool fWow64 = false;
do
{
hProcess = ::OpenProcess(GetQueryAccess(), FALSE, dwPID);
if (NULL == hProcess)
{
break;
}
BOOL Wow64Process = FALSE;
if (!::IsWow64Process(hProcess, &Wow64Process))
{
break;
}
fWow64 = Wow64Process;
} while (false);
if (NULL != hProcess)
{
::CloseHandle(hProcess);
}
return fWow64;
}
bool IsProcessX86(DWORD dwPID)
{
return true == IsWow64Process(dwPID);
}
bool IsProcessX64(DWORD dwPID)
{
return false == IsWow64Process(dwPID);
}
WORD GetMachine(DWORD dwPID)
{
PE_HEADER_INFO peHeader = { 0 };
if (!GetPEHeader(dwPID, &peHeader))
{
return 0;
}
if (IMAGE_NT_OPTIONAL_HDR32_MAGIC == peHeader.m_NtHeadersMagic)
{
return peHeader.m_NtHeaders32.FileHeader.Machine;
}
if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == peHeader.m_NtHeadersMagic)
{
return peHeader.m_NtHeaders64.FileHeader.Machine;
}
return 0;
}
bool IsX86(DWORD dwPID)
{
return IMAGE_FILE_MACHINE_I386 == GetMachine(dwPID);
}
bool IsX64(DWORD dwPID)
{
return IMAGE_FILE_MACHINE_AMD64 == GetMachine(dwPID);
}
bool IsARM32(DWORD dwPID)
{
WORD wMachine = GetMachine(dwPID);
return wMachine >= IMAGE_FILE_MACHINE_ARM && wMachine <= IMAGE_FILE_MACHINE_ARMNT;
}
bool IsARM64(DWORD dwPID)
{
return IMAGE_FILE_MACHINE_ARM64 == GetMachine(dwPID);
}
bool IsWindowsGUI(DWORD dwPID)
{
return IMAGE_SUBSYSTEM_WINDOWS_GUI == GetSubsystemType(dwPID);
}
bool IsWindowsCUI(DWORD dwPID)
{
return IMAGE_SUBSYSTEM_WINDOWS_CUI == GetSubsystemType(dwPID);
}
bool SuspendProcess(DWORD dwPID)
{
typedef NTSTATUS(*_NtSuspendProcess)(HANDLE hProcess);
_NtSuspendProcess NtSuspendProcess = NULL;
HANDLE hProcess = NULL;
HMODULE hModule = NULL;
bool fResult = false;
do
{
hModule = ::LoadLibrary(_T("ntdll.dll"));
if (NULL == hModule)
{
break;
}
hProcess = ::OpenProcess(PROCESS_SUSPEND_RESUME, FALSE, dwPID);
if (NULL == hProcess)
{
break;
}
NtSuspendProcess = (_NtSuspendProcess)::GetProcAddress(hModule, "NtSuspendProcess");
if (NULL == NtSuspendProcess)
{
break;
}
fResult = (STATUS_SUCCESS == NtSuspendProcess(hProcess));
} while (false);
if (hProcess)
{
::CloseHandle(hProcess);
}
if (hModule)
{
::FreeLibrary(hModule);
}
return fResult;
}
bool ResumeProcess(DWORD dwPID)
{
typedef NTSTATUS(*_NtResumeProcess)(HANDLE hProcess);
_NtResumeProcess NtResumeProcess = NULL;
HANDLE hProcess = NULL;
HMODULE hModule = NULL;
bool fResult = false;
do
{
hModule = ::LoadLibrary(_T("ntdll.dll"));
if (NULL == hModule)
{
break;
}
hProcess = ::OpenProcess(PROCESS_SUSPEND_RESUME, FALSE, dwPID);
if (NULL == hProcess)
{
break;
}
NtResumeProcess = (_NtResumeProcess)::GetProcAddress(hModule, "NtResumeProcess");
if (NULL == NtResumeProcess)
{
break;
}
fResult = (STATUS_SUCCESS == NtResumeProcess(hProcess));
} while (false);
if (hProcess)
{
::CloseHandle(hProcess);
}
if (hModule)
{
::FreeLibrary(hModule);
}
return fResult;
}
bool SuspendProcessNode(DWORD dwPID)
{
return _SuspendProcessNode(GetProcessNode(dwPID));
}
bool ResumeProcessNode(DWORD dwPID)
{
return _ResumeProcessNode(GetProcessNode(dwPID));
}
bool _SuspendProcessNode(const PROC_NODE& procNode)
{
bool fResult = false;
do
{
// 暂停主进程
if (!SuspendProcess(procNode.ProcInfo.dwPID))
{
break;
}
// 暂停子进程
for (const auto& item : procNode.NodeList)
{
if (!_SuspendProcessNode(item))
{
break;
}
}
fResult = true;
} while (false);
return fResult;
}
bool _ResumeProcessNode(const PROC_NODE& procNode)
{
bool fResult = false;
do
{
// 恢复主进程
if (!ResumeProcess(procNode.ProcInfo.dwPID))
{
break;
}
// 恢复子进程
for (const auto& item : procNode.NodeList)
{
if (!_ResumeProcessNode(item))
{
break;
}
}
fResult = true;
} while (false);
return fResult;
}
DWORD GetProcessHandleCount(DWORD dwPID)
{
HANDLE hProcess = NULL;
DWORD dwHandleCount = 0;
DWORD dwGdiCount = 0;
DWORD dwUserCount = 0;
do
{
// 打开进程
hProcess = ::OpenProcess(GetQueryAccess(), FALSE, dwPID);
if (NULL == hProcess)
{
break;
}
::GetProcessHandleCount(hProcess, &dwHandleCount);
dwGdiCount = GetGuiResources(hProcess, GR_GDIOBJECTS);
dwUserCount = GetGuiResources(hProcess, GR_USEROBJECTS);
} while (false);
if (NULL != hProcess)
{
::CloseHandle(hProcess);
}
return dwHandleCount;
}
std::vector<PROCESS_GROUPS_INFO> GetProcessGroupsInfo(DWORD dwPID)
{
std::vector<PROCESS_GROUPS_INFO> vResult;
HANDLE hToken = NULL;
PTOKEN_GROUPS pGroupInfo = NULL;
SID_NAME_USE SidType = SidTypeUser;
TCHAR szName[MAX_PATH] = { 0 };
TCHAR szDomain[MAX_PATH] = { 0 };
PSID pSID = NULL;
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
HANDLE hProcess = NULL;
DWORD dwSize = 0;
do
{
// 打开进程
hProcess = ::OpenProcess(GetQueryAccess(), FALSE, dwPID);
if (NULL == hProcess)
{
break;
}
// 打开进程令牌
if (!::OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
{
break;
}
// 获取令牌信息所需缓冲大小
if (!::GetTokenInformation(hToken, TokenGroups, NULL, dwSize, &dwSize))
{
if (ERROR_INSUFFICIENT_BUFFER != ::GetLastError())
{
break;
}
}
// 分配缓冲
pGroupInfo = (PTOKEN_GROUPS)::GlobalAlloc(GPTR, dwSize);
if (NULL == pGroupInfo)
{
break;
}
// 获取令牌组信息
if (!::GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSize, &dwSize))
{
break;
}
// 分配和初始化一个安全标识符
if (!::AllocateAndInitializeSid(&SIDAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pSID))
{
break;
}
// 检索SID信息
for (DWORD i = 0; i < pGroupInfo->GroupCount; i++)
{
PROCESS_GROUPS_INFO info;
dwSize = _countof(szName);
if (!::LookupAccountSid(NULL, pGroupInfo->Groups[i].Sid, szName, &dwSize, szDomain, &dwSize, &SidType))
{
if (ERROR_NONE_MAPPED != ::GetLastError())
{
break;
}
_tcscpy_s(szName, dwSize, _T("NONE_MAPPED"));
}
LPTSTR pStringSid = NULL;
if (ConvertSidToStringSid(pGroupInfo->Groups[i].Sid, &pStringSid))
{
info.SID = pStringSid;
::LocalFree(pStringSid);
}
info.DomainName = szDomain;
info.UserName = szName;
info.Attributes = pGroupInfo->Groups[i].Attributes;
vResult.push_back(info);
}
} while (false);
if (pSID)
{
::FreeSid(pSID);
}
if (pGroupInfo)
{
::GlobalFree(pGroupInfo);
}
if (NULL != hProcess)
{
::CloseHandle(hProcess);
}
return vResult;
}
DWORD _DuplicateProcessToken(
const _tstring& strName,
DWORD dwSessionId,
DWORD dwDesiredAccess,
PHANDLE phToken
)
{
PROCESSENTRY32 pe = { 0 };
PRIVILEGE_SET ps = { 0 };
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
BOOL fResult = FALSE;
DWORD dwErr = ERROR_SUCCESS;
BOOL fFound = FALSE;
ps.PrivilegeCount = 1;
ps.Control = PRIVILEGE_SET_ALL_NECESSARY;
do
{
if (!::LookupPrivilegeValue(NULL, SE_TCB_NAME, &ps.Privilege[0].Luid))
{
break;
}
hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot)
{
break;
}
pe.dwSize = sizeof(pe);
if (!::Process32First(hSnapshot, &pe))
{
break;
}
do
{
HANDLE hProcess = NULL;
HANDLE hToken = NULL;
DWORD dwRetLen = 0;
DWORD sid = 0;
if (0 != _tcsicmp(pe.szExeFile, strName.c_str()))
{
continue;
}
hProcess = ::OpenProcess(GetQueryAccess(), FALSE, pe.th32ProcessID);
if (!hProcess)
{
break;
}
do
{
BOOL fTcb = FALSE;
if (!::OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_DUPLICATE, &hToken))
{
break;
}
if (!::PrivilegeCheck(hToken, &ps, &fTcb) && fTcb)
{
break;
}
if (!::GetTokenInformation(hToken, TokenSessionId, &sid, sizeof(sid), &dwRetLen) && sid == dwSessionId)
{
break;
}
if (!::DuplicateTokenEx(hToken, dwDesiredAccess, NULL, SecurityImpersonation, TokenImpersonation, phToken))
{
break;
}
fFound = true;
dwErr = ERROR_SUCCESS;
} while (false);
if (hToken)
{
::CloseHandle(hToken);
}
if (hProcess)
{
::CloseHandle(hProcess);
}
if (fFound)
{
break;
}
} while (::Process32Next(hSnapshot, &pe));
if (!fFound)
{
dwErr = ERROR_NOT_FOUND;
break;
}
fResult = true;
} while (false);
if (!fResult)
{
dwErr = ::GetLastError();
if (!fFound)
{
dwErr = ERROR_NOT_FOUND;
}
}
if (INVALID_HANDLE_VALUE != hSnapshot)
{
::CloseHandle(hSnapshot);
}
return dwErr;
}
DWORD _CreateProcessWithUIAccess(
const _tstring& strExePath,
const _tstring& strCommand,
const _tstring& strCurDir/* = _T("")*/,
bool fUIAccess/* = true*/
)
{
HANDLE hTokenUIAccess = NULL;
DWORD dwErr = ERROR_SUCCESS;
BOOL fResult = FALSE;
_tstring exePath = strExePath;
_tstring exeCommand = strCommand;
_tstring exeCurDir = strCurDir;
LPCTSTR lpApplicationName = NULL;
LPTSTR lpCommandLine = NULL;
LPCTSTR lpCurrentDir = NULL;
if (!strExePath.empty())
{
lpApplicationName = exePath.c_str();
}
if (!strCommand.empty())
{
lpCommandLine = (LPTSTR)exeCommand.c_str();
}
if (!exeCurDir.empty())
{
lpCurrentDir = exeCurDir.c_str();
}
do
{
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
dwErr = _CreateUIAccessToken(&hTokenUIAccess);
if (ERROR_SUCCESS != dwErr)
{
break;
}
if (!fUIAccess)
{
BOOL fTokenInformation = FALSE;
::SetTokenInformation(hTokenUIAccess, TokenUIAccess, &fTokenInformation, sizeof(fTokenInformation));
}
::GetStartupInfo(&si);
if (!::CreateProcessAsUser(hTokenUIAccess, lpApplicationName, lpCommandLine, NULL, NULL, FALSE, 0, NULL, lpCurrentDir, &si, &pi))
{
break;
}
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
} while (false);
if (!fResult)
{
dwErr = ::GetLastError();
}
if (hTokenUIAccess)
{
::CloseHandle(hTokenUIAccess);
}
return dwErr;
}
bool CreateProcessWithPidToken(
DWORD pid,
const _tstring& strExePath,
const _tstring& strCommand,
const _tstring& strCurDir
)
{
STARTUPINFOW si = { 0 };
PROCESS_INFORMATION pi = { 0 };
HANDLE hProcess = NULL;
HANDLE hProcessToken = NULL;
HANDLE hDuplicateToken = NULL;
bool fResult = false;
si.cb = sizeof(STARTUPINFO);
std::wstring exePath = _TStrToWStr(strExePath);
std::wstring exeCommand = _TStrToWStr(strCommand);
std::wstring exeCurDir = _TStrToWStr(strCurDir);
LPCWSTR lpApplicationName = NULL;
LPWSTR lpCommandLine = NULL;
LPCWSTR lpCurrentDir = NULL;
if (!exePath.empty())
{
lpApplicationName = exePath.c_str();
}
if (!exeCommand.empty())
{
lpCommandLine = (LPWSTR)exeCommand.c_str();
}
if (!exeCurDir.empty())
{
lpCurrentDir = exeCurDir.c_str();
}
do
{
// 打开进程句柄
hProcess = ::OpenProcess(GetQueryAccess(), TRUE, pid);
if (NULL == hProcess)
{
break;
}
// 打开进程令牌
DWORD dwOpenDesiredAccess = TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY;
if (!::OpenProcessToken(hProcess, dwOpenDesiredAccess, &hProcessToken))
{
break;
}
// 模拟登录用户
if (!::ImpersonateLoggedOnUser(hProcessToken))
{
break;
}
// 终止客户端应用程序的模拟
::RevertToSelf();
// 创建一个复制现有令牌的新访问令牌
DWORD dwDuplicateDesiredAccess = TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY;
if (!::DuplicateTokenEx(hProcessToken, dwDuplicateDesiredAccess, NULL, SecurityImpersonation, TokenPrimary, &hDuplicateToken))
{
break;
}
// 使用令牌创建进程
// 调用 CreateProcessWithTokenW 的进程必须具有SE_IMPERSONATE_NAME特权。
if (!::CreateProcessWithTokenW(hDuplicateToken, LOGON_WITH_PROFILE, lpApplicationName, lpCommandLine, 0, NULL, lpCurrentDir, &si, &pi))
{
break;
}
fResult = true;
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
} while (false);
if (hDuplicateToken)
{
::CloseHandle(hDuplicateToken);
}
if (hProcessToken)
{
::CloseHandle(hProcessToken);
}
if (hProcess)
{
::CloseHandle(hProcess);
}
return fResult;
}
DWORD _CreateUIAccessToken(
PHANDLE phToken
)
{
DWORD dwErr = ERROR_SUCCESS;
HANDLE hTokenSelf = NULL;
HANDLE hWinlogonToken = NULL;
BOOL fResult = FALSE;
do
{
DWORD dwDesiredAccess = TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_DEFAULT;
DWORD dwSessionId = 0;
DWORD dwRetLen = 0;
BOOL bUIAccess = TRUE;
if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE, &hTokenSelf))
{
break;
}
if (!::GetTokenInformation(hTokenSelf, TokenSessionId, &dwSessionId, sizeof(dwSessionId), &dwRetLen))
{
break;
}
dwErr = _DuplicateProcessToken(_T("winlogon.exe"), dwSessionId, TOKEN_IMPERSONATE, &hWinlogonToken);
if (ERROR_SUCCESS != dwErr)
{
break;
}
if (!::SetThreadToken(NULL, hWinlogonToken))
{
break;
}
if (!::DuplicateTokenEx(hTokenSelf, dwDesiredAccess, NULL, SecurityAnonymous, TokenPrimary, phToken))
{
break;
}
if (!::SetTokenInformation(*phToken, TokenUIAccess, &bUIAccess, sizeof(bUIAccess)))
{
break;
}
::RevertToSelf();
fResult = TRUE;
} while (false);
if (!fResult)
{
if (*phToken)
{
::CloseHandle(*phToken);
*phToken = NULL;
}
dwErr = ::GetLastError();
}
if (hWinlogonToken)
{
::CloseHandle(hWinlogonToken);
}
if (hTokenSelf)
{
::CloseHandle(hTokenSelf);
}
return dwErr;
}
DWORD CreateProcessWithUIAccess(
const _tstring& strExePath,
const _tstring& strCommand,
const _tstring& strCurDir/* = _T("")*/
)
{
return _CreateProcessWithUIAccess(strExePath, strCommand, strCurDir, true);
}
DWORD CreateProcessNoUIAccess(
const _tstring& strExePath,
const _tstring& strCommand,
const _tstring& strCurDir/* = _T("")*/
)
{
return _CreateProcessWithUIAccess(strExePath, strCommand, strCurDir, false);
}
bool CreateProcessWithSystem(
const _tstring& strExePath,
const _tstring& strCommand,
const _tstring& strCurDir/* = _T("")*/
)
{
PROC_INFO_LIST infos = GetProcessInfos(_T("winlogon.exe"), 0);
if (infos.empty())
{
return false;
}
return CreateProcessWithPidToken(infos.begin()->first, strExePath, strCommand, strCurDir);
}
BOOL CheckProcessUIAccess(
DWORD dwPid,
DWORD* pdwErr,
DWORD* pfUIAccess
)
{
HANDLE hProcess = NULL;
HANDLE hToken = NULL;
DWORD dwRetLen = 0;
BOOL result = FALSE;
do
{
hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid);
if (!hProcess)
{
break;
}
if (!::OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
{
break;
}
if (!::GetTokenInformation(hToken, TokenUIAccess, pfUIAccess, sizeof(*pfUIAccess), &dwRetLen))
{
break;
}
result = TRUE;
} while (false);
if (!result)
{
*pdwErr = ::GetLastError();
}
if (hProcess)
{
::CloseHandle(hProcess);
}
if (hToken)
{
::CloseHandle(hToken);
}
return result;
}
void _EnumProcessWindows(std::map<HWND, WND_INFO>& infos, HWND hWnd, DWORD dwPid)
{
HWND childWindow = NULL;
ULONG nMaxTimes = 0x4000;
//使用 FindWindowEx 函数搜索子窗口
while (nMaxTimes > 0 && (childWindow = ::FindWindowEx(hWnd, childWindow, NULL, NULL)))
{
ULONG processId = 0;
ULONG threadId = 0;
threadId = ::GetWindowThreadProcessId(childWindow, &processId);
if (dwPid == processId)
{
TCHAR szClassBuf[MAX_PATH] = { 0 };
TCHAR szTextBuf[MAX_PATH] = { 0 };
::GetClassName(childWindow, szClassBuf, _countof(szClassBuf));
::GetWindowText(childWindow, szTextBuf, _countof(szTextBuf));
WND_INFO info;
info.hWnd = childWindow;
info.dwPid = processId;
info.dwTid = threadId;
info.strClass = szClassBuf;
info.strText = szTextBuf;
infos.insert(std::make_pair(childWindow, info));
}
nMaxTimes--;
}
}
std::map<HWND, WND_INFO> GetProcessWindows(DWORD dwPid)
{
std::map<HWND, WND_INFO> infos;
//枚举 桌面窗口 的子窗口
_EnumProcessWindows(infos, ::GetDesktopWindow(), dwPid);
//枚举 仅消息窗口 的子窗口
_EnumProcessWindows(infos, HWND_MESSAGE, dwPid);
return infos;
}
WND_NODE _GetWindowNode(HWND hWnd, std::vector<MODULE_INFO>& modules)
{
TCHAR szClassBuf[MAX_PATH] = { 0 };
TCHAR szTextBuf[MAX_PATH] = { 0 };
::GetClassName(hWnd, szClassBuf, _countof(szClassBuf));
::GetWindowText(hWnd, szTextBuf, _countof(szTextBuf));
WND_NODE node;
node.hWnd = hWnd;
node.strClass = szClassBuf;
node.strText = szTextBuf;
node.dwTid = ::GetWindowThreadProcessId(hWnd, &node.dwPid);
HMODULE hModule = (HMODULE)::GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
for (const auto& item : modules)
{
if (hModule == item.hModule)
{
node.strModule = item.strModule;
}
}
HWND childWindow = NULL;
ULONG nMaxTimes = 0x4000;
//使用 FindWindowEx 函数搜索子窗口
while (nMaxTimes > 0 && (childWindow = ::FindWindowEx(hWnd, childWindow, NULL, NULL)))
{
node.NodeList.push_back(_GetWindowNode(childWindow, modules));
nMaxTimes--;
}
return node;
}
std::map<HWND, WND_NODE> GetProcessWindowNodes(DWORD dwPid)
{
std::map<HWND, WND_NODE> nodes;
std::map<HWND, WND_INFO> infos;
std::vector<MODULE_INFO> moduleInfos = GetModuleInfos(dwPid);
//枚举 桌面窗口 的子窗口
_EnumProcessWindows(infos, ::GetDesktopWindow(), dwPid);
//枚举 仅消息窗口 的子窗口
_EnumProcessWindows(infos, HWND_MESSAGE, dwPid);
for (const auto& item : infos)
{
WND_NODE node = _GetWindowNode(item.first, moduleInfos);
nodes.insert(std::make_pair(item.first, node));
}
return nodes;
}
#pragma pack(push)
#pragma pack(1)
// 包含文件的版本信息。 此信息与语言和代码页无关
// https://learn.microsoft.com/zh-cn/windows/win32/menurc/vs-versioninfo
typedef struct {
WORD wLength; // VS_VERSIONINFO 结构的长度(以字节为单位),此长度不包括在 32 位边界上对齐任何后续版本资源数据的填充
WORD wValueLength; // Value 成员的长度(以字节为单位)
WORD wType; // 版本资源中的数据类型, 1: 资源包含文本数据 0: 版本资源包含二进制数据
WCHAR szKey[15]; // Unicode 字符串 L“VS_VERSION_INFO”
WORD Padding1; // 在 32 位边界上对齐 Children 成员所需的任意或零个 WORD
//VS_FIXEDFILEINFO Value
//WORD Padding2
//WORD Children
} VS_VERSIONINFO, * PVS_VERSIONINFO;
#pragma pack(pop)
static VERSION_LIST _GetFileVersionList(const _tstring& strFile, bool fLocalised)
{
VERSION_LIST infoResult;
PVOID pFsRedirectionOldValue = NULL;
bool isDisableWow64Fs = false;
UINT cbTranslate = 0;
DWORD dwVerSize;
LPVOID lpVerData = NULL;
// 加载文件
if (strFile.empty())
{
return infoResult;
}
// 禁用文件重定向
isDisableWow64Fs = ::Wow64DisableWow64FsRedirection(&pFsRedirectionOldValue);
do
{
DWORD dwFlags = fLocalised ? FILE_VER_GET_LOCALISED : FILE_VER_GET_NEUTRAL;
dwFlags |= FILE_VER_GET_PREFETCHED;
// 获取版本信息数据大小
dwVerSize = ::GetFileVersionInfoSize(strFile.c_str(), NULL);
//dwVerSize = ::GetFileVersionInfoSizeEx(dwFlags, strFile.c_str(), NULL);
if (0 == dwVerSize)
{
break;
}
// 分配版本信息缓冲
lpVerData = ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dwVerSize);
if (!lpVerData)
{
break;
}
// 获取版本信息
BOOL fResult = FALSE;
fResult = ::GetFileVersionInfo(strFile.c_str(), NULL, dwVerSize, lpVerData);
//fResult = ::GetFileVersionInfoEx(dwFlags, strFile.c_str(), NULL, dwVerSize, lpVerData);
if (!fResult)
{
break;
}
// 获取语言代码
LANGANDCODEPAGE* lpTranslate = NULL;
if (!::VerQueryValue(lpVerData, _T("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate))
{
break;
}
DWORD dwCount = cbTranslate / sizeof(LANGANDCODEPAGE);
for (DWORD i = 0; i < dwCount; i++)
{
LANGANDCODEPAGE langCodePage = lpTranslate[i];
VERSION_INFO versionInfo;
// 获取 VS_FIXEDFILEINFO 信息
PVS_VERSIONINFO lpVersion = (PVS_VERSIONINFO)lpVerData;
if (0 != lpVersion->wValueLength)
{
VS_FIXEDFILEINFO* pFixedFileInfo = (VS_FIXEDFILEINFO*)((LPBYTE)lpVersion + sizeof(VS_VERSIONINFO));
DWORD dwAlign = 4;
DWORD_PTR dwPadding = ((DWORD_PTR)pFixedFileInfo % dwAlign);
if (0 != dwPadding)
{
pFixedFileInfo = (VS_FIXEDFILEINFO*)((LPBYTE)pFixedFileInfo + (dwAlign - dwPadding));
}
versionInfo.vsFixedInfo = *((PVS_VER_FIXEDFILEINFO)pFixedFileInfo);
}
// 查询所有信息
// 查询单个信息函数
auto _QueryInfo = [](const _tstring& strName, const LPVOID lpData, const LANGANDCODEPAGE& code) {
TCHAR strQuery[MAX_PATH] = { 0 };
LPCTSTR lpQueryRes = NULL;
UINT uQueryCchSize;
(void)::StringCchPrintf(strQuery, _countof(strQuery),
_T("\\StringFileInfo\\%04x%04x\\%s"),
code.wLanguage, code.wCodePage, strName.c_str());
if (::VerQueryValue(lpData, strQuery, (LPVOID*)&lpQueryRes, &uQueryCchSize))
{
return lpQueryRes;
}
return _T("");
};
auto _GetVersionStr = [](VERSON_NUMBER hi, VERSON_NUMBER lo) -> _tstring {
TCHAR szBuf[MAX_PATH] = { 0 };
(void)::StringCchPrintf(szBuf, _countof(szBuf), _T("%hd.%hd.%hd.%hd"),
hi.Version.wHigh,
hi.Version.wLow,
lo.Version.wHigh,
lo.Version.wLow
);
return szBuf;
};
auto _GetLanguageNameStr = [](LANGANDCODEPAGE langCodePage) -> _tstring {
TCHAR szBuf[MAX_PATH] = { 0 };
::VerLanguageName(langCodePage.wLanguage, szBuf, _countof(szBuf));
return szBuf;
};
versionInfo.langAndCodePage = langCodePage;
versionInfo.strComments = _QueryInfo(_T("Comments"), lpVerData, langCodePage);
versionInfo.strInternalName = _QueryInfo(_T("InternalName"), lpVerData, langCodePage);
versionInfo.strProductName = _QueryInfo(_T("ProductName"), lpVerData, langCodePage);
versionInfo.strCompanyName = _QueryInfo(_T("CompanyName"), lpVerData, langCodePage);
versionInfo.strLegalCopyright = _QueryInfo(_T("LegalCopyright"), lpVerData, langCodePage);
versionInfo.strProductVersion = _QueryInfo(_T("ProductVersion"), lpVerData, langCodePage);
versionInfo.strFileDescription = _QueryInfo(_T("FileDescription"), lpVerData, langCodePage);
versionInfo.strLegalTrademarks = _QueryInfo(_T("LegalTrademarks"), lpVerData, langCodePage);
versionInfo.strPrivateBuild = _QueryInfo(_T("PrivateBuild"), lpVerData, langCodePage);
versionInfo.strFileVersion = _QueryInfo(_T("FileVersion"), lpVerData, langCodePage);
versionInfo.strOriginalFilename = _QueryInfo(_T("OriginalFilename"), lpVerData, langCodePage);
versionInfo.strSpecialBuild = _QueryInfo(_T("SpecialBuild"), lpVerData, langCodePage);
VS_VER_FIXEDFILEINFO& vsFixedInfo = versionInfo.vsFixedInfo;
versionInfo.strFileVersionEx = _GetVersionStr(vsFixedInfo.dwFileVersionMS, vsFixedInfo.dwFileVersionLS);
versionInfo.strProductVersionEx = _GetVersionStr(vsFixedInfo.dwProductVersionMS, vsFixedInfo.dwProductVersionLS);
versionInfo.strLanguageName = _GetLanguageNameStr(langCodePage);
versionInfo.FileVerNumber = versionInfo.strFileVersionEx.c_str();
versionInfo.ProductVerNumber = versionInfo.strProductVersionEx.c_str();
infoResult.emplace(langCodePage, versionInfo);
}
} while (false);
// 恢复文件重定向
if (isDisableWow64Fs)
{
::Wow64RevertWow64FsRedirection(pFsRedirectionOldValue);
}
if (lpVerData)
{
::HeapFree(::GetProcessHeap(), 0, lpVerData);
lpVerData = NULL;
}
return infoResult;
}
VERSION_LIST GetFileVersionList(const _tstring& strFile, bool fLocalised/* = true*/)
{
VERSION_LIST fileInfos = _GetFileVersionList(strFile, fLocalised);
return fileInfos;
}
VERSION_INFO GetFileVersion(const _tstring& strFile, bool fLocalised/* = true*/)
{
VERSION_INFO info;
VERSION_LIST fileInfos = _GetFileVersionList(strFile, fLocalised);
if (!fileInfos.empty())
{
info = fileInfos.begin()->second;
}
return info;
}
}
main.cpp
#include <locale.h>
#include <tchar.h>
#include "Win32Utils/CProcessUtils.h"
int _tmain(int argc, LPCTSTR argv[])
{
setlocale(LC_ALL, "");
CProcessUtils::PROC_INFO_LIST procList = CProcessUtils::GetProcessInfos();
return 0;
}