如何获取给定进程的窗口站

How to get window station for a given process?

本文关键字:进程 窗口 何获取 获取      更新时间:2023-10-16

比方说,如果我有一个进程ID或它的句柄,我能得到进程运行的窗口站吗?

不要直截了当,但试试这个:

  1. 调用EnumWindowStations()以枚举与调用进程相同会话中的可用窗口站(如果需要查询另一个会话中的进程,则此操作将不起作用)。

  2. 对于每个窗口工作站,调用EnumDesktops()以枚举其桌面。

  3. 对于每个桌面,调用EnumDesktopWindows()来枚举其顶级窗口。

  4. 对于每个窗口,调用GetWindowThreadProcessId()获取其进程ID,并将其与您要查找的ID进行比较。

另一种选择可能是执行以下操作:

  1. 调用OpenProcess()从目标进程ID中获取HANDLE

  2. 调用NtQueryInformationProcess()以检索进程的PEB结构的地址。

  3. 调用ReadProcessMemory()读取PEB。它的ProcessParams.DesktopName字段包含当前与进程关联的工作站/桌面的名称PEB.ProcessParams中的可用字段比MSDN显示的要多得多)。

  4. 解析DesktopName以提取窗口站和桌面名称。

  5. 根据需要枚举工作站,从GetUserObjectInformation()中查找匹配的名称。

好吧,这个不适合胆小的人。这是我在@RemyLebeau的建议下想出的代码。事实证明,对于32/64位进程,我需要采取不同的做法。我找不到64位进程的确切PEB结构,所以我做了一些基本的逆向工程来匹配它

还有一个非常有趣的结果:

  1. 如果我把它称为我自己的过程,我会得到这样的东西:Winsta0Default
  2. 如果我在其他GUI进程上调用它,我会得到:Default

总体而言,可以获得以下类型的台式机/工作站:

  • Default用于您的常规输入桌面(您现在正在使用)
  • 用于安全桌面的WinlogonWinsta0Winlogon(例如,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

  • 使用EnumWindowStationsEnumDesktopsEnumDesktopWindows迭代会话中的所有窗口;则使用CCD_ 26并将进程ID与目标进程的进程ID进行比较。当然,如果流程当前没有窗口,那么这是行不通的。

您也可以尝试使用GetThreadDesktopGetUserObjectInformation来获取桌面名称;我不确定这是否包括窗口站的名称。如果这样做有效,请参阅MSDN中的遍历线程列表以枚举属于进程的线程。