【问题标题】:CreateProcessAsUserW processes not searching PATHCreateProcessAsUserW 进程未搜索 PATH
【发布时间】:2021-07-22 06:05:02
【问题描述】:

我的目标是以您在cmd.exe 中运行它们的相同方式运行进程。例如:

C:\Users\zjoseal\Desktop>whoami.exe
ant\zjoseal

这是因为cmd.exe 在搜索路径中搜索whoami.exe。我还需要环境变量评估。

我还需要以不同的用户身份执行该过程,因此我不得不使用 Windows API 的 CreateProcessAsUserW 而不是 Java 的简单 Runtime::execProcessBuilder

不幸的是,这个 API 函数没有提供我上面提到的命令行解释器功能。当我运行C:\Windows\System32\cmd.exe /c whoami.exe > whoami.txt 时,我得到:

'whoami.exe' is not recognized as an internal or external command,
operable program or batch file.

只有当我运行"C:\\Windows\\System32\\cmd.exe /c C:\\Windows\\SysWOW64\\whoami.exe > whoami.txt"(注意whoami 的绝对路径)时,我的程序才能工作。

请注意,whoami 只是一个示例程序。我需要像在命令行上运行任何给定命令一样运行它。

我需要做什么才能获得完整的命令行体验?根据CreateProcessAsUserW docs,如果我将NULL传递给lpEnvironment,则新进程会继承调用进程的环境,因此PATH应该会被继承。

这是我的代码的主要部分:

// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfow
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;
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_information
final PROCESS_INFORMATION.ByReference processInformation =
    new PROCESS_INFORMATION.ByReference();
processInformation.hProcess = processInformation.hThread
    = Pointer.NULL;
processInformation.dwProcessId = processInformation.dwThreadId
    = 0;
// Converts string to char array with 0 as last element.
final char[] whoamiCmd = toCString(
    "C:\\Windows\\System32\\cmd.exe /c whoami.exe > whoami.txt"
);
System.out.printf(
    "last err code = %d\n",
    ErrHandlingApi.INSTANCE.GetLastError()
);
final boolean createProcessOk = MyProcessThreadsApi.INSTANCE
    .CreateProcessAsUserW(
        userPrimaryToken.getValue(),
        Pointer.NULL,
        whoamiCmd,
        Pointer.NULL,
        Pointer.NULL,
        false,
        WinBase.CREATE_UNICODE_ENVIRONMENT,
        new PointerByReference(),
        Pointer.NULL,
        startupInfoW,
        processInformation
    );
System.out.printf(
    "last err code = %d\n",
    ErrHandlingApi.INSTANCE.GetLastError()
);
System.out.printf("ok = %b\n", createProcessOk);
System.out.printf(
    "dwProcessId = %d\n", processInformation.dwProcessId
);
public static char[] toCString(final String str) {
    final char[] cString = new char[str.length() + 1];
    for (int i = 0; i < str.length(); i++) {
        cString[i] = str.charAt(i);
    }
    // c-strings end in 0 for lack of bounds checking
    cString[cString.length-1] = 0;
    return cString;
}
C:\Users\zjoseal\Desktop>java -cp windows-credentials-poc-1.0-SNAPSHOT.jar Main
last err code = 0
last err code = 0
last err code = 0
last err code = 0
my-password
ptr.peer = 0
last err code = 0
last err code = 0
ok = true
ptr.peer = 1052
last err code = 0
last err code = 5
ok = true
dwProcessId = 8936

C:\Users\zjoseal\Desktop>'whoami.exe' is not recognized as an internal or external command,
operable program or batch file.

【问题讨论】:

  • exec cmd 毫无意义。直接运行whoami.exe
  • 还有redirect its output using the STARTUPINFO struct,这样你就可以自己捕获输出,然后你可以用它做任何你想做的事情。
  • 如链接所说CreateProcessAsUserW - "...该函数不会使用搜索路径..." docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/…
  • @Christian.K 你和理查德都是对的:它忽略了 PATH 但它确实有一组它搜索的目录。但同一段表明它使用“第一个空格分隔的标记”,在上述情况下是 cmd.exe。执行得很好。在此示例中,您不需要 cmd.exe 的路径,但如果参数不在当前目录中,则需要参数的路径。
  • new PointerByReference() 是你的错误lpEnvironment

标签: java c++ windows winapi jna


【解决方案1】:

cmets 中有一个关于CreateProcessAsUserW 行为的细微讨论,以防有人感兴趣。

但是,C:\\Windows\\System32\\cmd.exe /c whoami.exe &gt; whoami.txt 不起作用的原因是我错误地传递了 lpEnvironment 参数。而不是通过new PointerByReference(),我应该通过Pointer.NULL。这需要将我的 JNA 函数的参数类型更改为 Pointer 而不是 PointerByReference

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-01
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 1970-01-01
    相关资源
    最近更新 更多