1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) DIGITEO - 2010 - Allan CORNET
4 *
5 * Copyright (C) 2012 - 2016 - Scilab Enterprises
6 *
7 * This file is hereby licensed under the terms of the GNU GPL v2.0,
8 * pursuant to article 5.3.4 of the CeCILL v.2.1.
9 * This file was originally licensed under the terms of the CeCILL v2.1,
10 * and continues to be available under such terms.
11 * For more information, see the COPYING file which you should have received
12 * along with this program.
13 *
14 */
15 /*--------------------------------------------------------------------------*/
16 #include <windows.h>
17 #include <WinNT.h>
18 #include <setjmp.h>
19 #include "forkWindows.h"
20 /*--------------------------------------------------------------------------*/
21 typedef LONG NTSTATUS;
22 /*--------------------------------------------------------------------------*/
23 typedef struct _SYSTEM_HANDLE_INFORMATION
24 {
25 ULONG ProcessId;
26 UCHAR ObjectTypeNumber;
27 UCHAR Flags;
28 USHORT Handle;
29 PVOID Object;
30 ACCESS_MASK GrantedAccess;
31 } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
32 /*--------------------------------------------------------------------------*/
33 typedef struct _OBJECT_ATTRIBUTES
34 {
35 ULONG Length;
36 HANDLE RootDirectory;
37 PVOID /* really PUNICODE_STRING */ ObjectName;
38 ULONG Attributes;
39 PVOID SecurityDescriptor; /* type SECURITY_DESCRIPTOR */
40 PVOID SecurityQualityOfService; /* type SECURITY_QUALITY_OF_SERVICE */
41 } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
42 /*--------------------------------------------------------------------------*/
43 typedef enum _MEMORY_INFORMATION_
44 {
45 MemoryBasicInformation,
46 MemoryWorkingSetList,
47 MemorySectionName,
48 MemoryBasicVlmInformation
49 } MEMORY_INFORMATION_CLASS;
50 /*--------------------------------------------------------------------------*/
51 typedef struct _CLIENT_ID
52 {
53 HANDLE UniqueProcess;
54 HANDLE UniqueThread;
55 } CLIENT_ID, *PCLIENT_ID;
56 /*--------------------------------------------------------------------------*/
57 typedef struct _USER_STACK
58 {
59 PVOID FixedStackBase;
60 PVOID FixedStackLimit;
61 PVOID ExpandableStackBase;
62 PVOID ExpandableStackLimit;
63 PVOID ExpandableStackBottom;
64 } USER_STACK, *PUSER_STACK;
65 /*--------------------------------------------------------------------------*/
66 typedef LONG KPRIORITY;
67 typedef ULONG_PTR KAFFINITY;
68 typedef KAFFINITY *PKAFFINITY;
69 /*--------------------------------------------------------------------------*/
70 typedef struct _THREAD_BASIC_INFORMATION
71 {
72 NTSTATUS ExitStatus;
73 PVOID TebBaseAddress;
74 CLIENT_ID ClientId;
75 KAFFINITY AffinityMask;
76 KPRIORITY Priority;
77 KPRIORITY BasePriority;
78 } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
79 /*--------------------------------------------------------------------------*/
80 typedef enum _SYSTEM_INFORMATION_CLASS { SystemHandleInformation = 0x10 } SYSTEM_INFORMATION_CLASS;
81 /*--------------------------------------------------------------------------*/
82 typedef NTSTATUS (NTAPI *ZwWriteVirtualMemory_t)(IN HANDLE ProcessHandle,
83 IN PVOID BaseAddress,
84 IN PVOID Buffer,
85 IN ULONG NumberOfBytesToWrite,
86 OUT PULONG NumberOfBytesWritten OPTIONAL);
87 /*--------------------------------------------------------------------------*/
88 typedef NTSTATUS (NTAPI *ZwCreateProcess_t)(OUT PHANDLE ProcessHandle,
89 IN ACCESS_MASK DesiredAccess,
90 IN POBJECT_ATTRIBUTES ObjectAttributes,
91 IN HANDLE InheriteFromProcessHandle,
92 IN BOOLEAN InheritHandles,
93 IN HANDLE SectionHandle OPTIONAL,
94 IN HANDLE DebugPort OPTIONAL,
95 IN HANDLE ExceptionPort OPTIONAL);
96 /*--------------------------------------------------------------------------*/
97 typedef NTSTATUS (WINAPI *ZwQuerySystemInformation_t)(SYSTEM_INFORMATION_CLASS SystemInformationClass,
98 PVOID SystemInformation,
99 ULONG SystemInformationLength,
100 PULONG ReturnLength);
101 typedef NTSTATUS (NTAPI *ZwQueryVirtualMemory_t)(IN HANDLE ProcessHandle,
102 IN PVOID BaseAddress,
103 IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
104 OUT PVOID MemoryInformation,
105 IN ULONG MemoryInformationLength,
106 OUT PULONG ReturnLength OPTIONAL);
107 /*--------------------------------------------------------------------------*/
108 typedef NTSTATUS (NTAPI *ZwGetContextThread_t)(IN HANDLE ThreadHandle, OUT PCONTEXT Context);
109 typedef NTSTATUS (NTAPI *ZwCreateThread_t)(OUT PHANDLE ThreadHandle,
110 IN ACCESS_MASK DesiredAccess,
111 IN POBJECT_ATTRIBUTES ObjectAttributes,
112 IN HANDLE ProcessHandle,
113 OUT PCLIENT_ID ClientId,
114 IN PCONTEXT ThreadContext,
115 IN PUSER_STACK UserStack,
116 IN BOOLEAN CreateSuspended);
117 /*--------------------------------------------------------------------------*/
118 typedef NTSTATUS (NTAPI *ZwResumeThread_t)(IN HANDLE ThreadHandle, OUT PULONG SuspendCount OPTIONAL);
119 typedef NTSTATUS (NTAPI *ZwClose_t)(IN HANDLE ObjectHandle);
120 typedef NTSTATUS (NTAPI *ZwQueryInformationThread_t)(IN HANDLE ThreadHandle,
121 IN THREAD_INFORMATION_CLASS ThreadInformationClass,
122 OUT PVOID ThreadInformation,
123 IN ULONG ThreadInformationLength,
124 OUT PULONG ReturnLength OPTIONAL );
125 /*--------------------------------------------------------------------------*/
126 static ZwCreateProcess_t ZwCreateProcess = NULL;
127 static ZwQuerySystemInformation_t ZwQuerySystemInformation = NULL;
128 static ZwQueryVirtualMemory_t ZwQueryVirtualMemory = NULL;
129 static ZwCreateThread_t ZwCreateThread = NULL;
130 static ZwGetContextThread_t ZwGetContextThread = NULL;
131 static ZwResumeThread_t ZwResumeThread = NULL;
132 static ZwClose_t ZwClose = NULL;
133 static ZwQueryInformationThread_t ZwQueryInformationThread = NULL;
134 static ZwWriteVirtualMemory_t ZwWriteVirtualMemory = NULL;
135 /*--------------------------------------------------------------------------*/
136 #define NtCurrentProcess() ((HANDLE)-1)
137 #define NtCurrentThread() ((HANDLE) -2)
138 /* we use really the Nt versions - so the following is just for completeness */
139 #define ZwCurrentProcess() NtCurrentProcess()
140 #define ZwCurrentThread() NtCurrentThread()
141 #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
142 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
143 /*--------------------------------------------------------------------------*/
144 /* setjmp env for the jump back into the fork() function */
145 static jmp_buf jenv;
146 /*--------------------------------------------------------------------------*/
147 /* entry point for our child thread process - just longjmp into fork */
child_entry(void)148 static int child_entry(void)
149 {
150 longjmp(jenv, 1);
151 return 0;
152 }
153 /*--------------------------------------------------------------------------*/
haveLoadedFunctionsForFork(void)154 static BOOL haveLoadedFunctionsForFork(void)
155 {
156 HMODULE ntdll = GetModuleHandle("ntdll");
157 if (ntdll == NULL)
158 {
159 return FALSE;
160 }
161
162 if (ZwCreateProcess && ZwQuerySystemInformation && ZwQueryVirtualMemory &&
163 ZwCreateThread && ZwGetContextThread && ZwResumeThread &&
164 ZwQueryInformationThread && ZwWriteVirtualMemory && ZwClose)
165 {
166 return TRUE;
167 }
168
169 ZwCreateProcess = (ZwCreateProcess_t) GetProcAddress(ntdll, "ZwCreateProcess");
170 ZwQuerySystemInformation = (ZwQuerySystemInformation_t) GetProcAddress(ntdll, "ZwQuerySystemInformation");
171 ZwQueryVirtualMemory = (ZwQueryVirtualMemory_t) GetProcAddress(ntdll, "ZwQueryVirtualMemory");
172 ZwCreateThread = (ZwCreateThread_t) GetProcAddress(ntdll, "ZwCreateThread");
173 ZwGetContextThread = (ZwGetContextThread_t) GetProcAddress(ntdll, "ZwGetContextThread");
174 ZwResumeThread = (ZwResumeThread_t) GetProcAddress(ntdll, "ZwResumeThread");
175 ZwQueryInformationThread = (ZwQueryInformationThread_t) GetProcAddress(ntdll, "ZwQueryInformationThread");
176 ZwWriteVirtualMemory = (ZwWriteVirtualMemory_t) GetProcAddress(ntdll, "ZwWriteVirtualMemory");
177 ZwClose = (ZwClose_t) GetProcAddress(ntdll, "ZwClose");
178
179 if (ZwCreateProcess && ZwQuerySystemInformation && ZwQueryVirtualMemory &&
180 ZwCreateThread && ZwGetContextThread && ZwResumeThread &&
181 ZwQueryInformationThread && ZwWriteVirtualMemory && ZwClose)
182 {
183 return TRUE;
184 }
185 else
186 {
187 ZwCreateProcess = NULL;
188 ZwQuerySystemInformation = NULL;
189 ZwQueryVirtualMemory = NULL;
190 ZwCreateThread = NULL;
191 ZwGetContextThread = NULL;
192 ZwResumeThread = NULL;
193 ZwQueryInformationThread = NULL;
194 ZwWriteVirtualMemory = NULL;
195 ZwClose = NULL;
196 }
197 return FALSE;
198 }
199 /*--------------------------------------------------------------------------*/
fork(void)200 int fork(void)
201 {
202 HANDLE hProcess = 0, hThread = 0;
203 OBJECT_ATTRIBUTES oa = { sizeof(oa) };
204 MEMORY_BASIC_INFORMATION mbi;
205 CLIENT_ID cid;
206 USER_STACK stack;
207 PNT_TIB tib;
208 THREAD_BASIC_INFORMATION tbi;
209
210 CONTEXT context = {CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT};
211
212 if (setjmp(jenv) != 0)
213 {
214 return 0; /* return as a child */
215 }
216
217 /* check whether the entry points are initilized and get them if necessary */
218 if (!ZwCreateProcess && !haveLoadedFunctionsForFork())
219 {
220 return -1;
221 }
222
223 /* create forked process */
224 ZwCreateProcess(&hProcess, PROCESS_ALL_ACCESS, &oa, NtCurrentProcess(), TRUE, 0, 0, 0);
225
226 /* set the Eip for the child process to our child function */
227 ZwGetContextThread(NtCurrentThread(), &context);
228
229 /* In x64 the Eip and Esp are not present, their x64 counterparts are Rip and
230 Rsp respectively.
231 */
232 #if _WIN64
233 context.Rip = (ULONG)child_entry;
234 #else
235 context.Eip = (ULONG)child_entry;
236 #endif
237
238 #if _WIN64
239 ZwQueryVirtualMemory(NtCurrentProcess(), (PVOID)context.Rsp, MemoryBasicInformation, &mbi, sizeof mbi, 0);
240 #else
241 ZwQueryVirtualMemory(NtCurrentProcess(), (PVOID)context.Esp, MemoryBasicInformation, &mbi, sizeof mbi, 0);
242 #endif
243
244 stack.FixedStackBase = 0;
245 stack.FixedStackLimit = 0;
246 stack.ExpandableStackBase = (PCHAR)mbi.BaseAddress + mbi.RegionSize;
247 stack.ExpandableStackLimit = mbi.BaseAddress;
248 stack.ExpandableStackBottom = mbi.AllocationBase;
249
250 /* create thread using the modified context and stack */
251 ZwCreateThread(&hThread, THREAD_ALL_ACCESS, &oa, hProcess, &cid, &context, &stack, TRUE);
252
253 /* copy exception table */
254 ZwQueryInformationThread(NtCurrentThread(), ThreadMemoryPriority, &tbi, sizeof tbi, 0);
255 tib = (PNT_TIB)tbi.TebBaseAddress;
256 ZwQueryInformationThread(hThread, ThreadMemoryPriority, &tbi, sizeof tbi, 0);
257 ZwWriteVirtualMemory(hProcess, tbi.TebBaseAddress, &tib->ExceptionList, sizeof tib->ExceptionList, 0);
258
259 /* start (resume really) the child */
260 ZwResumeThread(hThread, 0);
261
262 /* clean up */
263 ZwClose(hThread);
264 ZwClose(hProcess);
265
266 /* exit with child's pid */
267 return (int)cid.UniqueProcess;
268 }
269 /*--------------------------------------------------------------------------*/
270