《Windows核心编程》——四 进程

本文详细介绍了Windows环境下进程的基本概念,包括进程的定义、组成部分及其生命周期管理。深入探讨了进程实例句柄、环境变量、关联性和错误模式等核心特性,并讲解了CreateProcess函数的使用方法及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

    一般将进程定义为一个正在运行的程序的一个实例,它由两部分组成:

    ①一个内核对象,操作系统用它来管理进程。内核对象也是系统保存进程统计信息的地方

    ②一个地址空间,其中包含所有可执行文件或dll模块的代码和数据。此外,它还包含动态内存分配,比如线程堆栈和堆的分配。

    进程是有“惰性”的,进程要做任何事情,都必须让一个线程在它的上下文中运行。该线程负责执行进程地址空间包含的代码。一个进程可以有多个线程,所有线程都在进程的地址空间中“同时“执行代码,每个线程都有它自己的一组CPU寄存器和它自己的堆栈。当系统创建一个进程的时候,会自动为进程创建一个线程,这称为主线程。然后,这个线程可以再创建更多的线程。如果没有线程要执行进程地址空间包含的代码,进程就失去了继续存在的理由。这时,系统会自动销毁进程及其地址空间。

 

4.1 编写第一个windows应用程序(GUI或CUI)

   

    完成所有上述这些初始化工作之后,C/C++启动函数就会调用应用程序的入口点函数(用户编写的入口点函数)。

 

4.1.1进程实例句柄:

    加载到进程地址空间的每一个可执行文件或者dll文件都被赋予了一个独一无二的实例句柄。可执行文件的实例被当作(w)WinMain函数的第一个参数hInstanceExe传入。在需要加载资源的函数调用中,一般都要提供此句柄的值。(w)WinMain的hInstanceExe参数的实际值是一个内存基地址;系统将可执行文件的映像加载到地址空间中的这个位置。可执行文件的映像具体加载到哪一个基地址,是由连接器决定的。可以通过调用GetModuleHandle来获取一个可执行文件或dll文件被加载到进程地址空间的位置。如果给该函数传入NULL将获取主线程的可执行文件的基地址。

 

4.1.2 进程前一个实例的句柄

    C/C++运行库启动代码总是向(w)WinMain的hPreInstance参数传递NULL。

4.1.3 进程的命名行

    系统在创建一个新进程时,会传入一个命令行给它,这个命令行几乎总是非空的。(w)WinMain的pszCmdLine,用户应该将它当作一个只读的缓冲区对待,如果相对命令行进行修改,首先应该将命令行缓冲区复制到应用程序的一个本地缓冲区,再对自己本地的缓冲区进行修改。

    可以通过调用GetCommandLine函数来获取一个指向进程完整命令行的指针,它返回的总是同一个缓冲区的地址,修改它之后就没办法知道原来的命令行是什么。

4.1.4 进程的环境变量

    每个进程都有一个与它关联的环境块,这是在进程地址空间内分配的一块内存。可以通过GetEnvironmentStrings函数来获取完整的环境块,如果不再需要该函数返回的内存块,应该调用FreeEnviromentStrings函数来释放它。

    通常子进程会继承一组环境变量,这些环境变量和父进程的环境变量相同。不过父进程可以控制哪些环境变量允许子进程继承,可通过CreateProcess时进行控制。这里所说的“继承”是指子进程获得父进程的环境块的一个副本,这个副本是子进程专用的,也就是说子进程和父进程不共享同一个环境块。这意味着子进程可以在自己的环境块中添加、删除或修改变量,但这些改动不会影响父进程的环境块。

4.1.5 进程的关联性

    通常中的线程可以在主机的任何CPU上执行,不过也可以强迫线程在特定的CPU上执行,这称为“处理器关联性”。

4.1.6 进程的错误模式(ErrorMode)

    进程可以调用SetErrorMode函数来告诉系统如何处理错误。默认情况下,子进程会继承父进程的错误模式标志;父进程可以阻止子进程继承其错误模式,方法是在调用CreateProcess时指定CREATE_DEFAULT_ERROR_MODE标志。

4.1.7 进程当前所在的驱动器和目录

    如果不提供完整的路径名,各种Windows函数会在当前驱动器的当前目录查找文件和目录。系统在内部跟踪记录着一个进程的当前驱动器和目录。由于这种信息是以进程为单位来维护的,所以假如进程中的一个线程更改了当前驱动器或目录,那么对于该进程中的所有线程来说,此信息被更改了。Get/SetCurrentDirectory。

4.1.8 进程的当前目录

    系统跟踪记录着进程的当前驱动器和目录,但它没有记录每个驱动器的当前目录。

 

4.2 CreateProcess函数

4.2.1 pszApplicationName和pszCommandLine参数

    这两个参数分别指定新进程要使用的可执行文件的名称,以及要传给新进程的命名行字符串。

    pszCommandLine是一个非“常量字符串”的地址,在内部,CreateProcess实际上会修改我们传给它的命令行字符串,但是在CreateProcess返回之前,它会将这个字符串还原为原来的形式。因此不能为这个字符串传入一个常量字符串。

    如果可执行文件的名称没有扩展名,就会默认是.exe扩展名,CreateProcess还会按照以下顺序搜索可执行文件。

4.2.2 psaProcess,psaThread和bInheritHandles参数

    为了创建一个新的进程,系统必须创建一个进程内核对象和一个线程内核对象(用于进程的主线程)。由于这些都是内核对象,所以父进程有机会将安全属性关联到这两个对象上。可以根据自己的需要分别使用psaProtobuffer和psaThread参数来为进程对象和线程对象指定安全属性。

4.2.3 fdwCreate参数(新进程的创建方式)

4.2.4 pnEnvironment(环境变量)

    为该变量传入NULL时,这将导致子进程继承其父进程使用的一组环境字符串。

4.2.5 pszCurDir参数(当前驱动器和目录)

    为该变量传入NULL时,这将导致新进程的工作目录与生成新进程的应用程序一样。

4.2.3 psiStartinfo(必须清零)

    如果没有该参数对应的结构的内容清零,则成员将包含主调线程的栈上的垃圾数据。把这种垃圾数据传给CreateProcess,会造成新进程有时能创建,有时则不能,具体取决于垃圾数据的内容。因此必须将这个数据结构中的未使用的成员清零,确保CreateProcess始终都能正常地工作。

4.2.7 ppiProcInfo参数

    ppiProcInfo参数指向一个PROCESS_INFORMATION结构(由我们负责分配),CreateProcess函数在返回之前会初始化这个结构的成员。

 

4.3 终止进程

4.3.1 主线程的入口点函数返回

4.3.2 ExitProcess函数

4.3.3 TerminateProcess函数(异步的)

4.3.4 当进程中的所有线程终止时

    一旦系统检测到一个进程中没有任何线程在运行,就会终止这个进程。这个进程的退出代码会被设为最后一个终止的那个线程的退出代码。

4.3.5 当进程终止时

 

4.4 子进程

4.5 管理员以标准用户权限运行时

账户对应的安全令牌(管理员身份)

经过筛选的令牌(标准用户)

 

    权限受限的进程无法访问需要更高权限才能访问的安全资源,但是可以通过几种方式来提高权限。

    首先,我们可以要求操作系统提升权限,但只能在进程边界上提升。默认情况下,一个进程启动时,它会与当前登录用户的筛选后的令牌关联起来。要为进程授予更多的权限,我们需要指示Windows做这样一件事情:在进程启动之前,先友好地征得最终用户的同意。

4.5.1 自动提升进程的权限

4.5.2 手动提升进程的权限(ShellExecuteEx)

    注意,当一个进程使用提升后的权限启动时,它每次用CreateProcess来生成另一个进程时,子进程都会获得和它的父进程一样的提升后的权限,在这种情况下,不需要调用ShellExecuteEx。假如一个应用程序是用一个筛选后的令牌来运行的,那么一旦试图用CreateProcess来生成一个要求提升权限的可执行文件,这个调用就会失败,GetLastError会返回ERROR_ELEVATION_REQUIRED。

4.5.3 何为当前权限上下文

    如何判断应用程序是否是以管理员身份运行;更重要的是,如何判断它是以提升的权限来启动的,还是正在使用筛选的令牌运行。GetProcessElevation能返回提升类型和一个指出进程是否正在以管理员身份运行的布尔值。

4.5.4 枚举系统中正在运行的进程

    用户可以通过ToolHelp函数来枚举系统中正在运行的进程。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值