进程创建过程详解 CreateProcess

来源:互联网 发布:php登录代码 编辑:程序博客网 时间:2024/06/14 07:34

转载请您注明出处:http://www.cnblogs.com/lsh123/p/7405796.html

0x01 CreateProcessW

  CreateProcess的使用有ANSI版本的CreateProcessA和UNICODE版本的CreateProcessW:

  不过查看源码就可以发现其实CreateProcessA内部调用的还是CreateProcessW:

BOOLWINAPICreateProcessA(    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的十个参数:

WINBASEAPIBOOLWINAPICreateProcessW(    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             else1006 #endif // WX861007 #if defined(_AXP64_)1008             if (ImageInformation.Machine == IMAGE_FILE_MACHINE_ALPHA) {1009                // Fall through since this is a valid machine type.1010                 }1011              else1012 #elif defined(_IA64_)1013             if (ImageInformation.Machine == IMAGE_FILE_MACHINE_I386) {1014                // Fall through since this is a valid machine type.1015                 }1016              else1017 #endif // _AXP64_1018 #if defined(BUILD_WOW6432)1019             // 32-bit kernel32.dll on NT64 can run 64-bit binaries1020 #if defined(_ALPHA_)1021             if (ImageInformation.Machine == IMAGE_FILE_MACHINE_ALPHA) {1022                // Fall through since this is a valid machine type.1023                 }1024              else1025 #elif defined(_X86_)1026             if (ImageInformation.Machine == IMAGE_FILE_MACHINE_I386) {1027                // Fall through since this is a valid machine type.1028                 }1029              else1030 #endif  // ALPHA or IA641031 #endif  // BUILD_WOW64321032                 {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                                   &ErrorResponse1045                                 );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 exe1064 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                                               &SubSysCommandLine1074                                             ) ) {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 DBG1117             DbgPrint( "BASE: Calling debugger with '%wZ'\n", &SubSysCommandLine );1118 #endif1119             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 object1131         //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                     NULL1148                     );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 Below1156         // 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 with1196         // process handle.1197         //1198 1199         if (VdmBinaryType) {1200             VdmWaitHandle = ProcessHandle;1201             if (!BaseUpdateVDMEntry(UPDATE_VDM_PROCESS_HANDLE,1202                                     &VdmWaitHandle,1203                                     iTask,1204                                     VdmBinaryType1205                                     ))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, so1222         // 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 necessary1240         // (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_READWRITE1252                         );1253             if ( !NT_SUCCESS(Status) ){1254                 BaseSetLastNTError(Status);1255                 return FALSE;1256             }1257     }1258 #endif1259 1260         //1261         // Determine the location of the1262         // processes PEB.1263         //1264 1265         Status = NtQueryInformationProcess(1266                     ProcessHandle,1267                     ProcessBasicInformation,1268                     &ProcessInfo,1269                     sizeof( ProcessInfo ),1270                     NULL1271                     );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 process1281         //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                                 &CurdirFilePart1296                                 );1297             if ( CurdirLength2 > MAX_PATH ) {1298                 SetLastError(ERROR_DIRECTORY);1299                 return FALSE;1300                 }1301 1302             //1303             // now make sure the directory exists1304             //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 : 01357                 ) ) {1358             return FALSE;1359             }1360 1361 1362         RtlFreeUnicodeString(&VdmNameString);1363         VdmNameString.Buffer = NULL;1364 1365         //1366         // Stuff in the standard handles if needed1367         //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_CUI1373            ) {1374             PRTL_USER_PROCESS_PARAMETERS ParametersInNewProcess;1375 1376             Status = NtReadVirtualMemory( ProcessHandle,1377                                           &Peb->ProcessParameters,1378                                           &ParametersInNewProcess,1379                                           sizeof( ParametersInNewProcess ),1380                                           NULL1381                                         );1382             if (NT_SUCCESS( Status )) {1383                 if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardInput )) {1384                     StuffStdHandle( ProcessHandle,1385                                     NtCurrentPeb()->ProcessParameters->StandardInput,1386                                     &ParametersInNewProcess->StandardInput1387                                   );1388                     }1389                 if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardOutput )) {1390                     StuffStdHandle( ProcessHandle,1391                                     NtCurrentPeb()->ProcessParameters->StandardOutput,1392                                     &ParametersInNewProcess->StandardOutput1393                                   );1394                     }1395                 if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardError )) {1396                     StuffStdHandle( ProcessHandle,1397                                     NtCurrentPeb()->ProcessParameters->StandardError,1398                                     &ParametersInNewProcess->StandardError1399                                   );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 target1410         // process.1411         //1412 1413         StackStatus = BaseCreateStack(1414                         ProcessHandle,1415                         ImageInformation.CommittedStackSize,1416                         (ImageInformation.MaximumStackSize < 256*1024) ? 256*1024 : ImageInformation.MaximumStackSize,1417                         &InitialTeb1418                         );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             BaseContextTypeProcess1436             );1437 1438 1439         //1440         // Create the actual thread object1441         //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                     TRUE1454                     );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 the1463         // new process.  WOW64's implementation of NtCreateThread()1464         // reshuffles the new process' address space if the current1465         // process is 32-bit and the new process is 64-bit.1466         //1467 #if DBG1468         Peb = NULL;1469 #endif1470 1471 #if defined(WX86) || defined(_AXP64_)1472 1473         //1474         // if this is a Wx86 Process, setup for a Wx86 emulated Thread1475         //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                                        TRUE1488                                        );1489 1490             if (!NT_SUCCESS(Status)) {1491                 BaseSetLastNTError(Status);1492                 return( FALSE );1493                 }1494 1495 1496             //1497             // Mark Process as WX861498             //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 #endif1511 1512 1513         //1514         // Call the Windows server to let it know about the1515         // 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 to1539         // know this so it can synchronize the startup of this app1540         // (WaitForInputIdle api). This info is passed using the process1541         // handle tag bits.  The 1 bit asks the window manager to turn on1542         // or turn off the application start cursor (hourglass/pointer).1543         //1544         // When starting a WOW process, lie and tell UserSrv NTVDM.EXE is a GUI1545         // process.  We also turn on bit 0x8 so that UserSrv can ignore the1546         // 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 cursor1556             // 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 truth1577 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 #else1586         CsrClientCallServer( (PCSR_API_MSG)&m,1587                              NULL,1588                              CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,1589                                                   BasepCreateProcess1590                                                 ),1591                              sizeof( *a )1592                            );1593 #endif1594 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 a1616                 // chance to work.  Shared WOW VDM "process" handles are actually1617                 // event handles,  Separate WOW VDM handles are real process1618                 // handles. Also mark DOS handles with 0x1 so WaitForInputIdle1619                 // 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, so1628                     // we don't have a process ID or thread ID to1629                     // return if the VDM already existed.1630                     //1631                     // Separate WOW doesn't hit this codepath1632                     // (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 the1649                 // 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                 VdmBinaryType1707                 );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函数:

NTSTATUSNtCreateProcess(    __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);}NTSTATUSNtCreateProcessEx(    __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函数。

  

NTSTATUSPspCreateProcess(    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函数的线程创建了:

NTSTATUSNtCreateThread(    __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

NTSTATUSPspCreateThread(    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()在用户空间完成

原创粉丝点击