#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <stdlib.h>
#include <setjmp.h>
#include <ntport.h>
#include "forkdata.h"
#include "sh.h"
#pragma intrinsic("memcpy", "memset","memcmp")
#pragma warning(push,3) // forget about W4 here
typedef unsigned long u_long;
typedef void *ptr_t;
typedef unsigned char U_char;
typedef unsigned int U_int;
typedef unsigned short U_short;
typedef unsigned long U_long;
static void stack_probe(void *ptr) ;
BOOL CreateWow64Events(DWORD , HANDLE *, HANDLE *, BOOL);
extern int fork_copy_user_mem(HANDLE );
ForkData gForkData = {0,0,0,0,0,{0},0,0,0};
#ifdef _M_IX86
u_long _old_exr = 0;
#endif // _M_ALPHA
NT_TIB * (* myNtCurrentTeb)(void);
#define GETEXCEPTIONREGIST() (((NT_TIB*)get_teb())->ExceptionList)
#define GETSTACKBASE() (((NT_TIB*)get_teb())->StackBase)
static NT_TIB *the_tib;
#if !defined(_M_IA64) && !defined(_M_AMD64)
void *get_teb(void) {
if (the_tib)
return the_tib;
myNtCurrentTeb = (void*)GetProcAddress(LoadLibrary("ntdll.dll"),
"NtCurrentTeb");
if (!myNtCurrentTeb)
return NULL;
the_tib = myNtCurrentTeb();
if (the_tib == NULL)
abort();
return the_tib;
}
#else
#define get_teb NtCurrentTeb
#endif _M_IA64
void set_stackbase(void*ptr){
GETSTACKBASE() = ptr;
}
extern BOOL bIsWow64Process;
int fork_init(void) {
if (__forked) {
#ifdef _M_IX86
_old_exr = __fork_context[6];
__fork_context[6] =(int)GETEXCEPTIONREGIST();#endif _M_ALPHA
longjmp(__fork_context,1);
}
return 0;
}
int fork(void) {
size_t rc;
size_t stacksize;
char modname[512];
HANDLE hProc,hThread, hArray[2];
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
DWORD dwCreationflags;
unsigned int priority;
HANDLE h64Parent,h64Child;
#ifndef _M_ALPHA
unsigned long fork_stack_end;
#endif _M_ALPHA
__fork_stack_begin =GETSTACKBASE();
#ifndef _M_ALPHA
__fork_stack_end = &fork_stack_end;
#else
__fork_stack_end = (unsigned long *)__asm("mov $sp, $0");
#endif
h64Parent = h64Child = NULL;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor =0;
sa.bInheritHandle = TRUE;
if (!__hforkchild)
__hforkchild = CreateEvent(&sa,TRUE,FALSE,NULL);
if (!__hforkparent)
__hforkparent = CreateEvent(&sa,TRUE,FALSE,NULL);
rc = setjmp(__fork_context);
if (rc) { #ifdef _M_IX86
GETEXCEPTIONREGIST() = (struct _EXCEPTION_REGISTRATION_RECORD*)_old_exr;
#endif // _M_ALPHA
SetEvent(__hforkchild);
dprintf("Child ready to rumble\n");
if(WaitForSingleObject(__hforkparent,FORK_TIMEOUT) != WAIT_OBJECT_0)
ExitProcess(0xFFFF);
CloseHandle(__hforkchild);
CloseHandle(__hforkparent);
__hforkchild = __hforkparent=0;
restore_fds();
STR_environ = blk2short(environ);
environ = short2blk(STR_environ);
return 0;
}
copy_fds();
memset(&si,0,sizeof(si));
si.cb= sizeof(si);
if (!GetModuleFileName(GetModuleHandle(NULL),modname,512) ) {
rc = GetLastError();
return -1;
}
dwCreationflags = GetPriorityClass(GetCurrentProcess());
priority = GetThreadPriority(GetCurrentThread());
rc = CreateProcess(NULL,
modname,
NULL,
NULL,
TRUE,
CREATE_SUSPENDED | dwCreationflags,
NULL,
NULL,
&si,
&pi);
if (!rc) {
rc = GetLastError();
return -1;
}
ResetEvent(__hforkchild);
ResetEvent(__hforkparent);
hProc = pi.hProcess;
hThread = pi.hThread;
__forked=1;
if (bIsWow64Process) {
if (VirtualAllocEx(hProc,
__heap_base,
__heap_size,
MEM_RESERVE,
PAGE_READWRITE) == NULL) {
dprintf("virtual allocex failed %d\n",GetLastError());
goto error;
}
if (VirtualAllocEx(hProc,
__heap_base,
__heap_size,
MEM_COMMIT,
PAGE_READWRITE) == NULL) {
dprintf("virtual allocex2 failed %d\n",GetLastError());
goto error;
}
if (!CreateWow64Events(pi.dwProcessId,&h64Parent,&h64Child,FALSE)) {
goto error;
}
ResumeThread(hThread);
hArray[0] = h64Child;
hArray[1] = hProc;
if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) !=
WAIT_OBJECT_0){
rc = GetLastError();
goto error;
}
}
if (!WriteProcessMemory(hProc,&gForkData,&gForkData,
sizeof(ForkData),&rc)) {
goto error;
}
if (rc != sizeof(ForkData))
goto error;
if (!bIsWow64Process) {
rc = ResumeThread(hThread);
}
else {
SetEvent(h64Parent);
hArray[0] = h64Child;
hArray[1] = hProc;
if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) !=
WAIT_OBJECT_0){
rc = GetLastError();
goto error;
}
CloseHandle(h64Parent);
CloseHandle(h64Child);
h64Parent = h64Child = NULL;
}
hArray[0] = __hforkchild;
hArray[1] = hProc;
if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) != WAIT_OBJECT_0){
int err = GetLastError(); dprintf("wait failed err %d\n",err);
goto error;
}
SuspendThread(hThread);
if (!SetThreadPriority(hThread,priority) ) {
priority =GetLastError();
}
stacksize = (char*)__fork_stack_begin - (char*)__fork_stack_end;
if (!WriteProcessMemory(hProc,(char *)__fork_stack_end,
(char *)__fork_stack_end,
(u_long)stacksize,
&rc)){
goto error;
}
if (!WriteProcessMemory(hProc, (void*)__heap_base,(void*)__heap_base,
(DWORD)((char*)__heap_top-(char*)__heap_base),
&rc)){
goto error;
}
rc = fork_copy_user_mem(hProc);
if(rc) {
goto error;
}
SetEvent(__hforkparent);
rc = ResumeThread(hThread);
__forked=0;
dprintf("forked process %d\n",pi.dwProcessId);
start_sigchild_thread(hProc,pi.dwProcessId);
close_copied_fds();
CloseHandle(hThread);
return pi.dwProcessId;
error:
__forked=0;
SetEvent(__hforkparent);
ResumeThread(hThread);
CloseHandle(hProc);
CloseHandle(hThread);
if (h64Parent) {
SetEvent(h64Parent); CloseHandle(h64Parent);
}
if (h64Child)
CloseHandle(h64Child);
return -1;
}
#pragma optimize("",off)
void stack_probe (void *ptr) {
char buf[1000];
int x;
if (&x > (int *)ptr)
stack_probe(ptr);
(void)buf;
}
#pragma optimize("",on)
void heap_init(void) {
char * temp;
int err;
if (__forked) {
temp = (char *)VirtualAlloc((void*)__heap_base,__heap_size, MEM_RESERVE,
PAGE_READWRITE);
if (temp != (char*)__heap_base) {
if (!temp){
err = GetLastError();
if (bIsWow64Process)
ExitProcess(0);
abort();
}
else
__heap_base = temp;
}
if (!VirtualAlloc(__heap_base,(char*)__heap_top -(char*)__heap_base,
MEM_COMMIT,PAGE_READWRITE)){
err = GetLastError();
if (bIsWow64Process)
ExitProcess(0);
abort();
}
temp = (char*)__heap_base;
}
else {
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
__heap_size = sysinfo.dwPageSize * 1024;
__heap_base = VirtualAlloc(0 , __heap_size,MEM_RESERVE|MEM_TOP_DOWN,
PAGE_READWRITE);
if (__heap_base == 0) {
abort();
}
__heap_top = __heap_base;
}
}
void * sbrk(int delta) {
void *retval;
void *old_top=__heap_top;
char *b = (char*)__heap_top;
if (delta == 0)
return __heap_top;
if (delta > 0) {
retval =VirtualAlloc((void*)__heap_top,delta,MEM_COMMIT,PAGE_READWRITE);
if (retval == 0 )
abort();
b += delta;
__heap_top = (void*)b;
}
else {
retval = VirtualAlloc((void*)((char*)__heap_top - delta),
delta,MEM_DECOMMIT, PAGE_READWRITE);
if (retval == 0)
abort();
b -= delta;
__heap_top = (void*)b;
}
return (void*) old_top;
}
#define TCSH_WOW64_PARENT_EVENT_NAME "tcsh-wow64-parent-event"
#define TCSH_WOW64_CHILD_EVENT_NAME "tcsh-wow64-child-event"
BOOL CreateWow64Events(DWORD pid, HANDLE *hParent, HANDLE *hChild,
BOOL bOpenExisting) {
SECURITY_ATTRIBUTES sa;
char parentname[256],childname[256];
*hParent = *hChild = NULL;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor =0;
sa.bInheritHandle = FALSE;
#pragma warning(disable:4995)
wsprintfA(parentname, "Local\\%d-%s",pid, TCSH_WOW64_PARENT_EVENT_NAME);
wsprintfA(childname, "Local\\%d-%s",pid, TCSH_WOW64_CHILD_EVENT_NAME );
#pragma warning(default:4995)
*hParent = OpenEvent(EVENT_ALL_ACCESS,FALSE, parentname);
if(*hParent) {
if (bOpenExisting == FALSE) { CloseHandle(*hParent);
*hParent = NULL;
return FALSE;
}
*hChild = OpenEvent(EVENT_ALL_ACCESS,FALSE, childname);
if (!*hChild) {
CloseHandle(*hParent);
*hParent = NULL;
return FALSE;
}
return TRUE;
}
else { if (bOpenExisting == TRUE)
return FALSE;
}
*hParent = CreateEvent(&sa,FALSE,FALSE,parentname);
if (!*hParent)
return FALSE;
*hChild = CreateEvent(&sa,FALSE,FALSE,childname);
if (!*hChild){
CloseHandle(*hParent);
*hParent = NULL;
return FALSE;
}
return TRUE;
}