/********************************************************/ /* ntapi: Native API core library */ /* Copyright (C) 2013--2017 Z. Gilboa */ /* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ /********************************************************/ #include #include #include #include #include #include "ntapi_impl.h" static int32_t __ipc_connect_return( intptr_t * hlock, int32_t status) { at_store(hlock,0); return status; } static void __ipc_init_ctrl_msg_semctl( const nt_port_attr * attr, nt_tty_ipc_msg * msg) { __ntapi->tt_aligned_block_memset( (uintptr_t *)msg, 0,sizeof(*msg)); msg->data.ipcinfo.ctrlsvc.type = attr->type; msg->data.ipcinfo.ctrlsvc.subtype = attr->subtype; msg->data.ipcinfo.ctrlsvc.keys.key[0] = attr->keys.key[0]; msg->data.ipcinfo.ctrlsvc.keys.key[1] = attr->keys.key[1]; msg->data.ipcinfo.ctrlsvc.keys.key[2] = attr->keys.key[2]; msg->data.ipcinfo.ctrlsvc.keys.key[3] = attr->keys.key[3]; msg->data.ipcinfo.ctrlsvc.keys.key[4] = attr->keys.key[4]; msg->data.ipcinfo.ctrlsvc.keys.key[5] = attr->keys.key[5]; __ntapi->tt_guid_copy( &msg->data.ipcinfo.ctrlsvc.guid, &attr->guid); } static void __ipc_init_ctrl_msg_semsvc( nt_rtdata * rtdata, nt_tty_ipc_msg * msg) { __ntapi->tt_aligned_block_memset( (uintptr_t *)msg, 0,sizeof(*msg)); msg->data.ipcinfo.ctrlsvc.type = rtdata->semctl_type; msg->data.ipcinfo.ctrlsvc.subtype = rtdata->semctl_subtype; msg->data.ipcinfo.ctrlsvc.keys.key[0] = rtdata->semctl_keys[0]; msg->data.ipcinfo.ctrlsvc.keys.key[1] = rtdata->semctl_keys[1]; msg->data.ipcinfo.ctrlsvc.keys.key[2] = rtdata->semctl_keys[2]; msg->data.ipcinfo.ctrlsvc.keys.key[3] = rtdata->semctl_keys[3]; msg->data.ipcinfo.ctrlsvc.keys.key[4] = rtdata->semctl_keys[4]; msg->data.ipcinfo.ctrlsvc.keys.key[5] = rtdata->semctl_keys[5]; __ntapi->tt_guid_copy( &msg->data.ipcinfo.ctrlsvc.guid, &rtdata->semctl_guid); } static void __ipc_init_ctrl_msg_msqctl( const nt_port_attr * attr, nt_tty_ipc_msg * msg) { __ntapi->tt_aligned_block_memset( (uintptr_t *)msg, 0,sizeof(*msg)); msg->data.ipcinfo.ctrlsvc.type = attr->type; msg->data.ipcinfo.ctrlsvc.subtype = attr->subtype; msg->data.ipcinfo.ctrlsvc.keys.key[0] = attr->keys.key[0]; msg->data.ipcinfo.ctrlsvc.keys.key[1] = attr->keys.key[1]; msg->data.ipcinfo.ctrlsvc.keys.key[2] = attr->keys.key[2]; msg->data.ipcinfo.ctrlsvc.keys.key[3] = attr->keys.key[3]; msg->data.ipcinfo.ctrlsvc.keys.key[4] = attr->keys.key[4]; msg->data.ipcinfo.ctrlsvc.keys.key[5] = attr->keys.key[5]; __ntapi->tt_guid_copy( &msg->data.ipcinfo.ctrlsvc.guid, &attr->guid); } static void __ipc_init_ctrl_msg_msqsvc( nt_rtdata * rtdata, nt_tty_ipc_msg * msg) { __ntapi->tt_aligned_block_memset( (uintptr_t *)msg, 0,sizeof(*msg)); msg->data.ipcinfo.ctrlsvc.type = rtdata->msqctl_type; msg->data.ipcinfo.ctrlsvc.subtype = rtdata->msqctl_subtype; msg->data.ipcinfo.ctrlsvc.keys.key[0] = rtdata->msqctl_keys[0]; msg->data.ipcinfo.ctrlsvc.keys.key[1] = rtdata->msqctl_keys[1]; msg->data.ipcinfo.ctrlsvc.keys.key[2] = rtdata->msqctl_keys[2]; msg->data.ipcinfo.ctrlsvc.keys.key[3] = rtdata->msqctl_keys[3]; msg->data.ipcinfo.ctrlsvc.keys.key[4] = rtdata->msqctl_keys[4]; msg->data.ipcinfo.ctrlsvc.keys.key[5] = rtdata->msqctl_keys[5]; __ntapi->tt_guid_copy( &msg->data.ipcinfo.ctrlsvc.guid, &rtdata->msqctl_guid); } static void __ipc_init_ctrl_msg_aflctl( const nt_port_attr * attr, nt_tty_ipc_msg * msg) { __ntapi->tt_aligned_block_memset( (uintptr_t *)msg, 0,sizeof(*msg)); msg->data.ipcinfo.ctrlsvc.type = attr->type; msg->data.ipcinfo.ctrlsvc.subtype = attr->subtype; msg->data.ipcinfo.ctrlsvc.keys.key[0] = attr->keys.key[0]; msg->data.ipcinfo.ctrlsvc.keys.key[1] = attr->keys.key[1]; msg->data.ipcinfo.ctrlsvc.keys.key[2] = attr->keys.key[2]; msg->data.ipcinfo.ctrlsvc.keys.key[3] = attr->keys.key[3]; msg->data.ipcinfo.ctrlsvc.keys.key[4] = attr->keys.key[4]; msg->data.ipcinfo.ctrlsvc.keys.key[5] = attr->keys.key[5]; __ntapi->tt_guid_copy( &msg->data.ipcinfo.ctrlsvc.guid, &attr->guid); } static void __ipc_init_ctrl_msg_aflsvc( nt_rtdata * rtdata, nt_tty_ipc_msg * msg) { __ntapi->tt_aligned_block_memset( (uintptr_t *)msg, 0,sizeof(*msg)); msg->data.ipcinfo.ctrlsvc.type = rtdata->aflctl_type; msg->data.ipcinfo.ctrlsvc.subtype = rtdata->aflctl_subtype; msg->data.ipcinfo.ctrlsvc.keys.key[0] = rtdata->aflctl_keys[0]; msg->data.ipcinfo.ctrlsvc.keys.key[1] = rtdata->aflctl_keys[1]; msg->data.ipcinfo.ctrlsvc.keys.key[2] = rtdata->aflctl_keys[2]; msg->data.ipcinfo.ctrlsvc.keys.key[3] = rtdata->aflctl_keys[3]; msg->data.ipcinfo.ctrlsvc.keys.key[4] = rtdata->aflctl_keys[4]; msg->data.ipcinfo.ctrlsvc.keys.key[5] = rtdata->aflctl_keys[5]; __ntapi->tt_guid_copy( &msg->data.ipcinfo.ctrlsvc.guid, &rtdata->aflctl_guid); } static void __ipc_init_ctrl_msg_ipcpeer( nt_rtdata * rtdata, nt_tty_ipc_msg * msg) { __ntapi->tt_aligned_block_memset( (uintptr_t *)msg, 0,sizeof(*msg)); msg->data.ipcinfo.ctrlsvc.type = rtdata->srv_type; msg->data.ipcinfo.ctrlsvc.subtype = rtdata->srv_subtype; msg->data.ipcinfo.ctrlsvc.keys.key[0] = rtdata->srv_keys[0]; msg->data.ipcinfo.ctrlsvc.keys.key[1] = rtdata->srv_keys[1]; msg->data.ipcinfo.ctrlsvc.keys.key[2] = rtdata->srv_keys[2]; msg->data.ipcinfo.ctrlsvc.keys.key[3] = rtdata->srv_keys[3]; msg->data.ipcinfo.ctrlsvc.keys.key[4] = rtdata->srv_keys[4]; msg->data.ipcinfo.ctrlsvc.keys.key[5] = rtdata->srv_keys[5]; __ntapi->tt_guid_copy( &msg->data.ipcinfo.ctrlsvc.guid, &rtdata->srv_guid); } static int32_t __ipc_set_client_keys( void * hport, const nt_port_attr * attr, nt_rtdata * rtdata) { int32_t status; nt_tty_ipc_msg msg; uint32_t opcode; switch (attr->type) { case NT_PORT_TYPE_SEMCTL: if (rtdata->srv_type == NT_PORT_TYPE_SEMSVC) __ipc_init_ctrl_msg_ipcpeer( rtdata,&msg); else __ipc_init_ctrl_msg_semctl( attr,&msg); opcode = NT_TTY_SEM_FCNTL; break; case NT_PORT_TYPE_SEMSVC: if (rtdata->srv_type == NT_PORT_TYPE_SEMCTL) return NT_STATUS_SUCCESS; __ipc_init_ctrl_msg_semsvc( rtdata,&msg); opcode = NT_TTY_SEM_FCNTL; break; case NT_PORT_TYPE_MSQCTL: if (rtdata->srv_type == NT_PORT_TYPE_MSQSVC) __ipc_init_ctrl_msg_ipcpeer( rtdata,&msg); else __ipc_init_ctrl_msg_msqctl( attr,&msg); opcode = NT_TTY_MSQ_FCNTL; break; case NT_PORT_TYPE_MSQSVC: if (rtdata->srv_type == NT_PORT_TYPE_MSQCTL) return NT_STATUS_SUCCESS; __ipc_init_ctrl_msg_msqsvc( rtdata,&msg); opcode = NT_TTY_MSQ_FCNTL; break; case NT_PORT_TYPE_AFLCTL: if (rtdata->srv_type == NT_PORT_TYPE_AFLSVC) __ipc_init_ctrl_msg_ipcpeer( rtdata,&msg); else __ipc_init_ctrl_msg_aflctl( attr,&msg); opcode = NT_TTY_AFL_FCNTL; break; case NT_PORT_TYPE_AFLSVC: if (rtdata->srv_type == NT_PORT_TYPE_AFLCTL) return NT_STATUS_SUCCESS; __ipc_init_ctrl_msg_aflsvc( rtdata,&msg); opcode = NT_TTY_AFL_FCNTL; break; default: return NT_STATUS_SUCCESS; } msg.header.msg_type = NT_LPC_NEW_MESSAGE; msg.header.data_size = sizeof(msg.data); msg.header.msg_size = sizeof(msg); msg.data.ttyinfo.opcode = opcode; msg.data.ipcinfo.ipckeys[0] = rtdata->ipc_keys[0]; msg.data.ipcinfo.ipckeys[1] = rtdata->ipc_keys[1]; msg.data.ipcinfo.ipckeys[2] = rtdata->ipc_keys[2]; msg.data.ipcinfo.ipckeys[3] = rtdata->ipc_keys[3]; msg.data.ipcinfo.ipckeys[4] = rtdata->ipc_keys[4]; msg.data.ipcinfo.ipckeys[5] = rtdata->ipc_keys[5]; if ((status = __ntapi->zw_request_wait_reply_port(hport,&msg,&msg))) return status; else if (msg.data.ttyinfo.status) return msg.data.ttyinfo.status; return NT_STATUS_SUCCESS; } static int32_t __ipc_connect_by_attr( void ** hport, const nt_port_attr * attr, nt_unicode_string * str, void * hconn, void ** hsection, void ** secaddr, size_t * secsize, int fexisting) { int32_t status; struct dalist_node_ex * node; const nt_port_attr * conn; nt_port_attr * nconn; nt_ipc_conn * ipc; intptr_t * hlock; nt_rtdata * rtdata; ntapi_internals * __internals; /* init */ __internals = __ntapi_internals(); rtdata = __internals->rtdata; /* lock */ hlock = &(__internals->hlock); while (at_locked_cas(hlock,0,1)) __ntapi->zw_delay_execution( NT_SYNC_NON_ALERTABLE, &(nt_timeout){{0,0}}); /* already connected? */ node = (struct dalist_node_ex *)__internals->ipc_conns.head; for (; node; node=node->next) { ipc = (nt_ipc_conn *)&node->dblock; conn = &ipc->attr; if ((attr->keys.key[0] == conn->keys.key[0]) && (attr->keys.key[1] == conn->keys.key[1]) && (attr->keys.key[2] == conn->keys.key[2]) && (attr->keys.key[3] == conn->keys.key[3]) && (attr->keys.key[4] == conn->keys.key[4]) && (attr->keys.key[5] == conn->keys.key[5]) && !__ntapi->tt_guid_compare( &attr->guid, &conn->guid)) { /* already connected */ if (hconn && ((uintptr_t)hconn != node->key)) return __ipc_connect_return( hlock,NT_STATUS_CONTEXT_MISMATCH); *hport = (void *)node->key; *hsection = ipc->hsection; *secaddr = ipc->secaddr; *secsize = ipc->secsize; return __ipc_connect_return(hlock,NT_STATUS_SUCCESS); } } /* __ipc_get_port? */ if (fexisting) return __ipc_connect_return(hlock,NT_STATUS_NOT_FOUND); /* allocate list node */ if ((status = dalist_get_free_node( &__internals->ipc_conns, (void **)&node))) return __ipc_connect_return(hlock,status); /* connect as needed */ if (!hconn) { status = __ntapi->zw_connect_port( &hconn,str,0,0,0,0,0,0); if (status) { dalist_deposit_free_node( &__internals->ipc_conns, node); return __ipc_connect_return(hlock,status); } } /* server-to-server synchronization */ if (!rtdata->ipc_keys[0]) { rtdata->ipc_keys[0] = __ntapi->tt_buffer_crc32( (uint32_t)(uintptr_t)&hport, (char *)__internals,sizeof(*__internals)); rtdata->ipc_keys[1] = __ntapi->tt_buffer_crc32( (uint32_t)(uintptr_t)&hconn, (char *)rtdata,sizeof(*rtdata)); rtdata->ipc_keys[2] = __ntapi->tt_buffer_crc32( (uint32_t)(uintptr_t)&attr, (char *)attr,sizeof(*attr)); rtdata->ipc_keys[3] = __ntapi->tt_buffer_crc32( (uint32_t)(uintptr_t)&node, (char *)node,sizeof(*node)); rtdata->ipc_keys[4] = __ntapi->tt_buffer_crc32( (uint32_t)(uintptr_t)&str, (char *)pe_get_peb_address(), sizeof(nt_peb)); rtdata->ipc_keys[5] = __ntapi->tt_buffer_crc32( (uint32_t)(uintptr_t)&conn, (char *)pe_get_teb_address(), sizeof(nt_tib)); } if ((status = __ipc_set_client_keys(hconn,attr,rtdata))) { __ntapi->zw_close(hconn); dalist_deposit_free_node(&__internals->ipc_conns,node); return __ipc_connect_return(hlock,status); } /* add connection */ node->key = (uintptr_t)hconn; ipc = (nt_ipc_conn *)&node->dblock; nconn = &ipc->attr; __ntapi->tt_aligned_block_memcpy( (uintptr_t *)nconn, (uintptr_t *)attr, sizeof(nt_port_attr)); ipc->hsection = 0; ipc->secaddr = 0; ipc->secsize = 0; dalist_insert_node_by_key( &__internals->ipc_conns, node); /* all done */ *hport = hconn; *hsection = 0; *secaddr = 0; *secsize = 0; return __ipc_connect_return(hlock,NT_STATUS_SUCCESS); } int32_t __stdcall __ntapi_ipc_connect_section_by_attr( __out void ** hport, __in nt_port_attr * attr, __out void ** hsection, __out void ** secaddr, __out size_t * secsize) { nt_port_name name; nt_unicode_string str; __ntapi->tt_port_name_from_attr( &name,attr); str.strlen = ((size_t)&(((nt_port_name *)0)->null_termination)); str.maxlen = 0; str.buffer = &name.base_named_objects[0]; return __ipc_connect_by_attr( hport,attr,&str,0, hsection,secaddr,secsize,0); } int32_t __stdcall __ntapi_ipc_connect_section_by_name( __out void ** hport, __in nt_port_name * name, __out void ** hsection, __out void ** secaddr, __out size_t * secsize) { int32_t status; nt_port_attr attr; nt_unicode_string str; if ((status = __ntapi->tt_port_attr_from_name(&attr,name))) return status; str.strlen = ((size_t)&(((nt_port_name *)0)->null_termination)); str.maxlen = 0; str.buffer = &name->base_named_objects[0]; return __ipc_connect_by_attr( hport,&attr,&str,0, hsection,secaddr,secsize,0); } int32_t __stdcall __ntapi_ipc_connect_section_by_symlink( __out void ** hport, __in void * hsymlink, __out void ** hsection, __out void ** secaddr, __out size_t * secsize) { int32_t status; nt_port_attr attr; nt_port_name * name; size_t namelen; uintptr_t buffer[512/sizeof(uintptr_t)]; nt_unicode_string * str; str = (nt_unicode_string *)buffer; str->strlen = 0; str->maxlen = sizeof(buffer) - sizeof(nt_unicode_string); str->buffer = (wchar16_t *)&str[1]; if ((status = __ntapi->zw_query_symbolic_link_object( hsymlink,str,&namelen))) return status; if (str->strlen != ((size_t)&(((nt_port_name *)0)->null_termination))) return NT_STATUS_INVALID_PORT_ATTRIBUTES; name = (nt_port_name *)str->buffer; if ((status = __ntapi->tt_port_attr_from_name(&attr,name))) return status; return __ipc_connect_by_attr( hport,&attr,str,0, hsection,secaddr,secsize,0); } int32_t __stdcall __ntapi_ipc_connect_section_by_port( __in void * hconn, __in nt_port_attr * attr, __out void ** hsection, __out void ** secaddr, __out size_t * secsize) { return __ipc_connect_by_attr( &(void *){0},attr,0,hconn, hsection,secaddr,secsize,0); } int32_t __stdcall __ntapi_ipc_connect_by_attr( __out void ** hport, __in nt_port_attr * attr) { return __ntapi_ipc_connect_section_by_attr( hport,attr, &(void *){0}, &(void *){0}, &(size_t){0}); } int32_t __stdcall __ntapi_ipc_connect_by_name( __out void ** hport, __in nt_port_name * name) { return __ntapi_ipc_connect_section_by_name( hport,name, &(void *){0}, &(void *){0}, &(size_t){0}); } int32_t __stdcall __ntapi_ipc_connect_by_symlink( __out void ** hport, __in void * hsymlink) { return __ntapi_ipc_connect_section_by_symlink( hport,hsymlink, &(void *){0}, &(void *){0}, &(size_t){0}); } int32_t __stdcall __ntapi_ipc_connect_by_port( __in void * hconn, __in nt_port_attr * attr) { return __ntapi_ipc_connect_section_by_port( hconn,attr, &(void *){0}, &(void *){0}, &(size_t){0}); } int __ntapi_ipc_page_alloc( struct dalist_ex * dlist, void ** addr, size_t * alloc_size) { int32_t status; size_t size; ntapi_internals * __internals; __internals = __ntapi_internals(); size = __NT_INTERNAL_PAGE_SIZE; if (__internals->ipc_page == __NT_IPC_PAGES) return NT_STATUS_QUOTA_EXCEEDED; if ((status = __ntapi->zw_allocate_virtual_memory( NT_CURRENT_PROCESS_HANDLE, addr,0,&size, NT_MEM_COMMIT, NT_PAGE_READWRITE))) return status; dalist_deposit_memory_block( dlist,*addr,size); __internals->ipc_pages[__internals->ipc_page++] = *addr; *alloc_size = size; return 0; } int32_t __stdcall __ntapi_ipc_get_port_by_attr( __out void ** hport, __in nt_port_attr * attr) { return __ipc_connect_by_attr( hport,attr,0,0, &(void *){0}, &(void *){0}, &(size_t){0}, 1); } int32_t __stdcall __ntapi_ipc_get_port_section_by_attr( __out void ** hport, __in nt_port_attr * attr, __out void ** hsection, __out void ** section_addr, __out size_t * section_size) { return __ipc_connect_by_attr( hport,attr,0,0, hsection, section_addr, section_size, 1); } int32_t __stdcall __ntapi_ipc_init_section_by_port( __in void * hconn, __out void ** hsection, __out void ** secaddr, __out size_t * secsize) { int32_t status; nt_tty_section_info secinfo; nt_iosb iosb; struct dalist_node_ex * node; nt_ipc_conn * ipc; void * addr; size_t size; ntapi_internals * __internals; /* init */ __internals = __ntapi_internals(); /* lock */ if (at_locked_cas(&__internals->hlock,0,1)) return NT_STATUS_RESOURCE_NOT_OWNED; /* connection node */ if ((status = dalist_get_node_by_key( &__internals->ipc_conns, &node,(uintptr_t)hconn, DALIST_NODE_TYPE_EXISTING, &(uintptr_t){0}))) return __ipc_connect_return( &__internals->hlock, NT_STATUS_INTERNAL_ERROR); else if (!node) return __ipc_connect_return( &__internals->hlock, NT_STATUS_NOT_FOUND); else ipc = (nt_ipc_conn *)&node->dblock; /* already mapped? */ if (ipc->secaddr) return __ipc_connect_return( &__internals->hlock, NT_STATUS_SUCCESS); /* section info */ if ((status = __ntapi->tty_query_information_section( hconn,&iosb,&secinfo,0))) return __ipc_connect_return( &__internals->hlock, status); /* map section */ addr = 0; size = 0; if ((status = __ntapi->zw_map_view_of_section( secinfo.section, NT_CURRENT_PROCESS_HANDLE, &addr,0, secinfo.section_size,0,&size, NT_VIEW_UNMAP,0, NT_PAGE_READWRITE))) return __ipc_connect_return( &__internals->hlock, status); /* update */ *hsection = secinfo.section; *secaddr = addr; *secsize = size; /* all done */ return __ipc_connect_return( &__internals->hlock, NT_STATUS_SUCCESS); } int32_t __stdcall __ntapi_ipc_disconnect_unmap_section_by_port( __in void * hconn) { int32_t status; struct dalist_node_ex * node; nt_ipc_conn * ipc; ntapi_internals * __internals; /* init */ __internals = __ntapi_internals(); /* lock */ if (at_locked_cas(&__internals->hlock,0,1)) return NT_STATUS_RESOURCE_NOT_OWNED; /* connection node */ if ((status = dalist_get_node_by_key( &__internals->ipc_conns, &node,(uintptr_t)hconn, DALIST_NODE_TYPE_EXISTING, &(uintptr_t){0}))) return __ipc_connect_return( &__internals->hlock, NT_STATUS_INTERNAL_ERROR); else if (!node) return __ipc_connect_return( &__internals->hlock, NT_STATUS_NOT_FOUND); else ipc = (nt_ipc_conn *)&node->dblock; /* unmap section */ if (ipc->secaddr) __ntapi->zw_unmap_view_of_section( NT_CURRENT_PROCESS_HANDLE, ipc->secaddr); /* close section */ if (ipc->hsection) __ntapi->zw_close(ipc->hsection); /* disconnect */ __ntapi->zw_close(hconn); /* remove node */ dalist_discard_node(&__internals->ipc_conns,node); return __ipc_connect_return( &__internals->hlock, NT_STATUS_SUCCESS); }