/*
2004/7/5
试图写一个自己的exe loader,失败!
2004/7/11
a gui 'hello, world' app is successfully launched
by this toy CreateProcessW implemention
*/
#include < nt.h >
#include < ntrtl.h >
#include < nturtl.h >
#include < stdio.h >
#include < windows.h >
#define ROUND_UP(VALUE,ROUND) ((ULONG)(((ULONG)VALUE +
((ULONG)ROUND - 1L )) & ( ~ ((ULONG)ROUND - 1L ))))
#define MAX_PATH 260
#define BASESRV_SERVERDLL_INDEX 1
HANDLE BaseNamedObjectDirectory;
typedef enum _BASE_CONTEXT_TYPE ... {
BaseContextTypeProcess,
BaseContextTypeThread,
BaseContextTypeFiber
} BASE_CONTEXT_TYPE, * PBASE_CONTEXT_TYPE;
#define CALL_STDCALL 0
#define CALL_CDECL 1
#define CALL_FASTCALL 2
// #include "var.h"
#include " ntcsrmsg.h "
#include " basemsg.h "
extern NTSTATUS __declspec(dllimport) _stdcall
CsrClientCallServer(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_CAPTURE_HEADER CaptureBuffer OPTIONAL,
IN CSR_API_NUMBER ApiNumber,
IN ULONG ArgLength
);
ULONG
BaseSetLastNTError(IN NTSTATUS Status)
... {
ULONG dwErrorCode;
dwErrorCode = RtlNtStatusToDosError( Status );
SetLastError( dwErrorCode );
return( dwErrorCode );
}
BOOLEAN
BasePushProcessParameters(
HANDLE Process,
PPEB Peb,
LPCWSTR ApplicationPathName,
LPCWSTR CurrentDirectory,
LPCWSTR CommandLine,
PVOID Environment,
LPSTARTUPINFOW lpStartupInfo,
ULONG dwCreationFlags,
BOOLEAN bInheritHandles,
ULONG dwSubsystem
)
... {
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLineString;
UNICODE_STRING CurrentDirString;
UNICODE_STRING DllPath;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopInfo;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeInfo;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PRTL_USER_PROCESS_PARAMETERS ParametersInNewProcess;
ULONG ParameterLength, EnvironmentLength, RegionSize;
PWCHAR s;
NTSTATUS Status;
WCHAR CurDirBuffer[MAX_PATH];
WCHAR DllPathBuffer[10240];
UNICODE_STRING BasePathVariableName;
RtlInitUnicodeString(&BasePathVariableName, L"PATH");
DllPath.Length = 0;
DllPath.Buffer = DllPathBuffer;
DllPath.MaximumLength = 10240;
RtlQueryEnvironmentVariable_U( Environment,
&BasePathVariableName,
&DllPath
);
RtlInitUnicodeString(&ImagePathName, ApplicationPathName);
RtlInitUnicodeString(&CommandLineString, CommandLine );
if(ARGUMENT_PRESENT(CurrentDirectory))...{
RtlInitUnicodeString(&CurrentDirString, CurrentDirectory);
}else...{
RtlGetCurrentDirectory_U(MAX_PATH, CurDirBuffer);
RtlInitUnicodeString( &CurrentDirString, CurDirBuffer);
}
if ( lpStartupInfo->lpDesktop ) ...{
RtlInitUnicodeString(
&DesktopInfo,
lpStartupInfo->lpDesktop
);
}
else ...{
RtlInitUnicodeString( &DesktopInfo, L"");
}
if ( lpStartupInfo->lpReserved ) ...{
RtlInitUnicodeString(&ShellInfo, lpStartupInfo->lpReserved);
}
else ...{
RtlInitUnicodeString( &ShellInfo, L"");
}
RuntimeInfo.Buffer = (PWSTR)lpStartupInfo->lpReserved2;
RuntimeInfo.Length = lpStartupInfo->cbReserved2;
RuntimeInfo.MaximumLength = RuntimeInfo.Length;
if ( lpStartupInfo->lpTitle ) ...{
RtlInitUnicodeString(&WindowTitle, lpStartupInfo->lpTitle);
}else...{
RtlInitUnicodeString( &WindowTitle, ApplicationPathName);
}
Status = RtlCreateProcessParameters( &ProcessParameters,
&ImagePathName,
&DllPath,
(ARGUMENT_PRESENT(CurrentDirectory)?
&CurrentDirString : NULL
),
&CommandLineString,
Environment,
&WindowTitle,
&DesktopInfo,
&ShellInfo,
&RuntimeInfo
);
if (!NT_SUCCESS( Status )) ...{
BaseSetLastNTError(Status);
return FALSE;
}
if ( !bInheritHandles ) ...{
ProcessParameters->CurrentDirectory.Handle = NULL;
}
__try ...{
if (s = ProcessParameters->Environment) ...{
while (*s) ...{
while (*s++) ...{
}
}
s++;
Environment = ProcessParameters->Environment;
EnvironmentLength = (PUCHAR)s - (PUCHAR)Environment;
ProcessParameters->Environment = NULL;
RegionSize = EnvironmentLength;
Status = NtAllocateVirtualMemory( Process,
(PVOID *)&ProcessParameters->Environment,
0,
&RegionSize,
MEM_COMMIT,
PAGE_READWRITE
);
if ( !NT_SUCCESS( Status ) ) ...{
BaseSetLastNTError(Status);
return( FALSE );
}
Status = NtWriteVirtualMemory( Process,
ProcessParameters->Environment,
Environment,
EnvironmentLength,
NULL
);
if ( !NT_SUCCESS( Status ) ) ...{
BaseSetLastNTError(Status);
return( FALSE );
}
}
//
// Push the parameters into the new process
//
ProcessParameters->StartingX = lpStartupInfo->dwX;
ProcessParameters->StartingY = lpStartupInfo->dwY;
ProcessParameters->CountX = lpStartupInfo->dwXSize;
ProcessParameters->CountY = lpStartupInfo->dwYSize;
ProcessParameters->CountCharsX =
lpStartupInfo->dwXCountChars;
ProcessParameters->CountCharsY =
lpStartupInfo->dwYCountChars;
ProcessParameters->FillAttribute =
lpStartupInfo->dwFillAttribute;
ProcessParameters->WindowFlags =
lpStartupInfo->dwFlags;
ProcessParameters->ShowWindowFlags =
lpStartupInfo->wShowWindow;
if(lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES | STARTF_USEHOTKEY
/**//* | STARTF_HASSHELLDATA */
)) ...{
ProcessParameters->StandardInput =
lpStartupInfo->hStdInput;
ProcessParameters->StandardOutput =
lpStartupInfo->hStdOutput;
ProcessParameters->StandardError =
lpStartupInfo->hStdError;
}
if (dwCreationFlags & DETACHED_PROCESS) ...{
#if 0
ProcessParameters->ConsoleHandle =
(HANDLE)CONSOLE_DETACHED_PROCESS;
} else if (dwCreationFlags & CREATE_NEW_CONSOLE) ...{
ProcessParameters->ConsoleHandle =
(HANDLE)CONSOLE_NEW_CONSOLE;
} else if (dwCreationFlags & CREATE_NO_WINDOW) ...{
ProcessParameters->ConsoleHandle =
(HANDLE)CONSOLE_CREATE_NO_WINDOW;
#endif
} else ...{
ProcessParameters->ConsoleHandle =
NtCurrentPeb()->ProcessParameters->ConsoleHandle;
if (!(lpStartupInfo->dwFlags & STARTF_USESTDHANDLES)) ...{
ProcessParameters->StandardInput =
NtCurrentPeb()->ProcessParameters->StandardInput;
ProcessParameters->StandardOutput =
NtCurrentPeb()->ProcessParameters->StandardOutput;
ProcessParameters->StandardError =
NtCurrentPeb()->ProcessParameters->StandardError;
}
}
if (dwCreationFlags & CREATE_NEW_PROCESS_GROUP) ...{
ProcessParameters->ConsoleFlags = 1;
}
ProcessParameters->Flags |=
(NtCurrentPeb()->ProcessParameters->Flags
&
RTL_USER_PROC_DISABLE_HEAP_DECOMMIT
);
ParameterLength = ProcessParameters->Length;
//
// Allocate memory in the new process to push the parameters
//
ParametersInNewProcess = NULL;
Status = NtAllocateVirtualMemory(
Process,
(PVOID *)&ParametersInNewProcess,
0,
&ParameterLength,
MEM_COMMIT,
PAGE_READWRITE
);
if ( !NT_SUCCESS( Status ) ) ...{
BaseSetLastNTError(Status);
return FALSE;
}
ProcessParameters->MaximumLength = ParameterLength;
if ( dwCreationFlags & PROFILE_USER ) ...{
ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_USER;
}
if ( dwCreationFlags & PROFILE_KERNEL ) ...{
ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_KERNEL;
}
if ( dwCreationFlags & PROFILE_SERVER ) ...{
ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_SERVER;
}
//
// Push the parameters
//
Status = NtWriteVirtualMemory(
Process,
ParametersInNewProcess,
ProcessParameters,
ProcessParameters->Length,
NULL
);
if ( !NT_SUCCESS( Status ) ) ...{
BaseSetLastNTError(Status);
return FALSE;
}
//
// Make the processes PEB point to the parameters.
//
Status = NtWriteVirtualMemory(
Process,
&Peb->ProcessParameters,
&ParametersInNewProcess,
sizeof( ParametersInNewProcess ),
NULL
);
if ( !NT_SUCCESS( Status ) ) ...{
BaseSetLastNTError(Status);
return FALSE;
}
//
// Set subsystem type in PEB if requested by caller.
// Ignore error
//
if (dwSubsystem != 0) ...{
NtWriteVirtualMemory(
Process,
&Peb->ImageSubsystem,
&dwSubsystem,
sizeof( Peb->ImageSubsystem ),
NULL
);
}
}__finally...{
}
return TRUE;
}
HANDLE loadLibrary( const wchar_t * _dllName)
... {
HANDLE hDll;
UNICODE_STRING dllName;
NTSTATUS st;
RtlInitUnicodeString(&dllName, _dllName);
st = LdrLoadDll(
NULL,
NULL,
&dllName,
&hDll
);
if(!NT_SUCCESS(st))...{
return 0;
}
return hDll;
}
int callDll(
const wchar_t * _dllName,
const char * _procName,
int * result,
int callConvention,
int numOfParameters,
...
)
... {
STRING procName;
HANDLE hDll;
PVOID entry;
NTSTATUS st;
if(result)...{
*result = 0;
}
if(callConvention != CALL_STDCALL)...{
// unimplemented
return -3;
}
hDll = loadLibrary(_dllName);
if ((int)_procName & 0xffff0000) ...{
RtlInitString(&procName, _procName);
st = LdrGetProcedureAddress(
hDll,
&procName,
0L,
&entry
);
}else...{
st = LdrGetProcedureAddress(
hDll,
NULL,
(ULONG)_procName,
&entry
);
}
if(!NT_SUCCESS(st))...{
LdrUnloadDll(hDll);
return -2;
}
/**//*
fake a call stack frame and do a function call
maybe we should use a thunk to make this bit
of code more readable
*/
__asm...{
lea esi, numOfParameters
mov ecx, [esi]
add esi, 4
lea ebx, [ecx * 4]
sub esp, ebx
mov edi, esp
rep movsd
call entry
mov entry, eax
}
// for debug, leave the dll there
// LdrUnloadDll(hDll);
if(result)...{
*result = (int)entry;
}
return 0;
}
NTSTATUS
BaseCreateStack(
IN HANDLE Process,
IN ULONG StackSize,
IN ULONG MaximumStackSize,
OUT PINITIAL_TEB InitialTeb
)
... {
NTSTATUS Status;
PCH Stack;
BOOLEAN GuardPage;
ULONG RegionSize;
ULONG OldProtect;
ULONG ImageStackSize, ImageStackCommit;
PIMAGE_NT_HEADERS NtHeaders;
PPEB Peb;
ULONG PageSize;
Peb = NtCurrentPeb();
PageSize = 0X1000;
//
// If the stack size was not supplied, then use the sizes
// from the image header.
//
NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
ImageStackSize =
NtHeaders->OptionalHeader.SizeOfStackReserve;
ImageStackCommit =
NtHeaders->OptionalHeader.SizeOfStackCommit;
if ( !MaximumStackSize ) ...{
MaximumStackSize = ImageStackSize;
}
if (!StackSize) ...{
StackSize = ImageStackCommit;
}
else ...{
//
// Now Compute how much additional stack space is to be
// reserved. This is done by... If the StackSize is <=
// Reserved size in the image, then reserve whatever the
// image specifies. Otherwise, round up to 1Mb.
//
if ( StackSize >= MaximumStackSize ) ...{
MaximumStackSize = ROUND_UP(StackSize, (1024*1024));
}
}
//
// Align the stack size to a page boundry and the reserved
// size to an allocation granularity boundry.
//
StackSize = ROUND_UP( StackSize, PageSize );
MaximumStackSize = ROUND_UP(
MaximumStackSize,
0x10000
// BaseStaticServerData->SysInfo.AllocationGranularity
);
//
// Reserve address space for the stack
//
Stack = NULL,
Status = NtAllocateVirtualMemory(
Process,
(PVOID *)&Stack,
0,
&MaximumStackSize,
MEM_RESERVE,
PAGE_READWRITE
);
if ( !NT_SUCCESS( Status ) ) ...{
return Status;
}
InitialTeb->OldInitialTeb.OldStackBase = NULL;
InitialTeb->OldInitialTeb.OldStackLimit = NULL;
InitialTeb->StackAllocationBase = Stack;
InitialTeb->StackBase = Stack + MaximumStackSize;
Stack += MaximumStackSize - StackSize;
if (MaximumStackSize > StackSize) ...{
Stack -= PageSize;
StackSize += PageSize;
GuardPage = TRUE;
}
else ...{
GuardPage = FALSE;
}
//
// Commit the initially valid portion of the stack
//
Status = NtAllocateVirtualMemory(
Process,
(PVOID *)&Stack,
0,
&StackSize,
MEM_COMMIT,
PAGE_READWRITE
);
if ( !NT_SUCCESS( Status ) ) ...{
//
// If the commit fails, then delete the address space
// for the stack
//
RegionSize = 0;
NtFreeVirtualMemory(
Process,
(PVOID *)&Stack,
&RegionSize,
MEM_RELEASE
);
return Status;
}
InitialTeb->StackLimit = Stack;
//
// if we have space, create a guard page.
//
if (GuardPage) ...{
RegionSize = PageSize;
Status = NtProtectVirtualMemory(
Process,
(PVOID *)&Stack,
&RegionSize,
PAGE_GUARD | PAGE_READWRITE,
&OldProtect
);
if ( !NT_SUCCESS( Status ) ) ...{
return Status;
}
InitialTeb->StackLimit = (PVOID)(
(PUCHAR)InitialTeb->StackLimit + RegionSize
);
}
return STATUS_SUCCESS;
}
VOID
BaseInitializeContext(
OUT PCONTEXT Context,
IN PVOID Parameter OPTIONAL,
IN PVOID InitialPc OPTIONAL,
IN PVOID InitialSp OPTIONAL,
IN BASE_CONTEXT_TYPE ContextType
)
... {
Context->Eax = (ULONG)InitialPc;
Context->Ebx = (ULONG)Parameter;
Context->SegGs = 0;
Context->SegFs = KGDT_R3_TEB;
Context->SegEs = KGDT_R3_DATA;
Context->SegDs = KGDT_R3_DATA;
Context->SegSs = KGDT_R3_DATA;
Context->SegCs = KGDT_R3_CODE;
//
// Start the thread at IOPL=3.
//
Context->EFlags = 0x3000;
//
// Always start the thread at the thread start thunk.
//
Context->Esp = (ULONG) InitialSp;
Context->Eip = (ULONG)InitialPc;
//
// add code to check alignment and raise exception...
//
Context->ContextFlags = CONTEXT_FULL;
// Reserve room for ret address
Context->Esp -= sizeof(Parameter);
}
HANDLE
BaseGetNamedObjectDirectory(
VOID
)
... {
OBJECT_ATTRIBUTES Obja;
NTSTATUS Status;
ACCESS_MASK DirAccess = DIRECTORY_ALL_ACCESS &
~(DELETE | WRITE_DAC | WRITE_OWNER);
RtlAcquirePebLock();
if ( !BaseNamedObjectDirectory ) ...{
InitializeObjectAttributes(
&Obja,
NULL,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenDirectoryObject(
&BaseNamedObjectDirectory,
DirAccess,
&Obja
);
if ( !NT_SUCCESS(Status) ) ...{
BaseNamedObjectDirectory = NULL;
}
}
RtlReleasePebLock();
return BaseNamedObjectDirectory;
}
POBJECT_ATTRIBUTES
BaseFormatObjectAttributes(
OUT POBJECT_ATTRIBUTES ObjectAttributes,
IN PUNICODE_STRING ObjectName
)
... {
HANDLE RootDirectory;
ULONG Attributes;
PVOID SecurityDescriptor = NULL;
if (ARGUMENT_PRESENT(ObjectName) ) ...{
if ( ARGUMENT_PRESENT(ObjectName) ) ...{
RootDirectory = BaseGetNamedObjectDirectory();
}
else ...{
RootDirectory = NULL;
}
if ( ARGUMENT_PRESENT(ObjectName) ) ...{
Attributes |= OBJ_OPENIF;
}
InitializeObjectAttributes(
ObjectAttributes,
ObjectName,
Attributes,
RootDirectory,
SecurityDescriptor
);
return ObjectAttributes;
}else...{
return NULL;
}
}
UCHAR _stdcall createProcess(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
UCHAR bInheritHandles,
ULONG dwCreationFlags,
PVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
)
... {
HANDLE FileHandle;
NTSTATUS Status, StackStatus;
OBJECT_ATTRIBUTES Obja, *pObja;
UNICODE_STRING PathName;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE SectionHandle;
HANDLE ProcessHandle;
SECTION_IMAGE_INFORMATION ImageInformation;
PROCESS_BASIC_INFORMATION ProcessInfo;
PPEB Peb;
LPWSTR CurdirBuffer, CurdirFilePart;
ULONG CurdirLength,CurdirLength2;
HANDLE ThreadHandle;
INITIAL_TEB InitialTeb;
CONTEXT ThreadContext;
CLIENT_ID ClientId;
STARTUPINFOW StartupInfo;
BASE_API_MSG m;
PBASE_CREATEPROCESS_MSG a=
(PBASE_CREATEPROCESS_MSG)&m.u.CreateProcess;
StartupInfo = *lpStartupInfo;
if(ARGUMENT_PRESENT(lpApplicationName))...{
Status = RtlDosPathNameToNtPathName_U(
lpApplicationName,
&PathName,
NULL,
NULL
);
if(!NT_SUCCESS(Status))...{
return FALSE;
}
InitializeObjectAttributes(
&Obja,
&PathName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenFile(
&FileHandle,
SYNCHRONIZE | FILE_EXECUTE,// | FILE_WRITE_DATA,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
);
if(!NT_SUCCESS(Status))...{
return FALSE;
}
Status = NtCreateSection(
&SectionHandle,
SECTION_ALL_ACCESS,
NULL,
NULL,
PAGE_EXECUTE,
SEC_IMAGE,
FileHandle
);
NtClose(FileHandle);
FileHandle = NULL;
if(!NT_SUCCESS(Status))...{
return FALSE;
}
//
// Query the section to determine the stack parameters and
// image entrypoint.
//
Status = NtQuerySection(
SectionHandle,
SectionImageInformation,
&ImageInformation,
sizeof( ImageInformation ),
NULL
);
}else...{
// simulate a fork operation
SectionHandle = NULL;
}
//
// Create the process object
//
if(!NT_SUCCESS(Status))...{
return FALSE;
}
if (StartupInfo.lpDesktop == NULL) ...{
StartupInfo.lpDesktop =
(LPWSTR)((PRTL_USER_PROCESS_PARAMETERS)NtCurrentPeb()->
ProcessParameters)->DesktopInfo.Buffer;
}
pObja = BaseFormatObjectAttributes(&Obja, NULL);
Status = NtCreateProcess(
&ProcessHandle,
PROCESS_ALL_ACCESS,
pObja,
NtCurrentProcess(),
(BOOLEAN)bInheritHandles,
SectionHandle,
NULL,
NULL
);
if ( !NT_SUCCESS(Status) ) ...{
return FALSE;
}
NtClose(SectionHandle);
SectionHandle = NULL;
//
// Determine the location of the
// processes PEB.
//
Status = NtQueryInformationProcess(
ProcessHandle,
ProcessBasicInformation,
&ProcessInfo,
sizeof( ProcessInfo ),
NULL
);
if ( !NT_SUCCESS( Status ) ) ...{
return FALSE;
}
Peb = ProcessInfo.PebBaseAddress;
#if 1
//
// Push the parameters into the address space
// of the new process
//
if ( ARGUMENT_PRESENT(lpCurrentDirectory) ) ...{
CurdirBuffer = RtlAllocateHeap(
RtlProcessHeap(),
0, //MAKE_TAG( TMP_TAG ),
(MAX_PATH*2)+sizeof(UNICODE_NULL)
);
if ( !CurdirBuffer ) ...{
BaseSetLastNTError(STATUS_NO_MEMORY);
return FALSE;
}
CurdirLength2 = GetFullPathNameW(
lpCurrentDirectory,
MAX_PATH,
CurdirBuffer,
&CurdirFilePart
);
if ( CurdirLength2 > MAX_PATH ) ...{
SetLastError(ERROR_DIRECTORY);
return FALSE;
}
//
// now make sure the directory exists
//
CurdirLength = GetFileAttributesW(CurdirBuffer);
if ( (CurdirLength == 0xffffffff) ||
!(CurdirLength & FILE_ATTRIBUTE_DIRECTORY) ) ...{
SetLastError(ERROR_DIRECTORY);
return FALSE;
}
}
if (!BasePushProcessParameters(
ProcessHandle,
Peb,
lpApplicationName,
lpCurrentDirectory,
lpCommandLine,
lpEnvironment,
&StartupInfo,
dwCreationFlags,
bInheritHandles,
0
) ) ...{
return FALSE;
}
#endif
StackStatus = BaseCreateStack(
ProcessHandle,
ImageInformation.CommittedStackSize,
ImageInformation.MaximumStackSize,
&InitialTeb
);
if ( !NT_SUCCESS(StackStatus) ) ...{
BaseSetLastNTError(StackStatus);
return FALSE;
}
//
// Create an initial context for the new thread.
//
BaseInitializeContext(
&ThreadContext,
Peb,
ImageInformation.TransferAddress,
InitialTeb.StackBase,
BaseContextTypeProcess
);
//
// Create the actual thread object
//
pObja = BaseFormatObjectAttributes(&Obja, NULL);
Status = NtCreateThread(
&ThreadHandle,
THREAD_ALL_ACCESS,
pObja,
ProcessHandle,
&ClientId,
&ThreadContext,
&InitialTeb,
TRUE
);
if (!NT_SUCCESS(Status) ) ...{
BaseSetLastNTError(Status);
return FALSE;
}
//
// Call the Windows server to let it know about the
// process.
//
memset(&m, 0, sizeof(m));
a->ProcessHandle = ProcessHandle;
a->ThreadHandle = ThreadHandle;
a->ClientId = ClientId;
a->CreationFlags = dwCreationFlags;
#if 0
if(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))...{
Status = DbgUiConnectToDbg();
if ( !NT_SUCCESS(Status) ) ...{
NtTerminateProcess(ProcessHandle,Status);
BaseSetLastNTError(Status);
return FALSE;
}
a->DebuggerClientId = NtCurrentTeb()->ClientId;
}
else ...{
a->DebuggerClientId.UniqueProcess = NULL;
a->DebuggerClientId.UniqueThread = NULL;
}
#endif
#if 0
//
// Set the 2 bit if a gui app is starting. The window
// manager needs to
// know this so it can synchronize the startup of this app
// (WaitForInputIdle api). This info is passed using the
// process
// handle tag bits. The 1 bit asks the window manager to
// turn on
// or turn off the application start cursor
// (hourglass/pointer).
//
// When starting a WOW process, lie and tell UserSrv
// NTVDM.EXE is a GUI
// process. We also turn on bit 0x8 so that UserSrv can
// ignore the
// UserNotifyConsoleApplication call made by the console
// during startup.
//
if(ImageInformation.SubSystemType ==
IMAGE_SUBSYSTEM_WINDOWS_GUI
// || IsWowBinary
) ...{
a->ProcessHandle = (HANDLE)((ULONG)a->ProcessHandle | 2);
//
// If the creating process is a GUI app, turn on the app.
// start cursor
// by default. This can be overridden by
// STARTF_FORCEOFFFEEDBACK.
//
NtHeaders = RtlImageNtHeader((PVOID)GetModuleHandle(NULL));
if ( NtHeaders->OptionalHeader.Subsystem ==
IMAGE_SUBSYSTEM_WINDOWS_GUI
)...{
a->ProcessHandle = (HANDLE)((ULONG)a->ProcessHandle | 1);
}
}
#endif
#if 1
//
// If feedback is forced on, turn it on. If forced off,
// turn it off.
// Off overrides on.
//
if (StartupInfo.dwFlags & STARTF_FORCEONFEEDBACK)
a->ProcessHandle = (HANDLE)((ULONG)a->ProcessHandle | 1);
if (StartupInfo.dwFlags & STARTF_FORCEOFFFEEDBACK)
a->ProcessHandle = (HANDLE)((ULONG)a->ProcessHandle & ~1);
CsrClientCallServer(
(PCSR_API_MSG)&m,
NULL,
CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepCreateProcess),
sizeof( *a )
);
if (!NT_SUCCESS((NTSTATUS)m.ReturnValue)) ...{
BaseSetLastNTError((NTSTATUS)m.ReturnValue);
NtTerminateProcess(ProcessHandle, 0);
return FALSE;
}
#endif
if (!( dwCreationFlags & CREATE_SUSPENDED) ) ...{
NtResumeThread(ThreadHandle, (PULONG)NULL);
}
return TRUE;
}
int wmain( int c, const wchar_t ** v)
... {
static PROCESS_INFORMATION pi;
static STARTUPINFOW si = ...{sizeof(si)};
BOOLEAN ret;
if(c < 2)...{
return -1;
}
wprintf(L"launching %s...", v[1]);
__try...{
ret = createProcess(
v[1],
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi
);
if(ret)...{
printf("Ok. ");
}else...{
printf("Failed(%d). ", GetLastError());
}
}__except(1)...{
;
}
ExitProcess(0);
// NtTerminateProcess(NtCurrentProcess(), 0);
// callDll(L"kernel32.dll", "ExitProcess", CALL_STDCALL, 1, 0);
return 0;
}
void __declspec(dllexport) _stdcall
startW(HWND hwnd, HINSTANCE h, wchar_t * cmdLine, int nCmdShow)
... {
static PROCESS_INFORMATION pi;
static STARTUPINFOW si = ...{sizeof(si)};
__try...{
createProcess(
cmdLine,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi
);
}__except(1)...{
;
}
}
BOOLEAN _stdcall dllMain( int a, int b, int c)
... {
return TRUE;
}
2004/7/5
试图写一个自己的exe loader,失败!
2004/7/11
a gui 'hello, world' app is successfully launched
by this toy CreateProcessW implemention
*/
#include < nt.h >
#include < ntrtl.h >
#include < nturtl.h >
#include < stdio.h >
#include < windows.h >
#define ROUND_UP(VALUE,ROUND) ((ULONG)(((ULONG)VALUE +
((ULONG)ROUND - 1L )) & ( ~ ((ULONG)ROUND - 1L ))))
#define MAX_PATH 260
#define BASESRV_SERVERDLL_INDEX 1
HANDLE BaseNamedObjectDirectory;
typedef enum _BASE_CONTEXT_TYPE ... {
BaseContextTypeProcess,
BaseContextTypeThread,
BaseContextTypeFiber
} BASE_CONTEXT_TYPE, * PBASE_CONTEXT_TYPE;
#define CALL_STDCALL 0
#define CALL_CDECL 1
#define CALL_FASTCALL 2
// #include "var.h"
#include " ntcsrmsg.h "
#include " basemsg.h "
extern NTSTATUS __declspec(dllimport) _stdcall
CsrClientCallServer(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_CAPTURE_HEADER CaptureBuffer OPTIONAL,
IN CSR_API_NUMBER ApiNumber,
IN ULONG ArgLength
);
ULONG
BaseSetLastNTError(IN NTSTATUS Status)
... {
ULONG dwErrorCode;
dwErrorCode = RtlNtStatusToDosError( Status );
SetLastError( dwErrorCode );
return( dwErrorCode );
}
BOOLEAN
BasePushProcessParameters(
HANDLE Process,
PPEB Peb,
LPCWSTR ApplicationPathName,
LPCWSTR CurrentDirectory,
LPCWSTR CommandLine,
PVOID Environment,
LPSTARTUPINFOW lpStartupInfo,
ULONG dwCreationFlags,
BOOLEAN bInheritHandles,
ULONG dwSubsystem
)
... {
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLineString;
UNICODE_STRING CurrentDirString;
UNICODE_STRING DllPath;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopInfo;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeInfo;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PRTL_USER_PROCESS_PARAMETERS ParametersInNewProcess;
ULONG ParameterLength, EnvironmentLength, RegionSize;
PWCHAR s;
NTSTATUS Status;
WCHAR CurDirBuffer[MAX_PATH];
WCHAR DllPathBuffer[10240];
UNICODE_STRING BasePathVariableName;
RtlInitUnicodeString(&BasePathVariableName, L"PATH");
DllPath.Length = 0;
DllPath.Buffer = DllPathBuffer;
DllPath.MaximumLength = 10240;
RtlQueryEnvironmentVariable_U( Environment,
&BasePathVariableName,
&DllPath
);
RtlInitUnicodeString(&ImagePathName, ApplicationPathName);
RtlInitUnicodeString(&CommandLineString, CommandLine );
if(ARGUMENT_PRESENT(CurrentDirectory))...{
RtlInitUnicodeString(&CurrentDirString, CurrentDirectory);
}else...{
RtlGetCurrentDirectory_U(MAX_PATH, CurDirBuffer);
RtlInitUnicodeString( &CurrentDirString, CurDirBuffer);
}
if ( lpStartupInfo->lpDesktop ) ...{
RtlInitUnicodeString(
&DesktopInfo,
lpStartupInfo->lpDesktop
);
}
else ...{
RtlInitUnicodeString( &DesktopInfo, L"");
}
if ( lpStartupInfo->lpReserved ) ...{
RtlInitUnicodeString(&ShellInfo, lpStartupInfo->lpReserved);
}
else ...{
RtlInitUnicodeString( &ShellInfo, L"");
}
RuntimeInfo.Buffer = (PWSTR)lpStartupInfo->lpReserved2;
RuntimeInfo.Length = lpStartupInfo->cbReserved2;
RuntimeInfo.MaximumLength = RuntimeInfo.Length;
if ( lpStartupInfo->lpTitle ) ...{
RtlInitUnicodeString(&WindowTitle, lpStartupInfo->lpTitle);
}else...{
RtlInitUnicodeString( &WindowTitle, ApplicationPathName);
}
Status = RtlCreateProcessParameters( &ProcessParameters,
&ImagePathName,
&DllPath,
(ARGUMENT_PRESENT(CurrentDirectory)?
&CurrentDirString : NULL
),
&CommandLineString,
Environment,
&WindowTitle,
&DesktopInfo,
&ShellInfo,
&RuntimeInfo
);
if (!NT_SUCCESS( Status )) ...{
BaseSetLastNTError(Status);
return FALSE;
}
if ( !bInheritHandles ) ...{
ProcessParameters->CurrentDirectory.Handle = NULL;
}
__try ...{
if (s = ProcessParameters->Environment) ...{
while (*s) ...{
while (*s++) ...{
}
}
s++;
Environment = ProcessParameters->Environment;
EnvironmentLength = (PUCHAR)s - (PUCHAR)Environment;
ProcessParameters->Environment = NULL;
RegionSize = EnvironmentLength;
Status = NtAllocateVirtualMemory( Process,
(PVOID *)&ProcessParameters->Environment,
0,
&RegionSize,
MEM_COMMIT,
PAGE_READWRITE
);
if ( !NT_SUCCESS( Status ) ) ...{
BaseSetLastNTError(Status);
return( FALSE );
}
Status = NtWriteVirtualMemory( Process,
ProcessParameters->Environment,
Environment,
EnvironmentLength,
NULL
);
if ( !NT_SUCCESS( Status ) ) ...{
BaseSetLastNTError(Status);
return( FALSE );
}
}
//
// Push the parameters into the new process
//
ProcessParameters->StartingX = lpStartupInfo->dwX;
ProcessParameters->StartingY = lpStartupInfo->dwY;
ProcessParameters->CountX = lpStartupInfo->dwXSize;
ProcessParameters->CountY = lpStartupInfo->dwYSize;
ProcessParameters->CountCharsX =
lpStartupInfo->dwXCountChars;
ProcessParameters->CountCharsY =
lpStartupInfo->dwYCountChars;
ProcessParameters->FillAttribute =
lpStartupInfo->dwFillAttribute;
ProcessParameters->WindowFlags =
lpStartupInfo->dwFlags;
ProcessParameters->ShowWindowFlags =
lpStartupInfo->wShowWindow;
if(lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES | STARTF_USEHOTKEY
/**//* | STARTF_HASSHELLDATA */
)) ...{
ProcessParameters->StandardInput =
lpStartupInfo->hStdInput;
ProcessParameters->StandardOutput =
lpStartupInfo->hStdOutput;
ProcessParameters->StandardError =
lpStartupInfo->hStdError;
}
if (dwCreationFlags & DETACHED_PROCESS) ...{
#if 0
ProcessParameters->ConsoleHandle =
(HANDLE)CONSOLE_DETACHED_PROCESS;
} else if (dwCreationFlags & CREATE_NEW_CONSOLE) ...{
ProcessParameters->ConsoleHandle =
(HANDLE)CONSOLE_NEW_CONSOLE;
} else if (dwCreationFlags & CREATE_NO_WINDOW) ...{
ProcessParameters->ConsoleHandle =
(HANDLE)CONSOLE_CREATE_NO_WINDOW;
#endif
} else ...{
ProcessParameters->ConsoleHandle =
NtCurrentPeb()->ProcessParameters->ConsoleHandle;
if (!(lpStartupInfo->dwFlags & STARTF_USESTDHANDLES)) ...{
ProcessParameters->StandardInput =
NtCurrentPeb()->ProcessParameters->StandardInput;
ProcessParameters->StandardOutput =
NtCurrentPeb()->ProcessParameters->StandardOutput;
ProcessParameters->StandardError =
NtCurrentPeb()->ProcessParameters->StandardError;
}
}
if (dwCreationFlags & CREATE_NEW_PROCESS_GROUP) ...{
ProcessParameters->ConsoleFlags = 1;
}
ProcessParameters->Flags |=
(NtCurrentPeb()->ProcessParameters->Flags
&
RTL_USER_PROC_DISABLE_HEAP_DECOMMIT
);
ParameterLength = ProcessParameters->Length;
//
// Allocate memory in the new process to push the parameters
//
ParametersInNewProcess = NULL;
Status = NtAllocateVirtualMemory(
Process,
(PVOID *)&ParametersInNewProcess,
0,
&ParameterLength,
MEM_COMMIT,
PAGE_READWRITE
);
if ( !NT_SUCCESS( Status ) ) ...{
BaseSetLastNTError(Status);
return FALSE;
}
ProcessParameters->MaximumLength = ParameterLength;
if ( dwCreationFlags & PROFILE_USER ) ...{
ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_USER;
}
if ( dwCreationFlags & PROFILE_KERNEL ) ...{
ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_KERNEL;
}
if ( dwCreationFlags & PROFILE_SERVER ) ...{
ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_SERVER;
}
//
// Push the parameters
//
Status = NtWriteVirtualMemory(
Process,
ParametersInNewProcess,
ProcessParameters,
ProcessParameters->Length,
NULL
);
if ( !NT_SUCCESS( Status ) ) ...{
BaseSetLastNTError(Status);
return FALSE;
}
//
// Make the processes PEB point to the parameters.
//
Status = NtWriteVirtualMemory(
Process,
&Peb->ProcessParameters,
&ParametersInNewProcess,
sizeof( ParametersInNewProcess ),
NULL
);
if ( !NT_SUCCESS( Status ) ) ...{
BaseSetLastNTError(Status);
return FALSE;
}
//
// Set subsystem type in PEB if requested by caller.
// Ignore error
//
if (dwSubsystem != 0) ...{
NtWriteVirtualMemory(
Process,
&Peb->ImageSubsystem,
&dwSubsystem,
sizeof( Peb->ImageSubsystem ),
NULL
);
}
}__finally...{
}
return TRUE;
}
HANDLE loadLibrary( const wchar_t * _dllName)
... {
HANDLE hDll;
UNICODE_STRING dllName;
NTSTATUS st;
RtlInitUnicodeString(&dllName, _dllName);
st = LdrLoadDll(
NULL,
NULL,
&dllName,
&hDll
);
if(!NT_SUCCESS(st))...{
return 0;
}
return hDll;
}
int callDll(
const wchar_t * _dllName,
const char * _procName,
int * result,
int callConvention,
int numOfParameters,
...
)
... {
STRING procName;
HANDLE hDll;
PVOID entry;
NTSTATUS st;
if(result)...{
*result = 0;
}
if(callConvention != CALL_STDCALL)...{
// unimplemented
return -3;
}
hDll = loadLibrary(_dllName);
if ((int)_procName & 0xffff0000) ...{
RtlInitString(&procName, _procName);
st = LdrGetProcedureAddress(
hDll,
&procName,
0L,
&entry
);
}else...{
st = LdrGetProcedureAddress(
hDll,
NULL,
(ULONG)_procName,
&entry
);
}
if(!NT_SUCCESS(st))...{
LdrUnloadDll(hDll);
return -2;
}
/**//*
fake a call stack frame and do a function call
maybe we should use a thunk to make this bit
of code more readable
*/
__asm...{
lea esi, numOfParameters
mov ecx, [esi]
add esi, 4
lea ebx, [ecx * 4]
sub esp, ebx
mov edi, esp
rep movsd
call entry
mov entry, eax
}
// for debug, leave the dll there
// LdrUnloadDll(hDll);
if(result)...{
*result = (int)entry;
}
return 0;
}
NTSTATUS
BaseCreateStack(
IN HANDLE Process,
IN ULONG StackSize,
IN ULONG MaximumStackSize,
OUT PINITIAL_TEB InitialTeb
)
... {
NTSTATUS Status;
PCH Stack;
BOOLEAN GuardPage;
ULONG RegionSize;
ULONG OldProtect;
ULONG ImageStackSize, ImageStackCommit;
PIMAGE_NT_HEADERS NtHeaders;
PPEB Peb;
ULONG PageSize;
Peb = NtCurrentPeb();
PageSize = 0X1000;
//
// If the stack size was not supplied, then use the sizes
// from the image header.
//
NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
ImageStackSize =
NtHeaders->OptionalHeader.SizeOfStackReserve;
ImageStackCommit =
NtHeaders->OptionalHeader.SizeOfStackCommit;
if ( !MaximumStackSize ) ...{
MaximumStackSize = ImageStackSize;
}
if (!StackSize) ...{
StackSize = ImageStackCommit;
}
else ...{
//
// Now Compute how much additional stack space is to be
// reserved. This is done by... If the StackSize is <=
// Reserved size in the image, then reserve whatever the
// image specifies. Otherwise, round up to 1Mb.
//
if ( StackSize >= MaximumStackSize ) ...{
MaximumStackSize = ROUND_UP(StackSize, (1024*1024));
}
}
//
// Align the stack size to a page boundry and the reserved
// size to an allocation granularity boundry.
//
StackSize = ROUND_UP( StackSize, PageSize );
MaximumStackSize = ROUND_UP(
MaximumStackSize,
0x10000
// BaseStaticServerData->SysInfo.AllocationGranularity
);
//
// Reserve address space for the stack
//
Stack = NULL,
Status = NtAllocateVirtualMemory(
Process,
(PVOID *)&Stack,
0,
&MaximumStackSize,
MEM_RESERVE,
PAGE_READWRITE
);
if ( !NT_SUCCESS( Status ) ) ...{
return Status;
}
InitialTeb->OldInitialTeb.OldStackBase = NULL;
InitialTeb->OldInitialTeb.OldStackLimit = NULL;
InitialTeb->StackAllocationBase = Stack;
InitialTeb->StackBase = Stack + MaximumStackSize;
Stack += MaximumStackSize - StackSize;
if (MaximumStackSize > StackSize) ...{
Stack -= PageSize;
StackSize += PageSize;
GuardPage = TRUE;
}
else ...{
GuardPage = FALSE;
}
//
// Commit the initially valid portion of the stack
//
Status = NtAllocateVirtualMemory(
Process,
(PVOID *)&Stack,
0,
&StackSize,
MEM_COMMIT,
PAGE_READWRITE
);
if ( !NT_SUCCESS( Status ) ) ...{
//
// If the commit fails, then delete the address space
// for the stack
//
RegionSize = 0;
NtFreeVirtualMemory(
Process,
(PVOID *)&Stack,
&RegionSize,
MEM_RELEASE
);
return Status;
}
InitialTeb->StackLimit = Stack;
//
// if we have space, create a guard page.
//
if (GuardPage) ...{
RegionSize = PageSize;
Status = NtProtectVirtualMemory(
Process,
(PVOID *)&Stack,
&RegionSize,
PAGE_GUARD | PAGE_READWRITE,
&OldProtect
);
if ( !NT_SUCCESS( Status ) ) ...{
return Status;
}
InitialTeb->StackLimit = (PVOID)(
(PUCHAR)InitialTeb->StackLimit + RegionSize
);
}
return STATUS_SUCCESS;
}
VOID
BaseInitializeContext(
OUT PCONTEXT Context,
IN PVOID Parameter OPTIONAL,
IN PVOID InitialPc OPTIONAL,
IN PVOID InitialSp OPTIONAL,
IN BASE_CONTEXT_TYPE ContextType
)
... {
Context->Eax = (ULONG)InitialPc;
Context->Ebx = (ULONG)Parameter;
Context->SegGs = 0;
Context->SegFs = KGDT_R3_TEB;
Context->SegEs = KGDT_R3_DATA;
Context->SegDs = KGDT_R3_DATA;
Context->SegSs = KGDT_R3_DATA;
Context->SegCs = KGDT_R3_CODE;
//
// Start the thread at IOPL=3.
//
Context->EFlags = 0x3000;
//
// Always start the thread at the thread start thunk.
//
Context->Esp = (ULONG) InitialSp;
Context->Eip = (ULONG)InitialPc;
//
// add code to check alignment and raise exception...
//
Context->ContextFlags = CONTEXT_FULL;
// Reserve room for ret address
Context->Esp -= sizeof(Parameter);
}
HANDLE
BaseGetNamedObjectDirectory(
VOID
)
... {
OBJECT_ATTRIBUTES Obja;
NTSTATUS Status;
ACCESS_MASK DirAccess = DIRECTORY_ALL_ACCESS &
~(DELETE | WRITE_DAC | WRITE_OWNER);
RtlAcquirePebLock();
if ( !BaseNamedObjectDirectory ) ...{
InitializeObjectAttributes(
&Obja,
NULL,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenDirectoryObject(
&BaseNamedObjectDirectory,
DirAccess,
&Obja
);
if ( !NT_SUCCESS(Status) ) ...{
BaseNamedObjectDirectory = NULL;
}
}
RtlReleasePebLock();
return BaseNamedObjectDirectory;
}
POBJECT_ATTRIBUTES
BaseFormatObjectAttributes(
OUT POBJECT_ATTRIBUTES ObjectAttributes,
IN PUNICODE_STRING ObjectName
)
... {
HANDLE RootDirectory;
ULONG Attributes;
PVOID SecurityDescriptor = NULL;
if (ARGUMENT_PRESENT(ObjectName) ) ...{
if ( ARGUMENT_PRESENT(ObjectName) ) ...{
RootDirectory = BaseGetNamedObjectDirectory();
}
else ...{
RootDirectory = NULL;
}
if ( ARGUMENT_PRESENT(ObjectName) ) ...{
Attributes |= OBJ_OPENIF;
}
InitializeObjectAttributes(
ObjectAttributes,
ObjectName,
Attributes,
RootDirectory,
SecurityDescriptor
);
return ObjectAttributes;
}else...{
return NULL;
}
}
UCHAR _stdcall createProcess(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
UCHAR bInheritHandles,
ULONG dwCreationFlags,
PVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
)
... {
HANDLE FileHandle;
NTSTATUS Status, StackStatus;
OBJECT_ATTRIBUTES Obja, *pObja;
UNICODE_STRING PathName;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE SectionHandle;
HANDLE ProcessHandle;
SECTION_IMAGE_INFORMATION ImageInformation;
PROCESS_BASIC_INFORMATION ProcessInfo;
PPEB Peb;
LPWSTR CurdirBuffer, CurdirFilePart;
ULONG CurdirLength,CurdirLength2;
HANDLE ThreadHandle;
INITIAL_TEB InitialTeb;
CONTEXT ThreadContext;
CLIENT_ID ClientId;
STARTUPINFOW StartupInfo;
BASE_API_MSG m;
PBASE_CREATEPROCESS_MSG a=
(PBASE_CREATEPROCESS_MSG)&m.u.CreateProcess;
StartupInfo = *lpStartupInfo;
if(ARGUMENT_PRESENT(lpApplicationName))...{
Status = RtlDosPathNameToNtPathName_U(
lpApplicationName,
&PathName,
NULL,
NULL
);
if(!NT_SUCCESS(Status))...{
return FALSE;
}
InitializeObjectAttributes(
&Obja,
&PathName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenFile(
&FileHandle,
SYNCHRONIZE | FILE_EXECUTE,// | FILE_WRITE_DATA,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
);
if(!NT_SUCCESS(Status))...{
return FALSE;
}
Status = NtCreateSection(
&SectionHandle,
SECTION_ALL_ACCESS,
NULL,
NULL,
PAGE_EXECUTE,
SEC_IMAGE,
FileHandle
);
NtClose(FileHandle);
FileHandle = NULL;
if(!NT_SUCCESS(Status))...{
return FALSE;
}
//
// Query the section to determine the stack parameters and
// image entrypoint.
//
Status = NtQuerySection(
SectionHandle,
SectionImageInformation,
&ImageInformation,
sizeof( ImageInformation ),
NULL
);
}else...{
// simulate a fork operation
SectionHandle = NULL;
}
//
// Create the process object
//
if(!NT_SUCCESS(Status))...{
return FALSE;
}
if (StartupInfo.lpDesktop == NULL) ...{
StartupInfo.lpDesktop =
(LPWSTR)((PRTL_USER_PROCESS_PARAMETERS)NtCurrentPeb()->
ProcessParameters)->DesktopInfo.Buffer;
}
pObja = BaseFormatObjectAttributes(&Obja, NULL);
Status = NtCreateProcess(
&ProcessHandle,
PROCESS_ALL_ACCESS,
pObja,
NtCurrentProcess(),
(BOOLEAN)bInheritHandles,
SectionHandle,
NULL,
NULL
);
if ( !NT_SUCCESS(Status) ) ...{
return FALSE;
}
NtClose(SectionHandle);
SectionHandle = NULL;
//
// Determine the location of the
// processes PEB.
//
Status = NtQueryInformationProcess(
ProcessHandle,
ProcessBasicInformation,
&ProcessInfo,
sizeof( ProcessInfo ),
NULL
);
if ( !NT_SUCCESS( Status ) ) ...{
return FALSE;
}
Peb = ProcessInfo.PebBaseAddress;
#if 1
//
// Push the parameters into the address space
// of the new process
//
if ( ARGUMENT_PRESENT(lpCurrentDirectory) ) ...{
CurdirBuffer = RtlAllocateHeap(
RtlProcessHeap(),
0, //MAKE_TAG( TMP_TAG ),
(MAX_PATH*2)+sizeof(UNICODE_NULL)
);
if ( !CurdirBuffer ) ...{
BaseSetLastNTError(STATUS_NO_MEMORY);
return FALSE;
}
CurdirLength2 = GetFullPathNameW(
lpCurrentDirectory,
MAX_PATH,
CurdirBuffer,
&CurdirFilePart
);
if ( CurdirLength2 > MAX_PATH ) ...{
SetLastError(ERROR_DIRECTORY);
return FALSE;
}
//
// now make sure the directory exists
//
CurdirLength = GetFileAttributesW(CurdirBuffer);
if ( (CurdirLength == 0xffffffff) ||
!(CurdirLength & FILE_ATTRIBUTE_DIRECTORY) ) ...{
SetLastError(ERROR_DIRECTORY);
return FALSE;
}
}
if (!BasePushProcessParameters(
ProcessHandle,
Peb,
lpApplicationName,
lpCurrentDirectory,
lpCommandLine,
lpEnvironment,
&StartupInfo,
dwCreationFlags,
bInheritHandles,
0
) ) ...{
return FALSE;
}
#endif
StackStatus = BaseCreateStack(
ProcessHandle,
ImageInformation.CommittedStackSize,
ImageInformation.MaximumStackSize,
&InitialTeb
);
if ( !NT_SUCCESS(StackStatus) ) ...{
BaseSetLastNTError(StackStatus);
return FALSE;
}
//
// Create an initial context for the new thread.
//
BaseInitializeContext(
&ThreadContext,
Peb,
ImageInformation.TransferAddress,
InitialTeb.StackBase,
BaseContextTypeProcess
);
//
// Create the actual thread object
//
pObja = BaseFormatObjectAttributes(&Obja, NULL);
Status = NtCreateThread(
&ThreadHandle,
THREAD_ALL_ACCESS,
pObja,
ProcessHandle,
&ClientId,
&ThreadContext,
&InitialTeb,
TRUE
);
if (!NT_SUCCESS(Status) ) ...{
BaseSetLastNTError(Status);
return FALSE;
}
//
// Call the Windows server to let it know about the
// process.
//
memset(&m, 0, sizeof(m));
a->ProcessHandle = ProcessHandle;
a->ThreadHandle = ThreadHandle;
a->ClientId = ClientId;
a->CreationFlags = dwCreationFlags;
#if 0
if(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))...{
Status = DbgUiConnectToDbg();
if ( !NT_SUCCESS(Status) ) ...{
NtTerminateProcess(ProcessHandle,Status);
BaseSetLastNTError(Status);
return FALSE;
}
a->DebuggerClientId = NtCurrentTeb()->ClientId;
}
else ...{
a->DebuggerClientId.UniqueProcess = NULL;
a->DebuggerClientId.UniqueThread = NULL;
}
#endif
#if 0
//
// Set the 2 bit if a gui app is starting. The window
// manager needs to
// know this so it can synchronize the startup of this app
// (WaitForInputIdle api). This info is passed using the
// process
// handle tag bits. The 1 bit asks the window manager to
// turn on
// or turn off the application start cursor
// (hourglass/pointer).
//
// When starting a WOW process, lie and tell UserSrv
// NTVDM.EXE is a GUI
// process. We also turn on bit 0x8 so that UserSrv can
// ignore the
// UserNotifyConsoleApplication call made by the console
// during startup.
//
if(ImageInformation.SubSystemType ==
IMAGE_SUBSYSTEM_WINDOWS_GUI
// || IsWowBinary
) ...{
a->ProcessHandle = (HANDLE)((ULONG)a->ProcessHandle | 2);
//
// If the creating process is a GUI app, turn on the app.
// start cursor
// by default. This can be overridden by
// STARTF_FORCEOFFFEEDBACK.
//
NtHeaders = RtlImageNtHeader((PVOID)GetModuleHandle(NULL));
if ( NtHeaders->OptionalHeader.Subsystem ==
IMAGE_SUBSYSTEM_WINDOWS_GUI
)...{
a->ProcessHandle = (HANDLE)((ULONG)a->ProcessHandle | 1);
}
}
#endif
#if 1
//
// If feedback is forced on, turn it on. If forced off,
// turn it off.
// Off overrides on.
//
if (StartupInfo.dwFlags & STARTF_FORCEONFEEDBACK)
a->ProcessHandle = (HANDLE)((ULONG)a->ProcessHandle | 1);
if (StartupInfo.dwFlags & STARTF_FORCEOFFFEEDBACK)
a->ProcessHandle = (HANDLE)((ULONG)a->ProcessHandle & ~1);
CsrClientCallServer(
(PCSR_API_MSG)&m,
NULL,
CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepCreateProcess),
sizeof( *a )
);
if (!NT_SUCCESS((NTSTATUS)m.ReturnValue)) ...{
BaseSetLastNTError((NTSTATUS)m.ReturnValue);
NtTerminateProcess(ProcessHandle, 0);
return FALSE;
}
#endif
if (!( dwCreationFlags & CREATE_SUSPENDED) ) ...{
NtResumeThread(ThreadHandle, (PULONG)NULL);
}
return TRUE;
}
int wmain( int c, const wchar_t ** v)
... {
static PROCESS_INFORMATION pi;
static STARTUPINFOW si = ...{sizeof(si)};
BOOLEAN ret;
if(c < 2)...{
return -1;
}
wprintf(L"launching %s...", v[1]);
__try...{
ret = createProcess(
v[1],
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi
);
if(ret)...{
printf("Ok. ");
}else...{
printf("Failed(%d). ", GetLastError());
}
}__except(1)...{
;
}
ExitProcess(0);
// NtTerminateProcess(NtCurrentProcess(), 0);
// callDll(L"kernel32.dll", "ExitProcess", CALL_STDCALL, 1, 0);
return 0;
}
void __declspec(dllexport) _stdcall
startW(HWND hwnd, HINSTANCE h, wchar_t * cmdLine, int nCmdShow)
... {
static PROCESS_INFORMATION pi;
static STARTUPINFOW si = ...{sizeof(si)};
__try...{
createProcess(
cmdLine,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi
);
}__except(1)...{
;
}
}
BOOLEAN _stdcall dllMain( int a, int b, int c)
... {
return TRUE;
}