Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: If a GUI program has a space in its program exe file path, it'll failed started from windows service. #2205

Closed
fengbenming opened this issue Nov 30, 2022 · 5 comments
Labels
question Further information is requested

Comments

@fengbenming
Copy link

Which crate is this about?

windows

Crate version

0.43.0

Summary

when I use CreateProcessAsUserW to start a GUI program from windows service, if the the GUI program file path has space in it, it will started and then quit immediately. if the program file path has no space, it will started OK.

additional: if start the GUI program not from windows service, it'll ok in spite of a space in file path or not.

Toolchain version/configuration

Default host: x86_64-pc-windows-msvc
rustup home: C:\Users\PC.rustup

stable-x86_64-pc-windows-msvc (default)
rustc 1.64.0 (a55dd71d5 2022-09-19)

Reproducible example

pub unsafe fn get_cur_user_token() -> ::windows::core::Result<HANDLE> {
    let mut h_token: HANDLE = HANDLE::default();

    let snapshot_result = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    let snapshot = snapshot_result?;
    let mut process_entry = PROCESSENTRY32W {
        dwSize: std::mem::size_of::<PROCESSENTRY32W>() as u32,
        ..Default::default()
    };

    let cur_session_id = WTSGetActiveConsoleSessionId();

    if Process32FirstW(snapshot, &mut process_entry).as_bool() {
        loop {
            if Process32NextW(snapshot, &mut process_entry).as_bool() {
                let abc =
                    &process_entry.szExeFile[..PCWSTR::from(h!("explorer.exe")).as_wide().len()];
                if abc.eq(PCWSTR::from(h!("explorer.exe")).as_wide()) {
                    let mut psessionid: u32 = 0;
                    ProcessIdToSessionId(process_entry.th32ProcessID, &mut psessionid);
                    if cur_session_id != psessionid {
                        continue;
                    }

                    let handle_result = OpenProcess(
                        PROCESS_QUERY_INFORMATION,
                        false,
                        process_entry.th32ProcessID,
                    );

                    if OpenProcessToken(handle_result?, TOKEN_ALL_ACCESS, &mut h_token).as_bool() {
                        return Ok(h_token);
                    }

                    break;
                }
            } else {
                break;
            }
        }
    }
    Err(::windows::core::Error::new(HRESULT(1), HSTRING::new()))
}

pub fn create_process_as_user() -> AgentResult<()> {
    unsafe {
        let mut pi = PROCESS_INFORMATION::default();

        let si = STARTUPINFOW {
            cb: std::mem::size_of::<STARTUPINFOW>() as u32,
            dwFlags: STARTF_USESHOWWINDOW,
            wShowWindow: SW_SHOWMAXIMIZED.0 as u16,
            ..Default::default()
        };

        let package_exe = PCWSTR::from(h!(
            r#"C:\Users\PC\AppData\Local\xxxxx\xxxxx.exe"# // r"C:\Program Files\xxxxx\xxxxx.exe"
        ));

        let h_token: HANDLE = get_cur_user_token()?;

        let mut h_token_dup: HANDLE = HANDLE::default();

        if !DuplicateTokenEx(
            h_token,
            TOKEN_ALL_ACCESS,
            None,
            SecurityIdentification,
            TokenPrimary,
            &mut h_token_dup,
        )
        .as_bool()
        {
            CloseHandle(h_token);
            return Ok(());
        }

        if !CreateProcessAsUserW(
            h_token_dup,
            package_exe,
            PWSTR::null(),
            None,
            None,
            false,
            NORMAL_PRIORITY_CLASS.0 | CREATE_NEW_CONSOLE.0,
            None,
            None,
            &si,
            &mut pi,
        )
        .as_bool()
        {
            CloseHandle(h_token_dup);
        }
        Ok(())
    }
}

Crate manifest

[dependencies]
windows-service = "0.5.0"
serde = { version = "1.0", features = ["derive"] }
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
rust-crypto = "0.2.36"
dotenv = "0.15.0"
lazy_static = "1.4.0"

[dependencies.windows]
version = "0.43.0"
features = [
    "Win32_System_ApplicationInstallationAndServicing",
    "Win32_System_Threading",
    "Win32_Foundation",
    "Win32_Security",
    "Win32_UI_WindowsAndMessaging",
    "Win32_System_RemoteDesktop",
    "Win32_System_Diagnostics_ToolHelp",
    "Win32_System_EventLog",
    "Win32_System_Environment",
    "Win32_System_Registry",
]

Expected behavior

No response

Actual behavior

No response

Additional comments

No response

@fengbenming fengbenming added the bug Something isn't working label Nov 30, 2022
@fengbenming fengbenming changed the title Bug: Bug: If a GUI program has a space in its program exe file path, it'll failed started from windows service. Nov 30, 2022
@riverar riverar added question Further information is requested and removed bug Something isn't working labels Nov 30, 2022
@riverar
Copy link
Collaborator

riverar commented Nov 30, 2022

@kennykerr
Copy link
Collaborator

Please ask general API questions on https://stackoverflow.com/ or https://learn.microsoft.com/en-us/answers/topics/windows-api.html

@fengbenming
Copy link
Author

fengbenming commented Dec 1, 2022

Did you try quoting your paths?

Thanks very much for your reply, riverar : )
I have try this before, and I try it again seriously after your suggestion, and the problem still exist.
I think the problem is case by a space in file path and also is not case by a space in file path, it's contradiction. let me talk about:

  1. when there is no space in path, the program started by service ok. according to this, I guess the problem case by a space in file path.
  2. when there is a space in path, the program can started by service, I can see the GUI window, but exit immediately. according to this, I can guess the program exe path with a space is ok, CreateProcessAsUserW function can find the program exe through path with a space.

so, it's contradiction and confuse me, why GUI program exit immediately, path? security? or others? I don't know and I can't find any logs.

@fengbenming
Copy link
Author

Please ask general API questions on https://stackoverflow.com/ or https://learn.microsoft.com/en-us/answers/topics/windows-api.html

Ok, thanks for relpy!

@fengbenming fengbenming changed the title Bug: If a GUI program has a space in its program exe file path, it'll failed started from windows service. Question: If a GUI program has a space in its program exe file path, it'll failed started from windows service. Dec 1, 2022
@fengbenming
Copy link
Author

This problem has sovled. When you use system user or start the program by user with administrator role from windows service, regardless of a space in the program path or not, it will start ok.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants