本文介绍了如何启动一个进程Unelevated的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序运行作为 requestedExecutionLevel 设置为 highestAvailable

My app runs as requestedExecutionLevel set to highestAvailable.

我如何运行一个进程unelevated

How do I run a process unelevated?

我试过以下,但它没有工作:

I tried the following but it didn't work:

Process.Start(new ProcessStartInfo {FileName = "foo.exe", Verb = "open"})

我曾尝试以下信任级别使用Win32 API,但他们没有正常工作,开始我的过程:

I have tried the following trust levels to start my process using Win32 API but none of them work correctly:

0
1260: This program is blocked by group policy. For more information, contact your system administrator.

0x1000
The application was unable to start correctly (0xc0000142). Click OK to close the application.

0x10000
Process starts then hangs

0x20000
All options are not available

0x40000
Runs as admin

如果我跑 TSKILL富从我高架的应用程序,将重新启动以正确的权限富。

If I run tskill foo from my elevated app, it restarts foo with correct privileges.

我需要的是在我没有指定信任级别的解决方案。这个过程应该用正确的信任级别自动就像 TSKILL 工具将重新启动 foo.exe的在正确的信任级别启动。用户选择并运行 foo.exe的,因此它可以是任何东西。

What I need is a solution in which I don't have to specify the trust level. The process should start with the correct trust level automatically just like the tskill tool restarts foo.exe in the correct trust level. The user selects and runs foo.exe and so it can be anything.

如果我能得到的信任级别总得过程中,我可以从 foo.exe的很容易做到这一点运行时我的应用程序可以捕获它的信任级别。

If I can get the trust level of a process somehow, I can do this easily since foo.exe runs when my app can capture its trust level.

推荐答案

Win32的安全管理功能提供了创建具有普通用户权限受限令牌的能力;与令牌,你可以叫 CreateProcessAsUser 与该令牌运行的进程。下面是运行CMD.EXE作为普通用户,不管过程是否在提升的上下文中运行的一个概念证明。

The Win32 Security Management functions provide the capability to create a restricted token with normal user rights; with the token, you can call CreateProcessAsUser to run the process with that token. Below is a proof of concept that runs cmd.exe as a normal user, regardless of whether the process is run in an elevated context.

// Initialize variables.
IntPtr hSaferLevel, hToken;
STARTUPINFO si = default(STARTUPINFO);
SECURITY_ATTRIBUTES processAttributes = default(SECURITY_ATTRIBUTES);
SECURITY_ATTRIBUTES threadAttributes = default(SECURITY_ATTRIBUTES);
PROCESS_INFORMATION pi;
si.cb = Marshal.SizeOf(si);

// The process to start (for demonstration, cmd.exe)
string ProcessName = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.System),
    "cmd.exe");

// Create the restricted token info
if (!SaferCreateLevel(
     SaferScopes.User,
     SaferLevels.NormalUser, // Program will execute as a normal user
     1, // required
     out hSaferLevel,
     IntPtr.Zero))
         throw new Win32Exception(Marshal.GetLastWin32Error());

// From the level create a token
if (!SaferComputeTokenFromLevel(
     hSaferLevel,
     IntPtr.Zero,
     out hToken,
     SaferComputeTokenFlags.None,
     IntPtr.Zero))
         throw new Win32Exception(Marshal.GetLastWin32Error());

// Run the process with the restricted token
if (!CreateProcessAsUser(
     hToken,
     ProcessName,
     null, ref processAttributes, ref threadAttributes,
     true, 0, IntPtr.Zero, null,
     ref si, out pi))
         throw new Win32Exception(Marshal.GetLastWin32Error());

 // Cleanup
 if (!CloseHandle(pi.hProcess))
     throw new Win32Exception(Marshal.GetLastWin32Error());
 if (!CloseHandle(pi.hThread))
     throw new Win32Exception(Marshal.GetLastWin32Error());
 if (!SaferCloseLevel(hSaferLevel))
     throw new Win32Exception(Marshal.GetLastWin32Error());

这方法使得使用下面的Win32函数:

This approach makes use the following Win32 functions:


  • 的以表明身份级(限,正常或升高)。设置 levelId SAFER_LEVELID_NORMALUSER (地址0x20000)提供了普通用户级别。

  • 会为提供水平的令牌。通过 NULL 来的InAccessToken参数使用当前线程的身份。

  • 的创建与所提供的令牌的过程。因为该会话已经是互动的,大多数参数可以保持在默认值。 (第三个参数, lpCommandLine 可以作为一个字符串指定命令行提供)

  • 的和的释放分配的内存。

  • SaferIdentifyLevel to indicate the identity level (limited, normal, or elevated). Setting the levelId to SAFER_LEVELID_NORMALUSER (0x20000) provides the normal user level.
  • SaferComputeTokenFromLevel creates a token for the provided level. Passing NULL to the InAccessToken parameter uses the identity of the current thread.
  • CreateProcessAsUser creates the process with the provided token. Since the session is already interactive, most of the parameters can be kept at default values. (The third parameter, lpCommandLine can be provided as a string to specify the command line.)
  • CloseHandle (Kernel32) and SaferCloseLevel to free allocated memory.

最后,的p / Invoke代码如下(从pinvoke.net复制居多):

Finally, the P/Invoke code is below (copied mostly from pinvoke.net):

[Flags]
public enum SaferLevels : uint
{
    Disallowed = 0,
    Untrusted = 0x1000,
    Constrained = 0x10000,
    NormalUser = 0x20000,
    FullyTrusted = 0x40000
}

[Flags]
public enum SaferComputeTokenFlags : uint
{
    None = 0x0,
    NullIfEqual = 0x1,
    CompareOnly = 0x2,
    MakeIntert = 0x4,
    WantFlags = 0x8
}

[Flags]
public enum SaferScopes : uint
{
    Machine = 1,
    User = 2
}

[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
    public int nLength;
    public IntPtr lpSecurityDescriptor;
    public int bInheritHandle;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFO
{
    public Int32 cb;
    public string lpReserved;
    public string lpDesktop;
    public string lpTitle;
    public Int32 dwX;
    public Int32 dwY;
    public Int32 dwXSize;
    public Int32 dwYSize;
    public Int32 dwXCountChars;
    public Int32 dwYCountChars;
    public Int32 dwFillAttribute;
    public Int32 dwFlags;
    public Int16 wShowWindow;
    public Int16 cbReserved2;
    public IntPtr lpReserved2;
    public IntPtr hStdInput;
    public IntPtr hStdOutput;
    public IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
    public IntPtr hProcess;
    public IntPtr hThread;
    public int dwProcessId;
    public int dwThreadId;
}


[DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool SaferComputeTokenFromLevel(IntPtr LevelHandle, IntPtr InAccessToken, out IntPtr OutAccessToken, int dwFlags, IntPtr lpReserved);

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CreateProcessAsUser(
    IntPtr hToken,
    string lpApplicationName,
    string lpCommandLine,
    ref SECURITY_ATTRIBUTES lpProcessAttributes,
    ref SECURITY_ATTRIBUTES lpThreadAttributes,
    bool bInheritHandles,
    uint dwCreationFlags,
    IntPtr lpEnvironment,
    string lpCurrentDirectory,
    ref STARTUPINFO lpStartupInfo,
    out PROCESS_INFORMATION lpProcessInformation);

[DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool SaferCreateLevel(
    SaferScopes dwScopeId,
    SaferLevels dwLevelId,
    int OpenFlags,
    out IntPtr pLevelHandle,
    IntPtr lpReserved);

[DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool SaferCloseLevel(
    IntPtr pLevelHandle);

[DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool SaferComputeTokenFromLevel(
  IntPtr levelHandle,
  IntPtr inAccessToken,
  out IntPtr outAccessToken,
  SaferComputeTokenFlags dwFlags,
  IntPtr lpReserved
);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

这篇关于如何启动一个进程Unelevated的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 06:36