Skip to content

Commit

Permalink
fix: 修复不支持中文路径的问题。
Browse files Browse the repository at this point in the history
  • Loading branch information
hamflx committed Aug 9, 2022
1 parent 9071f52 commit 9fbc313
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 53 deletions.
19 changes: 13 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "common"
version = "0.1.8"
version = "0.1.9"
edition = "2021"

[dependencies]
Expand Down
70 changes: 42 additions & 28 deletions packages/common/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ use serde::{Deserialize, Serialize};
use std::{
ffi::{c_void, CStr, CString},
intrinsics::transmute,
mem::MaybeUninit,
mem::{size_of_val, MaybeUninit},
ptr,
slice::{from_raw_parts, from_raw_parts_mut},
sync::Mutex,
};
use widestring::U16CString;
use widestring::{U16CString, WideCString};
use windows_sys::{
core::{PCSTR, PCWSTR, PWSTR},
core::{PCWSTR, PWSTR},
Win32::{
Foundation::{GetLastError, BOOL, HANDLE},
Security::SECURITY_ATTRIBUTES,
System::{
Diagnostics::Debug::{WriteProcessMemory, PROCESSOR_ARCHITECTURE_INTEL},
LibraryLoader::{GetModuleFileNameA, GetProcAddress, LoadLibraryA},
LibraryLoader::{GetModuleFileNameW, GetProcAddress, LoadLibraryW},
Memory::{VirtualAllocEx, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READWRITE},
SystemInformation::{
GetNativeSystemInfo, GetSystemDirectoryA, FIRMWARE_TABLE_ID,
GetNativeSystemInfo, GetSystemDirectoryW, FIRMWARE_TABLE_ID,
FIRMWARE_TABLE_PROVIDER, SYSTEM_INFO,
},
Threading::{
Expand Down Expand Up @@ -452,11 +452,7 @@ fn detour_create_process(
let should_inject = opts
.as_ref()
.map(|opts| {
opts.includes_system_process
|| (!app_name_string.trim().is_empty()
&& !check_path_is_system(app_name_string.as_str())
|| !cmd_line_string.trim().is_empty()
&& !check_path_is_system(cmd_line_string.as_str()))
should_inject_process(opts, app_name_string.as_str(), cmd_line_string.as_str())
})
.unwrap_or(true);
if should_inject {
Expand Down Expand Up @@ -541,33 +537,45 @@ pub fn enable_hook(opts: Option<InjectOptions>) -> anyhow::Result<()> {
Ok(())
}

fn should_inject_process(opts: &InjectOptions, app_name: &str, cmd_line: &str) -> bool {
opts.includes_system_process
|| (if !app_name.trim().is_empty() {
!check_path_is_system(app_name)
} else {
!check_path_is_system(cmd_line)
})
}

unsafe fn get_proc_address(
proc_name: &str,
module_name: &str,
) -> anyhow::Result<unsafe extern "system" fn() -> isize> {
let module_name_cstr = CString::new(module_name)?;
let proc_name_cstr = CString::new(proc_name)?;
let h_inst = LoadLibraryA(module_name_cstr.as_ptr() as PCSTR);

let module_name_cstr = WideCString::from_str(module_name)?;
let h_inst = LoadLibraryW(module_name_cstr.as_ptr());
if h_inst == 0 {
return Err(anyhow::anyhow!(
"LoadLibraryA failed: {}",
"LoadLibraryW failed: {}",
std::io::Error::last_os_error()
));
}

GetProcAddress(h_inst, proc_name_cstr.as_ptr() as PCSTR).ok_or_else(|| {
let proc_name_cstr = CString::new(proc_name)?;
GetProcAddress(h_inst, proc_name_cstr.as_ptr() as _).ok_or_else(|| {
anyhow::anyhow!("GetProcAddress failed: {}", std::io::Error::last_os_error())
})
}

fn check_path_is_system(path: &str) -> bool {
let mut path_buffer = [0; 4096];
let size = unsafe { GetSystemDirectoryA(path_buffer.as_mut_ptr(), path_buffer.len() as u32) };
let size = unsafe { GetSystemDirectoryW(path_buffer.as_mut_ptr(), path_buffer.len() as _) };
if size > 0 {
if let Ok(sys_dir) = String::from_utf8(path_buffer[..size as usize].to_vec()) {
let slash_sys_dir = sys_dir.replace('\\', "/");
let slash_path = path.replace('\\', "/");
let sys_dir = unsafe { WideCString::from_ptr(path_buffer.as_ptr(), size as _) }
.ok()
.and_then(|s| s.to_string().ok());
info!("System directory: {:?}", sys_dir);
if let Some(sys_dir) = sys_dir {
let slash_sys_dir = sys_dir.replace('\\', "/").to_ascii_lowercase();
let slash_path = path.replace('\\', "/").to_ascii_lowercase();
return slash_path.starts_with(&slash_sys_dir)
|| (slash_path.chars().next() == Some('"')
&& slash_path[1..].starts_with(&slash_sys_dir));
Expand Down Expand Up @@ -601,11 +609,11 @@ unsafe fn inject_to_process(
info!("Get enable_hook address from {}", lib_full_path);
let fp_enable_hook = get_proc_address("enable_hook", lib_full_path)?;

let library_name_with_null = format!("{}\0", LIBRARY_NAME);
let core_module_handle = LoadLibraryA(library_name_with_null.as_ptr() as PCSTR);
let mut core_full_name_buffer = [0u8; 4096];
let library_name_with_null = WideCString::from_str(LIBRARY_NAME)?;
let core_module_handle = LoadLibraryW(library_name_with_null.as_ptr() as _);
let mut core_full_name_buffer = [0; 4096];
if core_module_handle == 0
|| GetModuleFileNameA(
|| GetModuleFileNameW(
core_module_handle,
core_full_name_buffer.as_mut_ptr(),
core_full_name_buffer.len() as u32,
Expand All @@ -616,8 +624,14 @@ unsafe fn inject_to_process(
GetLastError()
));
}
let library_name_addr = write_process_memory(process_handle, &core_full_name_buffer)?;
let fp_load_library = get_proc_address("LoadLibraryA", "kernel32.dll")?;
let library_name_addr = write_process_memory(
process_handle,
std::slice::from_raw_parts(
core_full_name_buffer.as_ptr() as _,
size_of_val(&core_full_name_buffer),
),
)?;
let fp_load_library = get_proc_address("LoadLibraryW", "kernel32.dll")?;
let load_library_thread = CreateRemoteThread(
process_handle,
ptr::null(),
Expand All @@ -634,7 +648,7 @@ unsafe fn inject_to_process(
));
}
info!(
"Created LoadLibraryA thread with id: {}",
"Created LoadLibraryW thread with id: {}",
GetThreadId(load_library_thread)
);
let wait_result = WaitForSingleObject(load_library_thread, 0xFFFFFFFF);
Expand All @@ -648,7 +662,7 @@ unsafe fn inject_to_process(
if GetExitCodeThread(load_library_thread, &mut module_handle as *mut u32) != 0
&& module_handle == 0
{
return Err(anyhow::anyhow!("Remote LoadLibraryA failed"));
return Err(anyhow::anyhow!("Remote LoadLibraryW failed"));
}

let enable_hook_params = if let Some(opts) = opts {
Expand Down
2 changes: 1 addition & 1 deletion packages/huawei-pc-manager-bootstrap-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "huawei-pc-manager-bootstrap-core"
version = "0.1.8"
version = "0.1.9"
edition = "2021"

[lib]
Expand Down
3 changes: 2 additions & 1 deletion packages/huawei-pc-manager-bootstrap/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "huawei-pc-manager-bootstrap"
version = "0.1.8"
version = "0.1.9"
edition = "2021"

[dependencies]
Expand All @@ -27,3 +27,4 @@ simplelog = "0.11.2"
directories = "4.0.1"
sysinfo = { git = "https://github.com/hamflx/sysinfo.git" }
clap = { version = "3.1.12", features = ["derive"] }
widestring = "1.0.2"
10 changes: 5 additions & 5 deletions packages/huawei-pc-manager-bootstrap/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::ffi::CStr;
use std::fs::File;
use std::path::PathBuf;
use std::process::Command;
Expand All @@ -17,7 +16,8 @@ use log::{error, info, warn, LevelFilter};
use rfd::FileDialog;
use simplelog::{ConfigBuilder, WriteLogger};
use sysinfo::{ProcessExt, SystemExt};
use windows_sys::Win32::UI::Shell::{SHGetSpecialFolderPathA, CSIDL_PROGRAM_FILES};
use widestring::WideCStr;
use windows_sys::Win32::UI::Shell::{SHGetSpecialFolderPathW, CSIDL_PROGRAM_FILES};

pub struct BootstrapApp {
log_file_path: String,
Expand Down Expand Up @@ -251,7 +251,7 @@ impl BootstrapApp {
fn get_pc_manager_dir() -> anyhow::Result<PathBuf> {
let mut path_buffer = [0; 4096];
let get_dir_success = unsafe {
SHGetSpecialFolderPathA(
SHGetSpecialFolderPathW(
0,
path_buffer.as_mut_ptr(),
CSIDL_PROGRAM_FILES.try_into().unwrap(),
Expand All @@ -266,12 +266,12 @@ impl BootstrapApp {
}

let program_files_dir =
unsafe { CStr::from_ptr(path_buffer.as_ptr() as *const i8).to_str()? };
unsafe { WideCStr::from_ptr_str(path_buffer.as_ptr()).to_string()? };
let x86_suffix = " (x86)";
let program_files_dir = if program_files_dir.ends_with(x86_suffix) {
&program_files_dir[..program_files_dir.len() - x86_suffix.len()]
} else {
program_files_dir
&program_files_dir
};

Ok([program_files_dir, "Huawei", "PCManager"].iter().collect())
Expand Down
23 changes: 13 additions & 10 deletions packages/huawei-pc-manager-bootstrap/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] //Hide console window in release builds on Windows, this blocks stdout.
#![feature(iter_intersperse)]

use std::ffi::CString;

use clap::Parser;
use windows_sys::Win32::UI::Shell::{IsUserAnAdmin, ShellExecuteA};
use widestring::WideCString;
use windows_sys::Win32::UI::Shell::{IsUserAnAdmin, ShellExecuteW};

mod app;

Expand Down Expand Up @@ -35,8 +34,11 @@ fn main() {
println!("No administrator");
return;
}
let executable_file_null_ter =
format!("{}\0", std::env::current_exe().unwrap().to_str().unwrap());
let executable_file_null_ter = WideCString::from_str(format!(
"{}\0",
std::env::current_exe().unwrap().to_str().unwrap()
))
.unwrap();

let mut cmd_line: String = std::env::args()
.skip(1)
Expand All @@ -50,14 +52,15 @@ fn main() {
.intersperse(" ".to_string())
.collect();
cmd_line.push_str(" --ensure-admin");
let cmd_line = CString::new(cmd_line).unwrap();

let cmd_line = WideCString::from_str(cmd_line).unwrap();
unsafe {
ShellExecuteA(
ShellExecuteW(
0,
"runas\0".as_ptr(),
WideCString::from_str("runas\0").unwrap().as_ptr(),
executable_file_null_ter.as_ptr(),
cmd_line.as_ptr() as *const u8,
0 as *const u8,
cmd_line.as_ptr(),
0 as _,
5,
)
};
Expand Down
2 changes: 1 addition & 1 deletion packages/version/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "version"
version = "0.1.8"
version = "0.1.9"
edition = "2021"

[lib]
Expand Down

0 comments on commit 9fbc313

Please sign in to comment.