/********************************************************/ /* 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 "ntapi_impl.h" 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]; uint32_t written; wchar16_t * imgbuf; /* rtctx (convenience) */ rtctx = sparams->rtctx; /* validation */ 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 */ hat = (rtctx->hroot && (sparams->argv[0][0] == '/')) ? rtctx->hroot : rtctx->hcwd ? rtctx->hcwd : peb->process_params->cwd_handle; /* patharg */ patharg = (sparams->patharg[0] == '/') ? (sparams->patharg[1] == '?') ? &sparams->patharg[0] : &sparams->patharg[1] : &sparams->patharg[0]; /* rtblock, rdata */ rtblock.addr = 0; rtblock.size = 0x20000; 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)); /* abi */ 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 */ imgbuf = (wchar16_t *)rtblock.addr; imgbuf += 0x10000 / sizeof(*imgbuf); /* hfile */ if (sparams->himage) hfile = sparams->himage; else if ((status = __ntapi_tt_open_file_utf8( &hfile,hat,patharg,1, imgbuf,0x2000))) return status; /* imgname */ if ((status = __ntapi->zw_query_object( hfile, NT_OBJECT_NAME_INFORMATION, imgbuf,0x10000,&written))) return __tt_spawn_return( &rtblock,0,0,status); imgname = (nt_unicode_string *)imgbuf; /* argv, envp */ if ((status = __ntapi->tt_array_copy_utf8( &rdata->argc, (const char **)sparams->argv, (const char **)sparams->envp, sparams->image, sparams->interpreter, sparams->optarg, rtblock.addr, rdata->buffer, rtblock.size - sizeof(*rdata), &rtblock.remote_size))) 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 + (rtblock.remote_size / sizeof(uintptr_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 ((status = __ntapi->tt_array_convert_utf8_to_utf16( rargv, rdata->wargv, rdata, wch, rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer), &rtblock.remote_size))) return __tt_spawn_return( &rtblock,0,0,status); wch += rtblock.remote_size/sizeof(wchar16_t); if ((status = __ntapi->tt_array_convert_utf8_to_utf16( renvp, rdata->wenvp, rdata, wch, rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer), &rtblock.remote_size))) 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 *); /* session */ 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); } /* cparams */ __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 = 0x10000; cparams.rtblock = &crtblock; /* hoppla */ if ((status = __ntapi->tt_create_native_process(&cparams))) return __tt_spawn_return( &rtblock,0,0,status); /* tidy up */ if (!sparams->himage) __ntapi->zw_close(hfile); /* tty session (optional) */ 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); } /* output */ 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)); /* create suspended? */ if (sparams->fsuspended) return __tt_spawn_return( &rtblock,0,0,NT_STATUS_SUCCESS); /* tada */ if ((status = __ntapi->zw_resume_thread(cparams.hthread,0))) return __tt_spawn_return( &rtblock, cparams.hprocess, cparams.hthread, status); /* hready */ 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); /* all done */ return __tt_spawn_return( &rtblock,0,0,NT_STATUS_SUCCESS); }