| /* A part of the Native C Library for Windows NT |
| Copyright 2007-2015 PC GO Ld. |
| |
| This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| */ |
| |
| #include <windows.h> |
| #include <nt.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <process.h> |
| #include <pathname.h> |
| #include <string.h> |
| #include <wchar.h> |
| |
| //#include <stdio.h> |
| |
| wchar_t *__environ_to_wenvblock(wchar_t *buffer, size_t buffer_size); |
| |
| static long int open_file_for_execute(void **handle, UNICODE_STRING *ntpathname) { |
| //void *fh; |
| OBJECT_ATTRIBUTES foa = { sizeof(OBJECT_ATTRIBUTES), NULL, ntpathname, OBJ_INHERIT, NULL, NULL }; |
| IO_STATUS_BLOCK io_status; |
| unsigned long int file_share = FILE_SHARE_READ | FILE_SHARE_DELETE; |
| return NtOpenFile(handle, SYNCHRONIZE | FILE_EXECUTE, &foa, &io_status, file_share, FILE_NON_DIRECTORY_FILE); |
| } |
| |
| pid_t _create_process(const char *program, const char *commandline, int start) { |
| if(!program) { |
| errno = EFAULT; |
| return -1; |
| } |
| if(!*program) { |
| errno = ENOENT; |
| return -1; |
| } |
| if(*program != '/') { |
| errno = ENOSYS; |
| return -1; |
| } |
| if(!commandline) { |
| int i, offset = 0; |
| for(i=0; program[i]; i++) if(program[i] == '/') offset = i + 1; |
| //commandline = offset ? program + offset + 1 : program; |
| commandline = program + offset; |
| for(i=offset; program[i]; i++) if(program[i] == ' ') { |
| static char buffer[258] = "\""; |
| size_t len = strlen(commandline); |
| if(len > 255) len = 255; |
| memcpy(buffer + 1, commandline, len); |
| memcpy(buffer + 1 + len, "\"", 2); |
| commandline = buffer; |
| break; |
| } |
| } |
| UNICODE_STRING ntpathname; |
| UNICODE_STRING command_line; |
| KUSER_SHARED_DATA *shared_data = (KUSER_SHARED_DATA *)USER_SHARED_DATA; |
| size_t dllpath_len = wcslen(shared_data->NtSystemRoot) * 2 + 5 + 1; |
| wchar_t wdllpath[dllpath_len]; |
| wcscpy(wdllpath, shared_data->NtSystemRoot); |
| wcscat(wdllpath, L"\\lib;"); |
| wcscat(wdllpath, shared_data->NtSystemRoot); |
| UNICODE_STRING dllpath = { (dllpath_len - 1) * sizeof(wchar_t), dllpath_len * sizeof(wchar_t), wdllpath }; |
| if(!RtlCreateUnicodeStringFromAsciiz(&ntpathname, program)) { |
| errno = ENOMEM; |
| return -1; |
| } |
| if(!RtlCreateUnicodeStringFromAsciiz(&command_line, commandline)) { |
| errno = ENOMEM; |
| return -1; |
| } |
| RTL_USER_PROCESS_PARAMETERS *processparameters; |
| RTL_USER_PROCESS_INFORMATION pi; |
| wchar_t wenvblock[1024]; |
| memset(&pi, 0, sizeof pi); |
| __environ_to_wenvblock(wenvblock, sizeof wenvblock); |
| long int status = RtlCreateProcessParameters(&processparameters, &ntpathname, &dllpath, NULL, &command_line, wenvblock, 0, 0, 0, 0); |
| //printf("nativelibc debug: _create_process: status = 0x%lx\n", status); |
| RtlFreeUnicodeString(&command_line); |
| if(status < 0) { |
| __set_errno_from_ntstatus(status); |
| return -1; |
| } |
| processparameters->StandardOutput = (void *)_get_stdout_fd(); |
| processparameters->StandardError = (void *)_get_stderr_fd(); |
| |
| PATHNAME_UNIX2NT_UTF16_STRUCT(ntpathname); |
| |
| void *fh; |
| status = open_file_for_execute(&fh, &ntpathname); |
| //printf("nativelibc debug: _create_process: open_file_for_execute returned: 0x%lx\n", status); |
| RtlFreeUnicodeString(&ntpathname); |
| if(status < 0) { |
| __set_errno_from_ntstatus(status); |
| return -1; |
| } |
| |
| void *sh; |
| status = NtCreateSection(&sh, SECTION_ALL_ACCESS, NULL, NULL, PAGE_EXECUTE, SEC_IMAGE, fh); |
| //printf("nativelibc debug: _create_process: status = 0x%lx\n", status); |
| NtClose(fh); |
| if(status < 0) { |
| __set_errno_from_ntstatus(status); |
| return -1; |
| } |
| |
| OBJECT_ATTRIBUTES object_attrib = { sizeof(OBJECT_ATTRIBUTES), NULL, NULL, 0, NULL, NULL }; |
| status = NtCreateProcess(&pi.ProcessHandle, PROCESS_ALL_ACCESS, &object_attrib, (void *)-1, 1, sh, NULL, NULL); |
| //printf("nativelibc debug: _create_process: status = 0x%lx\n", status); |
| if(status < 0) { |
| NtClose(sh); |
| __set_errno_from_ntstatus(status); |
| return -1; |
| } |
| |
| status = NtQuerySection(sh, SectionImageInformation, &pi.ImageInformation, sizeof pi.ImageInformation, NULL); |
| //printf("nativelibc debug: _create_process: status = 0x%lx\n", status); |
| if(status < 0) goto failed; |
| |
| PROCESS_BASIC_INFORMATION pbi; |
| status = NtQueryInformationProcess(pi.ProcessHandle, ProcessBasicInformation, &pbi, sizeof pbi, NULL); |
| //printf("nativelibc debug: _create_process: status = 0x%lx\n", status); |
| if(status < 0) goto failed; |
| |
| OBJECT_BASIC_INFORMATION obi; |
| switch((int)processparameters->StandardOutput) { |
| case TTY_FD_DEFAULT: |
| case TTY_FD_INVALID: |
| break; |
| default: |
| status = NtQueryObject(processparameters->StandardOutput, ObjectBasicInformation, &obi, sizeof obi, NULL); |
| if(status < 0) break; |
| if(obi.Attributes & OBJ_INHERIT) break; |
| status = NtDuplicateObject((void *)-1, processparameters->StandardOutput, pi.ProcessHandle, |
| &processparameters->StandardOutput, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); |
| if(status < 0) goto failed; |
| } |
| switch((int)processparameters->StandardError) { |
| case TTY_FD_DEFAULT: |
| case TTY_FD_INVALID: |
| break; |
| default: |
| status = NtQueryObject(processparameters->StandardError, ObjectBasicInformation, &obi, sizeof obi, NULL); |
| if(status < 0) break; |
| if(obi.Attributes & OBJ_INHERIT) break; |
| status = NtDuplicateObject((void *)-1, processparameters->StandardError, pi.ProcessHandle, |
| &processparameters->StandardError, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); |
| if(status < 0) goto failed; |
| } |
| |
| if(processparameters->Environment) { |
| // Copy the environment block |
| const wchar_t *s = processparameters->Environment; |
| void *e = NULL; |
| size_t envblock_size = 2; |
| while(*s++ || *s) envblock_size++; |
| envblock_size *= sizeof(wchar_t); |
| size_t envblock_size_ = envblock_size; |
| status = NtAllocateVirtualMemory(pi.ProcessHandle, &e, 0, &envblock_size_, MEM_COMMIT, PAGE_READWRITE); |
| //printf("nativelibc debug: _create_process: status = 0x%lx\n", status); |
| if(status < 0) goto failed; |
| status = NtWriteVirtualMemory(pi.ProcessHandle, e, processparameters->Environment, envblock_size, NULL); |
| //printf("nativelibc debug: _create_process: status = 0x%lx\n", status); |
| if(status < 0) goto failed; |
| processparameters->Environment = e; |
| } |
| |
| { |
| // Copy the process parameters |
| RTL_USER_PROCESS_PARAMETERS *p = NULL; |
| size_t pp_size = processparameters->MaximumLength; |
| status = NtAllocateVirtualMemory(pi.ProcessHandle, &p, 0, &pp_size, MEM_COMMIT, PAGE_READWRITE); |
| //printf("nativelibc debug: _create_process: status = 0x%lx, MaximumLength = %lu, Length = %lu\n", status, processparameters->MaximumLength, processparameters->Length); |
| if(status < 0) goto failed; |
| status = NtWriteVirtualMemory(pi.ProcessHandle, p, processparameters, processparameters->Length, NULL); |
| //printf("nativelibc debug: _create_process: status = 0x%lx\n", status); |
| if(status < 0) goto failed; |
| |
| // Copy the pointer of process parameters to the process environment block |
| status = NtWriteVirtualMemory(pi.ProcessHandle, &pbi.PebBaseAddress->ProcessParameters, &p, sizeof p, NULL); |
| //printf("nativelibc debug: _create_process: status = 0x%lx\n", status); |
| if(status < 0) goto failed; |
| } |
| |
| RtlDestroyProcessParameters(processparameters); |
| |
| // Create the main thread |
| status = RtlCreateUserThread(pi.ProcessHandle, NULL, start, pi.ImageInformation.ZeroBits, pi.ImageInformation.MaximumStackSize, |
| pi.ImageInformation.CommittedStackSize, (PUSER_THREAD_START_ROUTINE)pi.ImageInformation.TransferAddress, pbi.PebBaseAddress, &pi.ThreadHandle, &pi.ClientId); |
| //printf("nativelibc debug: _create_process: status = 0x%lx\n", status); |
| NtClose(sh); |
| if(status < 0) { |
| NtClose(pi.ProcessHandle); |
| NtClose(pi.ThreadHandle); |
| __set_errno_from_ntstatus(status); |
| return -1; |
| } |
| |
| if(start) { |
| status = NtResumeThread(pi.ThreadHandle, NULL); |
| if(status < 0) { |
| NtClose(pi.ProcessHandle); |
| NtClose(pi.ThreadHandle); |
| __set_errno_from_ntstatus(status); |
| return -1; |
| } |
| } |
| NtClose(pi.ThreadHandle); |
| |
| __child_process_table_add(pi.ClientId.UniqueProcess, pi.ProcessHandle); |
| |
| return pi.ClientId.UniqueProcess; |
| |
| failed: |
| NtClose(pi.ProcessHandle); |
| NtClose(sh); |
| RtlDestroyProcessParameters(processparameters); |
| __set_errno_from_ntstatus(status); |
| return -1; |
| } |