CreateProcessAsUserW 错误代码 6 无效句柄 JNA
CreateProcessAsUserW error code 6 Invalid Handle JNA
我正在使用 JNA 调用 Windows API。我想以特定用户的身份启动一个进程(无关紧要)。我使用的两个 API 调用是:
LogonUserW 成功,但 CreateProcessAsUserW 失败并出现错误 6。根据 Windows System Error Codes Doc,这对应于“ERROR_INVALID_HANDLE”。
据我所知,我传入的唯一句柄是用户句柄。我看不出这有什么问题。根据 LogonUserW 文档,
In most cases, the returned handle is a primary token that you can use in calls to the CreateProcessAsUser function. However, if you specify the LOGON32_LOGON_NETWORK flag, LogonUser returns an impersonation token that you cannot use in CreateProcessAsUser unless you call DuplicateTokenEx to convert it to a primary token.
但是,我不使用 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
有什么建议吗?
看这段代码:
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(),
....
);
我正在使用 JNA 调用 Windows API。我想以特定用户的身份启动一个进程(无关紧要)。我使用的两个 API 调用是:
LogonUserW 成功,但 CreateProcessAsUserW 失败并出现错误 6。根据 Windows System Error Codes Doc,这对应于“ERROR_INVALID_HANDLE”。
据我所知,我传入的唯一句柄是用户句柄。我看不出这有什么问题。根据 LogonUserW 文档,
In most cases, the returned handle is a primary token that you can use in calls to the CreateProcessAsUser function. However, if you specify the LOGON32_LOGON_NETWORK flag, LogonUser returns an impersonation token that you cannot use in CreateProcessAsUser unless you call DuplicateTokenEx to convert it to a primary token.
但是,我不使用 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
有什么建议吗?
看这段代码:
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(),
....
);