diff --git a/include/ntapi/nt_process.h b/include/ntapi/nt_process.h index 092a95e..0443b3f 100644 --- a/include/ntapi/nt_process.h +++ b/include/ntapi/nt_process.h @@ -6,6 +6,7 @@ #include "nt_object.h" #include "nt_memory.h" #include "nt_section.h" +#include "nt_sync.h" typedef enum _nt_process_info_class { NT_PROCESS_BASIC_INFORMATION, @@ -533,6 +534,29 @@ typedef struct _nt_create_process_params { } nt_create_process_params; +typedef struct _nt_spawn_process_params { + __out void * hprocess; + __out void * hthread; + __out void * rdata; + __out nt_client_id cid; + __out nt_process_basic_information pbi; + __out nt_event_basic_information eready; + __in nt_runtime_data * rtctx; + __in void * hsession; + __in void * htoken; + __in void * himage; + __in char * patharg; + __in const char * image; + __in const char * interpreter; + __in const char * optarg; + __in char ** argv; + __in char ** envp; + __in void * hready; + __in nt_timeout * timeout; + __in int fsuspended; +} nt_spawn_process_params; + + typedef int32_t __stdcall ntapi_zw_create_process( __out void ** hprocess, __in uint32_t desired_access, @@ -659,6 +683,8 @@ typedef int32_t __stdcall ntapi_tt_create_remote_process_params( typedef int32_t __stdcall ntapi_tt_create_native_process( __out nt_create_process_params * params); +typedef int32_t __stdcall ntapi_tt_spawn_native_process( + __in_out nt_spawn_process_params * sparams); typedef int32_t __stdcall ntapi_tt_get_runtime_data( __out nt_runtime_data ** pdata, diff --git a/include/ntapi/ntapi.h b/include/ntapi/ntapi.h index b596f32..21af579 100644 --- a/include/ntapi/ntapi.h +++ b/include/ntapi/ntapi.h @@ -448,6 +448,7 @@ typedef struct _ntapi_vtbl { ntapi_tt_fork * tt_fork; ntapi_tt_create_remote_process_params * tt_create_remote_process_params; ntapi_tt_create_native_process * tt_create_native_process; + ntapi_tt_spawn_native_process * tt_spawn_native_process; ntapi_tt_get_runtime_data * tt_get_runtime_data; ntapi_tt_init_runtime_data * tt_init_runtime_data; ntapi_tt_update_runtime_data * tt_update_runtime_data; diff --git a/project/common.mk b/project/common.mk index 09f23bf..fe3a444 100644 --- a/project/common.mk +++ b/project/common.mk @@ -38,6 +38,7 @@ COMMON_SRCS = \ src/process/ntapi_tt_get_runtime_data.c \ src/process/ntapi_tt_init_runtime_data.c \ src/process/ntapi_tt_map_image_as_data.c \ + src/process/ntapi_tt_spawn_native_process.c \ src/process/tt_fork_v1.c \ src/pty/ntapi_pty_cancel.c \ src/pty/ntapi_pty_fd.c \ diff --git a/src/internal/ntapi.c b/src/internal/ntapi.c index de44bbf..6559b5b 100644 --- a/src/internal/ntapi.c +++ b/src/internal/ntapi.c @@ -212,6 +212,7 @@ static int32_t __fastcall __ntapi_init_once(ntapi_vtbl ** pvtbl) /* nt_process.h */ __ntapi->tt_create_remote_process_params = __ntapi_tt_create_remote_process_params; + __ntapi->tt_spawn_native_process = __ntapi_tt_spawn_native_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; diff --git a/src/internal/ntapi_fnapi.h b/src/internal/ntapi_fnapi.h index 723576b..6a1f14c 100644 --- a/src/internal/ntapi_fnapi.h +++ b/src/internal/ntapi_fnapi.h @@ -100,6 +100,7 @@ ntapi_tt_create_remote_process_params __ntapi_tt_create_remote_process_params; ntapi_tt_create_remote_runtime_data __ntapi_tt_create_remote_runtime_data; ntapi_tt_create_native_process __ntapi_tt_create_native_process_v1; ntapi_tt_create_native_process __ntapi_tt_create_native_process_v2; +ntapi_tt_spawn_native_process __ntapi_tt_spawn_native_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; 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 +#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)); + + /* 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); +}