zoukankan      html  css  js  c++  java
  • 进程创建过程详解 CreateProcess

    转载请您注明出处: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)'	' ) {
     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 95winword.exe /embedding -automation
     429                 // require this. Our first iteration will stop at c:word, our next
     430                 // will stop at c:word 95winword.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'
    ", &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 }
    CreateProcessW
      暂且忽略掉之前的一些环境字符串等等相关操作,注意到第一个值得关注的函数:NtOpenFile()打开其目标文件获取到了文件句柄FIileHandle
     
      
            //
            // Open the file for execute access
            //
    
            Status = NtOpenFile(
                        &FileHandle,
                        SYNCHRONIZE | FILE_EXECUTE,
                        &Obja,
                        &IoStatusBlock,
                        FILE_SHARE_READ | FILE_SHARE_DELETE,
                        FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
                        );
    

      

      紧接其后的是NtCreateSectiont通过文件句柄创建一个Section文件映射区,将文件内容映射进来
            //
            // Create a section object backed by the file
            //
    
            Status = NtCreateSection(
                        &SectionHandle,
                        SECTION_ALL_ACCESS,
                        NULL,
                        NULL,
                        PAGE_EXECUTE,
                        SEC_IMAGE,
                        FileHandle
                        );
    

      

      继续向下看关键函数:NtCreateProcess出现啦!

            Status = NtCreateProcess(
                        &ProcessHandle,
                        PROCESS_ALL_ACCESS,
                        pObja,
                        NtCurrentProcess(),
                        (BOOLEAN)bInheritHandles,
                        SectionHandle,
                        NULL,
                        NULL
                        );
    

      在源码中继续延伸,发现调用过程是NtCreateProcess——>NtCreateProcessEx——>PspCreateProcess(Windows2000源码中是没有NtCreateProcessEx函数这个中间过程的,我是在另外一套源码中找到的NtCreateProcessEx函数,但无奈另一套较新的源码中又没有CreateProcessW的定义,故而开始参考的是Windows2000 源码)

      NtCreateProcess函数和NtCreateProcessEx函数:

    NTSTATUS
    NtCreateProcess(
        __out PHANDLE ProcessHandle,
        __in ACCESS_MASK DesiredAccess,
        __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
        __in HANDLE ParentProcess,
        __in BOOLEAN InheritObjectTable,
        __in_opt HANDLE SectionHandle,
        __in_opt HANDLE DebugPort,
        __in_opt HANDLE ExceptionPort
        )
    {
        ULONG Flags = 0;
    
        if ((ULONG_PTR)SectionHandle & 1) {
            Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY;
        }
    
        if ((ULONG_PTR) DebugPort & 1) {
            Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT;
        }
    
        if (InheritObjectTable) {
            Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
        }
    
        return NtCreateProcessEx (ProcessHandle,
                                  DesiredAccess,
                                  ObjectAttributes OPTIONAL,
                                  ParentProcess,
                                  Flags,
                                  SectionHandle,
                                  DebugPort,
                                  ExceptionPort,
                                  0);
    }
    
    NTSTATUS
    NtCreateProcessEx(
        __out PHANDLE ProcessHandle,
        __in ACCESS_MASK DesiredAccess,
        __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
        __in HANDLE ParentProcess,
        __in ULONG Flags,
        __in_opt HANDLE SectionHandle,
        __in_opt HANDLE DebugPort,
        __in_opt HANDLE ExceptionPort,
        __in ULONG JobMemberLevel
        )
    
    
    
    {
        NTSTATUS Status;
    
        PAGED_CODE();
    
        if (KeGetPreviousMode() != KernelMode) {
    
            //
            // Probe all arguments
            //
    
            try {
                ProbeForWriteHandle (ProcessHandle);
            } except (EXCEPTION_EXECUTE_HANDLER) {
                return GetExceptionCode ();
            }
        }
    
        if (ARGUMENT_PRESENT (ParentProcess)) {
            Status = PspCreateProcess (ProcessHandle,
                                       DesiredAccess,
                                       ObjectAttributes,
                                       ParentProcess,
                                       Flags,
                                       SectionHandle,
                                       DebugPort,
                                       ExceptionPort,
                                       JobMemberLevel);
        } else {
            Status = STATUS_INVALID_PARAMETER;
        }
    
        return Status;
    }
    

      

      看以看到NtCreateProcess函数简单地对处理一下参数,然后把创建进程的任务交给NtCreateProcessEx函数。

      NtCreateProcessEx函数的流程。它也只是简单地检查ProcessHandle参数代表的句柄是否可写,ParentProcess是否不为空。真正的创建工作交给PspCreateProcess函数。

      

    NTSTATUS
    PspCreateProcess(
        OUT PHANDLE ProcessHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
        IN HANDLE ParentProcess OPTIONAL,
        IN ULONG Flags,
        IN HANDLE SectionHandle OPTIONAL,
        IN HANDLE DebugPort OPTIONAL,
        IN HANDLE ExceptionPort OPTIONAL,
        IN ULONG JobMemberLevel
        )
    /*++
    
    Routine Description:
    
        This routine creates and initializes a process object.  It implements the
        foundation for NtCreateProcess and for system initialization process
        creation.
    
    --*/
    
    {
    
        NTSTATUS Status;
        PEPROCESS Process;
        PEPROCESS CurrentProcess;
        PEPROCESS Parent;
        PETHREAD CurrentThread;
        KAFFINITY Affinity;
        KPRIORITY BasePriority;
        PVOID SectionObject;
        PVOID ExceptionPortObject;
        PVOID DebugPortObject;
        ULONG WorkingSetMinimum, WorkingSetMaximum;
        HANDLE LocalProcessHandle;
        KPROCESSOR_MODE PreviousMode;
        INITIAL_PEB InitialPeb;
        BOOLEAN CreatePeb;
        ULONG_PTR DirectoryTableBase[2];
        BOOLEAN AccessCheck;
        BOOLEAN MemoryAllocated;
        PSECURITY_DESCRIPTOR SecurityDescriptor;
        SECURITY_SUBJECT_CONTEXT SubjectContext;
        NTSTATUS accesst;
        NTSTATUS SavedStatus;
        ULONG ImageFileNameSize;
        HANDLE_TABLE_ENTRY CidEntry;
        PEJOB Job;
        PPEB Peb;
        AUX_ACCESS_DATA AuxData;
        PACCESS_STATE AccessState;
        ACCESS_STATE LocalAccessState;
        BOOLEAN UseLargePages;
        SCHAR QuantumReset;
    #if defined(_WIN64)
        INITIAL_PEB32 InitialPeb32;
    #endif
    
        PAGED_CODE();
    
        CurrentThread = PsGetCurrentThread ();
        PreviousMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
        CurrentProcess = PsGetCurrentProcessByThread (CurrentThread);
    
        CreatePeb = FALSE;
        UseLargePages = FALSE;
        DirectoryTableBase[0] = 0;
        DirectoryTableBase[1] = 0;
        Peb = NULL;
        
        //
        // Reject bogus create parameters for future expansion
        //
        if (Flags&~PROCESS_CREATE_FLAGS_LEGAL_MASK) {
            return STATUS_INVALID_PARAMETER;
        }
    
        //
        // Parent
        //
    
        if (ARGUMENT_PRESENT (ParentProcess)) {
            Status = ObReferenceObjectByHandle (ParentProcess,
                                                PROCESS_CREATE_PROCESS,
                                                PsProcessType,
                                                PreviousMode,
                                                &Parent,
                                                NULL);
            if (!NT_SUCCESS (Status)) {
                return Status;
            }
    
            if (JobMemberLevel != 0 && Parent->Job == NULL) {
                ObDereferenceObject (Parent);
                return STATUS_INVALID_PARAMETER;
            }
    
            Affinity = Parent->Pcb.Affinity;
            WorkingSetMinimum = PsMinimumWorkingSet;
            WorkingSetMaximum = PsMaximumWorkingSet;
    
    
        } else {
    
            Parent = NULL;
            Affinity = KeActiveProcessors;
            WorkingSetMinimum = PsMinimumWorkingSet;
            WorkingSetMaximum = PsMaximumWorkingSet;
        }
    
        //
        // Create the process object
        //
        Status = ObCreateObject (PreviousMode,
                                 PsProcessType,
                                 ObjectAttributes,
                                 PreviousMode,
                                 NULL,
                                 sizeof (EPROCESS),
                                 0,
                                 0,
                                 &Process);
    
        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref_parent;
        }
    
        //
        // The process object is created set to NULL. Errors
        // That occur after this step cause the process delete
        // routine to be entered.
        //
        // Teardown actions that occur in the process delete routine
        // do not need to be performed inline.
        //
    
        RtlZeroMemory (Process, sizeof(EPROCESS));
        ExInitializeRundownProtection (&Process->RundownProtect);
        PspInitializeProcessLock (Process);
        InitializeListHead (&Process->ThreadListHead);
    
    #if defined(_WIN64)
    
        if (Flags & PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE) {
            PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_OVERRIDE_ADDRESS_SPACE);
        }
    
    #endif
    
        PspInheritQuota (Process, Parent);
        ObInheritDeviceMap (Process, Parent);
        if (Parent != NULL) {
            Process->DefaultHardErrorProcessing = Parent->DefaultHardErrorProcessing;
            Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId;
    
        } else {
            Process->DefaultHardErrorProcessing = PROCESS_HARDERROR_DEFAULT;
            Process->InheritedFromUniqueProcessId = NULL;
        }
    
        //
        // Section
        //
    
        if (ARGUMENT_PRESENT (SectionHandle)) {
            Status = ObReferenceObjectByHandle (SectionHandle,
                                                SECTION_MAP_EXECUTE,
                                                MmSectionObjectType,
                                                PreviousMode,
                                                &SectionObject,
                                                NULL);
            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }
    
        } else {
            SectionObject = NULL;
            if (Parent != PsInitialSystemProcess) {
    
                //
                // Fetch the section pointer from the parent process
                // as we will be cloning. Since the section pointer
                // is removed at last thread exit we need to protect against
                // process exit here to be safe.
                //
    
                if (ExAcquireRundownProtection (&Parent->RundownProtect)) {
                    SectionObject = Parent->SectionObject;
                    if (SectionObject != NULL) {
                        ObReferenceObject (SectionObject);
                    }
    
                    ExReleaseRundownProtection (&Parent->RundownProtect);
                }
    
                if (SectionObject == NULL) {
                    Status = STATUS_PROCESS_IS_TERMINATING;
                    goto exit_and_deref;
                }
            }
        }
    
        Process->SectionObject = SectionObject;
    
        //
        // DebugPort
        //
    
        if (ARGUMENT_PRESENT (DebugPort)) {
            Status = ObReferenceObjectByHandle (DebugPort,
                                                DEBUG_PROCESS_ASSIGN,
                                                DbgkDebugObjectType,
                                                PreviousMode,
                                                &DebugPortObject,
                                                NULL);
    
            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }
    
            Process->DebugPort = DebugPortObject;
            if (Flags&PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT) {
                PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_NO_DEBUG_INHERIT);
            }
    
        } else {
            if (Parent != NULL) {
                DbgkCopyProcessDebugPort (Process, Parent);
            }
        }
    
        //
        // ExceptionPort
        //
    
        if (ARGUMENT_PRESENT (ExceptionPort)) {
            Status = ObReferenceObjectByHandle (ExceptionPort,
                                                0,
                                                LpcPortObjectType,
                                                PreviousMode,
                                                &ExceptionPortObject,
                                                NULL);
    
            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }
    
            Process->ExceptionPort = ExceptionPortObject;
        }
    
        Process->ExitStatus = STATUS_PENDING;
    
        //
        // Clone parent's object table.
        // If no parent (booting) then use the current object table created in
        // ObInitSystem.
        //
    
        if (Parent != NULL) {
    
            //
            // Calculate address space
            //
            //      If Parent == PspInitialSystem
            //
    
            if (!MmCreateProcessAddressSpace (WorkingSetMinimum,
                                              Process,
                                              &DirectoryTableBase[0])) {
    
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto exit_and_deref;
            }
    
        } else {
            Process->ObjectTable = CurrentProcess->ObjectTable;
    
            //
            // Initialize the Working Set Mutex and address creation mutex
            // for this "hand built" process.
            // Normally, the call to MmInitializeAddressSpace initializes the
            // working set mutex, however, in this case, we have already initialized
            // the address space and we are now creating a second process using
            // the address space of the idle thread.
            //
    
            Status = MmInitializeHandBuiltProcess (Process, &DirectoryTableBase[0]);
            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }
        }
    
        PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_HAS_ADDRESS_SPACE);
        Process->Vm.MaximumWorkingSetSize = WorkingSetMaximum;
        KeInitializeProcess (&Process->Pcb,
                             NORMAL_BASE_PRIORITY,
                             Affinity,
                             &DirectoryTableBase[0],
                             (BOOLEAN)(Process->DefaultHardErrorProcessing & PROCESS_HARDERROR_ALIGNMENT_BIT));
    
        //
        //  Initialize the security fields of the process
        //  The parent may be null exactly once (during system init).
        //  Thereafter, a parent is always required so that we have a
        //  security context to duplicate for the new process.
        //
    
        Status = PspInitializeProcessSecurity (Parent, Process);
        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref;
        }
    
        Process->PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
        if (Parent != NULL) {
            if (Parent->PriorityClass == PROCESS_PRIORITY_CLASS_IDLE ||
                Parent->PriorityClass == PROCESS_PRIORITY_CLASS_BELOW_NORMAL) {
                Process->PriorityClass = Parent->PriorityClass;
            }
    
            //
            // if address space creation worked, then when going through
            // delete, we will attach. Of course, attaching means that the kprocess
            // must be initialized, so we delay the object stuff till here.
            //
    
            Status = ObInitProcess ((Flags&PROCESS_CREATE_FLAGS_INHERIT_HANDLES) ? Parent : NULL,
                                    Process);
    
            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }
    
        } else {
            Status = MmInitializeHandBuiltProcess2 (Process);
            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }
        }
    
        Status = STATUS_SUCCESS;
        SavedStatus = STATUS_SUCCESS;
    
        //
        // Initialize the process address space
        // The address space has four possibilities
        //
        //      1 - Boot Process. Address space is initialized during
        //          MmInit. Parent is not specified.
        //
        //      2 - System Process. Address space is a virgin address
        //          space that only maps system space. Process is same
        //          as PspInitialSystemProcess.
        //
        //      3 - User Process (Cloned Address Space). Address space
        //          is cloned from the specified process.
        //
        //      4 - User Process (New Image Address Space). Address space
        //          is initialized so that it maps the specified section.
        //
    
        if (SectionHandle != NULL) {
    
            //
            // User Process (New Image Address Space). Don't specify Process to
            // clone, just SectionObject.
            //
            // Passing in the 4th parameter as below lets the EPROCESS struct contain its image file name, provided that
            // appropriate audit settings are enabled.  Memory is allocated inside of MmInitializeProcessAddressSpace
            // and pointed to by ImageFileName, so that must be freed in the process deletion routine (PspDeleteProcess())
            //
    
            Status = MmInitializeProcessAddressSpace (Process,
                                                      NULL,
                                                      SectionObject,
                                                      &Flags,
                                                      &(Process->SeAuditProcessCreationInfo.ImageFileName));
    
            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }
    
            //
            // In order to support relocating executables, the proper status
            // (STATUS_IMAGE_NOT_AT_BASE) must be returned, so save it here.
            //
    
            SavedStatus = Status;
            CreatePeb = TRUE;
            UseLargePages = ((Flags & PROCESS_CREATE_FLAGS_LARGE_PAGES) != 0 ? TRUE : FALSE);
    
        } else if (Parent != NULL) {
            if (Parent != PsInitialSystemProcess) {
                Process->SectionBaseAddress = Parent->SectionBaseAddress;
    
                //
                // User Process ( Cloned Address Space ).  Don't specify section to
                // map, just Process to clone.
                //
    
                Status = MmInitializeProcessAddressSpace (Process,
                                                          Parent,
                                                          NULL,
                                                          &Flags,
                                                          NULL);
    
                if (!NT_SUCCESS (Status)) {
                    goto exit_and_deref;
                }
    
                CreatePeb = TRUE;
                UseLargePages = ((Flags & PROCESS_CREATE_FLAGS_LARGE_PAGES) != 0 ? TRUE : FALSE);
                
                //
                // A cloned process isn't started from an image file, so we give it the name
                // of the process of which it is a clone, provided the original has a name.
                //
    
                if (Parent->SeAuditProcessCreationInfo.ImageFileName != NULL) {
                    ImageFileNameSize = sizeof(OBJECT_NAME_INFORMATION) +
                                        Parent->SeAuditProcessCreationInfo.ImageFileName->Name.MaximumLength;
    
                    Process->SeAuditProcessCreationInfo.ImageFileName =
                        ExAllocatePoolWithTag (PagedPool,
                                               ImageFileNameSize,
                                               'aPeS');
    
                    if (Process->SeAuditProcessCreationInfo.ImageFileName != NULL) {
                        RtlCopyMemory (Process->SeAuditProcessCreationInfo.ImageFileName,
                                       Parent->SeAuditProcessCreationInfo.ImageFileName,
                                       ImageFileNameSize);
    
                        //
                        // The UNICODE_STRING in the process is self contained, so calculate the
                        // offset for the buffer.
                        //
    
                        Process->SeAuditProcessCreationInfo.ImageFileName->Name.Buffer =
                            (PUSHORT)(((PUCHAR) Process->SeAuditProcessCreationInfo.ImageFileName) +
                            sizeof(UNICODE_STRING));
    
                    } else {
                        Status = STATUS_INSUFFICIENT_RESOURCES;
                        goto exit_and_deref;
                    }
                }
    
            } else {
    
                //
                // System Process.  Don't specify Process to clone or section to map
                //
    
                Flags &= ~PROCESS_CREATE_FLAGS_ALL_LARGE_PAGE_FLAGS;
                Status = MmInitializeProcessAddressSpace (Process,
                                                          NULL,
                                                          NULL,
                                                          &Flags,
                                                          NULL);
    
                if (!NT_SUCCESS (Status)) {
                    goto exit_and_deref;
                }
    
                //
                // In case the image file name of this system process is ever queried, we give
                // a zero length UNICODE_STRING.
                //
    
                Process->SeAuditProcessCreationInfo.ImageFileName =
                    ExAllocatePoolWithTag (PagedPool,
                                           sizeof(OBJECT_NAME_INFORMATION),
                                           'aPeS');
    
                if (Process->SeAuditProcessCreationInfo.ImageFileName != NULL) {
                    RtlZeroMemory (Process->SeAuditProcessCreationInfo.ImageFileName,
                                   sizeof(OBJECT_NAME_INFORMATION));
                } else {
                    Status = STATUS_INSUFFICIENT_RESOURCES;
                    goto exit_and_deref;
                }
            }
        }
    
        //
        // Create the process ID
        //
    
        CidEntry.Object = Process;
        CidEntry.GrantedAccess = 0;
        Process->UniqueProcessId = ExCreateHandle (PspCidTable, &CidEntry);
        if (Process->UniqueProcessId == NULL) {
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto exit_and_deref;
        }
    
        ExSetHandleTableOwner (Process->ObjectTable, Process->UniqueProcessId);
    
        //
        // Audit the process creation.
        //
    
        if (SeDetailedAuditingWithToken (NULL)) {
            SeAuditProcessCreation (Process);
        }
    
        //
        // See if the parent has a job. If so reference the job
        // and add the process in.
        //
    
        if (Parent) {
            Job = Parent->Job;
            if (Job != NULL && !(Job->LimitFlags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)) {
                if (Flags&PROCESS_CREATE_FLAGS_BREAKAWAY) {
                    if (!(Job->LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK)) {
                        Status = STATUS_ACCESS_DENIED;
    
                    } else {
                        Status = STATUS_SUCCESS;
                    }
    
                } else {
                    Status = PspGetJobFromSet (Job, JobMemberLevel, &Process->Job);
                    if (NT_SUCCESS (Status)) {
                        PACCESS_TOKEN Token, NewToken;
                        Job = Process->Job;
                        Status = PspAddProcessToJob (Job, Process);
    
                        //
                        // Duplicate a new process token if one is specified for the job
                        //
    
                        Token = Job->Token;
                        if (Token != NULL) {
                            Status = SeSubProcessToken (Token,
                                                        &NewToken,
                                                        FALSE,
                                                        Job->SessionId);
    
                            if (!NT_SUCCESS (Status)) {
                                goto exit_and_deref;
                            }
    
                            SeAssignPrimaryToken (Process, NewToken);    
                            ObDereferenceObject (NewToken);                    
                        }
                    }
                }
    
                if (!NT_SUCCESS (Status)) {
                    goto exit_and_deref;
                }
            }
        }
    
        if (Parent && CreatePeb) {
    
            //
            // For processes created w/ a section,
            // a new "virgin" PEB is created. Otherwise,
            // for forked processes, uses inherited PEB
            // with an updated mutant.
            //
    
            RtlZeroMemory (&InitialPeb, FIELD_OFFSET(INITIAL_PEB, Mutant));
    
            InitialPeb.Mutant = (HANDLE)(-1);
            InitialPeb.ImageUsesLargePages = (BOOLEAN) UseLargePages;
                
            if (SectionHandle != NULL) {
                Status = MmCreatePeb (Process, &InitialPeb, &Process->Peb);
                if (!NT_SUCCESS (Status)) {
                    Process->Peb = NULL;
                    goto exit_and_deref;
                }
    
                Peb =  Process->Peb;
    
            } else {
                SIZE_T BytesCopied;
    
                InitialPeb.InheritedAddressSpace = TRUE;
                Process->Peb = Parent->Peb;
                MmCopyVirtualMemory (CurrentProcess,
                                     &InitialPeb,
                                     Process,
                                     Process->Peb,
                                     sizeof (INITIAL_PEB),
                                     KernelMode,
                                     &BytesCopied);
    
    #if defined(_WIN64)
                if (Process->Wow64Process != NULL) {
                    
                    RtlZeroMemory (&InitialPeb32, FIELD_OFFSET(INITIAL_PEB32, Mutant));
                    InitialPeb32.Mutant = -1;
                    InitialPeb32.InheritedAddressSpace = TRUE;
                    InitialPeb32.ImageUsesLargePages = (BOOLEAN) UseLargePages;
    
                    MmCopyVirtualMemory (CurrentProcess,
                                         &InitialPeb32,
                                         Process,
                                         Process->Wow64Process->Wow64,
                                         sizeof (INITIAL_PEB32),
                                         KernelMode,
                                         &BytesCopied);
                }
    #endif
    
            }
        }
    
        Peb = Process->Peb;
    
        //
        // Add the process to the global list of processes.
        //
    
        PspLockProcessList (CurrentThread);
        InsertTailList (&PsActiveProcessHead, &Process->ActiveProcessLinks);
        PspUnlockProcessList (CurrentThread);
        AccessState = NULL;
        if (!PsUseImpersonationToken) {
            AccessState = &LocalAccessState;
            Status = SeCreateAccessStateEx (NULL,
                                            (Parent == NULL || Parent != PsInitialSystemProcess)?
                                               PsGetCurrentProcessByThread (CurrentThread) :
                                               PsInitialSystemProcess,
                                            AccessState,
                                            &AuxData,
                                            DesiredAccess,
                                            &PsProcessType->TypeInfo.GenericMapping);
            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }
        }
    
        //
        // Insert the object. Once we do this is reachable from the outside world via
        // open by name. Open by ID is still disabled. Since its reachable
        // somebody might create a thread in the process and cause
        // rundown.
        //
    
        Status = ObInsertObject (Process,
                                 AccessState,
                                 DesiredAccess,
                                 1,     // bias the refcnt by one for future process manipulations
                                 NULL,
                                 &LocalProcessHandle);
    
        if (AccessState != NULL) {
            SeDeleteAccessState (AccessState);
        }
    
        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref_parent;
        }
    
        //
        // Compute the base priority and quantum reset values for the process and
        // set the memory priority.
        //
    
        ASSERT(IsListEmpty(&Process->ThreadListHead) == TRUE);
    
        BasePriority = PspComputeQuantumAndPriority(Process,
                                                    PsProcessPriorityBackground,
                                                    &QuantumReset);
    
        Process->Pcb.BasePriority = (SCHAR)BasePriority;
        Process->Pcb.QuantumReset = QuantumReset;
    
        //
        // As soon as a handle to the process is accessible, allow the process to
        // be deleted.
        //
    
        Process->GrantedAccess = PROCESS_TERMINATE;
        if (Parent && Parent != PsInitialSystemProcess) {
            Status = ObGetObjectSecurity (Process,
                                          &SecurityDescriptor,
                                          &MemoryAllocated);
    
            if (!NT_SUCCESS (Status)) {
                ObCloseHandle (LocalProcessHandle, PreviousMode);
                goto exit_and_deref;
            }
    
            //
            // Compute the subject security context
            //
    
            SubjectContext.ProcessAuditId = Process;
            SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
            SubjectContext.ClientToken = NULL;
            AccessCheck = SeAccessCheck (SecurityDescriptor,
                                         &SubjectContext,
                                         FALSE,
                                         MAXIMUM_ALLOWED,
                                         0,
                                         NULL,
                                         &PsProcessType->TypeInfo.GenericMapping,
                                         PreviousMode,
                                         &Process->GrantedAccess,
                                         &accesst);
    
            PsDereferencePrimaryTokenEx (Process, SubjectContext.PrimaryToken);
            ObReleaseObjectSecurity (SecurityDescriptor,
                                     MemoryAllocated);
    
            if (!AccessCheck) {
                Process->GrantedAccess = 0;
            }
    
            //
            // It does not make any sense to create a process that can not
            // do anything to itself.
            // Note: Changes to this set of bits should be reflected in psquery.c
            // code, in PspSetPrimaryToken.
            //
    
            Process->GrantedAccess |= (PROCESS_VM_OPERATION |
                                       PROCESS_VM_READ |
                                       PROCESS_VM_WRITE |
                                       PROCESS_QUERY_INFORMATION |
                                       PROCESS_TERMINATE |
                                       PROCESS_CREATE_THREAD |
                                       PROCESS_DUP_HANDLE |
                                       PROCESS_CREATE_PROCESS |
                                       PROCESS_SET_INFORMATION |
                                       STANDARD_RIGHTS_ALL |
                                       PROCESS_SET_QUOTA);
    
        } else {
            Process->GrantedAccess = PROCESS_ALL_ACCESS;
        }
    
        KeQuerySystemTime (&Process->CreateTime);
        try {
            if (Peb != NULL && CurrentThread->Tcb.Teb != NULL) {
                ((PTEB)(CurrentThread->Tcb.Teb))->NtTib.ArbitraryUserPointer = Peb;
            }
    
            *ProcessHandle = LocalProcessHandle;
    
        } except (EXCEPTION_EXECUTE_HANDLER) {
            NOTHING;
        }
    
        if (SavedStatus != STATUS_SUCCESS) {
            Status = SavedStatus;
        }
    
    exit_and_deref:
        ObDereferenceObject (Process);
    
    exit_and_deref_parent:
        if (Parent != NULL) {
            ObDereferenceObject (Parent);
        }
    
        return Status;
    }
    

      

     

      来具体分析一下PspCreateProcess所做的关键工作:

      (1)调用ObCreateObject 创建一个类型为PsProcessType的内核对象,置于局部变量Process中,对象体为EPROCESS,即创建EPROCESS

        Status = ObCreateObject (PreviousMode,
                                 PsProcessType,
                                 ObjectAttributes,
                                 PreviousMode,
                                 NULL,
                                 sizeof (EPROCESS),
                                 0,
                                 0,
                                 &Process);
    

     

      (2)MmCreateProcessAddressSpace创建新的地址空间

        if (Parent != NULL) {
            //创建新的地址空间
            if (!MmCreateProcessAddressSpace (WorkingSetMinimum,
                                              Process,
                                              &DirectoryTableBase[0])) {
    
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto exit_and_deref;
            }
    

      

      (3)MmInitializeProcessAddressSpace 初始化新进程的地址空间

    if (Parent != PsInitialSystemProcess) {
           //根据父进程来初始化进程地址空间,并把父进程的映像名称拷贝到新进程对象的数据结构中。 Process->SectionBaseAddress = Parent->SectionBaseAddress; // // User Process ( Cloned Address Space ). Don't specify section to // map, just Process to clone. // Status = MmInitializeProcessAddressSpace (Process, Parent, NULL, &Flags, NULL); if (!NT_SUCCESS (Status)) { goto exit_and_deref; } CreatePeb = TRUE; UseLargePages = ((Flags & PROCESS_CREATE_FLAGS_LARGE_PAGES) != 0 ? TRUE : FALSE); // // A cloned process isn't started from an image file, so we give it the name // of the process of which it is a clone, provided the original has a name. // if (Parent->SeAuditProcessCreationInfo.ImageFileName != NULL) { ImageFileNameSize = sizeof(OBJECT_NAME_INFORMATION) + Parent->SeAuditProcessCreationInfo.ImageFileName->Name.MaximumLength; Process->SeAuditProcessCreationInfo.ImageFileName = ExAllocatePoolWithTag (PagedPool, ImageFileNameSize, 'aPeS'); if (Process->SeAuditProcessCreationInfo.ImageFileName != NULL) { RtlCopyMemory (Process->SeAuditProcessCreationInfo.ImageFileName, Parent->SeAuditProcessCreationInfo.ImageFileName, ImageFileNameSize); // // The UNICODE_STRING in the process is self contained, so calculate the // offset for the buffer. // Process->SeAuditProcessCreationInfo.ImageFileName->Name.Buffer = (PUSHORT)(((PUCHAR) Process->SeAuditProcessCreationInfo.ImageFileName) + sizeof(UNICODE_STRING)); } else { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit_and_deref; } } } else { // // System Process. Don't specify Process to clone or section to map // Flags &= ~PROCESS_CREATE_FLAGS_ALL_LARGE_PAGE_FLAGS; Status = MmInitializeProcessAddressSpace (Process, NULL, NULL, &Flags, NULL); if (!NT_SUCCESS (Status)) { goto exit_and_deref; } // // In case the image file name of this system process is ever queried, we give // a zero length UNICODE_STRING. // Process->SeAuditProcessCreationInfo.ImageFileName = ExAllocatePoolWithTag (PagedPool, sizeof(OBJECT_NAME_INFORMATION), 'aPeS'); if (Process->SeAuditProcessCreationInfo.ImageFileName != NULL) { RtlZeroMemory (Process->SeAuditProcessCreationInfo.ImageFileName, sizeof(OBJECT_NAME_INFORMATION)); } else { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit_and_deref; } } }

      (4)ExCreateHandle函数在CID句柄表中创建一个进程ID项。

      

        CidEntry.Object = Process;
        CidEntry.GrantedAccess = 0;
        Process->UniqueProcessId = ExCreateHandle (PspCidTable, &CidEntry);
        if (Process->UniqueProcessId == NULL) {
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto exit_and_deref;
        }
    
        ExSetHandleTableOwner (Process->ObjectTable, Process->UniqueProcessId);
    

      (5)MmCreatePeb 创建一个PEB,如果进程通过映像内存区来创建,创建一个PEB,如果是进程拷贝,则使用继承的PEB。

      

     RtlZeroMemory (&InitialPeb, FIELD_OFFSET(INITIAL_PEB, Mutant));
    
            InitialPeb.Mutant = (HANDLE)(-1);
            InitialPeb.ImageUsesLargePages = (BOOLEAN) UseLargePages;
                
            if (SectionHandle != NULL) {
                Status = MmCreatePeb (Process, &InitialPeb, &Process->Peb);
                if (!NT_SUCCESS (Status)) {
                    Process->Peb = NULL;
                    goto exit_and_deref;
                }
    
                Peb =  Process->Peb;
    
            } else {
                SIZE_T BytesCopied;
    
                InitialPeb.InheritedAddressSpace = TRUE;
                Process->Peb = Parent->Peb;
                MmCopyVirtualMemory (CurrentProcess,
                                     &InitialPeb,
                                     Process,
                                     Process->Peb,
                                     sizeof (INITIAL_PEB),
                                     KernelMode,
                                     &BytesCopied);
    

      (6)InsertTailList 函数把新进程加入全局的LIST_ENTRY进程链表中(位置:PsActiveProcessHead)

        PspLockProcessList (CurrentThread);
        InsertTailList (&PsActiveProcessHead, &Process->ActiveProcessLinks);
        PspUnlockProcessList (CurrentThread);
        AccessState = NULL;
        if (!PsUseImpersonationToken) {
            AccessState = &LocalAccessState;
            Status = SeCreateAccessStateEx (NULL,
                                            (Parent == NULL || Parent != PsInitialSystemProcess)?
                                               PsGetCurrentProcessByThread (CurrentThread) :
                                               PsInitialSystemProcess,
                                            AccessState,
                                            &AuxData,
                                            DesiredAccess,
                                            &PsProcessType->TypeInfo.GenericMapping);
            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }
        }
    

      (7)ObInsertObject 将新进程对象记录到当前进程的句柄表中。

    Status = ObInsertObject (Process,
                                 AccessState,
                                 DesiredAccess,
                                 1,     // bias the refcnt by one for future process manipulations
                                 NULL,
                                 &LocalProcessHandle);
    

      

      

      NtCreateProcess结束后,就创建好了进程,然而进程只不过是一个容器,接下来的代码就可以看到NtCreateThread函数的线程创建了:

    NTSTATUS
    NtCreateThread(
        __out PHANDLE ThreadHandle,
        __in ACCESS_MASK DesiredAccess,
        __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
        __in HANDLE ProcessHandle,
        __out PCLIENT_ID ClientId,
        __in PCONTEXT ThreadContext,
        __in PINITIAL_TEB InitialTeb,
        __in BOOLEAN CreateSuspended
        )
    /*++
    
    Routine Description:
    
        This system service API creates and initializes a thread object.
    
    --*/
    
    {
        NTSTATUS Status;
        INITIAL_TEB CapturedInitialTeb;
    
        PAGED_CODE();
    
    
        //
        // Probe all arguments
        //
    
        try {
            if (KeGetPreviousMode () != KernelMode) {
                ProbeForWriteHandle (ThreadHandle);
    
                if (ARGUMENT_PRESENT (ClientId)) {
                    ProbeForWriteSmallStructure (ClientId, sizeof (CLIENT_ID), sizeof (ULONG));
                }
    
                if (ARGUMENT_PRESENT (ThreadContext) ) {
                    ProbeForReadSmallStructure (ThreadContext, sizeof (CONTEXT), CONTEXT_ALIGN);
                } else {
                    return STATUS_INVALID_PARAMETER;
                }
                ProbeForReadSmallStructure (InitialTeb, sizeof (InitialTeb->OldInitialTeb), sizeof (ULONG));
            }
    
            CapturedInitialTeb.OldInitialTeb = InitialTeb->OldInitialTeb;
            if (CapturedInitialTeb.OldInitialTeb.OldStackBase == NULL &&
                CapturedInitialTeb.OldInitialTeb.OldStackLimit == NULL) {
                //
                // Since the structure size here is less than 64k we don't need to reprobe
                //
                CapturedInitialTeb = *InitialTeb;
            }
        } except (ExSystemExceptionFilter ()) {
            return GetExceptionCode ();
        }
    
        Status = PspCreateThread (ThreadHandle,
                                  DesiredAccess,
                                  ObjectAttributes,
                                  ProcessHandle,
                                  NULL,
                                  ClientId,
                                  ThreadContext,
                                  &CapturedInitialTeb,
                                  CreateSuspended,
                                  NULL,
                                  NULL);
    
        return Status;
    }
    

      

      看到这里NtCreateThread函数还是调用了PspCreateThread函数来完成实际的工作。NtCreateThread——>PspCreateThread

    
    NTSTATUS
    PspCreateThread(
        OUT PHANDLE ThreadHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
        IN HANDLE ProcessHandle,
        IN PEPROCESS ProcessPointer,
        OUT PCLIENT_ID ClientId OPTIONAL,
        IN PCONTEXT ThreadContext OPTIONAL,
        IN PINITIAL_TEB InitialTeb OPTIONAL,
        IN BOOLEAN CreateSuspended,
        IN PKSTART_ROUTINE StartRoutine OPTIONAL,
        IN PVOID StartContext
        )
    /*++
    Routine Description:
        This routine creates and initializes a thread object. It implements the
        foundation for NtCreateThread and for PsCreateSystemThread.
    --*/
    
    {
    
        HANDLE_TABLE_ENTRY CidEntry;
        NTSTATUS Status;
        PETHREAD Thread;
        PETHREAD CurrentThread;
        PEPROCESS Process;
        PTEB Teb;
        KPROCESSOR_MODE PreviousMode;
        HANDLE LocalThreadHandle;
        BOOLEAN AccessCheck;
        BOOLEAN MemoryAllocated;
        PSECURITY_DESCRIPTOR SecurityDescriptor;
        SECURITY_SUBJECT_CONTEXT SubjectContext;
        NTSTATUS accesst;
        LARGE_INTEGER CreateTime;
        ULONG OldActiveThreads;
        PEJOB Job;
        AUX_ACCESS_DATA AuxData;
        PACCESS_STATE AccessState;
        ACCESS_STATE LocalAccessState;
    
        PAGED_CODE();
    
    
        CurrentThread = PsGetCurrentThread ();
    
        if (StartRoutine != NULL) {
            PreviousMode = KernelMode;
        } else {
            PreviousMode = KeGetPreviousModeByThread (&CurrentThread->Tcb);
        }
    
        Teb = NULL;
    
        Thread = NULL;
        Process = NULL;
    
        if (ProcessHandle != NULL) {
            //
            // Process object reference count is biased by one for each thread.
            // This accounts for the pointer given to the kernel that remains
            // in effect until the thread terminates (and becomes signaled)
            //
    
            Status = ObReferenceObjectByHandle (ProcessHandle,
                                                PROCESS_CREATE_THREAD,
                                                PsProcessType,
                                                PreviousMode,
                                                &Process,
                                                NULL);
        } else {
            if (StartRoutine != NULL) {
                ObReferenceObject (ProcessPointer);
                Process = ProcessPointer;
                Status = STATUS_SUCCESS;
            } else {
                Status = STATUS_INVALID_HANDLE;
            }
        }
    
        if (!NT_SUCCESS (Status)) {
            return Status;
        }
    
        //
        // If the previous mode is user and the target process is the system
        // process, then the operation cannot be performed.
        //
    
        if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess)) {
            ObDereferenceObject (Process);
            return STATUS_INVALID_HANDLE;
        }
    
        Status = ObCreateObject (PreviousMode,
                                 PsThreadType,
                                 ObjectAttributes,
                                 PreviousMode,
                                 NULL,
                                 sizeof(ETHREAD),
                                 0,
                                 0,
                                 &Thread);
    
        if (!NT_SUCCESS (Status)) {
            ObDereferenceObject (Process);
            return Status;
        }
    
        RtlZeroMemory (Thread, sizeof (ETHREAD));
    
        //
        // Initialize rundown protection for cross thread TEB refs etc.
        //
        ExInitializeRundownProtection (&Thread->RundownProtect);
    
        //
        // Assign this thread to the process so that from now on
        // we don't have to dereference in error paths.
        //
        Thread->ThreadsProcess = Process;
    
        Thread->Cid.UniqueProcess = Process->UniqueProcessId;
    
        CidEntry.Object = Thread;
        CidEntry.GrantedAccess = 0;
        Thread->Cid.UniqueThread = ExCreateHandle (PspCidTable, &CidEntry);
    
        if (Thread->Cid.UniqueThread == NULL) {
            ObDereferenceObject (Thread);
            return (STATUS_INSUFFICIENT_RESOURCES);
        }
    
        //
        // Initialize Mm
        //
    
        Thread->ReadClusterSize = MmReadClusterSize;
    
        //
        // Initialize LPC
        //
    
        KeInitializeSemaphore (&Thread->LpcReplySemaphore, 0L, 1L);
        InitializeListHead (&Thread->LpcReplyChain);
    
        //
        // Initialize Io
        //
    
        InitializeListHead (&Thread->IrpList);
    
        //
        // Initialize Registry
        //
    
        InitializeListHead (&Thread->PostBlockList);
    
        //
        // Initialize the thread lock
        //
    
        PspInitializeThreadLock (Thread);
    
        KeInitializeSpinLock (&Thread->ActiveTimerListLock);
        InitializeListHead (&Thread->ActiveTimerListHead);
    
    
        if (!ExAcquireRundownProtection (&Process->RundownProtect)) {
            ObDereferenceObject (Thread);
            return STATUS_PROCESS_IS_TERMINATING;
        }
    
        if (ARGUMENT_PRESENT (ThreadContext)) {
    
            //
            // User-mode thread. Create TEB etc
            //
    
            Status = MmCreateTeb (Process, InitialTeb, &Thread->Cid, &Teb);
            if (!NT_SUCCESS (Status)) {
                ExReleaseRundownProtection (&Process->RundownProtect);
                ObDereferenceObject (Thread);
                return Status;
            }
    
    
            try {
                //
                // Initialize kernel thread object for user mode thread.
                //
    
                Thread->StartAddress = (PVOID)CONTEXT_TO_PROGRAM_COUNTER(ThreadContext);
    
    #if defined(_AMD64_)
    
                Thread->Win32StartAddress = (PVOID)ThreadContext->Rdx;
    
    #elif defined(_X86_)
    
                Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
    
    #else
    
    #error "no target architecture"
    
    #endif
    
            } except (EXCEPTION_EXECUTE_HANDLER) {
    
                Status = GetExceptionCode();
            }
    
            if (NT_SUCCESS (Status)) {
                Status = KeInitThread (&Thread->Tcb,
                                       NULL,
                                       PspUserThreadStartup,
                                       (PKSTART_ROUTINE)NULL,
                                       Thread->StartAddress,
                                       ThreadContext,
                                       Teb,
                                       &Process->Pcb);
           }
    
    
        } else {
    
            Teb = NULL;
            //
            // Set the system thread bit thats kept for all time
            //
            PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_SYSTEM);
    
            //
            // Initialize kernel thread object for kernel mode thread.
            //
    
            Thread->StartAddress = (PKSTART_ROUTINE) StartRoutine;
            Status = KeInitThread (&Thread->Tcb,
                                   NULL,
                                   PspSystemThreadStartup,
                                   StartRoutine,
                                   StartContext,
                                   NULL,
                                   NULL,
                                   &Process->Pcb);
        }
    
    
        if (!NT_SUCCESS (Status)) {
            if (Teb != NULL) {
                MmDeleteTeb(Process, Teb);
            }
            ExReleaseRundownProtection (&Process->RundownProtect);
            ObDereferenceObject (Thread);
            return Status;
        }
    
        PspLockProcessExclusive (Process, CurrentThread);
        //
        // Process is exiting or has had delete process called
        // We check the calling threads termination status so we
        // abort any thread creates while ExitProcess is being called --
        // but the call is blocked only if the new thread would be created
        // in the terminating thread's process.
        //
        if ((Process->Flags&PS_PROCESS_FLAGS_PROCESS_DELETE) != 0 ||
            (((CurrentThread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_TERMINATED) != 0) &&
            (ThreadContext != NULL) &&
            (THREAD_TO_PROCESS(CurrentThread) == Process))) {
    
            PspUnlockProcessExclusive (Process, CurrentThread);
    
            KeUninitThread (&Thread->Tcb);
    
            if (Teb != NULL) {
                MmDeleteTeb(Process, Teb);
            }
            ExReleaseRundownProtection (&Process->RundownProtect);
            ObDereferenceObject(Thread);
    
            return STATUS_PROCESS_IS_TERMINATING;
        }
    
    
        OldActiveThreads = Process->ActiveThreads++;
        InsertTailList (&Process->ThreadListHead, &Thread->ThreadListEntry);
    
        KeStartThread (&Thread->Tcb);
    
        PspUnlockProcessExclusive (Process, CurrentThread);
    
        ExReleaseRundownProtection (&Process->RundownProtect);
    
        //
        // Failures that occur after this point cause the thread to
        // go through PspExitThread
        //
    
    
        if (OldActiveThreads == 0) {
            PERFINFO_PROCESS_CREATE (Process);
    
            if (PspCreateProcessNotifyRoutineCount != 0) {
                ULONG i;
                PEX_CALLBACK_ROUTINE_BLOCK CallBack;
                PCREATE_PROCESS_NOTIFY_ROUTINE Rtn;
    
                for (i=0; i<PSP_MAX_CREATE_PROCESS_NOTIFY; i++) {
                    CallBack = ExReferenceCallBackBlock (&PspCreateProcessNotifyRoutine[i]);
                    if (CallBack != NULL) {
                        Rtn = (PCREATE_PROCESS_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack);
                        Rtn (Process->InheritedFromUniqueProcessId,
                             Process->UniqueProcessId,
                             TRUE);
                        ExDereferenceCallBackBlock (&PspCreateProcessNotifyRoutine[i],
                                                    CallBack);
                    }
                }
            }
        }
    
        //
        // If the process has a job with a completion port,
        // AND if the process is really considered to be in the Job, AND
        // the process has not reported, report in
        //
        // This should really be done in add process to job, but can't
        // in this path because the process's ID isn't assigned until this point
        // in time
        //
        Job = Process->Job;
        if (Job != NULL && Job->CompletionPort &&
            !(Process->JobStatus & (PS_JOB_STATUS_NOT_REALLY_ACTIVE|PS_JOB_STATUS_NEW_PROCESS_REPORTED))) {
    
            PS_SET_BITS (&Process->JobStatus, PS_JOB_STATUS_NEW_PROCESS_REPORTED);
    
            KeEnterCriticalRegionThread (&CurrentThread->Tcb);
            ExAcquireResourceSharedLite (&Job->JobLock, TRUE);
            if (Job->CompletionPort != NULL) {
                IoSetIoCompletion (Job->CompletionPort,
                                   Job->CompletionKey,
                                   (PVOID)Process->UniqueProcessId,
                                   STATUS_SUCCESS,
                                   JOB_OBJECT_MSG_NEW_PROCESS,
                                   FALSE);
            }
            ExReleaseResourceLite (&Job->JobLock);
            KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
        }
    
        PERFINFO_THREAD_CREATE(Thread, InitialTeb);
    
        //
        // Notify registered callout routines of thread creation.
        //
    
        if (PspCreateThreadNotifyRoutineCount != 0) {
            ULONG i;
            PEX_CALLBACK_ROUTINE_BLOCK CallBack;
            PCREATE_THREAD_NOTIFY_ROUTINE Rtn;
    
            for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) {
                CallBack = ExReferenceCallBackBlock (&PspCreateThreadNotifyRoutine[i]);
                if (CallBack != NULL) {
                    Rtn = (PCREATE_THREAD_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack);
                    Rtn (Thread->Cid.UniqueProcess,
                         Thread->Cid.UniqueThread,
                         TRUE);
                    ExDereferenceCallBackBlock (&PspCreateThreadNotifyRoutine[i],
                                                CallBack);
                }
            }
        }
    
    
        //
        // Reference count of thread is biased once for itself and once for the handle if we create it.
        //
    
        ObReferenceObjectEx (Thread, 2);
    
        if (CreateSuspended) {
            try {
                KeSuspendThread (&Thread->Tcb);
            } except ((GetExceptionCode () == STATUS_SUSPEND_COUNT_EXCEEDED)?
                         EXCEPTION_EXECUTE_HANDLER :
                         EXCEPTION_CONTINUE_SEARCH) {
            }
            //
            // If deletion was started after we suspended then wake up the thread
            //
            if (Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_TERMINATED) {
                KeForceResumeThread (&Thread->Tcb);
            }
        }
    
        AccessState = NULL;
        if (!PsUseImpersonationToken) {
            AccessState = &LocalAccessState;
            Status = SeCreateAccessStateEx (NULL,
                                            ARGUMENT_PRESENT (ThreadContext)?PsGetCurrentProcessByThread (CurrentThread) : Process,
                                            AccessState,
                                            &AuxData,
                                            DesiredAccess,
                                            &PsThreadType->TypeInfo.GenericMapping);
    
            if (!NT_SUCCESS (Status)) {
                PS_SET_BITS (&Thread->CrossThreadFlags,
                             PS_CROSS_THREAD_FLAGS_DEADTHREAD);
    
                if (CreateSuspended) {
                    (VOID) KeResumeThread (&Thread->Tcb);
                }
                KeReadyThread (&Thread->Tcb);
                ObDereferenceObjectEx (Thread, 2);
    
                return Status;
            }
        }
    
        Status = ObInsertObject (Thread,
                                 AccessState,
                                 DesiredAccess,
                                 0,
                                 NULL,
                                 &LocalThreadHandle);
    
        if (AccessState != NULL) {
            SeDeleteAccessState (AccessState);
        }
    
        if (!NT_SUCCESS (Status)) {
    
            //
            // The insert failed. Terminate the thread.
            //
    
            //
            // This trick is used so that Dbgk doesn't report
            // events for dead threads
            //
    
            PS_SET_BITS (&Thread->CrossThreadFlags,
                         PS_CROSS_THREAD_FLAGS_DEADTHREAD);
    
            if (CreateSuspended) {
                KeResumeThread (&Thread->Tcb);
            }
    
        } else {
    
            try {
    
                *ThreadHandle = LocalThreadHandle;
                if (ARGUMENT_PRESENT (ClientId)) {
                    *ClientId = Thread->Cid;
                }
            } except(EXCEPTION_EXECUTE_HANDLER) {
    
                PS_SET_BITS (&Thread->CrossThreadFlags,
                             PS_CROSS_THREAD_FLAGS_DEADTHREAD);
    
                if (CreateSuspended) {
                    (VOID) KeResumeThread (&Thread->Tcb);
                }
                KeReadyThread (&Thread->Tcb);
                ObDereferenceObject (Thread);
                ObCloseHandle (LocalThreadHandle, PreviousMode);
                return GetExceptionCode();
            }
        }
    
        KeQuerySystemTime(&CreateTime);
        ASSERT ((CreateTime.HighPart & 0xf0000000) == 0);
        PS_SET_THREAD_CREATE_TIME(Thread, CreateTime);
    
    
        if ((Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_DEADTHREAD) == 0) {
            Status = ObGetObjectSecurity (Thread,
                                          &SecurityDescriptor,
                                          &MemoryAllocated);
            if (!NT_SUCCESS (Status)) {
                //
                // This trick us used so that Dbgk doesn't report
                // events for dead threads
                //
                PS_SET_BITS (&Thread->CrossThreadFlags,
                             PS_CROSS_THREAD_FLAGS_DEADTHREAD);
    
                if (CreateSuspended) {
                    KeResumeThread(&Thread->Tcb);
                }
                KeReadyThread (&Thread->Tcb);
                ObDereferenceObject (Thread);
                ObCloseHandle (LocalThreadHandle, PreviousMode);
                return Status;
            }
    
            //
            // Compute the subject security context
            //
    
            SubjectContext.ProcessAuditId = Process;
            SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
            SubjectContext.ClientToken = NULL;
    
            AccessCheck = SeAccessCheck (SecurityDescriptor,
                                         &SubjectContext,
                                         FALSE,
                                         MAXIMUM_ALLOWED,
                                         0,
                                         NULL,
                                         &PsThreadType->TypeInfo.GenericMapping,
                                         PreviousMode,
                                         &Thread->GrantedAccess,
                                         &accesst);
    
            PsDereferencePrimaryTokenEx (Process, SubjectContext.PrimaryToken);
    
            ObReleaseObjectSecurity (SecurityDescriptor,
                                     MemoryAllocated);
    
            if (!AccessCheck) {
                Thread->GrantedAccess = 0;
            }
    
            Thread->GrantedAccess |= (THREAD_TERMINATE | THREAD_SET_INFORMATION | THREAD_QUERY_INFORMATION);
    
        } else {
            Thread->GrantedAccess = THREAD_ALL_ACCESS;
        }
    
        KeReadyThread (&Thread->Tcb);
        ObDereferenceObject (Thread);
    
        return Status;
    }
    

      继续分析PspCreateThread函数实现的关键步骤:

      (1)ObCreateObject创建一个线程对象ETHREAD,并初始化为零。

        Status = ObCreateObject (PreviousMode,
                                 PsThreadType,
                                 ObjectAttributes,
                                 PreviousMode,
                                 NULL,
                                 sizeof(ETHREAD),
                                 0,
                                 0,
                                 &Thread);
    
        if (!NT_SUCCESS (Status)) {
            ObDereferenceObject (Process);
            return Status;
        }
    
        RtlZeroMemory (Thread, sizeof (ETHREAD));
    

      (2)ExCreateHandle函数创建线程ID

    Thread->ThreadsProcess = Process;
    
        Thread->Cid.UniqueProcess = Process->UniqueProcessId;
    
        CidEntry.Object = Thread;
        CidEntry.GrantedAccess = 0;
        Thread->Cid.UniqueThread = ExCreateHandle (PspCidTable, &CidEntry);
    
        if (Thread->Cid.UniqueThread == NULL) {
            ObDereferenceObject (Thread);
            return (STATUS_INSUFFICIENT_RESOURCES);
        }
    

      (3)MmCreateTeb函数创建TEB

    Status = MmCreateTeb (Process, InitialTeb, &Thread->Cid, &Teb);
            if (!NT_SUCCESS (Status)) {
                ExReleaseRundownProtection (&Process->RundownProtect);
                ObDereferenceObject (Thread);
                return Status;
            }
    

      (4)利用ThreadContext中的程序指针(Eip寄存器)来设置线程的启动地址

           Thread->StartAddress = (PKSTART_ROUTINE) StartRoutine;
    

      (5)InsertTailList 函数将线程插入线程LIST_ENTRY链表

    OldActiveThreads = Process->ActiveThreads++;
        InsertTailList (&Process->ThreadListHead, &Thread->ThreadListEntry);
    

      (6)判断如果这个线程是进程中的第一个进程,回调函数则触发进程的创建通知

    if (OldActiveThreads == 0) {
            PERFINFO_PROCESS_CREATE (Process);
    
            if (PspCreateProcessNotifyRoutineCount != 0) {
                ULONG i;
                PEX_CALLBACK_ROUTINE_BLOCK CallBack;
                PCREATE_PROCESS_NOTIFY_ROUTINE Rtn;
    
                for (i=0; i<PSP_MAX_CREATE_PROCESS_NOTIFY; i++) {
                    CallBack = ExReferenceCallBackBlock (&PspCreateProcessNotifyRoutine[i]);
                    if (CallBack != NULL) {
                        Rtn = (PCREATE_PROCESS_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack);
                        Rtn (Process->InheritedFromUniqueProcessId,
                             Process->UniqueProcessId,
                             TRUE);
                        ExDereferenceCallBackBlock (&PspCreateProcessNotifyRoutine[i],
                                                    CallBack);
                    }
                }
            }
        }
    

      (7)ObInsertObject函数将线程对象插入到当前进程的句柄表中

      

        Status = ObInsertObject (Thread,
                                 AccessState,
                                 DesiredAccess,
                                 0,
                                 NULL,
                                 &LocalThreadHandle);
    

      (8)KeReadyThread函数使线程进入“就绪”状态,准备马上执行

      

        KeReadyThread (&Thread->Tcb);
        ObDereferenceObject (Thread);
    

      到目前为止进程对象和线程对象的创建工作就完成了。

    0x03  创建进程详细步骤2: 通知windows子系统有新进程创建,启动初始线程,用户空间的初始化和Dll连接

      四:通知windows子系统

     
      每个进程在创建/退出的时候都要向windows子系统进程csrss.exe进程发出通知,因为它担负着对windows所有进程的管理的责任,
    注意,这里发出通知的是CreateProcess的调用者,不是新建出来的进程,因为它还没有开始运行
     
      至此,CreateProcess的操作已经完成,但子进程中的线程却尚未开始运行,它的运行还要经历下面的第五和第六阶段。
     
      五:启动初始线程
     

      在内核中,新线程的启动例程是KiThreadStartup函数,这是当PspCreateThread 调用KeInitThread 函数时,KeInitThread 函数调用KiInitializeContextThread(参见base toskei386 hredini.c 文件)来设置的。

    KiThreadStartup 函数首先将IRQL 降低到APC_LEVEL,然后调用系统初始的线程函数PspUserThreadStartup。这里的PspUserThreadStartup 函数是PspCreateThread 函数在调用KeInitThread 时指定的,。注意,PspCreateThread函数在创建系统线程时指定的初始线程函数为PspSystemThreadStartup  。线程启动函数被作为一个参数传递给PspUserThreadStartup,在这里,它应该是kernel32.dll 中的BaseProcessStart。

    PspUserThreadStartup 函数被调用。逻辑并不复杂,但是涉及异步函数调用(APC)机制。

     

      新创建的线程未必是可以被立即调度运行的,因为用户可能在创建时把标志位CREATE_ SUSPENDED设成了1;
    如果那样的话,就需要等待别的进程通过系统调用恢复其运行资格以后才可以被调度运行。否则现在已经可以被调度运行了。至于什么时候才会被调度运行,则就要看优先级等等条件了。
     
     
      六:用户空间的初始化和Dll连接
     

      PspUserThreadStartup 函数返回以后,KiThreadStartup 函数返回到用户模式,此时,PspUserThreadStartup 插入的APC 被交付,于是LdrInitializeThunk 函数被调用,这是映像加载器(image loader)的初始化函数。LdrInitializeThunk 函数完成加载器、堆管理器等初始化工作,然后加载任何必要的DLL,并且调用这些DLL 的入口函数。最后,当LdrInitializeThunk 返回到用户模式APC 分发器时,该线程开始在用户模式下执行,调用应用程序指定的线程启动函数,此启动函数的地址已经在APC 交付时被压到用户栈中。


      DLL连接由ntdll.dll中的LdrInitializeThunk()在用户空间完成。在此之前ntdll.dll与应用软件尚未连接,但是已经被映射到了用户空间
    函数LdrInitializeThunk()在映像中的位置是系统初始化时就预先确定并记录在案的,所以在进入这个函数之前也不需要连接。

     

    0x04  最后总结一下整个流程

        1.打开目标映像文件(NtOpenFile()获取句柄, NtCreateSectiont通过文件句柄创建一个Section文件映射区,将文件内容映射进来

        2.创建进程对象

           NtCreateProcess——>NtCreateProcessEx——>PspCreateProcess——>

                               ObCreateObject函数创建EPROCESS

                               MmCreateProcessAddressSpace创建新的地址空间,MmInitializeProcessAddressSpace 初始化新进程的地址空间

                               ExCreateHandle函数在CID句柄表中创建一个进程ID项。

                                  MmCreatePeb 创建一个PEB,如果进程通过映像内存区来创建,创建一个PEB,如果是进程拷贝,则使用继承的PEB。

                               InsertTailList 函数把新进程加入全局的LIST_ENTRY进程链表中(位置:PsActiveProcessHead)

                               ObInsertObject 将新进程对象记录到当前进程的句柄表中。

            3.创建线程对象

          NtCreateThread——>PspCreateThread——>

                               ObCreateObject创建一个线程对象ETHREAD,并初始化为零。

                               ExCreateHandle函数创建线程ID

                               MmCreateTeb函数创建TEB

                               利用ThreadContext中的程序指针(Eip寄存器)来设置线程的启动地址Thread->StartAddress = (PKSTART_ROUTINE) StartRoutine;

                                  InsertTailList 函数将线程插入线程LIST_ENTRY链表

                               判断如果这个线程是进程中的第一个进程,回调函数则触发进程的创建通知PCREATE_PROCESS_NOTIFY_ROUTINE Rtn;

                                  ObInsertObject函数将线程对象插入到当前进程的句柄表中

                                  KeReadyThread函数使线程进入“就绪”状态,准备马上执行

        4.通知windows子系统

         CreateProcess的调用者向windows子系统进程csrss.exe进程发出进程创建通知

        5.启动初始线程

           在内核中,新线程的启动例程是KiThreadStartup函数,这是当PspCreateThread 调用KeInitThread 函数时,KeInitThread 函数调用KiInitializeContextThread(参见base toskei386 hredini.c 文件)来设置的。

        6.用户空间的初始化和Dll连接

         DLL连接由ntdll.dll中的LdrInitializeThunk()在用户空间完成

  • 相关阅读:
    storm 学习教程
    Scala 面向接口编程
    Scala 继承
    IntelliJ IDEA 代码检查规范QAPlug
    Spark入门实战系列
    IntelliJ Idea 常用快捷键 列表(实战终极总结!!!!)
    使用DOM解析XML文档
    栈结构Stack
    队列Queue ,双端队列Deque
    集合转换为数组toArray(),数组转换为集合asList()
  • 原文地址:https://www.cnblogs.com/lsh123/p/7405796.html
Copyright © 2011-2022 走看看