| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int32_t __stdcall __tt_spawn_return( |
| nt_runtime_data_block * rtblock, |
| void * hprocess, |
| void * hthread, |
| int32_t status) |
| { |
| nt_runtime_data * rtdata; |
| |
| rtdata = (nt_runtime_data *)rtblock->addr; |
| |
| if (hprocess) { |
| __ntapi->zw_terminate_process( |
| hprocess,status); |
| |
| __ntapi->zw_close(hprocess); |
| __ntapi->zw_close(hthread); |
| } |
| |
| if (rtdata->hready) |
| __ntapi->zw_close( |
| rtdata->hready); |
| |
| __ntapi->zw_free_virtual_memory( |
| NT_CURRENT_PROCESS_HANDLE, |
| &rtblock->addr, |
| &rtblock->size, |
| NT_MEM_RELEASE); |
| |
| return status; |
| } |
| |
| int32_t __stdcall __ntapi_tt_spawn_native_process(nt_spawn_process_params * sparams) |
| { |
| int32_t status; |
| nt_create_process_params cparams; |
| nt_tty_session_info session; |
| nt_runtime_data_block rtblock; |
| nt_runtime_data_block crtblock; |
| nt_runtime_data * rtctx; |
| nt_runtime_data * rdata; |
| nt_unicode_string * imgname; |
| nt_peb * peb; |
| char * patharg; |
| void * hat; |
| void * hfile; |
| char ** parg; |
| char ** rargv; |
| char ** renvp; |
| wchar16_t ** pwarg; |
| wchar16_t * wch; |
| void * hchild[2]; |
| wchar16_t * imgbuf; |
| uint32_t fsuspended; |
| size_t buflen; |
| size_t written; |
| |
| |
| rtctx = sparams->rtctx; |
| |
| |
| if (!sparams->himage && !sparams->patharg) |
| return NT_STATUS_OBJECT_PATH_INVALID; |
| |
| if (rtctx->argc || rtctx->argv || rtctx->envc || rtctx->envp) |
| return NT_STATUS_INVALID_PARAMETER; |
| |
| if (rtctx->hready || rtctx->hsession) |
| return NT_STATUS_INVALID_PARAMETER_MIX; |
| |
| if (!(peb = (nt_peb *)pe_get_peb_address())) |
| return NT_STATUS_INTERNAL_ERROR; |
| |
| if (!peb->process_params) |
| return NT_STATUS_INTERNAL_ERROR; |
| |
| |
| hat = (sparams->hroot && (sparams->argv[0][0] == '/')) |
| ? sparams->hroot |
| : rtctx->hcwd |
| ? rtctx->hcwd |
| : peb->process_params->cwd_handle; |
| |
| |
| patharg = sparams->patharg |
| ? (sparams->patharg[0] == '/') |
| ? (sparams->patharg[1] == '?') |
| ? &sparams->patharg[0] |
| : &sparams->patharg[1] |
| : &sparams->patharg[0] |
| : 0; |
| |
| |
| rtblock.addr = 0; |
| rtblock.size = 0x40000; |
| rtblock.remote_addr = 0; |
| rtblock.remote_size = 0; |
| rtblock.flags = 0; |
| |
| if ((status = __ntapi->zw_allocate_virtual_memory( |
| NT_CURRENT_PROCESS_HANDLE, |
| &rtblock.addr,0, |
| &rtblock.size, |
| NT_MEM_COMMIT, |
| NT_PAGE_READWRITE))) |
| return status; |
| |
| __ntapi->tt_aligned_block_memset( |
| rtblock.addr,0,rtblock.size); |
| |
| __ntapi->tt_aligned_block_memcpy( |
| (uintptr_t *)(rdata = (nt_runtime_data *)rtblock.addr), |
| (const uintptr_t *)rtctx, |
| sizeof(*rtctx)); |
| |
| |
| if (!(__ntapi->tt_guid_compare(&rdata->abi,&(nt_guid)NT_PROCESS_GUID_UNSPEC))) |
| __ntapi->tt_guid_copy( |
| &rdata->abi, |
| &(nt_guid)NT_PROCESS_GUID_RTDATA); |
| |
| |
| imgbuf = (wchar16_t *)rtblock.addr; |
| imgbuf += 0x30000 / sizeof(*imgbuf); |
| |
| |
| if (sparams->himage) |
| hfile = sparams->himage; |
| else if ((status = __ntapi_tt_open_file_utf8( |
| &hfile,hat,patharg,1, |
| imgbuf,0x2000))) |
| return status; |
| |
| |
| if ((status = __ntapi->zw_query_object( |
| hfile, |
| NT_OBJECT_NAME_INFORMATION, |
| imgbuf,0x10000, |
| &(uint32_t){0}))) |
| return __tt_spawn_return( |
| &rtblock,0,0,status); |
| |
| imgname = (nt_unicode_string *)imgbuf; |
| |
| |
| buflen = rtblock.size; |
| buflen -= sizeof(*rdata); |
| |
| if ((status = __ntapi->tt_array_copy_utf8( |
| &rdata->argc, |
| (const char **)sparams->argv, |
| (const char **)sparams->envp, |
| sparams->interp, |
| sparams->optarg, |
| sparams->script, |
| rtblock.addr, |
| rdata->buffer, |
| buflen,&written))) |
| return __tt_spawn_return( |
| &rtblock,0,0,status); |
| |
| rdata->argv = (char **)&((nt_runtime_data *)0)->buffer; |
| rdata->envp = rdata->argv + rdata->argc + 1; |
| |
| rdata->wargv = (wchar16_t **)rdata->buffer; |
| rdata->wargv += written / sizeof(wchar16_t **) + 1; |
| rdata->wenvp = rdata->wargv + rdata->argc + 1; |
| |
| rargv = rdata->argv + ((uintptr_t)rtblock.addr / sizeof(char *)); |
| renvp = rdata->envp + ((uintptr_t)rtblock.addr / sizeof(char *)); |
| |
| for (rdata->envc=0, parg=sparams->envp; *parg; parg++) |
| rdata->envc++; |
| |
| pwarg = rdata->wenvp + rdata->envc + 1; |
| wch = (wchar16_t *)pwarg; |
| |
| if ((written == (uintptr_t)wch - (uintptr_t)rdata) > rtblock.size) |
| return __tt_spawn_return( |
| &rtblock,0,0,NT_STATUS_BUFFER_TOO_SMALL); |
| |
| buflen = rtblock.size; |
| buflen -= written; |
| |
| if ((status = __ntapi->tt_array_convert_utf8_to_utf16( |
| rargv, |
| rdata->wargv, |
| rdata,wch, |
| buflen,&written))) |
| return __tt_spawn_return( |
| &rtblock,0,0,status); |
| |
| wch += written/sizeof(wchar16_t); |
| buflen -= written; |
| |
| if ((status = __ntapi->tt_array_convert_utf8_to_utf16( |
| renvp, |
| rdata->wenvp, |
| rdata,wch, |
| buflen,&written))) |
| return __tt_spawn_return( |
| &rtblock,0,0,status); |
| |
| rdata->wargv -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *); |
| rdata->wenvp -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *); |
| |
| wch += written/sizeof(wchar16_t); |
| buflen -= written; |
| |
| if (buflen < 0x10000) |
| return __tt_spawn_return( |
| &rtblock,0,0,NT_STATUS_BUFFER_TOO_SMALL); |
| |
| |
| if (sparams->hready) { |
| if ((status = __ntapi->zw_duplicate_object( |
| NT_CURRENT_PROCESS_HANDLE, |
| sparams->hready, |
| NT_CURRENT_PROCESS_HANDLE, |
| &rdata->hready, |
| 0,0, |
| NT_DUPLICATE_SAME_ACCESS|NT_DUPLICATE_SAME_ATTRIBUTES))) |
| return __tt_spawn_return( |
| &rtblock,0,0,status); |
| } else { |
| if ((status = __ntapi->tt_create_inheritable_event( |
| &rdata->hready, |
| NT_NOTIFICATION_EVENT, |
| NT_EVENT_NOT_SIGNALED))) |
| return __tt_spawn_return( |
| &rtblock,0,0,status); |
| } |
| |
| |
| if (sparams->processflags & NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED) |
| fsuspended = NT_CREATE_SUSPENDED; |
| |
| else if (sparams->threadflags & NT_CREATE_SUSPENDED) |
| fsuspended = NT_CREATE_SUSPENDED; |
| |
| |
| __ntapi->tt_aligned_block_memset( |
| &cparams,0,sizeof(cparams)); |
| |
| __ntapi->tt_generic_memcpy( |
| &crtblock,&rtblock,sizeof(rtblock)); |
| |
| cparams.image_name = imgname->buffer; |
| cparams.creation_flags_process = NT_PROCESS_CREATE_FLAGS_INHERIT_HANDLES; |
| cparams.creation_flags_thread = NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED; |
| |
| crtblock.size = (size_t)wch - (size_t)rdata; |
| crtblock.size += 0xFFFF; |
| crtblock.size |= 0xFFFF; |
| crtblock.size ^= 0xFFFF; |
| cparams.rtblock = &crtblock; |
| |
| |
| if ((status = __ntapi->tt_create_native_process(&cparams))) |
| return __tt_spawn_return( |
| &rtblock,0,0,status); |
| |
| |
| if (!sparams->himage) |
| __ntapi->zw_close(hfile); |
| |
| |
| if (sparams->hsession) { |
| if ((status = __ntapi->tty_client_process_register( |
| sparams->hsession, |
| cparams.pbi.unique_process_id, |
| 0,NT_TTY_INHERIT_HANDLES,0))) |
| return __tt_spawn_return( |
| &rtblock, |
| cparams.hprocess, |
| cparams.hthread, |
| status); |
| |
| session.pid = rtctx->alt_cid_self.pid; |
| session.pgid = rtctx->alt_cid_self.pgid; |
| session.sid = rtctx->alt_cid_self.sid; |
| session.syspid = (uint32_t)cparams.pbi.unique_process_id; |
| |
| if ((status = __ntapi->tty_client_session_set( |
| sparams->hsession, |
| &session))) |
| return __tt_spawn_return( |
| &rtblock, |
| cparams.hprocess, |
| cparams.hthread, |
| status); |
| } |
| |
| |
| sparams->hprocess = cparams.hprocess; |
| sparams->hthread = cparams.hthread; |
| sparams->rdata = crtblock.remote_addr; |
| |
| sparams->cid.process_id = cparams.pbi.unique_process_id; |
| sparams->cid.thread_id = cparams.cid.thread_id; |
| |
| __ntapi->tt_generic_memcpy( |
| &sparams->pbi, |
| &cparams.pbi, |
| sizeof(nt_pbi)); |
| |
| |
| if (fsuspended) |
| return __tt_spawn_return( |
| &rtblock,0,0,NT_STATUS_SUCCESS); |
| |
| |
| if ((status = __ntapi->zw_resume_thread(cparams.hthread,0))) |
| return __tt_spawn_return( |
| &rtblock, |
| cparams.hprocess, |
| cparams.hthread, |
| status); |
| |
| |
| hchild[1] = cparams.hprocess; |
| hchild[0] = rdata->hready; |
| |
| __ntapi->zw_wait_for_multiple_objects( |
| 2,hchild, |
| NT_WAIT_ANY, |
| NT_SYNC_NON_ALERTABLE, |
| sparams->timeout); |
| |
| if ((status = __ntapi->zw_query_event( |
| rdata->hready, |
| NT_EVENT_BASIC_INFORMATION, |
| &sparams->eready, |
| sizeof(sparams->eready), |
| &(size_t){0}))) |
| return __tt_spawn_return( |
| &rtblock, |
| cparams.hprocess, |
| cparams.hthread, |
| status); |
| |
| |
| return __tt_spawn_return( |
| &rtblock,0,0,NT_STATUS_SUCCESS); |
| } |