I need to invoke windows process by another user with primary token, using jna (java). I am able to peform:
- Login with username, domain & password
- Duplicate token, to generate primary token with dwDesiredAccess set to 33554432 . I'm not sure on the value, this may be the culprit here. Please guide what's the correct value for this. I need to give MAXIMUM_ALLOWED permission, not sure what's equivalent for that in terms of java Integer
- Invoking some random windows command.
On step 3, i'm getting issue that A required privilege is not held by the client. I have tried different ways, OpenThreadToken and AdjustTokenPrivilege, but that didn't work for me.
Can someone please guide me on how to invoke a process using jna with below code.
Note: I need to invoke multiple commands thus, need to use primary token way.
public static void main(String[] args) throws Exception {
HANDLE loginToken = null;
HANDLE primaryToken = null;
try {
loginToken = performLogin("username", "domain", "password");
setThreadToken(loginToken);
primaryToken = createPrimaryToken(loginToken, 33554432);
invokeCommand(primaryToken);
} catch (ProcessCreationException e) {
e.printStackTrace();
} finally {
if (loginToken != null)
Kernel32.INSTANCE.CloseHandle(loginToken);
if (primaryToken != null)
Kernel32.INSTANCE.CloseHandle(primaryToken);
}
}
private static HANDLE performLogin(String username, String domain, String password) throws ProcessCreationException {
HANDLEByReference pointer = new HANDLEByReference();
invokeWindowsMethod("login", () -> Advapi32.INSTANCE.LogonUser(username, domain,
password, WinBase.LOGON32_LOGON_NETWORK, WinBase.LOGON32_PROVIDER_DEFAULT, pointer));
return pointer.getValue();
}
private static HANDLE createPrimaryToken(HANDLE loginToken, int desiredAccess) throws ProcessCreationException {
System.out.println("dwDesiredAccess:" + desiredAccess);
HANDLEByReference pointer = new HANDLEByReference();
invokeWindowsMethod("duplicated", () -> Advapi32.INSTANCE.DuplicateTokenEx(
loginToken,
desiredAccess,
null,
SECURITY_IMPERSONATION_LEVEL.SecurityDelegation,
TOKEN_TYPE.TokenPrimary,
pointer
));
return pointer.getValue();
}
private static void invokeCommand(HANDLE primaryToken) throws ProcessCreationException {
STARTUPINFO si = new STARTUPINFO();
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
pi.clear();
invokeWindowsMethod("invokeCommand", () -> Advapi32.INSTANCE.CreateProcessAsUser(
primaryToken,
null,
"whoami",
null,
null,
true,
1024,
null,
null,
si,
pi));
}
private static void invokeWindowsMethod(String method, Supplier<Boolean> processor) throws ProcessCreationException {
Boolean res = processor.get();
System.out.println(method + " : " + res);
if (!res) {
throw lastErrorProcessCreationException(method, Kernel32.INSTANCE.GetLastError());
}
}
private static ProcessCreationException lastErrorProcessCreationException(String context, int errorCode) {
return new ProcessCreationException(String.format("[%s] %s", context,
Kernel32Util.formatMessageFromLastErrorCode(errorCode)));
}
You are
And you need
The Windows API generally tells you what privileges each command needs.
I assume you found the value 33554432 in someone's code somewhere. It's generally more readable if you use the appropriate constant corresponding to its meaning. A decimal to hex converter tells me that's 0x2000000 which is WSManFlagSkipRevocationCheck. Define that constant and use it in your code ... if indeed that's the one you need. But what you really need is shown by the docs for the command you are running:
The "Random Command" you chose is
CreateProcessAsUserwhich tells you exactly how to handle this error:So your calling process doesn't have the right privileges. You need to enable those. See this answer for how to enable a privelege on the current process using Java/JNA code (change the
SE_DEBUG_NAMEto the privilege you are requesting).Further, the
CreateProcessAsUserdocs continue:Requiring no special privilege seems a better option for you to use than a "Random windows command" that needs other steps.