/********************************************************/ /* 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" typedef int32_t win32_create_process_utf16( __in_opt wchar16_t * appname, __in_out_opt wchar16_t * cmdline, __in_opt nt_sa * process_sa_attr, __in_opt nt_sa * thread_sa_attr, __in int32_t inherit_handles, __in uint32_t creation_flags, __in wchar16_t * environment, __in_opt wchar16_t * cwd, __in nt_process_startup_info * startup_info, __out nt_process_info * process_info); 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_process_info processinfo; nt_create_process_params cparams; nt_runtime_data_block rtblock; nt_unicode_string * imgname; nt_peb * peb; char * patharg; void * hkernel32; void * hat; void * hfile; uint32_t written; wchar16_t * imgbuf; char ** parg; char * mark; char * ch; char * ch_arg; char * ch_cap; int fquote; uint32_t finherit; uint32_t fsuspended; wchar16_t * cmdline; nt_strconv_mbtonative uparams; nt_unicode_string nt_image; nt_unicode_string nt_cmd_line; win32_create_process_utf16 * create_process_fn; char create_process_fn_name[] = "CreateProcessW"; /* validation */ if (!sparams->argv) 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; /* hkernel32 */ if (!(hkernel32 = pe_get_kernel32_module_handle())) return NT_STATUS_DLL_NOT_FOUND; if (!(create_process_fn = (win32_create_process_utf16 *) (pe_get_procedure_address( hkernel32,create_process_fn_name)))) return NT_STATUS_PROCEDURE_NOT_FOUND; /* 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); if (sparams->startupinfo) { cparams.process_params->hstdin = sparams->startupinfo->hstdin; cparams.process_params->hstdout = sparams->startupinfo->hstdout; cparams.process_params->hstderr = sparams->startupinfo->hstderr; } /* inherit handles? */ if (cparams.process_params->hstdin || cparams.process_params->hstdout || cparams.process_params->hstderr) finherit = 1; else if (sparams->processflags & NT_PROCESS_CREATE_FLAGS_INHERIT_HANDLES) finherit = 1; else finherit = 0; /* process flags */ if (sparams->processflags & NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED) fsuspended = NT_CREATE_SUSPENDED; else if (sparams->threadflags & NT_CREATE_SUSPENDED) fsuspended = NT_CREATE_SUSPENDED; else fsuspended = 0; /* hoppla: try either via kernel32 (sparams->startupinfo), or natively */ if (sparams->spawnflags & NT_PROCESS_SPAWN_FLAG_DELEGATE_TO_SYSTEM_LIBRARY) { processinfo.hprocess = 0; processinfo.hthread = 0; processinfo.process_id = 0; processinfo.thread_id = 0; if (!(create_process_fn( nt_image.buffer, nt_cmd_line.buffer, 0, 0, finherit, sparams->interopflags | fsuspended, 0, 0, sparams->startupinfo, &processinfo))) return __tt_spawn_return( &rtblock,0,0,status); if ((status = __ntapi->zw_query_information_process( processinfo.hprocess, NT_PROCESS_BASIC_INFORMATION, &cparams.pbi,sizeof(cparams.pbi), 0))) return __tt_spawn_return( &rtblock,0,0,status); cparams.hprocess = processinfo.hprocess; cparams.hthread = processinfo.hthread; cparams.cid.process_id = processinfo.process_id; cparams.cid.thread_id = processinfo.thread_id; } else { cparams.creation_flags_thread = NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED; if (finherit) cparams.creation_flags_process |= NT_PROCESS_CREATE_FLAGS_INHERIT_HANDLES; 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 (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); }