Hook `GetModuleFileNameA` for mwldeppc GC 3.0+
This commit is contained in:
parent
db4f9af254
commit
b85eab4cc8
|
@ -70,7 +70,7 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sjiswrap"
|
name = "sjiswrap"
|
||||||
version = "1.1.0"
|
version = "1.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
|
|
|
@ -3,7 +3,7 @@ name = "sjiswrap"
|
||||||
description = "UTF-8 to Shift JIS wrapper for old compilers."
|
description = "UTF-8 to Shift JIS wrapper for old compilers."
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
version = "1.1.0"
|
version = "1.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
repository = "https://github.com/encounter/sjiswrap"
|
repository = "https://github.com/encounter/sjiswrap"
|
||||||
|
|
63
src/main.rs
63
src/main.rs
|
@ -19,8 +19,8 @@ use windows::{
|
||||||
core::{PCSTR, PCWSTR},
|
core::{PCSTR, PCWSTR},
|
||||||
Win32::{
|
Win32::{
|
||||||
Foundation::{
|
Foundation::{
|
||||||
CloseHandle, GetLastError, SetLastError, BOOL, GENERIC_ACCESS_RIGHTS, GENERIC_READ,
|
CloseHandle, GetLastError, SetLastError, BOOL, ERROR_INSUFFICIENT_BUFFER,
|
||||||
HANDLE, INVALID_HANDLE_VALUE,
|
GENERIC_ACCESS_RIGHTS, GENERIC_READ, HANDLE, HMODULE, INVALID_HANDLE_VALUE,
|
||||||
},
|
},
|
||||||
Security::SECURITY_ATTRIBUTES,
|
Security::SECURITY_ATTRIBUTES,
|
||||||
Storage::FileSystem::{
|
Storage::FileSystem::{
|
||||||
|
@ -68,23 +68,23 @@ fn main() -> Result<()> {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe { GLOBAL_STATE = MaybeUninit::new(GlobalState::default()) };
|
|
||||||
|
|
||||||
let path = PathBuf::from(&args[1]);
|
let path = PathBuf::from(&args[1]);
|
||||||
let parent = CString::new(
|
let abs_path_cstr =
|
||||||
path.parent()
|
get_full_path(&CString::new(path.as_os_str().to_string_lossy().as_ref()).unwrap())
|
||||||
.context("Failed to get executable parent directory")?
|
.context("Failed to get absolute executable path")?;
|
||||||
.to_string_lossy()
|
let abs_path = PathBuf::from(abs_path_cstr.to_string_lossy().as_ref());
|
||||||
.as_ref(),
|
let parent = abs_path.parent().context("Failed to get absolute executable parent directory")?;
|
||||||
)
|
let parent_cstr = CString::new(parent.as_os_str().to_string_lossy().as_ref()).unwrap();
|
||||||
.unwrap();
|
unsafe { SetDllDirectoryA(PCSTR(parent_cstr.as_ptr() as *const u8)) }
|
||||||
let parent =
|
|
||||||
get_full_path(&parent).expect("Failed to get absolute executable parent directory");
|
|
||||||
unsafe { SetDllDirectoryA(PCSTR(parent.as_ptr() as *const u8)) }
|
|
||||||
.ok()
|
.ok()
|
||||||
.context("SetDllDirectoryA() failed")?;
|
.context("SetDllDirectoryA() failed")?;
|
||||||
debug_println!("SetDllDirectoryA({:?})", parent.to_string_lossy());
|
debug_println!("SetDllDirectoryA({:?})", parent.to_string_lossy());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
GLOBAL_STATE =
|
||||||
|
MaybeUninit::new(GlobalState { exe_path: abs_path_cstr, ..Default::default() })
|
||||||
|
};
|
||||||
|
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
File::open(&path)
|
File::open(&path)
|
||||||
.with_context(|| format!("Failed to open executable: '{}'", path.display()))?
|
.with_context(|| format!("Failed to open executable: '{}'", path.display()))?
|
||||||
|
@ -101,6 +101,8 @@ fn main() -> Result<()> {
|
||||||
hooks.insert("kernel32.dll!ReadFile".into(), hook_ReadFile as *const c_void);
|
hooks.insert("kernel32.dll!ReadFile".into(), hook_ReadFile as *const c_void);
|
||||||
hooks.insert("kernel32.dll!SetFilePointer".into(), hook_SetFilePointer as *const c_void);
|
hooks.insert("kernel32.dll!SetFilePointer".into(), hook_SetFilePointer as *const c_void);
|
||||||
hooks.insert("kernel32.dll!IsDBCSLeadByte".into(), hook_IsDBCSLeadByte as *const c_void);
|
hooks.insert("kernel32.dll!IsDBCSLeadByte".into(), hook_IsDBCSLeadByte as *const c_void);
|
||||||
|
hooks
|
||||||
|
.insert("kernel32.dll!GetModuleFileNameA".into(), hook_GetModuleFileNameA as *const c_void);
|
||||||
unsafe { memexec::memexec_exe_with_hooks(&buf, &hooks) }.expect("Failed to execute");
|
unsafe { memexec::memexec_exe_with_hooks(&buf, &hooks) }.expect("Failed to execute");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -114,6 +116,7 @@ struct FileHandle {
|
||||||
/// Global state shared between hooks.
|
/// Global state shared between hooks.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct GlobalState {
|
struct GlobalState {
|
||||||
|
exe_path: CString,
|
||||||
cmdline: Option<CString>,
|
cmdline: Option<CString>,
|
||||||
encoded_files: FxHashMap<PathBuf, Vec<u8>>,
|
encoded_files: FxHashMap<PathBuf, Vec<u8>>,
|
||||||
file_handles: FxHashMap<isize, FileHandle>,
|
file_handles: FxHashMap<isize, FileHandle>,
|
||||||
|
@ -447,6 +450,38 @@ extern "stdcall" fn hook_SetFilePointer(
|
||||||
/// `IsDBCSLeadByte` hook. This normally uses the system codepage, override with Shift JIS behavior.
|
/// `IsDBCSLeadByte` hook. This normally uses the system codepage, override with Shift JIS behavior.
|
||||||
extern "stdcall" fn hook_IsDBCSLeadByte(TestChar: u8) -> BOOL { (TestChar & 0x80 != 0).into() }
|
extern "stdcall" fn hook_IsDBCSLeadByte(TestChar: u8) -> BOOL { (TestChar & 0x80 != 0).into() }
|
||||||
|
|
||||||
|
/// `GetModuleFileNameA` hook. Return the absolute path of the executable.
|
||||||
|
extern "stdcall" fn hook_GetModuleFileNameA(
|
||||||
|
hModule: HMODULE,
|
||||||
|
lpFilename: *mut c_char,
|
||||||
|
nSize: u32,
|
||||||
|
) -> u32 {
|
||||||
|
let _ = hModule; // ?
|
||||||
|
|
||||||
|
let state = unsafe { GLOBAL_STATE.assume_init_ref() };
|
||||||
|
let path_bytes = state.exe_path.as_bytes(); // Without nul terminator
|
||||||
|
let ret = min(nSize.saturating_sub(1), path_bytes.len() as u32);
|
||||||
|
if !lpFilename.is_null() && ret > 0 {
|
||||||
|
unsafe {
|
||||||
|
std::ptr::copy_nonoverlapping(path_bytes.as_ptr(), lpFilename as *mut u8, ret as usize);
|
||||||
|
}
|
||||||
|
unsafe { *lpFilename.offset(ret as isize) = 0 };
|
||||||
|
}
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
{
|
||||||
|
let slice = unsafe { std::slice::from_raw_parts(lpFilename as *const u8, ret as usize) };
|
||||||
|
let str = unsafe { std::str::from_utf8_unchecked(slice) };
|
||||||
|
eprintln!(
|
||||||
|
"OVERRIDE GetModuleFileNameA({:#X}, {:?}, {:#X}) = {:#X} ({})",
|
||||||
|
hModule.0, lpFilename, nSize, ret, str
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ret < path_bytes.len() as u32 {
|
||||||
|
unsafe { SetLastError(ERROR_INSUFFICIENT_BUFFER) };
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the absolute path of a file.
|
/// Get the absolute path of a file.
|
||||||
fn get_full_path(path: &CStr) -> Result<CString> {
|
fn get_full_path(path: &CStr) -> Result<CString> {
|
||||||
let mut buf = [0u8; 4096];
|
let mut buf = [0u8; 4096];
|
||||||
|
|
Loading…
Reference in New Issue