程序建立過程詳解 CreateProcess
阿新 • • 發佈:2019-01-08
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