1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-24 18:16:24 +01:00
2017-05-14 02:11:57 -05:00

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);
}