Re: GetDesktopWindow from non-interactive service...

From: Eric Perlin [MS] (ericperl_at_microsoft.com)
Date: 09/15/03


Date: Sun, 14 Sep 2003 18:49:47 -0700


SetProcessWindowStation & SetThreadDesktop are dangerous APIs.
They may allow users process to peek into your process space, in particular
if you create windows.
Also, you assume that the desktop being monitored is in session 0, which
might not always be true (Terminal Services or Fast User Switching).

Getting the logged on user's token is not very difficult from a service
running as LocalSystem.
WTSQueryUserToken just does that.
When this API is not available, you can grab the process token of any
process running as this user (explorer.exe ?).

-- 
Eric Perlin [MS]
This posting is provided "AS IS" with no warranties, and confers no rights.
---
"Robb Sharer" <robert.shearer@citicorp.com> wrote in message
news:055a01c37a3b$25f554c0$a001280a@phx.gbl...
>
> I appreciate the help Eric, but I don't think that will
> help me.  I don't have a token from the user, nor do I
> know the username / password.
>
> I am not able to set the "Interact with desktop" switch
> on the service.   But the service is running as
> LocalSystem -- which I thought would allow this
> service access to the desktop.
>
> Thanks.
>
>
>
> >-----Original Message-----
> >I recommend that you spawn a process running as the
> logged on user to do the
> >snapshot (CreateProcessAsUser).
> >You won't have to worry about crossing
> windowstation/desktop  boundaries and
> >ACLs
> >-- 
> >Eric Perlin [MS]
> >This posting is provided "AS IS" with no warranties, and
> confers no rights.
> >---
> >
> >"Robb Shearer" <robert.shearer@citicorp.com> wrote in
> message
> >news:01b001c3797c$809156a0$3101280a@phx.gbl...
> >>
> >> We have a service that is monitoring production desktop.
> >> It can determine when something bad has happend on the
> >> production desktop, and generate an e-mail notification
> to
> >> a 'OnCall' e-mail box.
> >>
> >> I have cobbled together some examples from MSDN and
> other
> >> places, and added the ability for the service to take a
> >> snapshot of the desktop, and include it as an
> attachment.
> >>
> >> This works GREAT on my workstation -- running as a
> >> service. But on a test machine (and in production) it
> will
> >> receive an ACCESS DENIED error with the BitBlt.
> >>
> >> Here is the code I am using to do the snapshot -- minus
> >> all the AddTheAceWindowStation -- which are from MSDN.
> >>
> >> I have tried it w/ and w/o the #define
> >> TRY_USING_MS_ADDACE_EXAMPLE.  Which
> AddTheAceWindowStation
> >> fails.
> >>
> >> Any idea / help would be GREATLY appreciated.
> >>
> >> Thank you.
> >>
> >>
> >>
> >> PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp)
> >> {
> >>     BITMAP bmp;
> >>     PBITMAPINFO pbmi;
> >>     WORD    cClrBits;
> >>
> >>     // Retrieve the bitmap color format, width, and
> >> height.
> >>     if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
> >> return NULL;
> >>
> >>     // Convert the color format to a count of bits.
> >>     cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
> >>     if (cClrBits == 1)
> >>         cClrBits = 1;
> >>     else if (cClrBits <= 4)
> >>         cClrBits = 4;
> >>     else if (cClrBits <= 8)
> >>         cClrBits = 8;
> >>     else if (cClrBits <= 16)
> >>         cClrBits = 16;
> >>     else if (cClrBits <= 24)
> >>         cClrBits = 24;
> >>     else cClrBits = 32;
> >>
> >>     // Allocate memory for the BITMAPINFO structure.
> (This
> >> structure
> >>     // contains a BITMAPINFOHEADER structure and an
> array
> >> of RGBQUAD
> >>     // data structures.)
> >>
> >>      if (cClrBits != 24)
> >>          pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
> >>                     sizeof(BITMAPINFOHEADER) +
> >>                     sizeof(RGBQUAD) * (1<< cClrBits));
> >>
> >>      // There is no RGBQUAD array for the 24-bit-per-
> pixel
> >> format.
> >>
> >>      else
> >>          pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
> >>                     sizeof(BITMAPINFOHEADER));
> >>
> >>     // Initialize the fields in the BITMAPINFO
> structure.
> >>
> >>     pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
> >>     pbmi->bmiHeader.biWidth = bmp.bmWidth;
> >>     pbmi->bmiHeader.biHeight = bmp.bmHeight;
> >>     pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
> >>     pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
> >>     if (cClrBits < 24)
> >>         pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
> >>
> >>     // If the bitmap is not compressed, set the BI_RGB
> >> flag.
> >>     pbmi->bmiHeader.biCompression = BI_RGB;
> >>
> >>     // Compute the number of bytes in the array of color
> >>     // indices and store the result in biSizeImage.
> >>     // For Windows NT, the width must be DWORD aligned
> >> unless
> >>     // the bitmap is RLE compressed. This example shows
> >> this.
> >>     // For Windows 95/98/Me, the width must be WORD
> >> aligned unless the
> >>     // bitmap is RLE compressed.
> >>     pbmi->bmiHeader.biSizeImage = ((pbmi-
> >> >bmiHeader.biWidth * cClrBits +31) & ~31) /8
> >>                                   * pbmi-
> >> >bmiHeader.biHeight;
> >>     // Set biClrImportant to 0, indicating that all of
> the
> >>     // device colors are important.
> >>      pbmi->bmiHeader.biClrImportant = 0;
> >>      return pbmi;
> >> }
> >>
> >>
> >> HBITMAP CreateBitmapOfDesktop(HWND desktopWindow)
> >> {
> >> HWND hwnd = desktopWindow;
> >> HDC hScreenDC = GetDC(hwnd);
> >> int ScreenWidth = GetDeviceCaps(hScreenDC,
> >> HORZRES);
> >> int ScreenHeight = GetDeviceCaps(hScreenDC,
> >> VERTRES);
> >>
> >> HBITMAP bitmap = CreateCompatibleBitmap(hScreenDC,
> >> ScreenWidth, ScreenHeight);
> >> HDC bitmapDC = CreateCompatibleDC(hScreenDC);
> >> HBITMAP oldBitmap = (HBITMAP)SelectObject
> >> (bitmapDC, bitmap);
> >>
> >> if ( BitBlt(bitmapDC, 0, 0, ScreenWidth,
> >> ScreenHeight, hScreenDC, 0, 0, SRCCOPY | CAPTUREBLT) ==
> 0 )
> >> return NULL;
> >>
> >> SelectObject(bitmapDC, oldBitmap);
> >> DeleteObject(bitmapDC);
> >> ReleaseDC(hwnd, hScreenDC);
> >> return bitmap;
> >> }
> >>
> >>
> >> void SaveBitmapToFile(LPTSTR pszFile, PBITMAPINFO pbi,
> >> HBITMAP hBMP, HWND desktopWindow)
> >> {
> >> HANDLE hf;                 // file handle
> >> BITMAPFILEHEADER hdr;       // bitmap file-header
> >> PBITMAPINFOHEADER pbih;     // bitmap info-header
> >> LPBYTE lpBits;              // memory pointer
> >> DWORD dwTotal;              // total count of
> >> bytes
> >> DWORD cb;                   // incremental count
> >> of bytes
> >> BYTE *hp;                   // byte pointer
> >> DWORD dwTmp;
> >>
> >>     pbih = (PBITMAPINFOHEADER) pbi;
> >>     lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih-
> >> >biSizeImage);
> >>
> >>     if (!lpBits)
> >> return;
> >>
> >> HWND hwnd = desktopWindow;
> >> HDC hScreenDC = GetDC(hwnd);
> >>
> >>     // Retrieve the color table (RGBQUAD array) and the
> >> bits
> >>     // (array of palette indices) from the DIB.
> >>     if (!GetDIBits(hScreenDC, hBMP, 0, (WORD) pbih-
> >> >biHeight, lpBits, pbi, DIB_RGB_COLORS))
> >> {
> >> ReleaseDC(hwnd, hScreenDC);
> >> return;
> >> }
> >> ReleaseDC(hwnd, hScreenDC);
> >>
> >>     // Create the .BMP file.
> >>     hf = CreateFile(pszFile,
> >>                    GENERIC_READ | GENERIC_WRITE,
> >>                    (DWORD) 0,
> >>                     NULL,
> >>                    CREATE_ALWAYS,
> >>                    FILE_ATTRIBUTE_NORMAL,
> >>                    (HANDLE) NULL);
> >>     if (hf == INVALID_HANDLE_VALUE)
> >> return;
> >>
> >>     hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"
> >>     // Compute the size of the entire file.
> >>     hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
> pbih-
> >> >biSize + pbih->biClrUsed * sizeof(RGBQUAD) + pbih-
> >> >biSizeImage);
> >>     hdr.bfReserved1 = 0;
> >>     hdr.bfReserved2 = 0;
> >>
> >>     // Compute the offset to the array of color indices.
> >>     hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
> >> pbih->biSize + pbih->biClrUsed * sizeof (RGBQUAD);
> >>
> >>     // Copy the BITMAPFILEHEADER into the .BMP file.
> >>     if (!WriteFile(hf, (LPVOID) &hdr, sizeof
> >> (BITMAPFILEHEADER), (LPDWORD) &dwTmp,  NULL))
> >> return;
> >>
> >>     // Copy the BITMAPINFOHEADER and RGBQUAD array into
> >> the file.
> >>     if (!WriteFile(hf, (LPVOID) pbih, sizeof
> >> (BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD),
> >> (LPDWORD) &dwTmp, ( NULL)) )
> >> return;
> >>
> >>     // Copy the array of color indices into the .BMP
> file.
> >>     dwTotal = cb = pbih->biSizeImage;
> >>     hp = lpBits;
> >>     if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD)
> >> &dwTmp,NULL))
> >> return;
> >>
> >>     // Close the .BMP file.
> >>      if (!CloseHandle(hf))
> >> return;
> >>
> >>     // Free memory.
> >>     GlobalFree((HGLOBAL)lpBits);
> >> }
> >>
> >>
> >> BOOL CALLBACK FindDesktopWindow(HWND hwnd, LPARAM p)
> >> {
> >> char winName[256];
> >> char className[256];
> >>
> >> className[0] = 0;
> >> GetClassName(hwnd, className, 255);
> >> if ( stricmp(className, "#32769") == 0 )
> >> {
> >> DWORD* desktopWindow = (DWORD*)p;
> >> *desktopWindow = (long)hwnd;
> >> return FALSE;
> >> }
> >> HWND parent= hwnd;
> >> do {
> >> className[0] = 0;
> >> parent = GetParent(parent);
> >> GetClassName(parent, className, 255);
> >> if ( stricmp(className, "#32769") == 0 )
> >> {
> >> DWORD* desktopWindow = (DWORD*)p;
> >> *desktopWindow = (long)parent;
> >> return FALSE;
> >> }
> >> } while ( parent != NULL );
> >> return TRUE;
> >> }
> >>
> >>
> >>
> >> //  called with "winsta0, default"
> >> STDMETHODIMP GrabDesktopSnapshot(char* UserWinStaName,
> >> char* UserDesktopName)
> >> {
> >> HDESK               hdesk;
> >> HDESK hdeskold;
> >> HWINSTA             hwinsta;
> >>
> >> hwinsta = OpenWindowStation(UserWinStaName, FALSE,
> >> READ_CONTROL);
> >> if (hwinsta == NULL)
> >> return E_FAIL;
> >>
> >> HWINSTA hwinstaold = GetProcessWindowStation();
> >> if (hwinstaold == NULL)
> >> return E_FAIL;
> >>
> >> hdeskold = GetThreadDesktop(GetCurrentThreadId());
> >>
> >>
> >> //
> >> // set the windowstation to winsta0 so that you
> >> obtain the
> >> // correct default desktop
> >> //
> >>
> >> if (!SetProcessWindowStation(hwinsta))
> >> return E_FAIL;
> >>
> >> //
> >> // obtain a handle to the user desktop
> >> //
> >> hdesk = OpenDesktop(UserDesktopName, 0, FALSE,
> >> READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS |
> >> DESKTOP_READOBJECTS  );
> >> if (hdesk == NULL)
> >> return E_FAIL;
> >>
> >> SetThreadDesktop(hdesk);
> >>
> >> #ifdef TRY_USING_MS_ADDACE_EXAMPLE
> >>
> >> HANDLE hToken;
> >> PSID psid;
> >>
> >> if (!LogonUser("Foo", "DomainLab", "Bar",
> >> LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
> >> &hToken))
> >> return E_FAIL;
> >>
> >> // example function form MSDN
> >> if (!GetLogonSID(hToken, &psid))
> >> return E_FAIL;
> >>
> >>
> >> //
> >> // add the user to interactive windowstation --- 
> >> sample function from MSDN
> >> //
> >> if (!AddTheAceWindowStation(hwinsta, psid))
> >> return E_FAIL;
> >>
> >>
> >> //
> >> // add user to "default" desktop -- 
> >> sample function from MSDN
> >> //
> >> if (!AddTheAceDesktop(hdesk, psid))
> >> return E_FAIL;
> >>
> >>
> >> //
> >> // free the buffer for the logon sid
> >> //
> >> RemoveSid(&psid);
> >> #endif
> >>
> >>
> >> // Don't want to use GetDesktopWindow()..  This
> >> might eventually be used
> >> // in a TerminalServer environment.
> >> //
> >> // Or -- is that a totally mute point? --- Will
> >> GetDesktopWindow() work if the
> >> // SetProcessWindowStation() and SetThreadDesktop
> >> () are set correctly?
> >> //
> >> HWND DesktopWindow = 0;
> >> EnumDesktopWindows(hdesk, FindDesktopWindow, (long)
> >> &DesktopWindow);
> >> if ( DesktopWindow == 0 )
> >> return E_FAIL;
> >>
> >> HBITMAP bitmap = CreateBitmapOfDesktop
> >> (DesktopWindow);
> >> if ( bitmap == NULL )
> >> return E_FAIL;
> >>
> >> PBITMAPINFO bitmapInfo = CreateBitmapInfoStruct
> >> (bitmap);
> >>
> >>
> >> char filename[256];
> >> SYSTEMTIME st;
> >> GetSystemTime(&st);
> >> SystemTimeToTzSpecificLocalTime(NULL, &st, &st);
> >>
> >> sprintf(filename, "c:\\temp\\Snapshot_%04.04d%
> >> 02.02d%02.02d_%02.02d%02.02d%02.02d.bmp", st.wYear,
> >> st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
> >>
> >> SaveBitmapToFile(filename, bitmapInfo, bitmap,
> >> DesktopWindow);
> >>
> >> DeleteObject(bitmap);
> >>
> >> SetThreadDesktop(hdeskold);
> >>    if (!SetProcessWindowStation(hwinstaold))
> >>    return E_FAIL;
> >>
> >> // we will continue even if this fails
> >> int closeRes = CloseWindowStation(hwinsta);
> >>
> >> if (!CloseDesktop(hdesk))
> >> return E_FAIL;
> >> CloseHandle(hToken);
> >> return S_OK;
> >> }
> >>
> >>
> >
> >
> >.
> >


Relevant Pages

  • Re: GetDesktopWindow from non-interactive service...
    ... BITMAP bmp; ... // contains a BITMAPINFOHEADER structure and an array ... > HBITMAP CreateBitmapOfDesktop(HWND desktopWindow) ... > HWND hwnd = desktopWindow; ...
    (microsoft.public.platformsdk.security)
  • Direct2D: CopyFromRenderTarget() results in black bitmap?
    ... I'm trying to scroll an area of a HWND render target with Direct2D, ... hwndTarget->DrawBitmap ...
    (microsoft.public.win32.programmer.directx.graphics)
  • Re: Help with BitBlt ??
    ... To put a bitmap on a button for Pocket PC, ... HWND InitializeCustomItem ... LRESULT CALLBACK WndProc (HWND hwnd, UINT uimessage, WPARAM wParam, ... LPARAM lParam) ...
    (microsoft.public.win32.programmer.ui)
  • Re: draw bitmap on Explorer-Style Custom Templates
    ... I am trying to preview a bitmap file by using Explorer-Style Custom ... UINT_PTR CALLBACK GetOpenFileNameHook(HWND hwnd, UINT msg, WPARAM wParam, ... LPOFNOTIFY lpOfNotify = lParam; ...
    (microsoft.public.vc.language)
  • Re: draw bitmap on Explorer-Style Custom Templates
    ... I am trying to preview a bitmap file by using Explorer-Style Custom ... UINT_PTR CALLBACK GetOpenFileNameHook(HWND hwnd, UINT msg, WPARAM wParam, ... LPOFNOTIFY lpOfNotify = lParam; ...
    (microsoft.public.vc.mfc)