进程创建过程详解 CreateProcess

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

0x01 CreateProcessW

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

进程创建过程详解 CreateProcess_第1张图片

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

BOOL

WINAPI

CreateProcessA(

    LPCSTR lpApplicationName,

    LPSTR lpCommandLine,

    LPSECURITY_ATTRIBUTES lpProcessAttributes,

    LPSECURITY_ATTRIBUTES lpThreadAttributes,

    BOOL bInheritHandles,

    DWORD dwCreationFlags,

    LPVOID lpEnvironment,

    LPCSTR lpCurrentDirectory,

    LPSTARTUPINFOA lpStartupInfo,

    LPPROCESS_INFORMATION lpProcessInformation

    )

 

/*++

 

    ANSI thunk to CreateProcessW

 

--*/

 

{

    NTSTATUS Status;

    PUNICODE_STRING CommandLine;

    UNICODE_STRING ApplicationName;

    UNICODE_STRING CurrentDirectory;

    STARTUPINFOW StartupInfo;

    ANSI_STRING AnsiString;

    UNICODE_STRING Unicode;

    UNICODE_STRING DynamicCommandLine;

    UNICODE_STRING NullUnicodeString;

    BOOL ReturnStatus;

 

    if (ARGUMENT_PRESENT (lpCommandLine)) {

        if ( (strlen( lpCommandLine ) + 1) * sizeofWCHAR ) <

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

WINBASEAPI

BOOL

WINAPI

CreateProcessW(

    LPCWSTR lpApplicationName,    //指向一个NULL结尾的,新进程的可执行文件的名称

    LPWSTR lpCommandLine,          //指向一个NULL结尾的,传给新进程的命令行字符串

    LPSECURITY_ATTRIBUTES lpProcessAttributes,

    //指向一个SECURITY_ATTRIBUTES结构体,分配给新的进程对象

    //SECURITY_ATTRIBUTES结构可以决定是否返回的句柄可以被子进程继承(bInheritHandle )。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。

    //SECURITY_ATTRIBUTES结构的lpSecurityDescriptor成员可以指定新进程的安全描述符,如果参数为空,新进程使用默认的安全描述符。

    LPSECURITY_ATTRIBUTES lpThreadAttributes,

    //指向一个SECURITY_ATTRIBUTES结构体,分配给新的线程对象

    BOOL bInheritHandles,

    //标识新进程是否可以从调用进程处继承所有可继承的句柄。被继承的句柄与原进程拥有完全相同的值和访问权限。

    DWORD dwCreationFlags,

    //标识了影响新进程创建方式的标志,多个标志按位或进行组合

    LPVOID lpEnvironment,

    //指向一块内存,其中包含新进程要使用的环境字符串。如果此参数为空,新进程继承父进程的一组环境字符串。

    LPCWSTR lpCurrentDirectory,

    //指向一个以NULL结尾的字符串,用来设置新进程的当前驱动器和目录,这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与父进程相同的驱动器和目录。

    LPSTARTUPINFOW lpStartupInfo,

    //指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。

    LPPROCESS_INFORMATION lpProcessInformation

    //指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。

    );

  (1)STARTUPINFO 和 PROCESS_INFORMATION的使用前初始化为空:

  STARTUPINFO StartupInfo = { 0 };
  StartupInfo.cb = sizeof(STARTUPINFO);
  PROCESS_INFORMATION ProcessInfo = { 0 };

 

  (2)第六参数:dwCreationFlags 的部分标志:

  ⑴值:CREATE_DEFAULT_ERROR_MODE

  含义:新的进程不继承调用进程的错误模式。CreateProcess函数赋予新进程当前的默认错误模式作为替代。应用程序可以调用SetErrorMode函数设置当前的默认错误模式。

  这个标志对于那些运行在没有硬件错误环境下的多线程外壳程序是十分有用的。

  对于CreateProcess函数,默认的行为是为新进程继承调用者的错误模式。设置这个标志以改变默认的处理方式。

 

  ⑵值:CREATE_NEW_CONSOLE

  含义:新的进程将使用一个新的控制台,而不是继承父进程的控制台。这个标志不能与DETACHED_PROCESS标志一起使用。

 

  ⑶值:CREATE_NEW_PROCESS_GROUP

  含义:新进程将是一个进程树的根进程。进程树中的全部进程都是根进程的子进程。新进程树的用户标识符与这个进程的标识符是相同的,由lpProcessInformation参数返回。进程树经常使用GenerateConsoleCtrlEvent函数允许发送CTRL+C或   CTRL+BREAK信号到一组控制台进程。

 

  ⑷值:CREATE_SEPARATE_WOW_VDM

  如果被设置,新进程将会在一个私有的虚拟DOS机(VDM)中运行。另外,默认情况下所有的16位Windows应用程序都会在同一个共享的VDM中以线程的方式运行。单独运行一个16位程序的优点是一个应用程序的崩溃只会结束这一个VDM的运行;其他那些在不同VDM中运行的程序会继续正常的运行。同样的,在不同VDM中运行的16位Windows应用程序拥有不同的输入队列,这意味着如果一个程序暂时失去响应,在独立的VDM中的应用程序能够继续获得输入。

 

  ⑸值:CREATE_SHARED_WOW_VDM

如果WIN.INI中的Windows段的DefaultSeparateVDM选项被设置为真,这个标识使得CreateProcess函数越过这个选项并在共享的虚拟DOS机中运行新进程。

 

  ⑹值:CREATE_SUSPENDED

  含义:新进程的主线程会以挂起的状态被创建,直到调用ResumeThread函数被调用时才运行。

 

  ⑺值:CREATE_UNICODE_ENVIRONMENT

  含义:如果被设置,由lpEnvironment参数指定环境块使用Unicode字符,如果为空,环境块默认使用ANSI字符。

 

  ⑻值:DEBUG_PROCESS

  含义:如果这个标志被设置,调用进程将被当做一个调试程序,并且新进程会被当做被调试的进程。系统把被调试程序发生的所有调试事件通知给调试器。

  如果你使用这个标志创建进程,只有调用进程(调用CreateProcess函数的进程)可以调用WaitForDebugEvent函数。

 

  ⑼值:DEBUG_ONLY_THIS_PROCESS

  含义:如果此标志没有被设置且调用进程正在被调试,新进程将成为调试调用进程的调试器的另一个调试对象。如果调用进程没有被调试,有关调试的行为就不会产生。

 

  ⑽值:DETACHED_PROCESS

  含义:对于控制台进程,新进程没有访问父进程控制台的权限。新进程可以通过AllocConsole函数自己创建一个新的控制台。这个标志不可以与CREATE_NEW_CONSOLE标志一起使用。

 

  〔11〕值:CREATE_NO_WINDOW

  含义:系统不为新进程创建CUI窗口,使用该标志可以创建不含窗口的CUI程序。

 

 

 

 

 

 

 

 

 

 

0x02  创建进程详细步骤1:打开目标映像文件,创建进程对象,线程对象

    

   CreateProcessW源代码(windows2000)

   

 CreateProcessW

 

  暂且忽略掉之前的一些环境字符串等等相关操作,注意到第一个值得关注的函数:NtOpenFile()打开其目标文件获取到了文件句柄FIileHandle

 

  

1

2

3

4

5

6

7

8

9

10

11

12

//

// 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文件映射区,将文件内容映射进来

1

2

3

4

5

6

7

8

9

10

11

12

13

//

// Create a section object backed by the file

//

 

Status = NtCreateSection(

            &SectionHandle,

            SECTION_ALL_ACCESS,

            NULL,

            NULL,

            PAGE_EXECUTE,

            SEC_IMAGE,

            FileHandle

            );

  

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

1

2

3

4

5

6

7

8

9

10

Status = NtCreateProcess(

            &ProcessHandle,

            PROCESS_ALL_ACCESS,

            pObja,

            NtCurrentProcess(),

            (BOOLEAN)bInheritHandles,

            SectionHandle,

            NULL,

            NULL

            );

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

 

  NtCreateProcess函数和NtCreateProcessEx函数:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

NTSTATUS

NtCreateProcess(

    __out PHANDLE ProcessHandle,

    __in ACCESS_MASK DesiredAccess,

    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,

    __in HANDLE ParentProcess,

    __in BOOLEAN InheritObjectTable,

    __in_opt HANDLE SectionHandle,

    __in_opt HANDLE DebugPort,

    __in_opt HANDLE ExceptionPort

    )

{

    ULONG Flags = 0;

 

    if ((ULONG_PTR)SectionHandle & 1) {

        Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY;

    }

 

    if ((ULONG_PTR) DebugPort & 1) {

        Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT;

    }

 

    if (InheritObjectTable) {

        Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;

    }

 

    return NtCreateProcessEx (ProcessHandle,

                              DesiredAccess,

                              ObjectAttributes OPTIONAL,

                              ParentProcess,

                              Flags,

                              SectionHandle,

                              DebugPort,

                              ExceptionPort,

                              0);

}

 

NTSTATUS

NtCreateProcessEx(

    __out PHANDLE ProcessHandle,

    __in ACCESS_MASK DesiredAccess,

    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,

    __in HANDLE ParentProcess,

    __in ULONG Flags,

    __in_opt HANDLE SectionHandle,

    __in_opt HANDLE DebugPort,

    __in_opt HANDLE ExceptionPort,

    __in ULONG JobMemberLevel

    )

 

 

 

{

    NTSTATUS Status;

 

    PAGED_CODE();

 

    if (KeGetPreviousMode() != KernelMode) {

 

        //

        // Probe all arguments

        //

 

        try {

            ProbeForWriteHandle (ProcessHandle);

        } except (EXCEPTION_EXECUTE_HANDLER) {

            return GetExceptionCode ();

        }

    }

 

    if (ARGUMENT_PRESENT (ParentProcess)) {

        Status = PspCreateProcess (ProcessHandle,

                                   DesiredAccess,

                                   ObjectAttributes,

                                   ParentProcess,

                                   Flags,

                                   SectionHandle,

                                   DebugPort,

                                   ExceptionPort,

                                   JobMemberLevel);

    else {

        Status = STATUS_INVALID_PARAMETER;

    }

 

    return Status;

}

  

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

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

  

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546

547

548

549

550

551

552

553

554

555

556

557

558

559

560

561

562

563

564

565

566

567

568

569

570

571

572

573

574

575

576

577

578

579

580

581

582

583

584

585

586

587

588

589

590

591

592

593

594

595

596

597

598

599

600

601

602

603

604

605

606

607

608

609

610

611

612

613

614

615

616

617

618

619

620

621

622

623

624

625

626

627

628

629

630

631

632

633

634

635

636

637

638

639

640

641

642

643

644

645

646

647

648

649

650

651

652

653

654

655

656

657

658

659

660

661

662

663

664

665

666

667

668

669

670

671

672

673

674

675

676

677

678

679

680

681

682

683

684

685

686

687

688

689

690

691

692

693

694

695

696

697

698

699

700

701

702

703

704

705

706

707

708

709

710

711

712

713

714

715

716

717

718

719

720

721

722

723

724

725

726

727

728

729

730

731

732

733

734

735

736

737

738

739

740

741

742

743

744

745

746

747

748

749

750

751

752

753

754

755

756

757

758

759

760

761

762

763

764

765

NTSTATUS

PspCreateProcess(

    OUT PHANDLE ProcessHandle,

    IN ACCESS_MASK DesiredAccess,

    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,

    IN HANDLE ParentProcess OPTIONAL,

    IN ULONG Flags,

    IN HANDLE SectionHandle OPTIONAL,

    IN HANDLE DebugPort OPTIONAL,

    IN HANDLE ExceptionPort OPTIONAL,

    IN ULONG JobMemberLevel

    )

/*++

 

Routine Description:

 

    This routine creates and initializes a process object.  It implements the

    foundation for NtCreateProcess and for system initialization process

    creation.

 

--*/

 

{

 

    NTSTATUS Status;

    PEPROCESS Process;

    PEPROCESS CurrentProcess;

    PEPROCESS Parent;

    PETHREAD CurrentThread;

    KAFFINITY Affinity;

    KPRIORITY BasePriority;

    PVOID SectionObject;

    PVOID ExceptionPortObject;

    PVOID DebugPortObject;

    ULONG WorkingSetMinimum, WorkingSetMaximum;

    HANDLE LocalProcessHandle;

    KPROCESSOR_MODE PreviousMode;

    INITIAL_PEB InitialPeb;

    BOOLEAN CreatePeb;

    ULONG_PTR DirectoryTableBase[2];

    BOOLEAN AccessCheck;

    BOOLEAN MemoryAllocated;

    PSECURITY_DESCRIPTOR SecurityDescriptor;

    SECURITY_SUBJECT_CONTEXT SubjectContext;

    NTSTATUS accesst;

    NTSTATUS SavedStatus;

    ULONG ImageFileNameSize;

    HANDLE_TABLE_ENTRY CidEntry;

    PEJOB Job;

    PPEB Peb;

    AUX_ACCESS_DATA AuxData;

    PACCESS_STATE AccessState;

    ACCESS_STATE LocalAccessState;

    BOOLEAN UseLargePages;

    SCHAR QuantumReset;

#if defined(_WIN64)

    INITIAL_PEB32 InitialPeb32;

#endif

 

    PAGED_CODE();

 

    CurrentThread = PsGetCurrentThread ();

    PreviousMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);

    CurrentProcess = PsGetCurrentProcessByThread (CurrentThread);

 

    CreatePeb = FALSE;

    UseLargePages = FALSE;

    DirectoryTableBase[0] = 0;

    DirectoryTableBase[1] = 0;

    Peb = NULL;

     

    //

    // Reject bogus create parameters for future expansion

    //

    if (Flags&~PROCESS_CREATE_FLAGS_LEGAL_MASK) {

        return STATUS_INVALID_PARAMETER;

    }

 

    //

    // Parent

    //

 

    if (ARGUMENT_PRESENT (ParentProcess)) {

        Status = ObReferenceObjectByHandle (ParentProcess,

                                            PROCESS_CREATE_PROCESS,

                                            PsProcessType,

                                            PreviousMode,

                                            &Parent,

                                            NULL);

        if (!NT_SUCCESS (Status)) {

            return Status;

        }

 

        if (JobMemberLevel != 0 && Parent->Job == NULL) {

            ObDereferenceObject (Parent);

            return STATUS_INVALID_PARAMETER;

        }

 

        Affinity = Parent->Pcb.Affinity;

        WorkingSetMinimum = PsMinimumWorkingSet;

        WorkingSetMaximum = PsMaximumWorkingSet;

 

 

    else {

 

        Parent = NULL;

        Affinity = KeActiveProcessors;

        WorkingSetMinimum = PsMinimumWorkingSet;

        WorkingSetMaximum = PsMaximumWorkingSet;

    }

 

    //

    // Create the process object

    //

    Status = ObCreateObject (PreviousMode,

                             PsProcessType,

                             ObjectAttributes,

                             PreviousMode,

                             NULL,

                             sizeof (EPROCESS),

                             0,

                             0,

                             &Process);

 

    if (!NT_SUCCESS (Status)) {

        goto exit_and_deref_parent;

    }

 

    //

    // The process object is created set to NULL. Errors

    // That occur after this step cause the process delete

    // routine to be entered.

    //

    // Teardown actions that occur in the process delete routine

    // do not need to be performed inline.

    //

 

    RtlZeroMemory (Process, sizeof(EPROCESS));

    ExInitializeRundownProtection (&Process->RundownProtect);

    PspInitializeProcessLock (Process);

    InitializeListHead (&Process->ThreadListHead);

 

#if defined(_WIN64)

 

    if (Flags & PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE) {

        PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_OVERRIDE_ADDRESS_SPACE);

    }

 

#endif

 

    PspInheritQuota (Process, Parent);

    ObInheritDeviceMap (Process, Parent);

    if (Parent != NULL) {

        Process->DefaultHardErrorProcessing = Parent->DefaultHardErrorProcessing;

        Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId;

 

    else {

        Process->DefaultHardErrorProcessing = PROCESS_HARDERROR_DEFAULT;

        Process->InheritedFromUniqueProcessId = NULL;

    }

 

    //

    // Section

    //

 

    if (ARGUMENT_PRESENT (SectionHandle)) {

        Status = ObReferenceObjectByHandle (SectionHandle,

                                            SECTION_MAP_EXECUTE,

                                            MmSectionObjectType,

                                            PreviousMode,

                                            &SectionObject,

                                            NULL);

        if (!NT_SUCCESS (Status)) {

            goto exit_and_deref;

        }

 

    else {

        SectionObject = NULL;

        if (Parent != PsInitialSystemProcess) {

 

            //

            // Fetch the section pointer from the parent process

            // as we will be cloning. Since the section pointer

            // is removed at last thread exit we need to protect against

            // process exit here to be safe.

            //

 

            if (ExAcquireRundownProtection (&Parent->RundownProtect)) {

                SectionObject = Parent->SectionObject;

                if (SectionObject != NULL) {

                    ObReferenceObject (SectionObject);

                }

 

                ExReleaseRundownProtection (&Parent->RundownProtect);

            }

 

            if (SectionObject == NULL) {

                Status = STATUS_PROCESS_IS_TERMINATING;

                goto exit_and_deref;

            }

        }

    }

 

    Process->SectionObject = SectionObject;

 

    //

    // DebugPort

    //

 

    if (ARGUMENT_PRESENT (DebugPort)) {

        Status = ObReferenceObjectByHandle (DebugPort,

                                            DEBUG_PROCESS_ASSIGN,

                                            DbgkDebugObjectType,

                                            PreviousMode,

                                            &DebugPortObject,

                                            NULL);

 

        if (!NT_SUCCESS (Status)) {

            goto exit_and_deref;

        }

 

        Process->DebugPort = DebugPortObject;

        if (Flags&PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT) {

            PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_NO_DEBUG_INHERIT);

        }

 

    else {

        if (Parent != NULL) {

            DbgkCopyProcessDebugPort (Process, Parent);

        }

    }

 

    //

    // ExceptionPort

    //

 

    if (ARGUMENT_PRESENT (ExceptionPort)) {

        Status = ObReferenceObjectByHandle (ExceptionPort,

                                            0,

                                            LpcPortObjectType,

                                            PreviousMode,

                                            &ExceptionPortObject,

                                            NULL);

 

        if (!NT_SUCCESS (Status)) {

            goto exit_and_deref;

        }

 

        Process->ExceptionPort = ExceptionPortObject;

    }

 

    Process->ExitStatus = STATUS_PENDING;

 

    //

    // Clone parent's object table.

    // If no parent (booting) then use the current object table created in

    // ObInitSystem.

    //

 

    if (Parent != NULL) {

 

        //

        // Calculate address space

        //

        //      If Parent == PspInitialSystem

        //

 

        if (!MmCreateProcessAddressSpace (WorkingSetMinimum,

                                          Process,

                                          &DirectoryTableBase[0])) {

 

            Status = STATUS_INSUFFICIENT_RESOURCES;

            goto exit_and_deref;

        }

 

    else {

        Process->ObjectTable = CurrentProcess->ObjectTable;

 

        //

        // Initialize the Working Set Mutex and address creation mutex

        // for this "hand built" process.

        // Normally, the call to MmInitializeAddressSpace initializes the

        // working set mutex, however, in this case, we have already initialized

        // the address space and we are now creating a second process using

        // the address space of the idle thread.

        //

 

        Status = MmInitializeHandBuiltProcess (Process, &DirectoryTableBase[0]);

        if (!NT_SUCCESS (Status)) {

            goto exit_and_deref;

        }

    }

 

    PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_HAS_ADDRESS_SPACE);

    Process->Vm.MaximumWorkingSetSize = WorkingSetMaximum;

    KeInitializeProcess (&Process->Pcb,

                         NORMAL_BASE_PRIORITY,

                         Affinity,

                         &DirectoryTableBase[0],

                         (BOOLEAN)(Process->DefaultHardErrorProcessing & PROCESS_HARDERROR_ALIGNMENT_BIT));

 

    //

    //  Initialize the security fields of the process

    //  The parent may be null exactly once (during system init).

    //  Thereafter, a parent is always required so that we have a

    //  security context to duplicate for the new process.

    //

 

    Status = PspInitializeProcessSecurity (Parent, Process);

    if (!NT_SUCCESS (Status)) {

        goto exit_and_deref;

    }

 

    Process->PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;

    if (Parent != NULL) {

        if (Parent->PriorityClass == PROCESS_PRIORITY_CLASS_IDLE ||

            Parent->PriorityClass == PROCESS_PRIORITY_CLASS_BELOW_NORMAL) {

            Process->PriorityClass = Parent->PriorityClass;

        }

 

        //

        // if address space creation worked, then when going through

        // delete, we will attach. Of course, attaching means that the kprocess

        // must be initialized, so we delay the object stuff till here.

        //

 

        Status = ObInitProcess ((Flags&PROCESS_CREATE_FLAGS_INHERIT_HANDLES) ? Parent : NULL,

                                Process);

 

        if (!NT_SUCCESS (Status)) {

            goto exit_and_deref;

        }

 

    else {

        Status = MmInitializeHandBuiltProcess2 (Process);

        if (!NT_SUCCESS (Status)) {

            goto exit_and_deref;

        }

    }

 

    Status = STATUS_SUCCESS;

    SavedStatus = STATUS_SUCCESS;

 

    //

    // Initialize the process address space

    // The address space has four possibilities

    //

    //      1 - Boot Process. Address space is initialized during

    //          MmInit. Parent is not specified.

    //

    //      2 - System Process. Address space is a virgin address

    //          space that only maps system space. Process is same

    //          as PspInitialSystemProcess.

    //

    //      3 - User Process (Cloned Address Space). Address space

    //          is cloned from the specified process.

    //

    //      4 - User Process (New Image Address Space). Address space

    //          is initialized so that it maps the specified section.

    //

 

    if (SectionHandle != NULL) {

 

        //

        // User Process (New Image Address Space). Don't specify Process to

        // clone, just SectionObject.

        //

        // Passing in the 4th parameter as below lets the EPROCESS struct contain its image file name, provided that

        // appropriate audit settings are enabled.  Memory is allocated inside of MmInitializeProcessAddressSpace

        // and pointed to by ImageFileName, so that must be freed in the process deletion routine (PspDeleteProcess())

        //

 

        Status = MmInitializeProcessAddressSpace (Process,

                                                  NULL,

                                                  SectionObject,

                                                  &Flags,

                                                  &(Process->SeAuditProcessCreationInfo.ImageFileName));

 

        if (!NT_SUCCESS (Status)) {

            goto exit_and_deref;

        }

 

        //

        // In order to support relocating executables, the proper status

        // (STATUS_IMAGE_NOT_AT_BASE) must be returned, so save it here.

        //

 

        SavedStatus = Status;

        CreatePeb = TRUE;

        UseLargePages = ((Flags & PROCESS_CREATE_FLAGS_LARGE_PAGES) != 0 ? TRUE : FALSE);

 

    else if (Parent != NULL) {

        if (Parent != PsInitialSystemProcess) {

            Process->SectionBaseAddress = Parent->SectionBaseAddress;

 

            //

            // User Process ( Cloned Address Space ).  Don't specify section to

            // map, just Process to clone.

            //

 

            Status = MmInitializeProcessAddressSpace (Process,

                                                      Parent,

                                                      NULL,

                                                      &Flags,

                                                      NULL);

 

            if (!NT_SUCCESS (Status)) {

                goto exit_and_deref;

            }

 

            CreatePeb = TRUE;

            UseLargePages = ((Flags & PROCESS_CREATE_FLAGS_LARGE_PAGES) != 0 ? TRUE : FALSE);

             

            //

            // A cloned process isn't started from an image file, so we give it the name

            // of the process of which it is a clone, provided the original has a name.

            //

 

            if (Parent->SeAuditProcessCreationInfo.ImageFileName != NULL) {

                ImageFileNameSize = sizeof(OBJECT_NAME_INFORMATION) +

                                    Parent->SeAuditProcessCreationInfo.ImageFileName->Name.MaximumLength;

 

                Process->SeAuditProcessCreationInfo.ImageFileName =

                    ExAllocatePoolWithTag (PagedPool,

                                           ImageFileNameSize,

                                           'aPeS');

 

                if (Process->SeAuditProcessCreationInfo.ImageFileName != NULL) {

                    RtlCopyMemory (Process->SeAuditProcessCreationInfo.ImageFileName,

                                   Parent->SeAuditProcessCreationInfo.ImageFileName,

                                   ImageFileNameSize);

 

                    //

                    // The UNICODE_STRING in the process is self contained, so calculate the

                    // offset for the buffer.

                    //

 

                    Process->SeAuditProcessCreationInfo.ImageFileName->Name.Buffer =

                        (PUSHORT)(((PUCHAR) Process->SeAuditProcessCreationInfo.ImageFileName) +

                        sizeof(UNICODE_STRING));

 

                else {

                    Status = STATUS_INSUFFICIENT_RESOURCES;

                    goto exit_and_deref;

                }

            }

 

        else {

 

            //

            // System Process.  Don't specify Process to clone or section to map

            //

 

            Flags &= ~PROCESS_CREATE_FLAGS_ALL_LARGE_PAGE_FLAGS;

            Status = MmInitializeProcessAddressSpace (Process,

                                                      NULL,

                                                      NULL,

                                                      &Flags,

                                                      NULL);

 

            if (!NT_SUCCESS (Status)) {

                goto exit_and_deref;

            }

 

            //

            // In case the image file name of this system process is ever queried, we give

            // a zero length UNICODE_STRING.

            //

 

            Process->SeAuditProcessCreationInfo.ImageFileName =

                ExAllocatePoolWithTag (PagedPool,

                                       sizeof(OBJECT_NAME_INFORMATION),

                                       'aPeS');

 

            if (Process->SeAuditProcessCreationInfo.ImageFileName != NULL) {

                RtlZeroMemory (Process->SeAuditProcessCreationInfo.ImageFileName,

                               sizeof(OBJECT_NAME_INFORMATION));

            else {

                Status = STATUS_INSUFFICIENT_RESOURCES;

                goto exit_and_deref;

            }

        }

    }

 

    //

    // Create the process ID

    //

 

    CidEntry.Object = Process;

    CidEntry.GrantedAccess = 0;

    Process->UniqueProcessId = ExCreateHandle (PspCidTable, &CidEntry);

    if (Process->UniqueProcessId == NULL) {

        Status = STATUS_INSUFFICIENT_RESOURCES;

        goto exit_and_deref;

    }

 

    ExSetHandleTableOwner (Process->ObjectTable, Process->UniqueProcessId);

 

    //

    // Audit the process creation.

    //

 

    if (SeDetailedAuditingWithToken (NULL)) {

        SeAuditProcessCreation (Process);

    }

 

    //

    // See if the parent has a job. If so reference the job

    // and add the process in.

    //

 

    if (Parent) {

        Job = Parent->Job;

        if (Job != NULL && !(Job->LimitFlags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)) {

            if (Flags&PROCESS_CREATE_FLAGS_BREAKAWAY) {

                if (!(Job->LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK)) {

                    Status = STATUS_ACCESS_DENIED;

 

                else {

                    Status = STATUS_SUCCESS;

                }

 

            else {

                Status = PspGetJobFromSet (Job, JobMemberLevel, &Process->Job);

                if (NT_SUCCESS (Status)) {

                    PACCESS_TOKEN Token, NewToken;

                    Job = Process->Job;

                    Status = PspAddProcessToJob (Job, Process);

 

                    //

                    // Duplicate a new process token if one is specified for the job

                    //

 

                    Token = Job->Token;

                    if (Token != NULL) {

                        Status = SeSubProcessToken (Token,

                                                    &NewToken,

                                                    FALSE,

                                                    Job->SessionId);

 

                        if (!NT_SUCCESS (Status)) {

                            goto exit_and_deref;

                        }

 

                        SeAssignPrimaryToken (Process, NewToken);   

                        ObDereferenceObject (NewToken);                   

                    }

                }

            }

 

            if (!NT_SUCCESS (Status)) {

                goto exit_and_deref;

            }

        }

    }

 

    if (Parent && CreatePeb) {

 

        //

        // For processes created w/ a section,

        // a new "virgin" PEB is created. Otherwise,

        // for forked processes, uses inherited PEB

        // with an updated mutant.

        //

 

        RtlZeroMemory (&InitialPeb, FIELD_OFFSET(INITIAL_PEB, Mutant));

 

        InitialPeb.Mutant = (HANDLE)(-1);

        InitialPeb.ImageUsesLargePages = (BOOLEAN) UseLargePages;

             

        if (SectionHandle != NULL) {

            Status = MmCreatePeb (Process, &InitialPeb, &Process->Peb);

            if (!NT_SUCCESS (Status)) {

                Process->Peb = NULL;

                goto exit_and_deref;

            }

 

            Peb =  Process->Peb;

 

        else {

            SIZE_T BytesCopied;

 

            InitialPeb.InheritedAddressSpace = TRUE;

            Process->Peb = Parent->Peb;

            MmCopyVirtualMemory (CurrentProcess,

                                 &InitialPeb,

                                 Process,

                                 Process->Peb,

                                 sizeof (INITIAL_PEB),

                                 KernelMode,

                                 &BytesCopied);

 

#if defined(_WIN64)

            if (Process->Wow64Process != NULL) {

                 

                RtlZeroMemory (&InitialPeb32, FIELD_OFFSET(INITIAL_PEB32, Mutant));

                InitialPeb32.Mutant = -1;

                InitialPeb32.InheritedAddressSpace = TRUE;

                InitialPeb32.ImageUsesLargePages = (BOOLEAN) UseLargePages;

 

                MmCopyVirtualMemory (CurrentProcess,

                                     &InitialPeb32,

                                     Process,

                                     Process->Wow64Process->Wow64,

                                     sizeof (INITIAL_PEB32),

                                     KernelMode,

                                     &BytesCopied);

            }

#endif

 

        }

    }

 

    Peb = Process->Peb;

 

    //

    // Add the process to the global list of processes.

    //

 

    PspLockProcessList (CurrentThread);

    InsertTailList (&PsActiveProcessHead, &Process->ActiveProcessLinks);

    PspUnlockProcessList (CurrentThread);

    AccessState = NULL;

    if (!PsUseImpersonationToken) {

        AccessState = &LocalAccessState;

        Status = SeCreateAccessStateEx (NULL,

                                        (Parent == NULL || Parent != PsInitialSystemProcess)?

                                           PsGetCurrentProcessByThread (CurrentThread) :

                                           PsInitialSystemProcess,

                                        AccessState,

                                        &AuxData,

                                        DesiredAccess,

                                        &PsProcessType->TypeInfo.GenericMapping);

        if (!NT_SUCCESS (Status)) {

            goto exit_and_deref;

        }

    }

 

    //

    // Insert the object. Once we do this is reachable from the outside world via

    // open by name. Open by ID is still disabled. Since its reachable

    // somebody might create a thread in the process and cause

    // rundown.

    //

 

    Status = ObInsertObject (Process,

                             AccessState,

                             DesiredAccess,

                             1,     // bias the refcnt by one for future process manipulations

                             NULL,

                             &LocalProcessHandle);

 

    if (AccessState != NULL) {

        SeDeleteAccessState (AccessState);

    }

 

    if (!NT_SUCCESS (Status)) {

        goto exit_and_deref_parent;

    }

 

    //

    // Compute the base priority and quantum reset values for the process and

    // set the memory priority.

    //

 

    ASSERT(IsListEmpty(&Process->ThreadListHead) == TRUE);

 

    BasePriority = PspComputeQuantumAndPriority(Process,

                                                PsProcessPriorityBackground,

                                                &QuantumReset);

 

    Process->Pcb.BasePriority = (SCHAR)BasePriority;

    Process->Pcb.QuantumReset = QuantumReset;

 

    //

    // As soon as a handle to the process is accessible, allow the process to

    // be deleted.

    //

 

    Process->GrantedAccess = PROCESS_TERMINATE;

    if (Parent && Parent != PsInitialSystemProcess) {

        Status = ObGetObjectSecurity (Process,

                                      &SecurityDescriptor,

                                      &MemoryAllocated);

 

        if (!NT_SUCCESS (Status)) {

            ObCloseHandle (LocalProcessHandle, PreviousMode);

            goto exit_and_deref;

        }

 

        //

        // Compute the subject security context

        //

 

        SubjectContext.ProcessAuditId = Process;

        SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);

        SubjectContext.ClientToken = NULL;

        AccessCheck = SeAccessCheck (SecurityDescriptor,

                                     &SubjectContext,

                                     FALSE,

                                     MAXIMUM_ALLOWED,

                                     0,

                                     NULL,

                                     &PsProcessType->TypeInfo.GenericMapping,

                                     PreviousMode,

                                     &Process->GrantedAccess,

                                     &accesst);

 

        PsDereferencePrimaryTokenEx (Process, SubjectContext.PrimaryToken);

        ObReleaseObjectSecurity (SecurityDescriptor,

                                 MemoryAllocated);

 

        if (!AccessCheck) {

            Process->GrantedAccess = 0;

        }

 

        //

        // It does not make any sense to create a process that can not

        // do anything to itself.

        // Note: Changes to this set of bits should be reflected in psquery.c

        // code, in PspSetPrimaryToken.

        //

 

        Process->GrantedAccess |= (PROCESS_VM_OPERATION |

                                   PROCESS_VM_READ |

                                   PROCESS_VM_WRITE |

                                   PROCESS_QUERY_INFORMATION |

                                   PROCESS_TERMINATE |

                                   PROCESS_CREATE_THREAD |

                                   PROCESS_DUP_HANDLE |

                                   PROCESS_CREATE_PROCESS |

                                   PROCESS_SET_INFORMATION |

                                   STANDARD_RIGHTS_ALL |

                                   PROCESS_SET_QUOTA);

 

    else {

        Process->GrantedAccess = PROCESS_ALL_ACCESS;

    }

 

    KeQuerySystemTime (&Process->CreateTime);

    try {

        if (Peb != NULL && CurrentThread->Tcb.Teb != NULL) {

            ((PTEB)(CurrentThread->Tcb.Teb))->NtTib.ArbitraryUserPointer = Peb;

        }

 

        *ProcessHandle = LocalProcessHandle;

 

    } except (EXCEPTION_EXECUTE_HANDLER) {

        NOTHING;

    }

 

    if (SavedStatus != STATUS_SUCCESS) {

        Status = SavedStatus;

    }

 

exit_and_deref:

    ObDereferenceObject (Process);

 

exit_and_deref_parent:

    if (Parent != NULL) {

        ObDereferenceObject (Parent);

    }

 

    return Status;

}

  

 

 

 

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

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

1

2

3

4

5

6

7

8

9

Status = ObCreateObject (PreviousMode,

                         PsProcessType,

                         ObjectAttributes,

                         PreviousMode,

                         NULL,

                         sizeof (EPROCESS),

                         0,

                         0,

                         &Process);

 

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

1

2

3

4

5

6

7

8

9

if (Parent != NULL) {

    //创建新的地址空间

    if (!MmCreateProcessAddressSpace (WorkingSetMinimum,

                                      Process,

                                      &DirectoryTableBase[0])) {

 

        Status = STATUS_INSUFFICIENT_RESOURCES;

        goto exit_and_deref;

    }

  

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

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项。

  

1

2

3

4

5

6

7

8

9

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。

  

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

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)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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 将新进程对象记录到当前进程的句柄表中。

1

2

3

4

5

6

Status = ObInsertObject (Process,

                             AccessState,

                             DesiredAccess,

                             1,     // bias the refcnt by one for future process manipulations

                             NULL,

                             &LocalProcessHandle);

  

  

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

NTSTATUS

NtCreateThread(

    __out PHANDLE ThreadHandle,

    __in ACCESS_MASK DesiredAccess,

    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,

    __in HANDLE ProcessHandle,

    __out PCLIENT_ID ClientId,

    __in PCONTEXT ThreadContext,

    __in PINITIAL_TEB InitialTeb,

    __in BOOLEAN CreateSuspended

    )

/*++

 

Routine Description:

 

    This system service API creates and initializes a thread object.

 

--*/

 

{

    NTSTATUS Status;

    INITIAL_TEB CapturedInitialTeb;

 

    PAGED_CODE();

 

 

    //

    // Probe all arguments

    //

 

    try {

        if (KeGetPreviousMode () != KernelMode) {

            ProbeForWriteHandle (ThreadHandle);

 

            if (ARGUMENT_PRESENT (ClientId)) {

                ProbeForWriteSmallStructure (ClientId, sizeof (CLIENT_ID), sizeof (ULONG));

            }

 

            if (ARGUMENT_PRESENT (ThreadContext) ) {

                ProbeForReadSmallStructure (ThreadContext, sizeof (CONTEXT), CONTEXT_ALIGN);

            else {

                return STATUS_INVALID_PARAMETER;

            }

            ProbeForReadSmallStructure (InitialTeb, sizeof (InitialTeb->OldInitialTeb), sizeof (ULONG));

        }

 

        CapturedInitialTeb.OldInitialTeb = InitialTeb->OldInitialTeb;

        if (CapturedInitialTeb.OldInitialTeb.OldStackBase == NULL &&

            CapturedInitialTeb.OldInitialTeb.OldStackLimit == NULL) {

            //

            // Since the structure size here is less than 64k we don't need to reprobe

            //

            CapturedInitialTeb = *InitialTeb;

        }

    } except (ExSystemExceptionFilter ()) {

        return GetExceptionCode ();

    }

 

    Status = PspCreateThread (ThreadHandle,

                              DesiredAccess,

                              ObjectAttributes,

                              ProcessHandle,

                              NULL,

                              ClientId,

                              ThreadContext,

                              &CapturedInitialTeb,

                              CreateSuspended,

                              NULL,

                              NULL);

 

    return Status;

}

  

 

 

 

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

NTSTATUS

PspCreateThread(

    OUT PHANDLE ThreadHandle,

    IN ACCESS_MASK DesiredAccess,

    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,

    IN HANDLE ProcessHandle,

    IN PEPROCESS ProcessPointer,

    OUT PCLIENT_ID ClientId OPTIONAL,

    IN PCONTEXT ThreadContext OPTIONAL,

    IN PINITIAL_TEB InitialTeb OPTIONAL,

    IN BOOLEAN CreateSuspended,

    IN PKSTART_ROUTINE StartRoutine OPTIONAL,

    IN PVOID StartContext

    )

/*++

Routine Description:

    This routine creates and initializes a thread object. It implements the

    foundation for NtCreateThread and for PsCreateSystemThread.

--*/

 

{

 

    HANDLE_TABLE_ENTRY CidEntry;

    NTSTATUS Status;

    PETHREAD Thread;

    PETHREAD CurrentThread;

    PEPROCESS Process;

    PTEB Teb;

    KPROCESSOR_MODE PreviousMode;

    HANDLE LocalThreadHandle;

    BOOLEAN AccessCheck;

    BOOLEAN MemoryAllocated;

    PSECURITY_DESCRIPTOR SecurityDescriptor;

    SECURITY_SUBJECT_CONTEXT SubjectContext;

    NTSTATUS accesst;

    LARGE_INTEGER CreateTime;

    ULONG OldActiveThreads;

    PEJOB Job;

    AUX_ACCESS_DATA AuxData;

    PACCESS_STATE AccessState;

    ACCESS_STATE LocalAccessState;

 

    PAGED_CODE();

 

 

    CurrentThread = PsGetCurrentThread ();

 

    if (StartRoutine != NULL) {

        PreviousMode = KernelMode;

    else {

        PreviousMode = KeGetPreviousModeByThread (&CurrentThread->Tcb);

    }

 

    Teb = NULL;

 

    Thread = NULL;

    Process = NULL;

 

    if (ProcessHandle != NULL) {

        //

        // Process object reference count is biased by one for each thread.

        // This accounts for the pointer given to the kernel that remains

        // in effect until the thread terminates (and becomes signaled)

        //

 

        Status = ObReferenceObjectByHandle (ProcessHandle,

                                            PROCESS_CREATE_THREAD,

                                            PsProcessType,

                                            PreviousMode,

                                            &Process,

                                            NULL);

    else {

        if (StartRoutine != NULL) {

            ObReferenceObject (ProcessPointer);

            Process = ProcessPointer;

            Status = STATUS_SUCCESS;

        else {

            Status = STATUS_INVALID_HANDLE;

        }

    }

 

    if (!NT_SUCCESS (Status)) {

        return Status;

    }

 

    //

    // If the previous mode is user and the target process is the system

    // process, then the operation cannot be performed.

    //

 

    if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess)) {

        ObDereferenceObject (Process);

        return STATUS_INVALID_HANDLE;

    }

 

    Status = ObCreateObject (PreviousMode,

                             PsThreadType,

                             ObjectAttributes,

                             PreviousMode,

                             NULL,

                             sizeof(ETHREAD),

                             0,

                             0,

                             &Thread);

 

    if (!NT_SUCCESS (Status)) {

        ObDereferenceObject (Process);

        return Status;

    }

 

    RtlZeroMemory (Thread, sizeof (ETHREAD));

 

    //

    // Initialize rundown protection for cross thread TEB refs etc.

    //

    ExInitializeRundownProtection (&Thread->RundownProtect);

 

    //

    // Assign this thread to the process so that from now on

    // we don't have to dereference in error paths.

    //

    Thread->ThreadsProcess = Process;

 

    Thread->Cid.UniqueProcess = Process->UniqueProcessId;

 

    CidEntry.Object = Thread;

    CidEntry.GrantedAccess = 0;

    Thread->Cid.UniqueThread = ExCreateHandle (PspCidTable, &CidEntry);

 

    if (Thread->Cid.UniqueThread == NULL) {

        ObDereferenceObject (Thread);

        return (STATUS_INSUFFICIENT_RESOURCES);

    }

 

    //

    // Initialize Mm

    //

 

    Thread->ReadClusterSize = MmReadClusterSize;

 

    //

    // Initialize LPC

    //

 

    KeInitializeSemaphore (&Thread->LpcReplySemaphore, 0L, 1L);

    InitializeListHead (&Thread->LpcReplyChain);

 

    //

    // Initialize Io

    //

 

    InitializeListHead (&Thread->IrpList);

 

    //

    // Initialize Registry

    //

 

    InitializeListHead (&Thread->PostBlockList);

 

    //

    // Initialize the thread lock

    //

 

    PspInitializeThreadLock (Thread);

 

    KeInitializeSpinLock (&Thread->ActiveTimerListLock);

    InitializeListHead (&Thread->ActiveTimerListHead);

 

 

    if (!ExAcquireRundownProtection (&Process->RundownProtect)) {

        ObDereferenceObject (Thread);

        return STATUS_PROCESS_IS_TERMINATING;

    }

 

    if (ARGUMENT_PRESENT (ThreadContext)) {

 

        //

        // User-mode thread. Create TEB etc

        //

 

        Status = MmCreateTeb (Process, InitialTeb, &Thread->Cid, &Teb);

        if (!NT_SUCCESS (Status)) {

            ExReleaseRundownProtection (&Process->RundownProtect);

            ObDereferenceObject (Thread);

            return Status;

        }

 

 

        try {

            //

            // Initialize kernel thread object for user mode thread.

            //

 

            Thread->StartAddress = (PVOID)CONTEXT_TO_PROGRAM_COUNTER(ThreadContext);

 

#if defined(_AMD64_)

 

            Thread->Win32StartAddress = (PVOID)ThreadContext->Rdx;

 

#elif defined(_X86_)

 

            Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;

 

#else

 

#error "no target architecture"

 

#endif

 

        } except (EXCEPTION_EXECUTE_HANDLER) {

 

            Status = GetExceptionCode();

        }

 

        if (NT_SUCCESS (Status)) {

            Status = KeInitThread (&Thread->Tcb,

                                   NULL,

                                   PspUserThreadStartup,

                                   (PKSTART_ROUTINE)NULL,

                                   Thread->StartAddress,

                                   ThreadContext,

                                   Teb,

                                   &Process->Pcb);

       }

 

 

    else {

 

        Teb = NULL;

        //

        // Set the system thread bit thats kept for all time

        //

        PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_SYSTEM);

 

        //

        // Initialize kernel thread object for kernel mode thread.

        //

 

        Thread->StartAddress = (PKSTART_ROUTINE) StartRoutine;

        Status = KeInitThread (&Thread->Tcb,

                               NULL,

                               PspSystemThreadStartup,

                               StartRoutine,

                               StartContext,

                               NULL,

                               NULL,

                               &Process->Pcb);

    }

 

 

    if (!NT_SUCCESS (Status)) {

        if (Teb != NULL) {

            MmDeleteTeb(Process, Teb);

        }

        ExReleaseRundownProtection (&Process->RundownProtect);

        ObDereferenceObject (Thread);

        return Status;

    }

 

    PspLockProcessExclusive (Process, CurrentThread);

    //

    // Process is exiting or has had delete process called

    // We check the calling threads termination status so we

    // abort any thread creates while ExitProcess is being called --

    // but the call is blocked only if the new thread would be created

    // in the terminating thread's process.

    //

    if ((Process->Flags&PS_PROCESS_FLAGS_PROCESS_DELETE) != 0 ||

        (((CurrentThread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_TERMINATED) != 0) &&

        (ThreadContext != NULL) &&

        (THREAD_TO_PROCESS(CurrentThread) == Process))) {

 

        PspUnlockProcessExclusive (Process, CurrentThread);

 

        KeUninitThread (&Thread->Tcb);

 

        if (Teb != NULL) {

            MmDeleteTeb(Process, Teb);

        }

        ExReleaseRundownProtection (&Process->RundownProtect);

        ObDereferenceObject(Thread);

 

        return STATUS_PROCESS_IS_TERMINATING;

    }

 

 

    OldActiveThreads = Process->ActiveThreads++;

    InsertTailList (&Process->ThreadListHead, &Thread->ThreadListEntry);

 

    KeStartThread (&Thread->Tcb);

 

    PspUnlockProcessExclusive (Process, CurrentThread);

 

    ExReleaseRundownProtection (&Process->RundownProtect);

 

    //

    // Failures that occur after this point cause the thread to

    // go through PspExitThread

    //

 

 

    if (OldActiveThreads == 0) {

        PERFINFO_PROCESS_CREATE (Process);

 

        if (PspCreateProcessNotifyRoutineCount != 0) {

            ULONG i;

            PEX_CALLBACK_ROUTINE_BLOCK CallBack;

            PCREATE_PROCESS_NOTIFY_ROUTINE Rtn;

 

            for (i=0; i

                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,并初始化为零。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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

1

2

3

4

5

6

7

8

9

10

11

12

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

1

2

3

4

5

6

Status = MmCreateTeb (Process, InitialTeb, &Thread->Cid, &Teb);

        if (!NT_SUCCESS (Status)) {

            ExReleaseRundownProtection (&Process->RundownProtect);

            ObDereferenceObject (Thread);

            return Status;

        }

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

1

Thread->StartAddress = (PKSTART_ROUTINE) StartRoutine;

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

 

1

2

OldActiveThreads = Process->ActiveThreads++;

    InsertTailList (&Process->ThreadListHead, &Thread->ThreadListEntry);

 

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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

                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函数将线程对象插入到当前进程的句柄表中

  

1

2

3

4

5

6

Status = ObInsertObject (Thread,

                         AccessState,

                         DesiredAccess,

                         0,

                         NULL,

                         &LocalThreadHandle);

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

  

1

2

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

 

 

 

进程创建过程详解 CreateProcess_第2张图片

 

你可能感兴趣的:(CreateProcess,Windows)