[英]How to get window station for a given process?
不是直截了當,但試試這個:
調用EnumWindowStations()
以枚舉與調用進程相同的 Session 中的可用窗口站(如果您需要查詢另一個 Session 中的進程,則這將不起作用)。
對於每個窗口站,調用EnumDesktops()
以枚舉其桌面。
對於每個桌面,調用EnumDesktopWindows()
以枚舉其頂級窗口。
對於每個窗口,調用GetWindowThreadProcessId()
以獲取其進程 ID 並將其與您要查找的 ID 進行比較。
另一種選擇可能是執行以下操作:
調用OpenProcess()
從目標進程 ID 獲取HANDLE
。
調用NtQueryInformationProcess()
來檢索進程的PEB
結構的地址。
調用ReadProcessMemory()
讀取PEB
。 它的ProcessParams.DesktopName
字段包含當前與進程關聯的工作站/桌面的名稱( PEB.ProcessParams
中有更多的字段可用,然后 MSDN 顯示)。
解析DesktopName
以提取窗口站和桌面名稱。
根據需要枚舉工作站,從GetUserObjectInformation()
查找匹配的名稱。
好吧,這個不適合膽小的人。 這是我在@RemyLebeau 的建議之后想出的代碼。 事實證明,對於 32/64 位進程,我需要以不同的方式執行此操作。 我找不到 64 位進程的確切 PEB 結構,所以我做了一些基本的逆向工程來匹配它。
還有一個很有趣的結果:
Winsta0\\Default
Default
總體而言,您可以獲得以下類型的桌面/winstation:
Default
(您現在正在使用)Winlogon
或Winsta0\\Winlogon
用於安全桌面(例如,Windows 登錄屏幕)""
或空字符串。所以接下來是代碼。 如果有人可以評論它會很好:
//'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: %d\n", ::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: %s\n", (LPCTSTR)pDesktopName);
}
else
_tprintf(L"ERROR in ReadProcessMemory DesktopName: %d\n", ::GetLastError());
delete[] pDesktopName;
}
else
_tprintf(L"ERROR DesktopName ptr\n");
}
else
_tprintf(L"ERROR in ReadProcessMemory RTL_USER_PROCESS_PARAMETERS_32: %d\n", ::GetLastError());
}
else
_tprintf(L"ERROR in ReadProcessMemory PEB-32: %d\n", ::GetLastError());
}
else
_tprintf(L"ERROR in NtQueryInformationProcess: %d\n", ntStatus);
}
else
_tprintf(L"ERROR NtQueryInformationProcess API\n");
}
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: %s\n", pStrDesktopName);
}
else
_tprintf(L"ERROR in NtWow64ReadVirtualMemory64 DesktopName: %d\n", ::GetLastError());
delete[] pBytesDesktopName;
}
else
_tprintf(L"ERROR DesktopName64 ptr\n");
}
else
_tprintf(L"ERROR in NtWow64ReadVirtualMemory64 RTL_USER_PROCESS_PARAMETERS_32: %d\n", ::GetLastError());
}
else
_tprintf(L"ERROR in NtWow64ReadVirtualMemory64 PEB-64: %d\n", ::GetLastError());
}
else
_tprintf(L"ERROR in NtQueryInformationProcess64: %d\n", ntStatus);
}
else
_tprintf(L"ERROR NtWow64QueryInformationProcess64 API\n");
}
::CloseHandle(hProc);
}
else
_tprintf(L"ERROR in OpenProcess: %d\n", ::GetLastError());
按照您的鏈接,以下頁面可能會有所幫助:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684859(v=vs.85).aspx
進程不在窗口站下運行,而是窗口站與進程“關聯”。
似乎沒有任何直接方法可以找到與給定進程關聯的窗口站。
我看到兩個選項:
使用代碼注入在目標進程中運行GetProcessWindowStation
和GetUserObjectInformation
。
使用EnumWindowStations
、 EnumDesktops
和EnumDesktopWindows
遍歷會話中的所有窗口; 然后使用GetWindowThreadProcessId
並將進程 ID 與目標進程的進程 ID 進行比較。 當然,如果進程當前沒有窗口,這將不起作用。
您也可以嘗試使用GetThreadDesktop
和GetUserObjectInformation
來獲取桌面名稱; 我不確定這是否包括窗口站名稱。 如果這樣做有效,請參閱 MSDN 中的遍歷線程列表以枚舉屬於該進程的線程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.