如何获取给定进程的窗口站
How to get window station for a given process?
比方说,如果我有一个进程ID或它的句柄,我能得到进程运行的窗口站吗?
不要直截了当,但试试这个:
-
调用
EnumWindowStations()
以枚举与调用进程相同会话中的可用窗口站(如果需要查询另一个会话中的进程,则此操作将不起作用)。 -
对于每个窗口工作站,调用
EnumDesktops()
以枚举其桌面。 -
对于每个桌面,调用
EnumDesktopWindows()
来枚举其顶级窗口。 -
对于每个窗口,调用
GetWindowThreadProcessId()
获取其进程ID,并将其与您要查找的ID进行比较。
另一种选择可能是执行以下操作:
-
调用
OpenProcess()
从目标进程ID中获取HANDLE
。 -
调用
NtQueryInformationProcess()
以检索进程的PEB
结构的地址。 -
调用
ReadProcessMemory()
读取PEB
。它的ProcessParams.DesktopName
字段包含当前与进程关联的工作站/桌面的名称(PEB.ProcessParams
中的可用字段比MSDN显示的要多得多)。 -
解析
DesktopName
以提取窗口站和桌面名称。 -
根据需要枚举工作站,从
GetUserObjectInformation()
中查找匹配的名称。
好吧,这个不适合胆小的人。这是我在@RemyLebeau的建议下想出的代码。事实证明,对于32/64位进程,我需要采取不同的做法。我找不到64位进程的确切PEB结构,所以我做了一些基本的逆向工程来匹配它
还有一个非常有趣的结果:
- 如果我把它称为我自己的过程,我会得到这样的东西:
Winsta0Default
- 如果我在其他GUI进程上调用它,我会得到:
Default
总体而言,可以获得以下类型的台式机/工作站:
Default
用于您的常规输入桌面(您现在正在使用)- 用于安全桌面的
Winlogon
或Winsta0Winlogon
(例如,Windows登录屏幕) - 适用于Metro(或Modern UI)Windows 8应用程序的
""
或空字符串
接下来就是代码。如果有人能评论一下就好了:
//'dwProcID' = process ID to look up window station for
HANDLE hProc = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcID);
if(hProc)
{
BOOL (WINAPI *pfnIsWow64Process)(HANDLE, PBOOL);
(FARPROC&)pfnIsWow64Process = ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "IsWow64Process");
SYSTEM_INFO si = {0};
::GetNativeSystemInfo(&si);
//See if 32-bit process on 64-bit OS
BOOL bWow64Proc = TRUE;
if(si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
{
if(pfnIsWow64Process)
if(!pfnIsWow64Process(hProc, &bWow64Proc))
{
//Error
_tprintf(L"ERROR in IsWow64Process: %dn", ::GetLastError());
}
}
NTSTATUS ntStatus;
if(bWow64Proc)
{
//32-bit process
NTSTATUS (WINAPI *pfnNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
(FARPROC&)pfnNtQueryInformationProcess = ::GetProcAddress(::GetModuleHandle(L"Ntdll.dll"), "NtQueryInformationProcess");
if(pfnNtQueryInformationProcess)
{
PROCESS_BASIC_INFORMATION pbi = {0};
DWORD dwsz = 0;
if((ntStatus = pfnNtQueryInformationProcess(hProc, ProcessBasicInformation, &pbi, sizeof(pbi), &dwsz)) == 0 &&
dwsz <= sizeof(pbi) &&
pbi.PebBaseAddress)
{
//Define PEB structs
typedef struct _RTL_DRIVE_LETTER_CURDIR
{
WORD Flags;
WORD Length;
ULONG TimeStamp;
STRING DosPath;
} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
struct RTL_USER_PROCESS_PARAMETERS_32
{
ULONG MaximumLength;
ULONG Length;
ULONG Flags;
ULONG DebugFlags;
PVOID ConsoleHandle;
ULONG ConsoleFlags;
HANDLE StdInputHandle;
HANDLE StdOutputHandle;
HANDLE StdErrorHandle;
UNICODE_STRING CurrentDirectoryPath;
HANDLE CurrentDirectoryHandle;
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
PVOID Environment;
ULONG StartingPositionLeft;
ULONG StartingPositionTop;
ULONG Width;
ULONG Height;
ULONG CharWidth;
ULONG CharHeight;
ULONG ConsoleTextAttributes;
ULONG WindowFlags;
ULONG ShowWindowFlags;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopName;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeData;
RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
};
struct PEB_32
{
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
void* Ldr;
RTL_USER_PROCESS_PARAMETERS_32* ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
void* PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
};
//Read PEB-32
PEB_32 peb32 = {0};
DWORD dwcbSzRead = 0;
if(ReadProcessMemory(hProc, pbi.PebBaseAddress, &peb32, sizeof(peb32), &dwcbSzRead) &&
dwcbSzRead == sizeof(peb32) &&
peb32.ProcessParameters)
{
//Read RTL_USER_PROCESS_PARAMETERS_32
RTL_USER_PROCESS_PARAMETERS_32 rupp32 = {0};
dwcbSzRead = 0;
if(ReadProcessMemory(hProc, peb32.ProcessParameters, &rupp32, sizeof(rupp32), &dwcbSzRead) &&
dwcbSzRead == sizeof(rupp32) &&
rupp32.DesktopName.Buffer)
{
//Get desktop name
int ncbSzLn = rupp32.DesktopName.Length + sizeof(TCHAR);
BYTE* pDesktopName = new (std::nothrow) BYTE[ncbSzLn];
if(pDesktopName)
{
dwcbSzRead = 0;
if(ReadProcessMemory(hProc, rupp32.DesktopName.Buffer, pDesktopName, ncbSzLn, &dwcbSzRead) &&
dwcbSzRead == ncbSzLn)
{
//Set last NULL
*(TCHAR*)(pDesktopName + ncbSzLn - sizeof(TCHAR)) = 0;
//We're done
_tprintf(L"Desktop32: %sn", (LPCTSTR)pDesktopName);
}
else
_tprintf(L"ERROR in ReadProcessMemory DesktopName: %dn", ::GetLastError());
delete[] pDesktopName;
}
else
_tprintf(L"ERROR DesktopName ptrn");
}
else
_tprintf(L"ERROR in ReadProcessMemory RTL_USER_PROCESS_PARAMETERS_32: %dn", ::GetLastError());
}
else
_tprintf(L"ERROR in ReadProcessMemory PEB-32: %dn", ::GetLastError());
}
else
_tprintf(L"ERROR in NtQueryInformationProcess: %dn", ntStatus);
}
else
_tprintf(L"ERROR NtQueryInformationProcess APIn");
}
else
{
//64-bit process
NTSTATUS (WINAPI *pfnNtQueryInformationProcess64)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
NTSTATUS (WINAPI *pfnNtWow64ReadVirtualMemory64)(HANDLE, PVOID64, PVOID, ULONG64, PULONG64);
(FARPROC&)pfnNtQueryInformationProcess64 = ::GetProcAddress(::GetModuleHandle(L"Ntdll.dll"), "NtWow64QueryInformationProcess64");
(FARPROC&)pfnNtWow64ReadVirtualMemory64 = ::GetProcAddress(::GetModuleHandle(L"Ntdll.dll"), "NtWow64ReadVirtualMemory64");
if(pfnNtQueryInformationProcess64 &&
pfnNtWow64ReadVirtualMemory64)
{
//Define PEB structs
struct UNICODE_STRING_64 {
USHORT Length;
USHORT MaximumLength;
PVOID64 Buffer;
};
struct PROCESS_BASIC_INFORMATION64
{
PVOID Reserved1[2];
PVOID64 PebBaseAddress;
PVOID Reserved2[4];
ULONG_PTR UniqueProcessId[2];
PVOID Reserved3[2];
};
PROCESS_BASIC_INFORMATION64 pbi64 = {0};
DWORD dwsz = 0;
if((ntStatus = pfnNtQueryInformationProcess64(hProc, ProcessBasicInformation, &pbi64, sizeof(pbi64), &dwsz)) == 0 &&
dwsz <= sizeof(pbi64))
{
struct PEB_64
{
UCHAR InheritedAddressSpace;
UCHAR ReadImageFileExecOptions;
UCHAR BeingDebugged;
BYTE b003;
ULONG Reserved0;
ULONG64 Mutant;
ULONG64 ImageBaseAddress;
ULONG64 Ldr;
PVOID64 ProcessParameters;
};
//Read PEB-64
PEB_64 peb64 = {0};
ULONG64 uicbSzRead = 0;
if(pfnNtWow64ReadVirtualMemory64(hProc, pbi64.PebBaseAddress, &peb64, sizeof(peb64), &uicbSzRead) == 0 &&
uicbSzRead == sizeof(peb64) &&
peb64.ProcessParameters)
{
//Don't know the structure of RTL_USER_PROCESS_PARAMETERS_64 thus read raw bytes
const int ncbSz_rawRUPP64 = sizeof(DWORD) * (6 * 8) + sizeof(UNICODE_STRING_64);
BYTE rawRUPP64[ncbSz_rawRUPP64] = {0};
uicbSzRead = 0;
if(pfnNtWow64ReadVirtualMemory64(hProc, peb64.ProcessParameters, &rawRUPP64, ncbSz_rawRUPP64, &uicbSzRead) == 0 &&
uicbSzRead == ncbSz_rawRUPP64)
{
//Point to the location in raw byte array
UNICODE_STRING_64* pDesktopName = (UNICODE_STRING_64*)(rawRUPP64 + sizeof(DWORD) * (6 * 8));
//Get desktop name
int ncbSzLn = pDesktopName->Length + sizeof(TCHAR);
BYTE* pBytesDesktopName = new (std::nothrow) BYTE[ncbSzLn];
if(pBytesDesktopName)
{
uicbSzRead = 0;
if(pfnNtWow64ReadVirtualMemory64(hProc, pDesktopName->Buffer, pBytesDesktopName, ncbSzLn, &uicbSzRead) == 0 &&
uicbSzRead == ncbSzLn)
{
//Set last NULL
*(TCHAR*)(pBytesDesktopName + ncbSzLn - sizeof(TCHAR)) = 0;
LPCTSTR pStrDesktopName = (LPCTSTR)pBytesDesktopName;
//We're done
_tprintf(L"Desktop64: %sn", pStrDesktopName);
}
else
_tprintf(L"ERROR in NtWow64ReadVirtualMemory64 DesktopName: %dn", ::GetLastError());
delete[] pBytesDesktopName;
}
else
_tprintf(L"ERROR DesktopName64 ptrn");
}
else
_tprintf(L"ERROR in NtWow64ReadVirtualMemory64 RTL_USER_PROCESS_PARAMETERS_32: %dn", ::GetLastError());
}
else
_tprintf(L"ERROR in NtWow64ReadVirtualMemory64 PEB-64: %dn", ::GetLastError());
}
else
_tprintf(L"ERROR in NtQueryInformationProcess64: %dn", ntStatus);
}
else
_tprintf(L"ERROR NtWow64QueryInformationProcess64 APIn");
}
::CloseHandle(hProc);
}
else
_tprintf(L"ERROR in OpenProcess: %dn", ::GetLastError());
链接后,以下页面可能会有所帮助:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684859(v=vs.85).aspx
进程不在窗口站下运行,而是窗口站与进程"关联"。
似乎没有任何直接的方法来查找与给定进程关联的窗口站。
我看到两个选项:
-
使用代码注入在目标进程中运行
GetProcessWindowStation
,然后运行GetUserObjectInformation
。 -
使用
EnumWindowStations
、EnumDesktops
和EnumDesktopWindows
迭代会话中的所有窗口;则使用CCD_ 26并将进程ID与目标进程的进程ID进行比较。当然,如果流程当前没有窗口,那么这是行不通的。
您也可以尝试使用GetThreadDesktop
和GetUserObjectInformation
来获取桌面名称;我不确定这是否包括窗口站的名称。如果这样做有效,请参阅MSDN中的遍历线程列表以枚举属于进程的线程。
- 创建进程 API 失败,在窗口 122 上出现错误代码 10
- 通过 pid 窗口判断进程是否存在
- C++ 窗口本地系统模拟在子进程中失败
- 如何在窗口上设置使用 CreateProcess 创建的新进程的主线程的堆栈大小?
- 有没有办法为使用 Boost 生成的进程创建新的控制台窗口
- 提升 1.58.0 窗口进程.h 错误
- 在单个进程中使Qt顶级窗口被其他非Qt窗口"owned"
- 查找窗口找不到进程
- 将窗口句柄从一个进程使用到另一个进程(插件 vst 音频)
- Win32/Gdigrab - 如何将另一个进程窗口设置为无边框
- 强制将以SW_HIDE启动的进程中的窗口显示为STARTUPINFO
- 有没有办法接收有关在窗口中启动的进程的事件
- 窗口 :创建仅具有对我的进程的权限的目录 (C++)
- 如何在没有窗口类的情况下编写QT系统托盘应用程序,并将其与另一个进程集成
- 如何获取具有可见窗口的任何进程的名称 - WinAPI?
- C++ Windows CreateChildProcess - 隐藏/不显示子进程的控制台窗口
- 如何使用在窗口中使用C++从CreateToolhelp32Snapshot获取64/32位进程详细信息和进程信息
- 如何在列表框窗口进程中捕获VK_ESCAPE
- 将 CreateProcess() 的 stdout 重定向到管道并在另一个进程 c++ 窗口中读取它
- C + + Kill进程窗口标题