If a service is running in the security context of the LocalSystem
account but does not include the SERVICE_INTERACTIVE_PROCESS
attribute, it uses the following window station and desktop:
Service-0x0-3e7$default. This window station is not interactive, so
the service cannot display a user interface. In addition, processes
created by the service cannot display a user interface.
Refer: Window Station and Desktop Creation
The interactive window station is the only window station that can
display a user interface or receive user input. It is assigned to the
logon session of the interactive user, and contains the keyboard,
mouse, and display device. It is always named "WinSta0". All other
window stations are noninteractive, which means they cannot display a
user interface or receive user input.
Refer: Window Stations
It is said that screen you want to capture is in the default desktop of the interactive window station (Winsta0default). You can create a child process in Winsta0default
, and the child process is used for screenshots. Use CreateProcessAsUser to call the child process in the service.
Refer to the following C++ code. Although this is not a Go language, I think it is enough to be familiar with the call of winapi.
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Entry"));
WCHAR station[] = L"Winsta0\default";
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = station;
si.dwFlags = STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi;
HANDLE hToken;
bool err = WTSQueryUserToken(WTSGetActiveConsoleSessionId(), &hToken);
WCHAR path[] = L"D:\child.exe"; //child.exe is used to take screenshots
if (CreateProcessAsUser(hToken, path, NULL, 0, 0, true, CREATE_NO_WINDOW, 0, 0, &si, &pi))
{
...
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…