/********************************************************/ /* 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ntapi_impl.h" #include "ntapi_hash_table.h" /* simplified once mechanism for free-standing applications */ typedef int32_t __fastcall __ntapi_init_fn(ntapi_vtbl ** pvtbl); static __ntapi_init_fn __ntapi_init_once; static __ntapi_init_fn __ntapi_init_pending; static __ntapi_init_fn __ntapi_init_completed; static intptr_t __ntapi_init_idx = 0; static __ntapi_init_fn * __ntapi_init_vtbl[3] = { __ntapi_init_once, __ntapi_init_pending, __ntapi_init_completed}; /* accessor */ ntapi_vtbl ___ntapi; ntapi_vtbl ___ntapi_shadow; /* .bss */ static __ntapi_img_sec_bss __ntapi_img_bss; /* .rdata */ static union __ntapi_img_rdata __ntapi_rdata = {{ {__NTAPI_HASH_TABLE}, /* __ntapi_import_table */ 0, /* __ntapi */ { /* __session_name */ {0},0,{0}, {0,{0},0}, {{0},0,{0},0,{0},0,{0},0,{0},0,{0}}, 0}, 0}}; #define internals __ntapi_rdata.img_sec_data.__internals #define import_table __ntapi_rdata.img_sec_data.__ntapi_import_table static int32_t __fastcall __ntapi_init_once(ntapi_vtbl ** pvtbl) { int32_t status; void * hntdll; size_t block_size; size_t buf[64]; nt_oa oa; nt_cid cid; ntapi_zw_allocate_virtual_memory * pfn_zw_allocate_virtual_memory; char fname_allocate_virtual_memory[] = "ZwAllocateVirtualMemory"; /* once */ at_locked_inc(&__ntapi_init_idx); /* pvtbl */ if (!(pvtbl)) return NT_STATUS_INVALID_PARAMETER; else *pvtbl = (ntapi_vtbl *)0; /* ntdll */ if (!(hntdll = pe_get_ntdll_module_handle())) return NT_STATUS_DLL_INIT_FAILED; pfn_zw_allocate_virtual_memory = (ntapi_zw_allocate_virtual_memory *) pe_get_procedure_address( hntdll, fname_allocate_virtual_memory); if (!pfn_zw_allocate_virtual_memory) return NT_STATUS_DLL_INIT_FAILED; /* ntapi_internals: alloc */ block_size = sizeof(ntapi_internals); status = pfn_zw_allocate_virtual_memory( NT_CURRENT_PROCESS_HANDLE, (void **)&internals, 0, &block_size, NT_MEM_COMMIT, NT_PAGE_READWRITE); if (status != NT_STATUS_SUCCESS) return status; /* ipc connection list */ if ((status = dalist_init_ex( &internals->ipc_conns, sizeof(nt_ipc_conn), NT_ALLOCATION_GRANULARITY, __ntapi_ipc_page_alloc, DALIST_MEMFN_CUSTOM))) return status; dalist_deposit_memory_block( &internals->ipc_conns, &__ntapi_img_bss.ipc_buffer, __NT_BSS_IPC_BUFFER_SIZE); /* hashed import table */ __ntapi_tt_populate_hashed_import_table( pe_get_ntdll_module_handle(), __ntapi, import_table, __NT_IMPORTED_SYMBOLS_ARRAY_SIZE); /* alternate implementation */ __ntapi->rtl_init_unicode_string = __ntapi_tt_init_unicode_string_from_utf16; __ntapi->strlen = __ntapi_tt_string_null_offset_multibyte; __ntapi->wcslen = __ntapi_tt_wcslen; /* extension functions */ /* nt_object.h */ __ntapi->tt_open_ipc_object_directory = __ntapi_tt_open_ipc_object_directory; __ntapi->tt_create_ipc_object_directory_entry = __ntapi_tt_create_ipc_object_directory_entry; __ntapi->tt_create_keyed_object_directory = __ntapi_tt_create_keyed_object_directory; __ntapi->tt_open_keyed_object_directory = __ntapi_tt_open_keyed_object_directory; __ntapi->tt_create_keyed_object_directory_entry = __ntapi_tt_create_keyed_object_directory_entry; __ntapi->tt_sid_copy = __ntapi_tt_sid_copy; /* nt_crc32.h */ __ntapi->tt_buffer_crc32 = __ntapi_tt_buffer_crc32; __ntapi->tt_mbstr_crc32 = __ntapi_tt_mbstr_crc32; __ntapi->tt_crc32_table = __ntapi_tt_crc32_table; /* nt_crc64.h */ __ntapi->tt_buffer_crc64 = __ntapi_tt_buffer_crc64; __ntapi->tt_mbstr_crc64 = __ntapi_tt_mbstr_crc64; __ntapi->tt_crc64_table = __ntapi_tt_crc64_table; /* nt_file.h */ __ntapi->tt_get_file_handle_type = __ntapi_tt_get_file_handle_type; __ntapi->tt_open_logical_parent_directory = __ntapi_tt_open_logical_parent_directory; __ntapi->tt_open_physical_parent_directory = __ntapi_tt_open_physical_parent_directory; /* nt_ipc.h */ __ntapi->ipc_connect_by_attr = __ntapi_ipc_connect_by_attr; __ntapi->ipc_connect_by_name = __ntapi_ipc_connect_by_name; __ntapi->ipc_connect_by_symlink = __ntapi_ipc_connect_by_symlink; __ntapi->ipc_connect_by_port = __ntapi_ipc_connect_by_port; __ntapi->ipc_connect_section_by_attr = __ntapi_ipc_connect_section_by_attr; __ntapi->ipc_connect_section_by_name = __ntapi_ipc_connect_section_by_name; __ntapi->ipc_connect_section_by_symlink = __ntapi_ipc_connect_section_by_symlink; __ntapi->ipc_connect_section_by_port = __ntapi_ipc_connect_section_by_port; __ntapi->ipc_get_port_by_attr = __ntapi_ipc_get_port_by_attr; __ntapi->ipc_get_port_section_by_attr = __ntapi_ipc_get_port_section_by_attr; __ntapi->ipc_init_section_by_port = __ntapi_ipc_init_section_by_port; __ntapi->ipc_disconnect_unmap_section_by_port = __ntapi_ipc_disconnect_unmap_section_by_port; /* nt_sem.h */ __ntapi->sem_create = __ntapi_sem_create; __ntapi->sem_open = __ntapi_sem_open; __ntapi->sem_fcntl = __ntapi_sem_fcntl; __ntapi->sem_ioctl = __ntapi_sem_ioctl; __ntapi->sem_query = __ntapi_sem_query; __ntapi->sem_set = __ntapi_sem_set; __ntapi->sem_cancel = __ntapi_sem_cancel; __ntapi->sem_free = __ntapi_sem_free; /* nt_msq.h */ __ntapi->msq_create = __ntapi_msq_create; __ntapi->msq_open = __ntapi_msq_open; __ntapi->msq_send = __ntapi_msq_send; __ntapi->msq_recv = __ntapi_msq_recv; __ntapi->msq_fcntl = __ntapi_msq_fcntl; __ntapi->msq_ioctl = __ntapi_msq_ioctl; __ntapi->msq_query = __ntapi_msq_query; __ntapi->msq_set = __ntapi_msq_set; __ntapi->msq_cancel = __ntapi_msq_cancel; __ntapi->msq_free = __ntapi_msq_free; /* nt_ldr.h */ __ntapi->ldr_load_system_dll = __ntapi_ldr_load_system_dll; __ntapi->ldr_create_state_snapshot = __ntapi_ldr_create_state_snapshot; __ntapi->ldr_revert_state_to_snapshot = __ntapi_ldr_revert_state_to_snapshot; /* nt_string.h */ __ntapi->tt_string_null_offset_multibyte = __ntapi_tt_string_null_offset_multibyte; __ntapi->tt_string_null_offset_short = __ntapi_tt_string_null_offset_short; __ntapi->tt_string_null_offset_dword = __ntapi_tt_string_null_offset_dword; __ntapi->tt_string_null_offset_qword = __ntapi_tt_string_null_offset_qword; __ntapi->tt_string_null_offset_ptrsize = __ntapi_tt_string_null_offset_ptrsize; __ntapi->tt_strcmp_multibyte = __ntapi_tt_strcmp_multibyte; __ntapi->tt_strcmp_utf16 = __ntapi_tt_strcmp_utf16; __ntapi->tt_strncmp_multibyte = __ntapi_tt_strncmp_multibyte; __ntapi->tt_strncmp_utf16 = __ntapi_tt_strncmp_utf16; __ntapi->tt_aligned_block_memset = __ntapi_tt_aligned_block_memset; __ntapi->tt_aligned_block_memcpy = __ntapi_tt_aligned_block_memcpy; __ntapi->tt_memcpy_utf16 = __ntapi_tt_memcpy_utf16; __ntapi->tt_aligned_memcpy_utf16 = __ntapi_tt_aligned_memcpy_utf16; __ntapi->tt_generic_memset = __ntapi_tt_generic_memset; __ntapi->tt_generic_memcpy = __ntapi_tt_generic_memcpy; __ntapi->tt_uint16_to_hex_utf16 = __ntapi_tt_uint16_to_hex_utf16; __ntapi->tt_uint32_to_hex_utf16 = __ntapi_tt_uint32_to_hex_utf16; __ntapi->tt_uint64_to_hex_utf16 = __ntapi_tt_uint64_to_hex_utf16; __ntapi->tt_uintptr_to_hex_utf16 = __ntapi_tt_uintptr_to_hex_utf16; __ntapi->tt_hex_utf16_to_uint16 = __ntapi_tt_hex_utf16_to_uint16; __ntapi->tt_hex_utf16_to_uint32 = __ntapi_tt_hex_utf16_to_uint32; __ntapi->tt_hex_utf16_to_uint64 = __ntapi_tt_hex_utf16_to_uint64; __ntapi->tt_hex_utf16_to_uintptr = __ntapi_tt_hex_utf16_to_uintptr; __ntapi->tt_init_unicode_string_from_utf16 = __ntapi_tt_init_unicode_string_from_utf16; __ntapi->tt_uint16_to_hex_utf8 = __ntapi_tt_uint16_to_hex_utf8; __ntapi->tt_uint32_to_hex_utf8 = __ntapi_tt_uint32_to_hex_utf8; __ntapi->tt_uint64_to_hex_utf8 = __ntapi_tt_uint64_to_hex_utf8; __ntapi->tt_uintptr_to_hex_utf8 = __ntapi_tt_uintptr_to_hex_utf8; /* nt_guid.h */ __ntapi->tt_guid_copy = __ntapi_tt_guid_copy; __ntapi->tt_guid_compare = __ntapi_tt_guid_compare; __ntapi->tt_guid_to_string_utf16 = __ntapi_tt_guid_to_string_utf16; __ntapi->tt_string_to_guid_utf16 = __ntapi_tt_string_to_guid_utf16; /* nt_sysinfo.h */ __ntapi->tt_get_system_directory_native_path = __ntapi_tt_get_system_directory_native_path; __ntapi->tt_get_system_directory_dos_path = __ntapi_tt_get_system_directory_dos_path; __ntapi->tt_get_system_directory_handle = __ntapi_tt_get_system_directory_handle; __ntapi->tt_get_system_info_snapshot = __ntapi_tt_get_system_info_snapshot; /* nt_thread.h */ __ntapi->tt_create_local_thread = __ntapi_tt_create_local_thread; __ntapi->tt_create_remote_thread = __ntapi_tt_create_remote_thread; __ntapi->tt_create_thread = __ntapi_tt_create_thread; /* nt_process.h */ __ntapi->tt_fork = __ntapi_tt_fork; __ntapi->tt_create_remote_process_params = __ntapi_tt_create_remote_process_params; __ntapi->tt_spawn_native_process = __ntapi_tt_spawn_native_process; __ntapi->tt_spawn_foreign_process = __ntapi_tt_spawn_foreign_process; __ntapi->tt_get_runtime_data = __ntapi_tt_get_runtime_data; __ntapi->tt_init_runtime_data = __ntapi_tt_init_runtime_data; __ntapi->tt_update_runtime_data = __ntapi_tt_update_runtime_data; __ntapi->tt_exec_map_image_as_data = __ntapi_tt_exec_map_image_as_data; __ntapi->tt_exec_unmap_image = __ntapi_tt_exec_unmap_image; /* nt_token.h */ __ntapi->tt_enable_token_privilege = __ntapi_tt_enable_token_privilege; __ntapi->tt_disable_token_privilege = __ntapi_tt_disable_token_privilege; /* nt_section.h */ __ntapi->tt_get_section_name = __ntapi_tt_get_section_name; /* nt_sync.h */ __ntapi->tt_create_inheritable_event = __ntapi_tt_create_inheritable_event; __ntapi->tt_create_private_event = __ntapi_tt_create_private_event; __ntapi->tt_wait_for_dummy_event = __ntapi_tt_wait_for_dummy_event; __ntapi->tt_sync_block_init = __ntapi_tt_sync_block_init; __ntapi->tt_sync_block_discard = __ntapi_tt_sync_block_discard; __ntapi->tt_sync_block_lock = __ntapi_tt_sync_block_lock; __ntapi->tt_sync_block_unlock = __ntapi_tt_sync_block_unlock; __ntapi->tt_sync_block_server_lock = __ntapi_tt_sync_block_server_lock; /* nt_port.h */ __ntapi->csr_port_handle = __ntapi_csr_port_handle; __ntapi->tt_port_guid_from_type = __ntapi_tt_port_guid_from_type; __ntapi->tt_port_type_from_guid = __ntapi_tt_port_type_from_guid; __ntapi->tt_port_generate_keys = __ntapi_tt_port_generate_keys; __ntapi->tt_port_format_keys = __ntapi_tt_port_format_keys; __ntapi->tt_port_name_from_attr = __ntapi_tt_port_name_from_attr; __ntapi->tt_port_attr_from_name = __ntapi_tt_port_attr_from_name; __ntapi->tt_port_attr_from_string = __ntapi_tt_port_attr_from_string; __ntapi->tt_port_attr_from_symlink = __ntapi_tt_port_attr_from_symlink; /* nt_argv.h */ __ntapi->tt_get_cmd_line_utf16 = __ntapi_tt_get_cmd_line_utf16; __ntapi->tt_get_peb_env_block_utf16 = __ntapi_tt_get_peb_env_block_utf16; __ntapi->tt_parse_cmd_line_args_utf16 = __ntapi_tt_parse_cmd_line_args_utf16; __ntapi->tt_get_argv_envp_utf8 = __ntapi_tt_get_argv_envp_utf8; __ntapi->tt_get_argv_envp_utf16 = __ntapi_tt_get_argv_envp_utf16; __ntapi->tt_get_env_var_meta_utf8 = __ntapi_tt_get_env_var_meta_utf8; __ntapi->tt_get_env_var_meta_utf16 = __ntapi_tt_get_env_var_meta_utf16; __ntapi->tt_array_copy_utf16 = __ntapi_tt_array_copy_utf16; __ntapi->tt_array_copy_utf8 = __ntapi_tt_array_copy_utf8; __ntapi->tt_array_convert_utf8_to_utf16 = __ntapi_tt_array_convert_utf8_to_utf16; __ntapi->tt_array_convert_utf16_to_utf8 = __ntapi_tt_array_convert_utf16_to_utf8; /* nt_blitter.h */ __ntapi->blt_alloc = __ntapi_blt_alloc; __ntapi->blt_free = __ntapi_blt_free; __ntapi->blt_acquire = __ntapi_blt_acquire; __ntapi->blt_obtain = __ntapi_blt_obtain; __ntapi->blt_possess = __ntapi_blt_possess; __ntapi->blt_release = __ntapi_blt_release; __ntapi->blt_get = __ntapi_blt_get; __ntapi->blt_set = __ntapi_blt_set; /* nt_unicode.h */ __ntapi->uc_validate_unicode_stream_utf8 = __ntapi_uc_validate_unicode_stream_utf8; __ntapi->uc_validate_unicode_stream_utf16 = __ntapi_uc_validate_unicode_stream_utf16; __ntapi->uc_get_code_point_byte_count_utf8 = __ntapi_uc_get_code_point_byte_count_utf8; __ntapi->uc_get_code_point_byte_count_utf16 = __ntapi_uc_get_code_point_byte_count_utf16; __ntapi->uc_convert_unicode_stream_utf8_to_utf16 = __ntapi_uc_convert_unicode_stream_utf8_to_utf16; __ntapi->uc_convert_unicode_stream_utf8_to_utf32 = __ntapi_uc_convert_unicode_stream_utf8_to_utf32; __ntapi->uc_convert_unicode_stream_utf16_to_utf8 = __ntapi_uc_convert_unicode_stream_utf16_to_utf8; __ntapi->uc_convert_unicode_stream_utf16_to_utf32 = __ntapi_uc_convert_unicode_stream_utf16_to_utf32; /* nt_daemon.h */ __ntapi->dsr_init = __ntapi_dsr_init; __ntapi->dsr_start = __ntapi_dsr_start; __ntapi->dsr_create_port = __ntapi_dsr_create_port; __ntapi->dsr_connect_internal_client = __ntapi_dsr_connect_internal_client; __ntapi->dsr_internal_client_connect = __ntapi_dsr_internal_client_connect; /* nt_vfd.h */ __ntapi->vfd_dev_name_init = __ntapi_vfd_dev_name_init; /* nt_tty.h */ __ntapi->tty_create_session = __ntapi_tty_create_session; __ntapi->tty_join_session = __ntapi_tty_join_session; __ntapi->tty_connect = __ntapi_tty_connect; __ntapi->tty_client_session_disconnect = __ntapi_tty_client_session_disconnect; __ntapi->tty_client_session_query = __ntapi_tty_client_session_query; __ntapi->tty_client_session_set = __ntapi_tty_client_session_set; __ntapi->tty_client_process_register = __ntapi_tty_client_process_register; __ntapi->tty_query_information_section = __ntapi_tty_query_information_section; __ntapi->tty_query_information_server = __ntapi_tty_query_information_server; __ntapi->tty_query_information_service = __ntapi_tty_query_information_service; __ntapi->tty_request_peer = __ntapi_tty_request_peer; __ntapi->tty_vms_query = __ntapi_tty_vms_query; __ntapi->tty_vms_request = __ntapi_tty_vms_request; __ntapi->pty_open = __ntapi_pty_open; __ntapi->pty_open_pair = __ntapi_pty_open_pair; __ntapi->pty_reopen = __ntapi_pty_reopen; __ntapi->pty_inherit = __ntapi_pty_inherit; __ntapi->pty_inherit_runtime_ctty = __ntapi_pty_inherit_runtime_ctty; __ntapi->pty_close = __ntapi_pty_close; __ntapi->pty_read = __ntapi_pty_read; __ntapi->pty_write = __ntapi_pty_write; __ntapi->pty_ioctl = __ntapi_pty_ioctl; __ntapi->pty_query = __ntapi_pty_query; __ntapi->pty_set = __ntapi_pty_set; __ntapi->pty_cancel = __ntapi_pty_cancel; /* nt_socket.h */ __ntapi->sc_listen = __ntapi_sc_listen; __ntapi->sc_accept = __ntapi_sc_accept; __ntapi->sc_send = __ntapi_sc_send; __ntapi->sc_recv = __ntapi_sc_recv; __ntapi->sc_shutdown = __ntapi_sc_shutdown; __ntapi->sc_server_duplicate_socket = __ntapi_sc_server_duplicate_socket; __ntapi->sc_setsockopt = __ntapi_sc_setsockopt; __ntapi->sc_getsockopt = __ntapi_sc_getsockopt; __ntapi->sc_wait = __ntapi_sc_wait; /* nt_mount.h */ __ntapi->tt_get_dos_drive_device_handle = __ntapi_tt_get_dos_drive_device_handle; __ntapi->tt_get_dos_drive_root_handle = __ntapi_tt_get_dos_drive_root_handle; __ntapi->tt_get_dos_drive_device_name = __ntapi_tt_get_dos_drive_device_name; __ntapi->tt_get_dos_drive_mount_points = __ntapi_tt_get_dos_drive_mount_points; __ntapi->tt_dev_mount_points_to_statfs = __ntapi_tt_dev_mount_points_to_statfs; __ntapi->tt_get_dos_drive_letter_from_device = __ntapi_tt_get_dos_drive_letter_from_device; /* nt_istat.h */ __ntapi->tt_istat = __ntapi_tt_istat; /* nt_stat.h */ __ntapi->tt_stat = __ntapi_tt_stat; /* nt_statfs.h */ __ntapi->tt_statfs = __ntapi_tt_statfs; /* nt_debug.h */ #ifdef __DEBUG __ntapi->dbg_write = __dbg_write; __ntapi->dbg_fn_call = __dbg_fn_call; __ntapi->dbg_msg = __dbg_msg; #endif /* OS version dependent functions */ if (__ntapi->zw_create_user_process) { __ntapi->tt_create_native_process = __ntapi_tt_create_native_process_v2; __ntapi->ipc_create_pipe = __ntapi_ipc_create_pipe_v2; __ntapi->sc_socket = __ntapi_sc_socket_v2; __ntapi->sc_bind = __ntapi_sc_bind_v2; __ntapi->sc_connect = __ntapi_sc_connect_v2; __ntapi->sc_server_accept_connection = __ntapi_sc_server_accept_connection_v2; __ntapi->sc_getsockname = __ntapi_sc_getsockname_v2; __ntapi->sc_getpeername = __ntapi_sc_getpeername_v2; } else { __ntapi->tt_create_native_process = __ntapi_tt_create_native_process_v1; __ntapi->ipc_create_pipe = __ntapi_ipc_create_pipe_v1; __ntapi->sc_socket = __ntapi_sc_socket_v1; __ntapi->sc_bind = __ntapi_sc_bind_v1; __ntapi->sc_connect = __ntapi_sc_connect_v1; __ntapi->sc_server_accept_connection = __ntapi_sc_server_accept_connection_v1; __ntapi->sc_getsockname = __ntapi_sc_getsockname_v1; __ntapi->sc_getpeername = __ntapi_sc_getpeername_v1; } /* internals */ internals->ntapi_img_sec_bss = &__ntapi_img_bss; internals->subsystem = &__ntapi_rdata.img_sec_data.__session_name; internals->tt_get_csr_port_handle_addr_by_logic = __GET_CSR_PORT_HANDLE_BY_LOGIC; internals->csr_port_handle_addr = __GET_CSR_PORT_HANDLE_BY_LOGIC(); /* shadow copy for client libraries */ __ntapi->tt_aligned_block_memcpy( (uintptr_t *)&___ntapi_shadow, (uintptr_t *)&___ntapi, sizeof(ntapi_vtbl)); /* process handle */ oa.len = sizeof(oa); oa.root_dir = 0; oa.obj_name = 0; oa.obj_attr = 0; oa.sec_desc = 0; oa.sec_qos = 0; cid.process_id = pe_get_current_process_id(); cid.thread_id = pe_get_current_thread_id(); if ((status = __ntapi->zw_open_process( &internals->hprocess, NT_PROCESS_ALL_ACCESS, &oa,&cid))) return status; /* process token */ if ((status = __ntapi->zw_open_process_token( NT_CURRENT_PROCESS_HANDLE, NT_TOKEN_ALL_ACCESS, &internals->htoken))) return status; __ntapi->tt_enable_token_privilege( internals->htoken, NT_SE_CREATE_SYMBOLIC_LINK_PRIVILEGE); /* sid */ if ((status = __ntapi->zw_query_information_token( internals->htoken, NT_TOKEN_USER, buf,sizeof(buf), &block_size))) return status; internals->sid = (nt_sid *)&internals->sid_buffer; __ntapi->tt_sid_copy( internals->sid, ((nt_sid_and_attributes *)buf)->sid); /* done */ *pvtbl = &___ntapi_shadow; at_locked_inc(&__ntapi_init_idx); return NT_STATUS_SUCCESS; } static int32_t __fastcall __ntapi_init_pending(ntapi_vtbl ** pvtbl) { (void)pvtbl; return NT_STATUS_PENDING; } static int32_t __fastcall __ntapi_init_completed(ntapi_vtbl ** pvtbl) { *pvtbl = &___ntapi_shadow; return NT_STATUS_SUCCESS; }; __ntapi_api int32_t __fastcall ntapi_init(ntapi_vtbl ** pvtbl) { return __ntapi_init_vtbl[__ntapi_init_idx](pvtbl); } ntapi_internals * __cdecl __ntapi_internals(void) { return internals; }