You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AssignProcessToJobObject返回ACCESS_DENIED(CreateProcessWithTokenW启动进程场景)

问题:管理员上下文控制台应用启动当前用户进程后无法分配到JobObject(ACCESS_DENIED)

我有一个运行在管理员上下文的控制台应用,需要以当前用户上下文启动子进程,为此编写了启动进程的代码;同时为了实现控制台退出时自动终止子进程,编写了基于JobObject的进程跟踪代码。

已修正原代码中CreateProcessWithTokenW调用语法错误及AddProcessHandle参数错误,但调用AssignProcessToJobObject时仍返回false并触发ACCESS_DENIED错误,无法完成进程跟踪。

预期效果:进程句柄成功分配给JobObject,控制台应用退出时该子进程自动终止。

启动当前用户进程的代码

private static bool RunAsCurrentUser(string fileName, string arguments)
{
    var hProcessToken = IntPtr.Zero;
    try
    {
        var process = GetCurrentProcess();
        if (!OpenProcessToken(process, 0x0020, ref hProcessToken))
            return false;

        var tkp = new TOKEN_PRIVILEGES
        {
            PrivilegeCount = 1,
            Privileges = new LUID_AND_ATTRIBUTES[1]
        };

        if (!LookupPrivilegeValue(null, "SeIncreaseQuotaPrivilege", ref tkp.Privileges[0].Luid))
            return false;

        tkp.Privileges[0].Attributes = 0x00000002;

        if (!AdjustTokenPrivileges(hProcessToken, false, ref tkp, 0, IntPtr.Zero, IntPtr.Zero))
            return false;
    }
    finally
    {
        CloseHandle(hProcessToken);
    }

    var hwnd = NativeMethods.GetShellWindow();
    if (hwnd == IntPtr.Zero)
        return false;

    var hShellProcess = IntPtr.Zero;
    var hShellProcessToken = IntPtr.Zero;
    var hPrimaryToken = IntPtr.Zero;
    try
    {
        // Get the PID of the desktop shell process.
        uint dwPID;
        if (GetWindowThreadProcessId(hwnd, out dwPID) == 0)
            return false;

        // Open the desktop shell process in order to query it (get the token)
        hShellProcess = OpenProcess(NativeMethods.ProcessAccessFlags.QueryInformation, false, dwPID);
        if (hShellProcess == IntPtr.Zero)
            return false;

        // Get the process token of the desktop shell.
        if (!OpenProcessToken(hShellProcess, 0x0002, ref hShellProcessToken))
            return false;
        var dwTokenRights = 395U;

        // CreateProcessWithTokenW (contrary to current documentation).
        if (!DuplicateTokenEx(hShellProcessToken, dwTokenRights, IntPtr.Zero, NativeMethods.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, NativeMethods.TOKEN_TYPE.TokenPrimary, out hPrimaryToken))
            return false;
        int STARTF_USESHOWWINDOW = 0x00000001;
        short SW_SHOW = 5;
        // Start the target process with the new token.
        var si = new STARTUPINFO();
        var pi = new PROCESS_INFORMATION();
        si.cb = Marshal.SizeOf(si);
        si.lpDesktop = "winsta0\\default";
        si.dwFlags = STARTF_USESHOWWINDOW;
        si.wShowWindow = SW_SHOW;
        string finalArgs = $"\"{fileName}\" {arguments}";               
        if (!CreateProcessWithTokenW(hPrimaryToken, 0, fileName, finalArgs, 0, IntPtr.Zero, Path.GetDirectoryName(fileName), ref si, out pi))
            return false;                
        ChildProcessTracker.AddProcessHandle(pi.hProcess);
        return true;
    }
    catch (Exception) { return false; }
    finally
    {
        NativeMethods.CloseHandle(hShellProcessToken);
        NativeMethods.CloseHandle(hPrimaryToken);
        NativeMethods.CloseHandle(hShellProcess);
    }
}

进程跟踪(JobObject)代码

public static void AddProcessHandle(IntPtr handle)
{
    if (s_jobHandle != IntPtr.Zero)
    {
        bool success = AssignProcessToJobObject(s_jobHandle, handle);
        if (!success)
            throw new Win32Exception();
    }
}


static ChildProcessTracker()
{
    string jobName = "MyProcess" + Process.GetCurrentProcess().Id;
    s_jobHandle = CreateJobObject(IntPtr.Zero, jobName);

    var info = new JobobjectBasicLimitInformation();
    info.LimitFlags = JOBOBJECTLIMITS.KillOnJobClose;

    var extendedInfo = new JobObjectExtendedLimitInformation();
    extendedInfo.BasicLimitInformation = info;
    int length = Marshal.SizeOf(typeof(JobObjectExtendedLimitInformation));
    IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);
    try
    {
        Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);

        SetInformationJobObject(s_jobHandle, JobObjectInfoType.ExtendedLimitInformation,
            extendedInfoPtr, (uint)length);
    }
    finally
    {
        Marshal.FreeHGlobal(extendedInfoPtr);
    }
}

内容的提问来源于stack exchange,提问作者manikanta vh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 00:47:03