转载请您注明出处:http://www.cnblogs.com/lsh123/p/7405796.html
0x01 CreateProcessW
CreateProcess的使用有ANSI版本的CreateProcessA和UNICODE版本的CreateProcessW:
不过查看源码就可以发现其实CreateProcessA内部调用的还是CreateProcessW:
BOOL
WINAPI
CreateProcessA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
)
/*++
ANSI thunk to CreateProcessW
--*/
{
NTSTATUS Status;
PUNICODE_STRING CommandLine;
UNICODE_STRING ApplicationName;
UNICODE_STRING CurrentDirectory;
STARTUPINFOW StartupInfo;
ANSI_STRING AnsiString;
UNICODE_STRING Unicode;
UNICODE_STRING DynamicCommandLine;
UNICODE_STRING NullUnicodeString;
BOOL ReturnStatus;
if (ARGUMENT_PRESENT (lpCommandLine)) {
if ( (strlen( lpCommandLine ) + 1) * sizeof( WCHAR ) <
NtCurrentTeb()->StaticUnicodeString.MaximumLength ) {
DynamicCommandLine.Buffer = NULL;
CommandLine = Basep8BitStringToStaticUnicodeString( lpCommandLine );
if (CommandLine == NULL) {
return FALSE;
}
} else {
if (!Basep8BitStringToDynamicUnicodeString( &DynamicCommandLine,
lpCommandLine )) {
return FALSE;
}
}
} else {
DynamicCommandLine.Buffer = NULL;
CommandLine = &NullUnicodeString;
CommandLine->Buffer = NULL;
}
ApplicationName.Buffer = NULL;
ApplicationName.Buffer = NULL;
CurrentDirectory.Buffer = NULL;
RtlMoveMemory(&StartupInfo,lpStartupInfo,sizeof(*lpStartupInfo));
ASSERT(sizeof(StartupInfo) == sizeof(*lpStartupInfo));
StartupInfo.lpReserved = NULL;
StartupInfo.lpDesktop = NULL;
StartupInfo.lpTitle = NULL;
try {
try {
if (ARGUMENT_PRESENT(lpApplicationName)) {
if (!Basep8BitStringToDynamicUnicodeString( &ApplicationName,
lpApplicationName )) {
ReturnStatus = FALSE;
goto tryexit;
}
}
if (ARGUMENT_PRESENT(lpCurrentDirectory)) {
if (!Basep8BitStringToDynamicUnicodeString( &CurrentDirectory,
lpCurrentDirectory )) {
ReturnStatus = FALSE;
goto tryexit;
}
}
if (ARGUMENT_PRESENT(lpStartupInfo->lpReserved)) {
//
// Win95 does not touch reserved, and Intergraph Voxtel passes
// garbage for this. Handle this by probing lpReserved, and if
// the pointer is bad, ignore it
//
try {
RtlInitAnsiString(&AnsiString,lpStartupInfo->lpReserved);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH) {
goto bail_on_reserved;
}
Unicode.MaximumLength = (USHORT)RtlAnsiStringToUnicodeSize(&AnsiString) ;
StartupInfo.lpReserved = RtlAllocateHeap( RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
Unicode.MaximumLength);
if ( !StartupInfo.lpReserved ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
ReturnStatus = FALSE;
goto tryexit;
}
Unicode.Buffer = StartupInfo.lpReserved;
Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
ReturnStatus = FALSE;
goto tryexit;
}
}
bail_on_reserved:
if (ARGUMENT_PRESENT(lpStartupInfo->lpDesktop)) {
RtlInitAnsiString(&AnsiString,lpStartupInfo->lpDesktop);
Unicode.MaximumLength = (USHORT)RtlAnsiStringToUnicodeSize(&AnsiString) ;
StartupInfo.lpDesktop = RtlAllocateHeap( RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
Unicode.MaximumLength);
if ( !StartupInfo.lpDesktop ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
ReturnStatus = FALSE;
goto tryexit;
}
Unicode.Buffer = StartupInfo.lpDesktop;
Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
ReturnStatus = FALSE;
goto tryexit;
}
}
if (ARGUMENT_PRESENT(lpStartupInfo->lpTitle)) {
RtlInitAnsiString(&AnsiString,lpStartupInfo->lpTitle);
Unicode.MaximumLength = (USHORT)RtlAnsiStringToUnicodeSize(&AnsiString) ;
StartupInfo.lpTitle = RtlAllocateHeap( RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
Unicode.MaximumLength);
if ( !StartupInfo.lpTitle ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
ReturnStatus = FALSE;
goto tryexit;
}
Unicode.Buffer = StartupInfo.lpTitle;
Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
ReturnStatus = FALSE;
goto tryexit;
}
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH) {
BaseSetLastNTError(GetExceptionCode());
ReturnStatus = FALSE;
goto tryexit;
}
ReturnStatus = CreateProcessW(
ApplicationName.Buffer,
DynamicCommandLine.Buffer ? DynamicCommandLine.Buffer
: CommandLine->Buffer,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
CurrentDirectory.Buffer,
&StartupInfo,
lpProcessInformation
);
tryexit:;
}
finally {
RtlFreeUnicodeString(&DynamicCommandLine);
RtlFreeUnicodeString(&ApplicationName);
RtlFreeUnicodeString(&CurrentDirectory);
RtlFreeHeap(RtlProcessHeap(), 0,StartupInfo.lpReserved);
RtlFreeHeap(RtlProcessHeap(), 0,StartupInfo.lpDesktop);
RtlFreeHeap(RtlProcessHeap(), 0,StartupInfo.lpTitle);
}
return ReturnStatus;
}
CreateProcessW的十个参数:
WINBASEAPI
BOOL
WINAPI
CreateProcessW(
LPCWSTR lpApplicationName, //指向一个NULL结尾的,新进程的可执行文件的名称
LPWSTR lpCommandLine, //指向一个NULL结尾的,传给新进程的命令行字符串
LPSECURITY_ATTRIBUTES lpProcessAttributes,
//指向一个SECURITY_ATTRIBUTES结构体,分配给新的进程对象
//SECURITY_ATTRIBUTES结构可以决定是否返回的句柄可以被子进程继承(bInheritHandle )。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。
//SECURITY_ATTRIBUTES结构的lpSecurityDescriptor成员可以指定新进程的安全描述符,如果参数为空,新进程使用默认的安全描述符。
LPSECURITY_ATTRIBUTES lpThreadAttributes,
//指向一个SECURITY_ATTRIBUTES结构体,分配给新的线程对象
BOOL bInheritHandles,
//标识新进程是否可以从调用进程处继承所有可继承的句柄。被继承的句柄与原进程拥有完全相同的值和访问权限。
DWORD dwCreationFlags,
//标识了影响新进程创建方式的标志,多个标志按位或进行组合
LPVOID lpEnvironment,
//指向一块内存,其中包含新进程要使用的环境字符串。如果此参数为空,新进程继承父进程的一组环境字符串。
LPCWSTR lpCurrentDirectory,
//指向一个以NULL结尾的字符串,用来设置新进程的当前驱动器和目录,这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与父进程相同的驱动器和目录。
LPSTARTUPINFOW lpStartupInfo,
//指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。
LPPROCESS_INFORMATION lpProcessInformation
//指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。
);
(1)STARTUPINFO 和 PROCESS_INFORMATION的使用前初始化为空:
STARTUPINFO StartupInfo = { 0 };
StartupInfo.cb = sizeof(STARTUPINFO);
PROCESS_INFORMATION ProcessInfo = { 0 };
(2)第六参数:dwCreationFlags 的部分标志:
⑴值:CREATE_DEFAULT_ERROR_MODE
含义:新的进程不继承调用进程的错误模式。CreateProcess函数赋予新进程当前的默认错误模式作为替代。应用程序可以调用SetErrorMode函数设置当前的默认错误模式。
这个标志对于那些运行在没有硬件错误环境下的多线程外壳程序是十分有用的。
对于CreateProcess函数,默认的行为是为新进程继承调用者的错误模式。设置这个标志以改变默认的处理方式。
⑵值:CREATE_NEW_CONSOLE
含义:新的进程将使用一个新的控制台,而不是继承父进程的控制台。这个标志不能与DETACHED_PROCESS标志一起使用。
⑶值:CREATE_NEW_PROCESS_GROUP
含义:新进程将是一个进程树的根进程。进程树中的全部进程都是根进程的子进程。新进程树的用户标识符与这个进程的标识符是相同的,由lpProcessInformation参数返回。进程树经常使用GenerateConsoleCtrlEvent函数允许发送CTRL+C或 CTRL+BREAK信号到一组控制台进程。
⑷值:CREATE_SEPARATE_WOW_VDM
如果被设置,新进程将会在一个私有的虚拟DOS机(VDM)中运行。另外,默认情况下所有的16位Windows应用程序都会在同一个共享的VDM中以线程的方式运行。单独运行一个16位程序的优点是一个应用程序的崩溃只会结束这一个VDM的运行;其他那些在不同VDM中运行的程序会继续正常的运行。同样的,在不同VDM中运行的16位Windows应用程序拥有不同的输入队列,这意味着如果一个程序暂时失去响应,在独立的VDM中的应用程序能够继续获得输入。
⑸值:CREATE_SHARED_WOW_VDM
如果WIN.INI中的Windows段的DefaultSeparateVDM选项被设置为真,这个标识使得CreateProcess函数越过这个选项并在共享的虚拟DOS机中运行新进程。
⑹值:CREATE_SUSPENDED
含义:新进程的主线程会以挂起的状态被创建,直到调用ResumeThread函数被调用时才运行。
⑺值:CREATE_UNICODE_ENVIRONMENT
含义:如果被设置,由lpEnvironment参数指定环境块使用Unicode字符,如果为空,环境块默认使用ANSI字符。
⑻值:DEBUG_PROCESS
含义:如果这个标志被设置,调用进程将被当做一个调试程序,并且新进程会被当做被调试的进程。系统把被调试程序发生的所有调试事件通知给调试器。
如果你使用这个标志创建进程,只有调用进程(调用CreateProcess函数的进程)可以调用WaitForDebugEvent函数。
⑼值:DEBUG_ONLY_THIS_PROCESS
含义:如果此标志没有被设置且调用进程正在被调试,新进程将成为调试调用进程的调试器的另一个调试对象。如果调用进程没有被调试,有关调试的行为就不会产生。
⑽值:DETACHED_PROCESS
含义:对于控制台进程,新进程没有访问父进程控制台的权限。新进程可以通过AllocConsole函数自己创建一个新的控制台。这个标志不可以与CREATE_NEW_CONSOLE标志一起使用。
〔11〕值:CREATE_NO_WINDOW
含义:系统不为新进程创建CUI窗口,使用该标志可以创建不含窗口的CUI程序。
0x02 创建进程详细步骤1:打开目标映像文件,创建进程对象,线程对象
CreateProcessW源代码(windows2000)
1 BOOL 2 WINAPI 3 CreateProcessW( 4 LPCWSTR lpApplicationName, 5 LPWSTR lpCommandLine, 6 LPSECURITY_ATTRIBUTES lpProcessAttributes, 7 LPSECURITY_ATTRIBUTES lpThreadAttributes, 8 BOOL bInheritHandles, 9 DWORD dwCreationFlags, 10 LPVOID lpEnvironment, 11 LPCWSTR lpCurrentDirectory, 12 LPSTARTUPINFOW lpStartupInfo, 13 LPPROCESS_INFORMATION lpProcessInformation 14 ) 15 16 { 17 NTSTATUS Status; 18 OBJECT_ATTRIBUTES Obja; 19 POBJECT_ATTRIBUTES pObja; 20 HANDLE ProcessHandle, ThreadHandle, VdmWaitHandle = NULL; 21 HANDLE FileHandle, SectionHandle; 22 CLIENT_ID ClientId; 23 UNICODE_STRING PathName; 24 IO_STATUS_BLOCK IoStatusBlock; 25 BOOLEAN TranslationStatus; 26 RTL_RELATIVE_NAME RelativeName; 27 PVOID FreeBuffer; 28 LPWSTR NameBuffer; 29 LPWSTR WhiteScan; 30 ULONG Length,i; 31 PROCESS_BASIC_INFORMATION ProcessInfo; 32 SECTION_IMAGE_INFORMATION ImageInformation; 33 NTSTATUS StackStatus; 34 BOOLEAN bStatus; 35 INITIAL_TEB InitialTeb; 36 CONTEXT ThreadContext; 37 PPEB Peb; 38 BASE_API_MSG m; 39 PBASE_CREATEPROCESS_MSG a= (PBASE_CREATEPROCESS_MSG)&m.u.CreateProcess; 40 PBASE_CHECKVDM_MSG b= (PBASE_CHECKVDM_MSG)&m.u.CheckVDM; 41 PWCH TempNull = NULL; 42 WCHAR TempChar; 43 UNICODE_STRING VdmNameString; 44 PVOID BaseAddress; 45 ULONG VdmReserve; 46 SIZE_T BigVdmReserve; 47 ULONG iTask=0; 48 LPWSTR CurdirBuffer, CurdirFilePart; 49 DWORD CurdirLength,CurdirLength2; 50 ULONG VDMCreationState=0; 51 ULONG VdmBinaryType = 0; 52 UNICODE_STRING SubSysCommandLine; 53 PIMAGE_NT_HEADERS NtHeaders; 54 DWORD dwNoWindow = (dwCreationFlags & CREATE_NO_WINDOW); 55 ANSI_STRING AnsiStringVDMEnv; 56 UNICODE_STRING UnicodeStringVDMEnv; 57 WCHAR ImageFileDebuggerCommand[ 64 ]; 58 LPWSTR QuotedBuffer; 59 BOOLEAN QuoteInsert; 60 BOOLEAN QuoteCmdLine = FALSE; 61 BOOLEAN QuoteFound; 62 BOOLEAN SearchRetry; 63 BOOLEAN IsWowBinary = FALSE; 64 STARTUPINFOW StartupInfo; 65 DWORD LastError; 66 DWORD fileattr; 67 PROCESS_PRIORITY_CLASS PriClass; 68 PVOID State; 69 #if defined(BUILD_WOW6432) || defined(_WIN64) 70 LPCWSTR lpOriginalApplicationName = lpApplicationName; 71 LPWSTR lpOriginalCommandLine = lpCommandLine; 72 #endif 73 74 #if defined(WX86) || defined(_AXP64_) 75 HANDLE Wx86Info = NULL; 76 #endif 77 78 #if defined WX86 79 BOOLEAN UseKnownWx86Dll; 80 UseKnownWx86Dll = NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll; 81 NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE; 82 #endif 83 84 85 RtlZeroMemory(lpProcessInformation,sizeof(*lpProcessInformation)); 86 87 // Private VDM flag should be ignored; Its meant for internal use only. 88 dwCreationFlags &= (ULONG)~CREATE_NO_WINDOW; 89 90 // 91 // CREATE_WITH_USERPROFILE is the new Create Flag that is used 92 // only by CreateProcessWithLogonW. If this flags ends up getting 93 // passed to CreateProcess, we must reject it. 94 // 95 if (dwCreationFlags & CREATE_WITH_USERPROFILE ) { 96 SetLastError(ERROR_INVALID_PARAMETER); 97 return FALSE; 98 } 99 100 if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) == 101 (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) { 102 103 SetLastError(ERROR_INVALID_PARAMETER); 104 return FALSE; 105 } 106 107 AnsiStringVDMEnv.Buffer = NULL; 108 UnicodeStringVDMEnv.Buffer = NULL; 109 110 // 111 // the lowest specified priority class is used. 112 // 113 114 if (dwCreationFlags & IDLE_PRIORITY_CLASS ) { 115 PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE; 116 } 117 else if (dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS ) { 118 PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL; 119 } 120 else if (dwCreationFlags & NORMAL_PRIORITY_CLASS ) { 121 PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; 122 } 123 else if (dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS ) { 124 PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; 125 } 126 else if (dwCreationFlags & HIGH_PRIORITY_CLASS ) { 127 PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; 128 } 129 else if (dwCreationFlags & REALTIME_PRIORITY_CLASS ) { 130 if ( BasepIsRealtimeAllowed(FALSE) ) { 131 PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME; 132 } 133 else { 134 PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; 135 } 136 } 137 else { 138 PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_UNKNOWN; 139 } 140 PriClass.Foreground = FALSE; 141 142 dwCreationFlags = (dwCreationFlags & ~PRIORITY_CLASS_MASK ); 143 144 // 145 // Default separate/shared VDM option if not explicitly specified. 146 // 147 148 if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM) { 149 if (dwCreationFlags & CREATE_SHARED_WOW_VDM) { 150 SetLastError(ERROR_INVALID_PARAMETER); 151 152 return FALSE; 153 } 154 } 155 else 156 if ((dwCreationFlags & CREATE_SHARED_WOW_VDM) == 0) { 157 if (BaseStaticServerData->DefaultSeparateVDM) { 158 dwCreationFlags |= CREATE_SEPARATE_WOW_VDM; 159 } 160 } 161 162 if ((dwCreationFlags & CREATE_SEPARATE_WOW_VDM) == 0) { 163 // 164 // If the creator is running inside a job object, always 165 // set SEPERATE_WOW_VDM so the VDM is part of the job. 166 // 167 JOBOBJECT_BASIC_UI_RESTRICTIONS UiRestrictions; 168 169 Status = NtQueryInformationJobObject(NULL, 170 JobObjectBasicUIRestrictions, 171 &UiRestrictions, 172 sizeof(UiRestrictions), 173 NULL); 174 if (Status != STATUS_ACCESS_DENIED) { 175 // 176 // Anything other than STATUS_ACCESS_DENIED indicates the 177 // current process is inside a job. 178 // 179 dwCreationFlags = (dwCreationFlags & (~CREATE_SHARED_WOW_VDM)) | 180 CREATE_SEPARATE_WOW_VDM; 181 } 182 } 183 184 185 // 186 // If ANSI environment, convert to Unicode 187 // 188 189 if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) ) { 190 PUCHAR s; 191 STRING Ansi; 192 UNICODE_STRING Unicode; 193 MEMORY_BASIC_INFORMATION MemoryInformation; 194 195 Ansi.Buffer = s = lpEnvironment; 196 while (*s || *(s+1)) // find end of block 197 s++; 198 199 Ansi.Length = (USHORT)(s - Ansi.Buffer) + 1; 200 Ansi.MaximumLength = Ansi.Length + 1; 201 MemoryInformation.RegionSize = Ansi.MaximumLength * sizeof(WCHAR); 202 Unicode.Buffer = NULL; 203 Status = NtAllocateVirtualMemory( NtCurrentProcess(), 204 &Unicode.Buffer, 205 0, 206 &MemoryInformation.RegionSize, 207 MEM_COMMIT, 208 PAGE_READWRITE 209 ); 210 if (!NT_SUCCESS(Status) ) { 211 BaseSetLastNTError(Status); 212 213 return FALSE; 214 } 215 216 Unicode.MaximumLength = (USHORT)MemoryInformation.RegionSize; 217 Status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, FALSE); 218 if (!NT_SUCCESS(Status) ) { 219 NtFreeVirtualMemory( NtCurrentProcess(), 220 &Unicode.Buffer, 221 &MemoryInformation.RegionSize, 222 MEM_RELEASE 223 ); 224 BaseSetLastNTError(Status); 225 226 return FALSE; 227 } 228 lpEnvironment = Unicode.Buffer; 229 } 230 231 FileHandle = NULL; 232 SectionHandle = NULL; 233 ProcessHandle = NULL; 234 ThreadHandle = NULL; 235 FreeBuffer = NULL; 236 NameBuffer = NULL; 237 VdmNameString.Buffer = NULL; 238 BaseAddress = (PVOID)1; 239 VdmReserve = 0; 240 CurdirBuffer = NULL; 241 CurdirFilePart = NULL; 242 SubSysCommandLine.Buffer = NULL; 243 QuoteFound = FALSE; 244 QuoteInsert = FALSE; 245 QuotedBuffer = NULL; 246 247 try { 248 249 // 250 // Make a copy of the startup info so we can change it. 251 // 252 253 StartupInfo = *lpStartupInfo; 254 255 // 256 // STARTF_USEHOTKEY means hStdInput is really the hotkey value. 257 // STARTF_HASSHELLDATA means std handles are used for shell-private 258 // data. This flag is used if an icon is passed to ShellExecuteEx. 259 // As a result they cannot be specified with STARTF_USESTDHANDLES. 260 // Consistent with Win95, USESTDHANDLES is ignored. 261 // 262 263 if (StartupInfo.dwFlags & STARTF_USESTDHANDLES && 264 StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_HASSHELLDATA)) { 265 266 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES; 267 } 268 269 VdmRetry: 270 LastError = 0; 271 SearchRetry = TRUE; 272 QuoteInsert = FALSE; 273 QuoteCmdLine = FALSE; 274 if (!ARGUMENT_PRESENT( lpApplicationName )) { 275 276 // 277 // Locate the image 278 // 279 280 // forgot to free NameBuffer before goto VdmRetry??? 281 ASSERT(NameBuffer == NULL); 282 283 NameBuffer = RtlAllocateHeap( RtlProcessHeap(), 284 MAKE_TAG( TMP_TAG ), 285 MAX_PATH * sizeof( WCHAR )); 286 if ( !NameBuffer ) { 287 BaseSetLastNTError(STATUS_NO_MEMORY); 288 return FALSE; 289 } 290 lpApplicationName = lpCommandLine; 291 TempNull = (PWCH)lpApplicationName; 292 WhiteScan = (LPWSTR)lpApplicationName; 293 294 // 295 // check for lead quote 296 // 297 if ( *WhiteScan == L'\"' ) { 298 SearchRetry = FALSE; 299 WhiteScan++; 300 lpApplicationName = WhiteScan; 301 while(*WhiteScan) { 302 if ( *WhiteScan == (WCHAR)'\"' ) { 303 TempNull = (PWCH)WhiteScan; 304 QuoteFound = TRUE; 305 break; 306 } 307 WhiteScan++; 308 TempNull = (PWCH)WhiteScan; 309 } 310 } 311 else { 312 retrywsscan: 313 lpApplicationName = lpCommandLine; 314 while(*WhiteScan) { 315 if ( *WhiteScan == (WCHAR)' ' || 316 *WhiteScan == (WCHAR)'\t' ) { 317 TempNull = (PWCH)WhiteScan; 318 break; 319 } 320 WhiteScan++; 321 TempNull = (PWCH)WhiteScan; 322 } 323 } 324 TempChar = *TempNull; 325 *TempNull = UNICODE_NULL; 326 327 #ifdef WX86 328 329 // 330 // Wx86 applications must use x86 version of known exes 331 // for compatibility. 332 // 333 334 if (UseKnownWx86Dll) { 335 LPWSTR KnownName; 336 337 NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE; 338 339 KnownName = BasepWx86KnownExe(lpApplicationName); 340 if (KnownName) { 341 lpApplicationName = KnownName; 342 } 343 } 344 #endif 345 346 347 Length = SearchPathW( 348 NULL, 349 lpApplicationName, 350 (PWSTR)L".exe", 351 MAX_PATH, 352 NameBuffer, 353 NULL 354 )*2; 355 356 if (Length != 0 && Length < MAX_PATH * sizeof( WCHAR )) { 357 // 358 // SearchPathW worked, but file might be a directory 359 // if this happens, we need to keep trying 360 // 361 fileattr = GetFileAttributesW(NameBuffer); 362 if ( fileattr != 0xffffffff && 363 (fileattr & FILE_ATTRIBUTE_DIRECTORY) ) { 364 Length = 0; 365 } else { 366 Length++; 367 Length++; 368 } 369 } 370 371 if ( !Length || Length >= MAX_PATH<<1 ) { 372 373 // 374 // If we search pathed, then return file not found. 375 // otherwise, try to be more specific. 376 // 377 RTL_PATH_TYPE PathType; 378 HANDLE hFile; 379 380 PathType = RtlDetermineDosPathNameType_U(lpApplicationName); 381 if ( PathType != RtlPathTypeRelative ) { 382 383 // 384 // The failed open should set get last error properly. 385 // 386 387 hFile = CreateFileW( 388 lpApplicationName, 389 GENERIC_READ, 390 FILE_SHARE_READ | FILE_SHARE_WRITE, 391 NULL, 392 OPEN_EXISTING, 393 FILE_ATTRIBUTE_NORMAL, 394 NULL 395 ); 396 if ( hFile != INVALID_HANDLE_VALUE ) { 397 CloseHandle(hFile); 398 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND); 399 } 400 } 401 else { 402 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND); 403 } 404 405 // 406 // remember initial last error value for the retry scan path 407 // 408 409 if ( LastError ) { 410 SetLastError(LastError); 411 } 412 else { 413 LastError = GetLastError(); 414 } 415 416 // 417 // restore the command line 418 // 419 420 *TempNull = TempChar; 421 lpApplicationName = NameBuffer; 422 423 // 424 // If we still have command line left, then keep going 425 // the point is to march through the command line looking 426 // for whitespace so we can try to find an image name 427 // launches of things like: 428 // c:\word 95\winword.exe /embedding -automation 429 // require this. Our first iteration will stop at c:\word, our next 430 // will stop at c:\word 95\winword.exe 431 // 432 if (*WhiteScan && SearchRetry) { 433 WhiteScan++; 434 TempNull = WhiteScan; 435 QuoteInsert = TRUE; 436 QuoteFound = TRUE; 437 goto retrywsscan; 438 } 439 440 return FALSE; 441 } 442 // 443 // restore the command line 444 // 445 446 *TempNull = TempChar; 447 lpApplicationName = NameBuffer; 448 } 449 else 450 if (!ARGUMENT_PRESENT( lpCommandLine ) || *lpCommandLine == UNICODE_NULL ) { 451 QuoteCmdLine = TRUE; 452 lpCommandLine = (LPWSTR)lpApplicationName; 453 } 454 455 456 #ifdef WX86 457 458 // 459 // Wx86 applications must use x86 version of known exes 460 // for compatibility. 461 // 462 463 if (UseKnownWx86Dll) { 464 LPWSTR KnownName; 465 466 NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE; 467 468 KnownName = BasepWx86KnownExe(lpApplicationName); 469 if (KnownName) { 470 471 RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer); 472 NameBuffer = KnownName; 473 lpApplicationName = KnownName; 474 } 475 } 476 477 #endif 478 479 480 // 481 // Translate to an NT name. 482 // 483 484 TranslationStatus = RtlDosPathNameToNtPathName_U( 485 lpApplicationName, 486 &PathName, 487 NULL, 488 &RelativeName 489 ); 490 491 if ( !TranslationStatus ) { 492 SetLastError(ERROR_PATH_NOT_FOUND); 493 494 return FALSE; 495 } 496 497 // forgot to free FreeBuffer before goto VdmRetry???? 498 ASSERT(FreeBuffer == NULL); 499 FreeBuffer = PathName.Buffer; 500 501 if ( RelativeName.RelativeName.Length ) { 502 PathName = *(PUNICODE_STRING)&RelativeName.RelativeName; 503 } 504 else { 505 RelativeName.ContainingDirectory = NULL; 506 } 507 508 InitializeObjectAttributes( 509 &Obja, 510 &PathName, 511 OBJ_CASE_INSENSITIVE, 512 RelativeName.ContainingDirectory, 513 NULL 514 ); 515 516 // 517 // Open the file for execute access 518 // 519 520 Status = NtOpenFile( 521 &FileHandle, 522 SYNCHRONIZE | FILE_EXECUTE, 523 &Obja, 524 &IoStatusBlock, 525 FILE_SHARE_READ | FILE_SHARE_DELETE, 526 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE 527 ); 528 if (!NT_SUCCESS(Status) ) { 529 530 // 531 // if we failed, see if this is a device. If it is a device, 532 // then just return invalid image format 533 // 534 535 if ( RtlIsDosDeviceName_U((PWSTR)lpApplicationName) ) { 536 SetLastError(ERROR_BAD_DEVICE); 537 } 538 else { 539 BaseSetLastNTError(Status); 540 } 541 542 return FALSE; 543 } 544 545 // 546 // If no desktop has been specified, use the caller's 547 // desktop. 548 // 549 550 if (StartupInfo.lpDesktop == NULL) { 551 StartupInfo.lpDesktop = 552 (LPWSTR)((PRTL_USER_PROCESS_PARAMETERS)NtCurrentPeb()-> 553 ProcessParameters)->DesktopInfo.Buffer; 554 } 555 556 // 557 // Create a section object backed by the file 558 // 559 560 Status = NtCreateSection( 561 &SectionHandle, 562 SECTION_ALL_ACCESS, 563 NULL, 564 NULL, 565 PAGE_EXECUTE, 566 SEC_IMAGE, 567 FileHandle 568 ); 569 570 571 NtClose(FileHandle); 572 FileHandle = NULL; 573 574 575 576 // 577 // App Certification DLL 578 // 579 580 if (NT_SUCCESS(Status)) { 581 582 Status = BasepIsProcessAllowed(lpApplicationName); 583 584 if (!NT_SUCCESS(Status)) { 585 BaseSetLastNTError(Status); 586 return FALSE; 587 } 588 589 } 590 591 592 593 if (!NT_SUCCESS(Status)) { 594 595 switch (Status) { 596 // 16 bit OS/2 exe 597 case STATUS_INVALID_IMAGE_NE_FORMAT: 598 #ifdef i386 599 // 600 // Use OS/2 if x86 (OS/2 not supported on risc), 601 // and CreationFlags don't have forcedos bit 602 // and Registry didn't specify ForceDos 603 // 604 // else execute as a DOS bound app. 605 // 606 // 607 608 if (!(dwCreationFlags & CREATE_FORCEDOS) && 609 !BaseStaticServerData->ForceDos) 610 { 611 612 if ( !BuildSubSysCommandLine( L"OS2 /P ", 613 lpApplicationName, 614 lpCommandLine, 615 &SubSysCommandLine 616 ) ) { 617 return FALSE; 618 } 619 620 lpCommandLine = SubSysCommandLine.Buffer; 621 622 lpApplicationName = NULL; 623 624 RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer); 625 FreeBuffer = NULL; 626 RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer); 627 NameBuffer = NULL; 628 goto VdmRetry; 629 } 630 #endif 631 // Falls into Dos case, so that stub message will be 632 // printed, and bound apps will run w/o OS/2 subsytem 633 634 // Dos .exe or .com 635 636 case STATUS_INVALID_IMAGE_PROTECT: 637 case STATUS_INVALID_IMAGE_NOT_MZ: 638 ForceDos: 639 { 640 ULONG BinarySubType; 641 642 BinarySubType = BINARY_TYPE_DOS_EXE; 643 if (Status == STATUS_INVALID_IMAGE_PROTECT || 644 Status == STATUS_INVALID_IMAGE_NE_FORMAT || 645 (BinarySubType = BaseIsDosApplication(&PathName,Status)) ) 646 { 647 VdmBinaryType = BINARY_TYPE_DOS; 648 649 // create the environment before going to the 650 // server. This was done becuase we want NTVDM 651 // to have the new environment when it gets 652 // created. 653 if (!BaseCreateVDMEnvironment( 654 lpEnvironment, 655 &AnsiStringVDMEnv, 656 &UnicodeStringVDMEnv 657 )) 658 return FALSE; 659 660 if(!BaseCheckVDM(VdmBinaryType | BinarySubType, 661 lpApplicationName, 662 lpCommandLine, 663 lpCurrentDirectory, 664 &AnsiStringVDMEnv, 665 &m, 666 &iTask, 667 dwCreationFlags, 668 &StartupInfo 669 )) 670 return FALSE; 671 672 673 // Check the return value from the server 674 switch (b->VDMState & VDM_STATE_MASK){ 675 case VDM_NOT_PRESENT: 676 // mark this so the server can undo 677 // creation if something goes wrong. 678 // We marked it "partitially created" because 679 // the NTVDM has yet not been fully created. 680 // a call to UpdateVdmEntry to update 681 // process handle will signal the NTVDM 682 // process completed creation 683 VDMCreationState = VDM_PARTIALLY_CREATED; 684 // fail the call if NTVDM process is being 685 // created DETACHED. 686 // note that, we let it go if NTVDM process 687 // is already running. 688 if (dwCreationFlags & DETACHED_PROCESS) { 689 SetLastError(ERROR_ACCESS_DENIED); 690 return FALSE; 691 } 692 if (!BaseGetVdmConfigInfo(lpCommandLine, 693 iTask, 694 VdmBinaryType, 695 &VdmNameString, 696 &VdmReserve 697 )) 698 { 699 BaseSetLastNTError(Status); 700 return FALSE; 701 } 702 703 lpCommandLine = VdmNameString.Buffer; 704 lpApplicationName = NULL; 705 706 break; 707 708 case VDM_PRESENT_NOT_READY: 709 SetLastError (ERROR_NOT_READY); 710 return FALSE; 711 712 case VDM_PRESENT_AND_READY: 713 VDMCreationState = VDM_BEING_REUSED; 714 VdmWaitHandle = b->WaitObjectForParent; 715 break; 716 } 717 RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer); 718 FreeBuffer = NULL; 719 RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer); 720 NameBuffer = NULL; 721 VdmReserve--; // we reserve from addr 1 722 if(VdmWaitHandle) 723 goto VdmExists; 724 else{ 725 bInheritHandles = FALSE; 726 if (lpEnvironment && 727 !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)){ 728 RtlDestroyEnvironment(lpEnvironment); 729 } 730 lpEnvironment = UnicodeStringVDMEnv.Buffer; 731 goto VdmRetry; 732 } 733 } 734 else { 735 736 // 737 // must be a .bat or .cmd file 738 // 739 740 static PWCHAR CmdPrefix = L"cmd /c "; 741 PWCHAR NewCommandLine; 742 ULONG Length; 743 PWCHAR Last4 = &PathName.Buffer[PathName.Length / sizeof( WCHAR )-4]; 744 745 if ( PathName.Length < 8 ) { 746 SetLastError(ERROR_BAD_EXE_FORMAT); 747 return FALSE; 748 } 749 750 if (_wcsnicmp( Last4, L".bat", 4 ) && _wcsnicmp( Last4, L".cmd", 4 )) { 751 SetLastError(ERROR_BAD_EXE_FORMAT); 752 return FALSE; 753 } 754 755 Length = wcslen( CmdPrefix ) 756 + (QuoteCmdLine || QuoteFound ) 757 + wcslen( lpCommandLine ) 758 + (QuoteCmdLine || QuoteFound) 759 + 1; 760 761 NewCommandLine = RtlAllocateHeap( RtlProcessHeap( ), 762 MAKE_TAG( TMP_TAG ), 763 Length * sizeof( WCHAR ) ); 764 765 if (NewCommandLine == NULL) { 766 BaseSetLastNTError(STATUS_NO_MEMORY); 767 return FALSE; 768 } 769 770 wcscpy( NewCommandLine, CmdPrefix ); 771 if (QuoteCmdLine || QuoteFound) { 772 wcscat( NewCommandLine, L"\"" ); 773 } 774 wcscat( NewCommandLine, lpCommandLine ); 775 if (QuoteCmdLine || QuoteFound) { 776 wcscat( NewCommandLine, L"\"" ); 777 } 778 779 RtlInitUnicodeString( &SubSysCommandLine, NewCommandLine ); 780 781 lpCommandLine = SubSysCommandLine.Buffer; 782 783 lpApplicationName = NULL; 784 785 RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer); 786 FreeBuffer = NULL; 787 RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer); 788 NameBuffer = NULL; 789 goto VdmRetry; 790 791 } 792 793 } 794 795 // 16 bit windows exe 796 case STATUS_INVALID_IMAGE_WIN_16: 797 #if defined(BUILD_WOW6432) || defined(_WIN64) 798 if (lpOriginalApplicationName == NULL) { 799 // pass in the part of the command line after the exe name 800 // including whitespace 801 lpCommandLine = ((*TempNull == '\"') ? TempNull + 1 : TempNull); 802 } else { 803 lpCommandLine = lpOriginalCommandLine; 804 } 805 return NtVdm64CreateProcess(lpOriginalApplicationName == NULL, 806 lpApplicationName, // this is now the real file name we've loaded 807 lpCommandLine, 808 lpProcessAttributes, 809 lpThreadAttributes, 810 bInheritHandles, 811 (dwCreationFlags & ~CREATE_UNICODE_ENVIRONMENT), // the environment has already been converted to unicode 812 lpEnvironment, 813 lpCurrentDirectory, 814 lpStartupInfo, 815 lpProcessInformation 816 ); 817 #endif 818 if (dwCreationFlags & CREATE_FORCEDOS) { 819 goto ForceDos; 820 } 821 822 IsWowBinary = TRUE; 823 if (!BaseCreateVDMEnvironment(lpEnvironment, 824 &AnsiStringVDMEnv, 825 &UnicodeStringVDMEnv 826 )) 827 { 828 return FALSE; 829 } 830 831 832 833 RetrySepWow: 834 VdmBinaryType = dwCreationFlags & CREATE_SEPARATE_WOW_VDM 835 ? BINARY_TYPE_SEPWOW : BINARY_TYPE_WIN16; 836 837 if (!BaseCheckVDM(VdmBinaryType, 838 lpApplicationName, 839 lpCommandLine, 840 lpCurrentDirectory, 841 &AnsiStringVDMEnv, 842 &m, 843 &iTask, 844 dwCreationFlags, 845 &StartupInfo 846 )) 847 { 848 // 849 // If we failed with access denied, caller may not 850 // be allowed allowed to access the shared wow's 851 // desktop, so retry as a separate wow 852 // 853 if (VdmBinaryType == BINARY_TYPE_WIN16 && 854 GetLastError() == ERROR_ACCESS_DENIED) 855 { 856 dwCreationFlags |= CREATE_SEPARATE_WOW_VDM; 857 } 858 else { 859 return FALSE; 860 } 861 goto RetrySepWow; 862 } 863 864 865 // Check the return value from the server 866 switch (b->VDMState & VDM_STATE_MASK){ 867 case VDM_NOT_PRESENT: 868 // mark this so the server can undo 869 // creation if something goes wrong. 870 // We marked it "partitially created" because 871 // the NTVDM has yet not been fully created. 872 // a call to UpdateVdmEntry to update 873 // process handle will signal the NTVDM 874 // process completed creation 875 876 VDMCreationState = VDM_PARTIALLY_CREATED; 877 878 if (!BaseGetVdmConfigInfo( 879 lpCommandLine, 880 iTask, 881 VdmBinaryType, 882 &VdmNameString, 883 &VdmReserve 884 )) 885 { 886 BaseSetLastNTError(Status); 887 return FALSE; 888 } 889 890 lpCommandLine = VdmNameString.Buffer; 891 lpApplicationName = NULL; 892 893 894 // 895 // Wow must have a hidden console 896 // Throw away DETACHED_PROCESS flag which isn't 897 // meaningful for Win16 apps. 898 // 899 900 dwCreationFlags |= CREATE_NO_WINDOW; 901 dwCreationFlags &= ~(CREATE_NEW_CONSOLE | DETACHED_PROCESS); 902 903 904 // 905 // We're starting a WOW VDM, turn on feedback unless 906 // the creator passed STARTF_FORCEOFFFEEDBACK. 907 // 908 909 StartupInfo.dwFlags |= STARTF_FORCEONFEEDBACK; 910 911 break; 912 913 case VDM_PRESENT_NOT_READY: 914 SetLastError (ERROR_NOT_READY); 915 return FALSE; 916 917 case VDM_PRESENT_AND_READY: 918 VDMCreationState = VDM_BEING_REUSED; 919 VdmWaitHandle = b->WaitObjectForParent; 920 break; 921 } 922 923 RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer); 924 FreeBuffer = NULL; 925 RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer); 926 NameBuffer = NULL; 927 VdmReserve--; // we reserve from addr 1 928 if(VdmWaitHandle) 929 goto VdmExists; 930 else { 931 bInheritHandles = FALSE; 932 // replace the environment with ours 933 if (lpEnvironment && 934 !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) { 935 RtlDestroyEnvironment(lpEnvironment); 936 } 937 lpEnvironment = UnicodeStringVDMEnv.Buffer; 938 goto VdmRetry; 939 } 940 941 942 default : 943 SetLastError(ERROR_BAD_EXE_FORMAT); 944 return FALSE; 945 } 946 } 947 948 // 949 // Make sure only WOW apps can have the CREATE_SEPARATE_WOW_VDM flag. 950 // 951 952 if (!IsWowBinary && (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)) { 953 dwCreationFlags &= ~CREATE_SEPARATE_WOW_VDM; 954 } 955 956 // 957 // Query the section to determine the stack parameters and 958 // image entrypoint. 959 // 960 961 Status = NtQuerySection( 962 SectionHandle, 963 SectionImageInformation, 964 &ImageInformation, 965 sizeof( ImageInformation ), 966 NULL 967 ); 968 969 if (!NT_SUCCESS( Status )) { 970 BaseSetLastNTError(Status); 971 RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer); 972 FreeBuffer = NULL; 973 return FALSE; 974 } 975 976 if (ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL) { 977 SetLastError(ERROR_BAD_EXE_FORMAT); 978 RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer); 979 FreeBuffer = NULL; 980 return FALSE; 981 } 982 983 ImageFileDebuggerCommand[ 0 ] = UNICODE_NULL; 984 if (!(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) || 985 NtCurrentPeb()->ReadImageFileExecOptions 986 ) { 987 LdrQueryImageFileExecutionOptions( &PathName, 988 L"Debugger", 989 REG_SZ, 990 ImageFileDebuggerCommand, 991 sizeof( ImageFileDebuggerCommand ), 992 NULL 993 ); 994 } 995 996 997 998 if ((ImageInformation.Machine < USER_SHARED_DATA->ImageNumberLow) || 999 (ImageInformation.Machine > USER_SHARED_DATA->ImageNumberHigh)) { 1000 #if defined(WX86) || defined(_AXP64_) 1001 if (ImageInformation.Machine == IMAGE_FILE_MACHINE_I386) 1002 { 1003 Wx86Info = (HANDLE)UIntToPtr(sizeof(WX86TIB)); 1004 } 1005 else 1006 #endif // WX86 1007 #if defined(_AXP64_) 1008 if (ImageInformation.Machine == IMAGE_FILE_MACHINE_ALPHA) { 1009 // Fall through since this is a valid machine type. 1010 } 1011 else 1012 #elif defined(_IA64_) 1013 if (ImageInformation.Machine == IMAGE_FILE_MACHINE_I386) { 1014 // Fall through since this is a valid machine type. 1015 } 1016 else 1017 #endif // _AXP64_ 1018 #if defined(BUILD_WOW6432) 1019 // 32-bit kernel32.dll on NT64 can run 64-bit binaries 1020 #if defined(_ALPHA_) 1021 if (ImageInformation.Machine == IMAGE_FILE_MACHINE_ALPHA) { 1022 // Fall through since this is a valid machine type. 1023 } 1024 else 1025 #elif defined(_X86_) 1026 if (ImageInformation.Machine == IMAGE_FILE_MACHINE_I386) { 1027 // Fall through since this is a valid machine type. 1028 } 1029 else 1030 #endif // ALPHA or IA64 1031 #endif // BUILD_WOW6432 1032 { 1033 ULONG_PTR ErrorParameters[2]; 1034 ULONG ErrorResponse; 1035 1036 ErrorResponse = ResponseOk; 1037 ErrorParameters[0] = (ULONG_PTR)&PathName; 1038 1039 NtRaiseHardError( STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE, 1040 1, 1041 1, 1042 ErrorParameters, 1043 OptionOk, 1044 &ErrorResponse 1045 ); 1046 if ( NtCurrentPeb()->ImageSubsystemMajorVersion <= 3 ) { 1047 SetLastError(ERROR_BAD_EXE_FORMAT); 1048 } 1049 else { 1050 SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH); 1051 } 1052 RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer); 1053 FreeBuffer = NULL; 1054 return FALSE; 1055 } 1056 } 1057 1058 RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer); 1059 FreeBuffer = NULL; 1060 if ( ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI && 1061 ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI ) { 1062 1063 // POSIX exe 1064 1065 NtClose(SectionHandle); 1066 SectionHandle = NULL; 1067 1068 if ( ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_POSIX_CUI ) { 1069 1070 if ( !BuildSubSysCommandLine( L"POSIX /P ", 1071 lpApplicationName, 1072 lpCommandLine, 1073 &SubSysCommandLine 1074 ) ) { 1075 return FALSE; 1076 } 1077 1078 lpCommandLine = SubSysCommandLine.Buffer; 1079 1080 lpApplicationName = NULL; 1081 RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer); 1082 NameBuffer = NULL; 1083 goto VdmRetry; 1084 } 1085 else { 1086 SetLastError(ERROR_CHILD_NOT_COMPLETE); 1087 return FALSE; 1088 } 1089 } 1090 else { 1091 if (!BasepIsImageVersionOk( ImageInformation.SubSystemMajorVersion, 1092 ImageInformation.SubSystemMinorVersion) ) { 1093 SetLastError(ERROR_BAD_EXE_FORMAT); 1094 return FALSE; 1095 } 1096 } 1097 1098 if (ImageFileDebuggerCommand[ 0 ] != UNICODE_NULL) { 1099 USHORT n; 1100 1101 n = (USHORT)wcslen( lpCommandLine ); 1102 if (n == 0) { 1103 lpCommandLine = (LPWSTR)lpApplicationName; 1104 n = (USHORT)wcslen( lpCommandLine ); 1105 } 1106 1107 n += wcslen( ImageFileDebuggerCommand ) + 1 + 2; 1108 n *= sizeof( WCHAR ); 1109 1110 SubSysCommandLine.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), n ); 1111 SubSysCommandLine.Length = 0; 1112 SubSysCommandLine.MaximumLength = n; 1113 RtlAppendUnicodeToString( &SubSysCommandLine, ImageFileDebuggerCommand ); 1114 RtlAppendUnicodeToString( &SubSysCommandLine, L" " ); 1115 RtlAppendUnicodeToString( &SubSysCommandLine, (PWSTR)lpCommandLine ); 1116 #if DBG 1117 DbgPrint( "BASE: Calling debugger with '%wZ'\n", &SubSysCommandLine ); 1118 #endif 1119 lpCommandLine = SubSysCommandLine.Buffer; 1120 lpApplicationName = NULL; 1121 1122 NtClose(SectionHandle); 1123 SectionHandle = NULL; 1124 RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer); 1125 NameBuffer = NULL; 1126 goto VdmRetry; 1127 } 1128 1129 // 1130 // Create the process object 1131 // 1132 1133 pObja = BaseFormatObjectAttributes(&Obja,lpProcessAttributes,NULL); 1134 1135 if (dwCreationFlags & CREATE_BREAKAWAY_FROM_JOB ) { 1136 SectionHandle = (HANDLE)( (UINT_PTR)SectionHandle | 1); 1137 } 1138 1139 Status = NtCreateProcess( 1140 &ProcessHandle, 1141 PROCESS_ALL_ACCESS, 1142 pObja, 1143 NtCurrentProcess(), 1144 (BOOLEAN)bInheritHandles, 1145 SectionHandle, 1146 NULL, 1147 NULL 1148 ); 1149 if ( !NT_SUCCESS(Status) ) { 1150 BaseSetLastNTError(Status); 1151 return FALSE; 1152 } 1153 1154 // 1155 // NtCreateProcess will set to normal OR inherit if parent is IDLE or Below 1156 // only override if a mask is given during the create. 1157 // 1158 1159 if ( PriClass.PriorityClass != PROCESS_PRIORITY_CLASS_UNKNOWN ) { 1160 State = NULL; 1161 if ( PriClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME ) { 1162 State = BasepIsRealtimeAllowed(TRUE); 1163 } 1164 Status = NtSetInformationProcess( 1165 ProcessHandle, 1166 ProcessPriorityClass, 1167 (PVOID)&PriClass, 1168 sizeof(PriClass) 1169 ); 1170 if ( State ) { 1171 BasepReleasePrivilege( State ); 1172 } 1173 1174 if ( !NT_SUCCESS(Status) ) { 1175 BaseSetLastNTError(Status); 1176 return FALSE; 1177 } 1178 } 1179 1180 NtClose(SectionHandle); 1181 SectionHandle = NULL; 1182 1183 if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE) { 1184 UINT NewMode; 1185 NewMode = SEM_FAILCRITICALERRORS; 1186 NtSetInformationProcess( 1187 ProcessHandle, 1188 ProcessDefaultHardErrorMode, 1189 (PVOID) &NewMode, 1190 sizeof(NewMode) 1191 ); 1192 } 1193 1194 // 1195 // If the process is being created for a VDM call the server with 1196 // process handle. 1197 // 1198 1199 if (VdmBinaryType) { 1200 VdmWaitHandle = ProcessHandle; 1201 if (!BaseUpdateVDMEntry(UPDATE_VDM_PROCESS_HANDLE, 1202 &VdmWaitHandle, 1203 iTask, 1204 VdmBinaryType 1205 )) 1206 { 1207 //make sure we don't close the handle twice -- 1208 //(VdmWaitHandle == ProcessHandle) if we don't do this. 1209 VdmWaitHandle = NULL; 1210 return FALSE; 1211 } 1212 1213 // 1214 // For Sep wow the VdmWaitHandle = NULL (there is none!) 1215 // 1216 1217 VDMCreationState |= VDM_FULLY_CREATED; 1218 } 1219 1220 // 1221 // if we're a detached priority, we don't have the focus, so 1222 // don't create with boosted priority. 1223 // 1224 1225 if (dwCreationFlags & DETACHED_PROCESS) { 1226 KPRIORITY SetBasePriority; 1227 1228 SetBasePriority = (KPRIORITY)NORMAL_BASE_PRIORITY; 1229 Status = NtSetInformationProcess(ProcessHandle, 1230 ProcessBasePriority, 1231 (PVOID) &SetBasePriority, 1232 sizeof(SetBasePriority) 1233 ); 1234 ASSERT(NT_SUCCESS(Status)); 1235 } 1236 1237 #if defined(i386) || defined(_IA64_) 1238 // 1239 // Reserve memory in the new process' address space if necessary 1240 // (for vdms). This is required only for x86 system. 1241 // 1242 1243 if ( VdmReserve ) { 1244 BigVdmReserve = VdmReserve; 1245 Status = NtAllocateVirtualMemory( 1246 ProcessHandle, 1247 &BaseAddress, 1248 0L, 1249 &BigVdmReserve, 1250 MEM_RESERVE, 1251 PAGE_EXECUTE_READWRITE 1252 ); 1253 if ( !NT_SUCCESS(Status) ){ 1254 BaseSetLastNTError(Status); 1255 return FALSE; 1256 } 1257 } 1258 #endif 1259 1260 // 1261 // Determine the location of the 1262 // processes PEB. 1263 // 1264 1265 Status = NtQueryInformationProcess( 1266 ProcessHandle, 1267 ProcessBasicInformation, 1268 &ProcessInfo, 1269 sizeof( ProcessInfo ), 1270 NULL 1271 ); 1272 if ( !NT_SUCCESS( Status ) ) { 1273 BaseSetLastNTError(Status); 1274 return FALSE; 1275 } 1276 1277 Peb = ProcessInfo.PebBaseAddress; 1278 1279 // 1280 // Push the parameters into the address space of the new process 1281 // 1282 1283 if ( ARGUMENT_PRESENT(lpCurrentDirectory) ) { 1284 CurdirBuffer = RtlAllocateHeap( RtlProcessHeap(), 1285 MAKE_TAG( TMP_TAG ), 1286 (MAX_PATH + 1) * sizeof( WCHAR ) ); 1287 if ( !CurdirBuffer ) { 1288 BaseSetLastNTError(STATUS_NO_MEMORY); 1289 return FALSE; 1290 } 1291 CurdirLength2 = GetFullPathNameW( 1292 lpCurrentDirectory, 1293 MAX_PATH, 1294 CurdirBuffer, 1295 &CurdirFilePart 1296 ); 1297 if ( CurdirLength2 > MAX_PATH ) { 1298 SetLastError(ERROR_DIRECTORY); 1299 return FALSE; 1300 } 1301 1302 // 1303 // now make sure the directory exists 1304 // 1305 1306 CurdirLength = GetFileAttributesW(CurdirBuffer); 1307 if ( (CurdirLength == 0xffffffff) || 1308 !(CurdirLength & FILE_ATTRIBUTE_DIRECTORY) ) { 1309 SetLastError(ERROR_DIRECTORY); 1310 return FALSE; 1311 } 1312 } 1313 1314 1315 if ( QuoteInsert || QuoteCmdLine) { 1316 QuotedBuffer = RtlAllocateHeap(RtlProcessHeap(),0,wcslen(lpCommandLine)*2+6); 1317 1318 if ( QuotedBuffer ) { 1319 wcscpy(QuotedBuffer,L"\""); 1320 1321 if ( QuoteInsert ) { 1322 TempChar = *TempNull; 1323 *TempNull = UNICODE_NULL; 1324 } 1325 1326 wcscat(QuotedBuffer,lpCommandLine); 1327 wcscat(QuotedBuffer,L"\""); 1328 1329 if ( QuoteInsert ) { 1330 *TempNull = TempChar; 1331 wcscat(QuotedBuffer,TempNull); 1332 } 1333 1334 } 1335 else { 1336 if ( QuoteInsert ) { 1337 QuoteInsert = FALSE; 1338 } 1339 if ( QuoteCmdLine ) { 1340 QuoteCmdLine = FALSE; 1341 } 1342 } 1343 } 1344 1345 1346 if (!BasePushProcessParameters( 1347 ProcessHandle, 1348 Peb, 1349 lpApplicationName, 1350 CurdirBuffer, 1351 QuoteInsert || QuoteCmdLine ? QuotedBuffer : lpCommandLine, 1352 lpEnvironment, 1353 &StartupInfo, 1354 dwCreationFlags | dwNoWindow, 1355 bInheritHandles, 1356 IsWowBinary ? IMAGE_SUBSYSTEM_WINDOWS_GUI : 0 1357 ) ) { 1358 return FALSE; 1359 } 1360 1361 1362 RtlFreeUnicodeString(&VdmNameString); 1363 VdmNameString.Buffer = NULL; 1364 1365 // 1366 // Stuff in the standard handles if needed 1367 // 1368 if (!VdmBinaryType && 1369 !bInheritHandles && 1370 !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) && 1371 !(dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE | CREATE_NO_WINDOW)) && 1372 ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI 1373 ) { 1374 PRTL_USER_PROCESS_PARAMETERS ParametersInNewProcess; 1375 1376 Status = NtReadVirtualMemory( ProcessHandle, 1377 &Peb->ProcessParameters, 1378 &ParametersInNewProcess, 1379 sizeof( ParametersInNewProcess ), 1380 NULL 1381 ); 1382 if (NT_SUCCESS( Status )) { 1383 if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardInput )) { 1384 StuffStdHandle( ProcessHandle, 1385 NtCurrentPeb()->ProcessParameters->StandardInput, 1386 &ParametersInNewProcess->StandardInput 1387 ); 1388 } 1389 if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardOutput )) { 1390 StuffStdHandle( ProcessHandle, 1391 NtCurrentPeb()->ProcessParameters->StandardOutput, 1392 &ParametersInNewProcess->StandardOutput 1393 ); 1394 } 1395 if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardError )) { 1396 StuffStdHandle( ProcessHandle, 1397 NtCurrentPeb()->ProcessParameters->StandardError, 1398 &ParametersInNewProcess->StandardError 1399 ); 1400 } 1401 } 1402 } 1403 1404 // 1405 // Create the thread... 1406 // 1407 1408 // 1409 // Allocate a stack for this thread in the address space of the target 1410 // process. 1411 // 1412 1413 StackStatus = BaseCreateStack( 1414 ProcessHandle, 1415 ImageInformation.CommittedStackSize, 1416 (ImageInformation.MaximumStackSize < 256*1024) ? 256*1024 : ImageInformation.MaximumStackSize, 1417 &InitialTeb 1418 ); 1419 1420 if ( !NT_SUCCESS(StackStatus) ) { 1421 BaseSetLastNTError(StackStatus); 1422 return FALSE; 1423 } 1424 1425 1426 // 1427 // Create an initial context for the new thread. 1428 // 1429 1430 BaseInitializeContext( 1431 &ThreadContext, 1432 Peb, 1433 ImageInformation.TransferAddress, 1434 InitialTeb.StackBase, 1435 BaseContextTypeProcess 1436 ); 1437 1438 1439 // 1440 // Create the actual thread object 1441 // 1442 1443 pObja = BaseFormatObjectAttributes(&Obja,lpThreadAttributes,NULL); 1444 1445 Status = NtCreateThread( 1446 &ThreadHandle, 1447 THREAD_ALL_ACCESS, 1448 pObja, 1449 ProcessHandle, 1450 &ClientId, 1451 &ThreadContext, 1452 &InitialTeb, 1453 TRUE 1454 ); 1455 1456 if (!NT_SUCCESS(Status) ) { 1457 BaseSetLastNTError(Status); 1458 return FALSE; 1459 } 1460 1461 // 1462 // From here on out, do not modify the address space of the 1463 // new process. WOW64's implementation of NtCreateThread() 1464 // reshuffles the new process' address space if the current 1465 // process is 32-bit and the new process is 64-bit. 1466 // 1467 #if DBG 1468 Peb = NULL; 1469 #endif 1470 1471 #if defined(WX86) || defined(_AXP64_) 1472 1473 // 1474 // if this is a Wx86 Process, setup for a Wx86 emulated Thread 1475 // 1476 1477 if (Wx86Info) { 1478 1479 // 1480 // create a WX86Tib and initialize it's Teb->Vdm. 1481 // 1482 Status = BaseCreateWx86Tib(ProcessHandle, 1483 ThreadHandle, 1484 (ULONG)((ULONG_PTR)ImageInformation.TransferAddress), 1485 (ULONG)ImageInformation.CommittedStackSize, 1486 (ULONG)ImageInformation.MaximumStackSize, 1487 TRUE 1488 ); 1489 1490 if (!NT_SUCCESS(Status)) { 1491 BaseSetLastNTError(Status); 1492 return( FALSE ); 1493 } 1494 1495 1496 // 1497 // Mark Process as WX86 1498 // 1499 Status = NtSetInformationProcess (ProcessHandle, 1500 ProcessWx86Information, 1501 &Wx86Info, 1502 sizeof(Wx86Info) 1503 ); 1504 1505 if (!NT_SUCCESS(Status)) { 1506 BaseSetLastNTError(Status); 1507 return( FALSE ); 1508 } 1509 } 1510 #endif 1511 1512 1513 // 1514 // Call the Windows server to let it know about the 1515 // process. 1516 // 1517 1518 a->ProcessHandle = ProcessHandle; 1519 a->ThreadHandle = ThreadHandle; 1520 a->ClientId = ClientId; 1521 a->CreationFlags = dwCreationFlags; 1522 1523 if ( dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS) ) { 1524 Status = DbgUiConnectToDbg(); 1525 if ( !NT_SUCCESS(Status) ) { 1526 NtTerminateProcess(ProcessHandle, Status); 1527 BaseSetLastNTError(Status); 1528 return FALSE; 1529 } 1530 a->DebuggerClientId = NtCurrentTeb()->ClientId; 1531 } 1532 else { 1533 a->DebuggerClientId.UniqueProcess = NULL; 1534 a->DebuggerClientId.UniqueThread = NULL; 1535 } 1536 1537 // 1538 // Set the 2 bit if a gui app is starting. The window manager needs to 1539 // know this so it can synchronize the startup of this app 1540 // (WaitForInputIdle api). This info is passed using the process 1541 // handle tag bits. The 1 bit asks the window manager to turn on 1542 // or turn off the application start cursor (hourglass/pointer). 1543 // 1544 // When starting a WOW process, lie and tell UserSrv NTVDM.EXE is a GUI 1545 // process. We also turn on bit 0x8 so that UserSrv can ignore the 1546 // UserNotifyConsoleApplication call made by the console during startup. 1547 // 1548 1549 if ( ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI || 1550 IsWowBinary ) { 1551 1552 a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle | 2); 1553 1554 // 1555 // If the creating process is a GUI app, turn on the app. start cursor 1556 // by default. This can be overridden by STARTF_FORCEOFFFEEDBACK. 1557 // 1558 1559 NtHeaders = RtlImageNtHeader((PVOID)GetModuleHandle(NULL)); 1560 if ( NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ) 1561 a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle | 1); 1562 1563 } 1564 1565 1566 // 1567 // If feedback is forced on, turn it on. If forced off, turn it off. 1568 // Off overrides on. 1569 // 1570 1571 if (StartupInfo.dwFlags & STARTF_FORCEONFEEDBACK) 1572 a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle | 1); 1573 if (StartupInfo.dwFlags & STARTF_FORCEOFFFEEDBACK) 1574 a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle & ~1); 1575 1576 a->VdmBinaryType = VdmBinaryType; // just tell server the truth 1577 1578 if (VdmBinaryType){ 1579 a->hVDM = iTask ? 0 : NtCurrentPeb()->ProcessParameters->ConsoleHandle; 1580 a->VdmTask = iTask; 1581 } 1582 1583 #if defined(BUILD_WOW6432) 1584 m.ReturnValue = CsrBasepCreateProcess(a); 1585 #else 1586 CsrClientCallServer( (PCSR_API_MSG)&m, 1587 NULL, 1588 CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX, 1589 BasepCreateProcess 1590 ), 1591 sizeof( *a ) 1592 ); 1593 #endif 1594 1595 if (!NT_SUCCESS((NTSTATUS)m.ReturnValue)) { 1596 BaseSetLastNTError((NTSTATUS)m.ReturnValue); 1597 NtTerminateProcess(ProcessHandle, (NTSTATUS)m.ReturnValue); 1598 return FALSE; 1599 } 1600 1601 1602 if (!( dwCreationFlags & CREATE_SUSPENDED) ) { 1603 NtResumeThread(ThreadHandle,&i); 1604 } 1605 1606 VdmExists: 1607 bStatus = TRUE; 1608 if (VDMCreationState) 1609 VDMCreationState |= VDM_CREATION_SUCCESSFUL; 1610 1611 try { 1612 if (VdmWaitHandle) { 1613 1614 // 1615 // tag Shared WOW VDM handles so that wait for input idle has a 1616 // chance to work. Shared WOW VDM "process" handles are actually 1617 // event handles, Separate WOW VDM handles are real process 1618 // handles. Also mark DOS handles with 0x1 so WaitForInputIdle 1619 // has a way to distinguish DOS apps and not block forever. 1620 // 1621 1622 if (VdmBinaryType == BINARY_TYPE_WIN16) { 1623 lpProcessInformation->hProcess = 1624 (HANDLE)((ULONG_PTR)VdmWaitHandle | 0x2); 1625 1626 // 1627 // Shared WOW doesn't always start a process, so 1628 // we don't have a process ID or thread ID to 1629 // return if the VDM already existed. 1630 // 1631 // Separate WOW doesn't hit this codepath 1632 // (no VdmWaitHandle). 1633 // 1634 1635 if (VDMCreationState & VDM_BEING_REUSED) { 1636 ClientId.UniqueProcess = 0; 1637 ClientId.UniqueThread = 0; 1638 } 1639 1640 } 1641 else { 1642 lpProcessInformation->hProcess = 1643 (HANDLE)((ULONG_PTR)VdmWaitHandle | 0x1); 1644 } 1645 1646 1647 // 1648 // Close the ProcessHandle, since we are returning the 1649 // VdmProcessHandle instead. 1650 // 1651 1652 if (ProcessHandle != NULL) 1653 NtClose(ProcessHandle); 1654 } 1655 else{ 1656 lpProcessInformation->hProcess = ProcessHandle; 1657 } 1658 1659 lpProcessInformation->hThread = ThreadHandle; 1660 lpProcessInformation->dwProcessId = HandleToUlong(ClientId.UniqueProcess); 1661 lpProcessInformation->dwThreadId = HandleToUlong(ClientId.UniqueThread); 1662 ProcessHandle = NULL; 1663 ThreadHandle = NULL; 1664 } 1665 except ( EXCEPTION_EXECUTE_HANDLER ) { 1666 NtClose( ProcessHandle ); 1667 NtClose( ThreadHandle ); 1668 ProcessHandle = NULL; 1669 ThreadHandle = NULL; 1670 if (VDMCreationState) 1671 VDMCreationState &= ~VDM_CREATION_SUCCESSFUL; 1672 } 1673 } 1674 finally { 1675 if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) ) { 1676 RtlDestroyEnvironment(lpEnvironment); 1677 lpEnvironment = NULL; 1678 } 1679 RtlFreeHeap(RtlProcessHeap(), 0,QuotedBuffer); 1680 RtlFreeHeap(RtlProcessHeap(), 0,NameBuffer); 1681 RtlFreeHeap(RtlProcessHeap(), 0,CurdirBuffer); 1682 RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer); 1683 if ( FileHandle ) { 1684 NtClose(FileHandle); 1685 } 1686 if ( SectionHandle ) { 1687 NtClose(SectionHandle); 1688 } 1689 if ( ThreadHandle ) { 1690 NtTerminateProcess(ProcessHandle,STATUS_SUCCESS); 1691 NtClose(ThreadHandle); 1692 } 1693 if ( ProcessHandle ) { 1694 NtClose(ProcessHandle); 1695 } 1696 RtlFreeUnicodeString(&VdmNameString); 1697 RtlFreeUnicodeString(&SubSysCommandLine); 1698 if (AnsiStringVDMEnv.Buffer || UnicodeStringVDMEnv.Buffer) 1699 BaseDestroyVDMEnvironment(&AnsiStringVDMEnv, &UnicodeStringVDMEnv); 1700 1701 if (VDMCreationState && !(VDMCreationState & VDM_CREATION_SUCCESSFUL)){ 1702 BaseUpdateVDMEntry ( 1703 UPDATE_VDM_UNDO_CREATION, 1704 (HANDLE *)&iTask, 1705 VDMCreationState, 1706 VdmBinaryType 1707 ); 1708 if(VdmWaitHandle) { 1709 NtClose(VdmWaitHandle); 1710 } 1711 } 1712 } 1713 1714 if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) ) { 1715 RtlDestroyEnvironment(lpEnvironment); 1716 } 1717 return bStatus; 1718 }