【发布时间】:2014-04-17 22:12:58
【问题描述】:
比方说,如果我有进程 ID 或它的句柄,我可以得到进程运行的window station 吗?
【问题讨论】:
比方说,如果我有进程 ID 或它的句柄,我可以得到进程运行的window station 吗?
【问题讨论】:
不是直截了当,但试试这个:
调用EnumWindowStations()枚举调用进程在同一个Session中的可用窗口站(如果你需要查询另一个Session中的进程那么这将不起作用)。
对于每个窗口站,调用EnumDesktops() 枚举其桌面。
对于每个桌面,调用EnumDesktopWindows() 枚举其顶级窗口。
对于每个窗口,调用GetWindowThreadProcessId() 以获取其进程 ID 并将其与您要查找的 ID 进行比较。
另一种选择可能是执行以下操作:
调用OpenProcess() 以从目标进程ID 中获取HANDLE。
调用NtQueryInformationProcess()获取进程的PEB结构地址。
致电ReadProcessMemory() 阅读PEB。它的ProcessParams.DesktopName 字段包含当前与进程关联的工作站/桌面的名称(PEB.ProcessParams 中可用的字段比 MSDN 显示的要多)。
解析DesktopName 以提取窗口站和桌面名称。
根据需要枚举工作站,从 GetUserObjectInformation() 中寻找匹配的名称。
【讨论】:
NtQueryInformationProcess() API 上的注释:NtQueryInformationProcess may be altered or unavailable in future versions of Windows. Applications should use the alternate functions listed in this topic
PEB中的信息,例如GetCommandLine()和GetCurrentProcessId()。这就是笔记所指的。但是没有替代函数可以访问进程的PEB 本身,因为大多数人不需要直接访问它。
DesktopName 有什么偏移量? 0x78 是 32 位的,但我找不到 64 位的。有人认识他们吗?
好的,这个不适合胆小的人。这是我在@RemyLebeau 的建议后提出的代码。事实证明,对于 32/64 位进程,我需要以不同的方式执行此操作。我找不到 64 位进程的确切 PEB 结构,所以我做了一些基本的逆向工程来匹配它。
也是一个很有趣的结果:
Winsta0\Default
Default
总体而言,可以获得以下类型的桌面/winstation:
Default 用于您的常规输入桌面(您现在正在使用)Winlogon 或 Winsta0\Winlogon 用于安全桌面(例如 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: %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 API 被这样调用:GetProcessWindowStation(DWORD dwPid)
GetProcessWindowStation()只对调用进程有效,不能用来查询其他进程。
似乎没有任何直接方法可以找到与给定进程关联的窗口站。
我看到两个选项:
使用代码注入在目标进程中运行GetProcessWindowStation然后GetUserObjectInformation。
使用EnumWindowStations、EnumDesktops和EnumDesktopWindows遍历会话中的所有窗口;然后使用GetWindowThreadProcessId 并将进程ID与目标进程的ID进行比较。当然,如果进程当前没有窗口,这将不起作用。
您也可以尝试使用GetThreadDesktop 和GetUserObjectInformation 来获取桌面名称;我不确定这是否包括窗口站名称。如果这确实有效,请参阅 MSDN 中的 Traversing the Thread List 以枚举属于该进程的线程。
【讨论】:
GetWindowProcessId() 或 GetWindowThreadProcess() 函数。你在想GetWindowThreadProcessId()吗?你不需要使用注入来调用它。
GetThreadDesktop),但我似乎无法让它工作。我会得到一个有问题的进程的主线程 ID,但随后GetThreadDesktop 将返回ERROR_ACCESS_DENIED。我需要特殊权限才能调用它吗?
GetProcessWindowStation。现已更正,谢谢。
GetThreadDesktop 也不起作用。谢谢。