Skip to content

C:frok

Win32 fork

/*
 * 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_WINNT 0x0600
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winnt.h>
#include <ntdef.h>
#include <stdio.h>
#include <errno.h>
#include <process.h>

#ifdef __MINGW32__
typedef struct _CLIENT_ID {
    PVOID UniqueProcess;
    PVOID UniqueThread;
} CLIENT_ID, *PCLIENT_ID;

typedef struct _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;

typedef struct _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;

#define RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED    0x00000001
#define RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES     0x00000002
#define RTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE      0x00000004

#define RTL_CLONE_PARENT                0
#define RTL_CLONE_CHILD                 297

#endif

typedef NTSTATUS (*RtlCloneUserProcess_f)(ULONG ProcessFlags,
    PSECURITY_DESCRIPTOR ProcessSecurityDescriptor /* optional */,
    PSECURITY_DESCRIPTOR ThreadSecurityDescriptor /* optional */,
    HANDLE DebugPort /* optional */,
    PRTL_USER_PROCESS_INFORMATION ProcessInformation);

pid_t fork(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 = 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 = GetCurrentProcess();
        pid_t child_pid;

        child_pid = GetProcessId(process_info.Process);

        ResumeThread(process_info.Thread);
        CloseHandle(process_info.Process);
        CloseHandle(process_info.Thread);

        return child_pid;
    }
    else if (result == RTL_CLONE_CHILD)
    {
        /* fix stdio */
        AllocConsole();
        return 0;
    }
    else
        return -1;

    /* NOTREACHED */
    return -1;
}

#ifdef __TEST__
int main(int argc, const char *argv[])
{
    pid_t pid = fork();

    switch (pid) {
    case 0:
    {
        FILE *f = fopen("C:/Users/nenolod/Documents/forktest.dat", "w");
        fprintf(f, "ok\n");
        fclose(f);
        break;
    }
    default:
        printf("child %d\n", pid);
        while (1) { Sleep(1000); }
        break;
    }
}
#endif

See also

Favorite site

See also