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

如何在Java中利用JNA调用CreateProcessWithTokenW并加载用户配置

在Java中加载用户配置或调用CreateProcessWithTokenW的解决方案

一、自定义JNA接口调用CreateProcessWithTokenW

CreateProcessWithTokenW 包含在advapi32.dll中,JNA/Waffle默认未提供封装,你可以通过自定义接口直接调用:

1. 定义扩展的Advapi32接口

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public interface Advapi32Extended extends StdCallLibrary {
    Advapi32Extended INSTANCE = Native.load("advapi32", Advapi32Extended.class, W32APIOptions.DEFAULT_OPTIONS);

    boolean CreateProcessWithTokenW(
        Pointer hToken,
        int dwLogonFlags,
        String lpApplicationName,
        String lpCommandLine,
        int dwCreationFlags,
        Pointer lpEnvironment,
        String lpCurrentDirectory,
        Structure lpStartupInfo,
        Structure lpProcessInformation
    );
}

2. 调用示例

假设你已经通过Waffle获取到目标用户的主token(比如WindowsIdentity对象的token):

import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.W32API;

// 从Waffle获取用户主token
Pointer userToken = new Pointer(windowsIdentity.getToken());

W32API.STARTUPINFO startupInfo = new W32API.STARTUPINFO();
W32API.PROCESS_INFORMATION processInfo = new W32API.PROCESS_INFORMATION();

// 调用CreateProcessWithTokenW,指定LOGON_WITH_PROFILE标志加载用户配置
boolean success = Advapi32Extended.INSTANCE.CreateProcessWithTokenW(
    userToken,
    0x00000001, // LOGON_WITH_PROFILE:加载用户配置文件
    "C:\\Windows\\notepad.exe",
    null,
    0,
    Pointer.NULL,
    null,
    startupInfo,
    processInfo
);

if (success) {
    // 进程创建成功后,关闭句柄释放资源
    Kernel32.INSTANCE.CloseHandle(processInfo.hProcess);
    Kernel32.INSTANCE.CloseHandle(processInfo.hThread);
} else {
    // 获取错误码排查问题
    int errorCode = Kernel32.INSTANCE.GetLastError();
    System.err.println("进程创建失败,错误码:" + errorCode);
}

二、手动调用LoadUserProfile加载配置(配合CreateProcessAsUser)

如果仍需使用CreateProcessAsUser,可以先通过LoadUserProfile加载用户配置,该函数在userenv.dll中,同样需要自定义JNA接口:

1. 定义Userenv接口和PROFILEINFO结构体

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public interface Userenv extends StdCallLibrary {
    Userenv INSTANCE = Native.load("userenv", Userenv.class, W32API.DEFAULT_OPTIONS);

    boolean LoadUserProfile(
        Pointer hToken,
        Structure lpProfileInfo
    );

    boolean UnloadUserProfile(
        Pointer hToken,
        Pointer hProfile
    );

    @Structure.FieldOrder({"dwSize", "dwFlags", "lpUserName", "lpProfilePath", "lpDefaultPath", "lpServerName", "lpPolicyPath", "hProfile"})
    class PROFILEINFO extends Structure {
        public int dwSize = size();
        public int dwFlags;
        public String lpUserName;
        public String lpProfilePath;
        public String lpDefaultPath;
        public String lpServerName;
        public String lpPolicyPath;
        public Pointer hProfile;
    }
}

2. 加载配置并创建进程

Userenv.PROFILEINFO profileInfo = new Userenv.PROFILEINFO();
profileInfo.lpUserName = "目标用户名";
profileInfo.dwFlags = 0x00000002; // PI_NOUI:不显示配置加载界面

// 加载用户配置
boolean loadSuccess = Userenv.INSTANCE.LoadUserProfile(userToken, profileInfo);
if (loadSuccess) {
    try {
        // 调用CreateProcessAsUser,指定用户配置路径
        boolean processSuccess = Advapi32.INSTANCE.CreateProcessAsUser(
            userToken,
            "C:\\Windows\\notepad.exe",
            null,
            null,
            null,
            false,
            0,
            Pointer.NULL,
            profileInfo.lpProfilePath, // 使用加载的用户配置目录
            startupInfo,
            processInfo
        );
        // 处理进程创建结果
    } finally {
        // 进程结束后必须卸载用户配置,避免资源泄漏
        Userenv.INSTANCE.UnloadUserProfile(userToken, profileInfo.hProfile);
    }
} else {
    int errorCode = Kernel32.INSTANCE.GetLastError();
    System.err.println("加载用户配置失败,错误码:" + errorCode);
}

关键注意事项

  • 权限要求:调用这些API需要进程拥有SE_INCREASE_QUOTA_NAME和SE_ASSIGNPRIMARYTOKEN_NAME权限,Waffle登录流程通常会处理,但如果遇到权限错误,需手动调整token权限。
  • 主token要求:CreateProcessWithTokenW和CreateProcessAsUser都需要用户的主token(primary token),而非模拟token,确保从Waffle获取的token类型正确。
  • 资源清理:进程创建后必须关闭PROCESS_INFORMATION中的句柄,加载的用户配置也必须调用UnloadUserProfile释放,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 11:25:23