nếu bạn gọi CreateProcess
hệ thống nội bộ gọi ZwCreateThread[Ex]
tạo chủ đề đầu tiên trong quá trình
khi bạn tạo chủ đề - bạn (nếu bạn trực tiếp gọi ZwCreateThread
) hoặc hệ thống khởi tạo các bản ghi CONTEXT
cho chủ đề mới - đây Eip(i386)
hay Rip(amd64)
sự điểm vào của chủ đề. nếu bạn làm điều này - bạn có thể chỉ định bất kỳ địa chỉ nào. nhưng khi bạn gọi điện thoại Create[Remote]Thread[Ex]
- làm thế nào tôi nói - hệ thống điền CONTEXT
và nó đặt tự thói quen là điểm nhập chủ đề. điểm vào ban đầu của bạn được lưu trong số Eax(i386)
hoặc Rcx(amd64)
đăng ký.
tên của thói quen này phụ thuộc từ phiên bản Windows.
đầu này là BaseThreadStartThunk
hoặc BaseProcessStartThunk
(trong trường hợp từ CreateProcess
được gọi) từ kernel32.dll
.
nhưng hiện tại hệ thống chỉ định RtlUserThreadStart
từ ntdll.dll
. số RtlUserThreadStart
thường gọi BaseThreadInitThunk
từ kernel32.dll
(ngoại trừ các ứng dụng gốc (thực thi khởi động), như smss.exe
và chkdsk.exe
không có bất kỳ không gian địa chỉ nào). BaseThreadInitThunk
đã gọi điểm nhập chuỗi ban đầu của bạn và sau (if) nó trở về - RtlExitUserThread
được gọi.
mục tiêu chính của chủ đề chung khởi động wrapper này - thiết lập mức độ đầu lọc SEH
. chỉ vì điều này chúng ta có thể gọi hàm SetUnhandledExceptionFilter
. nếu chuỗi bắt đầu trực tiếp từ điểm vào của bạn, không có trình bao bọc - chức năng của Top level Exception Filter sẽ không khả dụng.
nhưng bất kỳ điểm nhập chuỗi - luồng nào trong không gian người dùng - KHÔNG BAO GIỜ bắt đầu thực hiện từ điểm này!
đầu khi chế độ người dùng chủ đề bắt đầu thực hiện - Hệ thống chèn APC
cho chủ đề với LdrInitializeThunk
như APC-thường - điều này được thực hiện bằng cách sao chép (tiết kiệm) chủ đề CONTEXT
cho người sử dụng ngăn xếp và sau đó gọi KiUserApcDispatcher
mà gọi LdrInitializeThunk
.khi hoàn thành LdrInitializeThunk
- chúng tôi quay lại KiUserApcDispatcher
được gọi là NtContinue
với chuỗi đã lưu CONTEXT
- chỉ sau khi điểm nhập chủ đề đã bắt đầu được thực hiện.
nhưng bây giờ hệ thống thực hiện một số tối ưu hóa trong quy trình này - sao chép (lưu) chuỗi CONTEXT
vào ngăn xếp người dùng và cuộc gọi trực tiếp LdrInitializeThunk
. ở cuối hàm này NtContinue
được gọi là - và điểm nhập chủ đề đang được thực thi.
vì vậy MỌI chủ đề bắt đầu thực hiện ở chế độ người dùng từ LdrInitializeThunk
. (chức năng này với chính xác tên tồn tại và được gọi là trong tất cả các phiên bản Windows từ NT4 để win10)
gì là chức năng này làm gì? cho cái gì đây? bạn có thể nghe về thông báo DLL_THREAD_ATTACH
? khi thread mới trong quá trình bắt đầu được thực thi (với ngoại lệ cho các luồng làm việc của hệ thống đặc biệt, như LdrpWorkCallback
) - anh ta đi theo danh sách DLL được nạp và gọi các điểm nhập DLL với thông báo DLL_THREAD_ATTACH
(tất nhiên nếu DLL có điểm vào và DisableThreadLibraryCalls
không được gọi cho DLL này). nhưng làm thế nào điều này được thực hiện? nhờ LdrInitializeThunk
mà gọi LdrpInitialize
->LdrpInitializeThread
->LdrpCallInitRoutine
(đối với DLL EP)
khi thread đầu tiên trong quá trình khởi động - đây là trường hợp đặc biệt. cần làm thêm nhiều công việc để khởi tạo quá trình. tại thời điểm này chỉ có hai mô-đun được tải trong quy trình - EXE
và ntdll.dll
. LdrInitializeThunk
gọi LdrpInitializeProcess
cho công việc này. nếu rất ngắn gọn:
- cấu trúc quá trình khác nhau được khởi
- tải tất cả các DLL (và người phụ thuộc của họ) mà EXE tĩnh liên kết - nhưng không gọi họ EPS!
- gọi
LdrpDoDebuggerBreak
- chức năng nhìn này - là debugger gắn liền với quá trình, và nếu có - int 3
gọi là - vì vậy debugger nhận được thông báo ngoại lệ - STATUS_BREAKPOINT
- hầu hết gỡ rối có thể bắt đầu UI gỡ rối chỉ bắt đầu từ thời điểm này. Tuy nhiên tồn tại debugger (s) mà chúng ta hãy như quá trình gỡ lỗi từ LdrInitializeThunk
- tất cả các ảnh chụp màn hình của tôi từ debugger loại này
- điểm quan trọng - cho đến khi trong quá trình thực thi mã chỉ từ
ntdll.dll
(và có thể từ kernel32.dll
) - mã từ khác Các tệp DLL, bất kỳ mã của bên thứ ba nào chưa được thực thi trong quá trình.
- tùy chọn nạp shim dll để xử lý - Shim Engine khởi tạo. nhưng đây là BẮT BUỘC
- đi bộ bởi danh sách DLL được nạp và gọi EP với
DLL_PROCESS_DETACH
TLS khởi tạo và callbacks TLS gọi (nếu tồn tại)
ZwTestAlert
được gọi là - kiểm tra cuộc gọi này đang tồn tại APC trong thread xếp hàng và thực thi. điểm này tồn tại trong tất cả các phiên bản từ NT4 đến giành chiến thắng 10.này chúng ta hãy ví dụ như tạo ra quá trình trong lơ lửng trạng thái và sau đó chèn APC gọi (QueueUserAPC
) để nó là thread (PROCESS_INFORMATION.hThread
) - như kết quả cuộc gọi này sẽ được thực hiện sau khi quá trình sẽ được khởi tạo đầy đủ, tất cả DLL_PROCESS_DETACH
gọi, nhưng trước khi EXE điểm vào. trong ngữ cảnh của quy trình xử lý đầu tiên.
- và NtContinue gọi cuối cùng - điều này khôi phục lại lưu chủ đề bối cảnh và chúng tôi cuối cùng đã nhảy cho chủ đề EP
cũng Flow of CreateProcess
Bộ nạp là chịu trách nhiệm cho việc này đọc. Nó là một thành phần của hệ điều hành, và cách nó hoạt động là như vậy mà bạn sẽ không thấy nhiều bằng chứng về nó trong ngăn xếp cuộc gọi. Nó là nếu không quá phức tạp để giải thích trong một câu trả lời Stack tràn. Xem xét mua một cuốn sách trên Windows Internals nếu bạn muốn tìm hiểu về ... tốt, các internals của Windows. :-) –
Ngoài ra, Windows tải các tệp DLL cần thiết bởi EXE và thực hiện di chuyển. Và một số mã từ các DLL đó có thể thực thi trước main(). –
liên quan: quá trình khởi động trên Linux: http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html. Ngoài ra [làm thế nào để tạo ra một thực thi nhỏ nhưng vẫn chạy được Linux] (http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html). Linux thực hiện hầu hết các công cụ khởi động quá trình trong hạt nhân so với Windows, nhưng một nhị phân động vẫn chạy liên kết động và sau đó là mã khởi động CRT trong ngữ cảnh của quy trình không gian người dùng mới được thực thi trước C 'main()' chức năng. –