/* |
* fork.c |
* Experimental fork() on Windows. Requires NT 6 subsystem or |
* newer. |
* |
* Copyright (c) 2012 William Pitcock <[email protected]> |
* |
* Permission to use, copy, modify, and/or distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* copyright notice and this permission notice appear in all copies. |
* |
* This software is provided 'as is' and without any warranty, express or |
* implied. In no event shall the authors be liable for any damages arising |
* from the use of this software. |
*/ |
#define_WIN32_WINNT0x0600 |
#defineWIN32_LEAN_AND_MEAN |
#include<windows.h> |
#include<winnt.h> |
#include<winternl.h> |
#include<stdio.h> |
#include<errno.h> |
#include<assert.h> |
#include<process.h> |
typedefstruct _CLIENT_ID { |
PVOID UniqueProcess; |
PVOID UniqueThread; |
} CLIENT_ID, *PCLIENT_ID; |
typedefstruct _SECTION_IMAGE_INFORMATION { |
PVOID EntryPoint; |
ULONG StackZeroBits; |
ULONG StackReserved; |
ULONG StackCommit; |
ULONG ImageSubsystem; |
WORD SubSystemVersionLow; |
WORD SubSystemVersionHigh; |
ULONG Unknown1; |
ULONG ImageCharacteristics; |
ULONG ImageMachineType; |
ULONG Unknown2[3]; |
} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; |
typedefstruct _RTL_USER_PROCESS_INFORMATION { |
ULONG Size; |
HANDLE Process; |
HANDLE Thread; |
CLIENT_ID ClientId; |
SECTION_IMAGE_INFORMATION ImageInformation; |
} RTL_USER_PROCESS_INFORMATION, *PRTL_USER_PROCESS_INFORMATION; |
#defineRTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED0x00000001 |
#defineRTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES0x00000002 |
#defineRTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE0x00000004 |
#defineRTL_CLONE_PARENT0 |
#defineRTL_CLONE_CHILD297 |
typedef DWORD pid_t; |
typedefNTSTATUS (*RtlCloneUserProcess_f)(ULONG ProcessFlags, |
PSECURITY_DESCRIPTOR ProcessSecurityDescriptor /* optional */, |
PSECURITY_DESCRIPTOR ThreadSecurityDescriptor /* optional */, |
HANDLE DebugPort /* optional */, |
PRTL_USER_PROCESS_INFORMATION ProcessInformation); |
pid_tfork(void) |
{ |
HMODULE mod; |
RtlCloneUserProcess_f clone_p; |
RTL_USER_PROCESS_INFORMATION process_info; |
NTSTATUS result; |
mod = GetModuleHandle('ntdll.dll'); |
if (!mod) |
return -ENOSYS; |
clone_p = (RtlCloneUserProcess_f)GetProcAddress(mod, 'RtlCloneUserProcess'); |
if (clone_p NULL) |
return -ENOSYS; |
/* lets do this */ |
result = clone_p(RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED | RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES, NULL, NULL, NULL, &process_info); |
if (result RTL_CLONE_PARENT) |
{ |
HANDLE me, hp, ht, hcp = 0; |
DWORD pi, ti, mi; |
me = GetCurrentProcess(); |
pi = (DWORD)process_info.ClientId.UniqueProcess; |
ti = (DWORD)process_info.ClientId.UniqueThread; |
assert(hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi)); |
assert(ht = OpenThread(THREAD_ALL_ACCESS, FALSE, ti)); |
ResumeThread(ht); |
CloseHandle(ht); |
CloseHandle(hp); |
return (pid_t)pi; |
} |
elseif (result RTL_CLONE_CHILD) |
{ |
/* fix stdio */ |
AllocConsole(); |
return0; |
} |
else |
return -1; |
/* NOTREACHED */ |
return -1; |
} |
#ifdef __TEST__ |
intmain(int argc, constchar *argv[]) |
{ |
pid_t pid; |
printf('Forking.n'); |
pid = fork(); |
switch (pid) { |
case0: |
{ |
FILE *f = fopen('C:Developmentcpp.sandboxwin32win32-forkforktest.dat', 'w'); |
fprintf(f, 'okn'); |
fclose(f); |
break; |
} |
default: |
printf('child %dn', pid); |
while (1) { Sleep(1000); } |
break; |
} |
} |
#endif |