0%

win32程序运行原理

CPU的保护模式和windows系统:

windows多任务实现:

占有CPU时间片执行指令的不是进程,而是线程。线程是进程内代码执行的最小单元

每个进程都有私有空间,线程仅仅能访问属于它的进程的内存,其他进程的内存被屏蔽了

虚拟内存:

CPU在保护模式下支持虚拟存储,即虚拟内存。它帮助操作系统将磁盘空间当作内存空间使用。磁盘上应用于这一机制的文件叫页文件,它包含了对所有进程都有用的虚拟内存。

32位的地址空间为4GB,windows将前半部分留给进程作为私有空间,自己使用后半部分来存储操作系统内部使用的数据。

各进程地址空间被分为用户空间(进程的私有地址空间)和系统空间。

一个进程不能够以任何方式读写其他进程的用户空间的数据。

系统空间放置操作系统代码,包括内核代码、设备驱动代码、设备I/O缓冲区等。这部分在所有的进程中共享的。

内核模式与用户模式:

用户程序的代码在用户模式下运行,系统程序的代码在内核模式下运行。

虚拟内存的每一页页属性中都有访问模式标记,标识了哪一个模式的代码才有权访问该页。

当应用程序调用系统函数,用户的应用程序会从用户模式切换到内核模式去执行。应用程序使用的基本服务都是内核模式下的代码提供。

内核对象:

内核对象的引出:

内核对象是系统提供的用户模式下代码与内核模式下代码进行交互的基本接口。

一个内核对象是一块内核分配的内存,只能被内核模式下的代码访问。内核对象的数据在整个系统只有一份,也称系统资源。

内核对象和普通的数据结构间的最大巨别是其内部数据结构是隐藏的,必须调用一个对象服务才能从此次对象中获取数据,或是向其输入数据。此限制也允许windows在不断任何应用程序的情况下来添加、移除或者改变这些结构中的成员。

引入内核对象,系统方便完成四个任务:1.为系统资源提供可识别的名字。2.在进程之间共享资源和数据。3.保护资源不会被未经认可的代码访问。4.跟踪对象的引用情况。

对象句柄:

应用程序使用API函数访问内核对象。调用函数创建内核对象时,函数会返回标识此内核对象的句柄。此句柄是一个能够被进程中任何线程使用的一个不透明的值,许多API函数需要以它作为参数,以便系统知道操作哪个内核对象。

多个进程共享一个内核对象也是可能的,调用DuplicateHandle函数复制一个进程句柄传给其他进程即可。

进程的创建:

进程与线程:

进程是一个正在运行的程序,它拥有自己的虚拟地址空间,拥有自己的代码、数据和其他系统资源,如进程创建的文件、管道、同步对象等。一个进程也包含了一个或多个运行在此进程内的线程。

进程是不活泼的,一个进程要完成任何任务,必须运行在他的地址空间的线程。线程负责执行该进程地址空间的代码,每个进程至少拥有一个在他地址空间的线程。

主线程创建的线程为该进程的辅助线程。

win32进程的两个部分:

1.进程内核对象。操作系统使用此内核对象来管理进程。这个内核对象也是操作系统存放进程统计信息的地方。

2.私有的虚拟地址空间。包含了所有可执行的或者是dll模块的代码和数据,他也是程序动态申请内存的地方,比如说线程堆栈和进程堆。

应用程序的启动过程:

应用程序必须有一个入口函数,控制台应用程序的入口函数是main。

应用程序的启动过程是线程的创建过程。通过调用CreateProcess函数来创建新的进程。当一个线程调用CreateProcess函数时,系统创建一个进程内核对象,其使用计数初始化为1。此进程内核对象不是进程本身,仅仅是一个系统用来管理这个进程的小的数据结构。系统然后会为系的进程创建一个虚拟地址空间,加载应用程序运行时所需要的代码和数据。接着创建一个主线程,如果系统能够成功为新的进程创建一个主线程,CreateProcess函数返回TRUE,否则FALSE。

创建进程叫父进程,被创建的进程称为子进程。系统创建新的进程指定一个STARTUPINFO类型的变量,包含的父进程传递给子进程的一些显示信息。

结构体信息参考下面链接:

https://www.cnblogs.com/arsblog/p/4560282.html

进程可以调用GetStartupInfo函数来获取父进程创建自己时使用的STARTUPINFO结构。通过调用这个函数来取得当前进程的创建信息,以便对新进程中主窗口的属性设置默认值。

CreateProcess函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
CreateProcess
(
LPCTSTR lpApplicationName, //可执行文件名称
LPTSTR lpCommandLine, //指定了要传递给执行模块的参数
LPSECURITY_ATTRIBUTES lpProcessAttributes。//进程安全性
LPSECURITY_ATTRIBUTES lpThreadAttributes, //线程安全性
BOOL bInheritHandles, //可继承句柄是否可以被新进程继承
DWORD dwCreationFlags,//新进程的优先级及其他创建标志
LPVOID lpEnvironment, //新进程使用的环境变量
LPCTSTR lpCurrentDirectory, //新进程使用的当前目录
LPSTARTUPINFO lpStartupInfo, //新进程主窗口位置、大小和标准句柄
LPPROCESS_INFORMATION lpProcessInformation //返回新进程标志信息。如ID、句柄等
);

lpProcessInformation参数是一个指向PROCESS_INFORMATION结构的指针

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct_PROCESS_INFORMATION{
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
}PROCESS_INFORMATION;
其中成员含义如下。
① hProcess:返回新进程的句柄。
② hThread:返回主线程的句柄。
③ dwProcessId:返回一个全局进程标识符。该标识符用于标识一个进程。从进程被
创建到终止,该值始终有效。
④ dwThreadId:返回一个全局线程标识符。该标识符用于标识一个线程。从线程被创
建到终止,该值始终有效。

创建一个新的进程促进系统创建一个进程内核对象和一个线程内核对象。创建时初始值为1,CreteProcess返回之前,这个函数打开此进程内核对象和线程内核对象的句柄,并将他们的值传递给上述结构的hProcess和hThread成员。打开时,对象的使用计数会加到2父进程必须有一个线程调用CloseHandle关闭CreateProcess函数返回的两个内核对象的句柄。否则即便子进程已经终止,该进程的进程内核对象和主线程的内核对象任然没有释放。

当一个进程内核对象创建以后,系统会为这个内核对象分配一个唯一的ID号。进程和线程使用同一个号码分配器,所以一个进程和一个线程不可能拥有相同ID号。

进程控制:

获取系统进程:

TooHelp函数可以列出一系列正在运行的进程。

使用CreateToolhelp32snapshot函数给当前进程拍快拍。也就是获得一个进程列表。使用Process32First和Process32Next函数遍历快拍中记录的列表。

终止当前进程:

原因有四种:

1.主线程的入口函数返回

2.进程中一个线程调用了ExitProcess

3.此进程所有线程都结束

4.其他进程中一个线程调用了TerminateProcess函数

在使用第一个方法时必须取得该进程的句柄,CreateProcess会返回一个句柄,要使用OpenProcess函数获取这个进程的访问权限。

进程结束后使用GetExitCodeProcess函数可以取得其退出码。

一旦进程终止,会发生下面的事:

1.所有被这个进程创建或打开的对象句柄就会关闭。

2.此进程内所有线程将终止执行

3.进程内核对象变为受信状态,所有等待在此对象上的线程开始运行,WaitForSingleObject函数返回

4.系统将进程对象中退出代码的值由STILL_ACTION改为指定的退出码