进程的结束和UAC的权限提升

终止进程是通过以下4种方式来实现的:

     *主线程入口点函数返回.(推荐)
     *进程中线程调用ExitProcess函数(避免)
     *另一个进程中线程调用TerminateProcess函数(避免)*
     进程,自然死亡(几乎不可能) 
     
一、主线程的入口点函数返回 主程序入口点函数返回之后,这个应用程序的进程才终止. 
  
       主线程的入口点函数返回,保证以下操作会被执行. 
       1.线程创建任何C++对象都将由这些对象的析构函数正确销毁. 
       2.正确释放线程栈使用内存. 
       3.将进程的退出代码,设为入口点函数的返回值. 
       4.递减进程内核对象使用计数. 
             
二.ExitProcess函数:
  
      进程中的线程调用ExitProcess函数时终止:
      VOID ExitProcess(UINT fuExitCode);
         
      终止进程,并将进程的退出代码设为fuExitCode。ExitProcess不会返回值当主线程入口点函数返回时,
      会返回C/C++运行库启动代码,后者将正确清理进程使用的全部C运行时资源.释放了C运行时资源之后,
      C运行时启动代码将显式调用ExitProcess,将入口点函数返回的值传给它.为什么只需要从主线程入口点函数返回,
      就会终止整个进程.不管进程中是否还有其他线程在运行,只要应用程序的主线程从它的入口点函数返回,
      C/C++运行库就会调用ExitProcess来终止进程.调用是ExitThread,或者入口点函数直接返回,应用程序的主线程将停止执行,
      但只要进程中还有其他线程正在运行,进程就不会终止.
      调用ExitProcess或ExitThread会导致进程或线程直接运行-再也不会返回当前函数调用.
         
      C/C++应用程序应避免用这些函数,因为C/C++运行库也许不能执行正确清理工作.

      #include <windows.h>
      #include <stdio.h>

      class CSomeObj {
       public:
           CSomeObj() { printf("Constructor/r/n"); }
           ~CSomeObj() { printf("Destructor/r/n"); }
       };


       CSomeObj g_GlobalObj;

     void main () {
     CSomeObj LocalObj;
     ExitProcess(0);    // This shouldn't be here

           // At the end of this function, the compiler automatically added
           // the code necessary to call LocalObj's destructor.
           // ExitProcess prevents it from executing.
     }

    执行上述代码,会显示以下结果:

    Constructor
    Constructor


    ExitProcess造成进程"当场终止运行";C/C++运行时没有机会执行清理工作.
    任何时候都不要显式地调用ExitProcess.再运行这个程序就会得到以下结果...

    Constructor
    Constructor
    Destructor
    Destructor

三、 TerminateProcess函数
      
    TerminateProcess函数可终止一个进程
       Bool TerminateProcess(
               HANDLE Process, // 制定终止进程句柄
               UINT fuExitCode // 退出代码值,全传给fuExitCode参数
       );

   任何线程可通过TerminateProcess结束另一个或自己的进程。
   只有无法通过其它方法来强制进程退出时,才使用TerminateProcess
   另外TerminateProcess函数是异步的,它告诉系统我们希望进程终止,
   但函数返回时候,系统并不能保证进程已经被强行终止?
   为了确定进程是否已终止应调用WaitForSingleObject或者一个类似的函数
   并将进程句柄传给它。

四、进程终止运行时
    
   用过调用GetExitCodeProcess获得已经终止的一个进程退出代码

   BOOL GetExitCodeProcess(
   HANDLE hProcess,
   PDWORD pdwExitCode);

   函数会查找进程内核对象,并从内核对象的数据
   结构中提取用于标识进程退出代码的成员。
   任何时候都可调用此函数,调用GetExitCodeProcess进程还没终止
   将用STILL_ACTIVE 标识符,来填充DWORD如果进程已经终止,就返回实际退出代码值。

五、子进程

   Windows 提供几种不同进程间传递数据方式
包括动态数据交换(DDE)、OLE、管道、邮件槽等。
共享数据最好方式之一使用内存映射文件。

   PROCESS_INFORMATION pi;
   DWORD dwExitCode; // 退出代码

// Spawn the child process.
BOOL fSuccess = CreateProcess(..., &pi);
if (fSuccess) {

   // Close the thread handle as soon as it is no longer needed!
   CloseHandle(pi.hThread); // 关闭主线程内核对象句柄

   // Suspend our execution until the child has terminated.
   WaitForSingleObject(pi.hProcess, INFINITE);
   // 等待hObject参数被触发

   // The child process terminated; get its exit code.
   GetExitCodeProcess(pi.hProcess, &dwExitCode);
   // 获取子进程的退出代码

   // Close the process handle as soon as it is no longer needed.
   CloseHandle(pi.hProcess);
   // 关闭主进程内核对象句柄
}

WaitForSingleObject 函数声明:
DWORD WaitForSingleObject(HANDLE hObject, DWORD dwTimeout);

运行独立子进程
Windows 进程间的关系:
如当Windows资源管理器为用户创建一个新的进程,之后就不再关系这个进程是否继续存在,也
不关心用户是否要终止它。
   为断绝与子进程所有联系,Windows资源管理器必须调用 CloseHandle来关闭新进程及其主线程句柄。

五、管理员以标准用户权限运行时(UAC)

   为什么UAC,不一定询问,然后把安全数据保存到系统中,并让用户下次可不经过提示直接运行呢?
   如果提供这样一个安全数据库。那么数据被入侵了怎么办呢?
   
   任务管理器上的用户提示权限
     实际上你注意这任务管理器,在点击后的PID是不一样的,这意味着任务管理器,生成它的另一个实例。

六、自动提升进程权限

   如果在应用程序中可执行文件中嵌入一种特殊资源(RT_MANIFEST)
其中系统会检查<trustInfo>段,下面是示例清单文件的<trustInfo>段。
我们可以将清单保存到可知性文件所在目录中,名称和可执行文件相同
且扩展名使用 *.manifest那么效果也是一样的。
不过这个清单须要在注销系统后生效,可知性文件嵌入清单的优先权会比外部清单文件大。

...
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges>
         <requestedExecutionLevel
            level="requireAdministrator"
         />
       </requestedPrivileges>
    </security>
</trustInfo>
...

可能有3个不同的值
          
               level 属性的值

    值                                 描述

requireAdministrator     程序必须以管理员权限启动;否则不会运行

highestAvailable         使用管理员帐户登入,就会出现一个要求批准提升权限的对话框

                         使用管理员帐户登入,会出现一个要求批准提升权限的对话框
                         普通用户帐户登录,应用程序就会用这些标准权限来启动(不会提示用户提升权限)

asInvoker                应用程序使用与主调进程应用程序一样的权限来启动。

七、手动提升进程权限
   
   shellExecutEx函数

BOOL ShellExecuteEx(LPSHELLEXECUTEINFO pExecInfo);

typedef struct _SHELLEXECUTEINFO {
    DWORD cbSize;
    ULONG fMask;
    HWND hwnd;
    PCTSTR lpVerb;      // 必须设为runas
    PCTSTR lpFile;      // 提升后的权限启动一个可执行文件路径
    PCTSTR lpParameters;
    PCTSTR lpDirectory;
    int nShow;
    HINSTANCE hInstApp;
    PVOID lpIDList;
    PCTSTR lpClass;
    HKEY hkeyClass;
    DWORD dwHotKey;
    union {
        HANDLE hIcon;
        HANDLE hMonitor;
    } DUMMYUNIONNAME;
    HANDLE hProcess;
} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;

========================================================================
   实用例子:

// Initialize the structure.
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };

// Ask for privileges elevation.
sei.lpVerb = TEXT("runas");

// Create a Command Prompt from which you will be able to start
// other elevated applications.
sei.lpFile = TEXT("cmd.exe");

// Don't forget this parameter; otherwise, the window will be hidden.
sei.nShow = SW_SHOWNORMAL;

if (!ShellExecuteEx(&sei)) {
   DWORD dwStatus = GetLastError();

   if (dwStatus == ERROR_CANCELLED) {
      // The user refused to allow privileges elevation.
   }
   else
   if (dwStatus == ERROR_FILE_NOT_FOUND) {
     // The file defined by lpFile was not found and
     // an error message popped up.
   }
}

用户拒绝提升权限,shellExecutEx返回Flase,GetLastError通过使用一个ERROR_CANCELLED值来指出情况
   
当父进程以已经用shellExecutEx函数取得相关权限时,有继承权的子进程就不要在用CreateProcess函数

去申请同样释放权限,否则调用会失败的,GetLastError会返回 ERROR_ELEVATION_REQUIRED


八、 何为当前权限上下文

   我们可以通过GetProcessElevation函数 来返回提升类型和一个指出进程是否正以管理员身份运行的布尔值。

   BOOL GetProcessElevation(TOKEN_ELEVATION_TYPE* pElevationType, BOOL* pIsAdmin) {
   HANDLE hToken = NULL;
   DWORD dwSize;

   // Get current process token
   if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
      return(FALSE);

   BOOL bResult = FALSE;

   // Retrieve elevation type information
   if (GetTokenInformation(hToken, TokenElevationType,
      pElevationType, sizeof(TOKEN_ELEVATION_TYPE), &dwSize)) {
      // Create the SID corresponding to the Administrators group
      BYTE adminSID[SECURITY_MAX_SID_SIZE];
      dwSize = sizeof(adminSID);
      CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &adminSID,
         &dwSize);

      if (*pElevationType == TokenElevationTypeLimited) {
         // Get handle to linked token (will have one if we are lua)
         HANDLE hUnfilteredToken = NULL;
         GetTokenInformation(hToken, TokenLinkedToken, (VOID*)
            &hUnfilteredToken, sizeof(HANDLE), &dwSize);

         // Check if this original token contains admin SID
         if (CheckTokenMembership(hUnfilteredToken, &adminSID, pIsAdmin)) {
            bResult = TRUE;
         }

         // Don't forget to close the unfiltered token
         CloseHandle(hUnfilteredToken);
      } else {
         *pIsAdmin = IsUserAnAdmin();
         bResult = TRUE;
      }
   }

   // Don't forget to close the process token
   CloseHandle(hToken);

   return(bResult);
}

其中GetTokenInformation使用的与进程关联的安全令牌和 TokenElevationType 参数获得提升类型,
提升类型的值由TOKEN_ELEVATION_TYPE 枚举类型来定义。

TOKEN_ELEVATION_TYPE 的值
          值                             说明

TokenElevationTypeDefault         默认运行用户运行,UAC被禁用

TokenElevationTypeFull            权限被成功提升,而且令牌没有被筛选过

TokenElevationTypeLimited         进程以受限的权限运行,它对应于一个筛选过的令牌

 

 

 

http://hi.baidu.com/csw8923/blog/item/c1f329a98587edf61f17a206.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值