【问题标题】:CreateProcessAsUserW error code 6 Invalid Handle JNACreateProcessAsUserW 错误代码 6 无效句柄 JNA
【发布时间】:2021-09-18 00:01:13
【问题描述】:

我正在使用 JNA 调用 Windows API。我想以特定用户的身份启动一个进程(不管哪个)。我使用的两个 API 调用是:

LogonUserW 成功,但 CreateProcessAsUserW 失败并出现错误 6。根据Windows System Error Codes Doc,这对应于“ERROR_INVALID_HANDLE”。

据我所知,我传入的唯一句柄是用户句柄。我看不出这有什么问题。根据 LogonUserW 文档,

在大多数情况下,返回的句柄是您可以在调用 CreateProcessAsUser 函数时使用的主要标记。但是,如果您指定 LOGON32_LOGON_NETWORK 标志,LogonUser 将返回一个模拟令牌,除非您调用 DuplicateTokenEx 将其转换为主令牌,否则您无法在 CreateProcessAsUser 中使用该令牌。

但是,我不使用 LOGON32_LOGON_NETWORK。

一些结构参数有句柄,但我要么传递 NULL,要么通过 API 调用而不是我来填充它们。

这是我的代码的主要内容:

final PointerByReference userPrimaryToken =
    new PointerByReference();
System.out.printf(
    "ptr.peer = %d\n",
    Pointer.nativeValue(userPrimaryToken.getValue())
);

final boolean logonOk = MyWinBase.INSTANCE.LogonUserW(
    toCString(<my-username>), // hidden
    toCString("ANT"),
    toCString(<my-password>), // hidden
    /* This logon type is intended for batch servers, where
    processes may be executing on behalf of a user without their
    direct intervention. This type is also for higher
    performance servers that process many plaintext
    authentication attempts at a time, such as mail or web
    servers.*/
    WinBase.LOGON32_LOGON_BATCH,
    WinBase.LOGON32_PROVIDER_DEFAULT,
    userPrimaryToken
);
System.out.printf("ok = %b\n", logonOk);
System.out.printf(
    "ptr.peer = %d\n",
    Pointer.nativeValue(userPrimaryToken.getValue())
);

final STARTUPINFOW.ByReference startupInfoW =
    new STARTUPINFOW.ByReference();
startupInfoW.cb = startupInfoW.size();
startupInfoW.lpReserved = Pointer.NULL;
startupInfoW.lpDesktop = Pointer.NULL;
startupInfoW.lpTitle = Pointer.NULL;
startupInfoW.dwFlags
    = startupInfoW.dwX = startupInfoW.dwY
    = startupInfoW.dwXSize = startupInfoW.dwYSize
    = startupInfoW.dwXCountChars = startupInfoW.dwYCountChars
    = startupInfoW.dwFillAttribute
    = startupInfoW.wShowWindow
    = 0;
startupInfoW.cbReserved2  = 0;
startupInfoW.lpReserved2 = Pointer.NULL;
startupInfoW.hStdInput = startupInfoW.hStdOutput
    = startupInfoW.hStdError
    = Pointer.NULL;

final PROCESS_INFORMATION.ByReference processInformation =
    new PROCESS_INFORMATION.ByReference();
processInformation.hProcess = processInformation.hThread
    = Pointer.NULL;
processInformation.dwProcessId = processInformation.dwThreadId
    = 0;

final boolean createProcessOk = MyProcessThreadsApi.INSTANCE
    .CreateProcessAsUserW(
        userPrimaryToken.getPointer(),
        toCString("C:\\Windows\\System32\\cmd.exe"),
        // execute and terminate
        toCString("/c whoami > whoami.txt"),
        Pointer.NULL,
        Pointer.NULL,
        false,
        WinBase.CREATE_UNICODE_ENVIRONMENT,
        new PointerByReference(),
        Pointer.NULL,
        startupInfoW,
        processInformation
    );
System.out.printf("ok = %b\n", createProcessOk);
System.out.printf(
    "dwProcessId = %d\n", processInformation.dwProcessId
);
System.out.printf(
    "last err code = %d\n",
    ErrHandlingApi.INSTANCE.GetLastError()
);

这是我的输出:

ptr.peer = 0
ok = true
ptr.peer = 1040
ok = false
dwProcessId = 0
last err code = 6

有什么建议吗?

【问题讨论】:

    标签: java c++ windows winapi jna


    【解决方案1】:

    看这段代码:

    final PointerByReference userPrimaryToken = ...;
    

    在线文档说它代表一个指向指针的指针,C 表示法void**
    https://java-native-access.github.io/jna/4.2.1/com/sun/jna/ptr/PointerByReference.html
    在 LogonUser 的文档中,它需要一个指向 HANDLE 的 PHALDLE 指针,它类似于指向指针的指针,因为 HANDLE 类似于指针(它被声明为 typedef void *HANDLE;)。
    https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-logonuserw

    BOOL LogonUserW(
      ....
      DWORD   dwLogonProvider,
      PHANDLE phToken
    );
    

    但在 CreateProcessAsUser 的文档中指定此函数接受 HANDLE,而不是 PHANDLE
    https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw

    BOOL CreateProcessAsUserW(
      HANDLE                hToken,
      LPCWSTR               lpApplicationName,
      ....
    );
    

    所以我希望你传递 getValue 而不是 getPointer。通过使用 getPointer 您可以获得指针本身,在您的情况下,它很可能是指向指针的指针。我不知道 JNA,但期望来自 WinAPI 的知识

    final boolean createProcessOk = MyProcessThreadsApi.INSTANCE
        .CreateProcessAsUserW(
            userPrimaryToken.getValue(),
            ....
        );
    

    【讨论】:

    • 谢谢!!!我应该阅读方法描述。您对 void* 与 void** 值混淆是完全正确的。我仍然有其他错误代码不同的错误,但它们更多的是关于权限和访问。我会继续调试。
    猜你喜欢
    • 1970-01-01
    • 2013-08-01
    • 2019-10-16
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    相关资源
    最近更新 更多