diff --git a/include/ntapi/nt_process.h b/include/ntapi/nt_process.h index b69aa61..2dd51cf 100644 --- a/include/ntapi/nt_process.h +++ b/include/ntapi/nt_process.h @@ -788,6 +788,9 @@ typedef int32_t __stdcall ntapi_tt_create_native_process( typedef int32_t __stdcall ntapi_tt_spawn_native_process( __in_out nt_spawn_process_params * sparams); +typedef int32_t __stdcall ntapi_tt_spawn_foreign_process( + __in_out nt_spawn_process_params * sparams); + typedef int32_t __stdcall ntapi_tt_get_runtime_data( __out nt_runtime_data ** pdata, __in wchar16_t ** argv); diff --git a/include/ntapi/ntapi.h b/include/ntapi/ntapi.h index 528ab69..d1b50be 100644 --- a/include/ntapi/ntapi.h +++ b/include/ntapi/ntapi.h @@ -482,6 +482,7 @@ typedef struct _ntapi_vtbl { 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_spawn_foreign_process * tt_spawn_foreign_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 71b7da3..405f999 100644 --- a/project/common.mk +++ b/project/common.mk @@ -49,6 +49,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_foreign_process.c \ src/process/ntapi_tt_spawn_native_process.c \ src/process/tt_fork_v1.c \ src/pty/ntapi_pty_cancel.c \ diff --git a/src/internal/ntapi.c b/src/internal/ntapi.c index 1047606..06a70fe 100644 --- a/src/internal/ntapi.c +++ b/src/internal/ntapi.c @@ -271,6 +271,7 @@ static int32_t __fastcall __ntapi_init_once(ntapi_vtbl ** pvtbl) __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; diff --git a/src/internal/ntapi_fnapi.h b/src/internal/ntapi_fnapi.h index 05ff9ab..beb4fbb 100644 --- a/src/internal/ntapi_fnapi.h +++ b/src/internal/ntapi_fnapi.h @@ -143,6 +143,7 @@ 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_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; diff --git a/src/process/ntapi_tt_spawn_foreign_process.c b/src/process/ntapi_tt_spawn_foreign_process.c new file mode 100644 index 0000000..cc9fac4 --- /dev/null +++ b/src/process/ntapi_tt_spawn_foreign_process.c @@ -0,0 +1,316 @@ +/********************************************************/ +/* 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) +{ + if (hprocess) { + __ntapi->zw_terminate_process( + hprocess,status); + + __ntapi->zw_close(hprocess); + __ntapi->zw_close(hthread); + } + + __ntapi->zw_free_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + &rtblock->addr, + &rtblock->size, + NT_MEM_RELEASE); + + return status; +} + +int32_t __stdcall __ntapi_tt_spawn_foreign_process(nt_spawn_process_params * sparams) +{ + int32_t status; + nt_create_process_params cparams; + nt_runtime_data_block rtblock; + nt_unicode_string * imgname; + nt_peb * peb; + char * patharg; + void * hat; + void * hfile; + uint32_t written; + wchar16_t * imgbuf; + char ** parg; + char * mark; + char * ch; + char * ch_arg; + char * ch_cap; + int fquote; + wchar16_t * cmdline; + nt_strconv_mbtonative uparams; + nt_unicode_string nt_image; + nt_unicode_string nt_cmd_line; + + /* validation */ + if (!sparams->argv) + return NT_STATUS_INVALID_PARAMETER; + + if (!sparams->startupinfo) + return NT_STATUS_INVALID_PARAMETER; + + if (!sparams->himage && !sparams->patharg) + return NT_STATUS_OBJECT_PATH_INVALID; + + if (!(peb = (nt_peb *)pe_get_peb_address())) + return NT_STATUS_INTERNAL_ERROR; + + if (!peb->process_params) + return NT_STATUS_INTERNAL_ERROR; + + if (sparams->rtctx || sparams->hsession || sparams->hready) + return NT_STATUS_INVALID_PARAMETER; + + /* hat */ + hat = (sparams->hroot && (sparams->argv[0][0] == '/')) + ? sparams->hroot + : sparams->hcwd + ? sparams->hcwd + : peb->process_params->cwd_handle; + + /* patharg */ + patharg = sparams->patharg + ? (sparams->patharg[0] == '/') + ? (sparams->patharg[1] == '?') + ? &sparams->patharg[0] + : &sparams->patharg[1] + : &sparams->patharg[0] + : 0; + + /* rtblock, rdata */ + 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); + + /* imgbuf */ + imgbuf = (wchar16_t *)rtblock.addr; + imgbuf += 0x30000 / 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 --> cmdline (utf8) */ + ch_arg = (char *)rtblock.addr; + ch_cap = ch_arg + 0x10000; + + for (parg=sparams->argv; *parg; parg++) { + for (ch=*parg, fquote=0; *ch && !fquote; ch++) + fquote = ((*ch == ' ') + || (*ch == '\t') + || (*ch == '"')); + + if (fquote) + *ch_arg++ = '"'; + + for (ch=*parg, fquote=0; *ch && !fquote; ) { + if (ch[0] == '\\') { + for (mark=&ch[1]; *mark=='\\'; ) + mark++; + + if ((ch_arg + 2*(mark-ch)) >= ch_cap) + return __tt_spawn_return( + &rtblock,0,0, + NT_STATUS_NAME_TOO_LONG); + + if (!mark[0] && fquote) { + for (; *ch=='\\'; ch++) { + *ch_arg++ = '\\'; + *ch_arg++ = '\\'; + } + } else if (mark[0] == '"') { + for (; *ch=='\\'; ch++) { + *ch_arg++ = '\\'; + *ch_arg++ = '\\'; + } + } else { + *ch_arg++ = *ch++; + } + + } else if (ch[0] == '"') { + *ch_arg++ = '\\'; + *ch_arg++ = *ch++; + + } else { + *ch_arg++ = *ch++; + } + } + + if (fquote) + *ch_arg++ = '"'; + + *ch_arg++ = ' '; + + if (ch_arg >= ch_cap) + return __tt_spawn_return( + &rtblock,0,0, + NT_STATUS_NAME_TOO_LONG); + + } + + ch_arg[-1] = 0; + + /* cmdline (utf8) --> cmdline (utf16) */ + cmdline = (wchar16_t *)rtblock.addr; + cmdline += (0x10000 / sizeof(wchar16_t)); + + uparams.src = (unsigned char *)rtblock.addr; + uparams.src_size_in_bytes = 0; + uparams.dst = cmdline; + uparams.dst_size_in_bytes = 0x10000 - sizeof(wchar16_t); + uparams.code_points = 0; + uparams.bytes_written = 0; + + if ((status = __ntapi->uc_convert_unicode_stream_utf8_to_utf16(&uparams))) + return __tt_spawn_return( + &rtblock,0,0,status); + + else if (uparams.leftover_count) + return __tt_spawn_return( + &rtblock,0,0, + NT_STATUS_ILLEGAL_CHARACTER); + + cmdline[uparams.bytes_written / sizeof(wchar16_t)] = 0; + + /* nt_cmd_line */ + nt_cmd_line.strlen = uparams.bytes_written; + nt_cmd_line.maxlen = uparams.bytes_written + sizeof(wchar16_t); + nt_cmd_line.buffer = cmdline; + + /* nt_image */ + nt_image.buffer = (wchar16_t *)rtblock.addr; + nt_image.buffer += (0x20000 / sizeof(wchar16_t)); + + uparams.src = (unsigned char *)sparams->argv[0]; + uparams.src_size_in_bytes = 0; + uparams.dst = nt_image.buffer; + uparams.dst_size_in_bytes = 0x10000 - sizeof(wchar16_t); + uparams.code_points = 0; + uparams.bytes_written = 0; + + if ((status = __ntapi->uc_convert_unicode_stream_utf8_to_utf16(&uparams))) + return __tt_spawn_return( + &rtblock,0,0,status); + + else if (uparams.leftover_count) + return __tt_spawn_return( + &rtblock,0,0, + NT_STATUS_ILLEGAL_CHARACTER); + + nt_image.strlen = uparams.bytes_written; + nt_image.maxlen = uparams.bytes_written + sizeof(wchar16_t); + + nt_image.buffer[uparams.bytes_written / sizeof(wchar16_t)] = 0; + + /* cparams */ + __ntapi->tt_aligned_block_memset( + &cparams,0,sizeof(cparams)); + + cparams.image_name = imgname->buffer; + cparams.creation_flags_thread = NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED; + + /* process_params */ + if ((status = __ntapi->rtl_create_process_parameters( + &cparams.process_params, + &nt_image, + (nt_unicode_string *)0, + (nt_unicode_string *)0, + &nt_cmd_line, + __ntapi->tt_get_peb_env_block_utf16(), + (nt_unicode_string *)0, + (nt_unicode_string *)0, + (nt_unicode_string *)0, + (nt_unicode_string *)0))) + return status; + + __ntapi->rtl_normalize_process_params(cparams.process_params); + + cparams.process_params->hstdin = sparams->startupinfo->hstdin; + cparams.process_params->hstdout = sparams->startupinfo->hstdout; + cparams.process_params->hstderr = sparams->startupinfo->hstderr; + + /* 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); + + /* output */ + sparams->hprocess = cparams.hprocess; + sparams->hthread = cparams.hthread; + + 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); + + /* all done */ + return __tt_spawn_return( + &rtblock,0,0,NT_STATUS_SUCCESS); +}