/********************************************************/ /* 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); }