刘收获

导航

进程创建过程详解 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)'\t' ) {
 317                         TempNull = (PWCH)WhiteScan;
 318                         break;
 319                         }
 320                     WhiteScan++;
 321                     TempNull = (PWCH)WhiteScan;
 322                     }
 323                 }
 324             TempChar = *TempNull;
 325             *TempNull = UNICODE_NULL;
 326 
 327 #ifdef WX86
 328 
 329             //
 330             // Wx86 applications must use x86 version of known exes
 331             // for compatibility.
 332             //
 333 
 334             if (UseKnownWx86Dll) {
 335                LPWSTR KnownName;
 336 
 337                NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
 338 
 339                KnownName = BasepWx86KnownExe(lpApplicationName);
 340                if (KnownName) {
 341                   lpApplicationName = KnownName;
 342                   }
 343                }
 344 #endif
 345 
 346 
 347             Length = SearchPathW(
 348                         NULL,
 349                         lpApplicationName,
 350                         (PWSTR)L".exe",
 351                         MAX_PATH,
 352                         NameBuffer,
 353                         NULL
 354                         )*2;
 355 
 356             if (Length != 0 && Length < MAX_PATH * sizeof( WCHAR )) {
 357                 //
 358                 // SearchPathW worked, but file might be a directory
 359                 // if this happens, we need to keep trying
 360                 //
 361                 fileattr = GetFileAttributesW(NameBuffer);
 362                 if ( fileattr != 0xffffffff &&
 363                      (fileattr & FILE_ATTRIBUTE_DIRECTORY) ) {
 364                     Length = 0;
 365                 } else {
 366                     Length++;
 367                     Length++;
 368                 }
 369             }
 370 
 371             if ( !Length || Length >= MAX_PATH<<1 ) {
 372 
 373                 //
 374                 // If we search pathed, then return file not found.
 375                 // otherwise, try to be more specific.
 376                 //
 377                 RTL_PATH_TYPE PathType;
 378                 HANDLE hFile;
 379 
 380                 PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
 381                 if ( PathType != RtlPathTypeRelative ) {
 382 
 383                     //
 384                     // The failed open should set get last error properly.
 385                     //
 386 
 387                     hFile = CreateFileW(
 388                                 lpApplicationName,
 389                                 GENERIC_READ,
 390                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
 391                                 NULL,
 392                                 OPEN_EXISTING,
 393                                 FILE_ATTRIBUTE_NORMAL,
 394                                 NULL
 395                                 );
 396                     if ( hFile != INVALID_HANDLE_VALUE ) {
 397                         CloseHandle(hFile);
 398                         BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
 399                         }
 400                     }
 401                 else {
 402                     BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
 403                     }
 404 
 405                 //
 406                 // remember initial last error value for the retry scan path
 407                 //
 408 
 409                 if ( LastError ) {
 410                     SetLastError(LastError);
 411                     }
 412                 else {
 413                     LastError = GetLastError();
 414                     }
 415 
 416                 //
 417                 // restore the command line
 418                 //
 419 
 420                 *TempNull = TempChar;
 421                 lpApplicationName = NameBuffer;
 422 
 423                 //
 424                 // If we still have command line left, then keep going
 425                 // the point is to march through the command line looking
 426                 // for whitespace so we can try to find an image name
 427                 // launches of things like:
 428                 // c:\word 95\winword.exe /embedding -automation
 429                 // require this. Our first iteration will stop at c:\word, our next
 430                 // will stop at c:\word 95\winword.exe
 431                 //
 432                 if (*WhiteScan && SearchRetry) {
 433                     WhiteScan++;
 434                     TempNull = WhiteScan;
 435                     QuoteInsert = TRUE;
 436                     QuoteFound = TRUE;
 437                     goto retrywsscan;
 438                 }
 439 
 440                 return FALSE;
 441                 }
 442             //
 443             // restore the command line
 444             //
 445 
 446             *TempNull = TempChar;
 447             lpApplicationName = NameBuffer;
 448             }
 449         else
 450         if (!ARGUMENT_PRESENT( lpCommandLine ) || *lpCommandLine == UNICODE_NULL ) {
 451             QuoteCmdLine = TRUE;
 452             lpCommandLine = (LPWSTR)lpApplicationName;
 453             }
 454 
 455 
 456 #ifdef WX86
 457 
 458        //
 459        // Wx86 applications must use x86 version of known exes
 460        // for compatibility.
 461        //
 462 
 463        if (UseKnownWx86Dll) {
 464            LPWSTR KnownName;
 465 
 466            NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
 467 
 468            KnownName = BasepWx86KnownExe(lpApplicationName);
 469            if (KnownName) {
 470 
 471                RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer);
 472                NameBuffer = KnownName;
 473                lpApplicationName = KnownName;
 474                }
 475            }
 476 
 477 #endif
 478 
 479 
 480         //
 481         // Translate to an NT name.
 482         //
 483 
 484         TranslationStatus = RtlDosPathNameToNtPathName_U(
 485                                 lpApplicationName,
 486                                 &PathName,
 487                                 NULL,
 488                                 &RelativeName
 489                                 );
 490 
 491         if ( !TranslationStatus ) {
 492             SetLastError(ERROR_PATH_NOT_FOUND);
 493 
 494             return FALSE;
 495             }
 496 
 497         // forgot to free FreeBuffer before goto VdmRetry????
 498         ASSERT(FreeBuffer == NULL);
 499         FreeBuffer = PathName.Buffer;
 500 
 501         if ( RelativeName.RelativeName.Length ) {
 502             PathName = *(PUNICODE_STRING)&RelativeName.RelativeName;
 503             }
 504         else {
 505             RelativeName.ContainingDirectory = NULL;
 506             }
 507 
 508         InitializeObjectAttributes(
 509             &Obja,
 510             &PathName,
 511             OBJ_CASE_INSENSITIVE,
 512             RelativeName.ContainingDirectory,
 513             NULL
 514             );
 515 
 516         //
 517         // Open the file for execute access
 518         //
 519 
 520         Status = NtOpenFile(
 521                     &FileHandle,
 522                     SYNCHRONIZE | FILE_EXECUTE,
 523                     &Obja,
 524                     &IoStatusBlock,
 525                     FILE_SHARE_READ | FILE_SHARE_DELETE,
 526                     FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
 527                     );
 528         if (!NT_SUCCESS(Status) ) {
 529 
 530             //
 531             // if we failed, see if this is a device. If it is a device,
 532             // then just return invalid image format
 533             //
 534 
 535             if ( RtlIsDosDeviceName_U((PWSTR)lpApplicationName) ) {
 536                 SetLastError(ERROR_BAD_DEVICE);
 537                 }
 538             else {
 539                 BaseSetLastNTError(Status);
 540                 }
 541 
 542             return FALSE;
 543             }
 544 
 545         //
 546         // If no desktop has been specified, use the caller's
 547         // desktop.
 548         //
 549 
 550         if (StartupInfo.lpDesktop == NULL) {
 551             StartupInfo.lpDesktop =
 552                     (LPWSTR)((PRTL_USER_PROCESS_PARAMETERS)NtCurrentPeb()->
 553                         ProcessParameters)->DesktopInfo.Buffer;
 554             }
 555 
 556         //
 557         // Create a section object backed by the file
 558         //
 559 
 560         Status = NtCreateSection(
 561                     &SectionHandle,
 562                     SECTION_ALL_ACCESS,
 563                     NULL,
 564                     NULL,
 565                     PAGE_EXECUTE,
 566                     SEC_IMAGE,
 567                     FileHandle
 568                     );
 569 
 570 
 571         NtClose(FileHandle);
 572         FileHandle = NULL;
 573 
 574 
 575 
 576         //
 577         // App Certification DLL
 578         //
 579 
 580        if (NT_SUCCESS(Status)) {
 581 
 582           Status = BasepIsProcessAllowed(lpApplicationName);
 583 
 584           if (!NT_SUCCESS(Status)) {
 585             BaseSetLastNTError(Status);
 586             return FALSE;
 587           }
 588 
 589        }
 590 
 591 
 592 
 593         if (!NT_SUCCESS(Status)) {
 594 
 595             switch (Status) {
 596                 // 16 bit OS/2 exe
 597                 case STATUS_INVALID_IMAGE_NE_FORMAT:
 598 #ifdef i386
 599                 //
 600                 // Use OS/2 if x86 (OS/2 not supported on risc),
 601                 //    and CreationFlags don't have forcedos bit
 602                 //    and Registry didn't specify ForceDos
 603                 //
 604                 // else execute as a DOS bound app.
 605                 //
 606                 //
 607 
 608                 if (!(dwCreationFlags & CREATE_FORCEDOS) &&
 609                     !BaseStaticServerData->ForceDos)
 610                   {
 611 
 612                     if ( !BuildSubSysCommandLine( L"OS2 /P ",
 613                                                   lpApplicationName,
 614                                                   lpCommandLine,
 615                                                   &SubSysCommandLine
 616                                                 ) ) {
 617                         return FALSE;
 618                         }
 619 
 620                     lpCommandLine = SubSysCommandLine.Buffer;
 621 
 622                     lpApplicationName = NULL;
 623 
 624                     RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
 625                     FreeBuffer = NULL;
 626                     RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer);
 627                     NameBuffer = NULL;
 628                     goto VdmRetry;
 629                     }
 630 #endif
 631                     // Falls into Dos case, so that stub message will be
 632                     // printed, and bound apps will run w/o OS/2 subsytem
 633 
 634                 // Dos .exe or .com
 635 
 636                 case STATUS_INVALID_IMAGE_PROTECT:
 637                 case STATUS_INVALID_IMAGE_NOT_MZ:
 638 ForceDos:
 639                     {
 640                     ULONG BinarySubType;
 641 
 642                     BinarySubType = BINARY_TYPE_DOS_EXE;
 643                     if (Status == STATUS_INVALID_IMAGE_PROTECT   ||
 644                         Status == STATUS_INVALID_IMAGE_NE_FORMAT ||
 645                        (BinarySubType = BaseIsDosApplication(&PathName,Status)) )
 646                        {
 647                         VdmBinaryType = BINARY_TYPE_DOS;
 648 
 649                         // create the environment before going to the
 650                         // server. This was done becuase we want NTVDM
 651                         // to have the new environment when it gets
 652                         // created.
 653                         if (!BaseCreateVDMEnvironment(
 654                                     lpEnvironment,
 655                                     &AnsiStringVDMEnv,
 656                                     &UnicodeStringVDMEnv
 657                                     ))
 658                             return FALSE;
 659 
 660                         if(!BaseCheckVDM(VdmBinaryType | BinarySubType,
 661                                          lpApplicationName,
 662                                          lpCommandLine,
 663                                          lpCurrentDirectory,
 664                                          &AnsiStringVDMEnv,
 665                                          &m,
 666                                          &iTask,
 667                                          dwCreationFlags,
 668                                          &StartupInfo
 669                                          ))
 670                             return FALSE;
 671 
 672 
 673                         // Check the return value from the server
 674                         switch (b->VDMState & VDM_STATE_MASK){
 675                             case VDM_NOT_PRESENT:
 676                                 // mark this so the server can undo
 677                                 // creation if something goes wrong.
 678                                 // We marked it "partitially created" because
 679                                 // the NTVDM has yet not been fully created.
 680                                 // a call to UpdateVdmEntry to update
 681                                 // process handle will signal the NTVDM
 682                                 // process completed creation
 683                                 VDMCreationState = VDM_PARTIALLY_CREATED;
 684                                 // fail the call if NTVDM process is being
 685                                 // created DETACHED.
 686                                 // note that, we let it go if NTVDM process
 687                                 // is already running.
 688                                 if (dwCreationFlags & DETACHED_PROCESS) {
 689                                     SetLastError(ERROR_ACCESS_DENIED);
 690                                     return FALSE;
 691                                     }
 692                                 if (!BaseGetVdmConfigInfo(lpCommandLine,
 693                                                           iTask,
 694                                                           VdmBinaryType,
 695                                                           &VdmNameString,
 696                                                           &VdmReserve
 697                                                           ))
 698                                    {
 699                                     BaseSetLastNTError(Status);
 700                                     return FALSE;
 701                                     }
 702 
 703                                 lpCommandLine = VdmNameString.Buffer;
 704                                 lpApplicationName = NULL;
 705 
 706                                 break;
 707 
 708                             case VDM_PRESENT_NOT_READY:
 709                                 SetLastError (ERROR_NOT_READY);
 710                                 return FALSE;
 711 
 712                             case VDM_PRESENT_AND_READY:
 713                                 VDMCreationState = VDM_BEING_REUSED;
 714                                 VdmWaitHandle = b->WaitObjectForParent;
 715                                 break;
 716                             }
 717                          RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
 718                          FreeBuffer = NULL;
 719                          RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer);
 720                          NameBuffer = NULL;
 721                          VdmReserve--;               // we reserve from addr 1
 722                          if(VdmWaitHandle)
 723                             goto VdmExists;
 724                          else{
 725                             bInheritHandles = FALSE;
 726                             if (lpEnvironment &&
 727                                 !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)){
 728                                 RtlDestroyEnvironment(lpEnvironment);
 729                                 }
 730                             lpEnvironment = UnicodeStringVDMEnv.Buffer;
 731                             goto VdmRetry;
 732                             }
 733                         }
 734                     else {
 735 
 736                         //
 737                         //  must be a .bat or .cmd file
 738                         //
 739 
 740                         static PWCHAR CmdPrefix = L"cmd /c ";
 741                         PWCHAR NewCommandLine;
 742                         ULONG Length;
 743                         PWCHAR Last4 = &PathName.Buffer[PathName.Length / sizeof( WCHAR )-4];
 744 
 745                         if ( PathName.Length < 8 ) {
 746                             SetLastError(ERROR_BAD_EXE_FORMAT);
 747                             return FALSE;
 748                             }
 749 
 750                         if (_wcsnicmp( Last4, L".bat", 4 ) && _wcsnicmp( Last4, L".cmd", 4 )) {
 751                             SetLastError(ERROR_BAD_EXE_FORMAT);
 752                             return FALSE;
 753                         }
 754 
 755                         Length = wcslen( CmdPrefix )
 756                                  + (QuoteCmdLine || QuoteFound )
 757                                  + wcslen( lpCommandLine )
 758                                  + (QuoteCmdLine || QuoteFound)
 759                                  + 1;
 760 
 761                         NewCommandLine = RtlAllocateHeap( RtlProcessHeap( ),
 762                                                           MAKE_TAG( TMP_TAG ),
 763                                                           Length * sizeof( WCHAR ) );
 764 
 765                         if (NewCommandLine == NULL) {
 766                             BaseSetLastNTError(STATUS_NO_MEMORY);
 767                             return FALSE;
 768                         }
 769 
 770                         wcscpy( NewCommandLine, CmdPrefix );
 771                         if (QuoteCmdLine || QuoteFound) {
 772                             wcscat( NewCommandLine, L"\"" );
 773                         }
 774                         wcscat( NewCommandLine, lpCommandLine );
 775                         if (QuoteCmdLine || QuoteFound) {
 776                             wcscat( NewCommandLine, L"\"" );
 777                         }
 778 
 779                         RtlInitUnicodeString( &SubSysCommandLine, NewCommandLine );
 780 
 781                         lpCommandLine = SubSysCommandLine.Buffer;
 782 
 783                         lpApplicationName = NULL;
 784 
 785                         RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
 786                         FreeBuffer = NULL;
 787                         RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer);
 788                         NameBuffer = NULL;
 789                         goto VdmRetry;
 790 
 791                         }
 792 
 793                     }
 794 
 795                 // 16 bit windows exe
 796                 case STATUS_INVALID_IMAGE_WIN_16:
 797 #if defined(BUILD_WOW6432) || defined(_WIN64)
 798                    if (lpOriginalApplicationName == NULL) {
 799                        // pass in the part of the command line after the exe name
 800                        // including whitespace
 801                        lpCommandLine = ((*TempNull == '\"') ? TempNull + 1 : TempNull);
 802                    } else {
 803                        lpCommandLine = lpOriginalCommandLine;
 804                    }
 805                    return NtVdm64CreateProcess(lpOriginalApplicationName == NULL,
 806                                                lpApplicationName,             // this is now the real file name we've loaded
 807                                                lpCommandLine,
 808                                                lpProcessAttributes,
 809                                                lpThreadAttributes,
 810                                                bInheritHandles,
 811                                                (dwCreationFlags & ~CREATE_UNICODE_ENVIRONMENT),  // the environment has already been converted to unicode
 812                                                lpEnvironment,
 813                                                lpCurrentDirectory,
 814                                                lpStartupInfo,
 815                                                lpProcessInformation
 816                                                );
 817 #endif
 818                    if (dwCreationFlags & CREATE_FORCEDOS) {
 819                        goto ForceDos;
 820                        }
 821 
 822                     IsWowBinary = TRUE;
 823                     if (!BaseCreateVDMEnvironment(lpEnvironment,
 824                                                   &AnsiStringVDMEnv,
 825                                                   &UnicodeStringVDMEnv
 826                                                   ))
 827                        {
 828                         return FALSE;
 829                         }
 830 
 831 
 832 
 833 RetrySepWow:
 834                     VdmBinaryType = dwCreationFlags & CREATE_SEPARATE_WOW_VDM
 835                                      ? BINARY_TYPE_SEPWOW : BINARY_TYPE_WIN16;
 836 
 837                     if (!BaseCheckVDM(VdmBinaryType,
 838                                       lpApplicationName,
 839                                       lpCommandLine,
 840                                       lpCurrentDirectory,
 841                                       &AnsiStringVDMEnv,
 842                                       &m,
 843                                       &iTask,
 844                                       dwCreationFlags,
 845                                       &StartupInfo
 846                                       ))
 847                        {
 848                         //
 849                         // If we failed with access denied, caller may not
 850                         // be allowed allowed to access the shared wow's
 851                         // desktop, so retry as a separate wow
 852                         //
 853                         if (VdmBinaryType == BINARY_TYPE_WIN16 &&
 854                             GetLastError() == ERROR_ACCESS_DENIED)
 855                           {
 856                            dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
 857                            }
 858                         else {
 859                            return FALSE;
 860                            }
 861                         goto RetrySepWow;
 862                         }
 863 
 864 
 865                     // Check the return value from the server
 866                     switch (b->VDMState & VDM_STATE_MASK){
 867                         case VDM_NOT_PRESENT:
 868                             // mark this so the server can undo
 869                             // creation if something goes wrong.
 870                             // We marked it "partitially created" because
 871                             // the NTVDM has yet not been fully created.
 872                             // a call to UpdateVdmEntry to update
 873                             // process handle will signal the NTVDM
 874                             // process completed creation
 875 
 876                             VDMCreationState = VDM_PARTIALLY_CREATED;
 877 
 878                             if (!BaseGetVdmConfigInfo(
 879                                     lpCommandLine,
 880                                     iTask,
 881                                     VdmBinaryType,
 882                                     &VdmNameString,
 883                                     &VdmReserve
 884                                     ))
 885                                {
 886                                 BaseSetLastNTError(Status);
 887                                 return FALSE;
 888                                 }
 889 
 890                             lpCommandLine = VdmNameString.Buffer;
 891                             lpApplicationName = NULL;
 892 
 893 
 894                             //
 895                             // Wow must have a hidden console
 896                             // Throw away DETACHED_PROCESS flag which isn't
 897                             // meaningful for Win16 apps.
 898                             //
 899 
 900                             dwCreationFlags |= CREATE_NO_WINDOW;
 901                             dwCreationFlags &= ~(CREATE_NEW_CONSOLE | DETACHED_PROCESS);
 902 
 903 
 904                             //
 905                             // We're starting a WOW VDM, turn on feedback unless
 906                             // the creator passed STARTF_FORCEOFFFEEDBACK.
 907                             //
 908 
 909                             StartupInfo.dwFlags |= STARTF_FORCEONFEEDBACK;
 910 
 911                             break;
 912 
 913                         case VDM_PRESENT_NOT_READY:
 914                             SetLastError (ERROR_NOT_READY);
 915                             return FALSE;
 916 
 917                         case VDM_PRESENT_AND_READY:
 918                             VDMCreationState = VDM_BEING_REUSED;
 919                             VdmWaitHandle = b->WaitObjectForParent;
 920                             break;
 921                         }
 922 
 923                     RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
 924                     FreeBuffer = NULL;
 925                     RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer);
 926                     NameBuffer = NULL;
 927                     VdmReserve--;               // we reserve from addr 1
 928                     if(VdmWaitHandle)
 929                         goto VdmExists;
 930                     else {
 931                         bInheritHandles = FALSE;
 932                         // replace the environment with ours
 933                         if (lpEnvironment &&
 934                             !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) {
 935                             RtlDestroyEnvironment(lpEnvironment);
 936                             }
 937                         lpEnvironment = UnicodeStringVDMEnv.Buffer;
 938                         goto VdmRetry;
 939                         }
 940 
 941 
 942                 default :
 943                     SetLastError(ERROR_BAD_EXE_FORMAT);
 944                     return FALSE;
 945             }
 946         }
 947 
 948         //
 949         // Make sure only WOW apps can have the CREATE_SEPARATE_WOW_VDM flag.
 950         //
 951 
 952         if (!IsWowBinary && (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)) {
 953             dwCreationFlags &= ~CREATE_SEPARATE_WOW_VDM;
 954         }
 955 
 956         //
 957         // Query the section to determine the stack parameters and
 958         // image entrypoint.
 959         //
 960 
 961         Status = NtQuerySection(
 962                     SectionHandle,
 963                     SectionImageInformation,
 964                     &ImageInformation,
 965                     sizeof( ImageInformation ),
 966                     NULL
 967                     );
 968 
 969         if (!NT_SUCCESS( Status )) {
 970             BaseSetLastNTError(Status);
 971             RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
 972             FreeBuffer = NULL;
 973             return FALSE;
 974             }
 975 
 976         if (ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL) {
 977             SetLastError(ERROR_BAD_EXE_FORMAT);
 978             RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
 979             FreeBuffer = NULL;
 980             return FALSE;
 981             }
 982 
 983         ImageFileDebuggerCommand[ 0 ] = UNICODE_NULL;
 984         if (!(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) ||
 985             NtCurrentPeb()->ReadImageFileExecOptions
 986            ) {
 987             LdrQueryImageFileExecutionOptions( &PathName,
 988                                                L"Debugger",
 989                                                REG_SZ,
 990                                                ImageFileDebuggerCommand,
 991                                                sizeof( ImageFileDebuggerCommand ),
 992                                                NULL
 993                                              );
 994             }
 995 
 996 
 997 
 998         if ((ImageInformation.Machine < USER_SHARED_DATA->ImageNumberLow) ||
 999             (ImageInformation.Machine > USER_SHARED_DATA->ImageNumberHigh)) {
1000 #if defined(WX86) || defined(_AXP64_)
1001             if (ImageInformation.Machine == IMAGE_FILE_MACHINE_I386)
1002                {
1003                 Wx86Info = (HANDLE)UIntToPtr(sizeof(WX86TIB));
1004                 }
1005             else
1006 #endif // WX86
1007 #if defined(_AXP64_)
1008             if (ImageInformation.Machine == IMAGE_FILE_MACHINE_ALPHA) {
1009                // Fall through since this is a valid machine type.
1010                 }
1011              else
1012 #elif defined(_IA64_)
1013             if (ImageInformation.Machine == IMAGE_FILE_MACHINE_I386) {
1014                // Fall through since this is a valid machine type.
1015                 }
1016              else
1017 #endif // _AXP64_
1018 #if defined(BUILD_WOW6432)
1019             // 32-bit kernel32.dll on NT64 can run 64-bit binaries
1020 #if defined(_ALPHA_)
1021             if (ImageInformation.Machine == IMAGE_FILE_MACHINE_ALPHA) {
1022                // Fall through since this is a valid machine type.
1023                 }
1024              else
1025 #elif defined(_X86_)
1026             if (ImageInformation.Machine == IMAGE_FILE_MACHINE_I386) {
1027                // Fall through since this is a valid machine type.
1028                 }
1029              else
1030 #endif  // ALPHA or IA64
1031 #endif  // BUILD_WOW6432
1032                 {
1033                 ULONG_PTR ErrorParameters[2];
1034                 ULONG ErrorResponse;
1035 
1036                 ErrorResponse = ResponseOk;
1037                 ErrorParameters[0] = (ULONG_PTR)&PathName;
1038 
1039                 NtRaiseHardError( STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE,
1040                                   1,
1041                                   1,
1042                                   ErrorParameters,
1043                                   OptionOk,
1044                                   &ErrorResponse
1045                                 );
1046                 if ( NtCurrentPeb()->ImageSubsystemMajorVersion <= 3 ) {
1047                     SetLastError(ERROR_BAD_EXE_FORMAT);
1048                     }
1049                 else {
1050                     SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH);
1051                     }
1052                 RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
1053                 FreeBuffer = NULL;
1054                 return FALSE;
1055                 }
1056             }
1057 
1058         RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
1059         FreeBuffer = NULL;
1060         if ( ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI &&
1061              ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI ) {
1062 
1063             // POSIX exe
1064 
1065             NtClose(SectionHandle);
1066             SectionHandle = NULL;
1067 
1068             if ( ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_POSIX_CUI ) {
1069 
1070                 if ( !BuildSubSysCommandLine( L"POSIX /P ",
1071                                               lpApplicationName,
1072                                               lpCommandLine,
1073                                               &SubSysCommandLine
1074                                             ) ) {
1075                     return FALSE;
1076                 }
1077 
1078                 lpCommandLine = SubSysCommandLine.Buffer;
1079 
1080                 lpApplicationName = NULL;
1081                 RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer);
1082                 NameBuffer = NULL;
1083                 goto VdmRetry;
1084                 }
1085             else {
1086                 SetLastError(ERROR_CHILD_NOT_COMPLETE);
1087                 return FALSE;
1088                 }
1089             }
1090         else {
1091             if (!BasepIsImageVersionOk( ImageInformation.SubSystemMajorVersion,
1092                                         ImageInformation.SubSystemMinorVersion) ) {
1093                 SetLastError(ERROR_BAD_EXE_FORMAT);
1094                 return FALSE;
1095                 }
1096             }
1097 
1098         if (ImageFileDebuggerCommand[ 0 ] != UNICODE_NULL) {
1099             USHORT n;
1100 
1101             n = (USHORT)wcslen( lpCommandLine );
1102             if (n == 0) {
1103                 lpCommandLine = (LPWSTR)lpApplicationName;
1104                 n = (USHORT)wcslen( lpCommandLine );
1105                 }
1106 
1107             n += wcslen( ImageFileDebuggerCommand ) + 1 + 2;
1108             n *= sizeof( WCHAR );
1109 
1110             SubSysCommandLine.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), n );
1111             SubSysCommandLine.Length = 0;
1112             SubSysCommandLine.MaximumLength = n;
1113             RtlAppendUnicodeToString( &SubSysCommandLine, ImageFileDebuggerCommand );
1114             RtlAppendUnicodeToString( &SubSysCommandLine, L" " );
1115             RtlAppendUnicodeToString( &SubSysCommandLine, (PWSTR)lpCommandLine );
1116 #if DBG
1117             DbgPrint( "BASE: Calling debugger with '%wZ'\n", &SubSysCommandLine );
1118 #endif
1119             lpCommandLine = SubSysCommandLine.Buffer;
1120             lpApplicationName = NULL;
1121 
1122             NtClose(SectionHandle);
1123             SectionHandle = NULL;
1124             RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer);
1125             NameBuffer = NULL;
1126             goto VdmRetry;
1127             }
1128 
1129         //
1130         // Create the process object
1131         //
1132 
1133         pObja = BaseFormatObjectAttributes(&Obja,lpProcessAttributes,NULL);
1134 
1135         if (dwCreationFlags & CREATE_BREAKAWAY_FROM_JOB ) {
1136             SectionHandle = (HANDLE)( (UINT_PTR)SectionHandle | 1);
1137             }
1138 
1139         Status = NtCreateProcess(
1140                     &ProcessHandle,
1141                     PROCESS_ALL_ACCESS,
1142                     pObja,
1143                     NtCurrentProcess(),
1144                     (BOOLEAN)bInheritHandles,
1145                     SectionHandle,
1146                     NULL,
1147                     NULL
1148                     );
1149         if ( !NT_SUCCESS(Status) ) {
1150             BaseSetLastNTError(Status);
1151             return FALSE;
1152             }
1153 
1154         //
1155         // NtCreateProcess will set to normal OR inherit if parent is IDLE or Below
1156         // only override if a mask is given during the create.
1157         //
1158 
1159         if ( PriClass.PriorityClass != PROCESS_PRIORITY_CLASS_UNKNOWN ) {
1160             State = NULL;
1161             if ( PriClass.PriorityClass ==  PROCESS_PRIORITY_CLASS_REALTIME ) {
1162                 State = BasepIsRealtimeAllowed(TRUE);
1163                 }
1164             Status = NtSetInformationProcess(
1165                         ProcessHandle,
1166                         ProcessPriorityClass,
1167                         (PVOID)&PriClass,
1168                         sizeof(PriClass)
1169                         );
1170             if ( State ) {
1171                 BasepReleasePrivilege( State );
1172                 }
1173 
1174             if ( !NT_SUCCESS(Status) ) {
1175                 BaseSetLastNTError(Status);
1176                 return FALSE;
1177                 }
1178             }
1179 
1180         NtClose(SectionHandle);
1181         SectionHandle = NULL;
1182 
1183         if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE) {
1184             UINT NewMode;
1185             NewMode = SEM_FAILCRITICALERRORS;
1186             NtSetInformationProcess(
1187                 ProcessHandle,
1188                 ProcessDefaultHardErrorMode,
1189                 (PVOID) &NewMode,
1190                 sizeof(NewMode)
1191                 );
1192             }
1193 
1194         //
1195         // If the process is being created for a VDM call the server with
1196         // process handle.
1197         //
1198 
1199         if (VdmBinaryType) {
1200             VdmWaitHandle = ProcessHandle;
1201             if (!BaseUpdateVDMEntry(UPDATE_VDM_PROCESS_HANDLE,
1202                                     &VdmWaitHandle,
1203                                     iTask,
1204                                     VdmBinaryType
1205                                     ))
1206                {
1207                 //make sure we don't close the handle twice --
1208                 //(VdmWaitHandle == ProcessHandle) if we don't do this.
1209                 VdmWaitHandle = NULL;
1210                 return FALSE;
1211                 }
1212 
1213             //
1214             // For Sep wow the VdmWaitHandle = NULL (there is none!)
1215             //
1216 
1217             VDMCreationState |= VDM_FULLY_CREATED;
1218             }
1219 
1220         //
1221         // if we're a detached priority, we don't have the focus, so
1222         // don't create with boosted priority.
1223         //
1224 
1225         if (dwCreationFlags & DETACHED_PROCESS) {
1226             KPRIORITY SetBasePriority;
1227 
1228             SetBasePriority = (KPRIORITY)NORMAL_BASE_PRIORITY;
1229             Status =  NtSetInformationProcess(ProcessHandle,
1230                                               ProcessBasePriority,
1231                                               (PVOID) &SetBasePriority,
1232                                               sizeof(SetBasePriority)
1233                                               );
1234             ASSERT(NT_SUCCESS(Status));
1235         }
1236 
1237 #if defined(i386) || defined(_IA64_)
1238         //
1239         // Reserve memory in the new process' address space if necessary
1240         // (for vdms). This is required only for x86 system.
1241         //
1242 
1243     if ( VdmReserve ) {
1244             BigVdmReserve = VdmReserve;
1245             Status = NtAllocateVirtualMemory(
1246                         ProcessHandle,
1247                         &BaseAddress,
1248                         0L,
1249                         &BigVdmReserve,
1250                         MEM_RESERVE,
1251                         PAGE_EXECUTE_READWRITE
1252                         );
1253             if ( !NT_SUCCESS(Status) ){
1254                 BaseSetLastNTError(Status);
1255                 return FALSE;
1256             }
1257     }
1258 #endif
1259 
1260         //
1261         // Determine the location of the
1262         // processes PEB.
1263         //
1264 
1265         Status = NtQueryInformationProcess(
1266                     ProcessHandle,
1267                     ProcessBasicInformation,
1268                     &ProcessInfo,
1269                     sizeof( ProcessInfo ),
1270                     NULL
1271                     );
1272         if ( !NT_SUCCESS( Status ) ) {
1273             BaseSetLastNTError(Status);
1274             return FALSE;
1275             }
1276 
1277         Peb = ProcessInfo.PebBaseAddress;
1278 
1279         //
1280         // Push the parameters into the address space of the new process
1281         //
1282 
1283         if ( ARGUMENT_PRESENT(lpCurrentDirectory) ) {
1284             CurdirBuffer = RtlAllocateHeap( RtlProcessHeap(),
1285                                             MAKE_TAG( TMP_TAG ),
1286                                             (MAX_PATH + 1) * sizeof( WCHAR ) );
1287             if ( !CurdirBuffer ) {
1288                 BaseSetLastNTError(STATUS_NO_MEMORY);
1289                 return FALSE;
1290                 }
1291             CurdirLength2 = GetFullPathNameW(
1292                                 lpCurrentDirectory,
1293                                 MAX_PATH,
1294                                 CurdirBuffer,
1295                                 &CurdirFilePart
1296                                 );
1297             if ( CurdirLength2 > MAX_PATH ) {
1298                 SetLastError(ERROR_DIRECTORY);
1299                 return FALSE;
1300                 }
1301 
1302             //
1303             // now make sure the directory exists
1304             //
1305 
1306             CurdirLength = GetFileAttributesW(CurdirBuffer);
1307             if ( (CurdirLength == 0xffffffff) ||
1308                  !(CurdirLength & FILE_ATTRIBUTE_DIRECTORY) ) {
1309                 SetLastError(ERROR_DIRECTORY);
1310                 return FALSE;
1311                 }
1312             }
1313 
1314 
1315         if ( QuoteInsert || QuoteCmdLine) {
1316             QuotedBuffer = RtlAllocateHeap(RtlProcessHeap(),0,wcslen(lpCommandLine)*2+6);
1317 
1318             if ( QuotedBuffer ) {
1319                 wcscpy(QuotedBuffer,L"\"");
1320 
1321                 if ( QuoteInsert ) {
1322                     TempChar = *TempNull;
1323                     *TempNull = UNICODE_NULL;
1324                     }
1325 
1326                 wcscat(QuotedBuffer,lpCommandLine);
1327                 wcscat(QuotedBuffer,L"\"");
1328 
1329                 if ( QuoteInsert ) {
1330                     *TempNull = TempChar;
1331                     wcscat(QuotedBuffer,TempNull);
1332                     }
1333 
1334                 }
1335             else {
1336                 if ( QuoteInsert ) {
1337                     QuoteInsert = FALSE;
1338                     }
1339                 if ( QuoteCmdLine ) {
1340                     QuoteCmdLine = FALSE;
1341                     }
1342                 }
1343             }
1344 
1345 
1346         if (!BasePushProcessParameters(
1347                 ProcessHandle,
1348                 Peb,
1349                 lpApplicationName,
1350                 CurdirBuffer,
1351                 QuoteInsert || QuoteCmdLine ? QuotedBuffer : lpCommandLine,
1352                 lpEnvironment,
1353                 &StartupInfo,
1354                 dwCreationFlags | dwNoWindow,
1355                 bInheritHandles,
1356                 IsWowBinary ? IMAGE_SUBSYSTEM_WINDOWS_GUI : 0
1357                 ) ) {
1358             return FALSE;
1359             }
1360 
1361 
1362         RtlFreeUnicodeString(&VdmNameString);
1363         VdmNameString.Buffer = NULL;
1364 
1365         //
1366         // Stuff in the standard handles if needed
1367         //
1368         if (!VdmBinaryType &&
1369             !bInheritHandles &&
1370             !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
1371             !(dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE | CREATE_NO_WINDOW)) &&
1372             ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI
1373            ) {
1374             PRTL_USER_PROCESS_PARAMETERS ParametersInNewProcess;
1375 
1376             Status = NtReadVirtualMemory( ProcessHandle,
1377                                           &Peb->ProcessParameters,
1378                                           &ParametersInNewProcess,
1379                                           sizeof( ParametersInNewProcess ),
1380                                           NULL
1381                                         );
1382             if (NT_SUCCESS( Status )) {
1383                 if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardInput )) {
1384                     StuffStdHandle( ProcessHandle,
1385                                     NtCurrentPeb()->ProcessParameters->StandardInput,
1386                                     &ParametersInNewProcess->StandardInput
1387                                   );
1388                     }
1389                 if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardOutput )) {
1390                     StuffStdHandle( ProcessHandle,
1391                                     NtCurrentPeb()->ProcessParameters->StandardOutput,
1392                                     &ParametersInNewProcess->StandardOutput
1393                                   );
1394                     }
1395                 if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardError )) {
1396                     StuffStdHandle( ProcessHandle,
1397                                     NtCurrentPeb()->ProcessParameters->StandardError,
1398                                     &ParametersInNewProcess->StandardError
1399                                   );
1400                     }
1401                 }
1402             }
1403 
1404         //
1405         // Create the thread...
1406         //
1407 
1408         //
1409         // Allocate a stack for this thread in the address space of the target
1410         // process.
1411         //
1412 
1413         StackStatus = BaseCreateStack(
1414                         ProcessHandle,
1415                         ImageInformation.CommittedStackSize,
1416                         (ImageInformation.MaximumStackSize < 256*1024) ? 256*1024 : ImageInformation.MaximumStackSize,
1417                         &InitialTeb
1418                         );
1419 
1420         if ( !NT_SUCCESS(StackStatus) ) {
1421             BaseSetLastNTError(StackStatus);
1422             return FALSE;
1423             }
1424 
1425 
1426         //
1427         // Create an initial context for the new thread.
1428         //
1429 
1430         BaseInitializeContext(
1431             &ThreadContext,
1432             Peb,
1433             ImageInformation.TransferAddress,
1434             InitialTeb.StackBase,
1435             BaseContextTypeProcess
1436             );
1437 
1438 
1439         //
1440         // Create the actual thread object
1441         //
1442 
1443         pObja = BaseFormatObjectAttributes(&Obja,lpThreadAttributes,NULL);
1444 
1445         Status = NtCreateThread(
1446                     &ThreadHandle,
1447                     THREAD_ALL_ACCESS,
1448                     pObja,
1449                     ProcessHandle,
1450                     &ClientId,
1451                     &ThreadContext,
1452                     &InitialTeb,
1453                     TRUE
1454                     );
1455 
1456         if (!NT_SUCCESS(Status) ) {
1457             BaseSetLastNTError(Status);
1458             return FALSE;
1459             }
1460 
1461         //
1462         // From here on out, do not modify the address space of the
1463         // new process.  WOW64's implementation of NtCreateThread()
1464         // reshuffles the new process' address space if the current
1465         // process is 32-bit and the new process is 64-bit.
1466         //
1467 #if DBG
1468         Peb = NULL;
1469 #endif
1470 
1471 #if defined(WX86) || defined(_AXP64_)
1472 
1473         //
1474         // if this is a Wx86 Process, setup for a Wx86 emulated Thread
1475         //
1476 
1477         if (Wx86Info) {
1478 
1479             //
1480             // create a WX86Tib and initialize it's Teb->Vdm.
1481             //
1482             Status = BaseCreateWx86Tib(ProcessHandle,
1483                                        ThreadHandle,
1484                                        (ULONG)((ULONG_PTR)ImageInformation.TransferAddress),
1485                                        (ULONG)ImageInformation.CommittedStackSize,
1486                                        (ULONG)ImageInformation.MaximumStackSize,
1487                                        TRUE
1488                                        );
1489 
1490             if (!NT_SUCCESS(Status)) {
1491                 BaseSetLastNTError(Status);
1492                 return( FALSE );
1493                 }
1494 
1495 
1496             //
1497             // Mark Process as WX86
1498             //
1499             Status = NtSetInformationProcess (ProcessHandle,
1500                                               ProcessWx86Information,
1501                                               &Wx86Info,
1502                                               sizeof(Wx86Info)
1503                                               );
1504 
1505             if (!NT_SUCCESS(Status)) {
1506                 BaseSetLastNTError(Status);
1507                 return( FALSE );
1508                 }
1509             }
1510 #endif
1511 
1512 
1513         //
1514         // Call the Windows server to let it know about the
1515         // process.
1516         //
1517 
1518         a->ProcessHandle = ProcessHandle;
1519         a->ThreadHandle = ThreadHandle;
1520         a->ClientId = ClientId;
1521         a->CreationFlags = dwCreationFlags;
1522 
1523         if ( dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS) ) {
1524             Status = DbgUiConnectToDbg();
1525             if ( !NT_SUCCESS(Status) ) {
1526                 NtTerminateProcess(ProcessHandle, Status);
1527                 BaseSetLastNTError(Status);
1528                 return FALSE;
1529                 }
1530             a->DebuggerClientId = NtCurrentTeb()->ClientId;
1531             }
1532         else {
1533             a->DebuggerClientId.UniqueProcess = NULL;
1534             a->DebuggerClientId.UniqueThread = NULL;
1535             }
1536 
1537         //
1538         // Set the 2 bit if a gui app is starting. The window manager needs to
1539         // know this so it can synchronize the startup of this app
1540         // (WaitForInputIdle api). This info is passed using the process
1541         // handle tag bits.  The 1 bit asks the window manager to turn on
1542         // or turn off the application start cursor (hourglass/pointer).
1543         //
1544         // When starting a WOW process, lie and tell UserSrv NTVDM.EXE is a GUI
1545         // process.  We also turn on bit 0x8 so that UserSrv can ignore the
1546         // UserNotifyConsoleApplication call made by the console during startup.
1547         //
1548 
1549         if ( ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI ||
1550              IsWowBinary ) {
1551 
1552             a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle | 2);
1553 
1554             //
1555             // If the creating process is a GUI app, turn on the app. start cursor
1556             // by default.  This can be overridden by STARTF_FORCEOFFFEEDBACK.
1557             //
1558 
1559             NtHeaders = RtlImageNtHeader((PVOID)GetModuleHandle(NULL));
1560             if ( NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI )
1561                 a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle | 1);
1562 
1563             }
1564 
1565 
1566         //
1567         // If feedback is forced on, turn it on. If forced off, turn it off.
1568         // Off overrides on.
1569         //
1570 
1571         if (StartupInfo.dwFlags & STARTF_FORCEONFEEDBACK)
1572             a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle | 1);
1573         if (StartupInfo.dwFlags & STARTF_FORCEOFFFEEDBACK)
1574             a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle & ~1);
1575 
1576         a->VdmBinaryType = VdmBinaryType; // just tell server the truth
1577 
1578         if (VdmBinaryType){
1579            a->hVDM    = iTask ? 0 : NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1580            a->VdmTask = iTask;
1581         }
1582 
1583 #if defined(BUILD_WOW6432)
1584         m.ReturnValue = CsrBasepCreateProcess(a);
1585 #else
1586         CsrClientCallServer( (PCSR_API_MSG)&m,
1587                              NULL,
1588                              CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
1589                                                   BasepCreateProcess
1590                                                 ),
1591                              sizeof( *a )
1592                            );
1593 #endif
1594 
1595         if (!NT_SUCCESS((NTSTATUS)m.ReturnValue)) {
1596             BaseSetLastNTError((NTSTATUS)m.ReturnValue);
1597             NtTerminateProcess(ProcessHandle, (NTSTATUS)m.ReturnValue);
1598             return FALSE;
1599             }
1600 
1601 
1602         if (!( dwCreationFlags & CREATE_SUSPENDED) ) {
1603             NtResumeThread(ThreadHandle,&i);
1604             }
1605 
1606 VdmExists:
1607         bStatus = TRUE;
1608         if (VDMCreationState)
1609             VDMCreationState |= VDM_CREATION_SUCCESSFUL;
1610 
1611         try {
1612             if (VdmWaitHandle) {
1613 
1614                 //
1615                 // tag Shared WOW VDM handles so that wait for input idle has a
1616                 // chance to work.  Shared WOW VDM "process" handles are actually
1617                 // event handles,  Separate WOW VDM handles are real process
1618                 // handles. Also mark DOS handles with 0x1 so WaitForInputIdle
1619                 // has a way to distinguish DOS apps and not block forever.
1620                 //
1621 
1622                 if (VdmBinaryType == BINARY_TYPE_WIN16)  {
1623                     lpProcessInformation->hProcess =
1624                             (HANDLE)((ULONG_PTR)VdmWaitHandle | 0x2);
1625 
1626                     //
1627                     // Shared WOW doesn't always start a process, so
1628                     // we don't have a process ID or thread ID to
1629                     // return if the VDM already existed.
1630                     //
1631                     // Separate WOW doesn't hit this codepath
1632                     // (no VdmWaitHandle).
1633                     //
1634 
1635                     if (VDMCreationState & VDM_BEING_REUSED) {
1636                         ClientId.UniqueProcess = 0;
1637                         ClientId.UniqueThread = 0;
1638                         }
1639 
1640                     }
1641                 else  {
1642                     lpProcessInformation->hProcess =
1643                             (HANDLE)((ULONG_PTR)VdmWaitHandle | 0x1);
1644                     }
1645 
1646 
1647                 //
1648                 // Close the ProcessHandle, since we are returning the
1649                 // VdmProcessHandle instead.
1650                 //
1651 
1652                 if (ProcessHandle != NULL)
1653                     NtClose(ProcessHandle);
1654                 }
1655             else{
1656                 lpProcessInformation->hProcess = ProcessHandle;
1657                 }
1658 
1659             lpProcessInformation->hThread = ThreadHandle;
1660             lpProcessInformation->dwProcessId = HandleToUlong(ClientId.UniqueProcess);
1661             lpProcessInformation->dwThreadId = HandleToUlong(ClientId.UniqueThread);
1662             ProcessHandle = NULL;
1663             ThreadHandle = NULL;
1664             }
1665         except ( EXCEPTION_EXECUTE_HANDLER ) {
1666             NtClose( ProcessHandle );
1667             NtClose( ThreadHandle );
1668             ProcessHandle = NULL;
1669             ThreadHandle = NULL;
1670             if (VDMCreationState)
1671                 VDMCreationState &= ~VDM_CREATION_SUCCESSFUL;
1672             }
1673         }
1674     finally {
1675         if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) ) {
1676             RtlDestroyEnvironment(lpEnvironment);
1677             lpEnvironment = NULL;
1678             }
1679         RtlFreeHeap(RtlProcessHeap(), 0,QuotedBuffer);
1680         RtlFreeHeap(RtlProcessHeap(), 0,NameBuffer);
1681         RtlFreeHeap(RtlProcessHeap(), 0,CurdirBuffer);
1682         RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
1683         if ( FileHandle ) {
1684             NtClose(FileHandle);
1685             }
1686         if ( SectionHandle ) {
1687             NtClose(SectionHandle);
1688             }
1689         if ( ThreadHandle ) {
1690             NtTerminateProcess(ProcessHandle,STATUS_SUCCESS);
1691             NtClose(ThreadHandle);
1692             }
1693         if ( ProcessHandle ) {
1694             NtClose(ProcessHandle);
1695             }
1696         RtlFreeUnicodeString(&VdmNameString);
1697         RtlFreeUnicodeString(&SubSysCommandLine);
1698         if (AnsiStringVDMEnv.Buffer || UnicodeStringVDMEnv.Buffer)
1699             BaseDestroyVDMEnvironment(&AnsiStringVDMEnv, &UnicodeStringVDMEnv);
1700 
1701         if (VDMCreationState && !(VDMCreationState & VDM_CREATION_SUCCESSFUL)){
1702             BaseUpdateVDMEntry (
1703                 UPDATE_VDM_UNDO_CREATION,
1704                 (HANDLE *)&iTask,
1705                 VDMCreationState,
1706                 VdmBinaryType
1707                 );
1708             if(VdmWaitHandle) {
1709                 NtClose(VdmWaitHandle);
1710                 }
1711             }
1712         }
1713 
1714     if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) ) {
1715         RtlDestroyEnvironment(lpEnvironment);
1716         }
1717     return bStatus;
1718 }
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\ntos\ke\i386\thredini.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\ntos\ke\i386\thredini.c 文件)来设置的。

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

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

 

 

 

 

posted on 2017-08-21 17:47  沉疴  阅读(10331)  评论(1编辑  收藏  举报