Dot-Net

如何在 Vista (.NET) 中執行不提升

  • October 13, 2008

我有一個必須以管理員身份執行的應用程序。

該應用程序的一小部分是使用 Process.Start 啟動其他應用程序

啟動的應用程序也將以管理員身份執行,但我寧願看到它們以“普通”使用者身份執行。

我該如何做到這一點?

/約翰/

WinSafer API 允許以受限使用者、普通使用者或提升使用者身份啟動程序。

樣品用法:

CreateSaferProcess(@"calc.exe", "", SaferLevel.NormalUser);

原始碼:

//http://odetocode.com/Blogs/scott/archive/2004/10/28/602.aspx
public static void CreateSaferProcess(String fileName, String arguments, SaferLevel saferLevel)
{
  IntPtr saferLevelHandle = IntPtr.Zero;

  //Create a SaferLevel handle to match what was requested
  if (!WinSafer.SaferCreateLevel(
        SaferLevelScope.User, 
        saferLevel, 
        SaferOpen.Open, 
        out saferLevelHandle, 
        IntPtr.Zero))
  {
     throw new Win32Exception(Marshal.GetLastWin32Error());
  }
  try
  {
     //Generate the access token to use, based on the safer level handle.
     IntPtr hToken = IntPtr.Zero;

     if (!WinSafer.SaferComputeTokenFromLevel(
           saferLevelHandle,  // SAFER Level handle
           IntPtr.Zero,       // NULL is current thread token.
           out hToken,        // Target token
           SaferTokenBehaviour.Default,      // No flags
           IntPtr.Zero))      // Reserved
     {
        throw new Win32Exception(Marshal.GetLastWin32Error());
     }
     try
     {
        //Now that we have a security token, we can lauch the process
        //using the standard CreateProcessAsUser API
        STARTUPINFO si = new STARTUPINFO();
        si.cb = Marshal.SizeOf(si);
        si.lpDesktop = String.Empty;

        PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

        // Spin up the new process
        Boolean bResult = Windows.CreateProcessAsUser(
              hToken,
              fileName,
              arguments,
              IntPtr.Zero, //process attributes
              IntPtr.Zero, //thread attributes
              false, //inherit handles
              0, //CREATE_NEW_CONSOLE
              IntPtr.Zero, //environment
              null, //current directory
              ref si, //startup info
              out pi); //process info

        if (!bResult)
           throw new Win32Exception(Marshal.GetLastWin32Error());

        if (pi.hProcess != IntPtr.Zero)
           Windows.CloseHandle(pi.hProcess);

        if (pi.hThread != IntPtr.Zero)
           Windows.CloseHandle(pi.hThread);
     }
     finally
     {
        if (hToken != IntPtr.Zero)
           Windows.CloseHandle(hToken);
     }
  }
  finally
  {
     WinSafer.SaferCloseLevel(saferLevelHandle);
  }
}

P/Invoke 聲明:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace PInvoke
{
  public class WinSafer
  {
     /// <summary>
     /// The SaferCreateLevel function opens a SAFER_LEVEL_HANDLE.
     /// </summary>
     /// <param name="scopeId">The scope of the level to be created.</param>
     /// <param name="levelId">The level of the handle to be opened.</param>
     /// <param name="openFlags">Must be SaferOpenFlags.Open</param>
     /// <param name="levelHandle">The returned SAFER_LEVEL_HANDLE. When you have finished using the handle, release it by calling the SaferCloseLevel function.</param>
     /// <param name="reserved">This parameter is reserved for future use. IntPtr.Zero</param>
     /// <returns></returns>
     [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
     public static extern bool SaferCreateLevel(SaferLevelScope scopeId, SaferLevel levelId, SaferOpen openFlags,
           out IntPtr levelHandle, IntPtr reserved);

     /// <summary>
     /// The SaferComputeTokenFromLevel function restricts a token using restrictions specified by a SAFER_LEVEL_HANDLE.
     /// </summary>
     /// <param name="levelHandle">SAFER_LEVEL_HANDLE that contains the restrictions to place on the input token. Do not pass handles with a LevelId of SAFER_LEVELID_FULLYTRUSTED or SAFER_LEVELID_DISALLOWED to this function. This is because SAFER_LEVELID_FULLYTRUSTED is unrestricted and SAFER_LEVELID_DISALLOWED does not contain a token.</param>
     /// <param name="inAccessToken">Token to be restricted. If this parameter is NULL, the token of the current thread will be used. If the current thread does not contain a token, the token of the current process is used.</param>
     /// <param name="outAccessToken">The resulting restricted token.</param>
     /// <param name="flags">Specifies the behavior of the method.</param>
     /// <param name="lpReserved">Reserved for future use. This parameter should be set to IntPtr.EmptyParam.</param>
     /// <returns></returns>
     [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
     public static extern bool SaferComputeTokenFromLevel(IntPtr levelHandle, IntPtr inAccessToken,
           out IntPtr outAccessToken, SaferTokenBehaviour flags, IntPtr lpReserved);

     /// <summary>
     /// The SaferCloseLevel function closes a SAFER_LEVEL_HANDLE that was opened by using the SaferIdentifyLevel function or the SaferCreateLevel function.</summary>
     /// <param name="levelHandle">The SAFER_LEVEL_HANDLE to be closed.</param>
     /// <returns>TRUE if the function succeeds; otherwise, FALSE. For extended error information, call GetLastWin32Error.</returns>
     [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
     public static extern bool SaferCloseLevel(IntPtr levelHandle);
  } //class WinSafer

  /// <summary>
  /// Specifies the behaviour of the SaferComputeTokenFromLevel method
  /// </summary>
  public enum SaferTokenBehaviour : uint
  {
     /// <summary></summary>
     Default = 0x0,
     /// <summary>If the OutAccessToken parameter is not more restrictive than the InAccessToken parameter, the OutAccessToken parameter returns NULL.</summary>
     NullIfEqual = 0x1,
     /// <summary></summary>
     CompareOnly = 0x2,
     /// <summary></summary>
     MakeInert = 0x4,
     /// <summary></summary>
     WantFlags = 0x8
  }

  /// <summary>
  /// The level of the handle to be opened.
  /// </summary>
  public enum SaferLevel : uint
  {
     /// <summary>Software will not run, regardless of the user rights of the user.</summary>
     Disallowed = 0,
     /// <summary>Allows programs to execute with access only to resources granted to open well-known groups, blocking access to Administrator and Power User privileges and personally granted rights.</summary>
     Untrusted = 0x1000,
     /// <summary>Software cannot access certain resources, such as cryptographic keys and credentials, regardless of the user rights of the user.</summary>
     Constrained = 0x10000,
     /// <summary>Allows programs to execute as a user that does not have Administrator or Power User user rights. Software can access resources accessible by normal users.</summary>
     NormalUser = 0x20000,
     /// <summary>Software user rights are determined by the user rights of the user.</summary>
     FullyTrusted = 0x40000
  }

  /// <summary>
  /// The scope of the level to be created.
  /// </summary>
  public enum SaferLevelScope : uint
  {
     /// <summary>The created level is scoped by computer.</summary>
     Machine = 1,
     /// <summary>The created level is scoped by user.</summary>
     User = 2
  }

  public enum SaferOpen : uint
  {
     Open = 1
  }
} //namespace PInvoke

引用自:https://stackoverflow.com/questions/196949