• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2021-06-30 14:28 Aet 隐藏边栏 |   抢沙发  10 
文章评分 1 次,平均分 5.0

终止进程

方法

  1. 主线程的入口点函数返回。
  2. 进程中的一个线程调用ExitProcess函数(要避免这种方式)。
  3. 另一个进程中的线程调用TerminateProcess函数(要避免这种方式)。
  4. 进程中的所有线程都“自然死亡”(几乎从来不会发生)。

入口点函数返回

让主线程的入口点函数返回,可以确保以下操作会被执行:

  1. 该线程创建的任何C++对象都将由这些对象的析构函数正确销毁。
  2. 操作系统将正确释放线程栈使用的内存。
  3. 系统将进程的退出代码(在进程内核对象内维护)设为入口点函数的返回值。
  4. 系统递减进程内核对象的使用计数。

ExitProcess

进程会在该进程中的一个线程中调用ExitProcess函数时终止。

  1. 该函数将终止进程,并将进程的退出代码设为fuExitCode。
  2. 这个函数不会有返回值,因为进程已经被终止了。即使ExitProcess后面还有别的代码,这些代码也不会被执行。
  3. 当主函数的入口点函数WinMain、wWinMain、main和wmain返回时,会返回到C/C++运行库启动代码,C/C++运行库代码将正确清理进程使用的全部C运行时资源。
    释放了C运行时资源之后,C运行时启动代码将显示调用ExitProcess,并将入口点函数的返回值传给它。
  4. 需要注意的是,Windows Platform SDK中指出,一个进程在其所有线程都终止之后才会终止。从操作系统的角度来看,这种说法是正确的。
    但是事实上,C/C++运行库为应用程序采取了一个不同的策略:那就是不管进程中是否还有其他线程在运行,只要应用程序的主线程从它的入口函数返回,C/C++运行库就会调用ExitProcess来终止进程。
  5. 如果在应用程序的入口点函数中调用的是ExitThread,而不是ExitProcess或者从入口点函数直接返回,应用程序的主线程将停止执行,但进程中还有其他线程正在运行,进程就不会终止。
  6. ExitProcess和ExitThread都会导致进程或线程直接终止运行,再也不会返回当前函数调用。

TerminateProcess

调用这个函数也可以终止一个进程。

  1. 这个函数和ExitProcess的区别是:任何一个线程都可以调用TerminateProcess来终止另一个进程或它自己的进程。
  2. hProcess指定了要终止的进程的句柄。
    fuExitCode指要传过去的退出代码的值。
  3. 只有在无法通过其他方法强制进程退出时,才应使用TerminateProcess这个函数。
    因为被终止的进程得不到自己要被终止的通知,意味着应用程序不能正确清理,也不能阻止它自己被强行终止。
    对于这种情况,虽然进程没有机会机会做自己的清理工作,单操作系统会在进程终止之后彻底进行清理,以确保不会泄露任何操作系统资源。

当进程中的所有线程终止

  1. 如果一个进程中的所有线程都终止了(要么是调用了ExitThread,要么是调用了TerminateThread来终止),操作系统就认为没有任何理由再保持进程的地址空间。
  2. 一旦系统检测到进程中没有任何线程在运行,就会终止这个进程。进程的退出代码会被设为最后一个终止的那个线程的退出代码。

进程终止的过程

步骤

  1. 终止进程中遗留的任何线程。
  2. 释放进程分配的所有用户对象和GDI对象,关闭所有内核对象(如果没有其他进程使用这些内核对象的话)。
  3. 进程的退出代码从STILL_ACTIVE变为传给ExitProcess或TerminateProcess函数的代码。
  4. 进程内核对象的状态变为已触发状态。
  5. 进程内核对象的使用计数减1。

GetExitCodeProcess

  1. 可以通过调用这个函数来获取已经终止的一个进程的退出代码。
  2. 该函数会查找由hProcess标识的进程内核对象,并从内核对象的数据结构中提取用于标识进程退出代码的成员。
    任何时候都可以调用这个函数:
    如果在调用的时候,进程还没有终止,函数将用STILL_ACTIVE填充pdwExitCode的内容。
    如果在调用的时候,进程已经终止了,函数将返回实际的退出代码值。

子进程

  1. Windows提供了几种方式在不同进程之间传递数据:
    1. 动态数据交换(DDE)
    2. OLE
    3. 管道
    4. 邮件槽等
  2. 进程对象在终止的时候,就会变为已触发。
  3. 在CreateProcess返回之后,立即关闭了到子进程的主线程内核对象的句柄:
    1. 不会导致子进程的主线程终止,只会递减了子进程的主线程的内核对象的使用计数。
    2. 这样做的好处是:
      假如子进程的主线程生成了另外一个线程,然后主线程终止了。
      这个时候,假如父进程没有打开这个线程对象的句柄,那么系统就可以从内存中释放子进程的主线程对象。
      但是如果父进程打开了到子进程的主线程内核对象的一个句柄,那么系统是不会释放这个对象的。

子进程独立运行

  1. 为了让子进程独立运行,和创建它的父进程没有联系,如下:

管理员和标准用户权限

  1. 在Windows Vista中,如果用户使用管理员这样的一个被授予搞特权的账户登录,那么除了与这个账户对应的安全令牌之外,还会创建一个经过筛选的令牌。
  2. 这个经过筛选的令牌,只被授予标准用户的权限。
  3. 之后,从包含Windows任务管理器在内的第一个进程开始,这个筛选后的令牌,会与系统代表用户最终启动的所有新进程关联起来。
    1. 在这个情况下,所有应用程序都只有标准用户的权限集,那么它们如何访问受限制的资源呢?
    2. 答案是:权限受限的进程无法访问需要更高特权才能访问的安全资源。
  4. 我们可以要求操作系统提升权限,但只能在进程边界上提升。
    1. 默认情况下,一个进程启动起来,它会与当前登录用户的筛选后的令牌关联起来。
    2. 要提升权限的话,需要指示Windows做一件事情:在进程启动之前,先友好的获得最终用户对于提升权限的同意。
    3. 比如,最终用户可以右击应用程序,然后以管理员身份运行。
    4. 如果登录用户本身就是管理员身份,再点了这个以管理员身份运行的话,Windows就会弹出一个确认对话框,要求用户批准将权限提升到未筛选的安全令牌的级别。
    5. 如果登录用户不是管理员身份,而是标准用户身份,就会弹出一个登录对话框,要求登录权限更高的账号。
  5. Windows只允许在进程边界上进程权限提升。一旦进程启动,再要求更多的权限就已经迟了。

手动提升进程权限

ShellExecuteEx

  1. CreateProcess函数没有提升权限的参数,要提升权限,要调用这个函数。
  2. lpVerb必须被设为“runas”。
  3. lpFile必须包含使用提升后的权限来启动的一个可执行文件的路径。
  4. 如果用户拒绝提升权限,ShellExecuteEx将返回FALSE,GetLastError将返回ERROR_CANCELLED值来指出这个情况。

注意

  1. 当一个进程使用提升后的权限启动时,它每次使用CreateProcess生成的另一个进程时,子进程都会获得和父进程一样的提升后的权限。这种情况不需要调用ShellExecuteEx函数。

当前权限上下文

  1. 下面GetProcessElevation函数能返回提升类型和一个指出进程是否正在以管理员身份运行的布尔值。

描述
TokenElevationTypeDefault 进程以默认用户运行
TokenElevationTypeFull 进程权限被成功提升,而且令牌没有被筛选过
TokenElevationTypeLimited 进程以受限的权限运行,对应一个筛选过的令牌

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0 最后编辑于:2021-11-20
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享