|
|
c164ff |
/********************************************************/
|
|
|
c164ff |
/* ntapi: Native API core library */
|
|
|
dde53a |
/* Copyright (C) 2013--2017 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 |
wchar16_t * imgbuf;
|
|
|
ec0b96 |
uint32_t fsuspended;
|
|
|
da4030 |
size_t buflen;
|
|
|
da4030 |
size_t written;
|
|
|
103960 |
char * raddr;
|
|
|
103960 |
size_t rsize;
|
|
|
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 */
|
|
|
3c26f0 |
hat = (sparams->hroot && (sparams->argv[0][0] == '/'))
|
|
|
3c26f0 |
? sparams->hroot
|
|
|
c164ff |
: rtctx->hcwd
|
|
|
c164ff |
? rtctx->hcwd
|
|
|
c164ff |
: peb->process_params->cwd_handle;
|
|
|
c164ff |
|
|
|
c164ff |
/* patharg */
|
|
|
c03267 |
patharg = sparams->patharg
|
|
|
c03267 |
? (sparams->patharg[0] == '/')
|
|
|
c03267 |
? (sparams->patharg[1] == '?')
|
|
|
c03267 |
? &sparams->patharg[0]
|
|
|
c03267 |
: &sparams->patharg[1]
|
|
|
c03267 |
: &sparams->patharg[0]
|
|
|
c03267 |
: 0;
|
|
|
c164ff |
|
|
|
c164ff |
/* rtblock, rdata */
|
|
|
c164ff |
rtblock.addr = 0;
|
|
|
da4030 |
rtblock.size = 0x40000;
|
|
|
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 |
|
|
|
804edf |
/* abi */
|
|
|
804edf |
if (!(__ntapi->tt_guid_compare(&rdata->abi,&(nt_guid)NT_PROCESS_GUID_UNSPEC)))
|
|
|
804edf |
__ntapi->tt_guid_copy(
|
|
|
804edf |
&rdata->abi,
|
|
|
804edf |
&(nt_guid)NT_PROCESS_GUID_RTDATA);
|
|
|
804edf |
|
|
|
c164ff |
/* imgbuf */
|
|
|
c164ff |
imgbuf = (wchar16_t *)rtblock.addr;
|
|
|
da4030 |
imgbuf += 0x30000 / 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,
|
|
|
da4030 |
imgbuf,0x10000,
|
|
|
da4030 |
&(uint32_t){0})))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,status);
|
|
|
c164ff |
|
|
|
c164ff |
imgname = (nt_unicode_string *)imgbuf;
|
|
|
c164ff |
|
|
|
c164ff |
/* argv, envp */
|
|
|
da4030 |
buflen = rtblock.size;
|
|
|
da4030 |
buflen -= sizeof(*rdata);
|
|
|
da4030 |
|
|
|
c164ff |
if ((status = __ntapi->tt_array_copy_utf8(
|
|
|
c164ff |
&rdata->argc,
|
|
|
c164ff |
(const char **)sparams->argv,
|
|
|
c164ff |
(const char **)sparams->envp,
|
|
|
2104cf |
sparams->interp,
|
|
|
c164ff |
sparams->optarg,
|
|
|
15812f |
sparams->script,
|
|
|
c164ff |
rtblock.addr,
|
|
|
c164ff |
rdata->buffer,
|
|
|
da4030 |
buflen,&written)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,status);
|
|
|
c164ff |
|
|
|
da4030 |
rdata->argv = (char **)&((nt_runtime_data *)0)->buffer;
|
|
|
da4030 |
rdata->envp = rdata->argv + rdata->argc + 1;
|
|
|
c164ff |
|
|
|
da4030 |
rdata->wargv = (wchar16_t **)rdata->buffer;
|
|
|
da4030 |
rdata->wargv += written / sizeof(wchar16_t **) + 1;
|
|
|
da4030 |
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;
|
|
|
da4030 |
wch = (wchar16_t *)pwarg;
|
|
|
da4030 |
|
|
|
da4030 |
if ((written == (uintptr_t)wch - (uintptr_t)rdata) > rtblock.size)
|
|
|
da4030 |
return __tt_spawn_return(
|
|
|
da4030 |
&rtblock,0,0,NT_STATUS_BUFFER_TOO_SMALL);
|
|
|
da4030 |
|
|
|
da4030 |
buflen = rtblock.size;
|
|
|
da4030 |
buflen -= written;
|
|
|
c164ff |
|
|
|
c164ff |
if ((status = __ntapi->tt_array_convert_utf8_to_utf16(
|
|
|
c164ff |
rargv,
|
|
|
c164ff |
rdata->wargv,
|
|
|
da4030 |
rdata,wch,
|
|
|
da4030 |
buflen,&written)))
|
|
|
c164ff |
return __tt_spawn_return(
|
|
|
c164ff |
&rtblock,0,0,status);
|
|
|
c164ff |
|
|
|
da4030 |
wch += written/sizeof(wchar16_t);
|
|
|
da4030 |
buflen -= written;
|
|
|
c164ff |
|
|
|
c164ff |
if ((status = __ntapi->tt_array_convert_utf8_to_utf16(
|
|
|
c164ff |
renvp,
|
|
|
c164ff |
rdata->wenvp,
|
|
|
da4030 |
rdata,wch,
|
|
|
da4030 |
buflen,&written)))
|
|
|
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 |
|
|
|
da4030 |
wch += written/sizeof(wchar16_t);
|
|
|
da4030 |
buflen -= written;
|
|
|
da4030 |
|
|
|
da4030 |
if (buflen < 0x10000)
|
|
|
da4030 |
return __tt_spawn_return(
|
|
|
da4030 |
&rtblock,0,0,NT_STATUS_BUFFER_TOO_SMALL);
|
|
|
da4030 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
da4030 |
crtblock.size = (size_t)wch - (size_t)rdata;
|
|
|
da4030 |
crtblock.size += 0xFFFF;
|
|
|
da4030 |
crtblock.size |= 0xFFFF;
|
|
|
da4030 |
crtblock.size ^= 0xFFFF;
|
|
|
da4030 |
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 |
|
|
|
103960 |
/* additional context */
|
|
|
103960 |
if (rtctx->ctx_addr) {
|
|
|
103960 |
rdata->ctx_addr = 0;
|
|
|
103960 |
rdata->ctx_commit = rtctx->ctx_size;
|
|
|
103960 |
|
|
|
103960 |
rdata->ctx_commit += (__NT_INTERNAL_PAGE_SIZE - 1);
|
|
|
103960 |
rdata->ctx_commit |= (__NT_INTERNAL_PAGE_SIZE - 1);
|
|
|
103960 |
rdata->ctx_commit ^= (__NT_INTERNAL_PAGE_SIZE - 1);
|
|
|
103960 |
|
|
|
103960 |
if ((status = __ntapi->zw_allocate_virtual_memory(
|
|
|
103960 |
cparams.hprocess,
|
|
|
103960 |
&rdata->ctx_addr,0,
|
|
|
103960 |
&rdata->ctx_commit,
|
|
|
103960 |
NT_MEM_COMMIT,
|
|
|
103960 |
NT_PAGE_READWRITE)))
|
|
|
103960 |
return __tt_spawn_return(
|
|
|
103960 |
&rtblock,
|
|
|
103960 |
cparams.hprocess,
|
|
|
103960 |
cparams.hthread,
|
|
|
103960 |
status);
|
|
|
103960 |
|
|
|
103960 |
if ((status = __ntapi->zw_write_virtual_memory(
|
|
|
103960 |
cparams.hprocess,
|
|
|
103960 |
rdata->ctx_addr,
|
|
|
103960 |
rtctx->ctx_addr,
|
|
|
103960 |
rtctx->ctx_size,
|
|
|
103960 |
&rdata->ctx_size)))
|
|
|
103960 |
return __tt_spawn_return(
|
|
|
103960 |
&rtblock,
|
|
|
103960 |
cparams.hprocess,
|
|
|
103960 |
cparams.hthread,
|
|
|
103960 |
status);
|
|
|
103960 |
|
|
|
103960 |
raddr = crtblock.remote_addr;
|
|
|
103960 |
raddr += __offsetof(nt_runtime_data,ctx_addr);
|
|
|
103960 |
|
|
|
103960 |
rsize = __offsetof(nt_runtime_data,ctx_offset);
|
|
|
103960 |
rsize -= __offsetof(nt_runtime_data,ctx_addr);
|
|
|
103960 |
|
|
|
103960 |
if ((status = __ntapi->zw_write_virtual_memory(
|
|
|
103960 |
cparams.hprocess,
|
|
|
103960 |
raddr,(char *)&rdata->ctx_addr,
|
|
|
103960 |
rsize,&rsize)))
|
|
|
103960 |
return __tt_spawn_return(
|
|
|
103960 |
&rtblock,
|
|
|
103960 |
cparams.hprocess,
|
|
|
103960 |
cparams.hthread,
|
|
|
103960 |
status);
|
|
|
103960 |
}
|
|
|
103960 |
|
|
|
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;
|
|
|
3e609e |
session.syspid = (uint32_t)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? */
|
|
|
ec0b96 |
if (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 |
}
|