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