├── .gitignore ├── .github └── FUNDING.yml ├── vendor └── detours-sys │ ├── build │ └── wrapper.h │ ├── Cargo.toml │ ├── src │ ├── lib.rs │ └── bundled_bindings.rs │ └── build.rs ├── .gitmodules ├── README.md ├── Cargo.toml ├── src ├── paths.rs ├── windows │ ├── mod.rs │ └── hooks.rs ├── lib.rs ├── linux │ ├── hooks.rs │ └── mod.rs └── asar.rs ├── LICENSE └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: MeguminSama 2 | ko_fi: meguminsama 3 | -------------------------------------------------------------------------------- /vendor/detours-sys/build/wrapper.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/detours-sys/ext/detours"] 2 | path = vendor/detours-sys/ext/detours 3 | url = https://github.com/microsoft/detours 4 | -------------------------------------------------------------------------------- /vendor/detours-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "electron-hook-detours-sys" 3 | version = "0.1.0" 4 | edition = "2021" 5 | description = "microsoft detours bindings" 6 | homepage = "https://github.com/meguminsama/electron-hook" 7 | repository = "https://github.com/meguminsama/electron-hook" 8 | license = "MIT" 9 | 10 | [build-dependencies] 11 | bindgen = "0.71" 12 | cc = "1.2" 13 | cmake = "0.1" 14 | -------------------------------------------------------------------------------- /vendor/detours-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg(target_os = "windows")] 2 | 3 | //! Bindings to the Microsoft Detours API. 4 | #![allow(non_camel_case_types)] 5 | #![allow(non_snake_case)] 6 | 7 | // Rebuild with: 8 | // bindgen ..\build\wrapper.h --allowlist-function "Detour.*" -o bundled_bindings.rs -- "-fms-compatibility" "-fms-extensions" --target=x86_64-pc-windows-msvc -I ..\ext\detours\src\ 9 | include!("bundled_bindings.rs"); 10 | -------------------------------------------------------------------------------- /vendor/detours-sys/build.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | fn main() { 4 | build_detours().unwrap(); 5 | } 6 | 7 | const CPP_FILES: [&str; 5] = [ 8 | "./ext/detours/src/creatwth.cpp", 9 | "./ext/detours/src/detours.cpp", 10 | "./ext/detours/src/disasm.cpp", 11 | "./ext/detours/src/image.cpp", 12 | "./ext/detours/src/modules.cpp", 13 | ]; 14 | 15 | fn build_detours() -> Result<(), Box> { 16 | add_target_options( 17 | cc::Build::new() 18 | .include("./ext/detours/src") 19 | .files(&CPP_FILES), 20 | ) 21 | .try_compile("detours")?; 22 | Ok(()) 23 | } 24 | fn add_target_options(build: &mut cc::Build) -> &mut cc::Build { 25 | if std::env::var("CARGO_CFG_TARGET_ENV").unwrap() != "msvc" { 26 | build 27 | .compiler("clang") 28 | .cpp(true) 29 | .flag("-fms-extensions") 30 | .flag("-Wno-everything") 31 | } else { 32 | build 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # electron-hook 2 | 3 | A Rust library for loading mods into Electron applications without patching any files. 4 | 5 | [![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/MeguminSama) 6 | 7 | This project was designed to ease some pain points with modding Discord, but it can be used for most Electron applications. 8 | 9 | For some real-life uses of electron-hook, check out: 10 | 11 | - [moonlight launcher](https://github.com/meguminsama/moonlight-launcher) 12 | - [Vencord Launcher](https://github.com/meguminsama/vencord-launcher) 13 | 14 | # Installation 15 | 16 | Add this to your `Cargo.toml`: 17 | 18 | ```toml 19 | [dependencies] 20 | electron-hook = "0.2.0" 21 | 22 | [lib] 23 | crate-type = ["cdylib"] 24 | ``` 25 | 26 | And in your `lib.rs`: 27 | 28 | ```rust 29 | pub use electron_hook::*; 30 | ``` 31 | 32 | When you build your project with `--lib` it will generate a `.dll` or `.so`, which you can pass the path of into `electron_hook::launch` 33 | 34 | # Usage 35 | 36 | For a better example, check out the [Documentation](https://docs.rs/electron-hook) 37 | 38 | ```rust 39 | electron_hook::launch(&electron_executable, &library_path, &asar_path, vec![], true); 40 | ``` 41 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [".", "vendor/detours-sys"] 3 | 4 | [package] 5 | name = "electron-hook" 6 | description = "In-memory Electron mod loader." 7 | authors = ["Rie Takahashi "] 8 | version = "0.2.1" 9 | license = "LGPL-3.0" 10 | homepage = "https://github.com/meguminsama/electron-hook" 11 | repository = "https://github.com/meguminsama/electron-hook" 12 | categories = ["web-programming", "development-tools"] 13 | keywords = ["modding", "electron", "discord", "hook", "detour"] 14 | edition = "2021" 15 | 16 | [lib] 17 | crate-type = ["cdylib", "rlib"] 18 | 19 | [features] 20 | default = ["uuid", "asar"] 21 | asar = ["dep:asar"] 22 | uuid = ["dep:uuid"] 23 | 24 | [dependencies] 25 | ctor = "0.4.2" 26 | dirs = "6.0.0" 27 | libc = "0.2.172" 28 | serde_json = "1.0.140" 29 | uuid = { version = "1.16.0", features = ["v4"], optional = true } 30 | 31 | [dependencies.asar] 32 | version = "0.3.0" 33 | default-features = false 34 | features = ["write"] 35 | optional = true 36 | 37 | [target.'cfg(windows)'.dependencies] 38 | widestring = "1.2.0" 39 | winapi = { version = "0.3.9", features = ["handleapi", "winuser"] } 40 | detours-sys = { path = "vendor/detours-sys", package = "electron-hook-detours-sys", version = "0.1.0" } 41 | 42 | [target.'cfg(unix)'.dependencies] 43 | libc = "0.2.167" 44 | retour = { version = "0.3.1", features = ["static-detour"] } 45 | -------------------------------------------------------------------------------- /src/paths.rs: -------------------------------------------------------------------------------- 1 | //! Path utilities 2 | 3 | fn cache_dir() -> std::path::PathBuf { 4 | dirs::cache_dir() 5 | .expect("Failed to get cache directory") 6 | .join("electron-hook") 7 | } 8 | 9 | fn asar_cache_dir() -> std::path::PathBuf { 10 | ensure_dir(cache_dir().join("asar")) 11 | } 12 | 13 | /// The path to a specific .asar file 14 | pub fn asar_cache_path(asar_id: &str) -> std::path::PathBuf { 15 | asar_cache_dir().join(format!("{asar_id}.asar")) 16 | } 17 | 18 | fn mod_artifacts_dir() -> std::path::PathBuf { 19 | ensure_dir(cache_dir().join("mods")) 20 | } 21 | 22 | /// The path to a specific mod artifact folder 23 | pub fn mod_artifact_dir(mod_name: &str) -> std::path::PathBuf { 24 | mod_artifacts_dir().join(mod_name) 25 | } 26 | 27 | fn data_dir() -> std::path::PathBuf { 28 | dirs::data_dir() 29 | .expect("Failed to get data directory") 30 | .join("electron-hook") 31 | } 32 | 33 | fn data_profiles_dir() -> std::path::PathBuf { 34 | ensure_dir(data_dir().join("profiles")) 35 | } 36 | 37 | /// The path to a specific profile directory 38 | pub fn data_profile_dir(profile_id: &str) -> std::path::PathBuf { 39 | data_profiles_dir().join(profile_id) 40 | } 41 | 42 | /// Ensure a directory exists, recursively creating it if it doesn't 43 | pub fn ensure_dir(path: std::path::PathBuf) -> std::path::PathBuf { 44 | if !path.exists() { 45 | std::fs::create_dir_all(&path) 46 | .map_err(|e| format!("Failed to create directory: {e}")) 47 | .unwrap(); 48 | } 49 | path 50 | } 51 | -------------------------------------------------------------------------------- /src/windows/mod.rs: -------------------------------------------------------------------------------- 1 | mod hooks; 2 | 3 | use detours_sys::{DetourCreateProcessWithDllExA, _PROCESS_INFORMATION, _STARTUPINFOA}; 4 | use winapi::um::{ 5 | handleapi::CloseHandle, 6 | processthreadsapi::ResumeThread, 7 | winbase::CREATE_SUSPENDED, 8 | winuser::{MessageBoxA, MB_ICONERROR}, 9 | }; 10 | 11 | pub fn launch( 12 | executable: &str, 13 | library_path: &str, 14 | asar_path: &str, 15 | args: Vec, 16 | ) -> Result, String> { 17 | unsafe { 18 | let process_args = std::env::args().skip(1).collect::>(); 19 | let process_args_json = 20 | serde_json::to_string(&process_args).unwrap_or_else(|_| "[]".into()); 21 | 22 | let executable = std::path::Path::new(executable); 23 | 24 | let working_dir = executable 25 | .parent() 26 | .ok_or("Failed to get executable directory".to_string())?; 27 | 28 | let shared_object = std::ffi::CString::new(library_path) 29 | .map_err(|_| "Failed to convert shared object path to CString")?; 30 | 31 | let folder_name = working_dir 32 | .file_name() 33 | .and_then(|name| name.to_str()) 34 | .ok_or("Failed to get directory name as string")?; 35 | 36 | // Set env vars needed for the child processes 37 | std::env::set_var("MODLOADER_ASAR_PATH", asar_path); 38 | std::env::set_var("MODLOADER_EXECUTABLE", std::env::current_exe().unwrap()); 39 | std::env::set_var("MODLOADER_LIBRARY_PATH", library_path); 40 | std::env::set_var("MODLOADER_FOLDER_NAME", folder_name); 41 | std::env::set_var("MODLOADER_ORIGINAL_ASAR_RELATIVE", "../_app.asar"); 42 | std::env::set_var("MODLOADER_PROCESS_ARGV", process_args_json); 43 | 44 | let working_dir = std::ffi::CString::new(working_dir.parent().unwrap().to_str().unwrap()) 45 | .map_err(|_| "Failed to convert directory path to CString")?; 46 | 47 | let executable_path = executable 48 | .to_str() 49 | .ok_or("Failed to convert executable path to string")?; 50 | 51 | let executable = std::ffi::CString::new(executable_path) 52 | .map_err(|_| "Failed to convert executable path to CString")?; 53 | 54 | let args = args.join(" "); 55 | let command_line = format!("\"{executable_path}\" {args}"); 56 | let command_line = std::ffi::CString::new(command_line) 57 | .map_err(|_| "Failed to convert command line to CString")?; 58 | 59 | let mut startup_info: _STARTUPINFOA = std::mem::zeroed(); 60 | let mut process_info: _PROCESS_INFORMATION = std::mem::zeroed(); 61 | let result = DetourCreateProcessWithDllExA( 62 | executable.as_ptr() as *mut i8, 63 | command_line.as_ptr() as *mut i8, 64 | std::ptr::null_mut(), 65 | std::ptr::null_mut(), 66 | 0, 67 | CREATE_SUSPENDED, 68 | std::ptr::null_mut(), 69 | working_dir.as_ptr() as *mut i8, 70 | &raw mut startup_info as _, 71 | &raw mut process_info as _, 72 | shared_object.as_ptr() as *mut i8, 73 | None, 74 | ); 75 | 76 | if result == 0 { 77 | MessageBoxA( 78 | std::ptr::null_mut(), 79 | "Failed to hook CreateProcessW. Please report this issue.".as_ptr() as *const i8, 80 | "Error Hooking".as_ptr() as *const i8, 81 | MB_ICONERROR, 82 | ); 83 | return Err("Failed to hook CreateProcessW. Please report this issue.".into()); 84 | } 85 | 86 | ResumeThread(process_info.hThread as _); 87 | 88 | CloseHandle(process_info.hThread as _); 89 | CloseHandle(process_info.hProcess as _); 90 | } 91 | 92 | Ok(None) 93 | } 94 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn(missing_docs)] 2 | //! A library for modding Electron apps in-memory, without modifying any program files. 3 | //! 4 | //! This library was made for improving the modding experience for Discord, but it can be used for any Electron app. 5 | //! 6 | //! # Features 7 | //! 8 | //! - `asar`: Enables the ASAR archive builder. (enabled by default) 9 | //! - `uuid`: Enables the use of random UUIDs for ASAR archive names. (enabled by default) 10 | //! 11 | //! # Examples 12 | //! 13 | //! electron-hook maps the original `app.asar` to `_app.asar`, 14 | //! so keep this in mind if you need to call the original file anywhere, 15 | //! as shown in this example. 16 | //! 17 | //! ```rust,ignore 18 | //! use electron_hook::asar::Asar; 19 | //! 20 | //! let mod_dir = mod_artifact_dir("moonlight"); 21 | //! 22 | //! let _download_url = "https://github.com/moonlight-mod/moonlight/releases/latest/download/dist.tar.gz"; 23 | //! // extract and save `_download_url` into `mod_dir` 24 | //! 25 | //! let mod_entrypoint = mod_dir.join("injector.js"); 26 | //! 27 | //! let template = r#" 28 | //! console.log("Mod injected!!!"); 29 | //! let asar = require("path").resolve(__dirname, "../_app.asar"); 30 | //! require(process.env.MODLOADER_MOD_ENTRYPOINT).inject(asar); 31 | //! "#; 32 | //! 33 | //! // Create the asar file 34 | //! let asar = Asar::new() 35 | //! .with_id("moonlight") 36 | //! .with_template(template) 37 | //! .with_mod_entrypoint(mod_dir) 38 | //! .create() 39 | //! .unwrap(); 40 | //! 41 | //! electron_hook::launch( 42 | //! "/path/to/executable/Discord", 43 | //! asar.path().to_str().unwrap(), 44 | //! vec!["--pass-arguments-here"], 45 | //! None, // Optional profile directory 46 | //! true, // Detach the process 47 | //! ); 48 | //! ``` 49 | 50 | #[cfg(any(doc, feature = "asar"))] 51 | pub mod asar; 52 | pub mod paths; 53 | 54 | // For Linux 55 | #[cfg(target_os = "linux")] 56 | mod linux; 57 | 58 | // For Windows 59 | // TODO: Re-implement Windows support. 60 | #[cfg(target_os = "windows")] 61 | mod windows; 62 | 63 | // TODO: For MacOS 64 | 65 | /// Launches an Electron executable with the provided information. 66 | /// 67 | /// `id` on Linux: the path to the executable. 68 | /// 69 | /// `id` on Windows: the path to the directory containing `Update.exe`. 70 | /// 71 | /// `library_path`: The path to the electron-hook `.so` or `.dll` 72 | /// 73 | /// `asar_path`: The path to the ASAR file to inject 74 | /// 75 | /// `args`: Arguments to pass to the executable 76 | /// 77 | /// `detach`: It is recommended to set `detach` to true to prevent the process from dying when the parent process is closed. 78 | #[allow(unused_variables)] 79 | pub fn launch( 80 | executable: &str, 81 | library_path: &str, 82 | asar_path: &str, 83 | args: Vec, 84 | detach: bool, 85 | ) -> Result, String> { 86 | #[cfg(target_os = "linux")] 87 | { 88 | linux::launch(executable, library_path, asar_path, args, detach) 89 | } 90 | 91 | #[cfg(target_os = "windows")] 92 | { 93 | // No need for detach on Windows, as the process already detaches itself. 94 | windows::launch(executable, library_path, asar_path, args) 95 | } 96 | } 97 | 98 | /// Launches an Electron executable through Flatpak with the provided information. 99 | /// 100 | /// This is only available on Linux. 101 | /// 102 | /// TODO: This only supports global packages. Are --user flatpak packages handled differently? 103 | /// 104 | /// `id`: The ID of the flatpak package. 105 | /// 106 | /// `library_path`: The path to the electron-hook `.so` or `.dll` 107 | /// 108 | /// `asar_path`: The path to the ASAR file to inject 109 | /// 110 | /// `args`: Arguments to pass to the executable 111 | /// 112 | /// `detach`: It is recommended to set `detach` to true to prevent the process from dying when the parent process is closed. 113 | #[cfg(any(doc, target_os = "linux"))] 114 | pub fn launch_flatpak( 115 | id: &FlatpakID, 116 | library_path: &str, 117 | asar_path: &str, 118 | args: Vec, 119 | detach: bool, 120 | ) -> Result, String> { 121 | linux::launch_flatpak(id, library_path, asar_path, args, detach) 122 | } 123 | 124 | /// The ID of a Flatpak package. 125 | pub enum FlatpakID { 126 | /// A User install of a flatpak package. Will be run with `--user` 127 | User(String), 128 | /// A System install of a flatpak package. Will be run with `--system` 129 | System(String), 130 | } 131 | 132 | impl std::fmt::Display for FlatpakID { 133 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 134 | match self { 135 | FlatpakID::User(id) => write!(f, "{id}"), 136 | FlatpakID::System(id) => write!(f, "{id}"), 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/linux/hooks.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{c_char, c_void}; 2 | 3 | use retour::static_detour; 4 | 5 | mod env { 6 | use std::sync::LazyLock; 7 | 8 | macro_rules! lazy_env { 9 | ($name:expr) => { 10 | LazyLock::new(|| std::env::var($name).unwrap()) 11 | }; 12 | } 13 | 14 | pub static MODLOADER_ASAR_PATH: LazyLock = lazy_env!("MODLOADER_ASAR_PATH"); 15 | pub static MODLOADER_LIBRARY_PATH: LazyLock = lazy_env!("MODLOADER_LIBRARY_PATH"); 16 | } 17 | 18 | #[link(name = "dl")] 19 | unsafe extern "C" { 20 | unsafe fn dlsym(handle: *const c_void, symbol: *const c_char) -> *const c_void; 21 | } 22 | 23 | unsafe extern "C" { 24 | #[link_name = "uv_fs_lstat"] 25 | unsafe fn original_uv_fs_lstat( 26 | loop_: *const c_void, 27 | req: *const c_void, 28 | path: *const c_char, 29 | buf: *mut c_void, 30 | ) -> i32; 31 | } 32 | 33 | #[ctor::ctor] 34 | unsafe fn init_dynamic_hooks() { 35 | #[allow(clippy::missing_transmute_annotations)] 36 | UvFsLstatDetour 37 | .initialize( 38 | std::mem::transmute::(original_uv_fs_lstat), 39 | uv_fs_lstat, 40 | ) 41 | .unwrap(); 42 | 43 | UvFsLstatDetour.enable().unwrap(); 44 | } 45 | 46 | type UvFsLstat = unsafe extern "C" fn( 47 | loop_: *const c_void, 48 | req: *const c_void, 49 | path: *const c_char, 50 | cb: *mut c_void, 51 | ) -> i32; 52 | 53 | static_detour! { 54 | static UvFsLstatDetour: fn(*const c_void, *const c_void, *const c_char, *mut c_void) -> i32; 55 | } 56 | 57 | // This is a fix needed for flatpak support, as zypak is stripping our LD_PRELOAD incorrectly 58 | // See: https://github.com/refi64/zypak/issues/42 59 | #[no_mangle] 60 | unsafe extern "C" fn unsetenv(name: *const c_char) -> i32 { 61 | let name_str = std::ffi::CStr::from_ptr(name).to_str().unwrap(); 62 | 63 | let original_unsetenv: unsafe extern "C" fn(*const c_char) -> i32 = 64 | std::mem::transmute(dlsym(libc::RTLD_NEXT, c"unsetenv".as_ptr())); 65 | 66 | if name_str == "LD_PRELOAD" { 67 | std::env::set_var("LD_PRELOAD", &*env::MODLOADER_LIBRARY_PATH); 68 | return 0; 69 | } 70 | 71 | original_unsetenv(name) 72 | } 73 | 74 | // make the linker happy... TODO: Can we compile without this? 75 | #[export_name = "uv_fs_lstat"] 76 | unsafe extern "C" fn export_uv_vs_lstat( 77 | loop_: *const c_void, 78 | req: *const c_void, 79 | path: *const c_char, 80 | buf: *mut c_void, 81 | ) -> i32 { 82 | uv_fs_lstat(loop_, req, path, buf) 83 | } 84 | 85 | fn uv_fs_lstat( 86 | loop_: *const c_void, 87 | req: *const c_void, 88 | path: *const c_char, 89 | buf: *mut c_void, 90 | ) -> i32 { 91 | let path_str = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }; 92 | if path_str.contains("resources/_app.asar") { 93 | let redirect_to = path_str.replace("/_app.asar", "/app.asar"); 94 | let redirect_to_c = std::ffi::CString::new(redirect_to.as_str()).unwrap(); 95 | return UvFsLstatDetour.call(loop_, req, redirect_to_c.as_ptr(), buf); 96 | } 97 | 98 | UvFsLstatDetour.call(loop_, req, path, buf) 99 | } 100 | 101 | type XStat64 = unsafe extern "C" fn(i32, *const c_char, *mut libc::stat64) -> i64; 102 | 103 | #[no_mangle] 104 | unsafe extern "C" fn __xstat64(ver: i32, path: *const c_char, out: *mut libc::stat64) -> i64 { 105 | use std::sync::LazyLock; 106 | 107 | static ORIGINAL_XSTAT64: LazyLock = LazyLock::new(|| unsafe { 108 | std::mem::transmute(dlsym(libc::RTLD_NEXT, c"__xstat64".as_ptr())) 109 | }); 110 | 111 | let path_str = std::ffi::CStr::from_ptr(path).to_str().unwrap(); 112 | 113 | // If calling _app.asar, return the original app.asar 114 | if path_str.contains("resources/_app.asar") { 115 | let redirect_to = path_str.replace("/_app.asar", "/app.asar"); 116 | let redirect_to_c = std::ffi::CString::new(redirect_to.as_str()).unwrap(); 117 | return ORIGINAL_XSTAT64(ver, redirect_to_c.as_ptr(), out); 118 | } 119 | 120 | // If calling app.asar, return the custom app.asar 121 | if path_str.contains("resources/app.asar") { 122 | let asar_path_cstr = std::ffi::CString::new(env::MODLOADER_ASAR_PATH.as_str()).unwrap(); 123 | return ORIGINAL_XSTAT64(ver, asar_path_cstr.as_ptr(), out); 124 | } 125 | 126 | ORIGINAL_XSTAT64(ver, path, out) 127 | } 128 | 129 | type Open64 = unsafe extern "C" fn(*const c_char, i32, i32) -> i32; 130 | 131 | #[no_mangle] 132 | unsafe extern "C" fn open64(path: *const c_char, flags: i32, mode: i32) -> i32 { 133 | use std::sync::LazyLock; 134 | 135 | static ORIGINAL_OPENAT64: LazyLock = LazyLock::new(|| unsafe { 136 | std::mem::transmute(dlsym(libc::RTLD_NEXT, c"open64".as_ptr())) 137 | }); 138 | 139 | let path_str = std::ffi::CStr::from_ptr(path).to_str().unwrap(); 140 | 141 | // If calling _app.asar, return the original app.asar 142 | if path_str.contains("resources/_app.asar") { 143 | let redirect_to = path_str.replace("/_app.asar", "/app.asar"); 144 | let redirect_to_c = std::ffi::CString::new(redirect_to.as_str()).unwrap(); 145 | 146 | return ORIGINAL_OPENAT64(redirect_to_c.as_ptr(), flags, mode); 147 | } 148 | 149 | // If calling app.asar, return the custom app.asar 150 | if path_str.contains("resources/app.asar") { 151 | let redirect_to = std::ffi::CString::new(env::MODLOADER_ASAR_PATH.as_str()).unwrap(); 152 | 153 | return ORIGINAL_OPENAT64(redirect_to.as_ptr(), flags, mode); 154 | } 155 | 156 | ORIGINAL_OPENAT64(path, flags, mode) 157 | } 158 | -------------------------------------------------------------------------------- /src/linux/mod.rs: -------------------------------------------------------------------------------- 1 | mod hooks; 2 | 3 | use super::FlatpakID; 4 | 5 | pub(crate) fn launch_flatpak( 6 | id: &FlatpakID, 7 | library_path: &str, 8 | asar_path: &str, 9 | args: Vec, 10 | detach: bool, 11 | ) -> Result, String> { 12 | // If the library starts with /home, return the whole path. 13 | // If the library is absolute, prefix wtih /run/host 14 | // If it's a local file, provide the whole path 15 | // Otherwise, assume it's in /usr/lib, so prefix with /run/host/usr/lib 16 | let library_path = if library_path.starts_with("/home") { 17 | library_path.to_string() 18 | } else if library_path.starts_with('/') { 19 | format!("/run/host{}", library_path) 20 | } else { 21 | let current_dir = std::env::current_dir().unwrap(); 22 | let local_path = current_dir.join(&library_path); 23 | 24 | if local_path.is_file() { 25 | local_path.to_string_lossy().into_owned() 26 | } else { 27 | format!("/run/host/usr/lib/{}", library_path) 28 | } 29 | }; 30 | 31 | let asar_dir = std::path::PathBuf::from(asar_path); 32 | let asar_dir = asar_dir 33 | .parent() 34 | .ok_or("Failed to get parent directory from asar path")? 35 | .to_string_lossy(); 36 | 37 | let mod_entrypoint = std::env::var("MODLOADER_MOD_ENTRYPOINT") 38 | .map_err(|_| "MODLOADER_MOD_ENTRYPOINT not set")?; 39 | 40 | let mod_entrypoint_dir = std::path::PathBuf::from(mod_entrypoint); 41 | let mod_entrypoint_dir = mod_entrypoint_dir 42 | .parent() 43 | .ok_or("Failed to get parent directory from mod entrypoint")? 44 | .to_string_lossy(); 45 | 46 | let current_executable = std::env::current_exe().unwrap().display().to_string(); 47 | 48 | let current_executable = if current_executable.starts_with("/usr") { 49 | format!("/run/host{}", current_executable) 50 | } else { 51 | current_executable 52 | }; 53 | 54 | let mut target = std::process::Command::new("flatpak"); 55 | 56 | target.arg("run"); 57 | 58 | match id { 59 | FlatpakID::User(_) => target.arg("--user"), 60 | FlatpakID::System(_) => target.arg("--system"), 61 | }; 62 | 63 | target 64 | .arg("--filesystem=host:ro") // allows us to read /usr/lib as /run/host/usr/lib 65 | .arg(format!("--filesystem={}:ro", asar_dir)) // Read-only access to the ASAR dir 66 | .arg(format!("--filesystem={}:create", mod_entrypoint_dir)) // let the mod update itself... 67 | .arg(format!("--filesystem={}:ro", current_executable)) 68 | .arg(format!("--env=ZYPAK_LD_PRELOAD={}", library_path)) // give zypak our LD_PRELOAD 69 | .arg(format!("--env=MODLOADER_ASAR_PATH={}", asar_path)) 70 | .arg(format!("--env=MODLOADER_EXECUTABLE={}", current_executable)) 71 | .arg(format!("--env=MODLOADER_LIBRARY_PATH={}", library_path)) 72 | .arg(format!( 73 | "--env=MODLOADER_ORIGINAL_ASAR_RELATIVE=../_app.asar" 74 | )) 75 | .arg(id.to_string()) 76 | .args(args); 77 | 78 | // We also need to detach stdin. 79 | if detach { 80 | target 81 | .stdout(std::process::Stdio::null()) 82 | .stderr(std::process::Stdio::null()) 83 | .stdin(std::process::Stdio::null()); 84 | }; 85 | 86 | let Ok(mut target) = target.spawn() else { 87 | return Err("Failed to launch instance".into()); 88 | }; 89 | 90 | // If we aren't detaching, keep the process alive. 91 | if !detach { 92 | let Ok(_) = target.wait() else { 93 | return Err("Process exited unexpectedly".into()); 94 | }; 95 | 96 | return Ok(None); 97 | } 98 | 99 | let pid = target.id(); 100 | 101 | Ok(Some(pid)) 102 | } 103 | 104 | pub(crate) fn launch( 105 | executable: &str, 106 | library_path: &str, 107 | asar_path: &str, 108 | args: Vec, 109 | detach: bool, 110 | ) -> Result, String> { 111 | let executable = std::path::PathBuf::from(executable); 112 | 113 | // Detach the process from the parent. This prevents the application from dying when the parent process (e.g. terminal) is closed. 114 | if detach { 115 | unsafe { libc::setsid() }; 116 | } 117 | 118 | let working_dir = executable 119 | .parent() 120 | .ok_or("Failed to get parent directory from executable")?; 121 | 122 | let mut target = std::process::Command::new(&executable); 123 | 124 | let process_args = std::env::args().skip(1).collect::>(); 125 | let process_args_json = serde_json::to_string(&process_args).unwrap_or_else(|_| "[]".into()); 126 | 127 | target 128 | .current_dir(working_dir) 129 | .env("LD_PRELOAD", library_path) 130 | .env("MODLOADER_ASAR_PATH", asar_path) 131 | .env("MODLOADER_EXECUTABLE", std::env::current_exe().unwrap()) 132 | .env("MODLOADER_LIBRARY_PATH", library_path) 133 | .env("MODLOADER_ORIGINAL_ASAR_RELATIVE", "../_app.asar") 134 | .env("MODLOADER_PROCESS_ARGV", process_args_json) 135 | .args(args); 136 | 137 | // We also need to detach stdin. 138 | if detach { 139 | target 140 | .stdout(std::process::Stdio::null()) 141 | .stderr(std::process::Stdio::null()) 142 | .stdin(std::process::Stdio::null()); 143 | }; 144 | 145 | let Ok(mut target) = target.spawn() else { 146 | return Err("Failed to launch instance".into()); 147 | }; 148 | 149 | // If we aren't detaching, keep the process alive. 150 | if !detach { 151 | let Ok(_) = target.wait() else { 152 | return Err("Process exited unexpectedly".into()); 153 | }; 154 | 155 | return Ok(None); 156 | } 157 | 158 | let pid = target.id(); 159 | 160 | Ok(Some(pid)) 161 | } 162 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /src/asar.rs: -------------------------------------------------------------------------------- 1 | //! Module for creating asar archives 2 | //! 3 | //! Provides an API for creating ASAR entrypoints from a template. 4 | //! 5 | //! This module requires the `asar` feature to be enabled. 6 | 7 | fn make_package_json(wm_class: &Option) -> String { 8 | if let Some(wm_class) = wm_class { 9 | format!(r#"{{"main": "index.js", "name": "{wm_class}"}}"#) 10 | } else { 11 | r#"{"main": "index.js"}"#.to_string() 12 | } 13 | } 14 | 15 | /// A builder for creating ASAR archives and writing them to the filesystem. 16 | /// 17 | /// # Usage 18 | /// 19 | /// ```rust,ignore 20 | /// use electron_hook::asar::Asar; 21 | /// use electron_hook::paths::{mod_artifact_dir, data_profile_dir}; 22 | /// 23 | /// let entrypoint = mod_artifact_dir("vencord").join("patcher.js"); 24 | /// let profile_dir = data_profile_dir("vencord"); 25 | /// 26 | /// let asar = Asar::new() 27 | /// .with_id("vencord-release") 28 | /// .with_template("require(process.env.MODLOADER_MOD_ENTRYPOINT);") 29 | /// .with_mod_entrypoint(entrypoint.to_str().unwrap()) 30 | /// .with_profile_dir(profile_dir.to_str().unwrap()) // Optional 31 | /// .create(); 32 | /// 33 | /// // Linux: /home/CoolPerson/.cache/electron-hook/asar/vencord-release.asar 34 | /// // Windows: C:/Users/CoolPerson/AppData/Local/electron-hook/asar/vencord-release.asar 35 | /// // MacOS: TODO 36 | /// ``` 37 | #[derive(Debug, Default)] 38 | pub struct Asar { 39 | /// The unique identifier for the ASAR archive. 40 | /// e.g. if this is set to `my-mod-name`, the final name will be `{id}.asar`. 41 | /// 42 | /// This can either be a random UUID (with the `uuid` feature) or a custom reusable ID. 43 | /// 44 | /// The final path will be something like: 45 | /// 46 | /// Linux: `/home/CoolPerson/.cache/electron-hook/asar/my-mod-name.asar` 47 | /// 48 | /// Windows: `C:/Users/CoolPerson/AppData/Local/electron-hook/asar/my-mod-name.asar` 49 | /// 50 | /// MacOS: TODO 51 | pub id: String, 52 | 53 | /// The template for the index.js that will go into the ASAR archive. 54 | /// 55 | /// There are multiple environment variables that can be used in the template: 56 | /// 57 | /// | Environment Variable | Description | Notes | 58 | /// | ---------------------------------- | ----------------------------------------------- | ------------------------ | 59 | /// | `MODLOADER_EXECUTABLE` | Specifies the path to the Modloader executable. | | 60 | /// | `MODLOADER_MOD_ENTRYPOINT` | The path to the entrypoint of the mod. | | 61 | /// | `MODLOADER_ASAR_ID` | The name of the ASAR ID selected | | 62 | /// | `MODLOADER_ASAR_PATH` | The path to the ASAR file. | | 63 | /// | `MODLOADER_LIBRARY_PATH` | The path to the `.dll` or `.so`. | | 64 | /// | `MODLOADER_ORIGINAL_ASAR_RELATIVE` | The relative path to the original ASAR file | Is always `../_app.asar` | 65 | /// | `MODLOADER_PROFILE_DIR` | The path to the custom profile directory | Optional | 66 | /// | `MODLOADER_WM_CLASS` | The WM_CLASS of the Electron application. | Optional | 67 | /// | `MODLOADER_FOLDER_NAME` | the app- folder name | Windows only | 68 | /// 69 | /// For a basic implementation, you want to at least require your mod, e.g.: 70 | /// 71 | /// ```javascript 72 | /// require(process.env.MODLOADER_MOD_ENTRYPOINT); 73 | /// ``` 74 | pub template: String, 75 | 76 | /// The WM_CLASS of the application that the mod is for. 77 | /// 78 | /// You can use this to make it show as a different application on your Linux taskbar. 79 | /// 80 | /// This (probably) has no effect on Windows. 81 | pub wm_class: Option, 82 | 83 | /// The entrypoint for the mod. This should be the path to the main file for your mod. 84 | /// 85 | /// Preferably, you should get the path using [electron_hook::paths::mod_artifact_dir] 86 | /// 87 | /// You can use it like so: 88 | /// 89 | /// ```rust 90 | /// use electron_hook::paths::mod_artifact_dir; 91 | /// let entrypoint = mod_artifact_dir("vencord").join("patcher.js"); 92 | /// // Linux: /home/CoolPerson/.cache/electron-hook/mods/vencord/patcher.js 93 | /// // Windows: C:/Users/CoolPerson/AppData/Local/electron-hook/mods/vencord/patcher.js 94 | /// // MacOS: TODO 95 | /// ``` 96 | pub mod_entrypoint: String, 97 | 98 | /// An optional alternative profile for the mod. 99 | /// 100 | /// A profile is a unique instance of an application's data directory - meaning separate settings, cache, chromium instance, etc. 101 | /// You do not need to use this for basic installs, but if you want to run multiple instances of the same client with different mods or settings, you can use this. 102 | /// 103 | /// Preferably, you should get the path using [electron_hook::paths::data_profile_dir] 104 | /// 105 | /// You can use it like so: 106 | /// 107 | /// ```rust 108 | /// use electron_hook::paths::data_profile_dir; 109 | /// let profile_dir = data_profile_dir("moonlight"); 110 | /// // Linux: /home/CoolPerson/.local/share/electron-hook/profiles/moonlight 111 | /// // Windows: C:/Users/CoolPerson/AppData/Roaming/electron-hook/profiles/moonlight 112 | /// // MacOS: TODO 113 | /// ``` 114 | pub profile_dir: Option, 115 | } 116 | 117 | impl Asar { 118 | /// Create a new Asar builder. 119 | pub fn new() -> Self { 120 | Self::default() 121 | } 122 | 123 | /// Get the path to the ASAR archive. 124 | pub fn get_path(&self) -> Option { 125 | (!self.id.is_empty()).then(|| crate::paths::asar_cache_path(&self.id)) 126 | } 127 | 128 | /// Generate a random UUID for the ASAR archive to use. 129 | #[cfg(feature = "uuid")] 130 | pub fn with_uuid(mut self) -> Self { 131 | self.id = uuid::Uuid::new_v4().to_string(); 132 | std::env::set_var("MODLOADER_ASAR_ID", self.id.clone()); 133 | self 134 | } 135 | 136 | /// Provide a reusable ID for the ASAR archive to use. 137 | /// 138 | /// See [Asar::id] 139 | pub fn with_id(mut self, id: &str) -> Self { 140 | self.id = id.to_string(); 141 | std::env::set_var("MODLOADER_ASAR_ID", id); 142 | self 143 | } 144 | 145 | /// Provide the template for your index.js to use 146 | /// 147 | /// See [Asar::template] 148 | pub fn with_template(mut self, template: &str) -> Self { 149 | self.template = template.to_string(); 150 | self 151 | } 152 | 153 | /// Provide the entrypoint for your mod. 154 | /// 155 | /// See [Asar::mod_entrypoint] 156 | pub fn with_mod_entrypoint(mut self, mod_entrypoint: &str) -> Self { 157 | self.mod_entrypoint = mod_entrypoint.to_string(); 158 | std::env::set_var("MODLOADER_MOD_ENTRYPOINT", mod_entrypoint); 159 | self 160 | } 161 | 162 | /// Provide the WM_CLASS of the application on launch. 163 | /// 164 | /// See [Asar::wm_class] 165 | pub fn with_wm_class(mut self, wm_class: &str) -> Self { 166 | self.wm_class = Some(wm_class.to_string()); 167 | std::env::set_var("MODLOADER_WM_CLASS", wm_class); 168 | self 169 | } 170 | 171 | /// Provide the profile directory for your mod. 172 | /// 173 | /// See [Asar::profile_dir] 174 | pub fn with_profile_dir(mut self, profile_dir: &str) -> Self { 175 | self.profile_dir = Some(profile_dir.to_string()); 176 | std::env::set_var("MODLOADER_PROFILE_DIR", profile_dir); 177 | self 178 | } 179 | 180 | /// Create the ASAR file and write it to disk, returning the path to the ASAR file. 181 | /// 182 | /// See [Usage](crate::asar::Asar#usage) for how the path is generated. 183 | pub fn create(&self) -> Result { 184 | use crate::paths::asar_cache_path; 185 | 186 | let asar_path = asar_cache_path(&self.id); 187 | 188 | let mut asar = asar::AsarWriter::new(); 189 | 190 | asar.write_file("index.js", self.template.clone(), false) 191 | .map_err(|e| format!("Failed to write index.js: {e}"))?; 192 | 193 | asar.write_file("package.json", make_package_json(&self.wm_class), false) 194 | .map_err(|e| format!("Failed to write package.json: {e}"))?; 195 | 196 | let file = std::fs::File::create(&asar_path) 197 | .map_err(|e| format!("Failed to create file at {}: {e}", asar_path.display()))?; 198 | 199 | asar.finalize(file) 200 | .map_err(|e| format!("Failed to write asar to disk with error: {e}"))?; 201 | 202 | Ok(asar_path) 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/windows/hooks.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | ffi::{c_char, c_void, CStr, CString}, 3 | mem::transmute, 4 | str::FromStr, 5 | }; 6 | 7 | use detours_sys::{ 8 | DetourAttach, DetourCreateProcessWithDllW, DetourIsHelperProcess, DetourRestoreAfterWith, 9 | DetourTransactionAbort, DetourTransactionBegin, DetourTransactionCommit, DetourUpdateThread, 10 | }; 11 | use widestring::U16CString; 12 | use winapi::{ 13 | shared::minwindef::{BOOL, DWORD, HINSTANCE, LPVOID}, 14 | um::{ 15 | libloaderapi::{GetModuleHandleA, GetProcAddress}, 16 | minwinbase::LPSECURITY_ATTRIBUTES, 17 | processthreadsapi::{ 18 | GetCurrentThread, ResumeThread, LPPROCESS_INFORMATION, LPSTARTUPINFOW, 19 | }, 20 | winnt::{DLL_PROCESS_ATTACH, HANDLE, LPCWSTR, LPWSTR}, 21 | winuser::MessageBoxA, 22 | }, 23 | }; 24 | 25 | #[cfg(debug_assertions)] 26 | #[link(name = "kernel32")] 27 | unsafe extern "system" { 28 | unsafe fn AllocConsole() -> BOOL; 29 | } 30 | 31 | // Environment variables 32 | mod env { 33 | use std::sync::LazyLock; 34 | 35 | macro_rules! lazy_env { 36 | ($name:expr) => { 37 | LazyLock::new(|| std::env::var($name).unwrap()) 38 | }; 39 | } 40 | 41 | pub static ASAR_PATH: LazyLock = lazy_env!("MODLOADER_ASAR_PATH"); 42 | pub static EXE_PATH: LazyLock = lazy_env!("MODLOADER_EXECUTABLE"); 43 | pub static DLL_PATH: LazyLock = lazy_env!("MODLOADER_LIBRARY_PATH"); 44 | pub static FOLDER_NAME: LazyLock = lazy_env!("MODLOADER_FOLDER_NAME"); 45 | } 46 | 47 | // Import the original functions to be hooked 48 | #[allow(non_upper_case_globals)] 49 | mod original { 50 | use winapi::um::{ 51 | fileapi::{CreateFileW as CreateFileW_, GetFileAttributesW as GetFileAttributesW_}, 52 | processthreadsapi::CreateProcessW as CreateProcessW_, 53 | winbase::MoveFileExW as MoveFileExW_, 54 | }; 55 | 56 | #[link(name = "user32")] 57 | unsafe extern "C" { 58 | #[link_name = "SetCurrentProcessExplicitAppUserModelID"] 59 | unsafe fn SetAUMID_(app_id: *const u16); 60 | } 61 | 62 | type FnPtr = *mut std::ffi::c_void; 63 | 64 | pub static mut GetFileAttributesW: FnPtr = GetFileAttributesW_ as _; 65 | pub static mut CreateFileW: FnPtr = CreateFileW_ as _; 66 | pub static mut CreateProcessW: FnPtr = CreateProcessW_ as _; 67 | pub static mut MoveFileExW: FnPtr = MoveFileExW_ as _; 68 | pub static mut SetAUMID: FnPtr = SetAUMID_ as _; 69 | pub static mut uv_fs_lstat: FnPtr = std::ptr::null_mut(); 70 | } 71 | 72 | // We need to make sure that our hooks only affect the current version of Discord. 73 | // Otherwise, the updater might not work! 74 | fn prefix_file(file_name: &str) -> String { 75 | format!("{}\\{}", env::FOLDER_NAME.as_str(), file_name) 76 | } 77 | 78 | macro_rules! error_hooking_msg { 79 | ($msg:expr) => { 80 | MessageBoxA( 81 | std::ptr::null_mut(), 82 | $msg.as_ptr() as *const i8, 83 | "Error Hooking".as_ptr() as *const i8, 84 | 0, 85 | ); 86 | }; 87 | } 88 | 89 | #[no_mangle] 90 | pub unsafe extern "system" fn DllMain( 91 | _hinst_dll: HINSTANCE, 92 | fwd_reason: DWORD, 93 | _lpv_reserved: LPVOID, 94 | ) -> i32 { 95 | if DetourIsHelperProcess() == 1 { 96 | return 1; 97 | } 98 | 99 | if fwd_reason != DLL_PROCESS_ATTACH { 100 | return 1; 101 | } 102 | 103 | DetourRestoreAfterWith(); 104 | 105 | DetourTransactionBegin(); 106 | DetourUpdateThread(GetCurrentThread() as _); 107 | 108 | #[cfg(debug_assertions)] 109 | AllocConsole(); 110 | 111 | macro_rules! attach { 112 | ($orig:ident, $target:ident) => { 113 | let result = DetourAttach(&raw mut original::$orig, $target as _); 114 | 115 | if result != 0 { 116 | error_hooking_msg!(format!( 117 | "Failed to hook {}. Please report this issue.", 118 | stringify!($orig) 119 | )); 120 | DetourTransactionAbort(); 121 | return 1; 122 | }; 123 | }; 124 | } 125 | 126 | attach!(GetFileAttributesW, get_file_attributes_w); 127 | attach!(CreateFileW, create_file_w); 128 | attach!(MoveFileExW, move_file_ex_w); 129 | attach!(CreateProcessW, create_process_w); 130 | attach!(SetAUMID, set_aumid); 131 | 132 | fn get_executable_name() -> Option { 133 | let current_exe = std::env::current_exe().ok()?; 134 | let file_name = current_exe.file_name()?; 135 | let file_name = file_name.to_str()?; 136 | let file_name_cstr = CString::new(file_name).ok()?; 137 | Some(file_name_cstr) 138 | } 139 | 140 | if let Some(current_exe) = get_executable_name() { 141 | let process_handle = GetModuleHandleA(current_exe.as_ptr()); 142 | if !process_handle.is_null() { 143 | let uv_fs_lstat_ptr = GetProcAddress(process_handle as _, c"uv_fs_lstat".as_ptr()); 144 | if !uv_fs_lstat_ptr.is_null() { 145 | original::uv_fs_lstat = uv_fs_lstat_ptr as _; 146 | attach!(uv_fs_lstat, uv_fs_lstat); 147 | } 148 | } 149 | } 150 | 151 | DetourTransactionCommit(); 152 | 153 | 1 154 | } 155 | 156 | type UvFsLstat = unsafe extern "C" fn( 157 | _loop: *const c_void, 158 | req: *const c_void, 159 | path: *const c_char, 160 | cb: *const c_void, 161 | ) -> i32; 162 | unsafe extern "C" fn uv_fs_lstat( 163 | _loop: *const c_void, 164 | _req: *const c_void, 165 | path: *const c_char, 166 | _cb: *const c_void, 167 | ) -> i32 { 168 | let uv_fs_lstat: UvFsLstat = transmute(original::uv_fs_lstat); 169 | 170 | let file_name = CStr::from_ptr(path as _); 171 | let file_name = file_name.to_str().unwrap(); 172 | 173 | if file_name.contains("resources\\_app.asar") { 174 | let redirect_to = file_name.replace("\\_app.asar", "\\app.asar"); 175 | let redirect_to_c = std::ffi::CString::new(redirect_to.as_str()).unwrap(); 176 | 177 | return uv_fs_lstat(_loop, _req, redirect_to_c.as_ptr() as _, _cb); 178 | } 179 | if file_name.contains(&prefix_file("resources\\app.asar")) { 180 | let asar_path_cstr = std::ffi::CString::new(env::ASAR_PATH.as_str()).unwrap(); 181 | 182 | return uv_fs_lstat(_loop, _req, asar_path_cstr.as_ptr() as _, _cb); 183 | } 184 | uv_fs_lstat(_loop, _req, path, _cb) 185 | } 186 | 187 | type GetFileAttributesW = unsafe extern "C" fn(LPCWSTR) -> DWORD; 188 | 189 | unsafe extern "C" fn get_file_attributes_w(lp_file_name: LPCWSTR) -> DWORD { 190 | let file_name = U16CString::from_ptr_str(lp_file_name).to_string().unwrap(); 191 | 192 | let get_file_attributes_w: GetFileAttributesW = transmute(original::GetFileAttributesW); 193 | 194 | if file_name.contains("resources\\_app.asar") { 195 | let redirect_to = file_name.replace("\\_app.asar", "\\app.asar"); 196 | let redirect_to_c = std::ffi::CString::new(redirect_to.as_str()).unwrap(); 197 | let redirect_to = U16CString::from_str(redirect_to_c.to_str().unwrap()).unwrap(); 198 | 199 | return get_file_attributes_w(redirect_to.as_ptr()); 200 | } 201 | 202 | if file_name.contains(&prefix_file("resources\\app.asar")) { 203 | let asar_path_cstr = std::ffi::CString::new(env::ASAR_PATH.as_str()).unwrap(); 204 | let asar_path = U16CString::from_str(asar_path_cstr.to_str().unwrap()).unwrap(); 205 | 206 | return get_file_attributes_w(asar_path.as_ptr()); 207 | } 208 | 209 | get_file_attributes_w(lp_file_name) 210 | } 211 | 212 | type CreateFileW = unsafe extern "C" fn( 213 | LPCWSTR, 214 | DWORD, 215 | DWORD, 216 | LPSECURITY_ATTRIBUTES, 217 | DWORD, 218 | DWORD, 219 | HANDLE, 220 | ) -> HANDLE; 221 | 222 | unsafe extern "C" fn create_file_w( 223 | lp_file_name: LPCWSTR, 224 | dw_desired_access: DWORD, 225 | dw_share_mode: DWORD, 226 | lp_security_attributes: LPSECURITY_ATTRIBUTES, 227 | dw_creation_disposition: DWORD, 228 | dw_flags_and_attributes: DWORD, 229 | h_template_file: HANDLE, 230 | ) -> HANDLE { 231 | let create_file_w: CreateFileW = transmute(original::CreateFileW); 232 | 233 | let file_name = U16CString::from_ptr_str(lp_file_name).to_string().unwrap(); 234 | 235 | if file_name.contains("resources\\_app.asar") { 236 | let redirect_to = file_name.replace("\\_app.asar", "\\app.asar"); 237 | let redirect_to_c = std::ffi::CString::new(redirect_to.as_str()).unwrap(); 238 | let redirect_to = U16CString::from_str(redirect_to_c.to_str().unwrap()).unwrap(); 239 | 240 | return create_file_w( 241 | redirect_to.as_ptr(), 242 | dw_desired_access, 243 | dw_share_mode, 244 | lp_security_attributes, 245 | dw_creation_disposition, 246 | dw_flags_and_attributes, 247 | h_template_file, 248 | ); 249 | } 250 | 251 | if file_name.contains(&prefix_file("resources\\app.asar")) { 252 | let asar_path_cstr = std::ffi::CString::new(env::ASAR_PATH.as_str()).unwrap(); 253 | let asar_path = U16CString::from_str(asar_path_cstr.to_str().unwrap()).unwrap(); 254 | 255 | return create_file_w( 256 | asar_path.as_ptr(), 257 | dw_desired_access, 258 | dw_share_mode, 259 | lp_security_attributes, 260 | dw_creation_disposition, 261 | dw_flags_and_attributes, 262 | h_template_file, 263 | ); 264 | } 265 | 266 | create_file_w( 267 | lp_file_name, 268 | dw_desired_access, 269 | dw_share_mode, 270 | lp_security_attributes, 271 | dw_creation_disposition, 272 | dw_flags_and_attributes, 273 | h_template_file, 274 | ) 275 | } 276 | 277 | type MoveFileExW = unsafe extern "C" fn( 278 | lp_existing_file_name: LPCWSTR, 279 | lp_new_file_name: LPCWSTR, 280 | dw_flags: DWORD, 281 | ) -> BOOL; 282 | 283 | // This is needed to stop the updater from renaming app.asar to _app.asar 284 | unsafe extern "C" fn move_file_ex_w( 285 | lp_existing_file_name: LPCWSTR, 286 | lp_new_file_name: LPCWSTR, 287 | dw_flags: DWORD, 288 | ) -> BOOL { 289 | let move_file_ex_w: MoveFileExW = transmute(original::MoveFileExW); 290 | 291 | let new_file_name = U16CString::from_ptr_str(lp_new_file_name) 292 | .to_string() 293 | .unwrap(); 294 | 295 | // MoveFileExW moves _app.asar when we update Discord, so we should update MODLOADER_FOLDER_NAME just in case. 296 | if new_file_name.contains("\\_app.asar") { 297 | let redirect_to = new_file_name.replace("\\_app.asar", "\\app.asar"); 298 | 299 | if let Some(folder_name) = std::path::Path::new(&redirect_to) 300 | .parent() 301 | .and_then(|p| p.parent()) 302 | .and_then(|p| p.file_name()) 303 | { 304 | std::env::set_var( 305 | "MODLOADER_FOLDER_NAME", 306 | folder_name.to_string_lossy().to_string(), 307 | ); 308 | } 309 | 310 | let redirect_to_c = std::ffi::CString::new(redirect_to.as_str()).unwrap(); 311 | let redirect_to = U16CString::from_str(redirect_to_c.to_str().unwrap()).unwrap(); 312 | 313 | return move_file_ex_w(lp_existing_file_name, redirect_to.as_ptr(), dw_flags); 314 | } 315 | 316 | move_file_ex_w(lp_existing_file_name, lp_new_file_name, dw_flags) 317 | } 318 | 319 | type CreateProcessW = unsafe extern "C" fn( 320 | lp_application_name: LPCWSTR, 321 | lp_command_line: LPWSTR, 322 | lp_process_attributes: LPSECURITY_ATTRIBUTES, 323 | lp_thread_attributes: LPSECURITY_ATTRIBUTES, 324 | b_inherit_handles: BOOL, 325 | dw_creation_flags: DWORD, 326 | lp_environment: LPVOID, 327 | lp_current_directory: LPCWSTR, 328 | lp_startup_info: LPSTARTUPINFOW, 329 | lp_process_information: LPPROCESS_INFORMATION, 330 | ) -> BOOL; 331 | 332 | unsafe extern "C" fn create_process_w( 333 | lp_application_name: LPCWSTR, 334 | lp_command_line: LPWSTR, 335 | lp_process_attributes: LPSECURITY_ATTRIBUTES, 336 | lp_thread_attributes: LPSECURITY_ATTRIBUTES, 337 | b_inherit_handles: BOOL, 338 | dw_creation_flags: DWORD, 339 | lp_environment: LPVOID, 340 | lp_current_directory: LPCWSTR, 341 | lp_startup_info: LPSTARTUPINFOW, 342 | lp_process_information: LPPROCESS_INFORMATION, 343 | ) -> BOOL { 344 | let create_process_w: CreateProcessW = transmute(original::CreateProcessW); 345 | 346 | let command_line = U16CString::from_ptr_str(lp_command_line) 347 | .to_string() 348 | .unwrap(); 349 | 350 | // When the updater "restarts" Discord, it doesn't seem to pass any arguments to the process. 351 | // So we can just check if the command contains "--" to make sure we hook the new Discord instance. 352 | if command_line.contains("--") && !command_line.contains("--type=renderer") { 353 | // Run the original CreateProcessW 354 | return create_process_w( 355 | lp_application_name, 356 | lp_command_line, 357 | lp_process_attributes, 358 | lp_thread_attributes, 359 | b_inherit_handles, 360 | dw_creation_flags, 361 | lp_environment, 362 | lp_current_directory, 363 | lp_startup_info, 364 | lp_process_information, 365 | ); 366 | } 367 | 368 | let dll_path = CString::from_str(env::DLL_PATH.as_str()).unwrap(); 369 | 370 | #[allow( 371 | clippy::missing_transmute_annotations, 372 | reason = "Excessive boilerplate" 373 | )] 374 | let success = DetourCreateProcessWithDllW( 375 | lp_application_name, 376 | lp_command_line, 377 | lp_process_attributes as _, 378 | lp_thread_attributes as _, 379 | b_inherit_handles, 380 | dw_creation_flags, 381 | lp_environment as _, 382 | lp_current_directory, 383 | lp_startup_info as _, 384 | lp_process_information as _, 385 | dll_path.as_ptr(), 386 | Some(std::mem::transmute(original::CreateProcessW)), 387 | ); 388 | 389 | if success != 1 { 390 | eprintln!("[Electron Hook] Failed to create process"); 391 | return success; 392 | } 393 | 394 | ResumeThread((*lp_process_information).hThread as _); 395 | 396 | success 397 | } 398 | 399 | type SetAUMID = unsafe extern "system" fn(lp_app_id: LPCWSTR); 400 | 401 | unsafe extern "system" fn set_aumid(_lp_app_id: LPCWSTR) { 402 | let set_aumid: SetAUMID = std::mem::transmute(original::SetAUMID); 403 | 404 | // We set the AUMID to be the path of the launcher exe, so it looks like the launcher in the taskbar. 405 | // I spent way too long working on this. 406 | let new_id = U16CString::from_str(env::EXE_PATH.as_str()).unwrap(); 407 | set_aumid(new_id.as_ptr()); 408 | } 409 | -------------------------------------------------------------------------------- /vendor/detours-sys/src/bundled_bindings.rs: -------------------------------------------------------------------------------- 1 | /* automatically generated by rust-bindgen 0.69.4 */ 2 | 3 | pub type wchar_t = ::std::os::raw::c_ushort; 4 | pub type ULONG = ::std::os::raw::c_ulong; 5 | pub type DWORD = ::std::os::raw::c_ulong; 6 | pub type BOOL = ::std::os::raw::c_int; 7 | pub type BYTE = ::std::os::raw::c_uchar; 8 | pub type WORD = ::std::os::raw::c_ushort; 9 | pub type PBYTE = *mut BYTE; 10 | pub type LPBYTE = *mut BYTE; 11 | pub type PDWORD = *mut DWORD; 12 | pub type LPVOID = *mut ::std::os::raw::c_void; 13 | pub type LPCVOID = *const ::std::os::raw::c_void; 14 | pub type INT = ::std::os::raw::c_int; 15 | pub type PVOID = *mut ::std::os::raw::c_void; 16 | pub type CHAR = ::std::os::raw::c_char; 17 | pub type LONG = ::std::os::raw::c_long; 18 | pub type WCHAR = wchar_t; 19 | pub type LPWSTR = *mut WCHAR; 20 | pub type LPCWSTR = *const WCHAR; 21 | pub type LPSTR = *mut CHAR; 22 | pub type LPCSTR = *const CHAR; 23 | pub type HANDLE = *mut ::std::os::raw::c_void; 24 | #[repr(C)] 25 | #[derive(Debug, Copy, Clone)] 26 | pub struct _GUID { 27 | pub Data1: ::std::os::raw::c_ulong, 28 | pub Data2: ::std::os::raw::c_ushort, 29 | pub Data3: ::std::os::raw::c_ushort, 30 | pub Data4: [::std::os::raw::c_uchar; 8usize], 31 | } 32 | #[test] 33 | fn bindgen_test_layout__GUID() { 34 | const UNINIT: ::std::mem::MaybeUninit<_GUID> = ::std::mem::MaybeUninit::uninit(); 35 | let ptr = UNINIT.as_ptr(); 36 | assert_eq!( 37 | ::std::mem::size_of::<_GUID>(), 38 | 16usize, 39 | concat!("Size of: ", stringify!(_GUID)) 40 | ); 41 | assert_eq!( 42 | ::std::mem::align_of::<_GUID>(), 43 | 4usize, 44 | concat!("Alignment of ", stringify!(_GUID)) 45 | ); 46 | assert_eq!( 47 | unsafe { ::std::ptr::addr_of!((*ptr).Data1) as usize - ptr as usize }, 48 | 0usize, 49 | concat!( 50 | "Offset of field: ", 51 | stringify!(_GUID), 52 | "::", 53 | stringify!(Data1) 54 | ) 55 | ); 56 | assert_eq!( 57 | unsafe { ::std::ptr::addr_of!((*ptr).Data2) as usize - ptr as usize }, 58 | 4usize, 59 | concat!( 60 | "Offset of field: ", 61 | stringify!(_GUID), 62 | "::", 63 | stringify!(Data2) 64 | ) 65 | ); 66 | assert_eq!( 67 | unsafe { ::std::ptr::addr_of!((*ptr).Data3) as usize - ptr as usize }, 68 | 6usize, 69 | concat!( 70 | "Offset of field: ", 71 | stringify!(_GUID), 72 | "::", 73 | stringify!(Data3) 74 | ) 75 | ); 76 | assert_eq!( 77 | unsafe { ::std::ptr::addr_of!((*ptr).Data4) as usize - ptr as usize }, 78 | 8usize, 79 | concat!( 80 | "Offset of field: ", 81 | stringify!(_GUID), 82 | "::", 83 | stringify!(Data4) 84 | ) 85 | ); 86 | } 87 | pub type GUID = _GUID; 88 | #[repr(C)] 89 | #[derive(Debug, Copy, Clone)] 90 | pub struct HINSTANCE__ { 91 | pub unused: ::std::os::raw::c_int, 92 | } 93 | #[test] 94 | fn bindgen_test_layout_HINSTANCE__() { 95 | const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); 96 | let ptr = UNINIT.as_ptr(); 97 | assert_eq!( 98 | ::std::mem::size_of::(), 99 | 4usize, 100 | concat!("Size of: ", stringify!(HINSTANCE__)) 101 | ); 102 | assert_eq!( 103 | ::std::mem::align_of::(), 104 | 4usize, 105 | concat!("Alignment of ", stringify!(HINSTANCE__)) 106 | ); 107 | assert_eq!( 108 | unsafe { ::std::ptr::addr_of!((*ptr).unused) as usize - ptr as usize }, 109 | 0usize, 110 | concat!( 111 | "Offset of field: ", 112 | stringify!(HINSTANCE__), 113 | "::", 114 | stringify!(unused) 115 | ) 116 | ); 117 | } 118 | pub type HINSTANCE = *mut HINSTANCE__; 119 | pub type HMODULE = HINSTANCE; 120 | #[repr(C)] 121 | #[derive(Debug, Copy, Clone)] 122 | pub struct HWND__ { 123 | pub unused: ::std::os::raw::c_int, 124 | } 125 | #[test] 126 | fn bindgen_test_layout_HWND__() { 127 | const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); 128 | let ptr = UNINIT.as_ptr(); 129 | assert_eq!( 130 | ::std::mem::size_of::(), 131 | 4usize, 132 | concat!("Size of: ", stringify!(HWND__)) 133 | ); 134 | assert_eq!( 135 | ::std::mem::align_of::(), 136 | 4usize, 137 | concat!("Alignment of ", stringify!(HWND__)) 138 | ); 139 | assert_eq!( 140 | unsafe { ::std::ptr::addr_of!((*ptr).unused) as usize - ptr as usize }, 141 | 0usize, 142 | concat!( 143 | "Offset of field: ", 144 | stringify!(HWND__), 145 | "::", 146 | stringify!(unused) 147 | ) 148 | ); 149 | } 150 | pub type HWND = *mut HWND__; 151 | #[repr(C)] 152 | #[derive(Debug, Copy, Clone)] 153 | pub struct _SECURITY_ATTRIBUTES { 154 | pub nLength: DWORD, 155 | pub lpSecurityDescriptor: LPVOID, 156 | pub bInheritHandle: BOOL, 157 | } 158 | #[test] 159 | fn bindgen_test_layout__SECURITY_ATTRIBUTES() { 160 | const UNINIT: ::std::mem::MaybeUninit<_SECURITY_ATTRIBUTES> = ::std::mem::MaybeUninit::uninit(); 161 | let ptr = UNINIT.as_ptr(); 162 | assert_eq!( 163 | ::std::mem::size_of::<_SECURITY_ATTRIBUTES>(), 164 | 24usize, 165 | concat!("Size of: ", stringify!(_SECURITY_ATTRIBUTES)) 166 | ); 167 | assert_eq!( 168 | ::std::mem::align_of::<_SECURITY_ATTRIBUTES>(), 169 | 8usize, 170 | concat!("Alignment of ", stringify!(_SECURITY_ATTRIBUTES)) 171 | ); 172 | assert_eq!( 173 | unsafe { ::std::ptr::addr_of!((*ptr).nLength) as usize - ptr as usize }, 174 | 0usize, 175 | concat!( 176 | "Offset of field: ", 177 | stringify!(_SECURITY_ATTRIBUTES), 178 | "::", 179 | stringify!(nLength) 180 | ) 181 | ); 182 | assert_eq!( 183 | unsafe { ::std::ptr::addr_of!((*ptr).lpSecurityDescriptor) as usize - ptr as usize }, 184 | 8usize, 185 | concat!( 186 | "Offset of field: ", 187 | stringify!(_SECURITY_ATTRIBUTES), 188 | "::", 189 | stringify!(lpSecurityDescriptor) 190 | ) 191 | ); 192 | assert_eq!( 193 | unsafe { ::std::ptr::addr_of!((*ptr).bInheritHandle) as usize - ptr as usize }, 194 | 16usize, 195 | concat!( 196 | "Offset of field: ", 197 | stringify!(_SECURITY_ATTRIBUTES), 198 | "::", 199 | stringify!(bInheritHandle) 200 | ) 201 | ); 202 | } 203 | pub type LPSECURITY_ATTRIBUTES = *mut _SECURITY_ATTRIBUTES; 204 | #[repr(C)] 205 | #[derive(Debug, Copy, Clone)] 206 | pub struct _PROCESS_INFORMATION { 207 | pub hProcess: HANDLE, 208 | pub hThread: HANDLE, 209 | pub dwProcessId: DWORD, 210 | pub dwThreadId: DWORD, 211 | } 212 | #[test] 213 | fn bindgen_test_layout__PROCESS_INFORMATION() { 214 | const UNINIT: ::std::mem::MaybeUninit<_PROCESS_INFORMATION> = ::std::mem::MaybeUninit::uninit(); 215 | let ptr = UNINIT.as_ptr(); 216 | assert_eq!( 217 | ::std::mem::size_of::<_PROCESS_INFORMATION>(), 218 | 24usize, 219 | concat!("Size of: ", stringify!(_PROCESS_INFORMATION)) 220 | ); 221 | assert_eq!( 222 | ::std::mem::align_of::<_PROCESS_INFORMATION>(), 223 | 8usize, 224 | concat!("Alignment of ", stringify!(_PROCESS_INFORMATION)) 225 | ); 226 | assert_eq!( 227 | unsafe { ::std::ptr::addr_of!((*ptr).hProcess) as usize - ptr as usize }, 228 | 0usize, 229 | concat!( 230 | "Offset of field: ", 231 | stringify!(_PROCESS_INFORMATION), 232 | "::", 233 | stringify!(hProcess) 234 | ) 235 | ); 236 | assert_eq!( 237 | unsafe { ::std::ptr::addr_of!((*ptr).hThread) as usize - ptr as usize }, 238 | 8usize, 239 | concat!( 240 | "Offset of field: ", 241 | stringify!(_PROCESS_INFORMATION), 242 | "::", 243 | stringify!(hThread) 244 | ) 245 | ); 246 | assert_eq!( 247 | unsafe { ::std::ptr::addr_of!((*ptr).dwProcessId) as usize - ptr as usize }, 248 | 16usize, 249 | concat!( 250 | "Offset of field: ", 251 | stringify!(_PROCESS_INFORMATION), 252 | "::", 253 | stringify!(dwProcessId) 254 | ) 255 | ); 256 | assert_eq!( 257 | unsafe { ::std::ptr::addr_of!((*ptr).dwThreadId) as usize - ptr as usize }, 258 | 20usize, 259 | concat!( 260 | "Offset of field: ", 261 | stringify!(_PROCESS_INFORMATION), 262 | "::", 263 | stringify!(dwThreadId) 264 | ) 265 | ); 266 | } 267 | pub type LPPROCESS_INFORMATION = *mut _PROCESS_INFORMATION; 268 | #[repr(C)] 269 | #[derive(Debug, Copy, Clone)] 270 | pub struct _STARTUPINFOA { 271 | pub cb: DWORD, 272 | pub lpReserved: LPSTR, 273 | pub lpDesktop: LPSTR, 274 | pub lpTitle: LPSTR, 275 | pub dwX: DWORD, 276 | pub dwY: DWORD, 277 | pub dwXSize: DWORD, 278 | pub dwYSize: DWORD, 279 | pub dwXCountChars: DWORD, 280 | pub dwYCountChars: DWORD, 281 | pub dwFillAttribute: DWORD, 282 | pub dwFlags: DWORD, 283 | pub wShowWindow: WORD, 284 | pub cbReserved2: WORD, 285 | pub lpReserved2: LPBYTE, 286 | pub hStdInput: HANDLE, 287 | pub hStdOutput: HANDLE, 288 | pub hStdError: HANDLE, 289 | } 290 | #[test] 291 | fn bindgen_test_layout__STARTUPINFOA() { 292 | const UNINIT: ::std::mem::MaybeUninit<_STARTUPINFOA> = ::std::mem::MaybeUninit::uninit(); 293 | let ptr = UNINIT.as_ptr(); 294 | assert_eq!( 295 | ::std::mem::size_of::<_STARTUPINFOA>(), 296 | 104usize, 297 | concat!("Size of: ", stringify!(_STARTUPINFOA)) 298 | ); 299 | assert_eq!( 300 | ::std::mem::align_of::<_STARTUPINFOA>(), 301 | 8usize, 302 | concat!("Alignment of ", stringify!(_STARTUPINFOA)) 303 | ); 304 | assert_eq!( 305 | unsafe { ::std::ptr::addr_of!((*ptr).cb) as usize - ptr as usize }, 306 | 0usize, 307 | concat!( 308 | "Offset of field: ", 309 | stringify!(_STARTUPINFOA), 310 | "::", 311 | stringify!(cb) 312 | ) 313 | ); 314 | assert_eq!( 315 | unsafe { ::std::ptr::addr_of!((*ptr).lpReserved) as usize - ptr as usize }, 316 | 8usize, 317 | concat!( 318 | "Offset of field: ", 319 | stringify!(_STARTUPINFOA), 320 | "::", 321 | stringify!(lpReserved) 322 | ) 323 | ); 324 | assert_eq!( 325 | unsafe { ::std::ptr::addr_of!((*ptr).lpDesktop) as usize - ptr as usize }, 326 | 16usize, 327 | concat!( 328 | "Offset of field: ", 329 | stringify!(_STARTUPINFOA), 330 | "::", 331 | stringify!(lpDesktop) 332 | ) 333 | ); 334 | assert_eq!( 335 | unsafe { ::std::ptr::addr_of!((*ptr).lpTitle) as usize - ptr as usize }, 336 | 24usize, 337 | concat!( 338 | "Offset of field: ", 339 | stringify!(_STARTUPINFOA), 340 | "::", 341 | stringify!(lpTitle) 342 | ) 343 | ); 344 | assert_eq!( 345 | unsafe { ::std::ptr::addr_of!((*ptr).dwX) as usize - ptr as usize }, 346 | 32usize, 347 | concat!( 348 | "Offset of field: ", 349 | stringify!(_STARTUPINFOA), 350 | "::", 351 | stringify!(dwX) 352 | ) 353 | ); 354 | assert_eq!( 355 | unsafe { ::std::ptr::addr_of!((*ptr).dwY) as usize - ptr as usize }, 356 | 36usize, 357 | concat!( 358 | "Offset of field: ", 359 | stringify!(_STARTUPINFOA), 360 | "::", 361 | stringify!(dwY) 362 | ) 363 | ); 364 | assert_eq!( 365 | unsafe { ::std::ptr::addr_of!((*ptr).dwXSize) as usize - ptr as usize }, 366 | 40usize, 367 | concat!( 368 | "Offset of field: ", 369 | stringify!(_STARTUPINFOA), 370 | "::", 371 | stringify!(dwXSize) 372 | ) 373 | ); 374 | assert_eq!( 375 | unsafe { ::std::ptr::addr_of!((*ptr).dwYSize) as usize - ptr as usize }, 376 | 44usize, 377 | concat!( 378 | "Offset of field: ", 379 | stringify!(_STARTUPINFOA), 380 | "::", 381 | stringify!(dwYSize) 382 | ) 383 | ); 384 | assert_eq!( 385 | unsafe { ::std::ptr::addr_of!((*ptr).dwXCountChars) as usize - ptr as usize }, 386 | 48usize, 387 | concat!( 388 | "Offset of field: ", 389 | stringify!(_STARTUPINFOA), 390 | "::", 391 | stringify!(dwXCountChars) 392 | ) 393 | ); 394 | assert_eq!( 395 | unsafe { ::std::ptr::addr_of!((*ptr).dwYCountChars) as usize - ptr as usize }, 396 | 52usize, 397 | concat!( 398 | "Offset of field: ", 399 | stringify!(_STARTUPINFOA), 400 | "::", 401 | stringify!(dwYCountChars) 402 | ) 403 | ); 404 | assert_eq!( 405 | unsafe { ::std::ptr::addr_of!((*ptr).dwFillAttribute) as usize - ptr as usize }, 406 | 56usize, 407 | concat!( 408 | "Offset of field: ", 409 | stringify!(_STARTUPINFOA), 410 | "::", 411 | stringify!(dwFillAttribute) 412 | ) 413 | ); 414 | assert_eq!( 415 | unsafe { ::std::ptr::addr_of!((*ptr).dwFlags) as usize - ptr as usize }, 416 | 60usize, 417 | concat!( 418 | "Offset of field: ", 419 | stringify!(_STARTUPINFOA), 420 | "::", 421 | stringify!(dwFlags) 422 | ) 423 | ); 424 | assert_eq!( 425 | unsafe { ::std::ptr::addr_of!((*ptr).wShowWindow) as usize - ptr as usize }, 426 | 64usize, 427 | concat!( 428 | "Offset of field: ", 429 | stringify!(_STARTUPINFOA), 430 | "::", 431 | stringify!(wShowWindow) 432 | ) 433 | ); 434 | assert_eq!( 435 | unsafe { ::std::ptr::addr_of!((*ptr).cbReserved2) as usize - ptr as usize }, 436 | 66usize, 437 | concat!( 438 | "Offset of field: ", 439 | stringify!(_STARTUPINFOA), 440 | "::", 441 | stringify!(cbReserved2) 442 | ) 443 | ); 444 | assert_eq!( 445 | unsafe { ::std::ptr::addr_of!((*ptr).lpReserved2) as usize - ptr as usize }, 446 | 72usize, 447 | concat!( 448 | "Offset of field: ", 449 | stringify!(_STARTUPINFOA), 450 | "::", 451 | stringify!(lpReserved2) 452 | ) 453 | ); 454 | assert_eq!( 455 | unsafe { ::std::ptr::addr_of!((*ptr).hStdInput) as usize - ptr as usize }, 456 | 80usize, 457 | concat!( 458 | "Offset of field: ", 459 | stringify!(_STARTUPINFOA), 460 | "::", 461 | stringify!(hStdInput) 462 | ) 463 | ); 464 | assert_eq!( 465 | unsafe { ::std::ptr::addr_of!((*ptr).hStdOutput) as usize - ptr as usize }, 466 | 88usize, 467 | concat!( 468 | "Offset of field: ", 469 | stringify!(_STARTUPINFOA), 470 | "::", 471 | stringify!(hStdOutput) 472 | ) 473 | ); 474 | assert_eq!( 475 | unsafe { ::std::ptr::addr_of!((*ptr).hStdError) as usize - ptr as usize }, 476 | 96usize, 477 | concat!( 478 | "Offset of field: ", 479 | stringify!(_STARTUPINFOA), 480 | "::", 481 | stringify!(hStdError) 482 | ) 483 | ); 484 | } 485 | pub type LPSTARTUPINFOA = *mut _STARTUPINFOA; 486 | #[repr(C)] 487 | #[derive(Debug, Copy, Clone)] 488 | pub struct _STARTUPINFOW { 489 | pub cb: DWORD, 490 | pub lpReserved: LPWSTR, 491 | pub lpDesktop: LPWSTR, 492 | pub lpTitle: LPWSTR, 493 | pub dwX: DWORD, 494 | pub dwY: DWORD, 495 | pub dwXSize: DWORD, 496 | pub dwYSize: DWORD, 497 | pub dwXCountChars: DWORD, 498 | pub dwYCountChars: DWORD, 499 | pub dwFillAttribute: DWORD, 500 | pub dwFlags: DWORD, 501 | pub wShowWindow: WORD, 502 | pub cbReserved2: WORD, 503 | pub lpReserved2: LPBYTE, 504 | pub hStdInput: HANDLE, 505 | pub hStdOutput: HANDLE, 506 | pub hStdError: HANDLE, 507 | } 508 | #[test] 509 | fn bindgen_test_layout__STARTUPINFOW() { 510 | const UNINIT: ::std::mem::MaybeUninit<_STARTUPINFOW> = ::std::mem::MaybeUninit::uninit(); 511 | let ptr = UNINIT.as_ptr(); 512 | assert_eq!( 513 | ::std::mem::size_of::<_STARTUPINFOW>(), 514 | 104usize, 515 | concat!("Size of: ", stringify!(_STARTUPINFOW)) 516 | ); 517 | assert_eq!( 518 | ::std::mem::align_of::<_STARTUPINFOW>(), 519 | 8usize, 520 | concat!("Alignment of ", stringify!(_STARTUPINFOW)) 521 | ); 522 | assert_eq!( 523 | unsafe { ::std::ptr::addr_of!((*ptr).cb) as usize - ptr as usize }, 524 | 0usize, 525 | concat!( 526 | "Offset of field: ", 527 | stringify!(_STARTUPINFOW), 528 | "::", 529 | stringify!(cb) 530 | ) 531 | ); 532 | assert_eq!( 533 | unsafe { ::std::ptr::addr_of!((*ptr).lpReserved) as usize - ptr as usize }, 534 | 8usize, 535 | concat!( 536 | "Offset of field: ", 537 | stringify!(_STARTUPINFOW), 538 | "::", 539 | stringify!(lpReserved) 540 | ) 541 | ); 542 | assert_eq!( 543 | unsafe { ::std::ptr::addr_of!((*ptr).lpDesktop) as usize - ptr as usize }, 544 | 16usize, 545 | concat!( 546 | "Offset of field: ", 547 | stringify!(_STARTUPINFOW), 548 | "::", 549 | stringify!(lpDesktop) 550 | ) 551 | ); 552 | assert_eq!( 553 | unsafe { ::std::ptr::addr_of!((*ptr).lpTitle) as usize - ptr as usize }, 554 | 24usize, 555 | concat!( 556 | "Offset of field: ", 557 | stringify!(_STARTUPINFOW), 558 | "::", 559 | stringify!(lpTitle) 560 | ) 561 | ); 562 | assert_eq!( 563 | unsafe { ::std::ptr::addr_of!((*ptr).dwX) as usize - ptr as usize }, 564 | 32usize, 565 | concat!( 566 | "Offset of field: ", 567 | stringify!(_STARTUPINFOW), 568 | "::", 569 | stringify!(dwX) 570 | ) 571 | ); 572 | assert_eq!( 573 | unsafe { ::std::ptr::addr_of!((*ptr).dwY) as usize - ptr as usize }, 574 | 36usize, 575 | concat!( 576 | "Offset of field: ", 577 | stringify!(_STARTUPINFOW), 578 | "::", 579 | stringify!(dwY) 580 | ) 581 | ); 582 | assert_eq!( 583 | unsafe { ::std::ptr::addr_of!((*ptr).dwXSize) as usize - ptr as usize }, 584 | 40usize, 585 | concat!( 586 | "Offset of field: ", 587 | stringify!(_STARTUPINFOW), 588 | "::", 589 | stringify!(dwXSize) 590 | ) 591 | ); 592 | assert_eq!( 593 | unsafe { ::std::ptr::addr_of!((*ptr).dwYSize) as usize - ptr as usize }, 594 | 44usize, 595 | concat!( 596 | "Offset of field: ", 597 | stringify!(_STARTUPINFOW), 598 | "::", 599 | stringify!(dwYSize) 600 | ) 601 | ); 602 | assert_eq!( 603 | unsafe { ::std::ptr::addr_of!((*ptr).dwXCountChars) as usize - ptr as usize }, 604 | 48usize, 605 | concat!( 606 | "Offset of field: ", 607 | stringify!(_STARTUPINFOW), 608 | "::", 609 | stringify!(dwXCountChars) 610 | ) 611 | ); 612 | assert_eq!( 613 | unsafe { ::std::ptr::addr_of!((*ptr).dwYCountChars) as usize - ptr as usize }, 614 | 52usize, 615 | concat!( 616 | "Offset of field: ", 617 | stringify!(_STARTUPINFOW), 618 | "::", 619 | stringify!(dwYCountChars) 620 | ) 621 | ); 622 | assert_eq!( 623 | unsafe { ::std::ptr::addr_of!((*ptr).dwFillAttribute) as usize - ptr as usize }, 624 | 56usize, 625 | concat!( 626 | "Offset of field: ", 627 | stringify!(_STARTUPINFOW), 628 | "::", 629 | stringify!(dwFillAttribute) 630 | ) 631 | ); 632 | assert_eq!( 633 | unsafe { ::std::ptr::addr_of!((*ptr).dwFlags) as usize - ptr as usize }, 634 | 60usize, 635 | concat!( 636 | "Offset of field: ", 637 | stringify!(_STARTUPINFOW), 638 | "::", 639 | stringify!(dwFlags) 640 | ) 641 | ); 642 | assert_eq!( 643 | unsafe { ::std::ptr::addr_of!((*ptr).wShowWindow) as usize - ptr as usize }, 644 | 64usize, 645 | concat!( 646 | "Offset of field: ", 647 | stringify!(_STARTUPINFOW), 648 | "::", 649 | stringify!(wShowWindow) 650 | ) 651 | ); 652 | assert_eq!( 653 | unsafe { ::std::ptr::addr_of!((*ptr).cbReserved2) as usize - ptr as usize }, 654 | 66usize, 655 | concat!( 656 | "Offset of field: ", 657 | stringify!(_STARTUPINFOW), 658 | "::", 659 | stringify!(cbReserved2) 660 | ) 661 | ); 662 | assert_eq!( 663 | unsafe { ::std::ptr::addr_of!((*ptr).lpReserved2) as usize - ptr as usize }, 664 | 72usize, 665 | concat!( 666 | "Offset of field: ", 667 | stringify!(_STARTUPINFOW), 668 | "::", 669 | stringify!(lpReserved2) 670 | ) 671 | ); 672 | assert_eq!( 673 | unsafe { ::std::ptr::addr_of!((*ptr).hStdInput) as usize - ptr as usize }, 674 | 80usize, 675 | concat!( 676 | "Offset of field: ", 677 | stringify!(_STARTUPINFOW), 678 | "::", 679 | stringify!(hStdInput) 680 | ) 681 | ); 682 | assert_eq!( 683 | unsafe { ::std::ptr::addr_of!((*ptr).hStdOutput) as usize - ptr as usize }, 684 | 88usize, 685 | concat!( 686 | "Offset of field: ", 687 | stringify!(_STARTUPINFOW), 688 | "::", 689 | stringify!(hStdOutput) 690 | ) 691 | ); 692 | assert_eq!( 693 | unsafe { ::std::ptr::addr_of!((*ptr).hStdError) as usize - ptr as usize }, 694 | 96usize, 695 | concat!( 696 | "Offset of field: ", 697 | stringify!(_STARTUPINFOW), 698 | "::", 699 | stringify!(hStdError) 700 | ) 701 | ); 702 | } 703 | pub type LPSTARTUPINFOW = *mut _STARTUPINFOW; 704 | #[repr(C)] 705 | #[derive(Debug, Copy, Clone)] 706 | pub struct _DETOUR_TRAMPOLINE { 707 | _unused: [u8; 0], 708 | } 709 | pub type PDETOUR_TRAMPOLINE = *mut _DETOUR_TRAMPOLINE; 710 | #[doc = " Binary Typedefs."] 711 | pub type PF_DETOUR_BINARY_BYWAY_CALLBACK = ::std::option::Option< 712 | unsafe extern "C" fn(pContext: PVOID, pszFile: LPCSTR, ppszOutFile: *mut LPCSTR) -> BOOL, 713 | >; 714 | pub type PF_DETOUR_BINARY_FILE_CALLBACK = ::std::option::Option< 715 | unsafe extern "C" fn( 716 | pContext: PVOID, 717 | pszOrigFile: LPCSTR, 718 | pszFile: LPCSTR, 719 | ppszOutFile: *mut LPCSTR, 720 | ) -> BOOL, 721 | >; 722 | pub type PF_DETOUR_BINARY_SYMBOL_CALLBACK = ::std::option::Option< 723 | unsafe extern "C" fn( 724 | pContext: PVOID, 725 | nOrigOrdinal: ULONG, 726 | nOrdinal: ULONG, 727 | pnOutOrdinal: *mut ULONG, 728 | pszOrigSymbol: LPCSTR, 729 | pszSymbol: LPCSTR, 730 | ppszOutSymbol: *mut LPCSTR, 731 | ) -> BOOL, 732 | >; 733 | pub type PF_DETOUR_BINARY_COMMIT_CALLBACK = 734 | ::std::option::Option BOOL>; 735 | pub type PF_DETOUR_ENUMERATE_EXPORT_CALLBACK = ::std::option::Option< 736 | unsafe extern "C" fn(pContext: PVOID, nOrdinal: ULONG, pszName: LPCSTR, pCode: PVOID) -> BOOL, 737 | >; 738 | pub type PF_DETOUR_IMPORT_FILE_CALLBACK = ::std::option::Option< 739 | unsafe extern "C" fn(pContext: PVOID, hModule: HMODULE, pszFile: LPCSTR) -> BOOL, 740 | >; 741 | pub type PF_DETOUR_IMPORT_FUNC_CALLBACK = ::std::option::Option< 742 | unsafe extern "C" fn(pContext: PVOID, nOrdinal: DWORD, pszFunc: LPCSTR, pvFunc: PVOID) -> BOOL, 743 | >; 744 | pub type PF_DETOUR_IMPORT_FUNC_CALLBACK_EX = ::std::option::Option< 745 | unsafe extern "C" fn( 746 | pContext: PVOID, 747 | nOrdinal: DWORD, 748 | pszFunc: LPCSTR, 749 | ppvFunc: *mut PVOID, 750 | ) -> BOOL, 751 | >; 752 | pub type PDETOUR_BINARY = *mut ::std::os::raw::c_void; 753 | unsafe extern "C" { 754 | #[doc = " Transaction APIs."] 755 | pub fn DetourTransactionBegin() -> LONG; 756 | } 757 | unsafe extern "C" { 758 | pub fn DetourTransactionAbort() -> LONG; 759 | } 760 | unsafe extern "C" { 761 | pub fn DetourTransactionCommit() -> LONG; 762 | } 763 | unsafe extern "C" { 764 | pub fn DetourTransactionCommitEx(pppFailedPointer: *mut *mut PVOID) -> LONG; 765 | } 766 | unsafe extern "C" { 767 | pub fn DetourUpdateThread(hThread: HANDLE) -> LONG; 768 | } 769 | unsafe extern "C" { 770 | pub fn DetourAttach(ppPointer: *mut PVOID, pDetour: PVOID) -> LONG; 771 | } 772 | unsafe extern "C" { 773 | pub fn DetourAttachEx( 774 | ppPointer: *mut PVOID, 775 | pDetour: PVOID, 776 | ppRealTrampoline: *mut PDETOUR_TRAMPOLINE, 777 | ppRealTarget: *mut PVOID, 778 | ppRealDetour: *mut PVOID, 779 | ) -> LONG; 780 | } 781 | unsafe extern "C" { 782 | pub fn DetourDetach(ppPointer: *mut PVOID, pDetour: PVOID) -> LONG; 783 | } 784 | unsafe extern "C" { 785 | pub fn DetourSetIgnoreTooSmall(fIgnore: BOOL) -> BOOL; 786 | } 787 | unsafe extern "C" { 788 | pub fn DetourSetRetainRegions(fRetain: BOOL) -> BOOL; 789 | } 790 | unsafe extern "C" { 791 | pub fn DetourSetSystemRegionLowerBound(pSystemRegionLowerBound: PVOID) -> PVOID; 792 | } 793 | unsafe extern "C" { 794 | pub fn DetourSetSystemRegionUpperBound(pSystemRegionUpperBound: PVOID) -> PVOID; 795 | } 796 | unsafe extern "C" { 797 | #[doc = " Code Functions."] 798 | pub fn DetourFindFunction(pszModule: LPCSTR, pszFunction: LPCSTR) -> PVOID; 799 | } 800 | unsafe extern "C" { 801 | pub fn DetourCodeFromPointer(pPointer: PVOID, ppGlobals: *mut PVOID) -> PVOID; 802 | } 803 | unsafe extern "C" { 804 | pub fn DetourCopyInstruction( 805 | pDst: PVOID, 806 | ppDstPool: *mut PVOID, 807 | pSrc: PVOID, 808 | ppTarget: *mut PVOID, 809 | plExtra: *mut LONG, 810 | ) -> PVOID; 811 | } 812 | unsafe extern "C" { 813 | pub fn DetourSetCodeModule(hModule: HMODULE, fLimitReferencesToModule: BOOL) -> BOOL; 814 | } 815 | unsafe extern "C" { 816 | pub fn DetourAllocateRegionWithinJumpBounds( 817 | pbTarget: LPCVOID, 818 | pcbAllocatedSize: PDWORD, 819 | ) -> PVOID; 820 | } 821 | unsafe extern "C" { 822 | pub fn DetourIsFunctionImported(pbCode: PBYTE, pbAddress: PBYTE) -> BOOL; 823 | } 824 | unsafe extern "C" { 825 | #[doc = " Loaded Binary Functions."] 826 | pub fn DetourGetContainingModule(pvAddr: PVOID) -> HMODULE; 827 | } 828 | unsafe extern "C" { 829 | pub fn DetourEnumerateModules(hModuleLast: HMODULE) -> HMODULE; 830 | } 831 | unsafe extern "C" { 832 | pub fn DetourGetEntryPoint(hModule: HMODULE) -> PVOID; 833 | } 834 | unsafe extern "C" { 835 | pub fn DetourGetModuleSize(hModule: HMODULE) -> ULONG; 836 | } 837 | unsafe extern "C" { 838 | pub fn DetourEnumerateExports( 839 | hModule: HMODULE, 840 | pContext: PVOID, 841 | pfExport: PF_DETOUR_ENUMERATE_EXPORT_CALLBACK, 842 | ) -> BOOL; 843 | } 844 | unsafe extern "C" { 845 | pub fn DetourEnumerateImports( 846 | hModule: HMODULE, 847 | pContext: PVOID, 848 | pfImportFile: PF_DETOUR_IMPORT_FILE_CALLBACK, 849 | pfImportFunc: PF_DETOUR_IMPORT_FUNC_CALLBACK, 850 | ) -> BOOL; 851 | } 852 | unsafe extern "C" { 853 | pub fn DetourEnumerateImportsEx( 854 | hModule: HMODULE, 855 | pContext: PVOID, 856 | pfImportFile: PF_DETOUR_IMPORT_FILE_CALLBACK, 857 | pfImportFuncEx: PF_DETOUR_IMPORT_FUNC_CALLBACK_EX, 858 | ) -> BOOL; 859 | } 860 | unsafe extern "C" { 861 | pub fn DetourFindPayload(hModule: HMODULE, rguid: *const GUID, pcbData: *mut DWORD) -> PVOID; 862 | } 863 | unsafe extern "C" { 864 | pub fn DetourFindPayloadEx(rguid: *const GUID, pcbData: *mut DWORD) -> PVOID; 865 | } 866 | unsafe extern "C" { 867 | pub fn DetourGetSizeOfPayloads(hModule: HMODULE) -> DWORD; 868 | } 869 | unsafe extern "C" { 870 | pub fn DetourFreePayload(pvData: PVOID) -> BOOL; 871 | } 872 | unsafe extern "C" { 873 | #[doc = " Persistent Binary Functions."] 874 | pub fn DetourBinaryOpen(hFile: HANDLE) -> PDETOUR_BINARY; 875 | } 876 | unsafe extern "C" { 877 | pub fn DetourBinaryEnumeratePayloads( 878 | pBinary: PDETOUR_BINARY, 879 | pGuid: *mut GUID, 880 | pcbData: *mut DWORD, 881 | pnIterator: *mut DWORD, 882 | ) -> PVOID; 883 | } 884 | unsafe extern "C" { 885 | pub fn DetourBinaryFindPayload( 886 | pBinary: PDETOUR_BINARY, 887 | rguid: *const GUID, 888 | pcbData: *mut DWORD, 889 | ) -> PVOID; 890 | } 891 | unsafe extern "C" { 892 | pub fn DetourBinarySetPayload( 893 | pBinary: PDETOUR_BINARY, 894 | rguid: *const GUID, 895 | pData: PVOID, 896 | cbData: DWORD, 897 | ) -> PVOID; 898 | } 899 | unsafe extern "C" { 900 | pub fn DetourBinaryDeletePayload(pBinary: PDETOUR_BINARY, rguid: *const GUID) -> BOOL; 901 | } 902 | unsafe extern "C" { 903 | pub fn DetourBinaryPurgePayloads(pBinary: PDETOUR_BINARY) -> BOOL; 904 | } 905 | unsafe extern "C" { 906 | pub fn DetourBinaryResetImports(pBinary: PDETOUR_BINARY) -> BOOL; 907 | } 908 | unsafe extern "C" { 909 | pub fn DetourBinaryEditImports( 910 | pBinary: PDETOUR_BINARY, 911 | pContext: PVOID, 912 | pfByway: PF_DETOUR_BINARY_BYWAY_CALLBACK, 913 | pfFile: PF_DETOUR_BINARY_FILE_CALLBACK, 914 | pfSymbol: PF_DETOUR_BINARY_SYMBOL_CALLBACK, 915 | pfCommit: PF_DETOUR_BINARY_COMMIT_CALLBACK, 916 | ) -> BOOL; 917 | } 918 | unsafe extern "C" { 919 | pub fn DetourBinaryWrite(pBinary: PDETOUR_BINARY, hFile: HANDLE) -> BOOL; 920 | } 921 | unsafe extern "C" { 922 | pub fn DetourBinaryClose(pBinary: PDETOUR_BINARY) -> BOOL; 923 | } 924 | unsafe extern "C" { 925 | #[doc = " Create Process & Load Dll."] 926 | pub fn DetourFindRemotePayload( 927 | hProcess: HANDLE, 928 | rguid: *const GUID, 929 | pcbData: *mut DWORD, 930 | ) -> PVOID; 931 | } 932 | pub type PDETOUR_CREATE_PROCESS_ROUTINEA = ::std::option::Option< 933 | unsafe extern "C" fn( 934 | lpApplicationName: LPCSTR, 935 | lpCommandLine: LPSTR, 936 | lpProcessAttributes: LPSECURITY_ATTRIBUTES, 937 | lpThreadAttributes: LPSECURITY_ATTRIBUTES, 938 | bInheritHandles: BOOL, 939 | dwCreationFlags: DWORD, 940 | lpEnvironment: LPVOID, 941 | lpCurrentDirectory: LPCSTR, 942 | lpStartupInfo: LPSTARTUPINFOA, 943 | lpProcessInformation: LPPROCESS_INFORMATION, 944 | ) -> BOOL, 945 | >; 946 | pub type PDETOUR_CREATE_PROCESS_ROUTINEW = ::std::option::Option< 947 | unsafe extern "C" fn( 948 | lpApplicationName: LPCWSTR, 949 | lpCommandLine: LPWSTR, 950 | lpProcessAttributes: LPSECURITY_ATTRIBUTES, 951 | lpThreadAttributes: LPSECURITY_ATTRIBUTES, 952 | bInheritHandles: BOOL, 953 | dwCreationFlags: DWORD, 954 | lpEnvironment: LPVOID, 955 | lpCurrentDirectory: LPCWSTR, 956 | lpStartupInfo: LPSTARTUPINFOW, 957 | lpProcessInformation: LPPROCESS_INFORMATION, 958 | ) -> BOOL, 959 | >; 960 | unsafe extern "C" { 961 | pub fn DetourCreateProcessWithDllA( 962 | lpApplicationName: LPCSTR, 963 | lpCommandLine: LPSTR, 964 | lpProcessAttributes: LPSECURITY_ATTRIBUTES, 965 | lpThreadAttributes: LPSECURITY_ATTRIBUTES, 966 | bInheritHandles: BOOL, 967 | dwCreationFlags: DWORD, 968 | lpEnvironment: LPVOID, 969 | lpCurrentDirectory: LPCSTR, 970 | lpStartupInfo: LPSTARTUPINFOA, 971 | lpProcessInformation: LPPROCESS_INFORMATION, 972 | lpDllName: LPCSTR, 973 | pfCreateProcessA: PDETOUR_CREATE_PROCESS_ROUTINEA, 974 | ) -> BOOL; 975 | } 976 | unsafe extern "C" { 977 | pub fn DetourCreateProcessWithDllW( 978 | lpApplicationName: LPCWSTR, 979 | lpCommandLine: LPWSTR, 980 | lpProcessAttributes: LPSECURITY_ATTRIBUTES, 981 | lpThreadAttributes: LPSECURITY_ATTRIBUTES, 982 | bInheritHandles: BOOL, 983 | dwCreationFlags: DWORD, 984 | lpEnvironment: LPVOID, 985 | lpCurrentDirectory: LPCWSTR, 986 | lpStartupInfo: LPSTARTUPINFOW, 987 | lpProcessInformation: LPPROCESS_INFORMATION, 988 | lpDllName: LPCSTR, 989 | pfCreateProcessW: PDETOUR_CREATE_PROCESS_ROUTINEW, 990 | ) -> BOOL; 991 | } 992 | unsafe extern "C" { 993 | pub fn DetourCreateProcessWithDllExA( 994 | lpApplicationName: LPCSTR, 995 | lpCommandLine: LPSTR, 996 | lpProcessAttributes: LPSECURITY_ATTRIBUTES, 997 | lpThreadAttributes: LPSECURITY_ATTRIBUTES, 998 | bInheritHandles: BOOL, 999 | dwCreationFlags: DWORD, 1000 | lpEnvironment: LPVOID, 1001 | lpCurrentDirectory: LPCSTR, 1002 | lpStartupInfo: LPSTARTUPINFOA, 1003 | lpProcessInformation: LPPROCESS_INFORMATION, 1004 | lpDllName: LPCSTR, 1005 | pfCreateProcessA: PDETOUR_CREATE_PROCESS_ROUTINEA, 1006 | ) -> BOOL; 1007 | } 1008 | unsafe extern "C" { 1009 | pub fn DetourCreateProcessWithDllExW( 1010 | lpApplicationName: LPCWSTR, 1011 | lpCommandLine: LPWSTR, 1012 | lpProcessAttributes: LPSECURITY_ATTRIBUTES, 1013 | lpThreadAttributes: LPSECURITY_ATTRIBUTES, 1014 | bInheritHandles: BOOL, 1015 | dwCreationFlags: DWORD, 1016 | lpEnvironment: LPVOID, 1017 | lpCurrentDirectory: LPCWSTR, 1018 | lpStartupInfo: LPSTARTUPINFOW, 1019 | lpProcessInformation: LPPROCESS_INFORMATION, 1020 | lpDllName: LPCSTR, 1021 | pfCreateProcessW: PDETOUR_CREATE_PROCESS_ROUTINEW, 1022 | ) -> BOOL; 1023 | } 1024 | unsafe extern "C" { 1025 | pub fn DetourCreateProcessWithDllsA( 1026 | lpApplicationName: LPCSTR, 1027 | lpCommandLine: LPSTR, 1028 | lpProcessAttributes: LPSECURITY_ATTRIBUTES, 1029 | lpThreadAttributes: LPSECURITY_ATTRIBUTES, 1030 | bInheritHandles: BOOL, 1031 | dwCreationFlags: DWORD, 1032 | lpEnvironment: LPVOID, 1033 | lpCurrentDirectory: LPCSTR, 1034 | lpStartupInfo: LPSTARTUPINFOA, 1035 | lpProcessInformation: LPPROCESS_INFORMATION, 1036 | nDlls: DWORD, 1037 | rlpDlls: *mut LPCSTR, 1038 | pfCreateProcessA: PDETOUR_CREATE_PROCESS_ROUTINEA, 1039 | ) -> BOOL; 1040 | } 1041 | unsafe extern "C" { 1042 | pub fn DetourCreateProcessWithDllsW( 1043 | lpApplicationName: LPCWSTR, 1044 | lpCommandLine: LPWSTR, 1045 | lpProcessAttributes: LPSECURITY_ATTRIBUTES, 1046 | lpThreadAttributes: LPSECURITY_ATTRIBUTES, 1047 | bInheritHandles: BOOL, 1048 | dwCreationFlags: DWORD, 1049 | lpEnvironment: LPVOID, 1050 | lpCurrentDirectory: LPCWSTR, 1051 | lpStartupInfo: LPSTARTUPINFOW, 1052 | lpProcessInformation: LPPROCESS_INFORMATION, 1053 | nDlls: DWORD, 1054 | rlpDlls: *mut LPCSTR, 1055 | pfCreateProcessW: PDETOUR_CREATE_PROCESS_ROUTINEW, 1056 | ) -> BOOL; 1057 | } 1058 | unsafe extern "C" { 1059 | pub fn DetourProcessViaHelperA( 1060 | dwTargetPid: DWORD, 1061 | lpDllName: LPCSTR, 1062 | pfCreateProcessA: PDETOUR_CREATE_PROCESS_ROUTINEA, 1063 | ) -> BOOL; 1064 | } 1065 | unsafe extern "C" { 1066 | pub fn DetourProcessViaHelperW( 1067 | dwTargetPid: DWORD, 1068 | lpDllName: LPCSTR, 1069 | pfCreateProcessW: PDETOUR_CREATE_PROCESS_ROUTINEW, 1070 | ) -> BOOL; 1071 | } 1072 | unsafe extern "C" { 1073 | pub fn DetourProcessViaHelperDllsA( 1074 | dwTargetPid: DWORD, 1075 | nDlls: DWORD, 1076 | rlpDlls: *mut LPCSTR, 1077 | pfCreateProcessA: PDETOUR_CREATE_PROCESS_ROUTINEA, 1078 | ) -> BOOL; 1079 | } 1080 | unsafe extern "C" { 1081 | pub fn DetourProcessViaHelperDllsW( 1082 | dwTargetPid: DWORD, 1083 | nDlls: DWORD, 1084 | rlpDlls: *mut LPCSTR, 1085 | pfCreateProcessW: PDETOUR_CREATE_PROCESS_ROUTINEW, 1086 | ) -> BOOL; 1087 | } 1088 | unsafe extern "C" { 1089 | pub fn DetourUpdateProcessWithDll(hProcess: HANDLE, rlpDlls: *mut LPCSTR, nDlls: DWORD) 1090 | -> BOOL; 1091 | } 1092 | unsafe extern "C" { 1093 | pub fn DetourUpdateProcessWithDllEx( 1094 | hProcess: HANDLE, 1095 | hImage: HMODULE, 1096 | bIs32Bit: BOOL, 1097 | rlpDlls: *mut LPCSTR, 1098 | nDlls: DWORD, 1099 | ) -> BOOL; 1100 | } 1101 | unsafe extern "C" { 1102 | pub fn DetourCopyPayloadToProcess( 1103 | hProcess: HANDLE, 1104 | rguid: *const GUID, 1105 | pvData: LPCVOID, 1106 | cbData: DWORD, 1107 | ) -> BOOL; 1108 | } 1109 | unsafe extern "C" { 1110 | pub fn DetourCopyPayloadToProcessEx( 1111 | hProcess: HANDLE, 1112 | rguid: *const GUID, 1113 | pvData: LPCVOID, 1114 | cbData: DWORD, 1115 | ) -> PVOID; 1116 | } 1117 | unsafe extern "C" { 1118 | pub fn DetourRestoreAfterWith() -> BOOL; 1119 | } 1120 | unsafe extern "C" { 1121 | pub fn DetourRestoreAfterWithEx(pvData: PVOID, cbData: DWORD) -> BOOL; 1122 | } 1123 | unsafe extern "C" { 1124 | pub fn DetourIsHelperProcess() -> BOOL; 1125 | } 1126 | unsafe extern "C" { 1127 | pub fn DetourFinishHelperProcess(arg1: HWND, arg2: HINSTANCE, arg3: LPSTR, arg4: INT); 1128 | } 1129 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "1.1.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "android-tzdata" 31 | version = "0.1.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 34 | 35 | [[package]] 36 | name = "android_system_properties" 37 | version = "0.1.5" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 40 | dependencies = [ 41 | "libc", 42 | ] 43 | 44 | [[package]] 45 | name = "anstream" 46 | version = "0.6.18" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 49 | dependencies = [ 50 | "anstyle", 51 | "anstyle-parse", 52 | "anstyle-query", 53 | "anstyle-wincon", 54 | "colorchoice", 55 | "is_terminal_polyfill", 56 | "utf8parse", 57 | ] 58 | 59 | [[package]] 60 | name = "anstyle" 61 | version = "1.0.10" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 64 | 65 | [[package]] 66 | name = "anstyle-parse" 67 | version = "0.2.6" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 70 | dependencies = [ 71 | "utf8parse", 72 | ] 73 | 74 | [[package]] 75 | name = "anstyle-query" 76 | version = "1.1.2" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 79 | dependencies = [ 80 | "windows-sys 0.59.0", 81 | ] 82 | 83 | [[package]] 84 | name = "anstyle-wincon" 85 | version = "3.0.7" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" 88 | dependencies = [ 89 | "anstyle", 90 | "once_cell", 91 | "windows-sys 0.59.0", 92 | ] 93 | 94 | [[package]] 95 | name = "asar" 96 | version = "0.3.0" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "1b9051a11bd40b01b4f8b926956b9f22ff5ef08fcbc7eb34693e2a73982ff85e" 99 | dependencies = [ 100 | "byteorder", 101 | "clap", 102 | "color-eyre", 103 | "hex", 104 | "is_executable", 105 | "serde", 106 | "serde_json", 107 | "serde_with", 108 | "sha2", 109 | "thiserror 1.0.69", 110 | "walkdir", 111 | "wax", 112 | ] 113 | 114 | [[package]] 115 | name = "autocfg" 116 | version = "1.4.0" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 119 | 120 | [[package]] 121 | name = "backtrace" 122 | version = "0.3.71" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" 125 | dependencies = [ 126 | "addr2line", 127 | "cc", 128 | "cfg-if", 129 | "libc", 130 | "miniz_oxide", 131 | "object", 132 | "rustc-demangle", 133 | ] 134 | 135 | [[package]] 136 | name = "base64" 137 | version = "0.22.1" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 140 | 141 | [[package]] 142 | name = "bindgen" 143 | version = "0.71.1" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" 146 | dependencies = [ 147 | "bitflags 2.8.0", 148 | "cexpr", 149 | "clang-sys", 150 | "itertools", 151 | "log", 152 | "prettyplease", 153 | "proc-macro2", 154 | "quote", 155 | "regex", 156 | "rustc-hash", 157 | "shlex", 158 | "syn", 159 | ] 160 | 161 | [[package]] 162 | name = "bitflags" 163 | version = "1.3.2" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 166 | 167 | [[package]] 168 | name = "bitflags" 169 | version = "2.8.0" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" 172 | 173 | [[package]] 174 | name = "block-buffer" 175 | version = "0.10.4" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 178 | dependencies = [ 179 | "generic-array", 180 | ] 181 | 182 | [[package]] 183 | name = "bumpalo" 184 | version = "3.16.0" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 187 | 188 | [[package]] 189 | name = "byteorder" 190 | version = "1.5.0" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 193 | 194 | [[package]] 195 | name = "cc" 196 | version = "1.2.10" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" 199 | dependencies = [ 200 | "shlex", 201 | ] 202 | 203 | [[package]] 204 | name = "cexpr" 205 | version = "0.6.0" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 208 | dependencies = [ 209 | "nom", 210 | ] 211 | 212 | [[package]] 213 | name = "cfg-if" 214 | version = "1.0.0" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 217 | 218 | [[package]] 219 | name = "chrono" 220 | version = "0.4.39" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" 223 | dependencies = [ 224 | "android-tzdata", 225 | "iana-time-zone", 226 | "num-traits", 227 | "serde", 228 | "windows-targets", 229 | ] 230 | 231 | [[package]] 232 | name = "clang-sys" 233 | version = "1.8.1" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" 236 | dependencies = [ 237 | "glob", 238 | "libc", 239 | "libloading", 240 | ] 241 | 242 | [[package]] 243 | name = "clap" 244 | version = "4.5.27" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" 247 | dependencies = [ 248 | "clap_builder", 249 | "clap_derive", 250 | ] 251 | 252 | [[package]] 253 | name = "clap_builder" 254 | version = "4.5.27" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" 257 | dependencies = [ 258 | "anstream", 259 | "anstyle", 260 | "clap_lex", 261 | "strsim", 262 | ] 263 | 264 | [[package]] 265 | name = "clap_derive" 266 | version = "4.5.24" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" 269 | dependencies = [ 270 | "heck", 271 | "proc-macro2", 272 | "quote", 273 | "syn", 274 | ] 275 | 276 | [[package]] 277 | name = "clap_lex" 278 | version = "0.7.4" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 281 | 282 | [[package]] 283 | name = "cmake" 284 | version = "0.1.54" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" 287 | dependencies = [ 288 | "cc", 289 | ] 290 | 291 | [[package]] 292 | name = "color-eyre" 293 | version = "0.6.3" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" 296 | dependencies = [ 297 | "backtrace", 298 | "color-spantrace", 299 | "eyre", 300 | "indenter", 301 | "once_cell", 302 | "owo-colors", 303 | "tracing-error", 304 | ] 305 | 306 | [[package]] 307 | name = "color-spantrace" 308 | version = "0.2.1" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" 311 | dependencies = [ 312 | "once_cell", 313 | "owo-colors", 314 | "tracing-core", 315 | "tracing-error", 316 | ] 317 | 318 | [[package]] 319 | name = "colorchoice" 320 | version = "1.0.3" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 323 | 324 | [[package]] 325 | name = "const_format" 326 | version = "0.2.34" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" 329 | dependencies = [ 330 | "const_format_proc_macros", 331 | ] 332 | 333 | [[package]] 334 | name = "const_format_proc_macros" 335 | version = "0.2.34" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" 338 | dependencies = [ 339 | "proc-macro2", 340 | "quote", 341 | "unicode-xid", 342 | ] 343 | 344 | [[package]] 345 | name = "core-foundation-sys" 346 | version = "0.8.7" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 349 | 350 | [[package]] 351 | name = "cpufeatures" 352 | version = "0.2.17" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 355 | dependencies = [ 356 | "libc", 357 | ] 358 | 359 | [[package]] 360 | name = "crypto-common" 361 | version = "0.1.6" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 364 | dependencies = [ 365 | "generic-array", 366 | "typenum", 367 | ] 368 | 369 | [[package]] 370 | name = "ctor" 371 | version = "0.4.2" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "a4735f265ba6a1188052ca32d461028a7d1125868be18e287e756019da7607b5" 374 | dependencies = [ 375 | "ctor-proc-macro", 376 | "dtor", 377 | ] 378 | 379 | [[package]] 380 | name = "ctor-proc-macro" 381 | version = "0.0.5" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "4f211af61d8efdd104f96e57adf5e426ba1bc3ed7a4ead616e15e5881fd79c4d" 384 | 385 | [[package]] 386 | name = "darling" 387 | version = "0.20.10" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" 390 | dependencies = [ 391 | "darling_core", 392 | "darling_macro", 393 | ] 394 | 395 | [[package]] 396 | name = "darling_core" 397 | version = "0.20.10" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" 400 | dependencies = [ 401 | "fnv", 402 | "ident_case", 403 | "proc-macro2", 404 | "quote", 405 | "strsim", 406 | "syn", 407 | ] 408 | 409 | [[package]] 410 | name = "darling_macro" 411 | version = "0.20.10" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" 414 | dependencies = [ 415 | "darling_core", 416 | "quote", 417 | "syn", 418 | ] 419 | 420 | [[package]] 421 | name = "deranged" 422 | version = "0.3.11" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 425 | dependencies = [ 426 | "powerfmt", 427 | "serde", 428 | ] 429 | 430 | [[package]] 431 | name = "digest" 432 | version = "0.10.7" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 435 | dependencies = [ 436 | "block-buffer", 437 | "crypto-common", 438 | ] 439 | 440 | [[package]] 441 | name = "dirs" 442 | version = "6.0.0" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" 445 | dependencies = [ 446 | "dirs-sys", 447 | ] 448 | 449 | [[package]] 450 | name = "dirs-sys" 451 | version = "0.5.0" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" 454 | dependencies = [ 455 | "libc", 456 | "option-ext", 457 | "redox_users", 458 | "windows-sys 0.59.0", 459 | ] 460 | 461 | [[package]] 462 | name = "dtor" 463 | version = "0.0.6" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "97cbdf2ad6846025e8e25df05171abfb30e3ababa12ee0a0e44b9bbe570633a8" 466 | dependencies = [ 467 | "dtor-proc-macro", 468 | ] 469 | 470 | [[package]] 471 | name = "dtor-proc-macro" 472 | version = "0.0.5" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "7454e41ff9012c00d53cf7f475c5e3afa3b91b7c90568495495e8d9bf47a1055" 475 | 476 | [[package]] 477 | name = "either" 478 | version = "1.13.0" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 481 | 482 | [[package]] 483 | name = "electron-hook" 484 | version = "0.2.1" 485 | dependencies = [ 486 | "asar", 487 | "ctor", 488 | "dirs", 489 | "electron-hook-detours-sys", 490 | "libc", 491 | "retour", 492 | "serde_json", 493 | "uuid", 494 | "widestring", 495 | "winapi", 496 | ] 497 | 498 | [[package]] 499 | name = "electron-hook-detours-sys" 500 | version = "0.1.0" 501 | dependencies = [ 502 | "bindgen", 503 | "cc", 504 | "cmake", 505 | ] 506 | 507 | [[package]] 508 | name = "equivalent" 509 | version = "1.0.1" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 512 | 513 | [[package]] 514 | name = "eyre" 515 | version = "0.6.12" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" 518 | dependencies = [ 519 | "indenter", 520 | "once_cell", 521 | ] 522 | 523 | [[package]] 524 | name = "fnv" 525 | version = "1.0.7" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 528 | 529 | [[package]] 530 | name = "generic-array" 531 | version = "0.14.7" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 534 | dependencies = [ 535 | "typenum", 536 | "version_check", 537 | ] 538 | 539 | [[package]] 540 | name = "getrandom" 541 | version = "0.2.15" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 544 | dependencies = [ 545 | "cfg-if", 546 | "libc", 547 | "wasi 0.11.0+wasi-snapshot-preview1", 548 | ] 549 | 550 | [[package]] 551 | name = "getrandom" 552 | version = "0.3.3" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 555 | dependencies = [ 556 | "cfg-if", 557 | "libc", 558 | "r-efi", 559 | "wasi 0.14.2+wasi-0.2.4", 560 | ] 561 | 562 | [[package]] 563 | name = "gimli" 564 | version = "0.28.1" 565 | source = "registry+https://github.com/rust-lang/crates.io-index" 566 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 567 | 568 | [[package]] 569 | name = "glob" 570 | version = "0.3.2" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" 573 | 574 | [[package]] 575 | name = "hashbrown" 576 | version = "0.12.3" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 579 | 580 | [[package]] 581 | name = "hashbrown" 582 | version = "0.15.2" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 585 | 586 | [[package]] 587 | name = "heck" 588 | version = "0.5.0" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 591 | 592 | [[package]] 593 | name = "hex" 594 | version = "0.4.3" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 597 | 598 | [[package]] 599 | name = "iana-time-zone" 600 | version = "0.1.61" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 603 | dependencies = [ 604 | "android_system_properties", 605 | "core-foundation-sys", 606 | "iana-time-zone-haiku", 607 | "js-sys", 608 | "wasm-bindgen", 609 | "windows-core", 610 | ] 611 | 612 | [[package]] 613 | name = "iana-time-zone-haiku" 614 | version = "0.1.2" 615 | source = "registry+https://github.com/rust-lang/crates.io-index" 616 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 617 | dependencies = [ 618 | "cc", 619 | ] 620 | 621 | [[package]] 622 | name = "ident_case" 623 | version = "1.0.1" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 626 | 627 | [[package]] 628 | name = "indenter" 629 | version = "0.3.3" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" 632 | 633 | [[package]] 634 | name = "indexmap" 635 | version = "1.9.3" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 638 | dependencies = [ 639 | "autocfg", 640 | "hashbrown 0.12.3", 641 | "serde", 642 | ] 643 | 644 | [[package]] 645 | name = "indexmap" 646 | version = "2.7.1" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" 649 | dependencies = [ 650 | "equivalent", 651 | "hashbrown 0.15.2", 652 | "serde", 653 | ] 654 | 655 | [[package]] 656 | name = "is_executable" 657 | version = "1.0.4" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "d4a1b5bad6f9072935961dfbf1cced2f3d129963d091b6f69f007fe04e758ae2" 660 | dependencies = [ 661 | "winapi", 662 | ] 663 | 664 | [[package]] 665 | name = "is_terminal_polyfill" 666 | version = "1.70.1" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 669 | 670 | [[package]] 671 | name = "itertools" 672 | version = "0.11.0" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" 675 | dependencies = [ 676 | "either", 677 | ] 678 | 679 | [[package]] 680 | name = "itoa" 681 | version = "1.0.14" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 684 | 685 | [[package]] 686 | name = "js-sys" 687 | version = "0.3.77" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 690 | dependencies = [ 691 | "once_cell", 692 | "wasm-bindgen", 693 | ] 694 | 695 | [[package]] 696 | name = "lazy_static" 697 | version = "1.5.0" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 700 | 701 | [[package]] 702 | name = "libc" 703 | version = "0.2.172" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 706 | 707 | [[package]] 708 | name = "libloading" 709 | version = "0.8.8" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" 712 | dependencies = [ 713 | "cfg-if", 714 | "windows-targets", 715 | ] 716 | 717 | [[package]] 718 | name = "libredox" 719 | version = "0.1.3" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 722 | dependencies = [ 723 | "bitflags 2.8.0", 724 | "libc", 725 | ] 726 | 727 | [[package]] 728 | name = "libudis86-sys" 729 | version = "0.2.1" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "139bbf9ddb1bfc90c1ac64dd2923d9c957cd433cee7315c018125d72ab08a6b0" 732 | dependencies = [ 733 | "cc", 734 | "libc", 735 | ] 736 | 737 | [[package]] 738 | name = "log" 739 | version = "0.4.25" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" 742 | 743 | [[package]] 744 | name = "mach2" 745 | version = "0.4.2" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" 748 | dependencies = [ 749 | "libc", 750 | ] 751 | 752 | [[package]] 753 | name = "memchr" 754 | version = "2.7.4" 755 | source = "registry+https://github.com/rust-lang/crates.io-index" 756 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 757 | 758 | [[package]] 759 | name = "minimal-lexical" 760 | version = "0.2.1" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 763 | 764 | [[package]] 765 | name = "miniz_oxide" 766 | version = "0.7.4" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 769 | dependencies = [ 770 | "adler", 771 | ] 772 | 773 | [[package]] 774 | name = "mmap-fixed-fixed" 775 | version = "0.1.3" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "0681853891801e4763dc252e843672faf32bcfee27a0aa3b19733902af450acc" 778 | dependencies = [ 779 | "libc", 780 | "winapi", 781 | ] 782 | 783 | [[package]] 784 | name = "nom" 785 | version = "7.1.3" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 788 | dependencies = [ 789 | "memchr", 790 | "minimal-lexical", 791 | ] 792 | 793 | [[package]] 794 | name = "num-conv" 795 | version = "0.1.0" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 798 | 799 | [[package]] 800 | name = "num-traits" 801 | version = "0.2.19" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 804 | dependencies = [ 805 | "autocfg", 806 | ] 807 | 808 | [[package]] 809 | name = "object" 810 | version = "0.32.2" 811 | source = "registry+https://github.com/rust-lang/crates.io-index" 812 | checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" 813 | dependencies = [ 814 | "memchr", 815 | ] 816 | 817 | [[package]] 818 | name = "once_cell" 819 | version = "1.20.2" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 822 | 823 | [[package]] 824 | name = "option-ext" 825 | version = "0.2.0" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 828 | 829 | [[package]] 830 | name = "owo-colors" 831 | version = "3.5.0" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" 834 | 835 | [[package]] 836 | name = "pin-project-lite" 837 | version = "0.2.16" 838 | source = "registry+https://github.com/rust-lang/crates.io-index" 839 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 840 | 841 | [[package]] 842 | name = "pori" 843 | version = "0.0.0" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "a4a63d338dec139f56dacc692ca63ad35a6be6a797442479b55acd611d79e906" 846 | dependencies = [ 847 | "nom", 848 | ] 849 | 850 | [[package]] 851 | name = "powerfmt" 852 | version = "0.2.0" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 855 | 856 | [[package]] 857 | name = "prettyplease" 858 | version = "0.2.34" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55" 861 | dependencies = [ 862 | "proc-macro2", 863 | "syn", 864 | ] 865 | 866 | [[package]] 867 | name = "proc-macro2" 868 | version = "1.0.93" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 871 | dependencies = [ 872 | "unicode-ident", 873 | ] 874 | 875 | [[package]] 876 | name = "quote" 877 | version = "1.0.38" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 880 | dependencies = [ 881 | "proc-macro2", 882 | ] 883 | 884 | [[package]] 885 | name = "r-efi" 886 | version = "5.2.0" 887 | source = "registry+https://github.com/rust-lang/crates.io-index" 888 | checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" 889 | 890 | [[package]] 891 | name = "redox_users" 892 | version = "0.5.0" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" 895 | dependencies = [ 896 | "getrandom 0.2.15", 897 | "libredox", 898 | "thiserror 2.0.11", 899 | ] 900 | 901 | [[package]] 902 | name = "regex" 903 | version = "1.11.1" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 906 | dependencies = [ 907 | "aho-corasick", 908 | "memchr", 909 | "regex-automata", 910 | "regex-syntax", 911 | ] 912 | 913 | [[package]] 914 | name = "regex-automata" 915 | version = "0.4.9" 916 | source = "registry+https://github.com/rust-lang/crates.io-index" 917 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 918 | dependencies = [ 919 | "aho-corasick", 920 | "memchr", 921 | "regex-syntax", 922 | ] 923 | 924 | [[package]] 925 | name = "regex-syntax" 926 | version = "0.8.5" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 929 | 930 | [[package]] 931 | name = "region" 932 | version = "3.0.2" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7" 935 | dependencies = [ 936 | "bitflags 1.3.2", 937 | "libc", 938 | "mach2", 939 | "windows-sys 0.52.0", 940 | ] 941 | 942 | [[package]] 943 | name = "retour" 944 | version = "0.3.1" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "a9af44d40e2400b44d491bfaf8eae111b09f23ac4de6e92728e79d93e699c527" 947 | dependencies = [ 948 | "cfg-if", 949 | "generic-array", 950 | "libc", 951 | "libudis86-sys", 952 | "mmap-fixed-fixed", 953 | "once_cell", 954 | "region", 955 | "slice-pool2", 956 | ] 957 | 958 | [[package]] 959 | name = "rustc-demangle" 960 | version = "0.1.24" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 963 | 964 | [[package]] 965 | name = "rustc-hash" 966 | version = "2.1.1" 967 | source = "registry+https://github.com/rust-lang/crates.io-index" 968 | checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" 969 | 970 | [[package]] 971 | name = "rustversion" 972 | version = "1.0.19" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" 975 | 976 | [[package]] 977 | name = "ryu" 978 | version = "1.0.18" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 981 | 982 | [[package]] 983 | name = "same-file" 984 | version = "1.0.6" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 987 | dependencies = [ 988 | "winapi-util", 989 | ] 990 | 991 | [[package]] 992 | name = "serde" 993 | version = "1.0.217" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 996 | dependencies = [ 997 | "serde_derive", 998 | ] 999 | 1000 | [[package]] 1001 | name = "serde_derive" 1002 | version = "1.0.217" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 1005 | dependencies = [ 1006 | "proc-macro2", 1007 | "quote", 1008 | "syn", 1009 | ] 1010 | 1011 | [[package]] 1012 | name = "serde_json" 1013 | version = "1.0.140" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 1016 | dependencies = [ 1017 | "itoa", 1018 | "memchr", 1019 | "ryu", 1020 | "serde", 1021 | ] 1022 | 1023 | [[package]] 1024 | name = "serde_with" 1025 | version = "3.12.0" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" 1028 | dependencies = [ 1029 | "base64", 1030 | "chrono", 1031 | "hex", 1032 | "indexmap 1.9.3", 1033 | "indexmap 2.7.1", 1034 | "serde", 1035 | "serde_derive", 1036 | "serde_json", 1037 | "serde_with_macros", 1038 | "time", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "serde_with_macros" 1043 | version = "3.12.0" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" 1046 | dependencies = [ 1047 | "darling", 1048 | "proc-macro2", 1049 | "quote", 1050 | "syn", 1051 | ] 1052 | 1053 | [[package]] 1054 | name = "sha2" 1055 | version = "0.10.8" 1056 | source = "registry+https://github.com/rust-lang/crates.io-index" 1057 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1058 | dependencies = [ 1059 | "cfg-if", 1060 | "cpufeatures", 1061 | "digest", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "sharded-slab" 1066 | version = "0.1.7" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1069 | dependencies = [ 1070 | "lazy_static", 1071 | ] 1072 | 1073 | [[package]] 1074 | name = "shlex" 1075 | version = "1.3.0" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1078 | 1079 | [[package]] 1080 | name = "slice-pool2" 1081 | version = "0.4.3" 1082 | source = "registry+https://github.com/rust-lang/crates.io-index" 1083 | checksum = "7a3d689654af89bdfeba29a914ab6ac0236d382eb3b764f7454dde052f2821f8" 1084 | 1085 | [[package]] 1086 | name = "strsim" 1087 | version = "0.11.1" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1090 | 1091 | [[package]] 1092 | name = "syn" 1093 | version = "2.0.96" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" 1096 | dependencies = [ 1097 | "proc-macro2", 1098 | "quote", 1099 | "unicode-ident", 1100 | ] 1101 | 1102 | [[package]] 1103 | name = "thiserror" 1104 | version = "1.0.69" 1105 | source = "registry+https://github.com/rust-lang/crates.io-index" 1106 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1107 | dependencies = [ 1108 | "thiserror-impl 1.0.69", 1109 | ] 1110 | 1111 | [[package]] 1112 | name = "thiserror" 1113 | version = "2.0.11" 1114 | source = "registry+https://github.com/rust-lang/crates.io-index" 1115 | checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" 1116 | dependencies = [ 1117 | "thiserror-impl 2.0.11", 1118 | ] 1119 | 1120 | [[package]] 1121 | name = "thiserror-impl" 1122 | version = "1.0.69" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1125 | dependencies = [ 1126 | "proc-macro2", 1127 | "quote", 1128 | "syn", 1129 | ] 1130 | 1131 | [[package]] 1132 | name = "thiserror-impl" 1133 | version = "2.0.11" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" 1136 | dependencies = [ 1137 | "proc-macro2", 1138 | "quote", 1139 | "syn", 1140 | ] 1141 | 1142 | [[package]] 1143 | name = "thread_local" 1144 | version = "1.1.8" 1145 | source = "registry+https://github.com/rust-lang/crates.io-index" 1146 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 1147 | dependencies = [ 1148 | "cfg-if", 1149 | "once_cell", 1150 | ] 1151 | 1152 | [[package]] 1153 | name = "time" 1154 | version = "0.3.37" 1155 | source = "registry+https://github.com/rust-lang/crates.io-index" 1156 | checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" 1157 | dependencies = [ 1158 | "deranged", 1159 | "itoa", 1160 | "num-conv", 1161 | "powerfmt", 1162 | "serde", 1163 | "time-core", 1164 | "time-macros", 1165 | ] 1166 | 1167 | [[package]] 1168 | name = "time-core" 1169 | version = "0.1.2" 1170 | source = "registry+https://github.com/rust-lang/crates.io-index" 1171 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 1172 | 1173 | [[package]] 1174 | name = "time-macros" 1175 | version = "0.2.19" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" 1178 | dependencies = [ 1179 | "num-conv", 1180 | "time-core", 1181 | ] 1182 | 1183 | [[package]] 1184 | name = "tracing" 1185 | version = "0.1.41" 1186 | source = "registry+https://github.com/rust-lang/crates.io-index" 1187 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1188 | dependencies = [ 1189 | "pin-project-lite", 1190 | "tracing-core", 1191 | ] 1192 | 1193 | [[package]] 1194 | name = "tracing-core" 1195 | version = "0.1.33" 1196 | source = "registry+https://github.com/rust-lang/crates.io-index" 1197 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 1198 | dependencies = [ 1199 | "once_cell", 1200 | "valuable", 1201 | ] 1202 | 1203 | [[package]] 1204 | name = "tracing-error" 1205 | version = "0.2.1" 1206 | source = "registry+https://github.com/rust-lang/crates.io-index" 1207 | checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" 1208 | dependencies = [ 1209 | "tracing", 1210 | "tracing-subscriber", 1211 | ] 1212 | 1213 | [[package]] 1214 | name = "tracing-subscriber" 1215 | version = "0.3.19" 1216 | source = "registry+https://github.com/rust-lang/crates.io-index" 1217 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 1218 | dependencies = [ 1219 | "sharded-slab", 1220 | "thread_local", 1221 | "tracing-core", 1222 | ] 1223 | 1224 | [[package]] 1225 | name = "typenum" 1226 | version = "1.17.0" 1227 | source = "registry+https://github.com/rust-lang/crates.io-index" 1228 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1229 | 1230 | [[package]] 1231 | name = "unicode-ident" 1232 | version = "1.0.15" 1233 | source = "registry+https://github.com/rust-lang/crates.io-index" 1234 | checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" 1235 | 1236 | [[package]] 1237 | name = "unicode-xid" 1238 | version = "0.2.6" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 1241 | 1242 | [[package]] 1243 | name = "utf8parse" 1244 | version = "0.2.2" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1247 | 1248 | [[package]] 1249 | name = "uuid" 1250 | version = "1.16.0" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" 1253 | dependencies = [ 1254 | "getrandom 0.3.3", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "valuable" 1259 | version = "0.1.1" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 1262 | 1263 | [[package]] 1264 | name = "version_check" 1265 | version = "0.9.5" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1268 | 1269 | [[package]] 1270 | name = "walkdir" 1271 | version = "2.5.0" 1272 | source = "registry+https://github.com/rust-lang/crates.io-index" 1273 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 1274 | dependencies = [ 1275 | "same-file", 1276 | "winapi-util", 1277 | ] 1278 | 1279 | [[package]] 1280 | name = "wasi" 1281 | version = "0.11.0+wasi-snapshot-preview1" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1284 | 1285 | [[package]] 1286 | name = "wasi" 1287 | version = "0.14.2+wasi-0.2.4" 1288 | source = "registry+https://github.com/rust-lang/crates.io-index" 1289 | checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" 1290 | dependencies = [ 1291 | "wit-bindgen-rt", 1292 | ] 1293 | 1294 | [[package]] 1295 | name = "wasm-bindgen" 1296 | version = "0.2.100" 1297 | source = "registry+https://github.com/rust-lang/crates.io-index" 1298 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 1299 | dependencies = [ 1300 | "cfg-if", 1301 | "once_cell", 1302 | "rustversion", 1303 | "wasm-bindgen-macro", 1304 | ] 1305 | 1306 | [[package]] 1307 | name = "wasm-bindgen-backend" 1308 | version = "0.2.100" 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" 1310 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 1311 | dependencies = [ 1312 | "bumpalo", 1313 | "log", 1314 | "proc-macro2", 1315 | "quote", 1316 | "syn", 1317 | "wasm-bindgen-shared", 1318 | ] 1319 | 1320 | [[package]] 1321 | name = "wasm-bindgen-macro" 1322 | version = "0.2.100" 1323 | source = "registry+https://github.com/rust-lang/crates.io-index" 1324 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 1325 | dependencies = [ 1326 | "quote", 1327 | "wasm-bindgen-macro-support", 1328 | ] 1329 | 1330 | [[package]] 1331 | name = "wasm-bindgen-macro-support" 1332 | version = "0.2.100" 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" 1334 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 1335 | dependencies = [ 1336 | "proc-macro2", 1337 | "quote", 1338 | "syn", 1339 | "wasm-bindgen-backend", 1340 | "wasm-bindgen-shared", 1341 | ] 1342 | 1343 | [[package]] 1344 | name = "wasm-bindgen-shared" 1345 | version = "0.2.100" 1346 | source = "registry+https://github.com/rust-lang/crates.io-index" 1347 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 1348 | dependencies = [ 1349 | "unicode-ident", 1350 | ] 1351 | 1352 | [[package]] 1353 | name = "wax" 1354 | version = "0.6.0" 1355 | source = "registry+https://github.com/rust-lang/crates.io-index" 1356 | checksum = "8d12a78aa0bab22d2f26ed1a96df7ab58e8a93506a3e20adb47c51a93b4e1357" 1357 | dependencies = [ 1358 | "const_format", 1359 | "itertools", 1360 | "nom", 1361 | "pori", 1362 | "regex", 1363 | "thiserror 1.0.69", 1364 | "walkdir", 1365 | ] 1366 | 1367 | [[package]] 1368 | name = "widestring" 1369 | version = "1.2.0" 1370 | source = "registry+https://github.com/rust-lang/crates.io-index" 1371 | checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" 1372 | 1373 | [[package]] 1374 | name = "winapi" 1375 | version = "0.3.9" 1376 | source = "registry+https://github.com/rust-lang/crates.io-index" 1377 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1378 | dependencies = [ 1379 | "winapi-i686-pc-windows-gnu", 1380 | "winapi-x86_64-pc-windows-gnu", 1381 | ] 1382 | 1383 | [[package]] 1384 | name = "winapi-i686-pc-windows-gnu" 1385 | version = "0.4.0" 1386 | source = "registry+https://github.com/rust-lang/crates.io-index" 1387 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1388 | 1389 | [[package]] 1390 | name = "winapi-util" 1391 | version = "0.1.9" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1394 | dependencies = [ 1395 | "windows-sys 0.59.0", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "winapi-x86_64-pc-windows-gnu" 1400 | version = "0.4.0" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1403 | 1404 | [[package]] 1405 | name = "windows-core" 1406 | version = "0.52.0" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 1409 | dependencies = [ 1410 | "windows-targets", 1411 | ] 1412 | 1413 | [[package]] 1414 | name = "windows-sys" 1415 | version = "0.52.0" 1416 | source = "registry+https://github.com/rust-lang/crates.io-index" 1417 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1418 | dependencies = [ 1419 | "windows-targets", 1420 | ] 1421 | 1422 | [[package]] 1423 | name = "windows-sys" 1424 | version = "0.59.0" 1425 | source = "registry+https://github.com/rust-lang/crates.io-index" 1426 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1427 | dependencies = [ 1428 | "windows-targets", 1429 | ] 1430 | 1431 | [[package]] 1432 | name = "windows-targets" 1433 | version = "0.52.6" 1434 | source = "registry+https://github.com/rust-lang/crates.io-index" 1435 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1436 | dependencies = [ 1437 | "windows_aarch64_gnullvm", 1438 | "windows_aarch64_msvc", 1439 | "windows_i686_gnu", 1440 | "windows_i686_gnullvm", 1441 | "windows_i686_msvc", 1442 | "windows_x86_64_gnu", 1443 | "windows_x86_64_gnullvm", 1444 | "windows_x86_64_msvc", 1445 | ] 1446 | 1447 | [[package]] 1448 | name = "windows_aarch64_gnullvm" 1449 | version = "0.52.6" 1450 | source = "registry+https://github.com/rust-lang/crates.io-index" 1451 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1452 | 1453 | [[package]] 1454 | name = "windows_aarch64_msvc" 1455 | version = "0.52.6" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1458 | 1459 | [[package]] 1460 | name = "windows_i686_gnu" 1461 | version = "0.52.6" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1464 | 1465 | [[package]] 1466 | name = "windows_i686_gnullvm" 1467 | version = "0.52.6" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1470 | 1471 | [[package]] 1472 | name = "windows_i686_msvc" 1473 | version = "0.52.6" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1476 | 1477 | [[package]] 1478 | name = "windows_x86_64_gnu" 1479 | version = "0.52.6" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1482 | 1483 | [[package]] 1484 | name = "windows_x86_64_gnullvm" 1485 | version = "0.52.6" 1486 | source = "registry+https://github.com/rust-lang/crates.io-index" 1487 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1488 | 1489 | [[package]] 1490 | name = "windows_x86_64_msvc" 1491 | version = "0.52.6" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1494 | 1495 | [[package]] 1496 | name = "wit-bindgen-rt" 1497 | version = "0.39.0" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 1500 | dependencies = [ 1501 | "bitflags 2.8.0", 1502 | ] 1503 | --------------------------------------------------------------------------------