diff options
Diffstat (limited to 'src/libmowgli/platform/win32/fork.c')
-rw-r--r-- | src/libmowgli/platform/win32/fork.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/src/libmowgli/platform/win32/fork.c b/src/libmowgli/platform/win32/fork.c new file mode 100644 index 0000000..c644122 --- /dev/null +++ b/src/libmowgli/platform/win32/fork.c @@ -0,0 +1,166 @@ +/* + * libmowgli: A collection of useful routines for programming. + * fork.c: Fastest possible NT fork() implementation + * + * Copyright (c) 2012 TortoiseLabs, LLC. + * + * 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 is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * References: + * - undocumented.ntinternals.net + * - http://www.cs.miami.edu/~burt/journal/NT/processinit.html + */ + +#include "mowgli.h" + +#ifdef NOTYET + +#ifdef _WIN32 + +#ifndef _WIN32_WINNT + +int fork(void) +{ +#warning fork is not possible on your platform in any sane way, sorry :( + return -ENOSYS; +} + +#else + +extern NTSTATUS NTAPI CsrCallClientServer(void *message, void *userdata, uint32_t opcode, uint32_t size); + +/* + * Definition of a message sent to an NT port on the CSRSS server. + * + * Not sure what dummy1/dummy2 do, but they're junk as far as I can see. + */ +struct csrss_message { + uint32_t dummy1; + uint32_t opcode; + uint32_t status; + uint32_t dummy2; +}; + +static inline void +inherit_handles(void) +{ + uint32_t n = 0x1000; + uint32_t *p = mowgli_alloc_array(sizeof(uint32_t), n); + uint32_t pid, i; + SYSTEM_HANDLE_INFORMATION *info; + + while (ZwQuerySystemInformation(SystemHandleInformation, p, n * sizeof(*p), 0) == STATUS_INFO_LENGTH_MISMATCH) + { + n *= 2; + + mowgli_free(p); + p = mowgli_alloc_array(sizeof(uint32_t), n); + } + + info = (SYSTEM_HANDLE_INFORMATION *) (p + 1); + pid = GetCurrentProcessId(); + + for (i = 0; i < *p; i++) + { + if (info[i].ProcessId == pid) + SetHandleInformation((HANDLE) h[i].Handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + } + + mowgli_free(p); +} + +static inline void +request_csrss_session(HANDLE proc_handle, HANDLE thread_handle, uint32_t pid, uint32_t tid) +{ + struct { + PORT_MESSAGE port_message; + struct csrss_message csrss_message; + PROCESS_INFORMATION process_information; + CLIENT_ID debugger; + uint32_t flags; + uint32_t vdminfo[2]; + } csrmsg = {{0}, {0}, {proc_handle, thread_handle, pid, tid}, {0}, 0, {0}}; + + CsrCallClientServer(&csrmsg, NULL, 0x10000, sizeof csrmsg); +} + +int child(void) +{ + typedef BOOL (*CsrpConnectToServer)(PWSTR); + + CsrpConnectToServer (0x77F8F65D) (L"\\Windows"); + __asm__("mov eax, 0; mov esp, ebp; pop ebp; ret"); +} + +int fork(void) +{ + HANDLE proc_handle, thread_handle; + OBJECT_ATTRIBUTES oa = { sizeof(oa) }; + CONTEXT context = { CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT }; + MEMORY_BASIC_INFORMATION mbi; + THREAD_BASIC_INFORMATION tbi; + PNT_TIB tib; + USER_STACK stack; + CLIENT_ID cid; + + /* ensure the child has the same handles and ports */ + inherit_handles(); + + /* create the actual LWP using ZwCreateProcess() */ + ZwCreateProcess(&proc_handle, PROCESS_ALL_ACCESS, &oa, NtCurrentProcess(), TRUE, 0, 0, 0); + + /* now set up a thread for that process using a context, cloning the current thread ... */ + ZwGetContextThread(NtCurrentThread(), &context); + context.Eip = (unsigned long) child; + + /* set up a stack for the thread now that the child sentinel is set up ... */ + ZwQueryVirtualMemory(NtCurrentProcess(), (void *) context.Esp, MemoryBasicInformation, + &mbi, sizeof mbi, 0); + + stack = (USER_STACK){0, 0, ((char *) mbi.BaseAddress) + mbi.RegionSize, + mbi.BaseAddress, mbi.AllocationBase}; + + /* now spawn the thread! */ + ZwCreateThread(&thread_handle, THREAD_ALL_ACCESS, &oa, proc_handle, &cid, &context, &stack, TRUE); + + /* thread is spawned, but frozen for inspection -- fix up memory protection before unfreezing */ + ZwQueryInformationThread(NtCurrentThread(), ThreadBasicInformation, &tbi, sizeof tbi, 0); + tib = tbi.TebBaseAddress; + + ZwQueryInformationThread(thread_handle, ThreadBasicInformation, &tbi, sizeof tbi, 0); + ZwWriteVirtualMemory(process_handle, tbi.TebBaseAddress, &tib->ExceptionList, sizeof(tib->ExceptionList), 0); + + /* ready to go, now request a CSRSS session */ + request_csrss_session(process_handle, thread_handle, (uint32_t) cid.UniqueProcess, (uint32_t) cid.UniqueThread); + + /* CSRSS session set up or we segfaulted by now, so unfreeze the child... */ + ZwResumeThread(thread_handle, 0); + + /* release handle refcount now that process is freestanding */ + ZwClose(thread_handle); + ZwClose(process_handle); + + return (int) cid.UniqueProcess; +} + +#endif + +#endif + +#endif |