|
|
c164ff |
/********************************************************/
|
|
|
c164ff |
/* ntapi: Native API core library */
|
|
|
c164ff |
/* Copyright (C) 2013--2016 Z. Gilboa */
|
|
|
c164ff |
/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
|
|
|
c164ff |
/********************************************************/
|
|
|
c164ff |
|
|
|
c164ff |
#include <psxtypes/psxtypes.h>
|
|
|
c164ff |
#include <pemagine/pemagine.h>
|
|
|
c164ff |
#include <ntapi/nt_status.h>
|
|
|
c164ff |
#include <ntapi/nt_object.h>
|
|
|
c164ff |
#include <ntapi/nt_thread.h>
|
|
|
c164ff |
#include <ntapi/nt_process.h>
|
|
|
c164ff |
#include <ntapi/nt_string.h>
|
|
|
c164ff |
#include <ntapi/ntapi.h>
|
|
|
c164ff |
#include "ntapi_impl.h"
|
|
|
c164ff |
|
|
|
c164ff |
static int32_t __stdcall __tt_spawn_return(
|
|
|
c164ff |
nt_runtime_data_block * rtblock,
|
|
|
c164ff |
void * hprocess,
|
|
|
c164ff |
void * hthread,
|
|
|
c164ff |
int32_t status)
|
|
|
c164ff |
{
|
|
|
c164ff |
nt_runtime_data * rtdata;
|
|
|
c164ff |
|
|
|
c164ff |
rtdata = (nt_runtime_data *)rtblock->addr;
|
|
|
c164ff |
|
|
|
c164ff |
if (hprocess) {
|
|
|
c164ff |
__ntapi->zw_terminate_process(
|
|
|
c164ff |
hprocess,status);
|
|
|
c164ff |
|
|
|
c164ff |
__ntapi->zw_close(hprocess);
|
|
|
c164ff |
__ntapi->zw_close(hthread);
|
|
|
c164ff |
}
|
|
|
c164ff |
|
|
|
c164ff |
if (rtdata->hready)
|
|
|
c164ff |
__ntapi->zw_close(
|
|
|
c164ff |
rtdata->hready);
|
|
|
c164ff |
|
|
|
c164ff |
__ntapi->zw_free_virtual_memory(
|
|
|
c164ff |
NT_CURRENT_PROCESS_HANDLE,
|
|
|
c164ff |
&rtblock->addr,
|
|
|
c164ff |
&rtblock->size,
|
|
|
c164ff |
NT_MEM_RELEASE);
|
|
|
c164ff |
|
|
|
c164ff |
return status;
|
|
|
c164ff |
}
|
|
|
c164ff |
|
|
|
c164ff |
int32_t __stdcall __ntapi_tt_spawn_native_process(nt_spawn_process_params * sparams)
|
|
|
c164ff |
{
|
|
|
c164ff |
int32_t status;
|
|
|
c164ff |
nt_create_process_params cparams;
|
|
|
c164ff |
nt_tty_session_info session;
|
|
|
c164ff |
nt_runtime_data_block rtblock;
|
|
|
c164ff |
nt_runtime_data_block crtblock;
|
|
|
c164ff |
nt_runtime_data * rtctx;
|
|
|
c164ff |
nt_runtime_data * rdata;
|
|
|
c164ff |
nt_unicode_string * imgname;
|
|
|
c164ff |
nt_peb * peb;
|
|
|
c164ff |
char * patharg;
|
|
|
c164ff |
void * hat;
|
|
|
c164ff |
void * hfile;
|
|
|
c164ff |
char ** parg;
|
|
|
c164ff |
char ** rargv;
|
|
|
c164ff |
char ** renvp;
|
|
|
c164ff |
wchar16_t ** pwarg;
|
|
|
c164ff |
wchar16_t * wch;
|
|
|
c164ff |
void * hchild[2];
|
|
|
c164ff |
uint32_t written;
|
|
|
c164ff |
wchar16_t * imgbuf;
|
|
|
c164ff |
|
|
|
c164ff |
/* rtctx (convenience) */
|
|
|
c164ff |
rtctx = sparams->rtctx;
|
|
|
c164ff |
|
|
|
c164ff |
/* validation */
|
|
|
c164ff |
if (!sparams->himage && !sparams->patharg)
|
|
|
c164ff |
return NT_STATUS_OBJECT_PATH_INVALID;
|
|
|
c164ff |
|
|
|
c164ff |
if (rtctx->argc || rtctx->argv || rtctx->envc || rtctx->envp)
|
|
|
c164ff |
return NT_STATUS_INVALID_PARAMETER;
|
|
|
c164ff |
|
|
|
c164ff |
if (rtctx->hready || rtctx->hsession)
|
|
|
c164ff |
return NT_STATUS_INVALID_PARAMETER_MIX;
|
|
|
c164ff |
|
|
|
c164ff |
if (!(peb = (nt_peb *)pe_get_peb_address()))
|
|
|
c164ff |
return NT_STATUS_INTERNAL_ERROR;
|
|
|
c164ff |
|
|
|
c164ff |
if (!peb->process_params)
|
|
|
c164ff |
return NT_STATUS_INTERNAL_ERROR;
|
|
|
c164ff |
|
|
|
c164ff |
/* hat */
|
|
|
c164ff |
hat = (rtctx->hroot && (sparams->argv[0][0] == '/'))
|
|
|
c164ff |
? rtctx->hroot
|
|
|
c164ff |
: rtctx->hcwd
|
|
|
c164ff |
? rtctx->hcwd
|
|
|
c164ff |
: peb->process_params->cwd_handle;
|
|
|
c164ff |
|
|
|
c164ff |
/* patharg */
|
|
|
c164ff |
patharg = (sparams->patharg[0] == '/')
|
|
|
c164ff |
? (sparams->patharg[1] == '?')
|
|
|
c164ff |
? &sparams->patharg[0]
|
|
|
c164ff |
: &sparams->patharg[1]
|
|
|
c164ff |
: &sparams->patharg[0];
|
|
|
c164ff |
|
|
|
c164ff |
/* rtblock, rdata */
|
|
|
c164ff |
rtblock.addr = 0;
|
|
|
c164ff |
rtblock.size = 0x20000;
|
|
|
c164ff |
rtblock.remote_addr = 0;
|
|
|
c164ff |
rtblock.remote_size = 0;
|
|
|
c164ff |
rtblock.flags = 0;
|
|
|
c164ff |
|
|
|
c164ff |
if ((status = __ntapi->zw_allocate_virtual_memory(
|
|
|
c164ff |
NT_CURRENT_PROCESS_HANDLE,
|
|
|
c164ff |
&rtblock.addr,0,
|
|
|
c164ff |
&rtblock.size,
|
|
|
c164ff |
NT_MEM_COMMIT,
|
|
|
c164ff |
NT_PAGE_READWRITE)))
|
|
|
c164ff |
return status;
|
|
|
c164ff |
|
|
|
c164ff |
__ntapi->tt_aligned_block_memset(
|
|
|
c164ff |
rtblock.addr,0,rtblock.size);
|
|
|
c164ff |
|
|
|
c164ff |
__ntapi->tt_aligned_block_memcpy(
|
|
|
c164ff |
(uintptr_t *)(rdata = (nt_runtime_data *)rtblock.addr),
|
|
|
c164ff |
(const uintptr_t *)rtctx,
|
|
|
c164ff |
sizeof(*rtctx));
|
|
|
c164ff |
|
|
|
c164ff |
/* imgbuf */
|
|
|
c164ff |
imgbuf = (wchar16_t *)rtblock.addr;
|
|
|
c164ff |
imgbuf += 0x10000 / sizeof(*imgbuf);
|
|
|
c164ff |
|
|
|
c164ff |
/* hfile */
|
|
|
c164ff |
if (sparams->himage)
|
|
|
c164ff |
hfile = sparams->himage;
|
|
|
c164ff |
else if ((status = __ntapi_tt_open_file_utf8(
|
|
|
c164ff |
&hfile,hat,patharg,1,
|
|
|
c164ff |
imgbuf,0x2000)))
|
|
|
c164ff |
return status;
|
|
|
c164ff |
|
|
|
c164ff |
/* imgname */
|
|
|
c164ff |
if ((status = __ntapi->zw_query_object(
|
|
|
c164ff |
hfile,
|
|
|
c164ff |
NT_OBJECT_NAME_INFORMATION,
|
|
|
c164ff |
imgbuf,0x10000,&written)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,status);
|
|
|
c164ff |
|
|
|
c164ff |
imgname = (nt_unicode_string *)imgbuf;
|
|
|
c164ff |
|
|
|
c164ff |
/* argv, envp */
|
|
|
c164ff |
if ((status = __ntapi->tt_array_copy_utf8(
|
|
|
c164ff |
&rdata->argc,
|
|
|
c164ff |
(const char **)sparams->argv,
|
|
|
c164ff |
(const char **)sparams->envp,
|
|
|
c164ff |
sparams->image,
|
|
|
c164ff |
sparams->interpreter,
|
|
|
c164ff |
sparams->optarg,
|
|
|
c164ff |
rtblock.addr,
|
|
|
c164ff |
rdata->buffer,
|
|
|
c164ff |
rtblock.size - sizeof(*rdata),
|
|
|
c164ff |
&rtblock.remote_size)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,status);
|
|
|
c164ff |
|
|
|
c164ff |
rdata->argv = (char **)&((nt_runtime_data *)0)->buffer;
|
|
|
c164ff |
rdata->envp = rdata->argv + rdata->argc + 1;
|
|
|
c164ff |
|
|
|
c164ff |
rdata->wargv = (wchar16_t **)(rdata->buffer + (rtblock.remote_size / sizeof(uintptr_t)) + 1);
|
|
|
c164ff |
rdata->wenvp = rdata->wargv + rdata->argc + 1;
|
|
|
c164ff |
|
|
|
c164ff |
rargv = rdata->argv + ((uintptr_t)rtblock.addr / sizeof(char *));
|
|
|
c164ff |
renvp = rdata->envp + ((uintptr_t)rtblock.addr / sizeof(char *));
|
|
|
c164ff |
|
|
|
c164ff |
for (rdata->envc=0, parg=sparams->envp; *parg; parg++)
|
|
|
c164ff |
rdata->envc++;
|
|
|
c164ff |
|
|
|
c164ff |
pwarg = rdata->wenvp + rdata->envc + 1;
|
|
|
c164ff |
wch = (wchar16_t *)pwarg;
|
|
|
c164ff |
|
|
|
c164ff |
if ((status = __ntapi->tt_array_convert_utf8_to_utf16(
|
|
|
c164ff |
rargv,
|
|
|
c164ff |
rdata->wargv,
|
|
|
c164ff |
rdata,
|
|
|
c164ff |
wch,
|
|
|
c164ff |
rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer),
|
|
|
c164ff |
&rtblock.remote_size)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,status);
|
|
|
c164ff |
|
|
|
c164ff |
wch += rtblock.remote_size/sizeof(wchar16_t);
|
|
|
c164ff |
|
|
|
c164ff |
if ((status = __ntapi->tt_array_convert_utf8_to_utf16(
|
|
|
c164ff |
renvp,
|
|
|
c164ff |
rdata->wenvp,
|
|
|
c164ff |
rdata,
|
|
|
c164ff |
wch,
|
|
|
c164ff |
rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer),
|
|
|
c164ff |
&rtblock.remote_size)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,status);
|
|
|
c164ff |
|
|
|
c164ff |
rdata->wargv -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *);
|
|
|
c164ff |
rdata->wenvp -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *);
|
|
|
c164ff |
|
|
|
c164ff |
/* session */
|
|
|
c164ff |
if (sparams->hready) {
|
|
|
c164ff |
if ((status = __ntapi->zw_duplicate_object(
|
|
|
c164ff |
NT_CURRENT_PROCESS_HANDLE,
|
|
|
c164ff |
sparams->hready,
|
|
|
c164ff |
NT_CURRENT_PROCESS_HANDLE,
|
|
|
c164ff |
&rdata->hready,
|
|
|
c164ff |
0,0,
|
|
|
c164ff |
NT_DUPLICATE_SAME_ACCESS|NT_DUPLICATE_SAME_ATTRIBUTES)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,status);
|
|
|
c164ff |
} else {
|
|
|
c164ff |
if ((status = __ntapi->tt_create_inheritable_event(
|
|
|
c164ff |
&rdata->hready,
|
|
|
c164ff |
NT_NOTIFICATION_EVENT,
|
|
|
c164ff |
NT_EVENT_NOT_SIGNALED)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,status);
|
|
|
c164ff |
}
|
|
|
c164ff |
|
|
|
c164ff |
/* cparams */
|
|
|
c164ff |
__ntapi->tt_aligned_block_memset(
|
|
|
c164ff |
&cparams,0,sizeof(cparams));
|
|
|
c164ff |
|
|
|
c164ff |
__ntapi->tt_generic_memcpy(
|
|
|
c164ff |
&crtblock,&rtblock,sizeof(rtblock));
|
|
|
c164ff |
|
|
|
c164ff |
cparams.image_name = imgname->buffer;
|
|
|
c164ff |
cparams.creation_flags_process = NT_PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
|
|
|
c164ff |
cparams.creation_flags_thread = NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED;
|
|
|
c164ff |
|
|
|
c164ff |
crtblock.size = 0x10000;
|
|
|
c164ff |
cparams.rtblock = &crtblock;
|
|
|
c164ff |
|
|
|
c164ff |
/* hoppla */
|
|
|
c164ff |
if ((status = __ntapi->tt_create_native_process(&cparams)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,status);
|
|
|
c164ff |
|
|
|
39c844 |
/* tidy up */
|
|
|
39c844 |
if (!sparams->himage)
|
|
|
39c844 |
__ntapi->zw_close(hfile);
|
|
|
39c844 |
|
|
|
c164ff |
/* tty session (optional) */
|
|
|
c164ff |
if (sparams->hsession) {
|
|
|
c164ff |
if ((status = __ntapi->tty_client_process_register(
|
|
|
c164ff |
sparams->hsession,
|
|
|
c164ff |
cparams.pbi.unique_process_id,
|
|
|
c164ff |
0,NT_TTY_INHERIT_HANDLES,0)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,
|
|
|
c164ff |
cparams.hprocess,
|
|
|
c164ff |
cparams.hthread,
|
|
|
c164ff |
status);
|
|
|
c164ff |
|
|
|
c164ff |
session.pid = rtctx->alt_cid_self.pid;
|
|
|
c164ff |
session.pgid = rtctx->alt_cid_self.pgid;
|
|
|
c164ff |
session.sid = rtctx->alt_cid_self.sid;
|
|
|
c164ff |
session.syspid = cparams.pbi.unique_process_id;
|
|
|
c164ff |
|
|
|
875bdc |
if ((status = __ntapi->tty_client_session_set(
|
|
|
875bdc |
sparams->hsession,
|
|
|
875bdc |
&session)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,
|
|
|
c164ff |
cparams.hprocess,
|
|
|
c164ff |
cparams.hthread,
|
|
|
c164ff |
status);
|
|
|
c164ff |
}
|
|
|
c164ff |
|
|
|
c164ff |
/* output */
|
|
|
c164ff |
sparams->hprocess = cparams.hprocess;
|
|
|
c164ff |
sparams->hthread = cparams.hthread;
|
|
|
c164ff |
sparams->rdata = crtblock.remote_addr;
|
|
|
c164ff |
|
|
|
c164ff |
sparams->cid.process_id = cparams.pbi.unique_process_id;
|
|
|
c164ff |
sparams->cid.thread_id = cparams.cid.thread_id;
|
|
|
c164ff |
|
|
|
c164ff |
__ntapi->tt_generic_memcpy(
|
|
|
c164ff |
&sparams->pbi,
|
|
|
c164ff |
&cparams.pbi,
|
|
|
c164ff |
sizeof(nt_pbi));
|
|
|
c164ff |
|
|
|
c164ff |
/* create suspended? */
|
|
|
c164ff |
if (sparams->fsuspended)
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,NT_STATUS_SUCCESS);
|
|
|
c164ff |
|
|
|
c164ff |
/* tada */
|
|
|
c164ff |
if ((status = __ntapi->zw_resume_thread(cparams.hthread,0)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,
|
|
|
c164ff |
cparams.hprocess,
|
|
|
c164ff |
cparams.hthread,
|
|
|
c164ff |
status);
|
|
|
c164ff |
|
|
|
c164ff |
/* hready */
|
|
|
c164ff |
hchild[1] = cparams.hprocess;
|
|
|
c164ff |
hchild[0] = rdata->hready;
|
|
|
c164ff |
|
|
|
c164ff |
__ntapi->zw_wait_for_multiple_objects(
|
|
|
c164ff |
2,hchild,
|
|
|
c164ff |
NT_WAIT_ANY,
|
|
|
c164ff |
NT_SYNC_NON_ALERTABLE,
|
|
|
c164ff |
sparams->timeout);
|
|
|
c164ff |
|
|
|
c164ff |
if ((status = __ntapi->zw_query_event(
|
|
|
c164ff |
rdata->hready,
|
|
|
c164ff |
NT_EVENT_BASIC_INFORMATION,
|
|
|
c164ff |
&sparams->eready,
|
|
|
c164ff |
sizeof(sparams->eready),
|
|
|
c164ff |
&(size_t){0})))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,
|
|
|
c164ff |
cparams.hprocess,
|
|
|
c164ff |
cparams.hthread,
|
|
|
c164ff |
status);
|
|
|
c164ff |
|
|
|
c164ff |
/* all done */
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,NT_STATUS_SUCCESS);
|
|
|
c164ff |
}
|