summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/ntapi/nt_process.h3
-rw-r--r--include/ntapi/ntapi.h1
-rw-r--r--project/common.mk1
-rw-r--r--src/internal/ntapi.c1
-rw-r--r--src/internal/ntapi_fnapi.h1
-rw-r--r--src/process/ntapi_tt_spawn_foreign_process.c316
6 files changed, 323 insertions, 0 deletions
diff --git a/include/ntapi/nt_process.h b/include/ntapi/nt_process.h
index b69aa61..2dd51cf 100644
--- a/include/ntapi/nt_process.h
+++ b/include/ntapi/nt_process.h
@@ -788,6 +788,9 @@ typedef int32_t __stdcall ntapi_tt_create_native_process(
typedef int32_t __stdcall ntapi_tt_spawn_native_process(
__in_out nt_spawn_process_params * sparams);
+typedef int32_t __stdcall ntapi_tt_spawn_foreign_process(
+ __in_out nt_spawn_process_params * sparams);
+
typedef int32_t __stdcall ntapi_tt_get_runtime_data(
__out nt_runtime_data ** pdata,
__in wchar16_t ** argv);
diff --git a/include/ntapi/ntapi.h b/include/ntapi/ntapi.h
index 528ab69..d1b50be 100644
--- a/include/ntapi/ntapi.h
+++ b/include/ntapi/ntapi.h
@@ -482,6 +482,7 @@ typedef struct _ntapi_vtbl {
ntapi_tt_create_remote_process_params * tt_create_remote_process_params;
ntapi_tt_create_native_process * tt_create_native_process;
ntapi_tt_spawn_native_process * tt_spawn_native_process;
+ ntapi_tt_spawn_foreign_process * tt_spawn_foreign_process;
ntapi_tt_get_runtime_data * tt_get_runtime_data;
ntapi_tt_init_runtime_data * tt_init_runtime_data;
ntapi_tt_update_runtime_data * tt_update_runtime_data;
diff --git a/project/common.mk b/project/common.mk
index 71b7da3..405f999 100644
--- a/project/common.mk
+++ b/project/common.mk
@@ -49,6 +49,7 @@ COMMON_SRCS = \
src/process/ntapi_tt_get_runtime_data.c \
src/process/ntapi_tt_init_runtime_data.c \
src/process/ntapi_tt_map_image_as_data.c \
+ src/process/ntapi_tt_spawn_foreign_process.c \
src/process/ntapi_tt_spawn_native_process.c \
src/process/tt_fork_v1.c \
src/pty/ntapi_pty_cancel.c \
diff --git a/src/internal/ntapi.c b/src/internal/ntapi.c
index 1047606..06a70fe 100644
--- a/src/internal/ntapi.c
+++ b/src/internal/ntapi.c
@@ -271,6 +271,7 @@ static int32_t __fastcall __ntapi_init_once(ntapi_vtbl ** pvtbl)
__ntapi->tt_fork = __ntapi_tt_fork;
__ntapi->tt_create_remote_process_params = __ntapi_tt_create_remote_process_params;
__ntapi->tt_spawn_native_process = __ntapi_tt_spawn_native_process;
+ __ntapi->tt_spawn_foreign_process = __ntapi_tt_spawn_foreign_process;
__ntapi->tt_get_runtime_data = __ntapi_tt_get_runtime_data;
__ntapi->tt_init_runtime_data = __ntapi_tt_init_runtime_data;
__ntapi->tt_update_runtime_data = __ntapi_tt_update_runtime_data;
diff --git a/src/internal/ntapi_fnapi.h b/src/internal/ntapi_fnapi.h
index 05ff9ab..beb4fbb 100644
--- a/src/internal/ntapi_fnapi.h
+++ b/src/internal/ntapi_fnapi.h
@@ -143,6 +143,7 @@ ntapi_tt_create_remote_runtime_data __ntapi_tt_create_remote_runtime_data;
ntapi_tt_create_native_process __ntapi_tt_create_native_process_v1;
ntapi_tt_create_native_process __ntapi_tt_create_native_process_v2;
ntapi_tt_spawn_native_process __ntapi_tt_spawn_native_process;
+ntapi_tt_spawn_foreign_process __ntapi_tt_spawn_foreign_process;
ntapi_tt_get_runtime_data __ntapi_tt_get_runtime_data;
ntapi_tt_init_runtime_data __ntapi_tt_init_runtime_data;
ntapi_tt_update_runtime_data __ntapi_tt_update_runtime_data;
diff --git a/src/process/ntapi_tt_spawn_foreign_process.c b/src/process/ntapi_tt_spawn_foreign_process.c
new file mode 100644
index 0000000..cc9fac4
--- /dev/null
+++ b/src/process/ntapi_tt_spawn_foreign_process.c
@@ -0,0 +1,316 @@
+/********************************************************/
+/* ntapi: Native API core library */
+/* Copyright (C) 2013--2017 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
+/********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <pemagine/pemagine.h>
+#include <ntapi/nt_status.h>
+#include <ntapi/nt_object.h>
+#include <ntapi/nt_thread.h>
+#include <ntapi/nt_process.h>
+#include <ntapi/nt_string.h>
+#include <ntapi/ntapi.h>
+#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);
+}