|
|
d326cc |
/********************************************************/
|
|
|
d326cc |
/* ntapi: Native API core library */
|
|
|
d326cc |
/* Copyright (C) 2013--2017 Z. Gilboa */
|
|
|
d326cc |
/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
|
|
|
d326cc |
/********************************************************/
|
|
|
d326cc |
|
|
|
d326cc |
#include <psxtypes/psxtypes.h>
|
|
|
d326cc |
#include <pemagine/pemagine.h>
|
|
|
d326cc |
#include <ntapi/nt_status.h>
|
|
|
d326cc |
#include <ntapi/nt_object.h>
|
|
|
d326cc |
#include <ntapi/nt_thread.h>
|
|
|
d326cc |
#include <ntapi/nt_process.h>
|
|
|
d326cc |
#include <ntapi/nt_string.h>
|
|
|
d326cc |
#include <ntapi/ntapi.h>
|
|
|
d326cc |
#include "ntapi_impl.h"
|
|
|
d326cc |
|
|
|
d326cc |
|
|
|
ec0b96 |
typedef int32_t win32_create_process_utf16(
|
|
|
ec0b96 |
__in_opt wchar16_t * appname,
|
|
|
ec0b96 |
__in_out_opt wchar16_t * cmdline,
|
|
|
ec0b96 |
__in_opt nt_sa * process_sa_attr,
|
|
|
ec0b96 |
__in_opt nt_sa * thread_sa_attr,
|
|
|
ec0b96 |
__in int32_t inherit_handles,
|
|
|
ec0b96 |
__in uint32_t creation_flags,
|
|
|
ec0b96 |
__in wchar16_t * environment,
|
|
|
ec0b96 |
__in_opt wchar16_t * cwd,
|
|
|
ec0b96 |
__in nt_process_startup_info * startup_info,
|
|
|
ec0b96 |
__out nt_process_info * process_info);
|
|
|
ec0b96 |
|
|
|
ec0b96 |
|
|
|
d326cc |
static int32_t __stdcall __tt_spawn_return(
|
|
|
d326cc |
nt_runtime_data_block * rtblock,
|
|
|
d326cc |
void * hprocess,
|
|
|
d326cc |
void * hthread,
|
|
|
d326cc |
int32_t status)
|
|
|
d326cc |
{
|
|
|
d326cc |
if (hprocess) {
|
|
|
d326cc |
__ntapi->zw_terminate_process(
|
|
|
d326cc |
hprocess,status);
|
|
|
d326cc |
|
|
|
d326cc |
__ntapi->zw_close(hprocess);
|
|
|
d326cc |
__ntapi->zw_close(hthread);
|
|
|
d326cc |
}
|
|
|
d326cc |
|
|
|
d326cc |
__ntapi->zw_free_virtual_memory(
|
|
|
d326cc |
NT_CURRENT_PROCESS_HANDLE,
|
|
|
d326cc |
&rtblock->addr,
|
|
|
d326cc |
&rtblock->size,
|
|
|
d326cc |
NT_MEM_RELEASE);
|
|
|
d326cc |
|
|
|
d326cc |
return status;
|
|
|
d326cc |
}
|
|
|
d326cc |
|
|
|
d326cc |
int32_t __stdcall __ntapi_tt_spawn_foreign_process(nt_spawn_process_params * sparams)
|
|
|
d326cc |
{
|
|
|
d326cc |
int32_t status;
|
|
|
ec0b96 |
nt_process_info processinfo;
|
|
|
d326cc |
nt_create_process_params cparams;
|
|
|
d326cc |
nt_runtime_data_block rtblock;
|
|
|
d326cc |
nt_unicode_string * imgname;
|
|
|
d326cc |
nt_peb * peb;
|
|
|
d326cc |
char * patharg;
|
|
|
ec0b96 |
void * hkernel32;
|
|
|
d326cc |
void * hat;
|
|
|
d326cc |
void * hfile;
|
|
|
d326cc |
uint32_t written;
|
|
|
d326cc |
wchar16_t * imgbuf;
|
|
|
d326cc |
char ** parg;
|
|
|
d326cc |
char * mark;
|
|
|
d326cc |
char * ch;
|
|
|
d326cc |
char * ch_arg;
|
|
|
d326cc |
char * ch_cap;
|
|
|
d326cc |
int fquote;
|
|
|
ec0b96 |
uint32_t finherit;
|
|
|
ec0b96 |
uint32_t fsuspended;
|
|
|
d326cc |
wchar16_t * cmdline;
|
|
|
d326cc |
nt_strconv_mbtonative uparams;
|
|
|
d326cc |
nt_unicode_string nt_image;
|
|
|
d326cc |
nt_unicode_string nt_cmd_line;
|
|
|
ec0b96 |
win32_create_process_utf16 * create_process_fn;
|
|
|
ec0b96 |
char create_process_fn_name[]
|
|
|
ec0b96 |
= "CreateProcessW";
|
|
|
d326cc |
|
|
|
d326cc |
/* validation */
|
|
|
d326cc |
if (!sparams->argv)
|
|
|
d326cc |
return NT_STATUS_INVALID_PARAMETER;
|
|
|
d326cc |
|
|
|
d326cc |
if (!sparams->himage && !sparams->patharg)
|
|
|
d326cc |
return NT_STATUS_OBJECT_PATH_INVALID;
|
|
|
d326cc |
|
|
|
d326cc |
if (!(peb = (nt_peb *)pe_get_peb_address()))
|
|
|
d326cc |
return NT_STATUS_INTERNAL_ERROR;
|
|
|
d326cc |
|
|
|
d326cc |
if (!peb->process_params)
|
|
|
d326cc |
return NT_STATUS_INTERNAL_ERROR;
|
|
|
d326cc |
|
|
|
d326cc |
if (sparams->rtctx || sparams->hsession || sparams->hready)
|
|
|
d326cc |
return NT_STATUS_INVALID_PARAMETER;
|
|
|
d326cc |
|
|
|
ec0b96 |
/* hkernel32 */
|
|
|
ec0b96 |
if (!(hkernel32 = pe_get_kernel32_module_handle()))
|
|
|
ec0b96 |
return NT_STATUS_DLL_NOT_FOUND;
|
|
|
ec0b96 |
|
|
|
ec0b96 |
if (!(create_process_fn = (win32_create_process_utf16 *)
|
|
|
ec0b96 |
(pe_get_procedure_address(
|
|
|
ec0b96 |
hkernel32,create_process_fn_name))))
|
|
|
ec0b96 |
return NT_STATUS_PROCEDURE_NOT_FOUND;
|
|
|
ec0b96 |
|
|
|
d326cc |
/* hat */
|
|
|
d326cc |
hat = (sparams->hroot && (sparams->argv[0][0] == '/'))
|
|
|
d326cc |
? sparams->hroot
|
|
|
d326cc |
: sparams->hcwd
|
|
|
d326cc |
? sparams->hcwd
|
|
|
d326cc |
: peb->process_params->cwd_handle;
|
|
|
d326cc |
|
|
|
d326cc |
/* patharg */
|
|
|
d326cc |
patharg = sparams->patharg
|
|
|
d326cc |
? (sparams->patharg[0] == '/')
|
|
|
d326cc |
? (sparams->patharg[1] == '?')
|
|
|
d326cc |
? &sparams->patharg[0]
|
|
|
d326cc |
: &sparams->patharg[1]
|
|
|
d326cc |
: &sparams->patharg[0]
|
|
|
d326cc |
: 0;
|
|
|
d326cc |
|
|
|
d326cc |
/* rtblock, rdata */
|
|
|
d326cc |
rtblock.addr = 0;
|
|
|
d326cc |
rtblock.size = 0x40000;
|
|
|
d326cc |
rtblock.remote_addr = 0;
|
|
|
d326cc |
rtblock.remote_size = 0;
|
|
|
d326cc |
rtblock.flags = 0;
|
|
|
d326cc |
|
|
|
d326cc |
if ((status = __ntapi->zw_allocate_virtual_memory(
|
|
|
d326cc |
NT_CURRENT_PROCESS_HANDLE,
|
|
|
d326cc |
&rtblock.addr,0,
|
|
|
d326cc |
&rtblock.size,
|
|
|
d326cc |
NT_MEM_COMMIT,
|
|
|
d326cc |
NT_PAGE_READWRITE)))
|
|
|
d326cc |
return status;
|
|
|
d326cc |
|
|
|
d326cc |
__ntapi->tt_aligned_block_memset(
|
|
|
d326cc |
rtblock.addr,0,rtblock.size);
|
|
|
d326cc |
|
|
|
d326cc |
/* imgbuf */
|
|
|
d326cc |
imgbuf = (wchar16_t *)rtblock.addr;
|
|
|
d326cc |
imgbuf += 0x30000 / sizeof(*imgbuf);
|
|
|
d326cc |
|
|
|
d326cc |
/* hfile */
|
|
|
d326cc |
if (sparams->himage)
|
|
|
d326cc |
hfile = sparams->himage;
|
|
|
d326cc |
|
|
|
d326cc |
else if ((status = __ntapi_tt_open_file_utf8(
|
|
|
d326cc |
&hfile,hat,patharg,1,
|
|
|
d326cc |
imgbuf,0x2000)))
|
|
|
d326cc |
return status;
|
|
|
d326cc |
|
|
|
d326cc |
/* imgname */
|
|
|
d326cc |
if ((status = __ntapi->zw_query_object(
|
|
|
d326cc |
hfile,
|
|
|
d326cc |
NT_OBJECT_NAME_INFORMATION,
|
|
|
d326cc |
imgbuf,0x10000,&written)))
|
|
|
d326cc |
return __tt_spawn_return(
|
|
|
d326cc |
&rtblock,0,0,status);
|
|
|
d326cc |
|
|
|
d326cc |
imgname = (nt_unicode_string *)imgbuf;
|
|
|
d326cc |
|
|
|
d326cc |
/* argv --> cmdline (utf8) */
|
|
|
d326cc |
ch_arg = (char *)rtblock.addr;
|
|
|
d326cc |
ch_cap = ch_arg + 0x10000;
|
|
|
d326cc |
|
|
|
d326cc |
for (parg=sparams->argv; *parg; parg++) {
|
|
|
d326cc |
for (ch=*parg, fquote=0; *ch && !fquote; ch++)
|
|
|
d326cc |
fquote = ((*ch == ' ')
|
|
|
d326cc |
|| (*ch == '\t')
|
|
|
d326cc |
|| (*ch == '"'));
|
|
|
d326cc |
|
|
|
d326cc |
if (fquote)
|
|
|
d326cc |
*ch_arg++ = '"';
|
|
|
d326cc |
|
|
|
d326cc |
for (ch=*parg, fquote=0; *ch && !fquote; ) {
|
|
|
d326cc |
if (ch[0] == '\\') {
|
|
|
d326cc |
for (mark=&ch[1]; *mark=='\\'; )
|
|
|
d326cc |
mark++;
|
|
|
d326cc |
|
|
|
d326cc |
if ((ch_arg + 2*(mark-ch)) >= ch_cap)
|
|
|
d326cc |
return __tt_spawn_return(
|
|
|
d326cc |
&rtblock,0,0,
|
|
|
d326cc |
NT_STATUS_NAME_TOO_LONG);
|
|
|
d326cc |
|
|
|
d326cc |
if (!mark[0] && fquote) {
|
|
|
d326cc |
for (; *ch=='\\'; ch++) {
|
|
|
d326cc |
*ch_arg++ = '\\';
|
|
|
d326cc |
*ch_arg++ = '\\';
|
|
|
d326cc |
}
|
|
|
d326cc |
} else if (mark[0] == '"') {
|
|
|
d326cc |
for (; *ch=='\\'; ch++) {
|
|
|
d326cc |
*ch_arg++ = '\\';
|
|
|
d326cc |
*ch_arg++ = '\\';
|
|
|
d326cc |
}
|
|
|
d326cc |
} else {
|
|
|
d326cc |
*ch_arg++ = *ch++;
|
|
|
d326cc |
}
|
|
|
d326cc |
|
|
|
d326cc |
} else if (ch[0] == '"') {
|
|
|
d326cc |
*ch_arg++ = '\\';
|
|
|
d326cc |
*ch_arg++ = *ch++;
|
|
|
d326cc |
|
|
|
d326cc |
} else {
|
|
|
d326cc |
*ch_arg++ = *ch++;
|
|
|
d326cc |
}
|
|
|
d326cc |
}
|
|
|
d326cc |
|
|
|
d326cc |
if (fquote)
|
|
|
d326cc |
*ch_arg++ = '"';
|
|
|
d326cc |
|
|
|
d326cc |
*ch_arg++ = ' ';
|
|
|
d326cc |
|
|
|
d326cc |
if (ch_arg >= ch_cap)
|
|
|
d326cc |
return __tt_spawn_return(
|
|
|
d326cc |
&rtblock,0,0,
|
|
|
d326cc |
NT_STATUS_NAME_TOO_LONG);
|
|
|
d326cc |
|
|
|
d326cc |
}
|
|
|
d326cc |
|
|
|
d326cc |
ch_arg[-1] = 0;
|
|
|
d326cc |
|
|
|
d326cc |
/* cmdline (utf8) --> cmdline (utf16) */
|
|
|
d326cc |
cmdline = (wchar16_t *)rtblock.addr;
|
|
|
d326cc |
cmdline += (0x10000 / sizeof(wchar16_t));
|
|
|
d326cc |
|
|
|
d326cc |
uparams.src = (unsigned char *)rtblock.addr;
|
|
|
d326cc |
uparams.src_size_in_bytes = 0;
|
|
|
d326cc |
uparams.dst = cmdline;
|
|
|
d326cc |
uparams.dst_size_in_bytes = 0x10000 - sizeof(wchar16_t);
|
|
|
d326cc |
uparams.code_points = 0;
|
|
|
d326cc |
uparams.bytes_written = 0;
|
|
|
d326cc |
|
|
|
d326cc |
if ((status = __ntapi->uc_convert_unicode_stream_utf8_to_utf16(&uparams)))
|
|
|
d326cc |
return __tt_spawn_return(
|
|
|
d326cc |
&rtblock,0,0,status);
|
|
|
d326cc |
|
|
|
d326cc |
else if (uparams.leftover_count)
|
|
|
d326cc |
return __tt_spawn_return(
|
|
|
d326cc |
&rtblock,0,0,
|
|
|
d326cc |
NT_STATUS_ILLEGAL_CHARACTER);
|
|
|
d326cc |
|
|
|
d326cc |
cmdline[uparams.bytes_written / sizeof(wchar16_t)] = 0;
|
|
|
d326cc |
|
|
|
d326cc |
/* nt_cmd_line */
|
|
|
d326cc |
nt_cmd_line.strlen = uparams.bytes_written;
|
|
|
d326cc |
nt_cmd_line.maxlen = uparams.bytes_written + sizeof(wchar16_t);
|
|
|
d326cc |
nt_cmd_line.buffer = cmdline;
|
|
|
d326cc |
|
|
|
d326cc |
/* nt_image */
|
|
|
d326cc |
nt_image.buffer = (wchar16_t *)rtblock.addr;
|
|
|
d326cc |
nt_image.buffer += (0x20000 / sizeof(wchar16_t));
|
|
|
d326cc |
|
|
|
d326cc |
uparams.src = (unsigned char *)sparams->argv[0];
|
|
|
d326cc |
uparams.src_size_in_bytes = 0;
|
|
|
d326cc |
uparams.dst = nt_image.buffer;
|
|
|
d326cc |
uparams.dst_size_in_bytes = 0x10000 - sizeof(wchar16_t);
|
|
|
d326cc |
uparams.code_points = 0;
|
|
|
d326cc |
uparams.bytes_written = 0;
|
|
|
d326cc |
|
|
|
d326cc |
if ((status = __ntapi->uc_convert_unicode_stream_utf8_to_utf16(&uparams)))
|
|
|
d326cc |
return __tt_spawn_return(
|
|
|
d326cc |
&rtblock,0,0,status);
|
|
|
d326cc |
|
|
|
d326cc |
else if (uparams.leftover_count)
|
|
|
d326cc |
return __tt_spawn_return(
|
|
|
d326cc |
&rtblock,0,0,
|
|
|
d326cc |
NT_STATUS_ILLEGAL_CHARACTER);
|
|
|
d326cc |
|
|
|
d326cc |
nt_image.strlen = uparams.bytes_written;
|
|
|
d326cc |
nt_image.maxlen = uparams.bytes_written + sizeof(wchar16_t);
|
|
|
d326cc |
|
|
|
d326cc |
nt_image.buffer[uparams.bytes_written / sizeof(wchar16_t)] = 0;
|
|
|
d326cc |
|
|
|
d326cc |
/* cparams */
|
|
|
d326cc |
__ntapi->tt_aligned_block_memset(
|
|
|
d326cc |
&cparams,0,sizeof(cparams));
|
|
|
d326cc |
|
|
|
d326cc |
cparams.image_name = imgname->buffer;
|
|
|
d326cc |
cparams.creation_flags_thread = NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED;
|
|
|
d326cc |
|
|
|
d326cc |
/* process_params */
|
|
|
d326cc |
if ((status = __ntapi->rtl_create_process_parameters(
|
|
|
d326cc |
&cparams.process_params,
|
|
|
d326cc |
&nt_image,
|
|
|
d326cc |
(nt_unicode_string *)0,
|
|
|
d326cc |
(nt_unicode_string *)0,
|
|
|
d326cc |
&nt_cmd_line,
|
|
|
d326cc |
__ntapi->tt_get_peb_env_block_utf16(),
|
|
|
d326cc |
(nt_unicode_string *)0,
|
|
|
d326cc |
(nt_unicode_string *)0,
|
|
|
d326cc |
(nt_unicode_string *)0,
|
|
|
d326cc |
(nt_unicode_string *)0)))
|
|
|
d326cc |
return status;
|
|
|
d326cc |
|
|
|
d326cc |
__ntapi->rtl_normalize_process_params(cparams.process_params);
|
|
|
d326cc |
|
|
|
ec0b96 |
if (sparams->startupinfo) {
|
|
|
ec0b96 |
cparams.process_params->hstdin = sparams->startupinfo->hstdin;
|
|
|
ec0b96 |
cparams.process_params->hstdout = sparams->startupinfo->hstdout;
|
|
|
ec0b96 |
cparams.process_params->hstderr = sparams->startupinfo->hstderr;
|
|
|
ec0b96 |
}
|
|
|
d326cc |
|
|
|
ec0b96 |
/* inherit handles? */
|
|
|
ec0b96 |
if (cparams.process_params->hstdin
|
|
|
ec0b96 |
|| cparams.process_params->hstdout
|
|
|
ec0b96 |
|| cparams.process_params->hstderr)
|
|
|
ec0b96 |
finherit = 1;
|
|
|
ec0b96 |
|
|
|
ec0b96 |
else if (sparams->processflags & NT_PROCESS_CREATE_FLAGS_INHERIT_HANDLES)
|
|
|
ec0b96 |
finherit = 1;
|
|
|
ec0b96 |
|
|
|
ec0b96 |
else
|
|
|
ec0b96 |
finherit = 0;
|
|
|
ec0b96 |
|
|
|
ec0b96 |
/* process flags */
|
|
|
ec0b96 |
if (sparams->processflags & NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED)
|
|
|
ec0b96 |
fsuspended = NT_CREATE_SUSPENDED;
|
|
|
ec0b96 |
|
|
|
ec0b96 |
else if (sparams->threadflags & NT_CREATE_SUSPENDED)
|
|
|
ec0b96 |
fsuspended = NT_CREATE_SUSPENDED;
|
|
|
ec0b96 |
|
|
|
ec0b96 |
else
|
|
|
ec0b96 |
fsuspended = 0;
|
|
|
ec0b96 |
|
|
|
ec0b96 |
/* hoppla: try either via kernel32 (sparams->startupinfo), or natively */
|
|
|
fa26cc |
if (sparams->spawnflags & NT_PROCESS_SPAWN_FLAG_DELEGATE_TO_SYSTEM_LIBRARY) {
|
|
|
ec0b96 |
processinfo.hprocess = 0;
|
|
|
ec0b96 |
processinfo.hthread = 0;
|
|
|
ec0b96 |
processinfo.process_id = 0;
|
|
|
ec0b96 |
processinfo.thread_id = 0;
|
|
|
ec0b96 |
|
|
|
ec0b96 |
if (!(create_process_fn(
|
|
|
ec0b96 |
nt_image.buffer,
|
|
|
ec0b96 |
nt_cmd_line.buffer,
|
|
|
ec0b96 |
0,
|
|
|
ec0b96 |
0,
|
|
|
ec0b96 |
finherit,
|
|
|
3c39f1 |
sparams->interopflags | fsuspended,
|
|
|
ec0b96 |
0,
|
|
|
ec0b96 |
0,
|
|
|
ec0b96 |
sparams->startupinfo,
|
|
|
ec0b96 |
&processinfo)))
|
|
|
ec0b96 |
return __tt_spawn_return(
|
|
|
ec0b96 |
&rtblock,0,0,status);
|
|
|
ec0b96 |
|
|
|
ec0b96 |
if ((status = __ntapi->zw_query_information_process(
|
|
|
ec0b96 |
processinfo.hprocess,
|
|
|
ec0b96 |
NT_PROCESS_BASIC_INFORMATION,
|
|
|
ec0b96 |
&cparams.pbi,sizeof(cparams.pbi),
|
|
|
ec0b96 |
0)))
|
|
|
ec0b96 |
return __tt_spawn_return(
|
|
|
ec0b96 |
&rtblock,0,0,status);
|
|
|
ec0b96 |
|
|
|
ec0b96 |
cparams.hprocess = processinfo.hprocess;
|
|
|
ec0b96 |
cparams.hthread = processinfo.hthread;
|
|
|
ec0b96 |
|
|
|
ec0b96 |
cparams.cid.process_id = processinfo.process_id;
|
|
|
ec0b96 |
cparams.cid.thread_id = processinfo.thread_id;
|
|
|
ec0b96 |
} else {
|
|
|
a1d104 |
cparams.creation_flags_thread = NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED;
|
|
|
a1d104 |
|
|
|
a1d104 |
if (finherit)
|
|
|
a1d104 |
cparams.creation_flags_process |= NT_PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
|
|
|
a1d104 |
|
|
|
ec0b96 |
if ((status = __ntapi->tt_create_native_process(&cparams)))
|
|
|
ec0b96 |
return __tt_spawn_return(
|
|
|
ec0b96 |
&rtblock,0,0,status);
|
|
|
ec0b96 |
}
|
|
|
d326cc |
|
|
|
d326cc |
/* tidy up */
|
|
|
d326cc |
if (!sparams->himage)
|
|
|
d326cc |
__ntapi->zw_close(hfile);
|
|
|
d326cc |
|
|
|
d326cc |
/* output */
|
|
|
d326cc |
sparams->hprocess = cparams.hprocess;
|
|
|
d326cc |
sparams->hthread = cparams.hthread;
|
|
|
d326cc |
|
|
|
d326cc |
sparams->cid.process_id = cparams.pbi.unique_process_id;
|
|
|
d326cc |
sparams->cid.thread_id = cparams.cid.thread_id;
|
|
|
d326cc |
|
|
|
d326cc |
__ntapi->tt_generic_memcpy(
|
|
|
d326cc |
&sparams->pbi,
|
|
|
d326cc |
&cparams.pbi,
|
|
|
d326cc |
sizeof(nt_pbi));
|
|
|
d326cc |
|
|
|
d326cc |
/* create suspended? */
|
|
|
ec0b96 |
if (fsuspended)
|
|
|
d326cc |
return __tt_spawn_return(
|
|
|
d326cc |
&rtblock,0,0,NT_STATUS_SUCCESS);
|
|
|
d326cc |
|
|
|
d326cc |
/* tada */
|
|
|
d326cc |
if ((status = __ntapi->zw_resume_thread(cparams.hthread,0)))
|
|
|
d326cc |
return __tt_spawn_return(
|
|
|
d326cc |
&rtblock,
|
|
|
d326cc |
cparams.hprocess,
|
|
|
d326cc |
cparams.hthread,
|
|
|
d326cc |
status);
|
|
|
d326cc |
|
|
|
d326cc |
/* all done */
|
|
|
d326cc |
return __tt_spawn_return(
|
|
|
d326cc |
&rtblock,0,0,NT_STATUS_SUCCESS);
|
|
|
d326cc |
}
|