mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-03-24 18:16:24 +01:00
196 lines
6.8 KiB
C
196 lines
6.8 KiB
C
/*!
|
|
* @file window.c
|
|
* @brief Definitions for window management functionality
|
|
*/
|
|
#include "extapi.h"
|
|
#include "window.h"
|
|
|
|
VOID add_enumerated_window(Packet *pResponse, QWORD qwHandle, const char* cpWindowTitle, DWORD dwProcessId);
|
|
DWORD enumerate_windows(Packet *response, BOOL bIncludeUnknown, QWORD parentWindow);
|
|
|
|
/*! @brief The maximum number of characters extracted from a window title. */
|
|
#define MAX_WINDOW_TITLE 256
|
|
|
|
/*! @brief EnumChildWindows function pointer type. */
|
|
typedef BOOL(WINAPI * PENUMCHILDWINDOWS)(HWND hWndParent, WNDENUMPROC enumProc, LPARAM lparam);
|
|
/*! @brief GetWindowTextA function pointer type. */
|
|
typedef int (WINAPI * PGETWINDOWTEXA)(HWND hWnd, LPSTR lpString, int nMaxCount);
|
|
/*! @brief GetWindowThreadProcessId function pointer type. */
|
|
typedef DWORD(WINAPI * PGETWINDOWTHREADPROCESSID)(HWND hWnd, LPDWORD lpdwProcessId);
|
|
|
|
/*! @brief Container type used to maintain state across EnumChildWindows callback calls. */
|
|
typedef struct _EnumWindowsState
|
|
{
|
|
Packet* pResponse; ///< Pointer to the \c Packet to add results to.
|
|
BOOL bIncludeUnknown; ///< Flag indicating if unknown windows should be included.
|
|
PGETWINDOWTEXA pGetWindowTextA; ///< Pointer to the GetWindowTextA function.
|
|
PGETWINDOWTHREADPROCESSID pGetWindowThreadProcessId; ///< Pointer to the GetWindowThreadProcessId function.
|
|
} EnumWindowsState;
|
|
|
|
/*!
|
|
* @brief Callback used during enumeration of desktop Windows.
|
|
* @hWnd Handle to the Window that was enumerated.
|
|
* @hWnd lParam State value passed in during enumeration.
|
|
* @returns Indication of whether to continue enumeration.
|
|
* This function always returns \c TRUE.
|
|
*/
|
|
BOOL CALLBACK enumerate_windows_callback(HWND hWnd, LPARAM lParam)
|
|
{
|
|
char windowTitle[MAX_WINDOW_TITLE];
|
|
DWORD dwThreadId = 0;
|
|
DWORD dwProcessId = 0;
|
|
EnumWindowsState* pState = (EnumWindowsState*)lParam;
|
|
|
|
dprintf("[EXTAPI WINDOW] Enumerated window %x", hWnd);
|
|
|
|
do
|
|
{
|
|
dprintf("[EXTAPI WINDOW] Getting window title %p", pState->pGetWindowTextA);
|
|
if (pState->pGetWindowTextA(hWnd, windowTitle, MAX_WINDOW_TITLE) == 0)
|
|
{
|
|
dprintf("[EXTAPI WINDOW] Unable to get window title. Setting to <unknown>.");
|
|
if (pState->bIncludeUnknown)
|
|
{
|
|
strncpy_s(windowTitle, MAX_WINDOW_TITLE, "<unknown>", MAX_WINDOW_TITLE - 1);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
dprintf("[EXTAPI WINDOW] Getting process ID %p", pState->pGetWindowThreadProcessId);
|
|
dwThreadId = pState->pGetWindowThreadProcessId(hWnd, &dwProcessId);
|
|
|
|
dprintf("[EXTAPI WINDOW] Adding enumerated response");
|
|
add_enumerated_window(pState->pResponse, (QWORD)hWnd, windowTitle, dwProcessId);
|
|
} while (0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*!
|
|
* @brief Perform enumeration of windows.
|
|
* @param response Pointer to the \c Packet which will contain the response.
|
|
* @param bIncludeUnknown Set to \c TRUE if unknown windows are to be included.
|
|
* @param parentWindow Handle to the parent window to use for enumeration.
|
|
* Set this value to \c NULL to enumerate top-level windows.
|
|
* @returns Indication success or failure.
|
|
*/
|
|
DWORD enumerate_windows(Packet *response, BOOL bIncludeUnknown, QWORD parentWindow)
|
|
{
|
|
DWORD dwResult;
|
|
HMODULE hUser32 = NULL;
|
|
PENUMCHILDWINDOWS pEnumChildWindows;
|
|
EnumWindowsState state;
|
|
|
|
do
|
|
{
|
|
dprintf("[EXTAPI WINDOW] Loading user32.dll");
|
|
if ((hUser32 = LoadLibraryA("user32.dll")) == NULL)
|
|
{
|
|
BREAK_ON_ERROR("[EXTAPI WINDOW] Unable to load user32.dll");
|
|
}
|
|
|
|
dprintf("[EXTAPI WINDOW] Searching for GetWindowTextA");
|
|
if ((state.pGetWindowTextA = (PGETWINDOWTEXA)GetProcAddress(hUser32, "GetWindowTextA")) == NULL)
|
|
{
|
|
BREAK_ON_ERROR("[EXTAPI WINDOW] Unable to locate GetWindowTextA in user32.dll");
|
|
}
|
|
dprintf("[EXTAPI WINDOW] Found GetWindowTextA %p", state.pGetWindowTextA);
|
|
|
|
dprintf("[EXTAPI WINDOW] Searching for GetWindowThreadProcessId");
|
|
if ((state.pGetWindowThreadProcessId = (PGETWINDOWTHREADPROCESSID)GetProcAddress(hUser32, "GetWindowThreadProcessId")) == NULL)
|
|
{
|
|
BREAK_ON_ERROR("[EXTAPI WINDOW] Unable to locate GetWindowThreadProcessId in user32.dll");
|
|
}
|
|
|
|
dprintf("[EXTAPI WINDOW] Found GetWindowThreadProcessId %p", state.pGetWindowThreadProcessId);
|
|
|
|
state.pResponse = response;
|
|
state.bIncludeUnknown = bIncludeUnknown;
|
|
|
|
dprintf("[EXTAPI WINDOW] Searching for EnumChildWindows");
|
|
if ((pEnumChildWindows = (PENUMCHILDWINDOWS)GetProcAddress(hUser32, "EnumChildWindows")) == NULL)
|
|
{
|
|
BREAK_ON_ERROR("[EXTAPI WINDOW] Unable to locate EnumChildWindows in user32.dll");
|
|
}
|
|
|
|
dprintf("[EXTAPI WINDOW] Beginning enumeration of child windows with parent %u", parentWindow);
|
|
if (!pEnumChildWindows(parentWindow != 0 ? (HWND)parentWindow : NULL, (WNDENUMPROC)enumerate_windows_callback, (LPARAM)&state))
|
|
{
|
|
BREAK_ON_ERROR("[EXTAPI WINDOW] Failed to enumerate child windows");
|
|
}
|
|
|
|
dwResult = ERROR_SUCCESS;
|
|
} while (0);
|
|
|
|
if (hUser32)
|
|
{
|
|
FreeLibrary(hUser32);
|
|
}
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
/*!
|
|
* @brief Handle the request for window enumeration.
|
|
* @param remote Pointer to the \c Remote making the request.
|
|
* @param packet Pointer to the request \c Packet.
|
|
* @returns Indication of success or failure.
|
|
*/
|
|
DWORD request_window_enum(Remote *remote, Packet *packet)
|
|
{
|
|
QWORD parentWindow = 0;
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
BOOL bIncludeUnknown = FALSE;
|
|
Packet * response = packet_create_response(packet);
|
|
|
|
do
|
|
{
|
|
if (!response)
|
|
{
|
|
dprintf("[EXTAPI WINDOW] Unable to create response packet");
|
|
dwResult = ERROR_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
// Extract the specified parent window. If this is NULL, that's ok, as we'll
|
|
// just enumerate top-level windows.
|
|
parentWindow = packet_get_tlv_value_qword(packet, TLV_TYPE_EXT_WINDOW_ENUM_HANDLE);
|
|
|
|
// Extract the flag that indicates of unknown windows should be included in the output
|
|
bIncludeUnknown = packet_get_tlv_value_bool(packet, TLV_TYPE_EXT_WINDOW_ENUM_INCLUDEUNKNOWN);
|
|
|
|
dprintf("[EXTAPI WINDOW] Beginning window enumeration");
|
|
dwResult = enumerate_windows(response, bIncludeUnknown, parentWindow);
|
|
|
|
} while (0);
|
|
|
|
dprintf("[EXTAPI WINDOW] Transmitting response back to caller.");
|
|
if (response)
|
|
{
|
|
packet_transmit_response(dwResult, remote, response);
|
|
}
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
/*!
|
|
* @brief Add an enumerated window to the response.
|
|
* @param pResponse Pointer to the \c Response to add the window detail to.
|
|
* @param qwHandle Handle to the window that was found/enumerated/
|
|
* @param cpWindowTitle Title of the window.
|
|
* @param dwProcessId ID of the process that the Window belongs to.
|
|
*/
|
|
VOID add_enumerated_window(Packet *pResponse, QWORD qwHandle, const char* cpWindowTitle, DWORD dwProcessId)
|
|
{
|
|
Packet* pGroup = packet_create_group();
|
|
|
|
packet_add_tlv_uint(pGroup, TLV_TYPE_EXT_WINDOW_ENUM_PID, dwProcessId);
|
|
packet_add_tlv_qword(pGroup, TLV_TYPE_EXT_WINDOW_ENUM_HANDLE, qwHandle);
|
|
packet_add_tlv_string(pGroup, TLV_TYPE_EXT_WINDOW_ENUM_TITLE, cpWindowTitle);
|
|
|
|
packet_add_group(pResponse, TLV_TYPE_EXT_WINDOW_ENUM_GROUP, pGroup);
|
|
}
|