1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-01-20 20:37:27 +01:00

Land #244, handle situations when SetProcessDPIAware is unavailable

This commit is contained in:
Brent Cook 2017-10-27 00:06:12 -07:00
commit 1010ded636
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96

View File

@ -13,7 +13,7 @@
/*
* Send a buffer to a named pipe server.
*/
DWORD screenshot_send( char * cpNamedPipe, BYTE * pJpegBuffer, DWORD dwJpegSize )
DWORD screenshot_send(char * cpNamedPipe, BYTE * pJpegBuffer, DWORD dwJpegSize)
{
DWORD dwResult = ERROR_ACCESS_DENIED;
HANDLE hPipe = NULL;
@ -22,31 +22,31 @@ DWORD screenshot_send( char * cpNamedPipe, BYTE * pJpegBuffer, DWORD dwJpegSize
do
{
hPipe = CreateFileA( cpNamedPipe, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if( !hPipe )
BREAK_ON_ERROR( "[SCREENSHOT] screenshot_send. CreateFileA failed" );
hPipe = CreateFileA(cpNamedPipe, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (!hPipe)
BREAK_ON_ERROR("[SCREENSHOT] screenshot_send. CreateFileA failed");
if( !WriteFile( hPipe, (LPCVOID)&dwJpegSize, sizeof(DWORD), &dwWritten, NULL ) )
BREAK_ON_ERROR( "[SCREENSHOT] screenshot_send. WriteFile JPEG length failed" );
if (!WriteFile(hPipe, (LPCVOID)&dwJpegSize, sizeof(DWORD), &dwWritten, NULL))
BREAK_ON_ERROR("[SCREENSHOT] screenshot_send. WriteFile JPEG length failed");
if( !dwJpegSize || !pJpegBuffer )
BREAK_WITH_ERROR( "[SCREENSHOT] screenshot_send. No JPEG to transmit.", ERROR_BAD_LENGTH );
if (!dwJpegSize || !pJpegBuffer)
BREAK_WITH_ERROR("[SCREENSHOT] screenshot_send. No JPEG to transmit.", ERROR_BAD_LENGTH);
while( dwTotal < dwJpegSize )
while(dwTotal < dwJpegSize)
{
if( !WriteFile( hPipe, (LPCVOID)(pJpegBuffer + dwTotal), (dwJpegSize - dwTotal), &dwWritten, NULL ) )
if (!WriteFile(hPipe, (LPCVOID)(pJpegBuffer + dwTotal), (dwJpegSize - dwTotal), &dwWritten, NULL))
break;
dwTotal += dwWritten;
}
if( dwTotal != dwJpegSize )
BREAK_WITH_ERROR( "[SCREENSHOT] screenshot_send. dwTotal != dwJpegSize", ERROR_BAD_LENGTH );
if (dwTotal != dwJpegSize)
BREAK_WITH_ERROR("[SCREENSHOT] screenshot_send. dwTotal != dwJpegSize", ERROR_BAD_LENGTH);
dwResult = ERROR_SUCCESS;
} while( 0 );
} while(0);
CLOSE_HANDLE( hPipe );
CLOSE_HANDLE(hPipe);
return dwResult;
}
@ -55,7 +55,7 @@ DWORD screenshot_send( char * cpNamedPipe, BYTE * pJpegBuffer, DWORD dwJpegSize
* Take a screenshot of this sessions default input desktop on WinSta0
* and send it as a JPEG image to a named pipe.
*/
DWORD screenshot( int quality, DWORD dwPipeName )
DWORD screenshot(int quality, DWORD dwPipeName)
{
DWORD dwResult = ERROR_ACCESS_DENIED;
HWINSTA hWindowStation = NULL;
@ -82,66 +82,66 @@ DWORD screenshot( int quality, DWORD dwPipeName )
do
{
_snprintf_s( cNamedPipe, sizeof(cNamedPipe), MAX_PATH, "\\\\.\\pipe\\%08X", dwPipeName );
_snprintf_s(cNamedPipe, sizeof(cNamedPipe), MAX_PATH, "\\\\.\\pipe\\%08X", dwPipeName);
os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if( !GetVersionEx( &os ) )
BREAK_ON_ERROR( "[SCREENSHOT] screenshot: GetVersionEx failed" )
if (!GetVersionEx(&os))
BREAK_ON_ERROR("[SCREENSHOT] screenshot: GetVersionEx failed")
// On NT we cant use SM_CXVIRTUALSCREEN/SM_CYVIRTUALSCREEN.
if( os.dwMajorVersion <= 4 )
if (os.dwMajorVersion <= 4)
{
xmetric = SM_CXSCREEN;
ymetric = SM_CYSCREEN;
}
// open the WinSta0 as some services are attached to a different window station.
hWindowStation = OpenWindowStationA( "WinSta0", FALSE, WINSTA_ALL_ACCESS );
if( !hWindowStation )
hWindowStation = OpenWindowStationA("WinSta0", FALSE, WINSTA_ALL_ACCESS);
if (!hWindowStation)
{
if( RevertToSelf() )
hWindowStation = OpenWindowStationA( "WinSta0", FALSE, WINSTA_ALL_ACCESS );
if (RevertToSelf())
hWindowStation = OpenWindowStationA("WinSta0", FALSE, WINSTA_ALL_ACCESS);
}
// if we cant open the defaut input station we wont be able to take a screenshot
if( !hWindowStation )
BREAK_WITH_ERROR( "[SCREENSHOT] screenshot: Couldnt get the WinSta0 Window Station", ERROR_INVALID_HANDLE );
if (!hWindowStation)
BREAK_WITH_ERROR("[SCREENSHOT] screenshot: Couldnt get the WinSta0 Window Station", ERROR_INVALID_HANDLE);
// get the current process's window station so we can restore it later on.
hOrigWindowStation = GetProcessWindowStation();
// set the host process's window station to this sessions default input station we opened
if( !SetProcessWindowStation( hWindowStation ) )
BREAK_ON_ERROR( "[SCREENSHOT] screenshot: SetProcessWindowStation failed" );
if (!SetProcessWindowStation(hWindowStation))
BREAK_ON_ERROR("[SCREENSHOT] screenshot: SetProcessWindowStation failed");
// grab a handle to the default input desktop (e.g. Default or WinLogon)
hInputDesktop = OpenInputDesktop( 0, FALSE, MAXIMUM_ALLOWED );
if( !hInputDesktop )
BREAK_ON_ERROR( "[SCREENSHOT] screenshot: OpenInputDesktop failed" );
hInputDesktop = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
if (!hInputDesktop)
BREAK_ON_ERROR("[SCREENSHOT] screenshot: OpenInputDesktop failed");
// get the threads current desktop so we can restore it later on
hOrigDesktop = GetThreadDesktop( GetCurrentThreadId() );
hOrigDesktop = GetThreadDesktop(GetCurrentThreadId());
// set this threads desktop to that of this sessions default input desktop on WinSta0
SetThreadDesktop( hInputDesktop );
SetThreadDesktop(hInputDesktop);
// and now we can grab a handle to this input desktop
hDesktopWnd = GetDesktopWindow();
// and get a DC from it so we can read its pixels!
hdc = GetDC( hDesktopWnd );
if( !hdc )
BREAK_ON_ERROR( "[SCREENSHOT] screenshot. GetDC failed" );
hdc = GetDC(hDesktopWnd);
if (!hdc)
BREAK_ON_ERROR("[SCREENSHOT] screenshot. GetDC failed");
// back up this DC with a memory DC
hmemdc = CreateCompatibleDC( hdc );
if( !hmemdc )
BREAK_ON_ERROR( "[SCREENSHOT] screenshot. CreateCompatibleDC failed" );
hmemdc = CreateCompatibleDC(hdc);
if (!hmemdc)
BREAK_ON_ERROR("[SCREENSHOT] screenshot. CreateCompatibleDC failed");
// calculate the width and height
sx = GetSystemMetrics( xmetric );
sy = GetSystemMetrics( ymetric );
sx = GetSystemMetrics(xmetric);
sy = GetSystemMetrics(ymetric);
// calculate the absolute virtual screen position
// prevent breaking functionality on <= NT 4.0
@ -153,119 +153,129 @@ DWORD screenshot( int quality, DWORD dwPipeName )
// and create a bitmap
hbmp = CreateCompatibleBitmap( hdc, sx, sy );
if( !hbmp )
BREAK_ON_ERROR( "[SCREENSHOT] screenshot. CreateCompatibleBitmap failed" );
hbmp = CreateCompatibleBitmap(hdc, sx, sy);
if (!hbmp)
BREAK_ON_ERROR("[SCREENSHOT] screenshot. CreateCompatibleBitmap failed");
// this bitmap is backed by the memory DC
if( !SelectObject( hmemdc, hbmp ) )
BREAK_ON_ERROR( "[SCREENSHOT] screenshot. SelectObject failed" );
if (!SelectObject(hmemdc, hbmp))
BREAK_ON_ERROR("[SCREENSHOT] screenshot. SelectObject failed");
// BitBlt the screenshot of this sessions default input desktop on WinSta0 onto the memory DC we created
// screenshot all available monitors by default
SetProcessDPIAware();
HMODULE user32 = NULL;
if ((user32 = LoadLibraryA("user32")))
{
FARPROC SPDA = GetProcAddress(user32, "SetProcessDPIAware");
if (SPDA)
{
SPDA();
}
FreeLibrary(user32);
}
if (!StretchBlt(hmemdc, 0, 0, sx, sy, hdc, sxpos, sypos, GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), SRCCOPY))
BREAK_ON_ERROR("[SCREENSHOT] screenshot. StretchBlt failed");
// finally convert the BMP we just made into a JPEG...
if( bmp2jpeg( hbmp, hmemdc, quality, &pJpegBuffer, &dwJpegSize ) != 1 )
BREAK_WITH_ERROR( "[SCREENSHOT] screenshot. bmp2jpeg failed", ERROR_INVALID_HANDLE );
if (bmp2jpeg(hbmp, hmemdc, quality, &pJpegBuffer, &dwJpegSize) != 1)
BREAK_WITH_ERROR("[SCREENSHOT] screenshot. bmp2jpeg failed", ERROR_INVALID_HANDLE);
// we have succeded
dwResult = ERROR_SUCCESS;
} while( 0 );
} while(0);
// if we have successfully taken a screenshot we send it back via the named pipe
// but if we have failed we send back a zero byte result to indicate this failure.
if( dwResult == ERROR_SUCCESS )
screenshot_send( cNamedPipe, pJpegBuffer, dwJpegSize );
if (dwResult == ERROR_SUCCESS)
screenshot_send(cNamedPipe, pJpegBuffer, dwJpegSize);
else
screenshot_send( cNamedPipe, NULL, 0 );
screenshot_send(cNamedPipe, NULL, 0);
if( hdc )
ReleaseDC( hDesktopWnd, hdc );
if (hdc)
ReleaseDC(hDesktopWnd, hdc);
if( hmemdc )
DeleteDC( hmemdc );
if (hmemdc)
DeleteDC(hmemdc);
if( hbmp )
DeleteObject( hbmp );
if (hbmp)
DeleteObject(hbmp);
// free the jpeg images buffer
if( pJpegBuffer )
free( pJpegBuffer );
if (pJpegBuffer)
free(pJpegBuffer);
// restore the origional process's window station
if( hOrigWindowStation )
SetProcessWindowStation( hOrigWindowStation );
if (hOrigWindowStation)
SetProcessWindowStation(hOrigWindowStation);
// restore the threads origional desktop
if( hOrigDesktop )
SetThreadDesktop( hOrigDesktop );
if (hOrigDesktop)
SetThreadDesktop(hOrigDesktop);
// close the WinSta0 window station handle we opened
if( hWindowStation )
CloseWindowStation( hWindowStation );
if (hWindowStation)
CloseWindowStation(hWindowStation);
// close this last to avoid a handle leak...
if( hInputDesktop )
CloseDesktop( hInputDesktop );
if (hInputDesktop)
CloseDesktop(hInputDesktop);
return dwResult;
}
/*
* Grab a DWORD value out of the command line.
* e.g. screenshot_command_dword( "/FOO:0x41414141 /BAR:0xCAFEF00D", "/FOO:" ) == 0x41414141
* e.g. screenshot_command_dword("/FOO:0x41414141 /BAR:0xCAFEF00D", "/FOO:") == 0x41414141
*/
DWORD screenshot_command_dword( char * cpCommandLine, char * cpCommand )
DWORD screenshot_command_dword(char * cpCommandLine, char * cpCommand)
{
char * cpString = NULL;
DWORD dwResult = 0;
do
{
if( !cpCommandLine || !cpCommand )
if (!cpCommandLine || !cpCommand)
break;
cpString = strstr( cpCommandLine, cpCommand );
if( !cpString )
cpString = strstr(cpCommandLine, cpCommand);
if (!cpString)
break;
cpString += strlen( cpCommand );
cpString += strlen(cpCommand);
dwResult = strtoul( cpString, NULL, 0 );
dwResult = strtoul(cpString, NULL, 0);
} while( 0 );
} while(0);
return dwResult;
}
/*
* Grab a int value out of the command line.
* e.g. screenshot_command_int( "/FOO:12345 /BAR:54321", "/FOO:" ) == 12345
* e.g. screenshot_command_int("/FOO:12345 /BAR:54321", "/FOO:") == 12345
*/
int screenshot_command_int( char * cpCommandLine, char * cpCommand )
int screenshot_command_int(char * cpCommandLine, char * cpCommand)
{
char * cpString = NULL;
int iResult = 0;
do
{
if( !cpCommandLine || !cpCommand )
if (!cpCommandLine || !cpCommand)
break;
cpString = strstr( cpCommandLine, cpCommand );
if( !cpString )
cpString = strstr(cpCommandLine, cpCommand);
if (!cpString)
break;
cpString += strlen( cpCommand );
cpString += strlen(cpCommand);
iResult = atoi( cpString );
iResult = atoi(cpString);
} while( 0 );
} while(0);
return iResult;
}
@ -273,54 +283,54 @@ int screenshot_command_int( char * cpCommandLine, char * cpCommand )
/*
* The real entrypoint for this app.
*/
VOID screenshot_main( char * cpCommandLine )
VOID screenshot_main(char * cpCommandLine)
{
DWORD dwResult = ERROR_INVALID_PARAMETER;
do
{
dprintf( "[SCREENSHOT] screenshot_main. cpCommandLine=0x%08X", (DWORD)cpCommandLine );
dprintf("[SCREENSHOT] screenshot_main. cpCommandLine=0x%08X", (DWORD)cpCommandLine);
if( !cpCommandLine )
if (!cpCommandLine)
break;
if( strlen( cpCommandLine ) == 0 )
if (strlen(cpCommandLine) == 0)
break;
dprintf( "[SCREENSHOT] screenshot_main. lpCmdLine=%s", cpCommandLine );
dprintf("[SCREENSHOT] screenshot_main. lpCmdLine=%s", cpCommandLine);
if( strstr( cpCommandLine, "/s" ) )
if (strstr(cpCommandLine, "/s"))
{
DWORD dwPipeName = 0;
int quality = 0;
quality = screenshot_command_int( cpCommandLine, "/q:" );
quality = screenshot_command_int(cpCommandLine, "/q:");
dwPipeName = screenshot_command_dword( cpCommandLine, "/p:" );
dwPipeName = screenshot_command_dword(cpCommandLine, "/p:");
dwResult = screenshot( quality, dwPipeName );
dwResult = screenshot(quality, dwPipeName);
}
} while( 0 );
} while(0);
dprintf( "[SCREENSHOT] screenshot_main. ExitThread dwResult=%d", dwResult );
dprintf("[SCREENSHOT] screenshot_main. ExitThread dwResult=%d", dwResult);
ExitThread( dwResult );
ExitThread(dwResult);
}
/*
* DLL entry point. If we have been injected via RDI, lpReserved will be our command line.
*/
BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
BOOL bReturnValue = TRUE;
switch( dwReason )
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
hAppInstance = hInstance;
if( lpReserved != NULL )
screenshot_main( (char *)lpReserved );
if (lpReserved != NULL)
screenshot_main((char *)lpReserved);
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH: