diff options
Diffstat (limited to 'src/process')
-rw-r--r-- | src/process/ntapi_tt_spawn_native_process.c | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/src/process/ntapi_tt_spawn_native_process.c b/src/process/ntapi_tt_spawn_native_process.c new file mode 100644 index 0000000..f072426 --- /dev/null +++ b/src/process/ntapi_tt_spawn_native_process.c @@ -0,0 +1,319 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013--2016 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include <psxtypes/psxtypes.h> +#include <pemagine/pemagine.h> +#include <ntapi/nt_status.h> +#include <ntapi/nt_object.h> +#include <ntapi/nt_thread.h> +#include <ntapi/nt_process.h> +#include <ntapi/nt_string.h> +#include <ntapi/ntapi.h> +#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)); + + /* 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); + + /* 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 = cparams.pbi.unique_process_id; + + if ((status = __ntapi->tty_client_session_set(0,&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); +} |