/*********************************************************/ /* ptycon: a pty-console bridge */ /* Copyright (C) 2016 Z. Gilboa */ /* Released under GPLv2 and GPLv3; see COPYING.PTYCON. */ /*********************************************************/ #include #include #include #include #include "ptycon_driver_impl.h" static int32_t __stdcall ptyc_spawn_return( nt_runtime_data_block * rtblock, int32_t status) { nt_runtime_data * rtdata; rtdata = (nt_runtime_data *)rtblock; if (rtdata->hready) ntapi->zw_close( rtdata->hready); ntapi->zw_free_virtual_memory( NT_CURRENT_PROCESS_HANDLE, &rtblock->addr, &rtblock->size, NT_MEM_RELEASE); return status; } int __stdcall ptyc_spawn(struct ptyc_driver_ctx * dctx) { int32_t status; char * patharg; void * hchild[2]; nt_create_process_params params; struct ptyc_driver_ctx_impl * ictx; struct ptyc_client_ctx * clctx; nt_tty_session_info session; nt_runtime_data_block rtblock; nt_runtime_data * rdata; nt_rtdata * self; nt_peb * peb; void * hat; void * hfile; char ** rargv; char ** renvp; wchar16_t ** pwarg; wchar16_t * wch; nt_unicode_string * imgname; uint32_t written; uintptr_t imgbuf[8192/sizeof(uintptr_t)]; /* init */ if (!(ictx = ptyc_get_driver_ictx(dctx))) return NT_STATUS_INVALID_HANDLE; if (!dctx->cctx->eargv) return NT_STATUS_SUCCESS; self = ictx->rtdata; clctx = &ictx->clctx; /* hat */ if (!(peb = (nt_peb *)pe_get_peb_address())) return NT_STATUS_INTERNAL_ERROR; if (!peb->process_params) return NT_STATUS_INTERNAL_ERROR; hat = (dctx->cctx->hroot && (dctx->cctx->eargv[0][0] == '/')) ? dctx->cctx->hroot : self->hcwd ? self->hcwd : peb->process_params->cwd_handle; patharg = (dctx->cctx->eargv[0][0] == '/') ? (dctx->cctx->eargv[0][1] == '?') ? &dctx->cctx->eargv[0][0] : &dctx->cctx->eargv[0][1] : &dctx->cctx->eargv[0][0]; /* hfile */ if ((status = ptyc_open_file(&hfile,hat,patharg,true))) return status; /* rtblock */ rtblock.addr = 0; rtblock.size = 0x10000; rtblock.remote_addr = 0; rtblock.remote_size = 0; rtblock.flags = 0; if ((status = ntapi->zw_allocate_virtual_memory( self->hprocess_self, &rtblock.addr,0, &rtblock.size, NT_MEM_COMMIT, NT_PAGE_READWRITE))) return status; ntapi->tt_aligned_block_memset( rtblock.addr,0,rtblock.size); if ((status = ntapi->zw_query_object( hfile, NT_OBJECT_NAME_INFORMATION, imgbuf,sizeof(imgbuf), &written))) return ptyc_spawn_return( &rtblock,status); imgname = (nt_unicode_string *)imgbuf; rdata = (nt_runtime_data *)rtblock.addr; /* argv, envp */ if ((status = ntapi->tt_array_copy_utf8( &rdata->argc, (const char **)dctx->cctx->eargv, (const char **)self->envp, 0,0,0, rtblock.addr, rdata->buffer, rtblock.size - sizeof(*rdata), &rtblock.remote_size))) return ptyc_spawn_return( &rtblock,status); rdata->argv = (char **)&((nt_runtime_data *)0)->buffer; rdata->envp = rdata->argv + rdata->argc + 1; rdata->wargv = (wchar16_t **)(rdata->buffer + (rtblock.remote_size / sizeof(uintptr_t)) + 1); rdata->wenvp = rdata->wargv + rdata->argc + 1; rargv = rdata->argv + ((uintptr_t)rtblock.addr / sizeof(char *)); renvp = rdata->envp + ((uintptr_t)rtblock.addr / sizeof(char *)); pwarg = rdata->wenvp + self->envc + 1; wch = (wchar16_t *)pwarg; if ((status = ntapi->tt_array_convert_utf8_to_utf16( rargv, rdata->wargv, rdata, wch, rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer), &rtblock.remote_size))) return ptyc_spawn_return( &rtblock,status); wch += rtblock.remote_size/sizeof(wchar16_t); if ((status = ntapi->tt_array_convert_utf8_to_utf16( renvp, rdata->wenvp, rdata, wch, rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer), &rtblock.remote_size))) return ptyc_spawn_return( &rtblock,status); rdata->wargv -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *); rdata->wenvp -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *); /* session */ if ((status = ntapi->tt_create_inheritable_event( &rdata->hready, NT_NOTIFICATION_EVENT, NT_EVENT_NOT_SIGNALED))) return ptyc_spawn_return( &rtblock,status); ntapi->tt_aligned_block_memcpy( (uintptr_t *)&rdata->cid_parent, (uintptr_t *)&self->cid_self, sizeof(nt_cid)); rdata->hroot = dctx->cctx->hroot; rdata->hcwd = self->hcwd ? self->hcwd : peb->process_params->cwd_handle; rdata->srv_keys[0] = self->srv_keys[0]; rdata->srv_keys[1] = self->srv_keys[1]; rdata->srv_keys[2] = self->srv_keys[2]; rdata->srv_keys[3] = self->srv_keys[3]; rdata->srv_keys[4] = self->srv_keys[4]; rdata->srv_keys[5] = self->srv_keys[5]; rdata->hstdin = NT_INVALID_HANDLE_VALUE; rdata->hstdout = NT_INVALID_HANDLE_VALUE; rdata->hstderr = NT_INVALID_HANDLE_VALUE; rdata->stdin_type = NT_FILE_TYPE_PTY; rdata->stdout_type = NT_FILE_TYPE_PTY; rdata->stderr_type = NT_FILE_TYPE_PTY; rdata->ptyany[0] = clctx->clinfo.any[0]; rdata->ptyany[1] = clctx->clinfo.any[1]; rdata->ptyany[2] = clctx->clinfo.any[2]; rdata->ptyany[3] = clctx->clinfo.any[3]; /* params */ ntapi->tt_aligned_block_memset( ¶ms,0,sizeof(params)); params.image_name = imgname->buffer; params.rtblock = &rtblock; params.creation_flags_process = NT_PROCESS_CREATE_FLAGS_INHERIT_HANDLES; params.creation_flags_thread = NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED; /* hoppla */ if ((status = ntapi->tt_create_native_process(¶ms))) return ptyc_spawn_return( &rtblock,status); /* clctx */ clctx->hprocess = params.hprocess; clctx->hthread = params.hthread; clctx->cid.process_id = params.cid.process_id; clctx->cid.thread_id = params.cid.thread_id; if ((status = ntapi->tty_client_process_register( self->hsession, params.pbi.unique_process_id, 0,NT_TTY_INHERIT_HANDLES,0))) ntapi->zw_terminate_process( params.hprocess, status); session.pid = 0; session.pgid = 0; session.sid = 0; session.syspid = params.pbi.unique_process_id; if ((status = ntapi->tty_client_session_set(0,&session))) ntapi->zw_terminate_process( params.hprocess, status); if ((status = ntapi->zw_resume_thread(params.hthread,0))) ntapi->zw_terminate_process( params.hprocess, status); hchild[1] = params.hprocess; hchild[0] = rdata->hready; ntapi->zw_wait_for_multiple_objects( 2,hchild, NT_WAIT_ANY, NT_SYNC_NON_ALERTABLE, 0); return ptyc_spawn_return( &rtblock,status); }